use axum::{ Extension, extract, http::StatusCode, response::{Html, IntoResponse}, }; use cave::db::Database; use crate::{ http_server::ServerState, oauth, }; async fn collect_token( db: Database, http_client: &reqwest::Client, host: &str, code: String, ) -> Result<(), String> { // try a few registered apps until one works for (client_id, client_secret) in db.get_apps(host).await .map_err(|e| format!("{e}"))? { let app = oauth::Application { client_id, client_secret, }; match app.obtain_token(http_client, host, code.clone()).await { Ok(token) => { db.add_token(host, &app.client_id, &token).await .expect("db.add_token"); // success, done! return Ok(()); } Err(e) => { tracing::error!("obtain_token for {}: {}", host, e); // app seems blocked, remove let _ = db.delete_app(host, &app.client_id).await; } } } Err(format!("No registered app found for instance {host}")) } #[derive(serde::Deserialize)] pub struct OAuthCode { code: String, } pub async fn get_token_collect( Extension(ServerState { db, http_client, mut store, .. }): Extension, extract::Path(host): extract::Path, extract::Query(OAuthCode { code }): extract::Query, ) -> impl IntoResponse { match collect_token(db, &http_client, &host, code.clone()).await { Ok(()) => { let _ = store.save_host(&host).await; ( StatusCode::SEE_OTHER, [("location", "/token/thanks")] ).into_response() } Err(e) => { tracing::error!("{}", e); ( StatusCode::INTERNAL_SERVER_ERROR, [("content-type", "text/plain")], e ).into_response() } } } pub async fn get_token_thanks() -> impl IntoResponse { Html(&include_bytes!("../../templates/token_thanks.html")[..]) }