Sign Markdown saved to the folder with the configured ENS name and key
This commit is contained in:
Generated
+573
-5
@@ -2,30 +2,283 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "alloy-primitives"
|
||||
version = "1.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5e9dbd49258ac3ab893a481d46be29b58be7f734dcac46cd80b6b13ee36566c"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cfg-if",
|
||||
"const-hex",
|
||||
"derive_more",
|
||||
"itoa",
|
||||
"k256",
|
||||
"paste",
|
||||
"ruint",
|
||||
"sha3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "base16ct"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
||||
|
||||
[[package]]
|
||||
name = "const-hex"
|
||||
version = "1.19.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e59eef12462b0f9b0a3620219be5d639afd79fe39dff0a42c3997061f9298b4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures 0.2.17",
|
||||
"proptest",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
|
||||
dependencies = [
|
||||
"derive_more-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more-impl"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn 2.0.119",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer 0.10.4",
|
||||
"const-oid",
|
||||
"crypto-common 0.1.6",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
|
||||
dependencies = [
|
||||
"block-buffer 0.12.1",
|
||||
"crypto-common 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ecdsa"
|
||||
version = "0.16.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
|
||||
dependencies = [
|
||||
"der",
|
||||
"digest 0.10.7",
|
||||
"elliptic-curve",
|
||||
"rfc6979",
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "elliptic-curve"
|
||||
version = "0.13.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"crypto-bigint",
|
||||
"digest 0.10.7",
|
||||
"ff",
|
||||
"generic-array",
|
||||
"group",
|
||||
"rand_core 0.6.4",
|
||||
"sec1",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
|
||||
dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
||||
dependencies = [
|
||||
"ff",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.17.1"
|
||||
@@ -41,6 +294,24 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest 0.10.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hybrid-array"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.3.0"
|
||||
@@ -65,12 +336,46 @@ version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "k256"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keccak"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leb128fmt"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.34"
|
||||
@@ -85,7 +390,18 @@ checksum = "6e7b3a5bbb2f63aaa223a671ea1bd0e7bc16bd30ce387324cf63995deaddbbd2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 3.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md-ens-signature"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/capsulizers/md-ens-signature?rev=051a5f611eeba8d61c66dbe5074a2e56517897a7#051a5f611eeba8d61c66dbe5074a2e56517897a7"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"anyhow",
|
||||
"k256",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -98,10 +414,36 @@ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
name = "memona-plugin-signature"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"md-ens-signature",
|
||||
"quick-xml",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.3.0"
|
||||
@@ -109,7 +451,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bfe0f4c752e450fc2faf62654f1c134747922825d5b04ca717b8874f41a40c0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
"syn 3.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -121,6 +463,20 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proptest"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"num-traits",
|
||||
"rand 0.9.5",
|
||||
"rand_chacha",
|
||||
"rand_xorshift",
|
||||
"unarray",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.37.5"
|
||||
@@ -139,6 +495,108 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c"
|
||||
dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41"
|
||||
dependencies = [
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
|
||||
dependencies = [
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfc6979"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
|
||||
dependencies = [
|
||||
"hmac",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruint"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2973657b5127d510e230f5c63d2d106af9c8f79393d8b9f4647323e8196bdde5"
|
||||
dependencies = [
|
||||
"proptest",
|
||||
"rand 0.8.8",
|
||||
"rand 0.9.5",
|
||||
"ruint-macro",
|
||||
"serde_core",
|
||||
"valuable",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruint-macro"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sec1"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"der",
|
||||
"generic-array",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.28"
|
||||
@@ -171,7 +629,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 3.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -187,6 +645,54 @@ dependencies = [
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures 0.2.17",
|
||||
"digest 0.10.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha3"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1"
|
||||
dependencies = [
|
||||
"digest 0.11.3",
|
||||
"keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"digest 0.10.7",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.6"
|
||||
@@ -198,12 +704,48 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||
|
||||
[[package]]
|
||||
name = "unarray"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.259.0"
|
||||
@@ -269,7 +811,7 @@ dependencies = [
|
||||
"heck",
|
||||
"indexmap",
|
||||
"prettyplease",
|
||||
"syn",
|
||||
"syn 3.0.6",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
@@ -286,7 +828,7 @@ dependencies = [
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 3.0.6",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
@@ -329,6 +871,32 @@ dependencies = [
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c17e8fafad82b542ff3717217ecdc736231b59e387768c9630123b4ce4d2db44"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "595f56e044df4f46a0c9a626f65c3d99eb8488f7e8a8baa12dd76326d9710bf2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.23"
|
||||
|
||||
@@ -12,6 +12,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
[dependencies]
|
||||
wit-bindgen = "=0.62.0"
|
||||
quick-xml = { version = "0.37", default-features = false }
|
||||
md-ens-signature = { git = "https://github.com/capsulizers/md-ens-signature", rev = "051a5f611eeba8d61c66dbe5074a2e56517897a7" }
|
||||
|
||||
[lints.clippy]
|
||||
panic = "deny"
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
# Memona signature plugin
|
||||
|
||||
Opens a WebDAV server as a folder inside Memona. It is the foundation for
|
||||
signing Markdown files with an ENS name as they are saved, writing `signer` and
|
||||
`signature` into each file's frontmatter so anyone can check who wrote it
|
||||
against the name's current ENSv2 records, using the
|
||||
Opens a WebDAV server as a folder inside Memona and signs every Markdown file
|
||||
saved to it with an ENS name, writing `signer` and `signature` into the file's
|
||||
frontmatter so anyone can check who wrote it against the name's current ENSv2
|
||||
records. Signing comes from the
|
||||
[md-ens-signature](https://github.com/capsulizers/md-ens-signature) library.
|
||||
This version is the WebDAV folder alone; signing is not in it yet.
|
||||
|
||||
The plugin is a WASI component: it speaks no sockets of its own and makes every
|
||||
request through the host's HTTP interface, under the connection's permissions.
|
||||
@@ -18,6 +17,9 @@ It registers one provider, `signature`, for the `signed-webdav` scheme.
|
||||
| Server address | The folder's address, for example `https://dav.example.com/files/` |
|
||||
| Username | Optional account name for HTTP basic authentication |
|
||||
| Password | Optional password, stored as a secret |
|
||||
| Signer name | The ENS name that signs, for example `laptop.alice.eth` |
|
||||
| Signing key | The private key of the address the name resolves to, stored as a secret |
|
||||
| Sepolia RPC address | The endpoint used to check signers against ENS, by default `https://ethereum-sepolia-rpc.publicnode.com` |
|
||||
|
||||
Listing, reading, writing, creating directories, renaming and deleting behave
|
||||
as in the WebDAV plugin: reads and writes stream in pieces of at most 1 MiB,
|
||||
@@ -25,6 +27,17 @@ conditional writes use `If-Match` and `If-None-Match`, change polling is not
|
||||
supported, a rename never replaces an existing target, and a folder with
|
||||
contents is refused rather than removed whole.
|
||||
|
||||
## Signing
|
||||
|
||||
Saving a `.md` file holds it whole, up to 8 MiB, and writes it once finished,
|
||||
with `signer` and `signature` set in its frontmatter; every other file streams
|
||||
straight through. The signature is EIP-191 `personal_sign` over the signer name
|
||||
and the body's SHA-256, made with the configured key; other frontmatter and the
|
||||
body stay byte for byte. A key that is not 32 bytes of hex refuses the
|
||||
connection, and a `.md` file that is not UTF-8 refuses the save. Reading passes
|
||||
every file through unchanged. The RPC address is for verifying signers, which a
|
||||
later version adds to reads.
|
||||
|
||||
## Building
|
||||
|
||||
```sh
|
||||
|
||||
@@ -33,6 +33,28 @@
|
||||
"label": "Password",
|
||||
"kind": "password",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"key": "ensName",
|
||||
"label": "Signer name",
|
||||
"description": "The ENS name that signs saved Markdown, for example laptop.alice.eth",
|
||||
"kind": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"key": "privateKey",
|
||||
"label": "Signing key",
|
||||
"description": "The private key of the address this name resolves to",
|
||||
"kind": "password",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"key": "rpcUrl",
|
||||
"label": "Sepolia RPC address",
|
||||
"description": "The Ethereum Sepolia endpoint used to check signers against ENS",
|
||||
"kind": "text",
|
||||
"required": false,
|
||||
"default": "https://ethereum-sepolia-rpc.publicnode.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+41
-2
@@ -3,6 +3,7 @@
|
||||
|
||||
mod dav;
|
||||
mod sdk;
|
||||
mod sign;
|
||||
|
||||
use sdk::host;
|
||||
use sdk::{
|
||||
@@ -10,6 +11,7 @@ use sdk::{
|
||||
GuestReader, GuestWriter, ListPage, Locator, Reader, Setting, WriteCondition,
|
||||
Writer,
|
||||
};
|
||||
use sign::Signer;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
/// The PROPFIND body. Asking for named properties rather than allprop keeps
|
||||
@@ -21,10 +23,13 @@ const PROPS: &str = concat!(
|
||||
"</d:prop></d:propfind>",
|
||||
);
|
||||
const MAX_CHUNK: u32 = 1024 * 1024;
|
||||
/// The largest Markdown file this plugin will hold whole to sign.
|
||||
const MAX_MARKDOWN: usize = 8 * 1024 * 1024;
|
||||
|
||||
struct Session {
|
||||
root: String,
|
||||
authorization: Option<String>,
|
||||
signer: Signer,
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
@@ -179,11 +184,27 @@ impl GuestReader for DavReader {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether a path names a Markdown file, the only kind this plugin signs.
|
||||
fn is_markdown(path: &str) -> bool {
|
||||
path.to_ascii_lowercase().ends_with(".md")
|
||||
}
|
||||
|
||||
/// Writes one file through a PUT whose body is pushed in pieces.
|
||||
struct DavWriter {
|
||||
call: host::Exchange,
|
||||
done: RefCell<bool>,
|
||||
written: Cell<u64>,
|
||||
/// A Markdown file waits here whole until `finish`, because its signature
|
||||
/// covers the entire body and lands in the frontmatter at the front.
|
||||
markdown: Option<RefCell<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl DavWriter {
|
||||
fn send(&self, data: &[u8]) -> Result<(), ErrorCode> {
|
||||
self.call.push(data).map_err(transport)?;
|
||||
self.written.set(self.written.get() + data.len() as u64);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl GuestWriter for DavWriter {
|
||||
@@ -191,8 +212,14 @@ impl GuestWriter for DavWriter {
|
||||
if *self.done.borrow() {
|
||||
return Err(ErrorCode::InvalidInput);
|
||||
}
|
||||
self.call.push(&data).map_err(transport)?;
|
||||
self.written.set(self.written.get() + data.len() as u64);
|
||||
let Some(markdown) = &self.markdown else {
|
||||
return self.send(&data);
|
||||
};
|
||||
let mut markdown = markdown.borrow_mut();
|
||||
if markdown.len() + data.len() > MAX_MARKDOWN {
|
||||
return Err(ErrorCode::Unsupported);
|
||||
}
|
||||
markdown.extend_from_slice(&data);
|
||||
Ok(())
|
||||
}
|
||||
/// One call is enough: the request body is already complete, so the response
|
||||
@@ -203,6 +230,12 @@ impl GuestWriter for DavWriter {
|
||||
return Err(ErrorCode::InvalidInput);
|
||||
}
|
||||
*self.done.borrow_mut() = true;
|
||||
if let Some(markdown) = &self.markdown {
|
||||
let signed = session(|session| session.signer.sign(&markdown.borrow()))?;
|
||||
for piece in signed.chunks(MAX_CHUNK as usize) {
|
||||
self.send(piece)?;
|
||||
}
|
||||
}
|
||||
let head = self.call.respond().map_err(transport)?;
|
||||
dav::outcome(head.status)?;
|
||||
let revision = head
|
||||
@@ -242,9 +275,14 @@ impl Guest for Webdav {
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let signer = Signer::new(
|
||||
&lookup("ensName").ok_or(ErrorCode::InvalidInput)?,
|
||||
&lookup("privateKey").ok_or(ErrorCode::InvalidInput)?,
|
||||
)?;
|
||||
SESSION.set(Some(Session {
|
||||
root,
|
||||
authorization,
|
||||
signer,
|
||||
}));
|
||||
Ok(Capabilities {
|
||||
write: true,
|
||||
@@ -358,6 +396,7 @@ impl Guest for Webdav {
|
||||
call,
|
||||
done: RefCell::new(false),
|
||||
written: Cell::new(0),
|
||||
markdown: is_markdown(&path).then(|| RefCell::new(Vec::new())),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
//! Signing a saved Markdown file, the only place this plugin touches its
|
||||
//! bytes. Everything the md-ens-signature library does for the plugin goes
|
||||
//! through the interface here.
|
||||
|
||||
use crate::sdk::ErrorCode;
|
||||
use md_ens_signature::document::{
|
||||
SignatureFields, body_digest, write_signature,
|
||||
};
|
||||
use md_ens_signature::signature::{address_of, sign};
|
||||
|
||||
/// One connection's signing identity: an ENS name and the private key bound
|
||||
/// to it.
|
||||
pub struct Signer {
|
||||
name: String,
|
||||
key: [u8; 32],
|
||||
}
|
||||
|
||||
/// Reads a 32-byte private key written as 64 hex characters, with or without
|
||||
/// a `0x` prefix.
|
||||
fn parse_key(text: &str) -> Option<[u8; 32]> {
|
||||
let digits = text.trim();
|
||||
let digits = digits.strip_prefix("0x").unwrap_or(digits).as_bytes();
|
||||
if digits.len() != 64 {
|
||||
return None;
|
||||
}
|
||||
let mut key = [0u8; 32];
|
||||
for (byte, pair) in key.iter_mut().zip(digits.chunks(2)) {
|
||||
let text = std::str::from_utf8(pair).ok()?;
|
||||
*byte = u8::from_str_radix(text, 16).ok()?;
|
||||
}
|
||||
Some(key)
|
||||
}
|
||||
|
||||
impl Signer {
|
||||
/// Takes the configured name and key, failing with `InvalidInput` when the
|
||||
/// key cannot sign, so a bad key refuses the connection rather than every
|
||||
/// later save.
|
||||
pub fn new(name: &str, private_key: &str) -> Result<Self, ErrorCode> {
|
||||
let name = name.trim().to_lowercase();
|
||||
let key = parse_key(private_key).ok_or(ErrorCode::InvalidInput)?;
|
||||
if name.is_empty() || address_of(&key).is_err() {
|
||||
return Err(ErrorCode::InvalidInput);
|
||||
}
|
||||
Ok(Self { name, key })
|
||||
}
|
||||
|
||||
/// Returns the whole file with its `signer` and `signature` frontmatter set
|
||||
/// for this identity, other frontmatter and the body untouched. A file that
|
||||
/// is not UTF-8 is not Markdown this plugin can sign.
|
||||
pub fn sign(&self, markdown: &[u8]) -> Result<Vec<u8>, ErrorCode> {
|
||||
let text =
|
||||
std::str::from_utf8(markdown).map_err(|_| ErrorCode::InvalidInput)?;
|
||||
let signature = sign(&self.key, &self.name, &body_digest(text))
|
||||
.map_err(|_| ErrorCode::Internal)?;
|
||||
let fields = SignatureFields {
|
||||
signer: self.name.clone(),
|
||||
signature,
|
||||
};
|
||||
Ok(write_signature(text, &fields).into_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Signer, parse_key};
|
||||
use crate::sdk::ErrorCode;
|
||||
use md_ens_signature::document::{body_digest, read_signature};
|
||||
use md_ens_signature::signature::{address_of, recover};
|
||||
|
||||
const KEY: &str =
|
||||
"0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318";
|
||||
|
||||
#[test]
|
||||
fn a_signed_file_recovers_to_the_key_and_keeps_its_body()
|
||||
-> Result<(), ErrorCode> {
|
||||
let signer = Signer::new(" Laptop.Alice.eth ", KEY)?;
|
||||
let saved = "---\ntitle: Notes\n---\n# Notes\n\nHello\n";
|
||||
let signed = String::from_utf8(signer.sign(saved.as_bytes())?)
|
||||
.map_err(|_| ErrorCode::Internal)?;
|
||||
assert!(signed.starts_with("---\ntitle: Notes\n"));
|
||||
assert!(signed.ends_with("---\n# Notes\n\nHello\n"));
|
||||
let fields = read_signature(&signed).ok_or(ErrorCode::Internal)?;
|
||||
assert_eq!(fields.signer, "laptop.alice.eth");
|
||||
let key = parse_key(KEY).ok_or(ErrorCode::Internal)?;
|
||||
let recovered =
|
||||
recover(&fields.signature, &fields.signer, &body_digest(&signed))
|
||||
.map_err(|_| ErrorCode::Internal)?;
|
||||
assert_eq!(Some(recovered), address_of(&key).ok());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_key_that_cannot_sign_refuses_the_connection() {
|
||||
assert!(Signer::new("alice.eth", "0x1234").is_err());
|
||||
assert!(Signer::new("alice.eth", &"zz".repeat(32)).is_err());
|
||||
assert!(Signer::new("alice.eth", &"00".repeat(32)).is_err());
|
||||
assert!(Signer::new(" ", KEY).is_err());
|
||||
assert!(Signer::new("alice.eth", &KEY[2..]).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_file_that_is_not_text_is_refused() -> Result<(), ErrorCode> {
|
||||
let signer = Signer::new("alice.eth", KEY)?;
|
||||
assert_eq!(signer.sign(&[0xff, 0xfe]), Err(ErrorCode::InvalidInput));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user