Skip to main content

uvb_storage_api/
enrollment.rs

1use async_trait::async_trait;
2use serde::{Deserialize, Serialize};
3use std::time::SystemTime;
4use thiserror::Error;
5use uvb_core::TenantId;
6
7#[derive(Debug, Error)]
8pub enum EnrollmentError {
9    #[error("enrollment not found")]
10    NotFound,
11    #[error("already enrolled")]
12    AlreadyEnrolled,
13    #[error("storage error: {0}")]
14    Storage(String),
15}
16
17/// Tracks which factors a user has enrolled in
18#[derive(Clone, Debug, Serialize, Deserialize)]
19pub struct EnrollmentRecord {
20    pub id: String,
21    pub user_id: String,
22    pub tenant_id: TenantId,
23    pub factor_id: String,
24    pub status: EnrollmentStatus,
25    pub display_name: Option<String>, // e.g., "iPhone 15", "YubiKey 5"
26    pub metadata: serde_json::Value,
27    pub enrolled_at: SystemTime,
28    pub last_used_at: Option<SystemTime>,
29    pub use_count: u64,
30}
31
32#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
33pub enum EnrollmentStatus {
34    Active,
35    Suspended,
36    Revoked,
37}
38
39/// Trait for pluggable enrollment storage
40#[async_trait]
41pub trait EnrollmentStore: Send + Sync {
42    /// Create a new enrollment
43    async fn create(&self, record: EnrollmentRecord) -> Result<String, EnrollmentError>;
44
45    /// Get a specific enrollment by ID
46    async fn get(&self, id: &str) -> Result<Option<EnrollmentRecord>, EnrollmentError>;
47
48    /// Check if user is enrolled in a specific factor
49    async fn is_enrolled(
50        &self,
51        user_id: &str,
52        tenant_id: &TenantId,
53        factor_id: &str,
54    ) -> Result<bool, EnrollmentError>;
55
56    /// List all enrollments for a user
57    async fn list_by_user(
58        &self,
59        user_id: &str,
60        tenant_id: &TenantId,
61    ) -> Result<Vec<EnrollmentRecord>, EnrollmentError>;
62
63    /// Update enrollment (e.g., status change, last_used)
64    async fn update(&self, record: EnrollmentRecord) -> Result<(), EnrollmentError>;
65
66    /// Delete/revoke an enrollment
67    async fn delete(&self, id: &str) -> Result<(), EnrollmentError>;
68
69    /// Record usage of a factor (increment counter, update timestamp)
70    async fn record_usage(&self, id: &str) -> Result<(), EnrollmentError>;
71}