Skip to main content

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}