Overhaul refactor. Still things in progress
This commit is contained in:
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user