use std::net::SocketAddr; use actix::prelude::*; use git_next_config::RepoAlias; use tracing::{info, warn}; use warp::reject::Rejection; use crate::actors::{repo::webhook::WebhookAuth, webhook::message::WebhookMessage}; use super::message; pub async fn start( socket_addr: SocketAddr, address: actix::prelude::Recipient, ) { // start webhook server use warp::Filter; // Define the Warp route to handle incoming HTTP requests let route = warp::post() .map(move || address.clone()) .and(warp::path::param()) // .and(warp::query::raw()) .and(warp::header::headers_cloned()) .and(warp::body::bytes()) .and_then( |recipient: Recipient, path: String, // query: String, headers: warp::http::HeaderMap, body: bytes::Bytes| async move { info!("POST received"); let repo_alias = RepoAlias::new(path); let bytes = body.to_vec(); let body = message::Body::new(String::from_utf8_lossy(&bytes).to_string()); headers.get("Authorization").map_or_else( || { warn!("No Authorization header"); Err(warp::reject()) }, |authorisation_header| { info!(?repo_alias, ?authorisation_header, "Received webhook",); match parse_auth(authorisation_header) { Ok(authorisation) => { let message = WebhookMessage::new(repo_alias, authorisation, body); recipient .try_send(message) .map(|_| { info!("Message sent ok"); warp::reply::with_status("OK", warp::http::StatusCode::OK) }) .map_err(|e| { warn!("Unknown error: {:?}", e); warp::reject() }) } Err(e) => { warn!(?e, "Failed to decode authorization header"); Err(warp::reject()) } } }, ) }, ); // Start the server info!("Starting webhook server: {}", socket_addr); warp::serve(route).run(socket_addr).await; } fn parse_auth(authorization_header: &warp::http::HeaderValue) -> Result { WebhookAuth::from_str( authorization_header .to_str() .map_err(|e| { warn!("Invalid non-ascii value in authorization: {:?}", e); warp::reject() }) // valid characters .map(|v| { info!("raw auth header: {}", v); v })? .strip_prefix("Basic ") .ok_or_else(|| { warn!("Authorization must be 'Basic'"); warp::reject() })?, // must start with "Basic " ) .map_err(|e| { warn!(?e, "decode error"); warp::reject() }) }