Files
zesdex/crates/zesdex-iam/src/infrastructure/persistence/session_repo.rs
T
asepharyana 1f0ae9f551 Refactor and clean up code across multiple modules
- Simplified token type assignment in OAuth service.
- Removed unused session_lock module and re-exported Session from zesdex_entities.
- Cleaned up session entity by removing unnecessary comments and code.
- Consolidated session handling in HTTP handlers for better readability.
- Improved formatting and readability in OAuth repository tests.
- Enhanced session lock repository with clearer match statements.
- Streamlined session repository error handling.
- Refined RNG tests for better clarity.
- Adjusted module visibility and organization in lib.rs.
- Updated IPC client and connection code for better error handling and clarity.
- Improved frame handling in IPC for better readability.
- Organized module imports and added test utilities for IPC.
- Enhanced database connection error handling.
- Simplified JWT token creation error handling.
- Improved password verification error handling.
- Cleaned up state management code for better readability.
- Refactored middleware for session authentication and rate limiting.
- Simplified clipboard utility for better error handling.
- Enhanced logging initialization for better error reporting.
- Improved pagination utility with clearer method annotations.
- Cleaned up sanitization functions for filenames and paths.
- Enhanced slug generation functions for better clarity and usability.
2026-07-17 09:08:41 +07:00

89 lines
3.1 KiB
Rust

#![allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_precision_loss,
clippy::cast_possible_wrap
)]
//! Filesystem-backed `SessionRepository` implementation.
//!
//! Each session is stored as `<base_dir>/sessions/<id>/session.json`.
//! Writes use a write-then-rename + fsync pattern for crash safety.
use std::path::Path;
use crate::domain::repository::SessionRepository;
use crate::domain::session::Session;
/// Concrete filesystem session repository.
#[derive(Debug, Clone, Default)]
pub struct FileSystemSessionRepository;
impl FileSystemSessionRepository {
/// Create a new filesystem session repository.
pub fn new() -> Self {
FileSystemSessionRepository
}
}
impl SessionRepository for FileSystemSessionRepository {
fn list_sessions(&self, base_dir: &Path) -> anyhow::Result<Vec<Session>> {
let sessions_dir = base_dir.join("sessions");
let Ok(entries) = std::fs::read_dir(&sessions_dir) else {
return Ok(Vec::new());
};
let mut sessions = Vec::new();
for entry in entries.flatten() {
if !entry.path().is_dir() {
continue;
}
let id = entry.file_name().to_string_lossy().to_string();
if let Ok(session) = self.load_session(base_dir, &id) {
sessions.push(session);
}
}
Ok(sessions)
}
fn load_session(&self, base_dir: &Path, id: &str) -> anyhow::Result<Session> {
// Directory-traversal prevention.
if id.contains('/') || id.contains('\\') || id.contains("..") {
anyhow::bail!("invalid session id '{id}': must not contain path separators");
}
let path = base_dir.join("sessions").join(id).join("session.json");
if !path.exists() {
anyhow::bail!("session not found: {id}");
}
let data = std::fs::read_to_string(&path)?;
let session: Session = serde_json::from_str(&data)?;
Ok(session)
}
fn save_session(&self, base_dir: &Path, session: &Session) -> anyhow::Result<()> {
let dir = session.session_dir(base_dir);
std::fs::create_dir_all(&dir)?;
let path = dir.join("session.json");
let data = serde_json::to_string_pretty(session)?;
let tmp = dir.join("session.json.tmp");
std::fs::write(&tmp, data)?;
// fsync before rename ensures the data is on disk.
let f = std::fs::File::open(&tmp)?;
f.sync_all()?;
std::fs::rename(&tmp, path)?;
// fsync the parent directory so the rename survives a crash.
if let Some(parent) = dir.parent() {
let _ = std::fs::File::open(parent).and_then(|d| d.sync_all());
}
Ok(())
}
fn delete_session(&self, base_dir: &Path, id: &str) -> anyhow::Result<()> {
if id.contains('/') || id.contains('\\') || id.contains("..") {
anyhow::bail!("invalid session id '{id}': must not contain path separators");
}
let dir = base_dir.join("sessions").join(id);
if dir.exists() {
std::fs::remove_dir_all(&dir)?;
}
Ok(())
}
}