mirror of
https://forgejo.ellis.link/continuwuation/continuwuity/
synced 2026-04-02 13:55:40 +00:00
Compare commits
6 Commits
jade/loggi
...
nex/meta/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a291a2a106 | ||
|
|
b340516610 | ||
|
|
f7891a3c6b | ||
|
|
9ce64a7697 | ||
|
|
07163510fa | ||
|
|
5f9eb0f505 |
@@ -64,7 +64,6 @@ runs:
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
flavor: |
|
||||
latest=auto
|
||||
suffix=${{ inputs.tag_suffix }},onlatest=true
|
||||
tags: |
|
||||
type=semver,pattern={{version}},prefix=v
|
||||
@@ -73,6 +72,7 @@ runs:
|
||||
type=ref,event=branch,prefix=${{ format('refs/heads/{0}', github.event.repository.default_branch) != github.ref && 'branch-' || '' }},
|
||||
type=ref,event=pr
|
||||
type=sha,format=short
|
||||
type=raw,value=latest${{ inputs.tag_suffix }},enable=${{ startsWith(github.ref, 'refs/tags/v') }},priority=1100
|
||||
images: ${{ inputs.images }}
|
||||
# default labels & annotations: https://github.com/docker/metadata-action/blob/master/src/meta.ts#L509
|
||||
env:
|
||||
|
||||
@@ -59,9 +59,10 @@ jobs:
|
||||
# Aggressive GC since cache restores don't increment counter
|
||||
echo "CARGO_INCREMENTAL_GC_TRIGGER=5" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup Rust
|
||||
- name: Setup Rust nightly
|
||||
uses: ./.forgejo/actions/setup-rust
|
||||
with:
|
||||
rust-version: nightly
|
||||
github-token: ${{ secrets.GH_PUBLIC_RO }}
|
||||
|
||||
- name: Get package version and component
|
||||
|
||||
@@ -23,7 +23,7 @@ repos:
|
||||
- id: check-added-large-files
|
||||
|
||||
- repo: https://github.com/crate-ci/typos
|
||||
rev: v1.41.0
|
||||
rev: v1.40.0
|
||||
hooks:
|
||||
- id: typos
|
||||
- id: typos
|
||||
@@ -31,7 +31,7 @@ repos:
|
||||
stages: [commit-msg]
|
||||
|
||||
- repo: https://github.com/crate-ci/committed
|
||||
rev: v1.1.9
|
||||
rev: v1.1.8
|
||||
hooks:
|
||||
- id: committed
|
||||
|
||||
|
||||
@@ -24,4 +24,3 @@ extend-ignore-re = [
|
||||
"continuwuity" = "continuwuity"
|
||||
"continuwity" = "continuwuity"
|
||||
"execuse" = "execuse"
|
||||
"oltp" = "OTLP"
|
||||
|
||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,12 +0,0 @@
|
||||
# Continuwuity 0.5.0 (2025-12-30)
|
||||
|
||||
**This release contains a CRITICAL vulnerability patch, and you must update as soon as possible**
|
||||
|
||||
## Features
|
||||
|
||||
- Enabled the OTLP exporter in default builds, and allow configuring the exporter protocol. (@Jade). (#1251)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Don't allow admin room upgrades, as this can break the admin room (@timedout) (#1245)
|
||||
- Fix invalid creators in power levels during upgrade to v12 (@timedout) (#1245)
|
||||
40
Cargo.lock
generated
40
Cargo.lock
generated
@@ -940,7 +940,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"conduwuit_admin",
|
||||
@@ -972,7 +972,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_admin"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"conduwuit_api",
|
||||
@@ -994,7 +994,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_api"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum 0.7.9",
|
||||
@@ -1027,14 +1027,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_build_metadata"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"built",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_core"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"arrayvec",
|
||||
@@ -1095,7 +1095,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_database"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"conduwuit_core",
|
||||
@@ -1114,7 +1114,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_macros"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"proc-macro2",
|
||||
@@ -1124,7 +1124,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_router"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"axum-client-ip",
|
||||
@@ -1159,7 +1159,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_service"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
@@ -1200,7 +1200,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_web"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"askama",
|
||||
"axum 0.7.9",
|
||||
@@ -1750,7 +1750,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2405,7 +2405,7 @@ dependencies = [
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2 0.6.1",
|
||||
"socket2 0.5.10",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -3121,7 +3121,7 @@ version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3305,8 +3305,6 @@ dependencies = [
|
||||
"prost",
|
||||
"reqwest",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@@ -3749,7 +3747,7 @@ dependencies = [
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"socket2 0.6.1",
|
||||
"socket2 0.5.10",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -3786,9 +3784,9 @@ dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2 0.6.1",
|
||||
"socket2 0.5.10",
|
||||
"tracing",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4325,7 +4323,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6206,7 +6204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"serde",
|
||||
@@ -6215,7 +6213,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xtask-generate-commands"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"clap-markdown",
|
||||
"clap_builder",
|
||||
|
||||
@@ -21,7 +21,7 @@ license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://forgejo.ellis.link/continuwuation/continuwuity"
|
||||
rust-version = "1.86.0"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
|
||||
[workspace.metadata.crane]
|
||||
name = "conduwuit"
|
||||
@@ -426,7 +426,7 @@ features = ["rt-tokio"]
|
||||
|
||||
[workspace.dependencies.opentelemetry-otlp]
|
||||
version = "0.31.0"
|
||||
features = ["http", "grpc-tonic", "trace", "logs", "metrics"]
|
||||
features = ["http", "trace", "logs", "metrics"]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
The `console` feature is now enabled by default, allowing the server console to be used for running admin commands directly.
|
||||
@@ -1 +0,0 @@
|
||||
Certain potentially dangerous admin commands are now restricted to only be usable in the admin room and server console.
|
||||
@@ -1 +0,0 @@
|
||||
Implemented a configuration defined admin list independent of the admin room. (@Terryiscool160).
|
||||
@@ -1 +0,0 @@
|
||||
Fixed unreliable room summary fetching and improved error messages. Contributed by @nex.
|
||||
@@ -1,2 +0,0 @@
|
||||
Client requested timeout parameter is now applied to e2ee key lookups and claims. Related federation requests are now
|
||||
also concurrent. Contributed by @nex.
|
||||
@@ -26,8 +26,8 @@
|
||||
# Also see the `[global.well_known]` config section at the very bottom.
|
||||
#
|
||||
# Examples of delegation:
|
||||
# - https://continuwuity.org/.well-known/matrix/server
|
||||
# - https://continuwuity.org/.well-known/matrix/client
|
||||
# - https://puppygock.gay/.well-known/matrix/server
|
||||
# - https://puppygock.gay/.well-known/matrix/client
|
||||
#
|
||||
# YOU NEED TO EDIT THIS. THIS CANNOT BE CHANGED AFTER WITHOUT A DATABASE
|
||||
# WIPE.
|
||||
@@ -608,11 +608,6 @@
|
||||
#
|
||||
#otlp_filter = "info"
|
||||
|
||||
# Protocol to use for OTLP tracing export. Options are "http" or "grpc".
|
||||
# The HTTP protocol uses port 4318 by default, while gRPC uses port 4317.
|
||||
#
|
||||
#otlp_protocol = "http"
|
||||
|
||||
# If the 'perf_measurements' compile-time feature is enabled, enables
|
||||
# collecting folded stack trace profile of tracing spans using
|
||||
# tracing_flame. The resulting profile can be visualized with inferno[1],
|
||||
@@ -1538,7 +1533,7 @@
|
||||
# a normal continuwuity admin command. The reply will be publicly visible
|
||||
# to the room, originating from the sender.
|
||||
#
|
||||
# example: \\!admin debug ping continuwuity.org
|
||||
# example: \\!admin debug ping puppygock.gay
|
||||
#
|
||||
#admin_escape_commands = true
|
||||
|
||||
@@ -1556,8 +1551,7 @@
|
||||
# For example: `./continuwuity --execute "server admin-notice continuwuity
|
||||
# has started up at $(date)"`
|
||||
#
|
||||
# example: admin_execute = ["debug ping continuwuity.org", "debug echo
|
||||
# hi"]`
|
||||
# example: admin_execute = ["debug ping puppygock.gay", "debug echo hi"]`
|
||||
#
|
||||
#admin_execute = []
|
||||
|
||||
@@ -1590,18 +1584,6 @@
|
||||
#
|
||||
#admin_room_tag = "m.server_notice"
|
||||
|
||||
# A list of Matrix IDs that are qualified as server admins.
|
||||
#
|
||||
# Any Matrix IDs within this list are regarded as an admin
|
||||
# regardless of whether they are in the admin room or not
|
||||
#
|
||||
#admins_list = []
|
||||
|
||||
# Defines whether those within the admin room are added to the
|
||||
# admins_list.
|
||||
#
|
||||
#admins_from_room = true
|
||||
|
||||
# Sentry.io crash/panic reporting, performance monitoring/metrics, etc.
|
||||
# This is NOT enabled by default.
|
||||
#
|
||||
|
||||
@@ -48,7 +48,7 @@ EOF
|
||||
|
||||
# Developer tool versions
|
||||
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
|
||||
ENV BINSTALL_VERSION=1.16.6
|
||||
ENV BINSTALL_VERSION=1.16.2
|
||||
# renovate: datasource=github-releases depName=psastras/sbom-rs
|
||||
ENV CARGO_SBOM_VERSION=0.9.1
|
||||
# renovate: datasource=crate depName=lddtree
|
||||
|
||||
@@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/etc/apk/cache apk add \
|
||||
|
||||
# Developer tool versions
|
||||
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
|
||||
ENV BINSTALL_VERSION=1.16.6
|
||||
ENV BINSTALL_VERSION=1.16.2
|
||||
# renovate: datasource=github-releases depName=psastras/sbom-rs
|
||||
ENV CARGO_SBOM_VERSION=0.9.1
|
||||
# renovate: datasource=crate depName=lddtree
|
||||
|
||||
@@ -128,7 +128,7 @@ ### Log Levels
|
||||
```rs
|
||||
// Good
|
||||
error!(
|
||||
error = ?err,
|
||||
error = %err,
|
||||
room_id = %room_id,
|
||||
"Failed to send event to room"
|
||||
);
|
||||
@@ -264,7 +264,7 @@ ### Code Comments
|
||||
warn!(
|
||||
destination = %destination,
|
||||
attempt = attempt,
|
||||
error = ?err,
|
||||
error = %err,
|
||||
retry_delay_ms = retry_delay.as_millis(),
|
||||
"Federation request failed, retrying"
|
||||
);
|
||||
|
||||
@@ -149,12 +149,11 @@ ### Creating pull requests
|
||||
*looks* done.
|
||||
|
||||
Before submitting a pull request, please ensure:
|
||||
1. Your code passes all CI checks (formatting, linting, typo detection, etc.). Run pre-commit for this.
|
||||
1. Your code passes all CI checks (formatting, linting, typo detection, etc.)
|
||||
2. Your code follows the [code style guide](./code_style)
|
||||
3. Your commit messages follow the conventional commits format
|
||||
4. Tests are added for new functionality
|
||||
5. Documentation is updated if needed
|
||||
6. You have written a [news fragment](#writing-news-fragments) for your changes
|
||||
|
||||
Direct all PRs/MRs to the `main` branch.
|
||||
|
||||
@@ -172,32 +171,3 @@ ### Creating pull requests
|
||||
[sytest]: https://github.com/matrix-org/sytest/
|
||||
[mdbook]: https://rust-lang.github.io/mdBook/
|
||||
[documentation.yml]: https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/.forgejo/workflows/documentation.yml
|
||||
|
||||
#### Writing news fragments
|
||||
|
||||
In order to make writing our changelogs easier, we make use of [Towncrier]. Towncrier builds changelogs based on
|
||||
"news fragments", which are little markdown files in the `changelog.d/` directory that describe individual changes.
|
||||
|
||||
When you make a pull request that changes functionality, fixes a bug, or adds documentation, please add a news fragment
|
||||
describing your change. The file name *MUST* be in the format of `{pull_request_number}.{type}`, where `{type}` is one
|
||||
of the following:
|
||||
|
||||
- `feature` - for new features
|
||||
- `bugfix` - for bug fixes
|
||||
- `doc` - for documentation changes
|
||||
- `misc` - for other changes that don't fit the above categories
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
$ echo "Fixed the quantum flux stabiliser. Contributed by @alice." > changelog.d/42.bugfix
|
||||
```
|
||||
|
||||
(Note: If you want to credit yourself, you should reference your forgejo handle, however links to other platforms are also acceptable.)
|
||||
|
||||
When the next release is made, Towncrier will automatically include your news fragment in the changelog.
|
||||
|
||||
You can read more about writing news fragments in the [Towncrier tutorial][tt].
|
||||
|
||||
[Towncrier]: https://towncrier.readthedocs.io/
|
||||
[tt]: https://towncrier.readthedocs.io/en/stable/tutorial.html#creating-news-fragments
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
"message": "Welcome to Continuwuity! Important announcements about the project will appear here."
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"id": 6,
|
||||
"mention_room": true,
|
||||
"date": "2025-12-30",
|
||||
"message": "Continuwuity v0.5.1 has been released. **The release contains a fix for the critical vulnerability [GHSA-m5p2-vccg-8c9v](https://github.com/continuwuity/continuwuity/security/advisories/GHSA-m5p2-vccg-8c9v) (embargoed) affecting all Conduit-derived servers. Update as soon as possible.**\n\nThis has been *actively exploited* to attempt account takeover and forge events bricking the Continuwuity rooms. The new space is accessible at [Continuwuity (room list)](https://matrix.to/#/!8cR4g-i9ucof69E4JHNg9LbPVkGprHb3SzcrGBDDJgk?via=continuwuity.org&via=starstruck.systems&via=gingershaped.computer)\n"
|
||||
"date": "2025-12-22",
|
||||
"message": "Continuwuity v0.5.0 has been released. **The release contains a fix for the critical vulnerability [GHSA-22fw-4jq7-g8r8](https://github.com/continuwuity/continuwuity/security/advisories/GHSA-22fw-4jq7-g8r8). Update as soon as possible.**\n\nThis has been *actively exploited* to create fake leave events in the Continuwuity rooms. Please leave and rejoin the rooms to fix any issues this may have caused. \n\n - [Continuwuity (space)](https://matrix.to/#/!PxtzompFuodlyzdCDtV5lzjXs10XIHeOOaq_FYodHyk?via=ellis.link&via=gingershaped.computer&via=continuwuity.org)\n - [Continuwuity](https://matrix.to/#/!kn3VQSLcgWGUFm0FFRid4MinJ_aeZPjHQ0irXbHa3bU?via=ellis.link&via=gingershaped.computer&via=continuwuity.org)\n - [Continuwuity Announcements](https://matrix.to/#/!d7zDZg1Vu5nhkCi50jNfOIObD5fpfGhfl48SZWZek7k?via=ellis.link)\n - [Continuwuity Offtopic](https://matrix.to/#/!QlOomq-suHC9rJHfDFVdbcGg4HS2ojSQ0bo4W2JOGMM?via=ellis.link&via=gingershaped.computer&via=continuwuity.org)\n - [Continuwuity Development](https://matrix.to/#/!aAvealFbgiKTJGzumNbjuwDgt1tOkBKwiyfYqE3ouk0?via=ellis.link&via=explodie.org&via=continuwuity.org)\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
tag-message = "chore: Release v{{version}}"
|
||||
@@ -48,31 +48,19 @@ pub enum AdminCommand {
|
||||
Query(QueryCommand),
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, name = "command", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "command")]
|
||||
pub(super) async fn process(command: AdminCommand, context: &Context<'_>) -> Result {
|
||||
use AdminCommand::*;
|
||||
|
||||
match command {
|
||||
| Appservices(command) => {
|
||||
// appservice commands are all restricted
|
||||
context.bail_restricted()?;
|
||||
appservice::process(command, context).await
|
||||
},
|
||||
| Appservices(command) => appservice::process(command, context).await,
|
||||
| Media(command) => media::process(command, context).await,
|
||||
| Users(command) => {
|
||||
// user commands are all restricted
|
||||
context.bail_restricted()?;
|
||||
user::process(command, context).await
|
||||
},
|
||||
| Users(command) => user::process(command, context).await,
|
||||
| Rooms(command) => room::process(command, context).await,
|
||||
| Federation(command) => federation::process(command, context).await,
|
||||
| Server(command) => server::process(command, context).await,
|
||||
| Debug(command) => debug::process(command, context).await,
|
||||
| Query(command) => {
|
||||
// query commands are all restricted
|
||||
context.bail_restricted()?;
|
||||
query::process(command, context).await
|
||||
},
|
||||
| Query(command) => query::process(command, context).await,
|
||||
| Check(command) => check::process(command, context).await,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{fmt, time::SystemTime};
|
||||
|
||||
use conduwuit::{Err, Result};
|
||||
use conduwuit::Result;
|
||||
use conduwuit_service::Services;
|
||||
use futures::{
|
||||
Future, FutureExt, TryFutureExt,
|
||||
@@ -8,7 +8,6 @@
|
||||
lock::Mutex,
|
||||
};
|
||||
use ruma::{EventId, UserId};
|
||||
use service::admin::InvocationSource;
|
||||
|
||||
pub(crate) struct Context<'a> {
|
||||
pub(crate) services: &'a Services,
|
||||
@@ -17,7 +16,6 @@ pub(crate) struct Context<'a> {
|
||||
pub(crate) reply_id: Option<&'a EventId>,
|
||||
pub(crate) sender: Option<&'a UserId>,
|
||||
pub(crate) output: Mutex<BufWriter<Vec<u8>>>,
|
||||
pub(crate) source: InvocationSource,
|
||||
}
|
||||
|
||||
impl Context<'_> {
|
||||
@@ -45,22 +43,4 @@ pub(crate) fn sender_or_service_user(&self) -> &UserId {
|
||||
self.sender
|
||||
.unwrap_or_else(|| self.services.globals.server_user.as_ref())
|
||||
}
|
||||
|
||||
/// Returns an Err if the [`Self::source`] of this context does not allow
|
||||
/// restricted commands to be executed.
|
||||
///
|
||||
/// This is intended to be placed at the start of restricted commands'
|
||||
/// implementations, like so:
|
||||
///
|
||||
/// ```ignore
|
||||
/// self.bail_restricted()?;
|
||||
/// // actual command impl
|
||||
/// ```
|
||||
pub(crate) fn bail_restricted(&self) -> Result {
|
||||
if self.source.allows_restricted() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err!("This command can only be used in the admin room.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,8 +291,6 @@ pub(super) async fn get_remote_pdu(
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn get_room_state(&self, room: OwnedRoomOrAliasId) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
let room_id = self.services.rooms.alias.resolve(&room).await?;
|
||||
let room_state: Vec<Raw<AnyStateEvent>> = self
|
||||
.services
|
||||
@@ -419,6 +417,27 @@ pub(super) async fn change_log_level(&self, filter: Option<String>, reset: bool)
|
||||
Err!("No log level was specified.")
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn sign_json(&self) -> Result {
|
||||
if self.body.len() < 2
|
||||
|| !self.body[0].trim().starts_with("```")
|
||||
|| self.body.last().unwrap_or(&"").trim() != "```"
|
||||
{
|
||||
return Err!("Expected code block in command body. Add --help for details.");
|
||||
}
|
||||
|
||||
let string = self.body[1..self.body.len().checked_sub(1).unwrap()].join("\n");
|
||||
match serde_json::from_str(&string) {
|
||||
| Err(e) => return Err!("Invalid json: {e}"),
|
||||
| Ok(mut value) => {
|
||||
self.services.server_keys.sign_json(&mut value)?;
|
||||
let json_text = serde_json::to_string_pretty(&value)?;
|
||||
write!(self, "{json_text}")
|
||||
},
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn verify_json(&self) -> Result {
|
||||
if self.body.len() < 2
|
||||
@@ -456,10 +475,8 @@ pub(super) async fn verify_pdu(&self, event_id: OwnedEventId) -> Result {
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
#[tracing::instrument(skip(self), level = "info")]
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub(super) async fn first_pdu_in_room(&self, room_id: OwnedRoomId) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if !self
|
||||
.services
|
||||
.rooms
|
||||
@@ -483,10 +500,8 @@ pub(super) async fn first_pdu_in_room(&self, room_id: OwnedRoomId) -> Result {
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
#[tracing::instrument(skip(self), level = "info")]
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub(super) async fn latest_pdu_in_room(&self, room_id: OwnedRoomId) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if !self
|
||||
.services
|
||||
.rooms
|
||||
@@ -510,15 +525,13 @@ pub(super) async fn latest_pdu_in_room(&self, room_id: OwnedRoomId) -> Result {
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
#[tracing::instrument(skip(self), level = "info")]
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub(super) async fn force_set_room_state_from_server(
|
||||
&self,
|
||||
room_id: OwnedRoomId,
|
||||
server_name: OwnedServerName,
|
||||
at_event: Option<OwnedEventId>,
|
||||
) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if !self
|
||||
.services
|
||||
.rooms
|
||||
|
||||
@@ -47,9 +47,9 @@ pub enum DebugCommand {
|
||||
shorteventid: ShortEventId,
|
||||
},
|
||||
|
||||
/// - Attempts to retrieve a PDU from a remote server. **Does not** insert
|
||||
/// it into the database
|
||||
/// or persist it anywhere.
|
||||
/// - Attempts to retrieve a PDU from a remote server. Inserts it into our
|
||||
/// database/timeline if found and we do not have this PDU already
|
||||
/// (following normal event auth rules, handles it as an incoming PDU).
|
||||
GetRemotePdu {
|
||||
/// An event ID (a $ followed by the base64 reference hash)
|
||||
event_id: OwnedEventId,
|
||||
@@ -125,6 +125,12 @@ pub enum DebugCommand {
|
||||
reset: bool,
|
||||
},
|
||||
|
||||
/// - Sign JSON blob
|
||||
///
|
||||
/// This command needs a JSON blob provided in a Markdown code block below
|
||||
/// the command.
|
||||
SignJson,
|
||||
|
||||
/// - Verify JSON signatures
|
||||
///
|
||||
/// This command needs a JSON blob provided in a Markdown code block below
|
||||
|
||||
@@ -8,14 +8,12 @@
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn disable_room(&self, room_id: OwnedRoomId) -> Result {
|
||||
self.bail_restricted()?;
|
||||
self.services.rooms.metadata.disable_room(&room_id, true);
|
||||
self.write_str("Room disabled.").await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn enable_room(&self, room_id: OwnedRoomId) -> Result {
|
||||
self.bail_restricted()?;
|
||||
self.services.rooms.metadata.disable_room(&room_id, false);
|
||||
self.write_str("Room enabled.").await
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ pub(super) async fn delete(
|
||||
mxc: Option<OwnedMxcUri>,
|
||||
event_id: Option<OwnedEventId>,
|
||||
) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if event_id.is_some() && mxc.is_some() {
|
||||
return Err!("Please specify either an MXC or an event ID, not both.",);
|
||||
}
|
||||
@@ -178,8 +176,6 @@ pub(super) async fn delete(
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn delete_list(&self) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if self.body.len() < 2
|
||||
|| !self.body[0].trim().starts_with("```")
|
||||
|| self.body.last().unwrap_or(&"").trim() != "```"
|
||||
@@ -235,8 +231,6 @@ pub(super) async fn delete_past_remote_media(
|
||||
after: bool,
|
||||
yes_i_want_to_delete_local_media: bool,
|
||||
) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if before && after {
|
||||
return Err!("Please only pick one argument, --before or --after.",);
|
||||
}
|
||||
@@ -279,8 +273,6 @@ pub(super) async fn delete_all_from_server(
|
||||
server_name: OwnedServerName,
|
||||
yes_i_want_to_delete_local_media: bool,
|
||||
) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if server_name == self.services.globals.server_name() && !yes_i_want_to_delete_local_media {
|
||||
return Err!("This command only works for remote media by default.",);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ pub(super) fn dispatch(services: Arc<Services>, command: CommandInput) -> Proces
|
||||
Box::pin(handle_command(services, command))
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, name = "admin", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "admin")]
|
||||
async fn handle_command(services: Arc<Services>, command: CommandInput) -> ProcessorResult {
|
||||
AssertUnwindSafe(Box::pin(process_command(services, &command)))
|
||||
.catch_unwind()
|
||||
@@ -59,7 +59,6 @@ async fn process_command(services: Arc<Services>, input: &CommandInput) -> Proce
|
||||
reply_id: input.reply_id.as_deref(),
|
||||
sender: input.sender.as_deref(),
|
||||
output: BufWriter::new(Vec::new()).into(),
|
||||
source: input.source,
|
||||
};
|
||||
|
||||
let (result, mut logs) = process(&context, command, &args).await;
|
||||
|
||||
@@ -98,7 +98,7 @@ async fn ban_room(&self, room: OwnedRoomOrAliasId) -> Result {
|
||||
{
|
||||
| Ok((room_id, servers)) => {
|
||||
debug!(
|
||||
%room_id,
|
||||
?room_id,
|
||||
?servers,
|
||||
"Got federation response fetching room ID for room {room}"
|
||||
);
|
||||
@@ -240,7 +240,7 @@ async fn ban_list_of_rooms(&self) -> Result {
|
||||
{
|
||||
| Ok((room_id, servers)) => {
|
||||
debug!(
|
||||
%room_id,
|
||||
?room_id,
|
||||
?servers,
|
||||
"Got federation response fetching room ID for \
|
||||
{room}",
|
||||
@@ -397,7 +397,7 @@ async fn unban_room(&self, room: OwnedRoomOrAliasId) -> Result {
|
||||
{
|
||||
| Ok((room_id, servers)) => {
|
||||
debug!(
|
||||
%room_id,
|
||||
?room_id,
|
||||
?servers,
|
||||
"Got federation response fetching room ID for room {room}"
|
||||
);
|
||||
|
||||
@@ -24,8 +24,6 @@ pub(super) async fn uptime(&self) -> Result {
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn show_config(&self) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
self.write_str(&format!("{}", *self.services.server.config))
|
||||
.await
|
||||
}
|
||||
@@ -120,8 +118,6 @@ pub(super) async fn list_backups(&self) -> Result {
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn backup_database(&self) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
let db = Arc::clone(&self.services.db);
|
||||
let result = self
|
||||
.services
|
||||
@@ -148,8 +144,6 @@ pub(super) async fn admin_notice(&self, message: Vec<String>) -> Result {
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn reload_mods(&self) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
self.services.server.reload()?;
|
||||
|
||||
self.write_str("Reloading server...").await
|
||||
@@ -174,8 +168,6 @@ pub(super) async fn restart(&self, force: bool) -> Result {
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn shutdown(&self) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
warn!("shutdown command");
|
||||
self.services.server.shutdown()?;
|
||||
|
||||
|
||||
@@ -461,11 +461,9 @@ pub(super) async fn force_join_list_of_local_users(
|
||||
);
|
||||
}
|
||||
|
||||
let server_admins = self.services.admin.get_admins().await;
|
||||
|
||||
if server_admins.is_empty() {
|
||||
return Err!("There are no admins set for this server.");
|
||||
}
|
||||
let Ok(admin_room) = self.services.admin.get_admin_room().await else {
|
||||
return Err!("There is not an admin room to check for server admins.",);
|
||||
};
|
||||
|
||||
let (room_id, servers) = self
|
||||
.services
|
||||
@@ -484,6 +482,15 @@ pub(super) async fn force_join_list_of_local_users(
|
||||
return Err!("We are not joined in this room.");
|
||||
}
|
||||
|
||||
let server_admins: Vec<_> = self
|
||||
.services
|
||||
.rooms
|
||||
.state_cache
|
||||
.active_local_users_in_room(&admin_room)
|
||||
.map(ToOwned::to_owned)
|
||||
.collect()
|
||||
.await;
|
||||
|
||||
if !self
|
||||
.services
|
||||
.rooms
|
||||
@@ -576,11 +583,9 @@ pub(super) async fn force_join_all_local_users(
|
||||
);
|
||||
}
|
||||
|
||||
let server_admins = self.services.admin.get_admins().await;
|
||||
|
||||
if server_admins.is_empty() {
|
||||
return Err!("There are no admins set for this server.");
|
||||
}
|
||||
let Ok(admin_room) = self.services.admin.get_admin_room().await else {
|
||||
return Err!("There is not an admin room to check for server admins.",);
|
||||
};
|
||||
|
||||
let (room_id, servers) = self
|
||||
.services
|
||||
@@ -599,6 +604,15 @@ pub(super) async fn force_join_all_local_users(
|
||||
return Err!("We are not joined in this room.");
|
||||
}
|
||||
|
||||
let server_admins: Vec<_> = self
|
||||
.services
|
||||
.rooms
|
||||
.state_cache
|
||||
.active_local_users_in_room(&admin_room)
|
||||
.map(ToOwned::to_owned)
|
||||
.collect()
|
||||
.await;
|
||||
|
||||
if !self
|
||||
.services
|
||||
.rooms
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
///
|
||||
/// Note: This will not reserve the username, so the username might become
|
||||
/// invalid when trying to register
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "register_available", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "register_available")]
|
||||
pub(crate) async fn get_register_available_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -138,7 +138,7 @@ pub(crate) async fn get_register_available_route(
|
||||
/// - If `inhibit_login` is false: Creates a device and returns device id and
|
||||
/// access_token
|
||||
#[allow(clippy::doc_markdown)]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "register", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "register")]
|
||||
pub(crate) async fn register_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -603,7 +603,7 @@ pub(crate) async fn register_route(
|
||||
/// last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "change_password", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "change_password")]
|
||||
pub(crate) async fn change_password_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -727,7 +727,7 @@ pub(crate) async fn whoami_route(
|
||||
/// - Forgets all to-device events
|
||||
/// - Triggers device list updates
|
||||
/// - Removes ability to log in again
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "deactivate", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "deactivate")]
|
||||
pub(crate) async fn deactivate_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
|
||||
@@ -102,7 +102,7 @@ pub(crate) async fn get_alias_route(
|
||||
};
|
||||
|
||||
let servers = room_available_servers(&services, &room_id, &room_alias, servers).await;
|
||||
debug!(%room_alias, %room_id, "available servers: {servers:?}");
|
||||
debug!(?room_alias, ?room_id, "available servers: {servers:?}");
|
||||
|
||||
Ok(get_alias::v3::Response::new(room_id, servers))
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ pub(crate) async fn get_context_route(
|
||||
}
|
||||
|
||||
if !visible {
|
||||
debug_warn!(req_evt = %event_id, ?base_id, %room_id, "Event requested by {sender_user} but is not allowed to see it, returning 404");
|
||||
debug_warn!(req_evt = ?event_id, ?base_id, ?room_id, "Event requested by {sender_user} but is not allowed to see it, returning 404");
|
||||
return Err!(Request(NotFound("Event not found.")));
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ pub(crate) async fn get_device_route(
|
||||
/// # `PUT /_matrix/client/r0/devices/{deviceId}`
|
||||
///
|
||||
/// Updates the metadata on a given device of the sender user.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "update_device", level = "debug")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "update_device")]
|
||||
pub(crate) async fn update_device_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
/// Lists the public rooms on this server.
|
||||
///
|
||||
/// - Rooms are ordered by the number of joined members
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms")]
|
||||
pub(crate) async fn get_public_rooms_filtered_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -80,7 +80,7 @@ pub(crate) async fn get_public_rooms_filtered_route(
|
||||
/// Lists the public rooms on this server.
|
||||
///
|
||||
/// - Rooms are ordered by the number of joined members
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms")]
|
||||
pub(crate) async fn get_public_rooms_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -116,7 +116,7 @@ pub(crate) async fn get_public_rooms_route(
|
||||
/// # `PUT /_matrix/client/r0/directory/list/room/{roomId}`
|
||||
///
|
||||
/// Sets the visibility of a given room in the room directory.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "room_directory", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "room_directory")]
|
||||
pub(crate) async fn set_room_visibility_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
time::Duration,
|
||||
};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
|
||||
use axum::extract::State;
|
||||
use conduwuit::{
|
||||
Err, Error, Result, debug, debug_warn, err,
|
||||
result::NotFound,
|
||||
utils,
|
||||
utils::{IterStream, stream::WidebandExt},
|
||||
};
|
||||
use conduwuit::{Err, Error, Result, debug, debug_warn, err, result::NotFound, utils};
|
||||
use conduwuit_service::{Services, users::parse_master_key};
|
||||
use futures::{StreamExt, stream::FuturesUnordered};
|
||||
use ruma::{
|
||||
@@ -52,7 +44,7 @@ pub(crate) async fn upload_keys_route(
|
||||
.deserialize()
|
||||
.inspect_err(|e| {
|
||||
debug_warn!(
|
||||
%key_id,
|
||||
?key_id,
|
||||
?one_time_key,
|
||||
"Invalid one time key JSON submitted by client, skipping: {e}"
|
||||
);
|
||||
@@ -94,8 +86,8 @@ pub(crate) async fn upload_keys_route(
|
||||
{
|
||||
if existing_keys.json().get() == device_keys.json().get() {
|
||||
debug!(
|
||||
%sender_user,
|
||||
%sender_device,
|
||||
?sender_user,
|
||||
?sender_device,
|
||||
?device_keys,
|
||||
"Ignoring user uploaded keys as they are an exact copy already in the \
|
||||
database"
|
||||
@@ -142,7 +134,6 @@ pub(crate) async fn get_keys_route(
|
||||
&body.device_keys,
|
||||
|u| u == sender_user,
|
||||
true, // Always allow local users to see device names of other local users
|
||||
body.timeout.unwrap_or(Duration::from_secs(10)),
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -154,12 +145,7 @@ pub(crate) async fn claim_keys_route(
|
||||
State(services): State<crate::State>,
|
||||
body: Ruma<claim_keys::v3::Request>,
|
||||
) -> Result<claim_keys::v3::Response> {
|
||||
claim_keys_helper(
|
||||
&services,
|
||||
&body.one_time_keys,
|
||||
body.timeout.unwrap_or(Duration::from_secs(10)),
|
||||
)
|
||||
.await
|
||||
claim_keys_helper(&services, &body.one_time_keys).await
|
||||
}
|
||||
|
||||
/// # `POST /_matrix/client/r0/keys/device_signing/upload`
|
||||
@@ -338,7 +324,7 @@ pub(crate) async fn upload_signatures_route(
|
||||
for (user_id, keys) in &body.signed_keys {
|
||||
for (key_id, key) in keys {
|
||||
let Ok(key) = serde_json::to_value(key)
|
||||
.inspect_err(|e| debug_warn!(%key_id, "Invalid \"key\" JSON: {e}"))
|
||||
.inspect_err(|e| debug_warn!(?key_id, "Invalid \"key\" JSON: {e}"))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
@@ -435,7 +421,6 @@ pub(crate) async fn get_keys_helper<F>(
|
||||
device_keys_input: &BTreeMap<OwnedUserId, Vec<OwnedDeviceId>>,
|
||||
allowed_signatures: F,
|
||||
include_display_names: bool,
|
||||
timeout: Duration,
|
||||
) -> Result<get_keys::v3::Response>
|
||||
where
|
||||
F: Fn(&UserId) -> bool + Send + Sync,
|
||||
@@ -527,10 +512,9 @@ pub(crate) async fn get_keys_helper<F>(
|
||||
|
||||
let mut failures = BTreeMap::new();
|
||||
|
||||
let futures = get_over_federation
|
||||
let mut futures: FuturesUnordered<_> = get_over_federation
|
||||
.into_iter()
|
||||
.stream()
|
||||
.wide_filter_map(|(server, vec)| async move {
|
||||
.map(|(server, vec)| async move {
|
||||
let mut device_keys_input_fed = BTreeMap::new();
|
||||
for (user_id, keys) in vec {
|
||||
device_keys_input_fed.insert(user_id.to_owned(), keys.clone());
|
||||
@@ -538,22 +522,17 @@ pub(crate) async fn get_keys_helper<F>(
|
||||
|
||||
let request =
|
||||
federation::keys::get_keys::v1::Request { device_keys: device_keys_input_fed };
|
||||
let response = tokio::time::timeout(
|
||||
timeout,
|
||||
services.sending.send_federation_request(server, request),
|
||||
)
|
||||
.await
|
||||
// Need to flatten the Result<Result<V, E>, E> into Result<V, E>
|
||||
.map_err(|_| err!(Request(Unknown("Timeout when getting keys over federation."))))
|
||||
.and_then(|res| res);
|
||||
|
||||
Some((server, response))
|
||||
let response = services
|
||||
.sending
|
||||
.send_federation_request(server, request)
|
||||
.await;
|
||||
|
||||
(server, response)
|
||||
})
|
||||
.collect::<FuturesUnordered<_>>()
|
||||
.await
|
||||
.into_iter();
|
||||
.collect();
|
||||
|
||||
for (server, response) in futures {
|
||||
while let Some((server, response)) = futures.next().await {
|
||||
match response {
|
||||
| Ok(response) => {
|
||||
for (user, master_key) in response.master_keys {
|
||||
@@ -585,8 +564,8 @@ pub(crate) async fn get_keys_helper<F>(
|
||||
self_signing_keys.extend(response.self_signing_keys);
|
||||
device_keys.extend(response.device_keys);
|
||||
},
|
||||
| Err(e) => {
|
||||
failures.insert(server.to_string(), json!({ "error": e.to_string() }));
|
||||
| _ => {
|
||||
failures.insert(server.to_string(), json!({}));
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -629,7 +608,6 @@ fn add_unsigned_device_display_name(
|
||||
pub(crate) async fn claim_keys_helper(
|
||||
services: &Services,
|
||||
one_time_keys_input: &BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, OneTimeKeyAlgorithm>>,
|
||||
timeout: Duration,
|
||||
) -> Result<claim_keys::v3::Response> {
|
||||
let mut one_time_keys = BTreeMap::new();
|
||||
|
||||
@@ -660,39 +638,32 @@ pub(crate) async fn claim_keys_helper(
|
||||
|
||||
let mut failures = BTreeMap::new();
|
||||
|
||||
let futures = get_over_federation
|
||||
let mut futures: FuturesUnordered<_> = get_over_federation
|
||||
.into_iter()
|
||||
.stream()
|
||||
.wide_filter_map(|(server, vec)| async move {
|
||||
.map(|(server, vec)| async move {
|
||||
let mut one_time_keys_input_fed = BTreeMap::new();
|
||||
for (user_id, keys) in vec {
|
||||
one_time_keys_input_fed.insert(user_id.clone(), keys.clone());
|
||||
}
|
||||
let response = tokio::time::timeout(
|
||||
timeout,
|
||||
services.sending.send_federation_request(
|
||||
server,
|
||||
federation::keys::claim_keys::v1::Request {
|
||||
(
|
||||
server,
|
||||
services
|
||||
.sending
|
||||
.send_federation_request(server, federation::keys::claim_keys::v1::Request {
|
||||
one_time_keys: one_time_keys_input_fed,
|
||||
},
|
||||
),
|
||||
})
|
||||
.await,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| err!(Request(Unknown("Timeout when claiming keys over federation."))))
|
||||
.and_then(|res| res);
|
||||
Some((server, response))
|
||||
})
|
||||
.collect::<FuturesUnordered<_>>()
|
||||
.await
|
||||
.into_iter();
|
||||
.collect();
|
||||
|
||||
for (server, response) in futures {
|
||||
while let Some((server, response)) = futures.next().await {
|
||||
match response {
|
||||
| Ok(keys) => {
|
||||
one_time_keys.extend(keys.one_time_keys);
|
||||
},
|
||||
| Err(e) => {
|
||||
failures.insert(server.to_string(), json!({"error": e.to_string()}));
|
||||
| Err(_e) => {
|
||||
failures.insert(server.to_string(), json!({}));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/invite`
|
||||
///
|
||||
/// Tries to send an invite event into the room.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "invite", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "invite")]
|
||||
pub(crate) async fn invite_user_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
},
|
||||
};
|
||||
|
||||
use super::{banned_room_check, validate_remote_member_event_stub};
|
||||
use super::banned_room_check;
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/join`
|
||||
@@ -59,7 +59,7 @@
|
||||
/// rules locally
|
||||
/// - If the server does not know about the room: asks other servers over
|
||||
/// federation
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "join", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "join")]
|
||||
pub(crate) async fn join_room_by_id_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -131,7 +131,7 @@ pub(crate) async fn join_room_by_id_route(
|
||||
/// - If the server does not know about the room: use the server name query
|
||||
/// param if specified. if not specified, asks other servers over federation
|
||||
/// via room alias server name and room ID server name
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "join", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "join")]
|
||||
pub(crate) async fn join_room_by_id_or_alias_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -351,7 +351,7 @@ pub async fn join_room_by_id_helper(
|
||||
Ok(join_room_by_id::v3::Response::new(room_id.to_owned()))
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(%sender_user, %room_id), name = "join_remote", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%sender_user, %room_id), name = "join_remote")]
|
||||
async fn join_room_by_id_helper_remote(
|
||||
services: &Services,
|
||||
sender_user: &UserId,
|
||||
@@ -709,7 +709,7 @@ async fn join_room_by_id_helper_remote(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(%sender_user, %room_id), name = "join_local", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%sender_user, %room_id), name = "join_local")]
|
||||
async fn join_room_by_id_helper_local(
|
||||
services: &Services,
|
||||
sender_user: &UserId,
|
||||
@@ -837,13 +837,6 @@ async fn join_room_by_id_helper_local(
|
||||
err!(BadServerResponse("Invalid make_join event json received from server: {e:?}"))
|
||||
})?;
|
||||
|
||||
validate_remote_member_event_stub(
|
||||
&MembershipState::Join,
|
||||
sender_user,
|
||||
room_id,
|
||||
&join_event_stub,
|
||||
)?;
|
||||
|
||||
let join_authorized_via_users_server = join_event_stub
|
||||
.get("content")
|
||||
.map(|s| {
|
||||
|
||||
@@ -38,13 +38,13 @@
|
||||
},
|
||||
};
|
||||
|
||||
use super::{banned_room_check, join::join_room_by_id_helper, validate_remote_member_event_stub};
|
||||
use super::{banned_room_check, join::join_room_by_id_helper};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/client/*/knock/{roomIdOrAlias}`
|
||||
///
|
||||
/// Tries to knock the room to ask permission to join for the sender user.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "knock", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "knock")]
|
||||
pub(crate) async fn knock_room_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -408,13 +408,6 @@ async fn knock_room_helper_local(
|
||||
err!(BadServerResponse("Invalid make_knock event json received from server: {e:?}"))
|
||||
})?;
|
||||
|
||||
validate_remote_member_event_stub(
|
||||
&MembershipState::Knock,
|
||||
sender_user,
|
||||
room_id,
|
||||
&knock_event_stub,
|
||||
)?;
|
||||
|
||||
knock_event_stub.insert(
|
||||
"origin".to_owned(),
|
||||
CanonicalJsonValue::String(services.globals.server_name().as_str().to_owned()),
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
};
|
||||
use service::Services;
|
||||
|
||||
use super::validate_remote_member_event_stub;
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/client/v3/rooms/{roomId}/leave`
|
||||
@@ -325,13 +324,6 @@ pub async fn remote_leave_room<S: ::std::hash::BuildHasher>(
|
||||
)))
|
||||
})?;
|
||||
|
||||
validate_remote_member_event_stub(
|
||||
&MembershipState::Leave,
|
||||
user_id,
|
||||
room_id,
|
||||
&leave_event_stub,
|
||||
)?;
|
||||
|
||||
// TODO: Is origin needed?
|
||||
leave_event_stub.insert(
|
||||
"origin".to_owned(),
|
||||
|
||||
@@ -13,14 +13,7 @@
|
||||
use axum::extract::State;
|
||||
use conduwuit::{Err, Result, warn};
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use ruma::{
|
||||
CanonicalJsonObject, OwnedRoomId, RoomId, ServerName, UserId,
|
||||
api::client::membership::joined_rooms,
|
||||
events::{
|
||||
StaticEventContent,
|
||||
room::member::{MembershipState, RoomMemberEventContent},
|
||||
},
|
||||
};
|
||||
use ruma::{OwnedRoomId, RoomId, ServerName, UserId, api::client::membership::joined_rooms};
|
||||
use service::Services;
|
||||
|
||||
pub(crate) use self::{
|
||||
@@ -63,7 +56,7 @@ pub(crate) async fn joined_rooms_route(
|
||||
///
|
||||
/// Performs automatic deactivation if `auto_deactivate_banned_room_attempts` is
|
||||
/// enabled
|
||||
#[tracing::instrument(skip(services), level = "info")]
|
||||
#[tracing::instrument(skip(services))]
|
||||
pub(crate) async fn banned_room_check(
|
||||
services: &Services,
|
||||
user_id: &UserId,
|
||||
@@ -160,80 +153,3 @@ pub(crate) async fn banned_room_check(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates that an event returned from a remote server by `/make_*`
|
||||
/// actually is a membership event with the expected fields.
|
||||
///
|
||||
/// Without checking this, the remote server could use the remote membership
|
||||
/// mechanism to trick our server into signing arbitrary malicious events.
|
||||
pub(crate) fn validate_remote_member_event_stub(
|
||||
membership: &MembershipState,
|
||||
user_id: &UserId,
|
||||
room_id: &RoomId,
|
||||
event_stub: &CanonicalJsonObject,
|
||||
) -> Result<()> {
|
||||
let Some(event_type) = event_stub.get("type") else {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with missing type field"
|
||||
));
|
||||
};
|
||||
if event_type != &RoomMemberEventContent::TYPE {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with invalid event type"
|
||||
));
|
||||
}
|
||||
|
||||
let Some(sender) = event_stub.get("sender") else {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with missing sender field"
|
||||
));
|
||||
};
|
||||
if sender != &user_id.as_str() {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with incorrect sender"
|
||||
));
|
||||
}
|
||||
|
||||
let Some(state_key) = event_stub.get("state_key") else {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with missing state_key field"
|
||||
));
|
||||
};
|
||||
if state_key != &user_id.as_str() {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with incorrect state_key"
|
||||
));
|
||||
}
|
||||
|
||||
let Some(event_room_id) = event_stub.get("room_id") else {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with missing room_id field"
|
||||
));
|
||||
};
|
||||
if event_room_id != &room_id.as_str() {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with incorrect room_id"
|
||||
));
|
||||
}
|
||||
|
||||
let Some(content) = event_stub
|
||||
.get("content")
|
||||
.and_then(|content| content.as_object())
|
||||
else {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with missing content field"
|
||||
));
|
||||
};
|
||||
let Some(event_membership) = content.get("membership") else {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with missing membership field"
|
||||
));
|
||||
};
|
||||
if event_membership != &membership.as_str() {
|
||||
return Err!(BadServerResponse(
|
||||
"Remote server returned member event with incorrect room_id"
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ async fn paginate_relations_with_filter(
|
||||
.user_can_see_event(sender_user, room_id, target)
|
||||
.await
|
||||
{
|
||||
debug_warn!(req_evt = %target, %room_id, "Event relations requested by {sender_user} but is not allowed to see it, returning 404");
|
||||
debug_warn!(req_evt = ?target, ?room_id, "Event relations requested by {sender_user} but is not allowed to see it, returning 404");
|
||||
return Err!(Request(NotFound("Event not found.")));
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ struct Report {
|
||||
/// # `POST /_matrix/client/v3/rooms/{roomId}/report`
|
||||
///
|
||||
/// Reports an abusive room to homeserver admins
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_room", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_room")]
|
||||
pub(crate) async fn report_room_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -85,7 +85,7 @@ pub(crate) async fn report_room_route(
|
||||
/// # `POST /_matrix/client/v3/rooms/{roomId}/report/{eventId}`
|
||||
///
|
||||
/// Reports an inappropriate event to homeserver admins
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_event", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_event")]
|
||||
pub(crate) async fn report_event_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -133,7 +133,7 @@ pub(crate) async fn report_event_route(
|
||||
Ok(report_content::v3::Response {})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_user", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_user")]
|
||||
pub(crate) async fn report_user_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
|
||||
@@ -492,7 +492,7 @@ pub(crate) async fn create_room_route(
|
||||
.boxed()
|
||||
.await
|
||||
{
|
||||
warn!(?e, "Failed to send invite");
|
||||
warn!(%e, "Failed to send invite");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,7 +627,7 @@ async fn room_alias_check(
|
||||
.map_err(|e| {
|
||||
err!(Request(InvalidParam(debug_error!(
|
||||
?e,
|
||||
%room_alias_name,
|
||||
?room_alias_name,
|
||||
"Failed to parse room alias.",
|
||||
))))
|
||||
})?;
|
||||
@@ -711,7 +711,7 @@ fn custom_room_id_check(services: &Services, custom_room_id: &str) -> Result<Own
|
||||
}
|
||||
})
|
||||
.inspect(|full_room_id| {
|
||||
debug_info!(%full_room_id, "Full custom room ID");
|
||||
debug_info!(?full_room_id, "Full custom room ID");
|
||||
})
|
||||
.inspect_err(|e| warn!(?e, %custom_room_id, "Failed to create room with custom room ID",))
|
||||
.inspect_err(|e| warn!(?e, ?custom_room_id, "Failed to create room with custom room ID",))
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug, debug_warn, info, trace,
|
||||
Err, Result, debug_warn, trace,
|
||||
utils::{IterStream, future::TryExtExt},
|
||||
};
|
||||
use futures::{
|
||||
FutureExt, StreamExt, TryFutureExt,
|
||||
FutureExt, StreamExt,
|
||||
future::{OptionFuture, join3},
|
||||
stream::FuturesUnordered,
|
||||
};
|
||||
@@ -46,7 +46,7 @@ pub(crate) async fn get_room_summary_legacy(
|
||||
/// # `GET /_matrix/client/v1/room_summary/{roomIdOrAlias}`
|
||||
///
|
||||
/// Returns a short description of the state of a room.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "room_summary", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "room_summary")]
|
||||
pub(crate) async fn get_room_summary(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -79,15 +79,9 @@ async fn room_summary_response(
|
||||
.server_in_room(services.globals.server_name(), room_id)
|
||||
.await
|
||||
{
|
||||
match local_room_summary_response(services, room_id, sender_user)
|
||||
return local_room_summary_response(services, room_id, sender_user)
|
||||
.boxed()
|
||||
.await
|
||||
{
|
||||
| Ok(response) => return Ok(response),
|
||||
| Err(e) => {
|
||||
debug_warn!("Failed to get local room summary: {e:?}, falling back to remote");
|
||||
},
|
||||
}
|
||||
.await;
|
||||
}
|
||||
|
||||
let room =
|
||||
@@ -116,31 +110,27 @@ async fn local_room_summary_response(
|
||||
room_id: &RoomId,
|
||||
sender_user: Option<&UserId>,
|
||||
) -> Result<get_summary::msc3266::Response> {
|
||||
trace!(
|
||||
sender_user = sender_user.map(tracing::field::display),
|
||||
"Sending local room summary response for {room_id:?}"
|
||||
);
|
||||
let (join_rule, world_readable, guest_can_join) = join3(
|
||||
services.rooms.state_accessor.get_join_rules(room_id),
|
||||
services.rooms.state_accessor.is_world_readable(room_id),
|
||||
services.rooms.state_accessor.guest_can_join(room_id),
|
||||
)
|
||||
.await;
|
||||
trace!(?sender_user, "Sending local room summary response for {room_id:?}");
|
||||
let join_rule = services.rooms.state_accessor.get_join_rules(room_id);
|
||||
|
||||
// Synapse allows server admins to bypass visibility checks.
|
||||
// That seems neat so we'll copy that behaviour.
|
||||
if sender_user.is_none() || !services.users.is_admin(sender_user.unwrap()).await {
|
||||
user_can_see_summary(
|
||||
services,
|
||||
room_id,
|
||||
&join_rule.clone().into(),
|
||||
guest_can_join,
|
||||
world_readable,
|
||||
join_rule.allowed_rooms(),
|
||||
sender_user,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
let world_readable = services.rooms.state_accessor.is_world_readable(room_id);
|
||||
|
||||
let guest_can_join = services.rooms.state_accessor.guest_can_join(room_id);
|
||||
|
||||
let (join_rule, world_readable, guest_can_join) =
|
||||
join3(join_rule, world_readable, guest_can_join).await;
|
||||
|
||||
trace!("{join_rule:?}, {world_readable:?}, {guest_can_join:?}");
|
||||
user_can_see_summary(
|
||||
services,
|
||||
room_id,
|
||||
&join_rule.clone().into(),
|
||||
guest_can_join,
|
||||
world_readable,
|
||||
join_rule.allowed_rooms(),
|
||||
sender_user,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let canonical_alias = services
|
||||
.rooms
|
||||
@@ -231,7 +221,7 @@ async fn remote_room_summary_hierarchy_response(
|
||||
servers: &[OwnedServerName],
|
||||
sender_user: Option<&UserId>,
|
||||
) -> Result<SpaceHierarchyParentSummary> {
|
||||
trace!(sender_user = ?sender_user.map(tracing::field::display), ?servers, "Sending remote room summary response for {room_id:?}");
|
||||
trace!(?sender_user, ?servers, "Sending remote room summary response for {room_id:?}");
|
||||
if !services.config.allow_federation {
|
||||
return Err!(Request(Forbidden("Federation is disabled.")));
|
||||
}
|
||||
@@ -241,27 +231,15 @@ async fn remote_room_summary_hierarchy_response(
|
||||
"Federaton of room {room_id} is currently disabled on this server."
|
||||
)));
|
||||
}
|
||||
if servers.is_empty() {
|
||||
return Err!(Request(MissingParam(
|
||||
"No servers were provided to fetch the room over federation"
|
||||
)));
|
||||
}
|
||||
|
||||
let request = get_hierarchy::v1::Request::new(room_id.to_owned());
|
||||
|
||||
let mut requests: FuturesUnordered<_> = servers
|
||||
.iter()
|
||||
.map(|server| {
|
||||
info!("Fetching room summary for {room_id} from server {server}");
|
||||
services
|
||||
.sending
|
||||
.send_federation_request(server, request.clone())
|
||||
.inspect_ok(move |v| {
|
||||
debug!("Fetched room summary for {room_id} from server {server}: {v:?}");
|
||||
})
|
||||
.inspect_err(move |e| {
|
||||
info!("Failed to fetch room summary for {room_id} from server {server}: {e}");
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -277,23 +255,23 @@ async fn remote_room_summary_hierarchy_response(
|
||||
continue;
|
||||
}
|
||||
|
||||
if sender_user.is_none() || !services.users.is_admin(sender_user.unwrap()).await {
|
||||
return user_can_see_summary(
|
||||
services,
|
||||
room_id,
|
||||
&room.join_rule,
|
||||
room.guest_can_join,
|
||||
room.world_readable,
|
||||
room.allowed_room_ids.iter().map(AsRef::as_ref),
|
||||
sender_user,
|
||||
)
|
||||
.await
|
||||
.map(|()| room);
|
||||
}
|
||||
return Ok(room);
|
||||
return user_can_see_summary(
|
||||
services,
|
||||
room_id,
|
||||
&room.join_rule,
|
||||
room.guest_can_join,
|
||||
room.world_readable,
|
||||
room.allowed_room_ids.iter().map(AsRef::as_ref),
|
||||
sender_user,
|
||||
)
|
||||
.await
|
||||
.map(|()| room);
|
||||
}
|
||||
|
||||
Err!(Request(NotFound("Room not found or is not accessible")))
|
||||
Err!(Request(NotFound(
|
||||
"Room is unknown to this server and was unable to fetch over federation with the \
|
||||
provided servers available"
|
||||
)))
|
||||
}
|
||||
|
||||
async fn user_can_see_summary<'a, I>(
|
||||
@@ -333,14 +311,21 @@ async fn user_can_see_summary<'a, I>(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err!(Request(Forbidden("Room is not accessible")))
|
||||
Err!(Request(Forbidden(
|
||||
"Room is not world readable, not publicly accessible/joinable, restricted room \
|
||||
conditions not met, and guest access is forbidden. Not allowed to see details \
|
||||
of this room."
|
||||
)))
|
||||
},
|
||||
| None => {
|
||||
if is_public_room || world_readable {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err!(Request(Forbidden("Room is not accessible")))
|
||||
Err!(Request(Forbidden(
|
||||
"Room is not world readable or publicly accessible/joinable, authentication is \
|
||||
required"
|
||||
)))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
///
|
||||
/// Get the supported login types of this server. One of these should be used as
|
||||
/// the `type` field when logging in.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login")]
|
||||
pub(crate) async fn get_login_types_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -53,7 +53,7 @@ pub(crate) async fn get_login_types_route(
|
||||
/// Authenticates the given user by its ID and its password.
|
||||
///
|
||||
/// Returns the user ID if successful, and an error otherwise.
|
||||
#[tracing::instrument(skip_all, fields(%user_id), name = "password", level = "debug")]
|
||||
#[tracing::instrument(skip_all, fields(%user_id), name = "password")]
|
||||
pub(crate) async fn password_login(
|
||||
services: &Services,
|
||||
user_id: &UserId,
|
||||
@@ -96,7 +96,7 @@ pub(crate) async fn password_login(
|
||||
///
|
||||
/// Creates the user if the user is found in the LDAP and do not already have an
|
||||
/// account.
|
||||
#[tracing::instrument(skip_all, fields(%user_id), name = "ldap", level = "debug")]
|
||||
#[tracing::instrument(skip_all, fields(%user_id), name = "ldap")]
|
||||
pub(super) async fn ldap_login(
|
||||
services: &Services,
|
||||
user_id: &UserId,
|
||||
@@ -212,7 +212,7 @@ pub(crate) async fn handle_login(
|
||||
/// Note: You can use [`GET
|
||||
/// /_matrix/client/r0/login`](fn.get_supported_versions_route.html) to see
|
||||
/// supported login types.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login")]
|
||||
pub(crate) async fn login_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -345,7 +345,7 @@ pub(crate) async fn login_route(
|
||||
/// to log in with the m.login.token flow.
|
||||
///
|
||||
/// <https://spec.matrix.org/v1.13/client-server-api/#post_matrixclientv1loginget_token>
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login_token", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login_token")]
|
||||
pub(crate) async fn login_token_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -413,7 +413,7 @@ pub(crate) async fn login_token_route(
|
||||
/// last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "logout", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "logout")]
|
||||
pub(crate) async fn logout_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
@@ -440,7 +440,7 @@ pub(crate) async fn logout_route(
|
||||
/// Note: This is equivalent to calling [`GET
|
||||
/// /_matrix/client/r0/logout`](fn.logout_route.html) from each device of this
|
||||
/// user.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "logout", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "logout")]
|
||||
pub(crate) async fn logout_all_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
|
||||
@@ -140,8 +140,8 @@ pub(crate) async fn get_state_events_for_key_route(
|
||||
.await
|
||||
.map_err(|_| {
|
||||
err!(Request(NotFound(debug_warn!(
|
||||
room_id = %body.room_id,
|
||||
event_type = %body.event_type,
|
||||
room_id = ?body.room_id,
|
||||
event_type = ?body.event_type,
|
||||
"State event not found in room.",
|
||||
))))
|
||||
})?;
|
||||
@@ -226,7 +226,7 @@ async fn allowed_to_send_state_event(
|
||||
match event_type {
|
||||
| StateEventType::RoomCreate => {
|
||||
return Err!(Request(BadJson(debug_warn!(
|
||||
%room_id,
|
||||
?room_id,
|
||||
"You cannot update m.room.create after a room has been created."
|
||||
))));
|
||||
},
|
||||
@@ -237,7 +237,7 @@ async fn allowed_to_send_state_event(
|
||||
| Ok(acl_content) => {
|
||||
if acl_content.allow_is_empty() {
|
||||
return Err!(Request(BadJson(debug_warn!(
|
||||
%room_id,
|
||||
?room_id,
|
||||
"Sending an ACL event with an empty allow key will permanently \
|
||||
brick the room for non-conduwuit's as this equates to no servers \
|
||||
being allowed to participate in this room."
|
||||
@@ -246,7 +246,7 @@ async fn allowed_to_send_state_event(
|
||||
|
||||
if acl_content.deny_contains("*") && acl_content.allow_contains("*") {
|
||||
return Err!(Request(BadJson(debug_warn!(
|
||||
%room_id,
|
||||
?room_id,
|
||||
"Sending an ACL event with a deny and allow key value of \"*\" will \
|
||||
permanently brick the room for non-conduwuit's as this equates to \
|
||||
no servers being allowed to participate in this room."
|
||||
@@ -258,7 +258,7 @@ async fn allowed_to_send_state_event(
|
||||
&& !acl_content.allow_contains(services.globals.server_name().as_str())
|
||||
{
|
||||
return Err!(Request(BadJson(debug_warn!(
|
||||
%room_id,
|
||||
?room_id,
|
||||
"Sending an ACL event with a deny key value of \"*\" and without \
|
||||
your own server name in the allow key will result in you being \
|
||||
unable to participate in this room."
|
||||
@@ -270,7 +270,7 @@ async fn allowed_to_send_state_event(
|
||||
&& !acl_content.allow_contains(services.globals.server_name().as_str())
|
||||
{
|
||||
return Err!(Request(BadJson(debug_warn!(
|
||||
%room_id,
|
||||
?room_id,
|
||||
"Sending an ACL event for an allow key without \"*\" and without \
|
||||
your own server name in the allow key will result in you being \
|
||||
unable to participate in this room."
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(
|
||||
room_id = %room_id,
|
||||
syncing_user = %sync_context.syncing_user,
|
||||
room_id = ?room_id,
|
||||
syncing_user = ?sync_context.syncing_user,
|
||||
),
|
||||
)]
|
||||
pub(super) async fn load_joined_room(
|
||||
@@ -578,7 +578,7 @@ async fn build_notification_counts(
|
||||
)
|
||||
.await;
|
||||
|
||||
trace!(%notification_count, %highlight_count, "syncing new notification counts");
|
||||
trace!(?notification_count, ?highlight_count, "syncing new notification counts");
|
||||
|
||||
Ok(Some(UnreadNotificationsCount {
|
||||
notification_count: Some(notification_count),
|
||||
@@ -692,8 +692,8 @@ async fn build_room_summary(
|
||||
};
|
||||
|
||||
trace!(
|
||||
%joined_member_count,
|
||||
%invited_member_count,
|
||||
?joined_member_count,
|
||||
?invited_member_count,
|
||||
heroes_length = heroes.as_ref().map(HashSet::len),
|
||||
"syncing updated summary"
|
||||
);
|
||||
|
||||
@@ -307,8 +307,8 @@ async fn build_left_state_and_timeline(
|
||||
}
|
||||
|
||||
trace!(
|
||||
%timeline_start_count,
|
||||
%timeline_end_count,
|
||||
?timeline_start_count,
|
||||
?timeline_end_count,
|
||||
"syncing {} timeline events (limited = {}) and {} state events",
|
||||
timeline.pdus.len(),
|
||||
timeline.limited,
|
||||
|
||||
@@ -275,7 +275,7 @@ pub(crate) async fn build_sync_events(
|
||||
match joined_room {
|
||||
| Ok((room, updates)) => Some((room_id, room, updates)),
|
||||
| Err(err) => {
|
||||
warn!(?err, %room_id, "error loading joined room");
|
||||
warn!(?err, ?room_id, "error loading joined room {}", room_id);
|
||||
None
|
||||
},
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ pub(super) async fn build_state_incremental<'a>(
|
||||
the performance penalty is acceptable.
|
||||
*/
|
||||
|
||||
trace!(%timeline_is_linear, %timeline.limited, "computing state for incremental sync");
|
||||
trace!(?timeline_is_linear, ?timeline.limited, "computing state for incremental sync");
|
||||
|
||||
// fetch the shorteventids of state events in the timeline
|
||||
let state_events_in_timeline: BTreeSet<ShortEventId> = services
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
/// TODO: Implement pagination, currently this just returns everything
|
||||
///
|
||||
/// An implementation of [MSC2666](https://github.com/matrix-org/matrix-spec-proposals/pull/2666)
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "mutual_rooms", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "mutual_rooms")]
|
||||
pub(crate) async fn get_mutual_rooms_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use axum::{Json, extract::State, response::IntoResponse};
|
||||
use conduwuit::{Error, Result};
|
||||
use futures::StreamExt;
|
||||
use ruma::api::client::{
|
||||
discovery::{
|
||||
discover_homeserver::{self, HomeserverInfo, SlidingSyncProxyInfo},
|
||||
@@ -70,18 +71,21 @@ pub(crate) async fn well_known_support(
|
||||
|
||||
// Try to add admin users as contacts if no contacts are configured
|
||||
if contacts.is_empty() {
|
||||
let admin_users = services.admin.get_admins().await;
|
||||
if let Ok(admin_room) = services.admin.get_admin_room().await {
|
||||
let admin_users = services.rooms.state_cache.room_members(&admin_room);
|
||||
let mut stream = admin_users;
|
||||
|
||||
for user_id in &admin_users {
|
||||
if *user_id == services.globals.server_user {
|
||||
continue;
|
||||
while let Some(user_id) = stream.next().await {
|
||||
// Skip server user
|
||||
if *user_id == services.globals.server_user {
|
||||
continue;
|
||||
}
|
||||
contacts.push(Contact {
|
||||
role: role_value.clone(),
|
||||
email_address: None,
|
||||
matrix_id: Some(user_id.to_owned()),
|
||||
});
|
||||
}
|
||||
|
||||
contacts.push(Contact {
|
||||
role: role_value.clone(),
|
||||
email_address: None,
|
||||
matrix_id: Some(user_id.to_owned()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ pub(crate) async fn get_missing_events_route(
|
||||
while i < queued_events.len() && events.len() < limit {
|
||||
let Ok(pdu) = services.rooms.timeline.get_pdu(&queued_events[i]).await else {
|
||||
debug!(
|
||||
body.origin = body.origin.as_ref().map(tracing::field::display),
|
||||
?body.origin,
|
||||
"Event {} does not exist locally, skipping", &queued_events[i]
|
||||
);
|
||||
i = i.saturating_add(1);
|
||||
@@ -59,7 +59,7 @@ pub(crate) async fn get_missing_events_route(
|
||||
.await
|
||||
{
|
||||
debug!(
|
||||
body.origin = body.origin.as_ref().map(tracing::field::display),
|
||||
?body.origin,
|
||||
"Server cannot see {:?} in {:?}, skipping", pdu.event_id, pdu.room_id
|
||||
);
|
||||
i = i.saturating_add(1);
|
||||
@@ -68,7 +68,7 @@ pub(crate) async fn get_missing_events_route(
|
||||
|
||||
let Ok(event) = to_canonical_object(&pdu) else {
|
||||
debug_error!(
|
||||
body.origin = body.origin.as_ref().map(tracing::field::display),
|
||||
?body.origin,
|
||||
"Failed to convert PDU in database to canonical JSON: {pdu:?}"
|
||||
);
|
||||
i = i.saturating_add(1);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
/// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`
|
||||
///
|
||||
/// Invites a remote user to a room.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "invite", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "invite")]
|
||||
pub(crate) async fn create_invite_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/// # `GET /_matrix/federation/v1/make_join/{roomId}/{userId}`
|
||||
///
|
||||
/// Creates a join template.
|
||||
#[tracing::instrument(skip_all, fields(room_id = %body.room_id, user_id = %body.user_id, origin = %body.origin()), level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(room_id = %body.room_id, user_id = %body.user_id, origin = %body.origin()))]
|
||||
pub(crate) async fn create_join_event_template_route(
|
||||
State(services): State<crate::State>,
|
||||
body: Ruma<prepare_join_event::v1::Request>,
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use conduwuit::{
|
||||
Err, Error, Result, debug, debug_warn, err, error,
|
||||
Err, Error, Result, debug,
|
||||
debug::INFO_SPAN_LEVEL,
|
||||
debug_warn, err, error,
|
||||
result::LogErr,
|
||||
trace,
|
||||
utils::{
|
||||
@@ -46,7 +48,7 @@
|
||||
/// Push EDUs and PDUs to this server.
|
||||
#[tracing::instrument(
|
||||
name = "txn",
|
||||
level = "debug",
|
||||
level = INFO_SPAN_LEVEL,
|
||||
skip_all,
|
||||
fields(
|
||||
%client,
|
||||
@@ -81,8 +83,8 @@ pub(crate) async fn send_transaction_message_route(
|
||||
pdus = body.pdus.len(),
|
||||
edus = body.edus.len(),
|
||||
elapsed = ?txn_start_time.elapsed(),
|
||||
id = %body.transaction_id,
|
||||
origin = %body.origin(),
|
||||
id = ?body.transaction_id,
|
||||
origin =?body.origin(),
|
||||
"Starting txn",
|
||||
);
|
||||
|
||||
@@ -108,8 +110,8 @@ pub(crate) async fn send_transaction_message_route(
|
||||
pdus = body.pdus.len(),
|
||||
edus = body.edus.len(),
|
||||
elapsed = ?txn_start_time.elapsed(),
|
||||
id = %body.transaction_id,
|
||||
origin = %body.origin(),
|
||||
id = ?body.transaction_id,
|
||||
origin =?body.origin(),
|
||||
"Finished txn",
|
||||
);
|
||||
for (id, result) in &results {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
use crate::Ruma;
|
||||
|
||||
/// helper method for /send_join v1 and v2
|
||||
#[tracing::instrument(skip(services, pdu, omit_members), fields(room_id = room_id.as_str(), origin = origin.as_str()), level = "info")]
|
||||
#[tracing::instrument(skip(services, pdu, omit_members), fields(room_id = room_id.as_str(), origin = origin.as_str()))]
|
||||
async fn create_join_event(
|
||||
services: &Services,
|
||||
origin: &ServerName,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use axum::extract::State;
|
||||
use conduwuit::{Error, Result};
|
||||
use futures::{FutureExt, StreamExt, TryFutureExt};
|
||||
@@ -98,7 +96,6 @@ pub(crate) async fn get_keys_route(
|
||||
&body.device_keys,
|
||||
|u| Some(u.server_name()) == body.origin.as_deref(),
|
||||
services.globals.allow_device_name_federation(),
|
||||
Duration::from_secs(0),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -127,8 +124,7 @@ pub(crate) async fn claim_keys_route(
|
||||
));
|
||||
}
|
||||
|
||||
let result =
|
||||
claim_keys_helper(&services, &body.one_time_keys, Duration::from_secs(0)).await?;
|
||||
let result = claim_keys_helper(&services, &body.one_time_keys).await?;
|
||||
|
||||
Ok(claim_keys::v1::Response { one_time_keys: result.one_time_keys })
|
||||
}
|
||||
|
||||
@@ -340,7 +340,7 @@ fn set<T>(key: &Key, val: T) -> Result<T>
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "get",
|
||||
level = "trace",
|
||||
level = "trace"
|
||||
skip_all,
|
||||
fields(?key)
|
||||
)]
|
||||
@@ -357,7 +357,7 @@ fn get<T>(key: &Key) -> Result<T>
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "xchg",
|
||||
level = "trace",
|
||||
level = "trace"
|
||||
skip_all,
|
||||
fields(?key, ?val)
|
||||
)]
|
||||
|
||||
@@ -59,7 +59,7 @@ fn deref(&self) -> &Self::Target { HANDLE.with_borrow_mut(|handle| self.load(han
|
||||
|
||||
/// Update the active configuration, returning prior configuration.
|
||||
#[implement(Manager)]
|
||||
#[tracing::instrument(skip_all, level = "info")]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn update(&self, config: Config) -> Result<Arc<Config>> {
|
||||
let config = Arc::new(config);
|
||||
let new = Arc::into_raw(config);
|
||||
|
||||
@@ -69,8 +69,8 @@ pub struct Config {
|
||||
/// Also see the `[global.well_known]` config section at the very bottom.
|
||||
///
|
||||
/// Examples of delegation:
|
||||
/// - https://continuwuity.org/.well-known/matrix/server
|
||||
/// - https://continuwuity.org/.well-known/matrix/client
|
||||
/// - https://puppygock.gay/.well-known/matrix/server
|
||||
/// - https://puppygock.gay/.well-known/matrix/client
|
||||
///
|
||||
/// YOU NEED TO EDIT THIS. THIS CANNOT BE CHANGED AFTER WITHOUT A DATABASE
|
||||
/// WIPE.
|
||||
@@ -737,13 +737,6 @@ pub struct Config {
|
||||
#[serde(default = "default_otlp_filter", alias = "jaeger_filter")]
|
||||
pub otlp_filter: String,
|
||||
|
||||
/// Protocol to use for OTLP tracing export. Options are "http" or "grpc".
|
||||
/// The HTTP protocol uses port 4318 by default, while gRPC uses port 4317.
|
||||
///
|
||||
/// default: "http"
|
||||
#[serde(default = "default_otlp_protocol")]
|
||||
pub otlp_protocol: String,
|
||||
|
||||
/// If the 'perf_measurements' compile-time feature is enabled, enables
|
||||
/// collecting folded stack trace profile of tracing spans using
|
||||
/// tracing_flame. The resulting profile can be visualized with inferno[1],
|
||||
@@ -1759,7 +1752,7 @@ pub struct Config {
|
||||
/// a normal continuwuity admin command. The reply will be publicly visible
|
||||
/// to the room, originating from the sender.
|
||||
///
|
||||
/// example: \\!admin debug ping continuwuity.org
|
||||
/// example: \\!admin debug ping puppygock.gay
|
||||
#[serde(default = "true_fn")]
|
||||
pub admin_escape_commands: bool,
|
||||
|
||||
@@ -1777,8 +1770,7 @@ pub struct Config {
|
||||
/// For example: `./continuwuity --execute "server admin-notice continuwuity
|
||||
/// has started up at $(date)"`
|
||||
///
|
||||
/// example: admin_execute = ["debug ping continuwuity.org", "debug echo
|
||||
/// hi"]`
|
||||
/// example: admin_execute = ["debug ping puppygock.gay", "debug echo hi"]`
|
||||
///
|
||||
/// default: []
|
||||
#[serde(default)]
|
||||
@@ -1819,22 +1811,6 @@ pub struct Config {
|
||||
#[serde(default = "default_admin_room_tag")]
|
||||
pub admin_room_tag: String,
|
||||
|
||||
/// A list of Matrix IDs that are qualified as server admins.
|
||||
///
|
||||
/// Any Matrix IDs within this list are regarded as an admin
|
||||
/// regardless of whether they are in the admin room or not
|
||||
///
|
||||
/// default: []
|
||||
#[serde(default)]
|
||||
pub admins_list: Vec<OwnedUserId>,
|
||||
|
||||
/// Defines whether those within the admin room are added to the
|
||||
/// admins_list.
|
||||
///
|
||||
/// default: true
|
||||
#[serde(default = "true_fn")]
|
||||
pub admins_from_room: bool,
|
||||
|
||||
/// Sentry.io crash/panic reporting, performance monitoring/metrics, etc.
|
||||
/// This is NOT enabled by default.
|
||||
#[serde(default)]
|
||||
@@ -2442,8 +2418,6 @@ fn default_otlp_filter() -> String {
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn default_otlp_protocol() -> String { "http".to_owned() }
|
||||
|
||||
fn default_tracing_flame_output_path() -> String { "./tracing.folded".to_owned() }
|
||||
|
||||
fn default_trusted_servers() -> Vec<OwnedServerName> {
|
||||
|
||||
@@ -532,8 +532,8 @@ pub async fn auth_check<E, F, Fut>(
|
||||
if sender_power_level < invite_level {
|
||||
warn!(
|
||||
%sender,
|
||||
has=%sender_power_level,
|
||||
required=%invite_level,
|
||||
has=?sender_power_level,
|
||||
required=?invite_level,
|
||||
"sender cannot send invites in this room"
|
||||
);
|
||||
return Ok(false);
|
||||
@@ -558,19 +558,12 @@ pub async fn auth_check<E, F, Fut>(
|
||||
// If type is m.room.power_levels
|
||||
if *incoming_event.event_type() == TimelineEventType::RoomPowerLevels {
|
||||
debug!("starting m.room.power_levels check");
|
||||
let mut creators = BTreeSet::new();
|
||||
if room_version.explicitly_privilege_room_creators {
|
||||
creators.insert(create_event.sender().to_owned());
|
||||
for creator in room_create_content.additional_creators.iter().flatten() {
|
||||
creators.insert(creator.deserialize()?);
|
||||
}
|
||||
}
|
||||
|
||||
match check_power_levels(
|
||||
room_version,
|
||||
incoming_event,
|
||||
power_levels_event.as_ref(),
|
||||
sender_power_level,
|
||||
&creators,
|
||||
) {
|
||||
| Some(required_pwr_lvl) =>
|
||||
if !required_pwr_lvl {
|
||||
@@ -605,8 +598,8 @@ pub async fn auth_check<E, F, Fut>(
|
||||
if !check_redaction(room_version, incoming_event, sender_power_level, redact_level)? {
|
||||
warn!(
|
||||
%sender,
|
||||
%sender_power_level,
|
||||
%redact_level,
|
||||
?sender_power_level,
|
||||
?redact_level,
|
||||
"redaction event was not allowed"
|
||||
);
|
||||
return Ok(false);
|
||||
@@ -772,12 +765,11 @@ struct GetThirdPartyInvite {
|
||||
power_levels_event.as_ref().is_some(),
|
||||
) || auth_user_pl >= invite_level;
|
||||
trace!(
|
||||
%auth_user_pl,
|
||||
%auth_user_pl,
|
||||
%invite_level,
|
||||
%user_joined,
|
||||
%okay_power,
|
||||
passing=%(user_joined && okay_power),
|
||||
auth_user_pl=?auth_user_pl,
|
||||
invite_level=?invite_level,
|
||||
user_joined=?user_joined,
|
||||
okay_power=?okay_power,
|
||||
passing=?(user_joined && okay_power),
|
||||
"user for join auth is valid check details"
|
||||
);
|
||||
user_joined && okay_power
|
||||
@@ -1212,7 +1204,7 @@ fn can_send_event(event: &impl Event, ple: Option<&impl Event>, user_level: Int)
|
||||
{
|
||||
warn!(
|
||||
%user_level,
|
||||
required=%event_type_power_level,
|
||||
required=?event_type_power_level,
|
||||
state_key=?event.state_key(),
|
||||
sender=%event.sender(),
|
||||
"state_key starts with @ but does not match sender",
|
||||
@@ -1229,8 +1221,8 @@ fn check_power_levels(
|
||||
power_event: &impl Event,
|
||||
previous_power_event: Option<&impl Event>,
|
||||
user_level: Int,
|
||||
creators: &BTreeSet<OwnedUserId>,
|
||||
) -> Option<bool> {
|
||||
// TODO(hydra): This function does not care about creators!
|
||||
match power_event.state_key() {
|
||||
| Some("") => {},
|
||||
| Some(key) => {
|
||||
@@ -1295,10 +1287,6 @@ fn check_power_levels(
|
||||
for user in user_levels_to_check {
|
||||
let old_level = old_state.users.get(user);
|
||||
let new_level = new_state.users.get(user);
|
||||
if new_level.is_some() && creators.contains(user) {
|
||||
warn!("creators cannot appear in the users list of m.room.power_levels");
|
||||
return Some(false); // cannot alter creator power level
|
||||
}
|
||||
if old_level.is_some() && new_level.is_some() && old_level == new_level {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use crate::util::map_err;
|
||||
|
||||
#[implement(Engine)]
|
||||
#[tracing::instrument(skip(self), level = "info")]
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn backup(&self) -> Result {
|
||||
let mut engine = self.backup_engine()?;
|
||||
let config = &self.ctx.server.config;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#[tracing::instrument(
|
||||
parent = None,
|
||||
name = "rocksdb",
|
||||
level = "trace",
|
||||
level = "trace"
|
||||
skip(msg),
|
||||
)]
|
||||
pub(crate) fn handle(level: LogLevel, msg: &str) {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use crate::{Context, or_else};
|
||||
|
||||
#[implement(Engine)]
|
||||
#[tracing::instrument(skip_all, level = "info")]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) async fn open(ctx: Arc<Context>, desc: &[Descriptor]) -> Result<Arc<Self>> {
|
||||
let server = &ctx.server;
|
||||
let config = &server.config;
|
||||
@@ -63,7 +63,7 @@ pub(crate) async fn open(ctx: Arc<Context>, desc: &[Descriptor]) -> Result<Arc<S
|
||||
}
|
||||
|
||||
#[implement(Engine)]
|
||||
#[tracing::instrument(name = "configure", skip_all, level = "debug")]
|
||||
#[tracing::instrument(name = "configure", skip_all)]
|
||||
fn configure_cfds(
|
||||
ctx: &Arc<Context>,
|
||||
db_opts: &Options,
|
||||
@@ -119,7 +119,7 @@ fn configure_cfds(
|
||||
}
|
||||
|
||||
#[implement(Engine)]
|
||||
#[tracing::instrument(name = "discover", skip_all, level = "debug")]
|
||||
#[tracing::instrument(name = "discover", skip_all)]
|
||||
fn discover_cfs(path: &Path, opts: &Options) -> BTreeSet<String> {
|
||||
Db::list_cf(opts, path)
|
||||
.unwrap_or_default()
|
||||
|
||||
@@ -26,7 +26,7 @@ pub struct Options {
|
||||
#[implement(super::Map)]
|
||||
#[tracing::instrument(
|
||||
name = "compact",
|
||||
level = "info",
|
||||
level = "info"
|
||||
skip(self),
|
||||
fields(%self),
|
||||
)]
|
||||
|
||||
@@ -113,7 +113,7 @@ fn drop(&mut self) {
|
||||
}
|
||||
|
||||
#[implement(Pool)]
|
||||
#[tracing::instrument(skip_all, level = "debug")]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) fn close(&self) {
|
||||
let workers = take(&mut *self.workers.lock());
|
||||
|
||||
@@ -147,8 +147,8 @@ pub(crate) fn close(&self) {
|
||||
.map(|result| result.map_err(Error::from_panic))
|
||||
.enumerate()
|
||||
.for_each(|(id, result)| match result {
|
||||
| Ok(()) => trace!(%id, "worker joined"),
|
||||
| Err(error) => error!(%id, "worker joined with error: {error}"),
|
||||
| Ok(()) => trace!(?id, "worker joined"),
|
||||
| Err(error) => error!(?id, "worker joined with error: {error}"),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ fn worker_init(&self, id: usize) {
|
||||
}
|
||||
|
||||
debug!(
|
||||
%group,
|
||||
?group,
|
||||
affinity = ?affinity.collect::<Vec<_>>(),
|
||||
"worker ready"
|
||||
);
|
||||
|
||||
@@ -105,8 +105,8 @@ pub(super) fn configure(server: &Arc<Server>) -> (usize, Vec<usize>, Vec<usize>)
|
||||
.unwrap_or("None"),
|
||||
?worker_counts,
|
||||
?queue_sizes,
|
||||
%total_workers,
|
||||
stream_width = %stream::automatic_width(),
|
||||
?total_workers,
|
||||
stream_width = ?stream::automatic_width(),
|
||||
"Frontend topology",
|
||||
);
|
||||
|
||||
@@ -139,13 +139,13 @@ fn update_stream_width(server: &Arc<Server>, num_queues: usize, total_workers: u
|
||||
let (old_width, new_width) = stream::set_width(req_width);
|
||||
let (old_amp, new_amp) = stream::set_amplification(req_amp);
|
||||
debug!(
|
||||
scale = %config.stream_width_scale,
|
||||
%num_queues,
|
||||
%req_width,
|
||||
%old_width,
|
||||
%new_width,
|
||||
%old_amp,
|
||||
%new_amp,
|
||||
scale = ?config.stream_width_scale,
|
||||
?num_queues,
|
||||
?req_width,
|
||||
?old_width,
|
||||
?new_width,
|
||||
?old_amp,
|
||||
?new_amp,
|
||||
"Updated global stream width"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -63,16 +63,15 @@ standard = [
|
||||
"systemd",
|
||||
"url_preview",
|
||||
"zstd_compression",
|
||||
"sentry_telemetry",
|
||||
"otlp_telemetry",
|
||||
"console",
|
||||
"sentry_telemetry"
|
||||
]
|
||||
full = [
|
||||
"standard",
|
||||
# "hardened_malloc", # Conflicts with jemalloc
|
||||
"jemalloc_prof",
|
||||
"perf_measurements",
|
||||
"tokio_console",
|
||||
"tokio_console"
|
||||
# sentry_telemetry
|
||||
]
|
||||
|
||||
blurhashing = [
|
||||
@@ -125,15 +124,12 @@ ldap = [
|
||||
media_thumbnail = [
|
||||
"conduwuit-service/media_thumbnail",
|
||||
]
|
||||
otlp_telemetry = [
|
||||
perf_measurements = [
|
||||
"dep:opentelemetry",
|
||||
"dep:tracing-flame",
|
||||
"dep:tracing-opentelemetry",
|
||||
"dep:opentelemetry_sdk",
|
||||
"dep:opentelemetry-otlp",
|
||||
]
|
||||
perf_measurements = [
|
||||
"dep:tracing-flame",
|
||||
"otlp_telemetry",
|
||||
"conduwuit-core/perf_measurements",
|
||||
"conduwuit-core/sentry_telemetry",
|
||||
]
|
||||
|
||||
@@ -6,12 +6,9 @@
|
||||
debug_warn, err,
|
||||
log::{ConsoleFormat, ConsoleWriter, LogLevelReloadHandles, capture, fmt_span},
|
||||
result::UnwrapOrErr,
|
||||
warn,
|
||||
};
|
||||
#[cfg(feature = "otlp_telemetry")]
|
||||
#[cfg(feature = "perf_measurements")]
|
||||
use opentelemetry::trace::TracerProvider;
|
||||
#[cfg(feature = "otlp_telemetry")]
|
||||
use opentelemetry_otlp::WithExportConfig;
|
||||
use tracing_subscriber::{EnvFilter, Layer, Registry, fmt, layer::SubscriberExt, reload};
|
||||
|
||||
#[cfg(feature = "perf_measurements")]
|
||||
@@ -73,57 +70,6 @@ pub(crate) fn init(
|
||||
subscriber.with(sentry_layer.with_filter(sentry_reload_filter))
|
||||
};
|
||||
|
||||
#[cfg(feature = "otlp_telemetry")]
|
||||
let subscriber = {
|
||||
let otlp_filter = EnvFilter::try_new(&config.otlp_filter)
|
||||
.map_err(|e| err!(Config("otlp_filter", "{e}.")))?;
|
||||
|
||||
let otlp_layer = config.allow_otlp.then(|| {
|
||||
opentelemetry::global::set_text_map_propagator(
|
||||
opentelemetry_sdk::propagation::TraceContextPropagator::new(),
|
||||
);
|
||||
|
||||
let exporter = match config.otlp_protocol.as_str() {
|
||||
| "grpc" => opentelemetry_otlp::SpanExporter::builder()
|
||||
.with_tonic()
|
||||
.with_protocol(opentelemetry_otlp::Protocol::Grpc) // TODO: build from env when 0.32 is released
|
||||
.build()
|
||||
.expect("Failed to create OTLP gRPC exporter"),
|
||||
| "http" => opentelemetry_otlp::SpanExporter::builder()
|
||||
.with_http()
|
||||
.build()
|
||||
.expect("Failed to create OTLP HTTP exporter"),
|
||||
| protocol => {
|
||||
warn!(
|
||||
"Invalid OTLP protocol '{}', falling back to HTTP. Valid options are \
|
||||
'http' or 'grpc'.",
|
||||
protocol
|
||||
);
|
||||
opentelemetry_otlp::SpanExporter::builder()
|
||||
.with_http()
|
||||
.build()
|
||||
.expect("Failed to create OTLP HTTP exporter")
|
||||
},
|
||||
};
|
||||
|
||||
let provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
|
||||
.with_batch_exporter(exporter)
|
||||
.build();
|
||||
|
||||
let tracer = provider.tracer(conduwuit_core::name());
|
||||
|
||||
let telemetry = tracing_opentelemetry::layer().with_tracer(tracer);
|
||||
|
||||
let (otlp_reload_filter, otlp_reload_handle) =
|
||||
reload::Layer::new(otlp_filter.clone());
|
||||
reload_handles.add("otlp", Box::new(otlp_reload_handle));
|
||||
|
||||
Some(telemetry.with_filter(otlp_reload_filter))
|
||||
});
|
||||
|
||||
subscriber.with(otlp_layer)
|
||||
};
|
||||
|
||||
#[cfg(feature = "perf_measurements")]
|
||||
let (subscriber, flame_guard) = {
|
||||
let (flame_layer, flame_guard) = if config.tracing_flame {
|
||||
@@ -143,7 +89,35 @@ pub(crate) fn init(
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let subscriber = subscriber.with(flame_layer);
|
||||
let otlp_filter = EnvFilter::try_new(&config.otlp_filter)
|
||||
.map_err(|e| err!(Config("otlp_filter", "{e}.")))?;
|
||||
|
||||
let otlp_layer = config.allow_otlp.then(|| {
|
||||
opentelemetry::global::set_text_map_propagator(
|
||||
opentelemetry_sdk::propagation::TraceContextPropagator::new(),
|
||||
);
|
||||
|
||||
let exporter = opentelemetry_otlp::SpanExporter::builder()
|
||||
.with_http()
|
||||
.build()
|
||||
.expect("Failed to create OTLP exporter");
|
||||
|
||||
let provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
|
||||
.with_batch_exporter(exporter)
|
||||
.build();
|
||||
|
||||
let tracer = provider.tracer(conduwuit_core::name());
|
||||
|
||||
let telemetry = tracing_opentelemetry::layer().with_tracer(tracer);
|
||||
|
||||
let (otlp_reload_filter, otlp_reload_handle) =
|
||||
reload::Layer::new(otlp_filter.clone());
|
||||
reload_handles.add("otlp", Box::new(otlp_reload_handle));
|
||||
|
||||
Some(telemetry.with_filter(otlp_reload_filter))
|
||||
});
|
||||
|
||||
let subscriber = subscriber.with(flame_layer).with(otlp_layer);
|
||||
(subscriber, flame_guard)
|
||||
};
|
||||
|
||||
|
||||
@@ -50,8 +50,7 @@ pub fn run_with_args(args: &Args) -> Result<()> {
|
||||
#[tracing::instrument(
|
||||
name = "main",
|
||||
parent = None,
|
||||
skip_all,
|
||||
level = "info"
|
||||
skip_all
|
||||
)]
|
||||
async fn async_main(server: &Arc<Server>) -> Result<(), Error> {
|
||||
extern crate conduwuit_router as router;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
use super::server::Server;
|
||||
|
||||
#[cfg(unix)]
|
||||
#[tracing::instrument(skip_all, level = "info")]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(super) async fn signal(server: Arc<Server>) {
|
||||
use signal::unix;
|
||||
use unix::SignalKind;
|
||||
@@ -39,13 +39,13 @@ pub(super) async fn signal(server: Arc<Server>) {
|
||||
};
|
||||
|
||||
if let Err(e) = result {
|
||||
debug_error!(%sig, "signal: {e}");
|
||||
debug_error!(?sig, "signal: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
#[tracing::instrument(skip_all, level = "info")]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(super) async fn signal(server: Arc<Server>) {
|
||||
loop {
|
||||
tokio::select! {
|
||||
|
||||
@@ -66,10 +66,7 @@ pub(crate) fn build(services: &Arc<Services>) -> Result<(Router, Guard)> {
|
||||
.layer(RequestBodyTimeoutLayer::new(Duration::from_secs(
|
||||
server.config.client_receive_timeout,
|
||||
)))
|
||||
.layer(TimeoutLayer::with_status_code(
|
||||
StatusCode::REQUEST_TIMEOUT,
|
||||
Duration::from_secs(server.config.client_request_timeout),
|
||||
))
|
||||
.layer(TimeoutLayer::with_status_code(StatusCode::REQUEST_TIMEOUT, Duration::from_secs(server.config.client_request_timeout)))
|
||||
.layer(SetResponseHeaderLayer::if_not_present(
|
||||
HeaderName::from_static("origin-agent-cluster"), // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin-Agent-Cluster
|
||||
HeaderValue::from_static("?1"),
|
||||
|
||||
@@ -102,13 +102,13 @@ fn handle_result(method: &Method, uri: &Uri, result: Response) -> Result<Respons
|
||||
let reason = status.canonical_reason().unwrap_or("Unknown Reason");
|
||||
|
||||
if status.is_server_error() {
|
||||
error!(%method, %uri, "{code} {reason}");
|
||||
error!(method = ?method, uri = ?uri, "{code} {reason}");
|
||||
} else if status.is_client_error() {
|
||||
debug_error!(%method, %uri, "{code} {reason}");
|
||||
debug_error!(method = ?method, uri = ?uri, "{code} {reason}");
|
||||
} else if status.is_redirection() {
|
||||
debug!(%method, %uri, "{code} {reason}");
|
||||
debug!(method = ?method, uri = ?uri, "{code} {reason}");
|
||||
} else {
|
||||
trace!(%method, %uri, "{code} {reason}");
|
||||
trace!(method = ?method, uri = ?uri, "{code} {reason}");
|
||||
}
|
||||
|
||||
if status == StatusCode::METHOD_NOT_ALLOWED {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
use crate::serve;
|
||||
|
||||
/// Main loop base
|
||||
#[tracing::instrument(skip_all, level = "info")]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) async fn run(services: Arc<Services>) -> Result<()> {
|
||||
let server = &services.server;
|
||||
debug!("Start");
|
||||
@@ -58,7 +58,7 @@ pub(crate) async fn run(services: Arc<Services>) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Async initializations
|
||||
#[tracing::instrument(skip_all, level = "info")]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) async fn start(server: Arc<Server>) -> Result<Arc<Services>> {
|
||||
debug!("Starting...");
|
||||
|
||||
@@ -73,7 +73,7 @@ pub(crate) async fn start(server: Arc<Server>) -> Result<Arc<Services>> {
|
||||
}
|
||||
|
||||
/// Async destructions
|
||||
#[tracing::instrument(skip_all, level = "info")]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) async fn stop(services: Arc<Services>) -> Result<()> {
|
||||
debug!("Shutting down...");
|
||||
|
||||
@@ -108,7 +108,7 @@ pub(crate) async fn stop(services: Arc<Services>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, level = "info")]
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn signal(server: Arc<Server>, tx: Sender<()>, handle: axum_server::Handle) {
|
||||
server
|
||||
.clone()
|
||||
@@ -126,7 +126,7 @@ async fn handle_shutdown(server: Arc<Server>, tx: Sender<()>, handle: axum_serve
|
||||
let timeout = Duration::from_secs(timeout);
|
||||
debug!(
|
||||
?timeout,
|
||||
handle_active = %server.metrics.requests_handle_active.load(Ordering::Relaxed),
|
||||
handle_active = ?server.metrics.requests_handle_active.load(Ordering::Relaxed),
|
||||
"Notifying for graceful shutdown"
|
||||
);
|
||||
|
||||
|
||||
@@ -9,10 +9,7 @@
|
||||
use termimad::MadSkin;
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
use crate::{
|
||||
Dep,
|
||||
admin::{self, InvocationSource},
|
||||
};
|
||||
use crate::{Dep, admin};
|
||||
|
||||
pub struct Console {
|
||||
server: Arc<Server>,
|
||||
@@ -163,11 +160,7 @@ async fn handle(self: Arc<Self>, line: String) {
|
||||
}
|
||||
|
||||
async fn process(self: Arc<Self>, line: String) {
|
||||
match self
|
||||
.admin
|
||||
.command_in_place(line, None, InvocationSource::Console)
|
||||
.await
|
||||
{
|
||||
match self.admin.command_in_place(line, None).await {
|
||||
| Ok(Some(ref content)) => self.output(content),
|
||||
| Err(ref content) => self.output_err(content),
|
||||
| _ => unreachable!(),
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
use ruma::events::room::message::RoomMessageEventContent;
|
||||
use tokio::time::{Duration, sleep};
|
||||
|
||||
use crate::admin::InvocationSource;
|
||||
|
||||
pub(super) const SIGNAL: &str = "SIGUSR2";
|
||||
|
||||
/// Possibly spawn the terminal console at startup if configured.
|
||||
@@ -90,10 +88,7 @@ pub(super) async fn signal_execute(&self) -> Result {
|
||||
async fn execute_command(&self, i: usize, command: String) -> Result {
|
||||
debug!("Execute command #{i}: executing {command:?}");
|
||||
|
||||
match self
|
||||
.command_in_place(command, None, InvocationSource::Console)
|
||||
.await
|
||||
{
|
||||
match self.command_in_place(command, None).await {
|
||||
| Ok(Some(output)) => Self::execute_command_output(i, &output),
|
||||
| Err(output) => Self::execute_command_error(i, &output),
|
||||
| Ok(None) => {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use conduwuit::{
|
||||
Err, Result, debug_info, debug_warn, error, implement, matrix::pdu::PduBuilder, warn,
|
||||
};
|
||||
use conduwuit::{Err, Result, debug_info, debug_warn, error, implement, matrix::pdu::PduBuilder};
|
||||
use ruma::{
|
||||
RoomId, UserId,
|
||||
events::{
|
||||
@@ -122,7 +120,7 @@ pub async fn make_user_admin(&self, user_id: &UserId) -> Result {
|
||||
let room_tag = self.services.server.config.admin_room_tag.as_str();
|
||||
if !room_tag.is_empty() {
|
||||
if let Err(e) = self.set_room_tag(&room_id, user_id, room_tag).await {
|
||||
error!(%room_id, %user_id, %room_tag, "Failed to set tag for admin grant: {e}");
|
||||
error!(?room_id, ?user_id, ?room_tag, "Failed to set tag for admin grant: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,19 +176,6 @@ async fn set_room_tag(&self, room_id: &RoomId, user_id: &UserId, tag: &str) -> R
|
||||
pub async fn revoke_admin(&self, user_id: &UserId) -> Result {
|
||||
use MembershipState::{Invite, Join, Knock, Leave};
|
||||
|
||||
if self
|
||||
.services
|
||||
.server
|
||||
.config
|
||||
.admins_list
|
||||
.contains(&user_id.to_owned())
|
||||
{
|
||||
warn!(
|
||||
"Revoking the admin status of {user_id} will not work correctly as they are within \
|
||||
the admins_list config."
|
||||
);
|
||||
}
|
||||
|
||||
let Ok(room_id) = self.get_admin_room().await else {
|
||||
return Err!(error!("No admin room available or created."));
|
||||
};
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
Error, Event, Result, Server, debug, err, error, error::default_log, pdu::PduBuilder,
|
||||
};
|
||||
pub use create::create_admin_room;
|
||||
use futures::{Future, FutureExt, StreamExt, TryFutureExt};
|
||||
use futures::{Future, FutureExt, TryFutureExt};
|
||||
use loole::{Receiver, Sender};
|
||||
use ruma::{
|
||||
Mxc, OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedUserId, RoomId, UInt, UserId,
|
||||
Mxc, OwnedEventId, OwnedMxcUri, OwnedRoomId, RoomId, UInt, UserId,
|
||||
events::{
|
||||
Mentions,
|
||||
room::{
|
||||
@@ -54,37 +54,15 @@ struct Services {
|
||||
media: Dep<crate::media::Service>,
|
||||
}
|
||||
|
||||
/// Inputs to a command are a multi-line string, invocation source, optional
|
||||
/// reply_id, and optional sender.
|
||||
/// Inputs to a command are a multi-line string, optional reply_id, and optional
|
||||
/// sender.
|
||||
#[derive(Debug)]
|
||||
pub struct CommandInput {
|
||||
pub command: String,
|
||||
pub reply_id: Option<OwnedEventId>,
|
||||
pub source: InvocationSource,
|
||||
pub sender: Option<Box<UserId>>,
|
||||
}
|
||||
|
||||
/// Where a command is being invoked from.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum InvocationSource {
|
||||
/// The server's private admin room
|
||||
AdminRoom,
|
||||
/// An escaped `\!admin` command in a public room
|
||||
EscapedCommand,
|
||||
/// The server's admin console
|
||||
Console,
|
||||
/// Some other trusted internal source
|
||||
Internal,
|
||||
}
|
||||
|
||||
impl InvocationSource {
|
||||
/// Returns whether this invocation source allows "restricted"
|
||||
/// commands, i.e. ones that could be potentially dangerous if executed by
|
||||
/// an attacker or in a public room.
|
||||
#[must_use]
|
||||
pub fn allows_restricted(&self) -> bool { !matches!(self, Self::EscapedCommand) }
|
||||
}
|
||||
|
||||
/// Prototype of the tab-completer. The input is buffered text when tab
|
||||
/// asserted; the output will fully replace the input buffer.
|
||||
pub type Completer = fn(&str) -> String;
|
||||
@@ -298,15 +276,10 @@ pub async fn text_to_file(&self, body: &str) -> Result<OwnedMxcUri> {
|
||||
/// Posts a command to the command processor queue and returns. Processing
|
||||
/// will take place on the service worker's task asynchronously. Errors if
|
||||
/// the queue is full.
|
||||
pub fn command(
|
||||
&self,
|
||||
command: String,
|
||||
reply_id: Option<OwnedEventId>,
|
||||
source: InvocationSource,
|
||||
) -> Result<()> {
|
||||
pub fn command(&self, command: String, reply_id: Option<OwnedEventId>) -> Result<()> {
|
||||
self.channel
|
||||
.0
|
||||
.send(CommandInput { command, reply_id, source, sender: None })
|
||||
.send(CommandInput { command, reply_id, sender: None })
|
||||
.map_err(|e| err!("Failed to enqueue admin command: {e:?}"))
|
||||
}
|
||||
|
||||
@@ -317,17 +290,11 @@ pub fn command_with_sender(
|
||||
&self,
|
||||
command: String,
|
||||
reply_id: Option<OwnedEventId>,
|
||||
source: InvocationSource,
|
||||
sender: Box<UserId>,
|
||||
) -> Result<()> {
|
||||
self.channel
|
||||
.0
|
||||
.send(CommandInput {
|
||||
command,
|
||||
reply_id,
|
||||
source,
|
||||
sender: Some(sender),
|
||||
})
|
||||
.send(CommandInput { command, reply_id, sender: Some(sender) })
|
||||
.map_err(|e| err!("Failed to enqueue admin command: {e:?}"))
|
||||
}
|
||||
|
||||
@@ -337,9 +304,8 @@ pub async fn command_in_place(
|
||||
&self,
|
||||
command: String,
|
||||
reply_id: Option<OwnedEventId>,
|
||||
source: InvocationSource,
|
||||
) -> ProcessorResult {
|
||||
self.process_command(CommandInput { command, reply_id, source, sender: None })
|
||||
self.process_command(CommandInput { command, reply_id, sender: None })
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -383,50 +349,16 @@ async fn process_command(&self, command: CommandInput) -> ProcessorResult {
|
||||
handle(services, command).await
|
||||
}
|
||||
|
||||
/// Returns the list of admins for this server. First loads
|
||||
/// the admin_list from the configuration, then adds users from
|
||||
/// the admin room if applicable.
|
||||
pub async fn get_admins(&self) -> Vec<OwnedUserId> {
|
||||
let mut generated_admin_list: Vec<OwnedUserId> =
|
||||
self.services.server.config.admins_list.clone();
|
||||
|
||||
if self.services.server.config.admins_from_room {
|
||||
if let Ok(admin_room) = self.get_admin_room().await {
|
||||
let admin_users = self.services.state_cache.room_members(&admin_room);
|
||||
let mut stream = admin_users;
|
||||
|
||||
while let Some(user_id) = stream.next().await {
|
||||
generated_admin_list.push(user_id.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generated_admin_list
|
||||
}
|
||||
|
||||
/// Checks whether a given user is an admin of this server
|
||||
pub async fn user_is_admin(&self, user_id: &UserId) -> bool {
|
||||
if self
|
||||
.services
|
||||
.server
|
||||
.config
|
||||
.admins_list
|
||||
.contains(&user_id.to_owned())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
let Ok(admin_room) = self.get_admin_room().await else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if self.services.server.config.admins_from_room {
|
||||
if let Ok(admin_room) = self.get_admin_room().await {
|
||||
return self
|
||||
.services
|
||||
.state_cache
|
||||
.is_joined(user_id, &admin_room)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
self.services
|
||||
.state_cache
|
||||
.is_joined(user_id, &admin_room)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Gets the room ID of the admin room
|
||||
@@ -527,59 +459,59 @@ async fn handle_response_error(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn is_admin_command<E>(&self, event: &E, body: &str) -> Option<InvocationSource>
|
||||
pub async fn is_admin_command<E>(&self, event: &E, body: &str) -> bool
|
||||
where
|
||||
E: Event + Send + Sync,
|
||||
{
|
||||
// If the user isn't an admin they definitely can't run admin commands
|
||||
if !self.user_is_admin(event.sender()).await {
|
||||
return None;
|
||||
// Server-side command-escape with public echo
|
||||
let is_escape = body.starts_with('\\');
|
||||
let is_public_escape = is_escape && body.trim_start_matches('\\').starts_with("!admin");
|
||||
|
||||
// Admin command with public echo (in admin room)
|
||||
let server_user = &self.services.globals.server_user;
|
||||
let is_public_prefix =
|
||||
body.starts_with("!admin") || body.starts_with(server_user.as_str());
|
||||
|
||||
// Expected backward branch
|
||||
if !is_public_escape && !is_public_prefix {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(room_id) = event.room_id()
|
||||
&& self.is_admin_room(room_id).await
|
||||
let user_is_local = self.services.globals.user_is_local(event.sender());
|
||||
|
||||
// only allow public escaped commands by local admins
|
||||
if is_public_escape && !user_is_local {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if server-side command-escape is disabled by configuration
|
||||
if is_public_escape && !self.services.server.config.admin_escape_commands {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent unescaped !admin from being used outside of the admin room
|
||||
if event.room_id().is_some()
|
||||
&& is_public_prefix
|
||||
&& !self.is_admin_room(event.room_id().unwrap()).await
|
||||
{
|
||||
// This is a message in the admin room
|
||||
|
||||
// Ignore messages which aren't admin commands
|
||||
let server_user = &self.services.globals.server_user;
|
||||
if !(body.starts_with("!admin") || body.starts_with(server_user.as_str())) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Ignore messages from the server user _unless_ the emergency password is set
|
||||
let emergency_password_set = self.services.server.config.emergency_password.is_some();
|
||||
if event.sender() == server_user && !emergency_password_set {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Looks good
|
||||
Some(InvocationSource::AdminRoom)
|
||||
} else {
|
||||
// This is a message outside the admin room
|
||||
|
||||
// Is it an escaped admin command? i.e. `\!admin --help`
|
||||
let is_public_escape =
|
||||
body.starts_with('\\') && body.trim_start_matches('\\').starts_with("!admin");
|
||||
|
||||
// Ignore the message if it's not
|
||||
if !is_public_escape {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Only admin users belonging to this server can use escaped commands
|
||||
if !self.services.globals.user_is_local(event.sender()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Check if escaped commands are disabled in the config
|
||||
if !self.services.server.config.admin_escape_commands {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Looks good
|
||||
Some(InvocationSource::EscapedCommand)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only senders who are admin can proceed
|
||||
if !self.user_is_admin(event.sender()).await {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This will evaluate to false if the emergency password is set up so that
|
||||
// the administrator can execute commands as the server user
|
||||
let emergency_password_set = self.services.server.config.emergency_password.is_some();
|
||||
let from_server = event.sender() == server_user && !emergency_password_set;
|
||||
if from_server && self.is_admin_room(event.room_id().unwrap()).await {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Authentic admin command
|
||||
true
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
||||
@@ -96,7 +96,7 @@ async fn worker(self: Arc<Self>) -> Result<()> {
|
||||
}
|
||||
|
||||
if let Err(e) = self.check().await {
|
||||
warn!(?e, "Failed to check for announcements");
|
||||
warn!(%e, "Failed to check for announcements");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ async fn perform<T>(
|
||||
let url = request.url().clone();
|
||||
let method = request.method().clone();
|
||||
|
||||
debug!(%method, %url, "Sending request");
|
||||
debug!(?method, ?url, "Sending request");
|
||||
match client.execute(request).await {
|
||||
| Ok(response) => handle_response::<T>(dest, actual, &method, &url, response).await,
|
||||
| Err(error) =>
|
||||
@@ -144,9 +144,9 @@ async fn into_http_response(
|
||||
) -> Result<http::Response<Bytes>> {
|
||||
let status = response.status();
|
||||
trace!(
|
||||
%status, %method,
|
||||
request_url = %url,
|
||||
response_url = %response.url(),
|
||||
?status, ?method,
|
||||
request_url = ?url,
|
||||
response_url = ?response.url(),
|
||||
"Received response from {}",
|
||||
actual.string(),
|
||||
);
|
||||
@@ -196,9 +196,9 @@ fn handle_error(
|
||||
debug_warn!("{e:?}");
|
||||
} else if e.is_redirect() {
|
||||
debug_error!(
|
||||
%method,
|
||||
%url,
|
||||
final_url = e.url().map(tracing::field::display),
|
||||
method = ?method,
|
||||
url = ?url,
|
||||
final_url = ?e.url(),
|
||||
"Redirect loop {}: {}",
|
||||
actual.host,
|
||||
e,
|
||||
|
||||
@@ -124,16 +124,16 @@ pub(super) async fn search_file_metadata(
|
||||
.next()
|
||||
.map(string_from_bytes)
|
||||
.transpose()
|
||||
.map_err(|e| err!(Database(error!(%mxc, "Content-type is invalid: {e}"))))?;
|
||||
.map_err(|e| err!(Database(error!(?mxc, "Content-type is invalid: {e}"))))?;
|
||||
|
||||
let content_disposition = parts
|
||||
.next()
|
||||
.map(Some)
|
||||
.ok_or_else(|| err!(Database(error!(%mxc, "Media ID in db is invalid."))))?
|
||||
.ok_or_else(|| err!(Database(error!(?mxc, "Media ID in db is invalid."))))?
|
||||
.filter(|bytes| !bytes.is_empty())
|
||||
.map(string_from_bytes)
|
||||
.transpose()
|
||||
.map_err(|e| err!(Database(error!(%mxc, "Content-type is invalid: {e}"))))?
|
||||
.map_err(|e| err!(Database(error!(?mxc, "Content-type is invalid: {e}"))))?
|
||||
.as_deref()
|
||||
.map(str::parse)
|
||||
.transpose()?;
|
||||
|
||||
@@ -118,14 +118,14 @@ pub async fn delete(&self, mxc: &Mxc<'_>) -> Result<()> {
|
||||
match self.db.search_mxc_metadata_prefix(mxc).await {
|
||||
| Ok(keys) => {
|
||||
for key in keys {
|
||||
trace!(%mxc, "MXC Key: {key:?}");
|
||||
debug_info!(%mxc, "Deleting from filesystem");
|
||||
trace!(?mxc, "MXC Key: {key:?}");
|
||||
debug_info!(?mxc, "Deleting from filesystem");
|
||||
|
||||
if let Err(e) = self.remove_media_file(&key).await {
|
||||
debug_error!(%mxc, "Failed to remove media file: {e}");
|
||||
debug_error!(?mxc, "Failed to remove media file: {e}");
|
||||
}
|
||||
|
||||
debug_info!(%mxc, "Deleting from database");
|
||||
debug_info!(?mxc, "Deleting from database");
|
||||
self.db.delete_file_mxc(mxc).await;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ pub async fn delete_from_user(&self, user: &UserId) -> Result<usize> {
|
||||
|
||||
for mxc in mxcs {
|
||||
let Ok(mxc) = mxc.as_str().try_into().inspect_err(|e| {
|
||||
debug_error!(%mxc, "Failed to parse MXC URI from database: {e}");
|
||||
debug_error!(?mxc, "Failed to parse MXC URI from database: {e}");
|
||||
}) else {
|
||||
continue;
|
||||
};
|
||||
@@ -210,7 +210,7 @@ pub async fn get_all_mxcs(&self) -> Result<Vec<OwnedMxcUri>> {
|
||||
|
||||
let Some(mxc_s) = mxc else {
|
||||
debug_warn!(
|
||||
mxc,
|
||||
?mxc,
|
||||
"Parsed MXC URL unicode bytes from database but is still invalid"
|
||||
);
|
||||
continue;
|
||||
@@ -256,7 +256,7 @@ pub async fn delete_all_media_within_timeframe(
|
||||
|
||||
let Some(mxc_s) = mxc else {
|
||||
debug_warn!(
|
||||
mxc,
|
||||
?mxc,
|
||||
"Parsed MXC URL unicode bytes from database but is still invalid"
|
||||
);
|
||||
continue;
|
||||
|
||||
@@ -71,10 +71,10 @@ async fn request_url_preview(&self, url: &Url) -> Result<UrlPreviewData> {
|
||||
let client = &self.services.client.url_preview;
|
||||
let response = client.head(url.as_str()).send().await?;
|
||||
|
||||
debug!(%url, "URL preview response headers: {:?}", response.headers());
|
||||
debug!(?url, "URL preview response headers: {:?}", response.headers());
|
||||
|
||||
if let Some(remote_addr) = response.remote_addr() {
|
||||
debug!(%url, "URL preview response remote address: {:?}", remote_addr);
|
||||
debug!(?url, "URL preview response remote address: {:?}", remote_addr);
|
||||
|
||||
if let Ok(ip) = IPAddress::parse(remote_addr.ip().to_string()) {
|
||||
if !self.services.client.valid_cidr_range(&ip) {
|
||||
|
||||
@@ -247,7 +247,7 @@ async fn handle_location(
|
||||
) -> Result<FileMeta> {
|
||||
self.location_request(location).await.map_err(|error| {
|
||||
err!(Request(NotFound(
|
||||
debug_warn!(%mxc, user = user.map(tracing::field::display), ?location, ?error, "Fetching media from location failed")
|
||||
debug_warn!(%mxc, ?user, ?location, ?error, "Fetching media from location failed")
|
||||
)))
|
||||
})
|
||||
}
|
||||
@@ -320,7 +320,7 @@ fn handle_federation_error(
|
||||
) -> Error {
|
||||
let fallback = || {
|
||||
err!(Request(NotFound(
|
||||
debug_error!(%mxc, user = user.map(tracing::field::display), server = server.map(tracing::field::display), ?error, "Remote media not found")
|
||||
debug_error!(%mxc, ?user, ?server, ?error, "Remote media not found")
|
||||
)))
|
||||
};
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ async fn get_thumbnail_generate(
|
||||
let mut cursor = std::io::Cursor::new(&mut thumbnail_bytes);
|
||||
thumbnail
|
||||
.write_to(&mut cursor, image::ImageFormat::Png)
|
||||
.map_err(|error| err!(error!(%error, "Error writing PNG thumbnail.")))?;
|
||||
.map_err(|error| err!(error!(?error, "Error writing PNG thumbnail.")))?;
|
||||
|
||||
// Save thumbnail in database so we don't have to generate it again next time
|
||||
let thumbnail_key = self.db.create_file_metadata(
|
||||
|
||||
@@ -677,7 +677,7 @@ async fn populate_userroomid_leftstate_table(services: &Services) -> Result {
|
||||
shortstatehash_cache.insert(room_id.to_owned(), shortstatehash);
|
||||
shortstatehash
|
||||
} else {
|
||||
warn!(%room_id, %user_id, "room has no shortstatehash");
|
||||
warn!(?room_id, ?user_id, "room has no shortstatehash");
|
||||
return Ok((total, fixed, shortstatehash_cache));
|
||||
};
|
||||
|
||||
@@ -698,8 +698,8 @@ async fn populate_userroomid_leftstate_table(services: &Services) -> Result {
|
||||
},
|
||||
| Err(_) => {
|
||||
warn!(
|
||||
%room_id,
|
||||
%user_id,
|
||||
?room_id,
|
||||
?user_id,
|
||||
"room cached as left has no leave event for user, removing \
|
||||
cache entry"
|
||||
);
|
||||
|
||||
@@ -198,11 +198,11 @@ pub async fn unset_all_presence(&self) {
|
||||
presence.presence,
|
||||
PresenceState::Unavailable | PresenceState::Online | PresenceState::Busy
|
||||
) {
|
||||
trace!(%user_id, ?presence, "Skipping user");
|
||||
trace!(?user_id, ?presence, "Skipping user");
|
||||
continue;
|
||||
}
|
||||
|
||||
trace!(%user_id, ?presence, "Resetting presence to offline");
|
||||
trace!(?user_id, ?presence, "Resetting presence to offline");
|
||||
|
||||
_ = self
|
||||
.set_presence(
|
||||
|
||||
@@ -427,20 +427,20 @@ async fn send_notice<E>(
|
||||
}
|
||||
|
||||
let d = vec![device];
|
||||
let mut notify = Notification::new(d);
|
||||
let mut notifi = Notification::new(d);
|
||||
|
||||
notify.event_id = Some(event.event_id().to_owned());
|
||||
notify.room_id = Some(event.room_id().unwrap().to_owned());
|
||||
notifi.event_id = Some(event.event_id().to_owned());
|
||||
notifi.room_id = Some(event.room_id().unwrap().to_owned());
|
||||
if http
|
||||
.data
|
||||
.get("org.matrix.msc4076.disable_badge_count")
|
||||
.is_none() && http.data.get("disable_badge_count").is_none()
|
||||
{
|
||||
notify.counts = NotificationCounts::new(unread, uint!(0));
|
||||
notifi.counts = NotificationCounts::new(unread, uint!(0));
|
||||
} else {
|
||||
// counts will not be serialised if it's the default (0, 0)
|
||||
// skip_serializing_if = "NotificationCounts::is_default"
|
||||
notify.counts = NotificationCounts::default();
|
||||
notifi.counts = NotificationCounts::default();
|
||||
}
|
||||
|
||||
if !event_id_only {
|
||||
@@ -449,30 +449,30 @@ async fn send_notice<E>(
|
||||
.iter()
|
||||
.any(|t| matches!(t, Tweak::Highlight(true) | Tweak::Sound(_)))
|
||||
{
|
||||
notify.prio = NotificationPriority::High;
|
||||
notifi.prio = NotificationPriority::High;
|
||||
} else {
|
||||
notify.prio = NotificationPriority::Low;
|
||||
notifi.prio = NotificationPriority::Low;
|
||||
}
|
||||
notify.sender = Some(event.sender().to_owned());
|
||||
notify.event_type = Some(event.kind().to_owned());
|
||||
notify.content = serde_json::value::to_raw_value(event.content()).ok();
|
||||
notifi.sender = Some(event.sender().to_owned());
|
||||
notifi.event_type = Some(event.kind().to_owned());
|
||||
notifi.content = serde_json::value::to_raw_value(event.content()).ok();
|
||||
|
||||
if *event.kind() == TimelineEventType::RoomMember {
|
||||
notify.user_is_target =
|
||||
notifi.user_is_target =
|
||||
event.state_key() == Some(event.sender().as_str());
|
||||
}
|
||||
|
||||
notify.sender_display_name =
|
||||
notifi.sender_display_name =
|
||||
self.services.users.displayname(event.sender()).await.ok();
|
||||
|
||||
notify.room_name = self
|
||||
notifi.room_name = self
|
||||
.services
|
||||
.state_accessor
|
||||
.get_name(event.room_id().unwrap())
|
||||
.await
|
||||
.ok();
|
||||
|
||||
notify.room_alias = self
|
||||
notifi.room_alias = self
|
||||
.services
|
||||
.state_accessor
|
||||
.get_canonical_alias(event.room_id().unwrap())
|
||||
@@ -480,7 +480,7 @@ async fn send_notice<E>(
|
||||
.ok();
|
||||
}
|
||||
|
||||
self.send_request(&http.url, send_event_notification::v1::Request::new(notify))
|
||||
self.send_request(&http.url, send_event_notification::v1::Request::new(notifi))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -151,7 +151,7 @@ async fn get_auth_chain_outer(
|
||||
let auth_chain = self.get_auth_chain_inner(room_id, event_id).await?;
|
||||
self.cache_auth_chain_vec(vec![shortid], auth_chain.as_slice());
|
||||
debug!(
|
||||
%event_id,
|
||||
?event_id,
|
||||
elapsed = ?started.elapsed(),
|
||||
"Cache missed event"
|
||||
);
|
||||
@@ -188,18 +188,18 @@ async fn get_auth_chain_inner(
|
||||
let mut found = HashSet::new();
|
||||
|
||||
while let Some(event_id) = todo.pop_front() {
|
||||
trace!(%event_id, "processing auth event");
|
||||
trace!(?event_id, "processing auth event");
|
||||
|
||||
match self.services.timeline.get_pdu(&event_id).await {
|
||||
| Err(e) => {
|
||||
debug_error!(%event_id, ?e, "Could not find pdu mentioned in auth events");
|
||||
debug_error!(?event_id, ?e, "Could not find pdu mentioned in auth events");
|
||||
},
|
||||
| Ok(pdu) => {
|
||||
if let Some(claimed_room_id) = pdu.room_id.clone() {
|
||||
if claimed_room_id != *room_id {
|
||||
return Err!(Request(Forbidden(error!(
|
||||
%event_id,
|
||||
%room_id,
|
||||
?event_id,
|
||||
?room_id,
|
||||
wrong_room_id = ?pdu.room_id.unwrap(),
|
||||
"auth event for incorrect room"
|
||||
))));
|
||||
@@ -214,7 +214,7 @@ async fn get_auth_chain_inner(
|
||||
.await;
|
||||
|
||||
if found.insert(sauthevent) {
|
||||
trace!(%event_id, ?auth_event, "adding auth event to processing queue");
|
||||
trace!(?event_id, ?auth_event, "adding auth event to processing queue");
|
||||
|
||||
todo.push_back(auth_event.clone());
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@ fn check_room_id<Pdu: Event>(room_id: &RoomId, pdu: &Pdu) -> Result {
|
||||
.is_some_and(|claimed_room_id| claimed_room_id != room_id)
|
||||
{
|
||||
return Err!(Request(InvalidParam(error!(
|
||||
pdu_event_id = %pdu.event_id(),
|
||||
pdu_room_id = pdu.room_id().map(tracing::field::display),
|
||||
%room_id,
|
||||
pdu_event_id = ?pdu.event_id(),
|
||||
pdu_room_id = ?pdu.room_id(),
|
||||
?room_id,
|
||||
"Found event from room in room",
|
||||
))));
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
/// contacted for whatever reason, Err(e) is returned, which generally is a
|
||||
/// fail-open operation.
|
||||
#[implement(super::Service)]
|
||||
#[tracing::instrument(skip(self, pdu, pdu_json, room_id), level = "info")]
|
||||
#[tracing::instrument(skip(self, pdu, pdu_json, room_id))]
|
||||
pub async fn ask_policy_server(
|
||||
&self,
|
||||
pdu: &PduEvent,
|
||||
@@ -184,7 +184,7 @@ pub async fn ask_policy_server(
|
||||
/// Asks a remote policy server for a signature on this event.
|
||||
/// If the policy server signs this event, the original data is mutated.
|
||||
#[implement(super::Service)]
|
||||
#[tracing::instrument(skip_all, fields(event_id=%pdu.event_id(), via=%via), level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(event_id=%pdu.event_id(), via=%via))]
|
||||
pub async fn fetch_policy_server_signature(
|
||||
&self,
|
||||
pdu: &PduEvent,
|
||||
|
||||
@@ -335,11 +335,10 @@ pub async fn append_pdu<'a, Leaves>(
|
||||
if let Some(body) = content.body {
|
||||
self.services.search.index_pdu(shortroomid, &pdu_id, &body);
|
||||
|
||||
if let Some(source) = self.services.admin.is_admin_command(pdu, &body).await {
|
||||
if self.services.admin.is_admin_command(pdu, &body).await {
|
||||
self.services.admin.command_with_sender(
|
||||
body,
|
||||
Some((pdu.event_id()).into()),
|
||||
source,
|
||||
pdu.sender.clone().into(),
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ pub async fn redact_pdu<Pdu: Event + Send + Sync>(
|
||||
.await
|
||||
.map(Event::into_pdu)
|
||||
.map_err(|e| {
|
||||
err!(Database(error!(?pdu_id, %event_id, ?e, "PDU ID points to invalid PDU.")))
|
||||
err!(Database(error!(?pdu_id, ?event_id, ?e, "PDU ID points to invalid PDU.")))
|
||||
})?;
|
||||
|
||||
if let Ok(content) = pdu.get_content::<ExtractBody>() {
|
||||
@@ -48,7 +48,7 @@ pub async fn redact_pdu<Pdu: Event + Send + Sync>(
|
||||
pdu.redact(&room_version_id, reason.to_value())?;
|
||||
|
||||
let obj = utils::to_canonical_object(&pdu).map_err(|e| {
|
||||
err!(Database(error!(%event_id, ?e, "Failed to convert PDU to canonical JSON")))
|
||||
err!(Database(error!(?event_id, ?e, "Failed to convert PDU to canonical JSON")))
|
||||
})?;
|
||||
|
||||
self.replace_pdu(&pdu_id, &obj).await
|
||||
|
||||
@@ -535,12 +535,12 @@ async fn select_edus_receipts_room(
|
||||
}
|
||||
|
||||
let Ok(event) = serde_json::from_str(read_receipt.json().get()) else {
|
||||
error!(%user_id, %count, ?read_receipt, "Invalid edu event in read_receipts.");
|
||||
error!(?user_id, ?count, ?read_receipt, "Invalid edu event in read_receipts.");
|
||||
continue;
|
||||
};
|
||||
|
||||
let AnySyncEphemeralRoomEvent::Receipt(r) = event else {
|
||||
error!(%user_id, %count, ?event, "Invalid event type in read_receipts");
|
||||
error!(?user_id, ?count, ?event, "Invalid event type in read_receipts");
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -755,7 +755,7 @@ async fn send_events_dest_push(
|
||||
let Ok(pusher) = self.services.pusher.get_pusher(&user_id, &pushkey).await else {
|
||||
return Err((
|
||||
Destination::Push(user_id.clone(), pushkey.clone()),
|
||||
err!(Database(error!(%user_id, ?pushkey, "Missing pusher"))),
|
||||
err!(Database(error!(?user_id, ?pushkey, "Missing pusher"))),
|
||||
));
|
||||
};
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ pub async fn acquire_pubkeys<'a, S, K>(&self, batch: S)
|
||||
}
|
||||
|
||||
for (server, key_ids) in missing {
|
||||
debug_warn!(%server, ?key_ids, "missing");
|
||||
debug_warn!(?server, ?key_ids, "missing");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,8 +174,8 @@ async fn acquire_origin(
|
||||
timeout: Instant,
|
||||
) -> (OwnedServerName, Vec<OwnedServerSigningKeyId>) {
|
||||
match timeout_at(timeout, self.server_request(&origin)).await {
|
||||
| Err(e) => debug_warn!(%origin, "timed out: {e}"),
|
||||
| Ok(Err(e)) => debug_error!(%origin, "{e}"),
|
||||
| Err(e) => debug_warn!(?origin, "timed out: {e}"),
|
||||
| Ok(Err(e)) => debug_error!(?origin, "{e}"),
|
||||
| Ok(Ok(server_keys)) => {
|
||||
trace!(
|
||||
%origin,
|
||||
|
||||
@@ -63,7 +63,7 @@ pub async fn get_pubkeys_for<'a, I>(&self, origin: &ServerName, key_ids: I) -> P
|
||||
}
|
||||
|
||||
#[implement(super::Service)]
|
||||
#[tracing::instrument(skip(self), level = "debug")]
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub async fn get_verify_key(
|
||||
&self,
|
||||
origin: &ServerName,
|
||||
@@ -96,8 +96,8 @@ pub async fn get_verify_key(
|
||||
}
|
||||
|
||||
Err!(BadServerResponse(debug_error!(
|
||||
%key_id,
|
||||
%origin,
|
||||
?key_id,
|
||||
?origin,
|
||||
"Failed to fetch federation signing-key"
|
||||
)))
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ async fn add_signing_keys(&self, new_keys: ServerSigningKeys) {
|
||||
}
|
||||
|
||||
#[implement(Service)]
|
||||
#[tracing::instrument(skip(self, object), level = "debug")]
|
||||
#[tracing::instrument(skip(self, object))]
|
||||
pub async fn required_keys_exist(
|
||||
&self,
|
||||
object: &CanonicalJsonObject,
|
||||
@@ -135,7 +135,7 @@ pub async fn required_keys_exist(
|
||||
}
|
||||
|
||||
#[implement(Service)]
|
||||
#[tracing::instrument(skip(self), level = "debug")]
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub async fn verify_key_exists(&self, origin: &ServerName, key_id: &ServerSigningKeyId) -> bool {
|
||||
type KeysMap<'a> = BTreeMap<&'a ServerSigningKeyId, &'a RawJsonValue>;
|
||||
|
||||
|
||||
@@ -494,8 +494,8 @@ pub async fn set_token(
|
||||
let key = (user_id, device_id);
|
||||
if self.db.userdeviceid_metadata.qry(&key).await.is_err() {
|
||||
return Err!(Database(error!(
|
||||
%user_id,
|
||||
%device_id,
|
||||
?user_id,
|
||||
?device_id,
|
||||
"User does not exist or device has no metadata."
|
||||
)));
|
||||
}
|
||||
@@ -539,8 +539,8 @@ pub async fn add_one_time_key(
|
||||
let key = (user_id, device_id);
|
||||
if self.db.userdeviceid_metadata.qry(&key).await.is_err() {
|
||||
return Err!(Database(error!(
|
||||
%user_id,
|
||||
%device_id,
|
||||
?user_id,
|
||||
?device_id,
|
||||
"User does not exist or device has no metadata."
|
||||
)));
|
||||
}
|
||||
@@ -1153,7 +1153,7 @@ pub async fn find_from_login_token(&self, token: &str) -> Result<OwnedUserId> {
|
||||
let (expires_at, user_id): (u64, OwnedUserId) = value.deserialized()?;
|
||||
|
||||
if expires_at < utils::millis_since_unix_epoch() {
|
||||
trace!(%user_id, ?token, "Removing expired login token");
|
||||
trace!(?user_id, ?token, "Removing expired login token");
|
||||
|
||||
self.db.logintoken_expiresatuserid.remove(token);
|
||||
|
||||
@@ -1231,7 +1231,7 @@ pub async fn search_ldap(&self, user_id: &UserId) -> Result<Vec<(String, bool)>>
|
||||
debug!(?uri, "LDAP creating connection...");
|
||||
let (conn, mut ldap) = LdapConnAsync::new(uri.as_str())
|
||||
.await
|
||||
.map_err(|e| err!(Ldap(error!(%user_id, "LDAP connection setup error: {e}"))))?;
|
||||
.map_err(|e| err!(Ldap(error!(?user_id, "LDAP connection setup error: {e}"))))?;
|
||||
|
||||
let driver = self.services.server.runtime().spawn(async move {
|
||||
match conn.drive().await {
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[tool.towncrier]
|
||||
name = "Continuwuity"
|
||||
directory = "changelog.d"
|
||||
filename = "CHANGELOG.md"
|
||||
Reference in New Issue
Block a user