diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-01-25 15:01:38 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-01-25 15:01:38 +0100 |
| commit | 5075aede44cb8ab2df10e6debba38483e8d11e96 (patch) | |
| tree | f719e4b4a0c29f3a27b4fa7cf0a6ee6f7739125c /server/src/auth.rs | |
| parent | 53361f4c6027d1569a707ce58889bc2c2ea3749c (diff) | |
| download | jellything-5075aede44cb8ab2df10e6debba38483e8d11e96.tar jellything-5075aede44cb8ab2df10e6debba38483e8d11e96.tar.bz2 jellything-5075aede44cb8ab2df10e6debba38483e8d11e96.tar.zst | |
remove some unused imports; css reload; port login logic
Diffstat (limited to 'server/src/auth.rs')
| -rw-r--r-- | server/src/auth.rs | 63 |
1 files changed, 58 insertions, 5 deletions
diff --git a/server/src/auth.rs b/server/src/auth.rs index e84c4d1..0e523ed 100644 --- a/server/src/auth.rs +++ b/server/src/auth.rs @@ -5,8 +5,13 @@ */ use crate::State; -use anyhow::{Result, anyhow}; -use jellycommon::jellyobject::ObjectBuffer; +use anyhow::{Result, anyhow, bail}; +use argon2::{Argon2, PasswordHasher, password_hash::Salt}; +use jellycommon::{ + USER_LOGIN, USER_PASSWORD, + jellyobject::{ObjectBuffer, Path}, +}; +use jellydb::query::{Filter, Query, Sort}; pub fn token_to_user(state: &State, token: &str) -> Result<ObjectBuffer> { let user_row = token::validate(&state.session_key, token)?; @@ -20,6 +25,55 @@ pub fn token_to_user(state: &State, token: &str) -> Result<ObjectBuffer> { user.ok_or(anyhow!("user was deleted")) } +pub fn login(state: &State, username: &str, password: &str, expire: Option<i64>) -> Result<String> { + let password = hash_password(username, password); + + let mut user_row = None; + let mut user = None; + state.database.read_transaction(&mut |txn| { + user_row = state.users.query_single( + txn, + Query { + filter: Filter::Match(Path(vec![USER_LOGIN.0]), username.as_bytes().to_vec()), + sort: Sort::None, + }, + )?; + if let Some(ur) = user_row { + user = state.users.get(txn, ur)?; + } + Ok(()) + }); + + let (Some(user_row), Some(user)) = (user_row, user) else { + bail!("unknown user"); + }; + let Some(correct_pw) = user.as_object().get(USER_PASSWORD) else { + bail!("password login is disabled") + }; + if password != correct_pw { + bail!("incorrect password") + } + + Ok(token::create( + &state.session_key, + user_row, + expire.unwrap_or(60 * 60 * 24 * 30), + )) +} + +pub fn hash_password(username: &str, password: &str) -> Vec<u8> { + Argon2::default() + .hash_password( + format!("{username}\0{password}").as_bytes(), + <&str as TryInto<Salt>>::try_into("IYMa13osbNeLJKnQ1T8LlA").unwrap(), + ) + .unwrap() + .hash + .unwrap() + .as_bytes() + .to_vec() +} + pub mod token { use aes_gcm_siv::{ Aes256GcmSiv, KeyInit, @@ -32,7 +86,6 @@ pub mod token { }; use chrono::Utc; use jellydb::table::RowNum; - use std::time::Duration; pub struct SessionKey(Aes256GcmSiv); @@ -43,8 +96,8 @@ pub mod token { } } - pub fn create(sk: &SessionKey, user: RowNum, expire: Duration) -> String { - let expire_ts = Utc::now().timestamp() + expire.as_secs() as i64; + pub fn create(sk: &SessionKey, user: RowNum, expire: i64) -> String { + let expire_ts = Utc::now().timestamp() + expire; let mut plain = Vec::new(); plain.extend(user.to_be_bytes()); plain.extend(expire_ts.to_be_bytes()); |