From 212a0f23bc894faf88e159560c113f504349cc05 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Tue, 29 Apr 2025 17:06:23 +0200 Subject: comiles again but still many logic holes --- server/src/ui/account/mod.rs | 171 +++++++++++++++---------------------------- 1 file changed, 57 insertions(+), 114 deletions(-) (limited to 'server/src/ui/account/mod.rs') diff --git a/server/src/ui/account/mod.rs b/server/src/ui/account/mod.rs index 54fa4d0..a9c28ea 100644 --- a/server/src/ui/account/mod.rs +++ b/server/src/ui/account/mod.rs @@ -8,22 +8,31 @@ pub mod settings; use super::error::MyError; use crate::{ database::Database, + helper::A, locale::AcceptLanguage, ui::{error::MyResult, home::rocket_uri_macro_r_home}, }; use anyhow::anyhow; -use chrono::Duration; -use jellycommon::user::{User, UserPermission}; +use jellycommon::user::User; +use jellyimport::is_importing; +use jellylogic::{ + login::{hash_password, login_logic}, + session::Session, +}; +use jellyui::{ + account::{AccountLogin, AccountLogout, AccountRegister, AccountRegisterSuccess}, + render_page, + scaffold::{RenderInfo, SessionInfo}, +}; use rocket::{ form::{Contextual, Form}, get, http::{Cookie, CookieJar}, post, - response::Redirect, + response::{content::RawHtml, Redirect}, FromForm, State, }; use serde::{Deserialize, Serialize}; -use std::collections::HashSet; #[derive(FromForm)] pub struct RegisterForm { @@ -36,15 +45,16 @@ pub struct RegisterForm { } #[get("/account/register")] -pub async fn r_account_register(lang: AcceptLanguage) -> DynLayoutPage<'static> { +pub async fn r_account_register(lang: AcceptLanguage) -> RawHtml { let AcceptLanguage(lang) = lang; - LayoutPage { - title: tr(lang, "account.register").to_string(), - content: markup::new! { - + RawHtml(render_page( + &AccountRegister { lang: &lang }, + RenderInfo { + importing: false, + session: None, }, - ..Default::default() - } + lang, + )) } #[derive(FromForm, Serialize, Deserialize)] @@ -58,69 +68,47 @@ pub struct LoginForm { } #[get("/account/login")] -pub fn r_account_login(sess: Option, lang: AcceptLanguage) -> DynLayoutPage<'static> { +pub fn r_account_login(session: Option>, lang: AcceptLanguage) -> RawHtml { let AcceptLanguage(lang) = lang; - let logged_in = sess.is_some(); - let title = tr( - lang, - if logged_in { - "account.login.switch" - } else { - "account.login" + let logged_in = session.is_some(); + RawHtml(render_page( + &AccountLogin { + lang: &lang, + logged_in, }, - ); - LayoutPage { - title: title.to_string(), - content: markup::new! { - form.account[method="POST", action=""] { - h1 { @title.to_string() } - - label[for="inp-username"] { @trs(&lang, "account.username") } - input[type="text", id="inp-username", name="username"]; br; - label[for="inp-password"] { @trs(&lang, "account.password") } - input[type="password", id="inp-password", name="password"]; br; - - input[type="submit", value=&*tr(lang, if logged_in { "account.login.submit.switch" } else { "account.login.submit" })]; - - @if logged_in { - p { @trs(&lang, "account.login.register.switch") " " a[href=uri!(r_account_register())] { @trs(&lang, "account.login.register_here") } } - } else { - p { @trs(&lang, "account.login.cookie_note") } - p { @trs(&lang, "account.login.register") " " a[href=uri!(r_account_register())] { @trs(&lang, "account.login.register_here") } } - } - } + RenderInfo { + session: session.map(|s| SessionInfo { user: s.0.user }), + importing: is_importing(), }, - ..Default::default() - } + lang, + )) } #[get("/account/logout")] -pub fn r_account_logout(lang: AcceptLanguage) -> DynLayoutPage<'static> { +pub fn r_account_logout(session: Option>, lang: AcceptLanguage) -> RawHtml { let AcceptLanguage(lang) = lang; - LayoutPage { - title: tr(lang, "account.logout").to_string(), - content: markup::new! { - form.account[method="POST", action=""] { - h1 { @trs(&lang, "account.logout") } - input[type="submit", value=&*tr(lang, "account.logout.submit")]; - } + RawHtml(render_page( + &AccountLogout { lang: &lang }, + RenderInfo { + session: session.map(|s| SessionInfo { user: s.0.user }), + importing: is_importing(), }, - ..Default::default() - } + lang, + )) } #[post("/account/register", data = "
")] pub fn r_account_register_post<'a>( database: &'a State, - _sess: Option, + session: Option>, form: Form>, lang: AcceptLanguage, -) -> MyResult> { +) -> MyResult> { let AcceptLanguage(lang) = lang; - let logged_in = _sess.is_some(); + let logged_in = session.is_some(); let form = match &form.value { Some(v) => v, - None => return Err(format_form_error(form)), + None => return Err(MyError(anyhow!(format_form_error(form)))), }; database.register_user( @@ -134,17 +122,17 @@ pub fn r_account_register_post<'a>( }, )?; - Ok(LayoutPage { - title: tr(lang, "account.register.success.title").to_string(), - content: markup::new! { - h1 { @trs(&lang, if logged_in { - "account.register.success.switch" - } else { - "account.register.success" - })} + Ok(RawHtml(render_page( + &AccountRegisterSuccess { + lang: &lang, + logged_in, + }, + RenderInfo { + session: session.map(|s| SessionInfo { user: s.0.user }), + importing: is_importing(), }, - ..Default::default() - }) + lang, + ))) } #[post("/account/login", data = "")] @@ -155,7 +143,7 @@ pub fn r_account_login_post( ) -> MyResult { let form = match &form.value { Some(v) => v, - None => return Err(format_form_error(form)), + None => return Err(MyError(anyhow!(format_form_error(form)))), }; jar.add( Cookie::build(( @@ -175,39 +163,7 @@ pub fn r_account_logout_post(jar: &CookieJar) -> MyResult { Ok(Redirect::found(rocket::uri!(r_home()))) } -pub fn login_logic( - database: &Database, - username: &str, - password: &str, - expire: Option, - drop_permissions: Option>, -) -> MyResult { - // hashing the password regardless if the accounts exists to better resist timing attacks - let password = hash_password(username, password); - - let mut user = database - .get_user(username)? - .ok_or(anyhow!("invalid password"))?; - - if user.password != password { - Err(anyhow!("invalid password"))? - } - - if let Some(ep) = drop_permissions { - // remove all grant perms that are in `ep` - user.permissions - .0 - .retain(|p, val| if *val { !ep.contains(p) } else { true }) - } - - Ok(session::create( - user.name, - user.permissions, - Duration::days(CONF.login_expire.min(expire.unwrap_or(i64::MAX))), - )) -} - -pub fn format_form_error(form: Form>) -> MyError { +pub fn format_form_error(form: Form>) -> String { let mut k = String::from("form validation failed:"); for e in form.context.errors() { k += &format!( @@ -218,18 +174,5 @@ pub fn format_form_error(form: Form>) -> MyError { .unwrap_or("".to_string()) ) } - MyError(anyhow!(k)) -} - -pub fn hash_password(username: &str, password: &str) -> Vec { - Argon2::default() - .hash_password( - format!("{username}\0{password}").as_bytes(), - <&str as TryInto>::try_into("IYMa13osbNeLJKnQ1T8LlA").unwrap(), - ) - .unwrap() - .hash - .unwrap() - .as_bytes() - .to_vec() + k } -- cgit v1.2.3-70-g09d2