diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-12 21:06:39 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-12 21:21:52 +0000 |
| commit | 82b56c37b26a2fac1a294873e539b19b9325dca6 (patch) | |
| tree | 07800949230f13f91fec2eebbd94b8fbb00dd83f /src/http | |
| parent | a12927181c571fc1641772ad44dd4c6a4ab209d9 (diff) | |
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.
Diffstat (limited to 'src/http')
| -rw-r--r-- | src/http/nip11.rs | 65 |
1 files changed, 64 insertions, 1 deletions
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 { | |||
| 74 | } | 74 | } |
| 75 | supported_grasps.push("GRASP-02".to_string()); | 75 | supported_grasps.push("GRASP-02".to_string()); |
| 76 | 76 | ||
| 77 | // Build curation field for archive read-only mode | 77 | // Build curation field for archive read-only mode or repository whitelist |
| 78 | let repository_config = config.repository_config().ok(); | ||
| 79 | let repository_whitelist_enabled = repository_config | ||
| 80 | .as_ref() | ||
| 81 | .map(|rc| rc.enabled()) | ||
| 82 | .unwrap_or(false); | ||
| 83 | |||
| 78 | let curation = if archive_read_only { | 84 | let curation = if archive_read_only { |
| 85 | // Archive read-only mode (GRASP-05 only) | ||
| 79 | if let Some(ref ac) = archive_config { | 86 | if let Some(ref ac) = archive_config { |
| 80 | if ac.archive_all { | 87 | if ac.archive_all { |
| 81 | Some("Read-only sync of all repositories found on network".to_string()) | 88 | Some("Read-only sync of all repositories found on network".to_string()) |
| @@ -87,6 +94,18 @@ impl RelayInformationDocument { | |||
| 87 | } else { | 94 | } else { |
| 88 | None | 95 | None |
| 89 | } | 96 | } |
| 97 | } else if archive_enabled && repository_whitelist_enabled { | ||
| 98 | // Both archive (non-read-only) AND repository whitelist enabled | ||
| 99 | Some( | ||
| 100 | "Accepts whitelisted repositories (with or without service listing) and whitelisted repositories that list this service" | ||
| 101 | .to_string(), | ||
| 102 | ) | ||
| 103 | } else if repository_whitelist_enabled { | ||
| 104 | // Repository whitelist only | ||
| 105 | Some( | ||
| 106 | "Accepts only whitelisted repositories and maintainers that list this service" | ||
| 107 | .to_string(), | ||
| 108 | ) | ||
| 90 | } else { | 109 | } else { |
| 91 | None | 110 | None |
| 92 | }; | 111 | }; |
| @@ -230,4 +249,48 @@ mod tests { | |||
| 230 | .unwrap() | 249 | .unwrap() |
| 231 | .contains("Read-only sync of whitelisted")); | 250 | .contains("Read-only sync of whitelisted")); |
| 232 | } | 251 | } |
| 252 | |||
| 253 | #[test] | ||
| 254 | fn test_nip11_with_repository_whitelist() { | ||
| 255 | let keys = nostr_sdk::Keys::generate(); | ||
| 256 | let test_npub = keys.public_key().to_bech32().unwrap(); | ||
| 257 | let mut config = Config::for_testing(); | ||
| 258 | config.domain = "relay.example.com".to_string(); | ||
| 259 | config.repository_whitelist = format!("{},bitcoin-core", test_npub); | ||
| 260 | |||
| 261 | let doc = RelayInformationDocument::from_config(&config); | ||
| 262 | |||
| 263 | // Repository whitelist doesn't enable GRASP-05 | ||
| 264 | assert_eq!(doc.supported_grasps, vec!["GRASP-01", "GRASP-02"]); | ||
| 265 | // Should have curation field for repository whitelist | ||
| 266 | assert!(doc.curation.is_some()); | ||
| 267 | assert!(doc | ||
| 268 | .curation | ||
| 269 | .unwrap() | ||
| 270 | .contains("Accepts only whitelisted repositories")); | ||
| 271 | } | ||
| 272 | |||
| 273 | #[test] | ||
| 274 | fn test_nip11_with_archive_and_repository_whitelist() { | ||
| 275 | let keys = nostr_sdk::Keys::generate(); | ||
| 276 | let test_npub = keys.public_key().to_bech32().unwrap(); | ||
| 277 | let mut config = Config::for_testing(); | ||
| 278 | config.domain = "relay.example.com".to_string(); | ||
| 279 | config.archive_whitelist = "bitcoin-core".to_string(); | ||
| 280 | config.archive_read_only = Some(false); // Non-read-only archive mode | ||
| 281 | config.repository_whitelist = test_npub; | ||
| 282 | |||
| 283 | let doc = RelayInformationDocument::from_config(&config); | ||
| 284 | |||
| 285 | // Should have GRASP-05 enabled due to archive whitelist | ||
| 286 | assert_eq!( | ||
| 287 | doc.supported_grasps, | ||
| 288 | vec!["GRASP-01", "GRASP-05", "GRASP-02"] | ||
| 289 | ); | ||
| 290 | // Should have curation field reflecting BOTH archive and repository whitelist | ||
| 291 | assert!(doc.curation.is_some()); | ||
| 292 | let curation = doc.curation.unwrap(); | ||
| 293 | assert!(curation.contains("whitelisted repositories")); | ||
| 294 | assert!(curation.contains("with or without service listing")); | ||
| 295 | } | ||
| 233 | } | 296 | } |