From d60fa03de6edae0667a93ac36be4206e76255a2c Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 26 May 2026 22:07:55 +0530 Subject: Add NIP-46 remote signing for kind:30618 state events - nip46.rs: full NIP-46 client with session management, NIP-04 encrypted relay-based communication, oneshot response awaiting - db.rs: nip46_sessions table, upsert/get methods - config.rs: Nip46Config with relays + signing_timeout_secs - git_mirror.rs: builds unsigned kind:30618 state event from bare repo refs, signs via NIP-46 before push, publishes to target server relay - http_health.rs: exposes NIP-46 session status in health endpoint - main.rs: wires NIP-46 client into daemon startup, passes to mirror_cycle --- src/main.rs | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs index 3fcd27b..8e1383e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod discovery; mod git_mirror; mod health; mod http_health; +mod nip46; mod nostr_mirror; mod signing; @@ -71,14 +72,50 @@ async fn run_daemon(config: config::ResolvedConfig, db: db::MirrorDb) -> Result< let db = Arc::new(db); let config = Arc::new(config); + let nip46_client = if let Some(ref nip46_cfg) = config.nip46 { + let client = nip46::Nip46Client::new( + nip46_cfg.relays.clone(), + nip46_cfg.signing_timeout_secs, + db.clone(), + ) + .await?; + + client.init_sessions(&config.npubs).await?; + client.start_listener().await; + + for status in client.get_status().await { + tracing::info!( + npub = %status.npub, + connected = status.connected, + "NIP-46 session status" + ); + if !status.connected { + if let Some(uri) = &status.pairing_uri { + tracing::info!( + npub = %status.npub, + uri = %uri, + "Pair this npub by opening the nostrconnect URI in Amber" + ); + } + } + } + + Some(Arc::new(client)) + } else { + tracing::warn!("no [nip46] config — remote signing disabled"); + None + }; + let (cycle_count_tx, cycle_count_rx) = tokio::sync::watch::channel(0u64); let (last_cycle_ok_tx, last_cycle_ok_rx) = tokio::sync::watch::channel(true); + let nip46_status = nip46_client.clone(); let health_state = Arc::new(http_health::HealthState { started_at: std::time::Instant::now(), cycle_count: cycle_count_rx, last_cycle_ok: last_cycle_ok_rx, db_path: config.storage.database.display().to_string(), + nip46_client: nip46_status, }); let health_port = config.storage.health_port; @@ -111,6 +148,8 @@ async fn run_daemon(config: config::ResolvedConfig, db: db::MirrorDb) -> Result< let mirror = git_mirror::GitMirror::new(&config.storage.mirror_dir); let nostr_mirror = nostr_mirror::NostrMirror::new(nostr_client.clone()); + let nip46_client_ref: Option> = nip46_client.clone(); + let mut interval = tokio::time::interval(std::time::Duration::from_secs( config.discovery.poll_interval_secs, )); @@ -132,6 +171,7 @@ async fn run_daemon(config: config::ResolvedConfig, db: db::MirrorDb) -> Result< &mirror, &nostr_mirror, &healthy, + nip46_client_ref.as_ref(), ).await; match &result { @@ -160,6 +200,7 @@ async fn mirror_cycle( mirror: &git_mirror::GitMirror, nostr_mirror: &nostr_mirror::NostrMirror, servers: &Arc>, + nip46_client: Option<&Arc>, ) -> Result<()> { tracing::info!("starting mirror cycle"); @@ -190,7 +231,7 @@ async fn mirror_cycle( "mirroring to missing servers" ); - if let Err(e) = mirror.mirror_repo_to_servers(db, repo, &missing).await { + if let Err(e) = mirror.mirror_repo_to_servers(db, repo, &missing, nip46_client).await { tracing::error!(identifier = %repo.identifier, error = %e, "git mirror failed for repo, continuing"); } @@ -310,6 +351,7 @@ async fn run_mirror_once(config: config::ResolvedConfig, db: db::MirrorDb) -> Re &mirror, &nostr_mirror, &healthy, + None, ) .await } -- cgit v1.2.3