use async_trait::async_trait;
use chrono::{DateTime, Utc};
use super::{Session, SessionId, User, UserId};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AuditAction {
TokenIssued,
TokenValidated,
TokenRejected,
TokenRevoked,
TokenRotated,
VaultRead,
VaultWrite,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AuditOutcome {
Success,
Failure,
}
#[derive(Debug, Clone)]
pub struct AuditEvent {
pub timestamp: DateTime<Utc>,
pub actor: Option<String>,
pub subject: String,
pub action: AuditAction,
pub outcome: AuditOutcome,
pub reason: Option<String>,
}
impl AuditEvent {
pub fn success(actor: Option<String>, subject: impl Into<String>, action: AuditAction) -> Self {
Self {
timestamp: Utc::now(),
actor,
subject: subject.into(),
action,
outcome: AuditOutcome::Success,
reason: None,
}
}
pub fn failure(
actor: Option<String>,
subject: impl Into<String>,
action: AuditAction,
reason: impl Into<String>,
) -> Self {
Self {
timestamp: Utc::now(),
actor,
subject: subject.into(),
action,
outcome: AuditOutcome::Failure,
reason: Some(reason.into()),
}
}
}
pub trait AuditSink: Send + Sync {
fn record(&self, event: AuditEvent);
}
pub trait RevocationStore: Send + Sync {
fn revoke(&self, jti: &str, exp: i64);
fn is_revoked(&self, jti: &str) -> bool;
}
#[async_trait]
pub trait UserStorage: Send + Sync {
async fn create(&self, user: &User) -> Result<(), String>;
async fn get_by_id(&self, id: &UserId) -> Result<Option<User>, String>;
async fn get_by_email(&self, email: &str) -> Result<Option<User>, String>;
async fn update(&self, user: &User) -> Result<(), String>;
async fn delete(&self, id: &UserId) -> Result<(), String>;
async fn list(&self) -> Result<Vec<User>, String>;
}
#[async_trait]
pub trait SessionStorage: Send + Sync {
async fn create(&self, session: &Session) -> Result<(), String>;
async fn get_by_id(&self, id: &SessionId) -> Result<Option<Session>, String>;
async fn update(&self, session: &Session) -> Result<(), String>;
async fn delete(&self, id: &SessionId) -> Result<(), String>;
async fn delete_by_user(&self, user_id: &str) -> Result<(), String>;
async fn delete_expired(&self) -> Result<usize, String>;
}
pub trait PasswordHasher: Send + Sync {
fn hash(&self, password: &str) -> Result<String, String>;
fn verify(&self, password: &str, hash: &str) -> bool;
}
#[derive(zeroize::ZeroizeOnDrop)]
pub struct DataKey {
pub plaintext: [u8; 32],
pub wrapped: Vec<u8>,
}
pub trait KeyManagementService: Send + Sync {
fn generate_data_key(&self) -> Result<DataKey, KmsError>;
fn decrypt_data_key(&self, wrapped: &[u8]) -> Result<[u8; 32], KmsError>;
}
#[derive(Debug, thiserror::Error)]
pub enum KmsError {
#[error("Failed to generate data key")]
GenerateFailed,
#[error("Failed to unwrap data key: tampered or wrong KEK")]
UnwrapFailed,
}
use crate::domain::vault::{VaultEntry, VaultError};
pub trait VaultStore: Send + Sync {
fn put(&self, key: &str, record: VaultEntry) -> Result<(), VaultError>;
fn get(&self, key: &str) -> Result<Option<VaultEntry>, VaultError>;
fn delete(&self, key: &str) -> Result<bool, VaultError>;
fn list_keys(&self) -> Result<Vec<String>, VaultError>;
}
pub trait RefreshTokenStore: Send + Sync {
fn insert_family(&self, family_id: &str, refresh_jti: &str, exp: i64);
fn rotate(
&self,
family_id: &str,
old_jti: &str,
new_jti: &str,
new_exp: i64,
) -> Result<(), bool>;
fn revoke_family(&self, family_id: &str);
}