upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/nostr/builder.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-01-12 21:51:57 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-01-12 21:51:57 +0000
commitc8ab2c9c294ae9401ff542d0eecc6606b7908412 (patch)
tree2ecf96e0265c855940df149781a0a24640408e1e /src/nostr/builder.rs
parent70c577f10bbe150b6b13bec545dc8720ad005a64 (diff)
feat(config): add event blacklist to block all events from specific authors
Adds NGIT_EVENT_BLACKLIST option for blocking all events from specific npubs, taking precedence over all other validation to enable comprehensive moderation without affecting curation policy. Key features: - Simple npub-only format: <npub>,<npub>,... - Checked FIRST before any other validation (including repository blacklist) - Blocks ALL event types (announcements, state events, PRs, comments, etc.) - Events never reach relay storage or purgatory - Specific rejection reason for operator debugging Implementation: - Add EventBlacklistConfig struct with check() method - Add NGIT_EVENT_BLACKLIST config option and event_blacklist_config() method - Add config field to PolicyContext for policy access - Add check_event_blacklist() to Nip34WritePolicy - Check event blacklist first in admit_event() method (before any other validation) - 4 new unit tests covering all blacklist behavior Configuration synced across all four sources: - src/config.rs: Core implementation with EventBlacklistConfig - .env.example: Comprehensive documentation with examples - docs/reference/configuration.md: Complete reference documentation - nix/module.nix: NixOS module option with environment mapping README updates: - Add comprehensive "Curation & Moderation" section - Document repository whitelists (GRASP-01 and GRASP-05 modes) - Document repository and event blacklists with precedence order - Add configuration table for all curation/moderation settings - Provide real-world examples for different relay configurations Testing: - 4 new tests for event blacklist functionality - All 336 library tests passing - All 64 integration tests passing - All 38 filter support tests passing Verification: - Repository blacklist confirmed to apply to sync (uses same admit_event flow) - Sync events validated through process_event_static -> write_policy.admit_event Use cases: - Block spam/abusive users completely - Prevent malicious actors from submitting any events - Temporary blocks for investigation - Moderation without affecting whitelist curation policy
Diffstat (limited to 'src/nostr/builder.rs')
-rw-r--r--src/nostr/builder.rs32
1 files changed, 31 insertions, 1 deletions
diff --git a/src/nostr/builder.rs b/src/nostr/builder.rs
index 9819e37..c2de1df 100644
--- a/src/nostr/builder.rs
+++ b/src/nostr/builder.rs
@@ -56,7 +56,13 @@ impl Nip34WritePolicy {
56 purgatory: std::sync::Arc<crate::purgatory::Purgatory>, 56 purgatory: std::sync::Arc<crate::purgatory::Purgatory>,
57 config: crate::config::Config, 57 config: crate::config::Config,
58 ) -> Self { 58 ) -> Self {
59 let ctx = PolicyContext::new(&config.domain, database, git_data_path, purgatory); 59 let ctx = PolicyContext::new(
60 &config.domain,
61 database,
62 git_data_path,
63 purgatory,
64 config.clone(),
65 );
60 Self { 66 Self {
61 announcement_policy: AnnouncementPolicy::new(ctx.clone(), config.clone()), 67 announcement_policy: AnnouncementPolicy::new(ctx.clone(), config.clone()),
62 state_policy: StatePolicy::new(ctx.clone()), 68 state_policy: StatePolicy::new(ctx.clone()),
@@ -66,6 +72,19 @@ impl Nip34WritePolicy {
66 } 72 }
67 } 73 }
68 74
75 /// Check if an event author is blacklisted
76 ///
77 /// Returns Some(reason) if blacklisted, None if not blacklisted.
78 fn check_event_blacklist(&self, event: &Event) -> Option<String> {
79 let event_blacklist = self.ctx.config.event_blacklist_config();
80 if !event_blacklist.enabled() {
81 return None;
82 }
83
84 let npub = event.pubkey.to_bech32().ok()?;
85 event_blacklist.check(&npub)
86 }
87
69 /// Get a reference to the purgatory for read-only access 88 /// Get a reference to the purgatory for read-only access
70 pub fn purgatory(&self) -> &std::sync::Arc<crate::purgatory::Purgatory> { 89 pub fn purgatory(&self) -> &std::sync::Arc<crate::purgatory::Purgatory> {
71 &self.ctx.purgatory 90 &self.ctx.purgatory
@@ -474,6 +493,17 @@ impl WritePolicy for Nip34WritePolicy {
474 addr: &'a SocketAddr, 493 addr: &'a SocketAddr,
475 ) -> BoxedFuture<'a, WritePolicyResult> { 494 ) -> BoxedFuture<'a, WritePolicyResult> {
476 Box::pin(async move { 495 Box::pin(async move {
496 // Check event blacklist FIRST - it overrides everything
497 if let Some(reason) = self.check_event_blacklist(event) {
498 tracing::debug!(
499 event_id = %event.id.to_bech32().unwrap_or_else(|_| event.id.to_hex()),
500 author = %event.pubkey.to_hex(),
501 reason = %reason,
502 "Rejected event from blacklisted author"
503 );
504 return WritePolicyResult::reject(reason);
505 }
506
477 // Detect if this is a synced event (from proactive sync) vs user-submitted 507 // Detect if this is a synced event (from proactive sync) vs user-submitted
478 // Sync uses localhost:0 as a dummy address 508 // Sync uses localhost:0 as a dummy address
479 let is_synced = addr.ip().is_loopback() && addr.port() == 0; 509 let is_synced = addr.ip().is_loopback() && addr.port() == 0;