use std::time::SystemTime; use axum::{ body::Body, extract::{Path, State}, http::{HeaderMap, StatusCode, Uri}, response::{IntoResponse, Response}, routing::get, Router, }; use axum_extra::extract::CookieJar; use crate::server::store::Store; use super::{ApiState, Handoffs}; pub fn bind(app: Router) -> Router { app.route("/check/:token/:scope", get(check_)) .route("/handoff", get(handoff)) } #[axum::debug_handler(state = ApiState)] async fn check_( Path((token, scope)): Path<(String, String)>, State(store): State, ) -> Response { let Some((name, _)) = store.check_token(&token).await else { return StatusCode::UNAUTHORIZED.into_response(); }; let Some(account) = store.get_account(&name).await else { return StatusCode::UNAUTHORIZED.into_response(); }; if account.scopes.contains(&scope) { StatusCode::OK.into_response() } else { StatusCode::FORBIDDEN.into_response() } } #[axum::debug_handler(state = ApiState)] async fn handoff( jar: CookieJar, State(Handoffs(handoffs)): State, State(store): State, headers: HeaderMap, ) -> Response { let Some(origin_header) = headers.get("Origin") else { return (StatusCode::BAD_REQUEST, "Missing Origin header").into_response(); }; let Some(origin) = origin_header .to_str() .ok() .and_then(|origin| origin.parse::().ok()) .and_then(|origin| origin.host().map(ToString::to_string)) else { return (StatusCode::BAD_REQUEST, "Malformed Origin header").into_response(); }; if !handoffs.contains(&origin) { return (StatusCode::FORBIDDEN, "Origin not registered for handoff").into_response(); } let builder = Response::builder() .header("Access-Control-Allow-Credentials", "true") .header("Access-Control-Allow-Origin", origin_header); if let Some(token) = jar.get("dissociate-token") { if let Some((_, expires)) = store.check_token(token.value()).await { let expires_in = expires .duration_since(SystemTime::now()) .unwrap_or_default() .as_secs(); return builder .status(StatusCode::OK) .body(Body::from(format!( r#"{{"token":"{}","expiresIn":{}}}"#, token.value().to_string(), expires_in, ))) .unwrap(); } } builder .status(StatusCode::UNAUTHORIZED) .body(Body::empty()) .unwrap() }