diff --git a/.env.example b/.env.example index c389251..5d29af8 100644 --- a/.env.example +++ b/.env.example @@ -247,13 +247,15 @@ # When enabled, incoming NIP-09 (kind 5) deletion requests are STORED but NOT # acted upon: targeted events remain fully accessible. This makes the relay an # archival server, preserving content and preventing "left-pad" scenarios. -# NIP-11 supported_nips will NOT advertise NIP-09 (deletion) in this mode. +# NIP-11 supported_nips will NOT advertise NIP-09 (deletion) or NIP-62 +# (request to vanish) in this mode. # # This ONLY affects NIP-09 user-initiated deletions. It does NOT prevent # blacklist-triggered deletions (operator moderation: spam/malware/abuse). # # When disabled (default), deletion requests are honoured: targeted events are -# deleted and re-submission stays rejected. NIP-09 is advertised in NIP-11. +# deleted and re-submission stays rejected. NIP-09 and NIP-62 are advertised in +# NIP-11. # # See: docs/explanation/deletion-requests.md # diff --git a/docs/explanation/deletion-requests.md b/docs/explanation/deletion-requests.md index d3fb4d4..807ac2a 100644 --- a/docs/explanation/deletion-requests.md +++ b/docs/explanation/deletion-requests.md @@ -79,10 +79,12 @@ tombstone; cascade = walk the references of a recorded deletion). therefore stored in the main DB so clients get an OK), but it is **not** acted upon: no purgatory eviction, no main-DB deletion, and no tombstone is recorded. Targeted events stay fully accessible, making the relay an archival server. - This only affects NIP-09 (kind 5); NIP-62 vanish handling is unchanged. - NIP-11 advertisement reflects the mode: NIP-09 (`9`) is included in + The short-circuit only affects NIP-09 (kind 5) *processing*; NIP-62 vanish + *handling* is unchanged. NIP-11 advertisement, however, reflects the mode for + both deletion NIPs: NIP-09 (`9`) and NIP-62 (`62`) are included in `supported_nips` only when disrespector is `false` - ([`src/http/nip11.rs`](../../src/http/nip11.rs)). + ([`src/http/nip11.rs`](../../src/http/nip11.rs)), so clients can discover that + an archival relay does not honour deletion requests. --- @@ -516,8 +518,8 @@ How long to retain archived events and git data before permanent deletion. Provi Deletion support is **conditionally advertised** in NIP-11 relay information (implemented in [`src/http/nip11.rs`](../../src/http/nip11.rs)): -- **When `deletion_request_disrespector = false`:** include `9` (`"deletion"`) in the supported NIPs array -- **When `deletion_request_disrespector = true`:** do NOT include `9` (archival mode doesn't honor deletions) +- **When `deletion_request_disrespector = false`:** include `9` (`"deletion"`) and `62` (`"request to vanish"`) in the supported NIPs array +- **When `deletion_request_disrespector = true`:** do NOT include `9` or `62` (archival mode doesn't honor deletions) This allows clients to discover whether a relay respects deletion requests. diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 7ed7641..b4c0e49 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -1055,14 +1055,14 @@ Event blacklist does **not** affect NIP-11 metadata: hard-deleted from the relay, matching purgatory entries are evicted, and a persistent tombstone is recorded so re-submission of the deleted event stays rejected across restarts. - - NIP-11 `supported_nips` includes `9` (deletion). + - NIP-11 `supported_nips` includes `9` (deletion) and `62` (request to vanish). - When `true`: - Incoming NIP-09 deletion requests are still **stored** (the client receives an OK), but they are **not acted upon**. Targeted events remain fully accessible. This makes the relay an archival server, preserving content and preventing "left-pad" scenarios. - - NIP-11 `supported_nips` does **not** include `9`, so clients can discover - that this relay does not honour deletions. + - NIP-11 `supported_nips` does **not** include `9` or `62`, so clients can + discover that this relay does not honour deletions. **IMPORTANT:** This setting ONLY affects NIP-09 user-initiated deletions. It does **NOT** prevent blacklist-triggered deletions, which are an operator moderation diff --git a/nix/module.nix b/nix/module.nix index b5259f1..c8f3f92 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -266,13 +266,14 @@ let When enabled, incoming NIP-09 (kind 5) deletion requests are stored but NOT acted upon: targeted events remain fully accessible. This preserves content and prevents "left-pad" scenarios. NIP-11 - supported_nips will NOT advertise NIP-09 (deletion). + supported_nips will NOT advertise NIP-09 (deletion) or NIP-62 + (request to vanish). This ONLY affects NIP-09 user-initiated deletions. It does NOT prevent blacklist-triggered deletions (operator moderation). - When disabled (default), deletion requests are honoured and NIP-09 is - advertised in NIP-11. + When disabled (default), deletion requests are honoured and NIP-09 and + NIP-62 are advertised in NIP-11. See: docs/explanation/deletion-requests.md ''; diff --git a/src/http/nip11.rs b/src/http/nip11.rs index ab25b23..68cb71f 100644 --- a/src/http/nip11.rs +++ b/src/http/nip11.rs @@ -112,13 +112,15 @@ impl RelayInformationDocument { 34, // NIP-34: Git repository announcements 77, // NIP-77: Negentropy sync (reconciliation protocol) ]; - // NIP-09 (deletion) is honoured only when not running as an - // archival "disrespector" relay. When disrespector mode is on - // the relay stores but ignores deletion requests, so we must not - // advertise NIP-09 support — clients can then discover that this - // relay does not honour deletions. + // NIP-09 (deletion) and NIP-62 (request to vanish) are honoured + // only when not running as an archival "disrespector" relay. When + // disrespector mode is on the relay stores but ignores deletion / + // vanish requests, so we must not advertise NIP-09 or NIP-62 + // support — clients can then discover that this relay does not + // honour deletions. if !config.deletion_request_disrespector { nips.push(9); // NIP-09: Event deletion requests + nips.push(62); // NIP-62: Request to vanish nips.sort_unstable(); } nips @@ -170,8 +172,10 @@ mod tests { assert!(doc.supported_nips.contains(&11)); assert!(doc.supported_nips.contains(&34)); assert!(doc.supported_nips.contains(&77)); - // NIP-09 (deletion) advertised by default (disrespector off). + // NIP-09 (deletion) and NIP-62 (vanish) advertised by default + // (disrespector off). assert!(doc.supported_nips.contains(&9)); + assert!(doc.supported_nips.contains(&62)); // Without archive mode, only GRASP-01 and GRASP-02 assert_eq!(doc.supported_grasps, vec!["GRASP-01", "GRASP-02"]); assert!(doc.repo_acceptance_criteria.contains("None")); @@ -329,8 +333,10 @@ mod tests { let config = Config::for_testing(); let doc = RelayInformationDocument::from_config(&config); - // NIP-09 (deletion) is honoured (and advertised) by default. + // NIP-09 (deletion) and NIP-62 (vanish) are honoured (and advertised) + // by default. assert!(doc.supported_nips.contains(&9)); + assert!(doc.supported_nips.contains(&62)); } #[test] @@ -340,9 +346,10 @@ mod tests { let doc = RelayInformationDocument::from_config(&config); - // Archival relays do not honour deletions, so NIP-09 must not be - // advertised. + // Archival relays do not honour deletions, so NIP-09 and NIP-62 must + // not be advertised. assert!(!doc.supported_nips.contains(&9)); + assert!(!doc.supported_nips.contains(&62)); // Other NIPs are unaffected. assert!(doc.supported_nips.contains(&1)); assert!(doc.supported_nips.contains(&34)); diff --git a/tests/nip09_disrespector.rs b/tests/nip09_disrespector.rs index 6e000d8..443f4ec 100644 --- a/tests/nip09_disrespector.rs +++ b/tests/nip09_disrespector.rs @@ -13,8 +13,8 @@ //! `OK`, yet the targeted announcement remains queryable afterwards. //! 2. **Normal mode honours deletion** — the same flow against a default relay //! removes the target. -//! 3. **NIP-11 advertisement** — a disrespector relay omits `9` from -//! `supported_nips`; a normal relay advertises it. +//! 3. **NIP-11 advertisement** — a disrespector relay omits `9` and `62` from +//! `supported_nips`; a normal relay advertises both. //! //! # Running //! @@ -330,10 +330,11 @@ async fn fetch_supported_nips(relay: &TestRelay) -> Vec { .expect("NIP-11 document must contain a supported_nips array") } -/// NIP-11 advertisement: disrespector omits NIP-09, normal mode advertises it. +/// NIP-11 advertisement: disrespector omits NIP-09/NIP-62, normal mode +/// advertises both. #[tokio::test] async fn nip11_advertisement_reflects_deletion_support() { - // Disrespector relay: NIP-09 (9) MUST be absent. + // Disrespector relay: NIP-09 (9) and NIP-62 (62) MUST be absent. let disrespector = TestRelay::start_with_deletion_disrespector().await; let supported = fetch_supported_nips(&disrespector).await; disrespector.stop().await; @@ -343,8 +344,13 @@ async fn nip11_advertisement_reflects_deletion_support() { "disrespector relay must NOT advertise NIP-09; supported_nips = {:?}", supported ); + assert!( + !supported.contains(&62), + "disrespector relay must NOT advertise NIP-62; supported_nips = {:?}", + supported + ); - // Normal relay: NIP-09 (9) MUST be present. + // Normal relay: NIP-09 (9) and NIP-62 (62) MUST be present. let normal = TestRelay::start().await; let supported = fetch_supported_nips(&normal).await; normal.stop().await; @@ -354,4 +360,9 @@ async fn nip11_advertisement_reflects_deletion_support() { "normal relay must advertise NIP-09; supported_nips = {:?}", supported ); + assert!( + supported.contains(&62), + "normal relay must advertise NIP-62; supported_nips = {:?}", + supported + ); }