Compare commits

..
Author SHA1 Message Date
Ginger 74c453d606 chore: Formatting 2026-07-26 20:23:47 -04:00
Ginger 523e7548d6 fix: Fix backwards logic in auth check 2026-07-26 20:20:14 -04:00
Ginger 6535246094 fix: Update error message wording 2026-07-26 20:20:13 -04:00
Ginger 6115bb3101 refactor: Remove redundant destination check in server auth logic
Ruma already does this check for us
2026-07-26 20:20:11 -04:00
Ginger 61f6930b5d refactor: Update Ruma and adjust auth logic 2026-07-26 20:20:11 -04:00
Ginger 2fb63f4cbc refactor: Use determine_registration_user_id in admin user create route 2026-07-26 19:11:04 -04:00
Ginger fcc8b3d697 feat: Set MSC4484 unstable feature flag 2026-07-26 19:11:04 -04:00
Ginger 5ead900e4a fix: Adjust admin API routes to work with new auth logic 2026-07-26 19:10:57 -04:00
timedoutandGinger 5b0aacb57f feat: Add user creation endpoint 2026-07-26 18:56:55 -04:00
timedoutandGinger 3f2d0ae2ff feat: Include predecessor and successor information in room list 2026-07-26 18:56:54 -04:00
timedoutandGinger 5d461d2023 feat: Add pagination to rooms list & include more information 2026-07-26 18:56:54 -04:00
timedoutandGinger 836748b569 feat: Enable pagination for the users list route 2026-07-26 18:56:54 -04:00
timedoutandGinger 643ca38710 feat: Define routes for listing and creating users 2026-07-26 18:56:54 -04:00
timedoutandGinger ef1506204d feat: Add version part to admin API URLs
This is a surprise tool that will help us later
2026-07-26 18:56:53 -04:00
timedoutandGinger 9589501db5 chore: Add some documentation to API stuff 2026-07-26 18:56:53 -04:00
timedoutandGinger 3a8040ccf1 feat: Drop ruminuwuity msc4323 definitions 2026-07-26 18:56:53 -04:00
176 changed files with 2630 additions and 4302 deletions
@@ -44,7 +44,7 @@ runs:
- name: Login to builtin registry
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4
with:
registry: ${{ env.BUILTIN_REGISTRY }}
username: ${{ inputs.registry_user }}
@@ -79,7 +79,7 @@ runs:
- name: Login to builtin registry
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4
with:
registry: ${{ env.BUILTIN_REGISTRY }}
username: ${{ inputs.registry_user }}
+1 -1
View File
@@ -71,7 +71,7 @@ runs:
- name: Install timelord-cli and git-warp-time
if: steps.check-binaries.outputs.need-install == 'true'
uses: https://github.com/taiki-e/install-action@7f4eb899022d8fe70b20c4f3de697aa85c309026 # v2
uses: https://github.com/taiki-e/install-action@a6b2e2dcd845ddd7f509ce4f3ed3d922b80cc5d9 # v2
with:
tool: git-warp-time,timelord-cli@3.0.1
+7 -57
View File
@@ -18,7 +18,6 @@ jobs:
strategy:
matrix:
container: [ "ubuntu-latest", "ubuntu-previous", "debian-latest", "debian-oldstable" ]
arch: [ "amd64", "arm64" ]
container:
image: "ghcr.io/tcpipuk/act-runner:${{ matrix.container }}"
@@ -55,9 +54,9 @@ jobs:
path: |
~/.cargo/registry
~/.cargo/git
key: cargo-debian-${{ steps.debian-version.outputs.distribution }}-${{ matrix.arch }}-${{ hashFiles('**/Cargo.lock') }}
key: cargo-debian-${{ steps.debian-version.outputs.distribution }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
cargo-debian-${{ steps.debian-version.outputs.distribution }}-${{ matrix.arch }}-
cargo-debian-${{ steps.debian-version.outputs.distribution }}-
- name: Setup sccache
uses: https://git.tomfos.tr/tom/sccache-action@v1
@@ -71,55 +70,11 @@ jobs:
# Aggressive GC since cache restores don't increment counter
echo "CARGO_INCREMENTAL_GC_TRIGGER=5" >> $GITHUB_ENV
- name: Install cross-compilation tools for arm64
if: matrix.arch == 'arm64'
run: |
dpkg --add-architecture arm64
if ! apt-get update; then
# Older Ubuntu releases (e.g. noble) advertise arm64 in their
# Release files but only serve amd64/i386 from archive.ubuntu.com,
# so apt update 404s. Restrict the main sources to amd64 and
# fetch arm64 from ports.ubuntu.com instead.
CODENAME=$(lsb_release -sc)
# deb822 sources (noble and newer)
if [ -f /etc/apt/sources.list.d/ubuntu.sources ]; then
sed -i '/^Components:/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources
fi
# one-line sources (jammy and older)
if [ -f /etc/apt/sources.list ]; then
sed -i 's/^deb /deb [arch=amd64] /' /etc/apt/sources.list
fi
printf 'deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports %s main restricted universe multiverse\n' \
"$CODENAME" "$CODENAME-updates" "$CODENAME-security" \
> /etc/apt/sources.list.d/arm64-ports.list
apt-get update
fi
apt-get install -y \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu \
libc6-dev-arm64-cross
- name: Setup Rust
uses: ./.forgejo/actions/setup-rust
with:
github-token: ${{ secrets.GH_PUBLIC_RO }}
- name: Add Rust target
run: |
TARGET=${{ matrix.arch == 'arm64' && 'aarch64-unknown-linux-gnu' || 'x86_64-unknown-linux-gnu' }}
rustup target add $TARGET
- name: Configure cross-compilation for arm64
if: matrix.arch == 'arm64'
run: |
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
echo "CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++" >> $GITHUB_ENV
# rust-rocksdb's build script probes liburing via pkg-config, which
# refuses to run when host != target unless explicitly allowed
echo "PKG_CONFIG_ALLOW_CROSS=1" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH_aarch64_unknown_linux_gnu=/usr/lib/aarch64-linux-gnu/pkgconfig" >> $GITHUB_ENV
- name: Get package version and component
id: package-meta
run: |
@@ -165,26 +120,21 @@ jobs:
apt-get update -y
# Build dependencies for rocksdb
apt-get install -y liburing-dev clang
# For arm64 builds, install cross-compiled dependencies.
# libstdc++6:arm64 is needed by dpkg-shlibdeps to resolve the
# dynamically-linked libstdc++ when cargo-deb computes $auto depends.
if [ "${{ matrix.arch }}" = "arm64" ]; then
apt-get install -y liburing-dev:arm64 libstdc++6:arm64
fi
- name: Run cargo-deb
id: cargo-deb
run: |
TARGET=${{ matrix.arch == 'arm64' && 'aarch64-unknown-linux-gnu' || 'x86_64-unknown-linux-gnu' }}
DEB_PATH=$(cargo deb --target $TARGET --deb-version ${{ steps.package-meta.outputs.version }})
DEB_PATH=$(cargo deb --deb-version ${{ steps.package-meta.outputs.version }})
echo "path=$DEB_PATH" >> $GITHUB_OUTPUT
- name: Test deb installation
if: matrix.arch == 'amd64'
run: |
echo "Installing: ${{ steps.cargo-deb.outputs.path }}"
apt-get install -y ${{ steps.cargo-deb.outputs.path }}
dpkg -s continuwuity
[ -f /usr/bin/conduwuit ] && echo "✅ Binary installed successfully"
[ -f /usr/lib/systemd/system/conduwuit.service ] && echo "✅ Systemd service installed"
[ -f /etc/conduwuit/conduwuit.toml ] && echo "✅ Config file installed"
@@ -192,7 +142,7 @@ jobs:
- name: Upload deb artifact
uses: forgejo/upload-artifact@v4
with:
name: continuwuity-${{ steps.debian-version.outputs.distribution }}-${{ matrix.arch }}
name: continuwuity-${{ steps.debian-version.outputs.distribution }}
path: ${{ steps.cargo-deb.outputs.path }}
- name: Publish to Forgejo package registry
+1 -1
View File
@@ -55,7 +55,7 @@ jobs:
# repositories: continuwuity
- name: Install regsync
uses: https://github.com/regclient/actions/regsync-installer@78eb729dbdb4ef6480e85ff697b4410e22112583 # main
uses: https://github.com/regclient/actions/regsync-installer@c48159175b58fb90cccd0f98410927a81e04a166 # main
- name: Check what images need mirroring
run: |
+1 -1
View File
@@ -53,7 +53,7 @@ jobs:
persist-credentials: false
- name: Check for file changes
uses: https://github.com/dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4
uses: https://github.com/dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4
id: filter
with:
filters: |
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
name: Renovate
runs-on: ubuntu-latest
container:
image: ghcr.io/renovatebot/renovate:43.288.0@sha256:bcde7a061ab42d1ae6d4500769d80727e5694bb889dbcbf1005e9f4e741ab76d
image: ghcr.io/renovatebot/renovate:43.272.6@sha256:e9dee374e7a32827af434362c6e503aa179168a96a8212cc4a5c64bb5c550142
options: --tmpfs /tmp:exec
steps:
- name: Checkout
+1 -1
View File
@@ -24,7 +24,7 @@ repos:
- id: check-added-large-files
- repo: https://github.com/crate-ci/typos
rev: v1.49.0
rev: v1.48.0
hooks:
- id: typos
- id: typos
+111 -138
View File
@@ -1,61 +1,11 @@
# Continuwuity v26.7.2 (2026-07-30)
## Bugfixes
- Sliding sync no longer continues streaming data to a user after they are removed from a room. Contributed by @eleboucher. (SEC10)
- Valid redaction events no longer arbitrarily soft-fail and are applied correctly as expected.
- Fixed a regression that caused the server to process events for rooms it no longer has any local users in, which caused users to be reset back *into* rooms.
# Continuwuity 26.7.0 (2026-07-27)
## Features
- Build and publish arm64 .deb packages alongside amd64 for all supported Debian and Ubuntu releases. (#1235)
- Dehydrated devices are now visible in the account panel. Contributed by @ginger. (#1970)
- Introduce `accepted_ip_sources` as a multiple options variant of `request_ip_source`, allowing for more advanced deployments and making fallbacks an explicit choice. Contributed by @Omar007 (#1985)
- Added an admin command to issue an access token for a bot account, to allow legacy bots to function while legacy authentication is disabled. Contributed by @ginger (#2044)
- Added support for the OAuth2 device authorization flow. Contributed by @ginger
- Added support for the stable mutual rooms query endpoint. Contributed by @ginger
- Fetch the joined member count once per event instead of once per notified user.
## Bugfixes
- Fix joining restricted rooms over federation failing with signature verification error. (fix-federation-signature)
- Fixed the client space hierarchy endpoint returning a 500 "Space hierarchy is unreasonably large" error for cyclic space graphs (e.g. a space containing itself). Rooms are now deduplicated during
traversal as required by the spec, and the traversal depth is bounded even when the client does not specify `max_depth`. (space-hierarchy-cycle)
- Fixed simplified sliding sync holding account data for up to 30 seconds, which made encryption setup and cross-signing resets appear to hang. (sss-account-data-longpoll)
- Fixed local invites and invite acceptances not being reflected in sync promptly. Contributed by @eleboucher (wake-local-member-sync)
- Fixed the deeplink redirect for deleting devices. Contributed by @koen (#1965)
- Fix status code for oauth registration. Contributed by @n00byking (#1984)
- Exempt m.room.create from auth_events check. Contributed by @eleboucher (#1987)
- Fixed `create` being returned as a supported prompt value regardless of if registration is enabled or not. Contributed by @ginger (#1994)
- Fixed high CPU usage when multiple clients from the same account were connected at once. Each sync woke the account's other sync loops, causing them to wake each other in a loop. (#2006)
- Fixed MSC4190 appservice device creation registering a random device ID instead of the requested one (and dropping the requested display name), which prevented encrypted mautrix bridges from
starting on OIDC-enabled servers and leaked an orphan device on the bridge bot per startup attempt. (#2015)
- Deactivated users and appservice puppets are no longer counted by `/_continuwuity/local_user_count`. Contributed by @ginger. (#2040)
- Re-introduced admin room registration alerts that were accidentally removed in the OAuth2 update. (#2057)
- Appservices are now properly able to create devices for E2EE.
- Appservices may now specify both the unstable and stable `device_id` query parameters in a request. The stable parameter will take priority. Contributed by @ginger.
- Fixed `roomuserid_lastnotificationread` being aliased to the highlight count table, which clobbered highlight counts when setting a read marker. Contributed by @eleboucher
- Fixed freshly left room failing to sync.
- Fixed newly created rooms failing to sync properly in clients using legacy sync.
- Fixed newly joined rooms failing to sync their full state (including the room name) to clients using legacy sync.
- Fixed requests returning `500 Internal Server Error` when the header selected by `request_ip_source` is absent, duplicated, or malformed (for example Envoy omitting `X-Envoy-External-Address` on
internal requests). The client IP now falls back to the connection peer address instead of failing the request. Contributed by @eleboucher
- Resolve alias service by correct name for auto-join. Contributed by @eleboucher
## Improved Documentation
- Updated an out-of-date statement about Oracle Linux release cadences. (#1999)
# Continuwuity 26.6.2 (2026-07-12)
## Bugfixes
- Fixed the server returning 500 errors if `admin_console_automatic` is enabled and no TTY is available. Contributed by @s1lv3r. (#1975)
- Fixed `global.oauth.compatibility_mode` being required, despite being ignored, when the `[global.oauth.oidc]` config section is provided.
- Fixed an issue with a migration that could cause user accounts imported from an identity provider to be marked as deactivated when the server started. If you have accounts affected by this issue,
use `!admin users reset-password --convert-to-local-account` to reactivate them.
- Fixed an issue with a migration that could cause user accounts imported from an identity provider to be marked as deactivated when the server started. If you have accounts affected by this issue, use `!admin users reset-password --convert-to-local-account` to reactivate them.
# Continuwuity 26.6.1 (2026-07-12)
@@ -71,6 +21,7 @@ ## Bugfixes
- Stopped appservice users from being erroneously marked as deactivated during a 26.6 database migration.
- Whitespace will now automatically be trimmed from the start and end of the `global.oauth.oidc.client_secret_file`.
# Continuwuity 26.6.0 (2026-07-10)
## Features
@@ -80,15 +31,19 @@ ## Features
- Added config option for default room ACLs. Contributed by @eve. (#1691)
- Added support for fallback encryption keys. (#1710)
- Add `!admin users reject-all-invites` to clean invite spam (#1741)
- Implemented event rejection, which should resolve and prevent future netsplits of the kinds observed within some Continuwuity rooms. Also resolved several bugs related to both soft-failing events,
and event backfilling, which should improve state resolution stability. The `!admin debug get-pdu` command was updated to disambiguate event acceptance status, and
`!admin debug show-auth-chain` was added to visually display event auth chains, which may assist developers in debugging strangely complex events.
- Implemented event rejection, which should resolve and prevent future netsplits of the kinds observed
within some Continuwuity rooms.
Also resolved several bugs related to both soft-failing events, and event backfilling, which should
improve state resolution stability.
The `!admin debug get-pdu` command was updated to disambiguate event acceptance status, and
`!admin debug show-auth-chain` was added to visually display event auth chains, which may assist
developers in debugging strangely complex events.
Contributed by @nex. (#1747)
- Added full support for [MSC4168: Update `m.space.*` state on room upgrade](https://github.com/matrix-org/matrix-spec-proposals/pull/4168). Contributed by @nex. (#1807)
- Improved the performance and reliability of fetching missing events, improving network partition recovery. Contributed by @nex. (#1818)
- Added static builds using Nix, allowing for Continuwuity on musl. During this, we also introduced a `max-perf-haswell` package, separating it from `max-perf`, so you may want to swap to this if you
are on NixOS. Contributed by @Henry-Hiles (QuadRadical). (#1853)
- Improved the performance and reliability of fetching missing events, improving network partition recovery. Contributed
by @nex. (#1818)
- Added static builds using Nix, allowing for Continuwuity on musl. During this, we also introduced a `max-perf-haswell` package, separating it from `max-perf`, so you may want to swap to this if you are on NixOS. Contributed by @Henry-Hiles (QuadRadical). (#1853)
- Added support for MSC4380 invite blocking, which has become part of the Matrix specification in v1.18. Contributed by @nex. (#1875)
- Added `!admin debug get-state-at` command (#1877)
- Added a configuration option to allow choosing a client IP source that is not the TCP connecting IP. Contributed by @nex. (#1931)
@@ -100,12 +55,10 @@ ## Features
## Bugfixes
- Adjusted legacy sync logic to allow the `roomsynctoken_shortstatehash` database column to be dropped, massively reducing database sizes, especially for old deployments. Contributed by @ginger.
(#917)
- Adjusted legacy sync logic to allow the `roomsynctoken_shortstatehash` database column to be dropped, massively reducing database sizes, especially for old deployments. Contributed by @ginger. (#917)
- Fixed a bug that caused the server to drop events during processing if several events for the same room were sent in a singular transaction. Contributed by @nex. (#1711)
- fix `!admin query account-data account-data-get` not returning the content (#1742)
- Fixed an issue where Continuwuity would only advertise support for the unstable endpoint for Mutual Rooms (MSC2666), despite only supporting the stable endpoint. Contributed by @Henry-Hiles
(QuadRadical) (#1752)
- Fixed an issue where Continuwuity would only advertise support for the unstable endpoint for Mutual Rooms (MSC2666), despite only supporting the stable endpoint. Contributed by @Henry-Hiles (QuadRadical) (#1752)
- Fixed admin commands being ignored when they had leading whitespace before admin commands. Contributed by @kitvonsnookerz. (#1804)
- Fixed several bugs in the `POST /_matrix/client/v3/rooms/{roomId}/upgrade` endpoint. Contributed by @nex. (#1807)
- Devices which set their presence as "offline" will no longer be considered for presence updates. Contributed by @timedout.
@@ -132,8 +85,8 @@ ## Misc
- #1505, #1829, #1927, #1933, #1934
- Switched from Continuwuity's fork of Ruma back to upstream Ruma. Contributed by @ginger.
- The version of Debian that the Docker-based build process uses has been upgraded from Bookworm to Trixie, meaning that standalone binaries now have a minimum glibc of 2.41, and can no longer be used
on distro versions from before 2025-01-30
- The version of Debian that the Docker-based build process uses has been upgraded from Bookworm to Trixie, meaning that standalone binaries now have a minimum glibc of 2.41, and can no longer be used on distro versions from before 2025-01-30
# Continuwuity 0.5.8 (2026-04-24)
@@ -151,6 +104,7 @@ ## Improved Documentation
- Updated config docs to state we support room version 12, and set it as default. Contributed by @ezera. (#1622)
- Improve instructions for generic deployments, removing unnecessary parts and documenting the new initial registration token flow. Contributed by @stratself (#1677)
# Continuwuity v0.5.7 (2026-04-17)
## Features
@@ -192,6 +146,7 @@ ## Misc
- Fixed compiler warning in cf_opts.rs when building in release. Contributed by @ezera. (#1620)
# Continuwuity 0.5.6 (2026-03-03)
## Security
@@ -201,33 +156,22 @@ ## Security
## Features
- Outgoing presence is now disabled by default, and the config option documentation has been adjusted to more accurately represent the weight of presence, typing indicators, and read receipts.
Contributed by @nex. ([#1399](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1399))
- Improved the concurrency handling of federation transactions, vastly improving performance and reliability by more accurately handling inbound transactions and reducing the amount of repeated wasted
work. Contributed by @nex and @Jade. ([#1428](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1428))
- Added [MSC3202](https://github.com/matrix-org/matrix-spec-proposals/pull/3202) Device masquerading (not all of MSC3202). This should fix issues with
enabling [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190) for some Mautrix bridges. Contributed by @Jade
([#1435](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1435))
- Added [MSC3814](https://github.com/matrix-org/matrix-spec-proposals/pull/3814) Dehydrated Devices - you can now decrypt messages sent while all devices were logged out.
([#1436](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1436))
- Implement [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143) MatrixRTC transport discovery endpoint. Move RTC foci configuration from `[global.well_known]` to a new
`[global.matrix_rtc]` section with a `foci` field. Contributed by @0xnim ([#1442](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1442))
- Outgoing presence is now disabled by default, and the config option documentation has been adjusted to more accurately represent the weight of presence, typing indicators, and read receipts. Contributed by @nex. ([#1399](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1399))
- Improved the concurrency handling of federation transactions, vastly improving performance and reliability by more accurately handling inbound transactions and reducing the amount of repeated wasted work. Contributed by @nex and @Jade. ([#1428](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1428))
- Added [MSC3202](https://github.com/matrix-org/matrix-spec-proposals/pull/3202) Device masquerading (not all of MSC3202). This should fix issues with enabling [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190) for some Mautrix bridges. Contributed by @Jade ([#1435](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1435))
- Added [MSC3814](https://github.com/matrix-org/matrix-spec-proposals/pull/3814) Dehydrated Devices - you can now decrypt messages sent while all devices were logged out. ([#1436](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1436))
- Implement [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143) MatrixRTC transport discovery endpoint. Move RTC foci configuration from `[global.well_known]` to a new `[global.matrix_rtc]` section with a `foci` field. Contributed by @0xnim ([#1442](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1442))
- Updated `list-backups` admin command to output one backup per line. ([#1394](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1394))
- Improved URL preview fetching with a more compatible user agent for sites like YouTube Music. Added `!admin media delete-url-preview <url>` command to clear cached URL previews that were stuck and
broken. ([#1434](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1434))
- Improved URL preview fetching with a more compatible user agent for sites like YouTube Music. Added `!admin media delete-url-preview <url>` command to clear cached URL previews that were stuck and broken. ([#1434](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1434))
## Bugfixes
- Removed non-compliant nor functional room alias lookups over federation. Contributed by @nex ([#1393](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1393))
- Removed ability to set rocksdb as read only. Doing so would cause unintentional and buggy behaviour. Contributed by @Terryiscool160.
([#1418](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1418))
- Fixed a startup crash in the sender service if we can't detect the number of CPU cores, even if the `sender_workers` config option is set correctly. Contributed by @katie.
([#1421](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1421))
- Removed ability to set rocksdb as read only. Doing so would cause unintentional and buggy behaviour. Contributed by @Terryiscool160. ([#1418](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1418))
- Fixed a startup crash in the sender service if we can't detect the number of CPU cores, even if the `sender_workers` config option is set correctly. Contributed by @katie. ([#1421](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1421))
- Removed the `allow_public_room_directory_without_auth` config option. Contributed by @0xnim. ([#1441](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1441))
- Fixed sliding sync v5 list ranges always starting from 0, causing extra rooms to be unnecessarily processed and returned. Contributed by @0xnim
([#1445](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1445))
- Fixed a bug that (repairably) caused a room split between continuwuity and non-continuwuity servers when the room had both `m.room.policy` and `org.matrix.msc4284.policy` in its room state.
Contributed by @nex ([#1481](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1481))
- Fixed sliding sync v5 list ranges always starting from 0, causing extra rooms to be unnecessarily processed and returned. Contributed by @0xnim ([#1445](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1445))
- Fixed a bug that (repairably) caused a room split between continuwuity and non-continuwuity servers when the room had both `m.room.policy` and `org.matrix.msc4284.policy` in its room state. Contributed by @nex ([#1481](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1481))
- Fixed `!admin media delete --mxc <url>` responding with an error message when the media was deleted successfully. Contributed by @lynxize
- Fixed spurious 404 media errors in the logs. Contributed by @benbot.
- Fixed spurious warn about needed backfill via federation for non-federated rooms. Contributed by @kraem.
@@ -237,15 +181,19 @@ # Continuwuity v0.5.5 (2026-02-15)
## Features
- Added unstable support for [MSC4406:
`M_SENDER_IGNORED`](https://github.com/matrix-org/matrix-spec-proposals/pull/4406). Contributed by @nex ([#1308](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1308))
- Introduce a resolver command to allow flushing a server from the cache or to flush the complete cache. Contributed by @Omar007
([#1349](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1349))
- Improved the handling of restricted join rules and improved the performance of local-first joins. Contributed by @nex. ([#1368](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1368))
- You can now set a custom User Agent for URL previews; the default one has been modified to be less likely to be rejected. Contributed by @trashpanda
([#1372](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1372))
`M_SENDER_IGNORED`](https://github.com/matrix-org/matrix-spec-proposals/pull/4406).
Contributed by @nex ([#1308](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1308))
- Introduce a resolver command to allow flushing a server from the cache or to flush the complete cache. Contributed by
@Omar007 ([#1349](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1349))
- Improved the handling of restricted join rules and improved the performance of local-first joins. Contributed by
@nex. ([#1368](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1368))
- You can now set a custom User Agent for URL previews; the default one has been modified to be less likely to be
rejected. Contributed by @trashpanda ([#1372](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1372))
- Improved the first-time setup experience for new homeserver administrators:
- Account registration is disabled on the first run, except for with a new special registration token that is logged to the console.
- Other helpful information is logged to the console as well, including a giant warning if open registration is enabled.
- Account registration is disabled on the first run, except for with a new special registration token that is logged
to the console.
- Other helpful information is logged to the console as well, including a giant warning if open registration is
enabled.
- The default index page now says to check the console for setup instructions if no accounts have been created.
- Once the first admin account is created, an improved welcome message is sent to the admin room.
@@ -253,10 +201,10 @@ ## Features
## Bugfixes
- Fixed invites sent to other users in the same homeserver not being properly sent down sync. Users with missing or broken invites should clear their client caches after updating to make them appear.
([#1249](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1249))
- LDAP-enabled servers will no longer have all admins demoted when LDAP-controlled admins are not configured. Contributed by @Jade
([#1307](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1307))
- Fixed invites sent to other users in the same homeserver not being properly sent down sync. Users with missing or
broken invites should clear their client caches after updating to make them appear. ([#1249](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1249))
- LDAP-enabled servers will no longer have all admins demoted when LDAP-controlled admins are not configured.
Contributed by @Jade ([#1307](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1307))
- Fixed sliding sync not resolving wildcard state key requests, enabling Video/Audio calls in Element X. ([#1370](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1370))
## Misc
@@ -267,78 +215,100 @@ # Continuwuity v0.5.4 (2026-02-08)
## Features
- The announcement checker will now announce errors it encounters in the first run to the admin room, plus a few other misc improvements. Contributed by @Jade
([#1288](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1288))
- Drastically improved the performance and reliability of account deactivations. Contributed by @nex ([#1314](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1314))
- Refuse to process requests for and events in rooms that we no longer have any local users in (reduces state resets and improves performance). Contributed by @nex
([#1316](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1316))
- Added server-specific admin API routes to ban and unban rooms, for use with moderation bots. Contributed by @nex ([#1301](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1301))
- The announcement checker will now announce errors it encounters in the first run to the admin room, plus a few other
misc improvements. Contributed by @Jade ([#1288](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1288))
- Drastically improved the performance and reliability of account deactivations. Contributed by
@nex ([#1314](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1314))
- Refuse to process requests for and events in rooms that we no longer have any local users in (reduces state resets
and improves performance). Contributed by
@nex ([#1316](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1316))
- Added server-specific admin API routes to ban and unban rooms, for use with moderation bots. Contributed by @nex
([#1301](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1301))
## Bugfixes
- Fix the generated configuration containing uncommented optional sections. Contributed by @Jade ([#1290](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1290))
- Fixed specification non-compliance when handling remote media errors. Contributed by @nex ([#1298](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1298))
- UIAA requests which check for out-of-band success (sent by matrix-js-sdk) will no longer create unhelpful errors in the logs. Contributed by @ginger
([#1305](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1305))
- Use exists instead of contains to save writing to a buffer in `src/service/users/mod.rs`: `is_login_disabled`. Contributed by @aprilgrimoire.
([#1340](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1340))
- Fixed backtraces being swallowed during panics. Contributed by @jade ([#1337](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1337))
- Fixed a potential vulnerability that could allow an evil remote server to return malicious events during the room join and knock process. Contributed by @nex, reported by
violet & [mat](https://matdoes.dev).
- Fixed a race condition that could result in outlier PDUs being incorrectly marked as visible to a remote server. Contributed by @nex, reported by violet & [mat](https://matdoes.dev).
- Fix the generated configuration containing uncommented optional sections. Contributed by
@Jade ([#1290](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1290))
- Fixed specification non-compliance when handling remote media errors. Contributed by
@nex ([#1298](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1298))
- UIAA requests which check for out-of-band success (sent by matrix-js-sdk) will no longer create unhelpful errors in
the logs. Contributed by @ginger ([#1305](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1305))
- Use exists instead of contains to save writing to a buffer in `src/service/users/mod.rs`: `is_login_disabled`.
Contributed
by @aprilgrimoire. ([#1340](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1340))
- Fixed backtraces being swallowed during panics. Contributed by
@jade ([#1337](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1337))
- Fixed a potential vulnerability that could allow an evil remote server to return malicious events during the room join
and knock process. Contributed by @nex, reported by violet & [mat](https://matdoes.dev).
- Fixed a race condition that could result in outlier PDUs being incorrectly marked as visible to a remote server.
Contributed by @nex, reported by violet & [mat](https://matdoes.dev).
- ACLs are no longer case-sensitive. Contributed by @nex, reported by [vel](matrix:u/vel:nhjkl.com?action=chat).
## Docs
- Fixed Fedora install instructions. Contributed by @julian45 ([#1342](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1342))
- Fixed Fedora install instructions. Contributed by
@julian45 ([#1342](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1342))
# Continuwuity 0.5.3 (2026-01-12)
## Features
- Improve the display of nested configuration with the `!admin server show-config` command. Contributed by @Jade ([#1279](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1279))
- Improve the display of nested configuration with the `!admin server show-config` command. Contributed by
@Jade ([#1279](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1279))
## Bugfixes
- Fixed `M_BAD_JSON` error when sending invites to other servers or when providing joins. Contributed by @nex ([#1286](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1286))
- Fixed `M_BAD_JSON` error when sending invites to other servers or when providing joins. Contributed by
@nex ([#1286](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1286))
## Docs
- Improve admin command documentation generation. Contributed by @ginger ([#1280](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1280))
- Improve admin command documentation generation. Contributed by
@ginger ([#1280](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1280))
## Misc
- Improve timeout-related code for federation and URL previews. Contributed by @Jade ([#1278](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1278))
- Improve timeout-related code for federation and URL previews. Contributed by
@Jade ([#1278](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1278))
# Continuwuity 0.5.2 (2026-01-09)
## Features
- Added support for issuing additional registration tokens, stored in the database, which supplement the existing registration token hardcoded in the config file. These tokens may optionally expire
after a certain number of uses or after a certain amount of time has passed. Additionally, the `registration_token_file` configuration option is superseded by this feature and **has been removed**.
Use the new `!admin token` command family to manage registration tokens. Contributed by @ginger (#783).
- Implemented a configuration defined admin list independent of the admin room. Contributed by @Terryiscool160. ([#1253](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1253))
- Added support for invite and join anti-spam via Draupnir and Meowlnir, similar to that of synapse-http-antispam. Contributed by @nex.
([#1263](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1263))
- Implemented account locking functionality, to complement user suspension. Contributed by @nex. ([#1266](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1266))
- Added admin command to forcefully log out all of a user's existing sessions. Contributed by @nex. ([#1271](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1271))
- Added support for issuing additional registration tokens, stored in the database, which supplement the existing
registration token hardcoded in the config file. These tokens may optionally expire after a certain number of uses or
after a certain amount of time has passed. Additionally, the `registration_token_file` configuration option is
superseded by this feature and **has been removed**. Use the new `!admin token` command family to manage registration
tokens. Contributed by @ginger (#783).
- Implemented a configuration defined admin list independent of the admin room. Contributed by
@Terryiscool160. ([#1253](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1253))
- Added support for invite and join anti-spam via Draupnir and Meowlnir, similar to that of synapse-http-antispam.
Contributed by @nex. ([#1263](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1263))
- Implemented account locking functionality, to complement user suspension. Contributed by
@nex. ([#1266](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1266))
- Added admin command to forcefully log out all of a user's existing sessions. Contributed by
@nex. ([#1271](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1271))
- Implemented toggling the ability for an account to log in without mutating any of its data. Contributed by @nex. (
[#1272](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1272))
- Add support for custom room create event timestamps, to allow generating custom prefixes in hashed room IDs. Contributed by @nex.
([#1277](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1277))
- Certain potentially dangerous admin commands are now restricted to only be usable in the admin room and server console. Contributed by @ginger.
- Add support for custom room create event timestamps, to allow generating custom prefixes in hashed room IDs.
Contributed by @nex. ([#1277](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1277))
- Certain potentially dangerous admin commands are now restricted to only be usable in the admin room and server
console. Contributed by @ginger.
## Bugfixes
- Fixed unreliable room summary fetching and improved error messages. Contributed by @nex. ([#1257](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1257))
- Client requested timeout parameter is now applied to e2ee key lookups and claims. Related federation requests are now also concurrent. Contributed by @nex.
([#1261](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1261))
- Fixed the whoami endpoint returning HTTP 404 instead of HTTP 403, which confused some appservices. Contributed by @nex. ([#1276](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1276))
- Fixed unreliable room summary fetching and improved error messages. Contributed by
@nex. ([#1257](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1257))
- Client requested timeout parameter is now applied to e2ee key lookups and claims. Related federation requests are now
also concurrent. Contributed by @nex. ([#1261](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1261))
- Fixed the whoami endpoint returning HTTP 404 instead of HTTP 403, which confused some appservices. Contributed by
@nex. ([#1276](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1276))
## Misc
- The `console` feature is now enabled by default, allowing the server console to be used for running admin commands directly. To automatically open the console on startup, set the
`admin_console_automatic` config option to `true`. Contributed by @ginger.
- The `console` feature is now enabled by default, allowing the server console to be used for running admin commands
directly. To automatically open the console on startup, set the `admin_console_automatic` config option to `true`.
Contributed by @ginger.
- We now (finally) document our container image mirrors. Contributed by @Jade
# Continuwuity 0.5.0 (2025-12-30)
@@ -347,9 +317,12 @@ # Continuwuity 0.5.0 (2025-12-30)
## Features
- Enabled the OTLP exporter in default builds, and allow configuring the exporter protocol. (@Jade). ([#1251](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1251))
- Enabled the OTLP exporter in default builds, and allow configuring the exporter protocol. (
@Jade). ([#1251](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1251))
## Bug Fixes
- Don't allow admin room upgrades, as this can break the admin room (@timedout) ([#1245](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1245))
- Fix invalid creators in power levels during upgrade to v12 (@timedout) ([#1245](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1245))
- Don't allow admin room upgrades, as this can break the admin room (
@timedout) ([#1245](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1245))
- Fix invalid creators in power levels during upgrade to v12 (
@timedout) ([#1245](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1245))
Generated
+191 -200
View File
File diff suppressed because it is too large Load Diff
+8 -7
View File
@@ -12,7 +12,7 @@ license = "Apache-2.0"
# See also `rust-toolchain.toml`
readme = "README.md"
repository = "https://forgejo.ellis.link/continuwuation/continuwuity"
version = "26.7.2"
version = "26.6.2"
[workspace.metadata.crane]
name = "conduwuit"
@@ -342,8 +342,9 @@ version = "1.1.1"
# Used for matrix spec type definitions and helpers
[workspace.dependencies.ruma]
git = "https://github.com/ruma/ruma.git"
rev = "c1100793d2fd464be34052773360f3f3773d0fc4"
# version = "0.14.1"
git = "https://github.com/gingershaped/ruwuma.git"
rev = "66811f042b1bdc147dab3c45f697383e902f28c0"
features = [
"appservice-api-c",
"client-api",
@@ -356,6 +357,7 @@ features = [
"compat-upload-signatures",
"compat-optional-txn-pdus",
"compat-get-3pids",
"unstable-msc2666",
"unstable-msc2867",
"unstable-msc2870",
"unstable-msc3061",
@@ -377,9 +379,8 @@ features = [
"unstable-msc4293",
"unstable-msc4406",
"unstable-msc4439",
"unstable-msc4354",
"unstable-msc4480",
"unstable-msc4466",
"unstable-msc4484",
"unstable-extensible-events",
]
@@ -503,7 +504,7 @@ default-features = false
version = "0.1"
[workspace.dependencies.syn]
version = "3.0"
version = "2.0"
default-features = false
features = ["full", "extra-traits"]
@@ -564,7 +565,7 @@ features = ["std"]
version = "0.3.0"
[workspace.dependencies.resolvematrix]
version = "1.3.0"
version = "1.2.0"
[workspace.dependencies.serde_urlencoded]
version = "0.7.1"
+1
View File
@@ -0,0 +1 @@
Added support for the OAuth2 device authorization flow. Contributed by @ginger
-1
View File
@@ -1 +0,0 @@
Update backup instructions: the right paths for `.sst` files are now in `$DATABASE_BACKUP_PATH/private/<number>` path instead of `$DATABASE_BACKUP_PATH/<number>`. Contributed by @stratself
+1
View File
@@ -0,0 +1 @@
Fixed requests returning `500 Internal Server Error` when the header selected by `request_ip_source` is absent, duplicated, or malformed (for example Envoy omitting `X-Envoy-External-Address` on internal requests). The client IP now falls back to the connection peer address instead of failing the request. Contributed by @eleboucher
+1
View File
@@ -0,0 +1 @@
Appservices are now properly able to create devices for E2EE.
-1
View File
@@ -1 +0,0 @@
Added MSC4480 sticky events to simplified sliding sync. Contributed by @eleboucher.
-1
View File
@@ -1 +0,0 @@
Added scoped typing updates to simplified Sliding Sync (MSC4508). Contributed by @eleboucher.
-1
View File
@@ -1 +0,0 @@
Replace deprecated `docker-compose` commands with `docker compose` to reflect latest Docker changes.
+1
View File
@@ -0,0 +1 @@
Resolve alias service by correct name for auto-join. Contributed by @eleboucher
-1
View File
@@ -1 +0,0 @@
Fixed typing notifications not interrupting a sync long poll. Contributed by @eleboucher.
+1
View File
@@ -0,0 +1 @@
Fixed newly created rooms failing to sync properly in clients using legacy sync.
+1
View File
@@ -0,0 +1 @@
Fixed newly joined rooms failing to sync their full state (including the room name) to clients using legacy sync.
-1
View File
@@ -1 +0,0 @@
Updated Ruma dependencies. Contributed by @eleboucher.
-1
View File
@@ -1 +0,0 @@
Fixed missed wake-ups and stale responses in legacy and sliding sync long polls. Contributed by @eleboucher.
+1
View File
@@ -0,0 +1 @@
Fixed `roomuserid_lastnotificationread` being aliased to the highlight count table, which clobbered highlight counts when setting a read marker. Contributed by @eleboucher
-1
View File
@@ -1 +0,0 @@
Livekit docs: `room.auto_create: false` is now included in default `livekit.yaml`, following `lk-jwt-service` recommendation.
-1
View File
@@ -1 +0,0 @@
Add caveat and workaround for container resolution (e.g. for dockerized appservices) when using mounted `/etc/resolv.conf`. Contributed by @stratself
+1
View File
@@ -0,0 +1 @@
Fixed freshly left room failing to sync.
-1
View File
@@ -1 +0,0 @@
Added MSC4354 sticky events, behind the `allow_sticky_events` config option. Contributed by @eleboucher.
+1
View File
@@ -0,0 +1 @@
Appservices may now specify both the unstable and stable `device_id` query parameters in a request. The stable parameter will take priority. Contributed by @ginger.
-1
View File
@@ -1 +0,0 @@
Added MSC4186 direct, encrypted, and room-type list filters, resolving invited rooms from their stripped invite state. Contributed by @eleboucher.
+1
View File
@@ -0,0 +1 @@
Fetch the joined member count once per event instead of once per notified user.
-1
View File
@@ -1 +0,0 @@
Preserve all users' read receipts when batching room receipt updates.
-1
View File
@@ -1 +0,0 @@
Refactor TURN docs and remove unsafe setups. Polish LiveKit docs. Add guidance for TURNS-over-443 multiplexing for both LiveKit and legacy calls. Contributed by @stratself
+1
View File
@@ -0,0 +1 @@
Fixed the deeplink redirect for deleting devices. Contributed by @koen
+1
View File
@@ -0,0 +1 @@
Fix status code for oauth registration. Contributed by @n00byking
+1
View File
@@ -0,0 +1 @@
Introduce `accepted_ip_sources` as a multiple options variant of `request_ip_source`, allowing for more advanced deployments and making fallbacks an explicit choice. Contributed by @Omar007
+1
View File
@@ -0,0 +1 @@
Exempt m.room.create from auth_events check. Contributed by @eleboucher
+1
View File
@@ -0,0 +1 @@
Fixed `create` being returned as a supported prompt value regardless of if registration is enabled or not. Contributed by @ginger
+1
View File
@@ -0,0 +1 @@
Updated an out-of-date statement about Oracle Linux release cadences.
+1
View File
@@ -0,0 +1 @@
Fixed high CPU usage when multiple clients from the same account were connected at once. Each sync woke the account's other sync loops, causing them to wake each other in a loop.
+1
View File
@@ -0,0 +1 @@
Fixed MSC4190 appservice device creation registering a random device ID instead of the requested one (and dropping the requested display name), which prevented encrypted mautrix bridges from starting on OIDC-enabled servers and leaked an orphan device on the bridge bot per startup attempt.
-1
View File
@@ -1 +0,0 @@
Updated admin command names (list-users -> list, list-rooms -> list, and reload-mods -> reload), old names are now aliases. Contributed by @PerformativeJade
+1
View File
@@ -0,0 +1 @@
Deactivated users and appservice puppets are no longer counted by `/_continuwuity/local_user_count`. Contributed by @ginger.
-1
View File
@@ -1 +0,0 @@
Updated the docs to reflect the current default User-Agent for URL previews
-1
View File
@@ -1 +0,0 @@
Resolve membership service by correct name for auto-join. Contributed by @Aranjedeath
-1
View File
@@ -1 +0,0 @@
Plugged a logic gap that may have been allowing Continuwuity to process events with incorrect room versions under certain conditions. Contributed by @nex.
-1
View File
@@ -1 +0,0 @@
Added missing documentation to config parameters. Contributed by @renegadespork
-1
View File
@@ -1 +0,0 @@
The OAuth 2.0 device authorization endpoint now rejects clients which did not register the device code grant type, instead of issuing them a device code. The token endpoint now returns the `unauthorized_client` error code when a client requests a grant type it did not register, instead of `invalid_grant`. Contributed by @mmaudet.
-1
View File
@@ -1 +0,0 @@
Generic deployment documentation: Use `/etc/caddy/Caddyfile` instead of `/etc/caddy/conf.d/*` paths, which do not exist on a majority of Caddy installations.
@@ -0,0 +1 @@
Fix joining restricted rooms over federation failing with signature verification error.
@@ -0,0 +1 @@
Fixed the client space hierarchy endpoint returning a 500 "Space hierarchy is unreasonably large" error for cyclic space graphs (e.g. a space containing itself). Rooms are now deduplicated during traversal as required by the spec, and the traversal depth is bounded even when the client does not specify `max_depth`.
@@ -0,0 +1 @@
Fixed simplified sliding sync holding account data for up to 30 seconds, which made encryption setup and cross-signing resets appear to hang.
@@ -0,0 +1 @@
Fixed local invites and invite acceptances not being reflected in sync promptly. Contributed by @eleboucher
+18 -151
View File
@@ -170,136 +170,43 @@
#
#db_write_buffer_capacity_mb = varies by system
# The maximum number of Persisted Data Units (PDUs) to cache.
# Accepts any 32-bit integer.
#
# PDUs are events broadcast from one homeserver to any others that have
# joined the same room (identified by Room ID). They are persisted in
# long-term storage and record the history of messages and state
# for a room.
#
# An example of a PDU would be a message or joining a room.
#
# Setting this higher might be useful if the server has a large memory
# capacity and is noticeably I/O limited.
#
# This defaults to 100,000 + (10,000 * CPU core count)
# This item is undocumented. Please contribute documentation for it.
#
#pdu_cache_capacity = varies by system
# The maximum number of auth chains to cache.
# Accepts any 32-bit integer.
#
# When determining is a user is authorized to send an event,
# the server will first check the cache for an auth chain.
# If the auth chain is not present in the cache,
# The server will read the auth chain from the database
# and add it to the cache.
#
# This defaults to 100,000 + (10,000 * CPU core count)
# This item is undocumented. Please contribute documentation for it.
#
#auth_chain_cache_capacity = varies by system
# Determines the cache size for eventid data references.
# Accepts any 32-bit integer.
#
# Each matrix event can be referenced in the database via either
# an eventid (string) or a shorteventid (64-bit integer).
# This caps the capacity of cached eventids referenced
# by their shorteventid.
#
# This defaults to 100,000 + (50,000 * CPU core count)
# This item is undocumented. Please contribute documentation for it.
#
#shorteventid_cache_capacity = varies by system
# Determines the cache size for eventid data references.
# Accepts any 32-bit integer.
#
# Each matrix event can be referenced in the database via either
# an eventid (string) or a shorteventid (64-bit integer).
# This caps the capacity of cached shorteventids referenced
# by their eventid.
#
# This defaults to 100,000 + (25,000 * CPU core count)
# This item is undocumented. Please contribute documentation for it.
#
#eventidshort_cache_capacity = varies by system
# Determines the cache size for pdu data references.
# Accepts any 32-bit integer.
#
# This caps the capacity of cached pdus referenced
# by their eventid.
#
# This defaults to 100,000 + (25,000 * CPU core count)
# This item is undocumented. Please contribute documentation for it.
#
#eventid_pdu_cache_capacity = varies by system
# Determines the cache size for state key data references.
# Accepts any 32-bit integer.
#
# State keys are used by the server to verify that a token
# from a third-party invite event was actually generated
# by the server where the room resides.
#
# These state keys can be referenced in the database via either
# a statekey (string) or a shortstatekey (64-bit integer).
# This caps the capacity of cached statekeys referenced
# by shortstatekeys.
#
# This defaults to 100,000 + (10,000 * CPU core count)
# This item is undocumented. Please contribute documentation for it.
#
#shortstatekey_cache_capacity = varies by system
# Determines the cache size for state key data references.
# Accepts any 32-bit integer.
#
# State keys are used by the server to verify that a token
# from a third-party invite event was actually generated
# by the server where the room resides.
#
# These state keys can be referenced in the database via either
# a statekey (string) or a shortstatekey (64-bit integer).
# This caps the capacity of cached shortstatekeys referenced
# by statekeys.
#
# This defaults to 100,000 + (10,000 * CPU core count)
# This item is undocumented. Please contribute documentation for it.
#
#statekeyshort_cache_capacity = varies by system
# Determines the cache size for event_data references scoped
# by server_name.
# Accepts any 32-bit integer.
#
# Event data can be referenced in the database by server name.
# This is useful if the server needs to clear all events associated
# with a particular federated server, for example.
# This caps the capacity of cached event_data referenced
# by server_name.
#
# This defaults to 500,000 + (100,000 * CPU core count)
# This item is undocumented. Please contribute documentation for it.
#
#servernameevent_data_cache_capacity = varies by system
# Determines the cache size for room states.
# Accepts any 32-bit integer.
#
# To ensure data integrity of room events across asynchronous
# requests from federated servers, Matrix tracks the state
# of a room using a statehash and the changes since the
# previous (parent) statehash.
# This caps the capacity of cached room state data.
#
# This defaults to 100 * CPU core count.
# This item is undocumented. Please contribute documentation for it.
#
#stateinfo_cache_capacity = varies by system
# Determines the cache size for spacehierarchy data.
# Accepts any 32-bit integer.
#
# Each roomid contains info on its place in the space hierarchy.
# This caps the capacity of cached spacehierarchy data.
#
# This defaults to 1,000 * CPU core count.
# This item is undocumented. Please contribute documentation for it.
#
#roomid_spacehierarchy_cache_capacity = varies by system
@@ -440,13 +347,7 @@
#
#max_request_size = 20971520
# Maximum number of prev_events the server will request from
# other servers.
#
# When requesting room events from another server, this server will
# specify a maximum prev_events for the other server to return in its
# response. This can be used for things like backfilling room data and
# getting missing events.
# This item is undocumented. Please contribute documentation for it.
#
#max_fetch_prev_events = 1024
@@ -831,15 +732,11 @@
#
#tracing_flame = false
# Which log level tracing_flame will trace.
#
# See "tracing_flame" for more details.
# This item is undocumented. Please contribute documentation for it.
#
#tracing_flame_filter = "info"
# The output path for tracing_flame data.
#
# See "tracing_flame" for more details.
# This item is undocumented. Please contribute documentation for it.
#
#tracing_flame_output_path = "./tracing.folded"
@@ -1067,7 +964,7 @@
#
#rocksdb_log_level = "error"
# Whether to output RocksDB errors to stderr.
# This item is undocumented. Please contribute documentation for it.
#
#rocksdb_log_stderr = false
@@ -1317,17 +1214,7 @@
#
#emergency_password =
# Specifies the path where push notifications will be sent to a
# push gateway.
#
# When a Matrix client registers for push notifications, it will specify
# a push gateway url where notification events will be sent.
# According to the current spec for Matrix Push Gateways, the path should
# always be "/_matrix/push/v1/notify".
# You should only change this if you have configured your own push gateway
# that requires a different path.
#
# For more information on Push Gateways: https://spec.matrix.org/latest/push-gateway-api/
# This item is undocumented. Please contribute documentation for it.
#
#notification_push_path = "/_matrix/push/v1/notify"
@@ -1419,12 +1306,6 @@
#
#allow_incoming_typing = true
# Allow the use of unstable persistent "sticky events" ([MSC4354])
#
# MSC4354: https://c10y.cc/MSC4354
#
#allow_sticky_events = false
# Maximum time federation user can indicate typing.
#
#typing_federation_timeout_s = 30
@@ -1484,10 +1365,7 @@
#
#allow_legacy_media = true
# If set to true, prevents fetching new legacy remote media.
#
# Legacy media may still be accessible if it was already fetched
# previously and allow_legacy_media is true.
# This item is undocumented. Please contribute documentation for it.
#
#freeze_legacy_media = true
@@ -1717,7 +1595,7 @@
# User agent that is used specifically when fetching url previews.
#
#url_preview_user_agent = "continuwuity/<version> (embedbot; facebookexternalhit/1.1; +https://continuwuity.org)"
#url_preview_user_agent = "continuwuity/<version> (bot; +https://continuwuity.org)"
# Determines whether audio and video files will be downloaded for URL
# previews.
@@ -1895,18 +1773,7 @@
#
#tokio_console = false
# A list of flags that modify startup behavior.
# Accepts an array of strings.
#
# During startup, the program will check for the presence of certain
# strings in this array. Matching values will modify how the program runs
# those startup tasks.
#
# If this variable is empty or contains no matches, the server will start
# normally.
#
# Currently this only checks for "smoke" which enables "Smoketest mode."
# This mode exits the program after running startup tasks.
# This item is undocumented. Please contribute documentation for it.
#
#test = false
+11 -19
View File
@@ -20,19 +20,17 @@ ## Set up the appservice - general instructions
registered on the homeserver automatically joins it. Then send a message into
the room like this:
~~~txt
!admin appservices register
```
paste
the
contents
of
the
yaml
registration
here
```
~~~
!admin appservices register
```
paste
the
contents
of
the
yaml
registration
here
```
You can confirm it worked by sending a message like this:
`!admin appservices list`
@@ -53,9 +51,3 @@ ### Remove an appservice
`!admin appservices unregister <name>`
where `<name>` one of the output of `appservices list`.
## Caveats
### Docker DNS
If you follow the [DNS tuning guide](./guides/dns.mdx#for-docker-users) and mount a custom `/etc/resolv.conf`, you may not be able to connect to appservices' containers using their hostnames. Follow the [workaround in the guide](./guides/dns.mdx#for-docker-users) to connect to your appservice using static IPs.
+3 -3
View File
@@ -3,11 +3,11 @@ # Calls
Matrix supports two types of calls:
- Element Call powered by [MatrixRTC](https://half-shot.github.io/msc-crafter/#msc/4143) and [LiveKit](https://github.com/livekit/livekit)
- Legacy calls, supported by a STUN/TURN server.
- Legacy calls, sometimes using Jitsi
Both types of calls are supported by different sets of clients, but most clients are moving towards MatrixRTC / Element Call.
For either one to work correctly, you have to do some additional setup:
For either one to work correctly, you have to do some additional setup.
- For legacy calls to work, you need to set up a TURN/STUN server. [Read the TURN guide for tips on how to set up coturn](./calls/turn.mdx)
- For MatrixRTC / Element Call to work, you have to set up the LiveKit backend. LiveKit also uses TURN/STUN to increase reliability - you can set up its built-in TURN server, or integrate with an existing one. [Read the LiveKit guide](./calls/livekit.mdx)
- For MatrixRTC / Element Call to work, you have to set up the LiveKit backend (foci). LiveKit also uses TURN/STUN to increase reliability - you can set up its built-in TURN server, or integrate with an existing one. [Read the LiveKit guide](./calls/livekit.mdx)
+87 -193
View File
@@ -1,6 +1,8 @@
# MatrixRTC/Element Call Setup
# Matrix RTC/Element Call Setup
This guide assumes that you are using docker compose for deployment.
:::info
This guide assumes that you are using docker compose for deployment. LiveKit only provides Docker images.
:::
:::tip
You can find help setting up MatrixRTC in our dedicated room - [#matrixrtc:continuwuity.org](https://matrix.to/#/%23matrixrtc%3Acontinuwuity.org)
@@ -8,15 +10,15 @@ # MatrixRTC/Element Call Setup
## Instructions
### 1. Set up your domain
### 1. Domain
LiveKit should live on its own domain or subdomain. In this guide we use `livekit.example.com` - this should be replaced with a domain you control.
Make sure the DNS record for the (sub)domain you plan to use is pointed to your server.
### 2. Set up the LiveKit services
### 2. Services
Using LiveKit with Matrix requires two services - LiveKit itself, and a brokering service (`lk-jwt-service`) that grants Matrix users permission to connect to it.
Using LiveKit with Matrix requires two services - LiveKit itself, and a service (`lk-jwt-service`) that grants Matrix users permission to connect to it.
You must generate a key and secret to allow the Matrix service to authenticate with LiveKit. `LK_MATRIX_KEY` should be around 20 random characters, and `LK_MATRIX_SECRET` should be around 64. Remember to replace these with the actual values!
@@ -79,23 +81,15 @@ # - "50100-50200:50100-50200/udp"
LK_MATRIX_KEY: LK_MATRIX_SECRET
# replace these with your key-secret pair. Example:
# APIUxUnMnSkuFWV: t93ZVjPeoEdyx7Wbet3kG4L3NGZIZVEFvqe0UuiVc22A
# do not create rooms by default
room:
auto_create: false
```
Consult [`config-sample.yaml`][livekit-config-sample-yaml] for all LiveKit options.
[livekit-config-sample-yaml]: https://github.com/livekit/livekit/blob/master/config-sample.yaml
#### Firewall hints
You will need to allow ports `7881/tcp` and `50100:50200/udp` through your firewall. If you use UFW, the commands are: `ufw allow 7881/tcp` and `ufw allow 50100:50200/udp`.
### 3. Telling clients where to find LiveKit
To tell clients where to find LiveKit, you need to add your `lk-jwt-service`'s address to the `[global.matrix_rtc] > foci` field of your Continuwuity config file.
To tell clients where to find LiveKit, you need to add the address of your `lk-jwt-service` to the `[global.matrix_rtc]` config section using the `foci` option.
The variable should be a list of servers serving as MatrixRTC endpoints. Replace the URL with the address you are deploying your instance of lk-jwt-service to:
@@ -106,12 +100,6 @@ ### 3. Telling clients where to find LiveKit
]
```
If you configure Continuwuity via environment variables, use the following:
```bash
CONTINUWUITY_MATRIX_RTC__FOCI=[{ type = "livekit", livekit_service_url = "https://livekit.example.com" }]
```
This will expose LiveKit information on the following endpoints for clients to discover:
- `/_matrix/client/unstable/org.matrix.msc4143/rtc/transports` (MSC4143 unstable, behind auth)
@@ -144,11 +132,6 @@ ### 4. Configure your Reverse Proxy
}
```
**Note**: if you run Caddy inside a container (e.g. by following the example [here](../deploying/docker.mdx#caddy-using-caddyfile)) instead of on the host, then:
- Put these containers on the same bridge network as caddy (by defining `networks: [ caddy ]` in each of the services), and
- Use appropriate container hostnames (`lk-jwt-service` and `livekit`) instead of `127.0.0.1` in the Caddyfile
</details>
<details>
@@ -204,7 +187,6 @@ ### 4. Configure your Reverse Proxy
```
</details>
<details>
<summary>Example docker compose file with caddy-docker-proxy labels</summary>
```yaml
@@ -280,9 +262,76 @@ ### 6. Start Everything
Start up the services using your usual method - for example `docker compose up -d`.
## Additional TURN configuration
### Using LiveKit's built-in TURN server
LiveKit includes a built-in TURN server which can be used in place of an external option. This TURN server will only work with LiveKit, so you can't use it for legacy Matrix calling or anything else.
If you don't want to set up a separate TURN server, you can enable this with the following changes:
```yaml
### add this to livekit.yaml ###
turn:
enabled: true
udp_port: 3478
relay_range_start: 50300
relay_range_end: 50400
domain: livekit.example.com
```
```yaml
### add these to livekit's docker-compose ###
ports:
- "3478:3478/udp"
- "50300-50400:50300-50400/udp"
### if you're using `network_mode: host`, you can skip this part
```
Recreate the LiveKit container (with `docker-compose up -d livekit`) to apply these changes. Remember to allow the new `3478/udp` and `50300:50400/udp` ports through your firewall.
### Integration with an external TURN server
If you've already [set up coturn](./turn), you can configure Livekit to use it.
:::tip Avoid port clashes between the two services
Before continuing, make sure coturn's `min-port` and `max-port` do not overlap with LiveKit's port range:
```ini
# in your coturn.conf
min-port=50201
max-port=65535
```
:::
Generate a long random secret for LiveKit, and add it to your coturn config under the `static-auth-secret` option. You can add as many secrets as you want, so set a different one for LiveKit to use.
Then configure LiveKit, making sure to replace `COTURN_SECRET` with the one you generated:
```yaml
# livekit.yaml
rtc:
turn_servers:
- host: coturn.example.com
port: 3478
protocol: udp
secret: "COTURN_SECRET"
- host: coturn.example.com
port: 3478
protocol: tcp
secret: "COTURN_SECRET"
- host: coturn.example.com
port: 5349
protocol: tls # Only if you have already set up TLS in your coturn
secret: "COTURN_SECRET"
```
Restart LiveKit and coturn to apply these changes.
## Testing
To test that LiveKit is successfully integrated with Continuwuity, you will need to replicate its [Token Exchange Flow](https://github.com/element-hq/lk-jwt-service#%EF%B8%8F-how-it-works--token-exchange-flow). Follow the steps below while checking Docker logs (`docker compose logs --follow`), in order to help [troubleshooting](#troubleshooting) any issues.
To test that LiveKit is successfully integrated with Continuwuity, you will need to replicate its [Token Exchange Flow](https://github.com/element-hq/lk-jwt-service#%EF%B8%8F-how-it-works--token-exchange-flow). Follow the steps below while checking Docker logs (`docker-compose logs --follow`), in order to help [troubleshooting](#troubleshooting) any issues.
First, you will need an access token for your current login session. These can be found in your client's settings or obtained via [this website](https://timedout.uk/mxtoken.html).
@@ -347,19 +396,16 @@ ## Testing
{"url":"wss://livekit.example.com","jwt":"a_really_really_long_string"}
```
Use this token to test at the [LiveKit Connection Tester][livekit-connection-test]. If everything works there, then you have set up LiveKit successfully!
[livekit-connection-test]: https://livekit.com/webrtc/connection-test
Use this token to test at the [LiveKit Connection Tester](https://livekit.io/connection-test). If everything works there, then you have set up LiveKit successfully!
## Troubleshooting
To debug any issues, you can place a call or redo the Testing instructions, and check the container logs for any specific errors. Use `docker compose logs --follow` to follow these logs in real-time.
To debug any issues, you can place a call or redo the Testing instructions, and check the container logs for any specific errors. Use `docker-compose logs --follow` to follow these logs in real-time.
### Common errors in Element Call UI
- `MISSING_MATRIX_RTC_FOCUS`/`MISSING_MATRIX_RTC_TRANSPORT`: LiveKit is missing from Continuwuity's config file
- `MISSING_MATRIX_RTC_FOCUS`: LiveKit is missing from Continuwuity's config file
- "Waiting for media" popup always showing: a LiveKit URL has been configured in Continuwuity, but your client cannot connect to it for some reason
- `OPEN_ID_ERROR`: Your client can reach out to `lk-jwt-service`, but has problems authenticating with it. In this case, check `lk-jwt-service` logs for more details
For browser-based clients, you can also inspect connections using DevTools' Networking tab, to see which requests are erroring out.
@@ -394,19 +440,6 @@ # --- some errors ---
After implementing the changes and restarting your compose, `lk-jwt-service` should now connect to your other services. The sidecar container test above should now return an `OK` from LiveKit.
### Incorrect IP address for LiveKit
By default, LiveKit auto-discovers its public IP address(es), which is reflected in the "Establishing WebRTC connection" section of the connection test page. If these IPs are incorrect, you may want to hardcode your own IP by doing the following:
```diff
### in your livekit.yaml ###
rtc:
# ... other configs here ...
- use_external_ip: true
+ use_external_ip: false
+ node_ip: "1.2.3.4"
```
### Workaround for non-federating servers
When deploying on servers with federation disabled (`allow_federation = false`), LiveKit will fail as it can't fetch the required [OpenID endpoint](https://spec.matrix.org/v1.17/server-server-api/#get_matrixfederationv1openiduserinfo) via federation paths.
@@ -425,156 +458,17 @@ ## Related Documentation
Guides:
- [Element Call self-hosting documentation from element-hq][element-call-selfhosting]
- [Community guide with overview of LiveKit's mechanisms][tom-livekit-guide]
- [Community guide using systemd][kimiblock-livekit-guide]
[element-call-selfhosting]: https://github.com/element-hq/element-call/blob/livekit/docs/self-hosting.md
[tom-livekit-guide]: https://tomfos.tr/matrix/livekit/
[kimiblock-livekit-guide]: https://blog.kimiblock.top/2024/12/24/hosting-element-call/
Configurations:
- [Livekit's `config-sample.yaml`][livekit-config-sample-yaml] - LiveKit configuration file with full options
- [Element Call self-hosting documentation](https://github.com/element-hq/element-call/blob/livekit/docs/self-hosting.md)
- [Community guide with overview of LiveKit's mechanisms](https://tomfos.tr/matrix/livekit/)
- [Community guide using systemd](https://blog.kimiblock.top/2024/12/24/hosting-element-call/)
Specifications:
- [MSC4143 - MatrixRTC proposal][MSC4143]
- [MSC4195 - LiveKit proposal][MSC4195]
[MSC4143]: https://github.com/matrix-org/matrix-spec-proposals/pull/4143
[MSC4195]: https://github.com/matrix-org/matrix-spec-proposals/pull/4195
- [MSC4143 - MatrixRTC proposal](https://github.com/matrix-org/matrix-spec-proposals/pull/4143)
- [MSC4195 - LiveKit proposal](https://github.com/matrix-org/matrix-spec-proposals/pull/4195)
Source code:
- [Element Call][element-call-github]
- [lk-jwt-service][lk-jwt-service-github]
- [LiveKit server][livekit-server-github]
[element-call-github]: https://github.com/element-hq/element-call
[lk-jwt-service-github]: https://github.com/element-hq/lk-jwt-service
[livekit-server-github]: https://github.com/livekit/livekit
Other:
- [Matrix VOIP and LiveKit][sspaeth-matrix-voip] - Community member deep dive on current VOIP solutions on Matrix
[sspaeth-matrix-voip]: https://sspaeth.de/2026/04/matrix-voip-and-livekit/
## Appendix
### Additional TURNS-over-443 configuration
Most of the time, LiveKit [**does not need TURN**][sspaeth-matrix-voip-turn] to function. However, there are situations where clients are in very restrictive networks that disallows non-standard ports and UDP. In these cases, a TURN-over-TLS server on port :443 could be employed to relay traffic for them.
[sspaeth-matrix-voip-turn]: https://sspaeth.de/2026/04/matrix-voip-and-livekit/#turn
You can either use LiveKit's built-in TURN server, or integrate LiveKit with [coturn](./turn).
<details>
<summary>Using LiveKit's built-in TURN server</summary>
First, set up LiveKit's built-in TURN server with its own domain - we'll use `livekit-turn.example.com` in our example.
```yaml
## add this to `livekit.yaml` ##
turn:
enabled: true
# note: the TLS port will always be advertised as :443
tls_port: 5349
# optional: configure an extra UDP port on :3478
# udp_port: 3478
relay_range_start: 50300
relay_range_end: 50400
domain: livekit-turn.example.com
# replace these with your actual cert/key files
cert_file: /path/to/livekit-turn.example.com.crt
key_file: /path/to/livekit-turn.example.com.key
```
```yaml
### add these ports to livekit's docker-compose ###
### if you're using `network_mode: host`, you can skip this part
ports:
- "127.0.0.1:5349:5349/tcp"
- "50300-50400:50300-50400/udp"
# "3478:3478/udp" # (optional UDP port)
```
Recreate the LiveKit container (with `docker compose up -d livekit`) to apply these changes. Remember to allow the new `50300:50400/udp` ports through your firewall.
Then, we will configure a route from port 443 of the host back to our `livekit-turn.example.com` service on port 5349. To both **multiplex** this and LiveKit's websocket on the same port, we will use a layer-4 reverse proxy with **SNI routing** capabilities, such as [caddy-l4][caddy-l4] on the host system.
```
## in your Caddyfile ##
{
servers {
listener_wrappers {
# intercept packets meant for the TURN domain first
# before forwarding other packets to "normal" HTTP listeners
layer4 {
@turn tls sni livekit-turn.example.com
route @turn {
proxy 127.0.0.1:5349 # forward to normal TURNS port
}
}
}
tls
}
}
}
# livekit stuff
https://livekit.example.com {
@lk-jwt-service path /healthz /get_token /sfu/get
route @lk-jwt-service {
reverse_proxy 127.0.0.1:8081
}
reverse_proxy http://127.0.0.1:7880
}
```
[caddy-l4]: https://github.com/mholt/caddy-l4
</details>
<details>
<summary>Using an external TURN server (coturn)</summary>
Before continuing, make sure coturn's `min-port` and `max-port` do not overlap with LiveKit's port range:
```ini
# in your coturn.conf
min-port=50201
max-port=65535
```
Then, generate a long random secret for LiveKit, and add it to your coturn config under the `static-auth-secret` option. You can add as many secrets as you want, so set a different one for LiveKit to use.
After that, refer to the following [**TURN instructions**](./turn#turns-over-443) to set up coturn with TLS, as well as multiplexing with LiveKit's websocket on port 443.
Then configure LiveKit, making sure to replace `COTURN_SECRET` with the one you generated:
```yaml
### in your livekit.yaml ###
rtc:
# ... other configs here ...
turn_servers:
- host: coturn.example.com
port: 443
protocol: tls
secret: "COTURN_SECRET"
```
Restart LiveKit, coturn, and Caddy-l4 to apply these changes.
</details>
After finishing configuration, you can run the Testing steps again to check that TURN-over-TLS is working. In the LiveKit connection test page, there should be a green tick saying "Can connect to TURN".
- [Element Call](https://github.com/element-hq/element-call)
- [lk-jwt-service](https://github.com/element-hq/lk-jwt-service)
- [LiveKit server](https://github.com/livekit/livekit)
+120 -284
View File
@@ -1,95 +1,36 @@
# Setting up TURN/STUN
[TURN][turn] and [STUN][stun] are used as a component in many calling systems. Matrix uses them directly for legacy calls and indirectly for MatrixRTC via Livekit.
[TURN](https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT) and [STUN](https://en.wikipedia.org/wiki/STUN) are used as a component in many calling systems. Matrix uses them directly for legacy calls and indirectly for MatrixRTC via Livekit.
Continuwuity recommends using [Coturn][coturn] as your TURN/STUN server, which is available as a Docker image or a distro package. This guide assumes that you are using docker compose for deployment.
:::tip
You can find help setting up TURN/STUN in our MatrixRTC room - [#matrixrtc:continuwuity.org](https://matrix.to/#/%23matrixrtc%3Acontinuwuity.org)
:::
[turn]: https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT
[stun]: https://en.wikipedia.org/wiki/STUN
[coturn]: https://github.com/coturn/coturn
Continuwuity recommends using [Coturn](https://github.com/coturn/coturn) as your TURN/STUN server, which is available as a Docker image or a distro package.
## Installing Coturn
### 1. Domain
Coturn should live on its own domain or subdomain. In this guide we use `coturn.example.com` - this should be replaced with a domain you control.
### 2. Configuration
### Configuration
Create a configuration file called `coturn.conf` containing:
```ini
use-auth-secret
static-auth-secret=<a secret key>
realm=coturn.example.com
realm=<your server domain>
```
:::tip Tip: Generate a long, secure secret with the following command
:::tip Generating a secure secret
A common way to generate a suitable alphanumeric secret key is by using:
```bash
pwgen -s 64 1
```
:::
If you want to enable TURN-over-TLS (TURNS), add the appropriate cert/key paths to your `coturn.conf` by adding the following lines:
```ini
cert=/etc/letsencrypt/coturn.example.com.crt
pkey=/etc/letsencrypt/coturn.example.com.key
```
The cert and key must be encoded in PEM format and are readable by the coturn user.
Check out the [`turnserver.conf`][turnserver-conf] example for all coturn options.
[turnserver-conf]: https://github.com/coturn/coturn/blob/master/examples/etc/turnserver.conf
### 3. Running the coturn container
Next, we will start the Coturn container with the [official image][coturn-image]. **Host networking mode** will be used, as it is better for performance and reduces configuration complexity (see [Coturn Docker docs][coturn-docker-docs] for rationale).
[coturn-image]: https://hub.docker.com/r/coturn/coturn
[coturn-docker-docs]: https://github.com/coturn/coturn/blob/master/docker/coturn/README.md#why-so-many-ports-opened
Create a `docker-compose.yml` file as follows and run `docker compose up -d`:
```yaml
version: '3'
services:
coturn:
container_name: coturn
image: docker.io/coturn/coturn
restart: unless-stopped
network_mode: "host"
volumes:
- ./coturn.conf:/etc/coturn/turnserver.conf
# replace this with actual paths to your certificates
- /path/to/certs:/etc/letsencrypt
```
### 4. Opening ports
#### Port Configuration
By default, coturn uses the following ports:
- `3478` (UDP/TCP): Standard TURN/STUN port
- `5349` (UDP/TCP): TURN/STUN over TLS
- `49152-65535` (UDP): Media relay ports
You will need to allow them through your firewall. If you use UFW, the commands are:
```bash
ufw allow 3478/udp
ufw allow 3478/tcp
ufw allow 5349/tcp
ufw allow 5349/udp
ufw allow 49152-65535/udp
```
::: tip For LiveKit users
If you're also running LiveKit, you'll need configure non-overlapping port ranges to avoid port conflicts:
If you're also running LiveKit, you'll need to avoid port conflicts. Configure non-overlapping port ranges:
```ini
# In coturn.conf
@@ -97,33 +38,57 @@ # In coturn.conf
max-port=65535
```
```bash
# With ufw
ufw allow 50201:65535/udp
```
This leaves ports `50100-50200` available for LiveKit's default configuration.
### Running with Docker
Run the [Coturn](https://hub.docker.com/r/coturn/coturn) image using:
```bash
docker run -d --network=host \
-v $(pwd)/coturn.conf:/etc/coturn/turnserver.conf \
coturn/coturn
```
### Running with Docker Compose
Create a `docker-compose.yml` file and run `docker compose up -d`:
```yaml
version: '3'
services:
turn:
container_name: coturn-server
image: docker.io/coturn/coturn
restart: unless-stopped
network_mode: "host"
volumes:
- ./coturn.conf:/etc/coturn/turnserver.conf
```
:::info Why host networking?
Coturn uses host networking mode because it needs to bind to multiple ports and work with various network protocols. Using host networking is better for performance, and reduces configuration complexity. To understand alternative configuration options, visit [Coturn's Docker documentation](https://github.com/coturn/coturn/blob/master/docker/coturn/README.md).
:::
### 5. Security Recommendations
### Security Recommendations
For Coturn hardening and security best practices, see Synapse's [Coturn documentation][synapse-coturn-guide],
which includes important firewall and access control recommendations.
[synapse-coturn-guide]: https://element-hq.github.io/synapse/latest/setup/turn/coturn.html#configuration
For security best practices, see Synapse's [Coturn documentation](https://element-hq.github.io/synapse/latest/turn-howto.html), which includes important firewall and access control recommendations.
## Configuring Continuwuity
Once your TURN server is running, configure Continuwuity to provide credentials to clients. Add the following to your Continuwuity configuration file:
### Shared Secret Authentication (Recommended)
This is the most secure method and generates time-limited credentials automatically:
```toml
# TURN URIs that clients should connect to
turn_uris = [
"turn:coturn.example.com:3478?transport=udp",
"turn:coturn.example.com:3478?transport=tcp",
# Add this if you're using TURN-over-TLS (note the `turns:` prefix)
"turns:coturn.example.com:5349?transport=tcp"
"turn:coturn.example.com?transport=udp",
"turn:coturn.example.com?transport=tcp",
"turns:coturn.example.com?transport=udp",
"turns:coturn.example.com?transport=tcp"
]
# Shared secret for generating credentials (must match coturn's static-auth-secret)
@@ -133,18 +98,54 @@ # Optional: Read secret from a file instead (takes priority over turn_secret)
# turn_secret_file = "/etc/continuwuity/.turn_secret"
# TTL for generated credentials in seconds (default: 86400 = 24 hours)
turn_ttl = 10800
turn_ttl = 86400
```
Restart Continuwuity, and the new changes should now be applied.
:::tip Using TLS
The `turns:` URI prefix instructs clients to connect to TURN over TLS, which is highly recommended for security. Make sure you've configured TLS in your coturn server first.
:::
### Static Credentials (Alternative)
If you prefer static username/password credentials instead of shared secrets:
```toml
turn_uris = [
"turn:coturn.example.com?transport=udp",
"turn:coturn.example.com?transport=tcp"
]
turn_username = "your_username"
turn_password = "your_password"
```
:::warning
Static credentials are less secure than shared secrets because they don't expire and must be configured in coturn separately. It is strongly advised you use shared secret authentication.
:::
### Guest Access
By default, TURN credentials require client authentication. To allow unauthenticated access:
```toml
turn_allow_guests = true
```
:::caution
This is not recommended as it allows unauthenticated users to access your TURN server, potentially enabling abuse by bots. All major Matrix clients that support legacy calls *also* support authenticated TURN access.
:::
### Important Notes
- Replace `coturn.example.com` with your actual TURN server domain (the `realm` from coturn.conf)
- The `turn_secret` must match the `static-auth-secret` in your coturn configuration
- Restart or reload Continuwuity after making configuration changes
## Testing Your TURN Server
### Testing Credentials
Get an access token for your current login session. These can be found in your client's settings or obtained via [this website](https://timedout.uk/mxtoken.html).
Then, using that token, verify that Continuwuity is correctly serving TURN credentials to clients:
Verify that Continuwuity is correctly serving TURN credentials to clients:
```bash
curl "https://matrix.example.com/_matrix/client/r0/voip/turnServer" \
@@ -158,221 +159,56 @@ ### Testing Credentials
"username": "1752792167:@jade:example.com",
"password": "KjlDlawdPbU9mvP4bhdV/2c/h65=",
"uris": [
"turns:coturn.example.com:3478?transport=tcp",
"turn:coturn.example.com:3478?transport=udp",
"turn:coturn.example.com:5349?transport=tcp"
"turns:coturn.example.com?transport=udp",
"turns:coturn.example.com?transport=tcp",
"turn:coturn.example.com?transport=udp",
"turn:coturn.example.com?transport=tcp"
],
"ttl": 86400
}
```
:::note MSC4166 Compliance
If no TURN URIs are configured (`turn_uris` is empty), Continuwuity will return a 404 Not Found response, as specified in MSC4166.
:::
### Testing Connectivity
Open the [Trickle ICE][trickle-ice] testing page in a browser and then:
Use [Trickle ICE](https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/) to verify that the TURN credentials actually work:
1. Copy the URIs and credentials from the response above
2. Paste them into the Trickle ICE testing tool, and click on "Add server"
3. When finished adding all URIs and credentials, click "Gather candidates"
1. Copy the credentials from the response above
2. Paste them into the Trickle ICE testing tool
3. Click "Gather candidates"
4. Look for successful `relay` candidates in the results
If you see `relay` candidates in the results, your TURN/STUN server is working correctly! You should now be able to place and receive legacy calls.
[trickle-ice]: https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/
If you see relay candidates, your TURN server is working correctly!
## Troubleshooting
To gather debug logs while troubleshooting Coturn, add `verbose` to your `coturn.conf`. You can then view these logs with `docker-compose logs --follow coturn`.
### Clients can't connect to TURN server
### Errors with Trickle ICE
- Verify firewall rules allow the necessary ports (3478, 5349, and your media port range)
- Check that DNS resolves correctly for your TURN domain
- Ensure your `turn_secret` matches coturn's `static-auth-secret`
- Test with Trickle ICE to isolate the issue
- `code=701` - the TURN server is not reachable
- Verify firewall rules allow the necessary ports (3478, 5349, and your media port range)
- Verify via logs that coturn is exposed on the correct addresses and interfaces
- Check that DNS resolves correctly for your TURN domain
- `code=401` - unauthorized credentials
- Ensure your `turn_secret` matches coturn's `static-auth-secret`
- Ensure the credentials you obtained from the Testing steps has not expired yet. You can adjust `turn_ttl` in your Continuwuity configuration to increase this, or simply re-request a new one
- Wrong IP address advertised
- This may be caused by coturn not recognizing its public-facing IP correctly, due to particular network setups. You can configure `external-ip=<desired-public-ip>` to fix this issue.
### Port conflicts with LiveKit
### 404 when calling the turnServer endpoint
- Make sure coturn's `min-port` starts above LiveKit's `port_range_end` (default: 50200)
- Or adjust LiveKit's port range to avoid coturn's default range
This is the correct response when no TURN servers are configured, as per [MSC4166][msc4166]. Verify that your `turn_uris` is not empty in your Continuwuity config and try again.
### 404 when calling turnServer endpoint
[msc4166]: https://github.com/matrix-org/matrix-spec-proposals/pull/4166
- Verify that `turn_uris` is not empty in your Continuwuity config
- This behavior is correct per MSC4166 if no TURN URIs are configured
## Related Documentation
### Credentials expire too quickly
- Adjust the `turn_ttl` value in your Continuwuity configuration
- Default is 86400 seconds (24 hours)
### Related Documentation
- [MatrixRTC/LiveKit Setup](./livekit.mdx) - Configure group calling with LiveKit
- [Coturn GitHub][coturn] - Official coturn repository
- [`turnserver.conf`][turnserver-conf] - Coturn TURN SERVER configuration file with full options
- [Synapse TURN Guide][synapse-turn-guide] - TURN server guide for Synapse
- [Synapse Coturn Guide][synapse-coturn-guide] - Coturn-specific guide for Synapse, with important security recommendations
[synapse-turn-guide]: https://element-hq.github.io/synapse/latest/turn-howto.html
## Appendix
### Using Eturnal
If you instead prefer to use [eturnal][eturnal], you can refer to the guides below:
- [Community guidance][eturnal-continuwuity] on using eturnal with Legacy Calls, LiveKit calls, and more
- Synapse's [eturnal documentation][synapse-eturnal-guide]
[eturnal]: https://eturnal.net
[eturnal-continuwuity]: https://muoi.me/~stratself/articles/an-eturnal-to-rule-them-all/
[synapse-eturnal-guide]: https://element-hq.github.io/synapse/latest/setup/turn/eturnal.html
### TURNS-over-443
Normally, TURN would work on their default setups. However, there are situations where clients are in very restrictive networks that disallows non-standard ports and UDP. In these cases, a TURN-over-TLS server on port :443 could be employed to relay traffic for them.
However, port 443 is usually utilized by other HTTPS services. Therefore, one would need to **multiplex** both TURN HTTPS on these ports, and filter packets to them via **SNI routing**.
Below are examples to multiplex Coturn and [LiveKit](./livekit.mdx) on port 443, using [caddy-l4][caddy-l4] on the host system.
<details>
<summary>Caddyfile with TLS passthrough</summary>
This Caddyfile:
- Route `turn.example.com` to the TURNS port for Coturn without TLS termination, and
- Route `livekit.example.com` to the [LiveKit services](./livekit.mdx) with TLS termination by Caddy
Please note that all traffic from Coturn's perspective will be coming from caddy-l4's IP now.
```
{
servers {
listener_wrappers {
# intercept packets meant for the TURN domain first
# before forwarding other packets to "normal" HTTP listeners
layer4 {
@turn tls sni turn.example.com
route @turn {
proxy 127.0.0.1:5349 # forward to normal TURNS port
}
}
tls
}
}
}
# livekit stuff
https://livekit.example.com {
@lk-jwt-service path /healthz /get_token /sfu/get
route @lk-jwt-service {
reverse_proxy 127.0.0.1:8081
}
reverse_proxy http://127.0.0.1:7880
}
```
</details>
<details>
<summary>Caddyfile with TLS termination and PROXY protocol forwarding</summary>
This setup:
- Terminates TLS for `turn.example.com`,
- Tag the decrypted packets with PROXY protocol, and route it to coturn's `tcp-proxy-port`
- Route `livekit.example.com` to the [LiveKit services](./livekit.mdx) with TLS termination by Caddy
It allows coturn to see real client IPs, but the TLS handling is done on Caddy's side.
First, enable coturn's PROXY-protocol accepting port by adding this:
```ini
# in coturn.conf
tcp-proxy-port=5555
```
Then, in the Caddyfile:
```
{
servers {
listener_wrappers {
# intercept packets meant for the TURN domain first
# before forwarding other packets to "normal" HTTP listeners
layer4 {
@turn tlssni turn.example.com
route @turn {
tls # terminate TLS for the turn.example.com packets
proxy {
# then, proxy them to tcp-proxy-port and enable PROXY protocol version 2
upstream 127.0.0.1:5555
proxy_protocol v2
}
}
}
tls
}
}
}
# livekit stuff
https://livekit.example.com {
@lk-jwt-service path /healthz /get_token /sfu/get
route @lk-jwt-service {
reverse_proxy 127.0.0.1:8081
}
reverse_proxy http://127.0.0.1:7880
}
# placeholder block to obtain certs for turn.example.com
https://turn.example.com {
respond "OK" 200
}
```
**Note**: the setup will disable TURN-over-TLS functionality on port 5349/tcp.
</details>
After configuration and spin-up, the destination `turns:turn.example.com:443?transport=tcp` should work with Trickle ICE tests. You can now advertise it as an address in your `turn_uris` as well as [LiveKit](./livekit#additional-turns-over-443-configuration).
[caddy-l4]: https://github.com/mholt/caddy-l4
### Unsafe TURN setups (not recommended)
<details>
<summary>Using static credentials</summary>
:::caution
Static credentials are less secure than shared secrets because they don't expire and must be configured in coturn separately. It is strongly advised you use [shared secret authentication](#2-configuration).
:::
If you prefer static username/password credentials instead of shared secrets:
```ini
# In coturn.conf
# Comment out options to use a secret
# use-auth-secret
# static-auth-secret=<a secret key>
# Define a username-password pair
user=your_username:your_password
```
```toml
# In continuwuity.toml
turn_uris = [
"turn:coturn.example.com?transport=udp",
"turn:coturn.example.com?transport=tcp"
]
turn_username = "your_username"
turn_password = "your_password"
```
</details>
- [Coturn GitHub](https://github.com/coturn/coturn) - Official coturn repository
- [Synapse TURN Guide](https://element-hq.github.io/synapse/latest/turn-howto.html) - Additional security recommendations
+6 -29
View File
@@ -9,7 +9,7 @@ ### Choose an image
| Image | Notes |
| ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| [https://forgejo.ellis.link/continuwuation/continuwuity:**latest**][latest] | Latest tagged release. (recommended) |
| [https://forgejo.ellis.link/continuwuation/continuwuity:**main**][main] | Latest `main` branch commit. Built with [CI][release-image] |
| [https://forgejo.ellis.link/continuwuation/continuwuity:**main**][main] | Latest `main` branch commit. |
| [https://forgejo.ellis.link/continuwuation/continuwuity:**latest-maxperf**][latest-maxperf] | Latest tagged release, [performance optimised version](./generic.mdx#performance-optimised-builds). |
| [https://forgejo.ellis.link/continuwuation/continuwuity:**main-maxperf**][main-maxperf] | Latest `main` branch commit, [performance optimised version](./generic.mdx#performance-optimised-builds). |
@@ -17,7 +17,6 @@ ### Choose an image
[main]: https://forgejo.ellis.link/continuwuation/-/packages/container/continuwuity/main
[latest-maxperf]: https://forgejo.ellis.link/continuwuation/-/packages/container/continuwuity/latest-maxperf
[main-maxperf]: https://forgejo.ellis.link/continuwuation/-/packages/container/continuwuity/main-maxperf
[release-image]: https://forgejo.ellis.link/continuwuation/continuwuity/actions/?workflow=release-image.yml
If you want a specific version or commit hash, you can browse for them [here][oci-all-versions].
@@ -26,11 +25,13 @@ ### Choose an image
- `ghcr.io/continuwuity/continuwuity` ([Github Registry][ghcr-io])
- `docker.io/jadedblueeyes/continuwuity` ([Docker Hub][docker-hub])
- `registry.gitlab.com/continuwuity/continuwuity` ([Gitlab Registry][gitlab-registry])
- `git.nexy7574.co.uk/mirrored/continuwuity` ([Nexy's forge][nexy-forge]. Releases only, no `main` tags)
[oci-all-versions]: https://forgejo.ellis.link/continuwuation/-/packages/container/continuwuity/versions
[ghcr-io]: https://github.com/continuwuity/continuwuity/pkgs/container/continuwuity/versions?filters%5Bversion_type%5D=tagged
[docker-hub]: https://hub.docker.com/r/jadedblueeyes/continuwuity/
[gitlab-registry]: https://gitlab.com/continuwuity/continuwuity/container_registry/8871720
[nexy-forge]: https://git.nexy7574.co.uk/mirrored/-/packages/container/continuwuity/versions
### Prerequisites
@@ -62,8 +63,8 @@ ### Choose Your Reverse Proxy
These examples include reverse proxy configurations for Matrix federation, which will route your Matrix domain (and optionally .well-known paths) to Continuwuity.
:::important Docker DNS Performance
Docker's default DNS resolver is known to [**cause timeout issues**](../troubleshooting#dns-issues) for Matrix federation. To bypass it and use a more performant resolver, mount a custom `/etc/resolv.conf` config file into the Continuwuity container:
:::note Docker DNS Performance
Docker's default DNS resolver are known to [cause timeout issues](../troubleshooting#dns-issues) for Matrix federation. To bypass it and use a more performant resolver, mount a custom `/etc/resolv.conf` config file into the Continuwuity container.
```yaml title='docker-compose.yml'
services:
@@ -84,19 +85,8 @@ ### Choose Your Reverse Proxy
#### Caddy (using Caddyfile)
<details>
<summary>docker-compose.with-caddy.yml ([view raw](/deploying/docker-compose.with-caddy.yml))</summary>
Create a Caddyfile with the following content:
```
https://example.com:443, https://example.com:8448 {
reverse_proxy http://homeserver:8008
}
```
Then, for the docker-compose:
```yaml file="../public/deploying/docker-compose.with-caddy.yml"
```
@@ -174,7 +164,7 @@ ### Starting Your Server
4. Check your server logs for a registration token:
```bash
docker compose logs continuwuity 2>&1
docker-compose logs continuwuity 2>&1
```
You'll see output as below.
@@ -197,19 +187,6 @@ ## Testing
Check your container logs using `docker-compose logs --follow` to debug any issues. See the [Troubleshooting](../troubleshooting.mdx) page for common errors and how to fix them.
## Updating
To update to a new version of Continuwuity, use the following commands:
```bash
# stop the services in docker-compose.yaml
docker compose down
# pull latest images for the services in docker-compose.yaml
docker compose pull
# spin up the containers again
docker compose up -d
```
## Other deployment methods
### Docker - Quick Run
+37 -33
View File
@@ -29,12 +29,19 @@ ### Prebuilt binary
#### Performance-optimised builds
Continuwuity provides `*-maxperf` tagged binaries, which uses the `release-max-perf` build profile with [link-time optimisation (LTO)][lto-rust-docs]. For the x86_64 architecture, these binaries specifically target the Haswell architecture (hence the `-haswell-` name extension), and enables hardware-accelerated CRC32 checksumming in
RocksDB which significantly improves database performance. If you're using an x86_64 system with CPUs from the last ~15 years, consider using these images for best performance.
For x86_64 systems with CPUs from the last ~15 years, use the
`-haswell-` optimised binaries for best performance. These
binaries enable hardware-accelerated CRC32 checksumming in
RocksDB, which significantly improves database performance.
The haswell instruction set provides an excellent balance of
compatibility and speed.
If you're using Docker instead, equivalent performance-optimised
images are available with the `-maxperf` suffix (e.g.
`forgejo.ellis.link/continuwuation/continuwuity:latest-maxperf`).
These images use the `release-max-perf` build profile with
[link-time optimisation (LTO)][lto-rust-docs]
and, for amd64, target the haswell CPU architecture.
[lto-rust-docs]: https://doc.rust-lang.org/cargo/reference/profiles.html#lto
@@ -52,7 +59,28 @@ ### Nix
### Compiling
Alternatively, you may compile the binary yourself. See the [Appendix subsection](#compiling-continuwuity) for more details.
Alternatively, you may compile the binary yourself.
#### Using Docker
See the [Building Docker Images](../development/index.mdx#building-docker-images)
section in the development documentation.
#### Manual
##### Dependencies
- Run `nix develop` to get a devshell with everything you need
- Or, install the following:
- (On linux) `liburing-dev` on the compiling machine, and `liburing` on the target host
- (On linux) `pkg-config` on the compiling machine to allow finding `liburing`
- A C++ compiler and (on linux) `libclang` for RocksDB
##### Build
You can now build Continuwuity using `cargo build --release`.
Continuwuity supports various optional features that can be enabled during compilation. Please see the Cargo.toml file for a comprehensive list, or ask in our rooms.
## Adding a Continuwuity user
@@ -151,11 +179,12 @@ ### Caddy
Caddy is the recommended reverse proxy as it is easy to use, has good defaults,
and handle TLS certificates automatically. After installing Caddy via your preferred
method, add the following content to your `/etc/caddy/Caddyfile` file
method, create `/etc/caddy/conf.d/conduwuit_caddyfile` and enter the following
(substitute `example.com` with your actual server name):
```
example.com, example.com:8448 {
# TCP reverse_proxy
reverse_proxy 127.0.0.1:8008
}
```
@@ -178,7 +207,7 @@ ### Other Reverse Proxies
- `/_matrix/client` - core Client-Server APIs. These should be available on port :443
- `/_continuwuity/` - Continuwuity's integrated account management interface and authentication path for OAuth-compatible clients
- `/_continuwuity/` - Continuwuity's integrated account management interface for OAuth-compatible clients
You can optionally reverse proxy the following individual routes:
@@ -186,7 +215,7 @@ ### Other Reverse Proxies
Continuwuity to perform delegation (see the `[global.well_known]` config section)
- `/.well-known/matrix/support` if using Continuwuity to send the homeserver admin
[contact and support page][well-known-support]
- `/` and `/_continuwuity/resources` if you would like to see the Continuwuity landing page
- `/` and `/_continuwuity/logo.svg` if you would like to see the Continuwuity landing page
Refer to the respective software's documentation and online guides on how to do so.
@@ -257,10 +286,10 @@ ## How do I know it works?
As a quick health check, you can also use these cURL commands:
```bash
curl https://example.com/_continuwuity/server_version
curl https://example.com/_conduwuit/server_version
# If using port 8448
curl https://example.com:8448/_continuwuity/server_version
curl https://example.com:8448/_conduwuit/server_version
# If federation is enabled
curl https://example.com:8448/_matrix/federation/v1/version
@@ -276,28 +305,3 @@ ## What's next?
- For Audio/Video call functionality see the [**Calls**](../calls.md) page.
- Consult the [Maintenance](../maintenance.mdx) page for guidance on maintaining your homeserver.
- If you want to set up an appservice, take a look at the [**Appservice Guide**](../appservices.md).
## Appendix
### Compiling Continuwuity
#### Using Docker
See the [Building Docker Images](../development/index.mdx#building-docker-images)
section in the development documentation.
#### Manual
##### DEPENDENCIES
- Run `nix develop` to get a devshell with everything you need
- Or, install the following:
- (On linux) `liburing-dev` on the compiling machine, and `liburing` on the target host
- (On linux) `pkg-config` on the compiling machine to allow finding `liburing`
- A C++ compiler and (on linux) `libclang` for RocksDB
##### BUILD
You can now build Continuwuity using `cargo build --release`.
Continuwuity supports various optional features that can be enabled during compilation. Please see the Cargo.toml file for a comprehensive list, or ask in our rooms.
+64 -82
View File
@@ -53,19 +53,12 @@ # Defaults to members of the admin room if unset
After doing the steps above, Continuwuity will serve these 3 JSON files:
- `/.well-known/matrix/client`: for Client-Server discovery
- `/.well-known/matrix/server`: for Server-Server (federation) discovery
- `/.well-known/matrix/support`: admin contact details (strongly recommended).
- By default, this include members of the admin room.
- `/.well-known/matrix/support`: admin contact details (strongly recommended to have)
To enable full discovery, you will need to reverse proxy these paths from the base domain back to Continuwuity.
## Serving well-known files
You can either reverse proxy the well-known paths to Continuwuity, or serve static JSON files yourself.
### Option 1: Reverse proxying well-known files to Continuwuity
## Reverse proxying well-known files to Continuwuity
<details>
@@ -103,7 +96,7 @@ ### Option 1: Reverse proxying well-known files to Continuwuity
For **Docker** users, consult the compose files in the [Appendix section](#docker-compose-examples).
After applying these changes, restart Continuwuity and your reverse proxy. Visit these routes and check that the responses match the examples below:
After applying these changes, restart Continuwuity and your reverse proxy.Visit these routes and check that the responses match the examples below:
<details open>
@@ -129,12 +122,12 @@ ### Option 1: Reverse proxying well-known files to Continuwuity
</details>
### Option 2: Manually serving static files for well-known
### Serving well-known files manually
Instead of reverse proxying well-known URIs, you can serve these files directly as static JSON that match the ones above. This is useful if your base domain points to a different physical server, and reverse proxying isn't feasible.
:::important Important: always configure [global.well_known]
Even if you choose to serve the well-known files manually, you **must** still set the `global.well_known.client` configuration option to the domain you're delegating to. Continuwuity needs to know the domain it runs on in order to redirect clients properly to email, OAuth, and account management endpoints.
:::warning
Even if you choose to serve the well-known files manually, if you are using delegation at all, you **must** still set the `global.well_known.client` configuration option to the domain you're delegating to. Continuwuity needs to know the domain it runs on for OAuth-compatible clients to work correctly.
:::
<details>
@@ -197,79 +190,16 @@ ### Issues with alternative setups
In these scenarios, further configurations would be needed. Refer to the [Related Documentation](#related-documentation) section for resolution steps and see how they could apply to your use case.
## Related Documentation
---
### Matrix Specification
See the following sections of the Matrix Specification for more details on client and server resolution mechanisms:
- [Server-to-Server resolution](https://spec.matrix.org/latest/server-server-api/#resolving-server-names)
- [Client-to-Server resolution](https://spec.matrix.org/latest/client-server-api/#server-discovery)
- [MSC1929: Homeserver Admin Contact and Support page](https://github.com/matrix-org/matrix-spec-proposals/pull/1929)
### Community guides
- [Federation Setup guide by MTRNord](https://connectivity-tester.mtrnord.blog/docs/getting-started/federation-setup)
## Appendix
### Docker Compose examples
The following Compose files are taken from [Docker deployment instructions](../deploying/docker.mdx) and reconfigured to support split-domain delegation. Note the updated `CONTINUWUITY_WELL_KNOWN` variable and relevant changes in reverse proxy rules.
<details>
<summary>Caddy (using Caddyfile) - delegated.docker-compose.with-caddy.yml ([view raw](/advanced/delegated.docker-compose.with-caddy.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.with-caddy.yml"
```
```txt title="Caddyfile"
https://matrix.example.com:443 {
reverse_proxy http://homeserver:8008
}
https://example.com:443 {
reverse_proxy /.well-known/matrix* http://homeserver:8008
}
```
</details>
<details>
<summary>Caddy (using labels) - delegated.docker-compose.with-caddy-labels.yml ([view raw](/advanced/delegated.docker-compose.with-caddy-labels.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.with-caddy-labels.yml"
```
</details>
<details>
<summary>Traefik (for existing setup) - delegated.docker-compose.for-traefik.yml ([view raw](/advanced/delegated.docker-compose.for-traefik.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.for-traefik.yml"
```
</details>
<details>
<summary>Traefik included - delegated.docker-compose.with-traefik.yml ([view raw](/advanced/delegated.docker-compose.with-traefik.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.with-traefik.yml"
```
</details>
### Using SRV records (not recommended)
## Using SRV records (not recommended)
:::warning
The following methods use DNS SRV records, and are **not recommended** due to increased complexity with few benefits. Additionally, they only work for federation traffic.
If you have already set up well-known delegation as above, you can safely skip this part.
The following methods are **not recommended** due to increased complexity with little benefits. If you have already set up `.well-known` delegation as above, you can safely skip this part.
:::
The following methods uses SRV DNS records and only work with federation traffic. They are only included for completeness.
<details>
<summary>Using only SRV records</summary>
@@ -311,7 +241,7 @@ ### Using SRV records (not recommended)
<details>
<summary>Using SRV records as a fallback for well-known delegation</summary>
<summary>Using SRV records as a fallback for .well-known delegation</summary>
Assume your delegation is as below:
@@ -333,3 +263,55 @@ ### Using SRV records (not recommended)
On the target's IP at port 443, you'll need to provide a valid route and cert for `example.com`.
</details>
---
## Related Documentation
See the following Matrix Specs for full details on client/server resolution mechanisms:
- [Server-to-Server resolution](https://spec.matrix.org/v1.17/server-server-api/#resolving-server-names) (see this for more information on SRV records)
- [Client-to-Server resolution](https://spec.matrix.org/v1.17/client-server-api/#server-discovery)
- [MSC1929: Homeserver Admin Contact and Support page](https://github.com/matrix-org/matrix-spec-proposals/pull/1929)
## Appendix
### Docker Compose examples
The following Compose files are taken from [Docker instructions](../deploying/docker.mdx) and reconfigured to support split-domain delegation. Note the updated `CONTINUWUITY_WELL_KNOWN` variable and relevant changes in reverse proxy rules.
<details>
<summary>Caddy (using Caddyfile) - delegated.docker-compose.with-caddy.yml ([view raw](/advanced/delegated.docker-compose.with-caddy.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.with-caddy.yml"
```
</details>
<details>
<summary>Caddy (using labels) - delegated.docker-compose.with-caddy-labels.yml ([view raw](/advanced/delegated.docker-compose.with-caddy-labels.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.with-caddy-labels.yml"
```
</details>
<details>
<summary>Traefik (for existing setup) - delegated.docker-compose.for-traefik.yml ([view raw](/advanced/delegated.docker-compose.for-traefik.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.for-traefik.yml"
```
</details>
<details>
<summary>Traefik included - delegated.docker-compose.with-traefik.yml ([view raw](/advanced/delegated.docker-compose.with-traefik.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.with-traefik.yml"
```
</details>
+18 -55
View File
@@ -8,7 +8,7 @@ # DNS Tuning (recommended)
## Overview
For generic deployments, install your resolver of choice and configure your host system's `/etc/resolv.conf` to point to it. The resolver should ideally reside on the same host as Continuwuity.
For generic deployments, install your resolver of choice and configure `/etc/resolv.conf` to point to it. The resolver should ideally reside on the same host as Continuwuity.
```txt title="/etc/resolv.conf"
nameserver 127.0.0.1
@@ -18,7 +18,7 @@ ## Overview
### For Docker users
By default, Docker bridge networks uses a poorly performing resolver to intercept and respond to container hostnames. **This resolver should also be avoided**. Instead, mount a custom `/etc/resolv.conf` file into the container, and hardcode a resolver address to bypass Docker's.
Docker bridge networks uses a non-performant resolver to intercept and respond to container hostnames, and **this should also be avoided**. Instead, mount a custom `/etc/resolv.conf` file into the container, and hardcode a resolver address to bypass Docker's.
It is recommended to run a dedicated resolver container for Continuwuity, as to separate from the host's resolver setup. To do this, create a custom bridge network and IP range, and explicitly define an IP address for the resolver container.
@@ -27,28 +27,23 @@ ### For Docker users
```yaml title="docker-compose.yml"
networks:
# re-use the `proxy` network, as shown in the Docker deployment docs
# (https://continuwuity.org/deploying/docker#choose-your-reverse-proxy)
# and configure it with a custom subnet
proxy:
matrix_net:
ipam:
driver: default
config:
- subnet: "10.10.10.0/24"
services:
homeserver:
# ...
volume:
- ./continuwuity-resolv.conf:/etc/resolv.conf:ro
networks:
- proxy
homeserver:
# ...
volume:
- ./continuwuity-resolv.conf:/etc/resolv.conf:ro
unbound:
# ...
networks:
proxy:
ipv4_address: 10.10.10.20
unbound:
# ...
networks:
matrix_net:
ipv4_address: 10.10.10.20
```
```txt title="continuwuity-resolv.conf"
@@ -57,41 +52,9 @@ # and configure it with a custom subnet
</details>
:::warning Breaking resolution with container hostnames
After you mount a custom `/etc/resolv.conf`, you won't be able to connect to other containers using their hostnames, such as for [appservices](../appservices.mdx) in the same Docker network. To work around this, force your appservice to use a static IP address, and refer to its static IP during registration.
<details>
<summary>Example Docker deployment with an appservice</summary>
```yaml title="docker-compose.yml"
# ... other parts of compose file ...
appservice:
# ...
networks:
proxy:
ipv4_address: 10.10.10.30
```
~~~txt
!admin appservices register
```
id: appservice-name
url: http://10.10.10.30:29318
# rest of the registration file
```
~~~
</details>
:::
### For IPv4-only users
If you don't have IPv6 connectivity, change `ip_lookup_strategy` to `1` in Continuwuity's configuration in order to onlyresolve IPv4 addresses and remove unnecessary IPv6 queries.
If you don't have IPv6 connectivity, changing `ip_lookup_strategy` to only resolve for IPv4 will reduce unnecessary AAAA queries.
```toml title="continuwuity.toml"
[global]
@@ -109,13 +72,13 @@ ## Unbound
- Increase `rrset-cache-size` and `msg-cache-size` to something much higher than the default `4M`, such as `64M`.
- Increase `discard-timeout` to something like `4800` to wait longer for upstream resolvers, as recursion can take a long time to respond to some domains. Continuwuity defaults to `dns_timeout = 10` seconds, so dropping requests early would lead to unnecessary retries and/or failures.
- Increase `discard-timeout` to something like `4800` to wait longer for upstream resolvers, as recursion can take a long time to respond to some domains. Continuwuity default to `dns_timeout = 10` seconds, so dropping requests early would lead to unnecessary retries and/or failures.
### Using a forwarder (optional)
### Recursion versus forwarding
Unbound employs **recursive resolution** by default, contacting many nameservers around the world in the process. While this is generally viable for most users, sometimes these recursive queries can be too slow to fully resolve. As an alternative, you may consider **forwarding** your queries to public resolvers, and benefit from faster responses from their caches.
Unbound by default employs **recursive resolution** and contacts many servers around the world. While this allows updated and authoritative answers and are generally viable for most users, sometimes these recursive queries can be too slow to fully resolve. As an alternative, you can consider **forwarding** your queries to public resolvers, and benefit from faster responses from their CDNs.
However, do note that most popular upstreams (such as Google DNS or Quad9) employ IP ratelimiting, so a generous Unbound cache is still needed to avoid making too many queries.
Do note that most popular upstreams (such as Google DNS or Quad9) employ IP ratelimiting, so a generous cache is still needed to avoid making too many queries.
If you want to use forwarders, configure it as follows:
@@ -181,7 +144,7 @@ ### Technitium DNS
## Testing
As a rough stress test, you can run `!admin query resolver flush-cache -a` or `!admin server clear-caches` to clear your destinations cache - this will then trigger a netburst of DNS queries. If your resolver can handle this load without issue, then it should be ready for regular Continuwuity activity.
As a rough stress test, you can run `!admin query resolver flush-cache -a` or `!admin server clear-caches` to trigger a netburst of DNS queries. If your resolver can handle these loads without problem, then it should be ready for regular Continuwuity activity.
To test connectivity against a specific server, use `!admin debug ping <SERVER_NAME>` and `!admin debug resolve-true-destination <SERVER_NAME>`.
+1 -3
View File
@@ -6,7 +6,7 @@ # Performance tuning
## DNS tuning (recommended)
DNS tuning is important to ensure a smooth experience for federated servers. Please see the dedicated [DNS tuning guide](./dns.mdx).
Please see the dedicated [DNS tuning guide](./dns.mdx).
## Cache capacities
@@ -115,8 +115,6 @@ ### Tuning your trusted servers
:::info Vet your trusted servers!
Trusted servers are your first point of contact when obtaining public keys from other servers, and they could theoretically impersonate other servers and cause significant harm to your deployment. Please thoroughly verify your trusted servers' credibility before adding them to your configuration.
If you need suggestions for trusted servers, ask in the Continuwuity main room.
:::
Trusted servers are queried sequentially in the order they are listed. If you have multiple trusted servers configured, put the faster ones first:
+35 -48
View File
@@ -42,16 +42,12 @@ ## Database (RocksDB)
creating unnecessary I/O amplification. RocksDB is built with io_uring support
via liburing for improved read performance.
RocksDB troubleshooting can be found [in the RocksDB section of troubleshooting](./troubleshooting.mdx#rocksdb--database-issues).
RocksDB troubleshooting can be found [in the RocksDB section of troubleshooting](troubleshooting.md).
### Compression
Some RocksDB settings can be adjusted, such as the chosen compression method and level.
See the RocksDB section in the [example config](./reference/config.mdx), and the
[database compression section](./guides/performance.mdx#tuning-database-compression)
in the performance tuning documentation for more.
#### Caveats for btrfs users
Some RocksDB settings can be adjusted such as the compression method chosen. See
the RocksDB section in the [example config](./reference/config.mdx).
btrfs users have reported that database compression does not need to be disabled
on Continuwuity as the filesystem already does not attempt to compress. This can be
@@ -61,12 +57,10 @@ #### Caveats for btrfs users
unbuffered Direct IO inoperable, significantly slowing down read and write
performance. See [the Btrfs docs](https://btrfs.readthedocs.io/en/latest/Compression.html#compatibility).
:::important
Compression is done using the COW mechanism so its incompatible with
`nodatacow`. Direct IO read works on compressed files but will fall back to
buffered writes and leads to no compression even if force compression is set.
Currently `nodatasum` and compression dont work together.
:::
> Compression is done using the COW mechanism so its incompatible with
> nodatacow. Direct IO read works on compressed files but will fall back to
> buffered writes and leads to no compression even if force compression is set.
> Currently nodatasum and compression dont work together.
### Files in database
@@ -84,47 +78,37 @@ ### Files in database
## Backups
### Database online backup
f you'd like to run an online backup of your database - that is, a backup with
no downtime - check the [`!admin server` command](./reference/admin/server.md)
for the required commands and the `database_backup_path` config options in
the example config.
Please note that the format of the database backup is not the exact same as the
format of offline backups. This is unfortunately a bad design choice by Facebook
as we are using the database backup engine API from RocksDB, however the data
is still there and can still be joined together.
Currently only RocksDB supports online backups. If you'd like to backup your
database online without any downtime, see the `!admin server` command for the
backup commands and the `database_backup_path` config options in the example
config. Please note that the format of the database backup is not the exact
same. This is unfortunately a bad design choice by Facebook as we are using the
database backup engine API from RocksDB, however the data is still there and can
still be joined together.
To restore a backup from an online RocksDB backup:
- Shutdown Continuwuity
- Create a new directory for merging together the data
- In the online backup created, copy all `.sst` files in
- shutdown Continuwuity
- create a new directory for merging together the data
- in the online backup created, copy all `.sst` files in
`$DATABASE_BACKUP_PATH/shared_checksum` to your new directory
- trim all the strings so instead of `######_sxxxxxxxxx.sst`, it reads
`######.sst`. A way of doing this with sed and bash is `for file in *.sst; do mv
"$file" "$(echo "$file" | sed 's/_s.*/.sst/')"; done`
- Copy all the files in `$DATABASE_BACKUP_PATH/private/1` (or the latest backup number
- copy all the files in `$DATABASE_BACKUP_PATH/1` (or the latest backup number
if you have multiple) to your new directory
- Set your `database_path` config option to your new directory, or replace your
- set your `database_path` config option to your new directory, or replace your
old one with the new one you crafted
- Start up Continuwuity again and it should open as normal
Note: You can verify the necessary files to copy by comparing them with contents in the `$DATABASE_BACKUP_PATH/meta/1` (or latest backup number) file.
### Database offline backup
- start up Continuwuity again and it should open as normal
If you'd like to do an offline backup, shutdown Continuwuity and copy your
`database_path` directory elsewhere. This can be restored with no modifications
needed.
### Media backup
Backing up media is also just copying the `media/` directory from your database
directory.
Media is stored in the `media/` subdirectory from your database directory.
Backing up media is also just copying that subdirectory.
## Media management
## Media
Media still needs various work, however Continuwuity implements media deletion via:
@@ -133,16 +117,19 @@ ## Media management
- Delete list of MXC URIs
- Delete remote media in the past `N` seconds/minutes via filesystem metadata on
the file created time (`btime`) or file modified time (`mtime`)
- Delete all media from a local user
- Delete all media from a remote server
- Delete cached URL previews
See the [`!admin media` commands](./reference/admin/media.md) for further information.
All media in Continuwuity is stored at `$DATABASE_DIR/media`.
See the `!admin media` command for further information. All media in Continuwuity
is stored at `$DATABASE_DIR/media`. This will be configurable soon.
While Continuwuity does not implement built-in S3 support, using an S3 filesystem
mount on the `media/` path will work. Continuwuity also sends a `Cache-Control`
header of 1 year with the `immutable` directive for all media requests
(download and thumbnail) to reduce unnecessary bandwidth and load.
If you are finding yourself needing extensive granular control over media, we
recommend looking into [Matrix Media
Repo](https://github.com/t2bot/matrix-media-repo). Continuwuity intends to
implement various utilities for media, but MMR is dedicated to extensive media
management.
Built-in S3 support is also planned, but for now using a "S3 filesystem" on
`media/` works. Continuwuity also sends a `Cache-Control` header of 1 year and
immutable for all media requests (download and thumbnail) to reduce unnecessary
media requests from browsers, reduce bandwidth usage, and reduce load.
[rocksdb-compaction]: https://github.com/facebook/rocksdb/wiki/Compaction
@@ -6,10 +6,10 @@
"message": "Welcome to Continuwuity! Important announcements about the project will appear here."
},
{
"id": 17,
"id": 16,
"mention_room": true,
"date": "2026-07-30",
"message": "[Continuwuity 26.7.2](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v26.7.2) (and [v26.7.1](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v26.7.1)) have been released! v26.7.1 includes several new bug fixes and features, such as the OAuth2 device authorization flow, and a fix for the \"empty room\" bug (check the release notes!). v26.7.2 is a hotfix that fixes a low severity vulnerability in simplified sliding sync (particularly relevant to multi-user homeservers) and two regressions. It is recommended every deployment upgrades as soon as possible. Join the [announcements room](https://matrix.to/#/#announcements:continuwuity.org) for more prompt announcements regarding updates!"
"date": "2026-07-13",
"message": "[Continuwuity 26.6.2](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v26.6.1) has just been released! This release fixes a severe bug with OIDC that could cause users' accounts to be flagged as deactivated. If you use OIDC, please update as soon as possible."
}
]
}
@@ -1,55 +1,54 @@
# Continuwuity - With Caddy Labels
services:
caddy:
# This compose file uses caddy-docker-proxy as the reverse proxy for Continuwuity!
# For more info, visit https://github.com/lucaslorentz/caddy-docker-proxy
image: "docker.io/lucaslorentz/caddy-docker-proxy:ci-alpine"
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=caddy
networks:
- proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
restart: unless-stopped
labels:
caddy: example.com
caddy.reverse_proxy: /.well-known/matrix/* homeserver:8008
caddy:
# This compose file uses caddy-docker-proxy as the reverse proxy for Continuwuity!
# For more info, visit https://github.com/lucaslorentz/caddy-docker-proxy
image: "docker.io/lucaslorentz/caddy-docker-proxy:ci-alpine"
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=caddy
networks:
- caddy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
restart: unless-stopped
labels:
caddy: example.com
caddy.reverse_proxy: /.well-known/matrix/* homeserver:8008
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
# - ./continuwuity.toml:/etc/continuwuity.toml
environment:
CONTINUWUITY_SERVER_NAME: example.com # EDIT THIS
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
# CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
#- ./continuwuity.toml:/etc/continuwuity.toml
environment:
CONTINUWUITY_SERVER_NAME: example.com # EDIT THIS
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
#CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
# Serve .well-known files to tell others to reach Continuwuity on port :443
CONTINUWUITY_WELL_KNOWN: |
{
client=https://matrix.example.com,
server=matrix.example.com:443
}
networks:
- proxy
labels:
caddy: matrix.example.com
caddy.reverse_proxy: "{{upstreams 8008}}"
# Serve .well-known files to tell others to reach Continuwuity on port :443
CONTINUWUITY_WELL_KNOWN: |
{
client=https://matrix.example.com,
server=matrix.example.com:443
}
networks:
- caddy
labels:
caddy: matrix.example.com
caddy.reverse_proxy: "{{upstreams 8008}}"
volumes:
db:
networks:
proxy:
caddy:
@@ -1,46 +1,57 @@
# Continuwuity - Using Caddy Docker Image
services:
caddy:
image: "docker.io/caddy:latest"
ports:
- 80:80
- 443:443
networks:
- caddy
volumes:
- ./data:/data
# mount your created Caddyfile into the container
- ./Caddyfile:/etc/caddy/Caddyfile
restart: unless-stopped
caddy:
image: "docker.io/caddy:latest"
ports:
- 80:80
- 443:443
networks:
- caddy
volumes:
- ./data:/data
restart: unless-stopped
configs:
- source: Caddyfile
target: /etc/caddy/Caddyfile
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
# - ./continuwuity.toml:/etc/continuwuity.toml
environment:
CONTINUWUITY_SERVER_NAME: example.com
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
# CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
#- ./continuwuity.toml:/etc/continuwuity.toml
environment:
CONTINUWUITY_SERVER_NAME: example.com
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
#CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
## Serve .well-known files to tell others to reach Continuwuity on port :443
CONTINUWUITY_WELL_KNOWN: |
{
client=https://example.com,
server=example.com:443
}
## Serve .well-known files to tell others to reach Continuwuity on port :443
CONTINUWUITY_WELL_KNOWN: |
{
client=https://matrix.example.com,
server=matrix.example.com:443
}
networks:
- proxy
networks:
- caddy
networks:
proxy:
caddy:
volumes:
db:
configs:
Caddyfile:
content: |
https://matrix.example.com:443 {
reverse_proxy http://homeserver:8008
}
https://example.com:443 {
reverse_proxy /.well-known/matrix* http://homeserver:8008
}
@@ -1,52 +1,51 @@
# Continuwuity - With Caddy Labels
services:
caddy:
# This compose file uses caddy-docker-proxy as the reverse proxy for Continuwuity!
# For more info, visit https://github.com/lucaslorentz/caddy-docker-proxy
image: "docker.io/lucaslorentz/caddy-docker-proxy:ci-alpine"
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=caddy
networks:
- proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
restart: unless-stopped
caddy:
# This compose file uses caddy-docker-proxy as the reverse proxy for Continuwuity!
# For more info, visit https://github.com/lucaslorentz/caddy-docker-proxy
image: "docker.io/lucaslorentz/caddy-docker-proxy:ci-alpine"
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=caddy
networks:
- caddy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
restart: unless-stopped
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
# - ./continuwuity.toml:/etc/continuwuity.toml
environment:
CONTINUWUITY_SERVER_NAME: example.com
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
# CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
#- ./continuwuity.toml:/etc/continuwuity.toml
environment:
CONTINUWUITY_SERVER_NAME: example.com
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
#CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
# Serve .well-known files to tell others to reach Continuwuity on port :443
CONTINUWUITY_WELL_KNOWN: |
{
client=https://example.com,
server=example.com:443
}
networks:
- proxy
labels:
caddy: example.com
caddy.reverse_proxy: "{{upstreams 8008}}"
# Serve .well-known files to tell others to reach Continuwuity on port :443
CONTINUWUITY_WELL_KNOWN: |
{
client=https://example.com,
server=example.com:443
}
networks:
- caddy
labels:
caddy: example.com
caddy.reverse_proxy: "{{upstreams 8008}}"
volumes:
db:
db:
networks:
proxy:
caddy:
@@ -1,48 +1,56 @@
# Continuwuity - Using Caddy Docker Image
services:
caddy:
image: "docker.io/caddy:latest"
ports:
- 80:80
- 443:443
- 8448:8448
networks:
- proxy
volumes:
- ./data:/data
# mount your created Caddyfile into the container
- ./Caddyfile:/etc/caddy/Caddyfile
restart: unless-stopped
caddy:
image: "docker.io/caddy:latest"
ports:
- 80:80
- 443:443
- 8448:8448
networks:
- caddy
volumes:
- ./data:/data
restart: unless-stopped
configs:
- source: Caddyfile
target: /etc/caddy/Caddyfile
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
# - ./continuwuity.toml:/etc/continuwuity.toml
environment:
CONTINUWUITY_SERVER_NAME: example.com
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
# CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
#- ./continuwuity.toml:/etc/continuwuity.toml
environment:
CONTINUWUITY_SERVER_NAME: example.com
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
#CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
## (Optional) Serve .well-known files to tell others to reach Continuwuity on port :443
## If you do this, remove all routes to port :8448 from the compose and Caddyfile
# CONTINUWUITY_WELL_KNOWN: |
# {
# client=https://example.com,
# server=example.com:443
# }
## (Optional) Serve .well-known files to tell others to reach Continuwuity on port :443
## If you do this, remove all routes to port :8448 from the compose and Caddyfile
# CONTINUWUITY_WELL_KNOWN: |
# {
# client=https://example.com,
# server=example.com:443
# }
networks:
- proxy
networks:
- caddy
networks:
proxy:
caddy:
volumes:
db:
db:
configs:
Caddyfile:
content: |
https://example.com:443, https://example.com:8448 {
reverse_proxy http://homeserver:8008
}
+1 -1
View File
@@ -4,7 +4,7 @@ # `!admin rooms`
Commands for managing rooms
## `!admin rooms list`
## `!admin rooms list-rooms`
List all rooms the server knows about
+1 -1
View File
@@ -36,7 +36,7 @@ ## `!admin server admin-notice`
Send a message to the admin room
## `!admin server reload`
## `!admin server reload-mods`
Hot-reload the server
+2 -6
View File
@@ -4,14 +4,10 @@ # `!admin users`
Commands for managing local users
## `!admin users create`
## `!admin users create-user`
Create a new user
## `!admin users issue-token`
Issue an access token for a user. This command will not work on shadow users, such as appservice puppets or accounts imported from an identity provider
## `!admin users reset-password`
Reset user password
@@ -92,7 +88,7 @@ ## `!admin users disable-login`
Disables login for the specified user without deactivating or locking their account. This prevents the user from obtaining new access tokens, but does not invalidate existing sessions.
## `!admin users list`
## `!admin users list-users`
List local users in the database
-5
View File
@@ -1,8 +1,3 @@
## Configuration file reference
This configuration file reflect the latest developments on the `main` branch. To check the configuration from a specific Continuwuity version, browse the [tags](https://forgejo.ellis.link/continuwuation/continuwuity/tags) and navigate to the `conduwuit-example.toml` file for that version.
---
```toml file="../../conduwuit-example.toml"
+3 -5
View File
@@ -13,7 +13,7 @@ ### Slow joins to rooms
Some slowness is to be expected if you're the first person on your homeserver to join a room (which will
always be the case for single-user homeservers). In this situation, your homeserver has to verify the signatures of
all of the state events sent by other servers before your join. To make this process as fast as possible, make sure you have
[multiple fast, trusted servers](./guides/performance.mdx#tuning-your-trusted-servers) listed in `trusted_servers` in your configuration, and ensure
multiple fast, trusted servers listed in `trusted_servers` in your configuration, and ensure
`query_trusted_key_servers_first_on_join` is set to true (the default).
If you need suggestions for trusted servers, ask in the Continuwuity main room.
@@ -23,8 +23,6 @@ ### Slow joins to rooms
the bug caused your homeserver to forget to tell your client. **To fix this, clear your client's cache.** Both Element and Cinny
have a button to clear their cache in the "About" section of their settings.
[Tuning your DNS](./guides/dns.mdx) can also help make initial joins faster.
### Configuration not working as expected
Sometimes you can make a mistake in your configuration that
@@ -66,7 +64,7 @@ ### DNS server overload
### Intermittent federation failures to a specific server
There may be circumstances where servers fail to connect to each other, probably due to a bad DNS cache. In such cases, issuing `!admin debug ping <SERVER_NAME>` would return some errors, and `!admin query resolver cache <SERVER_NAME>` would return a wrong destination endpoint.
There may be circumstances where servers fail to connect to each other, probably due to a bad DNS cache. In such cases, issuing `!admin debug ping <SERVER_NAME>` would return some errors.
To fix this, you can run `!admin query resolver flush-cache <SERVER_NAME>` to clear the bad cache for that domain, and outbound requests should work again.
@@ -123,7 +121,7 @@ ## Debugging
Note that users should not really need to debug things. If you find yourself
debugging and find the issue, please let us know and/or how we can fix it.
Various debug commands can be [found in `!admin debug`](./reference/admin/debug).
Various debug commands can be found in `!admin debug`.
### Debug/Trace log level
+126 -110
View File
@@ -16,21 +16,21 @@
}
},
"node_modules/@emnapi/core": {
"version": "1.11.3",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz",
"integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==",
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
"integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.3",
"@emnapi/wasi-threads": "1.2.2",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.11.3",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz",
"integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==",
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
"integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -39,9 +39,9 @@
}
},
"node_modules/@emnapi/wasi-threads": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz",
"integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==",
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
"integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -125,13 +125,13 @@
}
},
"node_modules/@rsbuild/core": {
"version": "2.1.10",
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.1.10.tgz",
"integrity": "sha512-lwxC5w88U2AMv6aNwG3VH7+AV33N4JJQjD//egVWFsMbV+OE/bnfCsurSpX8s3lGyRYkJMwUVN+YXMbmmYZFfw==",
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.1.5.tgz",
"integrity": "sha512-7TW4U1SH7VxQZzSTIOzvwj5lo9uNTmGpsmTXFr4axQAE4giLDKP3kVUA1ZW4P3/Mz4QQJJyvZP29mVcb8kZCfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rspack/core": "~2.1.8",
"@rspack/core": "~2.1.3",
"@swc/helpers": "^0.5.23"
},
"bin": {
@@ -169,30 +169,30 @@
}
},
"node_modules/@rspack/binding": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-2.1.8.tgz",
"integrity": "sha512-tmAyHzDbPiy8V7HvQqtuPsbs6dPgwV0YjzW5XrPRV9gzf+Hdm7pvsZJKE1QKO9WV5RuvGYav98xIX6O+abZxzQ==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-2.1.3.tgz",
"integrity": "sha512-4UGXJqUHmm36tWG1GgFZz3p8sQ5JuSgWI+gq1xPPoihS41uYJL3cXuJnirTeWsmVrusmYZTQhgU3tl3VYGcJYg==",
"dev": true,
"license": "MIT",
"optionalDependencies": {
"@rspack/binding-darwin-arm64": "2.1.8",
"@rspack/binding-darwin-x64": "2.1.8",
"@rspack/binding-linux-arm64-gnu": "2.1.8",
"@rspack/binding-linux-arm64-musl": "2.1.8",
"@rspack/binding-linux-riscv64-gnu": "2.1.8",
"@rspack/binding-linux-riscv64-musl": "2.1.8",
"@rspack/binding-linux-x64-gnu": "2.1.8",
"@rspack/binding-linux-x64-musl": "2.1.8",
"@rspack/binding-wasm32-wasi": "2.1.8",
"@rspack/binding-win32-arm64-msvc": "2.1.8",
"@rspack/binding-win32-ia32-msvc": "2.1.8",
"@rspack/binding-win32-x64-msvc": "2.1.8"
"@rspack/binding-darwin-arm64": "2.1.3",
"@rspack/binding-darwin-x64": "2.1.3",
"@rspack/binding-linux-arm64-gnu": "2.1.3",
"@rspack/binding-linux-arm64-musl": "2.1.3",
"@rspack/binding-linux-riscv64-gnu": "2.1.3",
"@rspack/binding-linux-riscv64-musl": "2.1.3",
"@rspack/binding-linux-x64-gnu": "2.1.3",
"@rspack/binding-linux-x64-musl": "2.1.3",
"@rspack/binding-wasm32-wasi": "2.1.3",
"@rspack/binding-win32-arm64-msvc": "2.1.3",
"@rspack/binding-win32-ia32-msvc": "2.1.3",
"@rspack/binding-win32-x64-msvc": "2.1.3"
}
},
"node_modules/@rspack/binding-darwin-arm64": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-2.1.8.tgz",
"integrity": "sha512-kia+eWtyWPvR4ntg1bWYoVU8nLPbUg2fG3zgBEocsTcsh5ZENSiEPxEKymDgMyIMONUqj611E0775cdUBoNmqw==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-2.1.3.tgz",
"integrity": "sha512-oOGI0RSL89Ehu9T22rugmfUY9OC2eBqLMeWRYsu7bhlUrjoXeVfGBBSEXCse666BQ1sAiM8hD/k7nqVria/okQ==",
"cpu": [
"arm64"
],
@@ -204,9 +204,9 @@
]
},
"node_modules/@rspack/binding-darwin-x64": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-2.1.8.tgz",
"integrity": "sha512-08pBkFhlD3Y3Qzh94w/Fc3skaIE3e96kl2P14m8+tnYTcglpOfpA2OwS3iHt9fOqy0HjoAVe6/MW3cBgs5iabA==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-2.1.3.tgz",
"integrity": "sha512-sVqWXNiFTMXAyN362y6IA+eJc8LXZKfHdhEJ/zDuMmRp+u2IvhgaF8tk3vX/OmeB9jydVjySijuiqk8No/FoCA==",
"cpu": [
"x64"
],
@@ -218,9 +218,9 @@
]
},
"node_modules/@rspack/binding-linux-arm64-gnu": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-2.1.8.tgz",
"integrity": "sha512-KLniMc9GzhKpVqhPzaJo3KJwzdAllXVVqZIk/uL1QipXOxs57fgM4u7IexKPFVla0o/u1PQG/Ah2YLDmda24Ow==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-2.1.3.tgz",
"integrity": "sha512-aCy9Zli/2Qf+Ee5otXfFQ6mhv5fEyn0wIoBVmouqtJoqOO21et6UTtJ+LHLsMDolwGLyHERAljeSFSmYX3/O5A==",
"cpu": [
"arm64"
],
@@ -235,9 +235,9 @@
]
},
"node_modules/@rspack/binding-linux-arm64-musl": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-2.1.8.tgz",
"integrity": "sha512-yUKAxHNGnICtw5RnxFWu4dHtsz/tdt7rbeFcsINNVre9HcrRxf5XP+FbOGL/SMxd9oM9XCo10paU2WckTKwbEA==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-2.1.3.tgz",
"integrity": "sha512-flIE7eluz0d21Fn28EVm3vPwoJooOSqtmjLFVSuOMcoCbwV9clfor195oIrAppp/W7dL/3XquFuVfrsa01Jy8Q==",
"cpu": [
"arm64"
],
@@ -252,9 +252,9 @@
]
},
"node_modules/@rspack/binding-linux-riscv64-gnu": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-2.1.8.tgz",
"integrity": "sha512-gg4S1jaitwYPHR9HZ3zNGH1EK2GXINm66p4kEpOP1gbc+akyOouVF/dMcu9NGPlRg58FbEhVRZYKu7Z/zcpKHg==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-2.1.3.tgz",
"integrity": "sha512-yojg8elye1nhsNeGncw0NrZ4pMGF7NVebR80CLg72TXyzfYwFJlFTdU5yUYb1Gy+JXIvrSCwzQt2QkyiEvmkfg==",
"cpu": [
"riscv64"
],
@@ -269,9 +269,9 @@
]
},
"node_modules/@rspack/binding-linux-riscv64-musl": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-2.1.8.tgz",
"integrity": "sha512-b/aU5j1h368SLNyz5u+flqpZVhzSZ1UIslaj9sZJuAvqkGWv3xsjc/28/PTo/RYXCxd0FNVAxTxWHKvRiAAS8w==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-2.1.3.tgz",
"integrity": "sha512-6PvbXb3FOK4X3S5QGvoSW/sqExmsvAoPnQ/YSFrXvTphkXFezA7wnobmGBHT8JQP31hcFRzJHIZSIOKktzSzzg==",
"cpu": [
"riscv64"
],
@@ -286,9 +286,9 @@
]
},
"node_modules/@rspack/binding-linux-x64-gnu": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-2.1.8.tgz",
"integrity": "sha512-EyegohSx0BJRqieCg9f/caCqFARRWkqI5hwJt6k530MoOTLeq8I3vsbeg24/2MktwIC1dmJi8bl0+WhPKQs4eQ==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-2.1.3.tgz",
"integrity": "sha512-lMXjoGKf0SnviH596fmTszgtnXLHmWOoE90G8grG9MvKVa3pelRmfps5ewZL9s8ENf3NXRfOxIhIf/M9as6MqA==",
"cpu": [
"x64"
],
@@ -303,9 +303,9 @@
]
},
"node_modules/@rspack/binding-linux-x64-musl": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-2.1.8.tgz",
"integrity": "sha512-I6E+goN+UQ297q4r1qdbiAyNCI3t0+a5Y0xDIAPOZfRDRxDTnH/LF8/y65gjsJoKRKyn7zxRC0T/NURTkRNQ9A==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-2.1.3.tgz",
"integrity": "sha512-0esT35v7pW2ZsJTMc/zDUHwpNXlPqyUCyuiLJvrAAUcdENrgOVe4DmFrgVJ2hwqI4GjeN1VBnGRJ8c+edAHH5w==",
"cpu": [
"x64"
],
@@ -320,9 +320,9 @@
]
},
"node_modules/@rspack/binding-wasm32-wasi": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-2.1.8.tgz",
"integrity": "sha512-om7GAKWAU3lcSvbCon2m7mzw8v9OTrO2LW2MZ1lGe/uVJJmwGGkl9HVoXFyWFLrN6YVFyx8iP+AkN4owDWB9Cw==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-2.1.3.tgz",
"integrity": "sha512-UsrDjD59UEP0mhfN/Z+uTc3vLgiUvIr+mn92WC1sbQi9gtZohTYvaQYFhWuMkBqsACGcmZp704JAbbSrVrVYCA==",
"cpu": [
"wasm32"
],
@@ -330,15 +330,15 @@
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "1.11.3",
"@emnapi/runtime": "1.11.3",
"@emnapi/core": "1.11.1",
"@emnapi/runtime": "1.11.1",
"@napi-rs/wasm-runtime": "1.1.6"
}
},
"node_modules/@rspack/binding-win32-arm64-msvc": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.1.8.tgz",
"integrity": "sha512-WDnsP/SUb9zbxyGX9XjPw5AXrX86u5oidn0MDdfJduOOqdCSpHwmRjlQ8NUJhbBq9WqVJMFlcab7NwZVWX/yyg==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.1.3.tgz",
"integrity": "sha512-42RS/SwKBTkNvXIPZXqTn0yEFN8zwGRfRe/ly0GDvPp/KxpLMFWxJmLxgtoLompU+0UCGvV4KpcBENt3oWs6BA==",
"cpu": [
"arm64"
],
@@ -350,9 +350,9 @@
]
},
"node_modules/@rspack/binding-win32-ia32-msvc": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-2.1.8.tgz",
"integrity": "sha512-QiMQMPNDiY3dhhaIdaFPzcPDC06cEYkNY89ea+EmDvNVgZq6V+2mFS/WnzZVMeEbGAYJCjsv/ABhhLT1hlYMvg==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-2.1.3.tgz",
"integrity": "sha512-thk43H1JHHbetNF3txcsGXeOwZi2m6Luf/uVUqNORXjxr5VV8woHAgaAx4QXVZRg70z1VDjd8mBWnHBnKI0FGA==",
"cpu": [
"ia32"
],
@@ -364,9 +364,9 @@
]
},
"node_modules/@rspack/binding-win32-x64-msvc": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-2.1.8.tgz",
"integrity": "sha512-b7sA5eB64vo2mbsuc//MOYzVLeCKHPn0dfP/GmNEoHdWbhRgZ/orZLWurYMQj04ELTLW6YCJEy59g5KRzNYHfw==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-2.1.3.tgz",
"integrity": "sha512-ObaUcj+BHo/aBL1weyM3orApaHyAR5Phr3YNEpQEifxjZbNKM1iO5X5prN4OqEv3H+7o5e/Wh9Fy3N7Vvd+psA==",
"cpu": [
"x64"
],
@@ -378,13 +378,13 @@
]
},
"node_modules/@rspack/core": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-2.1.8.tgz",
"integrity": "sha512-na1kyA6Mj8/LWw9O3A8NsrG9rNKN3Iq2WiXrEuIwsU5r/Nl/evm3hO7bWKHxgsRyydI6W7okwx3MXgf8rzel6g==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-2.1.3.tgz",
"integrity": "sha512-1iGnxLrP+iyY0ZSjLZeQTaxrISpQz4yLyqJPmaF/l4uw27/dBcrloszAeLOJQ9jiv7EJtU0T5zB+LOFPpivIxA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rspack/binding": "2.1.8"
"@rspack/binding": "2.1.3"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
@@ -419,21 +419,20 @@
}
},
"node_modules/@rspress/core": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/@rspress/core/-/core-2.0.19.tgz",
"integrity": "sha512-m0KfQNNXxjP975652nIOwUTqrvbJapRp4NpnoQMc5heawGhkC4+F7zTHvxY+huvzGYnKtL2fMMTrgWhEjKkrug==",
"version": "2.0.18",
"resolved": "https://registry.npmjs.org/@rspress/core/-/core-2.0.18.tgz",
"integrity": "sha512-DBpsr/6XAItQkZPL5FSjthLGuzdG9ks/7EOxkqaaXp93uAT54LO0PD5Dkoy6ydup1PnvkpHyiHpUyDcnHHTVhg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@mdx-js/mdx": "^3.1.1",
"@mdx-js/react": "^3.1.1",
"@rsbuild/core": "^2.1.8",
"@rsbuild/core": "^2.1.5",
"@rsbuild/plugin-react": "~2.1.0",
"@rspress/shared": "2.0.19",
"@rspress/shared": "2.0.18",
"@shikijs/rehype": "^4.2.0",
"@types/mdast": "^4.0.4",
"@types/react": "^19.2.17",
"@unhead/react": "^2.1.16",
"@types/unist": "^3.0.3",
"@unhead/react": "^2.1.15",
"body-scroll-lock": "4.0.0-beta.0",
"clsx": "2.1.1",
"copy-to-clipboard": "^3.3.3",
@@ -444,9 +443,10 @@
"mdast-util-mdxjs-esm": "^2.0.1",
"medium-zoom": "1.1.0",
"nprogress": "^0.2.0",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react-lazy-with-preload": "^2.2.1",
"react-reconciler": "0.33.0",
"react-render-to-markdown": "19.1.0",
"react-router-dom": "^7.18.1",
"rehype-external-links": "^3.0.0",
@@ -460,9 +460,9 @@
"scroll-into-view-if-needed": "^3.1.0",
"shiki": "^4.2.0",
"unified": "^11.0.5",
"unist-util-remove": "^4.0.0",
"unist-util-visit": "^5.1.0",
"unist-util-visit-children": "^3.0.0",
"vfile": "^6.0.3"
"unist-util-visit-children": "^3.0.0"
},
"bin": {
"rspress": "bin/rspress.js"
@@ -472,9 +472,9 @@
}
},
"node_modules/@rspress/plugin-client-redirects": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/@rspress/plugin-client-redirects/-/plugin-client-redirects-2.0.19.tgz",
"integrity": "sha512-BUwgEyj8vCkU58cV3Gp97aTSnfGJm7aXh40K0Dot1BqsCQ8ekdsMuaLXrICROdP9/ctd4oALtLBkOE+PKTa4Sg==",
"version": "2.0.18",
"resolved": "https://registry.npmjs.org/@rspress/plugin-client-redirects/-/plugin-client-redirects-2.0.18.tgz",
"integrity": "sha512-q70ufN0S125kl0QlucO7JuiZ0WJaxFOtPPoGu7eWwam9fb+i4YsWnOWtAKSKGH4JP5+897mgpDPP+dmfl9DPCw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -485,9 +485,9 @@
}
},
"node_modules/@rspress/plugin-sitemap": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/@rspress/plugin-sitemap/-/plugin-sitemap-2.0.19.tgz",
"integrity": "sha512-9ydrpj9hmmXWKWKIXUqJ1UrfxSvfxhHZRBZLb5OkTlOuQBNAg6BpsrW1WHoJqJr7p+3zqlz7S/9HTzSA3+EYcA==",
"version": "2.0.18",
"resolved": "https://registry.npmjs.org/@rspress/plugin-sitemap/-/plugin-sitemap-2.0.18.tgz",
"integrity": "sha512-XfaXzZx+ASN9OMTc0fOvW8QmbmyCyDWkO8xJj4XF4E0YJtsu7j/65+v8/KXXdwpywOfUIQ6M94/meRTy2urNmQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -498,16 +498,14 @@
}
},
"node_modules/@rspress/shared": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/@rspress/shared/-/shared-2.0.19.tgz",
"integrity": "sha512-INrETllWuR49lksqCz+xeLSO6rKtHA+5Ix2YQWcP9nerCuTSyGYwH8eBC0HrIacJkGHxB8wkkbV99tyzGtY8Wg==",
"version": "2.0.18",
"resolved": "https://registry.npmjs.org/@rspress/shared/-/shared-2.0.18.tgz",
"integrity": "sha512-GJswqJQCPSxvBt5r+gJzz8Em8EEK/sOmCQjTpemTvldvxr1Lva85BGVnSQZOgofnM0nrjt18kn4mmnuuSstbpA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rsbuild/core": "^2.1.8",
"@rsbuild/core": "^2.1.5",
"@shikijs/rehype": "^4.2.0",
"@types/react": "^19.2.17",
"mdast-util-mdx-jsx": "^3.2.0",
"unified": "^11.0.5"
}
},
@@ -725,6 +723,7 @@
"integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -1084,13 +1083,13 @@
"license": "ISC"
},
"node_modules/@unhead/react": {
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/@unhead/react/-/react-2.1.17.tgz",
"integrity": "sha512-KmcYksDjlLozL0fxUjIDwH/0k6+Lg2HWHLUPlkRW8Gl08hdB1AbLB5iU9QxFvkaT8p0Q4dFEqZWnz3g6RMeiRA==",
"version": "2.1.15",
"resolved": "https://registry.npmjs.org/@unhead/react/-/react-2.1.15.tgz",
"integrity": "sha512-5hfAaZ3XJq9JkspRzZdSPsMrXXA8v/SKiEOxZcN9L40o44byF/50bcQuOLgSSCAx8802mI5VG32KZXWTtsLu9Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"unhead": "2.1.17"
"unhead": "2.1.15"
},
"funding": {
"url": "https://github.com/sponsors/harlan-zw"
@@ -1273,7 +1272,8 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/debug": {
"version": "4.4.3",
@@ -3176,9 +3176,9 @@
}
},
"node_modules/react": {
"version": "19.2.8",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
"integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
"integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3186,16 +3186,16 @@
}
},
"node_modules/react-dom": {
"version": "19.2.8",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz",
"integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==",
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
"integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"scheduler": "^0.27.0"
},
"peerDependencies": {
"react": "^19.2.8"
"react": "^19.2.7"
}
},
"node_modules/react-lazy-with-preload": {
@@ -3736,9 +3736,9 @@
}
},
"node_modules/unhead": {
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/unhead/-/unhead-2.1.17.tgz",
"integrity": "sha512-HLMKXOszRhAPBrr6VlqCeVeJq2kbC4kXwzGLEZvvojPLWNYTJw22xG7Bfwhsvs31+IBet3Wl8ADg9dwYdyphfQ==",
"version": "2.1.15",
"resolved": "https://registry.npmjs.org/unhead/-/unhead-2.1.15.tgz",
"integrity": "sha512-MCt5T90mCWyr3Z6pUCdM9lVRXoMoVBlL7z7U4CYVIiaDiuzad/UCfLuMqz5MeNmpZUgoBCQnrucJimU7EZR+XA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3810,6 +3810,22 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/unist-util-remove": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-4.0.0.tgz",
"integrity": "sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0",
"unist-util-is": "^6.0.0",
"unist-util-visit-parents": "^6.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/unist-util-stringify-position": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
+1 -1
View File
@@ -18,7 +18,7 @@
#[derive(Debug, Subcommand)]
pub enum RoomCommand {
/// List all rooms the server knows about
#[command(name = "list", alias = "list-rooms")]
#[clap(alias = "list")]
ListRooms {
page: Option<usize>,
+1 -1
View File
@@ -40,7 +40,7 @@ pub enum ServerCommand {
},
/// Hot-reload the server
#[command(name = "reload", alias = "reload-mods")]
#[clap(alias = "reload")]
ReloadMods,
#[cfg(unix)]
+1 -1
View File
@@ -3,7 +3,7 @@
use service::registration_tokens::TokenExpires;
impl crate::Context<'_> {
pub(super) async fn issue_registration_token(&self, expires: super::TokenExpires) -> Result {
pub(super) async fn issue_token(&self, expires: super::TokenExpires) -> Result {
let expires = {
if expires.immortal {
None
+1 -1
View File
@@ -10,7 +10,7 @@
pub enum TokenCommand {
/// Issue a new registration token
#[clap(name = "issue")]
IssueRegistrationToken {
IssueToken {
/// When this token will expire.
#[command(flatten)]
expires: TokenExpires,
+16 -33
View File
@@ -20,7 +20,7 @@
tag::{TagEvent, TagEventContent, TagInfo},
},
};
use service::users::{AccountStatus, DeviceToken, HashedPassword};
use service::users::{AccountStatus, HashedPassword};
use crate::{
get_room_info,
@@ -59,42 +59,13 @@ pub(super) async fn create_user(&self, username: String, password: Option<String
self.services
.users
.create_local_account(
&user_id,
Some(HashedPassword::new(password)?),
None,
None,
None,
)
.create_local_account(&user_id, Some(HashedPassword::new(password)?), None)
.await?;
self.write_str(&format!("Created user {user_id} with password `{password}`"))
.await
}
pub(super) async fn issue_access_token(&self, username: String, password: String) -> Result {
let user_id = parse_active_local_user_id(self.services, &username).await?;
let user_id = self
.services
.users
.check_password(&user_id, &password)
.await?;
let token = DeviceToken::new_random();
let device_id = self
.services
.users
.create_device(&user_id, None, Some(token.clone()), None, None)
.await?;
self.write_str(&format!(
"Created device `{device_id}` with access token `{}` for {user_id}",
token.into_token()
))
.await
}
pub(super) async fn deactivate(&self, no_leave_rooms: bool, user_id: String) -> Result {
// Validate user id
let user_id = parse_local_user_id(self.services, &user_id)?;
@@ -131,6 +102,7 @@ pub(super) async fn deactivate(&self, no_leave_rooms: bool, user_id: String) ->
}
pub(super) async fn suspend(&self, user_id: String) -> Result {
self.bail_restricted()?;
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
if user_id == self.services.globals.server_user {
@@ -143,7 +115,7 @@ pub(super) async fn suspend(&self, user_id: String) -> Result {
// TODO: Record the actual user that sent the suspension where possible
self.services
.users
.suspend_account(&user_id, self.sender_or_service_user())
.suspend_account(&user_id, self.sender)
.await;
self.write_str(&format!("User {user_id} has been suspended."))
@@ -151,6 +123,7 @@ pub(super) async fn suspend(&self, user_id: String) -> Result {
}
pub(super) async fn unsuspend(&self, user_id: String) -> Result {
self.bail_restricted()?;
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
if user_id == self.services.globals.server_user {
@@ -962,6 +935,7 @@ pub(super) async fn force_leave_remote_room(
}
pub(super) async fn lock(&self, user_id: String) -> Result {
self.bail_restricted()?;
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
if user_id == self.services.globals.server_user {
@@ -974,7 +948,7 @@ pub(super) async fn lock(&self, user_id: String) -> Result {
self.services
.users
.lock_account(&user_id, self.sender_or_service_user())
.lock_account(&user_id, self.sender)
.await;
self.write_str(&format!("User {user_id} has been locked."))
@@ -982,6 +956,7 @@ pub(super) async fn lock(&self, user_id: String) -> Result {
}
pub(super) async fn unlock(&self, user_id: String) -> Result {
self.bail_restricted()?;
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
self.services.users.unlock_account(&user_id).await;
@@ -991,6 +966,7 @@ pub(super) async fn unlock(&self, user_id: String) -> Result {
}
pub(super) async fn logout(&self, user_id: String) -> Result {
self.bail_restricted()?;
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
if user_id == self.services.globals.server_user {
@@ -1016,6 +992,7 @@ pub(super) async fn logout(&self, user_id: String) -> Result {
}
pub(super) async fn disable_login(&self, user_id: String) -> Result {
self.bail_restricted()?;
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
if user_id == self.services.globals.server_user {
@@ -1034,6 +1011,7 @@ pub(super) async fn disable_login(&self, user_id: String) -> Result {
}
pub(super) async fn enable_login(&self, user_id: String) -> Result {
self.bail_restricted()?;
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
self.services.users.enable_login(&user_id);
@@ -1042,6 +1020,7 @@ pub(super) async fn enable_login(&self, user_id: String) -> Result {
}
pub(super) async fn get_email(&self, user_id: String) -> Result {
self.bail_restricted()?;
let user_id = parse_local_user_id(self.services, &user_id)?;
match self
@@ -1060,6 +1039,8 @@ pub(super) async fn get_email(&self, user_id: String) -> Result {
}
pub(super) async fn get_user_by_email(&self, email: String) -> Result {
self.bail_restricted()?;
let Ok(email) = Address::try_from(email) else {
return Err!("Invalid email address.");
};
@@ -1082,6 +1063,8 @@ pub(super) async fn get_user_by_email(&self, email: String) -> Result {
}
pub(super) async fn change_email(&self, user_id: String, email: Option<String>) -> Result {
self.bail_restricted()?;
let user_id = parse_local_user_id(self.services, &user_id)?;
let Ok(new_email) = email.map(Address::try_from).transpose() else {
return Err!("Invalid email address.");
+2 -11
View File
@@ -10,7 +10,7 @@
#[derive(Debug, Subcommand)]
pub enum UserCommand {
/// Create a new user
#[command(name = "create", alias = "create-user")]
#[clap(alias = "create")]
CreateUser {
/// Username of the new user
username: String,
@@ -18,15 +18,6 @@ pub enum UserCommand {
password: Option<String>,
},
/// Issue an access token for a user. This command will not work on
/// shadow users, such as appservice puppets or accounts imported from
/// an identity provider.
#[clap(name = "issue-token")]
IssueAccessToken {
username: String,
password: String,
},
/// Reset user password
ResetPassword {
/// Log out existing sessions
@@ -163,7 +154,7 @@ pub enum UserCommand {
},
/// List local users in the database
#[command(name = "list", alias = "list-users")]
#[clap(alias = "list")]
ListUsers,
/// Lists all the rooms (local and remote) that the specified user is
+2
View File
@@ -62,6 +62,8 @@ zstd_compression = [
"reqwest/zstd",
]
admin_api = []
[dependencies]
async-trait.workspace = true
axum-extra.workspace = true
-1
View File
@@ -1 +0,0 @@
pub mod rooms;
-36
View File
@@ -1,36 +0,0 @@
use axum::extract::State;
use conduwuit::{Err, Result};
use futures::StreamExt;
use ruma::OwnedRoomId;
use ruminuwuity::admin::continuwuity::rooms;
use crate::Ruma;
/// # `GET /_continuwuity/admin/rooms/list`
///
/// Lists all rooms known to this server, excluding banned ones.
pub(crate) async fn list_rooms(
State(services): State<crate::State>,
body: Ruma<rooms::list::v1::Request>,
) -> Result<rooms::list::v1::Response> {
let sender_user = body.identity.expect_sender_user()?;
if !services.users.is_admin(sender_user).await {
return Err!(Request(Forbidden("Only server administrators can use this endpoint")));
}
let mut rooms: Vec<OwnedRoomId> = services
.rooms
.metadata
.iter_ids()
.filter_map(|room_id| async move {
if !services.rooms.metadata.is_banned(&room_id).await {
Some(room_id.clone())
} else {
None
}
})
.collect()
.await;
rooms.sort();
Ok(rooms::list::v1::Response::new(rooms))
}
-2
View File
@@ -1,2 +0,0 @@
pub mod ban;
pub mod list;
+1
View File
@@ -25,6 +25,7 @@
};
use service::{mailer::messages, uiaa::UiaaInitiator, users::HashedPassword};
use super::DEVICE_ID_LENGTH;
use crate::{Ruma, router::ClientIdentity};
pub(crate) mod register;
+14 -11
View File
@@ -1,7 +1,10 @@
use std::collections::HashMap;
use axum::extract::State;
use conduwuit::{Err, Result, debug_info, info};
use conduwuit::{
Err, Result, debug_info, info,
utils::{self},
};
use conduwuit_service::Services;
use futures::StreamExt;
use lettre::{Address, message::Mailbox};
@@ -21,6 +24,7 @@
users::{DeviceToken, HashedPassword},
};
use super::DEVICE_ID_LENGTH;
use crate::{Ruma, client_ip::ClientIp};
/// # `POST /_matrix/client/v3/register`
@@ -95,13 +99,7 @@ pub(crate) async fn register_route(
services
.users
.create_local_account(
&user_id,
Some(password),
identity.email,
Some(&client),
body.initial_device_display_name.as_deref(),
)
.create_local_account(&user_id, Some(password), identity.email)
.await?;
user_id
@@ -116,21 +114,26 @@ pub(crate) async fn register_route(
)));
}
// Generate new device id if the user didn't specify one
let device_id = body
.device_id
.clone()
.unwrap_or_else(|| utils::random_string(DEVICE_ID_LENGTH).into());
// Generate new token for the device
let new_token = DeviceToken::new_random();
// Create device for this account
let device_id = services
services
.users
.create_device(
&user_id,
body.device_id.clone(),
&device_id,
Some(new_token.clone()),
body.initial_device_display_name.clone(),
Some(client.to_string()),
)
.await?;
(Some(new_token), Some(device_id))
} else {
// Don't create a device for inhibited logins
+7 -23
View File
@@ -1,6 +1,6 @@
use axum::extract::State;
use conduwuit::{Err, Result};
use futures::future::{join, join3};
use futures::join;
use ruma::api::client::admin::{is_user_locked, lock_user};
use crate::Ruma;
@@ -12,15 +12,7 @@ pub(crate) async fn get_lock_status(
State(services): State<crate::State>,
body: Ruma<is_user_locked::v1::Request>,
) -> Result<is_user_locked::v1::Response> {
let (admin, status) = join(
services.users.is_admin(body.identity.expect_sender_user()?),
services.users.status(&body.user_id),
)
.await;
if !admin {
return Err!(Request(Forbidden("Only server administrators can use this endpoint")));
}
let status = services.users.status(&body.user_id).await;
status.ensure_active()?;
@@ -36,22 +28,14 @@ pub(crate) async fn put_lock_status(
State(services): State<crate::State>,
body: Ruma<lock_user::v1::Request>,
) -> Result<lock_user::v1::Response> {
let sender_user = body.identity.expect_sender_user()?;
let sender_user = body.identity.sender_user();
let (sender_admin, status, target_admin) = join3(
services.users.is_admin(sender_user),
services.users.status(&body.user_id),
services.users.is_admin(&body.user_id),
)
.await;
if !sender_admin {
return Err!(Request(Forbidden("Only server administrators can use this endpoint")));
}
let (status, target_admin) =
join!(services.users.status(&body.user_id), services.users.is_admin(&body.user_id),);
status.ensure_active()?;
if body.user_id == *sender_user {
if sender_user.is_some_and(|sender_user| body.user_id == sender_user) {
return Err!(Request(Forbidden("You cannot lock yourself")));
}
@@ -79,7 +63,7 @@ pub(crate) async fn put_lock_status(
// Notify the admin room that an account has been un/suspended
services
.admin
.send_text(&format!("{} has been {} by {}.", body.user_id, action, sender_user))
.send_text(&format!("{} has been {} by {}.", body.user_id, action, body.identity))
.await;
}
+1
View File
@@ -1,4 +1,5 @@
mod lock;
pub(crate) mod site;
mod suspend;
pub(crate) use self::{lock::*, suspend::*};
+2
View File
@@ -0,0 +1,2 @@
pub(crate) mod rooms;
pub(crate) mod users;
@@ -6,7 +6,7 @@
use crate::{Ruma, client::leave_room};
/// # `PUT /_continuwuity/admin/rooms/{roomID}/ban`
/// # `PUT /_continuwuity/admin/v1/rooms/{roomID}/ban`
///
/// Bans or unbans a room.
pub(crate) async fn ban_room(
+178
View File
@@ -0,0 +1,178 @@
use axum::extract::State;
use conduwuit::{
Event, Result,
utils::stream::{BroadbandExt, WidebandExt},
};
use futures::StreamExt;
use ruma::{
OwnedRoomId,
events::{
StateEventType,
room::{
create::RoomCreateEventContent,
encryption::PossiblyRedactedRoomEncryptionEventContent,
tombstone::PossiblyRedactedRoomTombstoneEventContent,
},
},
};
use ruminuwuity::admin::continuwuity::rooms;
use tokio::join;
use crate::Ruma;
/// # `GET /_continuwuity/admin/rooms`
///
/// Lists all room IDs known to this server, excluding banned ones.
///
/// This is the legacy version of the endpoint, which does not support
/// pagination or including banned rooms. It is recommended to use the
/// `/v1/rooms` endpoint instead. This endpoint may be removed in a future
/// release.
pub(crate) async fn legacy_list_rooms(
State(services): State<crate::State>,
_body: Ruma<rooms::list::unstable::Request>,
) -> Result<rooms::list::unstable::Response> {
let mut rooms: Vec<OwnedRoomId> = services
.rooms
.metadata
.iter_ids()
.filter_map(|room_id| async move {
if !services.rooms.metadata.is_banned(&room_id).await {
Some(room_id.clone())
} else {
None
}
})
.collect()
.await;
rooms.sort();
Ok(rooms::list::unstable::Response::new(rooms))
}
/// # `GET /_continuwuity/admin/v1/rooms`
///
/// Lists rooms known to this server.
pub(crate) async fn list_rooms(
State(services): State<crate::State>,
body: Ruma<rooms::list::v1::Request>,
) -> Result<rooms::list::v1::Response> {
let include_banned_rooms = body.include_banned_rooms;
let rooms = services
.rooms
.metadata
.iter_ids()
.wide_filter_map(|room_id| async move {
if include_banned_rooms || !services.rooms.metadata.is_banned(&room_id).await {
Some(room_id.clone())
} else {
None
}
})
.skip(body.offset.unwrap_or_default())
.take(body.limit.unwrap_or(100).min(100))
.broad_filter_map(|room_id| async move {
let (
banned,
disabled,
member_count,
local_member_count,
resident_server_count,
published,
create_event,
encryption_event,
name_event,
topic_event,
canonical_alias_event,
join_rules_event,
history_visibility_event,
tombstone_event,
) = join!(
services.rooms.metadata.is_banned(&room_id),
services.rooms.metadata.is_disabled(&room_id),
services.rooms.state_cache.room_joined_count(&room_id),
services
.rooms
.state_cache
.active_local_users_in_room(&room_id)
.count(),
services.rooms.state_cache.room_servers(&room_id).count(),
services.rooms.directory.is_public_room(&room_id),
services.rooms.state_accessor.room_state_get(
&room_id,
&StateEventType::RoomCreate,
""
),
services
.rooms
.state_accessor
.room_state_get_content::<PossiblyRedactedRoomEncryptionEventContent>(
&room_id,
&StateEventType::RoomEncryption,
""
),
services.rooms.state_accessor.room_state_get_content(
&room_id,
&StateEventType::RoomName,
""
),
services.rooms.state_accessor.room_state_get_content(
&room_id,
&StateEventType::RoomTopic,
""
),
services.rooms.state_accessor.room_state_get_content(
&room_id,
&StateEventType::RoomCanonicalAlias,
""
),
services.rooms.state_accessor.room_state_get_content(
&room_id,
&StateEventType::RoomJoinRules,
""
),
services.rooms.state_accessor.room_state_get_content(
&room_id,
&StateEventType::RoomHistoryVisibility,
""
),
services
.rooms
.state_accessor
.room_state_get_content::<PossiblyRedactedRoomTombstoneEventContent>(
&room_id,
&StateEventType::RoomTombstone,
""
),
);
let Ok(create_event) = create_event else {
return None;
};
let create_content = create_event
.get_content::<RoomCreateEventContent>()
.expect("m.room.create content must be valid");
Some(rooms::list::v1::MinimalRoomInfo {
room_id,
banned,
disabled,
member_count: usize::try_from(member_count.unwrap_or_default())
.expect("u64 should fit in usize"),
local_member_count,
resident_server_count,
creators: vec![create_event.sender],
encrypted: encryption_event.is_ok_and(|c| c.algorithm.is_some()),
federated: create_content.federate,
published,
version: create_content.room_version,
name: name_event.unwrap_or(None),
topic: topic_event.unwrap_or(None),
canonical_alias: canonical_alias_event.unwrap_or(None),
join_rules: join_rules_event.unwrap_or(None),
history_visibility: history_visibility_event.unwrap_or(None),
predecessor: create_content.predecessor.map(|c| c.room_id),
successor: tombstone_event.map_or(None, |c| c.replacement_room),
})
})
.collect()
.await;
Ok(rooms::list::v1::Response::new(rooms))
}
+5
View File
@@ -0,0 +1,5 @@
mod ban;
mod list;
pub(crate) use ban::ban_room;
pub(crate) use list::*;
+142
View File
@@ -0,0 +1,142 @@
use axum::extract::State;
use conduwuit::{
err, error, info,
utils::{IterStream, stream::BroadbandExt},
warn,
};
use futures::{FutureExt, StreamExt};
use ruma::{api::client::profile::PropagateTo, profile::ProfileFieldValue};
use ruminuwuity::admin::continuwuity::users;
use service::users::{HashedPassword, ProfileFieldChange};
use crate::router::Ruma;
/// # `POST /_continuwuity/admin/v1/users/create`
///
/// Creates a new user.
pub(crate) async fn create_user(
State(services): State<crate::State>,
body: Ruma<users::create::v1::Request>,
) -> conduwuit::Result<users::create::v1::Response> {
let email = body
.email
.clone()
.map(lettre::Address::try_from)
.transpose()
.map_err(|e| err!(Request(BadJson("Invalid email address: {e}"))))?;
let ref user_id = services
.users
.determine_registration_user_id(Some(body.localpart.clone()), email.as_ref(), None)
.await?;
services.users.create_shadow_account(user_id).await?;
services
.users
.convert_to_local_account(user_id, HashedPassword::new(&body.password)?)
.await?;
if let Some(email) = &email {
services
.threepid
.associate_localpart_email(user_id.localpart(), email)
.await?;
}
if body.suspended {
services
.users
.suspend_account(user_id, body.identity.sender_user())
.await;
}
if body.locked {
services
.users
.lock_account(user_id, body.identity.sender_user())
.await;
}
if body.login_disabled {
services.users.disable_login(user_id);
}
if let Some(ref value) = body.display_name {
services
.users
.set_profile_field(
user_id,
ProfileFieldChange::Set(ProfileFieldValue::DisplayName(value.to_owned())),
PropagateTo::None,
)
.await?;
}
if let Some(ref value) = body.avatar_url {
services
.users
.set_profile_field(
user_id,
ProfileFieldChange::Set(ProfileFieldValue::AvatarUrl(value.to_owned())),
PropagateTo::None,
)
.await?;
}
if body.admin {
services
.admin
.make_user_admin(user_id)
.await
.inspect_err(|e| error!("failed to make new user {user_id} an admin: {e}"))
.ok();
}
body.auto_join_rooms
.clone()
.into_iter()
.stream()
.chain(
if body.skip_auto_join {
vec![]
} else {
services.config.auto_join_rooms.clone()
}
.into_iter()
.stream(),
)
.broad_filter_map(|room| async move {
services
.rooms
.alias
.resolve_with_servers(&room, None)
.await
.inspect_err(|e| {
warn!(
"Failed to resolve room alias to room ID when attempting to auto join \
{room}: {e}"
);
})
.ok()
})
.for_each_concurrent(None, |(room_id, servers)| async move {
match services
.rooms
.membership
.join_room(
user_id,
&room_id,
Some("Automatically joining this room upon registration".to_owned()),
servers.as_ref(),
)
.boxed()
.await
{
| Err(e) => {
warn!("Failed to automatically join {user_id} to {room_id}: {e}");
},
| _ => {
info!("Automatically joined room {user_id} to {room_id}");
},
}
})
.await;
Ok(users::create::v1::Response::new(user_id.to_owned()))
}
+42
View File
@@ -0,0 +1,42 @@
use axum::extract::State;
use conduwuit::utils::stream::WidebandExt;
use futures::StreamExt;
use ruminuwuity::admin::continuwuity::users;
use tokio::join;
use crate::router::Ruma;
/// # `GET /_continuwuity/admin/v1/users`
///
/// Lists all users on this homeserver.
pub(crate) async fn list_users(
State(services): State<crate::State>,
body: Ruma<users::list::v1::Request>,
) -> conduwuit::Result<users::list::v1::Response> {
let users = services
.users
.stream_local_users()
.skip(body.offset.unwrap_or_default())
.take(body.limit.unwrap_or(100).min(100))
.wide_filter_map(|user_id| async move {
let (status, suspended, locked, admin, login_disabled) = join!(
services.users.status(&user_id),
services.users.is_suspended(&user_id),
services.users.is_locked(&user_id),
services.users.is_admin(&user_id),
services.users.is_login_disabled(&user_id),
);
Some(users::list::v1::User {
user_id: user_id.clone(),
deactivated: !status.is_active(),
suspended: suspended.unwrap_or_default(),
locked: locked.unwrap_or_default(),
admin,
login_disabled,
})
})
.collect()
.await;
Ok(users::list::v1::Response::new(users))
}
+5
View File
@@ -0,0 +1,5 @@
mod create;
mod list;
pub(crate) use create::*;
pub(crate) use list::*;
+1 -1
View File
@@ -67,7 +67,7 @@ pub(crate) async fn put_suspended_status(
let action = if body.suspended {
services
.users
.suspend_account(&body.user_id, sender_user)
.suspend_account(&body.user_id, body.identity.sender_user())
.await;
"suspended"
} else {
+1 -1
View File
@@ -88,7 +88,7 @@ pub(crate) async fn update_device_route(
.users
.create_device(
sender_user,
Some(body.device_id.clone()),
&body.device_id,
None,
body.display_name.clone(),
Some(client.to_string()),
+3
View File
@@ -90,5 +90,8 @@
pub(super) use voip::*;
pub(super) use well_known::*;
/// generated device ID length
const DEVICE_ID_LENGTH: usize = 10;
/// generated user access token length
const TOKEN_LENGTH: usize = 32;

Some files were not shown because too many files have changed in this diff Show More