From 28a4d64c5ffd82fd3214ad6f1e9467ed59ea0116 Mon Sep 17 00:00:00 2001 From: Emi Tatsuo Date: Sun, 22 Nov 2020 22:24:36 -0500 Subject: [PATCH] Segregate features surrounding multiple certificates & passwords to a seperate feature --- Cargo.toml | 3 +- src/user_management/mod.rs | 4 ++ src/user_management/routes.rs | 75 ++++++++++++++++++++++++++--------- src/user_management/user.rs | 8 ++++ 4 files changed, 71 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3163cfa..e434fab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,8 @@ repository = "https://github.com/panicbit/northstar" documentation = "https://docs.rs/northstar" [features] -user_management = ["sled", "bincode", "serde/derive", "rust-argon2", "crc32fast", "ring"] +user_management = ["sled", "bincode", "serde/derive", "crc32fast"] +user_management_advanced = ["rust-argon2", "ring", "user_management"] default = ["serve_dir"] serve_dir = ["mime_guess", "tokio/fs"] diff --git a/src/user_management/mod.rs b/src/user_management/mod.rs index face405..ce51e6d 100644 --- a/src/user_management/mod.rs +++ b/src/user_management/mod.rs @@ -38,6 +38,7 @@ pub enum UserManagerError { DatabaseError(sled::Error), DatabaseTransactionError(sled::transaction::TransactionError), DeserializeError(bincode::Error), + #[cfg(feature = "user_management_advanced")] Argon2Error(argon2::Error), } @@ -59,6 +60,7 @@ impl From for UserManagerError { } } +#[cfg(feature = "user_management_advanced")] impl From for UserManagerError { fn from(error: argon2::Error) -> Self { Self::Argon2Error(error) @@ -71,6 +73,7 @@ impl std::error::Error for UserManagerError { Self::DatabaseError(e) => Some(e), Self::DatabaseTransactionError(e) => Some(e), Self::DeserializeError(e) => Some(e), + #[cfg(feature = "user_management_advanced")] Self::Argon2Error(e) => Some(e), _ => None } @@ -90,6 +93,7 @@ impl std::fmt::Display for UserManagerError { write!(f, "Error accessing the user database: {}", e), Self::DeserializeError(e) => write!(f, "Recieved messy data from database, possible corruption: {}", e), + #[cfg(feature = "user_management_advanced")] Self::Argon2Error(e) => write!(f, "Argon2 Error, likely malformed password hash, possible database corruption: {}", e), } diff --git a/src/user_management/routes.rs b/src/user_management/routes.rs index 11675a6..31ddbf3 100644 --- a/src/user_management/routes.rs +++ b/src/user_management/routes.rs @@ -9,7 +9,10 @@ use crate::types::document::HeadingLevel; use crate::user_management::{User, RegisteredUser, UserManagerError}; const UNAUTH: &str = include_str!("pages/unauth.gmi"); +#[cfg(feature = "user_management_advanced")] const NSI: &str = include_str!("pages/nsi.gmi"); +#[cfg(not(feature = "user_management_advanced"))] +const NSI: &str = include_str!("pages/nopass/nsi.gmi"); /// Import this trait to use [`add_um_routes()`](Self::add_um_routes()) pub trait UserManagementRoutes: private::Sealed { @@ -86,11 +89,18 @@ impl UserManagementRoutes for crate::Builder { /// /// See [`UserManagementRoutes::add_um_routes()`] fn add_um_routes(self, redir: &'static str) -> Self { - self.add_route("/account", move|r|handle_base::(r, redir)) + #[allow(unused_mut)] + let mut modified_self = self.add_route("/account", move|r|handle_base::(r, redir)) .add_route("/account/askcert", move|r|handle_ask_cert::(r, redir)) - .add_route("/account/register", move|r|handle_register::(r, redir)) - .add_route("/account/login", move|r|handle_login::(r, redir)) - .add_route("/account/password", handle_password::) + .add_route("/account/register", move|r|handle_register::(r, redir)); + + #[cfg(feature = "user_management_advanced")] { + modified_self = modified_self + .add_route("/account/login", move|r|handle_login::(r, redir)) + .add_route("/account/password", handle_password::); + } + + modified_self } /// Add a special route that requires users to be logged in @@ -171,7 +181,12 @@ async fn handle_ask_cert(request: Reques Response::client_certificate_required() }, User::NotSignedIn(_) => { - Response::success_gemini(include_str!("pages/askcert/success.gmi")) + #[cfg(feature = "user_management_advanced")] { + Response::success_gemini(include_str!("pages/askcert/success.gmi")) + } + #[cfg(not(feature = "user_management_advanced"))] { + Response::success_gemini(include_str!("pages/nopass/askcert/success.gmi")) + } }, User::SignedIn(user) => { Response::success_gemini(format!( @@ -192,17 +207,34 @@ async fn handle_register(reque if let Some(username) = request.input() { match nsi.register::(username.to_owned()) { Err(UserManagerError::UsernameNotUnique) => { - Response::success_gemini(format!( - include_str!("pages/register/exists.gmi"), - username = username, - )) + #[cfg(feature = "user_management_advanced")] { + Response::success_gemini(format!( + include_str!("pages/register/exists.gmi"), + username = username, + )) + } + #[cfg(not(feature = "user_management_advanced"))] { + Response::success_gemini(format!( + include_str!("pages/register/exists.gmi"), + username = username, + )) + } }, Ok(_) => { - Response::success_gemini(format!( - include_str!("pages/register/success.gmi"), - username = username, - redirect = redirect, - )) + #[cfg(feature = "user_management_advanced")] { + Response::success_gemini(format!( + include_str!("pages/register/success.gmi"), + username = username, + redirect = redirect, + )) + } + #[cfg(not(feature = "user_management_advanced"))] { + Response::success_gemini(format!( + include_str!("pages/nopass/register/success.gmi"), + username = username, + redirect = redirect, + )) + } }, Err(e) => return Err(e.into()) } @@ -216,6 +248,7 @@ async fn handle_register(reque }) } +#[cfg(feature = "user_management_advanced")] async fn handle_login(request: Request, redirect: &'static str) -> Result { Ok(match request.user::()? { User::Unauthenticated => { @@ -257,6 +290,7 @@ async fn handle_login(request: }) } +#[cfg(feature = "user_management_advanced")] async fn handle_password(request: Request) -> Result { Ok(match request.user::()? { User::Unauthenticated => { @@ -289,13 +323,17 @@ fn render_settings_menu( user: RegisteredUser, redirect: &str ) -> Response { - Document::new() + let mut document = Document::new(); + document .add_heading(HeadingLevel::H1, "User Settings") .add_blank_line() .add_text(&format!("Welcome {}!", user.username())) .add_blank_line() .add_link(redirect, "Back to the app") - .add_blank_line() + .add_blank_line(); + + #[cfg(feature = "user_management_advanced")] + document .add_text( if user.has_password() { concat!( @@ -312,8 +350,9 @@ fn render_settings_menu( } ) .add_blank_line() - .add_link("/account/password", if user.has_password() { "Change password" } else { "Set password" }) - .into() + .add_link("/account/password", if user.has_password() { "Change password" } else { "Set password" }); + + document.into() } mod private { diff --git a/src/user_management/user.rs b/src/user_management/user.rs index b806b7b..8894462 100644 --- a/src/user_management/user.rs +++ b/src/user_management/user.rs @@ -21,6 +21,7 @@ use crate::user_management::UserManager; use crate::user_management::Result; use crate::user_management::manager::CertificateData; +#[cfg(feature = "user_management_advanced")] const ARGON2_CONFIG: argon2::Config = argon2::Config { ad: &[], hash_length: 32, @@ -33,6 +34,7 @@ const ARGON2_CONFIG: argon2::Config = argon2::Config { version: argon2::Version::Version13, }; +#[cfg(feature = "user_management_advanced")] lazy_static::lazy_static! { static ref RANDOM: ring::rand::SystemRandom = ring::rand::SystemRandom::new(); } @@ -45,6 +47,7 @@ lazy_static::lazy_static! { pub (crate) struct PartialUser { pub data: UserData, pub certificates: Vec, + #[cfg(feature = "user_management_advanced")] pub pass_hash: Option<(Vec, [u8; 32])>, } @@ -120,6 +123,7 @@ impl NotSignedInUser { PartialUser { data: UserData::default(), certificates: Vec::with_capacity(1), + #[cfg(feature = "user_management_advanced")] pass_hash: None, }, ); @@ -133,6 +137,7 @@ impl NotSignedInUser { } } + #[cfg(feature = "user_management_advanced")] /// Attach this certificate to an existing user /// /// Try to add this certificate to another user using a username and password. If @@ -249,6 +254,7 @@ impl RegisteredUser { &self.username } + #[cfg(feature = "user_management_advanced")] /// Check a password against the user's password hash /// /// # Errors @@ -270,6 +276,7 @@ impl RegisteredUser { } } + #[cfg(feature = "user_management_advanced")] /// Set's the password for this user /// /// By default, users have no password, meaning the cannot add any certificates beyond @@ -352,6 +359,7 @@ impl RegisteredUser { Ok(()) } + #[cfg(feature = "user_management_advanced")] /// Check if the user has a password set /// /// Since authentication is done using client certificates, users aren't required to