From b03fe0e5f76e815de6f01aa8b6ef66be318be090 Mon Sep 17 00:00:00 2001 From: Emi Tatsuo Date: Sun, 22 Nov 2020 00:43:15 -0500 Subject: [PATCH] Add password management facilities --- .../pages/password/success.gmi | 5 ++ src/user_management/routes.rs | 65 +++++++++++++++++-- 2 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 src/user_management/pages/password/success.gmi diff --git a/src/user_management/pages/password/success.gmi b/src/user_management/pages/password/success.gmi new file mode 100644 index 0000000..8c764f8 --- /dev/null +++ b/src/user_management/pages/password/success.gmi @@ -0,0 +1,5 @@ +# Password Updated + +To add a certificate, log in using the new certificate and provide your username and password. + +=> /account Back to settings diff --git a/src/user_management/routes.rs b/src/user_management/routes.rs index 6b46a68..e56c01f 100644 --- a/src/user_management/routes.rs +++ b/src/user_management/routes.rs @@ -2,10 +2,12 @@ use anyhow::Result; use tokio::net::ToSocketAddrs; use serde::{Serialize, de::DeserializeOwned}; -use crate::{Request, Response}; +use crate::{Document, Request, Response}; +use crate::types::document::HeadingLevel; use crate::user_management::{User, RegisteredUser, UserManagerError}; const UNAUTH: &str = include_str!("pages/unauth.gmi"); +const NSI: &str = include_str!("pages/nsi.gmi"); pub trait UserManagementRoutes: private::Sealed { fn add_um_routes(self, redir: &'static str) -> Self; @@ -17,6 +19,7 @@ impl UserManagementRoutes for crate::Builder { .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::) } } @@ -26,7 +29,7 @@ async fn handle_base(request: Request, r Response::success_gemini(UNAUTH) }, User::NotSignedIn(_) => { - Response::success_gemini(include_str!("pages/nsi.gmi")) + Response::success_gemini(NSI) }, User::SignedIn(user) => { render_settings_menu(user, redirect) @@ -126,15 +129,63 @@ async fn handle_login(request: }) } +async fn handle_password(request: Request) -> Result { + Ok(match request.user::()? { + User::Unauthenticated => { + Response::success_gemini(UNAUTH) + }, + User::NotSignedIn(_) => { + Response::success_gemini(NSI) + }, + User::SignedIn(mut user) => { + if let Some(password) = request.input() { + user.set_password(password)?; + Response::success_gemini(include_str!("pages/password/success.gmi")) + } else { + Response::input( + format!("Please enter a {}password", + if user.has_password() { + "new " + } else { + "" + } + ) + )? + } + }, + }) +} + + fn render_settings_menu( user: RegisteredUser, redirect: &str ) -> Response { - Response::success_gemini(format!( - include_str!("pages/settings.gmi"), - username = user.username(), - redirect = redirect, - )) + Document::new() + .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_text( + if user.has_password() { + concat!( + "You currently have a password set. This can be used to link any new", + " certificates or clients to your account. If you don't remember your", + " password, or would like to change it, you may do so here.", + ) + } else { + concat!( + "You don't currently have a password set! Without a password, you cannot", + " link any new certificates to your account, and if you lose your current", + " client or certificate, you won't be able to recover your account.", + ) + } + ) + .add_blank_line() + .add_link("/account/password", if user.has_password() { "Change password" } else { "Set password" }) + .into() } mod private {