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}