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