You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

102 lines
2.8 KiB

//! 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<std::net::IpAddr, _>| 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/<req_id>/pw/<passwd hash> - Respond to an auth ID with a hashed password, salted with the salt obtained from the req call.
// /auth/resp/<req_id>/si[/<num of sigs in body>] - 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/<req_id>/pw/<passwd hash>
// /resp/<req_id>/si[/<num of sigs in body>]
resp
};
warp::path("auth")
.and(req.or(resp))
.recover(auth::AuthError::recover)
};
todo!()
}