Compare commits

...

26 commits

Author SHA1 Message Date
Matthias Ahouansou
44dd21f432 Merge branch 'TheDidek1-next-patch-00204' into 'next'
Update docs to point at new Synapse location

See merge request famedly/conduit!715
2024-07-19 08:58:05 +00:00
Dawid Rejowski
75a0f68349 Update docs to point at new Synapse location 2024-07-18 19:58:27 +00:00
Matthias Ahouansou
8abab8c8a0 Merge branch 'Crftbt-next-patch-43247' into 'next'
Update docker.md specifying port so that others don't also run into trying to...

See merge request famedly/conduit!712
2024-07-10 08:36:34 +00:00
Craft
324e1beabf Update docker.md specifying port so that others don't also run into trying to figure this out when following this md. 2024-07-09 21:49:55 +00:00
Matthias Ahouansou
00c9ef7b56 Merge branch 'send-invalid-pdu-correction' into 'next'
fix: don't fail the entire request if any PDU's format is invalid

See merge request famedly/conduit!709
2024-07-07 21:13:38 +00:00
Matthias Ahouansou
6455e918be
fix: don't always assume ruma can generate reference hashes 2024-07-07 21:40:56 +01:00
Matthias Ahouansou
ea3e7045b4
fix: don't fail the entire transaction if any PDU's format is invalid 2024-07-07 21:40:37 +01:00
Matthias Ahouansou
b8a1b4fee5 Merge branch 'remove-tls-override-when-no-srv-response' into 'next'
fix: remove TLS name override when no SRV record is present (but properly)

See merge request famedly/conduit!708
2024-07-06 16:49:38 +00:00
Matthias Ahouansou
d95345377b
fix: remove TLS name override when no SRV record is present (but properly)
The previous attempt only did so when no IP could be resolved, which isn't enough
2024-07-06 17:31:31 +01:00
Matthias Ahouansou
75322af8c7 Merge branch 'remove-tls-override-when-no-srv-response' into 'next'
fix: remove TLS name override when no SRV record is present

See merge request famedly/conduit!707
2024-07-06 16:24:32 +00:00
Matthias Ahouansou
11187b3fad
fix: remove TLS name override when no SRV record is present
this could have been an issue in cases where there was previously a SRV record, but later got removed
2024-07-06 17:06:11 +01:00
Matthias Ahouansou
1f313c6807 Merge branch 'finite-servername-cache' into 'next'
fix: don't cache server name lookups indefinitely

See merge request famedly/conduit!702
2024-07-01 09:52:18 +00:00
Matthias Ahouansou
e70d27af98 Merge branch 'timestamped-messaging' into 'next'
feat(appservice): support timestamped messaging

See merge request famedly/conduit!703
2024-07-01 09:36:14 +00:00
Matthias Ahouansou
ba8429cafe
fix: don't cache server name lookups indefinitely 2024-07-01 10:17:01 +01:00
Matthias Ahouansou
7a4d0f6fe8 Merge branch 'acl-dont-have-empty-exception' into 'next'
fix: don't ignore ACLs when there is no content

See merge request famedly/conduit!705
2024-06-26 21:41:42 +00:00
Matthias Ahouansou
2f45a907f9
fix: don't ignore ACLs when there is no content
despite this being very bad behavior, it is required by the spec
2024-06-26 22:06:46 +01:00
Matthias Ahouansou
de0deda179 Merge branch 'bump-ruma' into 'next'
chore: bump ruma

Closes #447

See merge request famedly/conduit!704
2024-06-25 09:43:15 +00:00
Matthias Ahouansou
62f1da053f
feat(appservice): support timestamped messaging 2024-06-25 10:25:58 +01:00
Matthias Ahouansou
602c56cae9
chore: bump ruma 2024-06-25 10:10:53 +01:00
Matthias Ahouansou
4b9520b5ad Merge branch 'bump-rust' into 'next'
chore: bump rust to 1.79.0 and apply new lints

See merge request famedly/conduit!700
2024-06-21 07:54:00 +00:00
Matthias Ahouansou
9014e43ce1
chore: bump rust to 1.79.0 and apply new lints 2024-06-21 08:29:33 +01:00
Matthias Ahouansou
ffc57f8997 Merge branch 'nightly-rustfmt' into 'next'
ci: use nightly rustfmt

See merge request famedly/conduit!699
2024-06-16 16:44:51 +00:00
Matthias Ahouansou
fd19dda5cb
ci: use nightly rustfmt
we were using this before, but it broke when refactoring the flake out into separate files
2024-06-16 17:28:05 +01:00
Matthias Ahouansou
dc0fa09a57 Merge branch 'bump' into 'next'
chore: bump version to 0.9.0-alpha

See merge request famedly/conduit!698
2024-06-14 12:02:56 +00:00
Matthias Ahouansou
ba1138aaa3
chore: bump version to 0.9.0-alpha 2024-06-14 12:33:40 +01:00
Matthias Ahouansou
6398136163 Merge branch 'debian-aarch64' into 'next'
ci: build for Debian aarch64

See merge request famedly/conduit!692
2024-06-14 11:10:59 +00:00
25 changed files with 523 additions and 310 deletions

47
Cargo.lock generated
View file

