combine service/users data w/ mod unit split sliding sync related out of service/users instrument database entry points remove increment crap from database interface de-wrap all database get() calls de-wrap all database insert() calls de-wrap all database remove() calls refactor database interface for async streaming add query key serializer for database implement Debug for result handle add query deserializer for database add deserialization trait for option handle start a stream utils suite de-wrap/asyncify/type-query count_one_time_keys() de-wrap/asyncify users count add admin query users command suite de-wrap/asyncify users exists de-wrap/partially asyncify user filter related asyncify/de-wrap users device/keys related asyncify/de-wrap user auth/misc related asyncify/de-wrap users blurhash asyncify/de-wrap account_data get; merge Data into Service partial asyncify/de-wrap uiaa; merge Data into Service partially asyncify/de-wrap transaction_ids get; merge Data into Service partially asyncify/de-wrap key_backups; merge Data into Service asyncify/de-wrap pusher service getters; merge Data into Service asyncify/de-wrap rooms alias getters/some iterators asyncify/de-wrap rooms directory getters/iterator partially asyncify/de-wrap rooms lazy-loading partially asyncify/de-wrap rooms metadata asyncify/dewrap rooms outlier asyncify/dewrap rooms pdu_metadata dewrap/partially asyncify rooms read receipt de-wrap rooms search service de-wrap/partially asyncify rooms user service partial de-wrap rooms state_compressor de-wrap rooms state_cache de-wrap room state et al de-wrap rooms timeline service additional users device/keys related de-wrap/asyncify sender asyncify services refactor database to TryFuture/TryStream refactor services for TryFuture/TryStream asyncify api handlers additional asyncification for admin module abstract stream related; support reverse streams additional stream conversions asyncify state-res related Signed-off-by: Jason Volk <jason@zemos.net>
380 lines
11 KiB
Rust
380 lines
11 KiB
Rust
use axum::extract::State;
|
|
use conduit::{err, Err};
|
|
use ruma::{
|
|
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,
|
|
},
|
|
UInt,
|
|
};
|
|
|
|
use crate::{Result, Ruma};
|
|
|
|
/// # `POST /_matrix/client/r0/room_keys/version`
|
|
///
|
|
/// Creates a new backup.
|
|
pub(crate) async fn create_backup_version_route(
|
|
State(services): State<crate::State>, body: Ruma<create_backup_version::v3::Request>,
|
|
) -> Result<create_backup_version::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
let version = services
|
|
.key_backups
|
|
.create_backup(sender_user, &body.algorithm)?;
|
|
|
|
Ok(create_backup_version::v3::Response {
|
|
version,
|
|
})
|
|
}
|
|
|
|
/// # `PUT /_matrix/client/r0/room_keys/version/{version}`
|
|
///
|
|
/// Update information about an existing backup. Only `auth_data` can be
|
|
/// modified.
|
|
pub(crate) async fn update_backup_version_route(
|
|
State(services): State<crate::State>, body: Ruma<update_backup_version::v3::Request>,
|
|
) -> Result<update_backup_version::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
services
|
|
.key_backups
|
|
.update_backup(sender_user, &body.version, &body.algorithm)
|
|
.await?;
|
|
|
|
Ok(update_backup_version::v3::Response {})
|
|
}
|
|
|
|
/// # `GET /_matrix/client/r0/room_keys/version`
|
|
///
|
|
/// Get information about the latest backup version.
|
|
pub(crate) async fn get_latest_backup_info_route(
|
|
State(services): State<crate::State>, body: Ruma<get_latest_backup_info::v3::Request>,
|
|
) -> Result<get_latest_backup_info::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
let (version, algorithm) = services
|
|
.key_backups
|
|
.get_latest_backup(sender_user)
|
|
.await
|
|
.map_err(|_| err!(Request(NotFound("Key backup does not exist."))))?;
|
|
|
|
Ok(get_latest_backup_info::v3::Response {
|
|
algorithm,
|
|
count: (UInt::try_from(services.key_backups.count_keys(sender_user, &version).await)
|
|
.expect("user backup keys count should not be that high")),
|
|
etag: services.key_backups.get_etag(sender_user, &version).await,
|
|
version,
|
|
})
|
|
}
|
|
|
|
/// # `GET /_matrix/client/v3/room_keys/version/{version}`
|
|
///
|
|
/// Get information about an existing backup.
|
|
pub(crate) async fn get_backup_info_route(
|
|
State(services): State<crate::State>, body: Ruma<get_backup_info::v3::Request>,
|
|
) -> Result<get_backup_info::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
let algorithm = services
|
|
.key_backups
|
|
.get_backup(sender_user, &body.version)
|
|
.await
|
|
.map_err(|_| err!(Request(NotFound("Key backup does not exist at version {:?}", body.version))))?;
|
|
|
|
Ok(get_backup_info::v3::Response {
|
|
algorithm,
|
|
count: services
|
|
.key_backups
|
|
.count_keys(sender_user, &body.version)
|
|
.await
|
|
.try_into()?,
|
|
etag: services
|
|
.key_backups
|
|
.get_etag(sender_user, &body.version)
|
|
.await,
|
|
version: body.version.clone(),
|
|
})
|
|
}
|
|
|
|
/// # `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
|
|
pub(crate) async fn delete_backup_version_route(
|
|
State(services): State<crate::State>, body: Ruma<delete_backup_version::v3::Request>,
|
|
) -> Result<delete_backup_version::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
services
|
|
.key_backups
|
|
.delete_backup(sender_user, &body.version)
|
|
.await;
|
|
|
|
Ok(delete_backup_version::v3::Response {})
|
|
}
|
|
|
|
/// # `PUT /_matrix/client/r0/room_keys/keys`
|
|
///
|
|
/// Add the received backup keys to the database.
|
|
///
|
|
/// - 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
|
|
pub(crate) async fn add_backup_keys_route(
|
|
State(services): State<crate::State>, body: Ruma<add_backup_keys::v3::Request>,
|
|
) -> Result<add_backup_keys::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
if services
|
|
.key_backups
|
|
.get_latest_backup_version(sender_user)
|
|
.await
|
|
.is_ok_and(|version| version != body.version)
|
|
{
|
|
return Err!(Request(InvalidParam(
|
|
"You may only manipulate the most recently created version of the backup."
|
|
)));
|
|
}
|
|
|
|
for (room_id, room) in &body.rooms {
|
|
for (session_id, key_data) in &room.sessions {
|
|
services
|
|
.key_backups
|
|
.add_key(sender_user, &body.version, room_id, session_id, key_data)
|
|
.await?;
|
|
}
|
|
}
|
|
|
|
Ok(add_backup_keys::v3::Response {
|
|
count: services
|
|
.key_backups
|
|
.count_keys(sender_user, &body.version)
|
|
.await
|
|
.try_into()?,
|
|
etag: services
|
|
.key_backups
|
|
.get_etag(sender_user, &body.version)
|
|
.await,
|
|
})
|
|
}
|
|
|
|
/// # `PUT /_matrix/client/r0/room_keys/keys/{roomId}`
|
|
///
|
|
/// Add the received backup keys to the database.
|
|
///
|
|
/// - 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
|
|
pub(crate) async fn add_backup_keys_for_room_route(
|
|
State(services): State<crate::State>, body: Ruma<add_backup_keys_for_room::v3::Request>,
|
|
) -> Result<add_backup_keys_for_room::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
if services
|
|
.key_backups
|
|
.get_latest_backup_version(sender_user)
|
|
.await
|
|
.is_ok_and(|version| version != body.version)
|
|
{
|
|
return Err!(Request(InvalidParam(
|
|
"You may only manipulate the most recently created version of the backup."
|
|
)));
|
|
}
|
|
|
|
for (session_id, key_data) in &body.sessions {
|
|
services
|
|
.key_backups
|
|
.add_key(sender_user, &body.version, &body.room_id, session_id, key_data)
|
|
.await?;
|
|
}
|
|
|
|
Ok(add_backup_keys_for_room::v3::Response {
|
|
count: services
|
|
.key_backups
|
|
.count_keys(sender_user, &body.version)
|
|
.await
|
|
.try_into()?,
|
|
etag: services
|
|
.key_backups
|
|
.get_etag(sender_user, &body.version)
|
|
.await,
|
|
})
|
|
}
|
|
|
|
/// # `PUT /_matrix/client/r0/room_keys/keys/{roomId}/{sessionId}`
|
|
///
|
|
/// Add the received backup key to the database.
|
|
///
|
|
/// - 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
|
|
pub(crate) async fn add_backup_keys_for_session_route(
|
|
State(services): State<crate::State>, body: Ruma<add_backup_keys_for_session::v3::Request>,
|
|
) -> Result<add_backup_keys_for_session::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
if services
|
|
.key_backups
|
|
.get_latest_backup_version(sender_user)
|
|
.await
|
|
.is_ok_and(|version| version != body.version)
|
|
{
|
|
return Err!(Request(InvalidParam(
|
|
"You may only manipulate the most recently created version of the backup."
|
|
)));
|
|
}
|
|
|
|
services
|
|
.key_backups
|
|
.add_key(sender_user, &body.version, &body.room_id, &body.session_id, &body.session_data)
|
|
.await?;
|
|
|
|
Ok(add_backup_keys_for_session::v3::Response {
|
|
count: services
|
|
.key_backups
|
|
.count_keys(sender_user, &body.version)
|
|
.await
|
|
.try_into()?,
|
|
etag: services
|
|
.key_backups
|
|
.get_etag(sender_user, &body.version)
|
|
.await,
|
|
})
|
|
}
|
|
|
|
/// # `GET /_matrix/client/r0/room_keys/keys`
|
|
///
|
|
/// Retrieves all keys from the backup.
|
|
pub(crate) async fn get_backup_keys_route(
|
|
State(services): State<crate::State>, body: Ruma<get_backup_keys::v3::Request>,
|
|
) -> Result<get_backup_keys::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
let rooms = services
|
|
.key_backups
|
|
.get_all(sender_user, &body.version)
|
|
.await;
|
|
|
|
Ok(get_backup_keys::v3::Response {
|
|
rooms,
|
|
})
|
|
}
|
|
|
|
/// # `GET /_matrix/client/r0/room_keys/keys/{roomId}`
|
|
///
|
|
/// Retrieves all keys from the backup for a given room.
|
|
pub(crate) async fn get_backup_keys_for_room_route(
|
|
State(services): State<crate::State>, body: Ruma<get_backup_keys_for_room::v3::Request>,
|
|
) -> Result<get_backup_keys_for_room::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
let sessions = services
|
|
.key_backups
|
|
.get_room(sender_user, &body.version, &body.room_id)
|
|
.await;
|
|
|
|
Ok(get_backup_keys_for_room::v3::Response {
|
|
sessions,
|
|
})
|
|
}
|
|
|
|
/// # `GET /_matrix/client/r0/room_keys/keys/{roomId}/{sessionId}`
|
|
///
|
|
/// Retrieves a key from the backup.
|
|
pub(crate) async fn get_backup_keys_for_session_route(
|
|
State(services): State<crate::State>, body: Ruma<get_backup_keys_for_session::v3::Request>,
|
|
) -> Result<get_backup_keys_for_session::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
let key_data = services
|
|
.key_backups
|
|
.get_session(sender_user, &body.version, &body.room_id, &body.session_id)
|
|
.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,
|
|
})
|
|
}
|
|
|
|
/// # `DELETE /_matrix/client/r0/room_keys/keys`
|
|
///
|
|
/// Delete the keys from the backup.
|
|
pub(crate) async fn delete_backup_keys_route(
|
|
State(services): State<crate::State>, body: Ruma<delete_backup_keys::v3::Request>,
|
|
) -> Result<delete_backup_keys::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
services
|
|
.key_backups
|
|
.delete_all_keys(sender_user, &body.version)
|
|
.await;
|
|
|
|
Ok(delete_backup_keys::v3::Response {
|
|
count: services
|
|
.key_backups
|
|
.count_keys(sender_user, &body.version)
|
|
.await
|
|
.try_into()?,
|
|
etag: services
|
|
.key_backups
|
|
.get_etag(sender_user, &body.version)
|
|
.await,
|
|
})
|
|
}
|
|
|
|
/// # `DELETE /_matrix/client/r0/room_keys/keys/{roomId}`
|
|
///
|
|
/// Delete the keys from the backup for a given room.
|
|
pub(crate) async fn delete_backup_keys_for_room_route(
|
|
State(services): State<crate::State>, body: Ruma<delete_backup_keys_for_room::v3::Request>,
|
|
) -> Result<delete_backup_keys_for_room::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
services
|
|
.key_backups
|
|
.delete_room_keys(sender_user, &body.version, &body.room_id)
|
|
.await;
|
|
|
|
Ok(delete_backup_keys_for_room::v3::Response {
|
|
count: services
|
|
.key_backups
|
|
.count_keys(sender_user, &body.version)
|
|
.await
|
|
.try_into()?,
|
|
etag: services
|
|
.key_backups
|
|
.get_etag(sender_user, &body.version)
|
|
.await,
|
|
})
|
|
}
|
|
|
|
/// # `DELETE /_matrix/client/r0/room_keys/keys/{roomId}/{sessionId}`
|
|
///
|
|
/// Delete a key from the backup.
|
|
pub(crate) async fn delete_backup_keys_for_session_route(
|
|
State(services): State<crate::State>, body: Ruma<delete_backup_keys_for_session::v3::Request>,
|
|
) -> Result<delete_backup_keys_for_session::v3::Response> {
|
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
|
|
|
services
|
|
.key_backups
|
|
.delete_room_key(sender_user, &body.version, &body.room_id, &body.session_id)
|
|
.await;
|
|
|
|
Ok(delete_backup_keys_for_session::v3::Response {
|
|
count: services
|
|
.key_backups
|
|
.count_keys(sender_user, &body.version)
|
|
.await
|
|
.try_into()?,
|
|
etag: services
|
|
.key_backups
|
|
.get_etag(sender_user, &body.version)
|
|
.await,
|
|
})
|
|
}
|