breez_sdk_liquid/plugin/
storage.rs1use 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}