diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-28 10:31:46 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-28 10:31:46 +0000 |
| commit | 744094c61d6e65892bcdb5a29b90b845ce87559f (patch) | |
| tree | 61c53f0ab93901b2b3d5378f7d13c3ac2b6dea98 /src/http | |
| parent | 4da51a8adb94f2979c0a911157f26596c1ee2cb5 (diff) | |
fix maintainer recursion
Diffstat (limited to 'src/http')
| -rw-r--r-- | src/http/mod.rs | 51 |
1 files changed, 38 insertions, 13 deletions
diff --git a/src/http/mod.rs b/src/http/mod.rs index befa006..07b47ee 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs | |||
| @@ -7,6 +7,7 @@ pub mod nip11; | |||
| 7 | use std::future::Future; | 7 | use std::future::Future; |
| 8 | use std::net::SocketAddr; | 8 | use std::net::SocketAddr; |
| 9 | use std::pin::Pin; | 9 | use std::pin::Pin; |
| 10 | use std::sync::Arc; | ||
| 10 | 11 | ||
| 11 | use hyper::body::{Bytes, Incoming}; | 12 | use hyper::body::{Bytes, Incoming}; |
| 12 | use hyper::header::{CONNECTION, SEC_WEBSOCKET_ACCEPT, UPGRADE}; | 13 | use hyper::header::{CONNECTION, SEC_WEBSOCKET_ACCEPT, UPGRADE}; |
| @@ -17,6 +18,8 @@ use hyper_util::rt::TokioIo; | |||
| 17 | use http_body_util::{BodyExt, Full}; | 18 | use http_body_util::{BodyExt, Full}; |
| 18 | use nostr_sdk::hashes::sha1::Hash as Sha1Hash; | 19 | use nostr_sdk::hashes::sha1::Hash as Sha1Hash; |
| 19 | use nostr_sdk::hashes::{Hash, HashEngine}; | 20 | use nostr_sdk::hashes::{Hash, HashEngine}; |
| 21 | use nostr_sdk::PublicKey; | ||
| 22 | use nostr_relay_builder::prelude::MemoryDatabase; | ||
| 20 | use nostr_relay_builder::LocalRelay; | 23 | use nostr_relay_builder::LocalRelay; |
| 21 | use tokio::net::TcpListener; | 24 | use tokio::net::TcpListener; |
| 22 | use base64::Engine; | 25 | use base64::Engine; |
| @@ -42,14 +45,17 @@ struct HttpService { | |||
| 42 | relay: LocalRelay, | 45 | relay: LocalRelay, |
| 43 | config: Config, | 46 | config: Config, |
| 44 | remote: SocketAddr, | 47 | remote: SocketAddr, |
| 48 | /// Database reference for direct queries (e.g., push authorization) | ||
| 49 | database: Arc<MemoryDatabase>, | ||
| 45 | } | 50 | } |
| 46 | 51 | ||
| 47 | impl HttpService { | 52 | impl HttpService { |
| 48 | fn new(relay: LocalRelay, config: Config, remote: SocketAddr) -> Self { | 53 | fn new(relay: LocalRelay, config: Config, remote: SocketAddr, database: Arc<MemoryDatabase>) -> Self { |
| 49 | Self { | 54 | Self { |
| 50 | relay, | 55 | relay, |
| 51 | config, | 56 | config, |
| 52 | remote, | 57 | remote, |
| 58 | database, | ||
| 53 | } | 59 | } |
| 54 | } | 60 | } |
| 55 | } | 61 | } |
| @@ -65,7 +71,7 @@ impl Service<Request<Incoming>> for HttpService { | |||
| 65 | let query = req.uri().query().map(|s| s.to_string()); | 71 | let query = req.uri().query().map(|s| s.to_string()); |
| 66 | let method = req.method().clone(); | 72 | let method = req.method().clone(); |
| 67 | let git_data_path = self.config.git_data_path.clone(); | 73 | let git_data_path = self.config.git_data_path.clone(); |
| 68 | let relay_domain = self.config.domain.clone(); | 74 | let database = self.database.clone(); |
| 69 | 75 | ||
| 70 | // Handle OPTIONS preflight requests (CORS) | 76 | // Handle OPTIONS preflight requests (CORS) |
| 71 | // GRASP-01 spec line 47: Respond to OPTIONS with 204 No Content | 77 | // GRASP-01 spec line 47: Respond to OPTIONS with 204 No Content |
| @@ -118,17 +124,27 @@ impl Service<Request<Incoming>> for HttpService { | |||
| 118 | git::handlers::handle_upload_pack(repo_path, body_bytes).await | 124 | git::handlers::handle_upload_pack(repo_path, body_bytes).await |
| 119 | } | 125 | } |
| 120 | 126 | ||
| 121 | // POST /git-receive-pack (push) - with GRASP authorization | 127 | // POST /git-receive-pack (push) - with GRASP authorization via database |
| 122 | (m, "git-receive-pack") if m == Method::POST => { | 128 | (m, "git-receive-pack") if m == Method::POST => { |
| 123 | // Build authorization parameters for GRASP validation | 129 | // Convert npub (bech32) to hex pubkey for authorization |
| 124 | // Use ws:// protocol for relay since we're connecting internally | 130 | let owner_pubkey_hex = match PublicKey::parse(&npub) { |
| 125 | let relay_url = format!("ws://{}", relay_domain); | 131 | Ok(pk) => pk.to_hex(), |
| 126 | let auth_params = git::handlers::PushAuthParams { | 132 | Err(e) => { |
| 127 | relay_url, | 133 | tracing::warn!("Invalid npub in URL {}: {}", npub, e); |
| 128 | owner_npub: npub.clone(), | 134 | return Ok(add_cors_headers(Response::builder()) |
| 129 | identifier: identifier.clone(), | 135 | .status(hyper::StatusCode::BAD_REQUEST) |
| 136 | .body(Full::new(Bytes::from(format!("Invalid npub: {}", e)))) | ||
| 137 | .unwrap()); | ||
| 138 | } | ||
| 130 | }; | 139 | }; |
| 131 | git::handlers::handle_receive_pack(repo_path, body_bytes.clone(), Some(auth_params)).await | 140 | |
| 141 | git::handlers::handle_receive_pack( | ||
| 142 | repo_path, | ||
| 143 | body_bytes.clone(), | ||
| 144 | Some(database.clone()), | ||
| 145 | &identifier, | ||
| 146 | &owner_pubkey_hex, | ||
| 147 | ).await | ||
| 132 | } | 148 | } |
| 133 | 149 | ||
| 134 | _ => { | 150 | _ => { |
| @@ -255,7 +271,16 @@ fn derive_accept_key(request_key: &[u8]) -> String { | |||
| 255 | } | 271 | } |
| 256 | 272 | ||
| 257 | /// Start the HTTP server with integrated Nostr relay | 273 | /// Start the HTTP server with integrated Nostr relay |
| 258 | pub async fn run_server(config: Config, relay: LocalRelay) -> anyhow::Result<()> { | 274 | /// |
| 275 | /// # Arguments | ||
| 276 | /// * `config` - Server configuration | ||
| 277 | /// * `relay` - The LocalRelay for WebSocket connections | ||
| 278 | /// * `database` - The database for direct queries (e.g., push authorization) | ||
| 279 | pub async fn run_server( | ||
| 280 | config: Config, | ||
| 281 | relay: LocalRelay, | ||
| 282 | database: Arc<MemoryDatabase>, | ||
| 283 | ) -> anyhow::Result<()> { | ||
| 259 | let bind_addr: SocketAddr = config.bind_address.parse()?; | 284 | let bind_addr: SocketAddr = config.bind_address.parse()?; |
| 260 | 285 | ||
| 261 | tracing::info!("Starting HTTP server on {}", bind_addr); | 286 | tracing::info!("Starting HTTP server on {}", bind_addr); |
| @@ -267,7 +292,7 @@ pub async fn run_server(config: Config, relay: LocalRelay) -> anyhow::Result<()> | |||
| 267 | loop { | 292 | loop { |
| 268 | let (socket, addr) = listener.accept().await?; | 293 | let (socket, addr) = listener.accept().await?; |
| 269 | let io = TokioIo::new(socket); | 294 | let io = TokioIo::new(socket); |
| 270 | let service = HttpService::new(relay.clone(), config.clone(), addr); | 295 | let service = HttpService::new(relay.clone(), config.clone(), addr, database.clone()); |
| 271 | 296 | ||
| 272 | tokio::spawn(async move { | 297 | tokio::spawn(async move { |
| 273 | if let Err(e) = http1::Builder::new() | 298 | if let Err(e) = http1::Builder::new() |