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