1use std::fmt;
7
8use fedimint_client::db::DbKeyPrefix as ClientDbKeyPrefix;
9use fedimint_core::db::{Database, IDatabaseTransactionOpsCoreTyped};
10use fedimint_core::encoding::{Decodable, Encodable};
11use fedimint_core::{PeerId, impl_db_record};
12use serde::{Deserialize, Serialize};
13
14const CLI_USER_DATA_SUB_PREFIX: u8 = 0x00;
16
17pub fn cli_database(db: &Database) -> Database {
19 db.with_prefix(vec![
20 ClientDbKeyPrefix::UserData as u8,
21 CLI_USER_DATA_SUB_PREFIX,
22 ])
23}
24
25#[repr(u8)]
27#[derive(Clone, Debug)]
28pub enum CliDbKeyPrefix {
29 AdminCreds = 0x00,
30}
31
32impl std::fmt::Display for CliDbKeyPrefix {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 write!(
35 f,
36 "{}",
37 match self {
38 CliDbKeyPrefix::AdminCreds => "AdminCreds",
39 }
40 )
41 }
42}
43
44#[derive(Debug, Clone, Encodable, Decodable)]
46pub struct AdminCredsKey;
47
48#[derive(Clone, Encodable, Decodable, Serialize, Deserialize)]
50pub struct StoredAdminCreds {
51 pub peer_id: PeerId,
53 pub auth: String,
56}
57
58impl fmt::Debug for StoredAdminCreds {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 f.debug_struct("StoredAdminCreds")
61 .field("peer_id", &self.peer_id)
62 .field("auth", &"<redacted>")
63 .finish()
64 }
65}
66
67impl_db_record!(
68 key = AdminCredsKey,
69 value = StoredAdminCreds,
70 db_prefix = CliDbKeyPrefix::AdminCreds,
71);
72
73pub async fn load_admin_creds(db: &Database) -> Option<StoredAdminCreds> {
75 let cli_db = cli_database(db);
76 cli_db
77 .begin_transaction_nc()
78 .await
79 .get_value(&AdminCredsKey)
80 .await
81}
82
83pub async fn store_admin_creds(db: &Database, creds: &StoredAdminCreds) {
85 let cli_db = cli_database(db);
86 let mut dbtx = cli_db.begin_transaction().await;
87 dbtx.insert_entry(&AdminCredsKey, creds).await;
88 dbtx.commit_tx().await;
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn stored_admin_creds_debug_redacts_auth() {
97 let auth = "admin-password";
98 let creds = StoredAdminCreds {
99 peer_id: PeerId::from(1),
100 auth: auth.to_owned(),
101 };
102
103 let debug = format!("{creds:?}");
104
105 assert!(!debug.contains(auth));
106 assert!(debug.contains(&format!("peer_id: {:?}", creds.peer_id)));
107 assert!(debug.contains(r#"auth: "<redacted>""#));
108 }
109}