upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/nostr
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-21 05:18:15 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-21 05:34:56 +0000
commit7a81643367515a9d01eb2d4deb623e9a7c071a12 (patch)
tree88d6f2e69ca051d2c94269f4753e2ef807882438 /src/nostr
parent7dda553918705277c7fa5b903c6a40e4b4a0aa8d (diff)
add repository creation
Diffstat (limited to 'src/nostr')
-rw-r--r--src/nostr/builder.rs83
1 files changed, 74 insertions, 9 deletions
diff --git a/src/nostr/builder.rs b/src/nostr/builder.rs
index 547db8e..259c380 100644
--- a/src/nostr/builder.rs
+++ b/src/nostr/builder.rs
@@ -3,7 +3,7 @@
3/// This module integrates nostr-relay-builder with NIP-34 validation logic 3/// This module integrates nostr-relay-builder with NIP-34 validation logic
4/// preserved from the original implementation. 4/// preserved from the original implementation.
5use std::net::SocketAddr; 5use std::net::SocketAddr;
6use std::path::Path; 6use std::path::{Path, PathBuf};
7use std::sync::Arc; 7use std::sync::Arc;
8 8
9use nostr::nips::nip19::ToBech32; 9use nostr::nips::nip19::ToBech32;
@@ -13,7 +13,7 @@ use nostr_relay_builder::prelude::*;
13 13
14use crate::config::{Config, DatabaseBackend}; 14use crate::config::{Config, DatabaseBackend};
15use crate::nostr::events::{ 15use crate::nostr::events::{
16 validate_announcement, validate_state, KIND_REPOSITORY_ANNOUNCEMENT, KIND_REPOSITORY_STATE, 16 validate_announcement, validate_state, RepositoryAnnouncement, KIND_REPOSITORY_ANNOUNCEMENT, KIND_REPOSITORY_STATE,
17}; 17};
18 18
19/// NIP-34 Write Policy with Full GRASP-01 Event Validation 19/// NIP-34 Write Policy with Full GRASP-01 Event Validation
@@ -30,16 +30,53 @@ use crate::nostr::events::{
30pub struct Nip34WritePolicy { 30pub struct Nip34WritePolicy {
31 domain: String, 31 domain: String,
32 database: Arc<MemoryDatabase>, 32 database: Arc<MemoryDatabase>,
33 git_data_path: PathBuf,
33} 34}
34 35
35impl Nip34WritePolicy { 36impl Nip34WritePolicy {
36 pub fn new(domain: impl Into<String>, database: Arc<MemoryDatabase>) -> Self { 37 pub fn new(domain: impl Into<String>, database: Arc<MemoryDatabase>, git_data_path: impl Into<PathBuf>) -> Self {
37 Self { 38 Self {
38 domain: domain.into(), 39 domain: domain.into(),
39 database, 40 database,
41 git_data_path: git_data_path.into(),
40 } 42 }
41 } 43 }
42 44
45 /// Create a bare git repository if it doesn't exist
46 /// Path format: <git_data_path>/<npub>/<identifier>.git
47 fn ensure_bare_repository(&self, announcement: &RepositoryAnnouncement) -> Result<(), String> {
48 let repo_path = self.git_data_path.join(&announcement.repo_path());
49
50 // Check if repository already exists
51 if repo_path.exists() {
52 tracing::debug!("Repository already exists at {}", repo_path.display());
53 return Ok(());
54 }
55
56 // Create parent directory (npub directory)
57 let parent = repo_path.parent().ok_or_else(|| {
58 format!("Invalid repository path: {}", repo_path.display())
59 })?;
60
61 std::fs::create_dir_all(parent).map_err(|e| {
62 format!("Failed to create directory {}: {}", parent.display(), e)
63 })?;
64
65 // Initialize bare repository using git command
66 let output = std::process::Command::new("git")
67 .args(&["init", "--bare", repo_path.to_str().unwrap()])
68 .output()
69 .map_err(|e| format!("Failed to execute git init: {}", e))?;
70
71 if !output.status.success() {
72 let stderr = String::from_utf8_lossy(&output.stderr);
73 return Err(format!("git init failed: {}", stderr));
74 }
75
76 tracing::info!("Created bare repository at {}", repo_path.display());
77 Ok(())
78 }
79
43 /// Extract all reference tags from an event (a, A, q, e, E) 80 /// Extract all reference tags from an event (a, A, q, e, E)
44 /// Returns (addressable_refs, event_refs) 81 /// Returns (addressable_refs, event_refs)
45 fn extract_reference_tags(event: &Event) -> (Vec<String>, Vec<EventId>) { 82 fn extract_reference_tags(event: &Event) -> (Vec<String>, Vec<EventId>) {
@@ -269,11 +306,35 @@ impl WritePolicy for Nip34WritePolicy {
269 match event.kind.as_u16() { 306 match event.kind.as_u16() {
270 KIND_REPOSITORY_ANNOUNCEMENT => match validate_announcement(event, &domain) { 307 KIND_REPOSITORY_ANNOUNCEMENT => match validate_announcement(event, &domain) {
271 Ok(_) => { 308 Ok(_) => {
272 tracing::debug!( 309 // Parse announcement to get repository details
273 "Accepted repository announcement: {}", 310 match RepositoryAnnouncement::from_event(event.clone()) {
274 event_id_str 311 Ok(announcement) => {
275 ); 312 // Try to create bare repository if it doesn't exist
276 PolicyResult::Accept 313 if let Err(e) = self.ensure_bare_repository(&announcement) {
314 tracing::warn!(
315 "Failed to create bare repository for {}: {}",
316 event_id_str,
317 e
318 );
319 // Note: We still accept the event even if repo creation fails
320 // The git operation failure shouldn't prevent event acceptance
321 }
322
323 tracing::debug!(
324 "Accepted repository announcement: {}",
325 event_id_str
326 );
327 PolicyResult::Accept
328 }
329 Err(e) => {
330 tracing::warn!(
331 "Failed to parse repository announcement {}: {}",
332 event_id_str,
333 e
334 );
335 PolicyResult::Reject(format!("Failed to parse announcement: {}", e))
336 }
337 }
277 } 338 }
278 Err(e) => { 339 Err(e) => {
279 tracing::warn!( 340 tracing::warn!(
@@ -432,7 +493,11 @@ pub fn create_relay(config: &Config) -> Result<LocalRelay> {
432 // Clone Arc for the write policy so both relay and policy can access the database 493 // Clone Arc for the write policy so both relay and policy can access the database
433 let builder = RelayBuilder::default() 494 let builder = RelayBuilder::default()
434 .database(database.clone()) 495 .database(database.clone())
435 .write_policy(Nip34WritePolicy::new(&config.domain, database.clone())); 496 .write_policy(Nip34WritePolicy::new(
497 &config.domain,
498 database.clone(),
499 &config.git_data_path,
500 ));
436 501
437 tracing::info!( 502 tracing::info!(
438 "Relay configured with GRASP-01 validation for domain: {}", 503 "Relay configured with GRASP-01 validation for domain: {}",