From 7abb33c4feaf9b8c05c8dec08bbac648df891404 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Tue, 21 Nov 2023 09:57:35 -0500 Subject: [PATCH] Work out how the session filter and the handlers can function --- Cargo.lock | 34 +++++++--- visions/server/Cargo.toml | 9 ++- visions/server/src/handlers.rs | 24 +++++++ visions/server/src/main.rs | 112 ++++++++++++++++++++++++--------- 4 files changed, 138 insertions(+), 41 deletions(-) create mode 100644 visions/server/src/handlers.rs diff --git a/Cargo.lock b/Cargo.lock index ce35caf..f02baf5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -937,7 +937,7 @@ dependencies = [ "cool_asserts", "futures-util", "hex-string", - "http", + "http 0.2.9", "image 0.23.14", "log 0.4.20", "logger", @@ -1597,7 +1597,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", "indexmap 1.9.3", "slab", "tokio", @@ -1648,7 +1648,7 @@ dependencies = [ "base64 0.21.4", "bytes", "headers-core", - "http", + "http 0.2.9", "httpdate", "mime 0.3.17", "sha1", @@ -1660,7 +1660,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", + "http 0.2.9", ] [[package]] @@ -1741,6 +1741,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -1748,7 +1759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.9", "pin-project-lite", ] @@ -1800,7 +1811,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.9", "http-body", "httparse", "httpdate", @@ -2337,7 +2348,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 0.2.9", "httparse", "log 0.4.20", "memchr", @@ -3204,7 +3215,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.9", "http-body", "hyper 0.14.27", "hyper-tls", @@ -4296,7 +4307,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.9", "httparse", "log 0.4.20", "rand 0.8.5", @@ -4546,6 +4557,9 @@ name = "visions" version = "0.1.0" dependencies = [ "authdb", + "http 1.0.0", + "serde 1.0.188", + "serde_json", "tokio", "warp", ] @@ -4593,7 +4607,7 @@ dependencies = [ "futures-channel", "futures-util", "headers", - "http", + "http 0.2.9", "hyper 0.14.27", "log 0.4.20", "mime 0.3.17", diff --git a/visions/server/Cargo.toml b/visions/server/Cargo.toml index 8c69b40..6105d04 100644 --- a/visions/server/Cargo.toml +++ b/visions/server/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -authdb = { path = "../../authdb/" } -tokio = { version = "1", features = [ "full" ] } -warp = { version = "0.3" } +authdb = { path = "../../authdb/" } +http = { version = "1" } +serde_json = { version = "*" } +serde = { version = "1" } +tokio = { version = "1", features = [ "full" ] } +warp = { version = "0.3" } diff --git a/visions/server/src/handlers.rs b/visions/server/src/handlers.rs new file mode 100644 index 0000000..c923163 --- /dev/null +++ b/visions/server/src/handlers.rs @@ -0,0 +1,24 @@ +use authdb::{AuthDB, AuthToken}; +use http::{response::Response, status::StatusCode, Error}; + +pub async fn handle_auth( + auth_ctx: &AuthDB, + auth_token: AuthToken, +) -> Result, Error> { + match auth_ctx.authenticate(auth_token).await { + Ok(Some(session)) => match serde_json::to_string(&session) { + Ok(session_token) => Response::builder() + .status(StatusCode::OK) + .body(session_token), + Err(_) => Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body("".to_owned()), + }, + Ok(None) => Response::builder() + .status(StatusCode::UNAUTHORIZED) + .body("".to_owned()), + Err(_) => Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body("".to_owned()), + } +} diff --git a/visions/server/src/main.rs b/visions/server/src/main.rs index 17910a5..18f1798 100644 --- a/visions/server/src/main.rs +++ b/visions/server/src/main.rs @@ -1,46 +1,102 @@ -use authdb::{AuthDB, Username}; +use authdb::{AuthDB, AuthError, AuthToken, SessionToken, Username}; use std::{ + convert::Infallible, net::{IpAddr, Ipv4Addr, SocketAddr}, path::PathBuf, - sync::{Arc, RwLock}, + sync::Arc, +}; +use warp::{ + header, + http::StatusCode, + reply::{Json, Reply}, + Filter, }; -use warp::{header, Filter}; -fn with_authentication( - auth_ctx: Arc>, +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").map(|value: String| { - println!("value: {:?}", value); - Username::from("savanni") + 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(RwLock::new(auth_db)); + let auth_ctx: Arc = Arc::new(auth_db); - let echo_unauthenticated = warp::path!("api" / "v1" / "echo" / String).map(|param: String| { - println!("param: {}", param); - warp::reply::json(&vec!["unauthenticated", param.as_str()]) - }); - - let authenticate = warp::path!("api" / "v1" / "auth" / String).map(|param: String| { - println!("param: {}", param); - warp::reply::json(¶m) - }); - - let echo_authenticated = warp::path!("api" / "v1" / "echo" / String) - .and(with_authentication(auth_ctx.clone())) - .map(|param: String, username: Username| { - println!("param: {:?}", username); - println!("param: {}", param); - warp::reply::json(&vec!["authenticated", username.as_str(), param.as_str()]) - }); - - let filter = echo_authenticated.or(authenticate).or(echo_unauthenticated); + 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