Skip to main content

mneme/crypto/
store.rs

1use crate::crypto::keys::RecipientKey;
2use chrono::Utc;
3use rusqlite::params;
4use std::sync::{Arc, Mutex};
5use uuid::Uuid;
6
7#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
8pub struct RegisteredKey {
9    pub id: Uuid,
10    pub alias: String,
11    pub key_type: String,
12    pub public_key: String,
13    pub is_default: bool,
14    pub added_at: chrono::DateTime<Utc>,
15}
16
17/// Persiste claves de encriptación en SQLite.
18pub struct KeyStore {
19    conn: Arc<Mutex<rusqlite::Connection>>,
20}
21
22impl KeyStore {
23    pub fn new(conn: Arc<Mutex<rusqlite::Connection>>) -> Self {
24        Self { conn }
25    }
26
27    /// Registra una nueva clave pública.
28    pub fn add(&self, alias: &str, key: &RecipientKey) -> crate::error::Result<RegisteredKey> {
29        let id = Uuid::new_v4();
30        let now = Utc::now().to_rfc3339();
31        let conn = self
32            .conn
33            .lock()
34            .map_err(|_| crate::error::MnemeError::Config("mutex poisoned".into()))?;
35        conn.execute(
36            "INSERT INTO encryption_keys (id, alias, key_type, public_key, is_default, added_at)
37             VALUES (?1, ?2, ?3, ?4, 0, ?5)",
38            params![
39                id.to_string(),
40                alias,
41                key.key_type(),
42                key.public_key_string(),
43                now
44            ],
45        )?;
46        Ok(RegisteredKey {
47            id,
48            alias: alias.to_string(),
49            key_type: key.key_type().to_string(),
50            public_key: key.public_key_string(),
51            is_default: false,
52            added_at: Utc::now(),
53        })
54    }
55
56    /// Elimina una clave por ID.
57    pub fn remove(&self, key_id: Uuid) -> crate::error::Result<()> {
58        let conn = self
59            .conn
60            .lock()
61            .map_err(|_| crate::error::MnemeError::Config("mutex poisoned".into()))?;
62        let n = conn.execute(
63            "DELETE FROM encryption_keys WHERE id = ?1",
64            params![key_id.to_string()],
65        )?;
66        if n == 0 {
67            return Err(crate::error::MnemeError::KeyNotFound(key_id.to_string()));
68        }
69        Ok(())
70    }
71
72    /// Lista todas las claves registradas.
73    pub fn list(&self) -> crate::error::Result<Vec<RegisteredKey>> {
74        let conn = self
75            .conn
76            .lock()
77            .map_err(|_| crate::error::MnemeError::Config("mutex poisoned".into()))?;
78        let mut stmt = conn.prepare(
79            "SELECT id, alias, key_type, public_key, is_default, added_at FROM encryption_keys ORDER BY added_at DESC"
80        )?;
81        let keys = stmt
82            .query_map([], |row| {
83                let id_str: String = row.get(0)?;
84                let added_str: String = row.get(5)?;
85                Ok((
86                    id_str,
87                    row.get::<_, String>(1)?,
88                    row.get::<_, String>(2)?,
89                    row.get::<_, String>(3)?,
90                    row.get::<_, bool>(4)?,
91                    added_str,
92                ))
93            })?
94            .filter_map(|r| r.ok())
95            .map(|(id_s, alias, key_type, public_key, is_default, added_s)| {
96                let id = Uuid::parse_str(&id_s).unwrap_or_else(|_| Uuid::new_v4());
97                let added_at = chrono::DateTime::parse_from_rfc3339(&added_s)
98                    .map(|d| d.with_timezone(&Utc))
99                    .unwrap_or_else(|_| Utc::now());
100                RegisteredKey {
101                    id,
102                    alias,
103                    key_type,
104                    public_key,
105                    is_default,
106                    added_at,
107                }
108            })
109            .collect();
110        Ok(keys)
111    }
112
113    /// Retorna la clave marcada como default.
114    pub fn get_default(&self) -> crate::error::Result<Option<RegisteredKey>> {
115        let all = self.list()?;
116        Ok(all.into_iter().find(|k| k.is_default))
117    }
118
119    /// Marca una clave como default (desmarca las demás).
120    pub fn set_default(&self, key_id: Uuid) -> crate::error::Result<()> {
121        let conn = self
122            .conn
123            .lock()
124            .map_err(|_| crate::error::MnemeError::Config("mutex poisoned".into()))?;
125        conn.execute("UPDATE encryption_keys SET is_default = 0", [])?;
126        let n = conn.execute(
127            "UPDATE encryption_keys SET is_default = 1 WHERE id = ?1",
128            params![key_id.to_string()],
129        )?;
130        if n == 0 {
131            return Err(crate::error::MnemeError::KeyNotFound(key_id.to_string()));
132        }
133        Ok(())
134    }
135
136    /// Carga todos los recipients para el CryptoEngine.
137    pub fn load_all_recipients(&self) -> crate::error::Result<Vec<RecipientKey>> {
138        let keys = self.list()?;
139        let mut recipients = Vec::new();
140        for key in keys {
141            match RecipientKey::from_string(&key.public_key) {
142                Ok(r) => recipients.push(r),
143                Err(e) => {
144                    tracing::warn!(key_id = %key.id, error = %e, "failed to parse registered key, skipping");
145                }
146            }
147        }
148        Ok(recipients)
149    }
150}