matrix_sdk/encryption/recovery/
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 matrix_sdk_base::crypto::store::RoomKeyCounts;
16use ruma::{
17    events::{EventContent, GlobalAccountDataEventType},
18    exports::ruma_macros::EventContent,
19};
20use serde::{Deserialize, Serialize};
21use thiserror::Error;
22use zeroize::{Zeroize, ZeroizeOnDrop};
23
24#[cfg(doc)]
25use crate::encryption::{
26    backups::Backups,
27    recovery::{futures::Enable, Recovery},
28};
29
30/// Result type alias for the [`Recovery`] subsystem.
31pub type Result<A, E = RecoveryError> = std::result::Result<A, E>;
32
33/// Error type for the [`Recovery`] subsystem.
34#[derive(Debug, Error)]
35pub enum RecoveryError {
36    /// A backup already exists on the homeserver, the recovery subsystem does
37    /// not allow backups to be overwritten, disable recovery first.
38    #[error(
39        "A backup already exists on the homeserver and the method does not allow to overwrite it"
40    )]
41    BackupExistsOnServer,
42
43    /// A typical SDK error.
44    #[error(transparent)]
45    Sdk(#[from] crate::Error),
46
47    /// Error in the secret storage subsystem.
48    #[error(transparent)]
49    SecretStorage(#[from] crate::encryption::secret_storage::SecretStorageError),
50}
51
52/// Enum describing the states the [`Recovery::enable()`] method can be in.
53#[derive(Debug, Default, Clone, Zeroize, ZeroizeOnDrop)]
54pub enum EnableProgress {
55    /// The client is just starting the process of enabling recovery, this is
56    /// the initial state.
57    #[default]
58    Starting,
59    /// The client is creating a new server-side key backup.
60    CreatingBackup,
61    /// The client is creating a new recovery key and uploading all the locally
62    /// cached secrets to the homeserver.
63    CreatingRecoveryKey,
64    /// The client is currently backing up room keys to the server-side key
65    /// backup. This state may be emitted multiple times until all room keys
66    /// have been backed up.
67    #[zeroize(skip)]
68    BackingUp(RoomKeyCounts),
69    /// The client encountered an error while trying to upload all room keys to
70    /// the server-side key backup.
71    ///
72    /// Not all room keys may have been backed up, the client will try to back
73    /// them up again at a later point. If you'd like to wait for the backup
74    /// to finish again you can use the [`Backups::wait_for_steady_state()`]
75    /// method.
76    RoomKeyUploadError,
77    /// Recovery has been successfully enabled, this is the final state.
78    Done {
79        /// The newly created recovery key.
80        // TODO: Can I remove this from here? It seems a bit dumb.
81        recovery_key: String,
82    },
83}
84
85/// The states the recovery subsystem can be in.
86///
87/// You can listen on the state of the recovery mechanism using the
88/// [`Recovery::state_stream()`] method.
89#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
90pub enum RecoveryState {
91    /// We didn't yet inform ourselves about the state of things.
92    #[default]
93    Unknown,
94    /// Secret storage is set up and we have all the secrets locally.
95    Enabled,
96    /// No default secret storage key exists or it is disabled explicitly using
97    /// the account data event.
98    Disabled,
99    /// Secret storage is set up but we're missing some secrets.
100    Incomplete,
101}
102
103/// A hack to allow the `m.secret_storage.default_key` event to be "deleted".
104///
105/// This allows us to set the `m.secret_storage.default_key` event to an empty
106/// JSON object, which means that the event will be invalid.
107#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
108#[ruma_event(type = "m.secret_storage.default_key", kind = GlobalAccountData)]
109pub(super) struct SecretStorageDisabledContent {}
110
111/// A custom global account data event which tells us that a new backup should
112/// not be automatically created.
113#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
114#[ruma_event(type = "m.org.matrix.custom.backup_disabled", kind = GlobalAccountData)]
115pub(super) struct BackupDisabledContent {
116    pub disabled: bool,
117}
118
119impl BackupDisabledContent {
120    /// Get the event type of the [`BackupDisabledContent`] global account data
121    /// event.
122    pub(super) fn event_type() -> GlobalAccountDataEventType {
123        // This is dumb, there's got to be a better way to get to the event type?
124        Self { disabled: false }.event_type()
125    }
126}