Refactor sessions management
This commit is contained in:
@ -1,40 +1,71 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use actix_identity::Identity;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::constants::{MAX_SESSION_DURATION, MIN_ACTIVITY_RECORD_TIME};
|
||||
use crate::data::user::User;
|
||||
use crate::utils::time::time;
|
||||
|
||||
pub struct SessionIdentity {
|
||||
pub id: String,
|
||||
pub is_admin: bool,
|
||||
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||
enum SessionStatus {
|
||||
SignedIn,
|
||||
NeedNewPassword,
|
||||
NeedMFA,
|
||||
}
|
||||
|
||||
impl SessionIdentity {
|
||||
pub fn from_user(user: &User) -> Self {
|
||||
Self {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct SessionIdentityData {
|
||||
pub id: String,
|
||||
pub is_admin: bool,
|
||||
last_access: u64,
|
||||
pub status: SessionStatus,
|
||||
}
|
||||
|
||||
pub struct SessionIdentity<'a>(pub &'a Identity);
|
||||
|
||||
impl<'a> SessionIdentity<'a> {
|
||||
pub fn set_user(&self, user: &User) {
|
||||
self.set_session_data(&SessionIdentityData {
|
||||
id: user.uid.clone(),
|
||||
is_admin: user.admin,
|
||||
}
|
||||
last_access: time(),
|
||||
status: SessionStatus::SignedIn,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn deserialize<D: Display>(input: D) -> Self {
|
||||
let input = input.to_string();
|
||||
let mut iter = input.split('-');
|
||||
Self {
|
||||
id: iter.next().unwrap_or_default().to_string(),
|
||||
is_admin: iter.next().unwrap_or_default() == "true",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize(&self) -> String {
|
||||
format!("{}-{}", self.id, self.is_admin)
|
||||
}
|
||||
|
||||
pub fn is_authenticated(i: &Identity) -> bool {
|
||||
i.identity()
|
||||
fn get_session_data(&self) -> Option<SessionIdentityData> {
|
||||
let mut res: Option<SessionIdentityData> = self.0.identity()
|
||||
.as_ref()
|
||||
.map(Self::deserialize)
|
||||
.map(|s| !s.id.is_empty())
|
||||
.map(String::as_str)
|
||||
.map(serde_json::from_str)
|
||||
.map(|f| f.expect("Failed to deserialize session data!"));
|
||||
|
||||
if let Some(session) = res.as_mut() {
|
||||
if session.last_access + MAX_SESSION_DURATION < time() {
|
||||
log::info!("Session is expired for {}", session.id);
|
||||
self.0.forget();
|
||||
return None;
|
||||
}
|
||||
|
||||
if session.last_access + MIN_ACTIVITY_RECORD_TIME < time() {
|
||||
log::debug!("Refresh last access for session");
|
||||
session.last_access = time();
|
||||
self.set_session_data(session);
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn set_session_data(&self, data: &SessionIdentityData) {
|
||||
let s = serde_json::to_string(data)
|
||||
.expect("Failed to serialize session data!");
|
||||
|
||||
self.0.remember(s);
|
||||
}
|
||||
|
||||
pub fn is_authenticated(&self) -> bool {
|
||||
self.get_session_data()
|
||||
.map(|s| s.status == SessionStatus::SignedIn)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user