use axum::{ 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, headers: HeaderMap, ) -> Response { let Some(origin) = headers.get("Origin") else { return (StatusCode::BAD_REQUEST, "Missing Origin header").into_response(); }; let Some(origin) = origin .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 Some(token) = jar.get("dissociate-token") else { return (StatusCode::UNAUTHORIZED, "Authenticate cookie missing").into_response(); }; return (StatusCode::OK, token.value().to_string()).into_response(); }