mirror of
https://gitlab.com/famedly/conduit.git
synced 2025-07-22 17:18:35 +00:00
Merge branch 'all-the-lints' into 'next'
refactor: all the clippy lints See merge request famedly/conduit!671
This commit is contained in:
commit
962c2097c4
72 changed files with 1091 additions and 1152 deletions
|
@ -17,11 +17,8 @@ pub(crate) async fn send_request<T>(
|
|||
where
|
||||
T: OutgoingRequest + Debug,
|
||||
{
|
||||
let destination = match registration.url {
|
||||
Some(url) => url,
|
||||
None => {
|
||||
return Ok(None);
|
||||
}
|
||||
let Some(destination) = registration.url else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let hs_token = registration.hs_token.as_str();
|
||||
|
@ -33,7 +30,7 @@ where
|
|||
&[MatrixVersion::V1_0],
|
||||
)
|
||||
.unwrap()
|
||||
.map(|body| body.freeze());
|
||||
.map(BytesMut::freeze);
|
||||
|
||||
let mut parts = http_request.uri().clone().into_parts();
|
||||
let old_path_and_query = parts.path_and_query.unwrap().as_str().to_owned();
|
||||
|
|
|
@ -69,11 +69,11 @@ pub async fn get_register_available_route(
|
|||
/// 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 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
|
||||
/// - If `inhibit_login` is false: Creates a device and returns device id and `access_token`
|
||||
pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<register::v3::Response> {
|
||||
if !services().globals.allow_registration() && body.appservice_info.is_none() {
|
||||
return Err(Error::BadRequest(
|
||||
|
@ -149,7 +149,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
|||
stages: vec![AuthType::RegistrationToken],
|
||||
}],
|
||||
completed: Vec::new(),
|
||||
params: Default::default(),
|
||||
params: Box::default(),
|
||||
session: None,
|
||||
auth_error: None,
|
||||
};
|
||||
|
@ -161,7 +161,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
|||
stages: vec![AuthType::Dummy],
|
||||
}],
|
||||
completed: Vec::new(),
|
||||
params: Default::default(),
|
||||
params: Box::default(),
|
||||
session: None,
|
||||
auth_error: None,
|
||||
};
|
||||
|
@ -307,7 +307,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
|||
/// - 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:
|
||||
/// 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
|
||||
|
@ -323,7 +323,7 @@ pub async fn change_password_route(
|
|||
stages: vec![AuthType::Password],
|
||||
}],
|
||||
completed: Vec::new(),
|
||||
params: Default::default(),
|
||||
params: Box::default(),
|
||||
session: None,
|
||||
auth_error: None,
|
||||
};
|
||||
|
@ -375,12 +375,12 @@ pub async fn change_password_route(
|
|||
|
||||
/// # `GET _matrix/client/r0/account/whoami`
|
||||
///
|
||||
/// Get user_id of the sender user.
|
||||
/// Get `user_id` of the sender user.
|
||||
///
|
||||
/// Note: Also works for Application Services
|
||||
pub async fn whoami_route(body: Ruma<whoami::v3::Request>) -> Result<whoami::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
let device_id = body.sender_device.as_ref().cloned();
|
||||
let device_id = body.sender_device.clone();
|
||||
|
||||
Ok(whoami::v3::Response {
|
||||
user_id: sender_user.clone(),
|
||||
|
@ -410,7 +410,7 @@ pub async fn deactivate_route(
|
|||
stages: vec![AuthType::Password],
|
||||
}],
|
||||
completed: Vec::new(),
|
||||
params: Default::default(),
|
||||
params: Box::default(),
|
||||
session: None,
|
||||
auth_error: None,
|
||||
};
|
||||
|
|
|
@ -121,7 +121,7 @@ pub(crate) async fn get_alias_helper(
|
|||
.send_federation_request(
|
||||
room_alias.server_name(),
|
||||
federation::query::get_room_information::v1::Request {
|
||||
room_alias: room_alias.to_owned(),
|
||||
room_alias: room_alias.clone(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
@ -166,14 +166,11 @@ pub(crate) async fn get_alias_helper(
|
|||
}
|
||||
};
|
||||
|
||||
let room_id = match room_id {
|
||||
Some(room_id) => room_id,
|
||||
None => {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::NotFound,
|
||||
"Room with alias not found.",
|
||||
))
|
||||
}
|
||||
let Some(room_id) = room_id else {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::NotFound,
|
||||
"Room with alias not found.",
|
||||
));
|
||||
};
|
||||
|
||||
Ok(get_alias::v3::Response::new(
|
||||
|
|
|
@ -86,7 +86,7 @@ pub async fn get_backup_info_route(
|
|||
etag: services()
|
||||
.key_backups
|
||||
.get_etag(sender_user, &body.version)?,
|
||||
version: body.version.to_owned(),
|
||||
version: body.version.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ pub async fn add_backup_keys_route(
|
|||
room_id,
|
||||
session_id,
|
||||
key_data,
|
||||
)?
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ pub async fn add_backup_keys_for_room_route(
|
|||
&body.room_id,
|
||||
session_id,
|
||||
key_data,
|
||||
)?
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(add_backup_keys_for_room::v3::Response {
|
||||
|
|
|
@ -11,7 +11,7 @@ use tracing::error;
|
|||
/// 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)
|
||||
/// joined, depending on `history_visibility`)
|
||||
pub async fn get_context_route(
|
||||
body: Ruma<get_context::v3::Request>,
|
||||
) -> Result<get_context::v3::Response> {
|
||||
|
@ -22,7 +22,7 @@ pub async fn get_context_route(
|
|||
LazyLoadOptions::Enabled {
|
||||
include_redundant_members,
|
||||
} => (true, *include_redundant_members),
|
||||
_ => (false, false),
|
||||
LazyLoadOptions::Disabled => (false, false),
|
||||
};
|
||||
|
||||
let mut lazy_loaded = HashSet::new();
|
||||
|
@ -103,8 +103,7 @@ pub async fn get_context_route(
|
|||
|
||||
let start_token = events_before
|
||||
.last()
|
||||
.map(|(count, _)| count.stringify())
|
||||
.unwrap_or_else(|| base_token.stringify());
|
||||
.map_or_else(|| base_token.stringify(), |(count, _)| count.stringify());
|
||||
|
||||
let events_before: Vec<_> = events_before
|
||||
.into_iter()
|
||||
|
@ -159,8 +158,7 @@ pub async fn get_context_route(
|
|||
|
||||
let end_token = events_after
|
||||
.last()
|
||||
.map(|(count, _)| count.stringify())
|
||||
.unwrap_or_else(|| base_token.stringify());
|
||||
.map_or_else(|| base_token.stringify(), |(count, _)| count.stringify());
|
||||
|
||||
let events_after: Vec<_> = events_after
|
||||
.into_iter()
|
||||
|
@ -176,21 +174,15 @@ pub async fn get_context_route(
|
|||
.get_statekey_from_short(shortstatekey)?;
|
||||
|
||||
if event_type != StateEventType::RoomMember {
|
||||
let pdu = match services().rooms.timeline.get_pdu(&id)? {
|
||||
Some(pdu) => pdu,
|
||||
None => {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
}
|
||||
let Some(pdu) = services().rooms.timeline.get_pdu(&id)? else {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
};
|
||||
state.push(pdu.to_state_event());
|
||||
} else if !lazy_load_enabled || lazy_loaded.contains(&state_key) {
|
||||
let pdu = match services().rooms.timeline.get_pdu(&id)? {
|
||||
Some(pdu) => pdu,
|
||||
None => {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
}
|
||||
let Some(pdu) = services().rooms.timeline.get_pdu(&id)? else {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
};
|
||||
state.push(pdu.to_state_event());
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ pub async fn delete_device_route(
|
|||
stages: vec![AuthType::Password],
|
||||
}],
|
||||
completed: Vec::new(),
|
||||
params: Default::default(),
|
||||
params: Box::default(),
|
||||
session: None,
|
||||
auth_error: None,
|
||||
};
|
||||
|
@ -137,7 +137,7 @@ pub async fn delete_devices_route(
|
|||
stages: vec![AuthType::Password],
|
||||
}],
|
||||
completed: Vec::new(),
|
||||
params: Default::default(),
|
||||
params: Box::default(),
|
||||
session: None,
|
||||
auth_error: None,
|
||||
};
|
||||
|
@ -162,7 +162,7 @@ pub async fn delete_devices_route(
|
|||
}
|
||||
|
||||
for device_id in &body.devices {
|
||||
services().users.remove_device(sender_user, device_id)?
|
||||
services().users.remove_device(sender_user, device_id)?;
|
||||
}
|
||||
|
||||
Ok(delete_devices::v3::Response {})
|
||||
|
|
|
@ -13,9 +13,8 @@ pub async fn get_filter_route(
|
|||
body: Ruma<get_filter::v3::Request>,
|
||||
) -> Result<get_filter::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
let filter = match services().users.get_filter(sender_user, &body.filter_id)? {
|
||||
Some(filter) => filter,
|
||||
None => return Err(Error::BadRequest(ErrorKind::NotFound, "Filter not found.")),
|
||||
let Some(filter) = services().users.get_filter(sender_user, &body.filter_id)? else {
|
||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Filter not found."));
|
||||
};
|
||||
|
||||
Ok(get_filter::v3::Response::new(filter))
|
||||
|
|
|
@ -106,7 +106,7 @@ pub async fn upload_signing_keys_route(
|
|||
stages: vec![AuthType::Password],
|
||||
}],
|
||||
completed: Vec::new(),
|
||||
params: Default::default(),
|
||||
params: Box::default(),
|
||||
session: None,
|
||||
auth_error: None,
|
||||
};
|
||||
|
@ -173,7 +173,6 @@ pub async fn upload_signatures_route(
|
|||
"Invalid signature.",
|
||||
))?
|
||||
.clone()
|
||||
.into_iter()
|
||||
{
|
||||
// Signature validation?
|
||||
let signature = (
|
||||
|
@ -401,48 +400,45 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
.collect();
|
||||
|
||||
while let Some((server, response)) = futures.next().await {
|
||||
match response {
|
||||
Ok(Ok(response)) => {
|
||||
for (user, masterkey) in response.master_keys {
|
||||
let (master_key_id, mut master_key) =
|
||||
services().users.parse_master_key(&user, &masterkey)?;
|
||||
if let Ok(Ok(response)) = response {
|
||||
for (user, masterkey) in response.master_keys {
|
||||
let (master_key_id, mut master_key) =
|
||||
services().users.parse_master_key(&user, &masterkey)?;
|
||||
|
||||
if let Some(our_master_key) = services().users.get_key(
|
||||
&master_key_id,
|
||||
sender_user,
|
||||
&user,
|
||||
&allowed_signatures,
|
||||
)? {
|
||||
let (_, our_master_key) =
|
||||
services().users.parse_master_key(&user, &our_master_key)?;
|
||||
master_key.signatures.extend(our_master_key.signatures);
|
||||
}
|
||||
let json = serde_json::to_value(master_key).expect("to_value always works");
|
||||
let raw = serde_json::from_value(json).expect("Raw::from_value always works");
|
||||
services().users.add_cross_signing_keys(
|
||||
&user, &raw, &None, &None,
|
||||
false, // Dont notify. A notification would trigger another key request resulting in an endless loop
|
||||
)?;
|
||||
master_keys.insert(user, raw);
|
||||
if let Some(our_master_key) = services().users.get_key(
|
||||
&master_key_id,
|
||||
sender_user,
|
||||
&user,
|
||||
&allowed_signatures,
|
||||
)? {
|
||||
let (_, our_master_key) =
|
||||
services().users.parse_master_key(&user, &our_master_key)?;
|
||||
master_key.signatures.extend(our_master_key.signatures);
|
||||
}
|
||||
|
||||
self_signing_keys.extend(response.self_signing_keys);
|
||||
device_keys.extend(response.device_keys);
|
||||
let json = serde_json::to_value(master_key).expect("to_value always works");
|
||||
let raw = serde_json::from_value(json).expect("Raw::from_value always works");
|
||||
services().users.add_cross_signing_keys(
|
||||
&user, &raw, &None, &None,
|
||||
false, // Dont notify. A notification would trigger another key request resulting in an endless loop
|
||||
)?;
|
||||
master_keys.insert(user, raw);
|
||||
}
|
||||
_ => {
|
||||
back_off(server.to_owned()).await;
|
||||
|
||||
failures.insert(server.to_string(), json!({}));
|
||||
}
|
||||
self_signing_keys.extend(response.self_signing_keys);
|
||||
device_keys.extend(response.device_keys);
|
||||
} else {
|
||||
back_off(server.to_owned()).await;
|
||||
|
||||
failures.insert(server.to_string(), json!({}));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(get_keys::v3::Response {
|
||||
failures,
|
||||
device_keys,
|
||||
master_keys,
|
||||
self_signing_keys,
|
||||
user_signing_keys,
|
||||
device_keys,
|
||||
failures,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ pub async fn join_room_by_id_route(
|
|||
.iter()
|
||||
.filter_map(|event| serde_json::from_str(event.json().get()).ok())
|
||||
.filter_map(|event: serde_json::Value| event.get("sender").cloned())
|
||||
.filter_map(|sender| sender.as_str().map(|s| s.to_owned()))
|
||||
.filter_map(|sender| sender.as_str().map(ToOwned::to_owned))
|
||||
.filter_map(|sender| UserId::parse(sender).ok())
|
||||
.map(|user| user.server_name().to_owned()),
|
||||
);
|
||||
|
@ -105,7 +105,7 @@ pub async fn join_room_by_id_or_alias_route(
|
|||
.iter()
|
||||
.filter_map(|event| serde_json::from_str(event.json().get()).ok())
|
||||
.filter_map(|event: serde_json::Value| event.get("sender").cloned())
|
||||
.filter_map(|sender| sender.as_str().map(|s| s.to_owned()))
|
||||
.filter_map(|sender| sender.as_str().map(ToOwned::to_owned))
|
||||
.filter_map(|sender| UserId::parse(sender).ok())
|
||||
.map(|user| user.server_name().to_owned()),
|
||||
);
|
||||
|
@ -540,313 +540,11 @@ async fn join_room_by_id_helper(
|
|||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
// Ask a remote server if we are not participating in this room
|
||||
if !services()
|
||||
if services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(services().globals.server_name(), room_id)?
|
||||
{
|
||||
info!("Joining {room_id} over federation.");
|
||||
|
||||
let (make_join_response, remote_server) =
|
||||
make_join_request(sender_user, room_id, servers).await?;
|
||||
|
||||
info!("make_join finished");
|
||||
|
||||
let room_version_id = match make_join_response.room_version {
|
||||
Some(room_version)
|
||||
if services()
|
||||
.globals
|
||||
.supported_room_versions()
|
||||
.contains(&room_version) =>
|
||||
{
|
||||
room_version
|
||||
}
|
||||
_ => return Err(Error::BadServerResponse("Room version is not supported")),
|
||||
};
|
||||
|
||||
let mut join_event_stub: CanonicalJsonObject =
|
||||
serde_json::from_str(make_join_response.event.get()).map_err(|_| {
|
||||
Error::BadServerResponse("Invalid make_join event json received from server.")
|
||||
})?;
|
||||
|
||||
let join_authorized_via_users_server = join_event_stub
|
||||
.get("content")
|
||||
.map(|s| {
|
||||
s.as_object()?
|
||||
.get("join_authorised_via_users_server")?
|
||||
.as_str()
|
||||
})
|
||||
.and_then(|s| OwnedUserId::try_from(s.unwrap_or_default()).ok());
|
||||
|
||||
// TODO: Is origin needed?
|
||||
join_event_stub.insert(
|
||||
"origin".to_owned(),
|
||||
CanonicalJsonValue::String(services().globals.server_name().as_str().to_owned()),
|
||||
);
|
||||
join_event_stub.insert(
|
||||
"origin_server_ts".to_owned(),
|
||||
CanonicalJsonValue::Integer(
|
||||
utils::millis_since_unix_epoch()
|
||||
.try_into()
|
||||
.expect("Timestamp is valid js_int value"),
|
||||
),
|
||||
);
|
||||
join_event_stub.insert(
|
||||
"content".to_owned(),
|
||||
to_canonical_value(RoomMemberEventContent {
|
||||
membership: MembershipState::Join,
|
||||
displayname: services().users.displayname(sender_user)?,
|
||||
avatar_url: services().users.avatar_url(sender_user)?,
|
||||
is_direct: None,
|
||||
third_party_invite: None,
|
||||
blurhash: services().users.blurhash(sender_user)?,
|
||||
reason,
|
||||
join_authorized_via_users_server,
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
);
|
||||
|
||||
// We don't leave the event id in the pdu because that's only allowed in v1 or v2 rooms
|
||||
join_event_stub.remove("event_id");
|
||||
|
||||
// In order to create a compatible ref hash (EventID) the `hashes` field needs to be present
|
||||
ruma::signatures::hash_and_sign_event(
|
||||
services().globals.server_name().as_str(),
|
||||
services().globals.keypair(),
|
||||
&mut join_event_stub,
|
||||
&room_version_id,
|
||||
)
|
||||
.expect("event is valid, we just created it");
|
||||
|
||||
// Generate event id
|
||||
let event_id = format!(
|
||||
"${}",
|
||||
ruma::signatures::reference_hash(&join_event_stub, &room_version_id)
|
||||
.expect("ruma can calculate reference hashes")
|
||||
);
|
||||
let event_id = <&EventId>::try_from(event_id.as_str())
|
||||
.expect("ruma's reference hashes are valid event ids");
|
||||
|
||||
// Add event_id back
|
||||
join_event_stub.insert(
|
||||
"event_id".to_owned(),
|
||||
CanonicalJsonValue::String(event_id.as_str().to_owned()),
|
||||
);
|
||||
|
||||
// It has enough fields to be called a proper event now
|
||||
let mut join_event = join_event_stub;
|
||||
|
||||
info!("Asking {remote_server} for send_join");
|
||||
let send_join_response = services()
|
||||
.sending
|
||||
.send_federation_request(
|
||||
&remote_server,
|
||||
federation::membership::create_join_event::v2::Request {
|
||||
room_id: room_id.to_owned(),
|
||||
event_id: event_id.to_owned(),
|
||||
pdu: PduEvent::convert_to_outgoing_federation_event(join_event.clone()),
|
||||
omit_members: false,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
info!("send_join finished");
|
||||
|
||||
if let Some(signed_raw) = &send_join_response.room_state.event {
|
||||
info!("There is a signed event. This room is probably using restricted joins. Adding signature to our event");
|
||||
let (signed_event_id, signed_value) =
|
||||
match gen_event_id_canonical_json(signed_raw, &room_version_id) {
|
||||
Ok(t) => t,
|
||||
Err(_) => {
|
||||
// Event could not be converted to canonical json
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Could not convert event to canonical json.",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
if signed_event_id != event_id {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Server sent event with wrong event id",
|
||||
));
|
||||
}
|
||||
|
||||
match signed_value["signatures"]
|
||||
.as_object()
|
||||
.ok_or(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Server sent invalid signatures type",
|
||||
))
|
||||
.and_then(|e| {
|
||||
e.get(remote_server.as_str()).ok_or(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Server did not send its signature",
|
||||
))
|
||||
}) {
|
||||
Ok(signature) => {
|
||||
join_event
|
||||
.get_mut("signatures")
|
||||
.expect("we created a valid pdu")
|
||||
.as_object_mut()
|
||||
.expect("we created a valid pdu")
|
||||
.insert(remote_server.to_string(), signature.clone());
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Server {remote_server} sent invalid signature in sendjoin signatures for event {signed_value:?}: {e:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
services().rooms.short.get_or_create_shortroomid(room_id)?;
|
||||
|
||||
info!("Parsing join event");
|
||||
let parsed_join_pdu = PduEvent::from_id_val(event_id, join_event.clone())
|
||||
.map_err(|_| Error::BadServerResponse("Invalid join event PDU."))?;
|
||||
|
||||
let mut state = HashMap::new();
|
||||
let pub_key_map = RwLock::new(BTreeMap::new());
|
||||
|
||||
info!("Fetching join signing keys");
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.fetch_join_signing_keys(&send_join_response, &room_version_id, &pub_key_map)
|
||||
.await?;
|
||||
|
||||
info!("Going through send_join response room_state");
|
||||
for result in send_join_response
|
||||
.room_state
|
||||
.state
|
||||
.iter()
|
||||
.map(|pdu| validate_and_add_event_id(pdu, &room_version_id, &pub_key_map))
|
||||
{
|
||||
let (event_id, value) = match result.await {
|
||||
Ok(t) => t,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let pdu = PduEvent::from_id_val(&event_id, value.clone()).map_err(|e| {
|
||||
warn!("Invalid PDU in send_join response: {} {:?}", e, value);
|
||||
Error::BadServerResponse("Invalid PDU in send_join response.")
|
||||
})?;
|
||||
|
||||
services()
|
||||
.rooms
|
||||
.outlier
|
||||
.add_pdu_outlier(&event_id, &value)?;
|
||||
if let Some(state_key) = &pdu.state_key {
|
||||
let shortstatekey = services()
|
||||
.rooms
|
||||
.short
|
||||
.get_or_create_shortstatekey(&pdu.kind.to_string().into(), state_key)?;
|
||||
state.insert(shortstatekey, pdu.event_id.clone());
|
||||
}
|
||||
}
|
||||
|
||||
info!("Going through send_join response auth_chain");
|
||||
for result in send_join_response
|
||||
.room_state
|
||||
.auth_chain
|
||||
.iter()
|
||||
.map(|pdu| validate_and_add_event_id(pdu, &room_version_id, &pub_key_map))
|
||||
{
|
||||
let (event_id, value) = match result.await {
|
||||
Ok(t) => t,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
services()
|
||||
.rooms
|
||||
.outlier
|
||||
.add_pdu_outlier(&event_id, &value)?;
|
||||
}
|
||||
|
||||
info!("Running send_join auth check");
|
||||
let authenticated = state_res::event_auth::auth_check(
|
||||
&state_res::RoomVersion::new(&room_version_id).expect("room version is supported"),
|
||||
&parsed_join_pdu,
|
||||
None::<PduEvent>, // TODO: third party invite
|
||||
|k, s| {
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.get_pdu(
|
||||
state.get(
|
||||
&services()
|
||||
.rooms
|
||||
.short
|
||||
.get_or_create_shortstatekey(&k.to_string().into(), s)
|
||||
.ok()?,
|
||||
)?,
|
||||
)
|
||||
.ok()?
|
||||
},
|
||||
)
|
||||
.map_err(|e| {
|
||||
warn!("Auth check failed: {e}");
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "Auth check failed")
|
||||
})?;
|
||||
|
||||
if !authenticated {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Auth check failed",
|
||||
));
|
||||
}
|
||||
|
||||
info!("Saving state from send_join");
|
||||
let (statehash_before_join, new, removed) = services().rooms.state_compressor.save_state(
|
||||
room_id,
|
||||
Arc::new(
|
||||
state
|
||||
.into_iter()
|
||||
.map(|(k, id)| {
|
||||
services()
|
||||
.rooms
|
||||
.state_compressor
|
||||
.compress_state_event(k, &id)
|
||||
})
|
||||
.collect::<Result<_>>()?,
|
||||
),
|
||||
)?;
|
||||
|
||||
services()
|
||||
.rooms
|
||||
.state
|
||||
.force_state(room_id, statehash_before_join, new, removed, &state_lock)
|
||||
.await?;
|
||||
|
||||
info!("Updating joined counts for new room");
|
||||
services().rooms.state_cache.update_joined_count(room_id)?;
|
||||
|
||||
// We append to state before appending the pdu, so we don't have a moment in time with the
|
||||
// pdu without it's state. This is okay because append_pdu can't fail.
|
||||
let statehash_after_join = services().rooms.state.append_to_state(&parsed_join_pdu)?;
|
||||
|
||||
info!("Appending new room join event");
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.append_pdu(
|
||||
&parsed_join_pdu,
|
||||
join_event,
|
||||
vec![(*parsed_join_pdu.event_id).to_owned()],
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
info!("Setting final room state for new room");
|
||||
// We set the room state after inserting the pdu, so that we never have a moment in time
|
||||
// where events in the current room state do not exist
|
||||
services()
|
||||
.rooms
|
||||
.state
|
||||
.set_room_state(room_id, statehash_after_join, &state_lock)?;
|
||||
} else {
|
||||
info!("We can join locally");
|
||||
|
||||
let join_rules_event = services().rooms.state_accessor.room_state_get(
|
||||
|
@ -867,10 +565,7 @@ async fn join_room_by_id_helper(
|
|||
|
||||
let restriction_rooms = match join_rules_event_content {
|
||||
Some(RoomJoinRulesEventContent {
|
||||
join_rule: JoinRule::Restricted(restricted),
|
||||
})
|
||||
| Some(RoomJoinRulesEventContent {
|
||||
join_rule: JoinRule::KnockRestricted(restricted),
|
||||
join_rule: JoinRule::Restricted(restricted) | JoinRule::KnockRestricted(restricted),
|
||||
}) => restricted
|
||||
.allow
|
||||
.into_iter()
|
||||
|
@ -898,12 +593,12 @@ async fn join_room_by_id_helper(
|
|||
.collect::<Vec<_>>()
|
||||
{
|
||||
if user.server_name() == services().globals.server_name()
|
||||
&& services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_invite(room_id, &user, sender_user, &state_lock)
|
||||
.await
|
||||
.unwrap_or(false)
|
||||
&& services().rooms.state_accessor.user_can_invite(
|
||||
room_id,
|
||||
&user,
|
||||
sender_user,
|
||||
&state_lock,
|
||||
)
|
||||
{
|
||||
auth_user = Some(user);
|
||||
break;
|
||||
|
@ -1053,17 +748,15 @@ async fn join_room_by_id_helper(
|
|||
.await?;
|
||||
|
||||
if let Some(signed_raw) = send_join_response.room_state.event {
|
||||
let (signed_event_id, signed_value) =
|
||||
match gen_event_id_canonical_json(&signed_raw, &room_version_id) {
|
||||
Ok(t) => t,
|
||||
Err(_) => {
|
||||
// Event could not be converted to canonical json
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Could not convert event to canonical json.",
|
||||
));
|
||||
}
|
||||
};
|
||||
let Ok((signed_event_id, signed_value)) =
|
||||
gen_event_id_canonical_json(&signed_raw, &room_version_id)
|
||||
else {
|
||||
// Event could not be converted to canonical json
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Could not convert event to canonical json.",
|
||||
));
|
||||
};
|
||||
|
||||
if signed_event_id != event_id {
|
||||
return Err(Error::BadRequest(
|
||||
|
@ -1092,6 +785,304 @@ async fn join_room_by_id_helper(
|
|||
} else {
|
||||
return Err(error);
|
||||
}
|
||||
} else {
|
||||
info!("Joining {room_id} over federation.");
|
||||
|
||||
let (make_join_response, remote_server) =
|
||||
make_join_request(sender_user, room_id, servers).await?;
|
||||
|
||||
info!("make_join finished");
|
||||
|
||||
let room_version_id = match make_join_response.room_version {
|
||||
Some(room_version)
|
||||
if services()
|
||||
.globals
|
||||
.supported_room_versions()
|
||||
.contains(&room_version) =>
|
||||
{
|
||||
room_version
|
||||
}
|
||||
_ => return Err(Error::BadServerResponse("Room version is not supported")),
|
||||
};
|
||||
|
||||
let mut join_event_stub: CanonicalJsonObject =
|
||||
serde_json::from_str(make_join_response.event.get()).map_err(|_| {
|
||||
Error::BadServerResponse("Invalid make_join event json received from server.")
|
||||
})?;
|
||||
|
||||
let join_authorized_via_users_server = join_event_stub
|
||||
.get("content")
|
||||
.map(|s| {
|
||||
s.as_object()?
|
||||
.get("join_authorised_via_users_server")?
|
||||
.as_str()
|
||||
})
|
||||
.and_then(|s| OwnedUserId::try_from(s.unwrap_or_default()).ok());
|
||||
|
||||
// TODO: Is origin needed?
|
||||
join_event_stub.insert(
|
||||
"origin".to_owned(),
|
||||
CanonicalJsonValue::String(services().globals.server_name().as_str().to_owned()),
|
||||
);
|
||||
join_event_stub.insert(
|
||||
"origin_server_ts".to_owned(),
|
||||
CanonicalJsonValue::Integer(
|
||||
utils::millis_since_unix_epoch()
|
||||
.try_into()
|
||||
.expect("Timestamp is valid js_int value"),
|
||||
),
|
||||
);
|
||||
join_event_stub.insert(
|
||||
"content".to_owned(),
|
||||
to_canonical_value(RoomMemberEventContent {
|
||||
membership: MembershipState::Join,
|
||||
displayname: services().users.displayname(sender_user)?,
|
||||
avatar_url: services().users.avatar_url(sender_user)?,
|
||||
is_direct: None,
|
||||
third_party_invite: None,
|
||||
blurhash: services().users.blurhash(sender_user)?,
|
||||
reason,
|
||||
join_authorized_via_users_server,
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
);
|
||||
|
||||
// We don't leave the event id in the pdu because that's only allowed in v1 or v2 rooms
|
||||
join_event_stub.remove("event_id");
|
||||
|
||||
// In order to create a compatible ref hash (EventID) the `hashes` field needs to be present
|
||||
ruma::signatures::hash_and_sign_event(
|
||||
services().globals.server_name().as_str(),
|
||||
services().globals.keypair(),
|
||||
&mut join_event_stub,
|
||||
&room_version_id,
|
||||
)
|
||||
.expect("event is valid, we just created it");
|
||||
|
||||
// Generate event id
|
||||
let event_id = format!(
|
||||
"${}",
|
||||
ruma::signatures::reference_hash(&join_event_stub, &room_version_id)
|
||||
.expect("ruma can calculate reference hashes")
|
||||
);
|
||||
let event_id = <&EventId>::try_from(event_id.as_str())
|
||||
.expect("ruma's reference hashes are valid event ids");
|
||||
|
||||
// Add event_id back
|
||||
join_event_stub.insert(
|
||||
"event_id".to_owned(),
|
||||
CanonicalJsonValue::String(event_id.as_str().to_owned()),
|
||||
);
|
||||
|
||||
// It has enough fields to be called a proper event now
|
||||
let mut join_event = join_event_stub;
|
||||
|
||||
info!("Asking {remote_server} for send_join");
|
||||
let send_join_response = services()
|
||||
.sending
|
||||
.send_federation_request(
|
||||
&remote_server,
|
||||
federation::membership::create_join_event::v2::Request {
|
||||
room_id: room_id.to_owned(),
|
||||
event_id: event_id.to_owned(),
|
||||
pdu: PduEvent::convert_to_outgoing_federation_event(join_event.clone()),
|
||||
omit_members: false,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
info!("send_join finished");
|
||||
|
||||
if let Some(signed_raw) = &send_join_response.room_state.event {
|
||||
info!("There is a signed event. This room is probably using restricted joins. Adding signature to our event");
|
||||
let Ok((signed_event_id, signed_value)) =
|
||||
gen_event_id_canonical_json(signed_raw, &room_version_id)
|
||||
else {
|
||||
// Event could not be converted to canonical json
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Could not convert event to canonical json.",
|
||||
));
|
||||
};
|
||||
|
||||
if signed_event_id != event_id {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Server sent event with wrong event id",
|
||||
));
|
||||
}
|
||||
|
||||
match signed_value["signatures"]
|
||||
.as_object()
|
||||
.ok_or(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Server sent invalid signatures type",
|
||||
))
|
||||
.and_then(|e| {
|
||||
e.get(remote_server.as_str()).ok_or(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Server did not send its signature",
|
||||
))
|
||||
}) {
|
||||
Ok(signature) => {
|
||||
join_event
|
||||
.get_mut("signatures")
|
||||
.expect("we created a valid pdu")
|
||||
.as_object_mut()
|
||||
.expect("we created a valid pdu")
|
||||
.insert(remote_server.to_string(), signature.clone());
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Server {remote_server} sent invalid signature in sendjoin signatures for event {signed_value:?}: {e:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
services().rooms.short.get_or_create_shortroomid(room_id)?;
|
||||
|
||||
info!("Parsing join event");
|
||||
let parsed_join_pdu = PduEvent::from_id_val(event_id, join_event.clone())
|
||||
.map_err(|_| Error::BadServerResponse("Invalid join event PDU."))?;
|
||||
|
||||
let mut state = HashMap::new();
|
||||
let pub_key_map = RwLock::new(BTreeMap::new());
|
||||
|
||||
info!("Fetching join signing keys");
|
||||
services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.fetch_join_signing_keys(&send_join_response, &room_version_id, &pub_key_map)
|
||||
.await?;
|
||||
|
||||
info!("Going through send_join response room_state");
|
||||
for result in send_join_response
|
||||
.room_state
|
||||
.state
|
||||
.iter()
|
||||
.map(|pdu| validate_and_add_event_id(pdu, &room_version_id, &pub_key_map))
|
||||
{
|
||||
let Ok((event_id, value)) = result.await else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let pdu = PduEvent::from_id_val(&event_id, value.clone()).map_err(|e| {
|
||||
warn!("Invalid PDU in send_join response: {} {:?}", e, value);
|
||||
Error::BadServerResponse("Invalid PDU in send_join response.")
|
||||
})?;
|
||||
|
||||
services()
|
||||
.rooms
|
||||
.outlier
|
||||
.add_pdu_outlier(&event_id, &value)?;
|
||||
if let Some(state_key) = &pdu.state_key {
|
||||
let shortstatekey = services()
|
||||
.rooms
|
||||
.short
|
||||
.get_or_create_shortstatekey(&pdu.kind.to_string().into(), state_key)?;
|
||||
state.insert(shortstatekey, pdu.event_id.clone());
|
||||
}
|
||||
}
|
||||
|
||||
info!("Going through send_join response auth_chain");
|
||||
for result in send_join_response
|
||||
.room_state
|
||||
.auth_chain
|
||||
.iter()
|
||||
.map(|pdu| validate_and_add_event_id(pdu, &room_version_id, &pub_key_map))
|
||||
{
|
||||
let Ok((event_id, value)) = result.await else {
|
||||
continue;
|
||||
};
|
||||
|
||||
services()
|
||||
.rooms
|
||||
.outlier
|
||||
.add_pdu_outlier(&event_id, &value)?;
|
||||
}
|
||||
|
||||
info!("Running send_join auth check");
|
||||
let authenticated = state_res::event_auth::auth_check(
|
||||
&state_res::RoomVersion::new(&room_version_id).expect("room version is supported"),
|
||||
&parsed_join_pdu,
|
||||
None::<PduEvent>, // TODO: third party invite
|
||||
|k, s| {
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.get_pdu(
|
||||
state.get(
|
||||
&services()
|
||||
.rooms
|
||||
.short
|
||||
.get_or_create_shortstatekey(&k.to_string().into(), s)
|
||||
.ok()?,
|
||||
)?,
|
||||
)
|
||||
.ok()?
|
||||
},
|
||||
)
|
||||
.map_err(|e| {
|
||||
warn!("Auth check failed: {e}");
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "Auth check failed")
|
||||
})?;
|
||||
|
||||
if !authenticated {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Auth check failed",
|
||||
));
|
||||
}
|
||||
|
||||
info!("Saving state from send_join");
|
||||
let (statehash_before_join, new, removed) = services().rooms.state_compressor.save_state(
|
||||
room_id,
|
||||
Arc::new(
|
||||
state
|
||||
.into_iter()
|
||||
.map(|(k, id)| {
|
||||
services()
|
||||
.rooms
|
||||
.state_compressor
|
||||
.compress_state_event(k, &id)
|
||||
})
|
||||
.collect::<Result<_>>()?,
|
||||
),
|
||||
)?;
|
||||
|
||||
services()
|
||||
.rooms
|
||||
.state
|
||||
.force_state(room_id, statehash_before_join, new, removed, &state_lock)
|
||||
.await?;
|
||||
|
||||
info!("Updating joined counts for new room");
|
||||
services().rooms.state_cache.update_joined_count(room_id)?;
|
||||
|
||||
// We append to state before appending the pdu, so we don't have a moment in time with the
|
||||
// pdu without it's state. This is okay because append_pdu can't fail.
|
||||
let statehash_after_join = services().rooms.state.append_to_state(&parsed_join_pdu)?;
|
||||
|
||||
info!("Appending new room join event");
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.append_pdu(
|
||||
&parsed_join_pdu,
|
||||
join_event,
|
||||
vec![(*parsed_join_pdu.event_id).to_owned()],
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
info!("Setting final room state for new room");
|
||||
// We set the room state after inserting the pdu, so that we never have a moment in time
|
||||
// where events in the current room state do not exist
|
||||
services()
|
||||
.rooms
|
||||
.state
|
||||
.set_room_state(room_id, statehash_after_join, &state_lock)?;
|
||||
}
|
||||
|
||||
Ok(join_room_by_id::v3::Response::new(room_id.to_owned()))
|
||||
|
@ -1272,16 +1263,13 @@ pub(crate) async fn invite_helper<'a>(
|
|||
let pub_key_map = RwLock::new(BTreeMap::new());
|
||||
|
||||
// We do not add the event_id field to the pdu here because of signature and hashes checks
|
||||
let (event_id, value) = match gen_event_id_canonical_json(&response.event, &room_version_id)
|
||||
{
|
||||
Ok(t) => t,
|
||||
Err(_) => {
|
||||
// Event could not be converted to canonical json
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Could not convert event to canonical json.",
|
||||
));
|
||||
}
|
||||
let Ok((event_id, value)) = gen_event_id_canonical_json(&response.event, &room_version_id)
|
||||
else {
|
||||
// Event could not be converted to canonical json
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Could not convert event to canonical json.",
|
||||
));
|
||||
};
|
||||
|
||||
if *pdu.event_id != *event_id {
|
||||
|
@ -1389,10 +1377,7 @@ pub async fn leave_all_rooms(user_id: &UserId) -> Result<()> {
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
for room_id in all_rooms {
|
||||
let room_id = match room_id {
|
||||
Ok(room_id) => room_id,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let Ok(room_id) = room_id else { continue };
|
||||
|
||||
let _ = leave_room(user_id, &room_id, None).await;
|
||||
}
|
||||
|
@ -1402,35 +1387,11 @@ pub async fn leave_all_rooms(user_id: &UserId) -> Result<()> {
|
|||
|
||||
pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<String>) -> Result<()> {
|
||||
// Ask a remote server if we don't have this room
|
||||
if !services()
|
||||
if services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.server_in_room(services().globals.server_name(), room_id)?
|
||||
{
|
||||
if let Err(e) = remote_leave_room(user_id, room_id).await {
|
||||
warn!("Failed to leave room {} remotely: {}", user_id, e);
|
||||
// Don't tell the client about this error
|
||||
}
|
||||
|
||||
let last_state = services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.invite_state(user_id, room_id)?
|
||||
.map_or_else(
|
||||
|| services().rooms.state_cache.left_state(user_id, room_id),
|
||||
|s| Ok(Some(s)),
|
||||
)?;
|
||||
|
||||
// We always drop the invite, we can't rely on other servers
|
||||
services().rooms.state_cache.update_membership(
|
||||
room_id,
|
||||
user_id,
|
||||
MembershipState::Leave,
|
||||
user_id,
|
||||
last_state,
|
||||
true,
|
||||
)?;
|
||||
} else {
|
||||
let mutex_state = Arc::clone(
|
||||
services()
|
||||
.globals
|
||||
|
@ -1492,6 +1453,30 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
|
|||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
if let Err(e) = remote_leave_room(user_id, room_id).await {
|
||||
warn!("Failed to leave room {} remotely: {}", user_id, e);
|
||||
// Don't tell the client about this error
|
||||
}
|
||||
|
||||
let last_state = services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.invite_state(user_id, room_id)?
|
||||
.map_or_else(
|
||||
|| services().rooms.state_cache.left_state(user_id, room_id),
|
||||
|s| Ok(Some(s)),
|
||||
)?;
|
||||
|
||||
// We always drop the invite, we can't rely on other servers
|
||||
services().rooms.state_cache.update_membership(
|
||||
room_id,
|
||||
user_id,
|
||||
MembershipState::Leave,
|
||||
user_id,
|
||||
last_state,
|
||||
true,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1515,7 +1500,7 @@ async fn remote_leave_room(user_id: &UserId, room_id: &RoomId) -> Result<()> {
|
|||
.iter()
|
||||
.filter_map(|event| serde_json::from_str(event.json().get()).ok())
|
||||
.filter_map(|event: serde_json::Value| event.get("sender").cloned())
|
||||
.filter_map(|sender| sender.as_str().map(|s| s.to_owned()))
|
||||
.filter_map(|sender| sender.as_str().map(ToOwned::to_owned))
|
||||
.filter_map(|sender| UserId::parse(sender).ok())
|
||||
.map(|user| user.server_name().to_owned())
|
||||
.collect();
|
||||
|
|
|
@ -110,7 +110,7 @@ pub async fn send_message_event_route(
|
|||
/// 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)
|
||||
/// joined, depending on `history_visibility`)
|
||||
pub async fn get_message_events_route(
|
||||
body: Ruma<get_message_events::v3::Request>,
|
||||
) -> Result<get_message_events::v3::Response> {
|
||||
|
|
|
@ -147,7 +147,7 @@ pub async fn get_displayname_route(
|
|||
|
||||
/// # `PUT /_matrix/client/r0/profile/{userId}/avatar_url`
|
||||
///
|
||||
/// Updates the avatar_url and blurhash.
|
||||
/// Updates the `avatar_url` and blurhash.
|
||||
///
|
||||
/// - Also makes sure other users receive the update using presence EDUs
|
||||
pub async fn set_avatar_url_route(
|
||||
|
@ -252,9 +252,9 @@ pub async fn set_avatar_url_route(
|
|||
|
||||
/// # `GET /_matrix/client/r0/profile/{userId}/avatar_url`
|
||||
///
|
||||
/// Returns the avatar_url and blurhash of the user.
|
||||
/// Returns the `avatar_url` and blurhash of the user.
|
||||
///
|
||||
/// - If user is on another server: Fetches avatar_url and blurhash over federation
|
||||
/// - If user is on another server: Fetches `avatar_url` and blurhash over federation
|
||||
pub async fn get_avatar_url_route(
|
||||
body: Ruma<get_avatar_url::v3::Request>,
|
||||
) -> Result<get_avatar_url::v3::Response> {
|
||||
|
@ -284,7 +284,7 @@ pub async fn get_avatar_url_route(
|
|||
|
||||
/// # `GET /_matrix/client/r0/profile/{userId}`
|
||||
///
|
||||
/// Returns the displayname, avatar_url and blurhash of the user.
|
||||
/// Returns the displayname, `avatar_url` and blurhash of the user.
|
||||
///
|
||||
/// - If user is on another server: Fetches profile over federation
|
||||
pub async fn get_profile_route(
|
||||
|
|
|
@ -281,7 +281,7 @@ pub async fn get_pushrule_enabled_route(
|
|||
let global = account_data.content.global;
|
||||
let enabled = global
|
||||
.get(body.kind.clone(), &body.rule_id)
|
||||
.map(|r| r.enabled())
|
||||
.map(ruma::push::AnyPushRuleRef::enabled)
|
||||
.ok_or(Error::BadRequest(
|
||||
ErrorKind::NotFound,
|
||||
"Push rule not found.",
|
||||
|
|
|
@ -140,7 +140,7 @@ pub async fn create_receipt_route(
|
|||
receipts.insert(ReceiptType::Read, user_receipts);
|
||||
|
||||
let mut receipt_content = BTreeMap::new();
|
||||
receipt_content.insert(body.event_id.to_owned(), receipts);
|
||||
receipt_content.insert(body.event_id.clone(), receipts);
|
||||
|
||||
services().rooms.edus.read_receipt.readreceipt_update(
|
||||
sender_user,
|
||||
|
|
|
@ -39,8 +39,8 @@ pub async fn get_relating_events_with_rel_type_and_event_type_route(
|
|||
sender_user,
|
||||
&body.room_id,
|
||||
&body.event_id,
|
||||
Some(body.event_type.clone()),
|
||||
Some(body.rel_type.clone()),
|
||||
&Some(body.event_type.clone()),
|
||||
&Some(body.rel_type.clone()),
|
||||
from,
|
||||
to,
|
||||
limit,
|
||||
|
@ -89,8 +89,8 @@ pub async fn get_relating_events_with_rel_type_route(
|
|||
sender_user,
|
||||
&body.room_id,
|
||||
&body.event_id,
|
||||
None,
|
||||
Some(body.rel_type.clone()),
|
||||
&None,
|
||||
&Some(body.rel_type.clone()),
|
||||
from,
|
||||
to,
|
||||
limit,
|
||||
|
@ -137,8 +137,8 @@ pub async fn get_relating_events_route(
|
|||
sender_user,
|
||||
&body.room_id,
|
||||
&body.event_id,
|
||||
None,
|
||||
None,
|
||||
&None,
|
||||
&None,
|
||||
from,
|
||||
to,
|
||||
limit,
|
||||
|
|
|
@ -14,14 +14,11 @@ pub async fn report_event_route(
|
|||
) -> Result<report_content::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
let pdu = match services().rooms.timeline.get_pdu(&body.event_id)? {
|
||||
Some(pdu) => pdu,
|
||||
_ => {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Invalid Event ID",
|
||||
))
|
||||
}
|
||||
let Some(pdu) = services().rooms.timeline.get_pdu(&body.event_id)? else {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Invalid Event ID",
|
||||
));
|
||||
};
|
||||
|
||||
if let Some(true) = body.score.map(|s| s > int!(0) || s < int!(-100)) {
|
||||
|
|
|
@ -34,7 +34,7 @@ use tracing::{info, warn};
|
|||
/// Creates a new room.
|
||||
///
|
||||
/// - Room ID is randomly generated
|
||||
/// - Create alias if room_alias_name is set
|
||||
/// - Create alias if `room_alias_name` is set
|
||||
/// - Send create event
|
||||
/// - Join sender user
|
||||
/// - Send power levels event
|
||||
|
@ -228,7 +228,7 @@ pub async fn create_room_route(
|
|||
event_type: TimelineEventType::RoomCreate,
|
||||
content: to_raw_value(&content).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -269,9 +269,10 @@ pub async fn create_room_route(
|
|||
|
||||
// Figure out preset. We need it for preset specific events
|
||||
let preset = body.preset.clone().unwrap_or(match &body.visibility {
|
||||
room::Visibility::Private => RoomPreset::PrivateChat,
|
||||
room::Visibility::Public => RoomPreset::PublicChat,
|
||||
_ => RoomPreset::PrivateChat, // Room visibility should not be custom
|
||||
// Room visibility is set to private, or custom
|
||||
// Room visibility should not be custom
|
||||
_ => RoomPreset::PrivateChat,
|
||||
});
|
||||
|
||||
let mut users = BTreeMap::new();
|
||||
|
@ -309,7 +310,7 @@ pub async fn create_room_route(
|
|||
content: to_raw_value(&power_levels_content)
|
||||
.expect("to_raw_value always works on serde_json::Value"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -332,7 +333,7 @@ pub async fn create_room_route(
|
|||
})
|
||||
.expect("We checked that alias earlier, it must be fine"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -358,7 +359,7 @@ pub async fn create_room_route(
|
|||
}))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -379,7 +380,7 @@ pub async fn create_room_route(
|
|||
))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -401,7 +402,7 @@ pub async fn create_room_route(
|
|||
}))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -418,7 +419,7 @@ pub async fn create_room_route(
|
|||
})?;
|
||||
|
||||
// Implicit state key defaults to ""
|
||||
pdu_builder.state_key.get_or_insert_with(|| "".to_owned());
|
||||
pdu_builder.state_key.get_or_insert_with(String::new);
|
||||
|
||||
// Silently skip encryption events if they are not allowed
|
||||
if pdu_builder.event_type == TimelineEventType::RoomEncryption
|
||||
|
@ -445,7 +446,7 @@ pub async fn create_room_route(
|
|||
content: to_raw_value(&RoomNameEventContent::new(name.clone()))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -467,7 +468,7 @@ pub async fn create_room_route(
|
|||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -539,7 +540,7 @@ pub async fn get_room_event_route(
|
|||
///
|
||||
/// 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
|
||||
/// - Only users joined to the room are allowed to call this TODO: Allow any user to call it if `history_visibility` is world readable
|
||||
pub async fn get_room_aliases_route(
|
||||
body: Ruma<aliases::v3::Request>,
|
||||
) -> Result<aliases::v3::Response> {
|
||||
|
@ -624,7 +625,7 @@ pub async fn upgrade_room_route(
|
|||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -725,7 +726,7 @@ pub async fn upgrade_room_route(
|
|||
content: to_raw_value(&create_event_content)
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -795,7 +796,7 @@ pub async fn upgrade_room_route(
|
|||
event_type: event_type.to_string().into(),
|
||||
content: event_content,
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
@ -845,7 +846,7 @@ pub async fn upgrade_room_route(
|
|||
content: to_raw_value(&power_levels_event_content)
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
state_key: Some(String::new()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
|
|
|
@ -3,7 +3,13 @@ use crate::{services, utils, Error, Result, Ruma};
|
|||
use ruma::{
|
||||
api::client::{
|
||||
error::ErrorKind,
|
||||
session::{get_login_types, login, logout, logout_all},
|
||||
session::{
|
||||
get_login_types::{
|
||||
self,
|
||||
v3::{ApplicationServiceLoginType, PasswordLoginType},
|
||||
},
|
||||
login, logout, logout_all,
|
||||
},
|
||||
uiaa::UserIdentifier,
|
||||
},
|
||||
UserId,
|
||||
|
@ -25,8 +31,8 @@ pub async fn get_login_types_route(
|
|||
_body: Ruma<get_login_types::v3::Request>,
|
||||
) -> Result<get_login_types::v3::Response> {
|
||||
Ok(get_login_types::v3::Response::new(vec![
|
||||
get_login_types::v3::LoginType::Password(Default::default()),
|
||||
get_login_types::v3::LoginType::ApplicationService(Default::default()),
|
||||
get_login_types::v3::LoginType::Password(PasswordLoginType::default()),
|
||||
get_login_types::v3::LoginType::ApplicationService(ApplicationServiceLoginType::default()),
|
||||
]))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{services, Result, Ruma};
|
||||
use ruma::api::client::space::get_hierarchy;
|
||||
|
||||
/// # `GET /_matrix/client/v1/rooms/{room_id}/hierarchy``
|
||||
/// # `GET /_matrix/client/v1/rooms/{room_id}/hierarchy`
|
||||
///
|
||||
/// Paginates over the space tree in a depth-first manner to locate child rooms of a given space.
|
||||
pub async fn get_hierarchy_route(
|
||||
|
|
|
@ -20,7 +20,7 @@ use tracing::log::warn;
|
|||
///
|
||||
/// - 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
|
||||
/// - If event is new `canonical_alias`: Rejects if alias is incorrect
|
||||
pub async fn send_state_event_for_key_route(
|
||||
body: Ruma<send_state_event::v3::Request>,
|
||||
) -> Result<send_state_event::v3::Response> {
|
||||
|
@ -31,7 +31,7 @@ pub async fn send_state_event_for_key_route(
|
|||
&body.room_id,
|
||||
&body.event_type,
|
||||
&body.body.body, // Yes, I hate it too
|
||||
body.state_key.to_owned(),
|
||||
body.state_key.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
@ -45,7 +45,7 @@ pub async fn send_state_event_for_key_route(
|
|||
///
|
||||
/// - 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
|
||||
/// - If event is new `canonical_alias`: Rejects if alias is incorrect
|
||||
pub async fn send_state_event_for_empty_key_route(
|
||||
body: Ruma<send_state_event::v3::Request>,
|
||||
) -> Result<RumaResponse<send_state_event::v3::Response>> {
|
||||
|
@ -64,7 +64,7 @@ pub async fn send_state_event_for_empty_key_route(
|
|||
&body.room_id,
|
||||
&body.event_type.to_string().into(),
|
||||
&body.body.body,
|
||||
body.state_key.to_owned(),
|
||||
body.state_key.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ use tracing::{error, info};
|
|||
/// - 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)
|
||||
/// - 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
|
||||
|
@ -83,7 +83,7 @@ pub async fn sync_events_route(
|
|||
Entry::Vacant(v) => {
|
||||
let (tx, rx) = tokio::sync::watch::channel(None);
|
||||
|
||||
v.insert((body.since.to_owned(), rx.clone()));
|
||||
v.insert((body.since.clone(), rx.clone()));
|
||||
|
||||
tokio::spawn(sync_helper_wrapper(
|
||||
sender_user.clone(),
|
||||
|
@ -95,7 +95,9 @@ pub async fn sync_events_route(
|
|||
rx
|
||||
}
|
||||
Entry::Occupied(mut o) => {
|
||||
if o.get().0 != body.since {
|
||||
if o.get().0 == body.since {
|
||||
o.get().1.clone()
|
||||
} else {
|
||||
let (tx, rx) = tokio::sync::watch::channel(None);
|
||||
|
||||
o.insert((body.since.clone(), rx.clone()));
|
||||
|
@ -110,8 +112,6 @@ pub async fn sync_events_route(
|
|||
));
|
||||
|
||||
rx
|
||||
} else {
|
||||
o.get().1.clone()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -198,7 +198,7 @@ async fn sync_helper(
|
|||
LazyLoadOptions::Enabled {
|
||||
include_redundant_members: redundant,
|
||||
} => (true, redundant),
|
||||
_ => (false, false),
|
||||
LazyLoadOptions::Disabled => (false, false),
|
||||
};
|
||||
|
||||
let full_state = body.full_state;
|
||||
|
@ -376,28 +376,23 @@ async fn sync_helper(
|
|||
None => HashMap::new(),
|
||||
};
|
||||
|
||||
let left_event_id = match services().rooms.state_accessor.room_state_get_id(
|
||||
let Some(left_event_id) = services().rooms.state_accessor.room_state_get_id(
|
||||
&room_id,
|
||||
&StateEventType::RoomMember,
|
||||
sender_user.as_str(),
|
||||
)? {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
error!("Left room but no left state event");
|
||||
continue;
|
||||
}
|
||||
)?
|
||||
else {
|
||||
error!("Left room but no left state event");
|
||||
continue;
|
||||
};
|
||||
|
||||
let left_shortstatehash = match services()
|
||||
let Some(left_shortstatehash) = services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.pdu_shortstatehash(&left_event_id)?
|
||||
{
|
||||
Some(s) => s,
|
||||
None => {
|
||||
error!("Leave event has no state");
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
error!("Leave event has no state");
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut left_state_ids = services()
|
||||
|
@ -425,12 +420,9 @@ async fn sync_helper(
|
|||
// TODO: Delete the following line when this is resolved: https://github.com/vector-im/element-web/issues/22565
|
||||
|| *sender_user == state_key
|
||||
{
|
||||
let pdu = match services().rooms.timeline.get_pdu(&id)? {
|
||||
Some(pdu) => pdu,
|
||||
None => {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
}
|
||||
let Some(pdu) = services().rooms.timeline.get_pdu(&id)? else {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
};
|
||||
|
||||
left_state_events.push(pdu.to_sync_state_event());
|
||||
|
@ -648,13 +640,11 @@ async fn load_joined_room(
|
|||
|
||||
// Database queries:
|
||||
|
||||
let current_shortstatehash =
|
||||
if let Some(s) = services().rooms.state.get_room_shortstatehash(room_id)? {
|
||||
s
|
||||
} else {
|
||||
error!("Room {} has no state", room_id);
|
||||
return Err(Error::BadDatabase("Room has no state"));
|
||||
};
|
||||
let Some(current_shortstatehash) = services().rooms.state.get_room_shortstatehash(room_id)?
|
||||
else {
|
||||
error!("Room {} has no state", room_id);
|
||||
return Err(Error::BadDatabase("Room has no state"));
|
||||
};
|
||||
|
||||
let since_shortstatehash = services()
|
||||
.rooms
|
||||
|
@ -788,12 +778,9 @@ async fn load_joined_room(
|
|||
.get_statekey_from_short(shortstatekey)?;
|
||||
|
||||
if event_type != StateEventType::RoomMember {
|
||||
let pdu = match services().rooms.timeline.get_pdu(&id)? {
|
||||
Some(pdu) => pdu,
|
||||
None => {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
}
|
||||
let Some(pdu) = services().rooms.timeline.get_pdu(&id)? else {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
};
|
||||
state_events.push(pdu);
|
||||
|
||||
|
@ -807,12 +794,9 @@ async fn load_joined_room(
|
|||
// TODO: Delete the following line when this is resolved: https://github.com/vector-im/element-web/issues/22565
|
||||
|| *sender_user == state_key
|
||||
{
|
||||
let pdu = match services().rooms.timeline.get_pdu(&id)? {
|
||||
Some(pdu) => pdu,
|
||||
None => {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
}
|
||||
let Some(pdu) = services().rooms.timeline.get_pdu(&id)? else {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
};
|
||||
|
||||
// This check is in case a bad user ID made it into the database
|
||||
|
@ -877,12 +861,9 @@ async fn load_joined_room(
|
|||
|
||||
for (key, id) in current_state_ids {
|
||||
if full_state || since_state_ids.get(&key) != Some(&id) {
|
||||
let pdu = match services().rooms.timeline.get_pdu(&id)? {
|
||||
Some(pdu) => pdu,
|
||||
None => {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
}
|
||||
let Some(pdu) = services().rooms.timeline.get_pdu(&id)? else {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
};
|
||||
|
||||
if pdu.kind == TimelineEventType::RoomMember {
|
||||
|
@ -1248,7 +1229,7 @@ pub async fn sync_events_v4_route(
|
|||
sender_user.clone(),
|
||||
sender_device.clone(),
|
||||
conn_id.clone(),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1286,13 +1267,12 @@ pub async fn sync_events_v4_route(
|
|||
);
|
||||
|
||||
for room_id in &all_joined_rooms {
|
||||
let current_shortstatehash =
|
||||
if let Some(s) = services().rooms.state.get_room_shortstatehash(room_id)? {
|
||||
s
|
||||
} else {
|
||||
error!("Room {} has no state", room_id);
|
||||
continue;
|
||||
};
|
||||
let Some(current_shortstatehash) =
|
||||
services().rooms.state.get_room_shortstatehash(room_id)?
|
||||
else {
|
||||
error!("Room {} has no state", room_id);
|
||||
continue;
|
||||
};
|
||||
|
||||
let since_shortstatehash = services()
|
||||
.rooms
|
||||
|
@ -1354,12 +1334,9 @@ pub async fn sync_events_v4_route(
|
|||
|
||||
for (key, id) in current_state_ids {
|
||||
if since_state_ids.get(&key) != Some(&id) {
|
||||
let pdu = match services().rooms.timeline.get_pdu(&id)? {
|
||||
Some(pdu) => pdu,
|
||||
None => {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
}
|
||||
let Some(pdu) = services().rooms.timeline.get_pdu(&id)? else {
|
||||
error!("Pdu in state not found: {}", id);
|
||||
continue;
|
||||
};
|
||||
if pdu.kind == TimelineEventType::RoomMember {
|
||||
if let Some(state_key) = &pdu.state_key {
|
||||
|
@ -1599,10 +1576,10 @@ pub async fn sync_events_v4_route(
|
|||
}))
|
||||
})?
|
||||
.or_else(|| {
|
||||
if roomsince != &0 {
|
||||
Some(roomsince.to_string())
|
||||
} else {
|
||||
if roomsince == &0 {
|
||||
None
|
||||
} else {
|
||||
Some(roomsince.to_string())
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1613,7 +1590,7 @@ pub async fn sync_events_v4_route(
|
|||
|
||||
let required_state = required_state_request
|
||||
.iter()
|
||||
.flat_map(|state| {
|
||||
.filter_map(|state| {
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
|
@ -1631,7 +1608,7 @@ pub async fn sync_events_v4_route(
|
|||
.room_members(room_id)
|
||||
.filter_map(|r| r.ok())
|
||||
.filter(|member| member != &sender_user)
|
||||
.flat_map(|member| {
|
||||
.filter_map(|member| {
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
|
|
|
@ -24,18 +24,19 @@ pub async fn update_tag_route(
|
|||
RoomAccountDataEventType::Tag,
|
||||
)?;
|
||||
|
||||
let mut tags_event = event
|
||||
.map(|e| {
|
||||
serde_json::from_str(e.get())
|
||||
.map_err(|_| Error::bad_database("Invalid account data event in db."))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
let mut tags_event = event.map_or_else(
|
||||
|| {
|
||||
Ok(TagEvent {
|
||||
content: TagEventContent {
|
||||
tags: BTreeMap::new(),
|
||||
},
|
||||
})
|
||||
})?;
|
||||
},
|
||||
|e| {
|
||||
serde_json::from_str(e.get())
|
||||
.map_err(|_| Error::bad_database("Invalid account data event in db."))
|
||||
},
|
||||
)?;
|
||||
|
||||
tags_event
|
||||
.content
|
||||
|
@ -68,18 +69,19 @@ pub async fn delete_tag_route(
|
|||
RoomAccountDataEventType::Tag,
|
||||
)?;
|
||||
|
||||
let mut tags_event = event
|
||||
.map(|e| {
|
||||
serde_json::from_str(e.get())
|
||||
.map_err(|_| Error::bad_database("Invalid account data event in db."))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
let mut tags_event = event.map_or_else(
|
||||
|| {
|
||||
Ok(TagEvent {
|
||||
content: TagEventContent {
|
||||
tags: BTreeMap::new(),
|
||||
},
|
||||
})
|
||||
})?;
|
||||
},
|
||||
|e| {
|
||||
serde_json::from_str(e.get())
|
||||
.map_err(|_| Error::bad_database("Invalid account data event in db."))
|
||||
},
|
||||
)?;
|
||||
|
||||
tags_event.content.tags.remove(&body.tag.clone().into());
|
||||
|
||||
|
@ -107,18 +109,19 @@ pub async fn get_tags_route(body: Ruma<get_tags::v3::Request>) -> Result<get_tag
|
|||
RoomAccountDataEventType::Tag,
|
||||
)?;
|
||||
|
||||
let tags_event = event
|
||||
.map(|e| {
|
||||
serde_json::from_str(e.get())
|
||||
.map_err(|_| Error::bad_database("Invalid account data event in db."))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
let tags_event = event.map_or_else(
|
||||
|| {
|
||||
Ok(TagEvent {
|
||||
content: TagEventContent {
|
||||
tags: BTreeMap::new(),
|
||||
},
|
||||
})
|
||||
})?;
|
||||
},
|
||||
|e| {
|
||||
serde_json::from_str(e.get())
|
||||
.map_err(|_| Error::bad_database("Invalid account data event in db."))
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(get_tags::v3::Response {
|
||||
tags: tags_event.content.tags,
|
||||
|
|
|
@ -63,7 +63,7 @@ pub async fn send_event_to_device_route(
|
|||
event.deserialize_as().map_err(|_| {
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid")
|
||||
})?,
|
||||
)?
|
||||
)?;
|
||||
}
|
||||
|
||||
DeviceIdOrAllDevices::AllDevices => {
|
||||
|
|
|
@ -17,7 +17,12 @@ pub async fn turn_server_route(
|
|||
|
||||
let turn_secret = services().globals.turn_secret().clone();
|
||||
|
||||
let (username, password) = if !turn_secret.is_empty() {
|
||||
let (username, password) = if turn_secret.is_empty() {
|
||||
(
|
||||
services().globals.turn_username().clone(),
|
||||
services().globals.turn_password().clone(),
|
||||
)
|
||||
} else {
|
||||
let expiry = SecondsSinceUnixEpoch::from_system_time(
|
||||
SystemTime::now() + Duration::from_secs(services().globals.turn_ttl()),
|
||||
)
|
||||
|
@ -32,11 +37,6 @@ pub async fn turn_server_route(
|
|||
let password: String = general_purpose::STANDARD.encode(mac.finalize().into_bytes());
|
||||
|
||||
(username, password)
|
||||
} else {
|
||||
(
|
||||
services().globals.turn_username().clone(),
|
||||
services().globals.turn_password().clone(),
|
||||
)
|
||||
};
|
||||
|
||||
Ok(get_turn_server_info::v3::Response {
|
||||
|
|
|
@ -226,7 +226,7 @@ where
|
|||
let keys_result = services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.fetch_signing_keys(&x_matrix.origin, vec![x_matrix.key.to_owned()])
|
||||
.fetch_signing_keys(&x_matrix.origin, vec![x_matrix.key.clone()])
|
||||
.await;
|
||||
|
||||
let keys = match keys_result {
|
||||
|
@ -334,8 +334,8 @@ where
|
|||
sender_user,
|
||||
sender_device,
|
||||
sender_servername,
|
||||
appservice_info,
|
||||
json_body,
|
||||
appservice_info,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ use tracing::{debug, error, warn};
|
|||
/// (colon-plus-port if it was specified).
|
||||
///
|
||||
/// Note: A `FedDest::Named` might contain an IP address in string form if there
|
||||
/// was no port specified to construct a SocketAddr with.
|
||||
/// was no port specified to construct a `SocketAddr` with.
|
||||
///
|
||||
/// # Examples:
|
||||
/// ```rust
|
||||
|
@ -344,7 +344,7 @@ fn add_port_to_hostname(destination_str: &str) -> FedDest {
|
|||
FedDest::Named(host.to_owned(), port.to_owned())
|
||||
}
|
||||
|
||||
/// Returns: actual_destination, host header
|
||||
/// Returns: `actual_destination`, host header
|
||||
/// Implemented according to the specification at <https://matrix.org/docs/spec/server_server/r0.1.4#resolving-server-names>
|
||||
/// Numbers in comments below refer to bullet points in linked section of specification
|
||||
async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDest) {
|
||||
|
@ -363,100 +363,91 @@ async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDe
|
|||
FedDest::Named(host.to_owned(), port.to_owned())
|
||||
} else {
|
||||
debug!("Requesting well known for {destination}");
|
||||
match request_well_known(destination.as_str()).await {
|
||||
Some(delegated_hostname) => {
|
||||
debug!("3: A .well-known file is available");
|
||||
hostname = add_port_to_hostname(&delegated_hostname).into_uri_string();
|
||||
match get_ip_with_port(&delegated_hostname) {
|
||||
Some(host_and_port) => host_and_port, // 3.1: IP literal in .well-known file
|
||||
None => {
|
||||
if let Some(pos) = delegated_hostname.find(':') {
|
||||
debug!("3.2: Hostname with port in .well-known file");
|
||||
let (host, port) = delegated_hostname.split_at(pos);
|
||||
FedDest::Named(host.to_owned(), port.to_owned())
|
||||
} else {
|
||||
debug!("Delegated hostname has no port in this branch");
|
||||
if let Some(hostname_override) =
|
||||
query_srv_record(&delegated_hostname).await
|
||||
if let Some(delegated_hostname) = request_well_known(destination.as_str()).await {
|
||||
debug!("3: A .well-known file is available");
|
||||
hostname = add_port_to_hostname(&delegated_hostname).into_uri_string();
|
||||
match get_ip_with_port(&delegated_hostname) {
|
||||
Some(host_and_port) => host_and_port, // 3.1: IP literal in .well-known file
|
||||
None => {
|
||||
if let Some(pos) = delegated_hostname.find(':') {
|
||||
debug!("3.2: Hostname with port in .well-known file");
|
||||
let (host, port) = delegated_hostname.split_at(pos);
|
||||
FedDest::Named(host.to_owned(), port.to_owned())
|
||||
} else {
|
||||
debug!("Delegated hostname has no port in this branch");
|
||||
if let Some(hostname_override) =
|
||||
query_srv_record(&delegated_hostname).await
|
||||
{
|
||||
debug!("3.3: SRV lookup successful");
|
||||
let force_port = hostname_override.port();
|
||||
|
||||
if let Ok(override_ip) = services()
|
||||
.globals
|
||||
.dns_resolver()
|
||||
.lookup_ip(hostname_override.hostname())
|
||||
.await
|
||||
{
|
||||
debug!("3.3: SRV lookup successful");
|
||||
let force_port = hostname_override.port();
|
||||
|
||||
if let Ok(override_ip) = services()
|
||||
services()
|
||||
.globals
|
||||
.dns_resolver()
|
||||
.lookup_ip(hostname_override.hostname())
|
||||
.await
|
||||
{
|
||||
services()
|
||||
.globals
|
||||
.tls_name_override
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(
|
||||
delegated_hostname.clone(),
|
||||
(
|
||||
override_ip.iter().collect(),
|
||||
force_port.unwrap_or(8448),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
warn!("Using SRV record, but could not resolve to IP");
|
||||
}
|
||||
|
||||
if let Some(port) = force_port {
|
||||
FedDest::Named(delegated_hostname, format!(":{port}"))
|
||||
} else {
|
||||
add_port_to_hostname(&delegated_hostname)
|
||||
}
|
||||
.tls_name_override
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(
|
||||
delegated_hostname.clone(),
|
||||
(
|
||||
override_ip.iter().collect(),
|
||||
force_port.unwrap_or(8448),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
warn!("Using SRV record, but could not resolve to IP");
|
||||
}
|
||||
|
||||
if let Some(port) = force_port {
|
||||
FedDest::Named(delegated_hostname, format!(":{port}"))
|
||||
} else {
|
||||
debug!("3.4: No SRV records, just use the hostname from .well-known");
|
||||
add_port_to_hostname(&delegated_hostname)
|
||||
}
|
||||
} else {
|
||||
debug!("3.4: No SRV records, just use the hostname from .well-known");
|
||||
add_port_to_hostname(&delegated_hostname)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
debug!("4: No .well-known or an error occured");
|
||||
match query_srv_record(&destination_str).await {
|
||||
Some(hostname_override) => {
|
||||
debug!("4: SRV record found");
|
||||
let force_port = hostname_override.port();
|
||||
} else {
|
||||
debug!("4: No .well-known or an error occured");
|
||||
if let Some(hostname_override) = query_srv_record(&destination_str).await {
|
||||
debug!("4: SRV record found");
|
||||
let force_port = hostname_override.port();
|
||||
|
||||
if let Ok(override_ip) = services()
|
||||
.globals
|
||||
.dns_resolver()
|
||||
.lookup_ip(hostname_override.hostname())
|
||||
.await
|
||||
{
|
||||
services()
|
||||
.globals
|
||||
.tls_name_override
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(
|
||||
hostname.clone(),
|
||||
(
|
||||
override_ip.iter().collect(),
|
||||
force_port.unwrap_or(8448),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
warn!("Using SRV record, but could not resolve to IP");
|
||||
}
|
||||
|
||||
if let Some(port) = force_port {
|
||||
FedDest::Named(hostname.clone(), format!(":{port}"))
|
||||
} else {
|
||||
add_port_to_hostname(&hostname)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
debug!("5: No SRV record found");
|
||||
add_port_to_hostname(&destination_str)
|
||||
}
|
||||
if let Ok(override_ip) = services()
|
||||
.globals
|
||||
.dns_resolver()
|
||||
.lookup_ip(hostname_override.hostname())
|
||||
.await
|
||||
{
|
||||
services()
|
||||
.globals
|
||||
.tls_name_override
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(
|
||||
hostname.clone(),
|
||||
(override_ip.iter().collect(), force_port.unwrap_or(8448)),
|
||||
);
|
||||
} else {
|
||||
warn!("Using SRV record, but could not resolve to IP");
|
||||
}
|
||||
|
||||
if let Some(port) = force_port {
|
||||
FedDest::Named(hostname.clone(), format!(":{port}"))
|
||||
} else {
|
||||
add_port_to_hostname(&hostname)
|
||||
}
|
||||
} else {
|
||||
debug!("5: No SRV record found");
|
||||
add_port_to_hostname(&destination_str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -660,15 +651,12 @@ pub fn parse_incoming_pdu(
|
|||
|
||||
let room_version_id = services().rooms.state.get_room_version(&room_id)?;
|
||||
|
||||
let (event_id, value) = match gen_event_id_canonical_json(pdu, &room_version_id) {
|
||||
Ok(t) => t,
|
||||
Err(_) => {
|
||||
// Event could not be converted to canonical json
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Could not convert event to canonical json.",
|
||||
));
|
||||
}
|
||||
let Ok((event_id, value)) = gen_event_id_canonical_json(pdu, &room_version_id) else {
|
||||
// Event could not be converted to canonical json
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Could not convert event to canonical json.",
|
||||
));
|
||||
};
|
||||
Ok((event_id, value, room_id))
|
||||
}
|
||||
|
@ -731,7 +719,7 @@ pub async fn send_transaction_message_route(
|
|||
.roomid_mutex_federation
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.entry(room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let mutex_lock = mutex.lock().await;
|
||||
|
@ -777,7 +765,6 @@ pub async fn send_transaction_message_route(
|
|||
.filter_map(|edu| serde_json::from_str::<Edu>(edu.json().get()).ok())
|
||||
{
|
||||
match edu {
|
||||
Edu::Presence(_) => {}
|
||||
Edu::Receipt(receipt) => {
|
||||
for (room_id, room_updates) in receipt.receipts {
|
||||
for (user_id, user_updates) in room_updates.read {
|
||||
|
@ -881,7 +868,7 @@ pub async fn send_transaction_message_route(
|
|||
"Event is invalid",
|
||||
)
|
||||
})?,
|
||||
)?
|
||||
)?;
|
||||
}
|
||||
|
||||
DeviceIdOrAllDevices::AllDevices => {
|
||||
|
@ -929,7 +916,7 @@ pub async fn send_transaction_message_route(
|
|||
)?;
|
||||
}
|
||||
}
|
||||
Edu::_Custom(_) => {}
|
||||
Edu::_Custom(_) | Edu::Presence(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1278,15 +1265,14 @@ pub async fn get_room_state_route(
|
|||
|
||||
Ok(get_room_state::v1::Response {
|
||||
auth_chain: auth_chain_ids
|
||||
.filter_map(
|
||||
|id| match services().rooms.timeline.get_pdu_json(&id).ok()? {
|
||||
Some(json) => Some(PduEvent::convert_to_outgoing_federation_event(json)),
|
||||
None => {
|
||||
error!("Could not find event json for {id} in db.");
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.filter_map(|id| {
|
||||
if let Some(json) = services().rooms.timeline.get_pdu_json(&id).ok()? {
|
||||
Some(PduEvent::convert_to_outgoing_federation_event(json))
|
||||
} else {
|
||||
error!("Could not find event json for {id} in db.");
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
pdus,
|
||||
})
|
||||
|
@ -1378,7 +1364,7 @@ pub async fn create_join_event_template_route(
|
|||
.roomid_mutex_state
|
||||
.write()
|
||||
.await
|
||||
.entry(body.room_id.to_owned())
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
@ -1518,15 +1504,12 @@ async fn create_join_event(
|
|||
|
||||
// We do not add the event_id field to the pdu here because of signature and hashes checks
|
||||
let room_version_id = services().rooms.state.get_room_version(room_id)?;
|
||||
let (event_id, value) = match gen_event_id_canonical_json(pdu, &room_version_id) {
|
||||
Ok(t) => t,
|
||||
Err(_) => {
|
||||
// Event could not be converted to canonical json
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Could not convert event to canonical json.",
|
||||
));
|
||||
}
|
||||
let Ok((event_id, value)) = gen_event_id_canonical_json(pdu, &room_version_id) else {
|
||||
// Event could not be converted to canonical json
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Could not convert event to canonical json.",
|
||||
));
|
||||
};
|
||||
|
||||
let origin: OwnedServerName = serde_json::from_value(
|
||||
|
@ -1841,11 +1824,11 @@ pub async fn get_profile_information_route(
|
|||
|
||||
match &body.field {
|
||||
Some(ProfileField::DisplayName) => {
|
||||
displayname = services().users.displayname(&body.user_id)?
|
||||
displayname = services().users.displayname(&body.user_id)?;
|
||||
}
|
||||
Some(ProfileField::AvatarUrl) => {
|
||||
avatar_url = services().users.avatar_url(&body.user_id)?;
|
||||
blurhash = services().users.blurhash(&body.user_id)?
|
||||
blurhash = services().users.blurhash(&body.user_id)?;
|
||||
}
|
||||
// TODO: what to do with custom
|
||||
Some(_) => {}
|
||||
|
@ -1857,9 +1840,9 @@ pub async fn get_profile_information_route(
|
|||
}
|
||||
|
||||
Ok(get_profile_information::v1::Response {
|
||||
blurhash,
|
||||
displayname,
|
||||
avatar_url,
|
||||
blurhash,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1958,7 +1941,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
add_port_to_hostname("example.com"),
|
||||
FedDest::Named(String::from("example.com"), String::from(":8448"))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1966,6 +1949,6 @@ mod tests {
|
|||
assert_eq!(
|
||||
add_port_to_hostname("example.com:1337"),
|
||||
FedDest::Named(String::from("example.com"), String::from(":1337"))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue