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:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-28 12:40:31 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-28 12:40:31 +0000
commitb94262161df99966fbb8aa6861fb46603039111f (patch)
treef0194656783d05263be2d940f4e182b1bec75070 /src/git
parentbf51a082ad54815f108bb255cf258fcae4a9bb4f (diff)
allow push to ref/nostr/<event-id>
Diffstat (limited to 'src/git')
-rw-r--r--src/git/authorization.rs18
-rw-r--r--src/git/handlers.rs35
2 files changed, 50 insertions, 3 deletions
diff --git a/src/git/authorization.rs b/src/git/authorization.rs
index 1be3de9..bb3bd01 100644
--- a/src/git/authorization.rs
+++ b/src/git/authorization.rs
@@ -29,7 +29,7 @@
29 29
30use anyhow::{anyhow, Result}; 30use anyhow::{anyhow, Result};
31use nostr_relay_builder::prelude::*; 31use nostr_relay_builder::prelude::*;
32use nostr_sdk::ToBech32; 32use nostr_sdk::{EventId, ToBech32};
33use std::collections::{HashMap, HashSet}; 33use std::collections::{HashMap, HashSet};
34use std::sync::Arc; 34use std::sync::Arc;
35use tracing::debug; 35use tracing::debug;
@@ -647,7 +647,21 @@ pub fn validate_push_refs(
647 647
648 // refs/nostr/* is handled separately per GRASP-01 648 // refs/nostr/* is handled separately per GRASP-01
649 if ref_name.starts_with("refs/nostr/") { 649 if ref_name.starts_with("refs/nostr/") {
650 debug!("refs/nostr/ push will be validated separately"); 650 // Extract event_id from "refs/nostr/<event-id>"
651 if let Some(event_id_str) = ref_name.strip_prefix("refs/nostr/") {
652 // Validate it parses as a valid EventId
653 if EventId::parse(event_id_str).is_err() {
654 return Err(anyhow!(
655 "Invalid event ID format in ref: {}. Expected valid nostr event ID.",
656 ref_name
657 ));
658 }
659 // Valid EventId format - allow push (skip state event check)
660 debug!("refs/nostr/{} push authorized (valid EventId)", event_id_str);
661 continue; // Skip the rest of ref validation for this ref
662 } else {
663 return Err(anyhow!("Invalid refs/nostr/ format: {}", ref_name));
664 }
651 } 665 }
652 } 666 }
653 667
diff --git a/src/git/handlers.rs b/src/git/handlers.rs
index 7974d8a..23d4b5b 100644
--- a/src/git/handlers.rs
+++ b/src/git/handlers.rs
@@ -7,6 +7,7 @@ use std::sync::Arc;
7use hyper::{body::Bytes, Response, StatusCode}; 7use hyper::{body::Bytes, Response, StatusCode};
8use http_body_util::Full; 8use http_body_util::Full;
9use nostr_relay_builder::prelude::MemoryDatabase; 9use nostr_relay_builder::prelude::MemoryDatabase;
10use nostr_sdk::EventId;
10use tokio::io::{AsyncReadExt, AsyncWriteExt}; 11use tokio::io::{AsyncReadExt, AsyncWriteExt};
11use tracing::{debug, error, info, warn}; 12use tracing::{debug, error, info, warn};
12 13
@@ -315,7 +316,39 @@ async fn authorize_push(
315 identifier, owner_pubkey 316 identifier, owner_pubkey
316 ); 317 );
317 318
318 // Get authorization result from database, scoped to specific owner 319 // Parse refs from the push request FIRST to check if this is a refs/nostr/ push
320 let pushed_refs = parse_pushed_refs(request_body);
321 debug!("Parsed {} refs from push request", pushed_refs.len());
322 for (old_oid, new_oid, ref_name) in &pushed_refs {
323 debug!(" {} {} -> {}", ref_name, old_oid, new_oid);
324 }
325
326 // Check if ALL pushed refs are to refs/nostr/ with valid EventId format
327 // Per GRASP-01: "MUST accept pushes via this service to `refs/nostr/<event-id>`"
328 // These pushes only require EventId format validation, not state validation
329 let all_refs_nostr_valid = !pushed_refs.is_empty()
330 && pushed_refs.iter().all(|(_, _, ref_name)| {
331 if let Some(event_id_str) = ref_name.strip_prefix("refs/nostr/") {
332 // Validate it parses as a valid EventId
333 EventId::parse(event_id_str).is_ok()
334 } else {
335 false
336 }
337 });
338
339 if all_refs_nostr_valid {
340 debug!("All refs are refs/nostr/ with valid EventId format - authorized without state check");
341 // Return success for refs/nostr/ pushes without requiring state
342 return Ok(AuthorizationResult {
343 authorized: true,
344 reason: "Push to refs/nostr/ with valid EventId format".to_string(),
345 state: None,
346 maintainers: vec![],
347 });
348 }
349
350 // For non-refs/nostr/ pushes, require state validation as normal
351 debug!("Non-refs/nostr/ push detected - checking state authorization");
319 let auth_result = get_authorization_for_owner(database, identifier, owner_pubkey).await?; 352 let auth_result = get_authorization_for_owner(database, identifier, owner_pubkey).await?;
320 353
321 if !auth_result.authorized { 354 if !auth_result.authorized {