matrix_sdk_crypto/gossiping/
mod.rs1mod machine;
16
17use std::{
18 collections::{BTreeMap, BTreeSet},
19 sync::Arc,
20};
21
22pub(crate) use machine::GossipMachine;
23use matrix_sdk_common::locks::RwLock as StdRwLock;
24use ruma::{
25 events::{
26 room_key_request::{Action, ToDeviceRoomKeyRequestEventContent},
27 secret::request::{
28 RequestAction, SecretName, ToDeviceSecretRequestEvent as SecretRequestEvent,
29 ToDeviceSecretRequestEventContent as SecretRequestEventContent,
30 },
31 AnyToDeviceEventContent, ToDeviceEventType,
32 },
33 serde::Raw,
34 to_device::DeviceIdOrAllDevices,
35 DeviceId, OwnedDeviceId, OwnedTransactionId, OwnedUserId, TransactionId, UserId,
36};
37use serde::{Deserialize, Serialize};
38
39use crate::{
40 types::{
41 events::{
42 olm_v1::DecryptedSecretSendEvent,
43 room_key_request::{RoomKeyRequestContent, RoomKeyRequestEvent, SupportedKeyInfo},
44 },
45 requests::{OutgoingRequest, ToDeviceRequest},
46 },
47 Device,
48};
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct GossippedSecret {
59 pub secret_name: SecretName,
61 pub gossip_request: GossipRequest,
63 pub event: DecryptedSecretSendEvent,
65}
66
67#[cfg(feature = "automatic-room-key-forwarding")]
69#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
70pub enum KeyForwardDecision {
71 #[error("can't find an active outbound group session")]
74 MissingOutboundSession,
75 #[error("outbound session wasn't shared with the requesting device")]
78 OutboundSessionNotShared,
79 #[error("requesting device isn't trusted")]
81 UntrustedDevice,
82 #[error("the device has changed their curve25519 sender key")]
85 ChangedSenderKey,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct GossipRequest {
91 pub request_recipient: OwnedUserId,
93 pub request_id: OwnedTransactionId,
95 pub info: SecretInfo,
97 pub sent_out: bool,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
103pub enum SecretInfo {
104 KeyRequest(SupportedKeyInfo),
106 SecretRequest(SecretName),
108}
109
110impl SecretInfo {
111 pub fn as_key(&self) -> String {
114 match &self {
115 SecretInfo::KeyRequest(info) => {
116 format!("keyRequest:{}:{}:{}", info.room_id(), info.session_id(), info.algorithm())
117 }
118 SecretInfo::SecretRequest(sname) => format!("secretName:{sname}"),
119 }
120 }
121}
122
123impl<T> From<T> for SecretInfo
124where
125 T: Into<SupportedKeyInfo>,
126{
127 fn from(v: T) -> Self {
128 Self::KeyRequest(v.into())
129 }
130}
131
132impl From<SecretName> for SecretInfo {
133 fn from(i: SecretName) -> Self {
134 Self::SecretRequest(i)
135 }
136}
137
138impl GossipRequest {
139 pub(crate) fn from_secret_name(own_user_id: OwnedUserId, secret_name: SecretName) -> Self {
141 Self {
142 request_recipient: own_user_id,
143 request_id: TransactionId::new(),
144 info: secret_name.into(),
145 sent_out: false,
146 }
147 }
148
149 fn request_type(&self) -> &str {
150 match &self.info {
151 SecretInfo::KeyRequest(_) => "m.room_key_request",
152 SecretInfo::SecretRequest(s) => s.as_ref(),
153 }
154 }
155
156 fn to_request(&self, own_device_id: &DeviceId) -> OutgoingRequest {
157 let request = match &self.info {
158 SecretInfo::KeyRequest(r) => {
159 let content = RoomKeyRequestContent::new_request(
160 r.clone().into(),
161 own_device_id.to_owned(),
162 self.request_id.to_owned(),
163 );
164 let content = Raw::new(&content)
165 .expect("We can always serialize a room key request info")
166 .cast();
167
168 ToDeviceRequest::with_id_raw(
169 &self.request_recipient,
170 DeviceIdOrAllDevices::AllDevices,
171 content,
172 ToDeviceEventType::RoomKeyRequest,
173 self.request_id.clone(),
174 )
175 }
176 SecretInfo::SecretRequest(s) => {
177 let content =
178 AnyToDeviceEventContent::SecretRequest(SecretRequestEventContent::new(
179 RequestAction::Request(s.clone()),
180 own_device_id.to_owned(),
181 self.request_id.clone(),
182 ));
183
184 ToDeviceRequest::with_id(
185 &self.request_recipient,
186 DeviceIdOrAllDevices::AllDevices,
187 &content,
188 self.request_id.clone(),
189 )
190 }
191 };
192
193 OutgoingRequest { request_id: request.txn_id.clone(), request: Arc::new(request.into()) }
194 }
195
196 fn to_cancellation(&self, own_device_id: &DeviceId) -> OutgoingRequest {
197 let content = match self.info {
198 SecretInfo::KeyRequest(_) => {
199 AnyToDeviceEventContent::RoomKeyRequest(ToDeviceRoomKeyRequestEventContent::new(
200 Action::CancelRequest,
201 None,
202 own_device_id.to_owned(),
203 self.request_id.clone(),
204 ))
205 }
206 SecretInfo::SecretRequest(_) => {
207 AnyToDeviceEventContent::SecretRequest(SecretRequestEventContent::new(
208 RequestAction::RequestCancellation,
209 own_device_id.to_owned(),
210 self.request_id.clone(),
211 ))
212 }
213 };
214
215 let request = ToDeviceRequest::with_id(
216 &self.request_recipient,
217 DeviceIdOrAllDevices::AllDevices,
218 &content,
219 TransactionId::new(),
220 );
221
222 OutgoingRequest { request_id: request.txn_id.clone(), request: Arc::new(request.into()) }
223 }
224}
225
226impl PartialEq for GossipRequest {
227 fn eq(&self, other: &Self) -> bool {
228 let is_info_equal = match (&self.info, &other.info) {
229 (SecretInfo::KeyRequest(first), SecretInfo::KeyRequest(second)) => first == second,
230 (SecretInfo::SecretRequest(first), SecretInfo::SecretRequest(second)) => {
231 first == second
232 }
233 (SecretInfo::KeyRequest(_), SecretInfo::SecretRequest(_))
234 | (SecretInfo::SecretRequest(_), SecretInfo::KeyRequest(_)) => false,
235 };
236
237 self.request_id == other.request_id && is_info_equal
238 }
239}
240
241#[derive(Debug)]
242enum RequestEvent {
243 KeyShare(RoomKeyRequestEvent),
244 Secret(SecretRequestEvent),
245}
246
247impl From<SecretRequestEvent> for RequestEvent {
248 fn from(e: SecretRequestEvent) -> Self {
249 Self::Secret(e)
250 }
251}
252
253impl From<RoomKeyRequestEvent> for RequestEvent {
254 fn from(e: RoomKeyRequestEvent) -> Self {
255 Self::KeyShare(e)
256 }
257}
258
259impl RequestEvent {
260 fn to_request_info(&self) -> RequestInfo {
261 RequestInfo::new(
262 self.sender().to_owned(),
263 self.requesting_device_id().into(),
264 self.request_id().to_owned(),
265 )
266 }
267
268 fn sender(&self) -> &UserId {
269 match self {
270 RequestEvent::KeyShare(e) => &e.sender,
271 RequestEvent::Secret(e) => &e.sender,
272 }
273 }
274
275 fn requesting_device_id(&self) -> &DeviceId {
276 match self {
277 RequestEvent::KeyShare(e) => &e.content.requesting_device_id,
278 RequestEvent::Secret(e) => &e.content.requesting_device_id,
279 }
280 }
281
282 fn request_id(&self) -> &TransactionId {
283 match self {
284 RequestEvent::KeyShare(e) => &e.content.request_id,
285 RequestEvent::Secret(e) => &e.content.request_id,
286 }
287 }
288}
289
290#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
291struct RequestInfo {
292 sender: OwnedUserId,
293 requesting_device_id: OwnedDeviceId,
294 request_id: OwnedTransactionId,
295}
296
297impl RequestInfo {
298 fn new(
299 sender: OwnedUserId,
300 requesting_device_id: OwnedDeviceId,
301 request_id: OwnedTransactionId,
302 ) -> Self {
303 Self { sender, requesting_device_id, request_id }
304 }
305}
306
307#[derive(Clone, Debug, Default)]
310struct WaitQueue {
311 inner: Arc<StdRwLock<WaitQueueInner>>,
312}
313
314#[derive(Debug, Default)]
315struct WaitQueueInner {
316 requests_waiting_for_session: BTreeMap<RequestInfo, RequestEvent>,
317 requests_ids_waiting: BTreeMap<(OwnedUserId, OwnedDeviceId), BTreeSet<OwnedTransactionId>>,
318}
319
320impl WaitQueue {
321 fn new() -> Self {
322 Self::default()
323 }
324
325 #[cfg(all(test, feature = "automatic-room-key-forwarding"))]
326 fn is_empty(&self) -> bool {
327 let read_guard = self.inner.read();
328 read_guard.requests_ids_waiting.is_empty()
329 && read_guard.requests_waiting_for_session.is_empty()
330 }
331
332 fn insert(&self, device: &Device, event: RequestEvent) {
333 let request_id = event.request_id().to_owned();
334 let requests_waiting_key = RequestInfo::new(
335 device.user_id().to_owned(),
336 device.device_id().into(),
337 request_id.clone(),
338 );
339 let ids_waiting_key = (device.user_id().to_owned(), device.device_id().into());
340
341 let mut write_guard = self.inner.write();
342 write_guard.requests_waiting_for_session.insert(requests_waiting_key, event);
343 write_guard.requests_ids_waiting.entry(ids_waiting_key).or_default().insert(request_id);
344 }
345
346 fn remove(&self, user_id: &UserId, device_id: &DeviceId) -> Vec<(RequestInfo, RequestEvent)> {
347 let mut write_guard = self.inner.write();
348
349 write_guard
350 .requests_ids_waiting
351 .remove(&(user_id.to_owned(), device_id.into()))
352 .map(|request_ids| {
353 request_ids
354 .iter()
355 .filter_map(|id| {
356 let key =
357 RequestInfo::new(user_id.to_owned(), device_id.into(), id.to_owned());
358 write_guard.requests_waiting_for_session.remove_entry(&key)
359 })
360 .collect()
361 })
362 .unwrap_or_default()
363 }
364}