1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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<RwLock<HashMap<String, Session>>>,
config: Arc<Config>,
}
impl SessionManager {
pub fn new(config: Arc<Config>) -> 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<Utc>)> = 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<Session> {
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
});
}
}
}
|