lb_rs/service/
keychain.rs1use std::collections::HashMap;
2use std::sync::{Arc, RwLock};
3
4use crate::LocalLb;
5use crate::model::account::Account;
6use crate::model::crypto::AESKey;
7use crate::model::errors::{LbErrKind, LbResult};
8use db_rs::hasher::UuidIdentityHasherBuilder;
9use libsecp256k1::PublicKey;
10use tokio::sync::OnceCell;
11use uuid::Uuid;
12
13pub type KeyCache = Arc<RwLock<HashMap<Uuid, AESKey, UuidIdentityHasherBuilder>>>;
14
15#[derive(Default, Clone)]
16pub struct Keychain {
17 key_cache: KeyCache,
18 account: Arc<OnceCell<Account>>,
19 public_key: Arc<OnceCell<PublicKey>>,
20}
21
22impl From<Option<&Account>> for Keychain {
23 fn from(value: Option<&Account>) -> Self {
24 match value {
25 Some(account) => {
26 let account = account.clone();
27 let pk = account.public_key();
28 let key_cache = Default::default();
29
30 Self {
31 account: Arc::new(OnceCell::from(account)),
32 public_key: Arc::new(OnceCell::from(pk)),
33 key_cache,
34 }
35 }
36 None => Self::default(),
37 }
38 }
39}
40
41impl LocalLb {
42 pub fn get_account(&self) -> LbResult<&Account> {
43 self.keychain.get_account()
44 }
45}
46
47impl Keychain {
48 pub fn get_account(&self) -> LbResult<&Account> {
49 self.account
50 .get()
51 .ok_or_else(|| LbErrKind::AccountNonexistent.into())
52 }
53
54 pub fn get_pk(&self) -> LbResult<PublicKey> {
55 self.public_key
56 .get()
57 .copied()
58 .ok_or_else(|| LbErrKind::AccountNonexistent.into())
59 }
60
61 #[doc(hidden)]
62 pub async fn cache_account(&self, account: Account) -> LbResult<()> {
63 let pk = account.public_key();
64 self.account
65 .set(account)
66 .map_err(|_| LbErrKind::AccountExists)?;
67 self.public_key
68 .set(pk)
69 .map_err(|_| LbErrKind::AccountExists)?;
70
71 Ok(())
72 }
73
74 pub fn contains_aes_key(&self, id: &Uuid) -> LbResult<bool> {
75 Ok(self.key_cache.read()?.contains_key(id))
76 }
77
78 pub fn insert_aes_key(&self, id: Uuid, key: AESKey) -> LbResult<()> {
79 self.key_cache.write()?.insert(id, key);
80 Ok(())
81 }
82
83 pub fn get_aes_key(&self, id: &Uuid) -> LbResult<Option<AESKey>> {
84 Ok(self.key_cache.read()?.get(id).copied())
85 }
86}