From 8391efd06343505013266879debfc96048c794f0 Mon Sep 17 00:00:00 2001 From: Aditya Bisht Date: Thu, 10 Oct 2024 06:38:19 +0700 Subject: [PATCH] feat: add smtp and imap interaction --- .gitignore | 6 +- Cargo.lock | 785 +++++++++++++----- packages/relayer/Cargo.toml | 9 +- packages/relayer/config.example.json | 6 +- .../email_templates/command_template.html | 2 +- .../migrations/20241008135456_init.down.sql | 5 + .../migrations/20241008135456_init.up.sql | 18 + packages/relayer/src/config.rs | 10 +- packages/relayer/src/db/mod.rs | 1 - packages/relayer/src/db/model.rs | 12 - packages/relayer/src/handler.rs | 148 +++- packages/relayer/src/mail.rs | 334 ++++++++ packages/relayer/src/main.rs | 9 +- packages/relayer/src/model.rs | 93 +++ packages/relayer/src/route.rs | 8 +- packages/relayer/src/schema.rs | 31 + packages/relayer/src/utils.rs | 12 + 17 files changed, 1268 insertions(+), 221 deletions(-) create mode 100644 packages/relayer/migrations/20241008135456_init.down.sql create mode 100644 packages/relayer/migrations/20241008135456_init.up.sql delete mode 100644 packages/relayer/src/db/mod.rs delete mode 100644 packages/relayer/src/db/model.rs create mode 100644 packages/relayer/src/mail.rs create mode 100644 packages/relayer/src/model.rs create mode 100644 packages/relayer/src/schema.rs create mode 100644 packages/relayer/src/utils.rs diff --git a/.gitignore b/.gitignore index 6c6e6de8..11170544 100644 --- a/.gitignore +++ b/.gitignore @@ -33,11 +33,7 @@ packages/contracts/deployments # Relayer target -packages/relayer/db/* -packages/relayer/*.db -packages/relayer/received_eml/*.eml -packages/relayer/received_eml/*.json -packages/relayer/proofs +packages/relayer/.sqlx/* packages/relayer/logs packages/relayer/config.json .ic.pem diff --git a/Cargo.lock b/Cargo.lock index ab3fd146..7eaf65d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,19 +14,13 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -94,9 +88,9 @@ checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -115,13 +109,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -144,6 +138,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "auto_impl" version = "1.2.0" @@ -152,14 +152,14 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" @@ -189,7 +189,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tower 0.5.1", + "tower", "tower-layer", "tower-service", "tracing", @@ -218,17 +218,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -368,9 +368,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" dependencies = [ "serde", ] @@ -430,9 +430,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.15" +version = "1.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" dependencies = [ "jobserver", "libc", @@ -579,9 +579,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" dependencies = [ "cfg-if", "cpufeatures", @@ -626,9 +626,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -761,7 +761,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -798,7 +798,7 @@ checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1141,10 +1141,10 @@ dependencies = [ "proc-macro2", "quote", "regex", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", - "syn 2.0.77", + "syn 2.0.79", "toml", "walkdir", ] @@ -1162,7 +1162,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1188,7 +1188,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.77", + "syn 2.0.79", "tempfile", "thiserror", "tiny-keccak", @@ -1203,7 +1203,7 @@ checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" dependencies = [ "chrono", "ethers-core", - "reqwest", + "reqwest 0.11.27", "semver 1.0.23", "serde", "serde_json", @@ -1228,7 +1228,7 @@ dependencies = [ "futures-locks", "futures-util", "instant", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", "thiserror", @@ -1260,7 +1260,7 @@ dependencies = [ "jsonwebtoken", "once_cell", "pin-project", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", "thiserror", @@ -1411,12 +1411,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -1436,6 +1436,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1463,9 +1478,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1478,9 +1493,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1488,15 +1503,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1516,9 +1531,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-locks" @@ -1532,26 +1547,26 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -1565,9 +1580,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1616,9 +1631,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -1661,7 +1676,26 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.5.0", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -1671,7 +1705,7 @@ dependencies = [ [[package]] name = "halo2curves" version = "0.7.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves.git#b753a832e92d5c86c5c997327a9cf9de86a18851" +source = "git+https://github.com/privacy-scaling-explorations/halo2curves.git#8771fe5a5d54fc03e74dbc8915db5dad3ab46a83" dependencies = [ "blake2", "digest", @@ -1697,7 +1731,7 @@ dependencies = [ [[package]] name = "halo2derive" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves.git#b753a832e92d5c86c5c997327a9cf9de86a18851" +source = "git+https://github.com/privacy-scaling-explorations/halo2curves.git#8771fe5a5d54fc03e74dbc8915db5dad3ab46a83" dependencies = [ "num-bigint", "num-integer", @@ -1707,6 +1741,20 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "handlebars" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25b617d1375ef96eeb920ae717e3da34a02fc979fe632c75128350f9e1f74a" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1723,6 +1771,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "hashers" version = "1.0.1" @@ -1872,9 +1926,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -1892,7 +1946,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "httparse", @@ -1915,6 +1969,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -1923,6 +1978,7 @@ dependencies = [ "pin-project-lite", "smallvec", "tokio", + "want", ] [[package]] @@ -1934,33 +1990,81 @@ dependencies = [ "futures-util", "http 0.2.12", "hyper 0.14.30", - "rustls", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "rustls 0.23.14", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.30", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "native-tls", "tokio", - "tokio-rustls", + "tokio-native-tls", + "tower-service", ] [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", + "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", "hyper 1.4.1", "pin-project-lite", + "socket2", "tokio", - "tower 0.4.13", "tower-service", + "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2056,12 +2160,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -2096,9 +2200,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is-terminal" @@ -2178,9 +2282,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa", @@ -2240,9 +2344,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libloading" @@ -2385,15 +2489,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -2415,6 +2510,23 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "neon" version = "0.10.1" @@ -2564,23 +2676,23 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "open-fastrlp" @@ -2607,6 +2719,50 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -2650,9 +2806,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -2761,6 +2917,51 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "pest_meta" +version = "2.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.6.5" @@ -2768,7 +2969,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.5.0", + "indexmap 2.6.0", ] [[package]] @@ -2811,7 +3012,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2834,22 +3035,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2887,9 +3088,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "poseidon-rs" @@ -2931,7 +3132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2959,9 +3160,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -3076,9 +3277,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] @@ -3096,9 +3297,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", @@ -3108,9 +3309,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", @@ -3119,9 +3320,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relayer" @@ -3130,7 +3331,11 @@ dependencies = [ "anyhow", "axum", "chrono", + "ethers", + "handlebars", + "regex", "relayer-utils", + "reqwest 0.12.8", "serde", "serde_json", "slog", @@ -3143,7 +3348,6 @@ dependencies = [ [[package]] name = "relayer-utils" version = "0.3.7" -source = "git+https://github.com/zkemail/relayer-utils.git?branch=main#5764f93c4e803cba39c0f06f8ced0cab1d229a25" dependencies = [ "anyhow", "base64 0.21.7", @@ -3155,6 +3359,7 @@ dependencies = [ "hmac-sha256", "itertools 0.10.5", "lazy_static", + "mailparse", "neon", "num-bigint", "num-traits", @@ -3162,6 +3367,7 @@ dependencies = [ "poseidon-rs", "rand_core", "regex", + "reqwest 0.11.27", "rsa", "serde", "serde_json", @@ -3184,27 +3390,30 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", - "hyper-rustls", + "hyper-rustls 0.24.2", + "hyper-tls 0.5.0", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", - "system-configuration", + "system-configuration 0.5.1", "tokio", - "tokio-rustls", + "tokio-native-tls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", @@ -3214,6 +3423,49 @@ dependencies = [ "winreg", ] +[[package]] +name = "reqwest" +version = "0.12.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-rustls 0.27.3", + "hyper-tls 0.6.0", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "system-configuration 0.6.1", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -3340,9 +3592,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.35" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -3359,10 +3611,23 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -3372,6 +3637,21 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -3382,6 +3662,17 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.17" @@ -3436,6 +3727,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "schannel" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -3484,6 +3784,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.9.0" @@ -3548,7 +3871,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3575,9 +3898,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -3792,9 +4115,9 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ "nom", "unicode_categories", @@ -3834,7 +4157,7 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.5.0", + "indexmap 2.6.0", "log", "memchr", "once_cell", @@ -3846,10 +4169,12 @@ dependencies = [ "smallvec", "sqlformat", "thiserror", + "time", "tokio", "tokio-stream", "tracing", "url", + "uuid 1.10.0", ] [[package]] @@ -3862,7 +4187,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3885,7 +4210,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.77", + "syn 2.0.79", "tempfile", "tokio", "url", @@ -3929,7 +4254,9 @@ dependencies = [ "sqlx-core", "stringprep", "thiserror", + "time", "tracing", + "uuid 1.10.0", "whoami", ] @@ -3967,7 +4294,9 @@ dependencies = [ "sqlx-core", "stringprep", "thiserror", + "time", "tracing", + "uuid 1.10.0", "whoami", ] @@ -3990,8 +4319,10 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", + "time", "tracing", "url", + "uuid 1.10.0", ] [[package]] @@ -4043,7 +4374,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4062,7 +4393,7 @@ dependencies = [ "fs2", "hex", "once_cell", - "reqwest", + "reqwest 0.11.27", "semver 1.0.23", "serde", "serde_json", @@ -4085,9 +4416,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -4116,6 +4447,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "system-configuration" @@ -4125,7 +4459,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", - "system-configuration-sys", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys 0.6.0", ] [[package]] @@ -4138,6 +4483,16 @@ dependencies = [ "libc", ] +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "take_mut" version = "0.2.2" @@ -4152,9 +4507,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -4176,22 +4531,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4285,7 +4640,17 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", ] [[package]] @@ -4294,15 +4659,26 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.14", + "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -4317,18 +4693,18 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tungstenite", "webpki-roots", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -4360,32 +4736,17 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", "winnow", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", -] - [[package]] name = "tower" version = "0.5.1" @@ -4448,7 +4809,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4534,7 +4895,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls", + "rustls 0.21.12", "sha1", "thiserror", "url", @@ -4547,6 +4908,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "uint" version = "0.9.5" @@ -4567,36 +4934,36 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unicode_categories" @@ -4730,7 +5097,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -4764,7 +5131,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4798,7 +5165,7 @@ checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4873,6 +5240,36 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -5023,9 +5420,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -5092,7 +5489,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] diff --git a/packages/relayer/Cargo.toml b/packages/relayer/Cargo.toml index b46f4954..2675f1bd 100644 --- a/packages/relayer/Cargo.toml +++ b/packages/relayer/Cargo.toml @@ -8,13 +8,18 @@ anyhow = "1.0.89" axum = "0.7.7" serde = { version = "1.0.210", features = ["derive"] } serde_json = "1.0.128" -sqlx = { version = "0.8.2", features = ["postgres", "runtime-tokio"] } +sqlx = { version = "0.8.2", features = ["postgres", "runtime-tokio", "migrate", "uuid", "time"] } tokio = { version = "1.40.0", features = ["full"] } tower-http = { version = "0.6.1", features = ["cors"] } -relayer-utils = { git = "https://github.com/zkemail/relayer-utils.git", branch = "main" } +# relayer-utils = { git = "https://github.com/zkemail/relayer-utils.git", branch = "main" } +relayer-utils = { path = "../../../relayer-utils" } slog = { version = "2.7.0", features = [ "max_level_trace", "release_max_level_warn", ] } uuid = { version = "1.10.0", features = ["serde", "v4"] } chrono = { version = "0.4.38", features = ["serde"] } +ethers = "2.0.14" +reqwest = { version = "0.12.8", features = ["json"] } +handlebars = "6.1.0" +regex = "1.11.0" diff --git a/packages/relayer/config.example.json b/packages/relayer/config.example.json index 415ec936..ce5da39f 100644 --- a/packages/relayer/config.example.json +++ b/packages/relayer/config.example.json @@ -1,10 +1,14 @@ { "port": 8000, "databaseUrl": "postgres://test@localhost:5432/relayer", + "smtpUrl": "http://localhost:3000", "proverUrl": "https://zkemail--email-auth-prover-v1-4-0-flask-app.modal.run", + "paths": { + "pem": "./.ic.pem", + "emailTemplates": "./email_templates" + }, "icp": { "canisterId": "q7eci-dyaaa-aaaak-qdbia-cai", - "pemPath": "./.ic.pem", "icReplicaUrl": "https://a4gq6-oaaaa-aaaab-qaa4q-cai.raw.icp0.io/?id=q7eci-dyaaa-aaaak-qdbia-cai" }, "chains": { diff --git a/packages/relayer/email_templates/command_template.html b/packages/relayer/email_templates/command_template.html index e3ca9232..91ad7ce2 100644 --- a/packages/relayer/email_templates/command_template.html +++ b/packages/relayer/email_templates/command_template.html @@ -126,7 +126,7 @@

