From 82b56c37b26a2fac1a294873e539b19b9325dca6 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Mon, 12 Jan 2026 21:06:39 +0000 Subject: feat(config): add repository whitelist for curated GRASP-01 acceptance Adds NGIT_REPOSITORY_WHITELIST option for curated relay operation that accepts only whitelisted repositories while maintaining GRASP-01 compliance (announcements must list the service). This differs from archive whitelist which enables GRASP-05 mode and doesn't require service listing. Key features: - Supports three whitelist formats: npub, npub/identifier, identifier - Enforces mutual exclusivity with archive read-only mode - Updates NIP-11 curation field when whitelist is enabled - Maintains GRASP-01 compliance (doesn't add GRASP-05 support) Configuration synced across all four sources: src/config.rs, docs/reference/configuration.md, nix/module.nix, and .env.example as required by AGENTS.md. --- src/http/nip11.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) (limited to 'src/http') diff --git a/src/http/nip11.rs b/src/http/nip11.rs index 71cadb1..ff7b8df 100644 --- a/src/http/nip11.rs +++ b/src/http/nip11.rs @@ -74,8 +74,15 @@ impl RelayInformationDocument { } supported_grasps.push("GRASP-02".to_string()); - // Build curation field for archive read-only mode + // Build curation field for archive read-only mode or repository whitelist + let repository_config = config.repository_config().ok(); + let repository_whitelist_enabled = repository_config + .as_ref() + .map(|rc| rc.enabled()) + .unwrap_or(false); + let curation = if archive_read_only { + // Archive read-only mode (GRASP-05 only) if let Some(ref ac) = archive_config { if ac.archive_all { Some("Read-only sync of all repositories found on network".to_string()) @@ -87,6 +94,18 @@ impl RelayInformationDocument { } else { None } + } else if archive_enabled && repository_whitelist_enabled { + // Both archive (non-read-only) AND repository whitelist enabled + Some( + "Accepts whitelisted repositories (with or without service listing) and whitelisted repositories that list this service" + .to_string(), + ) + } else if repository_whitelist_enabled { + // Repository whitelist only + Some( + "Accepts only whitelisted repositories and maintainers that list this service" + .to_string(), + ) } else { None }; @@ -230,4 +249,48 @@ mod tests { .unwrap() .contains("Read-only sync of whitelisted")); } + + #[test] + fn test_nip11_with_repository_whitelist() { + let keys = nostr_sdk::Keys::generate(); + let test_npub = keys.public_key().to_bech32().unwrap(); + let mut config = Config::for_testing(); + config.domain = "relay.example.com".to_string(); + config.repository_whitelist = format!("{},bitcoin-core", test_npub); + + let doc = RelayInformationDocument::from_config(&config); + + // Repository whitelist doesn't enable GRASP-05 + assert_eq!(doc.supported_grasps, vec!["GRASP-01", "GRASP-02"]); + // Should have curation field for repository whitelist + assert!(doc.curation.is_some()); + assert!(doc + .curation + .unwrap() + .contains("Accepts only whitelisted repositories")); + } + + #[test] + fn test_nip11_with_archive_and_repository_whitelist() { + let keys = nostr_sdk::Keys::generate(); + let test_npub = keys.public_key().to_bech32().unwrap(); + let mut config = Config::for_testing(); + config.domain = "relay.example.com".to_string(); + config.archive_whitelist = "bitcoin-core".to_string(); + config.archive_read_only = Some(false); // Non-read-only archive mode + config.repository_whitelist = test_npub; + + let doc = RelayInformationDocument::from_config(&config); + + // Should have GRASP-05 enabled due to archive whitelist + assert_eq!( + doc.supported_grasps, + vec!["GRASP-01", "GRASP-05", "GRASP-02"] + ); + // Should have curation field reflecting BOTH archive and repository whitelist + assert!(doc.curation.is_some()); + let curation = doc.curation.unwrap(); + assert!(curation.contains("whitelisted repositories")); + assert!(curation.contains("with or without service listing")); + } } -- cgit v1.2.3