mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-10-05 23:18:24 +00:00
Relay operators already have a stable Nostr identity for NIP-11 and NIP-42, but clients cannot resolve the domain itself to that key. Serve the NIP-05 root identifier so _@domain identifies a root-mounted relay without another key source. Add an exact root-level /.well-known/nostr.json route for GET and HEAD, serialize the relay-owner public key as lowercase hex under names._, retain permissive CORS, and give this route precedence over NIP-11 content negotiation. Derive NIP-11 support from the relay request path: only / advertises NIP-05, while nested relay paths omit it. Keep the changelog, architecture, README, and relay-owner configuration descriptions synchronized. The path check assumes the HTTP request path is the relay's public mount path; a future explicit base-path setting should remain the source for this decision if proxy routing hides that path. Named identities and recommended relay-hint mappings remain outside this change. Validated with 760 library tests, the root/non-root NIP-05 server integration test, strict all-target Clippy, cargo fmt, git diff checks, and Nix module parsing.
87 lines
2.7 KiB
Rust
87 lines
2.7 KiB
Rust
//! NIP-05 root-identifier integration tests.
|
|
|
|
mod common;
|
|
|
|
use common::TestRelay;
|
|
|
|
#[tokio::test]
|
|
async fn well_known_root_identity_matches_relay_pubkey() {
|
|
let relay = TestRelay::start().await;
|
|
let client = reqwest::Client::new();
|
|
|
|
let response = client
|
|
.get(format!(
|
|
"http://{}/.well-known/nostr.json?name=_",
|
|
relay.domain()
|
|
))
|
|
.header("Accept", "application/nostr+json, application/json")
|
|
.send()
|
|
.await
|
|
.expect("request NIP-05 root identity");
|
|
|
|
assert_eq!(response.status(), reqwest::StatusCode::OK);
|
|
assert_eq!(
|
|
response
|
|
.headers()
|
|
.get(reqwest::header::ACCESS_CONTROL_ALLOW_ORIGIN)
|
|
.and_then(|value| value.to_str().ok()),
|
|
Some("*")
|
|
);
|
|
assert!(response
|
|
.headers()
|
|
.get(reqwest::header::CONTENT_TYPE)
|
|
.and_then(|value| value.to_str().ok())
|
|
.is_some_and(|value| value.starts_with("application/json")));
|
|
|
|
let nip05: serde_json::Value = response.json().await.expect("parse NIP-05 document");
|
|
let root_pubkey = nip05["names"]["_"]
|
|
.as_str()
|
|
.expect("NIP-05 document should map the root identifier");
|
|
assert_eq!(root_pubkey.len(), 64);
|
|
assert!(root_pubkey
|
|
.chars()
|
|
.all(|character| character.is_ascii_digit() || ('a'..='f').contains(&character)));
|
|
|
|
let nip11: serde_json::Value = client
|
|
.get(format!("http://{}", relay.domain()))
|
|
.header("Accept", "application/nostr+json")
|
|
.send()
|
|
.await
|
|
.expect("request NIP-11 document")
|
|
.json()
|
|
.await
|
|
.expect("parse NIP-11 document");
|
|
|
|
assert_eq!(nip11["pubkey"], root_pubkey);
|
|
assert!(nip11["supported_nips"]
|
|
.as_array()
|
|
.expect("supported_nips should be an array")
|
|
.contains(&serde_json::json!(5)));
|
|
|
|
let nested_nip11: serde_json::Value = client
|
|
.get(format!("http://{}/relay", relay.domain()))
|
|
.header("Accept", "application/nostr+json")
|
|
.send()
|
|
.await
|
|
.expect("request NIP-11 document at a non-root relay path")
|
|
.json()
|
|
.await
|
|
.expect("parse nested-path NIP-11 document");
|
|
assert!(!nested_nip11["supported_nips"]
|
|
.as_array()
|
|
.expect("nested-path supported_nips should be an array")
|
|
.contains(&serde_json::json!(5)));
|
|
|
|
let nested_response = client
|
|
.get(format!(
|
|
"http://{}/repository/.well-known/nostr.json?name=_",
|
|
relay.domain()
|
|
))
|
|
.send()
|
|
.await
|
|
.expect("request a non-root well-known path");
|
|
assert_eq!(nested_response.status(), reqwest::StatusCode::NOT_FOUND);
|
|
|
|
relay.stop().await;
|
|
}
|