Skip to main content

matrix_sdk_crypto/store/
traits.rs

1// Copyright 2023, 2026 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{collections::HashMap, fmt, sync::Arc};
16
17use async_trait::async_trait;
18use matrix_sdk_common::{AsyncTraitDeps, cross_process_lock::CrossProcessLockGeneration};
19use ruma::{
20    DeviceId, OwnedDeviceId, RoomId, TransactionId, UserId, events::secret::request::SecretName,
21};
22use vodozemac::Curve25519PublicKey;
23use zeroize::Zeroizing;
24
25use super::{
26    CryptoStoreError, Result,
27    types::{
28        BackupKeys, Changes, DehydratedDeviceKey, PendingChanges, RoomKeyCounts, RoomSettings,
29        StoredRoomKeyBundleData, TrackedUser,
30    },
31};
32#[cfg(doc)]
33use crate::olm::SenderData;
34use crate::{
35    Account, DeviceData, GossipRequest, SecretInfo, UserIdentityData,
36    olm::{
37        InboundGroupSession, OlmMessageHash, OutboundGroupSession, PrivateCrossSigningIdentity,
38        SenderDataType, Session,
39    },
40    store::types::{RoomKeyWithheldEntry, RoomPendingKeyBundleDetails},
41};
42
43/// Represents a store that the `OlmMachine` uses to store E2EE data (such as
44/// cryptographic keys).
45#[cfg_attr(target_family = "wasm", async_trait(?Send))]
46#[cfg_attr(not(target_family = "wasm"), async_trait)]
47pub trait CryptoStore: AsyncTraitDeps {
48    /// The error type used by this crypto store.
49    type Error: fmt::Debug + Into<CryptoStoreError>;
50
51    /// Load an account that was previously stored.
52    async fn load_account(&self) -> Result<Option<Account>, Self::Error>;
53
54    /// Try to load a private cross signing identity, if one is stored.
55    async fn load_identity(&self) -> Result<Option<PrivateCrossSigningIdentity>, Self::Error>;
56
57    /// Save the set of changes to the store.
58    ///
59    /// # Arguments
60    ///
61    /// * `changes` - The set of changes that should be stored.
62    async fn save_changes(&self, changes: Changes) -> Result<(), Self::Error>;
63
64    /// Save the set of changes to the store.
65    ///
66    /// This is an updated version of `save_changes` that will replace it as
67    /// #2624 makes progress.
68    ///
69    /// # Arguments
70    ///
71    /// * `changes` - The set of changes that should be stored.
72    async fn save_pending_changes(&self, changes: PendingChanges) -> Result<(), Self::Error>;
73
74    /// Save a list of inbound group sessions to the store.
75    ///
76    /// # Arguments
77    ///
78    /// * `sessions` - The sessions to be saved.
79    /// * `backed_up_to_version` - If the keys should be marked as having been
80    ///   backed up, the version of the backup.
81    ///
82    /// Note: some implementations ignore `backup_version` and assume the
83    /// current backup version, which is normally the same.
84    async fn save_inbound_group_sessions(
85        &self,
86        sessions: Vec<InboundGroupSession>,
87        backed_up_to_version: Option<&str>,
88    ) -> Result<(), Self::Error>;
89
90    /// Get all the sessions that belong to the given sender key.
91    ///
92    /// # Arguments
93    ///
94    /// * `sender_key` - The sender key that was used to establish the sessions.
95    async fn get_sessions(&self, sender_key: &str) -> Result<Option<Vec<Session>>, Self::Error>;
96
97    /// Get the inbound group session from our store.
98    ///
99    /// # Arguments
100    /// * `room_id` - The room id of the room that the session belongs to.
101    ///
102    /// * `sender_key` - The sender key that sent us the session.
103    ///
104    /// * `session_id` - The unique id of the session.
105    async fn get_inbound_group_session(
106        &self,
107        room_id: &RoomId,
108        session_id: &str,
109    ) -> Result<Option<InboundGroupSession>, Self::Error>;
110
111    /// Get withheld info for this key.
112    /// Allows to know if the session was not sent on purpose.
113    /// This only returns withheld info sent by the owner of the group session,
114    /// not the one you can get from a response to a key request from
115    /// another of your device.
116    async fn get_withheld_info(
117        &self,
118        room_id: &RoomId,
119        session_id: &str,
120    ) -> Result<Option<RoomKeyWithheldEntry>, Self::Error>;
121
122    /// Get all the sessions where we have received an `m.room_key.withheld`
123    /// event (or, post-[MSC4268], where there was a `withheld` entry in the key
124    /// bundle).
125    ///
126    /// [MSC4268]: https://github.com/matrix-org/matrix-spec-proposals/pull/4268
127    ///
128    /// # Arguments
129    /// * `room_id` - The ID of the room to return withheld sessions for.
130    async fn get_withheld_sessions_by_room_id(
131        &self,
132        room_id: &RoomId,
133    ) -> Result<Vec<RoomKeyWithheldEntry>, Self::Error>;
134
135    /// Get all the inbound group sessions we have stored.
136    async fn get_inbound_group_sessions(&self) -> Result<Vec<InboundGroupSession>, Self::Error>;
137
138    /// Get the number inbound group sessions we have and how many of them are
139    /// backed up.
140    async fn inbound_group_session_counts(
141        &self,
142        backup_version: Option<&str>,
143    ) -> Result<RoomKeyCounts, Self::Error>;
144
145    /// Get all the inbound group sessions for a given room.
146    ///
147    /// # Arguments
148    /// * `room_id` - The ID of the room to return sessions for.
149    async fn get_inbound_group_sessions_by_room_id(
150        &self,
151        room_id: &RoomId,
152    ) -> Result<Vec<InboundGroupSession>, Self::Error>;
153
154    /// Get a batch of inbound group sessions for the device with the supplied
155    /// curve key, whose sender data is of the supplied type.
156    ///
157    /// Sessions are not necessarily returned in any specific order, but the
158    /// returned batches are consistent: if this function is called repeatedly
159    /// with `after_session_id` set to the session ID from the last result
160    /// from the previous call, until an empty result is returned, then
161    /// eventually all matching sessions are returned. (New sessions that are
162    /// added in the course of iteration may or may not be returned.)
163    ///
164    /// This function is used when the device information is updated via a
165    /// `/keys/query` response and we want to update the sender data based
166    /// on the new information.
167    ///
168    /// # Arguments
169    ///
170    /// * `curve_key` - only return sessions created by the device with this
171    ///   curve key.
172    ///
173    /// * `sender_data_type` - only return sessions whose [`SenderData`] record
174    ///   is in this state.
175    ///
176    /// * `after_session_id` - return the sessions after this id, or start at
177    ///   the earliest if this is None.
178    ///
179    /// * `limit` - return a maximum of this many sessions.
180    async fn get_inbound_group_sessions_for_device_batch(
181        &self,
182        curve_key: Curve25519PublicKey,
183        sender_data_type: SenderDataType,
184        after_session_id: Option<String>,
185        limit: usize,
186    ) -> Result<Vec<InboundGroupSession>, Self::Error>;
187
188    /// Return a batch of ['InboundGroupSession'] ("room keys") that have not
189    /// yet been backed up in the supplied backup version.
190    ///
191    /// The size of the returned `Vec` is <= `limit`.
192    ///
193    /// Note: some implementations ignore `backup_version` and assume the
194    /// current backup version, which is normally the same.
195    async fn inbound_group_sessions_for_backup(
196        &self,
197        backup_version: &str,
198        limit: usize,
199    ) -> Result<Vec<InboundGroupSession>, Self::Error>;
200
201    /// Store the fact that the supplied sessions were backed up into the backup
202    /// with version `backup_version`.
203    ///
204    /// Note: some implementations ignore `backup_version` and assume the
205    /// current backup version, which is normally the same.
206    async fn mark_inbound_group_sessions_as_backed_up(
207        &self,
208        backup_version: &str,
209        room_and_session_ids: &[(&RoomId, &str)],
210    ) -> Result<(), Self::Error>;
211
212    /// Reset the backup state of all the stored inbound group sessions.
213    ///
214    /// Note: this is mostly implemented by stores that ignore the
215    /// `backup_version` argument on `inbound_group_sessions_for_backup` and
216    /// `mark_inbound_group_sessions_as_backed_up`. Implementations that
217    /// pay attention to the supplied backup version probably don't need to
218    /// update their storage when the current backup version changes, so have
219    /// empty implementations of this method.
220    async fn reset_backup_state(&self) -> Result<(), Self::Error>;
221
222    /// Get the backup keys we have stored.
223    async fn load_backup_keys(&self) -> Result<BackupKeys, Self::Error>;
224
225    /// Get the dehydrated device pickle key we have stored.
226    async fn load_dehydrated_device_pickle_key(
227        &self,
228    ) -> Result<Option<DehydratedDeviceKey>, Self::Error>;
229
230    /// Deletes the previously stored dehydrated device pickle key.
231    async fn delete_dehydrated_device_pickle_key(&self) -> Result<(), Self::Error>;
232
233    /// Get the outbound group session we have stored that is used for the
234    /// given room.
235    async fn get_outbound_group_session(
236        &self,
237        room_id: &RoomId,
238    ) -> Result<Option<OutboundGroupSession>, Self::Error>;
239
240    /// Provide the list of users whose devices we are keeping track of, and
241    /// whether they are considered dirty/outdated.
242    async fn load_tracked_users(&self) -> Result<Vec<TrackedUser>, Self::Error>;
243
244    /// Update the list of users whose devices we are keeping track of, and
245    /// whether they are considered dirty/outdated.
246    ///
247    /// Replaces any existing entry with a matching user ID.
248    async fn save_tracked_users(&self, users: &[(&UserId, bool)]) -> Result<(), Self::Error>;
249
250    /// Get the device for the given user with the given device ID.
251    ///
252    /// # Arguments
253    ///
254    /// * `user_id` - The user that the device belongs to.
255    ///
256    /// * `device_id` - The unique id of the device.
257    async fn get_device(
258        &self,
259        user_id: &UserId,
260        device_id: &DeviceId,
261    ) -> Result<Option<DeviceData>, Self::Error>;
262
263    /// Get all the devices of the given user.
264    ///
265    /// # Arguments
266    ///
267    /// * `user_id` - The user for which we should get all the devices.
268    async fn get_user_devices(
269        &self,
270        user_id: &UserId,
271    ) -> Result<HashMap<OwnedDeviceId, DeviceData>, Self::Error>;
272
273    /// Get the device for the current client.
274    ///
275    /// Since our own device is set when the store is created, this will always
276    /// return a device (unless there is an error).
277    async fn get_own_device(&self) -> Result<DeviceData, Self::Error>;
278
279    /// Get the user identity that is attached to the given user id.
280    ///
281    /// # Arguments
282    ///
283    /// * `user_id` - The user for which we should get the identity.
284    async fn get_user_identity(
285        &self,
286        user_id: &UserId,
287    ) -> Result<Option<UserIdentityData>, Self::Error>;
288
289    /// Check if a hash for an Olm message stored in the database.
290    async fn is_message_known(&self, message_hash: &OlmMessageHash) -> Result<bool, Self::Error>;
291
292    /// Get an outgoing secret request that we created that matches the given
293    /// request id.
294    ///
295    /// # Arguments
296    ///
297    /// * `request_id` - The unique request id that identifies this outgoing
298    /// secret request.
299    async fn get_outgoing_secret_requests(
300        &self,
301        request_id: &TransactionId,
302    ) -> Result<Option<GossipRequest>, Self::Error>;
303
304    /// Get an outgoing key request that we created that matches the given
305    /// requested key info.
306    ///
307    /// # Arguments
308    ///
309    /// * `key_info` - The key info of an outgoing secret request.
310    async fn get_secret_request_by_info(
311        &self,
312        secret_info: &SecretInfo,
313    ) -> Result<Option<GossipRequest>, Self::Error>;
314
315    /// Get all outgoing secret requests that we have in the store.
316    async fn get_unsent_secret_requests(&self) -> Result<Vec<GossipRequest>, Self::Error>;
317
318    /// Delete an outgoing key request that we created that matches the given
319    /// request id.
320    ///
321    /// # Arguments
322    ///
323    /// * `request_id` - The unique request id that identifies this outgoing key
324    /// request.
325    async fn delete_outgoing_secret_requests(
326        &self,
327        request_id: &TransactionId,
328    ) -> Result<(), Self::Error>;
329
330    /// Get all the secrets with the given [`SecretName`] we have currently
331    /// stored.
332    async fn get_secrets_from_inbox(
333        &self,
334        secret_name: &SecretName,
335    ) -> Result<Vec<Zeroizing<String>>, Self::Error>;
336
337    /// Delete all the secrets with the given [`SecretName`] we have currently
338    /// stored.
339    async fn delete_secrets_from_inbox(&self, secret_name: &SecretName) -> Result<(), Self::Error>;
340
341    /// Get the room settings, such as the encryption algorithm or whether to
342    /// encrypt only for trusted devices.
343    ///
344    /// # Arguments
345    ///
346    /// * `room_id` - The room id of the room
347    async fn get_room_settings(
348        &self,
349        room_id: &RoomId,
350    ) -> Result<Option<RoomSettings>, Self::Error>;
351
352    /// Get the details about the room key bundle data received from the given
353    /// user for the given room.
354    async fn get_received_room_key_bundle_data(
355        &self,
356        room_id: &RoomId,
357        user_id: &UserId,
358    ) -> Result<Option<StoredRoomKeyBundleData>, Self::Error>;
359
360    /// Check whether we are awaiting a key bundle for the given room, and if so
361    /// return the details
362    async fn get_pending_key_bundle_details_for_room(
363        &self,
364        room_id: &RoomId,
365    ) -> Result<Option<RoomPendingKeyBundleDetails>, Self::Error>;
366
367    /// Retrieve a list of details for all rooms where we are currently awaiting
368    /// key bundles to be received.
369    async fn get_all_rooms_pending_key_bundles(
370        &self,
371    ) -> Result<Vec<RoomPendingKeyBundleDetails>, Self::Error>;
372
373    /// Get whether we have previously downloaded all room keys for a particular
374    /// room from the key backup in advance of building a room key bundle.
375    async fn has_downloaded_all_room_keys(&self, room_id: &RoomId) -> Result<bool, Self::Error>;
376
377    /// Get arbitrary data from the store
378    ///
379    /// # Arguments
380    ///
381    /// * `key` - The key to fetch data for
382    async fn get_custom_value(&self, key: &str) -> Result<Option<Vec<u8>>, Self::Error>;
383
384    /// Put arbitrary data into the store
385    ///
386    /// # Arguments
387    ///
388    /// * `key` - The key to insert data into
389    ///
390    /// * `value` - The value to insert
391    async fn set_custom_value(&self, key: &str, value: Vec<u8>) -> Result<(), Self::Error>;
392
393    /// Remove arbitrary data into the store
394    ///
395    /// # Arguments
396    ///
397    /// * `key` - The key to insert data into
398    async fn remove_custom_value(&self, key: &str) -> Result<(), Self::Error>;
399
400    /// Try to take a leased lock.
401    ///
402    /// This attempts to take a lock for the given lease duration.
403    ///
404    /// - If we already had the lease, this will extend the lease.
405    /// - If we didn't, but the previous lease has expired, we will acquire the
406    ///   lock.
407    /// - If there was no previous lease, we will acquire the lock.
408    /// - Otherwise, we don't get the lock.
409    ///
410    /// Returns whether taking the lock succeeded.
411    async fn try_take_leased_lock(
412        &self,
413        lease_duration_ms: u32,
414        key: &str,
415        holder: &str,
416    ) -> Result<Option<CrossProcessLockGeneration>, Self::Error>;
417
418    /// Load the next-batch token for a to-device query, if any.
419    async fn next_batch_token(&self) -> Result<Option<String>, Self::Error>;
420
421    /// Returns the size of the store in bytes, if known.
422    async fn get_size(&self) -> Result<Option<usize>, Self::Error>;
423}
424
425#[repr(transparent)]
426struct EraseCryptoStoreError<T>(T);
427
428#[cfg(not(tarpaulin_include))]
429impl<T: fmt::Debug> fmt::Debug for EraseCryptoStoreError<T> {
430    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431        self.0.fmt(f)
432    }
433}
434
435#[cfg_attr(target_family = "wasm", async_trait(?Send))]
436#[cfg_attr(not(target_family = "wasm"), async_trait)]
437impl<T: CryptoStore> CryptoStore for EraseCryptoStoreError<T> {
438    type Error = CryptoStoreError;
439
440    async fn load_account(&self) -> Result<Option<Account>> {
441        self.0.load_account().await.map_err(Into::into)
442    }
443
444    async fn load_identity(&self) -> Result<Option<PrivateCrossSigningIdentity>> {
445        self.0.load_identity().await.map_err(Into::into)
446    }
447
448    async fn save_changes(&self, changes: Changes) -> Result<()> {
449        self.0.save_changes(changes).await.map_err(Into::into)
450    }
451
452    async fn save_pending_changes(&self, changes: PendingChanges) -> Result<()> {
453        self.0.save_pending_changes(changes).await.map_err(Into::into)
454    }
455
456    async fn save_inbound_group_sessions(
457        &self,
458        sessions: Vec<InboundGroupSession>,
459        backed_up_to_version: Option<&str>,
460    ) -> Result<()> {
461        self.0.save_inbound_group_sessions(sessions, backed_up_to_version).await.map_err(Into::into)
462    }
463
464    async fn get_sessions(&self, sender_key: &str) -> Result<Option<Vec<Session>>> {
465        self.0.get_sessions(sender_key).await.map_err(Into::into)
466    }
467
468    async fn get_inbound_group_session(
469        &self,
470        room_id: &RoomId,
471        session_id: &str,
472    ) -> Result<Option<InboundGroupSession>> {
473        self.0.get_inbound_group_session(room_id, session_id).await.map_err(Into::into)
474    }
475
476    async fn get_inbound_group_sessions(&self) -> Result<Vec<InboundGroupSession>> {
477        self.0.get_inbound_group_sessions().await.map_err(Into::into)
478    }
479
480    async fn get_inbound_group_sessions_by_room_id(
481        &self,
482        room_id: &RoomId,
483    ) -> Result<Vec<InboundGroupSession>> {
484        self.0.get_inbound_group_sessions_by_room_id(room_id).await.map_err(Into::into)
485    }
486
487    async fn get_inbound_group_sessions_for_device_batch(
488        &self,
489        curve_key: Curve25519PublicKey,
490        sender_data_type: SenderDataType,
491        after_session_id: Option<String>,
492        limit: usize,
493    ) -> Result<Vec<InboundGroupSession>> {
494        self.0
495            .get_inbound_group_sessions_for_device_batch(
496                curve_key,
497                sender_data_type,
498                after_session_id,
499                limit,
500            )
501            .await
502            .map_err(Into::into)
503    }
504
505    async fn inbound_group_session_counts(
506        &self,
507        backup_version: Option<&str>,
508    ) -> Result<RoomKeyCounts> {
509        self.0.inbound_group_session_counts(backup_version).await.map_err(Into::into)
510    }
511    async fn inbound_group_sessions_for_backup(
512        &self,
513        backup_version: &str,
514        limit: usize,
515    ) -> Result<Vec<InboundGroupSession>> {
516        self.0.inbound_group_sessions_for_backup(backup_version, limit).await.map_err(Into::into)
517    }
518
519    async fn mark_inbound_group_sessions_as_backed_up(
520        &self,
521        backup_version: &str,
522        room_and_session_ids: &[(&RoomId, &str)],
523    ) -> Result<()> {
524        self.0
525            .mark_inbound_group_sessions_as_backed_up(backup_version, room_and_session_ids)
526            .await
527            .map_err(Into::into)
528    }
529
530    async fn reset_backup_state(&self) -> Result<()> {
531        self.0.reset_backup_state().await.map_err(Into::into)
532    }
533
534    async fn load_backup_keys(&self) -> Result<BackupKeys> {
535        self.0.load_backup_keys().await.map_err(Into::into)
536    }
537
538    async fn load_dehydrated_device_pickle_key(&self) -> Result<Option<DehydratedDeviceKey>> {
539        self.0.load_dehydrated_device_pickle_key().await.map_err(Into::into)
540    }
541
542    async fn delete_dehydrated_device_pickle_key(&self) -> Result<(), Self::Error> {
543        self.0.delete_dehydrated_device_pickle_key().await.map_err(Into::into)
544    }
545
546    async fn get_outbound_group_session(
547        &self,
548        room_id: &RoomId,
549    ) -> Result<Option<OutboundGroupSession>> {
550        self.0.get_outbound_group_session(room_id).await.map_err(Into::into)
551    }
552
553    async fn load_tracked_users(&self) -> Result<Vec<TrackedUser>> {
554        self.0.load_tracked_users().await.map_err(Into::into)
555    }
556
557    async fn save_tracked_users(&self, users: &[(&UserId, bool)]) -> Result<()> {
558        self.0.save_tracked_users(users).await.map_err(Into::into)
559    }
560
561    async fn get_device(
562        &self,
563        user_id: &UserId,
564        device_id: &DeviceId,
565    ) -> Result<Option<DeviceData>> {
566        self.0.get_device(user_id, device_id).await.map_err(Into::into)
567    }
568
569    async fn get_user_devices(
570        &self,
571        user_id: &UserId,
572    ) -> Result<HashMap<OwnedDeviceId, DeviceData>> {
573        self.0.get_user_devices(user_id).await.map_err(Into::into)
574    }
575
576    async fn get_own_device(&self) -> Result<DeviceData> {
577        self.0.get_own_device().await.map_err(Into::into)
578    }
579
580    async fn get_user_identity(&self, user_id: &UserId) -> Result<Option<UserIdentityData>> {
581        self.0.get_user_identity(user_id).await.map_err(Into::into)
582    }
583
584    async fn is_message_known(&self, message_hash: &OlmMessageHash) -> Result<bool> {
585        self.0.is_message_known(message_hash).await.map_err(Into::into)
586    }
587
588    async fn get_outgoing_secret_requests(
589        &self,
590        request_id: &TransactionId,
591    ) -> Result<Option<GossipRequest>> {
592        self.0.get_outgoing_secret_requests(request_id).await.map_err(Into::into)
593    }
594
595    async fn get_secret_request_by_info(
596        &self,
597        secret_info: &SecretInfo,
598    ) -> Result<Option<GossipRequest>> {
599        self.0.get_secret_request_by_info(secret_info).await.map_err(Into::into)
600    }
601
602    async fn get_unsent_secret_requests(&self) -> Result<Vec<GossipRequest>> {
603        self.0.get_unsent_secret_requests().await.map_err(Into::into)
604    }
605
606    async fn delete_outgoing_secret_requests(&self, request_id: &TransactionId) -> Result<()> {
607        self.0.delete_outgoing_secret_requests(request_id).await.map_err(Into::into)
608    }
609
610    async fn get_secrets_from_inbox(
611        &self,
612        secret_name: &SecretName,
613    ) -> Result<Vec<Zeroizing<String>>> {
614        self.0.get_secrets_from_inbox(secret_name).await.map_err(Into::into)
615    }
616
617    async fn delete_secrets_from_inbox(&self, secret_name: &SecretName) -> Result<()> {
618        self.0.delete_secrets_from_inbox(secret_name).await.map_err(Into::into)
619    }
620
621    async fn get_withheld_info(
622        &self,
623        room_id: &RoomId,
624        session_id: &str,
625    ) -> Result<Option<RoomKeyWithheldEntry>, Self::Error> {
626        self.0.get_withheld_info(room_id, session_id).await.map_err(Into::into)
627    }
628
629    async fn get_withheld_sessions_by_room_id(
630        &self,
631        room_id: &RoomId,
632    ) -> Result<Vec<RoomKeyWithheldEntry>, Self::Error> {
633        self.0.get_withheld_sessions_by_room_id(room_id).await.map_err(Into::into)
634    }
635
636    async fn get_room_settings(&self, room_id: &RoomId) -> Result<Option<RoomSettings>> {
637        self.0.get_room_settings(room_id).await.map_err(Into::into)
638    }
639
640    async fn get_received_room_key_bundle_data(
641        &self,
642        room_id: &RoomId,
643        user_id: &UserId,
644    ) -> Result<Option<StoredRoomKeyBundleData>> {
645        self.0.get_received_room_key_bundle_data(room_id, user_id).await.map_err(Into::into)
646    }
647
648    async fn has_downloaded_all_room_keys(&self, room_id: &RoomId) -> Result<bool, Self::Error> {
649        self.0.has_downloaded_all_room_keys(room_id).await.map_err(Into::into)
650    }
651
652    async fn get_pending_key_bundle_details_for_room(
653        &self,
654        room_id: &RoomId,
655    ) -> Result<Option<RoomPendingKeyBundleDetails>, Self::Error> {
656        self.0.get_pending_key_bundle_details_for_room(room_id).await.map_err(Into::into)
657    }
658
659    async fn get_all_rooms_pending_key_bundles(
660        &self,
661    ) -> Result<Vec<RoomPendingKeyBundleDetails>, Self::Error> {
662        self.0.get_all_rooms_pending_key_bundles().await.map_err(Into::into)
663    }
664
665    async fn get_custom_value(&self, key: &str) -> Result<Option<Vec<u8>>, Self::Error> {
666        self.0.get_custom_value(key).await.map_err(Into::into)
667    }
668
669    async fn set_custom_value(&self, key: &str, value: Vec<u8>) -> Result<(), Self::Error> {
670        self.0.set_custom_value(key, value).await.map_err(Into::into)
671    }
672
673    async fn remove_custom_value(&self, key: &str) -> Result<(), Self::Error> {
674        self.0.remove_custom_value(key).await.map_err(Into::into)
675    }
676
677    async fn try_take_leased_lock(
678        &self,
679        lease_duration_ms: u32,
680        key: &str,
681        holder: &str,
682    ) -> Result<Option<CrossProcessLockGeneration>, Self::Error> {
683        self.0.try_take_leased_lock(lease_duration_ms, key, holder).await.map_err(Into::into)
684    }
685
686    async fn next_batch_token(&self) -> Result<Option<String>, Self::Error> {
687        self.0.next_batch_token().await.map_err(Into::into)
688    }
689
690    async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
691        self.0.get_size().await.map_err(Into::into)
692    }
693}
694
695/// A type-erased [`CryptoStore`].
696pub type DynCryptoStore = dyn CryptoStore<Error = CryptoStoreError>;
697
698/// A type that can be type-erased into `Arc<DynCryptoStore>`.
699///
700/// This trait is not meant to be implemented directly outside
701/// `matrix-sdk-crypto`, but it is automatically implemented for everything that
702/// implements `CryptoStore`.
703pub trait IntoCryptoStore {
704    #[doc(hidden)]
705    fn into_crypto_store(self) -> Arc<DynCryptoStore>;
706}
707
708impl<T> IntoCryptoStore for T
709where
710    T: CryptoStore + 'static,
711{
712    fn into_crypto_store(self) -> Arc<DynCryptoStore> {
713        Arc::new(EraseCryptoStoreError(self))
714    }
715}
716
717// Turns a given `Arc<T>` into `Arc<DynCryptoStore>` by attaching the
718// CryptoStore impl vtable of `EraseCryptoStoreError<T>`.
719impl<T> IntoCryptoStore for Arc<T>
720where
721    T: CryptoStore + 'static,
722{
723    fn into_crypto_store(self) -> Arc<DynCryptoStore> {
724        let ptr: *const T = Arc::into_raw(self);
725        let ptr_erased = ptr as *const EraseCryptoStoreError<T>;
726        // SAFETY: EraseCryptoStoreError is repr(transparent) so T and
727        //         EraseCryptoStoreError<T> have the same layout and ABI
728        unsafe { Arc::from_raw(ptr_erased) }
729    }
730}
731
732impl IntoCryptoStore for Arc<DynCryptoStore> {
733    fn into_crypto_store(self) -> Arc<DynCryptoStore> {
734        self
735    }
736}