hatchery_keystore/
keyring.rs1use std::collections::BTreeSet;
5use std::path::PathBuf;
6
7use tesserax_keytree as kt;
8
9use crate::{HumanKey, Provisioned, Signature, Signer, SignerError};
10
11pub struct Keyring {
12 dir: PathBuf,
13 accounts: kt::MultiRoot<Signer>,
14}
15
16impl Keyring {
17 pub fn new(dir: impl Into<PathBuf>) -> Self {
18 Self { dir: dir.into(), accounts: kt::MultiRoot::new() }
19 }
20
21 fn path(&self, account: &str) -> Result<PathBuf, SignerError> {
22 let id = kt::branch_id(account).map_err(|_| SignerError::Denied("bad account id".into()))?;
23 Ok(self.dir.join(format!("{id}.sealed")))
24 }
25
26 pub fn enroll(&mut self, account: &str, human: &HumanKey) -> Result<(), SignerError> {
27 let mut s = Signer::init(self.path(account)?, human)?;
28 s.set_account(account)?;
29 self.accounts.insert(account, s).map_err(|_| SignerError::Denied("bad account id".into()))
30 }
31
32 pub fn unlock(&mut self, account: &str, human: &HumanKey) -> Result<(), SignerError> {
33 let mut s = Signer::open(self.path(account)?);
34 s.unlock(human)?;
35 if s.account()? != account {
36 return Err(SignerError::WrongHumanKey);
37 }
38 self.accounts.insert(account, s).map_err(|_| SignerError::Denied("bad account id".into()))
39 }
40
41 pub fn exists(&self, account: &str) -> bool {
43 self.path(account).map(|p| p.exists()).unwrap_or(false)
44 }
45
46 pub fn take_nodes(&mut self, account: &str, nodes: &[String]) -> Vec<String> {
49 let others: Vec<String> = self
50 .accounts
51 .iter()
52 .filter(|(a, s)| a.as_str() != account && nodes.iter().any(|n| s.has_node(n)))
53 .map(|(a, _)| a.clone())
54 .collect();
55 for a in &others {
56 self.accounts.remove(a);
57 }
58 others
59 }
60
61 pub fn lock(&mut self, account: &str) {
62 self.accounts.remove(account);
63 }
64
65 pub fn is_unlocked(&self, account: &str) -> bool {
66 self.accounts.get(account).is_some_and(Signer::is_unlocked)
67 }
68
69 pub fn branch(&mut self, account: &str) -> Result<&mut Signer, SignerError> {
70 self.accounts.get_mut(account).ok_or(SignerError::Locked)
71 }
72
73 pub fn account_of(token: &str) -> Result<String, SignerError> {
75 kt::unverified_fact(token, "account").map_err(|_| SignerError::BadToken)
76 }
77
78 pub fn account_for_node(&self, node: &str) -> Option<String> {
79 self.accounts.iter().find(|(_, s)| s.has_node(node)).map(|(a, _)| a.clone())
80 }
81
82 pub fn sign_from_node(&self, node: &str, token: &str, op: &str, payload: &[u8]) -> Result<Signature, SignerError> {
83 let account = Self::account_of(token)?;
84 self.accounts.get(&account).ok_or(SignerError::Locked)?.sign_from_node(node, token, op, payload)
85 }
86
87 pub fn sign(&self, token: &str, op: &str, payload: &[u8]) -> Result<Signature, SignerError> {
88 let account = Self::account_of(token)?;
89 self.accounts.get(&account).ok_or(SignerError::Locked)?.sign(token, op, payload)
90 }
91
92 pub fn m4a_vault_key(&self, node: &str, token: &str) -> Result<zeroize::Zeroizing<[u8; 32]>, SignerError> {
93 let account = Self::account_of(token)?;
94 self.accounts.get(&account).ok_or(SignerError::Locked)?.m4a_vault_key(node, token)
95 }
96
97 pub fn sign_m4a_keyproof(&self, node: &str, token: &str, message: &[u8]) -> Result<Signature, SignerError> {
98 let account = Self::account_of(token)?;
99 self.accounts.get(&account).ok_or(SignerError::Locked)?.sign_m4a_keyproof(node, token, message)
100 }
101
102 pub fn delegate(&self, token: &str, transport: &str) -> Result<String, SignerError> {
103 let account = Self::account_of(token)?;
104 self.accounts.get(&account).ok_or(SignerError::Locked)?.delegate(token, transport)
105 }
106
107 pub fn provision(&mut self, account: &str, node: &str, provider: &str, session: &str, rights: BTreeSet<String>, human: Option<&HumanKey>) -> Result<Provisioned, SignerError> {
108 self.branch(account)?.provision(node, provider, session, rights, human)
109 }
110
111 pub fn public_key_of(&self, account: &str, session: &str) -> Result<[u8; 32], SignerError> {
112 self.accounts.get(account).ok_or(SignerError::Locked)?.public_key_of(session)
113 }
114}