fix(nostr): ignore vanish in disrespector mode

This commit is contained in:
DanConwayDev
2026-06-24 10:53:24 +01:00
parent 7db7d31229
commit 3b4ed48df1
4 changed files with 109 additions and 8 deletions
+11 -3
View File
@@ -31,8 +31,16 @@ relay policy code:
- holding DB uses `process_nip09(false)` and `process_nip62(false)`
(`src/nostr/holding.rs`)
This keeps deletion behavior auditable and consistent across cascade, holding,
archive, and recovery flows.
This keeps deletion behavior auditable and prevents the storage backends from
silently applying deletion semantics outside ngit-grasp policy code.
The full cascade, holding, archive, and recovery flow currently applies to
NIP-09 repository/content deletions and operator-driven blacklist/whitelist
deletions. NIP-62 request-to-vanish handling is narrower: in normal mode a
targeted vanish request records a vanish tombstone, removes that author's events
from the main database, and evicts that author's purgatory entries. It does not
currently move those events through the holding database or archive/recovery
pipeline.
## The Left-Pad Problem
@@ -677,7 +685,7 @@ 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"`) 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)
- **When `deletion_request_disrespector = true`:** do NOT include `9` or `62` (archival mode stores but does not honor deletion or vanish requests)
This allows clients to discover whether a relay respects deletion requests.
+2 -1
View File
@@ -73,7 +73,8 @@ impl DeletionPolicy {
/// main database) so clients see an OK and the request is preserved, but it
/// is NOT acted upon — no purgatory eviction, no main-DB deletion, and no
/// tombstone recording. The targeted events therefore remain fully
/// accessible. This only affects NIP-09 user-initiated deletions.
/// accessible. The same archival-mode contract is applied to NIP-62 vanish
/// requests in [`DeletionService::handle_vanish`](super::service::DeletionService::handle_vanish).
pub async fn handle(&self, event: &Event) -> WritePolicyResult {
// Archival mode: store the deletion request but do not process it.
if self.ctx.config.deletion_request_disrespector {
+10
View File
@@ -78,6 +78,16 @@ impl DeletionService {
}
pub async fn handle_vanish(&self, event: &Event) -> WritePolicyResult {
// Archival mode: store the vanish request but do not process it.
if self.ctx.config.deletion_request_disrespector {
tracing::info!(
event_id = %event.id.to_hex(),
author = %event.pubkey.to_hex(),
"Disrespector mode: storing NIP-62 vanish request without acting on it"
);
return WritePolicyResult::Accept;
}
// Only honour requests that target this relay (or all relays). We do not
// configure a relay_url on the database, matching the historical
// behaviour where only ALL_RELAYS requests were actioned; but we accept
+86 -4
View File
@@ -9,15 +9,16 @@
//! purgatory based, so the disrespector simply accepts the kind-5 request and
//! does nothing with it. The two properties under test are:
//!
//! 1. **Disrespector accepts but ignores deletion** — a kind-5 request gets an
//! `OK`, yet the targeted announcement remains queryable afterwards.
//! 1. **Disrespector accepts but ignores deletion/vanish** — a kind-5 or
//! kind-62 request gets an `OK`, yet the targeted/author events remain
//! queryable afterwards and no vanish tombstone is laid down.
//! 2. **NIP-11 advertisement** — a disrespector relay omits `9` and `62` from
//! `supported_nips`; a normal relay advertises both.
//!
//! The normal-mode baseline ("a default relay honours the deletion") lives in
//! `nip09_validation.rs` as `normal_mode_honours_deletion`. Shared helpers
//! (`publish_served_repo`, `announcement_served_by_coordinate`,
//! `announcement_coordinate`, `build_deletion`) live in
//! `announcement_coordinate`, `build_deletion`, `build_vanish`) live in
//! `tests/common/nip09_helpers.rs`.
//!
//! # Running
@@ -30,7 +31,7 @@
mod common;
use common::{
announcement_coordinate, announcement_served_by_coordinate, build_deletion,
announcement_coordinate, announcement_served_by_coordinate, build_deletion, build_vanish,
publish_served_repo, TestRelay,
};
@@ -98,6 +99,87 @@ async fn disrespector_accepts_but_ignores_deletion() {
);
}
/// Disrespector mode: the kind-62 vanish request is accepted (OK) but ignored —
/// the author's events remain queryable and future writes are not blocked by a
/// vanish tombstone.
#[tokio::test]
async fn disrespector_accepts_but_ignores_vanish() {
let relay = TestRelay::start_with_deletion_disrespector().await;
let client = AuditClient::new(relay.url(), AuditConfig::isolated())
.await
.expect("create audit client");
let (announcement, repo_id) = publish_served_repo(&client, "disrespector-vanish").await;
let vanish = build_vanish(&client, None);
let vanish_id = vanish.id;
// The relay MUST accept the vanish request (archival mode still stores/acks it).
client
.send_event(vanish)
.await
.expect("disrespector relay should OK the kind-62 vanish request");
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
let vanish_served = client
.is_event_on_relay(vanish_id)
.await
.expect("query kind-62 vanish after send");
let target_served_by_id = client
.is_event_on_relay(announcement.id)
.await
.expect("query announcement by id after vanish");
let target_served_by_coordinate =
announcement_served_by_coordinate(&client, &announcement, &repo_id).await;
let later_issue = client
.create_issue(
&announcement,
"Post-ignored-vanish issue",
"still allowed",
vec![],
)
.expect("build post-vanish issue");
let later_issue_id = later_issue.id;
let later_issue_result = client.send_event(later_issue).await;
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
let later_issue_served = client
.is_event_on_relay(later_issue_id)
.await
.expect("query post-ignored-vanish issue");
relay.stop().await;
assert!(
vanish_served,
"disrespector relay must store/serve the kind-62 vanish request itself (id {})",
vanish_id
);
assert!(
target_served_by_id,
"disrespector relay must ignore vanish: announcement {} should still be \
queryable by id",
announcement.id
);
assert!(
target_served_by_coordinate,
"disrespector relay must ignore vanish: announcement {} should still be \
served for an author+kind+identifier query",
announcement.id
);
assert!(
later_issue_result.is_ok(),
"disrespector relay must not lay down a vanish tombstone; later write was {:?}",
later_issue_result
);
assert!(
later_issue_served,
"later event {} must be served because disrespector mode ignored vanish",
later_issue_id
);
}
/// Fetch the NIP-11 relay information document via HTTP and return the list of
/// advertised `supported_nips`.
///