reaching_link/
intermediary.rs1use std::collections::{HashMap, HashSet, VecDeque};
5
6use wasm_bindgen::prelude::*;
7use zeroize::Zeroizing;
8
9use reach_aliases::ReachRng;
10use reach_core::{
11 communication::Communicable,
12 memory::{
13 HintedEnvelopeId, Key, Message, MessageChunkMetadata, MessageOrder, OpenedEnvelope,
14 ReachingKeys,
15 },
16 wire::{
17 AttestantVerifyingKeys, CredentialVault, Envelope, EnvelopeId, MessageVaultId,
18 ReachableSignedKeys, RemoveEnvelopeIdHint, Salts,
19 },
20};
21
22use crate::memory::{ReachingSecrets, UnsignedReachingPublicKeys};
23
24#[wasm_bindgen]
25pub struct State {
26 pub(super) csprng: ReachRng,
27 pub(super) language: String,
28 pub(super) salts: Option<Salts>,
29 pub(super) attestant_verifying_keys: Option<AttestantVerifyingKeys>,
30 pub(super) passphrase: Option<Zeroizing<String>>,
31 pub(super) keys: Option<(ReachingSecrets, ReachingKeys, UnsignedReachingPublicKeys)>,
32 pub(super) reachable_signed_keys: VecDeque<Vec<ReachableSignedKeys>>,
33 pub(super) envelope_ids: HashSet<EnvelopeId>,
34 pub(super) envelopes: HashMap<MessageVaultId, (Envelope, OpenedEnvelope)>,
35 pub(super) envelope_seed_parts: Option<(Vec<ReachableSignedKeys>, Key, Vec<CredentialVault>)>,
36 pub(super) messages: Vec<Message>,
37}
38
39#[wasm_bindgen]
40impl State {
41 #[wasm_bindgen(constructor)]
42 pub fn new() -> Self {
43 Self::default()
44 }
45}
46
47impl Default for State {
48 fn default() -> Self {
49 let csprng = reach_core::memory::rng::<2048>().expect("Rng should initialize");
50
51 Self {
52 csprng,
53 language: "en".to_string(),
54 salts: None,
55 attestant_verifying_keys: None,
56 passphrase: None,
57 keys: None,
58 reachable_signed_keys: VecDeque::new(),
59 envelope_ids: HashSet::new(),
60 envelopes: HashMap::new(),
61 envelope_seed_parts: None,
62 messages: vec![],
63 }
64 }
65}
66
67#[wasm_bindgen]
68pub struct LinkHintedEnvelopeId {
69 envelope_id: Vec<u8>,
70 remove_envelope_id_hint: Vec<u8>,
71}
72
73impl From<&HintedEnvelopeId> for LinkHintedEnvelopeId {
74 fn from(value: &HintedEnvelopeId) -> Self {
75 LinkHintedEnvelopeId {
76 envelope_id: value.envelope_id.to_communication().encode(),
77 remove_envelope_id_hint: RemoveEnvelopeIdHint::from(value)
78 .to_communication()
79 .encode(),
80 }
81 }
82}
83
84#[wasm_bindgen]
85impl LinkHintedEnvelopeId {
86 pub fn envelope_id(&self) -> Vec<u8> {
87 self.envelope_id.clone()
88 }
89
90 pub fn remove_envelope_id_hint(&self) -> Vec<u8> {
91 self.remove_envelope_id_hint.clone()
92 }
93}
94
95#[wasm_bindgen]
96pub struct LinkMessage {
97 content: String,
98 language: String,
99 order: u64,
100 attachments: Vec<u8>,
101}
102
103#[wasm_bindgen]
104impl LinkMessage {
105 pub fn content(&self) -> String {
106 self.content.clone()
107 }
108
109 pub fn language(&self) -> String {
110 self.language.clone()
111 }
112
113 pub fn order(&self) -> u64 {
114 self.order
115 }
116
117 pub fn attachments(&self) -> Vec<u8> {
118 self.attachments.clone()
119 }
120}
121
122impl TryFrom<&Message> for LinkMessage {
123 type Error = LinkError;
124
125 fn try_from(message: &Message) -> Result<Self, Self::Error> {
126 let order = match message.order() {
127 MessageOrder::Relative(order) => Ok(*order),
128 _ => Err("Messages with absolute dates are not currently supported."),
129 }?;
130
131 let language = match &message.chunk.metadata {
132 MessageChunkMetadata::Language(language) => Ok(language.clone()),
133 _ => Err("Invalid message formatting"),
134 }?;
135
136 Ok(LinkMessage {
137 content: String::from_utf8(message.chunk.content.clone())?,
138 language,
139 order,
140 attachments: vec![],
141 })
142 }
143}
144
145#[wasm_bindgen]
146#[derive(Debug)]
147pub struct LinkError {
148 error: String,
149}
150
151#[wasm_bindgen]
152impl LinkError {
153 pub fn error(&self) -> String {
154 self.error.clone()
155 }
156}
157
158impl<T> From<T> for LinkError
159where
160 T: std::fmt::Display,
161{
162 fn from(value: T) -> Self {
163 Self {
164 error: format!("{}", value),
165 }
166 }
167}