tuwunel_api/client/backup/
mod.rs1mod keys;
2mod keys_room;
3mod keys_session;
4mod version;
5mod version_id;
6
7use futures::{FutureExt, future::try_join};
8use http::StatusCode;
9use ruma::{
10 CanonicalJsonValue, UInt, UserId,
11 api::error::{ErrorKind, WrongRoomKeysVersionErrorData},
12 serde::Raw,
13};
14use serde::Deserialize;
15use tuwunel_core::{Error, Result};
16use tuwunel_service::Services;
17
18pub(crate) use self::{
19 keys::{add_backup_keys_route, delete_backup_keys_route, get_backup_keys_route},
20 keys_room::{
21 add_backup_keys_for_room_route, delete_backup_keys_for_room_route,
22 get_backup_keys_for_room_route,
23 },
24 keys_session::{
25 add_backup_keys_for_session_route, delete_backup_keys_for_session_route,
26 get_backup_keys_for_session_route,
27 },
28 version::{create_backup_version_route, get_latest_backup_info_route},
29 version_id::{
30 delete_backup_version_route, get_backup_info_route, update_backup_version_route,
31 },
32};
33
34#[derive(Deserialize)]
38#[expect(unused)]
39struct AlgorithmShape {
40 algorithm: Raw<CanonicalJsonValue>,
41 auth_data: Raw<CanonicalJsonValue>,
42}
43
44pub(super) fn validate_algorithm_shape<T>(raw: &Raw<T>) -> Result {
45 raw.deserialize_as_unchecked::<AlgorithmShape>()
46 .map_err(Into::into)
47 .map(drop)
48}
49
50pub(super) async fn get_count_etag(
51 services: &Services,
52 sender_user: &UserId,
53 version: &str,
54) -> Result<(UInt, String)> {
55 let count = services
56 .key_backups
57 .count_keys(sender_user, version)
58 .map(TryInto::try_into);
59
60 let etag = services
61 .key_backups
62 .get_etag(sender_user, version)
63 .map(Ok);
64
65 Ok(try_join(count, etag).await?)
66}
67
68pub(super) async fn check_backup_version(
69 services: &Services,
70 sender_user: &UserId,
71 version: &str,
72) -> Result {
73 services
74 .key_backups
75 .get_latest_backup_version(sender_user)
76 .await
77 .ok()
78 .filter(|current| current.as_str() != version)
79 .map_or(Ok(()), |current_version| {
80 let data = WrongRoomKeysVersionErrorData::new(current_version);
81 let kind = ErrorKind::WrongRoomKeysVersion(data);
82
83 Err(Error::Request(
84 kind,
85 "You may only manipulate the most recently created version of the backup.".into(),
86 StatusCode::BAD_REQUEST,
87 ))
88 })
89}