use std::net::Ipv6Addr; use axum::{ extract::Query, http::StatusCode, response::IntoResponse, routing::{get, post}, Form, Json, Router, }; use secrecy::ExposeSecret; use serde::{Deserialize, Serialize}; use tracing::{event, instrument, Level}; use crate::auth::{AuthenticationError, UserServerKeyGenerator}; use crate::secrets::{Password, ServerHash, UserToken}; #[instrument] pub async fn run(port: u16) -> color_eyre::Result<()> { let app = Router::new() .route("/tls-check/success", get(|| async { "OK" })) .route("/api-login", post(api_login)) .route( "/generate-user-server-key-2", post(generate_user_server_key_2), ); let listener = tokio::net::TcpListener::bind((Ipv6Addr::UNSPECIFIED, port)).await?; axum::serve(listener, app).await?; Ok(()) } #[derive(Debug, Clone, PartialEq, Eq, Serialize)] struct ApiError { #[serde(skip_serializing)] status: StatusCode, error: String, message: String, } impl From for ApiError { fn from(err: AuthenticationError) -> Self { Self { status: StatusCode::UNAUTHORIZED, error: "authentication-failed".to_owned(), message: err.to_string(), } } } impl IntoResponse for ApiError { fn into_response(self) -> axum::response::Response { (self.status, Json(self)).into_response() } } type ApiResult = Result; #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] struct ApiVersion { api_version: String, } #[derive(Debug, Clone, Deserialize)] struct LoginRequest { username: String, password: Password, } #[derive(Debug, Clone, Serialize)] struct LoginResponse { username: String, token: String, } #[instrument] async fn api_login( Query(ApiVersion { api_version }): Query, Form(LoginRequest { username, password }): Form, ) -> ApiResult> { event!(Level::WARN, "Creating dummy token"); let user_token = UserToken("invalid".to_owned().into()); Ok(Json(LoginResponse { username, token: user_token.0.expose_secret().to_owned(), })) } #[derive(Debug, Clone, Deserialize)] struct UserServerKeyRequest { username: String, token: UserToken, server_hash: ServerHash, } #[derive(Debug, Clone, Serialize)] struct UserServerKeyResponse { server_key: String, server_key_timestamp: String, } #[instrument] async fn generate_user_server_key_2( Query(ApiVersion { api_version }): Query, Form(UserServerKeyRequest { username, token, server_hash, }): Form, ) -> ApiResult> { event!(Level::WARN, "Creating dummy user_server_key"); let generator: UserServerKeyGenerator = todo!(); let (server_key, server_key_timestamp) = generator .generate_user_server_key(&username, &token, &server_hash) .await?; Ok(Json(UserServerKeyResponse { server_key: server_key.0.expose_secret().to_owned(), server_key_timestamp, })) }