diff options
author | metamuffin <metamuffin@disroot.org> | 2023-12-11 01:19:51 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2023-12-11 01:19:51 +0100 |
commit | 36d7fb2790774c53415c96f8c6955be42bad952f (patch) | |
tree | 4481dac53a6d0896e90ff72b9b68665e59e159db /server/src/routes/ui | |
parent | 767d6c4c7b8518198b0343781128027051b94ae5 (diff) | |
download | jellything-36d7fb2790774c53415c96f8c6955be42bad952f.tar jellything-36d7fb2790774c53415c96f8c6955be42bad952f.tar.bz2 jellything-36d7fb2790774c53415c96f8c6955be42bad952f.tar.zst |
(partially) fix security problem with federated session
Diffstat (limited to 'server/src/routes/ui')
-rw-r--r-- | server/src/routes/ui/account/mod.rs | 28 | ||||
-rw-r--r-- | server/src/routes/ui/account/session/token.rs | 18 | ||||
-rw-r--r-- | server/src/routes/ui/account/settings.rs | 8 |
3 files changed, 35 insertions, 19 deletions
diff --git a/server/src/routes/ui/account/mod.rs b/server/src/routes/ui/account/mod.rs index 88f6f45..1c5b19a 100644 --- a/server/src/routes/ui/account/mod.rs +++ b/server/src/routes/ui/account/mod.rs @@ -6,6 +6,8 @@ pub mod session; pub mod settings; +use std::collections::HashSet; + use super::{error::MyError, layout::LayoutPage}; use crate::{ database::Database, @@ -16,7 +18,7 @@ use anyhow::anyhow; use argon2::{password_hash::Salt, Argon2, PasswordHasher}; use chrono::Duration; use jellybase::CONF; -use jellycommon::user::{PermissionSet, Theme, User}; +use jellycommon::user::{PermissionSet, Theme, User, UserPermission}; use rocket::{ form::{Contextual, Form}, get, @@ -162,7 +164,7 @@ pub fn r_account_login_post( jar.add( Cookie::build( "session", - login_logic(database, &form.username, &form.password)?, + login_logic(database, &form.username, &form.password, None, None)?, ) .permanent() .finish(), @@ -177,11 +179,17 @@ pub fn r_account_logout_post(jar: &CookieJar) -> MyResult<Redirect> { Ok(Redirect::found(rocket::uri!(r_home()))) } -pub fn login_logic(database: &Database, username: &str, password: &str) -> MyResult<String> { +pub fn login_logic( + database: &Database, + username: &str, + password: &str, + expire: Option<i64>, + drop_permissions: Option<HashSet<UserPermission>>, +) -> MyResult<String> { // hashing the password regardless if the accounts exists to prevent timing attacks let password = hash_password(username, password); - let user = database + let mut user = database .user .get(&username.to_string())? .ok_or(anyhow!("invalid password"))?; @@ -190,9 +198,17 @@ pub fn login_logic(database: &Database, username: &str, password: &str) -> MyRes 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::token::create( - &user, - Duration::days(CONF.login_expire), + user.name, + user.permissions, + Duration::days(CONF.login_expire.min(expire.unwrap_or(i64::MAX))), )) } diff --git a/server/src/routes/ui/account/session/token.rs b/server/src/routes/ui/account/session/token.rs index b6c22f7..969207d 100644 --- a/server/src/routes/ui/account/session/token.rs +++ b/server/src/routes/ui/account/session/token.rs @@ -12,7 +12,7 @@ use anyhow::anyhow; use base64::Engine; use chrono::{Duration, Utc}; use jellybase::CONF; -use jellycommon::user::User; +use jellycommon::user::PermissionSet; use log::warn; use std::sync::LazyLock; @@ -29,11 +29,11 @@ static SESSION_KEY: LazyLock<[u8; 32]> = LazyLock::new(|| { } }); -pub fn create(user: &User, expire: Duration) -> String { +pub fn create(username: String, permissions: PermissionSet, expire: Duration) -> String { let session_data = SessionData { expire: Utc::now() + expire, - username: user.name.to_owned(), - permissions: user.permissions.clone(), + username: username.to_owned(), + permissions, }; let mut plaintext = bincode::serde::encode_to_vec(&session_data, bincode::config::standard()).unwrap(); @@ -73,14 +73,8 @@ pub fn validate(token: &str) -> anyhow::Result<String> { #[test] fn test() { let tok = create( - &User { - name: "blub".to_string(), - display_name: "blub".to_owned(), - password: vec![], - admin: false, - permissions: jellycommon::user::PermissionSet::default(), - theme: jellycommon::user::Theme::Dark, - }, + "blub".to_string(), + jellycommon::user::PermissionSet::default(), Duration::days(1), ); validate(&tok).unwrap(); diff --git a/server/src/routes/ui/account/settings.rs b/server/src/routes/ui/account/settings.rs index 2192d43..90dcf37 100644 --- a/server/src/routes/ui/account/settings.rs +++ b/server/src/routes/ui/account/settings.rs @@ -13,7 +13,8 @@ use crate::{ }, uri, }; -use jellycommon::user::Theme; +use jellybase::permission::PermissionSetExt; +use jellycommon::user::{Theme, UserPermission}; use rocket::{ form::{self, validate::len, Contextual, Form}, get, @@ -95,6 +96,11 @@ pub fn r_account_settings_post( database: &State<Database>, form: Form<Contextual<SettingsForm>>, ) -> MyResult<DynLayoutPage<'static>> { + session + .user + .permissions + .assert(&UserPermission::ManageSelf)?; + let form = match &form.value { Some(v) => v, None => return Ok(settings_page(session, Some(Err(format_form_error(form))))), |