at main 1.7 kB view raw
1//! Authentication middleware. 2 3use axum::{extract::Request, http::StatusCode, middleware::Next, response::Response}; 4use tracing::warn; 5 6/// Auth middleware that checks X-Moderation-Key header for protected endpoints. 7pub async fn auth_middleware( 8 req: Request, 9 next: Next, 10 auth_token: Option<String>, 11) -> Result<Response, StatusCode> { 12 let path = req.uri().path(); 13 14 // Public endpoints - no auth required 15 // Note: /admin and /admin/review/:id serve HTML, auth is handled client-side for API calls 16 // Static files must be public for admin UI CSS/JS to load 17 let is_review_page = path.starts_with("/admin/review/") 18 && !path.ends_with("/data") 19 && !path.ends_with("/submit"); 20 if path == "/" 21 || path == "/health" 22 || path == "/sensitive-images" 23 || path == "/admin" 24 || is_review_page 25 || path.starts_with("/static/") 26 || path.starts_with("/xrpc/com.atproto.label.") 27 { 28 return Ok(next.run(req).await); 29 } 30 31 let Some(expected_token) = auth_token else { 32 warn!("no MODERATION_AUTH_TOKEN set - rejecting protected request"); 33 return Err(StatusCode::SERVICE_UNAVAILABLE); 34 }; 35 36 let token = req 37 .headers() 38 .get("X-Moderation-Key") 39 .and_then(|v| v.to_str().ok()); 40 41 match token { 42 Some(t) if t == expected_token => Ok(next.run(req).await), 43 Some(_) => { 44 warn!("invalid auth token provided"); 45 Err(StatusCode::UNAUTHORIZED) 46 } 47 None => { 48 warn!("missing X-Moderation-Key header"); 49 Err(StatusCode::UNAUTHORIZED) 50 } 51 } 52}