From e52b8e1c2e110d0feb74feb7905c2ff064b51d55 Mon Sep 17 00:00:00 2001 From: UMTS at Teleco Date: Sat, 13 Dec 2025 02:48:13 +0100 Subject: committing to insanity --- src/auth/session.rs | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 src/auth/session.rs (limited to 'src/auth/session.rs') diff --git a/src/auth/session.rs b/src/auth/session.rs new file mode 100644 index 0000000..277cef2 --- /dev/null +++ b/src/auth/session.rs @@ -0,0 +1,129 @@ +// Session management for SeckelAPI +use crate::config::Config; +use crate::models::Session; +use chrono::{Duration, Utc}; +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; +use uuid::Uuid; + +#[derive(Clone)] +pub struct SessionManager { + sessions: Arc>>, + config: Arc, +} + +impl SessionManager { + pub fn new(config: Arc) -> Self { + Self { + sessions: Arc::new(RwLock::new(HashMap::new())), + config, + } + } + + fn get_timeout_for_power(&self, power: i32) -> u64 { + self.config.get_session_timeout(power) + } + + pub fn create_session( + &self, + user_id: i32, + username: String, + role_id: i32, + role_name: String, + power: i32, + ) -> String { + let token = Uuid::new_v4().to_string(); + let now = Utc::now(); + + let session = Session { + user_id, + username, + role_id, + role_name, + power, + created_at: now, + last_accessed: now, + }; + + if let Ok(mut sessions) = self.sessions.write() { + // Check concurrent session limit for this user + let max_sessions = self.config.get_max_concurrent_sessions(power); + let user_sessions: Vec<(String, chrono::DateTime)> = sessions + .iter() + .filter(|(_, s)| s.user_id == user_id) + .map(|(token, s)| (token.clone(), s.created_at)) + .collect(); + + // If at limit, remove the oldest session + if user_sessions.len() >= max_sessions as usize { + if let Some(oldest_token) = user_sessions + .iter() + .min_by_key(|(_, created)| created) + .map(|(token, _)| token.clone()) + { + sessions.remove(&oldest_token); + } + } + + sessions.insert(token.clone(), session); + } + + token + } + + pub fn get_session(&self, token: &str) -> Option { + let mut session_to_update = None; + + { + if let Ok(sessions) = self.sessions.read() { + if let Some(session) = sessions.get(token) { + let now = Utc::now(); + let timeout_for_user = self.get_timeout_for_power(session.power); + let timeout_duration = Duration::minutes(timeout_for_user as i64); + + // Check if session has expired + if now - session.last_accessed > timeout_duration { + return None; // Session expired, will be cleaned up later + } else { + session_to_update = Some(session.clone()); + } + } + } + } + + if let Some(mut session) = session_to_update { + // Update last accessed time only if refresh_on_activity is enabled + if self.config.security.refresh_session_on_activity { + session.last_accessed = Utc::now(); + + if let Ok(mut sessions) = self.sessions.write() { + sessions.insert(token.to_string(), session.clone()); + } + } + + Some(session) + } else { + None + } + } + + pub fn remove_session(&self, token: &str) -> bool { + if let Ok(mut sessions) = self.sessions.write() { + sessions.remove(token).is_some() + } else { + false + } + } + + pub fn cleanup_expired_sessions(&self) { + let now = Utc::now(); + + if let Ok(mut sessions) = self.sessions.write() { + sessions.retain(|_, session| { + let timeout_for_user = self.get_timeout_for_power(session.power); + let timeout_duration = Duration::minutes(timeout_for_user as i64); + now - session.last_accessed <= timeout_duration + }); + } + } +} -- cgit v1.2.3-70-g09d2