Files
continuwuity/src/api/client/backup.rs
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

444 lines
12 KiB
Rust
Raw Normal View History

use std::cmp::Ordering;
2024-07-16 08:05:25 +00:00
use axum::extract::State;
use conduwuit::{Err, err};
2024-05-04 09:45:37 -04:00
use ruma::{
UInt,
2024-08-08 17:18:30 +00:00
api::client::backup::{
add_backup_keys, add_backup_keys_for_room, add_backup_keys_for_session,
create_backup_version, delete_backup_keys, delete_backup_keys_for_room,
delete_backup_keys_for_session, delete_backup_version, get_backup_info, get_backup_keys,
get_backup_keys_for_room, get_backup_keys_for_session, get_latest_backup_info,
update_backup_version,
2020-07-30 18:14:47 +02:00
},
};
2024-08-08 17:18:30 +00:00
use crate::{Result, Ruma};
2024-03-05 19:48:54 -05:00
2021-08-31 19:14:37 +02:00
/// # `POST /_matrix/client/r0/room_keys/version`
///
/// Creates a new backup.
2024-04-22 23:48:57 -04:00
pub(crate) async fn create_backup_version_route(
State(services): State<crate::State>,
body: Ruma<create_backup_version::v3::Request>,
2022-03-05 10:16:21 +08:00
) -> Result<create_backup_version::v3::Response> {
2024-07-16 08:05:25 +00:00
let version = services
2024-03-25 17:05:11 -04:00
.key_backups
.create_backup(body.sender_user(), &body.algorithm)?;
Ok(create_backup_version::v3::Response { version })
2020-07-30 18:14:47 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `PUT /_matrix/client/r0/room_keys/version/{version}`
///
/// Update information about an existing backup. Only `auth_data` can be
/// modified.
2024-04-22 23:48:57 -04:00
pub(crate) async fn update_backup_version_route(
State(services): State<crate::State>,
body: Ruma<update_backup_version::v3::Request>,
2022-03-05 10:16:21 +08:00
) -> Result<update_backup_version::v3::Response> {
2024-07-16 08:05:25 +00:00
services
2024-03-25 17:05:11 -04:00
.key_backups
.update_backup(body.sender_user(), &body.version, &body.algorithm)
2024-08-08 17:18:30 +00:00
.await?;
2022-03-05 10:16:21 +08:00
Ok(update_backup_version::v3::Response {})
2020-07-30 18:14:47 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/client/r0/room_keys/version`
///
/// Get information about the latest backup version.
2024-04-22 23:48:57 -04:00
pub(crate) async fn get_latest_backup_info_route(
State(services): State<crate::State>,
body: Ruma<get_latest_backup_info::v3::Request>,
2022-03-05 10:16:21 +08:00
) -> Result<get_latest_backup_info::v3::Response> {
2024-07-16 08:05:25 +00:00
let (version, algorithm) = services
2022-10-05 20:34:31 +02:00
.key_backups
.get_latest_backup(body.sender_user())
2024-08-08 17:18:30 +00:00
.await
.map_err(|_| err!(Request(NotFound("Key backup does not exist."))))?;
2024-03-05 19:48:54 -05:00
2022-03-05 10:16:21 +08:00
Ok(get_latest_backup_info::v3::Response {
2020-07-30 18:14:47 +02:00
algorithm,
count: (UInt::try_from(
services
.key_backups
.count_keys(body.sender_user(), &version)
.await,
)
.expect("user backup keys count should not be that high")),
etag: services
.key_backups
.get_etag(body.sender_user(), &version)
.await,
2020-07-30 18:14:47 +02:00
version,
2022-01-22 16:58:32 +01:00
})
2020-07-30 18:14:47 +02:00
}
/// # `GET /_matrix/client/v3/room_keys/version/{version}`
2021-08-31 19:14:37 +02:00
///
/// Get information about an existing backup.
2024-04-22 23:48:57 -04:00
pub(crate) async fn get_backup_info_route(
State(services): State<crate::State>,
body: Ruma<get_backup_info::v3::Request>,
2024-04-22 23:48:57 -04:00
) -> Result<get_backup_info::v3::Response> {
2024-07-16 08:05:25 +00:00
let algorithm = services
2020-07-30 18:14:47 +02:00
.key_backups
.get_backup(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await
.map_err(|_| {
err!(Request(NotFound("Key backup does not exist at version {:?}", body.version)))
})?;
2024-03-05 19:48:54 -05:00
2022-03-05 10:16:21 +08:00
Ok(get_backup_info::v3::Response {
2020-07-30 18:14:47 +02:00
algorithm,
2024-08-08 17:18:30 +00:00
count: services
.key_backups
.count_keys(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await
.try_into()?,
etag: services
.key_backups
.get_etag(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await,
2024-03-02 20:55:02 -05:00
version: body.version.clone(),
2022-01-22 16:58:32 +01:00
})
2020-07-30 18:14:47 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `DELETE /_matrix/client/r0/room_keys/version/{version}`
///
/// Delete an existing key backup.
///
/// - Deletes both information about the backup, as well as all key data related
/// to the backup
2024-04-22 23:48:57 -04:00
pub(crate) async fn delete_backup_version_route(
State(services): State<crate::State>,
body: Ruma<delete_backup_version::v3::Request>,
2022-03-05 10:16:21 +08:00
) -> Result<delete_backup_version::v3::Response> {
2024-07-16 08:05:25 +00:00
services
2024-03-25 17:05:11 -04:00
.key_backups
.delete_backup(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await;
2022-03-05 10:16:21 +08:00
Ok(delete_backup_version::v3::Response {})
}
2021-08-31 19:14:37 +02:00
/// # `PUT /_matrix/client/r0/room_keys/keys`
///
/// Add the received backup keys to the database.
2021-08-31 19:14:37 +02:00
///
/// - Only manipulating the most recently created version of the backup is
/// allowed
/// - Adds the keys to the backup
/// - Returns the new number of keys in this backup and the etag
2024-04-22 23:48:57 -04:00
pub(crate) async fn add_backup_keys_route(
State(services): State<crate::State>,
body: Ruma<add_backup_keys::v3::Request>,
2024-04-22 23:48:57 -04:00
) -> Result<add_backup_keys::v3::Response> {
2024-08-08 17:18:30 +00:00
if services
.key_backups
.get_latest_backup_version(body.sender_user())
2024-08-08 17:18:30 +00:00
.await
.is_ok_and(|version| version != body.version)
2024-03-25 17:05:11 -04:00
{
2024-08-08 17:18:30 +00:00
return Err!(Request(InvalidParam(
"You may only manipulate the most recently created version of the backup."
)));
2021-08-31 19:14:37 +02:00
}
2024-03-05 19:48:54 -05:00
2020-07-30 18:14:47 +02:00
for (room_id, room) in &body.rooms {
for (session_id, key_data) in &room.sessions {
2024-07-16 08:05:25 +00:00
services
2024-03-25 17:05:11 -04:00
.key_backups
.add_key(body.sender_user(), &body.version, room_id, session_id, key_data)
2024-08-08 17:18:30 +00:00
.await?;
2020-07-30 18:14:47 +02:00
}
}
2024-03-05 19:48:54 -05:00
2022-02-18 15:33:14 +01:00
Ok(add_backup_keys::v3::Response {
2024-08-08 17:18:30 +00:00
count: services
.key_backups
.count_keys(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await
.try_into()?,
etag: services
.key_backups
.get_etag(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await,
2022-01-22 16:58:32 +01:00
})
2020-07-30 18:14:47 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `PUT /_matrix/client/r0/room_keys/keys/{roomId}`
///
/// Add the received backup keys to the database.
2021-08-31 19:14:37 +02:00
///
/// - Only manipulating the most recently created version of the backup is
/// allowed
/// - Adds the keys to the backup
/// - Returns the new number of keys in this backup and the etag
2024-04-22 23:48:57 -04:00
pub(crate) async fn add_backup_keys_for_room_route(
State(services): State<crate::State>,
body: Ruma<add_backup_keys_for_room::v3::Request>,
2022-03-05 10:16:21 +08:00
) -> Result<add_backup_keys_for_room::v3::Response> {
2024-08-08 17:18:30 +00:00
if services
.key_backups
.get_latest_backup_version(body.sender_user())
2024-08-08 17:18:30 +00:00
.await
.is_ok_and(|version| version != body.version)
2024-03-25 17:05:11 -04:00
{
2024-08-08 17:18:30 +00:00
return Err!(Request(InvalidParam(
"You may only manipulate the most recently created version of the backup."
)));
2021-08-31 19:14:37 +02:00
}
2024-03-05 19:48:54 -05:00
for (session_id, key_data) in &body.sessions {
2024-07-16 08:05:25 +00:00
services
2024-03-25 17:05:11 -04:00
.key_backups
.add_key(body.sender_user(), &body.version, &body.room_id, session_id, key_data)
2024-08-08 17:18:30 +00:00
.await?;
}
2024-03-05 19:48:54 -05:00
2022-03-05 10:16:21 +08:00
Ok(add_backup_keys_for_room::v3::Response {
2024-08-08 17:18:30 +00:00
count: services
.key_backups
.count_keys(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await
.try_into()?,
etag: services
.key_backups
.get_etag(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await,
2022-01-22 16:58:32 +01:00
})
}
2021-08-31 19:14:37 +02:00
/// # `PUT /_matrix/client/r0/room_keys/keys/{roomId}/{sessionId}`
///
/// Add the received backup key to the database.
2021-08-31 19:14:37 +02:00
///
/// - Only manipulating the most recently created version of the backup is
/// allowed
/// - Adds the keys to the backup
/// - Returns the new number of keys in this backup and the etag
2024-04-22 23:48:57 -04:00
pub(crate) async fn add_backup_keys_for_session_route(
State(services): State<crate::State>,
body: Ruma<add_backup_keys_for_session::v3::Request>,
2022-03-05 10:16:21 +08:00
) -> Result<add_backup_keys_for_session::v3::Response> {
2024-08-08 17:18:30 +00:00
if services
.key_backups
.get_latest_backup_version(body.sender_user())
2024-08-08 17:18:30 +00:00
.await
.is_ok_and(|version| version != body.version)
2024-03-25 17:05:11 -04:00
{
2024-08-08 17:18:30 +00:00
return Err!(Request(InvalidParam(
"You may only manipulate the most recently created version of the backup."
)));
2021-08-31 19:14:37 +02:00
}
2024-03-05 19:48:54 -05:00
// Check if we already have a better key
let mut ok_to_replace = true;
if let Some(old_key) = &services
2024-03-25 17:05:11 -04:00
.key_backups
.get_session(body.sender_user(), &body.version, &body.room_id, &body.session_id)
.await
.ok()
{
let old_is_verified = old_key
.get_field::<bool>("is_verified")?
.unwrap_or_default();
let new_is_verified = body
.session_data
.get_field::<bool>("is_verified")?
.ok_or_else(|| err!(Request(BadJson("`is_verified` field should exist"))))?;
// Prefer key that `is_verified`
if old_is_verified != new_is_verified {
if old_is_verified {
ok_to_replace = false;
}
} else {
// If both have same `is_verified`, prefer the one with lower
// `first_message_index`
let old_first_message_index = old_key
.get_field::<UInt>("first_message_index")?
.unwrap_or(UInt::MAX);
let new_first_message_index = body
.session_data
.get_field::<UInt>("first_message_index")?
.ok_or_else(|| {
err!(Request(BadJson("`first_message_index` field should exist")))
})?;
ok_to_replace = match new_first_message_index.cmp(&old_first_message_index) {
| Ordering::Less => true,
| Ordering::Greater => false,
| Ordering::Equal => {
// If both have same `first_message_index`, prefer the one with lower
// `forwarded_count`
let old_forwarded_count = old_key
.get_field::<UInt>("forwarded_count")?
.unwrap_or(UInt::MAX);
let new_forwarded_count = body
.session_data
.get_field::<UInt>("forwarded_count")?
.ok_or_else(|| {
err!(Request(BadJson("`forwarded_count` field should exist")))
})?;
new_forwarded_count < old_forwarded_count
},
};
}
}
if ok_to_replace {
services
.key_backups
.add_key(
body.sender_user(),
&body.version,
&body.room_id,
&body.session_id,
&body.session_data,
)
.await?;
}
2024-03-05 19:48:54 -05:00
2022-03-05 10:16:21 +08:00
Ok(add_backup_keys_for_session::v3::Response {
2024-08-08 17:18:30 +00:00
count: services
.key_backups
.count_keys(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await
.try_into()?,
etag: services
.key_backups
.get_etag(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await,
2022-01-22 16:58:32 +01:00
})
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/client/r0/room_keys/keys`
///
/// Retrieves all keys from the backup.
2024-04-22 23:48:57 -04:00
pub(crate) async fn get_backup_keys_route(
State(services): State<crate::State>,
body: Ruma<get_backup_keys::v3::Request>,
2024-04-22 23:48:57 -04:00
) -> Result<get_backup_keys::v3::Response> {
2024-08-08 17:18:30 +00:00
let rooms = services
.key_backups
.get_all(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await;
2020-07-30 18:14:47 +02:00
Ok(get_backup_keys::v3::Response { rooms })
2020-07-30 18:14:47 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/client/r0/room_keys/keys/{roomId}`
///
/// Retrieves all keys from the backup for a given room.
2024-04-22 23:48:57 -04:00
pub(crate) async fn get_backup_keys_for_room_route(
State(services): State<crate::State>,
body: Ruma<get_backup_keys_for_room::v3::Request>,
2022-03-05 10:16:21 +08:00
) -> Result<get_backup_keys_for_room::v3::Response> {
2024-07-16 08:05:25 +00:00
let sessions = services
2024-03-25 17:05:11 -04:00
.key_backups
.get_room(body.sender_user(), &body.version, &body.room_id)
2024-08-08 17:18:30 +00:00
.await;
Ok(get_backup_keys_for_room::v3::Response { sessions })
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/client/r0/room_keys/keys/{roomId}/{sessionId}`
///
/// Retrieves a key from the backup.
2024-04-22 23:48:57 -04:00
pub(crate) async fn get_backup_keys_for_session_route(
State(services): State<crate::State>,
body: Ruma<get_backup_keys_for_session::v3::Request>,
2022-03-05 10:16:21 +08:00
) -> Result<get_backup_keys_for_session::v3::Response> {
2024-07-16 08:05:25 +00:00
let key_data = services
2024-03-25 17:05:11 -04:00
.key_backups
.get_session(body.sender_user(), &body.version, &body.room_id, &body.session_id)
2024-08-08 17:18:30 +00:00
.await
.map_err(|_| {
err!(Request(NotFound(debug_error!("Backup key not found for this user's session."))))
})?;
Ok(get_backup_keys_for_session::v3::Response { key_data })
}
2021-08-31 19:14:37 +02:00
/// # `DELETE /_matrix/client/r0/room_keys/keys`
///
/// Delete the keys from the backup.
2024-04-22 23:48:57 -04:00
pub(crate) async fn delete_backup_keys_route(
State(services): State<crate::State>,
body: Ruma<delete_backup_keys::v3::Request>,
2022-02-18 15:33:14 +01:00
) -> Result<delete_backup_keys::v3::Response> {
2024-07-16 08:05:25 +00:00
services
2024-03-25 17:05:11 -04:00
.key_backups
.delete_all_keys(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await;
2024-03-05 19:48:54 -05:00
2022-02-18 15:33:14 +01:00
Ok(delete_backup_keys::v3::Response {
2024-08-08 17:18:30 +00:00
count: services
.key_backups
.count_keys(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await
.try_into()?,
etag: services
.key_backups
.get_etag(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await,
2022-01-22 16:58:32 +01:00
})
}
2021-08-31 19:14:37 +02:00
/// # `DELETE /_matrix/client/r0/room_keys/keys/{roomId}`
///
/// Delete the keys from the backup for a given room.
2024-04-22 23:48:57 -04:00
pub(crate) async fn delete_backup_keys_for_room_route(
State(services): State<crate::State>,
body: Ruma<delete_backup_keys_for_room::v3::Request>,
2022-03-05 10:16:21 +08:00
) -> Result<delete_backup_keys_for_room::v3::Response> {
2024-07-16 08:05:25 +00:00
services
2024-03-25 17:05:11 -04:00
.key_backups
.delete_room_keys(body.sender_user(), &body.version, &body.room_id)
2024-08-08 17:18:30 +00:00
.await;
2024-03-05 19:48:54 -05:00
2022-03-05 10:16:21 +08:00
Ok(delete_backup_keys_for_room::v3::Response {
2024-08-08 17:18:30 +00:00
count: services
.key_backups
.count_keys(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await
.try_into()?,
etag: services
.key_backups
.get_etag(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await,
2022-01-22 16:58:32 +01:00
})
}
2021-08-31 19:14:37 +02:00
/// # `DELETE /_matrix/client/r0/room_keys/keys/{roomId}/{sessionId}`
///
/// Delete a key from the backup.
2024-04-22 23:48:57 -04:00
pub(crate) async fn delete_backup_keys_for_session_route(
State(services): State<crate::State>,
body: Ruma<delete_backup_keys_for_session::v3::Request>,
2022-03-05 10:16:21 +08:00
) -> Result<delete_backup_keys_for_session::v3::Response> {
2024-07-16 08:05:25 +00:00
services
2024-03-25 17:05:11 -04:00
.key_backups
.delete_room_key(body.sender_user(), &body.version, &body.room_id, &body.session_id)
2024-08-08 17:18:30 +00:00
.await;
2024-03-05 19:48:54 -05:00
2022-03-05 10:16:21 +08:00
Ok(delete_backup_keys_for_session::v3::Response {
2024-08-08 17:18:30 +00:00
count: services
.key_backups
.count_keys(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await
.try_into()?,
etag: services
.key_backups
.get_etag(body.sender_user(), &body.version)
2024-08-08 17:18:30 +00:00
.await,
2022-01-22 16:58:32 +01:00
})
}