From f5ef0a3885756c7afb61b0c5e745681966507f1e Mon Sep 17 00:00:00 2001 From: Kushal7788 Date: Thu, 20 Nov 2025 16:20:24 +0530 Subject: [PATCH] Added allowed-email-hosts field in zk-email auth to whitelist hosts able to generate the signatures --- Cargo.lock | 540 ++++++++++++++++++++------ Cargo.toml | 1 + contracts/account/Cargo.toml | 1 + contracts/account/src/auth.rs | 5 +- contracts/account/src/auth/zkemail.rs | 5 + contracts/account/src/contract.rs | 15 +- contracts/account/src/error.rs | 9 + contracts/account/src/execute.rs | 426 +++++++++++++++++++- contracts/account/src/msg.rs | 12 + 9 files changed, 882 insertions(+), 132 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e87368f..aba7308c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -22,9 +31,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "ark-bls12-381" @@ -189,6 +198,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + [[package]] name = "block-buffer" version = "0.10.4" @@ -212,18 +227,27 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" dependencies = [ "serde", ] [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "num-traits", +] [[package]] name = "const-oid" @@ -231,6 +255,19 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "cosmos-sdk-proto" +version = "0.23.0-pre" +source = "git+https://github.com/burnt-labs/cosmos-rust?branch=feat%2Fxion-zk#b7c2358d00fd51f258ba66c9d753d4cf71da2e41" +dependencies = [ + "pbjson", + "pbjson-types", + "prost", + "prost-types", + "serde", + "tendermint-proto", +] + [[package]] name = "cosmwasm-core" version = "2.2.2" @@ -269,7 +306,7 @@ checksum = "a782b93fae93e57ca8ad3e9e994e784583f5933aeaaa5c80a545c4b437be2047" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -293,7 +330,7 @@ checksum = "e01c9214319017f6ebd8e299036e1f717fa9bb6724e758f7d6fb2477599d1a29" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -406,7 +443,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -448,9 +485,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -483,7 +520,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "unicode-xid", ] @@ -507,7 +544,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -537,21 +574,25 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ + "pkcs8", + "serde", "signature", ] [[package]] name = "ed25519-zebra" -version = "4.0.3" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" +checksum = "0017d969298eec91e3db7a2985a8cab4df6341d86e6f3a6f5878b13fb7846bc9" dependencies = [ "curve25519-dalek", "ed25519", - "hashbrown 0.14.5", - "hex", + "hashbrown 0.15.5", + "pkcs8", "rand_core", + "serde", "sha2", + "subtle", "zeroize", ] @@ -582,6 +623,28 @@ dependencies = [ "zeroize", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "ff" version = "0.13.1" @@ -598,6 +661,12 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flex-error" version = "0.4.4" @@ -607,6 +676,12 @@ dependencies = [ "paste", ] +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -618,9 +693,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -638,6 +713,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "group" version = "0.13.0" @@ -660,14 +747,27 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "ahash", "allocator-api2", + "equivalent", + "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" @@ -685,9 +785,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -698,9 +798,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -711,11 +811,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -726,42 +825,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -791,13 +886,13 @@ dependencies = [ ] [[package]] -name = "informalsystems-pbjson" -version = "0.7.0" +name = "indexmap" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa4a0980c8379295100d70854354e78df2ee1c6ca0f96ffe89afeb3140e3a3d" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ - "base64 0.21.7", - "serde", + "equivalent", + "hashbrown 0.16.0", ] [[package]] @@ -809,6 +904,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -847,9 +951,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.175" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libm" @@ -857,17 +961,35 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "num-bigint" @@ -881,11 +1003,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -957,6 +1078,43 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pbjson" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" +dependencies = [ + "base64 0.21.7", + "serde", +] + +[[package]] +name = "pbjson-build" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" +dependencies = [ + "heck", + "itertools 0.13.0", + "prost", + "prost-types", +] + +[[package]] +name = "pbjson-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" +dependencies = [ + "bytes", + "chrono", + "pbjson", + "pbjson-build", + "prost", + "prost-build", + "serde", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -972,6 +1130,16 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "pkcs1" version = "0.7.5" @@ -995,9 +1163,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -1017,6 +1185,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.110", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -1029,9 +1207,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -1046,6 +1224,26 @@ dependencies = [ "prost-derive", ] +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck", + "itertools 0.14.0", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.110", + "tempfile", +] + [[package]] name = "prost-derive" version = "0.13.5" @@ -1056,18 +1254,33 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", +] + +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.8.5" @@ -1094,7 +1307,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", ] [[package]] @@ -1117,6 +1330,35 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + [[package]] name = "rfc6979" version = "0.4.0" @@ -1160,9 +1402,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" dependencies = [ "const-oid", "digest", @@ -1187,6 +1429,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "ryu" version = "1.0.20" @@ -1214,7 +1469,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1240,9 +1495,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -1269,22 +1524,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1295,7 +1550,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1366,9 +1621,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -1404,9 +1659,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" dependencies = [ "proc-macro2", "quote", @@ -1421,18 +1676,32 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys", ] [[package]] name = "tendermint-proto" -version = "0.40.4" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c40e13d39ca19082d8a7ed22de7595979350319833698f8b1080f29620a094" +checksum = "8ed14abe3b0502a3afe21ca74ca5cdd6c7e8d326d982c26f98a394445eb31d6e" dependencies = [ "bytes", "flex-error", "prost", + "prost-types", "serde", "serde_bytes", "subtle-encoding", @@ -1456,14 +1725,14 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "time" -version = "0.3.43" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "num-conv", @@ -1499,9 +1768,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -1511,29 +1780,26 @@ dependencies = [ name = "treasury" version = "0.1.0" dependencies = [ + "cosmos-sdk-proto", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus", "cw2", - "schemars", - "serde", - "serde_json", "thiserror", "url", - "xion-cosmos-sdk-proto", ] [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-xid" @@ -1583,11 +1849,41 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xion-account" @@ -1595,11 +1891,13 @@ version = "0.1.1" dependencies = [ "base64 0.21.7", "bech32 0.9.1", + "cosmos-sdk-proto", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus", "cw2", - "getrandom", + "ed25519-zebra", + "getrandom 0.2.16", "hex", "p256", "ripemd", @@ -1610,28 +1908,14 @@ dependencies = [ "sha2", "thiserror", "tiny-keccak", - "xion-cosmos-sdk-proto", -] - -[[package]] -name = "xion-cosmos-sdk-proto" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5950da92cdb6e0fdebe4513a1defd73b6c4af7d1fa72ae5f14780451c535bc2" -dependencies = [ - "informalsystems-pbjson", - "prost", - "serde", - "tendermint-proto", ] [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -1639,13 +1923,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "synstructure", ] @@ -1666,7 +1950,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1686,15 +1970,15 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] @@ -1707,14 +1991,14 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -1723,9 +2007,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -1734,11 +2018,11 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] diff --git a/Cargo.toml b/Cargo.toml index 17426ea3..06e5c609 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,5 +28,6 @@ phf = { version = "0.11.2", features = ["macros"] } rsa = { version = "0.9.2" } getrandom = { version = "0.2.10", features = ["custom"] } p256 = {version = "0.13.2", features = ["ecdsa-core", "arithmetic", "serde"]} +ed25519-zebra = { version = "4.1.0", features = ["alloc"] } cosmos-sdk-proto = {package = "cosmos-sdk-proto", git = "https://github.com/burnt-labs/cosmos-rust", branch = "feat/xion-zk", default-features = false, features = ["cosmwasm", "xion"]} url = "2.5.2" diff --git a/contracts/account/Cargo.toml b/contracts/account/Cargo.toml index 6e7b479a..b88a13fc 100644 --- a/contracts/account/Cargo.toml +++ b/contracts/account/Cargo.toml @@ -31,4 +31,5 @@ base64 = { workspace = true } rsa = { workspace = true } getrandom = { workspace = true } p256 = { workspace = true } +ed25519-zebra = { workspace = true } cosmos-sdk-proto = { workspace = true } \ No newline at end of file diff --git a/contracts/account/src/auth.rs b/contracts/account/src/auth.rs index 561e4516..d7418f6e 100644 --- a/contracts/account/src/auth.rs +++ b/contracts/account/src/auth.rs @@ -52,6 +52,7 @@ pub enum AddAuthenticator { ZKEmail { id: u8, email_salt: String, + allowed_email_hosts: Vec, signature: Binary, }, } @@ -94,6 +95,7 @@ pub enum Authenticator { }, ZKEmail { email_salt: String, + allowed_email_hosts: Vec, }, } @@ -170,9 +172,10 @@ impl Authenticator { } Authenticator::ZKEmail { email_salt, + allowed_email_hosts, } => { let tx_bytes_hash = util::base64url_encode(tx_bytes); - let verification = zkemail::verify(deps, tx_bytes_hash.as_bytes(), sig_bytes, email_salt)?; + let verification = zkemail::verify(deps, tx_bytes_hash.as_bytes(), sig_bytes, email_salt, allowed_email_hosts)?; Ok(verification) } } diff --git a/contracts/account/src/auth/zkemail.rs b/contracts/account/src/auth/zkemail.rs index d4fdbf2e..a715fe28 100644 --- a/contracts/account/src/auth/zkemail.rs +++ b/contracts/account/src/auth/zkemail.rs @@ -32,6 +32,7 @@ pub fn verify( tx_bytes: &[u8], sig_bytes: &[u8], email_salt: &str, + allowed_email_hosts: &[String], ) -> ContractResult { // split the sig_bytes into 2 parts proof and publicOutputs let sig: ZKEmailSignature = from_json(sig_bytes.to_vec())?; @@ -43,6 +44,7 @@ pub fn verify( proof: serde_json::to_vec(&proof)?, public_inputs: public_inputs.clone(), email_hash: email_salt.to_string(), + allowed_email_hosts: allowed_email_hosts.to_vec(), }; let verification_request_bytes = verification_request.to_bytes()?; @@ -470,6 +472,7 @@ mod tests { let signature = sample_zkemail_signature(); let tx_bytes = "test_transaction"; let email_salt = "test_salt"; + let allowed_email_hosts = vec!["example.com".to_string(), "test.com".to_string()]; // Test creating QueryVerifyRequest from signature components let verification_request = QueryVerifyRequest { @@ -477,12 +480,14 @@ mod tests { proof: serde_json::to_vec(&signature.proof).unwrap(), public_inputs: signature.public_inputs.clone(), email_hash: email_salt.to_string(), + allowed_email_hosts: allowed_email_hosts.clone(), }; // Verify the request is properly constructed assert_eq!(verification_request.tx_bytes, tx_bytes.as_bytes()); assert_eq!(verification_request.email_hash, email_salt.to_string()); assert_eq!(verification_request.public_inputs, signature.public_inputs); + assert_eq!(verification_request.allowed_email_hosts, allowed_email_hosts); // Verify proof serialization let proof_bytes = serde_json::to_vec(&signature.proof).unwrap(); diff --git a/contracts/account/src/contract.rs b/contracts/account/src/contract.rs index 0957147c..84fc912b 100644 --- a/contracts/account/src/contract.rs +++ b/contracts/account/src/contract.rs @@ -4,7 +4,10 @@ use cosmwasm_std::{ }; use crate::error::ContractError; -use crate::execute::{add_auth_method, assert_self, emit, remove_auth_method}; +use crate::execute::{ + add_auth_method, add_allowed_email_host, assert_self, emit, remove_allowed_email_host, + remove_auth_method, update_allowed_email_hosts, +}; use crate::msg::{ExecuteMsg, MigrateMsg}; use crate::{ error::ContractResult, @@ -91,6 +94,16 @@ pub fn execute( } ExecuteMsg::RemoveAuthMethod { id } => remove_auth_method(deps, env, *id), ExecuteMsg::Emit { data } => emit(env, data.to_string()), + ExecuteMsg::UpdateAllowedEmailHosts { + id, + allowed_email_hosts, + } => update_allowed_email_hosts(deps, env, *id, allowed_email_hosts.clone()), + ExecuteMsg::AddAllowedEmailHost { id, email_host } => { + add_allowed_email_host(deps, env, *id, email_host.clone()) + } + ExecuteMsg::RemoveAllowedEmailHost { id, email_host } => { + remove_allowed_email_host(deps, env, *id, email_host.clone()) + } } } diff --git a/contracts/account/src/error.rs b/contracts/account/src/error.rs index dab50ec0..4920f67d 100644 --- a/contracts/account/src/error.rs +++ b/contracts/account/src/error.rs @@ -90,6 +90,15 @@ pub enum ContractError { #[error("invalid ethereum address")] InvalidEthAddress, + + #[error("at least one allowed email host must be present")] + NoAllowedEmailHosts, + + #[error("authenticator not found")] + AuthenticatorNotFound, + + #[error("operation not supported for this authenticator type")] + UnsupportedAuthenticatorOperation, } pub type ContractResult = Result; diff --git a/contracts/account/src/execute.rs b/contracts/account/src/execute.rs index 9d1c7132..6b6738de 100644 --- a/contracts/account/src/execute.rs +++ b/contracts/account/src/execute.rs @@ -230,11 +230,17 @@ pub fn add_auth_method( AddAuthenticator::ZKEmail { id, email_salt, + allowed_email_hosts, signature, } => { - // extract email salt from signature + // Validate that at least one email host is provided + if allowed_email_hosts.is_empty() { + return Err(ContractError::NoAllowedEmailHosts); + } + let auth = Authenticator::ZKEmail { - email_salt: (*email_salt).clone() + email_salt: (*email_salt).clone(), + allowed_email_hosts: allowed_email_hosts.clone(), }; if !auth.verify( deps.as_ref(), @@ -311,6 +317,138 @@ pub fn assert_self(sender: &Addr, contract: &Addr) -> ContractResult<()> { Ok(()) } +pub fn update_allowed_email_hosts( + deps: DepsMut, + env: Env, + id: u8, + allowed_email_hosts: Vec, +) -> ContractResult { + // Validate that at least one email host is provided + if allowed_email_hosts.is_empty() { + return Err(ContractError::NoAllowedEmailHosts); + } + + // Load the authenticator + let authenticator = AUTHENTICATORS.load(deps.storage, id)?; + + // Ensure it's a ZKEmail authenticator + match authenticator { + Authenticator::ZKEmail { email_salt, .. } => { + // Update the authenticator with new allowed_email_hosts + let updated_auth = Authenticator::ZKEmail { + email_salt, + allowed_email_hosts: allowed_email_hosts.clone(), + }; + + AUTHENTICATORS.save(deps.storage, id, &updated_auth)?; + + Ok(Response::new().add_event( + Event::new("update_allowed_email_hosts").add_attributes(vec![ + ("contract_address", env.contract.address.to_string()), + ("authenticator_id", id.to_string()), + ("allowed_email_hosts", serde_json::to_string(&allowed_email_hosts)?), + ]), + )) + } + _ => Err(ContractError::UnsupportedAuthenticatorOperation), + } +} + +pub fn add_allowed_email_host( + deps: DepsMut, + env: Env, + id: u8, + email_host: String, +) -> ContractResult { + // Load the authenticator + let authenticator = AUTHENTICATORS.load(deps.storage, id)?; + + // Ensure it's a ZKEmail authenticator + match authenticator { + Authenticator::ZKEmail { + email_salt, + mut allowed_email_hosts, + } => { + // Check if the email host already exists + if allowed_email_hosts.contains(&email_host) { + return Ok(Response::new().add_event( + Event::new("add_allowed_email_host").add_attributes(vec![ + ("contract_address", env.contract.address.to_string()), + ("authenticator_id", id.to_string()), + ("email_host", email_host), + ("status", "already_exists".to_string()), + ]), + )); + } + + // Add the new email host + allowed_email_hosts.push(email_host.clone()); + + // Update the authenticator + let updated_auth = Authenticator::ZKEmail { + email_salt, + allowed_email_hosts, + }; + + AUTHENTICATORS.save(deps.storage, id, &updated_auth)?; + + Ok(Response::new().add_event( + Event::new("add_allowed_email_host").add_attributes(vec![ + ("contract_address", env.contract.address.to_string()), + ("authenticator_id", id.to_string()), + ("email_host", email_host), + ("status", "added".to_string()), + ]), + )) + } + _ => Err(ContractError::UnsupportedAuthenticatorOperation), + } +} + +pub fn remove_allowed_email_host( + deps: DepsMut, + env: Env, + id: u8, + email_host: String, +) -> ContractResult { + // Load the authenticator + let authenticator = AUTHENTICATORS.load(deps.storage, id)?; + + // Ensure it's a ZKEmail authenticator + match authenticator { + Authenticator::ZKEmail { + email_salt, + mut allowed_email_hosts, + } => { + // Ensure at least one email host remains after removal + if allowed_email_hosts.len() <= 1 { + return Err(ContractError::NoAllowedEmailHosts); + } + + // Remove the email host + allowed_email_hosts.retain(|host| host != &email_host); + + // Update the authenticator + let updated_auth = Authenticator::ZKEmail { + email_salt, + allowed_email_hosts, + }; + + AUTHENTICATORS.save(deps.storage, id, &updated_auth)?; + + Ok(Response::new().add_event( + Event::new("remove_allowed_email_host").add_attributes(vec![ + ("contract_address", env.contract.address.to_string()), + ("authenticator_id", id.to_string()), + ("email_host", email_host), + ("status", "removed".to_string()), + ]), + )) + } + _ => Err(ContractError::UnsupportedAuthenticatorOperation), + } +} + #[cfg(test)] pub mod tests { use base64::{engine::general_purpose, Engine as _}; @@ -448,6 +586,7 @@ pub mod tests { let mut add_authenticator = AddAuthenticator::ZKEmail { id: 1, email_salt: "test_email_salt".to_string(), + allowed_email_hosts: vec!["example.com".to_string()], signature: signature_binary, }; @@ -460,4 +599,287 @@ pub mod tests { // Verify the authenticator was not saved assert!(!AUTHENTICATORS.has(deps.as_ref().storage, 1)); } + + #[test] + fn test_allowed_email_hosts_operations() { + use crate::auth::Authenticator; + use crate::error::ContractError; + use crate::execute::{add_allowed_email_host, remove_allowed_email_host, update_allowed_email_hosts}; + + let mut deps = OwnedDeps { + storage: MockStorage::default(), + api: MockApi::default().with_prefix("xion"), + querier: MockQuerier::::new(&[]), + custom_query_type: std::marker::PhantomData, + }; + let env = mock_env(); + let auth_id = 1u8; + + // Setup: Create a ZKEmail authenticator with initial email hosts + let initial_authenticator = Authenticator::ZKEmail { + email_salt: "test_salt".to_string(), + allowed_email_hosts: vec!["example.com".to_string(), "test.com".to_string()], + }; + AUTHENTICATORS + .save(deps.as_mut().storage, auth_id, &initial_authenticator) + .unwrap(); + + // Test 1: Add a new email host + let result = add_allowed_email_host( + deps.as_mut(), + env.clone(), + auth_id, + "newhost.com".to_string(), + ); + assert!(result.is_ok()); + + // Verify the host was added + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { allowed_email_hosts, .. } => { + assert_eq!(allowed_email_hosts.len(), 3); + assert!(allowed_email_hosts.contains(&"newhost.com".to_string())); + } + _ => panic!("Expected ZKEmail authenticator"), + } + + // Test 2: Try to add a duplicate email host + let result = add_allowed_email_host( + deps.as_mut(), + env.clone(), + auth_id, + "newhost.com".to_string(), + ); + assert!(result.is_ok()); // Should succeed but not add duplicate + + // Verify no duplicate was added + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { allowed_email_hosts, .. } => { + assert_eq!(allowed_email_hosts.len(), 3); // Still 3, not 4 + assert_eq!( + allowed_email_hosts.iter().filter(|h| *h == "newhost.com").count(), + 1 + ); + } + _ => panic!("Expected ZKEmail authenticator"), + } + + // Test 3: Remove an email host + let result = remove_allowed_email_host( + deps.as_mut(), + env.clone(), + auth_id, + "newhost.com".to_string(), + ); + assert!(result.is_ok()); + + // Verify the host was removed + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { allowed_email_hosts, .. } => { + assert_eq!(allowed_email_hosts.len(), 2); + assert!(!allowed_email_hosts.contains(&"newhost.com".to_string())); + } + _ => panic!("Expected ZKEmail authenticator"), + } + + // Test 4: Try to remove the second-to-last email host (should succeed) + let result = remove_allowed_email_host( + deps.as_mut(), + env.clone(), + auth_id, + "example.com".to_string(), + ); + assert!(result.is_ok()); + + // Verify only one host remains + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { allowed_email_hosts, .. } => { + assert_eq!(allowed_email_hosts.len(), 1); + assert_eq!(allowed_email_hosts[0], "test.com"); + } + _ => panic!("Expected ZKEmail authenticator"), + } + + // Test 5: Try to remove the last email host (should fail) + let result = remove_allowed_email_host( + deps.as_mut(), + env.clone(), + auth_id, + "test.com".to_string(), + ); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), ContractError::NoAllowedEmailHosts); + + // Verify the host was not removed + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { allowed_email_hosts, .. } => { + assert_eq!(allowed_email_hosts.len(), 1); + } + _ => panic!("Expected ZKEmail authenticator"), + } + + // Test 6: Update allowed email hosts with a new list + let new_hosts = vec![ + "updated1.com".to_string(), + "updated2.com".to_string(), + "updated3.com".to_string(), + ]; + let result = update_allowed_email_hosts( + deps.as_mut(), + env.clone(), + auth_id, + new_hosts.clone(), + ); + assert!(result.is_ok()); + + // Verify the hosts were updated + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { allowed_email_hosts, .. } => { + assert_eq!(allowed_email_hosts, new_hosts); + } + _ => panic!("Expected ZKEmail authenticator"), + } + + // Test 7: Try to update with an empty list (should fail) + let result = update_allowed_email_hosts( + deps.as_mut(), + env.clone(), + auth_id, + vec![], + ); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), ContractError::NoAllowedEmailHosts); + + // Verify hosts were not changed + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { allowed_email_hosts, .. } => { + assert_eq!(allowed_email_hosts, new_hosts); + } + _ => panic!("Expected ZKEmail authenticator"), + } + + // Test 8: Try operations on a non-existent authenticator + let result = add_allowed_email_host( + deps.as_mut(), + env.clone(), + 99u8, // Non-existent ID + "test.com".to_string(), + ); + assert!(result.is_err()); + + // Test 9: Try operations on a non-ZKEmail authenticator + let secp_auth = Authenticator::Secp256K1 { + pubkey: Binary::from(vec![1, 2, 3]), + }; + AUTHENTICATORS + .save(deps.as_mut().storage, 2u8, &secp_auth) + .unwrap(); + + let result = add_allowed_email_host( + deps.as_mut(), + env.clone(), + 2u8, + "test.com".to_string(), + ); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), ContractError::UnsupportedAuthenticatorOperation); + + let result = remove_allowed_email_host( + deps.as_mut(), + env.clone(), + 2u8, + "test.com".to_string(), + ); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), ContractError::UnsupportedAuthenticatorOperation); + + let result = update_allowed_email_hosts( + deps.as_mut(), + env.clone(), + 2u8, + vec!["test.com".to_string()], + ); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), ContractError::UnsupportedAuthenticatorOperation); + + // Test 10: Try to remove a host that doesn't exist + let result = remove_allowed_email_host( + deps.as_mut(), + env.clone(), + auth_id, + "nonexistent.com".to_string(), + ); + // This should succeed but not change anything + assert!(result.is_ok()); + + // Verify the hosts remain unchanged + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { allowed_email_hosts, .. } => { + assert_eq!(allowed_email_hosts, new_hosts); + } + _ => panic!("Expected ZKEmail authenticator"), + } + + // Test 11: Update with a single host (edge case - minimum valid) + let result = update_allowed_email_hosts( + deps.as_mut(), + env.clone(), + auth_id, + vec!["single.com".to_string()], + ); + assert!(result.is_ok()); + + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { allowed_email_hosts, .. } => { + assert_eq!(allowed_email_hosts.len(), 1); + assert_eq!(allowed_email_hosts[0], "single.com"); + } + _ => panic!("Expected ZKEmail authenticator"), + } + + // Test 12: Add multiple hosts one by one + let result1 = add_allowed_email_host( + deps.as_mut(), + env.clone(), + auth_id, + "multi1.com".to_string(), + ); + assert!(result1.is_ok()); + + let result2 = add_allowed_email_host( + deps.as_mut(), + env.clone(), + auth_id, + "multi2.com".to_string(), + ); + assert!(result2.is_ok()); + + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { allowed_email_hosts, .. } => { + assert_eq!(allowed_email_hosts.len(), 3); + assert!(allowed_email_hosts.contains(&"single.com".to_string())); + assert!(allowed_email_hosts.contains(&"multi1.com".to_string())); + assert!(allowed_email_hosts.contains(&"multi2.com".to_string())); + } + _ => panic!("Expected ZKEmail authenticator"), + } + + // Test 13: Verify email_salt is preserved through updates + let updated_auth = AUTHENTICATORS.load(deps.as_ref().storage, auth_id).unwrap(); + match updated_auth { + Authenticator::ZKEmail { email_salt, .. } => { + assert_eq!(email_salt, "test_salt"); + } + _ => panic!("Expected ZKEmail authenticator"), + } + } } diff --git a/contracts/account/src/msg.rs b/contracts/account/src/msg.rs index f61a410d..3601ea1f 100644 --- a/contracts/account/src/msg.rs +++ b/contracts/account/src/msg.rs @@ -12,6 +12,18 @@ pub enum ExecuteMsg { AddAuthMethod { add_authenticator: AddAuthenticator }, RemoveAuthMethod { id: u8 }, Emit { data: String }, + UpdateAllowedEmailHosts { + id: u8, + allowed_email_hosts: Vec + }, + AddAllowedEmailHost { + id: u8, + email_host: String + }, + RemoveAllowedEmailHost { + id: u8, + email_host: String + }, } #[cw_serde]