diff options
Diffstat (limited to 'server/src/routes/ui/account')
| -rw-r--r-- | server/src/routes/ui/account/mod.rs | 71 | ||||
| -rw-r--r-- | server/src/routes/ui/account/session/guard.rs | 18 | ||||
| -rw-r--r-- | server/src/routes/ui/account/settings.rs | 53 | 
3 files changed, 88 insertions, 54 deletions
| diff --git a/server/src/routes/ui/account/mod.rs b/server/src/routes/ui/account/mod.rs index cd8695f..8af92a0 100644 --- a/server/src/routes/ui/account/mod.rs +++ b/server/src/routes/ui/account/mod.rs @@ -8,7 +8,7 @@ pub mod settings;  use super::{error::MyError, layout::LayoutPage};  use crate::{ -    database::Database, +    database::DataAcid,      routes::ui::{          account::session::Session, error::MyResult, home::rocket_uri_macro_r_home,          layout::DynLayoutPage, @@ -18,7 +18,10 @@ use crate::{  use anyhow::anyhow;  use argon2::{password_hash::Salt, Argon2, PasswordHasher};  use chrono::Duration; -use jellybase::CONF; +use jellybase::{ +    database::{Ser, TableExt, T_INVITE, T_USER}, +    CONF, +};  use jellycommon::user::{PermissionSet, Theme, User, UserPermission};  use rocket::{      form::{Contextual, Form}, @@ -121,7 +124,7 @@ pub fn r_account_logout() -> DynLayoutPage<'static> {  #[post("/account/register", data = "<form>")]  pub fn r_account_register_post<'a>( -    database: &'a State<Database>, +    database: &'a State<DataAcid>,      _sess: Option<Session>,      form: Form<Contextual<'a, RegisterForm>>,  ) -> MyResult<DynLayoutPage<'a>> { @@ -131,15 +134,17 @@ pub fn r_account_register_post<'a>(          None => return Err(format_form_error(form)),      }; -    if database.invite.remove(&form.invitation).unwrap().is_none() { -        return Err(MyError(anyhow!("invitation invalid"))); +    let txn = database.begin_write()?; +    let mut invites = txn.open_table(T_INVITE)?; +    let mut users = txn.open_table(T_USER)?; + +    if invites.remove(&*form.invitation)?.is_none() { +        Err(anyhow!("invitation invalid"))?;      } -    match database -        .user -        .compare_and_swap( -            &form.username, -            None, -            Some(&User { +    let prev_user = users +        .insert( +            &*form.username, +            Ser(User {                  display_name: form.username.clone(),                  name: form.username.clone(),                  password: hash_password(&form.username, &form.password), @@ -147,27 +152,32 @@ pub fn r_account_register_post<'a>(                  theme: Theme::Dark,                  permissions: PermissionSet::default(),              }), -        ) -        .unwrap() -    { -        Ok(_) => Ok(LayoutPage { -            title: "Registration successful".to_string(), -            content: markup::new! { -                h1 { @if logged_in { -                    "Registration successful, you may switch account now." -                } else { -                    "Registration successful, you may log in now." -                }} -            }, -            ..Default::default() -        }), -        Err(_) => Err(MyError(anyhow!("username is taken"))), +        )? +        .map(|x| x.value().0); +    if prev_user.is_some() { +        Err(anyhow!("username taken"))?;      } + +    drop(users); +    drop(invites); +    txn.commit()?; + +    Ok(LayoutPage { +        title: "Registration successful".to_string(), +        content: markup::new! { +            h1 { @if logged_in { +                "Registration successful, you may switch account now." +            } else { +                "Registration successful, you may log in now." +            }} +        }, +        ..Default::default() +    })  }  #[post("/account/login", data = "<form>")]  pub fn r_account_login_post( -    database: &State<Database>, +    database: &State<DataAcid>,      jar: &CookieJar,      form: Form<Contextual<LoginForm>>,  ) -> MyResult<Redirect> { @@ -194,7 +204,7 @@ pub fn r_account_logout_post(jar: &CookieJar) -> MyResult<Redirect> {  }  pub fn login_logic( -    database: &Database, +    database: &DataAcid,      username: &str,      password: &str,      expire: Option<i64>, @@ -203,9 +213,8 @@ pub fn login_logic(      // hashing the password regardless if the accounts exists to prevent timing attacks      let password = hash_password(username, password); -    let mut user = database -        .user -        .get(&username.to_string())? +    let mut user = T_USER +        .get(database, username)?          .ok_or(anyhow!("invalid password"))?;      if user.password != password { diff --git a/server/src/routes/ui/account/session/guard.rs b/server/src/routes/ui/account/session/guard.rs index ae1ebd3..b2fd408 100644 --- a/server/src/routes/ui/account/session/guard.rs +++ b/server/src/routes/ui/account/session/guard.rs @@ -4,8 +4,9 @@      Copyright (C) 2023 metamuffin <metamuffin.org>  */  use super::{AdminSession, Session}; -use crate::{database::Database, routes::ui::error::MyError}; +use crate::{database::DataAcid, routes::ui::error::MyError};  use anyhow::anyhow; +use jellybase::database::{ReadableTable, T_USER};  use log::warn;  use rocket::{      async_trait, @@ -35,8 +36,19 @@ impl Session {              username = "admin".to_string();          } -        let db = req.guard::<&State<Database>>().await.unwrap(); -        let user = db.user.get(&username)?.ok_or(anyhow!("user not found"))?; +        let db = req.guard::<&State<DataAcid>>().await.unwrap(); + +        let user = { +            let txn = db.inner.begin_read()?; +            let table = txn.open_table(T_USER)?; +            let user = table +                .get(&*username)? +                .ok_or(anyhow!("user not found"))? +                .value() +                .0; +            drop(table); +            user +        };          Ok(Session { user })      } diff --git a/server/src/routes/ui/account/settings.rs b/server/src/routes/ui/account/settings.rs index f14478b..ecc0723 100644 --- a/server/src/routes/ui/account/settings.rs +++ b/server/src/routes/ui/account/settings.rs @@ -5,7 +5,7 @@  */  use super::{format_form_error, hash_password};  use crate::{ -    database::Database, +    database::DataAcid,      routes::ui::{          account::{rocket_uri_macro_r_account_login, session::Session},          error::MyResult, @@ -13,7 +13,11 @@ use crate::{      },      uri,  }; -use jellybase::permission::PermissionSetExt; +use anyhow::anyhow; +use jellybase::{ +    database::{ReadableTable, Ser, T_USER}, +    permission::PermissionSetExt, +};  use jellycommon::user::{Theme, UserPermission};  use markup::{Render, RenderAttributeValue};  use rocket::{ @@ -97,7 +101,7 @@ pub fn r_account_settings(session: Session) -> DynLayoutPage<'static> {  #[post("/account/settings", data = "<form>")]  pub fn r_account_settings_post(      session: Session, -    database: &State<Database>, +    database: &State<DataAcid>,      form: Form<Contextual<SettingsForm>>,  ) -> MyResult<DynLayoutPage<'static>> {      session @@ -111,23 +115,32 @@ pub fn r_account_settings_post(      };      let mut out = String::new(); -    database.user.fetch_and_update(&session.user.name, |k| { -        k.map(|mut k| { -            if let Some(password) = &form.password { -                k.password = hash_password(&session.user.name, password); -                out += "Password updated\n"; -            } -            if let Some(display_name) = &form.display_name { -                k.display_name = display_name.clone(); -                out += "Display name updated\n"; -            } -            if let Some(theme) = form.theme { -                k.theme = theme; -                out += "Theme updated\n"; -            } -            k -        }) -    })?; + +    let txn = database.begin_write()?; +    let mut users = txn.open_table(T_USER)?; + +    let mut user = users +        .get(&*session.user.name)? +        .ok_or(anyhow!("user missing"))? +        .value() +        .0; + +    if let Some(password) = &form.password { +        user.password = hash_password(&session.user.name, password); +        out += "Password updated\n"; +    } +    if let Some(display_name) = &form.display_name { +        user.display_name = display_name.clone(); +        out += "Display name updated\n"; +    } +    if let Some(theme) = form.theme { +        user.theme = theme; +        out += "Theme updated\n"; +    } + +    users.insert(&*session.user.name, Ser(user))?; +    drop(users); +    txn.commit()?;      Ok(settings_page(          session, // using the old session here, results in outdated theme being displayed | 
