diff --git a/Cargo.lock b/Cargo.lock index 8fb00e3..28cfe90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,6 +231,7 @@ dependencies = [ "lazy_static", "log", "pretty_env_logger", + "serde", "tokio", "uuid", "warp", diff --git a/Cargo.toml b/Cargo.toml index 497dc55..b255fc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ futures = "0.3.8" lazy_static = "1.4.0" log = "0.4.11" pretty_env_logger = "0.4.0" +serde = {version = "1.0", features = ["derive"]} tokio = {version = "0.2", features = ["full"]} uuid = {version = "0.8.1", features = ["v4","serde"]} warp = "0.2.5" diff --git a/src/main.rs b/src/main.rs index 4e25779..a05d275 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ #![allow(dead_code)] +#![allow(unused_imports)] #[macro_use] extern crate log; @@ -15,6 +16,10 @@ use futures::{ prelude::*, }; use lazy_static::lazy_static; +use serde::{ + Serialize, + Deserialize, +}; fn install() -> eyre::Result<()> { diff --git a/src/server/web/auth.rs b/src/server/web/auth.rs index 0fea851..35e3ffa 100644 --- a/src/server/web/auth.rs +++ b/src/server/web/auth.rs @@ -12,10 +12,19 @@ impl str::FromStr for Sha256Hash } } -pub async fn auth_req(who: source::IpAddr, state: Arc) -> Result<(), Infallible> +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct AuthRequest +{ + id: uuid::Uuid, + sign_this: [u8; 32], + salt: [u8; 16], + passwd_is_allowed: bool, +} + +pub async fn auth_req(who: source::IpAddr, state: Arc) -> Result { - Ok(()) + todo!() } pub async fn auth_key(who: source::IpAddr, state: Arc, req_id: uuid::Uuid, num: usize, body: Bytes) -> Result<(), Infallible> diff --git a/src/server/web/mod.rs b/src/server/web/mod.rs index 924e058..6e2ddf9 100644 --- a/src/server/web/mod.rs +++ b/src/server/web/mod.rs @@ -39,10 +39,14 @@ pub async fn main(state: server::state::ServerState, cfg: settings::Settings) -> .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()); //TODO + .and(client_ip.clone()).and(state.clone()) + .and_then(auth::auth_req); let resp = { let resp_auth_with_state = warp::post() @@ -51,7 +55,9 @@ pub async fn main(state: server::state::ServerState, cfg: settings::Settings) -> let resp_auth_key = resp_auth_with_state.clone() .and(warp::path("si") - .and(warp::path::param().map(|num: usize| std::cmp::max(1, num)) + .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()) @@ -59,21 +65,29 @@ pub async fn main(state: server::state::ServerState, cfg: settings::Settings) -> // -- Paths -- - let resp_auth_pass = resp_auth_with_state - .and(warp::path::param().map(|hash: auth::Sha256Hash| hash.0)) - .and_then(auth::auth_pass); + 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::reject())}).boxed() + } + }; let resp = warp::path("resp") .and(resp_auth_key .or(resp_auth_pass)); - - + // /resp//pw/ // /resp//si[/] resp }; - warp::path("auth").and(req) + warp::path("auth").and(req.or(resp)) }; todo!() diff --git a/src/server/web/settings.rs b/src/server/web/settings.rs index 14d1521..fdef351 100644 --- a/src/server/web/settings.rs +++ b/src/server/web/settings.rs @@ -12,6 +12,14 @@ pub struct Settings /// First is max body len for auth responses, 2nd is for data. pub max_body_len: (u64, u64), pub trust_x_forwarded_for: bool, + + pub allow_passwd_auth: bool, + pub max_key_sigs_per_auth_response: usize, + + /// How long is an auth request ID is valid. + pub auth_req_ttl_millis: u64, + /// How long is an authentication token valid for an action. + pub auth_token_ttl_millis: u64, } impl Default for Settings @@ -22,6 +30,12 @@ impl Default for Settings Self { max_body_len: (DEFAULT_MAX_BODY_LEN_ARESP, DEFAULT_MAX_BODY_LEN), trust_x_forwarded_for: false, + + allow_passwd_auth: true, + max_key_sigs_per_auth_response: 16, + + auth_req_ttl_millis: 5000, //5 s + auth_token_ttl_millis: 60 * 2000, //2 m } } }