Skip to main content

secrets_core/
lease.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5use crate::storage::{StorageBackend, StorageEntry, StorageError};
6
7const LEASE_PREFIX: &str = "sys/leases/";
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Lease {
11    pub id: Uuid,
12    pub token_id_hash: String,
13    /// The `EngineMount::prefix` (see `router.rs`) that owns this lease and
14    /// must be asked to `revoke()` it.
15    pub engine_mount: String,
16    pub internal_data: serde_json::Value,
17    pub issued_at: DateTime<Utc>,
18    pub expires_at: DateTime<Utc>,
19}
20
21pub async fn store_lease(storage: &dyn StorageBackend, lease: &Lease) -> Result<(), StorageError> {
22    let path = format!("{LEASE_PREFIX}{}", lease.id);
23    let value = serde_json::to_vec(lease).map_err(|e| StorageError::Backend(e.to_string()))?;
24    storage
25        .put(
26            &path,
27            StorageEntry {
28                value,
29                expires_at: Some(lease.expires_at),
30            },
31        )
32        .await
33}
34
35pub async fn get_lease(storage: &dyn StorageBackend, id: Uuid) -> Result<Option<Lease>, StorageError> {
36    let path = format!("{LEASE_PREFIX}{id}");
37    let Some(entry) = storage.get(&path).await? else {
38        return Ok(None);
39    };
40    let lease: Lease =
41        serde_json::from_slice(&entry.value).map_err(|e| StorageError::Backend(e.to_string()))?;
42    Ok(Some(lease))
43}
44
45pub async fn delete_lease(storage: &dyn StorageBackend, id: Uuid) -> Result<(), StorageError> {
46    storage.delete(&format!("{LEASE_PREFIX}{id}")).await
47}
48
49/// Lists every lease currently persisted. Fine at v1 scale (single node, no
50/// distributed lock needed); a busier deployment would want this paginated
51/// or index-scanned by `expires_at` instead.
52pub async fn list_leases(storage: &dyn StorageBackend) -> Result<Vec<Lease>, StorageError> {
53    let keys = storage.list(LEASE_PREFIX).await?;
54    let mut leases = Vec::with_capacity(keys.len());
55    for key in keys {
56        if let Some(entry) = storage.get(&key).await?
57            && let Ok(lease) = serde_json::from_slice::<Lease>(&entry.value)
58        {
59            leases.push(lease);
60        }
61    }
62    Ok(leases)
63}