Overhaul refactor. Still things in progress

This commit is contained in:
2025-04-05 22:42:13 -04:00
parent 310d1eaad8
commit 769762dfa7
133 changed files with 119890 additions and 8784 deletions

View File

@@ -5,10 +5,10 @@ use redis::{AsyncCommands, RedisResult};
use crate::{
db::redis_async_connection,
error::{ApiError, ApiResult},
error::{Error, ApiResult},
};
use super::{csprng_128bit, hash, verify_hash};
use super::{csprng, hash, verify_hash};
pub const DEFAULT_SESSION_TTL: i64 = 86400; // (In seconds) 24 hours
pub const SESSION_COOKIE_NAME: &str = "session";
@@ -18,17 +18,21 @@ pub struct Session {
pub session_id: String,
pub email: String,
pub ip_address: String,
pub expires_at: DateTime<Utc>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expires_at: Option<DateTime<Utc>>,
}
impl Session {
pub fn new(email: &str, ip_address: &str) -> Self {
let now = chrono::Utc::now();
pub fn new(take: usize, email: &str, ip_address: &str, ttl: Option<i64>) -> Self {
let now = Utc::now();
Self {
session_id: csprng_128bit(32),
session_id: csprng(take),
email: email.to_string(),
ip_address: hash(&ip_address).unwrap(),
expires_at: now + chrono::Duration::seconds(DEFAULT_SESSION_TTL),
expires_at: match ttl {
Some(ttl) => Some(now + chrono::Duration::seconds(ttl)),
None => None,
},
}
}
@@ -36,7 +40,13 @@ impl Session {
let mut conn = redis_async_connection().await?;
let key = self.session_id.clone();
let value = serde_json::to_string(self)?;
let result: RedisResult<()> = conn.set_ex(key, &value, DEFAULT_SESSION_TTL as u64).await;
let result: RedisResult<()> = match self.expires_at {
Some(expires_at) => {
let ttl = expires_at.timestamp() - Utc::now().timestamp();
conn.set_ex(key, &value, ttl as u64).await
}
None => conn.set(key, value).await,
};
match result {
Ok(_) => Ok(()),
Err(err) => Err(err.into()),
@@ -66,26 +76,29 @@ impl Session {
// Check if the session exists
let session = match Self::get(session_id).await? {
Some(session) => session,
None => return Err(ApiError::new(401, "Session does not exist".to_string())),
None => return Err(Error::new(401, "Session does not exist".to_string())),
};
// Check if the IP Address matches the Session's IP Address
if verify_hash(ip_address, &session.ip_address) {
return Ok(session);
Ok(session)
} else {
return Err(ApiError::new(
401,
"IP Address does not match".to_string(),
));
Err(Error::new(401, "IP Address does not match".to_string()))
}
}
pub fn cookie(&self) -> Cookie {
pub fn to_cookie(&self) -> Cookie {
let expires_at = match self.expires_at {
Some(expires_at) => expires_at.timestamp(),
None => DEFAULT_SESSION_TTL,
};
let ttl = expires_at - Utc::now().timestamp();
Cookie::build(SESSION_COOKIE_NAME, self.session_id.clone())
.path("/")
.max_age(Duration::seconds(DEFAULT_SESSION_TTL))
.secure(true)
.http_only(true)
.max_age(Duration::seconds(ttl))
// TODO: enable secure and http_only
// .secure(true)
// .http_only(true)
.finish()
}
}