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}