Reply "Confirm" to this email to accept the request. - Your request ID is #{{requestId}}. + Your request ID is {{requestId}}.

If you did not initiate this request, please contact us immediately. diff --git a/packages/relayer/migrations/20241008135456_init.down.sql b/packages/relayer/migrations/20241008135456_init.down.sql new file mode 100644 index 00000000..2ff0f67a --- /dev/null +++ b/packages/relayer/migrations/20241008135456_init.down.sql @@ -0,0 +1,5 @@ +-- Add down migration script here + +DROP TABLE IF EXISTS requests; + +DROP TABLE IF EXISTS expected_replies; \ No newline at end of file diff --git a/packages/relayer/migrations/20241008135456_init.up.sql b/packages/relayer/migrations/20241008135456_init.up.sql new file mode 100644 index 00000000..bf18f5b3 --- /dev/null +++ b/packages/relayer/migrations/20241008135456_init.up.sql @@ -0,0 +1,18 @@ +-- Add up migration script here + +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + +CREATE TYPE status_enum AS ENUM ('Request received', 'Email sent', 'Email response received', 'Proving', 'Performing on chain transaction', 'Finished'); + +CREATE TABLE IF NOT EXISTS requests ( + id UUID PRIMARY KEY NOT NULL DEFAULT (uuid_generate_v4()), + status status_enum NOT NULL DEFAULT 'Request received', + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS expected_replies ( + message_id VARCHAR(255) PRIMARY KEY, + request_id VARCHAR(255), + has_reply BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); \ No newline at end of file diff --git a/packages/relayer/src/config.rs b/packages/relayer/src/config.rs index a1c191c9..05bf998b 100644 --- a/packages/relayer/src/config.rs +++ b/packages/relayer/src/config.rs @@ -10,17 +10,25 @@ use std::io::Read; pub struct Config { pub port: usize, pub database_url: String, + pub smtp_url: String, pub prover_url: String, + pub path: PathConfig, pub icp: IcpConfig, pub chains: HashMap, pub json_logger: bool, } +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PathConfig { + pub pem: String, + pub email_templates: String, +} + #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct IcpConfig { pub canister_id: String, - pub pem_path: String, pub ic_replica_url: String, } diff --git a/packages/relayer/src/db/mod.rs b/packages/relayer/src/db/mod.rs deleted file mode 100644 index ee2d47ae..00000000 --- a/packages/relayer/src/db/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod model; diff --git a/packages/relayer/src/db/model.rs b/packages/relayer/src/db/model.rs deleted file mode 100644 index fe91c428..00000000 --- a/packages/relayer/src/db/model.rs +++ /dev/null @@ -1,12 +0,0 @@ -use serde::{Deserialize, Serialize}; -use sqlx::FromRow; -use uuid::Uuid; - -#[derive(Debug, FromRow, Deserialize, Serialize)] -#[allow(non_snake_case)] -pub struct RequestModel { - pub id: Uuid, - pub status: String, - #[serde(rename = "updatedAt")] - pub updated_at: Option>, -} diff --git a/packages/relayer/src/handler.rs b/packages/relayer/src/handler.rs index 98ea8958..7cbc431b 100644 --- a/packages/relayer/src/handler.rs +++ b/packages/relayer/src/handler.rs @@ -1,4 +1,19 @@ -use axum::{response::IntoResponse, Json}; +use std::sync::Arc; + +use axum::{extract::State, http::StatusCode, response::IntoResponse, Json}; +use regex::Regex; +use relayer_utils::{field_to_hex, ParsedEmail, LOG}; +use serde_json::{json, Value}; +use slog::info; +use uuid::Uuid; + +use crate::{ + mail::handle_email_event, + model::{create_request, update_request, RequestStatus}, + schema::EmailTxAuthSchema, + utils::parse_command_template, + RelayerState, +}; pub async fn health_checker_handler() -> impl IntoResponse { const MESSAGE: &str = "Hello from ZK Email!"; @@ -10,3 +25,134 @@ pub async fn health_checker_handler() -> impl IntoResponse { Json(json_response) } + +pub async fn submit_handler( + State(relayer_state): State>, + Json(body): Json, +) -> Result)> { + info!(LOG, "Payload: {:?}", body); + + let uuid = create_request(&relayer_state.db).await.map_err(|e| { + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(json!({"error": e.to_string()})), + ) + })?; + + let command = parse_command_template(&body.command_template, &body.command_params); + + let account_code = if body.code_exists_in_email { + let hex_code = field_to_hex(&body.account_code.clone().0); + Some(hex_code.trim_start_matches("0x").to_string()) + } else { + None + }; + + handle_email_event( + crate::mail::EmailEvent::Command { + request_id: uuid, + email_address: body.email_address.clone(), + command, + account_code, + subject: body.subject.clone(), + body: body.body.clone(), + }, + (*relayer_state).clone(), + ) + .await + .map_err(|e| { + // Convert the error to the desired type + ( + reqwest::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(json!({"error": e.to_string()})), + ) + })?; + + let response = json!({ + "status": "success", + "message": "email sent", + "request_id": uuid + }); + + return Ok((StatusCode::OK, Json(response))); +} + +pub async fn receive_email_handler( + State(relayer_state): State>, + body: String, +) -> Result)> { + // Define the regex pattern for UUID + let uuid_regex = Regex::new( + r"\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b", + ) + .unwrap(); + + // Attempt to find a UUID in the body + let request_id = uuid_regex.find(&body).map(|m| m.as_str()); + + match request_id { + Some(request_id) => { + info!(LOG, "Extracted UUID: {:?}", request_id); + } + None => { + info!(LOG, "No UUID found in the body"); + // Handle the case where no UUID is found + let response = json!({ + "status": "error", + "message": "No UUID found in the email body", + }); + return Ok((StatusCode::BAD_REQUEST, Json(response))); + } + } + + let request_id = request_id + .ok_or_else(|| { + ( + reqwest::StatusCode::BAD_REQUEST, + axum::Json(json!({"error": "Request ID is None"})), + ) + }) + .and_then(|id| { + id.parse::().map_err(|_| { + ( + reqwest::StatusCode::BAD_REQUEST, + axum::Json(json!({"error": "Failed to parse request ID"})), + ) + }) + })?; + + update_request( + &relayer_state.db, + request_id, + RequestStatus::EmailResponseReceived, + ) + .await + .map_err(|e| { + // Convert the error to the expected type + ( + reqwest::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(json!({"error": e.to_string()})), + ) + })?; + + // Log the received body + info!(LOG, "Received email body: {:?}", body); + + let parsed_email = ParsedEmail::new_from_raw_email(&body).await.map_err(|e| { + // Convert the error to the expected type + ( + reqwest::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(json!({"error": e.to_string()})), + ) + })?; + + // Process the body as needed + // For example, you might want to parse it or pass it to another function + + let response = json!({ + "status": "success", + "message": "email received", + }); + + Ok((StatusCode::OK, Json(response))) +} diff --git a/packages/relayer/src/mail.rs b/packages/relayer/src/mail.rs new file mode 100644 index 00000000..4ca859a1 --- /dev/null +++ b/packages/relayer/src/mail.rs @@ -0,0 +1,334 @@ +use std::path::PathBuf; + +use anyhow::Result; +use handlebars::Handlebars; +use relayer_utils::ParsedEmail; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use sqlx::PgPool; +use tokio::fs::read_to_string; +use uuid::Uuid; + +use crate::{ + config::PathConfig, + model::{insert_expected_reply, is_valid_reply, update_request, RequestStatus}, + RelayerState, +}; + +/// Represents an email message to be sent. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EmailMessage { + pub to: String, + pub subject: String, + pub reference: Option, + pub reply_to: Option, + pub body_plain: String, + pub body_html: String, + pub body_attachments: Option>, +} + +/// Represents an attachment in an email message. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EmailAttachment { + pub inline_id: String, + pub content_type: String, + pub contents: Vec, +} + +/// Represents different types of email events. +#[derive(Debug, Clone)] +pub enum EmailEvent { + Command { + request_id: Uuid, + email_address: String, + command: String, + account_code: Option, + subject: String, + body: String, + }, + Ack { + email_addr: String, + command: String, + original_message_id: Option, + original_subject: String, + }, + Completion {}, + Error { + email_addr: String, + error: String, + original_subject: String, + original_message_id: Option, + }, +} + +/// Handles all possible email events and requests. +/// +/// # Arguments +/// +/// * `event` - The `EmailAuthEvent` to be handled. +/// +/// # Returns +/// +/// A `Result` indicating success or an `EmailError`. +pub async fn handle_email_event(event: EmailEvent, relayer_state: RelayerState) -> Result<()> { + match event { + EmailEvent::Command { + request_id, + email_address, + command, + account_code, + subject, + body, + } => { + // Prepare the command with the account code if it exists + let command = if let Some(code) = account_code { + format!("{} Code {}", command, code) + } else { + command + }; + + // Create the plain text body + let body_plain = format!( + "ZK Email request. \ + Your request ID is {}", + request_id + ); + + // Prepare data for HTML rendering + let render_data = serde_json::json!({ + "userEmailAddr": email_address, + "body": body, + "requestId": request_id, + "command": command, + }); + let body_html = + render_html("command_template.html", render_data, relayer_state.clone()).await?; + + // Create and send the email + let email = EmailMessage { + to: email_address, + subject, + reference: None, + reply_to: None, + body_plain, + body_html, + body_attachments: None, + }; + + send_email( + email, + Some(ExpectsReply::new(request_id)), + relayer_state.clone(), + ) + .await?; + + update_request(&relayer_state.db, request_id, RequestStatus::EmailSent).await?; + } + EmailEvent::Ack { + email_addr, + command, + original_message_id, + original_subject, + } => todo!(), + EmailEvent::Completion {} => todo!(), + EmailEvent::Error { + email_addr, + error, + original_subject, + original_message_id, + } => todo!(), // EmailEvent::Ack { + // email_addr, + // command, + // original_message_id, + // original_subject, + // } => { + // let body_plain = format!( + // "Hi {}!\nYour email with the command {} is received.", + // email_addr, command + // ); + // // Prepare data for HTML rendering + // let render_data = serde_json::json!({"userEmailAddr": email_addr, "request": command}); + // let body_html = render_html("acknowledgement.html", render_data).await?; + // let subject = format!("Re: {}", original_subject); + // // Create and send the email + // let email = EmailMessage { + // to: email_addr, + // subject, + // body_plain, + // body_html, + // reference: original_message_id.clone(), + // reply_to: original_message_id, + // body_attachments: None, + // }; + // send_email(email, None).await?; + // } + // EmailEvent::Completion {} => {} + // EmailEvent::Error { + // email_addr, + // error, + // original_subject, + // original_message_id, + // } => { + // let subject = format!("Re: {}", original_subject); + + // let body_plain = format!( + // "An error occurred while processing your request. \ + // Error: {}", + // error + // ); + + // // Prepare data for HTML rendering + // let render_data = serde_json::json!({ + // "error": error, + // "userEmailAddr": email_addr, + // }); + // let body_html = render_html("error.html", render_data).await?; + + // // Create and send the email + // let email = EmailMessage { + // to: email_addr, + // subject, + // reference: original_message_id.clone(), + // reply_to: original_message_id, + // body_plain, + // body_html, + // body_attachments: None, + // }; + + // send_email(email, None).await?; + // } + } + + Ok(()) +} + +/// Renders an HTML template with the given data. +/// +/// # Arguments +/// +/// * `template_name` - The name of the template file. +/// * `render_data` - The data to be used in rendering the template. +/// +/// # Returns +/// +/// A `Result` containing the rendered HTML string or an `Error`. +async fn render_html( + template_name: &str, + render_data: Value, + relayer_state: RelayerState, +) -> Result { + // Construct the full path to the email template + let email_template_filename = PathBuf::new() + .join(relayer_state.config.path.email_templates) + .join(template_name); + + // Read the email template file + let email_template = read_to_string(&email_template_filename).await?; + + // Create a new Handlebars instance + let reg = Handlebars::new(); + + // Render the template with the provided data + let template = reg.render_template(&email_template, &render_data)?; + Ok(template) +} + +/// Sends an email using the configured SMTP server. +/// +/// # Arguments +/// +/// * `email` - The `EmailMessage` to be sent. +/// * `expects_reply` - An optional `ExpectsReply` struct indicating if a reply is expected. +/// +/// # Returns +/// +/// A `Result` indicating success or an `EmailError`. +async fn send_email( + email: EmailMessage, + expects_reply: Option, + relayer_state: RelayerState, +) -> Result<()> { + // Send POST request to email server + let response = relayer_state + .http_client + .post(format!("{}/api/sendEmail", relayer_state.config.smtp_url)) + .json(&email) + .send() + .await?; + + // Check if the email was sent successfully + if !response.status().is_success() { + return Err(anyhow::anyhow!( + "Failed to send email: {}", + response.text().await.unwrap_or_default() + )); + } + + // Handle expected reply if necessary + if let Some(expects_reply) = expects_reply { + let response_body: EmailResponse = response.json().await?; + + let message_id = response_body.message_id; + insert_expected_reply(&relayer_state.db, &message_id, expects_reply.request_id).await?; + } + + Ok(()) +} + +/// Represents the response from the email server after sending an email. +#[derive(Debug, Clone, Serialize, Deserialize)] +struct EmailResponse { + status: String, + message_id: String, +} + +/// Represents an expectation of a reply to an email. +pub struct ExpectsReply { + request_id: Option, +} + +impl ExpectsReply { + /// Creates a new `ExpectsReply` instance with a request ID. + /// + /// # Arguments + /// + /// * `request_id` - The ID of the request expecting a reply. + fn new(request_id: Uuid) -> Self { + Self { + request_id: Some(request_id.to_string()), + } + } + + /// Creates a new `ExpectsReply` instance without a request ID. + fn new_no_request_id() -> Self { + Self { request_id: None } + } +} + +/// Checks if the email is a reply to a command that expects a reply. +/// Will return false for duplicate replies. +/// Will return true if the email is not a reply. +/// +/// # Arguments +/// +/// * `email` - The `ParsedEmail` to be checked. +/// +/// # Returns +/// +/// A `Result` containing a boolean indicating if the request is valid. +pub async fn check_is_valid_request(email: &ParsedEmail, pool: &PgPool) -> Result { + // Check if the email is a reply by looking for the "In-Reply-To" header + let reply_message_id = match email + .headers + .get_header("In-Reply-To") + .and_then(|v| v.first().cloned()) + { + Some(id) => id, + // Email is not a reply, so it's valid + None => return Ok(true), + }; + + // Check if the reply is valid (not a duplicate) using the database + let is_valid = is_valid_reply(pool, &reply_message_id).await?; + Ok(is_valid) +} diff --git a/packages/relayer/src/main.rs b/packages/relayer/src/main.rs index 4b622f3f..ca490f21 100644 --- a/packages/relayer/src/main.rs +++ b/packages/relayer/src/main.rs @@ -1,7 +1,10 @@ mod config; -mod db; mod handler; +mod mail; +mod model; mod route; +mod schema; +mod utils; use std::sync::Arc; @@ -11,6 +14,7 @@ use axum::http::{ Method, }; use relayer_utils::LOG; +use reqwest::Client; use route::create_router; use slog::info; use sqlx::{postgres::PgPoolOptions, Pool, Postgres}; @@ -18,7 +22,9 @@ use tower_http::cors::CorsLayer; use config::Config; +#[derive(Debug, Clone)] pub struct RelayerState { + http_client: Client, config: Config, db: Pool, } @@ -40,6 +46,7 @@ async fn main() -> Result<()> { .allow_headers([AUTHORIZATION, ACCEPT, CONTENT_TYPE]); let relayer = create_router(Arc::new(RelayerState { + http_client: Client::new(), config: config.clone(), db: pool.clone(), })) diff --git a/packages/relayer/src/model.rs b/packages/relayer/src/model.rs new file mode 100644 index 00000000..3070c8a9 --- /dev/null +++ b/packages/relayer/src/model.rs @@ -0,0 +1,93 @@ +use anyhow::{Error, Ok, Result}; +use serde::{Deserialize, Serialize}; +use sqlx::{FromRow, PgPool, Row}; +use uuid::Uuid; + +#[derive(Debug, FromRow, Deserialize, Serialize)] +#[allow(non_snake_case)] +pub struct RequestModel { + pub id: Uuid, + pub status: String, + #[serde(rename = "updatedAt")] + pub updated_at: Option>, +} + +#[derive(Debug, FromRow, Deserialize, Serialize)] +#[allow(non_snake_case)] +pub struct ExpectedReplyModel { + pub message_id: String, + pub request_id: Option, + pub has_reply: Option, + #[serde(rename = "createdAt")] + pub created_at: chrono::DateTime, +} + +#[derive(Debug, Serialize, Deserialize, sqlx::Type)] +#[sqlx(type_name = "status_enum")] +pub enum RequestStatus { + #[sqlx(rename = "Request received")] + RequestReceived, + #[sqlx(rename = "Email sent")] + EmailSent, + #[sqlx(rename = "Email response received")] + EmailResponseReceived, + #[sqlx(rename = "Proving")] + Proving, + #[sqlx(rename = "Performing on chain transaction")] + PerformingOnChainTransaction, + #[sqlx(rename = "Finished")] + Finished, +} + +pub async fn create_request(pool: &PgPool) -> Result { + let query_result = sqlx::query!("INSERT INTO requests DEFAULT VALUES RETURNING id") + .fetch_one(pool) + .await?; + + Ok(query_result.id) +} + +pub async fn update_request(pool: &PgPool, request_id: Uuid, status: RequestStatus) -> Result<()> { + sqlx::query!( + "UPDATE requests SET status = $1 WHERE id = $2", + status as RequestStatus, + request_id + ) + .execute(pool) + .await + .map_err(|e| Error::msg(format!("Failed to update request: {}", e)))?; + + Ok(()) +} + +pub async fn insert_expected_reply( + pool: &PgPool, + message_id: &str, + request_id: Option, +) -> Result<()> { + sqlx::query!( + "INSERT INTO expected_replies (message_id, request_id) VALUES ($1, $2)", + message_id, + request_id + ) + .execute(pool) + .await + .map_err(|e| Error::msg(format!("Failed to insert expected_reply: {}", e)))?; + + Ok(()) +} + +pub async fn is_valid_reply(pool: &PgPool, message_id: &str) -> Result { + let query_result = sqlx::query!( + "UPDATE expected_replies + SET has_reply = true + WHERE message_id = $1 AND has_reply = false + RETURNING has_reply", + message_id + ) + .fetch_one(pool) + .await + .map_err(|e| Error::msg(format!("Failed to validate reply: {}", e)))?; + + Ok(query_result.has_reply.unwrap_or(false)) +} diff --git a/packages/relayer/src/route.rs b/packages/relayer/src/route.rs index ea13578e..0a6d8723 100644 --- a/packages/relayer/src/route.rs +++ b/packages/relayer/src/route.rs @@ -5,13 +5,17 @@ use axum::{ Router, }; -use crate::{handler::health_checker_handler, RelayerState}; +use crate::{ + handler::{health_checker_handler, receive_email_handler, submit_handler}, + RelayerState, +}; pub fn create_router(relayer_state: Arc) -> Router { Router::new() .route("/api/healthz", get(health_checker_handler)) + .route("/api/submit", post(submit_handler)) + .route("/api/receiveEmail", post(receive_email_handler)) // .route("/api/status/:id", get(get_status_handler)) - // .route("/api/submit/", post(submit_handler)) // .route("/api/addDKIMKey", post(add_dkim_key_handler)) .with_state(relayer_state) } diff --git a/packages/relayer/src/schema.rs b/packages/relayer/src/schema.rs new file mode 100644 index 00000000..bb396c1d --- /dev/null +++ b/packages/relayer/src/schema.rs @@ -0,0 +1,31 @@ +use std::collections::HashMap; + +use ethers::{abi::Item, types::Address}; +use relayer_utils::AccountCode; +use serde::Deserialize; + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct EmailTxAuthSchema { + pub contract_address: Address, + pub email_auth_contract_address: Address, + pub account_code: AccountCode, + pub code_exists_in_email: bool, + pub function_abi: Item, + pub command_template: String, + pub command_params: HashMap, + pub remaining_args: HashMap, + pub email_address: String, + pub subject: String, + pub body: String, + pub chain: String, +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DKIMSchema { + dkim_contract_address: Address, + selector: String, + domain: String, + chain: String, +} diff --git a/packages/relayer/src/utils.rs b/packages/relayer/src/utils.rs new file mode 100644 index 00000000..8ddadd18 --- /dev/null +++ b/packages/relayer/src/utils.rs @@ -0,0 +1,12 @@ +use std::collections::HashMap; + +pub fn parse_command_template(template: &str, params: &HashMap) -> String { + let mut parsed_string = template.to_string(); + + for (key, value) in params { + let placeholder = format!("${{{}}}", key); + parsed_string = parsed_string.replace(&placeholder, value); + } + + parsed_string +}