use authdb::{AuthDB, AuthError, AuthToken, SessionToken, Username}; use std::{ convert::Infallible, net::{IpAddr, Ipv4Addr, SocketAddr}, path::PathBuf, sync::Arc, }; use warp::{ header, http::StatusCode, reply::{Json, Reply}, Filter, }; mod handlers; use handlers::handle_auth; #[derive(Debug)] struct Unauthorized; impl warp::reject::Reject for Unauthorized {} #[derive(Debug)] struct AuthDBError(AuthError); impl warp::reject::Reject for AuthDBError {} fn with_session( auth_ctx: Arc, ) -> impl Filter + Clone { header("authentication").and_then({ move |value: String| { let auth_ctx = auth_ctx.clone(); async move { match auth_ctx.validate_session(SessionToken::from(value)).await { Ok(Some(username)) => Ok(username), Ok(None) => Err(warp::reject::custom(Unauthorized)), Err(err) => Err(warp::reject::custom(AuthDBError(err))), } } } }) } fn route_echo_unauthenticated() -> impl Filter + Clone { warp::path!("api" / "v1" / "echo" / String).map(|param: String| { println!("param: {}", param); warp::reply::json(&vec!["unauthenticated", param.as_str()]) }) } fn route_authenticate( auth_ctx: Arc, ) -> impl Filter + Clone { let auth_ctx = auth_ctx.clone(); warp::path!("api" / "v1" / "auth") .and(warp::post()) .and(warp::body::json()) .map(move |param: AuthToken| { let res = handle_auth(&auth_ctx, param.clone()); warp::reply::json(¶m) }) } fn route_echo_authenticated( auth_ctx: Arc, ) -> impl Filter + Clone { warp::path!("api" / "v1" / "echo" / String) .and(with_session(auth_ctx.clone())) .map(move |param: String, username: Username| { println!("param: {:?}", username); println!("param: {}", param); warp::reply::json(&vec!["authenticated", username.as_str(), param.as_str()]) }) } async fn handle_rejection(err: warp::Rejection) -> Result { if let Some(Unauthorized) = err.find() { Ok(warp::reply::with_status( "".to_owned(), StatusCode::UNAUTHORIZED, )) } else { Ok(warp::reply::with_status( "".to_owned(), StatusCode::INTERNAL_SERVER_ERROR, )) } } #[tokio::main] pub async fn main() { let auth_db = AuthDB::new(PathBuf::from("./auth_db.sqlite")) .await .expect("AuthDB should initialize"); let auth_ctx: Arc = Arc::new(auth_db); let filter = route_echo_authenticated(auth_ctx.clone()) .or(route_authenticate(auth_ctx.clone())) .or(route_echo_unauthenticated()) .recover(handle_rejection); let server = warp::serve(filter); server .run(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8001)) .await; }