@ -487,7 +487,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "conduit"
version = "0.8.0"
version = "0.9.0-alpha"
dependencies = [
"async-trait",
"axum 0.7.5",
@ -1158,6 +1158,15 @@ dependencies = [
"itoa",
]
[[package]]
name = "http-auth"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "643c9bbf6a4ea8a656d6b4cd53d34f79e3f841ad5203c1a55fb7d761923bc255"
dependencies = [
"memchr",
]
[[package]]
name = "http-body"
version = "0.4.6"
@ -2223,7 +2232,7 @@ dependencies = [
[[package]]
name = "ruma"
version = "0.10.1"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"assign",
"js_int",
@ -2244,7 +2253,7 @@ dependencies = [
[[package]]
name = "ruma-appservice-api"
version = "0.10.0"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"js_int",
"ruma-common",
@ -2256,7 +2265,7 @@ dependencies = [
[[package]]
name = "ruma-client-api"
version = "0.18.0"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"as_variant",
"assign",
@ -2279,7 +2288,7 @@ dependencies = [
[[package]]
name = "ruma-common"
version = "0.13.0"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"as_variant",
"base64 0.22.1",
@ -2309,7 +2318,7 @@ dependencies = [
[[package]]
name = "ruma-events"
version = "0.28.1"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"as_variant",
"indexmap 2.2.6",
@ -2331,7 +2340,7 @@ dependencies = [
[[package]]
name = "ruma-federation-api"
version = "0.9.0"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"js_int",
"ruma-common",
@ -2343,7 +2352,7 @@ dependencies = [
[[package]]
name = "ruma-identifiers-validation"
version = "0.9.5"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"js_int",
"thiserror",
@ -2352,7 +2361,7 @@ dependencies = [
[[package]]
name = "ruma-identity-service-api"
version = "0.9.0"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"js_int",
"ruma-common",
@ -2362,7 +2371,7 @@ dependencies = [
[[package]]
name = "ruma-macros"
version = "0.13.0"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"once_cell",
"proc-macro-crate",
@ -2377,7 +2386,7 @@ dependencies = [
[[package]]
name = "ruma-push-gateway-api"
version = "0.9.0"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"js_int",
"ruma-common",
@ -2389,18 +2398,20 @@ dependencies = [
[[package]]
name = "ruma-server-util"
version = "0.3.0"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"headers",
"http 1.1.0",
"http-auth",
"ruma-common",
"thiserror",
"tracing",
"yap",
]
[[package]]
name = "ruma-signatures"
version = "0.15.0"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"base64 0.22.1",
"ed25519-dalek",
@ -2416,7 +2427,7 @@ dependencies = [
[[package]]
name = "ruma-state-res"
version = "0.11.0"
source = "git+https://github.com/ruma/ruma#ef40b184b7410a93e933b4ad719a72aea1bdd20e"
source = "git+https://github.com/ruma/ruma#fec2152d879a6c6c2bccce984d4b8f424f460cb2"
dependencies = [
"itertools",
"js_int",
@ -3757,12 +3768,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "yap"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfe269e7b803a5e8e20cbd97860e136529cd83bf2c9c6d37b142467e7e1f051f"
[[package]]
name = "zerocopy"
version = "0.7.34"

View file

@ -16,10 +16,10 @@ license = "Apache-2.0"
name = "conduit"
readme = "README.md"
repository = "https://gitlab.com/famedly/conduit"
version = "0.8.0"
version = "0.9.0-alpha"
# See also `rust-toolchain.toml`
rust-version = "1.78.0"
rust-version = "1.79.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View file

@ -1,4 +1,4 @@
FROM rust:1.78.0
FROM rust:1.79.0
WORKDIR /workdir

View file

@ -64,6 +64,7 @@ docker run -d -p 8448:6167 \
-e CONDUIT_MAX_REQUEST_SIZE="20000000" \
-e CONDUIT_TRUSTED_SERVERS="[\"matrix.org\"]" \
-e CONDUIT_MAX_CONCURRENT_REQUESTS="100" \
-e CONDUIT_PORT="6167" \
--name conduit <link>
```

View file

@ -2,7 +2,7 @@
## General instructions
* It is assumed you have a [Coturn server](https://github.com/coturn/coturn) up and running. See [Synapse reference implementation](https://github.com/matrix-org/synapse/blob/develop/docs/turn-howto.md).
* It is assumed you have a [Coturn server](https://github.com/coturn/coturn) up and running. See [Synapse reference implementation](https://github.com/element-hq/synapse/blob/develop/docs/turn-howto.md).
## Edit/Add a few settings to your existing conduit.toml

View file

@ -59,7 +59,7 @@
file = ./rust-toolchain.toml;
# See also `rust-toolchain.toml`
sha256 = "sha256-opUgs6ckUQCyDxcB9Wy51pqhd0MPGHUVbwRKKPGiwZU=";
sha256 = "sha256-Ngiz76YP4HTY75GGdH2P+APE/DEIx2R/Dn+BwwOyzZU=";
};
});
in

View file

@ -23,7 +23,7 @@ mkShell {
};
# Development tools
nativeBuildInputs = default.nativeBuildInputs ++ [
nativeBuildInputs = [
# Always use nightly rustfmt because most of its options are unstable
#
# This needs to come before `toolchain` in this list, otherwise
@ -57,5 +57,5 @@ mkShell {
# Useful for editing the book locally
mdbook
];
] ++ default.nativeBuildInputs ;
}

View file

@ -2,7 +2,6 @@
#
# Other files that need upkeep when this changes:
#
# * `.gitlab-ci.yml`
# * `Cargo.toml`
# * `flake.nix`
#
@ -10,7 +9,7 @@
# If you're having trouble making the relevant changes, bug a maintainer.
[toolchain]
channel = "1.78.0"
channel = "1.79.0"
components = [
# For rust-analyzer
"rust-src",

View file

@ -315,7 +315,11 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
pub async fn change_password_route(
body: Ruma<change_password::v3::Request>,
) -> Result<change_password::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_user = body
.sender_user
.as_ref()
// In the future password changes could be performed with UIA with 3PIDs, but we don't support that currently
.ok_or_else(|| Error::BadRequest(ErrorKind::MissingToken, "Missing access token."))?;
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
let mut uiaainfo = UiaaInfo {
@ -402,7 +406,11 @@ pub async fn whoami_route(body: Ruma<whoami::v3::Request>) -> Result<whoami::v3:
pub async fn deactivate_route(
body: Ruma<deactivate::v3::Request>,
) -> Result<deactivate::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_user = body
.sender_user
.as_ref()
// In the future password changes could be performed with UIA with SSO, but we don't support that currently
.ok_or_else(|| Error::BadRequest(ErrorKind::MissingToken, "Missing access token."))?;
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
let mut uiaainfo = UiaaInfo {

View file

@ -1,3 +1,6 @@
// Unauthenticated media is deprecated
#![allow(deprecated)]
use std::time::Duration;
use crate::{service::media::FileMeta, services, utils, Error, Result, Ruma};
@ -190,7 +193,7 @@ pub async fn get_content_thumbnail_route(
content_type,
cross_origin_resource_policy: Some("cross-origin".to_owned()),
})
} else if &*body.server_name != services().globals.server_name() && body.allow_remote {
} else if body.server_name != services().globals.server_name() && body.allow_remote {
let get_thumbnail_response = services()
.sending
.send_federation_request(
@ -204,6 +207,7 @@ pub async fn get_content_thumbnail_route(
media_id: body.media_id.clone(),
timeout_ms: Duration::from_secs(20),
allow_redirect: false,
animated: body.animated,
},
)
.await?;

View file

@ -241,6 +241,7 @@ pub async fn kick_user_route(
unsigned: None,
state_key: Some(body.user_id.to_string()),
redacts: None,
timestamp: None,
},
sender_user,
&body.room_id,
@ -313,6 +314,7 @@ pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_use
unsigned: None,
state_key: Some(body.user_id.to_string()),
redacts: None,
timestamp: None,
},
sender_user,
&body.room_id,
@ -386,6 +388,7 @@ pub async fn unban_user_route(
unsigned: None,
state_key: Some(body.user_id.to_string()),
redacts: None,
timestamp: None,
},
sender_user,
&body.room_id,
@ -624,7 +627,7 @@ async fn join_room_by_id_helper(
let event_id = format!(
"${}",
ruma::signatures::reference_hash(&join_event_stub, &room_version_id)
.expect("ruma can calculate reference hashes")
.expect("Event format validated when event was hashed")
);
let event_id = <&EventId>::try_from(event_id.as_str())
.expect("ruma's reference hashes are valid event ids");
@ -938,6 +941,7 @@ async fn join_room_by_id_helper(
unsigned: None,
state_key: Some(sender_user.to_string()),
redacts: None,
timestamp: None,
},
sender_user,
room_id,
@ -1141,7 +1145,7 @@ async fn validate_and_add_event_id(
let event_id = EventId::parse(format!(
"${}",
ruma::signatures::reference_hash(&value, room_version)
.expect("ruma can calculate reference hashes")
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid PDU format"))?
))
.expect("ruma's reference hashes are valid event ids");
@ -1260,6 +1264,7 @@ pub(crate) async fn invite_helper<'a>(
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
timestamp: None,
},
sender_user,
room_id,
@ -1379,6 +1384,7 @@ pub(crate) async fn invite_helper<'a>(
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
timestamp: None,
},
sender_user,
room_id,
@ -1506,6 +1512,7 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
timestamp: None,
},
user_id,
room_id,
@ -1607,7 +1614,7 @@ async fn remote_leave_room(user_id: &UserId, room_id: &RoomId) -> Result<()> {
let event_id = EventId::parse(format!(
"${}",
ruma::signatures::reference_hash(&leave_event_stub, &room_version_id)
.expect("ruma can calculate reference hashes")
.expect("Event format validated when event was hashed")
))
.expect("ruma's reference hashes are valid event ids");

View file

@ -84,6 +84,11 @@ pub async fn send_message_event_route(
unsigned: Some(unsigned),
state_key: None,
redacts: None,
timestamp: if body.appservice_info.is_some() {
body.timestamp
} else {
None
},
},
sender_user,
&body.room_id,

View file

@ -65,6 +65,7 @@ pub async fn set_displayname_route(
unsigned: None,
state_key: Some(sender_user.to_string()),
redacts: None,
timestamp: None,
},
room_id,
))
@ -200,6 +201,7 @@ pub async fn set_avatar_url_route(
unsigned: None,
state_key: Some(sender_user.to_string()),
redacts: None,
timestamp: None,
},
room_id,
))

View file

@ -44,6 +44,7 @@ pub async fn redact_event_route(
unsigned: None,
state_key: None,
redacts: Some(body.event_id.into()),
timestamp: None,
},
sender_user,
&body.room_id,

View file

@ -230,6 +230,7 @@ pub async fn create_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&room_id,
@ -258,6 +259,7 @@ pub async fn create_room_route(
unsigned: None,
state_key: Some(sender_user.to_string()),
redacts: None,
timestamp: None,
},
sender_user,
&room_id,
@ -311,6 +313,7 @@ pub async fn create_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&room_id,
@ -334,6 +337,7 @@ pub async fn create_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&room_id,
@ -360,6 +364,7 @@ pub async fn create_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&room_id,
@ -381,6 +386,7 @@ pub async fn create_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&room_id,
@ -403,6 +409,7 @@ pub async fn create_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&room_id,
@ -447,6 +454,7 @@ pub async fn create_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&room_id,
@ -469,6 +477,7 @@ pub async fn create_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&room_id,
@ -629,6 +638,7 @@ pub async fn upgrade_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&body.room_id,
@ -730,6 +740,7 @@ pub async fn upgrade_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&replacement_room,
@ -758,6 +769,7 @@ pub async fn upgrade_room_route(
unsigned: None,
state_key: Some(sender_user.to_string()),
redacts: None,
timestamp: None,
},
sender_user,
&replacement_room,
@ -800,6 +812,7 @@ pub async fn upgrade_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&replacement_room,
@ -850,6 +863,7 @@ pub async fn upgrade_room_route(
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
sender_user,
&body.room_id,

View file

@ -10,7 +10,7 @@ use ruma::{
room::canonical_alias::RoomCanonicalAliasEventContent, AnyStateEventContent, StateEventType,
},
serde::Raw,
EventId, RoomId, UserId,
EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId,
};
use tracing::log::warn;
@ -32,6 +32,11 @@ pub async fn send_state_event_for_key_route(
&body.event_type,
&body.body.body, // Yes, I hate it too
body.state_key.to_owned(),
if body.appservice_info.is_some() {
body.timestamp
} else {
None
},
)
.await?;
@ -65,6 +70,11 @@ pub async fn send_state_event_for_empty_key_route(
&body.event_type.to_string().into(),
&body.body.body,
body.state_key.to_owned(),
if body.appservice_info.is_some() {
body.timestamp
} else {
None
},
)
.await?;
@ -190,6 +200,7 @@ async fn send_state_event_for_key_helper(
event_type: &StateEventType,
json: &Raw<AnyStateEventContent>,
state_key: String,
timestamp: Option<MilliSecondsSinceUnixEpoch>,
) -> Result<Arc<EventId>> {
let sender_user = sender;
@ -243,6 +254,7 @@ async fn send_state_event_for_key_helper(
unsigned: None,
state_key: Some(state_key),
redacts: None,
timestamp,
},
sender_user,
room_id,

View file

@ -7,8 +7,11 @@ use axum::{
response::{IntoResponse, Response},
RequestExt, RequestPartsExt,
};
use axum_extra::headers::authorization::Bearer;
use axum_extra::{headers::Authorization, typed_header::TypedHeaderRejectionReason, TypedHeader};
use axum_extra::{
headers::{authorization::Bearer, Authorization},
typed_header::TypedHeaderRejectionReason,
TypedHeader,
};
use bytes::{BufMut, BytesMut};
use http::{Request, StatusCode};
use ruma::{
@ -186,7 +189,7 @@ where
let origin_signatures = BTreeMap::from_iter([(
x_matrix.key.clone(),
CanonicalJsonValue::String(x_matrix.sig),
CanonicalJsonValue::String(x_matrix.sig.to_string()),
)]);
let signatures = BTreeMap::from_iter([(

View file

@ -2,12 +2,16 @@
use crate::{
api::client_server::{self, claim_keys_helper, get_keys_helper},
service::pdu::{gen_event_id_canonical_json, PduBuilder},
service::{
globals::SigningKeys,
pdu::{gen_event_id_canonical_json, PduBuilder},
},
services, utils, Error, PduEvent, Result, Ruma,
};
use axum::{response::IntoResponse, Json};
use axum_extra::headers::{authorization::Credentials, CacheControl, Header};
use get_profile_information::v1::ProfileField;
use http::header::{HeaderValue, AUTHORIZATION};
use http::header::AUTHORIZATION;
use ruma::{
api::{
@ -44,6 +48,7 @@ use ruma::{
StateEventType, TimelineEventType,
},
serde::{Base64, JsonObject, Raw},
server_util::authorization::XMatrix,
to_device::DeviceIdOrAllDevices,
uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch,
OwnedEventId, OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, RoomId,
@ -94,13 +99,6 @@ impl FedDest {
}
}
fn into_uri_string(self) -> String {
match self {
Self::Literal(addr) => addr.to_string(),
Self::Named(host, ref port) => host + port,
}
}
fn hostname(&self) -> String {
match &self {
Self::Literal(addr) => addr.ip().to_string(),
@ -136,8 +134,6 @@ where
debug!("Preparing to send request to {destination}");
let mut write_destination_to_cache = false;
let cached_result = services()
.globals
.actual_destination_cache
@ -146,14 +142,63 @@ where
.get(destination)
.cloned();
let (actual_destination, host) = if let Some(result) = cached_result {
result
let actual_destination = if let Some(DestinationResponse {
actual_destination,
dest_type,
}) = cached_result
{
match dest_type {
DestType::IsIpOrHasPort => actual_destination,
DestType::LookupFailed {
well_known_retry,
well_known_backoff_mins,
} => {
if well_known_retry < Instant::now() {
find_actual_destination(destination, None, false, Some(well_known_backoff_mins))
.await
} else {
actual_destination
}
}
DestType::WellKnown { expires } => {
if expires < Instant::now() {
find_actual_destination(destination, None, false, None).await
} else {
actual_destination
}
}
DestType::WellKnownSrv {
srv_expires,
well_known_expires,
well_known_host,
} => {
if well_known_expires < Instant::now() {
find_actual_destination(destination, None, false, None).await
} else if srv_expires < Instant::now() {
find_actual_destination(destination, Some(well_known_host), true, None).await
} else {
actual_destination
}
}
DestType::Srv {
well_known_retry,
well_known_backoff_mins,
srv_expires,
} => {
if well_known_retry < Instant::now() {
find_actual_destination(destination, None, false, Some(well_known_backoff_mins))
.await
} else if srv_expires < Instant::now() {
find_actual_destination(destination, None, true, Some(well_known_backoff_mins))
.await
} else {
actual_destination
}
}
}
} else {
write_destination_to_cache = true;
let result = find_actual_destination(destination).await;
(result.0, result.1.into_uri_string())
find_actual_destination(destination, None, false, None).await
};
let actual_destination_str = actual_destination.clone().into_https_string();
@ -226,14 +271,15 @@ where
for s in signature_server {
http_request.headers_mut().insert(
AUTHORIZATION,
HeaderValue::from_str(&format!(
XMatrix::parse(&format!(
"X-Matrix origin=\"{}\",destination=\"{}\",key=\"{}\",sig=\"{}\"",
services().globals.server_name(),
destination,
s.0,
s.1
))
.unwrap(),
.expect("When Ruma signs JSON, it produces a valid base64 signature. All other types are valid ServerNames or OwnedKeyId")
.encode(),
);
}
}
@ -290,17 +336,6 @@ where
if status == 200 {
debug!("Parsing response bytes from {destination}");
let response = T::IncomingResponse::try_from_http_response(http_response);
if response.is_ok() && write_destination_to_cache {
services()
.globals
.actual_destination_cache
.write()
.await
.insert(
OwnedServerName::from(destination),
(actual_destination, host),
);
}
response.map_err(|e| {
warn!(
@ -345,142 +380,225 @@ fn add_port_to_hostname(destination_str: &str) -> FedDest {
FedDest::Named(host.to_owned(), port.to_owned())
}
/// Returns: actual_destination, host header
/// Implemented according to the specification at <https://matrix.org/docs/spec/server_server/r0.1.4#resolving-server-names>
#[derive(Clone)]
pub struct DestinationResponse {
pub actual_destination: FedDest,
pub dest_type: DestType,
}
#[derive(Clone)]
pub enum DestType {
WellKnownSrv {
srv_expires: Instant,
well_known_expires: Instant,
well_known_host: String,
},
WellKnown {
expires: Instant,
},
Srv {
srv_expires: Instant,
well_known_retry: Instant,
well_known_backoff_mins: u16,
},
IsIpOrHasPort,
LookupFailed {
well_known_retry: Instant,
well_known_backoff_mins: u16,
},
}
/// Implemented according to the specification at <https://spec.matrix.org/v1.11/server-server-api/#resolving-server-names>
/// Numbers in comments below refer to bullet points in linked section of specification
async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDest) {
async fn find_actual_destination(
destination: &'_ ServerName,
// The host used to potentially lookup SRV records against, only used when only_request_srv is true
well_known_dest: Option<String>,
// Should be used when only the SRV lookup has expired
only_request_srv: bool,
// The backoff time for the last well known failure, if any
well_known_backoff_mins: Option<u16>,
) -> FedDest {
debug!("Finding actual destination for {destination}");
let destination_str = destination.as_str().to_owned();
let mut hostname = destination_str.clone();
let actual_destination = match get_ip_with_port(&destination_str) {
Some(host_port) => {
debug!("1: IP literal with provided or default port");
host_port
}
None => {
if let Some(pos) = destination_str.find(':') {
debug!("2: Hostname with included port");
let (host, port) = destination_str.split_at(pos);
FedDest::Named(host.to_owned(), port.to_owned())
let destination_str = destination.to_string();
let next_backoff_mins = well_known_backoff_mins
// Errors are recommended to be cached for up to an hour
.map(|mins| (mins * 2).min(60))
.unwrap_or(1);
let (actual_destination, dest_type) = if only_request_srv {
let destination_str = well_known_dest.unwrap_or(destination_str);
let (dest, expires) = get_srv_destination(destination_str).await;
let well_known_retry =
Instant::now() + Duration::from_secs((60 * next_backoff_mins).into());
(
dest,
if let Some(expires) = expires {
DestType::Srv {
well_known_backoff_mins: next_backoff_mins,
srv_expires: expires,
well_known_retry,
}
} else {
debug!("Requesting well known for {destination}");
match request_well_known(destination.as_str()).await {
Some(delegated_hostname) => {
debug!("3: A .well-known file is available");
hostname = add_port_to_hostname(&delegated_hostname).into_uri_string();
match get_ip_with_port(&delegated_hostname) {
Some(host_and_port) => host_and_port, // 3.1: IP literal in .well-known file
None => {
if let Some(pos) = delegated_hostname.find(':') {
debug!("3.2: Hostname with port in .well-known file");
let (host, port) = delegated_hostname.split_at(pos);
FedDest::Named(host.to_owned(), port.to_owned())
} else {
debug!("Delegated hostname has no port in this branch");
if let Some(hostname_override) =
query_srv_record(&delegated_hostname).await
{
debug!("3.3: SRV lookup successful");
let force_port = hostname_override.port();
if let Ok(override_ip) = services()
.globals
.dns_resolver()
.lookup_ip(hostname_override.hostname())
.await
{
services()
.globals
.tls_name_override
.write()
.unwrap()
.insert(
delegated_hostname.clone(),
(
override_ip.iter().collect(),
force_port.unwrap_or(8448),
),
);
} else {
warn!("Using SRV record, but could not resolve to IP");
}
if let Some(port) = force_port {
FedDest::Named(delegated_hostname, format!(":{port}"))
} else {
add_port_to_hostname(&delegated_hostname)
}
DestType::LookupFailed {
well_known_retry,
well_known_backoff_mins: next_backoff_mins,
}
},
)
} else {
match get_ip_with_port(&destination_str) {
Some(host_port) => {
debug!("1: IP literal with provided or default port");
(host_port, DestType::IsIpOrHasPort)
}
None => {
if let Some(pos) = destination_str.find(':') {
debug!("2: Hostname with included port");
let (host, port) = destination_str.split_at(pos);
(
FedDest::Named(host.to_owned(), port.to_owned()),
DestType::IsIpOrHasPort,
)
} else {
debug!("Requesting well known for {destination_str}");
match request_well_known(destination_str.as_str()).await {
Some((delegated_hostname, timestamp)) => {
debug!("3: A .well-known file is available");
match get_ip_with_port(&delegated_hostname) {
// 3.1: IP literal in .well-known file
Some(host_and_port) => {
(host_and_port, DestType::WellKnown { expires: timestamp })
}
None => {
if let Some(pos) = delegated_hostname.find(':') {
debug!("3.2: Hostname with port in .well-known file");
let (host, port) = delegated_hostname.split_at(pos);
(
FedDest::Named(host.to_owned(), port.to_owned()),
DestType::WellKnown { expires: timestamp },
)
} else {
debug!("3.4: No SRV records, just use the hostname from .well-known");
add_port_to_hostname(&delegated_hostname)
debug!("Delegated hostname has no port in this branch");
let (dest, srv_expires) =
get_srv_destination(delegated_hostname.clone()).await;
(
dest,
if let Some(srv_expires) = srv_expires {
DestType::WellKnownSrv {
srv_expires,
well_known_expires: timestamp,
well_known_host: delegated_hostname,
}
} else {
DestType::WellKnown { expires: timestamp }
},
)
}
}
}
}
}
None => {
debug!("4: No .well-known or an error occured");
match query_srv_record(&destination_str).await {
Some(hostname_override) => {
debug!("4: SRV record found");
let force_port = hostname_override.port();
if let Ok(override_ip) = services()
.globals
.dns_resolver()
.lookup_ip(hostname_override.hostname())
.await
{
services()
.globals
.tls_name_override
.write()
.unwrap()
.insert(
hostname.clone(),
(
override_ip.iter().collect(),
force_port.unwrap_or(8448),
),
);
None => {
debug!("4: No .well-known or an error occured");
let (dest, expires) = get_srv_destination(destination_str).await;
let well_known_retry = Instant::now()
+ Duration::from_secs((60 * next_backoff_mins).into());
(
dest,
if let Some(expires) = expires {
DestType::Srv {
srv_expires: expires,
well_known_retry,
well_known_backoff_mins: next_backoff_mins,
}
} else {
warn!("Using SRV record, but could not resolve to IP");
}
if let Some(port) = force_port {
FedDest::Named(hostname.clone(), format!(":{port}"))
} else {
add_port_to_hostname(&hostname)
}
}
None => {
debug!("5: No SRV record found");
add_port_to_hostname(&destination_str)
}
DestType::LookupFailed {
well_known_retry,
well_known_backoff_mins: next_backoff_mins,
}
},
)
}
}
}
}
}
};
debug!("Actual destination: {actual_destination:?}");
// 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
let hostname = if let Ok(addr) = hostname.parse::<SocketAddr>() {
FedDest::Literal(addr)
} else if let Ok(addr) = hostname.parse::<IpAddr>() {
FedDest::Named(addr.to_string(), ":8448".to_owned())
} else if let Some(pos) = hostname.find(':') {
let (host, port) = hostname.split_at(pos);
FedDest::Named(host.to_owned(), port.to_owned())
} else {
FedDest::Named(hostname, ":8448".to_owned())
let response = DestinationResponse {
actual_destination,
dest_type,
};
(actual_destination, hostname)
services()
.globals
.actual_destination_cache
.write()
.await
.insert(destination.to_owned(), response.clone());
response.actual_destination
}
async fn query_given_srv_record(record: &str) -> Option<FedDest> {
/// Looks up the SRV records for federation usage
///
/// If no timestamp is returned, that means no SRV record was found
async fn get_srv_destination(delegated_hostname: String) -> (FedDest, Option<Instant>) {
if let Some((hostname_override, timestamp)) = query_srv_record(&delegated_hostname).await {
debug!("SRV lookup successful");
let force_port = hostname_override.port();
if let Ok(override_ip) = services()
.globals
.dns_resolver()
.lookup_ip(hostname_override.hostname())
.await
{
services()
.globals
.tls_name_override
.write()
.unwrap()
.insert(
delegated_hostname.clone(),
(override_ip.iter().collect(), force_port.unwrap_or(8448)),
);
} else {
// Removing in case there was previously a SRV record
services()
.globals
.tls_name_override
.write()
.unwrap()
.remove(&delegated_hostname);
warn!("Using SRV record, but could not resolve to IP");
}
if let Some(port) = force_port {
(
FedDest::Named(delegated_hostname, format!(":{port}")),
Some(timestamp),
)
} else {
(add_port_to_hostname(&delegated_hostname), Some(timestamp))
}
} else {
// Removing in case there was previously a SRV record
services()
.globals
.tls_name_override
.write()
.unwrap()
.remove(&delegated_hostname);
debug!("No SRV records found");
(add_port_to_hostname(&delegated_hostname), None)
}
}
async fn query_given_srv_record(record: &str) -> Option<(FedDest, Instant)> {
services()
.globals
.dns_resolver()
@ -488,16 +606,19 @@ async fn query_given_srv_record(record: &str) -> Option<FedDest> {
.await
.map(|srv| {
srv.iter().next().map(|result| {
FedDest::Named(
result.target().to_string().trim_end_matches('.').to_owned(),
format!(":{}", result.port()),
(
FedDest::Named(
result.target().to_string().trim_end_matches('.').to_owned(),
format!(":{}", result.port()),
),
srv.as_lookup().valid_until(),
)
})
})
.unwrap_or(None)
}
async fn query_srv_record(hostname: &'_ str) -> Option<FedDest> {
async fn query_srv_record(hostname: &'_ str) -> Option<(FedDest, Instant)> {
let hostname = hostname.trim_end_matches('.');
if let Some(host_port) = query_given_srv_record(&format!("_matrix-fed._tcp.{hostname}.")).await
@ -508,7 +629,7 @@ async fn query_srv_record(hostname: &'_ str) -> Option<FedDest> {
}
}
async fn request_well_known(destination: &str) -> Option<String> {
async fn request_well_known(destination: &str) -> Option<(String, Instant)> {
let response = services()
.globals
.default_client()
@ -516,14 +637,40 @@ async fn request_well_known(destination: &str) -> Option<String> {
.send()
.await;
debug!("Got well known response");
if let Err(e) = &response {
debug!("Well known error: {e:?}");
return None;
}
let text = response.ok()?.text().await;
let response = match response {
Err(e) => {
debug!("Well known error: {e:?}");
return None;
}
Ok(r) => r,
};
let mut headers = response.headers().values();
let cache_for = CacheControl::decode(&mut headers)
.ok()
.and_then(|cc| {
// Servers should respect the cache control headers present on the response, or use a sensible default when headers are not present.
if cc.no_store() || cc.no_cache() {
Some(Duration::ZERO)
} else {
cc.max_age()
// Servers should additionally impose a maximum cache time for responses: 48 hours is recommended.
.map(|age| age.min(Duration::from_secs(60 * 60 * 48)))
}
})
// The recommended sensible default is 24 hours.
.unwrap_or_else(|| Duration::from_secs(60 * 60 * 24));
let text = response.text().await;
debug!("Got well known response text");
let body: serde_json::Value = serde_json::from_str(&text.ok()?).ok()?;
Some(body.get("m.server")?.as_str()?.to_owned())
let host = || {
let body: serde_json::Value = serde_json::from_str(&text.ok()?).ok()?;
body.get("m.server")?.as_str().map(ToOwned::to_owned)
};
host().map(|host| (host, Instant::now() + cache_for))
}
/// # `GET /_matrix/federation/v1/version`
@ -663,17 +810,78 @@ pub fn parse_incoming_pdu(
let (event_id, value) = match gen_event_id_canonical_json(pdu, &room_version_id) {
Ok(t) => t,
Err(_) => {
Err(e) => {
// Event could not be converted to canonical json
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Could not convert event to canonical json.",
));
return Err(e);
}
};
Ok((event_id, value, room_id))
}
/// Attempts to parse and append PDU to timeline.
/// If no event ID is returned, then the PDU was failed to be parsed.
/// If the Ok(()) is returned, then the PDU was successfully appended to the timeline.
async fn handle_pdu_in_transaction(
origin: &ServerName,
pub_key_map: &RwLock<BTreeMap<String, SigningKeys>>,
pdu: &RawJsonValue,
) -> (Option<OwnedEventId>, Result<()>) {
let (event_id, value, room_id) = match parse_incoming_pdu(pdu) {
Ok(t) => t,
Err(e) => {
warn!("Could not parse PDU: {e}");
warn!("Full PDU: {:?}", &pdu);
return (None, Err(Error::BadServerResponse("Could not parse PDU")));
}
};
// Makes use of the m.room.create event. If we cannot fetch this event,
// we must have never been in that room.
if services().rooms.state.get_room_version(&room_id).is_err() {
debug!("Room {room_id} is not known to this server");
return (
Some(event_id),
Err(Error::BadServerResponse("Room is not known to this server")),
);
}
// We do not add the event_id field to the pdu here because of signature and hashes checks
let mutex = Arc::clone(
services()
.globals
.roomid_mutex_federation
.write()
.await
.entry(room_id.to_owned())
.or_default(),
);
let mutex_lock = mutex.lock().await;
let start_time = Instant::now();
if let Err(e) = services()
.rooms
.event_handler
.handle_incoming_pdu(origin, &event_id, &room_id, value, true, pub_key_map)
.await
{
warn!("Error appending PDU to timeline: {}: {:?}", e, pdu);
return (Some(event_id), Err(e));
}
drop(mutex_lock);
let elapsed = start_time.elapsed();
debug!(
"Handling transaction of event {} took {}m{}s",
event_id,
elapsed.as_secs() / 60,
elapsed.as_secs() % 60
);
(Some(event_id), Ok(()))
}
/// # `PUT /_matrix/federation/v1/send/{txnId}`
///
/// Push EDUs and PDUs to this server.
@ -698,77 +906,11 @@ pub async fn send_transaction_message_route(
// let mut auth_cache = EventMap::new();
for pdu in &body.pdus {
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")
})?;
let room_id: OwnedRoomId = value
.get("room_id")
.and_then(|id| RoomId::parse(id.as_str()?).ok())
.ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Invalid room id in pdu",
))?;
let (event_id, result) =
handle_pdu_in_transaction(sender_servername, &pub_key_map, pdu).await;
if services().rooms.state.get_room_version(&room_id).is_err() {
debug!("Server is not in room {room_id}");
continue;
}
let r = parse_incoming_pdu(pdu);
let (event_id, value, room_id) = match r {
Ok(t) => t,
Err(e) => {
warn!("Could not parse PDU: {e}");
warn!("Full PDU: {:?}", &pdu);
continue;
}
};
// We do not add the event_id field to the pdu here because of signature and hashes checks
let mutex = Arc::clone(
services()
.globals
.roomid_mutex_federation
.write()
.await
.entry(room_id.to_owned())
.or_default(),
);
let mutex_lock = mutex.lock().await;
let start_time = Instant::now();
resolved_map.insert(
event_id.clone(),
services()
.rooms
.event_handler
.handle_incoming_pdu(
sender_servername,
&event_id,
&room_id,
value,
true,
&pub_key_map,
)
.await
.map(|_| ()),
);
drop(mutex_lock);
let elapsed = start_time.elapsed();
debug!(
"Handling transaction of event {} took {}m{}s",
event_id,
elapsed.as_secs() / 60,
elapsed.as_secs() % 60
);
}
for pdu in &resolved_map {
if let Err(e) = pdu.1 {
if matches!(e, Error::BadRequest(ErrorKind::NotFound, _)) {
warn!("Incoming PDU failed {:?}", pdu);
}
if let Some(event_id) = event_id {
resolved_map.insert(event_id.clone(), result.map_err(|e| e.sanitized_error()));
}
}
@ -937,12 +1079,7 @@ pub async fn send_transaction_message_route(
}
}
Ok(send_transaction_message::v1::Response {
pdus: resolved_map
.into_iter()
.map(|(e, r)| (e, r.map_err(|e| e.sanitized_error())))
.collect(),
})
Ok(send_transaction_message::v1::Response { pdus: resolved_map })
}
/// # `GET /_matrix/federation/v1/event/{eventId}`
@ -1445,6 +1582,7 @@ pub async fn create_join_event_template_route(
unsigned: None,
state_key: Some(body.user_id.to_string()),
redacts: None,
timestamp: None,
},
&body.user_id,
&body.room_id,
@ -1684,7 +1822,7 @@ pub async fn create_invite_route(
let event_id = EventId::parse(format!(
"${}",
ruma::signatures::reference_hash(&signed_event, &body.room_version)
.expect("ruma can calculate reference hashes")
.expect("Event format validated when event was hashed")
))
.expect("ruma's reference hashes are valid event ids");

View file

@ -246,6 +246,7 @@ impl Service {
unsigned: None,
state_key: None,
redacts: None,
timestamp: None,
},
conduit_user,
&conduit_room,
@ -1105,6 +1106,7 @@ impl Service {
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1133,6 +1135,7 @@ impl Service {
unsigned: None,
state_key: Some(conduit_user.to_string()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1158,6 +1161,7 @@ impl Service {
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1177,6 +1181,7 @@ impl Service {
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1198,6 +1203,7 @@ impl Service {
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1219,6 +1225,7 @@ impl Service {
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1239,6 +1246,7 @@ impl Service {
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1259,6 +1267,7 @@ impl Service {
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1283,6 +1292,7 @@ impl Service {
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1352,6 +1362,7 @@ impl Service {
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1378,6 +1389,7 @@ impl Service {
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
timestamp: None,
},
user_id,
&room_id,
@ -1404,6 +1416,7 @@ impl Service {
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,
@ -1423,6 +1436,7 @@ impl Service {
unsigned: None,
state_key: None,
redacts: None,
timestamp: None,
},
conduit_user,
&room_id,

View file

@ -1,11 +1,11 @@
mod data;
pub use data::Data;
pub use data::SigningKeys;
use ruma::MilliSecondsSinceUnixEpoch;
use ruma::{serde::Base64, OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedServerName, OwnedUserId};
use ruma::{OwnedRoomAliasId, RoomAliasId};
pub use data::{Data, SigningKeys};
use ruma::{
serde::Base64, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedEventId, OwnedRoomAliasId,
OwnedRoomId, OwnedServerName, OwnedUserId, RoomAliasId,
};
use crate::api::server_server::FedDest;
use crate::api::server_server::DestinationResponse;
use crate::{services, Config, Error, Result};
use futures_util::FutureExt;
@ -16,7 +16,6 @@ use ruma::{
api::{client::sync::sync_events, federation::discovery::ServerSigningKeys},
DeviceId, RoomVersionId, ServerName, UserId,
};
use std::str::FromStr;
use std::{
collections::{BTreeMap, HashMap},
error::Error as StdError,
@ -25,6 +24,7 @@ use std::{
iter,
net::{IpAddr, SocketAddr},
path::PathBuf,
str::FromStr,
sync::{
atomic::{self, AtomicBool},
Arc, RwLock as StdRwLock,
@ -37,7 +37,7 @@ use tracing::{error, info};
use base64::{engine::general_purpose, Engine as _};
type WellKnownMap = HashMap<OwnedServerName, (FedDest, String)>;
type WellKnownMap = HashMap<OwnedServerName, DestinationResponse>;
type TlsNameMap = HashMap<String, (Vec<IpAddr>, u16)>;
type RateLimitState = (Instant, u32); // Time if last failed try, number of failed tries
type SyncHandle = (

View file

@ -166,22 +166,20 @@ impl Service {
/ u64::from(original_height)
};
if use_width {
if intermediate <= u64::from(::std::u32::MAX) {
if intermediate <= u64::from(u32::MAX) {
(width, intermediate as u32)
} else {
(
(u64::from(width) * u64::from(::std::u32::MAX) / intermediate)
as u32,
::std::u32::MAX,
(u64::from(width) * u64::from(u32::MAX) / intermediate) as u32,
u32::MAX,
)
}
} else if intermediate <= u64::from(::std::u32::MAX) {
} else if intermediate <= u64::from(u32::MAX) {
(intermediate as u32, height)
} else {
(
::std::u32::MAX,
(u64::from(height) * u64::from(::std::u32::MAX) / intermediate)
as u32,
u32::MAX,
(u64::from(height) * u64::from(u32::MAX) / intermediate) as u32,
)
}
};

View file

@ -1,5 +1,6 @@
use crate::Error;
use ruma::{
api::client::error::ErrorKind,
canonical_json::redact_content_in_place,
events::{
room::{member::RoomMemberEventContent, redaction::RoomRedactionEventContent},
@ -443,7 +444,7 @@ pub(crate) fn gen_event_id_canonical_json(
"${}",
// Anything higher than version3 behaves the same
ruma::signatures::reference_hash(&value, room_version_id)
.expect("ruma can calculate reference hashes")
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid PDU format"))?
)
.try_into()
.expect("ruma's reference hashes are valid event ids");
@ -460,4 +461,8 @@ pub struct PduBuilder {
pub unsigned: Option<BTreeMap<String, serde_json::Value>>,
pub state_key: Option<String>,
pub redacts: Option<Arc<EventId>>,
/// For timestamped messaging, should only be used for appservices
///
/// Will be set to current time if None
pub timestamp: Option<MilliSecondsSinceUnixEpoch>,
}

View file

@ -1477,7 +1477,7 @@ impl Service {
let event_id = format!(
"${}",
ruma::signatures::reference_hash(&value, room_version)
.expect("ruma can calculate reference hashes")
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid PDU format"))?
);
let event_id = <&EventId>::try_from(event_id.as_str())
.expect("ruma's reference hashes are valid event ids");
@ -1687,11 +1687,6 @@ impl Service {
}
};
if acl_event_content.allow.is_empty() {
// Ignore broken acl events
return Ok(());
}
if acl_event_content.is_allowed(server_name) {
Ok(())
} else {

View file

@ -321,6 +321,7 @@ impl Service {
unsigned: None,
state_key: Some(target_user.into()),
redacts: None,
timestamp: None,
};
Ok(services()

View file

@ -22,8 +22,8 @@ use ruma::{
},
push::{Action, Ruleset, Tweak},
state_res::{self, Event, RoomVersion},
uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId,
OwnedServerName, RoomId, RoomVersionId, ServerName, UserId,
uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch,
OwnedEventId, OwnedRoomId, OwnedServerName, RoomId, RoomVersionId, ServerName, UserId,
};
use serde::Deserialize;
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
@ -665,6 +665,7 @@ impl Service {
unsigned,
state_key,
redacts,
timestamp,
} = pdu_builder;
let prev_events: Vec<_> = services()
@ -734,9 +735,9 @@ impl Service {
event_id: ruma::event_id!("$thiswillbefilledinlater").into(),
room_id: room_id.to_owned(),
sender: sender.to_owned(),
origin_server_ts: utils::millis_since_unix_epoch()
.try_into()
.expect("time is valid"),
origin_server_ts: timestamp
.map(|ts| ts.get())
.unwrap_or_else(|| MilliSecondsSinceUnixEpoch::now().get()),
kind: event_type,
content,
state_key,
@ -814,7 +815,7 @@ impl Service {
pdu.event_id = EventId::parse_arc(format!(
"${}",
ruma::signatures::reference_hash(&pdu_json, &room_version_id)
.expect("ruma can calculate reference hashes")
.expect("Event format validated when event was hashed")
))
.expect("ruma's reference hashes are valid event ids");