diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-28 12:40:31 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-28 12:40:31 +0000 |
| commit | b94262161df99966fbb8aa6861fb46603039111f (patch) | |
| tree | f0194656783d05263be2d940f4e182b1bec75070 /src/git/handlers.rs | |
| parent | bf51a082ad54815f108bb255cf258fcae4a9bb4f (diff) | |
allow push to ref/nostr/<event-id>
Diffstat (limited to 'src/git/handlers.rs')
| -rw-r--r-- | src/git/handlers.rs | 35 |
1 files changed, 34 insertions, 1 deletions
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; | |||
| 7 | use hyper::{body::Bytes, Response, StatusCode}; | 7 | use hyper::{body::Bytes, Response, StatusCode}; |
| 8 | use http_body_util::Full; | 8 | use http_body_util::Full; |
| 9 | use nostr_relay_builder::prelude::MemoryDatabase; | 9 | use nostr_relay_builder::prelude::MemoryDatabase; |
| 10 | use nostr_sdk::EventId; | ||
| 10 | use tokio::io::{AsyncReadExt, AsyncWriteExt}; | 11 | use tokio::io::{AsyncReadExt, AsyncWriteExt}; |
| 11 | use tracing::{debug, error, info, warn}; | 12 | use 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 { |