whatsapp_rust/features/
signal.rs1use anyhow::{Result, anyhow};
6use wacore::libsignal::protocol::{
7 CiphertextMessage, PreKeySignalMessage, SignalMessage, UsePQRatchet, message_decrypt,
8 message_encrypt,
9};
10use wacore::message_processing::EncType;
11use wacore::messages::MessageUtils;
12use wacore::types::jid::{JidExt, make_sender_key_name};
13use wacore_binary::Jid;
14use wacore_binary::Node;
15
16use crate::client::Client;
17
18pub struct Signal<'a> {
20 client: &'a Client,
21}
22
23impl<'a> Signal<'a> {
24 pub(crate) fn new(client: &'a Client) -> Self {
25 Self { client }
26 }
27
28 pub async fn encrypt_message(&self, jid: &Jid, plaintext: &[u8]) -> Result<(EncType, Vec<u8>)> {
36 let encryption_jid = self.client.resolve_encryption_jid(jid).await;
38 let signal_addr = encryption_jid.to_protocol_address();
39
40 let lock = self.client.session_lock_for(signal_addr.as_str()).await;
41 let _guard = lock.lock().await;
42 let mut adapter = self.client.signal_adapter().await;
43
44 let encrypted = message_encrypt(
45 plaintext,
46 &signal_addr,
47 &mut adapter.session_store,
48 &mut adapter.identity_store,
49 )
50 .await?;
51
52 drop(_guard);
53 self.client.flush_signal_cache().await?;
54
55 let (_, is_prekey, bytes) = wacore::send::extract_ciphertext(encrypted)
56 .ok_or_else(|| anyhow!("unexpected ciphertext variant"))?;
57 let enc_type = if is_prekey {
58 EncType::PreKeyMessage
59 } else {
60 EncType::Message
61 };
62 Ok((enc_type, bytes.into_vec()))
63 }
64
65 pub async fn decrypt_message(
73 &self,
74 jid: &Jid,
75 enc_type: EncType,
76 ciphertext: &[u8],
77 ) -> Result<Vec<u8>> {
78 let parsed = match enc_type {
79 EncType::PreKeyMessage => {
80 CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from(ciphertext)?)
81 }
82 EncType::Message => {
83 CiphertextMessage::SignalMessage(SignalMessage::try_from(ciphertext)?)
84 }
85 EncType::SenderKey => {
86 return Err(anyhow!("use decrypt_group_message for sender-key messages"));
87 }
88 };
89
90 let encryption_jid = self.client.resolve_encryption_jid(jid).await;
91 let signal_addr = encryption_jid.to_protocol_address();
92
93 let lock = self.client.session_lock_for(signal_addr.as_str()).await;
94 let _guard = lock.lock().await;
95 let mut adapter = self.client.signal_adapter().await;
96 let mut rng = rand::make_rng::<rand::rngs::StdRng>();
97
98 let plaintext = message_decrypt(
99 &parsed,
100 &signal_addr,
101 &mut adapter.session_store,
102 &mut adapter.identity_store,
103 &mut adapter.pre_key_store,
104 &adapter.signed_pre_key_store,
105 &mut rng,
106 UsePQRatchet::No,
107 )
108 .await?;
109
110 drop(_guard);
111 self.client.flush_signal_cache().await?;
112
113 Ok(plaintext.to_vec())
114 }
115
116 pub async fn encrypt_group_message(
127 &self,
128 group_jid: &Jid,
129 plaintext: &[u8],
130 ) -> Result<(Option<Vec<u8>>, Vec<u8>)> {
131 let own_jid = self.client.get_own_jid_for_group(group_jid).await?;
132 let sender_addr = own_jid.to_protocol_address();
133 let sender_key_name = make_sender_key_name(group_jid, &sender_addr);
134
135 let device_store = self.client.persistence_manager.get_device_arc().await;
137 let device_guard = device_store.read().await;
138 let key_exists = self
139 .client
140 .signal_cache
141 .get_sender_key(&sender_key_name, &*device_guard.backend)
142 .await?
143 .is_some();
144 drop(device_guard);
145
146 let mut adapter = self.client.signal_adapter().await;
147 let mut rng = rand::make_rng::<rand::rngs::StdRng>();
148
149 let skdm_bytes = if !key_exists {
150 Some(
151 wacore::send::create_sender_key_distribution_message_for_group(
152 &mut adapter.sender_key_store,
153 group_jid,
154 &sender_addr,
155 )
156 .await?,
157 )
158 } else {
159 None
160 };
161
162 let ciphertext = wacore::send::encrypt_group_message(
163 &mut adapter.sender_key_store,
164 group_jid,
165 &sender_addr,
166 plaintext,
167 &mut rng,
168 )
169 .await?;
170
171 self.client.flush_signal_cache().await?;
172
173 Ok((skdm_bytes, ciphertext.into_serialized().into_vec()))
174 }
175
176 pub async fn decrypt_group_message(
184 &self,
185 group_jid: &Jid,
186 sender_jid: &Jid,
187 ciphertext: &[u8],
188 ) -> Result<Vec<u8>> {
189 let sender_key_name =
190 make_sender_key_name(group_jid, &sender_jid.to_non_ad().to_protocol_address());
191
192 let mut adapter = self.client.signal_adapter().await;
193
194 let plaintext = wacore::libsignal::protocol::group_decrypt(
195 ciphertext,
196 &mut adapter.sender_key_store,
197 &sender_key_name,
198 )
199 .await?;
200
201 self.client.flush_signal_cache().await?;
202
203 Ok(plaintext.to_vec())
204 }
205
206 pub async fn validate_session(&self, jid: &Jid) -> Result<bool> {
211 let resolved = self.client.resolve_encryption_jid(jid).await;
212 let signal_addr = resolved.to_protocol_address();
213 let device_store = self.client.persistence_manager.get_device_arc().await;
214 let device_guard = device_store.read().await;
215 self.client
216 .signal_cache
217 .has_session(&signal_addr, &*device_guard.backend)
218 .await
219 .map_err(|e| anyhow!("session check failed: {e}"))
220 }
221
222 pub async fn delete_sessions(&self, jids: &[Jid]) -> Result<()> {
231 for jid in jids {
232 let resolved = self.client.resolve_encryption_jid(jid).await;
233 let addr = resolved.to_protocol_address();
234
235 let lock = self.client.session_lock_for(addr.as_str()).await;
236 let _guard = lock.lock().await;
237
238 self.client.signal_cache.delete_session(&addr).await;
240 self.client.signal_cache.delete_identity(&addr).await;
241 }
242
243 self.client.flush_signal_cache().await?;
244 Ok(())
245 }
246
247 pub async fn create_participant_nodes(
254 &self,
255 recipient_jids: &[Jid],
256 message: &waproto::whatsapp::Message,
257 ) -> Result<(Vec<Node>, bool)> {
258 let device_jids = self.client.get_user_devices(recipient_jids).await?;
259 self.client.ensure_e2e_sessions(&device_jids).await?;
260
261 let lock_jids = self.client.build_session_lock_keys(&device_jids).await;
263 let session_mutexes = self.client.session_mutexes_for(&lock_jids).await;
264 let mut _session_guards = Vec::with_capacity(session_mutexes.len());
265 for mutex in &session_mutexes {
266 _session_guards.push(mutex.lock().await);
267 }
268
269 let plaintext = MessageUtils::encode_and_pad(message);
270 let mut adapter = self.client.signal_adapter().await;
271 let mediatype = wacore::send::media_type_from_message(message);
272 let hide_decrypt_fail = wacore::send::should_hide_decrypt_fail(message);
273
274 let mut stores = adapter.as_signal_stores();
275 let result = wacore::send::encrypt_for_devices(
276 &*self.client.runtime,
277 &mut stores,
278 self.client,
279 &device_jids,
280 &plaintext,
281 hide_decrypt_fail,
282 mediatype,
283 )
284 .await?;
285
286 drop(_session_guards);
287 self.client.flush_signal_cache().await?;
288
289 Ok((result.participant_nodes, result.includes_prekey_message))
290 }
291
292 pub async fn assert_sessions(&self, jids: &[Jid]) -> Result<()> {
294 self.client.ensure_e2e_sessions(jids).await
295 }
296
297 pub async fn get_user_devices(&self, jids: &[Jid]) -> Result<Vec<Jid>> {
299 self.client.get_user_devices(jids).await
300 }
301}
302
303impl Client {
304 pub fn signal(&self) -> Signal<'_> {
306 Signal::new(self)
307 }
308}