vs_store/store/
auth_blobs.rs1use rusqlite::params;
4
5use super::{epoch_secs, Store};
6use crate::auth::{decrypt, encrypt, EncryptedBlob, MasterKey};
7use crate::error::{Result, StoreError};
8use crate::types::AuthBlobMeta;
9
10impl Store {
11 pub fn save_auth(&mut self, name: &str, key: &MasterKey, plaintext: &[u8]) -> Result<()> {
14 let blob = encrypt(key, plaintext)?;
15 let now = epoch_secs();
16 self.conn().execute(
17 "INSERT INTO auth_blobs(name, ciphertext, nonce, created_at, last_used_at)
18 VALUES (?1, ?2, ?3, ?4, NULL)
19 ON CONFLICT(name) DO UPDATE
20 SET ciphertext=excluded.ciphertext,
21 nonce=excluded.nonce,
22 created_at=excluded.created_at,
23 last_used_at=NULL",
24 params![name, blob.ciphertext, blob.nonce.to_vec(), now],
25 )?;
26 Ok(())
27 }
28
29 pub fn load_auth(&mut self, name: &str, key: &MasterKey) -> Result<Vec<u8>> {
31 let (ciphertext, nonce_vec) = {
32 let mut stmt = self
33 .conn()
34 .prepare("SELECT ciphertext, nonce FROM auth_blobs WHERE name=?1")?;
35 let mut rows = stmt.query([name])?;
36 let row = rows.next()?.ok_or(StoreError::NotFound {
37 kind: "auth_blob",
38 id: name.to_string(),
39 })?;
40 let c: Vec<u8> = row.get(0)?;
41 let n: Vec<u8> = row.get(1)?;
42 (c, n)
43 };
44 if nonce_vec.len() != 12 {
45 return Err(StoreError::Crypto("nonce shape"));
46 }
47 let mut nonce = [0u8; 12];
48 nonce.copy_from_slice(&nonce_vec);
49 let plaintext = decrypt(key, &EncryptedBlob { ciphertext, nonce })?;
50 let now = epoch_secs();
51 self.conn().execute(
52 "UPDATE auth_blobs SET last_used_at=?2 WHERE name=?1",
53 params![name, now],
54 )?;
55 Ok(plaintext)
56 }
57
58 pub fn list_auth(&self) -> Result<Vec<AuthBlobMeta>> {
59 let mut stmt = self
60 .conn()
61 .prepare("SELECT name, created_at, last_used_at FROM auth_blobs ORDER BY name ASC")?;
62 let rows = stmt.query_map([], AuthBlobMeta::from_row)?;
63 Ok(rows.collect::<rusqlite::Result<Vec<_>>>()?)
64 }
65
66 pub fn delete_auth(&mut self, name: &str) -> Result<()> {
67 let n = self
68 .conn()
69 .execute("DELETE FROM auth_blobs WHERE name=?1", params![name])?;
70 if n == 0 {
71 return Err(StoreError::NotFound {
72 kind: "auth_blob",
73 id: name.to_string(),
74 });
75 }
76 Ok(())
77 }
78}