1use std::path::Path;
4
5use matrix_sdk_store_encryption::{EncryptedValue, StoreCipher};
6use serde::{Deserialize, Serialize, de::DeserializeOwned};
7use tokio::fs;
8
9pub(super) struct SecretFile;
11
12impl SecretFile {
13 pub(super) async fn read<T: DeserializeOwned>(
15 path: &Path,
16 passphrase: &str,
17 ) -> Result<T, SecretFileError> {
18 let (cipher, encrypted_secret) = Self::read_inner(path, passphrase).await?;
19 let serialized_secret = cipher.decrypt_value_data(encrypted_secret)?;
20 Ok(rmp_serde::from_slice(&serialized_secret)?)
21 }
22
23 async fn read_inner(
24 path: &Path,
25 passphrase: &str,
26 ) -> Result<(StoreCipher, EncryptedValue), SecretFileError> {
27 let bytes = fs::read(&path).await?;
28 let content = rmp_serde::from_slice::<SecretFileContent>(&bytes)?;
29 let cipher = StoreCipher::import(passphrase, &content.encrypted_cipher)?;
30 Ok((cipher, content.encrypted_secret))
31 }
32
33 async fn get_or_create_cipher(
35 path: &Path,
36 passphrase: &str,
37 ) -> Result<StoreCipher, SecretFileError> {
38 let cipher = match Self::read_inner(path, passphrase).await {
39 Ok((cipher, _)) => cipher,
40 Err(_) => StoreCipher::new()?,
41 };
42 Ok(cipher)
43 }
44
45 pub(super) async fn write<T: Serialize>(
47 path: &Path,
48 passphrase: &str,
49 secret: &T,
50 ) -> Result<(), SecretFileError> {
51 let cipher = Self::get_or_create_cipher(path, passphrase).await?;
52 let encrypted_secret = cipher.encrypt_value_data(rmp_serde::to_vec_named(secret)?)?;
57 let encrypted_cipher = cipher.export(passphrase)?;
58 let bytes = rmp_serde::to_vec(&SecretFileContent {
59 encrypted_cipher,
60 encrypted_secret,
61 })?;
62 fs::write(path, bytes).await?;
63 Ok(())
64 }
65}
66
67#[derive(Serialize, Deserialize)]
68struct SecretFileContent {
69 #[serde(with = "serde_bytes")]
70 encrypted_cipher: Vec<u8>,
71 encrypted_secret: EncryptedValue,
72}
73
74#[derive(Debug, thiserror::Error)]
76pub(super) enum SecretFileError {
77 #[error(transparent)]
79 File(#[from] std::io::Error),
80
81 #[error(transparent)]
83 Decode(#[from] rmp_serde::decode::Error),
84
85 #[error(transparent)]
87 Encode(#[from] rmp_serde::encode::Error),
88
89 #[error(transparent)]
91 Encryption(#[from] matrix_sdk_store_encryption::Error),
92}