1use std::ops::Deref;
6
7use wasm_bindgen::prelude::*;
8use zeroize::Zeroizing;
9
10use reach_core::{
11 ProstDecode, RandomFromRng,
12 communication::{Communicable, CommunicableOwned, Communication},
13 memory::{
14 Key, Message, MessageVaultLink, MessageVaultPassport, VerifyingKeys, shuffle_participants,
15 },
16 wire::{
17 AttestantVerifyingKeys, Envelope, Init, MessageVault, Reach, Salts, SealedMessageVaultId,
18 verify_signature_chains,
19 },
20};
21use reach_encryption::{
22 DecryptableWithNonce, Encryptable, HintTaker, Nonce, authenticated_encrypt_key,
23 build_envelope_seed,
24};
25use reach_passphrase::WORDLIST_EN_V0;
26use reach_signatures::Verifiable;
27use reach_visual_key_identity::visual_key_identity;
28
29pub mod intermediary;
30pub use intermediary::*;
31
32pub mod memory;
33use memory::*;
34
35pub mod utils;
36
37type Request = Communication<reach_core::wire::Request>;
38type Response = Communication<reach_core::wire::Response>;
39
40#[wasm_bindgen]
41pub fn set_attestant_verifying_keys(state: &mut State, bytes: Box<[u8]>) -> Result<(), LinkError> {
42 state.attestant_verifying_keys = Some(AttestantVerifyingKeys::decode(bytes)?);
43
44 Ok(())
45}
46
47#[wasm_bindgen]
48pub fn set_salts(state: &mut State, bytes: Box<[u8]>) -> Result<(), LinkError> {
49 let attestant_verifying_keys = get!(
50 &state.attestant_verifying_keys,
51 "Attestant Verifying Keys not set"
52 )?;
53 let salts = Salts::decode(bytes)?;
54
55 salts
56 .verify(attestant_verifying_keys)
57 .then(|| {
58 state.salts = Some(salts);
59 })
60 .ok_or("Could not verify Salts")?;
61
62 Ok(())
63}
64
65#[wasm_bindgen]
66pub fn set_language(state: &mut State, language: &str) {
67 state.language = language.to_string();
68}
69
70#[wasm_bindgen]
71pub fn get_attestant_visual_key_identity(state: &mut State) -> Result<String, LinkError> {
72 let attestant_verifying_keys = get!(
73 &state.attestant_verifying_keys,
74 "Attestant Verifying Keys not set"
75 )?;
76 let salts = get!(&state.salts, "Salts not set")?;
77
78 Ok(visual_key_identity(
79 attestant_verifying_keys,
80 &salts.attestant_identity,
81 )?)
82}
83
84#[wasm_bindgen]
85pub fn validate_passphrase(state: &mut State, passphrase: String) -> Result<(), LinkError> {
86 let passphrase = Zeroizing::new(passphrase);
87
88 let salts = get!(&state.salts, "Salts not set")?;
89
90 reach_passphrase::validate_passphrase(&passphrase, &salts.reaching_static, WORDLIST_EN_V0)
91 .map_err(|e| format!("{e:?}"))?;
92
93 state.passphrase = Some(passphrase);
94
95 Ok(())
96}
97
98#[wasm_bindgen]
99pub fn derive_secrets(state: &mut State) -> Result<(), LinkError> {
100 get!(
101 &state.attestant_verifying_keys,
102 "Attestant Verifying Keys not set"
103 )?;
104 let salts = get!(&state.salts, "Salts not set")?;
105 let passphrase = get!(&state.passphrase, "passhprase not set")?;
106
107 let secrets = ReachingSecrets::from_passphrase(passphrase, &WORDLIST_EN_V0, salts)
108 .map_err(|e| format!("{e:?}"))?;
109
110 let reaching_keys = secrets.reaching_keys(&mut state.csprng);
111 let previous_public_keys = secrets.previous_public_keys();
112
113 state.passphrase = None;
114 state.keys = Some((secrets, reaching_keys, previous_public_keys));
115
116 Ok(())
117}
118
119#[wasm_bindgen]
120pub fn generate_new_passphrase(state: &mut State) -> Result<String, LinkError> {
121 get!(
122 &state.attestant_verifying_keys,
123 "Attestant Verifying Keys not set"
124 )?;
125 let salts = get!(&state.salts, "Salts not set")?;
126
127 let passphrase = reach_passphrase::generate_passphrase(
128 WORDLIST_EN_V0,
129 &salts.reaching_static,
130 &mut state.csprng,
131 );
132 state.passphrase = Some(passphrase.clone());
133
134 Ok(passphrase.deref().clone())
135}
136
137#[wasm_bindgen]
138pub fn reach_init(_: &mut State) -> Result<Vec<u8>, LinkError> {
139 Ok(Init(0).to_communication().encode())
140}
141
142#[wasm_bindgen]
143pub fn reach(state: &mut State, bytes: Box<[u8]>) -> Result<Vec<LinkHintedEnvelopeId>, LinkError> {
144 let attestant_verifying_keys = get!(
145 &state.attestant_verifying_keys,
146 "Attestant Verifying Keys not set"
147 )?;
148 let salts = get!(&state.salts, "Salts not set")?;
149 let (secrets, _, _) = get!(&state.keys, "Reaching Secrets not set")?;
150
151 let communication = Response::decode(bytes)?;
152 let reach = Reach::try_from_communication(&communication)?;
153
154 verify_signature_chains(attestant_verifying_keys, &reach.reachable_signed_keys)?;
155
156 state
157 .reachable_signed_keys
158 .push_back(reach.reachable_signed_keys);
159
160 let hinted_envelope_ids_previous = secrets
161 .secret_keys_previous
162 .take_all_the_hints(&reach.envelope_id_hints, salts)?;
163 let hinted_envelope_ids_current = secrets
164 .secret_keys_current
165 .take_all_the_hints(&reach.envelope_id_hints, salts)?;
166
167 let mut hei_objects = Vec::new();
168
169 for hei in hinted_envelope_ids_previous
170 .iter()
171 .chain(hinted_envelope_ids_current.iter())
172 {
173 hei_objects.push(LinkHintedEnvelopeId::from(hei));
174 state.envelope_ids.insert(hei.envelope_id);
175 }
176
177 Ok(hei_objects)
178}
179
180#[wasm_bindgen]
181pub fn open_envelope(state: &mut State, bytes: Box<[u8]>) -> Result<Vec<u8>, LinkError> {
182 let salts = get!(&state.salts, "Salts not set")?;
183 let (secrets, reaching_keys, previous_public_keys) =
184 get!(&state.keys, "Reaching Secrets not set")?;
185
186 let communication = Response::decode(bytes)?;
187 let envelope = Envelope::try_from_communication(&communication)?;
188
189 let opened_envelope = reach_encryption::open_envelope(
190 &secrets.secret_keys_current,
191 &reaching_keys.public_keys,
192 &envelope,
193 salts,
194 )
195 .or(reach_encryption::open_envelope(
196 &secrets.secret_keys_previous,
197 previous_public_keys,
198 &envelope,
199 salts,
200 ))?;
201
202 let message_vault_id = match opened_envelope.message_vault_passport.message_vault_link {
203 MessageVaultLink::Link(message_vault_id) => Ok(message_vault_id),
204 MessageVaultLink::SealedLink(_) => Err("Encountered unexpected MessageLink::SealedLink"),
205 }?;
206
207 state
208 .envelopes
209 .insert(message_vault_id, (envelope, opened_envelope));
210
211 let mvi: Request = message_vault_id.to_communication();
212
213 Ok(mvi.encode())
214}
215
216#[wasm_bindgen]
217pub fn open_message_vault(state: &mut State, bytes: Box<[u8]>) -> Result<LinkMessage, LinkError> {
218 let communication = Response::decode(bytes)?;
219 let message_vault = MessageVault::try_from_communication(&communication)?;
220
221 let (envelope, opened_envelope) = state
222 .envelopes
223 .get(&message_vault.id)
224 .ok_or("No envelopes found for this message vault id")?;
225
226 let message = Message::decrypt_with_nonce(
227 &opened_envelope.credentials.key,
228 envelope.credential_vaults.nonce(),
229 &message_vault,
230 )?;
231
232 let link_message = LinkMessage::try_from(&message)?;
233 state.messages.push(message);
234
235 Ok(link_message)
236}
237
238#[wasm_bindgen]
239pub fn new_message_vault(state: &mut State, content: String) -> Result<Vec<u8>, LinkError> {
240 let salts = get!(&state.salts, "Salts not set")?;
241 let (secrets, reaching_keys, _) = get!(&state.keys, "Reaching Secrets not set")?;
242
243 let reachable_signed_keys = state
244 .reachable_signed_keys
245 .pop_front()
246 .ok_or("No Reachable Signed Keys available")?;
247
248 let msg = new_contact(content, state.language.clone(), reaching_keys);
249
250 let key = Key::random_from_rng(&mut state.csprng);
251 let credential_vaults = authenticated_encrypt_key(
252 &key,
253 &secrets.signing_keys,
254 &reaching_keys.verifying_keys,
255 &shuffle_participants(&reachable_signed_keys, None, &mut state.csprng),
256 salts,
257 &mut state.csprng,
258 )?;
259 let nonce = credential_vaults.nonce();
260
261 let message_vault_seed = msg
262 .encrypt_owned_with_nonce(&key, nonce)?
263 .to_communication();
264
265 state.envelope_seed_parts = Some((reachable_signed_keys, key, credential_vaults));
266
267 Ok(message_vault_seed.encode())
268}
269
270#[wasm_bindgen]
271pub fn new_envelope_seed(state: &mut State, bytes: Box<[u8]>) -> Result<Vec<u8>, LinkError> {
272 let ongoing_communication = state.envelope_seed_parts.take();
273 let (reachable_signed_keys, key, credential_vaults) =
274 get!(ongoing_communication, "Communication not initialised")?;
275
276 let (_, reaching_keys, _) = get!(&state.keys, "Reaching Secrets not set")?;
277
278 let communication = Response::decode(bytes)?;
279 let sealed_message_vault_id = SealedMessageVaultId::try_from_communication(&communication)?;
280
281 let message_vault_passport = MessageVaultPassport {
282 message_vault_link: MessageVaultLink::SealedLink(Box::new(sealed_message_vault_id)),
283 verifying_keys: VerifyingKeys::Reaching(reaching_keys.verifying_keys.clone()),
284 };
285
286 let envelope_seed: Request = build_envelope_seed(
287 message_vault_passport,
288 &reachable_signed_keys,
289 &key,
290 credential_vaults,
291 &mut state.csprng,
292 )?
293 .to_communication();
294
295 Ok(envelope_seed.encode())
296}