Menu
Public repository / 01b0c3e49ec2c526bbda745999ffed8ebfa8b8ee
AkurAI-Drive / backend/src/session.rs
Latest change 6e3a0824f4ec4d2bea2524a20b4960c7ab9e2766 - backend: akurai-drive-api (OIDC RP + per-tenant S3 provisioning) by olibuijr
use axum::http::{HeaderMap, header};
use crate::db::with_db;
const SESSION_TTL_SECS: i64 = 30 * 24 * 60 * 60; // ~30 days
/// A live, non-expired session loaded from the `sessions` table.
pub struct Session {
pub sub: String,
pub email: String,
pub groups: Vec<String>,
pub tenant_id: Option<String>,
}
/// Read a named cookie value out of the request `Cookie` header.
pub fn get_cookie(headers: &HeaderMap, name: &str) -> Option<String> {
let cookies = headers.get(header::COOKIE)?.to_str().ok()?;
let prefix = format!("{name}=");
for part in cookies.split(';') {
let part = part.trim();
if let Some(value) = part.strip_prefix(&prefix) {
return Some(value.to_string());
}
}
None
}
/// Persist a new session row and return its random id (to set as `drive_session`).
pub fn create_session(
sub: &str,
email: &str,
groups: &[String],
tenant_id: Option<&str>,
) -> String {
let id = crate::util::token();
let now = chrono::Utc::now().timestamp();
let expires = now + SESSION_TTL_SECS;
let groups_json = serde_json::to_string(groups).unwrap_or_else(|_| "[]".to_string());
with_db(|conn| {
conn.execute(
"INSERT INTO sessions (id, sub, email, groups, tenant_id, created, expires)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
rusqlite::params![id, sub, email, groups_json, tenant_id, now, expires],
)
.expect("failed to insert session");
});
id
}
/// Look up the current session from the `drive_session` cookie. Expired rows are
/// rejected (and treated as no session).
pub fn lookup_session(headers: &HeaderMap) -> Option<Session> {
let id = get_cookie(headers, "drive_session")?;
let now = chrono::Utc::now().timestamp();
with_db(|conn| {
conn.query_row(
"SELECT sub, email, groups, tenant_id
FROM sessions WHERE id = ?1 AND expires > ?2",
rusqlite::params![id, now],
|row| {
let groups_json: String = row.get(2)?;
Ok(Session {
sub: row.get(0)?,
email: row.get(1)?,
groups: serde_json::from_str(&groups_json).unwrap_or_default(),
tenant_id: row.get(3)?,
})
},
)
.ok()
})
}
/// Delete a session row by id (used on logout).
pub fn delete_session(id: &str) {
with_db(|conn| {
conn.execute("DELETE FROM sessions WHERE id = ?1", rusqlite::params![id])
.ok();
});
}