mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-10-05 15:08:24 +00:00
add nip11
This commit is contained in:
Generated
+510
-17
@@ -163,6 +163,12 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
@@ -225,6 +231,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
@@ -380,6 +392,16 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
@@ -446,12 +468,37 @@ version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[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 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.4"
|
||||
@@ -464,6 +511,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.2"
|
||||
@@ -618,6 +680,8 @@ dependencies = [
|
||||
"clap",
|
||||
"futures",
|
||||
"nostr-sdk 0.43.0",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
@@ -628,6 +692,25 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.12"
|
||||
@@ -639,7 +722,7 @@ dependencies = [
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http",
|
||||
"http 1.3.1",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
@@ -689,6 +772,17 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.3.1"
|
||||
@@ -700,6 +794,17 @@ dependencies = [
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http 0.2.12",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "1.0.1"
|
||||
@@ -707,7 +812,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"http 1.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -718,8 +823,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http",
|
||||
"http-body",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
@@ -735,6 +840,30 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2 0.3.27",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2 0.5.10",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.8.1"
|
||||
@@ -745,9 +874,9 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"h2 0.4.12",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
@@ -758,6 +887,19 @@ dependencies = [
|
||||
"want",
|
||||
]
|
||||
|
||||
[[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.32",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.18"
|
||||
@@ -766,9 +908,9 @@ checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"hyper 1.8.1",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
@@ -931,6 +1073,12 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
@@ -965,6 +1113,12 @@ version = "0.2.177"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
|
||||
[[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.1"
|
||||
@@ -1007,6 +1161,12 @@ version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.1.0"
|
||||
@@ -1018,6 +1178,23 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "negentropy"
|
||||
version = "0.5.0"
|
||||
@@ -1029,12 +1206,12 @@ name = "ngit-grasp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"base64 0.22.1",
|
||||
"dotenvy",
|
||||
"futures-util",
|
||||
"grasp-audit",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper 1.8.1",
|
||||
"hyper-util",
|
||||
"nostr-relay-builder",
|
||||
"nostr-sdk 0.44.1",
|
||||
@@ -1054,7 +1231,7 @@ version = "0.43.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62a97d745f1bd8d5e05a978632bbb87b0614567d5142906fe7c86fb2440faac6"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.22.1",
|
||||
"bech32",
|
||||
"bip39",
|
||||
"bitcoin_hashes 0.14.0",
|
||||
@@ -1077,7 +1254,7 @@ version = "0.44.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3595fecf0e0aaacb69a0dc0101a4453f3c76eda333d6bbc49f68f64390b3d85"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.22.1",
|
||||
"bech32",
|
||||
"bip39",
|
||||
"bitcoin_hashes 0.14.0",
|
||||
@@ -1242,6 +1419,50 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
|
||||
dependencies = [
|
||||
"bitflags 2.10.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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
@@ -1304,6 +1525,12 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "poly1305"
|
||||
version = "0.8.0"
|
||||
@@ -1422,7 +1649,19 @@ version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.10.0",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
@@ -1442,6 +1681,46 @@ version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2 0.3.27",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"hyper 0.14.32",
|
||||
"hyper-tls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
@@ -1456,6 +1735,19 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.34"
|
||||
@@ -1470,6 +1762,15 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.13.0"
|
||||
@@ -1511,6 +1812,15 @@ dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@@ -1549,6 +1859,29 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
@@ -1592,6 +1925,18 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
@@ -1650,6 +1995,16 @@ version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.1"
|
||||
@@ -1689,6 +2044,12 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.2"
|
||||
@@ -1700,6 +2061,40 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[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 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
@@ -1786,7 +2181,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"socket2 0.6.1",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
@@ -1802,6 +2197,16 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.4"
|
||||
@@ -1877,6 +2282,12 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.41"
|
||||
@@ -1952,7 +2363,7 @@ checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http",
|
||||
"http 1.3.1",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand 0.9.2",
|
||||
@@ -2047,6 +2458,12 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
@@ -2222,6 +2639,15 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
@@ -2249,6 +2675,21 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
@@ -2282,6 +2723,12 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.53.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
@@ -2294,6 +2741,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
@@ -2306,6 +2759,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
@@ -2330,6 +2789,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
@@ -2342,6 +2807,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
@@ -2354,6 +2825,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
@@ -2366,6 +2843,12 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
@@ -2378,6 +2861,16 @@ version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
|
||||
@@ -33,6 +33,10 @@ clap = { version = "4", features = ["derive"] }
|
||||
uuid = { version = "1", features = ["v4"] }
|
||||
chrono = "0.4"
|
||||
|
||||
# HTTP Client
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
regex = "1"
|
||||
|
||||
# Logging
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
@@ -84,6 +84,25 @@ impl AuditClient {
|
||||
self.keys.public_key()
|
||||
}
|
||||
|
||||
/// Get the relay URL
|
||||
pub async fn relay_url(&self) -> Result<String> {
|
||||
let relays = self.client.relays().await;
|
||||
let relay = relays.values().next()
|
||||
.ok_or_else(|| anyhow!("No relays configured"))?;
|
||||
Ok(relay.url().to_string())
|
||||
}
|
||||
|
||||
/// Convert WebSocket URL to HTTP(S) URL for NIP-11 requests
|
||||
pub fn ws_to_http_url(ws_url: &str) -> Result<String> {
|
||||
if ws_url.starts_with("ws://") {
|
||||
Ok(ws_url.replace("ws://", "http://"))
|
||||
} else if ws_url.starts_with("wss://") {
|
||||
Ok(ws_url.replace("wss://", "https://"))
|
||||
} else {
|
||||
Err(anyhow!("Invalid WebSocket URL: {}", ws_url))
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if connected to relay
|
||||
pub async fn is_connected(&self) -> bool {
|
||||
// Check if we have any connected relays
|
||||
|
||||
@@ -34,25 +34,53 @@ impl Nip11DocumentTests {
|
||||
///
|
||||
/// Spec: Line 11 of ../grasp/01.md
|
||||
/// Requirement: MUST serve NIP-11 document
|
||||
async fn test_nip11_document_exists(_client: &AuditClient) -> TestResult {
|
||||
pub async fn test_nip11_document_exists(client: &AuditClient) -> TestResult {
|
||||
TestResult::new(
|
||||
"nip11_document_exists",
|
||||
"GRASP-01:nostr-relay:11",
|
||||
"Serve NIP-11 relay information document",
|
||||
)
|
||||
.run(|| async {
|
||||
// TODO: Implementation
|
||||
// 1. Extract HTTP(S) URL from client's WebSocket URL
|
||||
// - ws://localhost:8081 -> http://localhost:8081
|
||||
// - wss://relay.example.com -> https://relay.example.com
|
||||
// 2. HTTP GET to base URL with header:
|
||||
// - Accept: application/nostr+json
|
||||
// 3. Verify 200 OK response
|
||||
// 4. Verify response is valid JSON
|
||||
// 5. Parse as NIP-11 document
|
||||
// 6. Verify has required fields (name, description, etc.)
|
||||
let ws_url = client.relay_url().await
|
||||
.map_err(|e| format!("Failed to get relay URL: {}", e))?;
|
||||
let http_url = AuditClient::ws_to_http_url(&ws_url)
|
||||
.map_err(|e| format!("Failed to convert WebSocket URL to HTTP: {}", e))?;
|
||||
|
||||
Err("Not implemented yet".to_string())
|
||||
// 2. HTTP GET to base URL with Accept: application/nostr+json header
|
||||
let http_client = reqwest::Client::new();
|
||||
let response = http_client
|
||||
.get(&http_url)
|
||||
.header("Accept", "application/nostr+json")
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to fetch NIP-11 document: {}", e))?;
|
||||
|
||||
// 3. Verify 200 OK response
|
||||
if !response.status().is_success() {
|
||||
return Err(format!(
|
||||
"Expected 200 OK, got {} {}",
|
||||
response.status().as_u16(),
|
||||
response.status().canonical_reason().unwrap_or("Unknown")
|
||||
));
|
||||
}
|
||||
|
||||
// 4. Verify response is valid JSON
|
||||
let json_text = response.text().await
|
||||
.map_err(|e| format!("Failed to read response body: {}", e))?;
|
||||
|
||||
let doc: serde_json::Value = serde_json::from_str(&json_text)
|
||||
.map_err(|e| format!("Response is not valid JSON: {}", e))?;
|
||||
|
||||
// 5. Verify has required NIP-11 fields
|
||||
let required_fields = ["name", "description", "software", "version"];
|
||||
for field in &required_fields {
|
||||
if !doc.get(field).is_some() {
|
||||
return Err(format!("Missing required NIP-11 field: {}", field));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
@@ -61,22 +89,68 @@ impl Nip11DocumentTests {
|
||||
///
|
||||
/// Spec: Line 12 of ../grasp/01.md
|
||||
/// Requirement: MUST list supported GRASPs as string array
|
||||
async fn test_nip11_supported_grasps_field(_client: &AuditClient) -> TestResult {
|
||||
pub async fn test_nip11_supported_grasps_field(client: &AuditClient) -> TestResult {
|
||||
TestResult::new(
|
||||
"nip11_supported_grasps_field",
|
||||
"GRASP-01:nostr-relay:12",
|
||||
"NIP-11 document includes supported_grasps field with GRASP-01",
|
||||
)
|
||||
.run(|| async {
|
||||
// TODO: Implementation
|
||||
// 1. Fetch NIP-11 document (same as above)
|
||||
// 2. Verify `supported_grasps` field exists
|
||||
// 3. Verify it's a JSON array of strings
|
||||
// 4. Verify array includes "GRASP-01"
|
||||
// 5. Verify format: each entry matches pattern "GRASP-\d{2}"
|
||||
// 6. Document other GRASPs found (for info)
|
||||
// 1. Fetch NIP-11 document
|
||||
let ws_url = client.relay_url().await
|
||||
.map_err(|e| format!("Failed to get relay URL: {}", e))?;
|
||||
let http_url = AuditClient::ws_to_http_url(&ws_url)
|
||||
.map_err(|e| format!("Failed to convert WebSocket URL to HTTP: {}", e))?;
|
||||
|
||||
Err("Not implemented yet".to_string())
|
||||
let http_client = reqwest::Client::new();
|
||||
let response = http_client
|
||||
.get(&http_url)
|
||||
.header("Accept", "application/nostr+json")
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to fetch NIP-11 document: {}", e))?;
|
||||
|
||||
let json_text = response.text().await
|
||||
.map_err(|e| format!("Failed to read response body: {}", e))?;
|
||||
|
||||
let doc: serde_json::Value = serde_json::from_str(&json_text)
|
||||
.map_err(|e| format!("Response is not valid JSON: {}", e))?;
|
||||
|
||||
// 2. Verify `supported_grasps` field exists
|
||||
let supported_grasps = doc.get("supported_grasps")
|
||||
.ok_or_else(|| "Missing required field: supported_grasps".to_string())?;
|
||||
|
||||
// 3. Verify it's a JSON array
|
||||
let grasps_array = supported_grasps.as_array()
|
||||
.ok_or_else(|| "supported_grasps must be an array".to_string())?;
|
||||
|
||||
// 4. Verify array includes "GRASP-01"
|
||||
let grasp_strings: Vec<String> = grasps_array
|
||||
.iter()
|
||||
.filter_map(|v| v.as_str().map(|s| s.to_string()))
|
||||
.collect();
|
||||
|
||||
if !grasp_strings.contains(&"GRASP-01".to_string()) {
|
||||
return Err(format!(
|
||||
"supported_grasps must include 'GRASP-01', found: {:?}",
|
||||
grasp_strings
|
||||
));
|
||||
}
|
||||
|
||||
// 5. Verify format: each entry should match pattern "GRASP-\d{2}"
|
||||
let grasp_pattern = regex::Regex::new(r"^GRASP-\d{2}$")
|
||||
.map_err(|e| format!("Failed to compile regex: {}", e))?;
|
||||
|
||||
for grasp in &grasp_strings {
|
||||
if !grasp_pattern.is_match(grasp) {
|
||||
return Err(format!(
|
||||
"Invalid GRASP format: '{}' (expected GRASP-XX where XX is two digits)",
|
||||
grasp
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
@@ -85,23 +159,47 @@ impl Nip11DocumentTests {
|
||||
///
|
||||
/// Spec: Line 13 of ../grasp/01.md
|
||||
/// Requirement: MUST list repository acceptance criteria
|
||||
async fn test_nip11_repo_acceptance_criteria_field(_client: &AuditClient) -> TestResult {
|
||||
pub async fn test_nip11_repo_acceptance_criteria_field(client: &AuditClient) -> TestResult {
|
||||
TestResult::new(
|
||||
"nip11_repo_acceptance_criteria_field",
|
||||
"GRASP-01:nostr-relay:13",
|
||||
"NIP-11 document includes repo_acceptance_criteria field",
|
||||
)
|
||||
.run(|| async {
|
||||
// TODO: Implementation
|
||||
// 1. Fetch NIP-11 document
|
||||
// 2. Verify `repo_acceptance_criteria` field exists
|
||||
// 3. Verify it's a string (human-readable)
|
||||
// 4. Verify non-empty
|
||||
// 5. Document the criteria (for info)
|
||||
// Examples: "Must list this relay in clone and relays tags"
|
||||
// "Pre-payment required via Lightning invoice"
|
||||
let ws_url = client.relay_url().await
|
||||
.map_err(|e| format!("Failed to get relay URL: {}", e))?;
|
||||
let http_url = AuditClient::ws_to_http_url(&ws_url)
|
||||
.map_err(|e| format!("Failed to convert WebSocket URL to HTTP: {}", e))?;
|
||||
|
||||
Err("Not implemented yet".to_string())
|
||||
let http_client = reqwest::Client::new();
|
||||
let response = http_client
|
||||
.get(&http_url)
|
||||
.header("Accept", "application/nostr+json")
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to fetch NIP-11 document: {}", e))?;
|
||||
|
||||
let json_text = response.text().await
|
||||
.map_err(|e| format!("Failed to read response body: {}", e))?;
|
||||
|
||||
let doc: serde_json::Value = serde_json::from_str(&json_text)
|
||||
.map_err(|e| format!("Response is not valid JSON: {}", e))?;
|
||||
|
||||
// 2. Verify `repo_acceptance_criteria` field exists
|
||||
let criteria = doc.get("repo_acceptance_criteria")
|
||||
.ok_or_else(|| "Missing required field: repo_acceptance_criteria".to_string())?;
|
||||
|
||||
// 3. Verify it's a string
|
||||
let criteria_str = criteria.as_str()
|
||||
.ok_or_else(|| "repo_acceptance_criteria must be a string".to_string())?;
|
||||
|
||||
// 4. Verify non-empty
|
||||
if criteria_str.trim().is_empty() {
|
||||
return Err("repo_acceptance_criteria must not be empty".to_string());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
@@ -110,24 +208,47 @@ impl Nip11DocumentTests {
|
||||
///
|
||||
/// Spec: Line 14 of ../grasp/01.md
|
||||
/// Requirement: MUST include curation if curated, omit otherwise
|
||||
async fn test_nip11_curation_field(_client: &AuditClient) -> TestResult {
|
||||
pub async fn test_nip11_curation_field(client: &AuditClient) -> TestResult {
|
||||
TestResult::new(
|
||||
"nip11_curation_field",
|
||||
"GRASP-01:nostr-relay:14",
|
||||
"NIP-11 curation field present if curated, absent otherwise",
|
||||
)
|
||||
.run(|| async {
|
||||
// TODO: Implementation
|
||||
// 1. Fetch NIP-11 document
|
||||
// 2. Check if `curation` field exists
|
||||
// 3. If present:
|
||||
// - Verify it's a non-empty string
|
||||
// - Document the curation policy
|
||||
// 4. If absent:
|
||||
// - Document that no curation beyond SPAM prevention
|
||||
// 5. Both cases are valid per spec
|
||||
let ws_url = client.relay_url().await
|
||||
.map_err(|e| format!("Failed to get relay URL: {}", e))?;
|
||||
let http_url = AuditClient::ws_to_http_url(&ws_url)
|
||||
.map_err(|e| format!("Failed to convert WebSocket URL to HTTP: {}", e))?;
|
||||
|
||||
Err("Not implemented yet".to_string())
|
||||
let http_client = reqwest::Client::new();
|
||||
let response = http_client
|
||||
.get(&http_url)
|
||||
.header("Accept", "application/nostr+json")
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to fetch NIP-11 document: {}", e))?;
|
||||
|
||||
let json_text = response.text().await
|
||||
.map_err(|e| format!("Failed to read response body: {}", e))?;
|
||||
|
||||
let doc: serde_json::Value = serde_json::from_str(&json_text)
|
||||
.map_err(|e| format!("Response is not valid JSON: {}", e))?;
|
||||
|
||||
// 2. Check if `curation` field exists
|
||||
if let Some(curation) = doc.get("curation") {
|
||||
// 3. If present: verify it's a non-empty string
|
||||
let curation_str = curation.as_str()
|
||||
.ok_or_else(|| "curation field must be a string when present".to_string())?;
|
||||
|
||||
if curation_str.trim().is_empty() {
|
||||
return Err("curation field must not be empty when present".to_string());
|
||||
}
|
||||
}
|
||||
// 4. If absent: both cases are valid per spec
|
||||
|
||||
// 5. Both cases are valid - test passes
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
@@ -163,4 +284,4 @@ mod tests {
|
||||
// Don't assert all passed yet - tests not implemented
|
||||
// assert!(results.all_passed(), "Some GRASP-01 NIP-11 document tests failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
///
|
||||
/// Provides hyper HTTP server with WebSocket upgrade support for the Nostr relay.
|
||||
pub mod landing;
|
||||
pub mod nip11;
|
||||
|
||||
use std::future::Future;
|
||||
use std::net::SocketAddr;
|
||||
@@ -46,6 +47,32 @@ impl Service<Request<Incoming>> for HttpService {
|
||||
fn call(&self, req: Request<Incoming>) -> Self::Future {
|
||||
let base = Response::builder().header("server", "ngit-grasp");
|
||||
|
||||
// Check for NIP-11 relay information request (Accept: application/nostr+json)
|
||||
if let Some(accept) = req.headers().get("accept") {
|
||||
if accept
|
||||
.to_str()
|
||||
.map(|s| s.contains("application/nostr+json"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
let doc = nip11::RelayInformationDocument::from_config(&self.config);
|
||||
let json = doc.to_json().unwrap_or_else(|e| {
|
||||
tracing::error!("Failed to serialize NIP-11 document: {}", e);
|
||||
"{}".to_string()
|
||||
});
|
||||
|
||||
tracing::debug!("Serving NIP-11 relay information document to {}", self.remote);
|
||||
|
||||
return Box::pin(async move {
|
||||
Ok(base
|
||||
.status(200)
|
||||
.header("content-type", "application/nostr+json")
|
||||
.header("access-control-allow-origin", "*")
|
||||
.body(json)
|
||||
.unwrap())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this is a WebSocket upgrade request
|
||||
if let (Some(c), Some(w)) = (
|
||||
req.headers().get("connection"),
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/// NIP-11 Relay Information Document
|
||||
///
|
||||
/// Implements NIP-11 relay information endpoint with GRASP-01 extensions.
|
||||
/// See: https://github.com/nostr-protocol/nips/blob/master/11.md
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::config::Config;
|
||||
|
||||
/// NIP-11 Relay Information Document
|
||||
///
|
||||
/// This structure represents the relay metadata served at the HTTP(S) endpoint
|
||||
/// when the client sends `Accept: application/nostr+json` header.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RelayInformationDocument {
|
||||
/// Relay name
|
||||
pub name: String,
|
||||
|
||||
/// Relay description
|
||||
pub description: String,
|
||||
|
||||
/// Relay owner's public key (hex format)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub pubkey: Option<String>,
|
||||
|
||||
/// Contact information for relay admin
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub contact: Option<String>,
|
||||
|
||||
/// List of NIPs supported by this relay
|
||||
pub supported_nips: Vec<u16>,
|
||||
|
||||
/// Relay software identifier
|
||||
pub software: String,
|
||||
|
||||
/// Software version
|
||||
pub version: String,
|
||||
|
||||
// GRASP-01 Extensions (lines 11-14 of GRASP-01 spec)
|
||||
|
||||
/// List of supported GRASPs (e.g., ["GRASP-01"])
|
||||
/// Required by GRASP-01 specification line 12
|
||||
pub supported_grasps: Vec<String>,
|
||||
|
||||
/// Repository acceptance criteria description
|
||||
/// Required by GRASP-01 specification line 13
|
||||
pub repo_acceptance_criteria: String,
|
||||
|
||||
/// Curation policy (present if curated, absent otherwise)
|
||||
/// Optional per GRASP-01 specification line 14
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub curation: Option<String>,
|
||||
}
|
||||
|
||||
impl RelayInformationDocument {
|
||||
/// Create NIP-11 relay information document from configuration
|
||||
pub fn from_config(config: &Config) -> Self {
|
||||
Self {
|
||||
name: config.relay_name.clone(),
|
||||
description: config.relay_description.clone(),
|
||||
pubkey: Some(config.owner_npub.clone()),
|
||||
contact: None, // Could be added to config if needed
|
||||
supported_nips: vec![
|
||||
1, // NIP-01: Basic protocol flow
|
||||
11, // NIP-11: Relay information document (this!)
|
||||
34, // NIP-34: Git repository announcements
|
||||
],
|
||||
software: env!("CARGO_PKG_NAME").to_string(),
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
|
||||
// GRASP-01 Extensions
|
||||
supported_grasps: vec!["GRASP-01".to_string()],
|
||||
repo_acceptance_criteria: format!(
|
||||
"Repositories must list this relay ({}) in both 'clone' and 'relays' tags of kind 30617 announcements. \
|
||||
All other events must reference accepted repositories or accepted events.",
|
||||
config.domain
|
||||
),
|
||||
curation: None, // Not a curated relay - only SPAM prevention via GRASP-01 policy
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize to JSON string
|
||||
pub fn to_json(&self) -> Result<String, serde_json::Error> {
|
||||
serde_json::to_string_pretty(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_relay_information_document_structure() {
|
||||
let config = Config {
|
||||
domain: "relay.example.com".to_string(),
|
||||
owner_npub: "npub1test".to_string(),
|
||||
relay_name: "Test Relay".to_string(),
|
||||
relay_description: "A test relay".to_string(),
|
||||
git_data_path: "./data/git".to_string(),
|
||||
relay_data_path: "./data/relay".to_string(),
|
||||
bind_address: "127.0.0.1:8080".to_string(),
|
||||
database_backend: crate::config::DatabaseBackend::Memory,
|
||||
};
|
||||
|
||||
let doc = RelayInformationDocument::from_config(&config);
|
||||
|
||||
assert_eq!(doc.name, "Test Relay");
|
||||
assert_eq!(doc.description, "A test relay");
|
||||
assert_eq!(doc.pubkey, Some("npub1test".to_string()));
|
||||
assert!(doc.supported_nips.contains(&1));
|
||||
assert!(doc.supported_nips.contains(&11));
|
||||
assert!(doc.supported_nips.contains(&34));
|
||||
assert_eq!(doc.supported_grasps, vec!["GRASP-01"]);
|
||||
assert!(doc.repo_acceptance_criteria.contains("relay.example.com"));
|
||||
assert!(doc.curation.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_relay_information_document_json() {
|
||||
let config = Config {
|
||||
domain: "relay.example.com".to_string(),
|
||||
owner_npub: "npub1test".to_string(),
|
||||
relay_name: "Test Relay".to_string(),
|
||||
relay_description: "A test relay".to_string(),
|
||||
git_data_path: "./data/git".to_string(),
|
||||
relay_data_path: "./data/relay".to_string(),
|
||||
bind_address: "127.0.0.1:8080".to_string(),
|
||||
database_backend: crate::config::DatabaseBackend::Memory,
|
||||
};
|
||||
|
||||
let doc = RelayInformationDocument::from_config(&config);
|
||||
let json = doc.to_json().expect("Failed to serialize to JSON");
|
||||
|
||||
// Verify JSON contains expected fields
|
||||
assert!(json.contains("\"name\""));
|
||||
assert!(json.contains("\"description\""));
|
||||
assert!(json.contains("\"supported_nips\""));
|
||||
assert!(json.contains("\"supported_grasps\""));
|
||||
assert!(json.contains("\"repo_acceptance_criteria\""));
|
||||
assert!(json.contains("GRASP-01"));
|
||||
|
||||
// Verify it's valid JSON by parsing
|
||||
let parsed: serde_json::Value = serde_json::from_str(&json).expect("Invalid JSON");
|
||||
assert_eq!(parsed["name"], "Test Relay");
|
||||
assert_eq!(parsed["supported_grasps"][0], "GRASP-01");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//! GRASP-01 NIP-11 Document Integration Tests
|
||||
//!
|
||||
//! Tests ngit-grasp relay's implementation of GRASP-01 NIP-11 relay information requirements.
|
||||
//! Uses grasp-audit library to avoid code duplication.
|
||||
//!
|
||||
//! # Test Strategy
|
||||
//!
|
||||
//! - Each test runs in complete isolation with its own fresh relay instance
|
||||
//! - Uses macro to eliminate boilerplate while maintaining test isolation
|
||||
//! - Calls individual test methods from grasp-audit for minimal duplication
|
||||
//!
|
||||
//! # Running Tests
|
||||
//!
|
||||
//! ```bash
|
||||
//! # Run all GRASP-01 NIP-11 tests
|
||||
//! cargo test --test nip11_document
|
||||
//!
|
||||
//! # Run specific test
|
||||
//! cargo test --test nip11_document test_nip11_document_exists
|
||||
//!
|
||||
//! # With output
|
||||
//! cargo test --test nip11_document -- --nocapture
|
||||
//! ```
|
||||
|
||||
mod common;
|
||||
|
||||
use common::TestRelay;
|
||||
use grasp_audit::*;
|
||||
|
||||
/// Macro to generate isolated integration tests
|
||||
///
|
||||
/// Each test runs with its own fresh relay instance to ensure complete isolation.
|
||||
/// This eliminates rate-limiting issues and ensures tests don't interfere with each other.
|
||||
macro_rules! isolated_test {
|
||||
($test_name:ident) => {
|
||||
#[tokio::test]
|
||||
async fn $test_name() {
|
||||
let relay = TestRelay::start().await;
|
||||
let config = AuditConfig::ci();
|
||||
let client = AuditClient::new(relay.url(), config)
|
||||
.await
|
||||
.expect("Failed to create audit client");
|
||||
|
||||
let result = specs::Nip11DocumentTests::$test_name(&client).await;
|
||||
|
||||
relay.stop().await;
|
||||
|
||||
assert!(
|
||||
result.passed,
|
||||
"{} failed: {}",
|
||||
stringify!($test_name),
|
||||
result.error.as_deref().unwrap_or("unknown error")
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Generate isolated tests for all GRASP-01 NIP-11 document tests
|
||||
isolated_test!(test_nip11_document_exists);
|
||||
isolated_test!(test_nip11_supported_grasps_field);
|
||||
isolated_test!(test_nip11_repo_acceptance_criteria_field);
|
||||
isolated_test!(test_nip11_curation_field);
|
||||
Reference in New Issue
Block a user