Merge branch 'docs' into 'master'
docs: documentation for every endpoint See merge request famedly/conduit!177
This commit is contained in:
commit
4e68c22457
36 changed files with 864 additions and 94 deletions
|
@ -9,7 +9,7 @@ use std::{
|
|||
};
|
||||
use tracing::warn;
|
||||
|
||||
pub async fn send_request<T: OutgoingRequest>(
|
||||
pub(crate) async fn send_request<T: OutgoingRequest>(
|
||||
globals: &crate::database::globals::Globals,
|
||||
registration: serde_yaml::Value,
|
||||
request: T,
|
||||
|
|
|
@ -40,8 +40,12 @@ const GUEST_NAME_LENGTH: usize = 10;
|
|||
///
|
||||
/// Checks if a username is valid and available on this server.
|
||||
///
|
||||
/// - Returns true if no user or appservice on this server claimed this username
|
||||
/// - This will not reserve the username, so the username might become invalid when trying to register
|
||||
/// Conditions for returning true:
|
||||
/// - The user id is not historical
|
||||
/// - The server name of the user id matches this server
|
||||
/// - No user or appservice on this server already claimed this username
|
||||
///
|
||||
/// Note: This will not reserve the username, so the username might become invalid when trying to register
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/register/available", data = "<body>")
|
||||
|
@ -80,11 +84,15 @@ pub async fn get_register_available_route(
|
|||
///
|
||||
/// Register an account on this homeserver.
|
||||
///
|
||||
/// - Returns the device id and access_token unless `inhibit_login` is true
|
||||
/// - When registering a guest account, all parameters except initial_device_display_name will be
|
||||
/// ignored
|
||||
/// - Creates a new account and a device for it
|
||||
/// - The account will be populated with default account data
|
||||
/// You can use [`GET /_matrix/client/r0/register/available`](fn.get_register_available_route.html)
|
||||
/// to check if the user id is valid and available.
|
||||
///
|
||||
/// - Only works if registration is enabled
|
||||
/// - If type is guest: ignores all parameters except initial_device_display_name
|
||||
/// - If sender is not appservice: Requires UIAA (but we only use a dummy stage)
|
||||
/// - If type is not guest and no username is given: Always fails after UIAA check
|
||||
/// - Creates a new account and populates it with default account data
|
||||
/// - If `inhibit_login` is false: Creates a device and returns device id and access_token
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/register", data = "<body>")
|
||||
|
@ -129,7 +137,7 @@ pub async fn register_route(
|
|||
))?;
|
||||
|
||||
// Check if username is creative enough
|
||||
if !missing_username && db.users.exists(&user_id)? {
|
||||
if db.users.exists(&user_id)? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::UserInUse,
|
||||
"Desired user ID is already taken.",
|
||||
|
@ -193,12 +201,12 @@ pub async fn register_route(
|
|||
// Create user
|
||||
db.users.create(&user_id, password)?;
|
||||
|
||||
// Default to pretty displayname
|
||||
let displayname = format!("{} ⚡️", user_id.localpart());
|
||||
|
||||
db.users
|
||||
.set_displayname(&user_id, Some(displayname.clone()))?;
|
||||
|
||||
// Initial data
|
||||
// Initial account data
|
||||
db.account_data.update(
|
||||
None,
|
||||
&user_id,
|
||||
|
@ -211,6 +219,7 @@ pub async fn register_route(
|
|||
&db.globals,
|
||||
)?;
|
||||
|
||||
// Inhibit login does not work for guests
|
||||
if !is_guest && body.inhibit_login {
|
||||
return Ok(register::Response {
|
||||
access_token: None,
|
||||
|
@ -231,7 +240,7 @@ pub async fn register_route(
|
|||
// Generate new token for the device
|
||||
let token = utils::random_string(TOKEN_LENGTH);
|
||||
|
||||
// Add device
|
||||
// Create device for this account
|
||||
db.users.create_device(
|
||||
&user_id,
|
||||
&device_id,
|
||||
|
@ -239,7 +248,7 @@ pub async fn register_route(
|
|||
body.initial_device_display_name.clone(),
|
||||
)?;
|
||||
|
||||
// If this is the first user on this server, create the admins room
|
||||
// If this is the first user on this server, create the admin room
|
||||
if db.users.count()? == 1 {
|
||||
// Create a user for the server
|
||||
let conduit_user = UserId::parse_with_server_name("conduit", db.globals.server_name())
|
||||
|
@ -529,9 +538,16 @@ pub async fn register_route(
|
|||
///
|
||||
/// Changes the password of this account.
|
||||
///
|
||||
/// - Invalidates all other access tokens if logout_devices is true
|
||||
/// - Deletes all other devices and most of their data (to-device events, last seen, etc.) if
|
||||
/// logout_devices is true
|
||||
/// - Requires UIAA to verify user password
|
||||
/// - Changes the password of the sender user
|
||||
/// - The password hash is calculated using argon2 with 32 character salt, the plain password is
|
||||
/// not saved
|
||||
///
|
||||
/// If logout_devices is true it does the following for each device except the sender device:
|
||||
/// - Invalidates access token
|
||||
/// - Deletes device metadata (device id, device display name, last seen ip, last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/account/password", data = "<body>")
|
||||
|
@ -598,9 +614,9 @@ pub async fn change_password_route(
|
|||
|
||||
/// # `GET _matrix/client/r0/account/whoami`
|
||||
///
|
||||
/// Get user_id of this account.
|
||||
/// Get user_id of the sender user.
|
||||
///
|
||||
/// - Also works for Application Services
|
||||
/// Note: Also works for Application Services
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/account/whoami", data = "<body>")
|
||||
|
@ -616,11 +632,13 @@ pub async fn whoami_route(body: Ruma<whoami::Request>) -> ConduitResult<whoami::
|
|||
|
||||
/// # `POST /_matrix/client/r0/account/deactivate`
|
||||
///
|
||||
/// Deactivate this user's account
|
||||
/// Deactivate sender user account.
|
||||
///
|
||||
/// - Leaves all rooms and rejects all invitations
|
||||
/// - Invalidates all access tokens
|
||||
/// - Deletes all devices
|
||||
/// - Deletes all device metadata (device id, device display name, last seen ip, last seen ts)
|
||||
/// - Forgets all to-device events
|
||||
/// - Triggers device list updates
|
||||
/// - Removes ability to log in again
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
|
@ -667,6 +685,7 @@ pub async fn deactivate_route(
|
|||
}
|
||||
|
||||
// Leave all joined rooms and reject all invitations
|
||||
// TODO: work over federation invites
|
||||
let all_rooms = db
|
||||
.rooms
|
||||
.rooms_joined(&sender_user)
|
||||
|
@ -730,6 +749,8 @@ pub async fn deactivate_route(
|
|||
/// # `GET _matrix/client/r0/account/3pid`
|
||||
///
|
||||
/// Get a list of third party identifiers associated with this account.
|
||||
///
|
||||
/// - Currently always returns empty list
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/account/3pid", data = "<body>")
|
||||
|
|
|
@ -15,6 +15,9 @@ use ruma::{
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{delete, get, put};
|
||||
|
||||
/// # `PUT /_matrix/client/r0/directory/room/{roomAlias}`
|
||||
///
|
||||
/// Creates a new room alias on this server.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/directory/room/<_>", data = "<body>")
|
||||
|
@ -24,6 +27,13 @@ pub async fn create_alias_route(
|
|||
db: DatabaseGuard,
|
||||
body: Ruma<create_alias::Request<'_>>,
|
||||
) -> ConduitResult<create_alias::Response> {
|
||||
if body.room_alias.server_name() != db.globals.server_name() {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Alias is from another server.",
|
||||
));
|
||||
}
|
||||
|
||||
if db.rooms.id_from_alias(&body.room_alias)?.is_some() {
|
||||
return Err(Error::Conflict("Alias already exists."));
|
||||
}
|
||||
|
@ -36,6 +46,12 @@ pub async fn create_alias_route(
|
|||
Ok(create_alias::Response::new().into())
|
||||
}
|
||||
|
||||
/// # `DELETE /_matrix/client/r0/directory/room/{roomAlias}`
|
||||
///
|
||||
/// Deletes a room alias from this server.
|
||||
///
|
||||
/// - TODO: additional access control checks
|
||||
/// - TODO: Update canonical alias event
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
delete("/_matrix/client/r0/directory/room/<_>", data = "<body>")
|
||||
|
@ -45,13 +61,27 @@ pub async fn delete_alias_route(
|
|||
db: DatabaseGuard,
|
||||
body: Ruma<delete_alias::Request<'_>>,
|
||||
) -> ConduitResult<delete_alias::Response> {
|
||||
if body.room_alias.server_name() != db.globals.server_name() {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Alias is from another server.",
|
||||
));
|
||||
}
|
||||
|
||||
db.rooms.set_alias(&body.room_alias, None, &db.globals)?;
|
||||
|
||||
// TODO: update alt_aliases?
|
||||
|
||||
db.flush()?;
|
||||
|
||||
Ok(delete_alias::Response::new().into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/directory/room/{roomAlias}`
|
||||
///
|
||||
/// Resolve an alias locally or over federation.
|
||||
///
|
||||
/// - TODO: Suggest more servers to join via
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/directory/room/<_>", data = "<body>")
|
||||
|
@ -64,7 +94,7 @@ pub async fn get_alias_route(
|
|||
get_alias_helper(&db, &body.room_alias).await
|
||||
}
|
||||
|
||||
pub async fn get_alias_helper(
|
||||
pub(crate) async fn get_alias_helper(
|
||||
db: &Database,
|
||||
room_alias: &RoomAliasId,
|
||||
) -> ConduitResult<get_alias::Response> {
|
||||
|
|
|
@ -12,6 +12,9 @@ use ruma::api::client::{
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{delete, get, post, put};
|
||||
|
||||
/// # `POST /_matrix/client/r0/room_keys/version`
|
||||
///
|
||||
/// Creates a new backup.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/unstable/room_keys/version", data = "<body>")
|
||||
|
@ -31,6 +34,9 @@ pub async fn create_backup_route(
|
|||
Ok(create_backup::Response { version }.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/room_keys/version/{version}`
|
||||
///
|
||||
/// Update information about an existing backup. Only `auth_data` can be modified.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/unstable/room_keys/version/<_>", data = "<body>")
|
||||
|
@ -49,6 +55,9 @@ pub async fn update_backup_route(
|
|||
Ok(update_backup::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/room_keys/version`
|
||||
///
|
||||
/// Get information about the latest backup version.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/unstable/room_keys/version", data = "<body>")
|
||||
|
@ -77,6 +86,9 @@ pub async fn get_latest_backup_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/room_keys/version`
|
||||
///
|
||||
/// Get information about an existing backup.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/unstable/room_keys/version/<_>", data = "<body>")
|
||||
|
@ -104,6 +116,11 @@ pub async fn get_backup_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `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
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
delete("/_matrix/client/unstable/room_keys/version/<_>", data = "<body>")
|
||||
|
@ -122,7 +139,13 @@ pub async fn delete_backup_route(
|
|||
Ok(delete_backup::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `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
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/unstable/room_keys/keys", data = "<body>")
|
||||
|
@ -134,6 +157,18 @@ pub async fn add_backup_keys_route(
|
|||
) -> ConduitResult<add_backup_keys::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if Some(&body.version)
|
||||
!= db
|
||||
.key_backups
|
||||
.get_latest_backup_version(sender_user)?
|
||||
.as_ref()
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::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 {
|
||||
db.key_backups.add_key(
|
||||
|
@ -156,7 +191,13 @@ pub async fn add_backup_keys_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `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
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/unstable/room_keys/keys/<_>", data = "<body>")
|
||||
|
@ -168,6 +209,18 @@ pub async fn add_backup_key_sessions_route(
|
|||
) -> ConduitResult<add_backup_key_sessions::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if Some(&body.version)
|
||||
!= db
|
||||
.key_backups
|
||||
.get_latest_backup_version(sender_user)?
|
||||
.as_ref()
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"You may only manipulate the most recently created version of the backup.",
|
||||
));
|
||||
}
|
||||
|
||||
for (session_id, key_data) in &body.sessions {
|
||||
db.key_backups.add_key(
|
||||
&sender_user,
|
||||
|
@ -188,7 +241,13 @@ pub async fn add_backup_key_sessions_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `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
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/unstable/room_keys/keys/<_>/<_>", data = "<body>")
|
||||
|
@ -200,6 +259,18 @@ pub async fn add_backup_key_session_route(
|
|||
) -> ConduitResult<add_backup_key_session::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if Some(&body.version)
|
||||
!= db
|
||||
.key_backups
|
||||
.get_latest_backup_version(sender_user)?
|
||||
.as_ref()
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"You may only manipulate the most recently created version of the backup.",
|
||||
));
|
||||
}
|
||||
|
||||
db.key_backups.add_key(
|
||||
&sender_user,
|
||||
&body.version,
|
||||
|
@ -218,6 +289,9 @@ pub async fn add_backup_key_session_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/room_keys/keys`
|
||||
///
|
||||
/// Retrieves all keys from the backup.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/unstable/room_keys/keys", data = "<body>")
|
||||
|
@ -234,6 +308,9 @@ pub async fn get_backup_keys_route(
|
|||
Ok(get_backup_keys::Response { rooms }.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/room_keys/keys/{roomId}`
|
||||
///
|
||||
/// Retrieves all keys from the backup for a given room.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/unstable/room_keys/keys/<_>", data = "<body>")
|
||||
|
@ -252,6 +329,9 @@ pub async fn get_backup_key_sessions_route(
|
|||
Ok(get_backup_key_sessions::Response { sessions }.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/room_keys/keys/{roomId}/{sessionId}`
|
||||
///
|
||||
/// Retrieves a key from the backup.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/unstable/room_keys/keys/<_>/<_>", data = "<body>")
|
||||
|
@ -274,6 +354,9 @@ pub async fn get_backup_key_session_route(
|
|||
Ok(get_backup_key_session::Response { key_data }.into())
|
||||
}
|
||||
|
||||
/// # `DELETE /_matrix/client/r0/room_keys/keys`
|
||||
///
|
||||
/// Delete the keys from the backup.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
delete("/_matrix/client/unstable/room_keys/keys", data = "<body>")
|
||||
|
@ -297,6 +380,9 @@ pub async fn delete_backup_keys_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `DELETE /_matrix/client/r0/room_keys/keys/{roomId}`
|
||||
///
|
||||
/// Delete the keys from the backup for a given room.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
delete("/_matrix/client/unstable/room_keys/keys/<_>", data = "<body>")
|
||||
|
@ -320,6 +406,9 @@ pub async fn delete_backup_key_sessions_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `DELETE /_matrix/client/r0/room_keys/keys/{roomId}/{sessionId}`
|
||||
///
|
||||
/// Delete a key from the backup.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
delete("/_matrix/client/unstable/room_keys/keys/<_>/<_>", data = "<body>")
|
||||
|
|
|
@ -13,7 +13,7 @@ use rocket::get;
|
|||
|
||||
/// # `GET /_matrix/client/r0/capabilities`
|
||||
///
|
||||
/// Get information on this server's supported feature set and other relevent capabilities.
|
||||
/// Get information on the supported feature set and other relevent capabilities of this server.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/capabilities", data = "<_body>")
|
||||
|
|
|
@ -16,6 +16,9 @@ use serde_json::{json, value::RawValue as RawJsonValue};
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{get, put};
|
||||
|
||||
/// # `PUT /_matrix/client/r0/user/{userId}/account_data/{type}`
|
||||
///
|
||||
/// Sets some account data for the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/user/<_>/account_data/<_>", data = "<body>")
|
||||
|
@ -48,6 +51,9 @@ pub async fn set_global_account_data_route(
|
|||
Ok(set_global_account_data::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}`
|
||||
///
|
||||
/// Sets some room account data for the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put(
|
||||
|
@ -83,6 +89,9 @@ pub async fn set_room_account_data_route(
|
|||
Ok(set_room_account_data::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/user/{userId}/account_data/{type}`
|
||||
///
|
||||
/// Gets some account data for the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/user/<_>/account_data/<_>", data = "<body>")
|
||||
|
@ -98,7 +107,6 @@ pub async fn get_global_account_data_route(
|
|||
.account_data
|
||||
.get::<Box<RawJsonValue>>(None, sender_user, body.event_type.clone().into())?
|
||||
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?;
|
||||
db.flush()?;
|
||||
|
||||
let account_data = serde_json::from_str::<ExtractGlobalEventContent>(event.get())
|
||||
.map_err(|_| Error::bad_database("Invalid account data event in db."))?
|
||||
|
@ -107,6 +115,9 @@ pub async fn get_global_account_data_route(
|
|||
Ok(get_global_account_data::Response { account_data }.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}`
|
||||
///
|
||||
/// Gets some room account data for the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get(
|
||||
|
@ -129,7 +140,6 @@ pub async fn get_room_account_data_route(
|
|||
body.event_type.clone().into(),
|
||||
)?
|
||||
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?;
|
||||
db.flush()?;
|
||||
|
||||
let account_data = serde_json::from_str::<ExtractRoomEventContent>(event.get())
|
||||
.map_err(|_| Error::bad_database("Invalid account data event in db."))?
|
||||
|
|
|
@ -5,6 +5,12 @@ use std::convert::TryFrom;
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::get;
|
||||
|
||||
/// # `GET /_matrix/client/r0/rooms/{roomId}/context`
|
||||
///
|
||||
/// Allows loading room history around an event.
|
||||
///
|
||||
/// - Only works if the user is joined (TODO: always allow, but only show events if the user was
|
||||
/// joined, depending on history_visibility)
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/rooms/<_>/context/<_>", data = "<body>")
|
||||
|
|
|
@ -11,6 +11,9 @@ use super::SESSION_ID_LENGTH;
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{delete, get, post, put};
|
||||
|
||||
/// # `GET /_matrix/client/r0/devices`
|
||||
///
|
||||
/// Get metadata on all devices of the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/devices", data = "<body>")
|
||||
|
@ -31,6 +34,9 @@ pub async fn get_devices_route(
|
|||
Ok(get_devices::Response { devices }.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/devices/{deviceId}`
|
||||
///
|
||||
/// Get metadata on a single device of the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/devices/<_>", data = "<body>")
|
||||
|
@ -50,6 +56,9 @@ pub async fn get_device_route(
|
|||
Ok(get_device::Response { device }.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/devices/{deviceId}`
|
||||
///
|
||||
/// Updates the metadata on a given device of the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/devices/<_>", data = "<body>")
|
||||
|
@ -76,6 +85,15 @@ pub async fn update_device_route(
|
|||
Ok(update_device::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/devices/{deviceId}`
|
||||
///
|
||||
/// Deletes the given device.
|
||||
///
|
||||
/// - Requires UIAA to verify user password
|
||||
/// - Invalidates access token
|
||||
/// - Deletes device metadata (device id, device display name, last seen ip, last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
delete("/_matrix/client/r0/devices/<_>", data = "<body>")
|
||||
|
@ -128,6 +146,17 @@ pub async fn delete_device_route(
|
|||
Ok(delete_device::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/devices/{deviceId}`
|
||||
///
|
||||
/// Deletes the given device.
|
||||
///
|
||||
/// - Requires UIAA to verify user password
|
||||
///
|
||||
/// For each device:
|
||||
/// - Invalidates access token
|
||||
/// - Deletes device metadata (device id, device display name, last seen ip, last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/delete_devices", data = "<body>")
|
||||
|
|
|
@ -28,6 +28,11 @@ use tracing::{info, warn};
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{get, post, put};
|
||||
|
||||
/// # `POST /_matrix/client/r0/publicRooms`
|
||||
///
|
||||
/// Lists the public rooms on this server.
|
||||
///
|
||||
/// - Rooms are ordered by the number of joined members
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/publicRooms", data = "<body>")
|
||||
|
@ -48,6 +53,11 @@ pub async fn get_public_rooms_filtered_route(
|
|||
.await
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/publicRooms`
|
||||
///
|
||||
/// Lists the public rooms on this server.
|
||||
///
|
||||
/// - Rooms are ordered by the number of joined members
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/publicRooms", data = "<body>")
|
||||
|
@ -77,6 +87,11 @@ pub async fn get_public_rooms_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/directory/list/room/{roomId}`
|
||||
///
|
||||
/// Sets the visibility of a given room in the room directory.
|
||||
///
|
||||
/// - TODO: Access control checks
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/directory/list/room/<_>", data = "<body>")
|
||||
|
@ -107,6 +122,9 @@ pub async fn set_room_visibility_route(
|
|||
Ok(set_room_visibility::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/directory/list/room/{roomId}`
|
||||
///
|
||||
/// Gets the visibility of a given room in the room directory.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/directory/list/room/<_>", data = "<body>")
|
||||
|
@ -126,7 +144,7 @@ pub async fn get_room_visibility_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
pub async fn get_public_rooms_filtered_helper(
|
||||
pub(crate) async fn get_public_rooms_filtered_helper(
|
||||
db: &Database,
|
||||
server: Option<&ServerName>,
|
||||
limit: Option<UInt>,
|
||||
|
|
|
@ -4,6 +4,9 @@ use ruma::api::client::r0::filter::{self, create_filter, get_filter};
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{get, post};
|
||||
|
||||
/// # `GET /_matrix/client/r0/user/{userId}/filter/{filterId}`
|
||||
///
|
||||
/// TODO: Loads a filter that was previously created.
|
||||
#[cfg_attr(feature = "conduit_bin", get("/_matrix/client/r0/user/<_>/filter/<_>"))]
|
||||
#[tracing::instrument]
|
||||
pub async fn get_filter_route() -> ConduitResult<get_filter::Response> {
|
||||
|
@ -18,6 +21,9 @@ pub async fn get_filter_route() -> ConduitResult<get_filter::Response> {
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/user/{userId}/filter`
|
||||
///
|
||||
/// TODO: Creates a new filter to be used by other endpoints.
|
||||
#[cfg_attr(feature = "conduit_bin", post("/_matrix/client/r0/user/<_>/filter"))]
|
||||
#[tracing::instrument]
|
||||
pub async fn create_filter_route() -> ConduitResult<create_filter::Response> {
|
||||
|
|
|
@ -24,6 +24,12 @@ use std::collections::{BTreeMap, HashMap, HashSet};
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{get, post};
|
||||
|
||||
/// # `POST /_matrix/client/r0/keys/upload`
|
||||
///
|
||||
/// Publish end-to-end encryption keys for the sender device.
|
||||
///
|
||||
/// - Adds one time keys
|
||||
/// - If there are no device keys yet: Adds device keys (TODO: merge with existing keys?)
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/keys/upload", data = "<body>")
|
||||
|
@ -49,6 +55,7 @@ pub async fn upload_keys_route(
|
|||
}
|
||||
|
||||
if let Some(device_keys) = &body.device_keys {
|
||||
// TODO: merge this and the existing event?
|
||||
// This check is needed to assure that signatures are kept
|
||||
if db
|
||||
.users
|
||||
|
@ -73,6 +80,13 @@ pub async fn upload_keys_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/keys/query`
|
||||
///
|
||||
/// Get end-to-end encryption keys for the given users.
|
||||
///
|
||||
/// - Always fetches users from other servers over federation
|
||||
/// - Gets master keys, self-signing keys, user signing keys and device keys.
|
||||
/// - The master and self-signing keys contain signatures that the user is allowed to see
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/keys/query", data = "<body>")
|
||||
|
@ -95,6 +109,9 @@ pub async fn get_keys_route(
|
|||
Ok(response.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/keys/claim`
|
||||
///
|
||||
/// Claims one-time keys
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/keys/claim", data = "<body>")
|
||||
|
@ -111,6 +128,11 @@ pub async fn claim_keys_route(
|
|||
Ok(response.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/keys/device_signing/upload`
|
||||
///
|
||||
/// Uploads end-to-end key information for the sender user.
|
||||
///
|
||||
/// - Requires UIAA to verify password
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/unstable/keys/device_signing/upload", data = "<body>")
|
||||
|
@ -172,6 +194,9 @@ pub async fn upload_signing_keys_route(
|
|||
Ok(upload_signing_keys::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/keys/signatures/upload`
|
||||
///
|
||||
/// Uploads end-to-end key signatures from the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/unstable/keys/signatures/upload", data = "<body>")
|
||||
|
@ -233,6 +258,11 @@ pub async fn upload_signatures_route(
|
|||
Ok(upload_signatures::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/keys/changes`
|
||||
///
|
||||
/// Gets a list of users who have updated their device identity keys since the previous sync token.
|
||||
///
|
||||
/// - TODO: left users
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/keys/changes", data = "<body>")
|
||||
|
@ -284,7 +314,7 @@ pub async fn get_key_changes_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
pub async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
||||
pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
||||
sender_user: Option<&UserId>,
|
||||
device_keys_input: &BTreeMap<UserId, Vec<Box<DeviceId>>>,
|
||||
allowed_signatures: F,
|
||||
|
@ -409,7 +439,7 @@ pub async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn claim_keys_helper(
|
||||
pub(crate) async fn claim_keys_helper(
|
||||
one_time_keys_input: &BTreeMap<UserId, BTreeMap<Box<DeviceId>, DeviceKeyAlgorithm>>,
|
||||
db: &Database,
|
||||
) -> Result<claim_keys::Response> {
|
||||
|
|
|
@ -12,6 +12,9 @@ use rocket::{get, post};
|
|||
|
||||
const MXC_LENGTH: usize = 32;
|
||||
|
||||
/// # `GET /_matrix/media/r0/config`
|
||||
///
|
||||
/// Returns max upload size.
|
||||
#[cfg_attr(feature = "conduit_bin", get("/_matrix/media/r0/config"))]
|
||||
#[tracing::instrument(skip(db))]
|
||||
pub async fn get_media_config_route(
|
||||
|
@ -23,6 +26,12 @@ pub async fn get_media_config_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/media/r0/upload`
|
||||
///
|
||||
/// Permanently save media in the server.
|
||||
///
|
||||
/// - Some metadata will be saved in the database
|
||||
/// - Media will be saved in the media/ directory
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/media/r0/upload", data = "<body>")
|
||||
|
@ -61,6 +70,11 @@ pub async fn create_content_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/media/r0/download/{serverName}/{mediaId}`
|
||||
///
|
||||
/// Load media from our server or over federation.
|
||||
///
|
||||
/// - Only allows federation if `allow_remote` is true
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/media/r0/download/<_>/<_>", data = "<body>")
|
||||
|
@ -114,6 +128,11 @@ pub async fn get_content_route(
|
|||
}
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/media/r0/thumbnail/{serverName}/{mediaId}`
|
||||
///
|
||||
/// Load media thumbnail from our server or over federation.
|
||||
///
|
||||
/// - Only allows federation if `allow_remote` is true
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/media/r0/thumbnail/<_>/<_>", data = "<body>")
|
||||
|
|
|
@ -38,6 +38,12 @@ use tracing::{debug, error, warn};
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{get, post};
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/join`
|
||||
///
|
||||
/// Tries to join the sender user into a room.
|
||||
///
|
||||
/// - If the server knowns about this room: creates the join event and does auth rules locally
|
||||
/// - If the server does not know about the room: asks other servers over federation
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/rooms/<_>/join", data = "<body>")
|
||||
|
@ -79,6 +85,12 @@ pub async fn join_room_by_id_route(
|
|||
ret
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/join/{roomIdOrAlias}`
|
||||
///
|
||||
/// Tries to join the sender user into a room.
|
||||
///
|
||||
/// - If the server knowns about this room: creates the join event and does auth rules locally
|
||||
/// - If the server does not know about the room: asks other servers over federation
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/join/<_>", data = "<body>")
|
||||
|
@ -133,6 +145,11 @@ pub async fn join_room_by_id_or_alias_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/leave`
|
||||
///
|
||||
/// Tries to leave the sender user from a room.
|
||||
///
|
||||
/// - This should always work if the user is currently joined.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/rooms/<_>/leave", data = "<body>")
|
||||
|
@ -151,6 +168,9 @@ pub async fn leave_room_route(
|
|||
Ok(leave_room::Response::new().into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/invite`
|
||||
///
|
||||
/// Tries to send an invite event into the room.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/rooms/<_>/invite", data = "<body>")
|
||||
|
@ -171,6 +191,9 @@ pub async fn invite_user_route(
|
|||
}
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/kick`
|
||||
///
|
||||
/// Tries to send a kick event into the room.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/rooms/<_>/kick", data = "<body>")
|
||||
|
@ -234,6 +257,9 @@ pub async fn kick_user_route(
|
|||
Ok(kick_user::Response::new().into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/ban`
|
||||
///
|
||||
/// Tries to send a ban event into the room.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/rooms/<_>/ban", data = "<body>")
|
||||
|
@ -307,6 +333,9 @@ pub async fn ban_user_route(
|
|||
Ok(ban_user::Response::new().into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/unban`
|
||||
///
|
||||
/// Tries to send an unban event into the room.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/rooms/<_>/unban", data = "<body>")
|
||||
|
@ -369,6 +398,14 @@ pub async fn unban_user_route(
|
|||
Ok(unban_user::Response::new().into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/forget`
|
||||
///
|
||||
/// Forgets about a room.
|
||||
///
|
||||
/// - If the sender user currently left the room: Stops sender user from receiving information about the room
|
||||
///
|
||||
/// Note: Other devices of the user have no way of knowing the room was forgotten, so this has to
|
||||
/// be called from every device
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/rooms/<_>/forget", data = "<body>")
|
||||
|
@ -387,6 +424,9 @@ pub async fn forget_room_route(
|
|||
Ok(forget_room::Response::new().into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/joined_rooms`
|
||||
///
|
||||
/// Lists all rooms the user has joined.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/joined_rooms", data = "<body>")
|
||||
|
@ -408,6 +448,11 @@ pub async fn joined_rooms_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/members`
|
||||
///
|
||||
/// Lists all joined users in a room (TODO: at a specific point in time, with a specific membership).
|
||||
///
|
||||
/// - Only works if the user is currently joined
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/rooms/<_>/members", data = "<body>")
|
||||
|
@ -419,6 +464,7 @@ pub async fn get_member_events_route(
|
|||
) -> ConduitResult<get_member_events::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
// TODO: check history visibility?
|
||||
if !db.rooms.is_joined(sender_user, &body.room_id)? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
|
@ -438,6 +484,12 @@ pub async fn get_member_events_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/joined_members`
|
||||
///
|
||||
/// Lists all members of a room.
|
||||
///
|
||||
/// - The sender user must be in the room
|
||||
/// - TODO: An appservice just needs a puppet joined
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/rooms/<_>/joined_members", data = "<body>")
|
||||
|
@ -449,11 +501,7 @@ pub async fn joined_members_route(
|
|||
) -> ConduitResult<joined_members::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if !db
|
||||
.rooms
|
||||
.is_joined(&sender_user, &body.room_id)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
if !db.rooms.is_joined(&sender_user, &body.room_id)? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"You aren't a member of the room.",
|
||||
|
@ -803,7 +851,7 @@ async fn validate_and_add_event_id(
|
|||
Ok((event_id, value))
|
||||
}
|
||||
|
||||
pub async fn invite_helper<'a>(
|
||||
pub(crate) async fn invite_helper<'a>(
|
||||
sender_user: &UserId,
|
||||
user_id: &UserId,
|
||||
room_id: &RoomId,
|
||||
|
|
|
@ -16,6 +16,13 @@ use std::{
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{get, put};
|
||||
|
||||
/// # `PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}`
|
||||
///
|
||||
/// Send a message event into the room.
|
||||
///
|
||||
/// - Is a NOOP if the txn id was already used before and returns the same event id again
|
||||
/// - The only requirement for the content is that it has to be valid json
|
||||
/// - Tries to send the event into the room, auth rules will determine if it is allowed
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/rooms/<_>/send/<_>/<_>", data = "<body>")
|
||||
|
@ -92,6 +99,12 @@ pub async fn send_message_event_route(
|
|||
Ok(send_message_event::Response::new(event_id).into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/rooms/{roomId}/messages`
|
||||
///
|
||||
/// Allows paginating through room history.
|
||||
///
|
||||
/// - Only works if the user is joined (TODO: always allow, but only show events where the user was
|
||||
/// joined, depending on history_visibility)
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/rooms/<_>/messages", data = "<body>")
|
||||
|
|
|
@ -71,6 +71,9 @@ pub const DEVICE_ID_LENGTH: usize = 10;
|
|||
pub const TOKEN_LENGTH: usize = 256;
|
||||
pub const SESSION_ID_LENGTH: usize = 256;
|
||||
|
||||
/// # `OPTIONS`
|
||||
///
|
||||
/// Web clients use this to get CORS headers.
|
||||
#[cfg(feature = "conduit_bin")]
|
||||
#[options("/<_..>")]
|
||||
#[tracing::instrument]
|
||||
|
|
|
@ -5,6 +5,9 @@ use std::{convert::TryInto, time::Duration};
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{get, put};
|
||||
|
||||
/// # `PUT /_matrix/client/r0/presence/{userId}/status`
|
||||
///
|
||||
/// Sets the presence state of the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/presence/<_>/status", data = "<body>")
|
||||
|
@ -46,6 +49,11 @@ pub async fn set_presence_route(
|
|||
Ok(set_presence::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/presence/{userId}/status`
|
||||
///
|
||||
/// Gets the presence state of the given user.
|
||||
///
|
||||
/// - Only works if you share a room with the user
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/presence/<_>/status", data = "<body>")
|
||||
|
@ -71,6 +79,7 @@ pub async fn get_presence_route(
|
|||
.get_last_presence_event(&sender_user, &room_id)?
|
||||
{
|
||||
presence_event = Some(presence);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,11 @@ use std::{convert::TryInto, sync::Arc};
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{get, put};
|
||||
|
||||
/// # `PUT /_matrix/client/r0/profile/{userId}/displayname`
|
||||
///
|
||||
/// Updates the displayname.
|
||||
///
|
||||
/// - Also makes sure other users receive the update using presence EDUs
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/profile/<_>/displayname", data = "<body>")
|
||||
|
@ -115,6 +120,11 @@ pub async fn set_displayname_route(
|
|||
Ok(set_display_name::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/profile/{userId}/displayname`
|
||||
///
|
||||
/// Returns the displayname of the user.
|
||||
///
|
||||
/// - If user is on another server: Fetches displayname over federation
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/profile/<_>/displayname", data = "<body>")
|
||||
|
@ -149,6 +159,11 @@ pub async fn get_displayname_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/profile/{userId}/avatar_url`
|
||||
///
|
||||
/// Updates the avatar_url and blurhash.
|
||||
///
|
||||
/// - Also makes sure other users receive the update using presence EDUs
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/profile/<_>/avatar_url", data = "<body>")
|
||||
|
@ -249,6 +264,11 @@ pub async fn set_avatar_url_route(
|
|||
Ok(set_avatar_url::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/profile/{userId}/avatar_url`
|
||||
///
|
||||
/// Returns the avatar_url and blurhash of the user.
|
||||
///
|
||||
/// - If user is on another server: Fetches avatar_url and blurhash over federation
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/profile/<_>/avatar_url", data = "<body>")
|
||||
|
@ -285,6 +305,11 @@ pub async fn get_avatar_url_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/profile/{userId}`
|
||||
///
|
||||
/// Returns the displayname, avatar_url and blurhash of the user.
|
||||
///
|
||||
/// - If user is on another server: Fetches profile over federation
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/profile/<_>", data = "<body>")
|
||||
|
|
|
@ -15,6 +15,9 @@ use ruma::{
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{delete, get, post, put};
|
||||
|
||||
/// # `GET /_matrix/client/r0/pushrules`
|
||||
///
|
||||
/// Retrieves the push rules event for this user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/pushrules", data = "<body>")
|
||||
|
@ -40,6 +43,9 @@ pub async fn get_pushrules_all_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}`
|
||||
///
|
||||
/// Retrieves a single specified push rule for this user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/pushrules/<_>/<_>/<_>", data = "<body>")
|
||||
|
@ -94,6 +100,9 @@ pub async fn get_pushrule_route(
|
|||
}
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}`
|
||||
///
|
||||
/// Creates a single specified push rule for this user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/pushrules/<_>/<_>/<_>", data = "<req>")
|
||||
|
@ -197,6 +206,9 @@ pub async fn set_pushrule_route(
|
|||
Ok(set_pushrule::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/actions`
|
||||
///
|
||||
/// Gets the actions of a single specified push rule for this user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/pushrules/<_>/<_>/<_>/actions", data = "<body>")
|
||||
|
@ -256,6 +268,9 @@ pub async fn get_pushrule_actions_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/actions`
|
||||
///
|
||||
/// Sets the actions of a single specified push rule for this user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/pushrules/<_>/<_>/<_>/actions", data = "<body>")
|
||||
|
@ -330,6 +345,9 @@ pub async fn set_pushrule_actions_route(
|
|||
Ok(set_pushrule_actions::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/enabled`
|
||||
///
|
||||
/// Gets the enabled status of a single specified push rule for this user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/pushrules/<_>/<_>/<_>/enabled", data = "<body>")
|
||||
|
@ -391,6 +409,9 @@ pub async fn get_pushrule_enabled_route(
|
|||
Ok(get_pushrule_enabled::Response { enabled }.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/enabled`
|
||||
///
|
||||
/// Sets the enabled status of a single specified push rule for this user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/pushrules/<_>/<_>/<_>/enabled", data = "<body>")
|
||||
|
@ -470,6 +491,9 @@ pub async fn set_pushrule_enabled_route(
|
|||
Ok(set_pushrule_enabled::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `DELETE /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}`
|
||||
///
|
||||
/// Deletes a single specified push rule for this user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
delete("/_matrix/client/r0/pushrules/<_>/<_>/<_>", data = "<body>")
|
||||
|
@ -539,6 +563,9 @@ pub async fn delete_pushrule_route(
|
|||
Ok(delete_pushrule::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/pushers`
|
||||
///
|
||||
/// Gets all currently active pushers for the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/pushers", data = "<body>")
|
||||
|
@ -556,6 +583,11 @@ pub async fn get_pushers_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/pushers/set`
|
||||
///
|
||||
/// Adds a pusher for the sender user.
|
||||
///
|
||||
/// - TODO: Handle `append`
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/pushers/set", data = "<body>")
|
||||
|
|
|
@ -13,6 +13,12 @@ use std::collections::BTreeMap;
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::post;
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/read_markers`
|
||||
///
|
||||
/// Sets different types of read markers.
|
||||
///
|
||||
/// - Updates fully-read account data event to `fully_read`
|
||||
/// - If `read_receipt` is set: Update private marker and public read receipt EDU
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/rooms/<_>/read_markers", data = "<body>")
|
||||
|
@ -80,6 +86,9 @@ pub async fn set_read_marker_route(
|
|||
Ok(set_read_marker::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/receipt/{receiptType}/{eventId}`
|
||||
///
|
||||
/// Sets private read marker and public read receipt EDU.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/rooms/<_>/receipt/<_>/<_>", data = "<body>")
|
||||
|
|
|
@ -9,6 +9,11 @@ use ruma::{
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::put;
|
||||
|
||||
/// # `PUT /_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}`
|
||||
///
|
||||
/// Tries to send a redaction event into the room.
|
||||
///
|
||||
/// - TODO: Handle txn id
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/rooms/<_>/redact/<_>/<_>", data = "<body>")
|
||||
|
|
|
@ -20,6 +20,22 @@ use tracing::{info, warn};
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{get, post};
|
||||
|
||||
/// # `POST /_matrix/client/r0/createRoom`
|
||||
///
|
||||
/// Creates a new room.
|
||||
///
|
||||
/// - Room ID is randomly generated
|
||||
/// - Create alias if room_alias_name is set
|
||||
/// - Send create event
|
||||
/// - Join sender user
|
||||
/// - Send power levels event
|
||||
/// - Send canonical room alias
|
||||
/// - Send join rules
|
||||
/// - Send history visibility
|
||||
/// - Send guest access
|
||||
/// - Send events listed in initial state
|
||||
/// - Send events implied by `name` and `topic`
|
||||
/// - Send invite events
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/createRoom", data = "<body>")
|
||||
|
@ -344,6 +360,11 @@ pub async fn create_room_route(
|
|||
Ok(create_room::Response::new(room_id).into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/rooms/{roomId}/event/{eventId}`
|
||||
///
|
||||
/// Gets a single event.
|
||||
///
|
||||
/// - You have to currently be joined to the room (TODO: Respect history visibility)
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/rooms/<_>/event/<_>", data = "<body>")
|
||||
|
@ -372,6 +393,11 @@ pub async fn get_room_event_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/rooms/{roomId}/aliases`
|
||||
///
|
||||
/// Lists all aliases of the room.
|
||||
///
|
||||
/// - Only users joined to the room are allowed to call this TODO: Allow any user to call it if history_visibility is world readable
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/rooms/<_>/aliases", data = "<body>")
|
||||
|
@ -400,6 +426,16 @@ pub async fn get_room_aliases_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/rooms/{roomId}/upgrade`
|
||||
///
|
||||
/// Upgrades the room.
|
||||
///
|
||||
/// - Creates a replacement room
|
||||
/// - Sends a tombstone event into the current room
|
||||
/// - Sender user joins the room
|
||||
/// - Transfers some state events
|
||||
/// - Moves local aliases
|
||||
/// - Modifies old room power levels to prevent users from speaking
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/rooms/<_>/upgrade", data = "<body>")
|
||||
|
|
|
@ -6,6 +6,11 @@ use rocket::post;
|
|||
use search_events::{EventContextResult, ResultCategories, ResultRoomEvents, SearchResult};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// # `POST /_matrix/client/r0/search`
|
||||
///
|
||||
/// Searches rooms for messages.
|
||||
///
|
||||
/// - Only works if the user is currently joined to the room (TODO: Respect history visibility)
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/search", data = "<body>")
|
||||
|
|
|
@ -24,7 +24,7 @@ use rocket::{get, post};
|
|||
|
||||
/// # `GET /_matrix/client/r0/login`
|
||||
///
|
||||
/// Get the homeserver's supported login types. One of these should be used as the `type` field
|
||||
/// Get the supported login types of this server. One of these should be used as the `type` field
|
||||
/// when logging in.
|
||||
#[cfg_attr(feature = "conduit_bin", get("/_matrix/client/r0/login"))]
|
||||
#[tracing::instrument]
|
||||
|
@ -41,9 +41,10 @@ pub async fn get_login_types_route() -> ConduitResult<get_login_types::Response>
|
|||
///
|
||||
/// Authenticates the user and returns an access token it can use in subsequent requests.
|
||||
///
|
||||
/// - The returned access token is associated with the user and device
|
||||
/// - Old access tokens of that device should be invalidated
|
||||
/// - If `device_id` is unknown, a new device will be created
|
||||
/// - The user needs to authenticate using their password (or if enabled using a json web token)
|
||||
/// - If `device_id` is known: invalidates old access token of that device
|
||||
/// - If `device_id` is unknown: creates a new device
|
||||
/// - Returns access token that is associated with the user and device
|
||||
///
|
||||
/// Note: You can use [`GET /_matrix/client/r0/login`](fn.get_supported_versions_route.html) to see
|
||||
/// supported login types.
|
||||
|
@ -162,8 +163,10 @@ pub async fn login_route(
|
|||
///
|
||||
/// Log out the current device.
|
||||
///
|
||||
/// - Invalidates the access token
|
||||
/// - Deletes the device and most of it's data (to-device events, last seen, etc.)
|
||||
/// - Invalidates access token
|
||||
/// - Deletes device metadata (device id, device display name, last seen ip, last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/logout", data = "<body>")
|
||||
|
@ -188,7 +191,9 @@ pub async fn logout_route(
|
|||
/// Log out all devices of this user.
|
||||
///
|
||||
/// - Invalidates all access tokens
|
||||
/// - Deletes devices and most of their data (to-device events, last seen, etc.)
|
||||
/// - Deletes all device metadata (device id, device display name, last seen ip, last seen ts)
|
||||
/// - Forgets all to-device events
|
||||
/// - Triggers device list updates
|
||||
///
|
||||
/// Note: This is equivalent to calling [`GET /_matrix/client/r0/logout`](fn.logout_route.html)
|
||||
/// from each device of this user.
|
||||
|
|
|
@ -22,6 +22,13 @@ use ruma::{
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{get, put};
|
||||
|
||||
/// # `PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}`
|
||||
///
|
||||
/// Sends a state event into the room.
|
||||
///
|
||||
/// - The only requirement for the content is that it has to be valid json
|
||||
/// - Tries to send the event into the room, auth rules will determine if it is allowed
|
||||
/// - If event is new canonical_alias: Rejects if alias is incorrect
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/rooms/<_>/state/<_>/<_>", data = "<body>")
|
||||
|
@ -48,6 +55,13 @@ pub async fn send_state_event_for_key_route(
|
|||
Ok(send_state_event::Response { event_id }.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}`
|
||||
///
|
||||
/// Sends a state event into the room.
|
||||
///
|
||||
/// - The only requirement for the content is that it has to be valid json
|
||||
/// - Tries to send the event into the room, auth rules will determine if it is allowed
|
||||
/// - If event is new canonical_alias: Rejects if alias is incorrect
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/rooms/<_>/state/<_>", data = "<body>")
|
||||
|
@ -74,6 +88,11 @@ pub async fn send_state_event_for_empty_key_route(
|
|||
Ok(send_state_event::Response { event_id }.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/rooms/{roomid}/state`
|
||||
///
|
||||
/// Get all state events for a room.
|
||||
///
|
||||
/// - If not joined: Only works if current room history visibility is world readable
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/rooms/<_>/state", data = "<body>")
|
||||
|
@ -121,6 +140,11 @@ pub async fn get_state_events_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/rooms/{roomid}/state/{eventType}/{stateKey}`
|
||||
///
|
||||
/// Get single state event of a room.
|
||||
///
|
||||
/// - If not joined: Only works if current room history visibility is world readable
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/rooms/<_>/state/<_>/<_>", data = "<body>")
|
||||
|
@ -172,6 +196,11 @@ pub async fn get_state_events_for_key_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/rooms/{roomid}/state/{eventType}`
|
||||
///
|
||||
/// Get single state event of a room.
|
||||
///
|
||||
/// - If not joined: Only works if current room history visibility is world readable
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/rooms/<_>/state/<_>", data = "<body>")
|
||||
|
@ -223,7 +252,7 @@ pub async fn get_state_events_for_empty_key_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
pub async fn send_state_event_for_key_helper(
|
||||
async fn send_state_event_for_key_helper(
|
||||
db: &Database,
|
||||
sender: &UserId,
|
||||
room_id: &RoomId,
|
||||
|
@ -233,6 +262,8 @@ pub async fn send_state_event_for_key_helper(
|
|||
) -> Result<EventId> {
|
||||
let sender_user = sender;
|
||||
|
||||
// TODO: Review this check, error if event is unparsable, use event type, allow alias if it
|
||||
// previously existed
|
||||
if let Ok(canonical_alias) =
|
||||
serde_json::from_str::<CanonicalAliasEventContent>(json.json().get())
|
||||
{
|
||||
|
|
|
@ -22,12 +22,33 @@ use rocket::{get, tokio};
|
|||
/// Synchronize the client's state with the latest state on the server.
|
||||
///
|
||||
/// - This endpoint takes a `since` parameter which should be the `next_batch` value from a
|
||||
/// previous request.
|
||||
/// - Calling this endpoint without a `since` parameter will return all recent events, the state
|
||||
/// of all rooms and more data. This should only be called on the initial login of the device.
|
||||
/// - To get incremental updates, you can call this endpoint with a `since` parameter. This will
|
||||
/// return all recent events, state updates and more data that happened since the last /sync
|
||||
/// request.
|
||||
/// previous request for incremental syncs.
|
||||
///
|
||||
/// Calling this endpoint without a `since` parameter returns:
|
||||
/// - Some of the most recent events of each timeline
|
||||
/// - Notification counts for each room
|
||||
/// - Joined and invited member counts, heroes
|
||||
/// - All state events
|
||||
///
|
||||
/// Calling this endpoint with a `since` parameter from a previous `next_batch` returns:
|
||||
/// For joined rooms:
|
||||
/// - Some of the most recent events of each timeline that happened after since
|
||||
/// - If user joined the room after since: All state events and device list updates in that room
|
||||
/// - If the user was already in the room: A list of all events that are in the state now, but were
|
||||
/// not in the state at `since`
|
||||
/// - If the state we send contains a member event: Joined and invited member counts, heroes
|
||||
/// - Device list updates that happened after `since`
|
||||
/// - If there are events in the timeline we send or the user send updated his read mark: Notification counts
|
||||
/// - EDUs that are active now (read receipts, typing updates, presence)
|
||||
///
|
||||
/// For invited rooms:
|
||||
/// - If the user was invited after `since`: A subset of the state of the room at the point of the invite
|
||||
///
|
||||
/// For left rooms:
|
||||
/// - If the user left after `since`: prev_batch token, empty state (TODO: subset of the state at the point of the leave)
|
||||
///
|
||||
/// - Sync is handled in an async task, multiple requests from the same device with the same
|
||||
/// `since` will be cached
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/sync", data = "<body>")
|
||||
|
@ -106,7 +127,7 @@ pub async fn sync_events_route(
|
|||
result
|
||||
}
|
||||
|
||||
pub async fn sync_helper_wrapper(
|
||||
async fn sync_helper_wrapper(
|
||||
db: Arc<DatabaseGuard>,
|
||||
sender_user: UserId,
|
||||
sender_device: Box<DeviceId>,
|
||||
|
|
|
@ -8,6 +8,11 @@ use std::collections::BTreeMap;
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::{delete, get, put};
|
||||
|
||||
/// # `PUT /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags/{tag}`
|
||||
///
|
||||
/// Adds a tag to the room.
|
||||
///
|
||||
/// - Inserts the tag into the tag event of the room account data.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/user/<_>/rooms/<_>/tags/<_>", data = "<body>")
|
||||
|
@ -45,6 +50,11 @@ pub async fn update_tag_route(
|
|||
Ok(create_tag::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `DELETE /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags/{tag}`
|
||||
///
|
||||
/// Deletes a tag from the room.
|
||||
///
|
||||
/// - Removes the tag from the tag event of the room account data.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
delete("/_matrix/client/r0/user/<_>/rooms/<_>/tags/<_>", data = "<body>")
|
||||
|
@ -79,6 +89,11 @@ pub async fn delete_tag_route(
|
|||
Ok(delete_tag::Response {}.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags`
|
||||
///
|
||||
/// Returns tags on the room.
|
||||
///
|
||||
/// - Gets the tag event of the room account data.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/user/<_>/rooms/<_>/tags", data = "<body>")
|
||||
|
|
|
@ -5,6 +5,9 @@ use ruma::api::client::r0::thirdparty::get_protocols;
|
|||
use rocket::get;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// # `GET /_matrix/client/r0/thirdparty/protocols`
|
||||
///
|
||||
/// TODO: Fetches all metadata about protocols supported by the homeserver.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/client/r0/thirdparty/protocols")
|
||||
|
|
|
@ -13,6 +13,9 @@ use ruma::{
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::put;
|
||||
|
||||
/// # `PUT /_matrix/client/r0/sendToDevice/{eventType}/{txnId}`
|
||||
///
|
||||
/// Send a to-device event to a set of client devices.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/sendToDevice/<_>/<_>", data = "<body>")
|
||||
|
|
|
@ -5,6 +5,9 @@ use ruma::api::client::r0::typing::create_typing_event;
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::put;
|
||||
|
||||
/// # `PUT /_matrix/client/r0/rooms/{roomId}/typing/{userId}`
|
||||
///
|
||||
/// Sets the typing state of the sender user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/client/r0/rooms/<_>/typing/<_>", data = "<body>")
|
||||
|
|
|
@ -10,7 +10,7 @@ use rocket::get;
|
|||
///
|
||||
/// - Versions take the form MAJOR.MINOR.PATCH
|
||||
/// - Only the latest PATCH release will be reported for each MAJOR.MINOR value
|
||||
/// - Unstable features should be namespaced and may include version information in their name
|
||||
/// - Unstable features are namespaced and may include version information in their name
|
||||
///
|
||||
/// Note: Unstable features are used while developing new features. Clients should avoid using
|
||||
/// unstable features in their stable releases
|
||||
|
|
|
@ -4,6 +4,11 @@ use ruma::api::client::r0::user_directory::search_users;
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::post;
|
||||
|
||||
/// # `POST /_matrix/client/r0/user_directory/search`
|
||||
///
|
||||
/// Searches all known users for a match.
|
||||
///
|
||||
/// - TODO: Hide users that are not in any public rooms?
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/user_directory/search", data = "<body>")
|
||||
|
|
|
@ -5,6 +5,9 @@ use std::time::Duration;
|
|||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::get;
|
||||
|
||||
/// # `GET /_matrix/client/r0/voip/turnServer`
|
||||
///
|
||||
/// TODO: Returns information about the recommended turn server.
|
||||
#[cfg_attr(feature = "conduit_bin", get("/_matrix/client/r0/voip/turnServer"))]
|
||||
#[tracing::instrument]
|
||||
pub async fn turn_server_route() -> ConduitResult<get_turn_server_info::Response> {
|
||||
|
|
|
@ -47,6 +47,8 @@ pub struct Config {
|
|||
database_path: String,
|
||||
#[serde(default = "default_db_cache_capacity_mb")]
|
||||
db_cache_capacity_mb: f64,
|
||||
#[serde(default = "default_pdu_cache_capacity")]
|
||||
pdu_cache_capacity: u32,
|
||||
#[serde(default = "default_sqlite_wal_clean_second_interval")]
|
||||
sqlite_wal_clean_second_interval: u32,
|
||||
#[serde(default = "default_max_request_size")]
|
||||
|
@ -107,6 +109,10 @@ fn default_db_cache_capacity_mb() -> f64 {
|
|||
200.0
|
||||
}
|
||||
|
||||
fn default_pdu_cache_capacity() -> u32 {
|
||||
100_000
|
||||
}
|
||||
|
||||
fn default_sqlite_wal_clean_second_interval() -> u32 {
|
||||
1 * 60 // every minute
|
||||
}
|
||||
|
@ -281,7 +287,12 @@ impl Database {
|
|||
softfailedeventids: builder.open_tree("softfailedeventids")?,
|
||||
|
||||
referencedevents: builder.open_tree("referencedevents")?,
|
||||
pdu_cache: Mutex::new(LruCache::new(100_000)),
|
||||
pdu_cache: Mutex::new(LruCache::new(
|
||||
config
|
||||
.pdu_cache_capacity
|
||||
.try_into()
|
||||
.expect("pdu cache capacity fits into usize"),
|
||||
)),
|
||||
auth_chain_cache: Mutex::new(LruCache::new(1_000_000)),
|
||||
shorteventid_cache: Mutex::new(LruCache::new(1_000_000)),
|
||||
eventidshort_cache: Mutex::new(LruCache::new(1_000_000)),
|
||||
|
|
|
@ -84,6 +84,27 @@ impl KeyBackups {
|
|||
Ok(version.to_string())
|
||||
}
|
||||
|
||||
pub fn get_latest_backup_version(&self, user_id: &UserId) -> Result<Option<String>> {
|
||||
let mut prefix = user_id.as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
let mut last_possible_key = prefix.clone();
|
||||
last_possible_key.extend_from_slice(&u64::MAX.to_be_bytes());
|
||||
|
||||
self.backupid_algorithm
|
||||
.iter_from(&last_possible_key, true)
|
||||
.take_while(move |(k, _)| k.starts_with(&prefix))
|
||||
.next()
|
||||
.map_or(Ok(None), |(key, _)| {
|
||||
utils::string_from_bytes(
|
||||
key.rsplit(|&b| b == 0xff)
|
||||
.next()
|
||||
.expect("rsplit always returns an element"),
|
||||
)
|
||||
.map_err(|_| Error::bad_database("backupid_algorithm key is invalid."))
|
||||
.map(Some)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_latest_backup(&self, user_id: &UserId) -> Result<Option<(String, BackupAlgorithm)>> {
|
||||
let mut prefix = user_id.as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
|
|
|
@ -1529,19 +1529,35 @@ impl Rooms {
|
|||
"get_auth_chain" => {
|
||||
if args.len() == 1 {
|
||||
if let Ok(event_id) = EventId::try_from(args[0]) {
|
||||
let start = Instant::now();
|
||||
let count = server_server::get_auth_chain(
|
||||
vec![Arc::new(event_id)],
|
||||
db,
|
||||
)?
|
||||
.count();
|
||||
let elapsed = start.elapsed();
|
||||
db.admin.send(AdminCommand::SendMessage(
|
||||
message::MessageEventContent::text_plain(format!(
|
||||
if let Some(event) = db.rooms.get_pdu_json(&event_id)? {
|
||||
let room_id_str = event
|
||||
.get("room_id")
|
||||
.and_then(|val| val.as_str())
|
||||
.ok_or_else(|| {
|
||||
Error::bad_database(
|
||||
"Invalid event in database",
|
||||
)
|
||||
})?;
|
||||
|
||||
let room_id = RoomId::try_from(room_id_str)
|
||||
.map_err(|_| Error::bad_database("Invalid room id field in event in database"))?;
|
||||
let start = Instant::now();
|
||||
let count = server_server::get_auth_chain(
|
||||
&room_id,
|
||||
vec![Arc::new(event_id)],
|
||||
db,
|
||||
)?
|
||||
.count();
|
||||
let elapsed = start.elapsed();
|
||||
db.admin.send(AdminCommand::SendMessage(
|
||||
message::MessageEventContent::text_plain(
|
||||
format!(
|
||||
"Loaded auth chain with length {} in {:?}",
|
||||
count, elapsed
|
||||
)),
|
||||
));
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3083,6 +3099,15 @@ impl Rooms {
|
|||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn server_in_room<'a>(&'a self, server: &ServerName, room_id: &RoomId) -> Result<bool> {
|
||||
let mut key = server.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(room_id.as_bytes());
|
||||
|
||||
self.serverroomids.get(&key).map(|o| o.is_some())
|
||||
}
|
||||
|
||||
/// Returns an iterator of all rooms a server participates in (as far as we know).
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn server_rooms<'a>(
|
||||
|
|
|
@ -119,7 +119,7 @@ impl FedDest {
|
|||
}
|
||||
|
||||
#[tracing::instrument(skip(globals, request))]
|
||||
pub async fn send_request<T: OutgoingRequest>(
|
||||
pub(crate) async fn send_request<T: OutgoingRequest>(
|
||||
globals: &crate::database::globals::Globals,
|
||||
destination: &ServerName,
|
||||
request: T,
|
||||
|
@ -487,7 +487,7 @@ async fn query_srv_record(
|
|||
}
|
||||
|
||||
#[tracing::instrument(skip(globals))]
|
||||
pub async fn request_well_known(
|
||||
async fn request_well_known(
|
||||
globals: &crate::database::globals::Globals,
|
||||
destination: &str,
|
||||
) -> Option<String> {
|
||||
|
@ -512,6 +512,9 @@ pub async fn request_well_known(
|
|||
Some(body.get("m.server")?.as_str()?.to_owned())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/federation/v1/version`
|
||||
///
|
||||
/// Get version information on this server.
|
||||
#[cfg_attr(feature = "conduit_bin", get("/_matrix/federation/v1/version"))]
|
||||
#[tracing::instrument(skip(db))]
|
||||
pub fn get_server_version_route(
|
||||
|
@ -530,6 +533,12 @@ pub fn get_server_version_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/key/v2/server`
|
||||
///
|
||||
/// Gets the public signing keys of this server.
|
||||
///
|
||||
/// - Matrix does not support invalidating public keys, so the key returned by this will be valid
|
||||
/// forever.
|
||||
// Response type for this endpoint is Json because we need to calculate a signature for the response
|
||||
#[cfg_attr(feature = "conduit_bin", get("/_matrix/key/v2/server"))]
|
||||
#[tracing::instrument(skip(db))]
|
||||
|
@ -578,12 +587,21 @@ pub fn get_server_keys_route(db: DatabaseGuard) -> Json<String> {
|
|||
Json(serde_json::to_string(&response).expect("JSON is canonical"))
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/key/v2/server/{keyId}`
|
||||
///
|
||||
/// Gets the public signing keys of this server.
|
||||
///
|
||||
/// - Matrix does not support invalidating public keys, so the key returned by this will be valid
|
||||
/// forever.
|
||||
#[cfg_attr(feature = "conduit_bin", get("/_matrix/key/v2/server/<_>"))]
|
||||
#[tracing::instrument(skip(db))]
|
||||
pub fn get_server_keys_deprecated_route(db: DatabaseGuard) -> Json<String> {
|
||||
get_server_keys_route(db)
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/federation/v1/publicRooms`
|
||||
///
|
||||
/// Lists the public rooms on this server.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/federation/v1/publicRooms", data = "<body>")
|
||||
|
@ -628,6 +646,9 @@ pub async fn get_public_rooms_filtered_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/federation/v1/publicRooms`
|
||||
///
|
||||
/// Lists the public rooms on this server.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/federation/v1/publicRooms", data = "<body>")
|
||||
|
@ -672,6 +693,9 @@ pub async fn get_public_rooms_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/federation/v1/send/{txnId}`
|
||||
///
|
||||
/// Push EDUs and PDUs to this server.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/federation/v1/send/<_>", data = "<body>")
|
||||
|
@ -921,7 +945,7 @@ type AsyncRecursiveType<'a, T> = Pin<Box<dyn Future<Output = T> + 'a + Send>>;
|
|||
/// 14. Use state resolution to find new room state
|
||||
// We use some AsyncRecursiveType hacks here so we can call this async funtion recursively
|
||||
#[tracing::instrument(skip(value, is_timeline_event, db, pub_key_map))]
|
||||
pub async fn handle_incoming_pdu<'a>(
|
||||
pub(crate) async fn handle_incoming_pdu<'a>(
|
||||
origin: &'a ServerName,
|
||||
event_id: &'a EventId,
|
||||
room_id: &'a RoomId,
|
||||
|
@ -1060,7 +1084,11 @@ pub async fn handle_incoming_pdu<'a>(
|
|||
})
|
||||
.map_err(|_| "Error sorting prev events".to_owned())?;
|
||||
|
||||
let mut errors = 0;
|
||||
for prev_id in dbg!(sorted) {
|
||||
if errors >= 5 {
|
||||
break;
|
||||
}
|
||||
if let Some((pdu, json)) = eventid_info.remove(&prev_id) {
|
||||
let start_time = Instant::now();
|
||||
let event_id = pdu.event_id.clone();
|
||||
|
@ -1075,6 +1103,7 @@ pub async fn handle_incoming_pdu<'a>(
|
|||
)
|
||||
.await
|
||||
{
|
||||
errors += 1;
|
||||
warn!("Prev event {} failed: {}", event_id, e);
|
||||
}
|
||||
let elapsed = start_time.elapsed();
|
||||
|
@ -1397,9 +1426,13 @@ async fn upgrade_outlier_to_timeline_pdu(
|
|||
let mut auth_chain_sets = Vec::new();
|
||||
for state in fork_states {
|
||||
auth_chain_sets.push(
|
||||
get_auth_chain(state.iter().map(|(_, id)| id.clone()).collect(), db)
|
||||
.map_err(|_| "Failed to load auth chain.".to_owned())?
|
||||
.collect(),
|
||||
get_auth_chain(
|
||||
&room_id,
|
||||
state.iter().map(|(_, id)| id.clone()).collect(),
|
||||
db,
|
||||
)
|
||||
.map_err(|_| "Failed to load auth chain.".to_owned())?
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1745,9 +1778,13 @@ async fn upgrade_outlier_to_timeline_pdu(
|
|||
let mut auth_chain_sets = Vec::new();
|
||||
for state in fork_states {
|
||||
auth_chain_sets.push(
|
||||
get_auth_chain(state.iter().map(|(_, id)| id.clone()).collect(), db)
|
||||
.map_err(|_| "Failed to load auth chain.".to_owned())?
|
||||
.collect(),
|
||||
get_auth_chain(
|
||||
&room_id,
|
||||
state.iter().map(|(_, id)| id.clone()).collect(),
|
||||
db,
|
||||
)
|
||||
.map_err(|_| "Failed to load auth chain.".to_owned())?
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2187,10 +2224,11 @@ fn append_incoming_pdu(
|
|||
}
|
||||
|
||||
#[tracing::instrument(skip(starting_events, db))]
|
||||
pub fn get_auth_chain(
|
||||
pub(crate) fn get_auth_chain<'a>(
|
||||
room_id: &RoomId,
|
||||
starting_events: Vec<Arc<EventId>>,
|
||||
db: &Database,
|
||||
) -> Result<impl Iterator<Item = Arc<EventId>> + '_> {
|
||||
db: &'a Database,
|
||||
) -> Result<impl Iterator<Item = Arc<EventId>> + 'a> {
|
||||
const NUM_BUCKETS: usize = 50;
|
||||
|
||||
let mut buckets = vec![BTreeSet::new(); NUM_BUCKETS];
|
||||
|
@ -2231,7 +2269,7 @@ pub fn get_auth_chain(
|
|||
chunk_cache.extend(cached.iter().cloned());
|
||||
} else {
|
||||
misses2 += 1;
|
||||
let auth_chain = Arc::new(get_auth_chain_inner(&event_id, db)?);
|
||||
let auth_chain = Arc::new(get_auth_chain_inner(&room_id, &event_id, db)?);
|
||||
db.rooms
|
||||
.cache_auth_chain(vec![sevent_id], Arc::clone(&auth_chain))?;
|
||||
println!(
|
||||
|
@ -2267,13 +2305,20 @@ pub fn get_auth_chain(
|
|||
}
|
||||
|
||||
#[tracing::instrument(skip(event_id, db))]
|
||||
fn get_auth_chain_inner(event_id: &EventId, db: &Database) -> Result<HashSet<u64>> {
|
||||
fn get_auth_chain_inner(
|
||||
room_id: &RoomId,
|
||||
event_id: &EventId,
|
||||
db: &Database,
|
||||
) -> Result<HashSet<u64>> {
|
||||
let mut todo = vec![event_id.clone()];
|
||||
let mut found = HashSet::new();
|
||||
|
||||
while let Some(event_id) = todo.pop() {
|
||||
match db.rooms.get_pdu(&event_id) {
|
||||
Ok(Some(pdu)) => {
|
||||
if &pdu.room_id != room_id {
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Evil event in db"));
|
||||
}
|
||||
for auth_event in &pdu.auth_events {
|
||||
let sauthevent = db
|
||||
.rooms
|
||||
|
@ -2297,6 +2342,11 @@ fn get_auth_chain_inner(event_id: &EventId, db: &Database) -> Result<HashSet<u64
|
|||
Ok(found)
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/federation/v1/event/{eventId}`
|
||||
///
|
||||
/// Retrieves a single event from the server.
|
||||
///
|
||||
/// - Only works if a user of this server is currently invited or joined the room
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/federation/v1/event/<_>", data = "<body>")
|
||||
|
@ -2310,18 +2360,39 @@ pub fn get_event_route(
|
|||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
let event = db
|
||||
.rooms
|
||||
.get_pdu_json(&body.event_id)?
|
||||
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?;
|
||||
|
||||
let room_id_str = event
|
||||
.get("room_id")
|
||||
.and_then(|val| val.as_str())
|
||||
.ok_or_else(|| Error::bad_database("Invalid event in database"))?;
|
||||
|
||||
let room_id = RoomId::try_from(room_id_str)
|
||||
.map_err(|_| Error::bad_database("Invalid room id field in event in database"))?;
|
||||
|
||||
if !db.rooms.server_in_room(sender_servername, &room_id)? {
|
||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Event not found."));
|
||||
}
|
||||
|
||||
Ok(get_event::v1::Response {
|
||||
origin: db.globals.server_name().to_owned(),
|
||||
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
|
||||
pdu: PduEvent::convert_to_outgoing_federation_event(
|
||||
db.rooms
|
||||
.get_pdu_json(&body.event_id)?
|
||||
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?,
|
||||
),
|
||||
pdu: PduEvent::convert_to_outgoing_federation_event(event),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/federation/v1/get_missing_events/{roomId}`
|
||||
///
|
||||
/// Retrieves events that the sender is missing.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/federation/v1/get_missing_events/<_>", data = "<body>")
|
||||
|
@ -2335,22 +2406,44 @@ pub fn get_missing_events_route(
|
|||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
if !db.rooms.server_in_room(sender_servername, &body.room_id)? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"Server is not in room",
|
||||
));
|
||||
}
|
||||
|
||||
let mut queued_events = body.latest_events.clone();
|
||||
let mut events = Vec::new();
|
||||
|
||||
let mut i = 0;
|
||||
while i < queued_events.len() && events.len() < u64::from(body.limit) as usize {
|
||||
if let Some(pdu) = db.rooms.get_pdu_json(&queued_events[i])? {
|
||||
let event_id =
|
||||
serde_json::from_value(
|
||||
serde_json::to_value(pdu.get("event_id").cloned().ok_or_else(|| {
|
||||
Error::bad_database("Event in db has no event_id field.")
|
||||
})?)
|
||||
.expect("canonical json is valid json value"),
|
||||
)
|
||||
.map_err(|_| Error::bad_database("Invalid event_id field in pdu in db."))?;
|
||||
let room_id_str = pdu
|
||||
.get("room_id")
|
||||
.and_then(|val| val.as_str())
|
||||
.ok_or_else(|| Error::bad_database("Invalid event in database"))?;
|
||||
|
||||
if body.earliest_events.contains(&event_id) {
|
||||
let event_room_id = RoomId::try_from(room_id_str)
|
||||
.map_err(|_| Error::bad_database("Invalid room id field in event in database"))?;
|
||||
|
||||
if event_room_id != body.room_id {
|
||||
warn!(
|
||||
"Evil event detected: Event {} found while searching in room {}",
|
||||
queued_events[i], body.room_id
|
||||
);
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Evil event detected",
|
||||
));
|
||||
}
|
||||
|
||||
if body.earliest_events.contains(&queued_events[i]) {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
@ -2371,6 +2464,11 @@ pub fn get_missing_events_route(
|
|||
Ok(get_missing_events::v1::Response { events }.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/federation/v1/event_auth/{roomId}/{eventId}`
|
||||
///
|
||||
/// Retrieves the auth chain for a given event.
|
||||
///
|
||||
/// - This does not include the event itself
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/federation/v1/event_auth/<_>/<_>", data = "<body>")
|
||||
|
@ -2384,7 +2482,29 @@ pub fn get_event_authorization_route(
|
|||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let auth_chain_ids = get_auth_chain(vec![Arc::new(body.event_id.clone())], &db)?;
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
let event = db
|
||||
.rooms
|
||||
.get_pdu_json(&body.event_id)?
|
||||
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?;
|
||||
|
||||
let room_id_str = event
|
||||
.get("room_id")
|
||||
.and_then(|val| val.as_str())
|
||||
.ok_or_else(|| Error::bad_database("Invalid event in database"))?;
|
||||
|
||||
let room_id = RoomId::try_from(room_id_str)
|
||||
.map_err(|_| Error::bad_database("Invalid room id field in event in database"))?;
|
||||
|
||||
if !db.rooms.server_in_room(sender_servername, &room_id)? {
|
||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Event not found."));
|
||||
}
|
||||
|
||||
let auth_chain_ids = get_auth_chain(&room_id, vec![Arc::new(body.event_id.clone())], &db)?;
|
||||
|
||||
Ok(get_event_authorization::v1::Response {
|
||||
auth_chain: auth_chain_ids
|
||||
|
@ -2395,6 +2515,9 @@ pub fn get_event_authorization_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/federation/v1/state/{roomId}`
|
||||
///
|
||||
/// Retrieves the current state of the room.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/federation/v1/state/<_>", data = "<body>")
|
||||
|
@ -2408,6 +2531,18 @@ pub fn get_room_state_route(
|
|||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
if !db.rooms.server_in_room(sender_servername, &body.room_id)? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"Server is not in room.",
|
||||
));
|
||||
}
|
||||
|
||||
let shortstatehash = db
|
||||
.rooms
|
||||
.pdu_shortstatehash(&body.event_id)?
|
||||
|
@ -2427,7 +2562,7 @@ pub fn get_room_state_route(
|
|||
})
|
||||
.collect();
|
||||
|
||||
let auth_chain_ids = get_auth_chain(vec![Arc::new(body.event_id.clone())], &db)?;
|
||||
let auth_chain_ids = get_auth_chain(&body.room_id, vec![Arc::new(body.event_id.clone())], &db)?;
|
||||
|
||||
Ok(get_room_state::v1::Response {
|
||||
auth_chain: auth_chain_ids
|
||||
|
@ -2443,6 +2578,9 @@ pub fn get_room_state_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/federation/v1/state_ids/{roomId}`
|
||||
///
|
||||
/// Retrieves the current state of the room.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/federation/v1/state_ids/<_>", data = "<body>")
|
||||
|
@ -2456,6 +2594,18 @@ pub fn get_room_state_ids_route(
|
|||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
.expect("server is authenticated");
|
||||
|
||||
if !db.rooms.server_in_room(sender_servername, &body.room_id)? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"Server is not in room.",
|
||||
));
|
||||
}
|
||||
|
||||
let shortstatehash = db
|
||||
.rooms
|
||||
.pdu_shortstatehash(&body.event_id)?
|
||||
|
@ -2471,7 +2621,7 @@ pub fn get_room_state_ids_route(
|
|||
.map(|(_, id)| (*id).clone())
|
||||
.collect();
|
||||
|
||||
let auth_chain_ids = get_auth_chain(vec![Arc::new(body.event_id.clone())], &db)?;
|
||||
let auth_chain_ids = get_auth_chain(&body.room_id, vec![Arc::new(body.event_id.clone())], &db)?;
|
||||
|
||||
Ok(get_room_state_ids::v1::Response {
|
||||
auth_chain_ids: auth_chain_ids.map(|id| (*id).clone()).collect(),
|
||||
|
@ -2480,6 +2630,9 @@ pub fn get_room_state_ids_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/federation/v1/make_join/{roomId}/{userId}`
|
||||
///
|
||||
/// Creates a join template.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/federation/v1/make_join/<_>/<_>", data = "<body>")
|
||||
|
@ -2719,7 +2872,11 @@ async fn create_join_event(
|
|||
drop(mutex_lock);
|
||||
|
||||
let state_ids = db.rooms.state_full_ids(shortstatehash)?;
|
||||
let auth_chain_ids = get_auth_chain(state_ids.iter().map(|(_, id)| id.clone()).collect(), &db)?;
|
||||
let auth_chain_ids = get_auth_chain(
|
||||
&room_id,
|
||||
state_ids.iter().map(|(_, id)| id.clone()).collect(),
|
||||
&db,
|
||||
)?;
|
||||
|
||||
for server in db
|
||||
.rooms
|
||||
|
@ -2745,6 +2902,9 @@ async fn create_join_event(
|
|||
})
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/federation/v1/send_join/{roomId}/{eventId}`
|
||||
///
|
||||
/// Submits a signed join event.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/federation/v1/send_join/<_>/<_>", data = "<body>")
|
||||
|
@ -2759,6 +2919,9 @@ pub async fn create_join_event_v1_route(
|
|||
Ok(create_join_event::v1::Response { room_state }.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/federation/v2/send_join/{roomId}/{eventId}`
|
||||
///
|
||||
/// Submits a signed join event.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/federation/v2/send_join/<_>/<_>", data = "<body>")
|
||||
|
@ -2773,6 +2936,9 @@ pub async fn create_join_event_v2_route(
|
|||
Ok(create_join_event::v2::Response { room_state }.into())
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`
|
||||
///
|
||||
/// Invites a remote user to a room.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
put("/_matrix/federation/v2/invite/<_>/<_>", data = "<body>")
|
||||
|
@ -2882,6 +3048,9 @@ pub async fn create_invite_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/federation/v1/user/devices/{userId}`
|
||||
///
|
||||
/// Gets information on all devices of the user.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/federation/v1/user/devices/<_>", data = "<body>")
|
||||
|
@ -2922,6 +3091,9 @@ pub fn get_devices_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/federation/v1/query/directory`
|
||||
///
|
||||
/// Resolve a room alias to a room id.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/federation/v1/query/directory", data = "<body>")
|
||||
|
@ -2950,6 +3122,9 @@ pub fn get_room_information_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/federation/v1/query/profile`
|
||||
///
|
||||
/// Gets information on a profile.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
get("/_matrix/federation/v1/query/profile", data = "<body>")
|
||||
|
@ -2990,6 +3165,9 @@ pub fn get_profile_information_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/federation/v1/user/keys/query`
|
||||
///
|
||||
/// Gets devices and identity keys for the given users.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/federation/v1/user/keys/query", data = "<body>")
|
||||
|
@ -3021,6 +3199,9 @@ pub async fn get_keys_route(
|
|||
.into())
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/federation/v1/user/keys/claim`
|
||||
///
|
||||
/// Claims one-time keys.
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/federation/v1/user/keys/claim", data = "<body>")
|
||||
|
@ -3045,7 +3226,7 @@ pub async fn claim_keys_route(
|
|||
}
|
||||
|
||||
#[tracing::instrument(skip(event, pub_key_map, db))]
|
||||
pub async fn fetch_required_signing_keys(
|
||||
pub(crate) async fn fetch_required_signing_keys(
|
||||
event: &BTreeMap<String, CanonicalJsonValue>,
|
||||
pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, String>>>,
|
||||
db: &Database,
|
||||
|
|
Loading…
Reference in a new issue