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