Skip to main content

fedimint_cli/
db.rs

1//! Database keys for fedimint-cli
2//!
3//! These keys use the UserData prefix (0xb0) as recommended for external/CLI
4//! data that shouldn't be in the core client database schema.
5
6use 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
14/// Sub-prefix for CLI-specific data under UserData (0xb0)
15const CLI_USER_DATA_SUB_PREFIX: u8 = 0x00;
16
17/// Get a CLI-specific database with the UserData prefix already applied
18pub 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/// Key prefix enum for CLI database keys
26#[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/// Key for storing admin credentials
45#[derive(Debug, Clone, Encodable, Decodable)]
46pub struct AdminCredsKey;
47
48/// The stored admin credentials value
49#[derive(Clone, Encodable, Decodable, Serialize, Deserialize)]
50pub struct StoredAdminCreds {
51    /// Guardian's own peer_id
52    pub peer_id: PeerId,
53    /// Authentication password (stored as String, will be wrapped in ApiAuth
54    /// when used)
55    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
73/// Load stored admin credentials from the CLI database
74pub 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
83/// Store admin credentials in the CLI database
84pub 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}