breez_sdk_liquid/plugin/
storage.rs

1use aes::cipher::generic_array::GenericArray;
2use aes_gcm::{
3    aead::{Aead, OsRng},
4    AeadCore as _, Aes256Gcm, KeyInit as _, Nonce,
5};
6use anyhow::{bail, Result};
7
8use std::sync::{Arc, Weak};
9
10use crate::persist::Persister;
11
12#[derive(Clone)]
13pub struct PluginStorage {
14    plugin_id: String,
15    persister: Weak<Persister>,
16    cipher: Aes256Gcm,
17}
18
19#[derive(Debug, thiserror::Error)]
20pub enum PluginStorageError {
21    #[error("Could not encrypt storage data: {err}")]
22    Encryption { err: String },
23
24    #[error("Plugin storage operation failed: {err}")]
25    Generic { err: String },
26}
27
28impl From<aes_gcm::Error> for PluginStorageError {
29    fn from(value: aes_gcm::Error) -> Self {
30        Self::Encryption {
31            err: value.to_string(),
32        }
33    }
34}
35
36impl From<anyhow::Error> for PluginStorageError {
37    fn from(value: anyhow::Error) -> Self {
38        Self::Generic {
39            err: value.to_string(),
40        }
41    }
42}
43
44impl PluginStorage {
45    pub(crate) fn new(
46        persister: Weak<Persister>,
47        passphrase: &[u8],
48        plugin_id: String,
49    ) -> Result<Self> {
50        if plugin_id.is_empty() {
51            log::error!("Plugin ID cannot be an empty string!");
52            bail!("Plugin ID cannot be an empty string!");
53        }
54        let passphrase = GenericArray::clone_from_slice(passphrase);
55        let cipher = Aes256Gcm::new(&passphrase);
56
57        Ok(Self {
58            cipher,
59            persister,
60            plugin_id,
61        })
62    }
63
64    fn get_persister(&self) -> Result<Arc<Persister>, PluginStorageError> {
65        self.persister.upgrade().ok_or(PluginStorageError::Generic {
66            err: "SDK is not running.".to_string(),
67        })
68    }
69
70    fn encrypt(&self, data: String) -> Result<String, PluginStorageError> {
71        let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
72        let encrypted = self.cipher.encrypt(&nonce, data.as_bytes())?;
73        let mut payload = nonce.to_vec();
74        payload.extend_from_slice(&encrypted);
75        Ok(hex::encode(payload))
76    }
77
78    fn decrypt(&self, data: String) -> Result<String, PluginStorageError> {
79        let decoded = hex::decode(data).map_err(|err| PluginStorageError::Encryption {
80            err: err.to_string(),
81        })?;
82        let (nonce, data) = decoded.split_at(12);
83        let nonce = Nonce::from_slice(nonce);
84        let decrypted = self.cipher.decrypt(nonce, data)?;
85        let result =
86            String::from_utf8(decrypted).map_err(|err| PluginStorageError::Encryption {
87                err: err.to_string(),
88            })?;
89        Ok(result)
90    }
91
92    pub(crate) fn scoped_key(&self, key: &str) -> String {
93        format!("{}-{}", self.plugin_id, key)
94    }
95
96    pub fn set_item(&self, key: &str, value: String) -> Result<(), PluginStorageError> {
97        let scoped_key = self.scoped_key(key);
98        self.get_persister()?
99            .update_cached_item(&scoped_key, self.encrypt(value)?)
100            .map_err(Into::into)
101    }
102
103    pub fn get_item(&self, key: &str) -> Result<Option<String>, PluginStorageError> {
104        let scoped_key = self.scoped_key(key);
105        let value = self
106            .get_persister()?
107            .get_cached_item(&scoped_key)
108            .map_err(Into::<PluginStorageError>::into)?;
109        if let Some(value) = value {
110            return Ok(Some(self.decrypt(value)?));
111        }
112        Ok(None)
113    }
114
115    pub fn remove_item(&self, key: &str) -> Result<(), PluginStorageError> {
116        let scoped_key = self.scoped_key(key);
117        self.get_persister()?
118            .delete_cached_item(&scoped_key)
119            .map_err(Into::into)
120    }
121}