upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/git
diff options
context:
space:
mode:
Diffstat (limited to 'src/git')
-rw-r--r--src/git/authorization.rs53
1 files changed, 36 insertions, 17 deletions
diff --git a/src/git/authorization.rs b/src/git/authorization.rs
index 2fe81b0..e9f59c7 100644
--- a/src/git/authorization.rs
+++ b/src/git/authorization.rs
@@ -17,7 +17,7 @@
17use anyhow::{anyhow, Result}; 17use anyhow::{anyhow, Result};
18use nostr_sdk::{Event, Filter, Kind, PublicKey, SingleLetterTag, Timestamp, ToBech32, Alphabet}; 18use nostr_sdk::{Event, Filter, Kind, PublicKey, SingleLetterTag, Timestamp, ToBech32, Alphabet};
19use std::collections::HashSet; 19use std::collections::HashSet;
20use tracing::{debug, warn}; 20use tracing::debug;
21 21
22use crate::nostr::events::{ 22use crate::nostr::events::{
23 RepositoryAnnouncement, RepositoryState, KIND_REPOSITORY_ANNOUNCEMENT, KIND_REPOSITORY_STATE, 23 RepositoryAnnouncement, RepositoryState, KIND_REPOSITORY_ANNOUNCEMENT, KIND_REPOSITORY_STATE,
@@ -128,40 +128,59 @@ impl AuthorizationContext {
128 /// - getMaintainers(alice) -> [alice, bob, charlie] 128 /// - getMaintainers(alice) -> [alice, bob, charlie]
129 /// - getMaintainers(bob) -> [bob, charlie] (bob doesn't have alice's trust) 129 /// - getMaintainers(bob) -> [bob, charlie] (bob doesn't have alice's trust)
130 pub fn get_maintainers(&self, pubkey: &str, identifier: &str) -> Vec<String> { 130 pub fn get_maintainers(&self, pubkey: &str, identifier: &str) -> Vec<String> {
131 let mut checked: HashSet<String> = HashSet::new(); 131 let mut visited: HashSet<String> = HashSet::new();
132 self.get_maintainers_recursive(pubkey, identifier, &mut checked); 132 let mut maintainers: HashSet<String> = HashSet::new();
133 self.get_maintainers_recursive(pubkey, identifier, &mut visited, &mut maintainers);
133 134
134 checked.into_iter().collect() 135 maintainers.into_iter().collect()
135 } 136 }
136 137
137 /// Recursive helper for get_maintainers 138 /// Recursive helper for get_maintainers
139 ///
140 /// The key insight is that a pubkey is a valid maintainer if:
141 /// 1. They have their own accepted announcement for this repo, OR
142 /// 2. They are listed in the "maintainers" tag of an accepted announcement
143 ///
144 /// This allows maintainers to publish state events without needing their own
145 /// announcement - they're authorized by being listed in the owner's announcement.
146 ///
147 /// We use separate sets:
148 /// - `visited`: Tracks which pubkeys we've already processed (cycle prevention)
149 /// - `maintainers`: The result set of valid maintainers
138 fn get_maintainers_recursive( 150 fn get_maintainers_recursive(
139 &self, 151 &self,
140 pubkey: &str, 152 pubkey: &str,
141 identifier: &str, 153 identifier: &str,
142 checked: &mut HashSet<String>, 154 visited: &mut HashSet<String>,
155 maintainers: &mut HashSet<String>,
143 ) { 156 ) {
144 // Skip if already processed 157 // Skip if already visited (prevents infinite loops)
145 if checked.contains(pubkey) { 158 if visited.contains(pubkey) {
146 return; 159 return;
147 } 160 }
161 visited.insert(pubkey.to_string());
148 162
149 // Find the announcement event for this pubkey 163 // Find the announcement event for this pubkey
150 let announcement = self.find_announcement_by_pubkey(pubkey, identifier); 164 let announcement = self.find_announcement_by_pubkey(pubkey, identifier);
151 if announcement.is_none() {
152 return;
153 }
154 165
155 // Mark this pubkey as checked (they have a valid announcement) 166 if let Some(announcement) = announcement {
156 checked.insert(pubkey.to_string()); 167 // This pubkey has an announcement - they are a valid maintainer
168 maintainers.insert(pubkey.to_string());
157 169
158 let announcement = announcement.unwrap(); 170 // Get maintainers listed in this announcement (maintainers tag)
171 // These are ALSO valid maintainers, even without their own announcement
172 for maintainer_pubkey in &announcement.maintainers {
173 // Add them to the maintainer set immediately - they're authorized
174 // by being listed in an accepted announcement
175 maintainers.insert(maintainer_pubkey.clone());
159 176
160 // Get maintainers listed in this announcement (p tags) 177 // Recursively check if they have their own announcement
161 for maintainer_pubkey in &announcement.maintainers { 178 // to get any maintainers THEY list (recursive maintainer chain)
162 // Recursively process each listed maintainer 179 self.get_maintainers_recursive(maintainer_pubkey, identifier, visited, maintainers);
163 self.get_maintainers_recursive(maintainer_pubkey, identifier, checked); 180 }
164 } 181 }
182 // If no announcement found, they can still be valid if they were
183 // added to maintainers by their parent caller
165 } 184 }
166 185
167 /// Find a repository announcement event by pubkey and identifier 186 /// Find a repository announcement event by pubkey and identifier