matrix_sdk/encryption/backups/types.rs
1// Copyright 2023 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::{
16 sync::{Arc, RwLock},
17 time::Duration,
18};
19
20use matrix_sdk_base::crypto::{store::RoomKeyCounts, RoomKeyImportResult};
21use tokio::sync::broadcast;
22
23use crate::utils::ChannelObservable;
24#[cfg(doc)]
25use crate::{
26 encryption::{backups::Backups, secret_storage::SecretStore},
27 Client,
28};
29
30/// The states the upload task can be in.
31///
32/// You can listen on the state of the upload task using the
33/// [`Backups::wait_for_steady_state()`] method.
34///
35/// [`Backups::wait_for_steady_state()`]: crate::encryption::backups::Backups::wait_for_steady_state
36#[derive(Clone, Debug)]
37pub enum UploadState {
38 /// The task is idle, waiting for new room keys to arrive to try to upload
39 /// them.
40 Idle,
41 /// The task is currently uploading room keys to the homeserver.
42 Uploading(RoomKeyCounts),
43 /// There was an error while trying to upload room keys, the task will go
44 /// back to the `Idle` state and try again later.
45 Error,
46 /// All room keys have been successfully uploaded, the task will now go back
47 /// to the `Idle` state.
48 Done,
49}
50
51pub(crate) struct BackupClientState {
52 pub(super) upload_delay: Arc<RwLock<Duration>>,
53 pub(crate) upload_progress: ChannelObservable<UploadState>,
54 pub(super) global_state: ChannelObservable<BackupState>,
55 pub(super) room_keys_broadcaster: broadcast::Sender<RoomKeyImportResult>,
56
57 /// Whether a key storage backup exists on the server, as far as we know.
58 ///
59 /// This is `None` if we have not asked the server yet, and `Some`
60 /// otherwise. This value is not always up-to-date: if the backup status
61 /// on the server was changed by some other client, we will have a old
62 /// value.
63 pub(super) backup_exists_on_server: RwLock<Option<bool>>,
64}
65
66impl BackupClientState {
67 /// Update the cached value indicating whether a key storage backup exists
68 /// on the server
69 pub(crate) fn set_backup_exists_on_server(&self, exists_on_server: bool) {
70 *self.backup_exists_on_server.write().unwrap() = Some(exists_on_server);
71 }
72
73 /// Ask whether the key storage backup exists on the server. Returns `None`
74 /// if we haven't checked. Note that this value will be out-of-date if
75 /// some other client changed the state since the last time we checked.
76 pub(crate) fn backup_exists_on_server(&self) -> Option<bool> {
77 *self.backup_exists_on_server.read().unwrap()
78 }
79
80 /// Clear out the cached value indicating whether a key storage backup
81 /// exists on the server, meaning that the code in
82 /// [`super::Backups`] will repopulate it when needed
83 /// with an up-to-date value.
84 pub(crate) fn clear_backup_exists_on_server(&self) {
85 *self.backup_exists_on_server.write().unwrap() = None;
86 }
87}
88
89const DEFAULT_BACKUP_UPLOAD_DELAY: Duration = Duration::from_millis(100);
90
91impl Default for BackupClientState {
92 fn default() -> Self {
93 Self {
94 upload_delay: RwLock::new(DEFAULT_BACKUP_UPLOAD_DELAY).into(),
95 upload_progress: ChannelObservable::new(UploadState::Idle),
96 global_state: Default::default(),
97 room_keys_broadcaster: broadcast::Sender::new(100),
98 backup_exists_on_server: RwLock::new(None),
99 }
100 }
101}
102
103/// The possible states of the [`Client`]'s room key backup mechanism.
104///
105/// A local backup instance can be created either by receiving a valid backup
106/// recovery key [[1]] or by having the [`Client`] create a new backup itself.
107///
108/// The [`Client`] can also delete and disable a currently active backup.
109///
110/// Backups will be enabled automatically if we receive the backup recovery key
111/// either from:
112///
113/// * Another device using `m.secret.send`[[2]], which usually happens after
114/// completing interactive verification.
115/// * Secret storage[[3]], which is done by calling the
116/// [`SecretStore::import_secrets()`] method.
117///
118/// [1]: https://spec.matrix.org/v1.8/client-server-api/#recovery-key
119/// [2]: https://spec.matrix.org/v1.8/client-server-api/#sharing
120/// [3]: https://spec.matrix.org/v1.8/client-server-api/#secret-storage
121#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
122pub enum BackupState {
123 /// There is no locally active backup and we don't know whether there backup
124 /// exists on the server.
125 ///
126 /// The reason we don't know whether a server-side backup exists is that we
127 /// don't get notified by the server about the creation and deletion of
128 /// backups. If we want to know the current state, we need to poll the
129 /// server, which is done using the [`Backups::fetch_exists_on_server()`]
130 /// method.
131 #[default]
132 Unknown,
133 /// A new backup is being created by this [`Client`]. This state will be
134 /// entered if you call the [`Backups::create()`] method.
135 Creating,
136 /// An existing backup is being enabled for use by this [`Client`]. We
137 /// will enter this state if we have received a backup recovery key.
138 Enabling,
139 /// An existing backup will be enabled to be used by this [`Client`] after
140 /// the client has been restored. This state happens every time a
141 /// [`Client`] is restored after we'd previously enabled a backup.
142 Resuming,
143 /// The backup is enabled and room keys are actively being backed up.
144 Enabled,
145 /// Room keys are currently being downloaded. This state will only happen
146 /// after an `Enabling` state. The [`Client`] will attempt to download
147 /// all room keys from the backup before transitioning into the
148 /// `Enabled` state.
149 Downloading,
150 /// The backup is being disabled and deleted from the server. This state
151 /// will happen when you call the [`Backups::disable()`] method. After it
152 /// has been disabled, we're going to transition into the `Unknown` state.
153 Disabling,
154}