2021-05-20 23:46:52 +02:00
|
|
|
|
use crate::{
|
2022-09-06 23:15:09 +02:00
|
|
|
|
api::client_server::{self, claim_keys_helper, get_keys_helper},
|
2022-10-05 20:34:31 +02:00
|
|
|
|
service::pdu::{gen_event_id_canonical_json, PduBuilder},
|
|
|
|
|
services, utils, Error, PduEvent, Result, Ruma,
|
2021-05-20 23:46:52 +02:00
|
|
|
|
};
|
2022-01-20 11:51:31 +01:00
|
|
|
|
use axum::{response::IntoResponse, Json};
|
2020-10-05 22:19:22 +02:00
|
|
|
|
use get_profile_information::v1::ProfileField;
|
2021-08-26 23:11:13 +02:00
|
|
|
|
use http::header::{HeaderValue, AUTHORIZATION};
|
2022-10-05 20:41:05 +02:00
|
|
|
|
|
2020-09-12 22:41:33 +02:00
|
|
|
|
use ruma::{
|
|
|
|
|
api::{
|
2021-06-17 20:12:36 +02:00
|
|
|
|
client::error::{Error as RumaError, ErrorKind},
|
2020-09-12 22:41:33 +02:00
|
|
|
|
federation::{
|
2021-06-14 11:36:18 +02:00
|
|
|
|
authorization::get_event_authorization,
|
2022-01-15 19:13:17 +02:00
|
|
|
|
backfill::get_backfill,
|
2021-04-21 10:51:34 +02:00
|
|
|
|
device::get_devices::{self, v1::UserDevice},
|
2020-09-25 12:26:29 +02:00
|
|
|
|
directory::{get_public_rooms, get_public_rooms_filtered},
|
2022-10-08 13:03:07 +02:00
|
|
|
|
discovery::{get_server_keys, get_server_version, ServerSigningKeys, VerifyKey},
|
2021-06-14 10:52:27 +02:00
|
|
|
|
event::{get_event, get_missing_events, get_room_state, get_room_state_ids},
|
2021-05-28 13:44:40 +02:00
|
|
|
|
keys::{claim_keys, get_keys},
|
2021-04-16 18:18:29 +02:00
|
|
|
|
membership::{
|
|
|
|
|
create_invite,
|
|
|
|
|
create_join_event::{self, RoomState},
|
2022-02-18 15:33:14 +01:00
|
|
|
|
prepare_join_event,
|
2021-04-16 18:18:29 +02:00
|
|
|
|
},
|
|
|
|
|
query::{get_profile_information, get_room_information},
|
2021-05-28 13:44:40 +02:00
|
|
|
|
transactions::{
|
2022-03-05 10:16:21 +08:00
|
|
|
|
edu::{DeviceListUpdateContent, DirectDeviceContent, Edu, SigningKeyUpdateContent},
|
2021-05-28 13:44:40 +02:00
|
|
|
|
send_transaction_message,
|
|
|
|
|
},
|
2020-08-06 08:29:59 -04:00
|
|
|
|
},
|
2022-02-12 21:04:38 +01:00
|
|
|
|
EndpointError, IncomingResponse, MatrixVersion, OutgoingRequest, OutgoingResponse,
|
|
|
|
|
SendAccessToken,
|
2020-08-14 11:29:32 +02:00
|
|
|
|
},
|
2020-09-14 11:42:16 +02:00
|
|
|
|
directory::{IncomingFilter, IncomingRoomNetwork},
|
2021-04-11 21:01:27 +02:00
|
|
|
|
events::{
|
2022-11-18 17:18:20 +01:00
|
|
|
|
presence::{PresenceEvent, PresenceEventContent},
|
2022-10-09 17:25:06 +02:00
|
|
|
|
receipt::{ReceiptEvent, ReceiptEventContent, ReceiptType},
|
2021-04-16 18:18:29 +02:00
|
|
|
|
room::{
|
2022-01-18 16:53:25 +01:00
|
|
|
|
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
2021-10-13 10:16:45 +02:00
|
|
|
|
member::{MembershipState, RoomMemberEventContent},
|
2021-04-16 18:18:29 +02:00
|
|
|
|
},
|
2022-04-06 21:31:29 +02:00
|
|
|
|
RoomEventType, StateEventType,
|
2021-04-11 21:01:27 +02:00
|
|
|
|
},
|
2022-02-18 15:33:14 +01:00
|
|
|
|
serde::{Base64, JsonObject, Raw},
|
2022-10-08 13:03:07 +02:00
|
|
|
|
to_device::DeviceIdOrAllDevices,
|
2022-11-27 23:25:42 +01:00
|
|
|
|
CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId,
|
2022-12-14 17:18:13 +02:00
|
|
|
|
OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, RoomId, ServerName, UInt,
|
2020-05-26 10:27:51 +02:00
|
|
|
|
};
|
2021-10-13 10:16:45 +02:00
|
|
|
|
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
|
2020-04-22 20:55:11 +02:00
|
|
|
|
use std::{
|
2022-12-14 17:18:13 +02:00
|
|
|
|
collections::{BTreeMap, HashSet, VecDeque},
|
2020-08-14 11:31:31 +02:00
|
|
|
|
fmt::Debug,
|
2021-04-29 20:58:05 +02:00
|
|
|
|
mem,
|
2020-12-08 12:34:46 +01:00
|
|
|
|
net::{IpAddr, SocketAddr},
|
2022-10-05 20:41:05 +02:00
|
|
|
|
sync::{Arc, RwLock},
|
2021-05-20 23:46:52 +02:00
|
|
|
|
time::{Duration, Instant, SystemTime},
|
2020-04-22 20:55:11 +02:00
|
|
|
|
};
|
2022-10-05 20:41:05 +02:00
|
|
|
|
|
2022-11-21 21:48:06 +02:00
|
|
|
|
use tracing::{debug, error, info, warn};
|
2020-04-19 14:14:47 +02:00
|
|
|
|
|
2021-04-21 00:35:44 -03:00
|
|
|
|
/// Wraps either an literal IP address plus port, or a hostname plus complement
|
|
|
|
|
/// (colon-plus-port if it was specified).
|
|
|
|
|
///
|
|
|
|
|
/// Note: A `FedDest::Named` might contain an IP address in string form if there
|
|
|
|
|
/// was no port specified to construct a SocketAddr with.
|
|
|
|
|
///
|
|
|
|
|
/// # Examples:
|
2022-04-14 16:42:08 +02:00
|
|
|
|
/// ```rust
|
2022-10-12 14:39:58 -07:00
|
|
|
|
/// # use conduit::api::server_server::FedDest;
|
2022-04-14 16:42:08 +02:00
|
|
|
|
/// # fn main() -> Result<(), std::net::AddrParseError> {
|
2021-04-21 00:35:44 -03:00
|
|
|
|
/// FedDest::Literal("198.51.100.3:8448".parse()?);
|
|
|
|
|
/// FedDest::Literal("[2001:db8::4:5]:443".parse()?);
|
|
|
|
|
/// FedDest::Named("matrix.example.org".to_owned(), "".to_owned());
|
|
|
|
|
/// FedDest::Named("matrix.example.org".to_owned(), ":8448".to_owned());
|
|
|
|
|
/// FedDest::Named("198.51.100.5".to_owned(), "".to_owned());
|
2022-04-14 16:42:08 +02:00
|
|
|
|
/// # Ok(())
|
|
|
|
|
/// # }
|
2021-04-21 00:35:44 -03:00
|
|
|
|
/// ```
|
2022-10-10 14:09:11 +02:00
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2021-08-26 23:11:13 +02:00
|
|
|
|
pub enum FedDest {
|
2021-04-16 00:27:26 -03:00
|
|
|
|
Literal(SocketAddr),
|
|
|
|
|
Named(String, String),
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-16 12:18:22 -03:00
|
|
|
|
impl FedDest {
|
2021-04-21 00:35:44 -03:00
|
|
|
|
fn into_https_string(self) -> String {
|
2021-04-16 00:27:26 -03:00
|
|
|
|
match self {
|
|
|
|
|
Self::Literal(addr) => format!("https://{}", addr),
|
|
|
|
|
Self::Named(host, port) => format!("https://{}{}", host, port),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 00:35:44 -03:00
|
|
|
|
fn into_uri_string(self) -> String {
|
2021-04-16 00:27:26 -03:00
|
|
|
|
match self {
|
|
|
|
|
Self::Literal(addr) => addr.to_string(),
|
|
|
|
|
Self::Named(host, ref port) => host + port,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 00:35:44 -03:00
|
|
|
|
fn hostname(&self) -> String {
|
2021-04-16 00:27:26 -03:00
|
|
|
|
match &self {
|
|
|
|
|
Self::Literal(addr) => addr.ip().to_string(),
|
2021-04-16 12:18:22 -03:00
|
|
|
|
Self::Named(host, _) => host.clone(),
|
2021-04-16 00:27:26 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-26 23:11:13 +02:00
|
|
|
|
|
|
|
|
|
fn port(&self) -> Option<u16> {
|
|
|
|
|
match &self {
|
|
|
|
|
Self::Literal(addr) => Some(addr.port()),
|
|
|
|
|
Self::Named(_, port) => port[1..].parse().ok(),
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-16 00:27:26 -03:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
#[tracing::instrument(skip(request))]
|
2021-08-31 19:14:37 +02:00
|
|
|
|
pub(crate) async fn send_request<T: OutgoingRequest>(
|
2021-01-14 14:39:56 -05:00
|
|
|
|
destination: &ServerName,
|
2020-04-19 14:14:47 +02:00
|
|
|
|
request: T,
|
2020-08-14 11:31:31 +02:00
|
|
|
|
) -> Result<T::IncomingResponse>
|
|
|
|
|
where
|
|
|
|
|
T: Debug,
|
|
|
|
|
{
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2020-11-14 23:13:06 +01:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
2020-10-06 21:04:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-26 23:11:13 +02:00
|
|
|
|
let mut write_destination_to_cache = false;
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
let cached_result = services()
|
|
|
|
|
.globals
|
2020-12-06 11:05:51 +01:00
|
|
|
|
.actual_destination_cache
|
|
|
|
|
.read()
|
|
|
|
|
.unwrap()
|
2021-01-14 14:39:56 -05:00
|
|
|
|
.get(destination)
|
2020-12-06 11:05:51 +01:00
|
|
|
|
.cloned();
|
2020-09-23 12:03:08 +02:00
|
|
|
|
|
2021-08-26 23:11:13 +02:00
|
|
|
|
let (actual_destination, host) = if let Some(result) = cached_result {
|
2020-12-06 11:05:51 +01:00
|
|
|
|
result
|
|
|
|
|
} else {
|
2021-08-26 23:11:13 +02:00
|
|
|
|
write_destination_to_cache = true;
|
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let result = find_actual_destination(destination).await;
|
2021-08-26 23:11:13 +02:00
|
|
|
|
|
2021-08-31 21:20:03 +02:00
|
|
|
|
(result.0, result.1.into_uri_string())
|
2020-12-06 11:05:51 +01:00
|
|
|
|
};
|
2020-08-14 11:31:31 +02:00
|
|
|
|
|
2021-08-26 23:11:13 +02:00
|
|
|
|
let actual_destination_str = actual_destination.clone().into_https_string();
|
|
|
|
|
|
2020-08-14 11:31:31 +02:00
|
|
|
|
let mut http_request = request
|
2022-02-12 21:04:38 +01:00
|
|
|
|
.try_into_http_request::<Vec<u8>>(
|
|
|
|
|
&actual_destination_str,
|
|
|
|
|
SendAccessToken::IfRequired(""),
|
|
|
|
|
&[MatrixVersion::V1_0],
|
|
|
|
|
)
|
2020-09-15 08:55:02 +02:00
|
|
|
|
.map_err(|e| {
|
2021-08-26 23:11:13 +02:00
|
|
|
|
warn!(
|
|
|
|
|
"Failed to find destination {}: {}",
|
|
|
|
|
actual_destination_str, e
|
|
|
|
|
);
|
2020-09-15 08:55:02 +02:00
|
|
|
|
Error::BadServerResponse("Invalid destination")
|
|
|
|
|
})?;
|
2020-04-22 11:53:06 +02:00
|
|
|
|
|
2020-04-22 21:14:40 +02:00
|
|
|
|
let mut request_map = serde_json::Map::new();
|
2020-04-19 14:14:47 +02:00
|
|
|
|
|
2020-04-22 21:14:40 +02:00
|
|
|
|
if !http_request.body().is_empty() {
|
2020-04-25 11:47:32 +02:00
|
|
|
|
request_map.insert(
|
|
|
|
|
"content".to_owned(),
|
2020-09-15 08:55:02 +02:00
|
|
|
|
serde_json::from_slice(http_request.body())
|
|
|
|
|
.expect("body is valid json, we just created it"),
|
2020-04-25 11:47:32 +02:00
|
|
|
|
);
|
2020-04-22 21:14:40 +02:00
|
|
|
|
};
|
2020-04-19 14:14:47 +02:00
|
|
|
|
|
2020-04-22 11:53:06 +02:00
|
|
|
|
request_map.insert("method".to_owned(), T::METADATA.method.to_string().into());
|
2020-08-14 11:31:31 +02:00
|
|
|
|
request_map.insert(
|
|
|
|
|
"uri".to_owned(),
|
|
|
|
|
http_request
|
|
|
|
|
.uri()
|
|
|
|
|
.path_and_query()
|
|
|
|
|
.expect("all requests have a path")
|
|
|
|
|
.to_string()
|
|
|
|
|
.into(),
|
|
|
|
|
);
|
2022-10-05 20:34:31 +02:00
|
|
|
|
request_map.insert(
|
|
|
|
|
"origin".to_owned(),
|
|
|
|
|
services().globals.server_name().as_str().into(),
|
|
|
|
|
);
|
2020-09-14 11:00:31 +02:00
|
|
|
|
request_map.insert("destination".to_owned(), destination.as_str().into());
|
2020-04-22 21:14:40 +02:00
|
|
|
|
|
2020-10-27 19:10:09 -04:00
|
|
|
|
let mut request_json =
|
|
|
|
|
serde_json::from_value(request_map.into()).expect("valid JSON is valid BTreeMap");
|
|
|
|
|
|
2020-06-05 18:19:26 +02:00
|
|
|
|
ruma::signatures::sign_json(
|
2022-09-06 23:15:09 +02:00
|
|
|
|
services().globals.server_name().as_str(),
|
|
|
|
|
services().globals.keypair(),
|
2020-12-31 21:07:05 +01:00
|
|
|
|
&mut request_json,
|
2020-05-09 21:47:09 +02:00
|
|
|
|
)
|
2020-09-15 08:55:02 +02:00
|
|
|
|
.expect("our request json is what ruma expects");
|
2020-04-19 14:14:47 +02:00
|
|
|
|
|
2020-10-27 19:10:09 -04:00
|
|
|
|
let request_json: serde_json::Map<String, serde_json::Value> =
|
|
|
|
|
serde_json::from_slice(&serde_json::to_vec(&request_json).unwrap()).unwrap();
|
|
|
|
|
|
2020-04-22 11:53:06 +02:00
|
|
|
|
let signatures = request_json["signatures"]
|
|
|
|
|
.as_object()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.values()
|
2020-08-14 11:31:31 +02:00
|
|
|
|
.map(|v| {
|
|
|
|
|
v.as_object()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|(k, v)| (k, v.as_str().unwrap()))
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for signature_server in signatures {
|
|
|
|
|
for s in signature_server {
|
|
|
|
|
http_request.headers_mut().insert(
|
|
|
|
|
AUTHORIZATION,
|
|
|
|
|
HeaderValue::from_str(&format!(
|
|
|
|
|
"X-Matrix origin={},key=\"{}\",sig=\"{}\"",
|
2022-09-06 23:15:09 +02:00
|
|
|
|
services().globals.server_name(),
|
2020-08-14 11:31:31 +02:00
|
|
|
|
s.0,
|
|
|
|
|
s.1
|
|
|
|
|
))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
}
|
2020-04-22 11:53:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-04 22:55:03 +02:00
|
|
|
|
let reqwest_request = reqwest::Request::try_from(http_request)
|
2020-08-14 11:31:31 +02:00
|
|
|
|
.expect("all http requests are valid reqwest requests");
|
|
|
|
|
|
2020-09-23 15:23:29 +02:00
|
|
|
|
let url = reqwest_request.url().clone();
|
2021-08-26 23:11:13 +02:00
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
let response = services()
|
|
|
|
|
.globals
|
|
|
|
|
.federation_client()
|
|
|
|
|
.execute(reqwest_request)
|
|
|
|
|
.await;
|
2020-04-22 11:53:06 +02:00
|
|
|
|
|
2021-04-29 20:58:05 +02:00
|
|
|
|
match response {
|
|
|
|
|
Ok(mut response) => {
|
|
|
|
|
// reqwest::Response -> http::Response conversion
|
|
|
|
|
let status = response.status();
|
|
|
|
|
let mut http_response_builder = http::Response::builder()
|
|
|
|
|
.status(status)
|
|
|
|
|
.version(response.version());
|
|
|
|
|
mem::swap(
|
|
|
|
|
response.headers_mut(),
|
|
|
|
|
http_response_builder
|
|
|
|
|
.headers_mut()
|
|
|
|
|
.expect("http::response::Builder is usable"),
|
|
|
|
|
);
|
2020-12-05 21:03:43 +01:00
|
|
|
|
|
2021-04-29 20:58:05 +02:00
|
|
|
|
let body = response.bytes().await.unwrap_or_else(|e| {
|
2021-04-13 15:00:45 +02:00
|
|
|
|
warn!("server error {}", e);
|
|
|
|
|
Vec::new().into()
|
|
|
|
|
}); // TODO: handle timeout
|
2020-12-05 21:03:43 +01:00
|
|
|
|
|
|
|
|
|
if status != 200 {
|
2021-08-21 14:22:21 +02:00
|
|
|
|
warn!(
|
2021-03-26 11:10:45 +01:00
|
|
|
|
"{} {}: {}",
|
|
|
|
|
url,
|
|
|
|
|
status,
|
2021-03-26 13:41:05 +01:00
|
|
|
|
String::from_utf8_lossy(&body)
|
|
|
|
|
.lines()
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
.join(" ")
|
2021-03-26 11:10:45 +01:00
|
|
|
|
);
|
2020-12-05 21:03:43 +01:00
|
|
|
|
}
|
2020-09-12 21:30:07 +02:00
|
|
|
|
|
2021-05-23 16:45:32 +02:00
|
|
|
|
let http_response = http_response_builder
|
|
|
|
|
.body(body)
|
|
|
|
|
.expect("reqwest body is valid http body");
|
|
|
|
|
|
|
|
|
|
if status == 200 {
|
|
|
|
|
let response = T::IncomingResponse::try_from_http_response(http_response);
|
2021-08-26 23:11:13 +02:00
|
|
|
|
if response.is_ok() && write_destination_to_cache {
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.globals
|
|
|
|
|
.actual_destination_cache
|
|
|
|
|
.write()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.insert(
|
2022-10-09 17:25:06 +02:00
|
|
|
|
OwnedServerName::from(destination),
|
2022-10-05 20:34:31 +02:00
|
|
|
|
(actual_destination, host),
|
|
|
|
|
);
|
2021-08-26 23:11:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-04 22:55:03 +02:00
|
|
|
|
response.map_err(|e| {
|
2021-08-17 16:06:09 +02:00
|
|
|
|
warn!(
|
|
|
|
|
"Invalid 200 response from {} on: {} {}",
|
|
|
|
|
&destination, url, e
|
|
|
|
|
);
|
2021-08-04 22:55:03 +02:00
|
|
|
|
Error::BadServerResponse("Server returned bad 200 response.")
|
|
|
|
|
})
|
2021-05-23 16:45:32 +02:00
|
|
|
|
} else {
|
|
|
|
|
Err(Error::FederationError(
|
|
|
|
|
destination.to_owned(),
|
2021-08-09 19:15:14 +02:00
|
|
|
|
RumaError::try_from_http_response(http_response).map_err(|e| {
|
2021-08-17 16:06:09 +02:00
|
|
|
|
warn!(
|
|
|
|
|
"Invalid {} response from {} on: {} {}",
|
|
|
|
|
status, &destination, url, e
|
|
|
|
|
);
|
2021-05-23 16:45:32 +02:00
|
|
|
|
Error::BadServerResponse("Server returned bad error response.")
|
|
|
|
|
})?,
|
|
|
|
|
))
|
|
|
|
|
}
|
2020-04-22 11:53:06 +02:00
|
|
|
|
}
|
2022-10-13 10:14:52 +02:00
|
|
|
|
Err(e) => {
|
2022-10-15 00:28:43 +02:00
|
|
|
|
warn!(
|
|
|
|
|
"Could not send request to {} at {}: {}",
|
|
|
|
|
destination, actual_destination_str, e
|
|
|
|
|
);
|
2022-10-13 10:14:52 +02:00
|
|
|
|
Err(e.into())
|
2022-10-15 00:28:43 +02:00
|
|
|
|
}
|
2020-04-22 11:53:06 +02:00
|
|
|
|
}
|
2020-04-19 14:14:47 +02:00
|
|
|
|
}
|
2020-04-22 20:55:11 +02:00
|
|
|
|
|
2021-04-16 12:18:22 -03:00
|
|
|
|
fn get_ip_with_port(destination_str: &str) -> Option<FedDest> {
|
2021-04-16 00:27:26 -03:00
|
|
|
|
if let Ok(destination) = destination_str.parse::<SocketAddr>() {
|
2021-04-16 12:18:22 -03:00
|
|
|
|
Some(FedDest::Literal(destination))
|
2020-12-08 12:34:46 +01:00
|
|
|
|
} else if let Ok(ip_addr) = destination_str.parse::<IpAddr>() {
|
2021-04-16 12:18:22 -03:00
|
|
|
|
Some(FedDest::Literal(SocketAddr::new(ip_addr, 8448)))
|
2020-12-08 12:34:46 +01:00
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-16 12:18:22 -03:00
|
|
|
|
fn add_port_to_hostname(destination_str: &str) -> FedDest {
|
2021-04-16 00:27:26 -03:00
|
|
|
|
let (host, port) = match destination_str.find(':') {
|
|
|
|
|
None => (destination_str, ":8448"),
|
|
|
|
|
Some(pos) => destination_str.split_at(pos),
|
|
|
|
|
};
|
2021-10-13 10:24:39 +02:00
|
|
|
|
FedDest::Named(host.to_owned(), port.to_owned())
|
2020-12-08 12:34:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-06 11:05:51 +01:00
|
|
|
|
/// Returns: actual_destination, host header
|
2020-12-08 12:34:46 +01:00
|
|
|
|
/// 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
|
2022-10-05 20:34:31 +02:00
|
|
|
|
async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDest) {
|
2020-12-08 12:34:46 +01:00
|
|
|
|
let destination_str = destination.as_str().to_owned();
|
2021-04-16 00:27:26 -03:00
|
|
|
|
let mut hostname = destination_str.clone();
|
|
|
|
|
let actual_destination = match get_ip_with_port(&destination_str) {
|
2021-04-16 12:18:22 -03:00
|
|
|
|
Some(host_port) => {
|
|
|
|
|
// 1: IP literal with provided or default port
|
|
|
|
|
host_port
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
if let Some(pos) = destination_str.find(':') {
|
|
|
|
|
// 2: Hostname with included port
|
|
|
|
|
let (host, port) = destination_str.split_at(pos);
|
2021-10-13 10:24:39 +02:00
|
|
|
|
FedDest::Named(host.to_owned(), port.to_owned())
|
2021-04-16 12:18:22 -03:00
|
|
|
|
} else {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
match request_well_known(destination.as_str()).await {
|
2021-04-16 12:18:22 -03:00
|
|
|
|
// 3: A .well-known file is available
|
|
|
|
|
Some(delegated_hostname) => {
|
2021-08-26 23:11:13 +02:00
|
|
|
|
hostname = add_port_to_hostname(&delegated_hostname).into_uri_string();
|
2021-04-16 12:18:22 -03:00
|
|
|
|
match get_ip_with_port(&delegated_hostname) {
|
|
|
|
|
Some(host_and_port) => host_and_port, // 3.1: IP literal in .well-known file
|
|
|
|
|
None => {
|
2021-08-26 19:00:08 +02:00
|
|
|
|
if let Some(pos) = delegated_hostname.find(':') {
|
2021-04-16 12:18:22 -03:00
|
|
|
|
// 3.2: Hostname with port in .well-known file
|
2021-08-26 19:00:08 +02:00
|
|
|
|
let (host, port) = delegated_hostname.split_at(pos);
|
2021-10-13 10:24:39 +02:00
|
|
|
|
FedDest::Named(host.to_owned(), port.to_owned())
|
2021-04-16 12:18:22 -03:00
|
|
|
|
} else {
|
2021-08-26 23:11:13 +02:00
|
|
|
|
// Delegated hostname has no port in this branch
|
|
|
|
|
if let Some(hostname_override) =
|
2022-09-06 23:15:09 +02:00
|
|
|
|
query_srv_record(&delegated_hostname).await
|
2021-08-26 23:11:13 +02:00
|
|
|
|
{
|
2021-04-16 12:18:22 -03:00
|
|
|
|
// 3.3: SRV lookup successful
|
2021-08-26 23:11:13 +02:00
|
|
|
|
let force_port = hostname_override.port();
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
if let Ok(override_ip) = services()
|
|
|
|
|
.globals
|
2021-08-26 23:11:13 +02:00
|
|
|
|
.dns_resolver()
|
|
|
|
|
.lookup_ip(hostname_override.hostname())
|
|
|
|
|
.await
|
|
|
|
|
{
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.globals
|
|
|
|
|
.tls_name_override
|
|
|
|
|
.write()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.insert(
|
|
|
|
|
delegated_hostname.clone(),
|
|
|
|
|
(
|
|
|
|
|
override_ip.iter().collect(),
|
|
|
|
|
force_port.unwrap_or(8448),
|
|
|
|
|
),
|
|
|
|
|
);
|
2021-08-26 23:11:13 +02:00
|
|
|
|
} else {
|
|
|
|
|
warn!("Using SRV record, but could not resolve to IP");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(port) = force_port {
|
2021-11-27 00:30:00 +01:00
|
|
|
|
FedDest::Named(delegated_hostname, format!(":{}", port))
|
2021-08-26 23:11:13 +02:00
|
|
|
|
} else {
|
|
|
|
|
add_port_to_hostname(&delegated_hostname)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-04-16 12:18:22 -03:00
|
|
|
|
// 3.4: No SRV records, just use the hostname from .well-known
|
2021-08-26 23:11:13 +02:00
|
|
|
|
add_port_to_hostname(&delegated_hostname)
|
2020-12-08 12:34:46 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-16 12:18:22 -03:00
|
|
|
|
}
|
|
|
|
|
// 4: No .well-known or an error occured
|
|
|
|
|
None => {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
match query_srv_record(&destination_str).await {
|
2021-04-16 12:18:22 -03:00
|
|
|
|
// 4: SRV record found
|
2021-08-26 23:11:13 +02:00
|
|
|
|
Some(hostname_override) => {
|
|
|
|
|
let force_port = hostname_override.port();
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
if let Ok(override_ip) = services()
|
|
|
|
|
.globals
|
2021-08-26 23:11:13 +02:00
|
|
|
|
.dns_resolver()
|
|
|
|
|
.lookup_ip(hostname_override.hostname())
|
|
|
|
|
.await
|
|
|
|
|
{
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.globals
|
|
|
|
|
.tls_name_override
|
|
|
|
|
.write()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.insert(
|
|
|
|
|
hostname.clone(),
|
|
|
|
|
(
|
|
|
|
|
override_ip.iter().collect(),
|
|
|
|
|
force_port.unwrap_or(8448),
|
|
|
|
|
),
|
|
|
|
|
);
|
2021-08-26 23:11:13 +02:00
|
|
|
|
} else {
|
|
|
|
|
warn!("Using SRV record, but could not resolve to IP");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(port) = force_port {
|
2021-11-27 00:30:00 +01:00
|
|
|
|
FedDest::Named(hostname.clone(), format!(":{}", port))
|
2021-08-26 23:11:13 +02:00
|
|
|
|
} else {
|
|
|
|
|
add_port_to_hostname(&hostname)
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-16 12:18:22 -03:00
|
|
|
|
// 5: No SRV record found
|
|
|
|
|
None => add_port_to_hostname(&destination_str),
|
2020-12-08 12:34:46 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-06 11:05:51 +01:00
|
|
|
|
}
|
2021-04-16 00:27:26 -03:00
|
|
|
|
}
|
2021-04-16 12:18:22 -03:00
|
|
|
|
};
|
2020-12-06 11:05:51 +01:00
|
|
|
|
|
2021-04-21 00:35:44 -03:00
|
|
|
|
// Can't use get_ip_with_port here because we don't want to add a port
|
|
|
|
|
// to an IP address if it wasn't specified
|
2021-04-16 12:18:22 -03:00
|
|
|
|
let hostname = if let Ok(addr) = hostname.parse::<SocketAddr>() {
|
|
|
|
|
FedDest::Literal(addr)
|
|
|
|
|
} else if let Ok(addr) = hostname.parse::<IpAddr>() {
|
2021-10-13 10:24:39 +02:00
|
|
|
|
FedDest::Named(addr.to_string(), ":8448".to_owned())
|
2021-04-16 12:18:22 -03:00
|
|
|
|
} else if let Some(pos) = hostname.find(':') {
|
|
|
|
|
let (host, port) = hostname.split_at(pos);
|
2021-10-13 10:24:39 +02:00
|
|
|
|
FedDest::Named(host.to_owned(), port.to_owned())
|
2021-04-16 12:18:22 -03:00
|
|
|
|
} else {
|
2021-10-13 10:24:39 +02:00
|
|
|
|
FedDest::Named(hostname, ":8448".to_owned())
|
2021-04-16 12:18:22 -03:00
|
|
|
|
};
|
2021-04-16 00:27:26 -03:00
|
|
|
|
(actual_destination, hostname)
|
2020-12-06 11:05:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
async fn query_srv_record(hostname: &'_ str) -> Option<FedDest> {
|
|
|
|
|
if let Ok(Some(host_port)) = services()
|
|
|
|
|
.globals
|
2020-12-08 12:34:46 +01:00
|
|
|
|
.dns_resolver()
|
|
|
|
|
.srv_lookup(format!("_matrix._tcp.{}", hostname))
|
|
|
|
|
.await
|
|
|
|
|
.map(|srv| {
|
|
|
|
|
srv.iter().next().map(|result| {
|
2021-04-16 12:18:22 -03:00
|
|
|
|
FedDest::Named(
|
2021-10-13 10:24:39 +02:00
|
|
|
|
result.target().to_string().trim_end_matches('.').to_owned(),
|
2021-04-16 12:18:22 -03:00
|
|
|
|
format!(":{}", result.port()),
|
2020-12-08 12:34:46 +01:00
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
Some(host_port)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
async fn request_well_known(destination: &str) -> Option<String> {
|
2020-12-08 12:34:46 +01:00
|
|
|
|
let body: serde_json::Value = serde_json::from_str(
|
2022-10-05 20:34:31 +02:00
|
|
|
|
&services()
|
|
|
|
|
.globals
|
2022-01-28 12:42:47 -06:00
|
|
|
|
.default_client()
|
2020-12-08 12:34:46 +01:00
|
|
|
|
.get(&format!(
|
|
|
|
|
"https://{}/.well-known/matrix/server",
|
|
|
|
|
destination
|
|
|
|
|
))
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
|
|
|
|
.ok()?
|
|
|
|
|
.text()
|
|
|
|
|
.await
|
|
|
|
|
.ok()?,
|
|
|
|
|
)
|
|
|
|
|
.ok()?;
|
|
|
|
|
Some(body.get("m.server")?.as_str()?.to_owned())
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/version`
|
|
|
|
|
///
|
|
|
|
|
/// Get version information on this server.
|
2022-01-20 11:51:31 +01:00
|
|
|
|
pub async fn get_server_version_route(
|
|
|
|
|
_body: Ruma<get_server_version::v1::Request>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_server_version::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2020-11-14 23:13:06 +01:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
2020-10-06 21:04:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-11 21:01:27 +02:00
|
|
|
|
Ok(get_server_version::v1::Response {
|
|
|
|
|
server: Some(get_server_version::v1::Server {
|
2020-04-22 20:55:11 +02:00
|
|
|
|
name: Some("Conduit".to_owned()),
|
|
|
|
|
version: Some(env!("CARGO_PKG_VERSION").to_owned()),
|
2020-04-28 20:03:14 +02:00
|
|
|
|
}),
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2020-04-22 20:55:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/key/v2/server`
|
|
|
|
|
///
|
|
|
|
|
/// Gets the public signing keys of this server.
|
|
|
|
|
///
|
|
|
|
|
/// - Matrix does not support invalidating public keys, so the key returned by this will be valid
|
|
|
|
|
/// forever.
|
2021-04-13 15:00:45 +02:00
|
|
|
|
// Response type for this endpoint is Json because we need to calculate a signature for the response
|
2022-09-06 23:15:09 +02:00
|
|
|
|
pub async fn get_server_keys_route() -> Result<impl IntoResponse> {
|
|
|
|
|
if !services().globals.allow_federation() {
|
2022-01-22 13:32:21 +01:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
2020-10-06 21:04:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-09 17:25:06 +02:00
|
|
|
|
let mut verify_keys: BTreeMap<OwnedServerSigningKeyId, VerifyKey> = BTreeMap::new();
|
2020-04-22 20:55:11 +02:00
|
|
|
|
verify_keys.insert(
|
2022-09-06 23:15:09 +02:00
|
|
|
|
format!("ed25519:{}", services().globals.keypair().version())
|
2021-11-27 00:30:28 +01:00
|
|
|
|
.try_into()
|
|
|
|
|
.expect("found invalid server signing keys in DB"),
|
2020-08-14 11:31:31 +02:00
|
|
|
|
VerifyKey {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
key: Base64::new(services().globals.keypair().public_key().to_vec()),
|
2020-04-22 20:55:11 +02:00
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
let mut response = serde_json::from_slice(
|
2021-04-13 15:00:45 +02:00
|
|
|
|
get_server_keys::v2::Response {
|
2022-02-18 15:33:14 +01:00
|
|
|
|
server_key: Raw::new(&ServerSigningKeys {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
server_name: services().globals.server_name().to_owned(),
|
2020-08-14 11:31:31 +02:00
|
|
|
|
verify_keys,
|
|
|
|
|
old_verify_keys: BTreeMap::new(),
|
|
|
|
|
signatures: BTreeMap::new(),
|
2021-05-20 23:46:52 +02:00
|
|
|
|
valid_until_ts: MilliSecondsSinceUnixEpoch::from_system_time(
|
2021-08-25 16:06:35 +02:00
|
|
|
|
SystemTime::now() + Duration::from_secs(86400 * 7),
|
2021-05-20 23:46:52 +02:00
|
|
|
|
)
|
|
|
|
|
.expect("time is valid"),
|
2022-02-18 15:33:14 +01:00
|
|
|
|
})
|
|
|
|
|
.expect("static conversion, no errors"),
|
2021-04-13 15:00:45 +02:00
|
|
|
|
}
|
2021-04-23 18:45:06 +02:00
|
|
|
|
.try_into_http_response::<Vec<u8>>()
|
2020-04-22 20:55:11 +02:00
|
|
|
|
.unwrap()
|
|
|
|
|
.body(),
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
2020-11-15 16:48:43 -05:00
|
|
|
|
|
2020-06-05 18:19:26 +02:00
|
|
|
|
ruma::signatures::sign_json(
|
2022-09-06 23:15:09 +02:00
|
|
|
|
services().globals.server_name().as_str(),
|
|
|
|
|
services().globals.keypair(),
|
2020-05-17 19:56:40 +02:00
|
|
|
|
&mut response,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
2020-11-15 16:48:43 -05:00
|
|
|
|
|
2022-01-22 13:32:21 +01:00
|
|
|
|
Ok(Json(response))
|
2020-04-22 20:55:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/key/v2/server/{keyId}`
|
|
|
|
|
///
|
|
|
|
|
/// Gets the public signing keys of this server.
|
|
|
|
|
///
|
|
|
|
|
/// - Matrix does not support invalidating public keys, so the key returned by this will be valid
|
|
|
|
|
/// forever.
|
2022-09-06 23:15:09 +02:00
|
|
|
|
pub async fn get_server_keys_deprecated_route() -> impl IntoResponse {
|
|
|
|
|
get_server_keys_route().await
|
2020-04-22 20:55:11 +02:00
|
|
|
|
}
|
2020-08-14 11:29:32 +02:00
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `POST /_matrix/federation/v1/publicRooms`
|
|
|
|
|
///
|
|
|
|
|
/// Lists the public rooms on this server.
|
2020-09-14 11:42:16 +02:00
|
|
|
|
pub async fn get_public_rooms_filtered_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<get_public_rooms_filtered::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_public_rooms_filtered::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2020-11-14 23:13:06 +01:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
2020-10-06 21:04:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 11:42:16 +02:00
|
|
|
|
let response = client_server::get_public_rooms_filtered_helper(
|
|
|
|
|
None,
|
|
|
|
|
body.limit,
|
|
|
|
|
body.since.as_deref(),
|
|
|
|
|
&body.filter,
|
|
|
|
|
&body.room_network,
|
|
|
|
|
)
|
2022-01-22 16:58:32 +01:00
|
|
|
|
.await?;
|
2020-09-14 11:42:16 +02:00
|
|
|
|
|
|
|
|
|
Ok(get_public_rooms_filtered::v1::Response {
|
2022-02-18 11:52:00 +01:00
|
|
|
|
chunk: response.chunk,
|
2020-09-14 11:42:16 +02:00
|
|
|
|
prev_batch: response.prev_batch,
|
|
|
|
|
next_batch: response.next_batch,
|
|
|
|
|
total_room_count_estimate: response.total_room_count_estimate,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2020-09-14 11:42:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/publicRooms`
|
|
|
|
|
///
|
|
|
|
|
/// Lists the public rooms on this server.
|
2020-08-14 11:29:32 +02:00
|
|
|
|
pub async fn get_public_rooms_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<get_public_rooms::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_public_rooms::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2020-11-14 23:13:06 +01:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
2020-10-06 21:04:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 11:42:16 +02:00
|
|
|
|
let response = client_server::get_public_rooms_filtered_helper(
|
2020-08-23 08:32:43 -04:00
|
|
|
|
None,
|
2020-09-14 11:42:16 +02:00
|
|
|
|
body.limit,
|
|
|
|
|
body.since.as_deref(),
|
|
|
|
|
&IncomingFilter::default(),
|
|
|
|
|
&IncomingRoomNetwork::Matrix,
|
2020-08-14 11:29:32 +02:00
|
|
|
|
)
|
2022-01-22 16:58:32 +01:00
|
|
|
|
.await?;
|
2020-08-14 11:29:32 +02:00
|
|
|
|
|
|
|
|
|
Ok(get_public_rooms::v1::Response {
|
2022-02-18 11:52:00 +01:00
|
|
|
|
chunk: response.chunk,
|
2020-09-14 11:42:16 +02:00
|
|
|
|
prev_batch: response.prev_batch,
|
|
|
|
|
next_batch: response.next_batch,
|
|
|
|
|
total_room_count_estimate: response.total_room_count_estimate,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2020-08-14 11:29:32 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `PUT /_matrix/federation/v1/send/{txnId}`
|
|
|
|
|
///
|
|
|
|
|
/// Push EDUs and PDUs to this server.
|
2021-06-08 18:10:00 +02:00
|
|
|
|
pub async fn send_transaction_message_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<send_transaction_message::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<send_transaction_message::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2020-11-14 23:13:06 +01:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
2020-10-06 21:04:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-06 19:08:23 +02:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2021-02-01 17:02:56 -05:00
|
|
|
|
let mut resolved_map = BTreeMap::new();
|
|
|
|
|
|
2021-04-13 21:34:31 +02:00
|
|
|
|
let pub_key_map = RwLock::new(BTreeMap::new());
|
2021-03-26 11:10:45 +01:00
|
|
|
|
|
|
|
|
|
// This is all the auth_events that have been recursively fetched so they don't have to be
|
|
|
|
|
// deserialized over and over again.
|
|
|
|
|
// TODO: make this persist across requests but not in a DB Tree (in globals?)
|
|
|
|
|
// TODO: This could potentially also be some sort of trie (suffix tree) like structure so
|
|
|
|
|
// that once an auth event is known it would know (using indexes maybe) all of the auth
|
|
|
|
|
// events that it references.
|
2021-06-29 20:18:52 -04:00
|
|
|
|
// let mut auth_cache = EventMap::new();
|
2021-03-26 11:10:45 +01:00
|
|
|
|
|
2021-04-05 21:46:10 +02:00
|
|
|
|
for pdu in &body.pdus {
|
2022-11-27 23:25:42 +01:00
|
|
|
|
let value: CanonicalJsonObject = serde_json::from_str(pdu.get()).map_err(|e| {
|
|
|
|
|
warn!("Error parsing incoming event {:?}: {:?}", pdu, e);
|
|
|
|
|
Error::BadServerResponse("Invalid PDU in server response")
|
|
|
|
|
})?;
|
2021-03-25 23:55:40 +01:00
|
|
|
|
|
2022-10-09 17:25:06 +02:00
|
|
|
|
let room_id: OwnedRoomId = match value
|
2021-07-01 19:55:26 +02:00
|
|
|
|
.get("room_id")
|
2021-11-27 00:30:28 +01:00
|
|
|
|
.and_then(|id| RoomId::parse(id.as_str()?).ok())
|
2021-07-01 19:55:26 +02:00
|
|
|
|
{
|
|
|
|
|
Some(id) => id,
|
|
|
|
|
None => {
|
|
|
|
|
// Event is invalid
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-11-27 23:25:42 +01:00
|
|
|
|
let room_version_id = match services().rooms.state.get_room_version(&room_id) {
|
|
|
|
|
Ok(v) => v,
|
|
|
|
|
Err(_) => {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// We do not add the event_id field to the pdu here because of signature and hashes checks
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.acl_check(sender_servername, &room_id)?;
|
2022-01-17 14:35:38 +01:00
|
|
|
|
|
2021-07-01 19:55:26 +02:00
|
|
|
|
let mutex = Arc::clone(
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.globals
|
2021-07-13 15:44:25 +02:00
|
|
|
|
.roomid_mutex_federation
|
2021-07-01 19:55:26 +02:00
|
|
|
|
.write()
|
|
|
|
|
.unwrap()
|
2022-06-18 16:38:41 +02:00
|
|
|
|
.entry(room_id.to_owned())
|
2021-07-01 19:55:26 +02:00
|
|
|
|
.or_default(),
|
|
|
|
|
);
|
|
|
|
|
let mutex_lock = mutex.lock().await;
|
2021-05-20 23:46:52 +02:00
|
|
|
|
let start_time = Instant::now();
|
2021-05-27 13:59:40 -03:00
|
|
|
|
resolved_map.insert(
|
|
|
|
|
event_id.clone(),
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
|
|
|
|
.handle_incoming_pdu(
|
2022-10-10 14:09:11 +02:00
|
|
|
|
sender_servername,
|
2022-10-05 20:34:31 +02:00
|
|
|
|
&event_id,
|
|
|
|
|
&room_id,
|
|
|
|
|
value,
|
|
|
|
|
true,
|
|
|
|
|
&pub_key_map,
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.map(|_| ()),
|
2021-05-27 13:59:40 -03:00
|
|
|
|
);
|
2021-07-01 19:55:26 +02:00
|
|
|
|
drop(mutex_lock);
|
2021-05-20 23:46:52 +02:00
|
|
|
|
|
|
|
|
|
let elapsed = start_time.elapsed();
|
2022-11-21 21:48:06 +02:00
|
|
|
|
debug!(
|
2021-08-12 17:55:16 +02:00
|
|
|
|
"Handling transaction of event {} took {}m{}s",
|
2021-08-06 20:00:08 +02:00
|
|
|
|
event_id,
|
|
|
|
|
elapsed.as_secs() / 60,
|
|
|
|
|
elapsed.as_secs() % 60
|
|
|
|
|
);
|
2021-03-25 23:55:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 11:10:45 +01:00
|
|
|
|
for pdu in &resolved_map {
|
|
|
|
|
if let Err(e) = pdu.1 {
|
2022-10-05 12:45:54 +02:00
|
|
|
|
if matches!(e, Error::BadRequest(ErrorKind::NotFound, _)) {
|
2021-03-26 11:10:45 +01:00
|
|
|
|
warn!("Incoming PDU failed {:?}", pdu);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-25 23:55:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-12 20:04:28 +02:00
|
|
|
|
for edu in body
|
|
|
|
|
.edus
|
|
|
|
|
.iter()
|
2021-06-11 15:47:53 -04:00
|
|
|
|
.filter_map(|edu| serde_json::from_str::<Edu>(edu.json().get()).ok())
|
2021-05-12 20:04:28 +02:00
|
|
|
|
{
|
|
|
|
|
match edu {
|
2022-11-18 17:18:20 +01:00
|
|
|
|
Edu::Presence(presence) => {
|
|
|
|
|
for presence_update in presence.push {
|
|
|
|
|
let user_id = presence_update.user_id;
|
|
|
|
|
for room_id in services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_cache
|
|
|
|
|
.rooms_joined(&user_id)
|
|
|
|
|
.filter_map(|room_id| room_id.ok())
|
|
|
|
|
{
|
|
|
|
|
services().rooms.edus.presence.update_presence(
|
|
|
|
|
&user_id,
|
|
|
|
|
&room_id,
|
|
|
|
|
PresenceEvent {
|
|
|
|
|
content: PresenceEventContent {
|
|
|
|
|
avatar_url: services().users.avatar_url(&user_id)?,
|
|
|
|
|
currently_active: Some(presence_update.currently_active),
|
|
|
|
|
displayname: services().users.displayname(&user_id)?,
|
|
|
|
|
last_active_ago: Some(presence_update.last_active_ago),
|
|
|
|
|
presence: presence_update.presence.clone(),
|
|
|
|
|
status_msg: presence_update.status_msg.clone(),
|
|
|
|
|
},
|
|
|
|
|
sender: user_id.clone(),
|
|
|
|
|
},
|
2022-11-18 22:39:05 +01:00
|
|
|
|
true,
|
2022-11-18 17:18:20 +01:00
|
|
|
|
)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-05-12 20:04:28 +02:00
|
|
|
|
Edu::Receipt(receipt) => {
|
2022-11-26 15:01:12 +01:00
|
|
|
|
if services().globals.allow_receiving_read_receipts() {
|
|
|
|
|
for (room_id, room_updates) in receipt.receipts {
|
|
|
|
|
for (user_id, user_updates) in room_updates.read {
|
|
|
|
|
if let Some((event_id, _)) = user_updates
|
|
|
|
|
.event_ids
|
|
|
|
|
.iter()
|
|
|
|
|
.filter_map(|id| {
|
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.timeline
|
|
|
|
|
.get_pdu_count(id)
|
|
|
|
|
.ok()
|
|
|
|
|
.flatten()
|
|
|
|
|
.map(|r| (id, r))
|
|
|
|
|
})
|
|
|
|
|
.max_by_key(|(_, count)| *count)
|
|
|
|
|
{
|
|
|
|
|
let mut user_receipts = BTreeMap::new();
|
|
|
|
|
user_receipts.insert(user_id.clone(), user_updates.data);
|
|
|
|
|
|
|
|
|
|
let mut receipts = BTreeMap::new();
|
|
|
|
|
receipts.insert(ReceiptType::Read, user_receipts);
|
|
|
|
|
|
|
|
|
|
let mut receipt_content = BTreeMap::new();
|
|
|
|
|
receipt_content.insert(event_id.to_owned(), receipts);
|
|
|
|
|
|
|
|
|
|
let event = ReceiptEvent {
|
|
|
|
|
content: ReceiptEventContent(receipt_content),
|
|
|
|
|
room_id: room_id.clone(),
|
|
|
|
|
};
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
2022-11-26 15:01:12 +01:00
|
|
|
|
.edus
|
|
|
|
|
.read_receipt
|
|
|
|
|
.readreceipt_update(&user_id, &room_id, event)?;
|
|
|
|
|
} else {
|
|
|
|
|
// TODO fetch missing events
|
|
|
|
|
info!("No known event ids in read receipt: {:?}", user_updates);
|
|
|
|
|
}
|
2021-05-12 20:04:28 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Edu::Typing(typing) => {
|
2022-10-05 20:34:31 +02:00
|
|
|
|
if services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_cache
|
|
|
|
|
.is_joined(&typing.user_id, &typing.room_id)?
|
|
|
|
|
{
|
2022-03-23 11:05:41 +01:00
|
|
|
|
if typing.typing {
|
2022-10-05 09:34:25 +02:00
|
|
|
|
services().rooms.edus.typing.typing_add(
|
2022-03-23 11:05:41 +01:00
|
|
|
|
&typing.user_id,
|
|
|
|
|
&typing.room_id,
|
|
|
|
|
3000 + utils::millis_since_unix_epoch(),
|
|
|
|
|
)?;
|
|
|
|
|
} else {
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.edus
|
|
|
|
|
.typing
|
|
|
|
|
.typing_remove(&typing.user_id, &typing.room_id)?;
|
2022-03-23 11:05:41 +01:00
|
|
|
|
}
|
2021-05-12 20:04:28 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-24 19:10:31 +02:00
|
|
|
|
Edu::DeviceListUpdate(DeviceListUpdateContent { user_id, .. }) => {
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services().users.mark_device_key_update(&user_id)?;
|
2021-05-28 13:44:40 +02:00
|
|
|
|
}
|
|
|
|
|
Edu::DirectToDevice(DirectDeviceContent {
|
|
|
|
|
sender,
|
|
|
|
|
ev_type,
|
|
|
|
|
message_id,
|
|
|
|
|
messages,
|
|
|
|
|
}) => {
|
|
|
|
|
// Check if this is a new transaction id
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if services()
|
2021-05-28 13:44:40 +02:00
|
|
|
|
.transaction_ids
|
2022-02-12 15:03:07 +01:00
|
|
|
|
.existing_txnid(&sender, None, &message_id)?
|
2021-05-28 13:44:40 +02:00
|
|
|
|
.is_some()
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (target_user_id, map) in &messages {
|
|
|
|
|
for (target_device_id_maybe, event) in map {
|
|
|
|
|
match target_device_id_maybe {
|
2021-06-17 20:12:36 +02:00
|
|
|
|
DeviceIdOrAllDevices::DeviceId(target_device_id) => {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
services().users.add_to_device_event(
|
2021-05-28 13:44:40 +02:00
|
|
|
|
&sender,
|
2021-09-13 19:45:56 +02:00
|
|
|
|
target_user_id,
|
|
|
|
|
target_device_id,
|
2021-06-17 20:12:36 +02:00
|
|
|
|
&ev_type.to_string(),
|
2022-10-13 10:14:52 +02:00
|
|
|
|
event.deserialize_as().map_err(|e| {
|
|
|
|
|
warn!("To-Device event is invalid: {event:?} {e}");
|
2021-05-28 13:44:40 +02:00
|
|
|
|
Error::BadRequest(
|
|
|
|
|
ErrorKind::InvalidParam,
|
|
|
|
|
"Event is invalid",
|
|
|
|
|
)
|
|
|
|
|
})?,
|
|
|
|
|
)?
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-17 20:12:36 +02:00
|
|
|
|
DeviceIdOrAllDevices::AllDevices => {
|
2022-10-05 20:34:31 +02:00
|
|
|
|
for target_device_id in
|
|
|
|
|
services().users.all_device_ids(target_user_id)
|
|
|
|
|
{
|
2022-09-06 23:15:09 +02:00
|
|
|
|
services().users.add_to_device_event(
|
2021-05-28 13:44:40 +02:00
|
|
|
|
&sender,
|
2021-09-13 19:45:56 +02:00
|
|
|
|
target_user_id,
|
2021-05-28 13:44:40 +02:00
|
|
|
|
&target_device_id?,
|
2021-06-17 20:12:36 +02:00
|
|
|
|
&ev_type.to_string(),
|
|
|
|
|
event.deserialize_as().map_err(|_| {
|
2021-05-28 13:44:40 +02:00
|
|
|
|
Error::BadRequest(
|
|
|
|
|
ErrorKind::InvalidParam,
|
|
|
|
|
"Event is invalid",
|
|
|
|
|
)
|
|
|
|
|
})?,
|
|
|
|
|
)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save transaction id with empty data
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.transaction_ids
|
2022-02-12 15:03:07 +01:00
|
|
|
|
.add_txnid(&sender, None, &message_id, &[])?;
|
2021-05-28 13:44:40 +02:00
|
|
|
|
}
|
2022-03-05 10:16:21 +08:00
|
|
|
|
Edu::SigningKeyUpdate(SigningKeyUpdateContent {
|
|
|
|
|
user_id,
|
|
|
|
|
master_key,
|
|
|
|
|
self_signing_key,
|
|
|
|
|
}) => {
|
2022-04-06 19:08:23 +02:00
|
|
|
|
if user_id.server_name() != sender_servername {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-03-05 10:16:21 +08:00
|
|
|
|
if let Some(master_key) = master_key {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
services().users.add_cross_signing_keys(
|
2022-03-05 10:16:21 +08:00
|
|
|
|
&user_id,
|
|
|
|
|
&master_key,
|
|
|
|
|
&self_signing_key,
|
|
|
|
|
&None,
|
|
|
|
|
)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-05-12 20:04:28 +02:00
|
|
|
|
Edu::_Custom(_) => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
Ok(send_transaction_message::v1::Response {
|
|
|
|
|
pdus: resolved_map
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(e, r)| (e, r.map_err(|e| e.to_string())))
|
|
|
|
|
.collect(),
|
|
|
|
|
})
|
2021-01-03 17:26:17 -05:00
|
|
|
|
}
|
2021-01-15 15:46:47 -05:00
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/event/{eventId}`
|
|
|
|
|
///
|
|
|
|
|
/// Retrieves a single event from the server.
|
|
|
|
|
///
|
|
|
|
|
/// - Only works if a user of this server is currently invited or joined the room
|
2022-01-20 11:51:31 +01:00
|
|
|
|
pub async fn get_event_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<get_event::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_event::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-04-07 15:56:57 +02:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let event = services()
|
2022-10-05 20:34:31 +02:00
|
|
|
|
.rooms
|
|
|
|
|
.timeline
|
2021-08-31 19:14:37 +02:00
|
|
|
|
.get_pdu_json(&body.event_id)?
|
|
|
|
|
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?;
|
|
|
|
|
|
|
|
|
|
let room_id_str = event
|
|
|
|
|
.get("room_id")
|
|
|
|
|
.and_then(|val| val.as_str())
|
|
|
|
|
.ok_or_else(|| Error::bad_database("Invalid event in database"))?;
|
|
|
|
|
|
2021-11-27 00:30:28 +01:00
|
|
|
|
let room_id = <&RoomId>::try_from(room_id_str)
|
2021-08-31 19:14:37 +02:00
|
|
|
|
.map_err(|_| Error::bad_database("Invalid room id field in event in database"))?;
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
if !services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_cache
|
|
|
|
|
.server_in_room(sender_servername, room_id)?
|
|
|
|
|
{
|
2022-01-17 14:35:38 +01:00
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::Forbidden,
|
|
|
|
|
"Server is not in room",
|
|
|
|
|
));
|
2021-08-31 19:14:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-07 15:56:57 +02:00
|
|
|
|
Ok(get_event::v1::Response {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
origin: services().globals.server_name().to_owned(),
|
2021-05-20 23:46:52 +02:00
|
|
|
|
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
|
2021-08-31 19:14:37 +02:00
|
|
|
|
pdu: PduEvent::convert_to_outgoing_federation_event(event),
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2021-04-07 15:56:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-15 19:13:17 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/backfill/<room_id>`
|
|
|
|
|
///
|
|
|
|
|
/// Retrieves events from before the sender joined the room, if the room's
|
|
|
|
|
/// history visibility allows.
|
|
|
|
|
pub async fn get_backfill_route(
|
|
|
|
|
body: Ruma<get_backfill::v1::IncomingRequest>,
|
|
|
|
|
) -> 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()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
|
|
|
|
info!("Got backfill request from: {}", sender_servername);
|
|
|
|
|
|
|
|
|
|
if !services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_cache
|
|
|
|
|
.server_in_room(sender_servername, &body.room_id)?
|
|
|
|
|
{
|
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::Forbidden,
|
|
|
|
|
"Server is not in room.",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-03 14:16:32 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
|
|
|
|
.acl_check(sender_servername, &body.room_id)?;
|
|
|
|
|
|
2022-01-15 19:13:17 +02:00
|
|
|
|
let origin = services().globals.server_name().to_owned();
|
|
|
|
|
let earliest_events = &[];
|
|
|
|
|
|
|
|
|
|
let events = get_missing_events(
|
|
|
|
|
sender_servername,
|
|
|
|
|
&body.room_id,
|
|
|
|
|
earliest_events,
|
|
|
|
|
&body.v,
|
|
|
|
|
body.limit,
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
Ok(get_backfill::v1::Response {
|
|
|
|
|
origin,
|
|
|
|
|
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
|
|
|
|
|
pdus: events,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `POST /_matrix/federation/v1/get_missing_events/{roomId}`
|
|
|
|
|
///
|
|
|
|
|
/// Retrieves events that the sender is missing.
|
2022-01-20 11:51:31 +01:00
|
|
|
|
pub async fn get_missing_events_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<get_missing_events::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_missing_events::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2020-11-14 23:13:06 +01:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
2020-10-06 21:04:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
if !services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_cache
|
|
|
|
|
.server_in_room(sender_servername, &body.room_id)?
|
|
|
|
|
{
|
2021-08-31 19:14:37 +02:00
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::Forbidden,
|
|
|
|
|
"Server is not in room",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.acl_check(sender_servername, &body.room_id)?;
|
2022-01-17 14:35:38 +01:00
|
|
|
|
|
2022-01-15 19:13:17 +02:00
|
|
|
|
let events = get_missing_events(
|
|
|
|
|
sender_servername,
|
|
|
|
|
&body.room_id,
|
|
|
|
|
&body.earliest_events,
|
|
|
|
|
&body.latest_events,
|
|
|
|
|
body.limit,
|
|
|
|
|
)?;
|
2020-09-25 12:26:29 +02:00
|
|
|
|
|
2022-01-15 19:13:17 +02:00
|
|
|
|
Ok(get_missing_events::v1::Response { events })
|
|
|
|
|
}
|
2021-08-31 19:14:37 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
/// Fetch events starting from `latest_events`, going backwards
|
|
|
|
|
/// through each event's `prev_events` until reaching the `earliest_events`.
|
|
|
|
|
///
|
|
|
|
|
/// Used by the federation /backfill and /get_missing_events routes.
|
2022-01-15 19:13:17 +02:00
|
|
|
|
fn get_missing_events(
|
|
|
|
|
sender_servername: &ServerName,
|
|
|
|
|
room_id: &RoomId,
|
|
|
|
|
earliest_events: &[OwnedEventId],
|
2022-01-22 18:26:28 +02:00
|
|
|
|
latest_events: &[OwnedEventId],
|
2022-01-15 19:13:17 +02:00
|
|
|
|
limit: UInt,
|
|
|
|
|
) -> Result<Vec<Box<RawJsonValue>>> {
|
2022-12-08 23:41:10 +02:00
|
|
|
|
let (room_members, room_errors): (Vec<_>, Vec<_>) = services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_cache
|
|
|
|
|
.room_members(room_id)
|
|
|
|
|
.partition(Result::is_ok);
|
2021-08-31 19:14:37 +02:00
|
|
|
|
|
2022-12-08 23:41:10 +02:00
|
|
|
|
// Just log errors and continue with correct users
|
|
|
|
|
if !room_errors.is_empty() {
|
|
|
|
|
warn!(?room_id, "Some errors occurred when fetching room members");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let current_server_members: Vec<OwnedUserId> = room_members
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(Result::unwrap)
|
|
|
|
|
.filter(|member| member.server_name() == sender_servername)
|
|
|
|
|
.collect();
|
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
let event_filter = |event_id: &EventId| {
|
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_accessor
|
|
|
|
|
.server_can_see_event(
|
|
|
|
|
sender_servername,
|
|
|
|
|
current_server_members.as_slice(),
|
|
|
|
|
event_id,
|
|
|
|
|
)
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
};
|
2022-01-15 19:13:17 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
let pdu_filter = |pdu: &CanonicalJsonObject| {
|
|
|
|
|
let event_room_id = pdu
|
|
|
|
|
.get("room_id")
|
|
|
|
|
.and_then(|val| val.as_str())
|
|
|
|
|
.and_then(|room_id_str| <&RoomId>::try_from(room_id_str).ok());
|
|
|
|
|
|
|
|
|
|
match event_room_id {
|
|
|
|
|
Some(event_room_id) => {
|
2022-12-14 18:02:35 +02:00
|
|
|
|
let valid_event = event_room_id == room_id;
|
2022-12-14 17:18:13 +02:00
|
|
|
|
if !valid_event {
|
|
|
|
|
error!(?room_id, ?event_room_id, "An evil event detected");
|
|
|
|
|
}
|
|
|
|
|
valid_event
|
2021-08-31 19:14:37 +02:00
|
|
|
|
}
|
2022-12-14 17:18:13 +02:00
|
|
|
|
None => {
|
|
|
|
|
error!(?pdu, "Can't extract valid `room_id` from pdu");
|
|
|
|
|
false
|
2021-08-31 19:14:37 +02:00
|
|
|
|
}
|
2022-12-14 17:18:13 +02:00
|
|
|
|
}
|
|
|
|
|
};
|
2021-04-14 10:43:31 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
#[inline]
|
|
|
|
|
fn get_pdu(event: &EventId) -> Option<CanonicalJsonObject> {
|
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.timeline
|
|
|
|
|
.get_pdu_json(event)
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
}
|
2022-01-15 19:13:17 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
let events = linearize_previous_events(
|
2022-12-16 08:57:35 +01:00
|
|
|
|
latest_events.iter().cloned(),
|
|
|
|
|
earliest_events.iter().cloned(),
|
2022-12-14 17:18:13 +02:00
|
|
|
|
limit,
|
|
|
|
|
get_pdu,
|
|
|
|
|
event_filter,
|
|
|
|
|
pdu_filter,
|
|
|
|
|
);
|
2022-01-15 19:13:17 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
Ok(events)
|
|
|
|
|
}
|
2021-08-31 19:14:37 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
/// Unwinds previous events by doing a breadth-first walk from given roots
|
|
|
|
|
///
|
|
|
|
|
/// # Arguments
|
|
|
|
|
///
|
|
|
|
|
/// * `roots`: Starting point to unwind event history
|
|
|
|
|
/// * `excluded`: Skipped events
|
|
|
|
|
/// * `limit`: How many events to extract
|
|
|
|
|
/// * `pdu_extractor`: Closure to extract PDU for given event_id, for example, from DB.
|
|
|
|
|
/// * `event_filter`: Closure to filter event by it's visiblity. It may or may not hit DB.
|
|
|
|
|
/// * `pdu_filter`: Closure to get basic validation against malformed PDUs.
|
|
|
|
|
///
|
|
|
|
|
/// # Returns
|
|
|
|
|
///
|
|
|
|
|
/// The previous events for given roots, without any `excluded` events, up to the provided `limit`.
|
|
|
|
|
///
|
|
|
|
|
/// # Note
|
|
|
|
|
///
|
|
|
|
|
/// In matrix specification, «Server-Server API», paragraph 8 there is no mention of previous events for excluded events.
|
|
|
|
|
/// Therefore, algorithm below excludes **only** events itself, but allows to process their history.
|
|
|
|
|
fn linearize_previous_events<E, L, F, V, P>(
|
|
|
|
|
roots: E,
|
|
|
|
|
excluded: E,
|
|
|
|
|
limit: L,
|
|
|
|
|
pdu_extractor: P,
|
|
|
|
|
event_filter: F,
|
|
|
|
|
pdu_filter: V,
|
|
|
|
|
) -> Vec<Box<RawJsonValue>>
|
|
|
|
|
where
|
|
|
|
|
E: IntoIterator<Item = OwnedEventId>,
|
|
|
|
|
F: Fn(&EventId) -> bool,
|
|
|
|
|
L: Into<u64>,
|
|
|
|
|
V: Fn(&CanonicalJsonObject) -> bool,
|
|
|
|
|
P: Fn(&EventId) -> Option<CanonicalJsonObject>,
|
|
|
|
|
{
|
|
|
|
|
let limit = limit.into() as usize;
|
|
|
|
|
assert!(limit > 0, "Limit should be > 0");
|
2021-08-31 19:14:37 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
#[inline]
|
|
|
|
|
fn get_previous_events(pdu: &CanonicalJsonObject) -> Option<Vec<OwnedEventId>> {
|
|
|
|
|
match pdu.get("prev_events") {
|
|
|
|
|
None => {
|
|
|
|
|
error!(?pdu, "A stored event has no 'prev_events' field");
|
2022-12-16 08:57:35 +01:00
|
|
|
|
None
|
2021-08-31 19:14:37 +02:00
|
|
|
|
}
|
2022-12-14 17:18:13 +02:00
|
|
|
|
Some(prev_events) => {
|
|
|
|
|
let val = prev_events.clone().into();
|
|
|
|
|
let events = serde_json::from_value::<Vec<OwnedEventId>>(val);
|
|
|
|
|
if let Err(error) = events {
|
|
|
|
|
error!(?prev_events, ?error, "Broken 'prev_events' field");
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
Some(events.unwrap_or_default())
|
2020-09-25 12:26:29 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
let mut visited: HashSet<OwnedEventId> = Default::default();
|
|
|
|
|
let mut history: Vec<Box<RawJsonValue>> = Default::default();
|
|
|
|
|
let mut queue: VecDeque<OwnedEventId> = Default::default();
|
|
|
|
|
let excluded: HashSet<_> = excluded.into_iter().collect();
|
2022-01-15 19:13:17 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
// Add all roots into processing queue
|
|
|
|
|
for root in roots {
|
|
|
|
|
queue.push_back(root);
|
|
|
|
|
}
|
2022-01-15 19:13:17 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
while let Some(current_event) = queue.pop_front() {
|
|
|
|
|
// Return all collected events if reached limit
|
|
|
|
|
if history.len() >= limit {
|
|
|
|
|
return history;
|
|
|
|
|
}
|
2022-01-15 19:13:17 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
// Skip an entire branch containing incorrect events
|
|
|
|
|
if !event_filter(¤t_event) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-11-28 01:43:17 +02:00
|
|
|
|
|
2022-12-14 17:18:13 +02:00
|
|
|
|
// Process PDU from a current event if it exists and valid
|
|
|
|
|
if let Some(pdu) = pdu_extractor(¤t_event).filter(&pdu_filter) {
|
|
|
|
|
if !&excluded.contains(¤t_event) {
|
|
|
|
|
history.push(PduEvent::convert_to_outgoing_federation_event(pdu.clone()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fetch previous events, if they exists
|
|
|
|
|
if let Some(previous_events) = get_previous_events(&pdu) {
|
|
|
|
|
for previous_event in previous_events {
|
|
|
|
|
if !visited.contains(&previous_event) {
|
|
|
|
|
visited.insert(previous_event.clone());
|
|
|
|
|
queue.push_back(previous_event);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-25 12:26:29 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-14 17:18:13 +02:00
|
|
|
|
// All done, return collected events
|
|
|
|
|
history
|
2020-09-25 12:26:29 +02:00
|
|
|
|
}
|
2020-10-05 22:19:22 +02:00
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/event_auth/{roomId}/{eventId}`
|
|
|
|
|
///
|
|
|
|
|
/// Retrieves the auth chain for a given event.
|
|
|
|
|
///
|
|
|
|
|
/// - This does not include the event itself
|
2022-01-20 11:51:31 +01:00
|
|
|
|
pub async fn get_event_authorization_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<get_event_authorization::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_event_authorization::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-06-14 11:36:18 +02:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
if !services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_cache
|
|
|
|
|
.server_in_room(sender_servername, &body.room_id)?
|
|
|
|
|
{
|
2022-01-17 14:35:38 +01:00
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::Forbidden,
|
|
|
|
|
"Server is not in room.",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.acl_check(sender_servername, &body.room_id)?;
|
2022-01-17 14:35:38 +01:00
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let event = services()
|
2022-10-05 20:34:31 +02:00
|
|
|
|
.rooms
|
|
|
|
|
.timeline
|
2021-08-31 19:14:37 +02:00
|
|
|
|
.get_pdu_json(&body.event_id)?
|
|
|
|
|
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?;
|
|
|
|
|
|
|
|
|
|
let room_id_str = event
|
|
|
|
|
.get("room_id")
|
|
|
|
|
.and_then(|val| val.as_str())
|
|
|
|
|
.ok_or_else(|| Error::bad_database("Invalid event in database"))?;
|
|
|
|
|
|
2021-11-27 00:30:28 +01:00
|
|
|
|
let room_id = <&RoomId>::try_from(room_id_str)
|
2021-08-31 19:14:37 +02:00
|
|
|
|
.map_err(|_| Error::bad_database("Invalid room id field in event in database"))?;
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
let auth_chain_ids = services()
|
|
|
|
|
.rooms
|
|
|
|
|
.auth_chain
|
|
|
|
|
.get_auth_chain(room_id, vec![Arc::from(&*body.event_id)])
|
|
|
|
|
.await?;
|
2021-06-14 11:36:18 +02:00
|
|
|
|
|
2021-07-18 20:43:39 +02:00
|
|
|
|
Ok(get_event_authorization::v1::Response {
|
|
|
|
|
auth_chain: auth_chain_ids
|
2022-10-05 09:34:25 +02:00
|
|
|
|
.filter_map(|id| services().rooms.timeline.get_pdu_json(&id).ok()?)
|
2021-08-26 17:58:32 -04:00
|
|
|
|
.map(PduEvent::convert_to_outgoing_federation_event)
|
2021-07-18 20:43:39 +02:00
|
|
|
|
.collect(),
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2021-06-14 11:36:18 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/state/{roomId}`
|
|
|
|
|
///
|
|
|
|
|
/// Retrieves the current state of the room.
|
2022-01-20 11:51:31 +01:00
|
|
|
|
pub async fn get_room_state_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<get_room_state::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_room_state::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-06-14 10:52:27 +02:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
if !services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_cache
|
|
|
|
|
.server_in_room(sender_servername, &body.room_id)?
|
|
|
|
|
{
|
2021-08-31 19:14:37 +02:00
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::Forbidden,
|
|
|
|
|
"Server is not in room.",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.acl_check(sender_servername, &body.room_id)?;
|
2022-01-17 14:35:38 +01:00
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let shortstatehash = services()
|
2022-10-05 20:34:31 +02:00
|
|
|
|
.rooms
|
|
|
|
|
.state_accessor
|
2021-06-14 10:52:27 +02:00
|
|
|
|
.pdu_shortstatehash(&body.event_id)?
|
|
|
|
|
.ok_or(Error::BadRequest(
|
|
|
|
|
ErrorKind::NotFound,
|
|
|
|
|
"Pdu state not found.",
|
|
|
|
|
))?;
|
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let pdus = services()
|
2022-10-05 20:34:31 +02:00
|
|
|
|
.rooms
|
|
|
|
|
.state_accessor
|
2022-06-18 16:38:41 +02:00
|
|
|
|
.state_full_ids(shortstatehash)
|
|
|
|
|
.await?
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.into_values()
|
|
|
|
|
.map(|id| {
|
2021-06-14 10:52:27 +02:00
|
|
|
|
PduEvent::convert_to_outgoing_federation_event(
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.timeline
|
|
|
|
|
.get_pdu_json(&id)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.unwrap(),
|
2021-06-14 10:52:27 +02:00
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
let auth_chain_ids = services()
|
|
|
|
|
.rooms
|
|
|
|
|
.auth_chain
|
|
|
|
|
.get_auth_chain(&body.room_id, vec![Arc::from(&*body.event_id)])
|
|
|
|
|
.await?;
|
2021-06-14 10:52:27 +02:00
|
|
|
|
|
2021-07-18 20:43:39 +02:00
|
|
|
|
Ok(get_room_state::v1::Response {
|
|
|
|
|
auth_chain: auth_chain_ids
|
2022-10-11 18:10:51 +02:00
|
|
|
|
.filter_map(
|
|
|
|
|
|id| match services().rooms.timeline.get_pdu_json(&id).ok()? {
|
|
|
|
|
Some(json) => Some(PduEvent::convert_to_outgoing_federation_event(json)),
|
|
|
|
|
None => {
|
|
|
|
|
error!("Could not find event json for {id} in db.");
|
|
|
|
|
None
|
2022-10-11 17:59:49 +02:00
|
|
|
|
}
|
2022-10-11 18:10:51 +02:00
|
|
|
|
},
|
|
|
|
|
)
|
2021-07-18 20:43:39 +02:00
|
|
|
|
.collect(),
|
|
|
|
|
pdus,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2021-06-14 10:52:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/state_ids/{roomId}`
|
|
|
|
|
///
|
|
|
|
|
/// Retrieves the current state of the room.
|
2022-01-20 11:51:31 +01:00
|
|
|
|
pub async fn get_room_state_ids_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<get_room_state_ids::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_room_state_ids::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-03-18 00:09:57 +01:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
if !services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_cache
|
|
|
|
|
.server_in_room(sender_servername, &body.room_id)?
|
|
|
|
|
{
|
2021-08-31 19:14:37 +02:00
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::Forbidden,
|
|
|
|
|
"Server is not in room.",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.acl_check(sender_servername, &body.room_id)?;
|
2022-01-17 14:35:38 +01:00
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let shortstatehash = services()
|
2022-10-05 20:34:31 +02:00
|
|
|
|
.rooms
|
|
|
|
|
.state_accessor
|
2021-03-18 00:09:57 +01:00
|
|
|
|
.pdu_shortstatehash(&body.event_id)?
|
|
|
|
|
.ok_or(Error::BadRequest(
|
|
|
|
|
ErrorKind::NotFound,
|
|
|
|
|
"Pdu state not found.",
|
|
|
|
|
))?;
|
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let pdu_ids = services()
|
2022-10-05 20:34:31 +02:00
|
|
|
|
.rooms
|
|
|
|
|
.state_accessor
|
2022-06-18 16:38:41 +02:00
|
|
|
|
.state_full_ids(shortstatehash)
|
|
|
|
|
.await?
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.into_values()
|
|
|
|
|
.map(|id| (*id).to_owned())
|
2021-07-01 19:55:26 +02:00
|
|
|
|
.collect();
|
2021-03-18 00:09:57 +01:00
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
let auth_chain_ids = services()
|
|
|
|
|
.rooms
|
|
|
|
|
.auth_chain
|
|
|
|
|
.get_auth_chain(&body.room_id, vec![Arc::from(&*body.event_id)])
|
|
|
|
|
.await?;
|
2021-03-18 00:09:57 +01:00
|
|
|
|
|
|
|
|
|
Ok(get_room_state_ids::v1::Response {
|
2021-11-26 20:36:40 +01:00
|
|
|
|
auth_chain_ids: auth_chain_ids.map(|id| (*id).to_owned()).collect(),
|
2021-03-18 00:09:57 +01:00
|
|
|
|
pdu_ids,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2021-03-18 00:09:57 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/make_join/{roomId}/{userId}`
|
|
|
|
|
///
|
|
|
|
|
/// Creates a join template.
|
2022-01-20 11:51:31 +01:00
|
|
|
|
pub async fn create_join_event_template_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<prepare_join_event::v1::IncomingRequest>,
|
2022-02-18 15:33:14 +01:00
|
|
|
|
) -> Result<prepare_join_event::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-04-16 18:18:29 +02:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 09:34:25 +02:00
|
|
|
|
if !services().rooms.metadata.exists(&body.room_id)? {
|
2021-04-16 18:18:29 +02:00
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::NotFound,
|
2022-01-17 14:35:38 +01:00
|
|
|
|
"Room is unknown to this server.",
|
2021-04-16 18:18:29 +02:00
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-17 14:35:38 +01:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.acl_check(sender_servername, &body.room_id)?;
|
2022-09-06 23:15:09 +02:00
|
|
|
|
|
|
|
|
|
let mutex_state = Arc::clone(
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.globals
|
2022-09-06 23:15:09 +02:00
|
|
|
|
.roomid_mutex_state
|
|
|
|
|
.write()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.entry(body.room_id.to_owned())
|
|
|
|
|
.or_default(),
|
|
|
|
|
);
|
|
|
|
|
let state_lock = mutex_state.lock().await;
|
2022-01-17 14:35:38 +01:00
|
|
|
|
|
2022-01-18 16:53:25 +01:00
|
|
|
|
// TODO: Conduit does not implement restricted join rules yet, we always reject
|
2022-10-05 20:34:31 +02:00
|
|
|
|
let join_rules_event = services().rooms.state_accessor.room_state_get(
|
|
|
|
|
&body.room_id,
|
|
|
|
|
&StateEventType::RoomJoinRules,
|
|
|
|
|
"",
|
|
|
|
|
)?;
|
2022-01-18 16:53:25 +01:00
|
|
|
|
|
|
|
|
|
let join_rules_event_content: Option<RoomJoinRulesEventContent> = join_rules_event
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|join_rules_event| {
|
|
|
|
|
serde_json::from_str(join_rules_event.content.get()).map_err(|e| {
|
|
|
|
|
warn!("Invalid join rules event: {}", e);
|
|
|
|
|
Error::bad_database("Invalid join rules event in db.")
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.transpose()?;
|
|
|
|
|
|
|
|
|
|
if let Some(join_rules_event_content) = join_rules_event_content {
|
|
|
|
|
if matches!(
|
|
|
|
|
join_rules_event_content.join_rule,
|
2022-10-11 11:53:13 +02:00
|
|
|
|
JoinRule::Restricted { .. } | JoinRule::KnockRestricted { .. }
|
2022-01-18 16:53:25 +01:00
|
|
|
|
) {
|
|
|
|
|
return Err(Error::BadRequest(
|
2022-10-11 11:53:13 +02:00
|
|
|
|
ErrorKind::UnableToAuthorizeJoin,
|
2022-01-18 16:53:25 +01:00
|
|
|
|
"Conduit does not support restricted rooms yet.",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 09:34:25 +02:00
|
|
|
|
let room_version_id = services().rooms.state.get_room_version(&body.room_id)?;
|
|
|
|
|
if !body.ver.contains(&room_version_id) {
|
2021-07-21 11:29:13 +02:00
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::IncompatibleRoomVersion {
|
|
|
|
|
room_version: room_version_id,
|
|
|
|
|
},
|
|
|
|
|
"Room version not supported.",
|
|
|
|
|
));
|
|
|
|
|
}
|
2021-04-16 18:18:29 +02:00
|
|
|
|
|
2021-10-13 10:16:45 +02:00
|
|
|
|
let content = to_raw_value(&RoomMemberEventContent {
|
2021-04-16 18:18:29 +02:00
|
|
|
|
avatar_url: None,
|
2021-07-15 23:17:58 +02:00
|
|
|
|
blurhash: None,
|
2021-04-16 18:18:29 +02:00
|
|
|
|
displayname: None,
|
|
|
|
|
is_direct: None,
|
|
|
|
|
membership: MembershipState::Join,
|
|
|
|
|
third_party_invite: None,
|
2021-08-19 11:01:18 +02:00
|
|
|
|
reason: None,
|
2021-11-27 17:44:52 +01:00
|
|
|
|
join_authorized_via_users_server: None,
|
2021-04-16 18:18:29 +02:00
|
|
|
|
})
|
|
|
|
|
.expect("member event is valid value");
|
|
|
|
|
|
2022-10-12 10:57:54 +02:00
|
|
|
|
let (_pdu, mut pdu_json) = services().rooms.timeline.create_hash_and_sign_event(
|
2022-10-05 20:34:31 +02:00
|
|
|
|
PduBuilder {
|
|
|
|
|
event_type: RoomEventType::RoomMember,
|
|
|
|
|
content,
|
|
|
|
|
unsigned: None,
|
|
|
|
|
state_key: Some(body.user_id.to_string()),
|
|
|
|
|
redacts: None,
|
|
|
|
|
},
|
|
|
|
|
&body.user_id,
|
|
|
|
|
&body.room_id,
|
|
|
|
|
&state_lock,
|
|
|
|
|
)?;
|
2021-04-16 18:18:29 +02:00
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
drop(state_lock);
|
2021-04-16 18:18:29 +02:00
|
|
|
|
|
2022-10-12 10:57:54 +02:00
|
|
|
|
pdu_json.remove("event_id");
|
|
|
|
|
|
2022-02-18 15:33:14 +01:00
|
|
|
|
Ok(prepare_join_event::v1::Response {
|
2021-07-21 11:29:13 +02:00
|
|
|
|
room_version: Some(room_version_id),
|
2021-10-13 10:16:45 +02:00
|
|
|
|
event: to_raw_value(&pdu_json).expect("CanonicalJson can be serialized to JSON"),
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2021-04-16 18:18:29 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-25 19:28:54 +02:00
|
|
|
|
async fn create_join_event(
|
2022-01-17 14:35:38 +01:00
|
|
|
|
sender_servername: &ServerName,
|
2021-07-25 19:28:54 +02:00
|
|
|
|
room_id: &RoomId,
|
2021-10-13 10:16:45 +02:00
|
|
|
|
pdu: &RawJsonValue,
|
2021-07-25 19:28:54 +02:00
|
|
|
|
) -> Result<RoomState> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-04-16 18:18:29 +02:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 09:34:25 +02:00
|
|
|
|
if !services().rooms.metadata.exists(room_id)? {
|
2022-01-17 14:35:38 +01:00
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::NotFound,
|
|
|
|
|
"Room is unknown to this server.",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.acl_check(sender_servername, room_id)?;
|
2022-01-17 14:35:38 +01:00
|
|
|
|
|
2022-01-18 16:53:25 +01:00
|
|
|
|
// TODO: Conduit does not implement restricted join rules yet, we always reject
|
2022-10-05 20:34:31 +02:00
|
|
|
|
let join_rules_event = services().rooms.state_accessor.room_state_get(
|
|
|
|
|
room_id,
|
|
|
|
|
&StateEventType::RoomJoinRules,
|
|
|
|
|
"",
|
|
|
|
|
)?;
|
2022-01-18 16:53:25 +01:00
|
|
|
|
|
|
|
|
|
let join_rules_event_content: Option<RoomJoinRulesEventContent> = join_rules_event
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|join_rules_event| {
|
|
|
|
|
serde_json::from_str(join_rules_event.content.get()).map_err(|e| {
|
|
|
|
|
warn!("Invalid join rules event: {}", e);
|
|
|
|
|
Error::bad_database("Invalid join rules event in db.")
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.transpose()?;
|
|
|
|
|
|
|
|
|
|
if let Some(join_rules_event_content) = join_rules_event_content {
|
|
|
|
|
if matches!(
|
|
|
|
|
join_rules_event_content.join_rule,
|
2022-10-11 11:53:13 +02:00
|
|
|
|
JoinRule::Restricted { .. } | JoinRule::KnockRestricted { .. }
|
2022-01-18 16:53:25 +01:00
|
|
|
|
) {
|
|
|
|
|
return Err(Error::BadRequest(
|
2022-10-11 11:53:13 +02:00
|
|
|
|
ErrorKind::UnableToAuthorizeJoin,
|
2022-01-18 16:53:25 +01:00
|
|
|
|
"Conduit does not support restricted rooms yet.",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-16 18:18:29 +02:00
|
|
|
|
// We need to return the state prior to joining, let's keep a reference to that here
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let shortstatehash = services()
|
2022-10-05 20:34:31 +02:00
|
|
|
|
.rooms
|
|
|
|
|
.state
|
2022-10-05 09:34:25 +02:00
|
|
|
|
.get_room_shortstatehash(room_id)?
|
2021-07-25 19:28:54 +02:00
|
|
|
|
.ok_or(Error::BadRequest(
|
|
|
|
|
ErrorKind::NotFound,
|
|
|
|
|
"Pdu state not found.",
|
|
|
|
|
))?;
|
2021-04-16 18:18:29 +02:00
|
|
|
|
|
|
|
|
|
let pub_key_map = RwLock::new(BTreeMap::new());
|
2021-06-29 20:18:52 -04:00
|
|
|
|
// let mut auth_cache = EventMap::new();
|
2021-04-16 18:18:29 +02:00
|
|
|
|
|
|
|
|
|
// We do not add the event_id field to the pdu here because of signature and hashes checks
|
2022-11-27 23:25:42 +01:00
|
|
|
|
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) {
|
2021-04-16 18:18:29 +02:00
|
|
|
|
Ok(t) => t,
|
|
|
|
|
Err(_) => {
|
|
|
|
|
// Event could not be converted to canonical json
|
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::InvalidParam,
|
|
|
|
|
"Could not convert event to canonical json.",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-10-09 17:25:06 +02:00
|
|
|
|
let origin: OwnedServerName = serde_json::from_value(
|
2021-04-16 18:18:29 +02:00
|
|
|
|
serde_json::to_value(value.get("origin").ok_or(Error::BadRequest(
|
|
|
|
|
ErrorKind::InvalidParam,
|
|
|
|
|
"Event needs an origin field.",
|
|
|
|
|
))?)
|
|
|
|
|
.expect("CanonicalJson is valid json value"),
|
|
|
|
|
)
|
|
|
|
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Origin field is invalid."))?;
|
|
|
|
|
|
2021-07-01 19:55:26 +02:00
|
|
|
|
let mutex = Arc::clone(
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.globals
|
2021-07-13 15:44:25 +02:00
|
|
|
|
.roomid_mutex_federation
|
2021-07-01 19:55:26 +02:00
|
|
|
|
.write()
|
|
|
|
|
.unwrap()
|
2021-11-26 20:36:40 +01:00
|
|
|
|
.entry(room_id.to_owned())
|
2021-07-01 19:55:26 +02:00
|
|
|
|
.or_default(),
|
|
|
|
|
);
|
|
|
|
|
let mutex_lock = mutex.lock().await;
|
2022-10-05 20:34:31 +02:00
|
|
|
|
let pdu_id: Vec<u8> = services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
|
|
|
|
.handle_incoming_pdu(&origin, &event_id, room_id, value, true, &pub_key_map)
|
2022-10-05 09:34:25 +02:00
|
|
|
|
.await?
|
2021-07-25 19:28:54 +02:00
|
|
|
|
.ok_or(Error::BadRequest(
|
2021-04-16 18:18:29 +02:00
|
|
|
|
ErrorKind::InvalidParam,
|
2021-07-25 19:28:54 +02:00
|
|
|
|
"Could not accept incoming PDU as timeline event.",
|
|
|
|
|
))?;
|
2021-07-01 19:55:26 +02:00
|
|
|
|
drop(mutex_lock);
|
2021-04-16 18:18:29 +02:00
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
let state_ids = services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_accessor
|
|
|
|
|
.state_full_ids(shortstatehash)
|
|
|
|
|
.await?;
|
|
|
|
|
let auth_chain_ids = services()
|
|
|
|
|
.rooms
|
|
|
|
|
.auth_chain
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.get_auth_chain(room_id, state_ids.values().cloned().collect())
|
2022-10-05 20:34:31 +02:00
|
|
|
|
.await?;
|
2021-04-16 18:18:29 +02:00
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let servers = services()
|
2021-04-16 18:18:29 +02:00
|
|
|
|
.rooms
|
2022-10-05 09:34:25 +02:00
|
|
|
|
.state_cache
|
2021-09-13 19:45:56 +02:00
|
|
|
|
.room_servers(room_id)
|
2021-04-16 18:18:29 +02:00
|
|
|
|
.filter_map(|r| r.ok())
|
2022-09-06 23:15:09 +02:00
|
|
|
|
.filter(|server| &**server != services().globals.server_name());
|
2021-04-16 18:18:29 +02:00
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
services().sending.send_pdu(servers, &pdu_id)?;
|
2021-07-14 07:07:08 +00:00
|
|
|
|
|
2021-07-25 19:28:54 +02:00
|
|
|
|
Ok(RoomState {
|
|
|
|
|
auth_chain: auth_chain_ids
|
2022-10-05 09:34:25 +02:00
|
|
|
|
.filter_map(|id| services().rooms.timeline.get_pdu_json(&id).ok().flatten())
|
2021-07-25 19:28:54 +02:00
|
|
|
|
.map(PduEvent::convert_to_outgoing_federation_event)
|
|
|
|
|
.collect(),
|
|
|
|
|
state: state_ids
|
|
|
|
|
.iter()
|
2022-10-05 09:34:25 +02:00
|
|
|
|
.filter_map(|(_, id)| services().rooms.timeline.get_pdu_json(id).ok().flatten())
|
2021-07-25 19:28:54 +02:00
|
|
|
|
.map(PduEvent::convert_to_outgoing_federation_event)
|
|
|
|
|
.collect(),
|
2022-11-09 18:46:10 +01:00
|
|
|
|
event: None, // TODO: handle restricted joins
|
2021-07-25 19:28:54 +02:00
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `PUT /_matrix/federation/v1/send_join/{roomId}/{eventId}`
|
|
|
|
|
///
|
|
|
|
|
/// Submits a signed join event.
|
2021-07-25 19:28:54 +02:00
|
|
|
|
pub async fn create_join_event_v1_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<create_join_event::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<create_join_event::v1::Response> {
|
2022-01-17 14:35:38 +01:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let room_state = create_join_event(sender_servername, &body.room_id, &body.pdu).await?;
|
2021-07-25 19:28:54 +02:00
|
|
|
|
|
2022-01-22 16:58:32 +01:00
|
|
|
|
Ok(create_join_event::v1::Response { room_state })
|
2021-07-25 19:28:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `PUT /_matrix/federation/v2/send_join/{roomId}/{eventId}`
|
|
|
|
|
///
|
|
|
|
|
/// Submits a signed join event.
|
2021-07-25 19:28:54 +02:00
|
|
|
|
pub async fn create_join_event_v2_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<create_join_event::v2::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<create_join_event::v2::Response> {
|
2022-01-17 14:35:38 +01:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let room_state = create_join_event(sender_servername, &body.room_id, &body.pdu).await?;
|
2021-07-25 19:28:54 +02:00
|
|
|
|
|
2022-01-22 16:58:32 +01:00
|
|
|
|
Ok(create_join_event::v2::Response { room_state })
|
2021-04-16 18:18:29 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`
|
|
|
|
|
///
|
|
|
|
|
/// Invites a remote user to a room.
|
2021-06-08 18:10:00 +02:00
|
|
|
|
pub async fn create_invite_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<create_invite::v2::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<create_invite::v2::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-04-16 18:18:29 +02:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-17 14:35:38 +01:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.event_handler
|
2022-10-10 14:09:11 +02:00
|
|
|
|
.acl_check(sender_servername, &body.room_id)?;
|
2022-01-17 14:35:38 +01:00
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
if !services()
|
|
|
|
|
.globals
|
|
|
|
|
.supported_room_versions()
|
|
|
|
|
.contains(&body.room_version)
|
|
|
|
|
{
|
2021-04-11 21:01:27 +02:00
|
|
|
|
return Err(Error::BadRequest(
|
|
|
|
|
ErrorKind::IncompatibleRoomVersion {
|
|
|
|
|
room_version: body.room_version.clone(),
|
|
|
|
|
},
|
|
|
|
|
"Server does not support this room version.",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut signed_event = utils::to_canonical_object(&body.event)
|
|
|
|
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invite event is invalid."))?;
|
|
|
|
|
|
|
|
|
|
ruma::signatures::hash_and_sign_event(
|
2022-09-06 23:15:09 +02:00
|
|
|
|
services().globals.server_name().as_str(),
|
|
|
|
|
services().globals.keypair(),
|
2021-04-11 21:01:27 +02:00
|
|
|
|
&mut signed_event,
|
|
|
|
|
&body.room_version,
|
|
|
|
|
)
|
|
|
|
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Failed to sign event."))?;
|
|
|
|
|
|
2021-04-13 21:34:31 +02:00
|
|
|
|
// Generate event id
|
2021-11-27 00:30:28 +01:00
|
|
|
|
let event_id = EventId::parse(format!(
|
2021-04-13 21:34:31 +02:00
|
|
|
|
"${}",
|
|
|
|
|
ruma::signatures::reference_hash(&signed_event, &body.room_version)
|
|
|
|
|
.expect("ruma can calculate reference hashes")
|
|
|
|
|
))
|
|
|
|
|
.expect("ruma's reference hashes are valid event ids");
|
|
|
|
|
|
|
|
|
|
// Add event_id back
|
|
|
|
|
signed_event.insert(
|
|
|
|
|
"event_id".to_owned(),
|
2022-10-09 17:25:06 +02:00
|
|
|
|
CanonicalJsonValue::String(event_id.to_string()),
|
2021-04-13 21:34:31 +02:00
|
|
|
|
);
|
|
|
|
|
|
2022-10-09 17:25:06 +02:00
|
|
|
|
let sender: OwnedUserId = serde_json::from_value(
|
2021-04-26 18:20:20 +02:00
|
|
|
|
signed_event
|
|
|
|
|
.get("sender")
|
|
|
|
|
.ok_or(Error::BadRequest(
|
|
|
|
|
ErrorKind::InvalidParam,
|
|
|
|
|
"Event had no sender field.",
|
|
|
|
|
))?
|
|
|
|
|
.clone()
|
|
|
|
|
.into(),
|
2021-04-11 21:01:27 +02:00
|
|
|
|
)
|
|
|
|
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "sender is not a user id."))?;
|
2021-04-26 18:20:20 +02:00
|
|
|
|
|
2021-11-26 20:36:40 +01:00
|
|
|
|
let invited_user: Box<_> = serde_json::from_value(
|
2021-04-26 18:20:20 +02:00
|
|
|
|
signed_event
|
|
|
|
|
.get("state_key")
|
|
|
|
|
.ok_or(Error::BadRequest(
|
|
|
|
|
ErrorKind::InvalidParam,
|
|
|
|
|
"Event had no state_key field.",
|
|
|
|
|
))?
|
|
|
|
|
.clone()
|
|
|
|
|
.into(),
|
2021-04-11 21:01:27 +02:00
|
|
|
|
)
|
|
|
|
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "state_key is not a user id."))?;
|
|
|
|
|
|
|
|
|
|
let mut invite_state = body.invite_room_state.clone();
|
|
|
|
|
|
2021-10-13 11:51:30 +02:00
|
|
|
|
let mut event: JsonObject = serde_json::from_str(body.event.get())
|
|
|
|
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid invite event bytes."))?;
|
2021-04-11 21:01:27 +02:00
|
|
|
|
|
|
|
|
|
event.insert("event_id".to_owned(), "$dummy".into());
|
|
|
|
|
|
2021-10-13 11:51:30 +02:00
|
|
|
|
let pdu: PduEvent = serde_json::from_value(event.into()).map_err(|e| {
|
2021-04-13 21:34:31 +02:00
|
|
|
|
warn!("Invalid invite event: {}", e);
|
|
|
|
|
Error::BadRequest(ErrorKind::InvalidParam, "Invalid invite event.")
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
invite_state.push(pdu.to_stripped_state_event());
|
|
|
|
|
|
2022-11-27 23:25:42 +01:00
|
|
|
|
// If we are active in the room, the remote server will notify us about the join via /send
|
|
|
|
|
if !services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_cache
|
|
|
|
|
.server_in_room(services().globals.server_name(), &body.room_id)?
|
|
|
|
|
{
|
2022-10-05 09:34:25 +02:00
|
|
|
|
services().rooms.state_cache.update_membership(
|
2021-04-13 21:34:31 +02:00
|
|
|
|
&body.room_id,
|
|
|
|
|
&invited_user,
|
|
|
|
|
MembershipState::Invite,
|
|
|
|
|
&sender,
|
|
|
|
|
Some(invite_state),
|
2021-08-17 00:22:52 +02:00
|
|
|
|
true,
|
2021-04-13 21:34:31 +02:00
|
|
|
|
)?;
|
|
|
|
|
}
|
2021-04-11 21:01:27 +02:00
|
|
|
|
|
|
|
|
|
Ok(create_invite::v2::Response {
|
|
|
|
|
event: PduEvent::convert_to_outgoing_federation_event(signed_event),
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2021-04-11 21:01:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/user/devices/{userId}`
|
|
|
|
|
///
|
|
|
|
|
/// Gets information on all devices of the user.
|
2022-01-20 11:51:31 +01:00
|
|
|
|
pub async fn get_devices_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<get_devices::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_devices::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-04-21 10:51:34 +02:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-06 18:49:46 +02:00
|
|
|
|
let sender_servername = body
|
|
|
|
|
.sender_servername
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("server is authenticated");
|
|
|
|
|
|
2021-04-21 10:51:34 +02:00
|
|
|
|
Ok(get_devices::v1::Response {
|
|
|
|
|
user_id: body.user_id.clone(),
|
2022-09-06 23:15:09 +02:00
|
|
|
|
stream_id: services()
|
2021-04-21 10:51:34 +02:00
|
|
|
|
.users
|
|
|
|
|
.get_devicelist_version(&body.user_id)?
|
|
|
|
|
.unwrap_or(0)
|
|
|
|
|
.try_into()
|
|
|
|
|
.expect("version will not grow that large"),
|
2022-09-06 23:15:09 +02:00
|
|
|
|
devices: services()
|
2021-04-21 10:51:34 +02:00
|
|
|
|
.users
|
|
|
|
|
.all_devices_metadata(&body.user_id)
|
|
|
|
|
.filter_map(|r| r.ok())
|
|
|
|
|
.filter_map(|metadata| {
|
|
|
|
|
Some(UserDevice {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
keys: services()
|
2021-04-21 10:51:34 +02:00
|
|
|
|
.users
|
|
|
|
|
.get_device_keys(&body.user_id, &metadata.device_id)
|
|
|
|
|
.ok()??,
|
|
|
|
|
device_id: metadata.device_id,
|
|
|
|
|
device_display_name: metadata.display_name,
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.collect(),
|
2022-09-06 23:15:09 +02:00
|
|
|
|
master_key: services()
|
2022-03-05 10:16:21 +08:00
|
|
|
|
.users
|
2022-10-05 15:33:57 +02:00
|
|
|
|
.get_master_key(&body.user_id, &|u| u.server_name() == sender_servername)?,
|
2022-09-06 23:15:09 +02:00
|
|
|
|
self_signing_key: services()
|
2022-03-05 10:16:21 +08:00
|
|
|
|
.users
|
2022-10-05 15:33:57 +02:00
|
|
|
|
.get_self_signing_key(&body.user_id, &|u| u.server_name() == sender_servername)?,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2021-04-21 10:51:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/query/directory`
|
|
|
|
|
///
|
|
|
|
|
/// Resolve a room alias to a room id.
|
2022-01-20 11:51:31 +01:00
|
|
|
|
pub async fn get_room_information_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<get_room_information::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_room_information::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-04-16 18:18:29 +02:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let room_id = services()
|
2021-04-16 18:18:29 +02:00
|
|
|
|
.rooms
|
2022-10-05 20:34:31 +02:00
|
|
|
|
.alias
|
|
|
|
|
.resolve_local_alias(&body.room_alias)?
|
2021-04-21 14:06:39 +02:00
|
|
|
|
.ok_or(Error::BadRequest(
|
|
|
|
|
ErrorKind::NotFound,
|
|
|
|
|
"Room alias not found.",
|
|
|
|
|
))?;
|
2021-04-16 18:18:29 +02:00
|
|
|
|
|
|
|
|
|
Ok(get_room_information::v1::Response {
|
|
|
|
|
room_id,
|
2022-09-06 23:15:09 +02:00
|
|
|
|
servers: vec![services().globals.server_name().to_owned()],
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2021-04-16 18:18:29 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `GET /_matrix/federation/v1/query/profile`
|
|
|
|
|
///
|
|
|
|
|
/// Gets information on a profile.
|
2022-01-20 11:51:31 +01:00
|
|
|
|
pub async fn get_profile_information_route(
|
2022-04-06 21:31:29 +02:00
|
|
|
|
body: Ruma<get_profile_information::v1::IncomingRequest>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<get_profile_information::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2020-11-14 23:13:06 +01:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
2020-10-06 21:04:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-05 22:19:22 +02:00
|
|
|
|
let mut displayname = None;
|
|
|
|
|
let mut avatar_url = None;
|
2021-07-15 23:17:58 +02:00
|
|
|
|
let mut blurhash = None;
|
2020-10-05 22:19:22 +02:00
|
|
|
|
|
2020-12-04 18:16:17 -05:00
|
|
|
|
match &body.field {
|
2022-10-05 20:34:31 +02:00
|
|
|
|
Some(ProfileField::DisplayName) => {
|
|
|
|
|
displayname = services().users.displayname(&body.user_id)?
|
|
|
|
|
}
|
2021-07-15 23:17:58 +02:00
|
|
|
|
Some(ProfileField::AvatarUrl) => {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
avatar_url = services().users.avatar_url(&body.user_id)?;
|
|
|
|
|
blurhash = services().users.blurhash(&body.user_id)?
|
2021-07-15 23:17:58 +02:00
|
|
|
|
}
|
2021-07-15 19:54:04 +02:00
|
|
|
|
// TODO: what to do with custom
|
|
|
|
|
Some(_) => {}
|
2020-10-05 22:19:22 +02:00
|
|
|
|
None => {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
displayname = services().users.displayname(&body.user_id)?;
|
|
|
|
|
avatar_url = services().users.avatar_url(&body.user_id)?;
|
|
|
|
|
blurhash = services().users.blurhash(&body.user_id)?;
|
2020-10-05 22:19:22 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(get_profile_information::v1::Response {
|
2021-07-15 23:17:58 +02:00
|
|
|
|
blurhash,
|
2020-10-05 22:19:22 +02:00
|
|
|
|
displayname,
|
|
|
|
|
avatar_url,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2020-10-05 22:19:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `POST /_matrix/federation/v1/user/keys/query`
|
|
|
|
|
///
|
|
|
|
|
/// Gets devices and identity keys for the given users.
|
2022-10-05 20:34:31 +02:00
|
|
|
|
pub async fn get_keys_route(body: Ruma<get_keys::v1::Request>) -> Result<get_keys::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-05-20 23:46:52 +02:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 20:34:31 +02:00
|
|
|
|
let result = get_keys_helper(None, &body.device_keys, |u| {
|
|
|
|
|
Some(u.server_name()) == body.sender_servername.as_deref()
|
|
|
|
|
})
|
2021-07-20 19:40:25 +02:00
|
|
|
|
.await?;
|
2021-05-20 23:46:52 +02:00
|
|
|
|
|
|
|
|
|
Ok(get_keys::v1::Response {
|
|
|
|
|
device_keys: result.device_keys,
|
|
|
|
|
master_keys: result.master_keys,
|
|
|
|
|
self_signing_keys: result.self_signing_keys,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2021-05-20 23:46:52 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 19:14:37 +02:00
|
|
|
|
/// # `POST /_matrix/federation/v1/user/keys/claim`
|
|
|
|
|
///
|
|
|
|
|
/// Claims one-time keys.
|
2021-06-08 18:10:00 +02:00
|
|
|
|
pub async fn claim_keys_route(
|
2021-05-28 13:44:40 +02:00
|
|
|
|
body: Ruma<claim_keys::v1::Request>,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
) -> Result<claim_keys::v1::Response> {
|
2022-09-06 23:15:09 +02:00
|
|
|
|
if !services().globals.allow_federation() {
|
2021-05-28 13:44:40 +02:00
|
|
|
|
return Err(Error::bad_config("Federation is disabled."));
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-06 23:15:09 +02:00
|
|
|
|
let result = claim_keys_helper(&body.one_time_keys).await?;
|
2021-05-28 13:44:40 +02:00
|
|
|
|
|
|
|
|
|
Ok(claim_keys::v1::Response {
|
|
|
|
|
one_time_keys: result.one_time_keys,
|
2022-01-22 16:58:32 +01:00
|
|
|
|
})
|
2021-05-28 13:44:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-08 12:34:46 +01:00
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
2022-12-16 08:57:35 +01:00
|
|
|
|
use super::{add_port_to_hostname, get_ip_with_port, linearize_previous_events, FedDest};
|
2022-12-14 17:19:01 +02:00
|
|
|
|
use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId};
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
2022-12-16 08:57:35 +01:00
|
|
|
|
use serde_json::{value::RawValue, Value};
|
2022-12-14 17:19:01 +02:00
|
|
|
|
use std::collections::HashMap;
|
2020-12-08 12:34:46 +01:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn ips_get_default_ports() {
|
|
|
|
|
assert_eq!(
|
2021-04-21 00:35:44 -03:00
|
|
|
|
get_ip_with_port("1.1.1.1"),
|
|
|
|
|
Some(FedDest::Literal("1.1.1.1:8448".parse().unwrap()))
|
2020-12-08 12:34:46 +01:00
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
2021-04-21 00:35:44 -03:00
|
|
|
|
get_ip_with_port("dead:beef::"),
|
|
|
|
|
Some(FedDest::Literal("[dead:beef::]:8448".parse().unwrap()))
|
2020-12-08 12:34:46 +01:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn ips_keep_custom_ports() {
|
|
|
|
|
assert_eq!(
|
2021-04-21 00:35:44 -03:00
|
|
|
|
get_ip_with_port("1.1.1.1:1234"),
|
|
|
|
|
Some(FedDest::Literal("1.1.1.1:1234".parse().unwrap()))
|
2020-12-08 12:34:46 +01:00
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
2021-04-21 00:35:44 -03:00
|
|
|
|
get_ip_with_port("[dead::beef]:8933"),
|
|
|
|
|
Some(FedDest::Literal("[dead::beef]:8933".parse().unwrap()))
|
2020-12-08 12:34:46 +01:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn hostnames_get_default_ports() {
|
|
|
|
|
assert_eq!(
|
2021-04-21 00:35:44 -03:00
|
|
|
|
add_port_to_hostname("example.com"),
|
|
|
|
|
FedDest::Named(String::from("example.com"), String::from(":8448"))
|
2020-12-08 12:34:46 +01:00
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn hostnames_keep_custom_ports() {
|
|
|
|
|
assert_eq!(
|
2021-04-21 00:35:44 -03:00
|
|
|
|
add_port_to_hostname("example.com:1337"),
|
|
|
|
|
FedDest::Named(String::from("example.com"), String::from(":1337"))
|
2020-12-08 12:34:46 +01:00
|
|
|
|
)
|
|
|
|
|
}
|
2022-12-14 17:19:01 +02:00
|
|
|
|
|
|
|
|
|
type PduStorage = HashMap<OwnedEventId, CanonicalJsonObject>;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
|
struct MockPDU {
|
|
|
|
|
content: i32,
|
|
|
|
|
prev_events: Vec<OwnedEventId>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn mock_event_id(id: &i32) -> OwnedEventId {
|
|
|
|
|
const DOMAIN: &str = "canterlot.eq";
|
|
|
|
|
<OwnedEventId>::try_from(format!("${id}:{DOMAIN}")).unwrap()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn create_graph(data: Vec<(i32, Vec<i32>)>) -> PduStorage {
|
|
|
|
|
data.iter()
|
|
|
|
|
.map(|(head, tail)| {
|
|
|
|
|
let key = mock_event_id(head);
|
|
|
|
|
let pdu = MockPDU {
|
|
|
|
|
content: *head,
|
|
|
|
|
prev_events: tail.iter().map(mock_event_id).collect(),
|
|
|
|
|
};
|
|
|
|
|
let value = serde_json::to_value(pdu).unwrap();
|
|
|
|
|
let value: CanonicalJsonValue = value.try_into().unwrap();
|
|
|
|
|
(key, value.as_object().unwrap().to_owned())
|
|
|
|
|
})
|
|
|
|
|
.collect()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn mock_full_graph() -> PduStorage {
|
|
|
|
|
/*
|
|
|
|
|
(1)
|
|
|
|
|
__________|___________
|
|
|
|
|
/ / \ \
|
|
|
|
|
(2) (3) (10) (11)
|
|
|
|
|
/ \ / \ | |
|
|
|
|
|
(4) (5) (6) (7) (12) (13)
|
|
|
|
|
| | |
|
|
|
|
|
(8) (9) (14)
|
|
|
|
|
\ /
|
|
|
|
|
(15)
|
|
|
|
|
|
|
|
|
|
|
(16)
|
|
|
|
|
*/
|
|
|
|
|
create_graph(vec![
|
|
|
|
|
(1, vec![2, 3, 10, 11]),
|
|
|
|
|
(2, vec![4, 5]),
|
|
|
|
|
(3, vec![6, 7]),
|
|
|
|
|
(4, vec![]),
|
|
|
|
|
(5, vec![8]),
|
|
|
|
|
(6, vec![9]),
|
|
|
|
|
(7, vec![]),
|
|
|
|
|
(8, vec![15]),
|
|
|
|
|
(9, vec![15]),
|
|
|
|
|
(10, vec![12]),
|
|
|
|
|
(11, vec![13]),
|
|
|
|
|
(12, vec![]),
|
|
|
|
|
(13, vec![14]),
|
|
|
|
|
(14, vec![]),
|
|
|
|
|
(15, vec![16]),
|
|
|
|
|
(16, vec![16]),
|
|
|
|
|
])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn extract_events_payload(events: Vec<Box<RawValue>>) -> Vec<i32> {
|
|
|
|
|
events
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|e| serde_json::from_str(e.get()).unwrap())
|
|
|
|
|
.map(|p: MockPDU| p.content)
|
|
|
|
|
.collect()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn backfill_empty() {
|
|
|
|
|
let events = linearize_previous_events(
|
|
|
|
|
vec![],
|
|
|
|
|
vec![],
|
|
|
|
|
16u64,
|
|
|
|
|
|_| unreachable!(),
|
|
|
|
|
|_| true,
|
|
|
|
|
|_| true,
|
|
|
|
|
);
|
|
|
|
|
assert!(events.is_empty());
|
|
|
|
|
}
|
|
|
|
|
#[test]
|
|
|
|
|
fn backfill_limit() {
|
|
|
|
|
/*
|
|
|
|
|
(5) → (4) → (3) → (2) → (1) → ×
|
|
|
|
|
*/
|
|
|
|
|
let events = create_graph(vec![
|
|
|
|
|
(1, vec![]),
|
|
|
|
|
(2, vec![1]),
|
|
|
|
|
(3, vec![2]),
|
|
|
|
|
(4, vec![3]),
|
|
|
|
|
(5, vec![4]),
|
|
|
|
|
]);
|
|
|
|
|
let roots = vec![mock_event_id(&5)];
|
|
|
|
|
let result = linearize_previous_events(
|
|
|
|
|
roots,
|
|
|
|
|
vec![],
|
|
|
|
|
3u64,
|
|
|
|
|
|e| events.get(e).cloned(),
|
|
|
|
|
|_| true,
|
|
|
|
|
|_| true,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(extract_events_payload(result), vec![5, 4, 3])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn backfill_bfs() {
|
|
|
|
|
let events = mock_full_graph();
|
|
|
|
|
let roots = vec![mock_event_id(&1)];
|
|
|
|
|
let result = linearize_previous_events(
|
|
|
|
|
roots,
|
|
|
|
|
vec![],
|
|
|
|
|
100u64,
|
|
|
|
|
|e| events.get(e).cloned(),
|
|
|
|
|
|_| true,
|
|
|
|
|
|_| true,
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
extract_events_payload(result),
|
|
|
|
|
vec![1, 2, 3, 10, 11, 4, 5, 6, 7, 12, 13, 8, 9, 14, 15, 16]
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn backfill_subgraph() {
|
|
|
|
|
let events = mock_full_graph();
|
|
|
|
|
let roots = vec![mock_event_id(&3)];
|
|
|
|
|
let result = linearize_previous_events(
|
|
|
|
|
roots,
|
|
|
|
|
vec![],
|
|
|
|
|
100u64,
|
|
|
|
|
|e| events.get(e).cloned(),
|
|
|
|
|
|_| true,
|
|
|
|
|
|_| true,
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(extract_events_payload(result), vec![3, 6, 7, 9, 15, 16])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn backfill_two_roots() {
|
|
|
|
|
let events = mock_full_graph();
|
|
|
|
|
let roots = vec![mock_event_id(&3), mock_event_id(&11)];
|
|
|
|
|
let result = linearize_previous_events(
|
|
|
|
|
roots,
|
|
|
|
|
vec![],
|
|
|
|
|
100u64,
|
|
|
|
|
|e| events.get(e).cloned(),
|
|
|
|
|
|_| true,
|
|
|
|
|
|_| true,
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
extract_events_payload(result),
|
|
|
|
|
vec![3, 11, 6, 7, 13, 9, 14, 15, 16]
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn backfill_exclude_events() {
|
|
|
|
|
let events = mock_full_graph();
|
|
|
|
|
let roots = vec![mock_event_id(&1)];
|
|
|
|
|
let excluded_events = vec![
|
|
|
|
|
mock_event_id(&14),
|
|
|
|
|
mock_event_id(&15),
|
|
|
|
|
mock_event_id(&16),
|
|
|
|
|
mock_event_id(&3),
|
|
|
|
|
];
|
|
|
|
|
let result = linearize_previous_events(
|
|
|
|
|
roots,
|
|
|
|
|
excluded_events,
|
|
|
|
|
100u64,
|
|
|
|
|
|e| events.get(e).cloned(),
|
|
|
|
|
|_| true,
|
|
|
|
|
|_| true,
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
extract_events_payload(result),
|
|
|
|
|
vec![1, 2, 10, 11, 4, 5, 6, 7, 12, 13, 8, 9]
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn backfill_exclude_branch_with_evil_event() {
|
|
|
|
|
let events = mock_full_graph();
|
|
|
|
|
let roots = vec![mock_event_id(&1)];
|
|
|
|
|
let result = linearize_previous_events(
|
|
|
|
|
roots,
|
|
|
|
|
vec![],
|
|
|
|
|
100u64,
|
|
|
|
|
|e| events.get(e).cloned(),
|
|
|
|
|
|_| true,
|
|
|
|
|
|e| {
|
|
|
|
|
let value: Value = CanonicalJsonValue::Object(e.clone()).into();
|
|
|
|
|
let pdu: MockPDU = serde_json::from_value(value).unwrap();
|
|
|
|
|
pdu.content != 3
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
extract_events_payload(result),
|
|
|
|
|
vec![1, 2, 10, 11, 4, 5, 12, 13, 8, 14, 15, 16]
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn backfill_exclude_branch_with_inaccessible_event() {
|
|
|
|
|
let events = mock_full_graph();
|
|
|
|
|
let roots = vec![mock_event_id(&1)];
|
|
|
|
|
let result = linearize_previous_events(
|
|
|
|
|
roots,
|
|
|
|
|
vec![],
|
|
|
|
|
100u64,
|
|
|
|
|
|e| events.get(e).cloned(),
|
|
|
|
|
|e| e != mock_event_id(&3),
|
|
|
|
|
|_| true,
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
extract_events_payload(result),
|
|
|
|
|
vec![1, 2, 10, 11, 4, 5, 12, 13, 8, 14, 15, 16]
|
|
|
|
|
)
|
|
|
|
|
}
|
2020-12-08 12:34:46 +01:00
|
|
|
|
}
|