Merge branch 'next' into 'room-v11'
# Conflicts: # src/service/rooms/timeline/mod.rs # src/utils/error.rs
This commit is contained in:
commit
b5e21f761b
109 changed files with 4239 additions and 3708 deletions
|
@ -1,23 +1,34 @@
|
|||
use crate::{services, utils, Error, Result};
|
||||
use bytes::BytesMut;
|
||||
use ruma::api::{IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken};
|
||||
use ruma::api::{
|
||||
appservice::Registration, IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken,
|
||||
};
|
||||
use std::{fmt::Debug, mem, time::Duration};
|
||||
use tracing::warn;
|
||||
|
||||
/// Sends a request to an appservice
|
||||
///
|
||||
/// Only returns None if there is no url specified in the appservice registration file
|
||||
#[tracing::instrument(skip(request))]
|
||||
pub(crate) async fn send_request<T: OutgoingRequest>(
|
||||
registration: serde_yaml::Value,
|
||||
registration: Registration,
|
||||
request: T,
|
||||
) -> Result<T::IncomingResponse>
|
||||
) -> Result<Option<T::IncomingResponse>>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
let destination = registration.get("url").unwrap().as_str().unwrap();
|
||||
let hs_token = registration.get("hs_token").unwrap().as_str().unwrap();
|
||||
let destination = match registration.url {
|
||||
Some(url) => url,
|
||||
None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
let hs_token = registration.hs_token.as_str();
|
||||
|
||||
let mut http_request = request
|
||||
.try_into_http_request::<BytesMut>(
|
||||
destination,
|
||||
&destination,
|
||||
SendAccessToken::IfRequired(hs_token),
|
||||
&[MatrixVersion::V1_0],
|
||||
)
|
||||
|
@ -39,8 +50,7 @@ where
|
|||
);
|
||||
*http_request.uri_mut() = parts.try_into().expect("our manipulation is always valid");
|
||||
|
||||
let mut reqwest_request = reqwest::Request::try_from(http_request)
|
||||
.expect("all http requests are valid reqwest requests");
|
||||
let mut reqwest_request = reqwest::Request::try_from(http_request)?;
|
||||
|
||||
*reqwest_request.timeout_mut() = Some(Duration::from_secs(30));
|
||||
|
||||
|
@ -55,9 +65,7 @@ where
|
|||
Err(e) => {
|
||||
warn!(
|
||||
"Could not send request to appservice {:?} at {}: {}",
|
||||
registration.get("id"),
|
||||
destination,
|
||||
e
|
||||
registration.id, destination, e
|
||||
);
|
||||
return Err(e.into());
|
||||
}
|
||||
|
@ -95,7 +103,8 @@ where
|
|||
.body(body)
|
||||
.expect("reqwest body is valid http body"),
|
||||
);
|
||||
response.map_err(|_| {
|
||||
|
||||
response.map(Some).map_err(|_| {
|
||||
warn!(
|
||||
"Appservice returned invalid response bytes {}\n{}",
|
||||
destination, url
|
||||
|
|
|
@ -3,7 +3,8 @@ use crate::{api::client_server, services, utils, Error, Result, Ruma};
|
|||
use ruma::{
|
||||
api::client::{
|
||||
account::{
|
||||
change_password, deactivate, get_3pids, get_username_availability, register,
|
||||
change_password, deactivate, get_3pids, get_username_availability,
|
||||
register::{self, LoginType},
|
||||
request_3pid_management_token_via_email, request_3pid_management_token_via_msisdn,
|
||||
whoami, ThirdPartyIdRemovalStatus,
|
||||
},
|
||||
|
@ -84,6 +85,13 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
|||
));
|
||||
}
|
||||
|
||||
if body.body.login_type == Some(LoginType::ApplicationService) && !body.from_appservice {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::MissingToken,
|
||||
"Missing appservice token.",
|
||||
));
|
||||
}
|
||||
|
||||
let is_guest = body.kind == RegistrationKind::Guest;
|
||||
|
||||
let user_id = match (&body.username, is_guest) {
|
||||
|
@ -239,13 +247,22 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
|||
|
||||
// If this is the first real user, grant them admin privileges
|
||||
// Note: the server user, @conduit:servername, is generated first
|
||||
if services().users.count()? == 2 {
|
||||
services()
|
||||
.admin
|
||||
.make_user_admin(&user_id, displayname)
|
||||
.await?;
|
||||
if !is_guest {
|
||||
if let Some(admin_room) = services().admin.get_admin_room()? {
|
||||
if services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_joined_count(&admin_room)?
|
||||
== Some(1)
|
||||
{
|
||||
services()
|
||||
.admin
|
||||
.make_user_admin(&user_id, displayname)
|
||||
.await?;
|
||||
|
||||
warn!("Granting {} admin privileges as the first user", user_id);
|
||||
warn!("Granting {} admin privileges as the first user", user_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(register::v3::Response {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::{services, Error, Result, Ruma};
|
||||
use rand::seq::SliceRandom;
|
||||
use regex::Regex;
|
||||
use ruma::{
|
||||
api::{
|
||||
appservice,
|
||||
|
@ -101,31 +100,20 @@ pub(crate) async fn get_alias_helper(
|
|||
match services().rooms.alias.resolve_local_alias(&room_alias)? {
|
||||
Some(r) => room_id = Some(r),
|
||||
None => {
|
||||
for (_id, registration) in services().appservice.all()? {
|
||||
let aliases = registration
|
||||
.get("namespaces")
|
||||
.and_then(|ns| ns.get("aliases"))
|
||||
.and_then(|aliases| aliases.as_sequence())
|
||||
.map_or_else(Vec::new, |aliases| {
|
||||
aliases
|
||||
.iter()
|
||||
.filter_map(|aliases| Regex::new(aliases.get("regex")?.as_str()?).ok())
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
if aliases
|
||||
.iter()
|
||||
.any(|aliases| aliases.is_match(room_alias.as_str()))
|
||||
&& services()
|
||||
.sending
|
||||
.send_appservice_request(
|
||||
registration,
|
||||
appservice::query::query_room_alias::v1::Request {
|
||||
room_alias: room_alias.clone(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.is_ok()
|
||||
for appservice in services().appservice.read().await.values() {
|
||||
if appservice.aliases.is_match(room_alias.as_str())
|
||||
&& matches!(
|
||||
services()
|
||||
.sending
|
||||
.send_appservice_request(
|
||||
appservice.registration.clone(),
|
||||
appservice::query::query_room_alias::v1::Request {
|
||||
room_alias: room_alias.clone(),
|
||||
},
|
||||
)
|
||||
.await,
|
||||
Ok(Some(_opt_result))
|
||||
)
|
||||
{
|
||||
room_id = Some(
|
||||
services()
|
||||
|
|
|
@ -339,17 +339,19 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
|
||||
let mut failures = BTreeMap::new();
|
||||
|
||||
let back_off = |id| match services()
|
||||
.globals
|
||||
.bad_query_ratelimiter
|
||||
.write()
|
||||
.unwrap()
|
||||
.entry(id)
|
||||
{
|
||||
hash_map::Entry::Vacant(e) => {
|
||||
e.insert((Instant::now(), 1));
|
||||
let back_off = |id| async {
|
||||
match services()
|
||||
.globals
|
||||
.bad_query_ratelimiter
|
||||
.write()
|
||||
.await
|
||||
.entry(id)
|
||||
{
|
||||
hash_map::Entry::Vacant(e) => {
|
||||
e.insert((Instant::now(), 1));
|
||||
}
|
||||
hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
|
||||
}
|
||||
hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
|
||||
};
|
||||
|
||||
let mut futures: FuturesUnordered<_> = get_over_federation
|
||||
|
@ -359,8 +361,8 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
.globals
|
||||
.bad_query_ratelimiter
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&*server)
|
||||
.await
|
||||
.get(server)
|
||||
{
|
||||
// Exponential backoff
|
||||
let mut min_elapsed_duration = Duration::from_secs(30) * (*tries) * (*tries);
|
||||
|
@ -393,7 +395,7 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| Error::BadServerResponse("Query took too long")),
|
||||
.map_err(|_e| Error::BadServerResponse("Query took too long")),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
@ -428,7 +430,8 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
|
|||
device_keys.extend(response.device_keys);
|
||||
}
|
||||
_ => {
|
||||
back_off(server.to_owned());
|
||||
back_off(server.to_owned()).await;
|
||||
|
||||
failures.insert(server.to_string(), json!({}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ pub async fn create_content_route(
|
|||
.await?;
|
||||
|
||||
Ok(create_content::v3::Response {
|
||||
content_uri: mxc.try_into().expect("Invalid mxc:// URI"),
|
||||
content_uri: mxc.into(),
|
||||
blurhash: None,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -26,9 +26,10 @@ use ruma::{
|
|||
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
|
||||
use std::{
|
||||
collections::{hash_map::Entry, BTreeMap, HashMap, HashSet},
|
||||
sync::{Arc, RwLock},
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
use crate::{
|
||||
|
@ -64,7 +65,12 @@ pub async fn join_room_by_id_route(
|
|||
.map(|user| user.server_name().to_owned()),
|
||||
);
|
||||
|
||||
servers.push(body.room_id.server_name().to_owned());
|
||||
servers.push(
|
||||
body.room_id
|
||||
.server_name()
|
||||
.expect("Room IDs should always have a server name")
|
||||
.into(),
|
||||
);
|
||||
|
||||
join_room_by_id_helper(
|
||||
body.sender_user.as_deref(),
|
||||
|
@ -105,7 +111,12 @@ pub async fn join_room_by_id_or_alias_route(
|
|||
.map(|user| user.server_name().to_owned()),
|
||||
);
|
||||
|
||||
servers.push(room_id.server_name().to_owned());
|
||||
servers.push(
|
||||
room_id
|
||||
.server_name()
|
||||
.expect("Room IDs should always have a server name")
|
||||
.into(),
|
||||
);
|
||||
|
||||
(servers, room_id)
|
||||
}
|
||||
|
@ -202,24 +213,28 @@ pub async fn kick_user_route(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&event).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(body.user_id.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&event).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(body.user_id.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
drop(state_lock);
|
||||
|
||||
|
@ -255,6 +270,7 @@ pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_use
|
|||
serde_json::from_str(event.content.get())
|
||||
.map(|event: RoomMemberEventContent| RoomMemberEventContent {
|
||||
membership: MembershipState::Ban,
|
||||
join_authorized_via_users_server: None,
|
||||
..event
|
||||
})
|
||||
.map_err(|_| Error::bad_database("Invalid member event in database."))
|
||||
|
@ -266,24 +282,28 @@ pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_use
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&event).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(body.user_id.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&event).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(body.user_id.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
drop(state_lock);
|
||||
|
||||
|
@ -324,24 +344,28 @@ pub async fn unban_user_route(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&event).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(body.user_id.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&event).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(body.user_id.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
drop(state_lock);
|
||||
|
||||
|
@ -400,7 +424,7 @@ pub async fn get_member_events_route(
|
|||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(&sender_user, &body.room_id)?
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
|
@ -435,7 +459,7 @@ pub async fn joined_members_route(
|
|||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(&sender_user, &body.room_id)?
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
|
@ -479,7 +503,7 @@ async fn join_room_by_id_helper(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
|
@ -619,7 +643,7 @@ async fn join_room_by_id_helper(
|
|||
));
|
||||
}
|
||||
|
||||
if let Ok(signature) = signed_value["signatures"]
|
||||
match signed_value["signatures"]
|
||||
.as_object()
|
||||
.ok_or(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
|
@ -630,18 +654,20 @@ async fn join_room_by_id_helper(
|
|||
ErrorKind::InvalidParam,
|
||||
"Server did not send its 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());
|
||||
} else {
|
||||
warn!(
|
||||
"Server {remote_server} sent invalid signature in sendjoin signatures for event {signed_value:?}",
|
||||
);
|
||||
}) {
|
||||
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:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -668,7 +694,7 @@ async fn join_room_by_id_helper(
|
|||
.iter()
|
||||
.map(|pdu| validate_and_add_event_id(pdu, &room_version_id, &pub_key_map))
|
||||
{
|
||||
let (event_id, value) = match result {
|
||||
let (event_id, value) = match result.await {
|
||||
Ok(t) => t,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
@ -698,7 +724,7 @@ async fn join_room_by_id_helper(
|
|||
.iter()
|
||||
.map(|pdu| validate_and_add_event_id(pdu, &room_version_id, &pub_key_map))
|
||||
{
|
||||
let (event_id, value) = match result {
|
||||
let (event_id, value) = match result.await {
|
||||
Ok(t) => t,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
@ -710,7 +736,7 @@ async fn join_room_by_id_helper(
|
|||
}
|
||||
|
||||
info!("Running send_join auth check");
|
||||
if !state_res::event_auth::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
|
||||
|
@ -733,7 +759,9 @@ async fn join_room_by_id_helper(
|
|||
.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",
|
||||
|
@ -770,12 +798,16 @@ async fn join_room_by_id_helper(
|
|||
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,
|
||||
)?;
|
||||
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
|
||||
|
@ -888,18 +920,23 @@ async fn join_room_by_id_helper(
|
|||
};
|
||||
|
||||
// Try normal join first
|
||||
let error = match services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&event).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(sender_user.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
room_id,
|
||||
&state_lock,
|
||||
) {
|
||||
let error = match services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&event).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(sender_user.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_event_id) => return Ok(join_room_by_id::v3::Response::new(room_id.to_owned())),
|
||||
Err(e) => e,
|
||||
};
|
||||
|
@ -1095,7 +1132,7 @@ async fn make_join_request(
|
|||
make_join_response_and_server
|
||||
}
|
||||
|
||||
fn validate_and_add_event_id(
|
||||
async fn validate_and_add_event_id(
|
||||
pdu: &RawJsonValue,
|
||||
room_version: &RoomVersionId,
|
||||
pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, Base64>>>,
|
||||
|
@ -1111,24 +1148,26 @@ fn validate_and_add_event_id(
|
|||
))
|
||||
.expect("ruma's reference hashes are valid event ids");
|
||||
|
||||
let back_off = |id| match services()
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.write()
|
||||
.unwrap()
|
||||
.entry(id)
|
||||
{
|
||||
Entry::Vacant(e) => {
|
||||
e.insert((Instant::now(), 1));
|
||||
let back_off = |id| async {
|
||||
match services()
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.write()
|
||||
.await
|
||||
.entry(id)
|
||||
{
|
||||
Entry::Vacant(e) => {
|
||||
e.insert((Instant::now(), 1));
|
||||
}
|
||||
Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
|
||||
}
|
||||
Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
|
||||
};
|
||||
|
||||
if let Some((time, tries)) = services()
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.read()
|
||||
.unwrap()
|
||||
.await
|
||||
.get(&event_id)
|
||||
{
|
||||
// Exponential backoff
|
||||
|
@ -1143,15 +1182,10 @@ fn validate_and_add_event_id(
|
|||
}
|
||||
}
|
||||
|
||||
if let Err(e) = ruma::signatures::verify_event(
|
||||
&*pub_key_map
|
||||
.read()
|
||||
.map_err(|_| Error::bad_database("RwLock is poisoned."))?,
|
||||
&value,
|
||||
room_version,
|
||||
) {
|
||||
if let Err(e) = ruma::signatures::verify_event(&*pub_key_map.read().await, &value, room_version)
|
||||
{
|
||||
warn!("Event {} failed verification {:?} {}", event_id, pdu, e);
|
||||
back_off(event_id);
|
||||
back_off(event_id).await;
|
||||
return Err(Error::BadServerResponse("Event failed verification."));
|
||||
}
|
||||
|
||||
|
@ -1177,7 +1211,7 @@ pub(crate) async fn invite_helper<'a>(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
|
@ -1298,34 +1332,38 @@ pub(crate) async fn invite_helper<'a>(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&RoomMemberEventContent {
|
||||
membership: MembershipState::Invite,
|
||||
displayname: services().users.displayname(user_id)?,
|
||||
avatar_url: services().users.avatar_url(user_id)?,
|
||||
is_direct: Some(is_direct),
|
||||
third_party_invite: None,
|
||||
blurhash: services().users.blurhash(user_id)?,
|
||||
reason,
|
||||
join_authorized_via_users_server: None,
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(user_id.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&RoomMemberEventContent {
|
||||
membership: MembershipState::Invite,
|
||||
displayname: services().users.displayname(user_id)?,
|
||||
avatar_url: services().users.avatar_url(user_id)?,
|
||||
is_direct: Some(is_direct),
|
||||
third_party_invite: None,
|
||||
blurhash: services().users.blurhash(user_id)?,
|
||||
reason,
|
||||
join_authorized_via_users_server: None,
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(user_id.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
drop(state_lock);
|
||||
|
||||
|
@ -1362,7 +1400,7 @@ 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().rooms.metadata.exists(room_id)?
|
||||
&& room_id.server_name() != services().globals.server_name()
|
||||
&& room_id.server_name() != Some(services().globals.server_name())
|
||||
{
|
||||
if let Err(e) = remote_leave_room(user_id, room_id).await {
|
||||
warn!("Failed to leave room {} remotely: {}", user_id, e);
|
||||
|
@ -1393,7 +1431,7 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
|
@ -1428,19 +1466,24 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
|
|||
|
||||
event.membership = MembershipState::Leave;
|
||||
event.reason = reason;
|
||||
event.join_authorized_via_users_server = None;
|
||||
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&event).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(user_id.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
user_id,
|
||||
room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&event).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(user_id.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
user_id,
|
||||
room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -32,7 +32,7 @@ pub async fn send_message_event_route(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
|
@ -73,19 +73,23 @@ pub async fn send_message_event_route(
|
|||
let mut unsigned = BTreeMap::new();
|
||||
unsigned.insert("transaction_id".to_owned(), body.txn_id.to_string().into());
|
||||
|
||||
let event_id = services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: body.event_type.to_string().into(),
|
||||
content: serde_json::from_str(body.body.body.json().get())
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?,
|
||||
unsigned: Some(unsigned),
|
||||
state_key: None,
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
let event_id = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: body.event_type.to_string().into(),
|
||||
content: serde_json::from_str(body.body.body.json().get())
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?,
|
||||
unsigned: Some(unsigned),
|
||||
state_key: None,
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
services().transaction_ids.add_txnid(
|
||||
sender_user,
|
||||
|
@ -124,14 +128,13 @@ pub async fn get_message_events_route(
|
|||
let to = body
|
||||
.to
|
||||
.as_ref()
|
||||
.and_then(|t| PduCount::try_from_string(&t).ok());
|
||||
.and_then(|t| PduCount::try_from_string(t).ok());
|
||||
|
||||
services().rooms.lazy_loading.lazy_load_confirm_delivery(
|
||||
sender_user,
|
||||
sender_device,
|
||||
&body.room_id,
|
||||
from,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.lazy_loading
|
||||
.lazy_load_confirm_delivery(sender_user, sender_device, &body.room_id, from)
|
||||
.await?;
|
||||
|
||||
let limit = u64::from(body.limit).min(100) as usize;
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use crate::{services, utils, Result, Ruma};
|
||||
use ruma::api::client::presence::{get_presence, set_presence};
|
||||
use crate::{services, utils, Error, Result, Ruma};
|
||||
use ruma::api::client::{
|
||||
error::ErrorKind,
|
||||
presence::{get_presence, set_presence},
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
/// # `PUT /_matrix/client/r0/presence/{userId}/status`
|
||||
|
@ -79,6 +82,9 @@ pub async fn get_presence_route(
|
|||
presence: presence.content.presence,
|
||||
})
|
||||
} else {
|
||||
todo!();
|
||||
Err(Error::BadRequest(
|
||||
ErrorKind::NotFound,
|
||||
"Presence state for this user was not found",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ pub async fn set_displayname_route(
|
|||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&RoomMemberEventContent {
|
||||
displayname: body.displayname.clone(),
|
||||
join_authorized_via_users_server: None,
|
||||
..serde_json::from_str(
|
||||
services()
|
||||
.rooms
|
||||
|
@ -77,18 +78,17 @@ pub async fn set_displayname_route(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
let _ = services().rooms.timeline.build_and_append_pdu(
|
||||
pdu_builder,
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
);
|
||||
let _ = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
|
||||
.await;
|
||||
|
||||
// Presence update
|
||||
services().rooms.edus.presence.update_presence(
|
||||
|
@ -175,6 +175,7 @@ pub async fn set_avatar_url_route(
|
|||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&RoomMemberEventContent {
|
||||
avatar_url: body.avatar_url.clone(),
|
||||
join_authorized_via_users_server: None,
|
||||
..serde_json::from_str(
|
||||
services()
|
||||
.rooms
|
||||
|
@ -212,18 +213,17 @@ pub async fn set_avatar_url_route(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
let _ = services().rooms.timeline.build_and_append_pdu(
|
||||
pdu_builder,
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
);
|
||||
let _ = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
|
||||
.await;
|
||||
|
||||
// Presence update
|
||||
services().rooms.edus.presence.update_presence(
|
||||
|
|
|
@ -24,28 +24,32 @@ pub async fn redact_event_route(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
let event_id = services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomRedaction,
|
||||
content: to_raw_value(&RoomRedactionEventContent {
|
||||
redacts: Some(body.event_id.clone()),
|
||||
reason: body.reason.clone(),
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: None,
|
||||
redacts: Some(body.event_id.into()),
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
let event_id = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomRedaction,
|
||||
content: to_raw_value(&RoomRedactionEventContent {
|
||||
redacts: Some(body.event_id.clone()),
|
||||
reason: body.reason.clone(),
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: None,
|
||||
redacts: Some(body.event_id.into()),
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
drop(state_lock);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ pub async fn get_relating_events_with_rel_type_and_event_type_route(
|
|||
let to = body
|
||||
.to
|
||||
.as_ref()
|
||||
.and_then(|t| PduCount::try_from_string(&t).ok());
|
||||
.and_then(|t| PduCount::try_from_string(t).ok());
|
||||
|
||||
// Use limit or else 10, with maximum 100
|
||||
let limit = body
|
||||
|
@ -73,7 +73,7 @@ pub async fn get_relating_events_with_rel_type_route(
|
|||
let to = body
|
||||
.to
|
||||
.as_ref()
|
||||
.and_then(|t| PduCount::try_from_string(&t).ok());
|
||||
.and_then(|t| PduCount::try_from_string(t).ok());
|
||||
|
||||
// Use limit or else 10, with maximum 100
|
||||
let limit = body
|
||||
|
@ -121,7 +121,7 @@ pub async fn get_relating_events_route(
|
|||
let to = body
|
||||
.to
|
||||
.as_ref()
|
||||
.and_then(|t| PduCount::try_from_string(&t).ok());
|
||||
.and_then(|t| PduCount::try_from_string(t).ok());
|
||||
|
||||
// Use limit or else 10, with maximum 100
|
||||
let limit = body
|
||||
|
|
|
@ -61,7 +61,7 @@ pub async fn create_room_route(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
|
@ -204,42 +204,50 @@ pub async fn create_room_route(
|
|||
}
|
||||
|
||||
// 1. The room create event
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomCreate,
|
||||
content: to_raw_value(&content).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomCreate,
|
||||
content: to_raw_value(&content).expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 2. Let the room creator join
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&RoomMemberEventContent {
|
||||
membership: MembershipState::Join,
|
||||
displayname: services().users.displayname(sender_user)?,
|
||||
avatar_url: services().users.avatar_url(sender_user)?,
|
||||
is_direct: Some(body.is_direct),
|
||||
third_party_invite: None,
|
||||
blurhash: services().users.blurhash(sender_user)?,
|
||||
reason: None,
|
||||
join_authorized_via_users_server: None,
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(sender_user.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_value(&RoomMemberEventContent {
|
||||
membership: MembershipState::Join,
|
||||
displayname: services().users.displayname(sender_user)?,
|
||||
avatar_url: services().users.avatar_url(sender_user)?,
|
||||
is_direct: Some(body.is_direct),
|
||||
third_party_invite: None,
|
||||
blurhash: services().users.blurhash(sender_user)?,
|
||||
reason: None,
|
||||
join_authorized_via_users_server: None,
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(sender_user.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 3. Power levels
|
||||
|
||||
|
@ -276,30 +284,14 @@ pub async fn create_room_route(
|
|||
}
|
||||
}
|
||||
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomPowerLevels,
|
||||
content: to_raw_value(&power_levels_content)
|
||||
.expect("to_raw_value always works on serde_json::Value"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
// 4. Canonical room alias
|
||||
if let Some(room_alias_id) = &alias {
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomCanonicalAlias,
|
||||
content: to_raw_value(&RoomCanonicalAliasEventContent {
|
||||
alias: Some(room_alias_id.to_owned()),
|
||||
alt_aliases: vec![],
|
||||
})
|
||||
.expect("We checked that alias earlier, it must be fine"),
|
||||
event_type: TimelineEventType::RoomPowerLevels,
|
||||
content: to_raw_value(&power_levels_content)
|
||||
.expect("to_raw_value always works on serde_json::Value"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
|
@ -307,64 +299,100 @@ pub async fn create_room_route(
|
|||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 4. Canonical room alias
|
||||
if let Some(room_alias_id) = &alias {
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomCanonicalAlias,
|
||||
content: to_raw_value(&RoomCanonicalAliasEventContent {
|
||||
alias: Some(room_alias_id.to_owned()),
|
||||
alt_aliases: vec![],
|
||||
})
|
||||
.expect("We checked that alias earlier, it must be fine"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
// 5. Events set by preset
|
||||
|
||||
// 5.1 Join Rules
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomJoinRules,
|
||||
content: to_raw_value(&RoomJoinRulesEventContent::new(match preset {
|
||||
RoomPreset::PublicChat => JoinRule::Public,
|
||||
// according to spec "invite" is the default
|
||||
_ => JoinRule::Invite,
|
||||
}))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomJoinRules,
|
||||
content: to_raw_value(&RoomJoinRulesEventContent::new(match preset {
|
||||
RoomPreset::PublicChat => JoinRule::Public,
|
||||
// according to spec "invite" is the default
|
||||
_ => JoinRule::Invite,
|
||||
}))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 5.2 History Visibility
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomHistoryVisibility,
|
||||
content: to_raw_value(&RoomHistoryVisibilityEventContent::new(
|
||||
HistoryVisibility::Shared,
|
||||
))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomHistoryVisibility,
|
||||
content: to_raw_value(&RoomHistoryVisibilityEventContent::new(
|
||||
HistoryVisibility::Shared,
|
||||
))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 5.3 Guest Access
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomGuestAccess,
|
||||
content: to_raw_value(&RoomGuestAccessEventContent::new(match preset {
|
||||
RoomPreset::PublicChat => GuestAccess::Forbidden,
|
||||
_ => GuestAccess::CanJoin,
|
||||
}))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomGuestAccess,
|
||||
content: to_raw_value(&RoomGuestAccessEventContent::new(match preset {
|
||||
RoomPreset::PublicChat => GuestAccess::Forbidden,
|
||||
_ => GuestAccess::CanJoin,
|
||||
}))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 6. Events listed in initial_state
|
||||
for event in &body.initial_state {
|
||||
|
@ -383,47 +411,54 @@ pub async fn create_room_route(
|
|||
continue;
|
||||
}
|
||||
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
pdu_builder,
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
|
||||
.await?;
|
||||
}
|
||||
|
||||
// 7. Events implied by name and topic
|
||||
if let Some(name) = &body.name {
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomName,
|
||||
content: to_raw_value(&RoomNameEventContent::new(Some(name.clone())))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomName,
|
||||
content: to_raw_value(&RoomNameEventContent::new(name.clone()))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(topic) = &body.topic {
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomTopic,
|
||||
content: to_raw_value(&RoomTopicEventContent {
|
||||
topic: topic.clone(),
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomTopic,
|
||||
content: to_raw_value(&RoomTopicEventContent {
|
||||
topic: topic.clone(),
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
// 8. Events implied by invite (and TODO: invite_3pid)
|
||||
|
@ -553,7 +588,7 @@ pub async fn upgrade_room_route(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(body.room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
|
@ -561,22 +596,26 @@ pub async fn upgrade_room_route(
|
|||
|
||||
// Send a m.room.tombstone event to the old room to indicate that it is not intended to be used any further
|
||||
// Fail if the sender does not have the required permissions
|
||||
let tombstone_event_id = services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomTombstone,
|
||||
content: to_raw_value(&RoomTombstoneEventContent {
|
||||
body: "This room has been replaced".to_owned(),
|
||||
replacement_room: replacement_room.clone(),
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
let tombstone_event_id = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomTombstone,
|
||||
content: to_raw_value(&RoomTombstoneEventContent {
|
||||
body: "This room has been replaced".to_owned(),
|
||||
replacement_room: replacement_room.clone(),
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Change lock to replacement room
|
||||
drop(state_lock);
|
||||
|
@ -585,7 +624,7 @@ pub async fn upgrade_room_route(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(replacement_room.clone())
|
||||
.or_default(),
|
||||
);
|
||||
|
@ -661,43 +700,51 @@ pub async fn upgrade_room_route(
|
|||
));
|
||||
}
|
||||
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomCreate,
|
||||
content: to_raw_value(&create_event_content)
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&replacement_room,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomCreate,
|
||||
content: to_raw_value(&create_event_content)
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some("".to_owned()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&replacement_room,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Join the new room
|
||||
services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_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: None,
|
||||
join_authorized_via_users_server: None,
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(sender_user.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&replacement_room,
|
||||
&state_lock,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: TimelineEventType::RoomMember,
|
||||
content: to_raw_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: None,
|
||||
join_authorized_via_users_server: None,
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
state_key: Some(sender_user.to_string()),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
&replacement_room,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Recommended transferable state events list from the specs
|
||||
let transferable_state_events = vec to see
|
||||
/// supported login types.
|
||||
pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Response> {
|
||||
// To allow deprecated login methods
|
||||
#![allow(deprecated)]
|
||||
// Validate login method
|
||||
// TODO: Other login methods
|
||||
let user_id = match &body.login_info {
|
||||
login::v3::LoginInfo::Password(login::v3::Password {
|
||||
identifier,
|
||||
password,
|
||||
user,
|
||||
address: _,
|
||||
medium: _,
|
||||
}) => {
|
||||
let username = if let UserIdentifier::UserIdOrLocalpart(user_id) = identifier {
|
||||
user_id.to_lowercase()
|
||||
let user_id = if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
|
||||
UserId::parse_with_server_name(
|
||||
user_id.to_lowercase(),
|
||||
services().globals.server_name(),
|
||||
)
|
||||
} else if let Some(user) = user {
|
||||
UserId::parse(user)
|
||||
} else {
|
||||
warn!("Bad login type: {:?}", &body.login_info);
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type."));
|
||||
};
|
||||
let user_id =
|
||||
UserId::parse_with_server_name(username, services().globals.server_name())
|
||||
.map_err(|_| {
|
||||
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
|
||||
})?;
|
||||
}
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?;
|
||||
|
||||
let hash = services()
|
||||
.users
|
||||
.password_hash(&user_id)?
|
||||
|
@ -105,24 +112,28 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
|
|||
));
|
||||
}
|
||||
}
|
||||
login::v3::LoginInfo::ApplicationService(login::v3::ApplicationService { identifier }) => {
|
||||
login::v3::LoginInfo::ApplicationService(login::v3::ApplicationService {
|
||||
identifier,
|
||||
user,
|
||||
}) => {
|
||||
if !body.from_appservice {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"Forbidden login type.",
|
||||
ErrorKind::MissingToken,
|
||||
"Missing appservice token.",
|
||||
));
|
||||
};
|
||||
let username = if let UserIdentifier::UserIdOrLocalpart(user_id) = identifier {
|
||||
user_id.to_lowercase()
|
||||
if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
|
||||
UserId::parse_with_server_name(
|
||||
user_id.to_lowercase(),
|
||||
services().globals.server_name(),
|
||||
)
|
||||
} else if let Some(user) = user {
|
||||
UserId::parse(user)
|
||||
} else {
|
||||
warn!("Bad login type: {:?}", &body.login_info);
|
||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type."));
|
||||
};
|
||||
let user_id =
|
||||
UserId::parse_with_server_name(username, services().globals.server_name())
|
||||
.map_err(|_| {
|
||||
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
|
||||
})?;
|
||||
user_id
|
||||
}
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?
|
||||
}
|
||||
_ => {
|
||||
warn!("Unsupported or unknown login type: {:?}", &body.login_info);
|
||||
|
@ -163,6 +174,8 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
|
|||
|
||||
info!("{} logged in", user_id);
|
||||
|
||||
// Homeservers are still required to send the `home_server` field
|
||||
#[allow(deprecated)]
|
||||
Ok(login::v3::Response {
|
||||
user_id,
|
||||
access_token: token,
|
||||
|
|
|
@ -85,7 +85,7 @@ pub async fn get_state_events_route(
|
|||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(&sender_user, &body.room_id)?
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
|
@ -118,7 +118,7 @@ pub async fn get_state_events_for_key_route(
|
|||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(&sender_user, &body.room_id)?
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
|
@ -157,7 +157,7 @@ pub async fn get_state_events_for_empty_key_route(
|
|||
if !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.user_can_see_state_events(&sender_user, &body.room_id)?
|
||||
.user_can_see_state_events(sender_user, &body.room_id)?
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
|
@ -227,24 +227,28 @@ async fn send_state_event_for_key_helper(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
let event_id = services().rooms.timeline.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: event_type.to_string().into(),
|
||||
content: serde_json::from_str(json.json().get()).expect("content is valid json"),
|
||||
unsigned: None,
|
||||
state_key: Some(state_key),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
room_id,
|
||||
&state_lock,
|
||||
)?;
|
||||
let event_id = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: event_type.to_string().into(),
|
||||
content: serde_json::from_str(json.json().get()).expect("content is valid json"),
|
||||
unsigned: None,
|
||||
state_key: Some(state_key),
|
||||
redacts: None,
|
||||
},
|
||||
sender_user,
|
||||
room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(event_id)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
service::rooms::timeline::PduCount, services, Error, PduEvent, Result, Ruma, RumaResponse,
|
||||
};
|
||||
|
||||
use ruma::{
|
||||
api::client::{
|
||||
filter::{FilterDefinition, LazyLoadOptions},
|
||||
|
@ -20,7 +21,7 @@ use ruma::{
|
|||
StateEventType, TimelineEventType,
|
||||
},
|
||||
serde::Raw,
|
||||
uint, DeviceId, OwnedDeviceId, OwnedUserId, RoomId, UInt, UserId,
|
||||
uint, DeviceId, JsOption, OwnedDeviceId, OwnedUserId, RoomId, UInt, UserId,
|
||||
};
|
||||
use std::{
|
||||
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet},
|
||||
|
@ -28,7 +29,7 @@ use std::{
|
|||
time::Duration,
|
||||
};
|
||||
use tokio::sync::watch::Sender;
|
||||
use tracing::error;
|
||||
use tracing::{error, info};
|
||||
|
||||
/// # `GET /_matrix/client/r0/sync`
|
||||
///
|
||||
|
@ -75,7 +76,7 @@ pub async fn sync_events_route(
|
|||
.globals
|
||||
.sync_receivers
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry((sender_user.clone(), sender_device.clone()))
|
||||
{
|
||||
Entry::Vacant(v) => {
|
||||
|
@ -98,6 +99,8 @@ pub async fn sync_events_route(
|
|||
|
||||
o.insert((body.since.clone(), rx.clone()));
|
||||
|
||||
info!("Sync started for {sender_user}");
|
||||
|
||||
tokio::spawn(sync_helper_wrapper(
|
||||
sender_user.clone(),
|
||||
sender_device.clone(),
|
||||
|
@ -147,7 +150,7 @@ async fn sync_helper_wrapper(
|
|||
.globals
|
||||
.sync_receivers
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry((sender_user, sender_device))
|
||||
{
|
||||
Entry::Occupied(o) => {
|
||||
|
@ -302,11 +305,11 @@ async fn sync_helper(
|
|||
.globals
|
||||
.roomid_mutex_insert
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let insert_lock = mutex_insert.lock().unwrap();
|
||||
let insert_lock = mutex_insert.lock().await;
|
||||
drop(insert_lock);
|
||||
}
|
||||
|
||||
|
@ -434,11 +437,11 @@ async fn sync_helper(
|
|||
.globals
|
||||
.roomid_mutex_insert
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.clone())
|
||||
.or_default(),
|
||||
);
|
||||
let insert_lock = mutex_insert.lock().unwrap();
|
||||
let insert_lock = mutex_insert.lock().await;
|
||||
drop(insert_lock);
|
||||
}
|
||||
|
||||
|
@ -554,6 +557,7 @@ async fn sync_helper(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn load_joined_room(
|
||||
sender_user: &UserId,
|
||||
sender_device: &DeviceId,
|
||||
|
@ -576,11 +580,11 @@ async fn load_joined_room(
|
|||
.globals
|
||||
.roomid_mutex_insert
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
let insert_lock = mutex_insert.lock().unwrap();
|
||||
let insert_lock = mutex_insert.lock().await;
|
||||
drop(insert_lock);
|
||||
}
|
||||
|
||||
|
@ -590,7 +594,7 @@ async fn load_joined_room(
|
|||
|| services()
|
||||
.rooms
|
||||
.user
|
||||
.last_notification_read(&sender_user, &room_id)?
|
||||
.last_notification_read(sender_user, room_id)?
|
||||
> since;
|
||||
|
||||
let mut timeline_users = HashSet::new();
|
||||
|
@ -598,17 +602,16 @@ async fn load_joined_room(
|
|||
timeline_users.insert(event.sender.as_str().to_owned());
|
||||
}
|
||||
|
||||
services().rooms.lazy_loading.lazy_load_confirm_delivery(
|
||||
&sender_user,
|
||||
&sender_device,
|
||||
&room_id,
|
||||
sincecount,
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.lazy_loading
|
||||
.lazy_load_confirm_delivery(sender_user, sender_device, room_id, sincecount)
|
||||
.await?;
|
||||
|
||||
// Database queries:
|
||||
|
||||
let current_shortstatehash =
|
||||
if let Some(s) = services().rooms.state.get_room_shortstatehash(&room_id)? {
|
||||
if let Some(s) = services().rooms.state.get_room_shortstatehash(room_id)? {
|
||||
s
|
||||
} else {
|
||||
error!("Room {} has no state", room_id);
|
||||
|
@ -618,7 +621,7 @@ async fn load_joined_room(
|
|||
let since_shortstatehash = services()
|
||||
.rooms
|
||||
.user
|
||||
.get_token_shortstatehash(&room_id, since)?;
|
||||
.get_token_shortstatehash(room_id, since)?;
|
||||
|
||||
let (heroes, joined_member_count, invited_member_count, joined_since_last_sync, state_events) =
|
||||
if timeline_pdus.is_empty() && since_shortstatehash == Some(current_shortstatehash) {
|
||||
|
@ -630,12 +633,12 @@ async fn load_joined_room(
|
|||
let joined_member_count = services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_joined_count(&room_id)?
|
||||
.room_joined_count(room_id)?
|
||||
.unwrap_or(0);
|
||||
let invited_member_count = services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_invited_count(&room_id)?
|
||||
.room_invited_count(room_id)?
|
||||
.unwrap_or(0);
|
||||
|
||||
// Recalculate heroes (first 5 members)
|
||||
|
@ -648,7 +651,7 @@ async fn load_joined_room(
|
|||
for hero in services()
|
||||
.rooms
|
||||
.timeline
|
||||
.all_pdus(&sender_user, &room_id)?
|
||||
.all_pdus(sender_user, room_id)?
|
||||
.filter_map(|pdu| pdu.ok()) // Ignore all broken pdus
|
||||
.filter(|(_, pdu)| pdu.kind == TimelineEventType::RoomMember)
|
||||
.map(|(_, pdu)| {
|
||||
|
@ -669,11 +672,11 @@ async fn load_joined_room(
|
|||
) && (services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.is_joined(&user_id, &room_id)?
|
||||
.is_joined(&user_id, room_id)?
|
||||
|| services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.is_invited(&user_id, &room_id)?)
|
||||
.is_invited(&user_id, room_id)?)
|
||||
{
|
||||
Ok::<_, Error>(Some(state_key.clone()))
|
||||
} else {
|
||||
|
@ -789,20 +792,24 @@ async fn load_joined_room(
|
|||
|
||||
// Reset lazy loading because this is an initial sync
|
||||
services().rooms.lazy_loading.lazy_load_reset(
|
||||
&sender_user,
|
||||
&sender_device,
|
||||
&room_id,
|
||||
sender_user,
|
||||
sender_device,
|
||||
room_id,
|
||||
)?;
|
||||
|
||||
// The state_events above should contain all timeline_users, let's mark them as lazy
|
||||
// loaded.
|
||||
services().rooms.lazy_loading.lazy_load_mark_sent(
|
||||
&sender_user,
|
||||
&sender_device,
|
||||
&room_id,
|
||||
lazy_loaded,
|
||||
next_batchcount,
|
||||
);
|
||||
services()
|
||||
.rooms
|
||||
.lazy_loading
|
||||
.lazy_load_mark_sent(
|
||||
sender_user,
|
||||
sender_device,
|
||||
room_id,
|
||||
lazy_loaded,
|
||||
next_batchcount,
|
||||
)
|
||||
.await;
|
||||
|
||||
(
|
||||
heroes,
|
||||
|
@ -866,14 +873,14 @@ async fn load_joined_room(
|
|||
}
|
||||
|
||||
if !services().rooms.lazy_loading.lazy_load_was_sent_before(
|
||||
&sender_user,
|
||||
&sender_device,
|
||||
&room_id,
|
||||
sender_user,
|
||||
sender_device,
|
||||
room_id,
|
||||
&event.sender,
|
||||
)? || lazy_load_send_redundant
|
||||
{
|
||||
if let Some(member_event) = services().rooms.state_accessor.room_state_get(
|
||||
&room_id,
|
||||
room_id,
|
||||
&StateEventType::RoomMember,
|
||||
event.sender.as_str(),
|
||||
)? {
|
||||
|
@ -883,13 +890,17 @@ async fn load_joined_room(
|
|||
}
|
||||
}
|
||||
|
||||
services().rooms.lazy_loading.lazy_load_mark_sent(
|
||||
&sender_user,
|
||||
&sender_device,
|
||||
&room_id,
|
||||
lazy_loaded,
|
||||
next_batchcount,
|
||||
);
|
||||
services()
|
||||
.rooms
|
||||
.lazy_loading
|
||||
.lazy_load_mark_sent(
|
||||
sender_user,
|
||||
sender_device,
|
||||
room_id,
|
||||
lazy_loaded,
|
||||
next_batchcount,
|
||||
)
|
||||
.await;
|
||||
|
||||
let encrypted_room = services()
|
||||
.rooms
|
||||
|
@ -934,7 +945,7 @@ async fn load_joined_room(
|
|||
match new_membership {
|
||||
MembershipState::Join => {
|
||||
// A new user joined an encrypted room
|
||||
if !share_encrypted_room(&sender_user, &user_id, &room_id)? {
|
||||
if !share_encrypted_room(sender_user, &user_id, room_id)? {
|
||||
device_list_updates.insert(user_id);
|
||||
}
|
||||
}
|
||||
|
@ -954,15 +965,15 @@ async fn load_joined_room(
|
|||
services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_members(&room_id)
|
||||
.room_members(room_id)
|
||||
.flatten()
|
||||
.filter(|user_id| {
|
||||
// Don't send key updates from the sender to the sender
|
||||
&sender_user != user_id
|
||||
sender_user != user_id
|
||||
})
|
||||
.filter(|user_id| {
|
||||
// Only send keys if the sender doesn't share an encrypted room with the target already
|
||||
!share_encrypted_room(&sender_user, user_id, &room_id)
|
||||
!share_encrypted_room(sender_user, user_id, room_id)
|
||||
.unwrap_or(false)
|
||||
}),
|
||||
);
|
||||
|
@ -997,7 +1008,7 @@ async fn load_joined_room(
|
|||
services()
|
||||
.rooms
|
||||
.user
|
||||
.notification_count(&sender_user, &room_id)?
|
||||
.notification_count(sender_user, room_id)?
|
||||
.try_into()
|
||||
.expect("notification count can't go that high"),
|
||||
)
|
||||
|
@ -1010,7 +1021,7 @@ async fn load_joined_room(
|
|||
services()
|
||||
.rooms
|
||||
.user
|
||||
.highlight_count(&sender_user, &room_id)?
|
||||
.highlight_count(sender_user, room_id)?
|
||||
.try_into()
|
||||
.expect("highlight count can't go that high"),
|
||||
)
|
||||
|
@ -1039,15 +1050,22 @@ async fn load_joined_room(
|
|||
.rooms
|
||||
.edus
|
||||
.read_receipt
|
||||
.readreceipts_since(&room_id, since)
|
||||
.readreceipts_since(room_id, since)
|
||||
.filter_map(|r| r.ok()) // Filter out buggy events
|
||||
.map(|(_, _, v)| v)
|
||||
.collect();
|
||||
|
||||
if services().rooms.edus.typing.last_typing_update(&room_id)? > since {
|
||||
if services()
|
||||
.rooms
|
||||
.edus
|
||||
.typing
|
||||
.last_typing_update(room_id)
|
||||
.await?
|
||||
> since
|
||||
{
|
||||
edus.push(
|
||||
serde_json::from_str(
|
||||
&serde_json::to_string(&services().rooms.edus.typing.typings_all(&room_id)?)
|
||||
&serde_json::to_string(&services().rooms.edus.typing.typings_all(room_id).await?)
|
||||
.expect("event is valid, we just created it"),
|
||||
)
|
||||
.expect("event is valid, we just created it"),
|
||||
|
@ -1056,7 +1074,7 @@ async fn load_joined_room(
|
|||
|
||||
// Save the state after this sync so we can send the correct state diff next sync
|
||||
services().rooms.user.associate_token_shortstatehash(
|
||||
&room_id,
|
||||
room_id,
|
||||
next_batch,
|
||||
current_shortstatehash,
|
||||
)?;
|
||||
|
@ -1065,7 +1083,7 @@ async fn load_joined_room(
|
|||
account_data: RoomAccountData {
|
||||
events: services()
|
||||
.account_data
|
||||
.changes_since(Some(&room_id), &sender_user, since)?
|
||||
.changes_since(Some(room_id), sender_user, since)?
|
||||
.into_iter()
|
||||
.filter_map(|(_, v)| {
|
||||
serde_json::from_str(v.json().get())
|
||||
|
@ -1110,13 +1128,13 @@ fn load_timeline(
|
|||
if services()
|
||||
.rooms
|
||||
.timeline
|
||||
.last_timeline_count(&sender_user, &room_id)?
|
||||
.last_timeline_count(sender_user, room_id)?
|
||||
> roomsincecount
|
||||
{
|
||||
let mut non_timeline_pdus = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.pdus_until(&sender_user, &room_id, PduCount::max())?
|
||||
.pdus_until(sender_user, room_id, PduCount::max())?
|
||||
.filter_map(|r| {
|
||||
// Filter out buggy events
|
||||
if r.is_err() {
|
||||
|
@ -1172,7 +1190,6 @@ fn share_encrypted_room(
|
|||
pub async fn sync_events_v4_route(
|
||||
body: Ruma<sync_events::v4::Request>,
|
||||
) -> Result<sync_events::v4::Response, RumaResponse<UiaaResponse>> {
|
||||
dbg!(&body.body);
|
||||
let sender_user = body.sender_user.expect("user is authenticated");
|
||||
let sender_device = body.sender_device.expect("user is authenticated");
|
||||
let mut body = body.body;
|
||||
|
@ -1232,7 +1249,7 @@ 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)? {
|
||||
if let Some(s) = services().rooms.state.get_room_shortstatehash(room_id)? {
|
||||
s
|
||||
} else {
|
||||
error!("Room {} has no state", room_id);
|
||||
|
@ -1242,7 +1259,7 @@ pub async fn sync_events_v4_route(
|
|||
let since_shortstatehash = services()
|
||||
.rooms
|
||||
.user
|
||||
.get_token_shortstatehash(&room_id, globalsince)?;
|
||||
.get_token_shortstatehash(room_id, globalsince)?;
|
||||
|
||||
let since_sender_member: Option<RoomMemberEventContent> = since_shortstatehash
|
||||
.and_then(|shortstatehash| {
|
||||
|
@ -1331,7 +1348,7 @@ pub async fn sync_events_v4_route(
|
|||
if !share_encrypted_room(
|
||||
&sender_user,
|
||||
&user_id,
|
||||
&room_id,
|
||||
room_id,
|
||||
)? {
|
||||
device_list_changes.insert(user_id);
|
||||
}
|
||||
|
@ -1352,7 +1369,7 @@ pub async fn sync_events_v4_route(
|
|||
services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_members(&room_id)
|
||||
.room_members(room_id)
|
||||
.flatten()
|
||||
.filter(|user_id| {
|
||||
// Don't send key updates from the sender to the sender
|
||||
|
@ -1360,7 +1377,7 @@ pub async fn sync_events_v4_route(
|
|||
})
|
||||
.filter(|user_id| {
|
||||
// Only send keys if the sender doesn't share an encrypted room with the target already
|
||||
!share_encrypted_room(&sender_user, user_id, &room_id)
|
||||
!share_encrypted_room(&sender_user, user_id, room_id)
|
||||
.unwrap_or(false)
|
||||
}),
|
||||
);
|
||||
|
@ -1451,7 +1468,7 @@ pub async fn sync_events_v4_route(
|
|||
}
|
||||
sync_events::v4::SyncOp {
|
||||
op: SlidingOp::Sync,
|
||||
range: Some(r.clone()),
|
||||
range: Some(r),
|
||||
index: None,
|
||||
room_ids,
|
||||
room_id: None,
|
||||
|
@ -1476,6 +1493,9 @@ pub async fn sync_events_v4_route(
|
|||
|
||||
let mut known_subscription_rooms = BTreeSet::new();
|
||||
for (room_id, room) in &body.room_subscriptions {
|
||||
if !services().rooms.metadata.exists(room_id)? {
|
||||
continue;
|
||||
}
|
||||
let todo_room = todo_rooms
|
||||
.entry(room_id.clone())
|
||||
.or_insert((BTreeSet::new(), 0, u64::MAX));
|
||||
|
@ -1523,7 +1543,7 @@ pub async fn sync_events_v4_route(
|
|||
let roomsincecount = PduCount::Normal(*roomsince);
|
||||
|
||||
let (timeline_pdus, limited) =
|
||||
load_timeline(&sender_user, &room_id, roomsincecount, *timeline_limit)?;
|
||||
load_timeline(&sender_user, room_id, roomsincecount, *timeline_limit)?;
|
||||
|
||||
if roomsince != &0 && timeline_pdus.is_empty() {
|
||||
continue;
|
||||
|
@ -1555,63 +1575,58 @@ pub async fn sync_events_v4_route(
|
|||
|
||||
let required_state = required_state_request
|
||||
.iter()
|
||||
.map(|state| {
|
||||
.flat_map(|state| {
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(&room_id, &state.0, &state.1)
|
||||
.room_state_get(room_id, &state.0, &state.1)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|state| state.to_sync_state_event())
|
||||
})
|
||||
.filter_map(|r| r.ok())
|
||||
.filter_map(|o| o)
|
||||
.map(|state| state.to_sync_state_event())
|
||||
.collect();
|
||||
|
||||
// Heroes
|
||||
let heroes = services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_members(&room_id)
|
||||
.room_members(room_id)
|
||||
.filter_map(|r| r.ok())
|
||||
.filter(|member| member != &sender_user)
|
||||
.map(|member| {
|
||||
Ok::<_, Error>(
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_member(&room_id, &member)?
|
||||
.map(|memberevent| {
|
||||
(
|
||||
memberevent
|
||||
.displayname
|
||||
.unwrap_or_else(|| member.to_string()),
|
||||
memberevent.avatar_url,
|
||||
)
|
||||
}),
|
||||
)
|
||||
.flat_map(|member| {
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_member(room_id, &member)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|memberevent| {
|
||||
(
|
||||
memberevent
|
||||
.displayname
|
||||
.unwrap_or_else(|| member.to_string()),
|
||||
memberevent.avatar_url,
|
||||
)
|
||||
})
|
||||
})
|
||||
.filter_map(|r| r.ok())
|
||||
.filter_map(|o| o)
|
||||
.take(5)
|
||||
.collect::<Vec<_>>();
|
||||
let name = if heroes.len() > 1 {
|
||||
let last = heroes[0].0.clone();
|
||||
Some(
|
||||
heroes[1..]
|
||||
let name = match &heroes[..] {
|
||||
[] => None,
|
||||
[only] => Some(only.0.clone()),
|
||||
[firsts @ .., last] => Some(
|
||||
firsts
|
||||
.iter()
|
||||
.map(|h| h.0.clone())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
+ " and "
|
||||
+ &last,
|
||||
)
|
||||
} else if heroes.len() == 1 {
|
||||
Some(heroes[0].0.clone())
|
||||
} else {
|
||||
None
|
||||
+ &last.0,
|
||||
),
|
||||
};
|
||||
|
||||
let avatar = if heroes.len() == 1 {
|
||||
heroes[0].1.clone()
|
||||
let avatar = if let [only] = &heroes[..] {
|
||||
only.1.clone()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -1619,16 +1634,16 @@ pub async fn sync_events_v4_route(
|
|||
rooms.insert(
|
||||
room_id.clone(),
|
||||
sync_events::v4::SlidingSyncRoom {
|
||||
name: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_name(&room_id)?
|
||||
.or_else(|| name),
|
||||
avatar: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_avatar(&room_id)?
|
||||
.map_or(avatar, |a| a.url),
|
||||
name: services().rooms.state_accessor.get_name(room_id)?.or(name),
|
||||
avatar: if let Some(avatar) = avatar {
|
||||
JsOption::Some(avatar)
|
||||
} else {
|
||||
match services().rooms.state_accessor.get_avatar(room_id)? {
|
||||
JsOption::Some(avatar) => JsOption::from_option(avatar.url),
|
||||
JsOption::Null => JsOption::Null,
|
||||
JsOption::Undefined => JsOption::Undefined,
|
||||
}
|
||||
},
|
||||
initial: Some(roomsince == &0),
|
||||
is_dm: None,
|
||||
invite_state: None,
|
||||
|
@ -1637,7 +1652,7 @@ pub async fn sync_events_v4_route(
|
|||
services()
|
||||
.rooms
|
||||
.user
|
||||
.highlight_count(&sender_user, &room_id)?
|
||||
.highlight_count(&sender_user, room_id)?
|
||||
.try_into()
|
||||
.expect("notification count can't go that high"),
|
||||
),
|
||||
|
@ -1645,7 +1660,7 @@ pub async fn sync_events_v4_route(
|
|||
services()
|
||||
.rooms
|
||||
.user
|
||||
.notification_count(&sender_user, &room_id)?
|
||||
.notification_count(&sender_user, room_id)?
|
||||
.try_into()
|
||||
.expect("notification count can't go that high"),
|
||||
),
|
||||
|
@ -1658,7 +1673,7 @@ pub async fn sync_events_v4_route(
|
|||
(services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_joined_count(&room_id)?
|
||||
.room_joined_count(room_id)?
|
||||
.unwrap_or(0) as u32)
|
||||
.into(),
|
||||
),
|
||||
|
@ -1666,7 +1681,7 @@ pub async fn sync_events_v4_route(
|
|||
(services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_invited_count(&room_id)?
|
||||
.room_invited_count(room_id)?
|
||||
.unwrap_or(0) as u32)
|
||||
.into(),
|
||||
),
|
||||
|
@ -1689,7 +1704,7 @@ pub async fn sync_events_v4_route(
|
|||
let _ = tokio::time::timeout(duration, watcher).await;
|
||||
}
|
||||
|
||||
Ok(dbg!(sync_events::v4::Response {
|
||||
Ok(sync_events::v4::Response {
|
||||
initial: globalsince == 0,
|
||||
txn_id: body.txn_id.clone(),
|
||||
pos: next_batch.to_string(),
|
||||
|
@ -1744,5 +1759,5 @@ pub async fn sync_events_v4_route(
|
|||
},
|
||||
},
|
||||
delta_token: None,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -23,17 +23,23 @@ pub async fn create_typing_event_route(
|
|||
}
|
||||
|
||||
if let Typing::Yes(duration) = body.state {
|
||||
services().rooms.edus.typing.typing_add(
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
duration.as_millis() as u64 + utils::millis_since_unix_epoch(),
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.edus
|
||||
.typing
|
||||
.typing_add(
|
||||
sender_user,
|
||||
&body.room_id,
|
||||
duration.as_millis() as u64 + utils::millis_since_unix_epoch(),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
services()
|
||||
.rooms
|
||||
.edus
|
||||
.typing
|
||||
.typing_remove(sender_user, &body.room_id)?;
|
||||
.typing_remove(sender_user, &body.room_id)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(create_typing_event::v3::Response {})
|
||||
|
|
|
@ -26,6 +26,7 @@ pub async fn get_supported_versions_route(
|
|||
"v1.2".to_owned(),
|
||||
"v1.3".to_owned(),
|
||||
"v1.4".to_owned(),
|
||||
"v1.5".to_owned(),
|
||||
],
|
||||
unstable_features: BTreeMap::from_iter([("org.matrix.e2e_cross_signing".to_owned(), true)]),
|
||||
};
|
||||
|
|
|
@ -48,6 +48,9 @@ pub async fn search_users_route(
|
|||
return None;
|
||||
}
|
||||
|
||||
// It's a matching user, but is the sender allowed to see them?
|
||||
let mut user_visible = false;
|
||||
|
||||
let user_is_in_public_rooms = services()
|
||||
.rooms
|
||||
.state_cache
|
||||
|
@ -69,22 +72,26 @@ pub async fn search_users_route(
|
|||
});
|
||||
|
||||
if user_is_in_public_rooms {
|
||||
return Some(user);
|
||||
user_visible = true;
|
||||
} else {
|
||||
let user_is_in_shared_rooms = services()
|
||||
.rooms
|
||||
.user
|
||||
.get_shared_rooms(vec![sender_user.clone(), user_id])
|
||||
.ok()?
|
||||
.next()
|
||||
.is_some();
|
||||
|
||||
if user_is_in_shared_rooms {
|
||||
user_visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
let user_is_in_shared_rooms = services()
|
||||
.rooms
|
||||
.user
|
||||
.get_shared_rooms(vec![sender_user.clone(), user_id])
|
||||
.ok()?
|
||||
.next()
|
||||
.is_some();
|
||||
|
||||
if user_is_in_shared_rooms {
|
||||
return Some(user);
|
||||
if !user_visible {
|
||||
return None;
|
||||
}
|
||||
|
||||
None
|
||||
Some(user)
|
||||
});
|
||||
|
||||
let results = users.by_ref().take(limit).collect();
|
||||
|
|
|
@ -15,13 +15,20 @@ use bytes::{Buf, BufMut, Bytes, BytesMut};
|
|||
use http::{Request, StatusCode};
|
||||
use ruma::{
|
||||
api::{client::error::ErrorKind, AuthScheme, IncomingRequest, OutgoingResponse},
|
||||
CanonicalJsonValue, OwnedDeviceId, OwnedServerName, UserId,
|
||||
CanonicalJsonValue, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use tracing::{debug, error, warn};
|
||||
|
||||
use super::{Ruma, RumaResponse};
|
||||
use crate::{services, Error, Result};
|
||||
use crate::{service::appservice::RegistrationInfo, services, Error, Result};
|
||||
|
||||
enum Token {
|
||||
Appservice(Box<RegistrationInfo>),
|
||||
User((OwnedUserId, OwnedDeviceId)),
|
||||
Invalid,
|
||||
None,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T, S, B> FromRequest<S, B> for Ruma<T>
|
||||
|
@ -78,179 +85,192 @@ where
|
|||
None => query_params.access_token.as_deref(),
|
||||
};
|
||||
|
||||
let token = if let Some(token) = token {
|
||||
if let Some(reg_info) = services().appservice.find_from_token(token).await {
|
||||
Token::Appservice(Box::new(reg_info.clone()))
|
||||
} else if let Some((user_id, device_id)) = services().users.find_from_token(token)? {
|
||||
Token::User((user_id, OwnedDeviceId::from(device_id)))
|
||||
} else {
|
||||
Token::Invalid
|
||||
}
|
||||
} else {
|
||||
Token::None
|
||||
};
|
||||
|
||||
let mut json_body = serde_json::from_slice::<CanonicalJsonValue>(&body).ok();
|
||||
|
||||
let appservices = services().appservice.all().unwrap();
|
||||
let appservice_registration = appservices.iter().find(|(_id, registration)| {
|
||||
registration
|
||||
.get("as_token")
|
||||
.and_then(|as_token| as_token.as_str())
|
||||
.map_or(false, |as_token| token == Some(as_token))
|
||||
});
|
||||
|
||||
let (sender_user, sender_device, sender_servername, from_appservice) =
|
||||
if let Some((_id, registration)) = appservice_registration {
|
||||
match metadata.authentication {
|
||||
AuthScheme::AccessToken => {
|
||||
let user_id = query_params.user_id.map_or_else(
|
||||
match (metadata.authentication, token) {
|
||||
(_, Token::Invalid) => {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::UnknownToken { soft_logout: false },
|
||||
"Unknown access token.",
|
||||
))
|
||||
}
|
||||
(
|
||||
AuthScheme::AccessToken
|
||||
| AuthScheme::AppserviceToken
|
||||
| AuthScheme::AccessTokenOptional
|
||||
| AuthScheme::None,
|
||||
Token::Appservice(info),
|
||||
) => {
|
||||
let user_id = query_params
|
||||
.user_id
|
||||
.map_or_else(
|
||||
|| {
|
||||
UserId::parse_with_server_name(
|
||||
registration
|
||||
.get("sender_localpart")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap(),
|
||||
info.registration.sender_localpart.as_str(),
|
||||
services().globals.server_name(),
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
|s| UserId::parse(s).unwrap(),
|
||||
);
|
||||
UserId::parse,
|
||||
)
|
||||
.map_err(|_| {
|
||||
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
|
||||
})?;
|
||||
if !services().users.exists(&user_id)? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"User does not exist.",
|
||||
));
|
||||
}
|
||||
|
||||
if !services().users.exists(&user_id).unwrap() {
|
||||
// TODO: Check if appservice is allowed to be that user
|
||||
(Some(user_id), None, None, true)
|
||||
}
|
||||
(AuthScheme::AccessToken, Token::None) => {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::MissingToken,
|
||||
"Missing access token.",
|
||||
));
|
||||
}
|
||||
(
|
||||
AuthScheme::AccessToken | AuthScheme::AccessTokenOptional | AuthScheme::None,
|
||||
Token::User((user_id, device_id)),
|
||||
) => (Some(user_id), Some(device_id), None, false),
|
||||
(AuthScheme::ServerSignatures, Token::None) => {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let TypedHeader(Authorization(x_matrix)) = parts
|
||||
.extract::<TypedHeader<Authorization<XMatrix>>>()
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Missing or invalid Authorization header: {}", e);
|
||||
|
||||
let msg = match e.reason() {
|
||||
TypedHeaderRejectionReason::Missing => {
|
||||
"Missing Authorization header."
|
||||
}
|
||||
TypedHeaderRejectionReason::Error(_) => {
|
||||
"Invalid X-Matrix signatures."
|
||||
}
|
||||
_ => "Unknown header-related error",
|
||||
};
|
||||
|
||||
Error::BadRequest(ErrorKind::Forbidden, msg)
|
||||
})?;
|
||||
|
||||
let origin_signatures = BTreeMap::from_iter([(
|
||||
x_matrix.key.clone(),
|
||||
CanonicalJsonValue::String(x_matrix.sig),
|
||||
)]);
|
||||
|
||||
let signatures = BTreeMap::from_iter([(
|
||||
x_matrix.origin.as_str().to_owned(),
|
||||
CanonicalJsonValue::Object(origin_signatures),
|
||||
)]);
|
||||
|
||||
let mut request_map = BTreeMap::from_iter([
|
||||
(
|
||||
"method".to_owned(),
|
||||
CanonicalJsonValue::String(parts.method.to_string()),
|
||||
),
|
||||
(
|
||||
"uri".to_owned(),
|
||||
CanonicalJsonValue::String(parts.uri.to_string()),
|
||||
),
|
||||
(
|
||||
"origin".to_owned(),
|
||||
CanonicalJsonValue::String(x_matrix.origin.as_str().to_owned()),
|
||||
),
|
||||
(
|
||||
"destination".to_owned(),
|
||||
CanonicalJsonValue::String(
|
||||
services().globals.server_name().as_str().to_owned(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"signatures".to_owned(),
|
||||
CanonicalJsonValue::Object(signatures),
|
||||
),
|
||||
]);
|
||||
|
||||
if let Some(json_body) = &json_body {
|
||||
request_map.insert("content".to_owned(), json_body.clone());
|
||||
};
|
||||
|
||||
let keys_result = services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.fetch_signing_keys(&x_matrix.origin, vec![x_matrix.key.to_owned()])
|
||||
.await;
|
||||
|
||||
let keys = match keys_result {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
warn!("Failed to fetch signing keys: {}", e);
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"User does not exist.",
|
||||
"Failed to fetch signing keys.",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Check if appservice is allowed to be that user
|
||||
(Some(user_id), None, None, true)
|
||||
}
|
||||
AuthScheme::ServerSignatures => (None, None, None, true),
|
||||
AuthScheme::None => (None, None, None, true),
|
||||
}
|
||||
} else {
|
||||
match metadata.authentication {
|
||||
AuthScheme::AccessToken => {
|
||||
let token = match token {
|
||||
Some(token) => token,
|
||||
_ => {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::MissingToken,
|
||||
"Missing access token.",
|
||||
))
|
||||
}
|
||||
};
|
||||
let pub_key_map =
|
||||
BTreeMap::from_iter([(x_matrix.origin.as_str().to_owned(), keys)]);
|
||||
|
||||
match services().users.find_from_token(token).unwrap() {
|
||||
None => {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::UnknownToken { soft_logout: false },
|
||||
"Unknown access token.",
|
||||
))
|
||||
}
|
||||
Some((user_id, device_id)) => (
|
||||
Some(user_id),
|
||||
Some(OwnedDeviceId::from(device_id)),
|
||||
None,
|
||||
false,
|
||||
),
|
||||
}
|
||||
}
|
||||
AuthScheme::ServerSignatures => {
|
||||
let TypedHeader(Authorization(x_matrix)) = parts
|
||||
.extract::<TypedHeader<Authorization<XMatrix>>>()
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Missing or invalid Authorization header: {}", e);
|
||||
match ruma::signatures::verify_json(&pub_key_map, &request_map) {
|
||||
Ok(()) => (None, None, Some(x_matrix.origin), false),
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Failed to verify json request from {}: {}\n{:?}",
|
||||
x_matrix.origin, e, request_map
|
||||
);
|
||||
|
||||
let msg = match e.reason() {
|
||||
TypedHeaderRejectionReason::Missing => {
|
||||
"Missing Authorization header."
|
||||
}
|
||||
TypedHeaderRejectionReason::Error(_) => {
|
||||
"Invalid X-Matrix signatures."
|
||||
}
|
||||
_ => "Unknown header-related error",
|
||||
};
|
||||
|
||||
Error::BadRequest(ErrorKind::Forbidden, msg)
|
||||
})?;
|
||||
|
||||
let origin_signatures = BTreeMap::from_iter([(
|
||||
x_matrix.key.clone(),
|
||||
CanonicalJsonValue::String(x_matrix.sig),
|
||||
)]);
|
||||
|
||||
let signatures = BTreeMap::from_iter([(
|
||||
x_matrix.origin.as_str().to_owned(),
|
||||
CanonicalJsonValue::Object(origin_signatures),
|
||||
)]);
|
||||
|
||||
let mut request_map = BTreeMap::from_iter([
|
||||
(
|
||||
"method".to_owned(),
|
||||
CanonicalJsonValue::String(parts.method.to_string()),
|
||||
),
|
||||
(
|
||||
"uri".to_owned(),
|
||||
CanonicalJsonValue::String(parts.uri.to_string()),
|
||||
),
|
||||
(
|
||||
"origin".to_owned(),
|
||||
CanonicalJsonValue::String(x_matrix.origin.as_str().to_owned()),
|
||||
),
|
||||
(
|
||||
"destination".to_owned(),
|
||||
CanonicalJsonValue::String(
|
||||
services().globals.server_name().as_str().to_owned(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"signatures".to_owned(),
|
||||
CanonicalJsonValue::Object(signatures),
|
||||
),
|
||||
]);
|
||||
|
||||
if let Some(json_body) = &json_body {
|
||||
request_map.insert("content".to_owned(), json_body.clone());
|
||||
};
|
||||
|
||||
let keys_result = services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.fetch_signing_keys(&x_matrix.origin, vec![x_matrix.key.to_owned()])
|
||||
.await;
|
||||
|
||||
let keys = match keys_result {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
warn!("Failed to fetch signing keys: {}", e);
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"Failed to fetch signing keys.",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let pub_key_map =
|
||||
BTreeMap::from_iter([(x_matrix.origin.as_str().to_owned(), keys)]);
|
||||
|
||||
match ruma::signatures::verify_json(&pub_key_map, &request_map) {
|
||||
Ok(()) => (None, None, Some(x_matrix.origin), false),
|
||||
Err(e) => {
|
||||
if parts.uri.to_string().contains('@') {
|
||||
warn!(
|
||||
"Failed to verify json request from {}: {}\n{:?}",
|
||||
x_matrix.origin, e, request_map
|
||||
);
|
||||
|
||||
if parts.uri.to_string().contains('@') {
|
||||
warn!(
|
||||
"Request uri contained '@' character. Make sure your \
|
||||
"Request uri contained '@' character. Make sure your \
|
||||
reverse proxy gives Conduit the raw uri (apache: use \
|
||||
nocanon)"
|
||||
);
|
||||
}
|
||||
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"Failed to verify X-Matrix signatures.",
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"Failed to verify X-Matrix signatures.",
|
||||
));
|
||||
}
|
||||
}
|
||||
AuthScheme::None => (None, None, None, false),
|
||||
}
|
||||
(
|
||||
AuthScheme::None
|
||||
| AuthScheme::AppserviceToken
|
||||
| AuthScheme::AccessTokenOptional,
|
||||
Token::None,
|
||||
) => (None, None, None, false),
|
||||
(AuthScheme::ServerSignatures, Token::Appservice(_) | Token::User(_)) => {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Unauthorized,
|
||||
"Only server signatures should be used on this endpoint.",
|
||||
));
|
||||
}
|
||||
(AuthScheme::AppserviceToken, Token::User(_)) => {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Unauthorized,
|
||||
"Only appservice access tokens should be used on this endpoint.",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -51,11 +51,12 @@ use std::{
|
|||
fmt::Debug,
|
||||
mem,
|
||||
net::{IpAddr, SocketAddr},
|
||||
sync::{Arc, RwLock},
|
||||
sync::Arc,
|
||||
time::{Duration, Instant, SystemTime},
|
||||
};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use tracing::{debug, error, trace, warn};
|
||||
use tracing::{debug, error, warn};
|
||||
|
||||
/// Wraps either an literal IP address plus port, or a hostname plus complement
|
||||
/// (colon-plus-port if it was specified).
|
||||
|
@ -137,7 +138,7 @@ where
|
|||
.globals
|
||||
.actual_destination_cache
|
||||
.read()
|
||||
.unwrap()
|
||||
.await
|
||||
.get(destination)
|
||||
.cloned();
|
||||
|
||||
|
@ -232,8 +233,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let reqwest_request = reqwest::Request::try_from(http_request)
|
||||
.expect("all http requests are valid reqwest requests");
|
||||
let reqwest_request = reqwest::Request::try_from(http_request)?;
|
||||
|
||||
let url = reqwest_request.url().clone();
|
||||
|
||||
|
@ -290,7 +290,7 @@ where
|
|||
.globals
|
||||
.actual_destination_cache
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.insert(
|
||||
OwnedServerName::from(destination),
|
||||
(actual_destination, host),
|
||||
|
@ -341,7 +341,7 @@ fn add_port_to_hostname(destination_str: &str) -> FedDest {
|
|||
}
|
||||
|
||||
/// Returns: actual_destination, host header
|
||||
/// Implemented according to the specification at https://matrix.org/docs/spec/server_server/r0.1.4#resolving-server-names
|
||||
/// 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) {
|
||||
debug!("Finding actual destination for {destination}");
|
||||
|
@ -475,12 +475,11 @@ async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDe
|
|||
(actual_destination, hostname)
|
||||
}
|
||||
|
||||
async fn query_srv_record(hostname: &'_ str) -> Option<FedDest> {
|
||||
let hostname = hostname.trim_end_matches('.');
|
||||
if let Ok(Some(host_port)) = services()
|
||||
async fn query_given_srv_record(record: &str) -> Option<FedDest> {
|
||||
services()
|
||||
.globals
|
||||
.dns_resolver()
|
||||
.srv_lookup(format!("_matrix._tcp.{hostname}."))
|
||||
.srv_lookup(record)
|
||||
.await
|
||||
.map(|srv| {
|
||||
srv.iter().next().map(|result| {
|
||||
|
@ -490,10 +489,17 @@ async fn query_srv_record(hostname: &'_ str) -> Option<FedDest> {
|
|||
)
|
||||
})
|
||||
})
|
||||
.unwrap_or(None)
|
||||
}
|
||||
|
||||
async fn query_srv_record(hostname: &'_ str) -> Option<FedDest> {
|
||||
let hostname = hostname.trim_end_matches('.');
|
||||
|
||||
if let Some(host_port) = query_given_srv_record(&format!("_matrix-fed._tcp.{hostname}.")).await
|
||||
{
|
||||
Some(host_port)
|
||||
} else {
|
||||
None
|
||||
query_given_srv_record(&format!("_matrix._tcp.{hostname}.")).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -600,10 +606,6 @@ pub async fn get_server_keys_deprecated_route() -> impl IntoResponse {
|
|||
pub async fn get_public_rooms_filtered_route(
|
||||
body: Ruma<get_public_rooms_filtered::v1::Request>,
|
||||
) -> Result<get_public_rooms_filtered::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let response = client_server::get_public_rooms_filtered_helper(
|
||||
None,
|
||||
body.limit,
|
||||
|
@ -627,10 +629,6 @@ pub async fn get_public_rooms_filtered_route(
|
|||
pub async fn get_public_rooms_route(
|
||||
body: Ruma<get_public_rooms::v1::Request>,
|
||||
) -> Result<get_public_rooms::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let response = client_server::get_public_rooms_filtered_helper(
|
||||
None,
|
||||
body.limit,
|
||||
|
@ -666,7 +664,7 @@ 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) {
|
||||
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
|
||||
|
@ -685,10 +683,6 @@ pub fn parse_incoming_pdu(
|
|||
pub async fn send_transaction_message_route(
|
||||
body: Ruma<send_transaction_message::v1::Request>,
|
||||
) -> Result<send_transaction_message::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
|
@ -724,7 +718,7 @@ pub async fn send_transaction_message_route(
|
|||
continue;
|
||||
}
|
||||
|
||||
let r = parse_incoming_pdu(&pdu);
|
||||
let r = parse_incoming_pdu(pdu);
|
||||
let (event_id, value, room_id) = match r {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
|
@ -740,7 +734,7 @@ pub async fn send_transaction_message_route(
|
|||
.globals
|
||||
.roomid_mutex_federation
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
|
@ -837,17 +831,23 @@ pub async fn send_transaction_message_route(
|
|||
.is_joined(&typing.user_id, &typing.room_id)?
|
||||
{
|
||||
if typing.typing {
|
||||
services().rooms.edus.typing.typing_add(
|
||||
&typing.user_id,
|
||||
&typing.room_id,
|
||||
3000 + utils::millis_since_unix_epoch(),
|
||||
)?;
|
||||
services()
|
||||
.rooms
|
||||
.edus
|
||||
.typing
|
||||
.typing_add(
|
||||
&typing.user_id,
|
||||
&typing.room_id,
|
||||
3000 + utils::millis_since_unix_epoch(),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
services()
|
||||
.rooms
|
||||
.edus
|
||||
.typing
|
||||
.typing_remove(&typing.user_id, &typing.room_id)?;
|
||||
.typing_remove(&typing.user_id, &typing.room_id)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -953,10 +953,6 @@ pub async fn send_transaction_message_route(
|
|||
pub async fn get_event_route(
|
||||
body: Ruma<get_event::v1::Request>,
|
||||
) -> Result<get_event::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
|
@ -992,7 +988,7 @@ pub async fn get_event_route(
|
|||
|
||||
if !services().rooms.state_accessor.server_can_see_event(
|
||||
sender_servername,
|
||||
&room_id,
|
||||
room_id,
|
||||
&body.event_id,
|
||||
)? {
|
||||
return Err(Error::BadRequest(
|
||||
|
@ -1015,10 +1011,6 @@ pub async fn get_event_route(
|
|||
pub async fn get_backfill_route(
|
||||
body: Ruma<get_backfill::v1::Request>,
|
||||
) -> Result<get_backfill::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
|
@ -1058,7 +1050,7 @@ pub async fn get_backfill_route(
|
|||
let all_events = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.pdus_until(&user_id!("@doesntmatter:conduit.rs"), &body.room_id, until)?
|
||||
.pdus_until(user_id!("@doesntmatter:conduit.rs"), &body.room_id, until)?
|
||||
.take(limit.try_into().unwrap());
|
||||
|
||||
let events = all_events
|
||||
|
@ -1075,7 +1067,7 @@ pub async fn get_backfill_route(
|
|||
})
|
||||
.map(|(_, pdu)| services().rooms.timeline.get_pdu_json(&pdu.event_id))
|
||||
.filter_map(|r| r.ok().flatten())
|
||||
.map(|pdu| PduEvent::convert_to_outgoing_federation_event(pdu))
|
||||
.map(PduEvent::convert_to_outgoing_federation_event)
|
||||
.collect();
|
||||
|
||||
Ok(get_backfill::v1::Response {
|
||||
|
@ -1091,10 +1083,6 @@ pub async fn get_backfill_route(
|
|||
pub async fn get_missing_events_route(
|
||||
body: Ruma<get_missing_events::v1::Request>,
|
||||
) -> Result<get_missing_events::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
|
@ -1180,10 +1168,6 @@ pub async fn get_missing_events_route(
|
|||
pub async fn get_event_authorization_route(
|
||||
body: Ruma<get_event_authorization::v1::Request>,
|
||||
) -> Result<get_event_authorization::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
|
@ -1242,10 +1226,6 @@ pub async fn get_event_authorization_route(
|
|||
pub async fn get_room_state_route(
|
||||
body: Ruma<get_room_state::v1::Request>,
|
||||
) -> Result<get_room_state::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
|
@ -1322,10 +1302,6 @@ pub async fn get_room_state_route(
|
|||
pub async fn get_room_state_ids_route(
|
||||
body: Ruma<get_room_state_ids::v1::Request>,
|
||||
) -> Result<get_room_state_ids::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
|
@ -1383,10 +1359,6 @@ pub async fn get_room_state_ids_route(
|
|||
pub async fn create_join_event_template_route(
|
||||
body: Ruma<prepare_join_event::v1::Request>,
|
||||
) -> Result<prepare_join_event::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
if !services().rooms.metadata.exists(&body.room_id)? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::NotFound,
|
||||
|
@ -1409,7 +1381,7 @@ pub async fn create_join_event_template_route(
|
|||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(body.room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
|
@ -1494,10 +1466,6 @@ async fn create_join_event(
|
|||
room_id: &RoomId,
|
||||
pdu: &RawJsonValue,
|
||||
) -> Result<create_join_event::v1::RoomState> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
if !services().rooms.metadata.exists(room_id)? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::NotFound,
|
||||
|
@ -1579,7 +1547,7 @@ async fn create_join_event(
|
|||
.globals
|
||||
.roomid_mutex_federation
|
||||
.write()
|
||||
.unwrap()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default(),
|
||||
);
|
||||
|
@ -1678,10 +1646,6 @@ pub async fn create_join_event_v2_route(
|
|||
pub async fn create_invite_route(
|
||||
body: Ruma<create_invite::v2::Request>,
|
||||
) -> Result<create_invite::v2::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
.sender_servername
|
||||
.as_ref()
|
||||
|
@ -1795,8 +1759,11 @@ pub async fn create_invite_route(
|
|||
pub async fn get_devices_route(
|
||||
body: Ruma<get_devices::v1::Request>,
|
||||
) -> Result<get_devices::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
if body.user_id.server_name() != services().globals.server_name() {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Tried to access user from other server.",
|
||||
));
|
||||
}
|
||||
|
||||
let sender_servername = body
|
||||
|
@ -1844,10 +1811,6 @@ pub async fn get_devices_route(
|
|||
pub async fn get_room_information_route(
|
||||
body: Ruma<get_room_information::v1::Request>,
|
||||
) -> Result<get_room_information::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
}
|
||||
|
||||
let room_id = services()
|
||||
.rooms
|
||||
.alias
|
||||
|
@ -1869,8 +1832,11 @@ pub async fn get_room_information_route(
|
|||
pub async fn get_profile_information_route(
|
||||
body: Ruma<get_profile_information::v1::Request>,
|
||||
) -> Result<get_profile_information::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
if body.user_id.server_name() != services().globals.server_name() {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Tried to access user from other server.",
|
||||
));
|
||||
}
|
||||
|
||||
let mut displayname = None;
|
||||
|
@ -1905,8 +1871,15 @@ pub async fn get_profile_information_route(
|
|||
///
|
||||
/// Gets devices and identity keys for the given users.
|
||||
pub async fn get_keys_route(body: Ruma<get_keys::v1::Request>) -> Result<get_keys::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
if body
|
||||
.device_keys
|
||||
.iter()
|
||||
.any(|(u, _)| u.server_name() != services().globals.server_name())
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Tried to access user from other server.",
|
||||
));
|
||||
}
|
||||
|
||||
let result = get_keys_helper(None, &body.device_keys, |u| {
|
||||
|
@ -1927,8 +1900,15 @@ pub async fn get_keys_route(body: Ruma<get_keys::v1::Request>) -> Result<get_key
|
|||
pub async fn claim_keys_route(
|
||||
body: Ruma<claim_keys::v1::Request>,
|
||||
) -> Result<claim_keys::v1::Response> {
|
||||
if !services().globals.allow_federation() {
|
||||
return Err(Error::bad_config("Federation is disabled."));
|
||||
if body
|
||||
.one_time_keys
|
||||
.iter()
|
||||
.any(|(u, _)| u.server_name() != services().globals.server_name())
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Tried to access user from other server.",
|
||||
));
|
||||
}
|
||||
|
||||
let result = claim_keys_helper(&body.one_time_keys).await?;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue