bsv/auth/
session_manager.rs1use std::collections::{HashMap, HashSet};
10
11use super::types::PeerSession;
12
13pub struct SessionManager {
22 nonce_to_session: HashMap<String, PeerSession>,
24 identity_to_nonces: HashMap<String, HashSet<String>>,
26}
27
28impl SessionManager {
29 pub fn new() -> Self {
31 SessionManager {
32 nonce_to_session: HashMap::new(),
33 identity_to_nonces: HashMap::new(),
34 }
35 }
36
37 pub fn add_session(&mut self, session: PeerSession) {
43 let nonce = session.session_nonce.clone();
44 let identity = session.peer_identity_key.clone();
45
46 self.nonce_to_session.insert(nonce.clone(), session);
47
48 self.identity_to_nonces
49 .entry(identity)
50 .or_default()
51 .insert(nonce);
52 }
53
54 pub fn get_session(&self, nonce: &str) -> Option<&PeerSession> {
56 self.nonce_to_session.get(nonce)
57 }
58
59 pub fn get_session_mut(&mut self, nonce: &str) -> Option<&mut PeerSession> {
61 self.nonce_to_session.get_mut(nonce)
62 }
63
64 pub fn get_sessions_for_identity(&self, identity_key: &str) -> Vec<&PeerSession> {
66 match self.identity_to_nonces.get(identity_key) {
67 Some(nonces) => nonces
68 .iter()
69 .filter_map(|n| self.nonce_to_session.get(n))
70 .collect(),
71 None => Vec::new(),
72 }
73 }
74
75 pub fn get_session_by_identifier(&self, identifier: &str) -> Option<&PeerSession> {
81 if let Some(session) = self.nonce_to_session.get(identifier) {
83 return Some(session);
84 }
85
86 let nonces = self.identity_to_nonces.get(identifier)?;
88 let mut best: Option<&PeerSession> = None;
89 for nonce in nonces {
90 if let Some(session) = self.nonce_to_session.get(nonce) {
91 match best {
92 None => best = Some(session),
93 Some(b) => {
94 if session.is_authenticated && !b.is_authenticated {
96 best = Some(session);
97 }
98 }
99 }
100 }
101 }
102 best
103 }
104
105 pub fn has_session(&self, nonce: &str) -> bool {
107 self.nonce_to_session.contains_key(nonce)
108 }
109
110 pub fn has_session_by_identifier(&self, identifier: &str) -> bool {
112 if self.nonce_to_session.contains_key(identifier) {
113 return true;
114 }
115 match self.identity_to_nonces.get(identifier) {
116 Some(nonces) => !nonces.is_empty(),
117 None => false,
118 }
119 }
120
121 pub fn update_session(&mut self, nonce: &str, session: PeerSession) {
123 if let Some(old_session) = self.nonce_to_session.get(nonce) {
125 let old_identity = old_session.peer_identity_key.clone();
126 if old_identity != session.peer_identity_key {
127 if let Some(nonces) = self.identity_to_nonces.get_mut(&old_identity) {
128 nonces.remove(nonce);
129 if nonces.is_empty() {
130 self.identity_to_nonces.remove(&old_identity);
131 }
132 }
133 }
134 }
135
136 let new_identity = session.peer_identity_key.clone();
137 self.nonce_to_session.insert(nonce.to_string(), session);
138 self.identity_to_nonces
139 .entry(new_identity)
140 .or_default()
141 .insert(nonce.to_string());
142 }
143
144 pub fn remove_session(&mut self, nonce: &str) -> Option<PeerSession> {
146 if let Some(session) = self.nonce_to_session.remove(nonce) {
147 if let Some(nonces) = self.identity_to_nonces.get_mut(&session.peer_identity_key) {
149 nonces.remove(nonce);
150 if nonces.is_empty() {
151 self.identity_to_nonces.remove(&session.peer_identity_key);
152 }
153 }
154 Some(session)
155 } else {
156 None
157 }
158 }
159}
160
161impl Default for SessionManager {
162 fn default() -> Self {
163 Self::new()
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 fn make_session(nonce: &str, identity: &str, authenticated: bool) -> PeerSession {
172 PeerSession {
173 session_nonce: nonce.to_string(),
174 peer_identity_key: identity.to_string(),
175 peer_nonce: format!("peer_{}", nonce),
176 is_authenticated: authenticated,
177 }
178 }
179
180 #[test]
181 fn test_add_and_get_session() {
182 let mut mgr = SessionManager::new();
183 let session = make_session("nonce1", "id_key_A", true);
184 mgr.add_session(session.clone());
185
186 let retrieved = mgr.get_session("nonce1").unwrap();
187 assert_eq!(retrieved.session_nonce, "nonce1");
188 assert_eq!(retrieved.peer_identity_key, "id_key_A");
189 assert!(retrieved.is_authenticated);
190 }
191
192 #[test]
193 fn test_has_session() {
194 let mut mgr = SessionManager::new();
195 assert!(!mgr.has_session("nonce1"));
196
197 mgr.add_session(make_session("nonce1", "id_key_A", true));
198 assert!(mgr.has_session("nonce1"));
199 assert!(!mgr.has_session("nonce2"));
200 }
201
202 #[test]
203 fn test_remove_session() {
204 let mut mgr = SessionManager::new();
205 mgr.add_session(make_session("nonce1", "id_key_A", true));
206
207 let removed = mgr.remove_session("nonce1").unwrap();
208 assert_eq!(removed.session_nonce, "nonce1");
209 assert!(!mgr.has_session("nonce1"));
210
211 let sessions = mgr.get_sessions_for_identity("id_key_A");
213 assert!(sessions.is_empty());
214 }
215
216 #[test]
217 fn test_get_sessions_for_identity() {
218 let mut mgr = SessionManager::new();
219 mgr.add_session(make_session("nonce1", "id_key_A", true));
220 mgr.add_session(make_session("nonce2", "id_key_A", false));
221 mgr.add_session(make_session("nonce3", "id_key_B", true));
222
223 let a_sessions = mgr.get_sessions_for_identity("id_key_A");
224 assert_eq!(a_sessions.len(), 2);
225
226 let b_sessions = mgr.get_sessions_for_identity("id_key_B");
227 assert_eq!(b_sessions.len(), 1);
228
229 let c_sessions = mgr.get_sessions_for_identity("id_key_C");
230 assert!(c_sessions.is_empty());
231 }
232
233 #[test]
234 fn test_get_session_by_identifier() {
235 let mut mgr = SessionManager::new();
236 mgr.add_session(make_session("nonce1", "id_key_A", false));
237 mgr.add_session(make_session("nonce2", "id_key_A", true));
238
239 let s = mgr.get_session_by_identifier("nonce1").unwrap();
241 assert_eq!(s.session_nonce, "nonce1");
242
243 let best = mgr.get_session_by_identifier("id_key_A").unwrap();
245 assert!(best.is_authenticated);
246 }
247
248 #[test]
249 fn test_has_session_by_identifier() {
250 let mut mgr = SessionManager::new();
251 mgr.add_session(make_session("nonce1", "id_key_A", true));
252
253 assert!(mgr.has_session_by_identifier("nonce1"));
254 assert!(mgr.has_session_by_identifier("id_key_A"));
255 assert!(!mgr.has_session_by_identifier("unknown"));
256 }
257
258 #[test]
259 fn test_update_session() {
260 let mut mgr = SessionManager::new();
261 mgr.add_session(make_session("nonce1", "id_key_A", false));
262
263 let updated = make_session("nonce1", "id_key_A", true);
265 mgr.update_session("nonce1", updated);
266
267 let s = mgr.get_session("nonce1").unwrap();
268 assert!(s.is_authenticated);
269 }
270
271 #[test]
272 fn test_get_session_mut() {
273 let mut mgr = SessionManager::new();
274 mgr.add_session(make_session("nonce1", "id_key_A", false));
275
276 let s = mgr.get_session_mut("nonce1").unwrap();
277 s.is_authenticated = true;
278
279 let s2 = mgr.get_session("nonce1").unwrap();
280 assert!(s2.is_authenticated);
281 }
282
283 #[test]
284 fn test_remove_nonexistent() {
285 let mut mgr = SessionManager::new();
286 assert!(mgr.remove_session("nonexistent").is_none());
287 }
288
289 #[test]
290 fn test_identity_cleanup_on_remove_last_session() {
291 let mut mgr = SessionManager::new();
292 mgr.add_session(make_session("nonce1", "id_key_A", true));
293 mgr.add_session(make_session("nonce2", "id_key_A", true));
294
295 mgr.remove_session("nonce1");
296 assert!(mgr.has_session_by_identifier("id_key_A"));
298
299 mgr.remove_session("nonce2");
300 assert!(!mgr.has_session_by_identifier("id_key_A"));
302 }
303}