Compare commits

..

2 Commits

Author SHA1 Message Date
Jade Ellis 9d0c89bd04 fix(v12): Create tombstone event on room upgrade 2025-09-24 18:22:16 +00:00
nexy7574 965db4aa43 fix: V12 room upgrades 2025-09-24 18:22:16 +00:00
25 changed files with 781 additions and 782 deletions
+2 -2
View File
@@ -32,7 +32,7 @@ jobs:
echo "Debian distribution: $DISTRIBUTION ($VERSION)" echo "Debian distribution: $DISTRIBUTION ($VERSION)"
- name: Checkout repository with full history - name: Checkout repository with full history
uses: https://code.forgejo.org/actions/checkout@v5 uses: https://code.forgejo.org/actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -132,7 +132,7 @@ jobs:
path: ${{ steps.cargo-deb.outputs.path }} path: ${{ steps.cargo-deb.outputs.path }}
- name: Publish to Forgejo package registry - name: Publish to Forgejo package registry
if: ${{ forge.event_name == 'push' || forge.event_name == 'workflow_dispatch' || forge.event_name == 'schedule' }} if: ${{ forge.event_name == 'push' || forge.event_name == 'workflow_dispatch' }}
run: | run: |
OWNER="continuwuation" OWNER="continuwuation"
DISTRIBUTION=${{ steps.debian-version.outputs.distribution }} DISTRIBUTION=${{ steps.debian-version.outputs.distribution }}
+2 -2
View File
@@ -30,7 +30,7 @@ jobs:
echo "Fedora version: $VERSION" echo "Fedora version: $VERSION"
- name: Checkout repository with full history - name: Checkout repository with full history
uses: https://code.forgejo.org/actions/checkout@v5 uses: https://code.forgejo.org/actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
@@ -250,7 +250,7 @@ jobs:
path: artifacts/*debuginfo*.rpm path: artifacts/*debuginfo*.rpm
- name: Publish to RPM Package Registry - name: Publish to RPM Package Registry
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
run: | run: |
# Find the main binary RPM (exclude debug and source RPMs) # Find the main binary RPM (exclude debug and source RPMs)
RPM=$(find artifacts -name "continuwuity-*.rpm" \ RPM=$(find artifacts -name "continuwuity-*.rpm" \
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
name: Renovate name: Renovate
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/renovatebot/renovate:41.146.4@sha256:bb70194b7405faf10a6f279b60caa10403a440ba37d158c5a4ef0ae7b67a0f92 image: ghcr.io/renovatebot/renovate:41.127.2@sha256:66bc84e2f889025fbb3c9df863500dcc18bc64ac85bcf629d015064377d77f31
options: --tmpfs /tmp:exec options: --tmpfs /tmp:exec
steps: steps:
- name: Checkout - name: Checkout
+2 -3
View File
@@ -7,7 +7,6 @@ on:
- "Cargo.lock" - "Cargo.lock"
- "Cargo.toml" - "Cargo.toml"
- "rust-toolchain.toml" - "rust-toolchain.toml"
- ".forgejo/workflows/update-flake-hashes.yml"
jobs: jobs:
update-flake-hashes: update-flake-hashes:
@@ -15,13 +14,13 @@ jobs:
steps: steps:
- uses: https://code.forgejo.org/actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - uses: https://code.forgejo.org/actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with: with:
fetch-depth: 0 fetch-depth: 1
fetch-tags: false fetch-tags: false
fetch-single-branch: true fetch-single-branch: true
submodules: false submodules: false
persist-credentials: false persist-credentials: false
- uses: https://github.com/cachix/install-nix-action@7ab6e7fd29da88e74b1e314a4ae9ac6b5cda3801 # v31.8.0 - uses: https://github.com/cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
Generated
+605 -322
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -551,9 +551,9 @@ features = ["std"]
version = "1.0.2" version = "1.0.2"
[workspace.dependencies.ldap3] [workspace.dependencies.ldap3]
version = "0.12.0" version = "0.11.5"
default-features = false default-features = false
features = ["sync", "tls-rustls", "rustls-provider"] features = ["sync", "tls-rustls"]
[workspace.dependencies.resolv-conf] [workspace.dependencies.resolv-conf]
version = "0.7.5" version = "0.7.5"
+1 -1
View File
@@ -48,7 +48,7 @@ EOF
# Developer tool versions # Developer tool versions
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall # renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
ENV BINSTALL_VERSION=1.15.7 ENV BINSTALL_VERSION=1.15.5
# renovate: datasource=github-releases depName=psastras/sbom-rs # renovate: datasource=github-releases depName=psastras/sbom-rs
ENV CARGO_SBOM_VERSION=0.9.1 ENV CARGO_SBOM_VERSION=0.9.1
# renovate: datasource=crate depName=lddtree # renovate: datasource=crate depName=lddtree
+1 -1
View File
@@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/etc/apk/cache apk add \
# Developer tool versions # Developer tool versions
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall # renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
ENV BINSTALL_VERSION=1.15.7 ENV BINSTALL_VERSION=1.15.5
# renovate: datasource=github-releases depName=psastras/sbom-rs # renovate: datasource=github-releases depName=psastras/sbom-rs
ENV CARGO_SBOM_VERSION=0.9.1 ENV CARGO_SBOM_VERSION=0.9.1
# renovate: datasource=crate depName=lddtree # renovate: datasource=crate depName=lddtree
Generated
+15 -15
View File
@@ -10,11 +10,11 @@
"nixpkgs-stable": "nixpkgs-stable" "nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1758711588, "lastModified": 1757683818,
"narHash": "sha256-0nZlCCDC5PfndsQJXXtcyrtrfW49I3KadGMDlutzaGU=", "narHash": "sha256-q7q0pWT+wu5AUU1Qlbwq8Mqb+AzHKhaMCVUq/HNZfo8=",
"owner": "zhaofengli", "owner": "zhaofengli",
"repo": "attic", "repo": "attic",
"rev": "12cbeca141f46e1ade76728bce8adc447f2166c6", "rev": "7c5d79ad62cda340cb8c80c99b921b7b7ffacf69",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -99,11 +99,11 @@
}, },
"crane_2": { "crane_2": {
"locked": { "locked": {
"lastModified": 1759893430, "lastModified": 1757183466,
"narHash": "sha256-yAy4otLYm9iZ+NtQwTMEbqHwswSFUbhn7x826RR6djw=", "narHash": "sha256-kTdCCMuRE+/HNHES5JYsbRHmgtr+l9mOtf5dpcMppVc=",
"owner": "ipetkov", "owner": "ipetkov",
"repo": "crane", "repo": "crane",
"rev": "1979a2524cb8c801520bd94c38bb3d5692419d93", "rev": "d599ae4847e7f87603e7082d73ca673aa93c916d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -152,11 +152,11 @@
"rust-analyzer-src": "rust-analyzer-src" "rust-analyzer-src": "rust-analyzer-src"
}, },
"locked": { "locked": {
"lastModified": 1760337631, "lastModified": 1758004879,
"narHash": "sha256-3nvEN2lEpWtM1x7nfuiwpYHLNDgEUiWeBbyvy4vtVw8=", "narHash": "sha256-kV7tQzcNbmo58wg2uE2MQ/etaTx+PxBMHeNrLP8vOgk=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "fee7cf67cbd80a74460563388ac358b394014238", "rev": "07e5ce53dd020e6b337fdddc934561bee0698fa2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -455,11 +455,11 @@
}, },
"nixpkgs_3": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1760256791, "lastModified": 1758029226,
"narHash": "sha256-uTpzDHRASEDeFUuToWSQ46Re8beXyG9dx4W36FQa0/c=", "narHash": "sha256-TjqVmbpoCqWywY9xIZLTf6ANFvDCXdctCjoYuYPYdMI=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "832e3b6db48508ae436c2c7bfc0cf914eac6938e", "rev": "08b8f92ac6354983f5382124fef6006cade4a1c1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -484,11 +484,11 @@
"rust-analyzer-src": { "rust-analyzer-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1760260966, "lastModified": 1757362324,
"narHash": "sha256-pOVvZz/aa+laeaUKyE6PtBevdo4rywMwjhWdSZE/O1c=", "narHash": "sha256-/PAhxheUq4WBrW5i/JHzcCqK5fGWwLKdH6/Lu1tyS18=",
"owner": "rust-lang", "owner": "rust-lang",
"repo": "rust-analyzer", "repo": "rust-analyzer",
"rev": "c5181dbbe33af6f21b9d83e02fdb6fda298a3b65", "rev": "9edc9cbe5d8e832b5864e09854fa94861697d2fd",
"type": "github" "type": "github"
}, },
"original": { "original": {
+7 -3
View File
@@ -64,8 +64,12 @@
"matchDatasources": ["docker"], "matchDatasources": ["docker"],
"matchPackageNames": ["ghcr.io/renovatebot/renovate"], "matchPackageNames": ["ghcr.io/renovatebot/renovate"],
"automerge": true, "automerge": true,
"automergeStrategy": "fast-forward", "automergeStrategy": "fast-forward"
"extends": ["schedule:earlyMondays"] },
{
"description": "Group lockfile updates into a single PR",
"matchUpdateTypes": ["lockFileMaintenance"],
"groupName": "lockfile-maintenance"
} }
], ],
"customManagers": [ "customManagers": [
@@ -77,7 +81,7 @@
"/(^|/|\\.)([Dd]ocker|[Cc]ontainer)file$/" "/(^|/|\\.)([Dd]ocker|[Cc]ontainer)file$/"
], ],
"matchStrings": [ "matchStrings": [
"# renovate: datasource=(?<datasource>[a-zA-Z0-9-._]+?) depName=(?<depName>[^\\s]+?)(?: (lookupName|packageName)=(?<packageName>[^\\s]+?))?(?: versioning=(?<versioning>[^\\s]+?))?(?: extractVersion=(?<extractVersion>[^\\s]+?))?(?: registryUrl=(?<registryUrl>[^\\s]+?))?\\s+(?:ENV\\s+|ARG\\s+)?[A-Za-z0-9_]+?_VERSION[ =][\"']?(?<currentValue>.+?)[\"']?\\s+(?:(?:ENV\\s+|ARG\\s+)?[A-Za-z0-9_]+?_CHECKSUM[ =][\"']?(?<currentDigest>.+?)[\"']?\\s)?" "# renovate: datasource=(?<datasource>[a-z-.]+?) depName=(?<depName>[^\\s]+?)(?: (lookupName|packageName)=(?<packageName>[^\\s]+?))?(?: versioning=(?<versioning>[^\\s]+?))?(?: extractVersion=(?<extractVersion>[^\\s]+?))?(?: registryUrl=(?<registryUrl>[^\\s]+?))?\\s+(?:ENV|ARG)\\s+[A-Za-z0-9_]+?_VERSION[ =][\"']?(?<currentValue>.+?)[\"']?\\s"
] ]
} }
] ]
+2 -6
View File
@@ -64,14 +64,10 @@ pub(crate) async fn create_content_route(
media_id: &utils::random_string(MXC_LENGTH), media_id: &utils::random_string(MXC_LENGTH),
}; };
if let Err(e) = services services
.media .media
.create(mxc, Some(user), Some(&content_disposition), content_type, &body.file) .create(mxc, Some(user), Some(&content_disposition), content_type, &body.file)
.await .await?;
{
err!("Failed to save uploaded media: {e}");
return Err!(Request(Unknown("Failed to save uploaded media")));
}
let blurhash = body.generate_blurhash.then(|| { let blurhash = body.generate_blurhash.then(|| {
services services
+3 -4
View File
@@ -97,12 +97,11 @@ pub(crate) async fn upgrade_room_route(
// Create a replacement room // Create a replacement room
let room_features = RoomVersion::new(&body.new_version)?; let room_features = RoomVersion::new(&body.new_version)?;
let replacement_room_owned = if !room_features.room_ids_as_hashes { let replacement_room: Option<&RoomId> = if room_features.room_ids_as_hashes {
Some(RoomId::new(services.globals.server_name()))
} else {
None None
} else {
Some(&RoomId::new(services.globals.server_name()))
}; };
let replacement_room: Option<&RoomId> = replacement_room_owned.as_ref().map(AsRef::as_ref);
let replacement_room_tmp = match replacement_room { let replacement_room_tmp = match replacement_room {
| Some(v) => v, | Some(v) => v,
| None => &RoomId::new(services.globals.server_name()), | None => &RoomId::new(services.globals.server_name()),
-1
View File
@@ -320,7 +320,6 @@ where
for mut range in ranges { for mut range in ranges {
range.0 = uint!(0); range.0 = uint!(0);
range.1 = range.1.checked_add(uint!(1)).unwrap_or(range.1);
range.1 = range range.1 = range
.1 .1
.clamp(range.0, UInt::try_from(active_rooms.len()).unwrap_or(UInt::MAX)); .clamp(range.0, UInt::try_from(active_rooms.len()).unwrap_or(UInt::MAX));
-13
View File
@@ -34,19 +34,6 @@ pub(super) async fn from(
let max_body_size = services.server.config.max_request_size; let max_body_size = services.server.config.max_request_size;
// Check if the Content-Length header is present and valid, saves us streaming
// the response into memory
if let Some(content_length) = parts.headers.get(http::header::CONTENT_LENGTH) {
if let Ok(content_length) = content_length
.to_str()
.map(|s| s.parse::<usize>().unwrap_or_default())
{
if content_length > max_body_size {
return Err(err!(Request(TooLarge("Request body too large"))));
}
}
}
let body = axum::body::to_bytes(body, max_body_size) let body = axum::body::to_bytes(body, max_body_size)
.await .await
.map_err(|e| err!(Request(TooLarge("Request body too large: {e}"))))?; .map_err(|e| err!(Request(TooLarge("Request body too large: {e}"))))?;
+87 -284
View File
@@ -200,15 +200,11 @@ where
if incoming_event.room_id().is_some() { if incoming_event.room_id().is_some() {
let Some(room_id_server_name) = incoming_event.room_id().unwrap().server_name() let Some(room_id_server_name) = incoming_event.room_id().unwrap().server_name()
else { else {
warn!("legacy room ID has no server name"); warn!("room ID has no servername");
return Ok(false); return Ok(false);
}; };
if room_id_server_name != sender.server_name() { if room_id_server_name != sender.server_name() {
warn!( warn!("servername of room ID does not match servername of sender");
expected = %sender.server_name(),
received = %room_id_server_name,
"server name of legacy room ID does not match server name of sender"
);
return Ok(false); return Ok(false);
} }
} }
@@ -219,12 +215,12 @@ where
.room_version .room_version
.is_some_and(|v| v.deserialize().is_err()) .is_some_and(|v| v.deserialize().is_err())
{ {
warn!("unsupported room version found in m.room.create event"); warn!("invalid room version found in m.room.create event");
return Ok(false); return Ok(false);
} }
if room_version.room_ids_as_hashes && incoming_event.room_id().is_some() { if room_version.room_ids_as_hashes && incoming_event.room_id().is_some() {
warn!("room create event incorrectly claims to have a room ID when it should not"); warn!("room create event incorrectly claims a room ID");
return Ok(false); return Ok(false);
} }
@@ -233,7 +229,7 @@ where
{ {
// If content has no creator field, reject // If content has no creator field, reject
if content.creator.is_none() { if content.creator.is_none() {
warn!("m.room.create event incorrectly omits 'creator' field"); warn!("no creator field found in m.room.create content");
return Ok(false); return Ok(false);
} }
} }
@@ -286,19 +282,16 @@ where
.room_version .room_version
.is_some_and(|v| v.deserialize().is_err()) .is_some_and(|v| v.deserialize().is_err())
{ {
warn!( warn!("invalid room version found in m.room.create event");
create_event_id = %room_create_event.event_id(),
"unsupported room version found in m.room.create event"
);
return Ok(false); return Ok(false);
} }
let expected_room_id = room_create_event.room_id_or_hash(); let expected_room_id = room_create_event.room_id_or_hash();
if incoming_event.room_id().expect("event must have a room ID") != expected_room_id { if incoming_event.room_id().unwrap() != expected_room_id {
warn!( warn!(
expected = %expected_room_id, expected = %expected_room_id,
received = %incoming_event.room_id().unwrap(), received = %incoming_event.room_id().unwrap(),
"room_id of incoming event ({}) does not match that of the m.room.create event ({})", "room_id of incoming event ({}) does not match room_id of m.room.create event ({})",
incoming_event.room_id().unwrap(), incoming_event.room_id().unwrap(),
expected_room_id, expected_room_id,
); );
@@ -311,15 +304,12 @@ where
.auth_events() .auth_events()
.any(|id| id == room_create_event.event_id()); .any(|id| id == room_create_event.event_id());
if room_version.room_ids_as_hashes && claims_create_event { if room_version.room_ids_as_hashes && claims_create_event {
warn!("event incorrectly references m.room.create event in auth events"); warn!("m.room.create event incorrectly found in auth events");
return Ok(false); return Ok(false);
} else if !room_version.room_ids_as_hashes && !claims_create_event { } else if !room_version.room_ids_as_hashes && !claims_create_event {
// If the create event is not referenced in the event's auth events, and this is // If the create event is not referenced in the event's auth events, and this is
// a v11 room, reject // a v11 room, reject
warn!( warn!("no m.room.create event found in auth events");
missing = %room_create_event.event_id(),
"event incorrectly did not reference an m.room.create in its auth events"
);
return Ok(false); return Ok(false);
} }
@@ -328,7 +318,7 @@ where
warn!( warn!(
expected = %expected_room_id, expected = %expected_room_id,
received = %pe.room_id().unwrap(), received = %pe.room_id().unwrap(),
"room_id of referenced power levels event does not match that of the m.room.create event" "room_id of power levels event does not match room_id of m.room.create event"
); );
return Ok(false); return Ok(false);
} }
@@ -342,9 +332,8 @@ where
&& room_create_event.sender().server_name() != incoming_event.sender().server_name() && room_create_event.sender().server_name() != incoming_event.sender().server_name()
{ {
warn!( warn!(
sender = %incoming_event.sender(), "room is not federated and event's sender domain does not match create event's \
create_sender = %room_create_event.sender(), sender domain"
"room is not federated and event's sender domain does not match create event's sender domain"
); );
return Ok(false); return Ok(false);
} }
@@ -427,6 +416,7 @@ where
&user_for_join_auth_membership, &user_for_join_auth_membership,
&room_create_event, &room_create_event,
)? { )? {
warn!("membership change not valid for some reason");
return Ok(false); return Ok(false);
} }
@@ -439,7 +429,7 @@ where
let sender_member_event = match sender_member_event { let sender_member_event = match sender_member_event {
| Some(mem) => mem, | Some(mem) => mem,
| None => { | None => {
warn!("sender has no membership event"); warn!("sender not found in room");
return Ok(false); return Ok(false);
}, },
}; };
@@ -450,7 +440,7 @@ where
!= expected_room_id != expected_room_id
{ {
warn!( warn!(
"room_id of incoming event ({}) does not match that of the m.room.create event ({})", "room_id of incoming event ({}) does not match room_id of m.room.create event ({})",
sender_member_event sender_member_event
.room_id() .room_id()
.expect("event must have a room ID"), .expect("event must have a room ID"),
@@ -463,7 +453,8 @@ where
from_json_str(sender_member_event.content().get())?; from_json_str(sender_member_event.content().get())?;
let Some(membership_state) = sender_membership_event_content.membership else { let Some(membership_state) = sender_membership_event_content.membership else {
warn!( warn!(
?sender_membership_event_content, sender_membership_event_content = format!("{sender_membership_event_content:?}"),
event_id = format!("{}", incoming_event.event_id()),
"Sender membership event content missing membership field" "Sender membership event content missing membership field"
); );
return Err(Error::InvalidPdu("Missing membership field".to_owned())); return Err(Error::InvalidPdu("Missing membership field".to_owned()));
@@ -471,11 +462,7 @@ where
let membership_state = membership_state.deserialize()?; let membership_state = membership_state.deserialize()?;
if !matches!(membership_state, MembershipState::Join) { if !matches!(membership_state, MembershipState::Join) {
warn!( warn!("sender's membership is not join");
%sender,
?membership_state,
"sender cannot send events without being joined to the room"
);
return Ok(false); return Ok(false);
} }
@@ -535,12 +522,7 @@ where
}; };
if sender_power_level < invite_level { if sender_power_level < invite_level {
warn!( warn!("sender's cannot send invites in this room");
%sender,
has=?sender_power_level,
required=?invite_level,
"sender cannot send invites in this room"
);
return Ok(false); return Ok(false);
} }
@@ -552,11 +534,7 @@ where
// level, reject If the event has a state_key that starts with an @ and does // level, reject If the event has a state_key that starts with an @ and does
// not match the sender, reject. // not match the sender, reject.
if !can_send_event(incoming_event, power_levels_event.as_ref(), sender_power_level) { if !can_send_event(incoming_event, power_levels_event.as_ref(), sender_power_level) {
warn!( warn!("user cannot send event");
%sender,
event_type=?incoming_event.kind(),
"sender cannot send event"
);
return Ok(false); return Ok(false);
} }
@@ -601,12 +579,6 @@ where
}; };
if !check_redaction(room_version, incoming_event, sender_power_level, redact_level)? { if !check_redaction(room_version, incoming_event, sender_power_level, redact_level)? {
warn!(
%sender,
?sender_power_level,
?redact_level,
"redaction event was not allowed"
);
return Ok(false); return Ok(false);
} }
} }
@@ -787,7 +759,7 @@ where
if prev_event_is_create_event && no_more_prev_events { if prev_event_is_create_event && no_more_prev_events {
trace!( trace!(
%sender, sender = %sender,
target_user = %target_user, target_user = %target_user,
?sender_creator, ?sender_creator,
?target_creator, ?target_creator,
@@ -807,33 +779,22 @@ where
); );
if sender != target_user { if sender != target_user {
// If the sender does not match state_key, reject. // If the sender does not match state_key, reject.
warn!( warn!("Can't make other user join");
%sender,
target_user = %target_user,
"sender cannot join on behalf of another user"
);
false false
} else if target_user_current_membership == MembershipState::Ban { } else if target_user_current_membership == MembershipState::Ban {
// If the sender is banned, reject. // If the sender is banned, reject.
warn!( warn!(?target_user_membership_event_id, "Banned user can't join");
%sender,
membership_event_id = ?target_user_membership_event_id,
"sender cannot join as they are banned from the room"
);
false false
} else { } else {
match join_rules { match join_rules {
| JoinRule::Invite => | JoinRule::Invite =>
if !membership_allows_join { if !membership_allows_join {
warn!( warn!(
%sender, membership=?target_user_current_membership,
membership_event_id = ?target_user_membership_event_id, "Join rule is invite but membership does not allow join"
membership = ?target_user_current_membership,
"sender cannot join as they are not invited to the invite-only room"
); );
false false
} else { } else {
trace!(sender=%sender, "sender is invited to room, allowing join");
true true
}, },
| JoinRule::Knock if !room_version.allow_knocking => { | JoinRule::Knock if !room_version.allow_knocking => {
@@ -843,14 +804,11 @@ where
| JoinRule::Knock => | JoinRule::Knock =>
if !membership_allows_join { if !membership_allows_join {
warn!( warn!(
%sender,
membership_event_id = ?target_user_membership_event_id,
membership=?target_user_current_membership, membership=?target_user_current_membership,
"sender cannot join a knock room without being invited or already joined" "Join rule is knock but membership does not allow join"
); );
false false
} else { } else {
trace!(sender=%sender, "sender is invited or already joined to room, allowing join");
true true
}, },
| JoinRule::KnockRestricted(_) if !room_version.knock_restricted_join_rule => | JoinRule::KnockRestricted(_) if !room_version.knock_restricted_join_rule =>
@@ -862,55 +820,33 @@ where
}, },
| JoinRule::KnockRestricted(_) => { | JoinRule::KnockRestricted(_) => {
if membership_allows_join || user_for_join_auth_is_valid { if membership_allows_join || user_for_join_auth_is_valid {
trace!(
%sender,
%membership_allows_join,
%user_for_join_auth_is_valid,
"sender is invited, already joined to, or authorised to join the room, allowing join"
);
true true
} else { } else {
warn!( warn!(
%sender,
membership_event_id = ?target_user_membership_event_id,
membership=?target_user_current_membership, membership=?target_user_current_membership,
%user_for_join_auth_is_valid, "Join rule is a restricted one, but no valid authorising user \
?user_for_join_auth, was given and the sender's current membership does not permit \
"sender cannot join as they are not invited nor already joined to the room, nor was a \ a join transition"
valid authorising user given to permit the join"
); );
false false
} }
}, },
| JoinRule::Restricted(_) => | JoinRule::Restricted(_) =>
if membership_allows_join || user_for_join_auth_is_valid { if membership_allows_join || user_for_join_auth_is_valid {
trace!(
%sender,
%membership_allows_join,
%user_for_join_auth_is_valid,
"sender is invited, already joined to, or authorised to join the room, allowing join"
);
true true
} else { } else {
warn!( warn!(
%sender, "Join rule is a restricted one but no valid authorising user \
membership_event_id = ?target_user_membership_event_id, was given"
membership=?target_user_current_membership,
%user_for_join_auth_is_valid,
?user_for_join_auth,
"sender cannot join as they are not invited nor already joined to the room, nor was a \
valid authorising user given to permit the join"
); );
false false
}, },
| JoinRule::Public => { | JoinRule::Public => true,
trace!(%sender, "join rule is public, allowing join");
true
},
| _ => { | _ => {
warn!( warn!(
join_rule=?join_rules, join_rule=?join_rules,
"Join rule is unknown, or the rule's conditions were not met" membership=?target_user_current_membership,
"Unknown join rule doesn't allow joining, or the rule's conditions were not met"
); );
false false
}, },
@@ -937,23 +873,16 @@ where
} }
allow allow
}, },
| _ => | _ => {
if !sender_is_joined { if !sender_is_joined
warn!( || target_user_current_membership == MembershipState::Join
%sender, || target_user_current_membership == MembershipState::Ban
?sender_membership_event_id, {
?sender_membership,
"sender cannot produce an invite without being joined to the room",
);
false
} else if matches!(
target_user_current_membership,
MembershipState::Join | MembershipState::Ban
) {
warn!( warn!(
?target_user_membership_event_id, ?target_user_membership_event_id,
?target_user_current_membership, ?sender_membership_event_id,
"cannot invite a user who is banned or already joined", "Can't invite user if sender not joined or the user is currently \
joined or banned",
); );
false false
} else { } else {
@@ -963,107 +892,56 @@ where
.is_some(); .is_some();
if !allow { if !allow {
warn!( warn!(
%sender, ?target_user_membership_event_id,
has=?sender_power, ?power_levels_event_id,
required=?power_levels.invite, "User does not have enough power to invite",
"sender does not have enough power to produce invites",
); );
} }
trace!(
%sender,
?sender_membership_event_id,
?sender_membership,
?target_user_membership_event_id,
?target_user_current_membership,
sender_pl=?sender_power,
required_pl=?power_levels.invite,
"allowing invite"
);
allow allow
}, }
},
} }
}, },
| MembershipState::Leave => { | MembershipState::Leave =>
let can_unban = if target_user_current_membership == MembershipState::Ban {
sender_creator || sender_power.filter(|&p| p < &power_levels.ban).is_some()
} else {
true
};
let can_kick = if !matches!(
target_user_current_membership,
MembershipState::Ban | MembershipState::Leave
) {
sender_creator || sender_power.filter(|&p| p < &power_levels.kick).is_some()
} else {
true
};
if sender == target_user { if sender == target_user {
// self-leave let allow = target_user_current_membership == MembershipState::Join
// let allow = target_user_current_membership == MembershipState::Join || target_user_current_membership == MembershipState::Invite
// || target_user_current_membership == MembershipState::Invite || target_user_current_membership == MembershipState::Knock;
// || target_user_current_membership == MembershipState::Knock;
let allow = matches!(
target_user_current_membership,
MembershipState::Join | MembershipState::Invite | MembershipState::Knock
);
if !allow { if !allow {
warn!( warn!(
%sender, ?target_user_membership_event_id,
current_membership_event_id=?target_user_membership_event_id, ?target_user_current_membership,
current_membership=?target_user_current_membership, "Can't leave if sender is not already invited, knocked, or joined"
"sender cannot leave as they are not already knocking on, invited to, or joined to the room"
); );
} }
trace!(sender=%sender, "allowing leave");
allow allow
} else if !sender_is_joined { } else if !sender_is_joined
|| target_user_current_membership == MembershipState::Ban
&& (sender_creator
|| sender_power.filter(|&p| p < &power_levels.ban).is_some())
{
warn!( warn!(
%sender, ?target_user_membership_event_id,
?sender_membership_event_id, ?sender_membership_event_id,
"sender cannot kick another user as they are not joined to the room", "Can't kick if sender not joined or user is already banned",
);
false
} else if !can_unban {
// If the target is banned, only a room creator or someone with ban power
// level can unban them
warn!(
%sender,
?target_user_membership_event_id,
?power_levels_event_id,
"sender lacks the power level required to unban users",
);
false
} else if !can_kick {
warn!(
%sender,
%target_user,
?target_user_membership_event_id,
?target_user_current_membership,
?power_levels_event_id,
"sender does not have enough power to kick the target",
); );
false false
} else { } else {
trace!( let allow = sender_creator
%sender, || (sender_power.filter(|&p| p >= &power_levels.kick).is_some()
%target_user, && target_power < sender_power);
?target_user_membership_event_id, if !allow {
?target_user_current_membership, warn!(
sender_pl=?sender_power, ?target_user_membership_event_id,
target_pl=?target_power, ?power_levels_event_id,
required_pl=?power_levels.kick, "User does not have enough power to kick",
"allowing kick/unban", );
); }
true allow
} },
},
| MembershipState::Ban => | MembershipState::Ban =>
if !sender_is_joined { if !sender_is_joined {
warn!( warn!(?sender_membership_event_id, "Can't ban user if sender is not joined");
%sender,
?sender_membership_event_id,
"sender cannot ban another user as they are not joined to the room",
);
false false
} else { } else {
let allow = sender_creator let allow = sender_creator
@@ -1071,11 +949,9 @@ where
&& target_power < sender_power); && target_power < sender_power);
if !allow { if !allow {
warn!( warn!(
%sender,
%target_user,
?target_user_membership_event_id, ?target_user_membership_event_id,
?power_levels_event_id, ?power_levels_event_id,
"sender does not have enough power to ban the target", "User does not have enough power to ban",
); );
} }
allow allow
@@ -1101,9 +977,9 @@ where
} else if sender != target_user { } else if sender != target_user {
// 3. If `sender` does not match `state_key`, reject. // 3. If `sender` does not match `state_key`, reject.
warn!( warn!(
%sender, ?sender,
%target_user, ?target_user,
"sender cannot knock on behalf of another user", "Can't make another user knock, sender did not match target"
); );
false false
} else if matches!( } else if matches!(
@@ -1115,25 +991,15 @@ where
// 5. Otherwise, reject. // 5. Otherwise, reject.
warn!( warn!(
?target_user_membership_event_id, ?target_user_membership_event_id,
?sender_membership,
"Knocking with a membership state of ban, invite or join is invalid", "Knocking with a membership state of ban, invite or join is invalid",
); );
false false
} else { } else {
trace!(%sender, "allowing knock");
true true
} }
}, },
| _ => { | _ => {
warn!( warn!("Unknown membership transition");
%sender,
?target_membership,
%target_user,
%target_user_current_membership,
"Unknown or invalid membership transition {} -> {}",
target_user_current_membership,
target_membership
);
false false
}, },
}) })
@@ -1163,13 +1029,6 @@ fn can_send_event(event: &impl Event, ple: Option<&impl Event>, user_level: Int)
if event.state_key().is_some_and(|k| k.starts_with('@')) if event.state_key().is_some_and(|k| k.starts_with('@'))
&& event.state_key() != Some(event.sender().as_str()) && event.state_key() != Some(event.sender().as_str())
{ {
warn!(
%user_level,
required=?event_type_power_level,
state_key=?event.state_key(),
sender=%event.sender(),
"state_key starts with @ but does not match sender",
);
return false; // permission required to post in this room return false; // permission required to post in this room
} }
@@ -1254,14 +1113,7 @@ fn check_power_levels(
// If the current value is equal to the sender's current power level, reject // If the current value is equal to the sender's current power level, reject
if user != power_event.sender() && old_level == Some(&user_level) { if user != power_event.sender() && old_level == Some(&user_level) {
warn!( warn!("m.room.power_level cannot remove ops == to own");
?old_level,
?new_level,
?user,
%user_level,
sender=%power_event.sender(),
"cannot alter the power level of a user with the same power level as sender's own"
);
return Some(false); // cannot remove ops level == to own return Some(false); // cannot remove ops level == to own
} }
@@ -1269,26 +1121,8 @@ fn check_power_levels(
// If the new value is higher than the sender's current power level, reject // If the new value is higher than the sender's current power level, reject
let old_level_too_big = old_level > Some(&user_level); let old_level_too_big = old_level > Some(&user_level);
let new_level_too_big = new_level > Some(&user_level); let new_level_too_big = new_level > Some(&user_level);
if old_level_too_big { if old_level_too_big || new_level_too_big {
warn!( warn!("m.room.power_level failed to add ops > than own");
?old_level,
?new_level,
?user,
%user_level,
sender=%power_event.sender(),
"cannot alter the power level of a user with a higher power level than sender's own"
);
return Some(false); // cannot add ops greater than own
}
if new_level_too_big {
warn!(
?old_level,
?new_level,
?user,
%user_level,
sender=%power_event.sender(),
"cannot set the power level of a user to a level higher than sender's own"
);
return Some(false); // cannot add ops greater than own return Some(false); // cannot add ops greater than own
} }
} }
@@ -1305,26 +1139,8 @@ fn check_power_levels(
// If the new value is higher than the sender's current power level, reject // If the new value is higher than the sender's current power level, reject
let old_level_too_big = old_level > Some(&user_level); let old_level_too_big = old_level > Some(&user_level);
let new_level_too_big = new_level > Some(&user_level); let new_level_too_big = new_level > Some(&user_level);
if old_level_too_big { if old_level_too_big || new_level_too_big {
warn!( warn!("m.room.power_level failed to add ops > than own");
?old_level,
?new_level,
?ev_type,
%user_level,
sender=%power_event.sender(),
"cannot alter the power level of an event with a higher power level than sender's own"
);
return Some(false); // cannot add ops greater than own
}
if new_level_too_big {
warn!(
?old_level,
?new_level,
?ev_type,
%user_level,
sender=%power_event.sender(),
"cannot set the power level of an event to a level higher than sender's own"
);
return Some(false); // cannot add ops greater than own return Some(false); // cannot add ops greater than own
} }
} }
@@ -1339,13 +1155,7 @@ fn check_power_levels(
let old_level_too_big = old_level > user_level; let old_level_too_big = old_level > user_level;
let new_level_too_big = new_level > user_level; let new_level_too_big = new_level > user_level;
if old_level_too_big || new_level_too_big { if old_level_too_big || new_level_too_big {
warn!( warn!("m.room.power_level failed to add ops > than own");
?old_level,
?new_level,
%user_level,
sender=%power_event.sender(),
"cannot alter the power level of notifications greater than sender's own"
);
return Some(false); // cannot add ops greater than own return Some(false); // cannot add ops greater than own
} }
} }
@@ -1369,14 +1179,7 @@ fn check_power_levels(
let new_level_too_big = new_lvl > user_level; let new_level_too_big = new_lvl > user_level;
if old_level_too_big || new_level_too_big { if old_level_too_big || new_level_too_big {
warn!( warn!("cannot add ops > than own");
?old_lvl,
?new_lvl,
%user_level,
sender=%power_event.sender(),
action=%lvl_name,
"cannot alter the power level of action greater than sender's own",
);
return Some(false); return Some(false);
} }
} }
+3 -14
View File
@@ -36,7 +36,7 @@ pub use self::{
room_version::RoomVersion, room_version::RoomVersion,
}; };
use crate::{ use crate::{
debug, debug_error, err, debug, debug_error,
matrix::{Event, StateKey}, matrix::{Event, StateKey},
state_res::room_version::StateResolutionVersion, state_res::room_version::StateResolutionVersion,
trace, trace,
@@ -319,19 +319,8 @@ where
path.pop(); path.pop();
continue; continue;
} }
trace!(event_id = event_id.as_str(), "fetching event for its auth events"); let evt = fetch_event(event_id.clone()).await?;
let evt = fetch_event(event_id.clone()).await; stack.push(evt.auth_events().map(ToOwned::to_owned).collect());
if evt.is_none() {
err!("could not fetch event {} to calculate conflicted subgraph", event_id);
path.pop();
continue;
}
stack.push(
evt.expect("checked")
.auth_events()
.map(ToOwned::to_owned)
.collect(),
);
seen.insert(event_id); seen.insert(event_id);
} }
Some(subgraph) Some(subgraph)
-1
View File
@@ -156,7 +156,6 @@ sentry_telemetry = [
] ]
systemd = [ systemd = [
"conduwuit-router/systemd", "conduwuit-router/systemd",
"conduwuit-service/systemd"
] ]
journald = [ # This is a stub on non-unix platforms journald = [ # This is a stub on non-unix platforms
"dep:tracing-journald", "dep:tracing-journald",
+1
View File
@@ -40,6 +40,7 @@ io_uring = [
"conduwuit-admin/io_uring", "conduwuit-admin/io_uring",
"conduwuit-api/io_uring", "conduwuit-api/io_uring",
"conduwuit-service/io_uring", "conduwuit-service/io_uring",
"conduwuit-api/io_uring",
] ]
jemalloc = [ jemalloc = [
"conduwuit-admin/jemalloc", "conduwuit-admin/jemalloc",
+2 -2
View File
@@ -65,7 +65,7 @@ pub(crate) async fn start(server: Arc<Server>) -> Result<Arc<Services>> {
let services = Services::build(server).await?.start().await?; let services = Services::build(server).await?.start().await?;
#[cfg(all(feature = "systemd", target_os = "linux"))] #[cfg(all(feature = "systemd", target_os = "linux"))]
sd_notify::notify(false, &[sd_notify::NotifyState::Ready]) sd_notify::notify(true, &[sd_notify::NotifyState::Ready])
.expect("failed to notify systemd of ready state"); .expect("failed to notify systemd of ready state");
debug!("Started"); debug!("Started");
@@ -78,7 +78,7 @@ pub(crate) async fn stop(services: Arc<Services>) -> Result<()> {
debug!("Shutting down..."); debug!("Shutting down...");
#[cfg(all(feature = "systemd", target_os = "linux"))] #[cfg(all(feature = "systemd", target_os = "linux"))]
sd_notify::notify(false, &[sd_notify::NotifyState::Stopping]) sd_notify::notify(true, &[sd_notify::NotifyState::Stopping])
.expect("failed to notify systemd of stopping state"); .expect("failed to notify systemd of stopping state");
// Wait for all completions before dropping or we'll lose them to the module // Wait for all completions before dropping or we'll lose them to the module
-7
View File
@@ -67,9 +67,6 @@ release_max_log_level = [
"tracing/max_level_trace", "tracing/max_level_trace",
"tracing/release_max_level_info", "tracing/release_max_level_info",
] ]
systemd = [
"dep:sd-notify",
]
url_preview = [ url_preview = [
"dep:image", "dep:image",
"dep:webpage", "dep:webpage",
@@ -122,9 +119,5 @@ blurhash.optional = true
recaptcha-verify = { version = "0.1.5", default-features = false } recaptcha-verify = { version = "0.1.5", default-features = false }
ctor.workspace = true ctor.workspace = true
[target.'cfg(all(unix, target_os = "linux"))'.dependencies]
sd-notify.workspace = true
sd-notify.optional = true
[lints] [lints]
workspace = true workspace = true
+3 -6
View File
@@ -45,16 +45,13 @@ impl Deref for Service {
fn handle_reload(&self) -> Result { fn handle_reload(&self) -> Result {
if self.server.config.config_reload_signal { if self.server.config.config_reload_signal {
#[cfg(all(feature = "systemd", target_os = "linux"))] #[cfg(all(feature = "systemd", target_os = "linux"))]
sd_notify::notify(false, &[ sd_notify::notify(true, &[sd_notify::NotifyState::Reloading])
sd_notify::NotifyState::Reloading, .expect("failed to notify systemd of reloading state");
sd_notify::NotifyState::monotonic_usec_now().expect("Failed to read monotonic time"),
])
.expect("failed to notify systemd of reloading state");
self.reload(iter::empty())?; self.reload(iter::empty())?;
#[cfg(all(feature = "systemd", target_os = "linux"))] #[cfg(all(feature = "systemd", target_os = "linux"))]
sd_notify::notify(false, &[sd_notify::NotifyState::Ready]) sd_notify::notify(true, &[sd_notify::NotifyState::Ready])
.expect("failed to notify systemd of ready state"); .expect("failed to notify systemd of ready state");
} }
+9 -14
View File
@@ -90,22 +90,17 @@ impl Service {
file: &[u8], file: &[u8],
) -> Result<()> { ) -> Result<()> {
// Width, Height = 0 if it's not a thumbnail // Width, Height = 0 if it's not a thumbnail
let key = self let key = self.db.create_file_metadata(
.db mxc,
.create_file_metadata(mxc, user, &Dim::default(), content_disposition, content_type) user,
.map_err(|e| { &Dim::default(),
err!(Database(error!("Failed to create media metadata for MXC {mxc}: {e}"))) content_disposition,
})?; content_type,
)?;
//TODO: Dangling metadata in database if creation fails //TODO: Dangling metadata in database if creation fails
let mut f = self.create_media_file(&key).await.map_err(|e| { let mut f = self.create_media_file(&key).await?;
err!(Database(error!( f.write_all(file).await?;
"Failed to create media file for MXC {mxc} at key {key:?}: {e}"
)))
})?;
f.write_all(file).await.map_err(|e| {
err!(Database(error!("Failed to write media file for MXC {mxc} at key {key:?}: {e}")))
})?;
Ok(()) Ok(())
} }
+1 -2
View File
@@ -9,7 +9,6 @@ use conduwuit::{
}, },
warn, warn,
}; };
use database::Json;
use futures::{FutureExt, StreamExt, TryStreamExt}; use futures::{FutureExt, StreamExt, TryStreamExt};
use itertools::Itertools; use itertools::Itertools;
use ruma::{ use ruma::{
@@ -607,7 +606,7 @@ async fn fix_corrupt_msc4133_fields(services: &Services) -> Result {
); );
}; };
useridprofilekey_value.put((user, key), Json(new_value)); useridprofilekey_value.put((user, key), new_value);
fixed = fixed.saturating_add(1); fixed = fixed.saturating_add(1);
} }
total = total.saturating_add(1); total = total.saturating_add(1);
@@ -4,8 +4,9 @@ use std::{
}; };
use conduwuit::{ use conduwuit::{
Event, PduEvent, debug, debug_warn, implement, matrix::event::gen_event_id_canonical_json, Event, PduEvent, debug, debug_error, debug_warn, implement,
trace, utils::continue_exponential_backoff_secs, warn, matrix::event::gen_event_id_canonical_json, trace, utils::continue_exponential_backoff_secs,
warn,
}; };
use ruma::{ use ruma::{
CanonicalJsonValue, EventId, OwnedEventId, RoomId, ServerName, CanonicalJsonValue, EventId, OwnedEventId, RoomId, ServerName,
@@ -51,14 +52,12 @@ where
}; };
let mut events_with_auth_events = Vec::with_capacity(events.clone().count()); let mut events_with_auth_events = Vec::with_capacity(events.clone().count());
trace!("Fetching {} outlier pdus", events.clone().count());
for id in events { for id in events {
// a. Look in the main timeline (pduid_pdu tree) // a. Look in the main timeline (pduid_pdu tree)
// b. Look at outlier pdu tree // b. Look at outlier pdu tree
// (get_pdu_json checks both) // (get_pdu_json checks both)
if let Ok(local_pdu) = self.services.timeline.get_pdu(id).await { if let Ok(local_pdu) = self.services.timeline.get_pdu(id).await {
trace!("Found {id} in main timeline or outlier tree");
events_with_auth_events.push((id.to_owned(), Some(local_pdu), vec![])); events_with_auth_events.push((id.to_owned(), Some(local_pdu), vec![]));
continue; continue;
} }
@@ -105,7 +104,7 @@ where
continue; continue;
} }
debug!("Fetching {next_id} over federation from {origin}."); debug!("Fetching {next_id} over federation.");
match self match self
.services .services
.sending .sending
@@ -116,7 +115,7 @@ where
.await .await
{ {
| Ok(res) => { | Ok(res) => {
debug!("Got {next_id} over federation from {origin}"); debug!("Got {next_id} over federation");
let Ok(room_version_id) = get_room_version_id(create_event) else { let Ok(room_version_id) = get_room_version_id(create_event) else {
back_off((*next_id).to_owned()); back_off((*next_id).to_owned());
continue; continue;
@@ -146,9 +145,6 @@ where
auth_event.clone().into(), auth_event.clone().into(),
) { ) {
| Ok(auth_event) => { | Ok(auth_event) => {
trace!(
"Found auth event id {auth_event} for event {next_id}"
);
todo_auth_events.push_back(auth_event); todo_auth_events.push_back(auth_event);
}, },
| _ => { | _ => {
@@ -164,7 +160,7 @@ where
events_all.insert(next_id); events_all.insert(next_id);
}, },
| Err(e) => { | Err(e) => {
warn!("Failed to fetch auth event {next_id} from {origin}: {e}"); debug_error!("Failed to fetch event {next_id}: {e}");
back_off((*next_id).to_owned()); back_off((*next_id).to_owned());
}, },
} }
@@ -179,7 +175,7 @@ where
// b. Look at outlier pdu tree // b. Look at outlier pdu tree
// (get_pdu_json checks both) // (get_pdu_json checks both)
if let Some(local_pdu) = local_pdu { if let Some(local_pdu) = local_pdu {
trace!("Found {id} in main timeline or outlier tree"); trace!("Found {id} in db");
pdus.push((local_pdu.clone(), None)); pdus.push((local_pdu.clone(), None));
} }
@@ -205,7 +201,6 @@ where
} }
} }
trace!("Handling outlier {next_id}");
match Box::pin(self.handle_outlier_pdu( match Box::pin(self.handle_outlier_pdu(
origin, origin,
create_event, create_event,
@@ -218,7 +213,6 @@ where
{ {
| Ok((pdu, json)) => | Ok((pdu, json)) =>
if next_id == *id { if next_id == *id {
trace!("Handled outlier {next_id} (original request)");
pdus.push((pdu, Some(json))); pdus.push((pdu, Some(json)));
}, },
| Err(e) => { | Err(e) => {
@@ -228,6 +222,6 @@ where
} }
} }
} }
trace!("Fetched and handled {} outlier pdus", pdus.len());
pdus pdus
} }
@@ -1,12 +1,11 @@
use std::collections::{BTreeMap, HashMap, hash_map}; use std::collections::{BTreeMap, HashMap, hash_map};
use conduwuit::{ use conduwuit::{
Err, Event, PduEvent, Result, debug, debug_info, debug_warn, err, implement, state_res, trace, Err, Event, PduEvent, Result, debug, debug_info, err, implement, state_res, trace, warn,
}; };
use futures::future::ready; use futures::future::ready;
use ruma::{ use ruma::{
CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, RoomId, ServerName, CanonicalJsonObject, CanonicalJsonValue, EventId, RoomId, ServerName, events::StateEventType,
events::StateEventType,
}; };
use super::{check_room_id, get_room_version_id, to_room_version}; use super::{check_room_id, get_room_version_id, to_room_version};
@@ -75,73 +74,36 @@ where
check_room_id(room_id, &pdu_event)?; check_room_id(room_id, &pdu_event)?;
// Fetch all auth events if !auth_events_known {
let mut auth_events: HashMap<OwnedEventId, PduEvent> = HashMap::new(); // 4. fetch any missing auth events doing all checks listed here starting at 1.
// These are not timeline events
for aid in pdu_event.auth_events() { // 5. Reject "due to auth events" if can't get all the auth events or some of
if let Ok(auth_event) = self.services.timeline.get_pdu(aid).await { // the auth events are also rejected "due to auth events"
check_room_id(room_id, &auth_event)?; // NOTE: Step 5 is not applied anymore because it failed too often
trace!("Found auth event {aid} for outlier event {event_id} locally"); debug!("Fetching auth events");
auth_events.insert(aid.to_owned(), auth_event); Box::pin(self.fetch_and_handle_outliers(
} else { origin,
debug_warn!("Could not find auth event {aid} for outlier event {event_id} locally"); pdu_event.auth_events(),
} create_event,
} room_id,
))
// Fetch any missing ones & reject invalid ones .await;
let missing_auth_events = if auth_events_known {
pdu_event
.auth_events()
.filter(|id| !auth_events.contains_key(*id))
.collect::<Vec<_>>()
} else {
pdu_event.auth_events().collect::<Vec<_>>()
};
if !missing_auth_events.is_empty() || !auth_events_known {
debug_info!(
"Fetching {} missing auth events for outlier event {event_id}",
missing_auth_events.len()
);
for (pdu, _) in self
.fetch_and_handle_outliers(
origin,
missing_auth_events.iter().copied(),
create_event,
room_id,
)
.await
{
auth_events.insert(pdu.event_id().to_owned(), pdu);
}
} else {
debug!("No missing auth events for outlier event {event_id}");
}
// reject if we are still missing some
let still_missing = pdu_event
.auth_events()
.filter(|id| !auth_events.contains_key(*id))
.collect::<Vec<_>>();
if !still_missing.is_empty() {
return Err!(Request(InvalidParam(
"Could not fetch all auth events for outlier event {event_id}, still missing: \
{still_missing:?}"
)));
} }
// 6. Reject "due to auth events" if the event doesn't pass auth based on the // 6. Reject "due to auth events" if the event doesn't pass auth based on the
// auth events // auth events
debug!("Checking based on auth events"); debug!("Checking based on auth events");
let mut auth_events_by_key: HashMap<_, _> = HashMap::with_capacity(auth_events.len());
// Build map of auth events // Build map of auth events
let mut auth_events = HashMap::with_capacity(pdu_event.auth_events().count());
for id in pdu_event.auth_events() { for id in pdu_event.auth_events() {
let auth_event = auth_events let Ok(auth_event) = self.services.timeline.get_pdu(id).await else {
.get(id) warn!("Could not find auth event {id}");
.expect("we just checked that we have all auth events") continue;
.to_owned(); };
check_room_id(room_id, &auth_event)?; check_room_id(room_id, &auth_event)?;
match auth_events_by_key.entry(( match auth_events.entry((
auth_event.kind.to_string().into(), auth_event.kind.to_string().into(),
auth_event auth_event
.state_key .state_key
@@ -161,7 +123,7 @@ where
// The original create event must be in the auth events // The original create event must be in the auth events
if !matches!( if !matches!(
auth_events_by_key.get(&(StateEventType::RoomCreate, String::new().into())), auth_events.get(&(StateEventType::RoomCreate, String::new().into())),
Some(_) | None Some(_) | None
) { ) {
return Err!(Request(InvalidParam("Incoming event refers to wrong create event."))); return Err!(Request(InvalidParam("Incoming event refers to wrong create event.")));
@@ -169,7 +131,7 @@ where
let state_fetch = |ty: &StateEventType, sk: &str| { let state_fetch = |ty: &StateEventType, sk: &str| {
let key = (ty.to_owned(), sk.into()); let key = (ty.to_owned(), sk.into());
ready(auth_events_by_key.get(&key).map(ToOwned::to_owned)) ready(auth_events.get(&key).map(ToOwned::to_owned))
}; };
let auth_check = state_res::event_auth::auth_check( let auth_check = state_res::event_auth::auth_check(