keystore_dump/
main.rs

1use color_eyre::eyre::Result;
2#[cfg(target_family = "wasm")]
3fn main() -> Result<()> {
4    println!("the keystore dump tool is not available for WASM");
5    Ok(())
6}
7
8#[cfg(not(target_family = "wasm"))]
9#[tokio::main]
10async fn main() -> Result<()> {
11    #[derive(Debug, clap::Parser)]
12    #[command(author, version, about, long_about = None)]
13    struct Args {
14        #[arg(short, long)]
15        /// The 256-bit database key, hex-encoded.
16        key: String,
17
18        path: String,
19    }
20
21    use chrono::TimeZone;
22    use clap::Parser as _;
23    use color_eyre::eyre::eyre;
24    use core_crypto_keystore::{Connection as Keystore, DatabaseKey, connection::FetchFromDatabase, entities::*};
25    use openmls::prelude::TlsDeserializeTrait;
26    use serde::ser::{SerializeMap, Serializer};
27
28    color_eyre::install()?;
29
30    let args = Args::parse();
31
32    if !tokio::fs::try_exists(&args.path).await.unwrap_or_default() {
33        return Err(eyre!("File not found: {}", args.path));
34    }
35
36    let key = DatabaseKey::try_from(hex::decode(&args.key)?.as_slice())?;
37    let keystore = Keystore::open_with_key(&args.path, &key)
38        .await
39        .map_err(|e| eyre!("The passkey is probably wrong; [err: {e}]"))?;
40
41    let mut json_serializer = serde_json::Serializer::pretty(std::io::stdout());
42    let mut json_map = json_serializer.serialize_map(None)?;
43
44    let mut credentials: Vec<serde_json::Value> = vec![];
45    for cred in keystore
46        .find_all::<MlsCredential>(Default::default())
47        .await?
48        .into_iter()
49    {
50        let mls_credential = openmls::prelude::Credential::tls_deserialize(&mut cred.credential.as_slice())?;
51        let date = chrono::Utc
52            .timestamp_opt(cred.created_at as i64, 0)
53            .single()
54            .ok_or_else(|| eyre!("Cannot parse credential creation date"))?;
55
56        credentials.push(serde_json::json!({
57            "id": cred.id,
58            "credential": mls_credential,
59            "created_at": date
60        }));
61    }
62    json_map.serialize_entry("mls_credentials", &credentials)?;
63
64    let mut signature_keypairs: Vec<serde_json::Value> = vec![];
65    for kp in keystore
66        .find_all::<MlsSignatureKeyPair>(Default::default())
67        .await?
68        .into_iter()
69    {
70        let mls_keypair = openmls_basic_credential::SignatureKeyPair::tls_deserialize(&mut kp.keypair.as_slice())?;
71        signature_keypairs.push(serde_json::json!({
72            "signature_scheme": kp.signature_scheme,
73            "mls_keypair": mls_keypair,
74            "credential_id": kp.credential_id,
75        }));
76    }
77    json_map.serialize_entry("mls_signature_keypairs", &signature_keypairs)?;
78
79    let hpke_sks: Vec<openmls_traits::types::HpkePrivateKey> = keystore
80        .find_all::<MlsHpkePrivateKey>(Default::default())
81        .await?
82        .into_iter()
83        .map(|hpke_sk| postcard::from_bytes::<openmls_traits::types::HpkePrivateKey>(&hpke_sk.sk))
84        .collect::<postcard::Result<_>>()?;
85    json_map.serialize_entry("mls_hpke_private_keys", &hpke_sks)?;
86
87    let hpke_keypairs: Vec<openmls_traits::types::HpkeKeyPair> = keystore
88        .find_all::<MlsEncryptionKeyPair>(Default::default())
89        .await?
90        .into_iter()
91        .map(|hpke_kp| postcard::from_bytes::<openmls_traits::types::HpkeKeyPair>(&hpke_kp.sk))
92        .collect::<postcard::Result<_>>()?;
93    json_map.serialize_entry("mls_hpke_keypairs", &hpke_keypairs)?;
94
95    let mut external_psks: std::collections::HashMap<String, openmls::schedule::psk::PskBundle> = Default::default();
96    for psk in keystore.find_all::<MlsPskBundle>(Default::default()).await?.into_iter() {
97        let mls_psk = postcard::from_bytes::<openmls::schedule::psk::PskBundle>(&psk.psk)?;
98        external_psks.insert(hex::encode(&psk.psk_id), mls_psk);
99    }
100
101    json_map.serialize_entry("external_psks", &external_psks)?;
102
103    let keypackages: Vec<openmls::prelude::KeyPackage> = keystore
104        .find_all::<MlsKeyPackage>(Default::default())
105        .await?
106        .into_iter()
107        .map(|kp| postcard::from_bytes::<openmls::prelude::KeyPackage>(&kp.keypackage))
108        .collect::<postcard::Result<_>>()?;
109    json_map.serialize_entry("mls_keypackages", &keypackages)?;
110
111    let e2ei_enrollments: Vec<core_crypto::prelude::E2eiEnrollment> = keystore
112        .find_all::<E2eiEnrollment>(Default::default())
113        .await?
114        .into_iter()
115        .map(|enrollment| serde_json::from_slice::<core_crypto::prelude::E2eiEnrollment>(&enrollment.content))
116        .collect::<serde_json::Result<_>>()?;
117    json_map.serialize_entry("e2ei_enrollments", &e2ei_enrollments)?;
118
119    let pgroups: Vec<openmls::prelude::MlsGroup> = keystore
120        .find_all::<PersistedMlsGroup>(Default::default())
121        .await?
122        .into_iter()
123        .map(|pgroup| core_crypto_keystore::deser::<openmls::prelude::MlsGroup>(&pgroup.state))
124        .collect::<core_crypto_keystore::CryptoKeystoreResult<_>>()?;
125    json_map.serialize_entry("mls_groups", &pgroups)?;
126
127    let pegroups: Vec<openmls::prelude::MlsGroup> = keystore
128        .find_all::<PersistedMlsPendingGroup>(Default::default())
129        .await?
130        .into_iter()
131        .map(|pgroup| core_crypto_keystore::deser::<openmls::prelude::MlsGroup>(&pgroup.state))
132        .collect::<core_crypto_keystore::CryptoKeystoreResult<_>>()?;
133    json_map.serialize_entry("mls_pending_groups", &pegroups)?;
134
135    if let Some(proteus_identity) = keystore.find::<ProteusIdentity>(&[]).await? {
136        let identity = {
137            let sk = proteus_identity.sk_raw();
138            let pk = proteus_identity.pk_raw();
139            proteus_wasm::keys::IdentityKeyPair::from_raw_key_pair(*sk, *pk)?
140        };
141        json_map.serialize_entry("proteus_identity", &identity)?;
142
143        let prekeys: Vec<proteus_wasm::keys::PreKey> = keystore
144            .find_all::<ProteusPrekey>(Default::default())
145            .await?
146            .into_iter()
147            .map(|pk| proteus_wasm::keys::PreKey::deserialise(&pk.prekey))
148            .collect::<Result<Vec<_>, proteus_wasm::DecodeError>>()?;
149        json_map.serialize_entry("proteus_prekeys", &prekeys)?;
150
151        let proteus_sessions: Vec<proteus_wasm::session::Session<proteus_wasm::keys::IdentityKeyPair>> = keystore
152            .find_all::<ProteusSession>(Default::default())
153            .await?
154            .into_iter()
155            .map(|session| proteus_wasm::session::Session::deserialise(identity.clone(), &session.session))
156            .collect::<Result<Vec<_>, proteus_wasm::DecodeError>>()?;
157
158        json_map.serialize_entry("proteus_sessions", &proteus_sessions)?;
159    }
160
161    json_map.end()?;
162
163    Ok(())
164}