//! datse server over HTTP use super::*; use warp::{ Filter, hyper::body::Bytes, }; use std::{ str, sync::Arc, convert::Infallible, }; use cryptohelpers::{ sha256, rsa, }; use state::State; use uuid::Uuid; use server::state::ServerState; use settings::Settings; /// Web server config #[derive(Debug, Clone, PartialEq, Eq)] pub struct Config { } pub mod settings; mod state; mod source; mod forwarded_list; mod auth; /// Main entry point for web server pub async fn main(state: ServerState, cfg: Settings) -> eyre::Result<()> { let state = Arc::new(State::new(state, cfg.clone())); let state = warp::any().map(move || state.clone()); // Extract the client IP or fail with custom rejection let client_ip = warp::addr::remote() .and(warp::header("X-Forwarded-For")) .map(source::extract(cfg.trust_x_forwarded_for)) .and_then(|req: Result| async move {req.map_err(warp::reject::custom)}); // /auth/req - Request an auth ID and information about how to respond (data to sign / password salt / what is supported, etc) // /auth/resp//pw/ - Respond to an auth ID with a hashed password, salted with the salt obtained from the req call. // /auth/resp//si[/] - Respond to an auth ID with one or more signatures of the data to be signed obtained in the auth request. If no number is provided, 1 is assumed. let auth = { let req = warp::path("req") .and(client_ip.clone()).and(state.clone()) .and_then(auth::auth_req); let resp = { let resp_auth_with_state = warp::post() .and(client_ip.clone()).and(state.clone()) .and(warp::path::param().map(|req_id: uuid::Uuid| req_id)); let resp_auth_key = resp_auth_with_state.clone() .and(warp::path("si") .and(warp::path::param().map(|num: usize| std::cmp::min(std::cmp::max(1, num), cfg.max_key_sigs_per_auth_response)) .or(warp::path::end().map(|| 1usize)).unify())) .and(warp::body::content_length_limit(cfg.max_body_len.0)) .and(warp::body::bytes()) .and_then(auth::auth_key); // -- Paths -- let resp_auth_pass = { let pw_path = resp_auth_with_state .and(warp::path("pw")); if cfg.allow_passwd_auth { pw_path.and(warp::path::param().map(|hash: auth::Sha256Hash| hash.0)) .and(warp::path::end()) .and_then(auth::auth_pass).boxed() } else { pw_path.and_then(|_addr, _state, _hash| async move {Err(warp::reject::not_found())}).boxed() } }; let resp = warp::path("resp") .and(resp_auth_key .or(resp_auth_pass)); // /resp//pw/ // /resp//si[/] resp }; warp::path("auth") .and(req.or(resp)) .recover(auth::AuthError::recover) }; todo!() }