diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-01-25 01:21:24 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-01-25 01:21:24 +0100 |
| commit | e3708145efd0bbed5d10320ee0a0deff0f38479e (patch) | |
| tree | 877ace344bc78c9fc11c3418f8361de660b594a5 /logic/src/session.rs | |
| parent | 2bcccb18a6cb8bf836f57c3d86f759b19699def2 (diff) | |
| download | jellything-e3708145efd0bbed5d10320ee0a0deff0f38479e.tar jellything-e3708145efd0bbed5d10320ee0a0deff0f38479e.tar.bz2 jellything-e3708145efd0bbed5d10320ee0a0deff0f38479e.tar.zst | |
start moving logic code; less arcing in stream
Diffstat (limited to 'logic/src/session.rs')
| -rw-r--r-- | logic/src/session.rs | 134 |
1 files changed, 0 insertions, 134 deletions
diff --git a/logic/src/session.rs b/logic/src/session.rs index 03ff3a3..e69de29 100644 --- a/logic/src/session.rs +++ b/logic/src/session.rs @@ -1,134 +0,0 @@ -/* - This file is part of jellything (https://codeberg.org/metamuffin/jellything) - which is licensed under the GNU Affero General Public License (version 3); see /COPYING. - Copyright (C) 2026 metamuffin <metamuffin.org> -*/ -use crate::{CONF, DATABASE}; -use aes_gcm_siv::{ - KeyInit, - aead::{Aead, generic_array::GenericArray}, -}; -use anyhow::anyhow; -use base64::Engine; -use log::warn; -use serde::{Deserialize, Serialize}; -use std::{sync::LazyLock, time::Duration}; - -pub struct Session { - pub user: User, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct SessionData { - username: String, - expire: DateTime<Utc>, - permissions: PermissionSet, -} - -static SESSION_KEY: LazyLock<[u8; 32]> = LazyLock::new(|| { - if let Some(sk) = &CONF.session_key { - let r = base64::engine::general_purpose::STANDARD - .decode(sk) - .expect("key invalid; should be valid base64"); - r.try_into() - .expect("key has the wrong length; should be 32 bytes") - } else { - warn!("session_key not configured; generating a random one."); - [(); 32].map(|_| rand::random()) - } -}); - -pub fn create(username: String, permissions: PermissionSet, expire: Duration) -> String { - let session_data = SessionData { - expire: Utc::now() + expire, - username: username.to_owned(), - permissions, - }; - let mut plaintext = - bincode::serde::encode_to_vec(&session_data, bincode::config::standard()).unwrap(); - - while plaintext.len().is_multiple_of(16) { - plaintext.push(0); - } - - let cipher = aes_gcm_siv::Aes256GcmSiv::new_from_slice(&*SESSION_KEY).unwrap(); - let nonce = [(); 12].map(|_| rand::random()); - let mut ciphertext = cipher - .encrypt(&GenericArray::from(nonce), plaintext.as_slice()) - .unwrap(); - ciphertext.extend(nonce); - - base64::engine::general_purpose::URL_SAFE.encode(&ciphertext) -} - -pub fn validate(token: &str) -> anyhow::Result<String> { - let ciphertext = base64::engine::general_purpose::URL_SAFE.decode(token)?; - let cipher = aes_gcm_siv::Aes256GcmSiv::new_from_slice(&*SESSION_KEY).unwrap(); - let (ciphertext, nonce) = ciphertext.split_at(ciphertext.len() - 12); - let plaintext = cipher - .decrypt(nonce.into(), ciphertext) - .map_err(|e| anyhow!("decryption failed: {e:?}"))?; - - let (session_data, _): (SessionData, _) = - bincode::serde::decode_from_slice(&plaintext, bincode::config::standard())?; - - if session_data.expire < Utc::now() { - Err(anyhow!("session expired"))? - } - - Ok(session_data.username) -} - -pub fn token_to_session(token: &str) -> anyhow::Result<Session> { - let username = validate(token)?; - let user = DATABASE - .get_user(&username)? - .ok_or(anyhow!("user does not exist"))?; - Ok(Session { user }) -} -pub fn bypass_auth_session() -> anyhow::Result<Session> { - let user = DATABASE - .get_user(CONF.admin_username.as_ref().unwrap())? - .ok_or(anyhow!("user does not exist"))?; - Ok(Session { user }) -} - -#[cfg(test)] -fn load_test_config() { - use std::path::PathBuf; - - use crate::{CONF_PRELOAD, Config}; - *CONF_PRELOAD.lock().unwrap() = Some(Config { - database_path: PathBuf::default(), - login_expire: 10, - session_key: None, - admin_password: None, - admin_username: None, - }); -} - -#[test] -fn test() { - load_test_config(); - let tok = create( - "blub".to_string(), - jellycommon::user::PermissionSet::default(), - Duration::from_days(1), - ); - validate(&tok).unwrap(); -} - -#[test] -fn test_crypto() { - load_test_config(); - let nonce = [(); 12].map(|_| rand::random()); - let cipher = aes_gcm_siv::Aes256GcmSiv::new_from_slice(&*SESSION_KEY).unwrap(); - let plaintext = b"testing stuff---"; - let ciphertext = cipher - .encrypt(&GenericArray::from(nonce), plaintext.as_slice()) - .unwrap(); - let plaintext2 = cipher - .decrypt((&nonce).into(), ciphertext.as_slice()) - .unwrap(); - assert_eq!(plaintext, plaintext2.as_slice()); -} |