aboutsummaryrefslogtreecommitdiff
path: root/server/src/auth.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-01-25 15:01:38 +0100
committermetamuffin <metamuffin@disroot.org>2026-01-25 15:01:38 +0100
commit5075aede44cb8ab2df10e6debba38483e8d11e96 (patch)
treef719e4b4a0c29f3a27b4fa7cf0a6ee6f7739125c /server/src/auth.rs
parent53361f4c6027d1569a707ce58889bc2c2ea3749c (diff)
downloadjellything-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.rs63
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());