mirror of
https://forgejo.ellis.link/continuwuation/continuwuity/
synced 2026-08-07 05:09:45 +00:00
Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7003e4a883 | ||
|
|
ba9837331e | ||
|
|
33983466f8 | ||
|
|
f6834cbe40 | ||
|
|
fddca8d534 | ||
|
|
c76a235726 | ||
|
|
062b3956c2 | ||
|
|
ec57159b86 | ||
|
|
ab64662857 | ||
|
|
fb12439ce5 | ||
|
|
0514491189 | ||
|
|
a30c355c03 |
@@ -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@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
|
||||
with:
|
||||
registry: ${{ env.BUILTIN_REGISTRY }}
|
||||
username: ${{ inputs.registry_user }}
|
||||
@@ -52,7 +52,7 @@ runs:
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
||||
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
|
||||
with:
|
||||
# Use persistent BuildKit if BUILDKIT_ENDPOINT is set (e.g. tcp://buildkit:8125)
|
||||
driver: ${{ env.BUILDKIT_ENDPOINT != '' && 'remote' || 'docker-container' }}
|
||||
@@ -61,7 +61,7 @@ runs:
|
||||
- name: Extract metadata (tags) for Docker
|
||||
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
||||
id: meta
|
||||
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6
|
||||
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
|
||||
with:
|
||||
flavor: |
|
||||
latest=auto
|
||||
|
||||
@@ -67,7 +67,7 @@ runs:
|
||||
uses: ./.forgejo/actions/rust-toolchain
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
|
||||
with:
|
||||
# Use persistent BuildKit if BUILDKIT_ENDPOINT is set (e.g. tcp://buildkit:8125)
|
||||
driver: ${{ env.BUILDKIT_ENDPOINT != '' && 'remote' || 'docker-container' }}
|
||||
@@ -75,11 +75,11 @@ runs:
|
||||
|
||||
- name: Set up QEMU
|
||||
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
|
||||
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
|
||||
|
||||
- name: Login to builtin registry
|
||||
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
|
||||
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
|
||||
with:
|
||||
registry: ${{ env.BUILTIN_REGISTRY }}
|
||||
username: ${{ inputs.registry_user }}
|
||||
@@ -87,7 +87,7 @@ runs:
|
||||
|
||||
- name: Extract metadata (labels, annotations) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6
|
||||
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
|
||||
with:
|
||||
images: ${{ inputs.images }}
|
||||
# default labels & annotations: https://github.com/docker/metadata-action/blob/master/src/meta.ts#L509
|
||||
|
||||
@@ -33,7 +33,7 @@ runs:
|
||||
echo "version=$(rustup --version)" >> $GITHUB_OUTPUT
|
||||
- name: Cache rustup toolchains
|
||||
if: steps.rustup-version.outputs.version == ''
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
~/.rustup
|
||||
|
||||
@@ -17,7 +17,7 @@ inputs:
|
||||
llvm-version:
|
||||
description: 'LLVM version to install'
|
||||
required: false
|
||||
default: '21'
|
||||
default: '20'
|
||||
|
||||
outputs:
|
||||
llvm-version:
|
||||
@@ -57,7 +57,7 @@ runs:
|
||||
|
||||
- name: Check for LLVM cache
|
||||
id: cache
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
/usr/bin/clang-*
|
||||
@@ -120,7 +120,7 @@ runs:
|
||||
|
||||
- name: Install additional packages
|
||||
if: inputs.extra-packages != ''
|
||||
uses: https://github.com/awalsh128/cache-apt-pkgs-action@553a35bb8ebd9fcabcb1c9451aa4c98e1b4ca8a9 # latest
|
||||
uses: https://github.com/awalsh128/cache-apt-pkgs-action@2c09a5e66da6c8016428a2172bd76e5e4f14bb17 # latest
|
||||
with:
|
||||
packages: ${{ inputs.extra-packages }}
|
||||
version: 1.0
|
||||
|
||||
@@ -65,7 +65,7 @@ runs:
|
||||
|
||||
- name: Cache toolchain binaries
|
||||
id: toolchain-cache
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
.cargo/bin
|
||||
@@ -76,7 +76,7 @@ runs:
|
||||
|
||||
- name: Cache Cargo registry and git
|
||||
id: registry-cache
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
.cargo/registry/index
|
||||
|
||||
@@ -31,7 +31,7 @@ runs:
|
||||
|
||||
- name: Restore binary cache
|
||||
id: binary-cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
/usr/share/rust/.cargo/bin
|
||||
@@ -71,13 +71,13 @@ 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@67729d5c413db75907f0ad1e39bb04b9c868ff60 # v2
|
||||
uses: https://github.com/taiki-e/install-action@787505cde8a44ea468a00478fe52baf23b15bccd # v2
|
||||
with:
|
||||
tool: git-warp-time,timelord-cli@3.0.1
|
||||
|
||||
- name: Save binary cache
|
||||
if: steps.check-binaries.outputs.need-install == 'true'
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
/usr/share/rust/.cargo/bin
|
||||
@@ -87,7 +87,7 @@ runs:
|
||||
|
||||
- name: Restore timelord cache with fallbacks
|
||||
id: timelord-restore
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: ${{ env.TIMELORD_CACHE_PATH }}
|
||||
key: ${{ env.TIMELORD_KEY }}
|
||||
@@ -114,7 +114,7 @@ runs:
|
||||
timelord sync --source-dir ${{ env.TIMELORD_PATH }} --cache-dir ${{ env.TIMELORD_CACHE_PATH }}
|
||||
|
||||
- name: Save updated timelord cache immediately
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: ${{ env.TIMELORD_CACHE_PATH }}
|
||||
key: ${{ env.TIMELORD_KEY }}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
- [ ] I have [tested my contribution][c1t] (or proof-read it for documentation-only changes)
|
||||
myself, if applicable. This includes ensuring code compiles.
|
||||
- [ ] My commit messages follow the [commit message format][c1cm] and are descriptive.
|
||||
- [ ] I have written a [news fragment][n1] for this PR, if applicable<!--(can be done after hitting open!)-->.
|
||||
|
||||
<!--
|
||||
Notes on these requirements:
|
||||
@@ -78,3 +79,4 @@
|
||||
[c1pc]: https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/CONTRIBUTING.md#pre-commit-checks
|
||||
[c1t]: https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/CONTRIBUTING.md#running-tests-locally
|
||||
[c1cm]: https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/CONTRIBUTING.md#commit-messages
|
||||
[n1]: https://towncrier.readthedocs.io/en/stable/tutorial.html#creating-news-fragments
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
const labelsToAdd = new Set();
|
||||
|
||||
for (const file of fileNames) {
|
||||
if (file.startsWith('docs/') || file.startsWith('theme/') || (file.endsWith('.md') && !file.startsWith('changelog.d/')) || file == 'rspress.config.ts') {
|
||||
if (file.startsWith('docs/') || file.startsWith('theme/') || file.endsWith('.md') || file == 'rspress.config.ts') {
|
||||
labelsToAdd.add('Documentation');
|
||||
}
|
||||
if (file.startsWith('.forgejo/')) {
|
||||
|
||||
@@ -10,7 +10,7 @@ on:
|
||||
- "v*.*.*"
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '30 0 * * 1'
|
||||
- cron: '30 0 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -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 }}"
|
||||
|
||||
@@ -44,20 +43,20 @@ jobs:
|
||||
# fi
|
||||
|
||||
- name: Checkout repository with full history
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref_name }}
|
||||
|
||||
- name: Cache Cargo registry
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
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: |
|
||||
@@ -127,10 +82,10 @@ jobs:
|
||||
# VERSION is the package version, COMPONENT is used in
|
||||
# apt's repository config like a git repo branch
|
||||
VERSION=$BASE_VERSION
|
||||
if [[ ${{ forge.ref_name }} =~ ^v+[0-9]+\.+[0-9]+\.+[0-9]+$ ]]; then
|
||||
if [[ ${{ forge.ref_name }} =~ ^v+[0-9]\.+[0-9]\.+[0-9]$ ]]; then
|
||||
# Use the "stable" component for tagged semver releases
|
||||
COMPONENT="stable"
|
||||
elif [[ ${{ forge.ref_name }} =~ ^v+[0-9]+\.+[0-9]+\.+[0-9]+ ]]; then
|
||||
elif [[ ${{ forge.ref_name }} =~ ^v+[0-9]\.+[0-9]\.+[0-9] ]]; then
|
||||
# Use the "unstable" component for tagged semver pre-releases
|
||||
COMPONENT="unstable"
|
||||
else
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
name: Build / Fedora RPM
|
||||
|
||||
concurrency:
|
||||
group: "build-fedora-${{ github.ref }}"
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
# paths:
|
||||
# - 'pkg/fedora/**'
|
||||
# - 'src/**'
|
||||
# - 'Cargo.toml'
|
||||
# - 'Cargo.lock'
|
||||
# - '.forgejo/workflows/build-fedora.yml'
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '30 0 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: fedora-latest
|
||||
steps:
|
||||
- name: Detect Fedora version
|
||||
id: fedora
|
||||
run: |
|
||||
VERSION=$(rpm -E %fedora)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Fedora version: $VERSION"
|
||||
|
||||
- name: Checkout repository with full history
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref_name }}
|
||||
|
||||
|
||||
- name: Cache DNF packages
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
/var/cache/dnf
|
||||
/var/cache/yum
|
||||
key: dnf-fedora${{ steps.fedora.outputs.version }}-${{ hashFiles('pkg/fedora/continuwuity.spec.rpkg') }}-v1
|
||||
restore-keys: |
|
||||
dnf-fedora${{ steps.fedora.outputs.version }}-
|
||||
|
||||
- name: Cache Cargo registry
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: cargo-fedora${{ steps.fedora.outputs.version }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
cargo-fedora${{ steps.fedora.outputs.version }}-
|
||||
|
||||
- name: Cache Rust build dependencies
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
~/rpmbuild/BUILD/*/target/release/deps
|
||||
~/rpmbuild/BUILD/*/target/release/build
|
||||
~/rpmbuild/BUILD/*/target/release/.fingerprint
|
||||
~/rpmbuild/BUILD/*/target/release/incremental
|
||||
key: rust-deps-fedora${{ steps.fedora.outputs.version }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
rust-deps-fedora${{ steps.fedora.outputs.version }}-
|
||||
|
||||
- name: Setup sccache
|
||||
uses: https://git.tomfos.tr/tom/sccache-action@v1
|
||||
|
||||
- name: Configure sccache environment
|
||||
run: |
|
||||
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
|
||||
echo "CMAKE_C_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
|
||||
echo "CMAKE_CXX_COMPILER_LAUNCHER=sccache" >> $GITHUB_ENV
|
||||
echo "SCCACHE_CACHE_SIZE=10G" >> $GITHUB_ENV
|
||||
# Aggressive GC since cache restores don't increment counter
|
||||
echo "CARGO_INCREMENTAL_GC_TRIGGER=5" >> $GITHUB_ENV
|
||||
|
||||
- name: Install base RPM tools
|
||||
run: |
|
||||
dnf install -y --setopt=keepcache=1 \
|
||||
fedora-packager \
|
||||
python3-pip \
|
||||
rpm-sign \
|
||||
rpkg \
|
||||
wget
|
||||
|
||||
- name: Setup build environment and build SRPM
|
||||
run: |
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
git config --global user.email "ci@continuwuity.org"
|
||||
git config --global user.name "Continuwuity"
|
||||
|
||||
rpmdev-setuptree
|
||||
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
|
||||
# Determine release suffix and version based on ref type and branch
|
||||
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
||||
# Tags get clean version numbers for stable releases
|
||||
RELEASE_SUFFIX=""
|
||||
TAG_NAME="${{ github.ref_name }}"
|
||||
# Extract version from tag (remove v prefix if present)
|
||||
TAG_VERSION=$(echo "$TAG_NAME" | sed 's/^v//' | tr '-' '~')
|
||||
|
||||
# Create spec file with tag version
|
||||
sed -e "s/^Version:.*$/Version: $TAG_VERSION/" \
|
||||
-e "s/^Release:.*$/Release: 1%{?dist}/" \
|
||||
pkg/fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
|
||||
elif [ "${{ github.ref_name }}" = "main" ]; then
|
||||
# Main branch gets .dev suffix
|
||||
RELEASE_SUFFIX=".dev"
|
||||
|
||||
# Replace the Release line to include our suffix
|
||||
sed "s/^Release:.*$/Release: 1${RELEASE_SUFFIX}%{?dist}/" \
|
||||
pkg/fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
|
||||
else
|
||||
# Other branches get sanitized branch name as suffix
|
||||
SAFE_BRANCH=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/_/g' | cut -c1-20)
|
||||
RELEASE_SUFFIX=".${SAFE_BRANCH}"
|
||||
|
||||
# Replace the Release line to include our suffix
|
||||
sed "s/^Release:.*$/Release: 1${RELEASE_SUFFIX}%{?dist}/" \
|
||||
pkg/fedora/continuwuity.spec.rpkg > continuwuity.spec.rpkg
|
||||
fi
|
||||
|
||||
rpkg srpm --outdir "$HOME/rpmbuild/SRPMS"
|
||||
|
||||
ls -la $HOME/rpmbuild/SRPMS/
|
||||
|
||||
|
||||
- name: Install build dependencies from SRPM
|
||||
run: |
|
||||
SRPM=$(find "$HOME/rpmbuild/SRPMS" -name "*.src.rpm" | head -1)
|
||||
|
||||
if [ -z "$SRPM" ]; then
|
||||
echo "Error: No SRPM file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Installing build dependencies from: $(basename $SRPM)"
|
||||
dnf builddep -y "$SRPM"
|
||||
|
||||
- name: Build RPM from SRPM
|
||||
run: |
|
||||
SRPM=$(find "$HOME/rpmbuild/SRPMS" -name "*.src.rpm" | head -1)
|
||||
|
||||
if [ -z "$SRPM" ]; then
|
||||
echo "Error: No SRPM file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Building from SRPM: $SRPM"
|
||||
|
||||
rpmbuild --rebuild "$SRPM" \
|
||||
--define "_topdir $HOME/rpmbuild" \
|
||||
--define "_sourcedir $GITHUB_WORKSPACE" \
|
||||
--nocheck # Skip %check section to avoid test dependencies
|
||||
|
||||
|
||||
- name: Test RPM installation
|
||||
run: |
|
||||
# Find the main binary RPM (exclude debug and source RPMs)
|
||||
RPM=$(find "$HOME/rpmbuild/RPMS" -name "continuwuity-*.rpm" \
|
||||
! -name "*debuginfo*" \
|
||||
! -name "*debugsource*" \
|
||||
! -name "*.src.rpm" | head -1)
|
||||
|
||||
if [ -z "$RPM" ]; then
|
||||
echo "Error: No binary RPM file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Testing installation of: $RPM"
|
||||
|
||||
# Dry run first
|
||||
rpm -qpi "$RPM"
|
||||
echo ""
|
||||
rpm -qpl "$RPM"
|
||||
|
||||
# Actually install it
|
||||
dnf install -y "$RPM"
|
||||
|
||||
# Verify installation
|
||||
rpm -qa | grep continuwuity
|
||||
|
||||
# Check that the binary exists
|
||||
[ -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"
|
||||
|
||||
- name: List built packages
|
||||
run: |
|
||||
echo "Binary RPMs:"
|
||||
find "$HOME/rpmbuild/RPMS" -name "*.rpm" -type f -exec ls -la {} \;
|
||||
|
||||
echo ""
|
||||
echo "Source RPMs:"
|
||||
find "$HOME/rpmbuild/SRPMS" -name "*.rpm" -type f -exec ls -la {} \;
|
||||
|
||||
- name: Collect artifacts
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
|
||||
find "$HOME/rpmbuild/RPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \;
|
||||
find "$HOME/rpmbuild/SRPMS" -name "*.rpm" -type f -exec cp {} artifacts/ \;
|
||||
|
||||
cd artifacts
|
||||
echo "Build Information:" > BUILD_INFO.txt
|
||||
echo "==================" >> BUILD_INFO.txt
|
||||
echo "Git commit: ${{ github.sha }}" >> BUILD_INFO.txt
|
||||
echo "Git branch: ${{ github.ref_name }}" >> BUILD_INFO.txt
|
||||
echo "Build date: $(date -u +%Y-%m-%d_%H:%M:%S_UTC)" >> BUILD_INFO.txt
|
||||
echo "" >> BUILD_INFO.txt
|
||||
echo "Package contents:" >> BUILD_INFO.txt
|
||||
echo "-----------------" >> BUILD_INFO.txt
|
||||
for rpm in *.rpm; do
|
||||
echo "" >> BUILD_INFO.txt
|
||||
echo "File: $rpm" >> BUILD_INFO.txt
|
||||
rpm -qpi "$rpm" 2>/dev/null | grep -E "^(Name|Version|Release|Architecture|Size)" >> BUILD_INFO.txt
|
||||
done
|
||||
|
||||
ls -la
|
||||
|
||||
- name: Upload binary RPM artifact
|
||||
run: |
|
||||
# Find the main binary RPM (exclude debug and source RPMs)
|
||||
BIN_RPM=$(find artifacts -name "continuwuity-*.rpm" \
|
||||
! -name "*debuginfo*" \
|
||||
! -name "*debugsource*" \
|
||||
! -name "*.src.rpm" \
|
||||
-type f)
|
||||
|
||||
mkdir -p upload-bin
|
||||
cp $BIN_RPM upload-bin/
|
||||
|
||||
- name: Upload binary RPM
|
||||
uses: forgejo/upload-artifact@v4
|
||||
with:
|
||||
name: continuwuity
|
||||
path: upload-bin/
|
||||
|
||||
- name: Upload debug RPM artifact
|
||||
uses: forgejo/upload-artifact@v4
|
||||
with:
|
||||
name: continuwuity-debug
|
||||
path: artifacts/*debuginfo*.rpm
|
||||
|
||||
- name: Publish to RPM Package Registry
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }}
|
||||
run: |
|
||||
# Find the main binary RPM (exclude debug and source RPMs)
|
||||
RPM=$(find artifacts -name "continuwuity-*.rpm" \
|
||||
! -name "*debuginfo*" \
|
||||
! -name "*debugsource*" \
|
||||
! -name "*.src.rpm" \
|
||||
-type f | head -1)
|
||||
|
||||
if [ -z "$RPM" ]; then
|
||||
echo "No binary RPM found to publish"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
RPM_BASENAME=$(basename "$RPM")
|
||||
echo "Publishing: $RPM_BASENAME"
|
||||
|
||||
# Determine the group based on ref type and branch
|
||||
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
||||
# For tags, extract the tag name for version info
|
||||
TAG_NAME="${{ github.ref_name }}"
|
||||
if [[ "$TAG_NAME" == *"-"* ]]; then
|
||||
GROUP="unstable"
|
||||
else
|
||||
GROUP="stable"
|
||||
fi
|
||||
elif [ "${{ github.ref_name }}" = "main" ]; then
|
||||
GROUP="dev"
|
||||
else
|
||||
# Use sanitized branch name as group for feature branches
|
||||
GROUP=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9]/-/g' | tr '[:upper:]' '[:lower:]' | cut -c1-30)
|
||||
fi
|
||||
|
||||
PACKAGE_INFO=$(rpm -qpi "$RPM" 2>/dev/null)
|
||||
PACKAGE_NAME=$(echo "$PACKAGE_INFO" | grep "^Name" | awk '{print $3}')
|
||||
PACKAGE_VERSION=$(echo "$PACKAGE_INFO" | grep "^Version" | awk '{print $3}')
|
||||
PACKAGE_RELEASE=$(echo "$PACKAGE_INFO" | grep "^Release" | awk '{print $3}')
|
||||
PACKAGE_ARCH=$(echo "$PACKAGE_INFO" | grep "^Architecture" | awk '{print $2}')
|
||||
|
||||
# Full version includes release
|
||||
FULL_VERSION="${PACKAGE_VERSION}-${PACKAGE_RELEASE}"
|
||||
|
||||
# Forgejo's RPM registry cannot overwrite existing packages, so we must delete first
|
||||
# 404 is OK if package doesn't exist yet
|
||||
echo "Removing any existing package: $PACKAGE_NAME-$FULL_VERSION.$PACKAGE_ARCH"
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/package/$PACKAGE_NAME/$FULL_VERSION/$PACKAGE_ARCH")
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
|
||||
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
|
||||
echo "ERROR: Failed to delete package (HTTP $HTTP_CODE)"
|
||||
echo "$RESPONSE" | head -n -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl --fail-with-body \
|
||||
-X PUT \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
-H "Content-Type: application/x-rpm" \
|
||||
-T "$RPM" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/$GROUP/upload?sign=true"
|
||||
|
||||
echo ""
|
||||
echo "✅ Published binary RPM to: https://forgejo.ellis.link/continuwuation/-/packages/rpm/continuwuity/"
|
||||
echo "Group: $GROUP"
|
||||
|
||||
# Upload debug RPMs to separate group
|
||||
DEBUG_RPMS=$(find artifacts -name "*debuginfo*.rpm")
|
||||
if [ -n "$DEBUG_RPMS" ]; then
|
||||
echo ""
|
||||
echo "Publishing debug RPMs to group: ${GROUP}-debug"
|
||||
|
||||
for DEBUG_RPM in $DEBUG_RPMS; do
|
||||
echo "Publishing: $(basename "$DEBUG_RPM")"
|
||||
|
||||
DEBUG_INFO=$(rpm -qpi "$DEBUG_RPM" 2>/dev/null)
|
||||
DEBUG_NAME=$(echo "$DEBUG_INFO" | grep "^Name" | awk '{print $3}')
|
||||
DEBUG_VERSION=$(echo "$DEBUG_INFO" | grep "^Version" | awk '{print $3}')
|
||||
DEBUG_RELEASE=$(echo "$DEBUG_INFO" | grep "^Release" | awk '{print $3}')
|
||||
DEBUG_ARCH=$(echo "$DEBUG_INFO" | grep "^Architecture" | awk '{print $2}')
|
||||
DEBUG_FULL_VERSION="${DEBUG_VERSION}-${DEBUG_RELEASE}"
|
||||
|
||||
# Must delete existing package first (Forgejo limitation)
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-debug/package/$DEBUG_NAME/$DEBUG_FULL_VERSION/$DEBUG_ARCH")
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
|
||||
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
|
||||
echo "ERROR: Failed to delete debug package (HTTP $HTTP_CODE)"
|
||||
echo "$RESPONSE" | head -n -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl --fail-with-body \
|
||||
-X PUT \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
-H "Content-Type: application/x-rpm" \
|
||||
-T "$DEBUG_RPM" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-debug/upload?sign=true"
|
||||
done
|
||||
|
||||
echo "✅ Published debug RPMs to group: ${GROUP}-debug"
|
||||
fi
|
||||
|
||||
# Also upload the SRPM to separate group
|
||||
SRPM=$(find artifacts -name "*.src.rpm" | head -1)
|
||||
if [ -n "$SRPM" ]; then
|
||||
echo ""
|
||||
echo "Publishing source RPM: $(basename "$SRPM")"
|
||||
echo "Publishing to group: ${GROUP}-src"
|
||||
|
||||
SRPM_INFO=$(rpm -qpi "$SRPM" 2>/dev/null)
|
||||
SRPM_NAME=$(echo "$SRPM_INFO" | grep "^Name" | awk '{print $3}')
|
||||
SRPM_VERSION=$(echo "$SRPM_INFO" | grep "^Version" | awk '{print $3}')
|
||||
SRPM_RELEASE=$(echo "$SRPM_INFO" | grep "^Release" | awk '{print $3}')
|
||||
SRPM_FULL_VERSION="${SRPM_VERSION}-${SRPM_RELEASE}"
|
||||
|
||||
# Must delete existing SRPM first (Forgejo limitation)
|
||||
echo "Removing any existing SRPM: $SRPM_NAME-$SRPM_FULL_VERSION.src"
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-src/package/$SRPM_NAME/$SRPM_FULL_VERSION/src")
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
|
||||
if [ "$HTTP_CODE" != "204" ] && [ "$HTTP_CODE" != "404" ]; then
|
||||
echo "ERROR: Failed to delete SRPM (HTTP $HTTP_CODE)"
|
||||
echo "$RESPONSE" | head -n -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl --fail-with-body \
|
||||
-X PUT \
|
||||
-H "Authorization: token ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}" \
|
||||
-H "Content-Type: application/x-rpm" \
|
||||
-T "$SRPM" \
|
||||
"https://forgejo.ellis.link/api/packages/continuwuation/rpm/${GROUP}-src/upload?sign=true"
|
||||
|
||||
echo "✅ Published source RPM to group: ${GROUP}-src"
|
||||
fi
|
||||
@@ -10,7 +10,7 @@ on:
|
||||
- "v*.*.*"
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '30 0 * * 3'
|
||||
- cron: '30 0 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
path: binaries
|
||||
merge-multiple: true
|
||||
- name: Create Release and Upload
|
||||
uses: https://github.com/softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3
|
||||
uses: https://github.com/softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3
|
||||
with:
|
||||
draft: true
|
||||
files: binaries/*
|
||||
|
||||
@@ -14,19 +14,23 @@ jobs:
|
||||
name: Check changelog is added
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
sparse-checkout: .
|
||||
|
||||
- name: Check for changelog entry
|
||||
id: check_files
|
||||
run: |
|
||||
AUTH=$(echo -n "x-access-token:${{ secrets.GITHUB_TOKEN }}" | base64 -w 0)
|
||||
git config --global http.${{ github.server_url }}/.extraheader "Authorization: basic $AUTH"
|
||||
git clone "${{ github.event.repository.clone_url }}" repo.git --bare
|
||||
|
||||
git -C repo.git fetch origin pull/${{ github.event.pull_request.number }}/head
|
||||
git fetch origin ${GITHUB_BASE_REF}
|
||||
|
||||
# Check for Added (A) or Modified (M) files in changelog.d
|
||||
CHANGELOG_CHANGES=$(git -C repo.git diff --name-status ${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }} -- changelog.d/)
|
||||
CHANGELOG_CHANGES=$(git diff --name-status origin/${GITHUB_BASE_REF}...HEAD -- changelog.d/)
|
||||
|
||||
SRC_CHANGES=$(git -C repo.git diff --name-status ${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }} -- src/)
|
||||
SRC_CHANGES=$(git diff --name-status origin/${GITHUB_BASE_REF}...HEAD -- src/)
|
||||
|
||||
echo "Changes in changelog.d/:"
|
||||
echo "$CHANGELOG_CHANGES"
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Sync repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
@@ -32,12 +32,12 @@ jobs:
|
||||
|
||||
- name: Setup Node.js
|
||||
if: steps.runner-env.outputs.node_major == '' || steps.runner-env.outputs.node_major < '20'
|
||||
uses: https://github.com/actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
||||
uses: https://github.com/actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Cache npm dependencies
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: continuwuity-rspress-${{ steps.runner-env.outputs.slug }}-${{ steps.runner-env.outputs.arch }}-node-${{ steps.runner-env.outputs.node_version }}-${{ hashFiles('package-lock.json') }}
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
|
||||
- name: Deploy to Cloudflare Pages (Production)
|
||||
if: github.ref == 'refs/heads/main' && vars.CLOUDFLARE_PROJECT_NAME != ''
|
||||
uses: https://github.com/cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4
|
||||
uses: https://github.com/cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3
|
||||
with:
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
|
||||
- name: Deploy to Cloudflare Pages (Preview)
|
||||
if: github.ref != 'refs/heads/main' && vars.CLOUDFLARE_PROJECT_NAME != ''
|
||||
uses: https://github.com/cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4
|
||||
uses: https://github.com/cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3
|
||||
with:
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 📦 Setup Node.js
|
||||
uses: https://github.com/actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
||||
uses: https://github.com/actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
- name: 🚀 Deploy to Cloudflare Pages
|
||||
if: vars.CLOUDFLARE_PROJECT_NAME != ''
|
||||
id: deploy
|
||||
uses: https://github.com/cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4
|
||||
uses: https://github.com/cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3
|
||||
with:
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
DOCKER_MIRROR_TOKEN: ${{ secrets.DOCKER_MIRROR_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
# repositories: continuwuity
|
||||
|
||||
- name: Install regsync
|
||||
uses: https://github.com/regclient/actions/regsync-installer@5c882eb04fcca27ebb4f5904e0da01f0780063ea # main
|
||||
uses: https://github.com/regclient/actions/regsync-installer@f3c6d87835906c175eb6ccfc18b348b69bb447e7 # main
|
||||
|
||||
- name: Check what images need mirroring
|
||||
run: |
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -48,12 +48,12 @@ jobs:
|
||||
rust: ${{ steps.filter.outputs.rust }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Check for file changes
|
||||
uses: https://github.com/dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4
|
||||
uses: https://github.com/dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Prepare Docker build environment
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
registry_password: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push Docker image by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
|
||||
with:
|
||||
context: .
|
||||
file: "docker/Dockerfile"
|
||||
@@ -74,7 +74,6 @@ jobs:
|
||||
CARGO_INCREMENTAL=${{ env.BUILDKIT_ENDPOINT != '' && '1' || '0' }}
|
||||
TARGET_CPU=
|
||||
RUST_PROFILE=release
|
||||
CARGO_FEATURES=default
|
||||
platforms: ${{ matrix.platform }}
|
||||
labels: ${{ steps.prepare.outputs.metadata_labels }}
|
||||
annotations: ${{ steps.prepare.outputs.metadata_annotations }}
|
||||
@@ -101,7 +100,7 @@ jobs:
|
||||
needs: build-release
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Create multi-platform manifest
|
||||
@@ -134,7 +133,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Prepare max-perf Docker build environment
|
||||
@@ -150,7 +149,7 @@ jobs:
|
||||
registry_password: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push max-perf Docker image by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
|
||||
with:
|
||||
context: .
|
||||
file: "docker/Dockerfile"
|
||||
@@ -162,7 +161,6 @@ jobs:
|
||||
CARGO_INCREMENTAL=${{ env.BUILDKIT_ENDPOINT != '' && '1' || '0' }}
|
||||
TARGET_CPU=${{ matrix.target_cpu }}
|
||||
RUST_PROFILE=release-max-perf
|
||||
CARGO_FEATURES=default,release_max_log_level
|
||||
platforms: ${{ matrix.platform }}
|
||||
labels: ${{ steps.prepare.outputs.metadata_labels }}
|
||||
annotations: ${{ steps.prepare.outputs.metadata_annotations }}
|
||||
@@ -189,7 +187,7 @@ jobs:
|
||||
needs: build-maxperf
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Create max-perf manifest
|
||||
@@ -218,7 +216,7 @@ jobs:
|
||||
path: binaries
|
||||
merge-multiple: true
|
||||
- name: Create Release and Upload
|
||||
uses: https://github.com/softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3
|
||||
uses: https://github.com/softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: true
|
||||
files: binaries/*
|
||||
|
||||
@@ -43,11 +43,11 @@ jobs:
|
||||
name: Renovate
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/renovatebot/renovate:43.288.0@sha256:bcde7a061ab42d1ae6d4500769d80727e5694bb889dbcbf1005e9f4e741ab76d
|
||||
image: ghcr.io/renovatebot/renovate:43.140.0@sha256:61303c28b10a491c559529fb6f41745850e4755a43a54c04c3ae6848d6eaf5cc
|
||||
options: --tmpfs /tmp:exec
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
run: /usr/local/renovate/node -e 'console.log(`node heap limit = ${require("v8").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'
|
||||
|
||||
- name: Restore renovate repo cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
/tmp/renovate/cache/renovate/repository
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
renovate-repo-cache-
|
||||
|
||||
- name: Restore renovate package cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
/tmp/renovate/cache/renovate/renovate-cache-sqlite
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
renovate-package-cache-
|
||||
|
||||
- name: Restore renovate OSV cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
/tmp/osv
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
|
||||
- name: Save renovate package cache
|
||||
if: always()
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
/tmp/renovate/cache/renovate/renovate-cache-sqlite
|
||||
@@ -125,7 +125,7 @@ jobs:
|
||||
|
||||
- name: Save renovate OSV cache
|
||||
if: always()
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
/tmp/osv
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
update-flake-hashes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: true
|
||||
token: ${{ secrets.FORGEJO_TOKEN }}
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
- name: Get new toolchain hash
|
||||
run: |
|
||||
# Set the current sha256 to an empty hash to make `nix build` calculate a new one
|
||||
awk '/fromToolchainName *\{/{found=1; print; next} found && /sha256 =/{sub(/sha256 = .*/, "sha256 = lib.fakeSha256;"); found=0} 1' nix/rust.nix > temp.nix
|
||||
awk '/fromToolchainFile *\{/{found=1; print; next} found && /sha256 =/{sub(/sha256 = .*/, "sha256 = lib.fakeSha256;"); found=0} 1' nix/rust.nix > temp.nix
|
||||
mv temp.nix nix/rust.nix
|
||||
|
||||
# Build continuwuity and filter for the new hash
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
sed -i "s|lib.fakeSha256|\"$new_hash\"|" nix/rust.nix
|
||||
|
||||
echo "New hash:"
|
||||
awk -F'"' '/fromToolchainName/{found=1; next} found && /sha256 =/{print $2; found=0}' nix/rust.nix
|
||||
awk -F'"' '/fromToolchainFile/{found=1; next} found && /sha256 =/{print $2; found=0}' nix/rust.nix
|
||||
echo "Expected new hash:"
|
||||
cat new_toolchain_hash.txt
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
github: [JadedBlueEyes, timedoutuk, gingershaped]
|
||||
github: [JadedBlueEyes, nexy7574, gingershaped]
|
||||
custom:
|
||||
- https://timedout.uk/donate.html
|
||||
- https://jade.ellis.link/sponsors
|
||||
|
||||
+1
-13
@@ -24,7 +24,7 @@ repos:
|
||||
- id: check-added-large-files
|
||||
|
||||
- repo: https://github.com/crate-ci/typos
|
||||
rev: v1.49.0
|
||||
rev: v1.45.2
|
||||
hooks:
|
||||
- id: typos
|
||||
- id: typos
|
||||
@@ -57,15 +57,3 @@ repos:
|
||||
types: [rust]
|
||||
stages:
|
||||
- pre-push
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: docs-build
|
||||
name: docs build
|
||||
entry: npm run docs:build
|
||||
language: system
|
||||
pass_filenames: false
|
||||
files: docs/
|
||||
types: [mdx]
|
||||
stages:
|
||||
- pre-commit
|
||||
|
||||
+173
-224
@@ -1,192 +1,96 @@
|
||||
# Continuwuity v26.7.2 (2026-07-30)
|
||||
# Continuwuity 0.5.11 (2026-06-20 take 2)
|
||||
|
||||
## Bugfixes
|
||||
This release purely contains some fix for the Nix package. There are no changes to the server itself.
|
||||
|
||||
- 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 0.5.10 (2026-06-20)
|
||||
|
||||
# Continuwuity 26.7.0 (2026-07-27)
|
||||
## Security
|
||||
|
||||
## Features
|
||||
- Fixed a bug that allowed a remote server to send to-device messages to a non-local user. Reported
|
||||
by [echoray](https://github.com/raidenrayray).
|
||||
- Fixed a bug that allowed local users to request URL previews of explicitly forbidden domains. Reported
|
||||
by [echoray](https://github.com/raidenrayray).
|
||||
- Fixed a bug that permitted authentication as a dehydrated device. Reported by @stratself.
|
||||
|
||||
- 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.
|
||||
# Continuwuity 0.5.9 (2026-05-07)
|
||||
|
||||
## Bugfixes
|
||||
## Security
|
||||
|
||||
- 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.
|
||||
|
||||
# Continuwuity 26.6.1 (2026-07-12)
|
||||
|
||||
## Features
|
||||
|
||||
- Added enforcement for new federated invite checks and corrected a bunch of related spec compliance issues along the way. Contributed by @nex. (#1952)
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- Fixed existing accounts failing to link when logging in with OIDC if `prompt_for_localpart` was `false`. (#1942)
|
||||
- Authentication is no longer required on the `/_matrix/client/v3/account/3pid/email/requestToken` endpoint. (#1953)
|
||||
- Fixed newly created rooms failing to sync properly in clients using legacy sync.
|
||||
- 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
|
||||
|
||||
- Added support for linking an external identity provider with OIDC. Contributed by @ginger. (#765)
|
||||
- Updated [MSC4284: Policy Servers](https://github.com/matrix-org/matrix-spec-proposals/pull/4284) implementation to support the newly stabilised proposal. Contributed by @nex. (#1487)
|
||||
- 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.
|
||||
|
||||
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)
|
||||
- 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)
|
||||
- Added support for MSC4466, which allows clients to customize how changes to a user's global profile are propagated. Contributed by @ginger.
|
||||
- Added support for Matrix 1.16's `state_after` feature, allowing clients which understand it to sync room state changes more reliably. Contributed by @ginger.
|
||||
- Added support for authenticating clients using the new OAuth 2.0 login API. Contributed by @ginger.
|
||||
- Appservice device management as outlined in MSC4190 (part of Matrix 1.17) is now fully supported. Contributed by @ginger.
|
||||
- Users may now be forbidden from deactivating their own accounts with the new `allow_deactivation` config option. Contributed by @ginger.
|
||||
|
||||
## 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)
|
||||
- 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 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.
|
||||
- Improved invite and join reliability in clients using legacy sync. Contributed by @ginger
|
||||
- The invite recipient's membership event is now included in invite stripped state, which should fix flaky invite display in some clients. Contributed by @ginger
|
||||
|
||||
## Improved Documentation
|
||||
|
||||
- Add performance tuning documentation. Contributed by @stratself. (#1498)
|
||||
- Explain accessing Continuwuity's server console when deployed via Docker. (#1671)
|
||||
- Clarified in the config that `max_request_size` affects federated media as well. (#1706)
|
||||
- Added example configuration using caddy-docker-proxy in the livekit setup section of the docs. Contributed by @Cease (#1762)
|
||||
- Updated deployment docs to account for new RPM package availability across more distros. Contributed by @julian45. (#1912)
|
||||
|
||||
## Deprecations and Removals
|
||||
|
||||
- Removed support for LDAP. (#1701)
|
||||
- Removed support for guest user registration, a little-used and deprecated approach to room previews.
|
||||
- Removed the `/_conduwuit/` versions of the `local_user_count` and `version` routes. These routes are still accessible under the `/_continuwuity` prefix.
|
||||
- Support for server-side blurhashing (part of MSC2448) has been removed.
|
||||
- The deprecated `well_known.rtc_focus_server_urls` config option has been removed. MatrixRTC foci should be configured using the `matrix_rtc.foci` config option.
|
||||
|
||||
## 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
|
||||
- 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)
|
||||
- Fixed a bug that caused the server to panic while handling transactions with malformed events, resulting in a
|
||||
deadlock that prevented the remote server from federating with us until the server was restarted. Contributed by @nex.
|
||||
- Fixed a bug that resulted in the `m.federate` field of `m.room.create` being ignored in v12 rooms, allowing remote
|
||||
servers to participate in local-only rooms. Contributed by @nex, reported
|
||||
by [@mat:emzee.ee](matrix:u/mat:emzee.ee?action=chat).
|
||||
|
||||
# Continuwuity 0.5.8 (2026-04-24)
|
||||
|
||||
## Features
|
||||
|
||||
- LDAP can now optionally be connected to using StartTLS, and you may unsafely skip verification. Contributed by @getz (#1389)
|
||||
- Users will now be prevented from removing their email if the server is configured to require an email when registering an account.
|
||||
- LDAP can now optionally be connected to using StartTLS, and you may unsafely skip verification. Contributed by @getz (
|
||||
#1389)
|
||||
- Users will now be prevented from removing their email if the server is configured to require an email when registering
|
||||
an account.
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- Fixed a situation where multiple email addresses could be associated with one user when that user changes their email address.
|
||||
- Fixed a situation where multiple email addresses could be associated with one user when that user changes their email
|
||||
address.
|
||||
|
||||
## 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)
|
||||
- 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
|
||||
|
||||
- Re-added support for reading registration tokens from a file. Contributed by @ginger and @benbot. (#1371)
|
||||
- Add new config option to allow or disallow search engine indexing through a `<meta ../>` tag. Defaults to blocking indexing (`content="noindex"`). Contributed by @s1lv3r and @ginger. (#1527)
|
||||
- Add new config option to allow or disallow search engine indexing through a `<meta ../>` tag. Defaults to blocking
|
||||
indexing (`content="noindex"`). Contributed by @s1lv3r and @ginger. (#1527)
|
||||
- Add new config option for [MSC4439](https://github.com/matrix-org/matrix-spec-proposals/pull/4439)
|
||||
PGP key URIs. Contributed by LogN. (#1609)
|
||||
- Added `!admin users reset-push-rules` command to reset the notification settings of users. Contributed by @nex. (#1613)
|
||||
- Notification pushers are now automatically removed when their associated device is. Admin commands now exist for manual cleanup too. Contributed by @nex. (#1614)
|
||||
- Added `!admin users reset-push-rules` command to reset the notification settings of users. Contributed by @nex. (
|
||||
#1613)
|
||||
- Notification pushers are now automatically removed when their associated device is. Admin commands now exist for
|
||||
manual cleanup too. Contributed by @nex. (#1614)
|
||||
- Implemented option to deprioritize servers for room join requests. Contributed by @ezera. (#1624)
|
||||
- Added admin commands to get build information and features. Contributed by @Jade (#1629)
|
||||
- Added support for associating email addresses with accounts, requiring email addresses for registration, and resetting passwords via email. Contributed by @ginger
|
||||
- Added support for associating email addresses with accounts, requiring email addresses for registration, and resetting
|
||||
passwords via email. Contributed by @ginger
|
||||
- Added support for requiring users to accept terms and conditions when registering.
|
||||
- Added support for using an admin command to issue self-service password reset links.
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- Fixed corrupted appservice registrations causing the server to enter a crash loop. Contributed by @nex. (#1265)
|
||||
- Prevent removing the admin room alias (`#admins`) to avoid accidentally breaking admin room functionality. Contributed by @0xnim (#1448)
|
||||
- Prevent removing the admin room alias (`#admins`) to avoid accidentally breaking admin room functionality. Contributed
|
||||
by @0xnim (#1448)
|
||||
- Stripped `join_authorised_via_users_server` from json if user is already in room (@partha:cxy.run) (#1542)
|
||||
- Fixed internal server errors for fetching thumbnails. Contributed by @PerformativeJade (#1572)
|
||||
- Fixed error 500 when joining non-existent rooms. Contributed by @ezera. (#1579)
|
||||
- Refactored nix package. Breaking, since `all-features` package no longer exists. Continuwuity is now built with jemalloc and liburing by default. Contributed by @Henry-Hiles (QuadRadical). (#1596)
|
||||
- Refactored nix package. Breaking, since `all-features` package no longer exists. Continuwuity is now built with
|
||||
jemalloc and liburing by default. Contributed by @Henry-Hiles (QuadRadical). (#1596)
|
||||
- Fixed resolving IP of servers that only use SRV delegation. Contributed by @tulir. (#1615)
|
||||
- Fixed "Sender must be a local user" error for make_join, make_knock, and make_leave federation routes. Contributed by @nex. (#1623)
|
||||
- Fixed restricted joins not being signed when we are being used as an authorising server. Contributed by @nex, reported by [vel](matrix:u/vel:nhjkl.com?action=chat). (#1630)
|
||||
- Fixed "Sender must be a local user" error for make_join, make_knock, and make_leave federation routes. Contributed by
|
||||
@nex. (#1623)
|
||||
- Fixed restricted joins not being signed when we are being used as an authorising server. Contributed by @nex, reported
|
||||
by [vel](matrix:u/vel:nhjkl.com?action=chat). (#1630)
|
||||
- Fixed room alias deletion so removing one local alias no longer removes other aliases from room alias listings.
|
||||
- Stopped left rooms from being unconditionally sent on initial sync, hopefully fixing spurious appearances of left rooms in some clients (and making sync faster as a bonus). Contributed by @ginger
|
||||
- Stopped left rooms from being unconditionally sent on initial sync, hopefully fixing spurious appearances of left
|
||||
rooms in some clients (and making sync faster as a bonus). Contributed by @ginger
|
||||
- Correct the response field name for MatrixRTC transports. Contributed by @spaetz
|
||||
|
||||
## Improved Documentation
|
||||
|
||||
- Added Testing and Troubleshooting instructions for Livekit documentation. Contributed by @stratself. (#1429)
|
||||
- Refactored docker docs to include new initial token workflow, and add Caddyfile example. Contributed by @stratself. (#1594)
|
||||
- Add DNS tuning guide for Continuwuity. Users are recommended to set up a local caching resolver following the guide's advice. Contributed by @stratself (#1601)
|
||||
- Refactored docker docs to include new initial token workflow, and add Caddyfile example. Contributed by @stratself. (
|
||||
#1594)
|
||||
- Add DNS tuning guide for Continuwuity. Users are recommended to set up a local caching resolver following the guide's
|
||||
advice. Contributed by @stratself (#1601)
|
||||
|
||||
## Misc
|
||||
|
||||
@@ -196,39 +100,53 @@ # Continuwuity 0.5.6 (2026-03-03)
|
||||
|
||||
## Security
|
||||
|
||||
- Admin escape commands received over federation will never be executed, as this is never valid in a genuine situation. Contributed by @Jade.
|
||||
- Fixed data amplification vulnerability (CWE-409) that affected configurations with server-side compression enabled (non-default). Contributed by @nex.
|
||||
- Admin escape commands received over federation will never be executed, as this is never valid in a genuine situation.
|
||||
Contributed by @Jade.
|
||||
- Fixed data amplification vulnerability (CWE-409) that affected configurations with server-side compression enabled (
|
||||
non-default). Contributed by @nex.
|
||||
|
||||
## 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))
|
||||
- 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
|
||||
- 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))
|
||||
|
||||
## 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 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 `!admin media delete --mxc <url>` responding with an error message when the media was deleted successfully. Contributed by @lynxize
|
||||
- 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 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 `!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 +155,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,11 +175,13 @@ ## 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 sliding sync not resolving wildcard state key requests, enabling Video/Audio calls in Element X. ([#1370](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1370))
|
||||
- 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 +191,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 +293,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))
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
Contributors are expected to follow the [Continuwuity Community Guidelines](https://continuwuity.org/community/guidelines).
|
||||
Contributors are expected to follow the [Continuwuity Community Guidelines](continuwuity.org/community/guidelines).
|
||||
|
||||
+5
-5
@@ -26,7 +26,7 @@ ### Pre-commit Checks
|
||||
|
||||
|
||||
```bash
|
||||
# Install prek using cargo-binstall https://github.com/cargo-bins/cargo-binstall
|
||||
# Install prek using cargo-binstall
|
||||
cargo binstall prek
|
||||
|
||||
# Install git hooks to run checks automatically
|
||||
@@ -137,9 +137,9 @@ ### Commit Messages
|
||||
|
||||
Examples:
|
||||
```
|
||||
feat: Add user authentication
|
||||
fix(database): Resolve connection pooling issue
|
||||
docs: Update installation instructions
|
||||
feat: add user authentication
|
||||
fix(database): resolve connection pooling issue
|
||||
docs: update installation instructions
|
||||
```
|
||||
|
||||
The project uses the `committed` hook to validate commit messages in pre-commit. This ensures all commits follow the conventional format.
|
||||
@@ -155,7 +155,7 @@ ### Creating pull requests
|
||||
|
||||
Before submitting a pull request, please ensure:
|
||||
1. Your code passes all CI checks (formatting, linting, typo detection, etc.)
|
||||
2. Your code follows the [code style guide](docs/development/code_style.mdx)
|
||||
2. Your code follows the [code style guide](/development/code_style.md)
|
||||
3. Your commit messages follow the conventional commits format
|
||||
4. Tests are added for new functionality
|
||||
5. Documentation is updated if needed
|
||||
|
||||
Generated
+1533
-1375
File diff suppressed because it is too large
Load Diff
+61
-63
@@ -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 = "0.5.11"
|
||||
|
||||
[workspace.metadata.crane]
|
||||
name = "conduwuit"
|
||||
@@ -39,13 +39,10 @@ features = ["ffi", "std", "union"]
|
||||
version = "1.1.0"
|
||||
|
||||
[workspace.dependencies.ctor]
|
||||
version = "1.0.6"
|
||||
|
||||
[workspace.dependencies.dtor]
|
||||
version = "1.0.0"
|
||||
version = "0.10.0"
|
||||
|
||||
[workspace.dependencies.cargo_toml]
|
||||
version = "1.0"
|
||||
version = "0.22"
|
||||
default-features = false
|
||||
features = ["features"]
|
||||
|
||||
@@ -71,7 +68,7 @@ default-features = false
|
||||
version = "0.1.3"
|
||||
|
||||
[workspace.dependencies.rand]
|
||||
version = "0.10.1"
|
||||
version = "0.10.0"
|
||||
|
||||
# Used for the http request / response body type for Ruma endpoints used with reqwest
|
||||
[workspace.dependencies.bytes]
|
||||
@@ -115,8 +112,8 @@ git = "https://github.com/vinchona/axum-server-dual-protocol.git"
|
||||
rev = "ca6db055254255b74238673ce4135698e347d71c" # feat!: bump axum_server to 0.8.0
|
||||
default-features = false
|
||||
|
||||
[workspace.dependencies.client-ip]
|
||||
version = "0.2"
|
||||
[workspace.dependencies.axum-client-ip]
|
||||
version = "1.3"
|
||||
|
||||
[workspace.dependencies.tower]
|
||||
version = "0.5.2"
|
||||
@@ -124,7 +121,7 @@ default-features = false
|
||||
features = ["util"]
|
||||
|
||||
[workspace.dependencies.tower-http]
|
||||
version = "0.7.0"
|
||||
version = "0.6.8"
|
||||
default-features = false
|
||||
features = [
|
||||
"add-extension",
|
||||
@@ -164,7 +161,7 @@ features = ["raw_value"]
|
||||
|
||||
# Used for appservice registration files
|
||||
[workspace.dependencies.serde-saphyr]
|
||||
version = "0.0.29"
|
||||
version = "0.0.24"
|
||||
|
||||
# Used to load forbidden room/user regex from config
|
||||
[workspace.dependencies.serde_regex]
|
||||
@@ -180,7 +177,7 @@ version = "0.5.3"
|
||||
features = ["alloc", "rand"]
|
||||
default-features = false
|
||||
|
||||
# Used to generate thumbnails for images
|
||||
# Used to generate thumbnails for images & blurhashes
|
||||
[workspace.dependencies.image]
|
||||
version = "0.25.5"
|
||||
default-features = false
|
||||
@@ -191,6 +188,14 @@ features = [
|
||||
"webp",
|
||||
]
|
||||
|
||||
[workspace.dependencies.blurhash]
|
||||
version = "0.2.3"
|
||||
default-features = false
|
||||
features = [
|
||||
"fast-linear-to-srgb",
|
||||
"image",
|
||||
]
|
||||
|
||||
# logging
|
||||
[workspace.dependencies.log]
|
||||
version = "0.4.27"
|
||||
@@ -296,7 +301,7 @@ default-features = false
|
||||
features = ["env", "toml"]
|
||||
|
||||
[workspace.dependencies.hickory-resolver]
|
||||
version = "0.26.0"
|
||||
version = "0.25.2"
|
||||
default-features = false
|
||||
features = [
|
||||
"serde",
|
||||
@@ -316,7 +321,7 @@ default-features = false
|
||||
|
||||
# Used to make working with iterators easier, was already a transitive depdendency
|
||||
[workspace.dependencies.itertools]
|
||||
version = "0.15.0"
|
||||
version = "0.14.0"
|
||||
|
||||
# to parse user-friendly time durations in admin commands
|
||||
#TODO: overlaps chrono?
|
||||
@@ -337,55 +342,56 @@ version = "0.1.88"
|
||||
[workspace.dependencies.lru-cache]
|
||||
version = "0.1.2"
|
||||
|
||||
[workspace.dependencies.assign]
|
||||
version = "1.1.1"
|
||||
|
||||
# Used for matrix spec type definitions and helpers
|
||||
[workspace.dependencies.ruma]
|
||||
git = "https://github.com/ruma/ruma.git"
|
||||
rev = "c1100793d2fd464be34052773360f3f3773d0fc4"
|
||||
git = "https://forgejo.ellis.link/continuwuation/ruwuma"
|
||||
#branch = "conduwuit-changes"
|
||||
rev = "d00b51a8669b21689c4eb47fb81f3a8b27c3e371"
|
||||
features = [
|
||||
"compat",
|
||||
"rand",
|
||||
"appservice-api-c",
|
||||
"client-api",
|
||||
"federation-api",
|
||||
"push-gateway-api-c",
|
||||
"state-res",
|
||||
"rand",
|
||||
"markdown",
|
||||
"push-gateway-api-c",
|
||||
"unstable-exhaustive-types",
|
||||
"ring-compat",
|
||||
"compat-upload-signatures",
|
||||
"compat-optional-txn-pdus",
|
||||
"compat-get-3pids",
|
||||
"identifiers-validation",
|
||||
"unstable-unspecified",
|
||||
"unstable-msc2448",
|
||||
"unstable-msc2666",
|
||||
"unstable-msc2867",
|
||||
"unstable-msc2870",
|
||||
"unstable-msc3026",
|
||||
"unstable-msc3061",
|
||||
"unstable-msc3814",
|
||||
"unstable-msc3245",
|
||||
"unstable-msc3381",
|
||||
"unstable-msc3489",
|
||||
"unstable-msc3930",
|
||||
"unstable-msc3266",
|
||||
"unstable-msc3381", # polls
|
||||
"unstable-msc3489", # beacon / live location
|
||||
"unstable-msc3575",
|
||||
"unstable-msc3930", # polls push rules
|
||||
"unstable-msc4075",
|
||||
"unstable-msc4095",
|
||||
"unstable-msc4121",
|
||||
"unstable-msc4125",
|
||||
"unstable-msc4155",
|
||||
"unstable-msc4186",
|
||||
"unstable-msc4195",
|
||||
"unstable-msc4203",
|
||||
"unstable-msc4310",
|
||||
"unstable-msc4380",
|
||||
"unstable-msc4143",
|
||||
"unstable-msc4293",
|
||||
"unstable-msc4406",
|
||||
"unstable-msc4439",
|
||||
"unstable-msc4354",
|
||||
"unstable-msc4480",
|
||||
"unstable-msc4466",
|
||||
"unstable-msc4203", # sending to-device events to appservices
|
||||
"unstable-msc4210", # remove legacy mentions
|
||||
"unstable-extensible-events",
|
||||
"unstable-pdu",
|
||||
"unstable-msc4155",
|
||||
"unstable-msc4143", # livekit well_known response
|
||||
"unstable-msc4284",
|
||||
"unstable-msc4439", # pgp_key in .well_known/matrix/support
|
||||
]
|
||||
|
||||
[workspace.dependencies.rust-rocksdb]
|
||||
git = "https://forgejo.ellis.link/continuwuation/rust-rocksdb-zaidoon1"
|
||||
rev = "0a25ff92f7c09b55eec496b9c192c7d5136ab2b8"
|
||||
rev = "31fb8f772c7afcdc0061ab6a40cfa3a1be2fccd9"
|
||||
default-features = false
|
||||
features = [
|
||||
"multi-threaded-cf",
|
||||
@@ -403,32 +409,29 @@ default-features = false
|
||||
version = "0.11.0"
|
||||
default-features = false
|
||||
|
||||
[workspace.dependencies.openidconnect]
|
||||
version = "4.0.1"
|
||||
|
||||
# optional opentelemetry, performance measurements, flamegraphs, etc for performance measurements and monitoring
|
||||
[workspace.dependencies.opentelemetry]
|
||||
version = "0.32.0"
|
||||
version = "0.31.0"
|
||||
|
||||
[workspace.dependencies.tracing-flame]
|
||||
version = "0.2.0"
|
||||
|
||||
[workspace.dependencies.tracing-opentelemetry]
|
||||
version = "0.33.0"
|
||||
version = "0.32.0"
|
||||
|
||||
[workspace.dependencies.opentelemetry_sdk]
|
||||
version = "0.32.0"
|
||||
version = "0.31.0"
|
||||
features = ["rt-tokio"]
|
||||
|
||||
[workspace.dependencies.opentelemetry-otlp]
|
||||
version = "0.32.0"
|
||||
version = "0.31.0"
|
||||
features = ["http", "grpc-tonic", "trace", "logs", "metrics"]
|
||||
|
||||
|
||||
|
||||
# optional sentry metrics for crash/panic reporting
|
||||
[workspace.dependencies.sentry]
|
||||
version = "0.48.0"
|
||||
version = "0.47.0"
|
||||
default-features = false
|
||||
features = [
|
||||
"backtrace",
|
||||
@@ -443,9 +446,9 @@ features = [
|
||||
]
|
||||
|
||||
[workspace.dependencies.sentry-tracing]
|
||||
version = "0.48.0"
|
||||
version = "0.47.0"
|
||||
[workspace.dependencies.sentry-tower]
|
||||
version = "0.48.0"
|
||||
version = "0.47.0"
|
||||
|
||||
# jemalloc usage
|
||||
[workspace.dependencies.tikv-jemalloc-sys]
|
||||
@@ -496,14 +499,14 @@ version = "0.4.9"
|
||||
default-features = false
|
||||
|
||||
[workspace.dependencies.termimad]
|
||||
version = "0.35.0"
|
||||
version = "0.34.0"
|
||||
default-features = false
|
||||
|
||||
[workspace.dependencies.checked_ops]
|
||||
version = "0.1"
|
||||
|
||||
[workspace.dependencies.syn]
|
||||
version = "3.0"
|
||||
version = "2.0"
|
||||
default-features = false
|
||||
features = ["full", "extra-traits"]
|
||||
|
||||
@@ -538,17 +541,22 @@ version = "2.1.1"
|
||||
features = ["std"]
|
||||
|
||||
[workspace.dependencies.minicbor-serde]
|
||||
version = "0.7.0"
|
||||
version = "0.6.0"
|
||||
features = ["std"]
|
||||
|
||||
[workspace.dependencies.maplit]
|
||||
version = "1.0.2"
|
||||
|
||||
[workspace.dependencies.ldap3]
|
||||
version = "0.12.0"
|
||||
default-features = false
|
||||
features = ["sync", "tls-rustls", "rustls-provider"]
|
||||
|
||||
[workspace.dependencies.yansi]
|
||||
version = "1.0.1"
|
||||
|
||||
[workspace.dependencies.askama]
|
||||
version = "0.16.0"
|
||||
version = "0.15.0"
|
||||
|
||||
[workspace.dependencies.lettre]
|
||||
version = "0.11.19"
|
||||
@@ -563,12 +571,6 @@ features = ["std"]
|
||||
[workspace.dependencies.nonzero_ext]
|
||||
version = "0.3.0"
|
||||
|
||||
[workspace.dependencies.resolvematrix]
|
||||
version = "1.3.0"
|
||||
|
||||
[workspace.dependencies.serde_urlencoded]
|
||||
version = "0.7.1"
|
||||
|
||||
#
|
||||
# Patches
|
||||
#
|
||||
@@ -656,10 +658,6 @@ default-features = false
|
||||
package = "conduwuit"
|
||||
path = "src/main"
|
||||
|
||||
[workspace.dependencies.ruminuwuity]
|
||||
package = "ruminuwuity"
|
||||
path = "src/ruminuwuity"
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Release profiles
|
||||
|
||||
+23
-68
@@ -1,90 +1,46 @@
|
||||
# Security Policy for Continuwuity
|
||||
|
||||
This document outlines the security policy for Continuwuity. Our goal is to maintain a secure platform for all users,
|
||||
and we take security matters seriously.
|
||||
This document outlines the security policy for Continuwuity. Our goal is to maintain a secure platform for all users, and we take security matters seriously.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We provide security updates for the following versions of Continuwuity:
|
||||
|
||||
| Version | Supported |
|
||||
|----------------|:---------:|
|
||||
| Latest release | ✅ |
|
||||
| Main branch | ✅ |
|
||||
| Older releases | ❌ |
|
||||
| Version | Supported |
|
||||
| -------------- |:----------------:|
|
||||
| Latest release | ✅ |
|
||||
| Main branch | ✅ |
|
||||
| Older releases | ❌ |
|
||||
|
||||
We may backport fixes to the previous release at our discretion, but we don't guarantee this; our versioning is designed
|
||||
to encourage users to stay up-to-date with the latest release, and we have no concept of "long term support".
|
||||
We may backport fixes to the previous release at our discretion, but we don't guarantee this.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
### Responsible Disclosure
|
||||
|
||||
We appreciate the efforts of security researchers and the community in identifying and reporting vulnerabilities. To
|
||||
ensure that potential vulnerabilities are addressed properly, please follow these guidelines:
|
||||
We appreciate the efforts of security researchers and the community in identifying and reporting vulnerabilities. To ensure that potential vulnerabilities are addressed properly, please follow these guidelines:
|
||||
|
||||
1. **Contact members of the team directly** over E2EE private message.
|
||||
- [@jade:ellis.link](https://matrix.to/#/@jade:ellis.link)
|
||||
- [@nex:nexy7574.co.uk](https://matrix.to/#/@nex:nexy7574.co.uk)
|
||||
- [@ginger:gingershaped.computer](https://matrix.to/#/@ginger:gingershaped.computer)
|
||||
2. **Email the security team** at [security@continuwuity.org](mailto:security@continuwuity.org). This is not E2EE, so
|
||||
don't include sensitive details.
|
||||
3. **Do not disclose the vulnerability publicly** until a fix has been pushed to the main branch.
|
||||
- [@jade:ellis.link](https://matrix.to/#/@jade:ellis.link)
|
||||
- [@nex:nexy7574.co.uk](https://matrix.to/#/@nex:nexy7574.co.uk)
|
||||
2. **Email the security team** at [security@continuwuity.org](mailto:security@continuwuity.org). This is not E2EE, so don't include sensitive details.
|
||||
3. **Do not disclose the vulnerability publicly** until it has been addressed
|
||||
4. **Provide detailed information** about the vulnerability, including:
|
||||
- A clear description of the issue
|
||||
- Steps to reproduce
|
||||
- Potential impact
|
||||
- Any possible mitigations
|
||||
- Version(s) affected, including specific commits if possible
|
||||
- How you want to be attributed if your report is accepted (website, social media handle, Matrix user ID, etc).
|
||||
**Please state explicitly if you wish to remain anonymous.**
|
||||
- A clear description of the issue
|
||||
- Steps to reproduce
|
||||
- Potential impact
|
||||
- Any possible mitigations
|
||||
- Version(s) affected, including specific commits if possible
|
||||
|
||||
If you have any doubts about a potential security vulnerability, contact us via private channels first! We'd prefer that
|
||||
you bother us, instead of having a vulnerability disclosed without a fix.
|
||||
If you have any doubts about a potential security vulnerability, contact us via private channels first! We'd prefer that you bother us, instead of having a vulnerability disclosed without a fix.
|
||||
|
||||
### Terms for credit
|
||||
|
||||
Before reporting a vulnerability, please remember that we are a small team maintaining a large codebase depended upon by
|
||||
a vast unknown number of users in our free time. While we always investigate *all* security reports, we may not
|
||||
acknowledge or credit your report under certain circumstances.
|
||||
|
||||
#### Following the security policy
|
||||
|
||||
If you do not report the vulnerability following this security policy, your report may be ignored and/or may not be
|
||||
credited if fixed. This includes filing for GitHub security advisories without contacting us directly first (we do not
|
||||
get notified about these!).
|
||||
|
||||
#### Automation-assisted reports
|
||||
|
||||
Reports assisted by automatic tooling such as LLMs MUST disclose such in the report.
|
||||
Assisted reports must also produce a working proof-of-concept (PoC) demonstrating the vulnerability against the latest
|
||||
release and/or main commit with no modifications to the codebase. This is to demonstrate that not only does
|
||||
the author understand the vulnerability that they are reporting, but also that the vulnerability is reproducible
|
||||
and not a false positive.
|
||||
|
||||
#### Reports for known issues
|
||||
|
||||
Reports for issues we are already aware of will only be credited if subsequent reporters provide new information.
|
||||
|
||||
#### Audits and CVE farming
|
||||
|
||||
Sweeping audits (vulnerability hunting) **must** be coordinated with the team first - receiving a rapsheet of new
|
||||
vulnerabilities is explicitly not helpful to us and only harms the project. If you are interested in performing a
|
||||
security audit, please contact us first to discuss the scope and methodology.
|
||||
|
||||
Likewise, CVE farming (reporting vulnerabilities with the primary intent to get a CVE number) is actively harmful to the
|
||||
project, and will not be credited. Severe violations of this policy will result in a permanent ban from collaborating
|
||||
with the project in any capacity. We are attempting to build high quality free software, not flesh out your CV/resume.
|
||||
|
||||
### What to expect
|
||||
### What to Expect
|
||||
|
||||
When you report a security vulnerability:
|
||||
|
||||
1. **Acknowledgment**: We will acknowledge receipt of your report. We may ask for further information.
|
||||
2. **Triage**: The report will be triaged into our internal tracker, and you will be provided with a reference number (
|
||||
in case you end up with multiple reports). An ETA for a fix will be provided if feasible.
|
||||
3. **Updates**: We will provide updates on our progress in addressing the vulnerability, including a heads-up for when
|
||||
we plan to release a fix.
|
||||
1. **Acknowledgment**: We will acknowledge receipt of your report.
|
||||
2. **Assessment**: We will assess the vulnerability and determine its impact on our users
|
||||
3. **Updates**: We will provide updates on our progress in addressing the vulnerability, and may request you help test mitigations
|
||||
4. **Resolution**: Once resolved, we will notify you and discuss coordinated disclosure
|
||||
5. **Credit**: We will recognize your contribution (unless you prefer to remain anonymous)
|
||||
|
||||
@@ -94,8 +50,7 @@ ## Security Update Process
|
||||
|
||||
1. We will develop and test fixes in a private fork
|
||||
2. Security updates will be released as soon as possible
|
||||
3. Release notes will include information about the vulnerabilities, avoiding details that could facilitate exploitation
|
||||
where possible
|
||||
3. Release notes will include information about the vulnerabilities, avoiding details that could facilitate exploitation where possible
|
||||
4. Critical security updates may be backported to the previous stable release
|
||||
|
||||
## Additional Resources
|
||||
|
||||
@@ -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 +0,0 @@
|
||||
Added MSC4480 sticky events to simplified sliding sync. Contributed by @eleboucher.
|
||||
@@ -1 +0,0 @@
|
||||
Replace deprecated `docker-compose` commands with `docker compose` to reflect latest Docker changes.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed typing notifications not interrupting a sync long poll. Contributed by @eleboucher.
|
||||
@@ -1 +0,0 @@
|
||||
Updated Ruma dependencies. Contributed by @eleboucher.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed missed wake-ups and stale responses in legacy and sliding sync long polls. Contributed by @eleboucher.
|
||||
@@ -1 +0,0 @@
|
||||
Livekit docs: `room.auto_create: false` is now included in default `livekit.yaml`, following `lk-jwt-service` recommendation.
|
||||
@@ -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 +0,0 @@
|
||||
Added MSC4354 sticky events, behind the `allow_sticky_events` config option. Contributed by @eleboucher.
|
||||
@@ -1 +0,0 @@
|
||||
Added MSC4186 direct, encrypted, and room-type list filters, resolving invited rooms from their stripped invite state. Contributed by @eleboucher.
|
||||
@@ -0,0 +1 @@
|
||||
Explain accessing Continuwuity's server console when deployed via Docker.
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
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).
|
||||
@@ -1 +0,0 @@
|
||||
Updated the docs to reflect the current default User-Agent for URL previews
|
||||
@@ -1 +0,0 @@
|
||||
Resolve membership service by correct name for auto-join. Contributed by @Aranjedeath
|
||||
@@ -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.
|
||||
@@ -7,6 +7,7 @@
|
||||
[global]
|
||||
address = "0.0.0.0"
|
||||
allow_device_name_federation = true
|
||||
allow_guest_registration = true
|
||||
allow_public_room_directory_over_federation = true
|
||||
allow_registration = true
|
||||
database_path = "/database"
|
||||
@@ -31,6 +32,7 @@ rocksdb_log_level = "info"
|
||||
rocksdb_max_log_files = 1
|
||||
rocksdb_recovery_mode = 0
|
||||
rocksdb_paranoid_file_checks = true
|
||||
log_guest_registrations = false
|
||||
allow_legacy_media = true
|
||||
startup_netburst = true
|
||||
startup_netburst_keep = -1
|
||||
|
||||
+186
-244
@@ -290,66 +290,13 @@
|
||||
#
|
||||
#ip_lookup_strategy = 5
|
||||
|
||||
# The preferred source to use for getting the real client IP.
|
||||
#
|
||||
# Takes any of the following options:
|
||||
#
|
||||
# "cf_connecting_ip" - `Cf-Connecting-Ip` header
|
||||
# "cloudfront_viewer_address" - `CloudFront-Viewer-Address` header
|
||||
# "fly_client_ip" - `Fly-Client-IP` header
|
||||
# "x_forwarded_for" - rightmost value of the `X-Forwarded-For` header
|
||||
# "true_client_ip" - `True-Client-Ip` header
|
||||
# "x_envoy_external_address" - `X-Envoy-External-Address` header
|
||||
# "x_real_ip" - `X-Real-Ip` header
|
||||
# "direct" - the directly connected IP address (fallback for other
|
||||
# options)
|
||||
#
|
||||
# Only set this if you are certain only your reverse proxy
|
||||
# will send the expected header. There is no "is the connecting IP allowed
|
||||
# to set this header" check; if the header selected is present, it is
|
||||
# used.
|
||||
#
|
||||
# Ignored if `accepted_ip_sources` is set.
|
||||
#
|
||||
# If not set set, `direct` is used. Additionally, `direct` is used
|
||||
# as a fallback if the chosen header is not found.
|
||||
#
|
||||
#request_ip_source = false
|
||||
|
||||
# The accepted source(s) for the real client IP.
|
||||
#
|
||||
# Takes any combination of the following options:
|
||||
#
|
||||
# "cf_connecting_ip" - `Cf-Connecting-Ip` header
|
||||
# "cloudfront_viewer_address" - `CloudFront-Viewer-Address` header
|
||||
# "fly_client_ip" - `Fly-Client-IP` header
|
||||
# "x_forwarded_for" - rightmost value of the `X-Forwarded-For` header
|
||||
# "true_client_ip" - `True-Client-Ip` header
|
||||
# "x_envoy_external_address" - `X-Envoy-External-Address` header
|
||||
# "x_real_ip" - `X-Real-Ip` header
|
||||
# "direct" - the directly connected IP address
|
||||
#
|
||||
# Only set this if you are certain only your reverse proxy
|
||||
# will send the expected header. There is no "is the connecting IP allowed
|
||||
# to set this header" check; if the header selected is present, it is
|
||||
# used.
|
||||
#
|
||||
# One of the configured sources must be available or the request is
|
||||
# rejected. If you want a fallback (including `direct`!), you have to
|
||||
# configure it. Priority is based on configuration order.
|
||||
#
|
||||
# If not set, `request_ip_source` configuration is used.
|
||||
#
|
||||
#accepted_ip_sources = []
|
||||
|
||||
# Max request size for file uploads in bytes. Defaults to 20MB.
|
||||
# Also limits incoming federated media.
|
||||
#
|
||||
#max_request_size = 20971520
|
||||
|
||||
# This item is undocumented. Please contribute documentation for it.
|
||||
#
|
||||
#max_fetch_prev_events = 1024
|
||||
#max_fetch_prev_events = 192
|
||||
|
||||
# How many incoming federation transactions the server is willing to be
|
||||
# processing at any given time before it becomes overloaded and starts
|
||||
@@ -424,18 +371,21 @@
|
||||
#
|
||||
#federation_timeout = 60
|
||||
|
||||
# Policy server request timeout (seconds). Generally policy
|
||||
# MSC4284 Policy server request timeout (seconds). Generally policy
|
||||
# servers should respond near instantly, however may slow down under
|
||||
# load. If a policy server doesn't respond in a short amount of time, the
|
||||
# room it is configured in may become unusable if this limit is set too
|
||||
# high. 30 seconds is a good default, however lower values may be
|
||||
# acceptable if temporary send failures are an okay trade-off.
|
||||
# high. 10 seconds is a good default, however dropping this to 3-5 seconds
|
||||
# can be acceptable.
|
||||
#
|
||||
# Please be aware that policy requests are *NOT* currently re-tried, so if
|
||||
# a spam check request fails, the event will be assumed to be not spam,
|
||||
# which in some cases may result in spam being sent to or received from
|
||||
# the room that would typically be prevented.
|
||||
#
|
||||
# About policy servers: https://matrix.org/blog/2025/04/introducing-policy-servers/
|
||||
# (Stabilized in Matrix v1.18)
|
||||
#
|
||||
#policy_server_request_timeout = 30
|
||||
#policy_server_request_timeout = 10
|
||||
|
||||
# Federation client idle connection pool timeout (seconds).
|
||||
#
|
||||
@@ -573,15 +523,17 @@
|
||||
#
|
||||
#recaptcha_private_site_key =
|
||||
|
||||
# Controls whether users are allowed to deactivate their own accounts
|
||||
# through the account management panel or their Matrix clients. Server
|
||||
# admins can always deactivate users using the relevant admin commands.
|
||||
# Policy documents, such as terms and conditions or a privacy policy,
|
||||
# which users must agree to when registering an account.
|
||||
#
|
||||
# Note that, in some jurisdictions, you may be legally required to honor
|
||||
# users who request to deactivate their accounts if you set this option
|
||||
# to `false`.
|
||||
# Example:
|
||||
# ```ignore
|
||||
# [global.registration_terms.privacy_policy]
|
||||
# en = { name = "Privacy Policy", url = "https://homeserver.example/en/privacy_policy.html" }
|
||||
# es = { name = "Política de Privacidad", url = "https://homeserver.example/es/privacy_policy.html" }
|
||||
# ```
|
||||
#
|
||||
#allow_deactivation = true
|
||||
#registration_terms = {}
|
||||
|
||||
# Controls whether encrypted rooms and events are allowed.
|
||||
#
|
||||
@@ -621,6 +573,18 @@
|
||||
#
|
||||
#allow_public_room_directory_over_federation = false
|
||||
|
||||
# Allow guests/unauthenticated users to access TURN credentials.
|
||||
#
|
||||
# This is the equivalent of Synapse's `turn_allow_guests` config option.
|
||||
# This allows any unauthenticated user to call the endpoint
|
||||
# `/_matrix/client/v3/voip/turnServer`.
|
||||
#
|
||||
# It is unlikely you need to enable this as all major clients support
|
||||
# authentication for this endpoint and prevents misuse of your TURN server
|
||||
# from potential bots.
|
||||
#
|
||||
#turn_allow_guests = false
|
||||
|
||||
# Set this to true to lock down your server's public room directory and
|
||||
# only allow admins to publish rooms to the room directory. Unpublishing
|
||||
# is still allowed by all users with this enabled.
|
||||
@@ -671,38 +635,6 @@
|
||||
#
|
||||
#default_room_version = "12"
|
||||
|
||||
# A default allow value for the Access Control List when creating a room.
|
||||
#
|
||||
# If a list is provided, new rooms will be created with
|
||||
# a m.room.server_acl event. Only servers which match one of the patterns
|
||||
# in the list will be permitted to participate in the room.
|
||||
#
|
||||
# ACLs in existing rooms will not be updated automatically. This is not
|
||||
# a substitute for moderation bots.
|
||||
#
|
||||
#default_room_acl_allow =
|
||||
|
||||
# A default deny value for the Access Control List when creating a room.
|
||||
#
|
||||
# If a list is provided, new rooms will be created with
|
||||
# a m.room.server_acl event. Servers which match one of the patterns
|
||||
# in the list will be NOT permitted to participate in the room.
|
||||
#
|
||||
# This config cannot be used if the default_room_acl_allow config is used.
|
||||
#
|
||||
# ACLs in existing rooms will not be updated automatically. This is not
|
||||
# a substitute for moderation bots.
|
||||
#
|
||||
#default_room_acl_deny =
|
||||
|
||||
# The number of forward extremities to tolerate in a room before
|
||||
# attempting to manually squash them with a "dummy event". Setting this
|
||||
# above 20 will hinder its efficacy, and setting it below 5 will cause
|
||||
# more dummy events to be sent than necessary (which increases federation
|
||||
# traffic).
|
||||
#
|
||||
#dummy_event_threshold = 10
|
||||
|
||||
# Enable OpenTelemetry OTLP tracing export. This replaces the deprecated
|
||||
# Jaeger exporter. Traces will be sent via OTLP to a collector (such as
|
||||
# Jaeger) that supports the OpenTelemetry Protocol.
|
||||
@@ -1306,12 +1238,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
|
||||
@@ -1356,6 +1282,21 @@
|
||||
#
|
||||
#brotli_compression = false
|
||||
|
||||
# Set to true to allow user type "guest" registrations. Some clients like
|
||||
# Element attempt to register guest users automatically.
|
||||
#
|
||||
#allow_guest_registration = false
|
||||
|
||||
# Set to true to log guest registrations in the admin room. Note that
|
||||
# these may be noisy or unnecessary if you're a public homeserver.
|
||||
#
|
||||
#log_guest_registrations = false
|
||||
|
||||
# Set to true to allow guest registrations/users to auto join any rooms
|
||||
# specified in `auto_join_rooms`.
|
||||
#
|
||||
#allow_guests_auto_join_rooms = false
|
||||
|
||||
# Enable the legacy unauthenticated Matrix media repository endpoints.
|
||||
# These endpoints consist of:
|
||||
# - /_matrix/media/*/config
|
||||
@@ -1492,11 +1433,6 @@
|
||||
#
|
||||
#send_messages_from_ignored_users_to_client = false
|
||||
|
||||
# Send "org.matrix.dummy_event" events to the client. This is a debugging
|
||||
# option.
|
||||
#
|
||||
#send_dummy_events_to_clients = false
|
||||
|
||||
# Vector list of IPv4 and IPv6 CIDR ranges / subnets *in quotes* that you
|
||||
# do not want continuwuity to send outbound requests to. Defaults to
|
||||
# RFC1918, unroutable, loopback, multicast, and testnet addresses for
|
||||
@@ -1601,7 +1537,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.
|
||||
@@ -1660,6 +1596,19 @@
|
||||
#
|
||||
#block_non_admin_invites = false
|
||||
|
||||
# Enable or disable making requests to MSC4284 Policy Servers.
|
||||
# It is recommended you keep this enabled unless you experience frequent
|
||||
# connectivity issues, such as in a restricted networking environment.
|
||||
#
|
||||
#enable_msc4284_policy_servers = true
|
||||
|
||||
# Enable running locally generated events through configured MSC4284
|
||||
# policy servers. You may wish to disable this if your server is
|
||||
# single-user for a slight speed benefit in some rooms, but otherwise
|
||||
# should leave it enabled.
|
||||
#
|
||||
#policy_server_check_own_events = true
|
||||
|
||||
# Allow admins to enter commands in rooms other than "#admins" (admin
|
||||
# room) by prefixing your message with "\!admin" or "\\!admin" followed up
|
||||
# a normal continuwuity admin command. The reply will be publicly visible
|
||||
@@ -1926,11 +1875,6 @@
|
||||
#
|
||||
#support_page =
|
||||
|
||||
# The ed25519 public key for the policy server available at this server's
|
||||
# name. Must be unpadded base64.
|
||||
#
|
||||
#policy_server_public_key =
|
||||
|
||||
# Role string for server support contacts, to be served as part of the
|
||||
# MSC1929 server support endpoint at /.well-known/matrix/support.
|
||||
#
|
||||
@@ -1956,6 +1900,34 @@
|
||||
#
|
||||
#support_pgp_key =
|
||||
|
||||
# **DEPRECATED**: Use `[global.matrix_rtc].foci` instead.
|
||||
#
|
||||
# A list of MatrixRTC foci URLs which will be served as part of the
|
||||
# MSC4143 client endpoint at /.well-known/matrix/client.
|
||||
#
|
||||
# This option is deprecated and will be removed in a future release.
|
||||
# Please migrate to the new `[global.matrix_rtc]` config section.
|
||||
#
|
||||
#rtc_focus_server_urls = []
|
||||
|
||||
[global.blurhashing]
|
||||
|
||||
# blurhashing x component, 4 is recommended by https://blurha.sh/
|
||||
#
|
||||
#components_x = 4
|
||||
|
||||
# blurhashing y component, 3 is recommended by https://blurha.sh/
|
||||
#
|
||||
#components_y = 3
|
||||
|
||||
# Max raw size that the server will blurhash, this is the size of the
|
||||
# image after converting it to raw data, it should be higher than the
|
||||
# upload limit but not too high. The higher it is the higher the
|
||||
# potential load will be for clients requesting blurhashes. The default
|
||||
# is 33.55MB. Setting it to 0 disables blurhashing.
|
||||
#
|
||||
#blurhash_max_raw_size = 33554432
|
||||
|
||||
[global.matrix_rtc]
|
||||
|
||||
# A list of MatrixRTC foci (transports) which will be served via the
|
||||
@@ -1973,6 +1945,102 @@
|
||||
#
|
||||
#foci = []
|
||||
|
||||
[global.ldap]
|
||||
|
||||
# Whether to enable LDAP login.
|
||||
#
|
||||
# example: "true"
|
||||
#
|
||||
#enable = false
|
||||
|
||||
# Whether to force LDAP authentication or authorize classical password
|
||||
# login.
|
||||
#
|
||||
# example: "true"
|
||||
#
|
||||
#ldap_only = false
|
||||
|
||||
# URI of the LDAP server.
|
||||
#
|
||||
# example: "ldap://ldap.example.com:389"
|
||||
#
|
||||
#uri = ""
|
||||
|
||||
# StartTLS for LDAP connections.
|
||||
#
|
||||
#use_starttls = false
|
||||
|
||||
# Skip TLS certificate verification, possibly dangerous.
|
||||
#
|
||||
#disable_tls_verification = false
|
||||
|
||||
# Root of the searches.
|
||||
#
|
||||
# example: "ou=users,dc=example,dc=org"
|
||||
#
|
||||
#base_dn = ""
|
||||
|
||||
# Bind DN if anonymous search is not enabled.
|
||||
#
|
||||
# You can use the variable `{username}` that will be replaced by the
|
||||
# entered username. In such case, the password used to bind will be the
|
||||
# one provided for the login and not the one given by
|
||||
# `bind_password_file`. Beware: automatically granting admin rights will
|
||||
# not work if you use this direct bind instead of a LDAP search.
|
||||
#
|
||||
# example: "cn=ldap-reader,dc=example,dc=org" or
|
||||
# "cn={username},ou=users,dc=example,dc=org"
|
||||
#
|
||||
#bind_dn = ""
|
||||
|
||||
# Path to a file on the system that contains the password for the
|
||||
# `bind_dn`.
|
||||
#
|
||||
# The server must be able to access the file, and it must not be empty.
|
||||
#
|
||||
#bind_password_file = ""
|
||||
|
||||
# Search filter to limit user searches.
|
||||
#
|
||||
# You can use the variable `{username}` that will be replaced by the
|
||||
# entered username for more complex filters.
|
||||
#
|
||||
# example: "(&(objectClass=person)(memberOf=matrix))"
|
||||
#
|
||||
#filter = "(objectClass=*)"
|
||||
|
||||
# Attribute to use to uniquely identify the user.
|
||||
#
|
||||
# example: "uid" or "cn"
|
||||
#
|
||||
#uid_attribute = "uid"
|
||||
|
||||
# Attribute containing the display name of the user.
|
||||
#
|
||||
# example: "givenName" or "sn"
|
||||
#
|
||||
#name_attribute = "givenName"
|
||||
|
||||
# Root of the searches for admin users.
|
||||
#
|
||||
# Defaults to `base_dn` if empty.
|
||||
#
|
||||
# example: "ou=admins,dc=example,dc=org"
|
||||
#
|
||||
#admin_base_dn = ""
|
||||
|
||||
# The LDAP search filter to find administrative users for continuwuity.
|
||||
#
|
||||
# If left blank, administrative state must be configured manually for each
|
||||
# user.
|
||||
#
|
||||
# You can use the variable `{username}` that will be replaced by the
|
||||
# entered username for more complex filters.
|
||||
#
|
||||
# example: "(objectClass=conduwuitAdmin)" or "(uid={username})"
|
||||
#
|
||||
#admin_filter = ""
|
||||
|
||||
#[global.antispam]
|
||||
|
||||
#[global.antispam.meowlnir]
|
||||
@@ -2041,10 +2109,8 @@
|
||||
#
|
||||
#sender =
|
||||
|
||||
# Whether to allow public registration with an email address.
|
||||
#
|
||||
# Note that, if this option is enabled, anyone will be able to register an
|
||||
# account with just an email address.
|
||||
# Whether to require that users provide an email address when they
|
||||
# register.
|
||||
#
|
||||
# If either this option or `require_email_for_token_registration` are set,
|
||||
# users will not be allowed to remove their email address.
|
||||
@@ -2052,130 +2118,6 @@
|
||||
#require_email_for_registration = false
|
||||
|
||||
# Whether to require that users who register with a registration token
|
||||
# provide an email address. This option is independent of
|
||||
# `require_email_for_registration`.
|
||||
# provide an email address.
|
||||
#
|
||||
#require_email_for_token_registration = false
|
||||
|
||||
#[global.registration_terms]
|
||||
|
||||
# The language code to provide to clients along with the policy documents.
|
||||
#
|
||||
#language = "en"
|
||||
|
||||
# Policy documents, such as terms and conditions or a privacy policy,
|
||||
# which users must agree to when registering an account.
|
||||
#
|
||||
# Example:
|
||||
# ```ignore
|
||||
# [global.registration_terms.documents]
|
||||
# privacy_policy = { name = "Privacy Policy", url = "https://homeserver.example/en/privacy_policy.html" }
|
||||
# ```
|
||||
#
|
||||
#documents =
|
||||
|
||||
#[global.oauth]
|
||||
|
||||
# The compatibility mode to use for OAuth.
|
||||
#
|
||||
# - "disabled": OAuth will be unavailable. Users will only be able to log
|
||||
# in using legacy authentication.
|
||||
# - "hybrid": OAuth and legacy authentication will both be available. Some
|
||||
# clients may only use one or the other.
|
||||
# - "exclusive": Only OAuth will be available. Clients which require
|
||||
# legacy authentication will be unable to log in.
|
||||
#
|
||||
#compatibility_mode = "hybrid"
|
||||
|
||||
#[global.oauth.oidc]
|
||||
# Uncommenting this section will enable Continuwuity's support for
|
||||
# authenticating users using an OpenID Connect-compatible identity provider.
|
||||
# This is referred to as "delegated authentication".
|
||||
#
|
||||
# IMPORTANT NOTE: When delegated authentication is active, Continuwuity will behave as if
|
||||
# the `global.oauth.compatibility_mode` setting is set to `exclusive`.
|
||||
# Matrix clients which do not support OAuth login (also referred to as "next-gen auth") will NOT be able
|
||||
# to log in while delegated authentication is active.
|
||||
|
||||
|
||||
# The OIDC issuer URL. Continuwuity will use OpenID Connect Discovery to
|
||||
# automatically fetch the identity provider's metadata from this URL.
|
||||
# Generally you should set this to the base domain your identity provider
|
||||
# runs on.
|
||||
#
|
||||
#discovery_url =
|
||||
|
||||
# The OAuth client ID for Continuwuity to use when communicating with the
|
||||
# identity provider.
|
||||
#
|
||||
#client_id =
|
||||
|
||||
# The OAuth client secret for Continuwuity to use when communicating with
|
||||
# the identity provider.
|
||||
#
|
||||
#client_secret =
|
||||
|
||||
# A path to a file which Continuwuity will read the client secret from.
|
||||
# If this option is set, it will override `client_secret`.
|
||||
#
|
||||
# The server will fail to start if the file cannot be read.
|
||||
#
|
||||
#client_secret_file =
|
||||
|
||||
# Additional scopes Continuwuity should request from the IDP. This may be
|
||||
# necessary to access certain claims. Continuwuity always requests the
|
||||
# `openid` scope.
|
||||
#
|
||||
#additional_scopes = []
|
||||
|
||||
# Whether the user should be prompted to choose a localpart
|
||||
# when signing in for the first time. If this is `false`, Continuwuity
|
||||
# will attempt to use the value of the `preferred_username_claim`
|
||||
# (see below) as the user's localpart. Authentication will
|
||||
# fail if this claim is missing or is not a valid localpart.
|
||||
#
|
||||
#prompt_for_localpart = true
|
||||
|
||||
# The claim to use for the user's localpart, if `prompt_for_localpart` is
|
||||
# false.
|
||||
#
|
||||
#preferred_username_claim = "preferred_username"
|
||||
|
||||
# The claim which will be used to set the user's email address,
|
||||
# either on initial registration or on every login depending on
|
||||
# the value of `profile_key_import_mode`. Continuwuity assumes that
|
||||
# the IDP has taken care of verifying that the user controls the email
|
||||
# address it provides.
|
||||
#
|
||||
# This option does nothing if SMTP is not configured.
|
||||
#
|
||||
# If this option is set, and `profile_key_import_mode` is `on_login`,
|
||||
# users will not be able to change their email addresses themselves.
|
||||
#
|
||||
#email_claim = "email"
|
||||
|
||||
# Defines how claims returned from the IDP should be mapped to a user's
|
||||
# profile data. The profile field named in each key will be set from the
|
||||
# claim named in the corresponding value when the user first registers,
|
||||
# and possibly on subsequent logins as well, depending on the value of
|
||||
# `profile_key_import_mode` (see below).
|
||||
#
|
||||
# Per-room overrides to the user's display name or avatar will be
|
||||
# preserved by the import process.
|
||||
#
|
||||
# SECURITY NOTE: If the `avatar_url` field is set, Continuwuity will
|
||||
# perform a HTTP GET to the URL in the mapped claim and use the returned
|
||||
# file as the user's profile picture. Make sure your users are not able
|
||||
# to set the value of the mapped claim to an arbitrary URL.
|
||||
#
|
||||
#profile_key_map = { displayname = "name" }
|
||||
|
||||
# When profile keys should be imported from the IDP's claims.
|
||||
#
|
||||
# - "on_registration": Listed keys will be imported once, when the user
|
||||
# logs in for the first time and their shadow account is created.
|
||||
# - "on_login": Listed keys will be imported every time the user logs in.
|
||||
# Additionally, users will not be able to manually edit any listed keys
|
||||
# through their Matrix client.
|
||||
#
|
||||
#profile_key_import_mode = "on_registration"
|
||||
|
||||
+5
-7
@@ -1,5 +1,5 @@
|
||||
ARG RUST_VERSION=1
|
||||
ARG DEBIAN_VERSION=trixie
|
||||
ARG DEBIAN_VERSION=bookworm
|
||||
|
||||
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
|
||||
FROM --platform=$BUILDPLATFORM rust:${RUST_VERSION}-slim-${DEBIAN_VERSION} AS base
|
||||
@@ -10,7 +10,7 @@ RUN rm -f /etc/apt/apt.conf.d/docker-clean
|
||||
|
||||
# Match Rustc version as close as possible
|
||||
# rustc -vV
|
||||
ARG LLVM_VERSION=22
|
||||
ARG LLVM_VERSION=21
|
||||
# ENV RUSTUP_TOOLCHAIN=${RUST_VERSION}
|
||||
|
||||
# Install repo tools
|
||||
@@ -22,7 +22,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && apt-get install -y \
|
||||
pkg-config make jq \
|
||||
wget curl git lsb-release gpg \
|
||||
wget curl git software-properties-common \
|
||||
file
|
||||
# golang cmake
|
||||
|
||||
@@ -50,7 +50,7 @@ EOF
|
||||
|
||||
# Developer tool versions
|
||||
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
|
||||
ENV BINSTALL_VERSION=1.21.1
|
||||
ENV BINSTALL_VERSION=1.18.1
|
||||
# renovate: datasource=github-releases depName=psastras/sbom-rs
|
||||
ENV CARGO_SBOM_VERSION=0.9.1
|
||||
# renovate: datasource=crate depName=lddtree
|
||||
@@ -171,7 +171,6 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
--mount=type=cache,target=/usr/local/cargo/git/db \
|
||||
--mount=type=cache,target=/app/target,id=continuwuity-cargo-target-${TARGET_CPU}-${TARGETPLATFORM}-${RUST_PROFILE} \
|
||||
bash <<'EOF'
|
||||
set -euo pipefail
|
||||
set -o allexport
|
||||
set -o xtrace
|
||||
. /etc/environment
|
||||
@@ -192,7 +191,7 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
jq -r ".target_directory"))
|
||||
mkdir /out/sbin
|
||||
PACKAGE=conduwuit
|
||||
CARGO_LOG=debug xx-cargo build --locked --profile ${RUST_PROFILE} \
|
||||
xx-cargo build --locked --profile ${RUST_PROFILE} \
|
||||
--no-default-features --features ${CARGO_FEATURES} \
|
||||
-p $PACKAGE;
|
||||
BINARIES=($(cargo metadata --no-deps --format-version 1 | \
|
||||
@@ -208,7 +207,6 @@ EOF
|
||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
--mount=type=cache,target=/usr/local/cargo/git/db \
|
||||
bash <<'EOF'
|
||||
set -euo pipefail
|
||||
set -o xtrace
|
||||
mkdir /out/sbom
|
||||
typeset -A PACKAGES
|
||||
|
||||
@@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/etc/apk/cache apk add \
|
||||
|
||||
# Developer tool versions
|
||||
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
|
||||
ENV BINSTALL_VERSION=1.21.1
|
||||
ENV BINSTALL_VERSION=1.18.1
|
||||
# renovate: datasource=github-releases depName=psastras/sbom-rs
|
||||
ENV CARGO_SBOM_VERSION=0.9.1
|
||||
# renovate: datasource=crate depName=lddtree
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@
|
||||
},
|
||||
{
|
||||
"type": "dir",
|
||||
"name": "guides",
|
||||
"label": "Guides"
|
||||
"name": "advanced",
|
||||
"label": "Advanced"
|
||||
},
|
||||
"security",
|
||||
{
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
[
|
||||
{
|
||||
"text": "Documentation",
|
||||
"text": "Guide",
|
||||
"link": "/introduction",
|
||||
"activeMatch": "^/(introduction|configuration|deploying|calls|appservices|maintenance|troubleshooting|guides)"
|
||||
"activeMatch": "^/(introduction|configuration|deploying|calls|appservices|maintenance|troubleshooting|advanced)"
|
||||
},
|
||||
{
|
||||
"text": "Development",
|
||||
|
||||
@@ -8,15 +8,6 @@
|
||||
"type": "file",
|
||||
"name": "dns",
|
||||
"label": "DNS tuning (recommended)"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"name": "performance",
|
||||
"label": "Performance tuning"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"name": "oidc",
|
||||
"label": "Delegated authentication"
|
||||
}
|
||||
|
||||
]
|
||||
@@ -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,13 +122,9 @@ ### 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.
|
||||
:::
|
||||
Instead of configuring `[global.well_known]` options and 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.
|
||||
|
||||
<details>
|
||||
|
||||
@@ -163,26 +152,13 @@ ### Option 2: Manually serving static files for well-known
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Accompanying Continuwuity configuration</summary>
|
||||
|
||||
```toml
|
||||
[global.well_known]
|
||||
client = "https://matrix.example.com/"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Remember to set the `Access-Control-Allow-Origin: *` header in your `/.well-known/matrix/client` path for web clients to work.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Check that other servers can connect to you.
|
||||
Here are some tools that can help identify federation issues:
|
||||
Check with the [Matrix Connectivity Tester][federation-tester] to see that it's working.
|
||||
|
||||
- [Matrix Connectivity Tester](https://federationtester.mtrnord.blog/)
|
||||
- [Matrix Federation Tester](https://federationtester.matrix.org/)
|
||||
[federation-tester]: https://federationtester.mtrnord.blog/
|
||||
|
||||
### Cannot log in with web clients
|
||||
|
||||
@@ -197,79 +173,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 +224,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 +246,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>
|
||||
@@ -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,15 @@ ## 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)
|
||||
|
||||
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. If this is not performant enough, consider forwarding your queries to public resolvers to benefit from their CDNs and get faster responses.
|
||||
|
||||
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.
|
||||
However, 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.
|
||||
|
||||
DNS-over-TLS forwarders may also be used should you need on-the-wire encryption, but TLS overhead causes some speed penalties.
|
||||
|
||||
If you want to use forwarders, configure it as follows:
|
||||
|
||||
@@ -134,8 +99,6 @@ # Use cloudflare public resolvers as an example
|
||||
# forward-addr: 2606:4700:4700::1111@53
|
||||
|
||||
# alternatively, use DNS-over-TLS for forwarders.
|
||||
# this will encrypt traffic between you and the forwarder,
|
||||
# but takes more time due to TLS overhead.
|
||||
# forward-zone:
|
||||
# name: "."
|
||||
# forward-tls-upstream: yes
|
||||
@@ -170,18 +133,16 @@ ### dnsmasq
|
||||
|
||||
[arch-linux-dnsmasq]: https://wiki.archlinux.org/title/Dnsmasq
|
||||
|
||||
### Technitium DNS
|
||||
### Technitium
|
||||
|
||||
[Technitium DNS Server][technitium] supports recursion as well as a myriad of forwarding protocols, allows saving cache to disk natively, and does work well with Continuwuity. Its out-of-the-box configs however ratelimits single-IP requests by a lot, and hence must be changed.
|
||||
|
||||
You may consult this [community guide][technitium-continuwuity] for more details on setting up and fine-tuning a dedicated Technitium instance for Continuwuity.
|
||||
[Technitium][technitium] supports recursion as well as a myriad of forwarding protocols, allows saving cache to disk natively, and does work well with Continuwuity. Its default configurations however ratelimits single-IP requests by a lot, and hence must be changed. You may consult this [community guide][technitium-continuwuity] for more details on setting up a dedicated Technitium for Continuwuity.
|
||||
|
||||
[technitium]: https://github.com/TechnitiumSoftware/DnsServer
|
||||
[technitium-continuwuity]: https://muoi.me/~stratself/articles/technitium-continuwuity/
|
||||
|
||||
## 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>`.
|
||||
|
||||
@@ -189,13 +150,11 @@ ## Testing
|
||||
|
||||
## Further steps
|
||||
|
||||
It is recommended to set **`dns_cache_entries = 0`** inside Continuwuity to fully rely on the external resolver. While Continuwuity does have an internal cache, it can run into reliability issues if you're federating with many domains.
|
||||
|
||||
Additionally, you can also make the following improvements:
|
||||
- (Recommended) Set **`dns_cache_entries = 0`** inside Continuwuity and fully rely on the more performant external resolver.
|
||||
|
||||
- Consider employing **persistent cache to disk**, so your resolver can still run without hassle after a restart. Unbound, via [Cache DB module][unbound-cachedb], can use Redis as a storage backend for this feature.
|
||||
|
||||
- Consider [enabling **Serve Stale**][unbound-serve-stale] functionality to serve expired data beyond DNS TTLs. Since most Matrix homeservers have static IPs, this should still allow federating with them when upstream resolvers have timed out. For dnsproxy, this corresponds to its [optimistic caching options][dnsproxy-usage].
|
||||
- Consider [enabling **Serve Stale**][unbound-serve-stale] functionality to serve expired data beyond DNS TTLs. Since most Matrix homeservers have static IPs, this should help improve federation with them especially when upstream resolvers have timed out. For dnsproxy, this corresponds to its [optimistic caching options][dnsproxy-usage].
|
||||
|
||||
- If you still experience DNS performance issues, another step could be to **disable DNSSEC** (which is computationally expensive) at a cost of slightly decreased security. On Unbound this is done by commenting out `trust-anchors` config options and removing the `validator` module.
|
||||
|
||||
+11
-19
@@ -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
@@ -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)
|
||||
|
||||
+98
-277
@@ -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,24 +10,24 @@ # 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!
|
||||
|
||||
:::tip Generating the secrets
|
||||
LiveKit provides a utility to generate secure random keys
|
||||
```bash
|
||||
docker run --rm livekit/livekit-server:latest generate-keys
|
||||
# API Key: APIUxUnMnSkuFWV
|
||||
# API Secret: t93ZVjPeoEdyx7Wbet3kG4L3NGZIZVEFvqe0UuiVc22A
|
||||
~$ docker run --rm livekit/livekit-server:latest generate-keys
|
||||
API Key: APIUxUnMnSkuFWV
|
||||
API Secret: t93ZVjPeoEdyx7Wbet3kG4L3NGZIZVEFvqe0UuiVc22A
|
||||
```
|
||||
:::
|
||||
|
||||
@@ -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>
|
||||
@@ -205,91 +188,88 @@ ### 4. Configure your Reverse Proxy
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Example docker compose file with caddy-docker-proxy labels</summary>
|
||||
```yaml
|
||||
# This setup assumes all containers share the same bridge network
|
||||
services:
|
||||
lk-jwt-service:
|
||||
image: ghcr.io/element-hq/lk-jwt-service:latest
|
||||
container_name: lk-jwt-service
|
||||
# lk-jwt-service environment config here..
|
||||
labels:
|
||||
caddy: livekit.example.com
|
||||
caddy.@lk-jwt-service.path: "/sfu/get* /healthz* /get_token*"
|
||||
caddy.reverse_proxy: "@lk-jwt-service {{upstreams 8081}}"
|
||||
|
||||
|
||||
livekit:
|
||||
image: livekit/livekit-server:latest
|
||||
container_name: livekit
|
||||
command: --config /etc/livekit.yaml
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
caddy: livekit.example.com
|
||||
caddy.reverse_proxy: "{{upstreams 7880}}"
|
||||
volumes:
|
||||
- ./livekit.yaml:/etc/livekit.yaml:ro
|
||||
ports:
|
||||
- "127.0.0.1:7880:7880/tcp"
|
||||
- "7881:7881/tcp"
|
||||
- "50100-50200:50100-50200/udp"
|
||||
|
||||
|
||||
caddy:
|
||||
image: lucaslorentz/caddy-docker-proxy:ci-alpine
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
environment:
|
||||
- CADDY_INGRESS_NETWORKS=caddy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./data:/data
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
# If you already configured `[global.well_known]` with Continuwuity,
|
||||
# comment out the *_respond labels and add this line
|
||||
# caddy.reverse_proxy: /.well-known/matrix/* homeserver:8008
|
||||
caddy.1_respond: /.well-known/matrix/server {"m.server":"matrix.example.com:443"}
|
||||
caddy.2_respond: /.well-known/matrix/client {"m.server":{"base_url":"https://matrix.example.com"},"m.homeserver":{"base_url":"https://matrix.example.com"},"org.matrix.msc4143.rtc_foci":[{"type":"livekit","livekit_service_url":"https://livekit.example.com"}]}
|
||||
|
||||
# If you are having problems with continuwuity serving headers uncomment
|
||||
# the header section below.
|
||||
|
||||
# caddy: example.com
|
||||
# caddy.0_header: "*"
|
||||
# caddy.0_header.Access-Control-Allow-Origin: "*"
|
||||
# caddy.0_header.Access-Control-Allow-Methods: "GET, POST, OPTIONS"
|
||||
# caddy.0_header.Access-Control-Allow-Headers: "Authorization"
|
||||
# caddy.0_header.Content-Type: "application/json"
|
||||
|
||||
homeserver:
|
||||
image: forgejo.ellis.link/continuwuation/continuwuity:latest
|
||||
restart: unless-stopped
|
||||
# add additional environment, volume, and network config here...
|
||||
labels:
|
||||
caddy: matrix.example.com
|
||||
caddy.reverse_proxy: "{{upstreams 8008}}"
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### 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).
|
||||
|
||||
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).
|
||||
|
||||
Then, using that token, fetch the discovery endpoints for MatrixRTC services:
|
||||
Then, using that token, fetch the discovery endpoints for MatrixRTC services
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer <session-access-token>" \
|
||||
curl -X POST -H "Authorization: Bearer <session-access-token>" \
|
||||
https://matrix.example.com/_matrix/client/unstable/org.matrix.msc4143/rtc/transports
|
||||
```
|
||||
|
||||
@@ -338,7 +318,7 @@ ## Testing
|
||||
You can then send this payload to the lk-jwt-service:
|
||||
|
||||
```bash
|
||||
curl -X POST -d @payload.json https://livekit.example.com/get_token
|
||||
~$ curl -X POST -d @payload.json https://livekit.example.com/get_token
|
||||
```
|
||||
|
||||
The lk-jwt-service will, after checking against Continuwuity, answer with a `jwt` token to create a LiveKit media room:
|
||||
@@ -347,38 +327,26 @@ ## 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 them 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.
|
||||
|
||||
### Docker loopback networking issues
|
||||
|
||||
Some distros do not allow Docker containers to connect to its host's public IP by default. This would cause `lk-jwt-service` to fail connecting to `livekit` or `continuwuity` on the same host. As a result, you would see connection refused/connection timeouts log entries in the JWT service, even when `LIVEKIT_URL` has been configured correctly.
|
||||
|
||||
You can also test that this is the case by cURLing from a sidecar container:
|
||||
|
||||
```bash
|
||||
docker run --rm --net container:lk-jwt-service docker.io/curlimages/curl https://livekit.example.com
|
||||
# --- some errors ---
|
||||
```
|
||||
|
||||
To alleviate this, you can try one of the following workarounds:
|
||||
|
||||
- Use `network_mode: host` for the `lk-jwt-service` container (instead of the default bridge networking).
|
||||
|
||||
- Add an `extra_hosts` file mapping livekit's (and continuwuity's) domain name to a locally-reachable address:
|
||||
- Add an `extra_hosts` file mapping livekit's (and continuwuity's) domain name to a localhost address:
|
||||
|
||||
```diff
|
||||
# in docker-compose.yaml
|
||||
@@ -392,19 +360,11 @@ # --- some errors ---
|
||||
|
||||
- (**untested, use at your own risk**) Implement an iptables workaround as shown [here](https://forums.docker.com/t/unable-to-connect-to-host-service-from-inside-docker-container/145749/6).
|
||||
|
||||
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.
|
||||
After implementing the changes and restarting your compose, you can test whether the connection works by cURLing from a sidecar container:
|
||||
|
||||
### 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"
|
||||
```bash
|
||||
~$ docker run --rm --net container:lk-jwt-service docker.io/curlimages/curl https://livekit.example.com
|
||||
OK
|
||||
```
|
||||
|
||||
### Workaround for non-federating servers
|
||||
@@ -425,156 +385,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
@@ -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
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"name": "rpm",
|
||||
"label": "RPM"
|
||||
"name": "fedora",
|
||||
"label": "Fedora"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
|
||||
+15
-41
@@ -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
|
||||
|
||||
@@ -43,7 +44,7 @@ ### Prerequisites
|
||||
- Alternatively, if you want both client and federation traffic on `:443`, you can configure `CONTINUWUITY_WELL_KNOWN` following some of the [examples](#choose-your-reverse-proxy) below.
|
||||
|
||||
:::tip Split-domain setups
|
||||
For more setups with `.well-known` delegation and split-domain deployments, consult the [Delegation/Split-domain](../guides/delegation) page.
|
||||
For more setups with `.well-known` delegation and split-domain deployments, consult the [Delegation/Split-domain](../advanced/delegation) page.
|
||||
:::
|
||||
|
||||
## Docker Compose
|
||||
@@ -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:
|
||||
@@ -78,25 +79,14 @@ ### Choose Your Reverse Proxy
|
||||
nameserver 1.1.1.1
|
||||
```
|
||||
|
||||
Consult the [**DNS tuning guide (recommended)**](../guides/dns.mdx) for full solutions to this issue.
|
||||
Consult the [**DNS tuning guide (recommended)**](../advanced/dns.mdx) for full solutions to this issue.
|
||||
:::
|
||||
|
||||
#### 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.
|
||||
@@ -195,28 +185,13 @@ ## Testing
|
||||
|
||||
Test that your setup works by following these [instructions](./generic.mdx#how-do-i-know-it-works)
|
||||
|
||||
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
|
||||
|
||||
:::warning For testing only
|
||||
The instructions below are only meant for a quick demo of Continuwuity with **federation disabled**.
|
||||
For production deployment, we recommend using [Docker Compose](#docker-compose).
|
||||
:::note For testing only
|
||||
The instructions below are only meant for a quick demo of Continuwuity.
|
||||
For production deployment, we recommend using [Docker Compose](#docker-compose)
|
||||
:::
|
||||
|
||||
Get a working Continuwuity server with an admin user in four steps:
|
||||
@@ -236,7 +211,7 @@ ### Docker - Quick Run
|
||||
-e CONTINUWUITY_SERVER_NAME="example.com" \
|
||||
-e CONTINUWUITY_DATABASE_PATH="/var/lib/continuwuity" \
|
||||
-e CONTINUWUITY_ADDRESS="0.0.0.0" \
|
||||
-e CONTINUWUITY_ALLOW_FEDERATION="false" \
|
||||
-e CONTINUWUITY_ALLOW_REGISTRATION="false" \
|
||||
--name continuwuity \
|
||||
forgejo.ellis.link/continuwuation/continuwuity:latest \
|
||||
/sbin/conduwuit
|
||||
@@ -258,9 +233,9 @@ ### Docker - Quick Run
|
||||
Pick your own username and password!
|
||||
```
|
||||
|
||||
4. Configure your reverse proxy to forward HTTPS traffic to Continuwuity at port 8008. See [Docker Compose](#docker-compose) or the [Generic instructions](./generic.mdx#setting-up-the-reverse-proxy) for examples.
|
||||
4. Configure your reverse proxy to forward HTTPS traffic to Continuwuity at port 8008. See [Docker Compose](#docker-compose) for examples.
|
||||
|
||||
Once configured, log in to your server with any Matrix client, and register for an account with the registration token from step 3. If you did not configure step 4., log in via the `http://<your_server_ip>:8008` address. You will be automatically invited to the admin room where you can [manage your server](../reference/admin).
|
||||
Once configured, log in to your server with any Matrix client, and register for an account with the registration token from step 3. You'll automatically be invited to the admin room where you can [manage your server](../reference/admin).
|
||||
|
||||
### (Optional) Building Custom Images
|
||||
|
||||
@@ -292,7 +267,6 @@ ### Accessing the Server's Console
|
||||
|
||||
## Next steps
|
||||
|
||||
- For smooth federation, set up a caching resolver according to the [**DNS tuning guide**](../guides/dns.mdx) (recommended)
|
||||
- For smooth federation, set up a caching resolver according to the [**DNS tuning guide**](../advanced/dns.mdx) (recommended)
|
||||
- To set up Audio/Video communication, see the [**Calls**](../calls.mdx) 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.mdx).
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
# RPM Installation Guide
|
||||
|
||||
Continuwuity is available as RPM packages for Fedora and compatible distributions.
|
||||
We do not currently have infrastructure to build RPMs for RHEL and compatible distributions, but this is a work in progress.
|
||||
|
||||
The RPM packaging files are maintained in the `fedora/` directory:
|
||||
- `continuwuity.spec.rpkg` - RPM spec file using rpkg macros for building from git
|
||||
- `continuwuity.service` - Systemd service file for the server
|
||||
- `RPM-GPG-KEY-continuwuity.asc` - GPG public key for verifying signed packages
|
||||
|
||||
RPM packages built by CI are signed with our GPG key (RSA, ID: `6595 E8DB 9191 D39A 46D6 A514 4BA7 F590 DF0B AA1D`). # spellchecker:disable-line
|
||||
|
||||
```bash
|
||||
# Import the signing key
|
||||
sudo rpm --import https://forgejo.ellis.link/api/packages/continuwuation/rpm/repository.key
|
||||
|
||||
# Verify a downloaded package
|
||||
rpm --checksig continuwuity-*.rpm
|
||||
```
|
||||
|
||||
## Installation methods
|
||||
|
||||
**Stable releases** (recommended)
|
||||
|
||||
```bash
|
||||
# Add the repository and install
|
||||
sudo dnf config-manager addrepo --from-repofile=https://forgejo.ellis.link/api/packages/continuwuation/rpm/stable.repo
|
||||
sudo dnf install continuwuity
|
||||
```
|
||||
|
||||
**Development builds** from main branch
|
||||
|
||||
```bash
|
||||
# Add the dev repository and install
|
||||
sudo dnf config-manager addrepo --from-repofile=https://forgejo.ellis.link/api/packages/continuwuation/rpm/dev.repo
|
||||
sudo dnf install continuwuity
|
||||
```
|
||||
|
||||
**Feature branch builds** (example: `tom/new-feature`)
|
||||
|
||||
```bash
|
||||
# Branch names are sanitized (slashes become hyphens, lowercase only)
|
||||
sudo dnf config-manager addrepo --from-repofile=https://forgejo.ellis.link/api/packages/continuwuation/rpm/tom-new-feature.repo
|
||||
sudo dnf install continuwuity
|
||||
```
|
||||
|
||||
**Manual repository configuration** (alternative method)
|
||||
|
||||
```bash
|
||||
cat << 'EOF' | sudo tee /etc/yum.repos.d/continuwuity.repo
|
||||
[continuwuity]
|
||||
name=Continuwuity - Matrix homeserver
|
||||
baseurl=https://forgejo.ellis.link/api/packages/continuwuation/rpm/stable
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
gpgkey=https://forgejo.ellis.link/api/packages/continuwuation/rpm/repository.key
|
||||
EOF
|
||||
|
||||
sudo dnf install continuwuity
|
||||
```
|
||||
|
||||
## Package management
|
||||
|
||||
**Automatic updates** with DNF Automatic
|
||||
|
||||
```bash
|
||||
# Install and configure
|
||||
sudo dnf install dnf-automatic
|
||||
sudo nano /etc/dnf/automatic.conf # Set: apply_updates = yes
|
||||
sudo systemctl enable --now dnf-automatic.timer
|
||||
```
|
||||
|
||||
**Manual updates**
|
||||
|
||||
```bash
|
||||
# Check for updates
|
||||
sudo dnf check-update continuwuity
|
||||
|
||||
# Update to latest version
|
||||
sudo dnf update continuwuity
|
||||
```
|
||||
|
||||
**Switching channels** (stable/dev/feature branches)
|
||||
|
||||
```bash
|
||||
# List enabled repositories
|
||||
dnf repolist | grep continuwuation
|
||||
|
||||
# Disable current repository
|
||||
sudo dnf config-manager --set-disabled continuwuation-stable # or -dev, or branch name
|
||||
|
||||
# Enable desired repository
|
||||
sudo dnf config-manager --set-enabled continuwuation-dev # or -stable, or branch name
|
||||
|
||||
# Update to the new channel's version
|
||||
sudo dnf update continuwuity
|
||||
```
|
||||
|
||||
**Verifying installation**
|
||||
|
||||
```bash
|
||||
# Check installed version
|
||||
rpm -q continuwuity
|
||||
|
||||
# View package information
|
||||
rpm -qi continuwuity
|
||||
|
||||
# List installed files
|
||||
rpm -ql continuwuity
|
||||
|
||||
# Verify package integrity
|
||||
rpm -V continuwuity
|
||||
```
|
||||
|
||||
## Service management and removal
|
||||
|
||||
**Systemd service commands**
|
||||
|
||||
```bash
|
||||
# Start the service
|
||||
sudo systemctl start conduwuit
|
||||
|
||||
# Enable on boot
|
||||
sudo systemctl enable conduwuit
|
||||
|
||||
# Check status
|
||||
sudo systemctl status conduwuit
|
||||
|
||||
# View logs
|
||||
sudo journalctl -u conduwuit -f
|
||||
```
|
||||
|
||||
**Uninstallation**
|
||||
|
||||
```bash
|
||||
# Stop and disable the service
|
||||
sudo systemctl stop conduwuit
|
||||
sudo systemctl disable conduwuit
|
||||
|
||||
# Remove the package
|
||||
sudo dnf remove continuwuity
|
||||
|
||||
# Remove the repository (optional)
|
||||
sudo rm /etc/yum.repos.d/continuwuation-*.repo
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**GPG key errors**: Temporarily disable GPG checking
|
||||
|
||||
```bash
|
||||
sudo dnf --nogpgcheck install continuwuity
|
||||
```
|
||||
|
||||
**Repository metadata issues**: Clear and rebuild cache
|
||||
|
||||
```bash
|
||||
sudo dnf clean all
|
||||
sudo dnf makecache
|
||||
```
|
||||
|
||||
**Finding specific versions**
|
||||
|
||||
```bash
|
||||
# List all available versions
|
||||
dnf --showduplicates list continuwuity
|
||||
|
||||
# Install a specific version
|
||||
sudo dnf install continuwuity-<version>
|
||||
```
|
||||
|
||||
## Building locally
|
||||
|
||||
Build the RPM locally using rpkg:
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
sudo dnf install rpkg rpm-build cargo-rpm-macros systemd-rpm-macros
|
||||
|
||||
# Clone the repository
|
||||
git clone https://forgejo.ellis.link/continuwuation/continuwuity.git
|
||||
cd continuwuity
|
||||
|
||||
# Build SRPM
|
||||
rpkg srpm
|
||||
|
||||
# Build RPM
|
||||
rpmbuild --rebuild *.src.rpm
|
||||
```
|
||||
+41
-44
@@ -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
|
||||
|
||||
@@ -142,7 +170,7 @@ ## Exposing ports in the firewall or the router
|
||||
are: `ufw allow 8448/tcp` and `ufw allow 443/tcp`.
|
||||
|
||||
:::tip Alternative port/domain setups
|
||||
If you would like to use only port 443, a different port, or a subdomain for the homeserver, you will need to set up `.well-known` delegation. Consult the `[global.well_known]` section of the config file, and the [**Delegation/Split-domain**](../guides/delegation) page to learn more about these kinds of deployments.
|
||||
If you would like to use only port 443, a different port, or a subdomain for the homeserver, you will need to set up `.well-known` delegation. Consult the `[global.well_known]` section of the config file, and the [**Delegation/Split-domain**](../advanced/delegation) page to learn more about these kinds of deployments.
|
||||
:::
|
||||
|
||||
## Setting up the Reverse Proxy
|
||||
@@ -179,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
|
||||
- `/_conduwuit/` and `/_continuwuity/` - ad-hoc Continuwuity routes for password resets, email verification, and server details such as `/local_user_count` and `/server_version`.
|
||||
|
||||
You can optionally reverse proxy the following individual routes:
|
||||
|
||||
@@ -187,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.
|
||||
|
||||
@@ -238,7 +266,7 @@ ## Starting Your Server
|
||||
```
|
||||
|
||||
You can then open [a Matrix client][matrix-clients],
|
||||
enter your homeserver address, and register with the provided token.
|
||||
enter your homeserver address, and try to register with the provided token.
|
||||
By default, the first user is the instance's first admin. They will be added
|
||||
to the `#admin:example.com` room and be able to [issue admin commands](../reference/admin/index.md).
|
||||
|
||||
@@ -246,22 +274,18 @@ ## Starting Your Server
|
||||
|
||||
## How do I know it works?
|
||||
|
||||
To check if your server can communicate with other homeservers,
|
||||
use an external testing tool:
|
||||
|
||||
- [Matrix Connectivity Tester](https://federationtester.mtrnord.blog/)
|
||||
- [Matrix Federation Tester](https://federationtester.matrix.org/)
|
||||
|
||||
If you can register your account but cannot join federated rooms, check your configuration
|
||||
To check if your server can communicate with other homeservers, use the
|
||||
[Matrix Federation Tester](https://federationtester.mtrnord.blog/). If you can
|
||||
register your account but cannot join federated rooms, check your configuration
|
||||
and verify that your federation endpoints are opened and forwarded correctly.
|
||||
|
||||
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
|
||||
@@ -272,33 +296,6 @@ # For client-server endpoints
|
||||
|
||||
## What's next?
|
||||
|
||||
- For smooth federation, set up a caching resolver according to the [**DNS tuning guide**](../guides/dns.mdx) (recommended)
|
||||
- To configure OIDC login with an identity provider, see the [**delegated authentication guide**](../guides/oidc.mdx).
|
||||
- For smooth federation, set up a caching resolver according to the [**DNS tuning guide**](../advanced/dns.mdx) (recommended)
|
||||
- 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.
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
import { Tab, Tabs} from '@rspress/core/theme';
|
||||
|
||||
# RPM Installation Guide
|
||||
|
||||
## Overview
|
||||
|
||||
Continuwuity versions v0.5.10+ are available as RPM packages for the following distributions:
|
||||
|
||||
<Tabs groupId="distro">
|
||||
<Tab label="Fedora">
|
||||
Available for upstream-supported Fedora versions (including compatible distributions, such as Ultramarine Linux) and Rawhide through Terra.
|
||||
</Tab>
|
||||
<Tab label="EL">
|
||||
Available for Enterprise Linux (RHEL, AlmaLinux, Rocky Linux, etc.) **10+** through Terra.
|
||||
|
||||
:::warning Oracle Linux support
|
||||
Due to upstream limitations, Terra is only usable on Oracle Linux if you use [upstream EPEL](https://docs.fedoraproject.org/en-US/epel/getting-started/)
|
||||
rather than Oracle's rebuilds of EPEL. Oracle tends to lag behind on new EL versions, both major and minor—for example, Oracle's release of 10.2 lagged
|
||||
approximately 1.5 months behind other ELs—so you may encounter further compatibility issues with EPEL.
|
||||
**For this reason, it is recommended that you use another EL distribution if at all possible.**
|
||||
:::
|
||||
|
||||
</Tab>
|
||||
<Tab label="SUSE">
|
||||
Available for openSUSE Tumbleweed and [supported Leap versions](https://en.opensuse.org/Lifetime) through the openSUSE Build Service.
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Installation methods
|
||||
|
||||
### Stable releases (recommended)
|
||||
|
||||
<Tabs groupId="distro">
|
||||
<Tab label="Fedora">
|
||||
1. Follow [Terra's directions for adding the Terra repo on your distribution](https://docs.terrapkg.com/usage/installing/#fedora-and-derivatives).
|
||||
2. Install the `continuwuity` package.
|
||||
</Tab>
|
||||
<Tab label="EL">
|
||||
1. Follow [Terra's directions for adding the Terra repo on your distribution](https://docs.terrapkg.com/usage/installing/#enterprise-linux). Be sure to acquire/enable relevant dependencies!
|
||||
2. Install the `continuwuity` package.
|
||||
</Tab>
|
||||
<Tab label="SUSE">
|
||||
openSUSE packages are available through an openSUSE Build Service project namespace provided by a community member.
|
||||
|
||||
1. Navigate to [this page](https://software.opensuse.org/download.html?project=home%3Ajulian45&package=continuwuity).
|
||||
2. Click on the "Add repository and install manually" text to expand install instructions.
|
||||
3. Follow the provided instructions for your version of openSUSE.
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Nightly releases
|
||||
Nightly versions are built from the latest commit on the `main` branch every 24 hours.
|
||||
|
||||
<Tabs groupId="distro">
|
||||
<Tab label="Fedora">
|
||||
1. Follow [Terra's directions for adding the Terra repo on your distribution](https://docs.terrapkg.com/usage/installing/#fedora-and-derivatives).
|
||||
2. Install the `continuwuity-nightly` package.
|
||||
</Tab>
|
||||
<Tab label="EL">
|
||||
1. Follow [Terra's directions for adding the Terra repo on your distribution](https://docs.terrapkg.com/usage/installing/#enterprise-linux). Be sure to acquire/enable relevant dependencies!
|
||||
2. Install the `continuwuity-nightly` package.
|
||||
</Tab>
|
||||
<Tab label="SUSE">
|
||||
Nightly packages for openSUSE are **not currently available**.
|
||||
|
||||
If there is an ongoing need for these, please ask in `#continuwuity:continuwuity.org` or [open an issue on Forgejo](https://forgejo.ellis.link/continuwuation/continuwuity/issues/new).
|
||||
In the meantime, you may follow the [generic deployment instructions](generic).
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Service management and removal
|
||||
|
||||
**Systemd service commands**
|
||||
|
||||
```bash
|
||||
# Start the service
|
||||
sudo systemctl start conduwuit
|
||||
|
||||
# Enable on boot
|
||||
sudo systemctl enable conduwuit
|
||||
|
||||
# Check status
|
||||
sudo systemctl status conduwuit
|
||||
|
||||
# View logs
|
||||
sudo journalctl -u conduwuit -f
|
||||
```
|
||||
|
||||
**Uninstallation**
|
||||
|
||||
```bash
|
||||
# Stop and disable the service
|
||||
sudo systemctl stop conduwuit
|
||||
sudo systemctl disable conduwuit
|
||||
|
||||
# Remove the package
|
||||
sudo dnf remove continuwuity # replace `dnf` with `zypper` on openSUSE
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**GPG key errors**: Temporarily disable GPG checking
|
||||
|
||||
```bash
|
||||
sudo dnf --nogpgcheck install continuwuity
|
||||
```
|
||||
|
||||
**Repository metadata issues**: Clear and rebuild cache
|
||||
|
||||
```bash
|
||||
sudo dnf clean all
|
||||
sudo dnf makecache
|
||||
```
|
||||
|
||||
**Finding specific versions**
|
||||
|
||||
```bash
|
||||
# List all available versions
|
||||
dnf --showduplicates list continuwuity
|
||||
|
||||
# Install a specific version
|
||||
sudo dnf install continuwuity-<version>
|
||||
```
|
||||
|
||||
## Building locally
|
||||
|
||||
<Tabs groupId="distro">
|
||||
<Tab label="Fedora">
|
||||
:::details Directly from Continuwuity source
|
||||
|
||||
Build the RPM locally using rpkg:
|
||||
```bash
|
||||
# Install dependencies
|
||||
sudo dnf install rpkg rpm-build cargo-rpm-macros systemd-rpm-macros
|
||||
|
||||
# Clone the repository
|
||||
git clone https://forgejo.ellis.link/continuwuation/continuwuity.git
|
||||
cd continuwuity
|
||||
|
||||
# Build SRPM
|
||||
rpkg srpm
|
||||
|
||||
# Build RPM
|
||||
rpmbuild --rebuild *.src.rpm
|
||||
```
|
||||
:::
|
||||
|
||||
Or, use Terra:
|
||||
1. Follow [Terra's prep directions](https://docs.terrapkg.com/contributing/getting-started/#preparation) to bootstrap your development environment.
|
||||
2. `git clone` the [Terra sources repo](https://github.com/terrapkg/packages).
|
||||
3. Follow [Terra's build instructions](https://docs.terrapkg.com/contributing/getting-started/#building), using the path `anda/misc/continuwuity/nightly/pkg`. If desiring a build of the latest stable version, replace `nightly` with `stable` instead.
|
||||
</Tab>
|
||||
<Tab label="EL">
|
||||
1. Follow [Terra's prep directions](https://docs.terrapkg.com/contributing/getting-started/#preparation) to bootstrap your development environment.
|
||||
2. `git clone` the [Terra sources repo](https://github.com/terrapkg/packages).
|
||||
3. Follow [Terra's build instructions](https://docs.terrapkg.com/contributing/getting-started/#building), using the path `anda/misc/continuwuity/nightly/pkg`. If desiring a build of the latest stable version, replace `nightly` with `stable` instead.
|
||||
</Tab>
|
||||
<Tab label="SUSE">
|
||||
1. Navigate to [this package's location in the openSUSE Build Service web UI](https://build.opensuse.org/package/show/home:julian45/continuwuity).
|
||||
2. Click on the "Checkout package" text and follow the instructions to acquire a local copy of the packaging source.
|
||||
3. In the `_service` file, adjust the revision within the `<param name="revision">` tag (approx. line 6) to your desired git repo revision.
|
||||
4. Run `osc service ra` to update your copy of the Continuwuity sources and vendored packages.
|
||||
5. Run `osc build` to locally build an openSUSE-ready RPM.
|
||||
</Tab>
|
||||
</Tabs>
|
||||
@@ -81,6 +81,8 @@ ## List of forked dependencies
|
||||
All forked dependencies are maintained under the
|
||||
[continuwuation organization on Forgejo](https://forgejo.ellis.link/continuwuation):
|
||||
|
||||
- [ruwuma][continuwuation-ruwuma] - Fork of [ruma/ruma][ruma] with various
|
||||
performance improvements, more features and better client/server interop
|
||||
- [rocksdb][continuwuation-rocksdb] - Fork of [facebook/rocksdb][rocksdb] via
|
||||
[`@zaidoon1`][8] with liburing build fixes and GCC debug build fixes
|
||||
- [jemallocator][continuwuation-jemallocator] - Fork of
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
# Configuring delegated authentication
|
||||
|
||||
Continuwuity supports delegating user authentication to an external identity provider that implements the OpenID Connect specification, such as Authentik, kanidm, or Keycloak.
|
||||
|
||||
:::warning{title="OIDC versus OAuth, and supported clients"}
|
||||
**OIDC** is not to be confused with **OAuth**. In the context of Matrix, OAuth is the protocol that Matrix clients use to authenticate with the _homeserver_. OIDC is the protocol that the _homeserver_ uses to communicate with the _identity provider_. Continuwuity supports OAuth by default, alongside the legacy **UIAA** authentication framework.
|
||||
|
||||
When OIDC is configured, Continuwuity will disable its support for legacy authentication. **Only clients that support OAuth**, such as the Element family of clients, will be able to log in when OIDC is configured. If your client of choice shows an error when you try to log in after configuring OIDC, it likely does not support OAuth. This is an issue with your client, not Continuwuity, and should be reported to your client's developers.
|
||||
:::
|
||||
|
||||
A simple OIDC configuration is as easy as creating a new OIDC application in your identity provider's settings and supplying Continuwuity with the client ID and client secret. This guide will use kanidm as an example, but the described steps are broadly applicable to other identity providers.
|
||||
|
||||
First, create a new application for Continuwuity in your identity provider.
|
||||
```sh
|
||||
# Here, `c10y` is the client ID that kanidm will use, and `Continuwuity` is the display name.
|
||||
# Other identity providers may generate a client ID for you.
|
||||
# Use the domain that clients can reach Continuwuity at, which may not be the same as your server name
|
||||
# if you have configured well-known delegation.
|
||||
kanidm system oauth2 create c10y Continuwuity https://matrix.yourdomain.com
|
||||
```
|
||||
|
||||
Configure the redirect URL that Continuwuity uses.
|
||||
```sh
|
||||
kanidm system oauth2 add-redirect-url c10y https://matrix.yourdomain.com/_continuwuity/oidc/complete
|
||||
```
|
||||
|
||||
Allow Continuwuity to request the `openid` scope. Other identity providers may not require this step.
|
||||
```sh
|
||||
kanidm system oauth2 update-scope-map c10y idm_all_persons openid
|
||||
```
|
||||
|
||||
Find the client secret that was generated. Other identity providers may show this information in their web UI.
|
||||
```sh
|
||||
kanidm system oauth2 show-basic-secret c10y
|
||||
d1qgx352kkuvs1j70b6w293d65x68jve1f7b27fyk90gjhpr
|
||||
```
|
||||
|
||||
Configure Continuwuity with the client ID, client secret, and discovery URL. kanidm has a different discovery URL for each client, but other identity providers may have a single discovery URL at the root of their domain.
|
||||
|
||||
```toml
|
||||
[global.oauth.oidc]
|
||||
|
||||
# `/.well-known/openid-configuration` will be appended automatically
|
||||
discovery_url = "https://idm.example.com/oauth2/openid/c10y"
|
||||
|
||||
# This may be randomly generated by your identity provider. kanidm requires
|
||||
# you to set it manually when you create the application.
|
||||
client_id = "c10y"
|
||||
|
||||
# From the previous step
|
||||
client_secret = "d1qgx352kkuvs1j70b6w293d65x68jve1f7b27fyk90gjhpr"
|
||||
```
|
||||
|
||||
Finally, restart Continuwuity, and log out and back in again. Your client should prompt you to continue in your web browser and open a webpage with the Continuwuity logo that allows you to continue in your identity provider. Once you log in successfully, you will be prompted to choose a user ID -- to link your existing account, enter its user ID, and then your old password when prompted.
|
||||
|
||||
Continuwuity offers several additional configuration options to tweak its integration with your identity provider. Review the `[global.oauth.oidc]` section towards the bottom of the [reference configuration](../reference/config) for a complete list of options and documentation.
|
||||
@@ -1,137 +0,0 @@
|
||||
# Performance tuning
|
||||
|
||||
Continuwuity's default configs are suited for many typical setups and scales appropriately with the size of your hardware. However, there are many scenarios where additional modifications can be made to better utilize your server resources.
|
||||
|
||||
This page aims to outline various performance tweaks for Continuwuity and their effects. These adjustments are especially helpful for homeservers that join many large federated rooms or have many users, and it will become increasingly necessary as the Matrix network expands. As always, your mileage may vary according to your setup's specifics. If you have further discussions or recommendations, please share them in the community rooms.
|
||||
|
||||
## DNS tuning (recommended)
|
||||
|
||||
DNS tuning is important to ensure a smooth experience for federated servers. Please see the dedicated [DNS tuning guide](./dns.mdx).
|
||||
|
||||
## Cache capacities
|
||||
|
||||
If you have memory to spare, consider increasing the `cache_capacity_modifier` value to a larger number to allow more data to be stored in hot memory. This *significantly* speeds up many intensive operations (such as state resolutions) and decreases CPU usage and disk I/O. Start with a baseline of `cache_capacity_modifier = 2.0` and tune up until you are satisfied with RAM usage.
|
||||
|
||||
On the other hand, if your system doesn't have a lot of RAM, consider decreasing the cache capacity modifier to something smaller than `1.0` to avoid low-memory issues (at the cost of higher load on disk/CPU). This recommendation also works if your system has abnormally little RAM compared to the number of CPU cores (for example, 2GB RAM for 12 cores), as cache capacities scale according to number of available cores.
|
||||
|
||||
## Disabling some features
|
||||
|
||||
You can disable outgoing **typing notifications** and **read markers** to reduce strain on the CPU and network when actively participating in rooms.
|
||||
|
||||
```toml
|
||||
# disables sending read receipts
|
||||
allow_outgoing_read_receipts = false
|
||||
# disables sending typing notifications
|
||||
allow_outgoing_typing = false
|
||||
```
|
||||
|
||||
Outgoing presence updates are also considered very expensive and have been disabled by default (`allow_outgoing_presence = false`). For more savings, you may wish to disable _all_ processing of presence entirely.
|
||||
|
||||
```toml title=continuwuity.toml
|
||||
# disabling presence updates entirely
|
||||
allow_local_presence = false
|
||||
allow_incoming_presence = false
|
||||
allow_outgoing_presence = false
|
||||
```
|
||||
|
||||
## Tuning database compression
|
||||
|
||||
:::warning
|
||||
These steps SHOULD be done **before** starting Continuwuity for the first time. While switching database compression midway through is theoretically possible, this has not been tested extensively in the wild.
|
||||
:::
|
||||
|
||||
### Changing the compression algorithm
|
||||
|
||||
For reduced CPU usage at a tradeoff of increased storage space, consider deploying Continuwuity with the faster and less intensive `lz4` algorithm instead of `zstd` for rocksdb, and disable WAL compression entirely:
|
||||
|
||||
```toml
|
||||
### in continuwuity.toml ###
|
||||
rocksdb_compression_algo = "lz4"
|
||||
rocksdb_wal_compression = "none"
|
||||
```
|
||||
|
||||
This tweak can especially be helpful if you have an older or less performant CPU (e.g. a Raspberry Pi) and disk space to spare.
|
||||
|
||||
### Increasing bottommost layer compression (`zstd` only)
|
||||
|
||||
The bottommost layer of the database usually contains old and read-only data, so it is a suitable place for further compression. In Continuwuity, this is possible by setting `rocksdb_bottommost_compression = true` and tuning `rocksdb_bottommost_compression_level` to a more compact level than the default one used in `rocksdb_compression_level`. This tweak comes at a cost of increased CPU usage, but may prevent your database from growing too large in the long run.
|
||||
|
||||
For those using `zstd` compression, the compression level ranges from 1 to 22. An example like this could apply:
|
||||
|
||||
```toml
|
||||
### in continuwuity.toml ###
|
||||
rocksdb_compression_algo = "zstd"
|
||||
rocksdb_compression_level = 32767 # magic number, translates to level 3 on zstd
|
||||
rocksdb_bottommost_compression = true
|
||||
rocksdb_bottommost_compression_level = 9 # level 9 on zstd
|
||||
```
|
||||
|
||||
For `lz4` users, the default level (`-1`) is already the most compact. You can only further decrease it to favor compression speed over ratio.
|
||||
|
||||
Consult these documents for more information on compression tuning and levels:
|
||||
|
||||
- [Rocksdb compression documentation][rocksdb-compression]
|
||||
- [Rocksdb default compression levels][rocksdb-compression-defaults]
|
||||
- [Zstd manual][zstd-manual]
|
||||
- [Lz4 manual][lz4-manual]
|
||||
|
||||
[rocksdb-compression]: https://github.com/facebook/rocksdb/wiki/Compression
|
||||
[rocksdb-compression-defaults]: https://github.com/facebook/rocksdb/blob/main/include/rocksdb/options.h#L208-L217
|
||||
[zstd-manual]: https://facebook.github.io/zstd/zstd_manual.html
|
||||
[lz4-manual]: https://github.com/lz4/lz4/blob/release/doc/lz4_manual.html
|
||||
|
||||
## Other tweaks
|
||||
|
||||
### Using UNIX sockets
|
||||
|
||||
If your homeserver and reverse proxy live on the same machine, you may wish to expose Continuwuity on a UNIX socket instead of a port. This removes TCP overhead between the two programs.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Example config with Caddy</summary>
|
||||
|
||||
```toml
|
||||
### in continuwuity.toml ###
|
||||
|
||||
# `address` and `port` has to be commented out first
|
||||
#address = ["127.0.0.1", "::1"]
|
||||
#port = 8008
|
||||
unix_socket_path = "/run/continuwuity/continuwuity.sock"
|
||||
```
|
||||
|
||||
```
|
||||
### in your Caddyfile ###
|
||||
https://matrix.example.com {
|
||||
reverse_proxy unix//run/continuwuity/continuwuity.sock
|
||||
|
||||
# alternatively, use the http2-plaintext protocol
|
||||
# reverse_proxy unix+h2c//run/continuwuity/continuwuity.sock
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### 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:
|
||||
|
||||
```toml
|
||||
# Example config, using maintainers' recommended homeservers
|
||||
trusted_servers = ["codestorm.net","starstruck.systems","unredacted.org","matrix.org"]
|
||||
```
|
||||
|
||||
Avoid prioritising `matrix.org` as your primary trusted server, as it tends to be quite slow.
|
||||
|
||||
Some users have also reported that increasing `trusted_server_batch_size` has helped with faster joins for huge rooms. Start with doubling the default to `2048` until you find a suitable value.
|
||||
|
||||
### Enable HTTP/3 on your reverse proxy
|
||||
|
||||
Consider enabling the newer **HTTP/3** protocol for inbound connections to Continuwuity. In Caddy HTTP/3 is allowed by default, but you must expose port :443/**udp** on your firewall.
|
||||
|
||||
HTTP/3 can vastly improve Client-Server connections especially on unstable networks, as it reduces packet losses and latency from TCP head-of-line blocking, includes workarounds for network switching, and reduces connection establishment handshakes. Continuwuity also includes experimental _outbound_ HTTP/3 support in its Docker images, so connections between Continuwuity servers can benefit from this too.
|
||||
+35
-48
@@ -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 it’s 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 don’t work together.
|
||||
:::
|
||||
> Compression is done using the COW mechanism so it’s 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 don’t 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,
|
||||
"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!"
|
||||
"id": 12,
|
||||
"mention_room": false,
|
||||
"date": "2026-04-24",
|
||||
"message": "[v0.5.8](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.8) is out! This is a patch release which fixes a bug in 0.5.7's email support -- upgrade soon if you use that feature."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -27,7 +27,3 @@ ## `!admin appservices show-appservice-config`
|
||||
## `!admin appservices list-registered`
|
||||
|
||||
List all the currently registered appservices
|
||||
|
||||
## `!admin appservices ensure-puppets-active`
|
||||
|
||||
Ensure no appservice puppets are marked as deactivated. This is a debug command to fix issues caused by a faulty database migration in Continuwuity 26.6.0
|
||||
|
||||
@@ -10,13 +10,7 @@ ## `!admin debug echo`
|
||||
|
||||
## `!admin debug get-auth-chain`
|
||||
|
||||
Loads the auth_chain of a PDU, reporting how long it took
|
||||
|
||||
## `!admin debug show-auth-chain`
|
||||
|
||||
Walks & displays the auth_chain of a PDU in a mermaid graph format.
|
||||
|
||||
This is useless to basically anyone but developers, and is also probably slow and memory hungry.
|
||||
Get the auth_chain of a PDU
|
||||
|
||||
## `!admin debug parse-pdu`
|
||||
|
||||
@@ -50,12 +44,6 @@ ## `!admin debug get-room-state`
|
||||
|
||||
Of course the check is still done on the actual client API.
|
||||
|
||||
## `!admin debug get-state-at`
|
||||
|
||||
Gets all the room state events at the specified event.
|
||||
|
||||
State at event might not be available for some PDUs, such as rejected ones.
|
||||
|
||||
## `!admin debug get-signing-keys`
|
||||
|
||||
Get and display signing keys from local cache or remote server
|
||||
@@ -146,10 +134,6 @@ ## `!admin debug send-test-email`
|
||||
|
||||
Send a test email to the invoking admin's email address
|
||||
|
||||
## `!admin debug rooms-by-extremity-count`
|
||||
|
||||
Lists room IDs by forward extremity count in descending order
|
||||
|
||||
## `!admin debug tester`
|
||||
|
||||
Developer test stubs
|
||||
|
||||
@@ -7,14 +7,13 @@ ## Running commands
|
||||
|
||||
* All commands listed here may be used by server administrators in the admin room by sending them as messages.
|
||||
* If the `admin_escape_commands` configuration option is enabled, server administrators may run certain commands in public rooms by prefixing them with a single backslash. These commands will only run on _their_ homeserver, even if they are a member of another homeserver's admin room. Some sensitive commands cannot be used outside the admin room and will return an error.
|
||||
* All commands listed here may be used in the server's console, if it is enabled. Commands entered in the console do not require the `!admin` prefix.
|
||||
* All commands listed here may be used in the server's console, if it is enabled. Commands entered in the console do not require the `!admin` prefix. If Continuwuity is deployed via Docker, be sure to set the appropriate options detailed in [the Docker deployment guide](../../deploying/docker.mdx#accessing-the-servers-console) to enable access to the server's console.
|
||||
|
||||
## Categories
|
||||
|
||||
- [`!admin appservices`](appservices/): Commands for managing appservices
|
||||
- [`!admin users`](users/): Commands for managing local users
|
||||
- [`!admin token`](token/): Commands for managing registration tokens
|
||||
- [`!admin oidc`](oidc/): Commands for managing OIDC
|
||||
- [`!admin rooms`](rooms/): Commands for managing rooms
|
||||
- [`!admin federation`](federation/): Commands for managing federation
|
||||
- [`!admin server`](server/): Commands for managing the server
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<!-- This file is generated by `cargo xtask generate-docs`. Do not edit. -->
|
||||
# `!admin oidc`
|
||||
|
||||
Commands for managing OIDC
|
||||
|
||||
|
||||
## `!admin oidc link`
|
||||
|
||||
Link a user ID to the given subject claim
|
||||
|
||||
## `!admin oidc unlink`
|
||||
|
||||
Unlink the given subject claim from its associated user ID
|
||||
@@ -104,9 +104,13 @@ ## `!admin query resolver`
|
||||
|
||||
resolver service
|
||||
|
||||
### `!admin query resolver cache`
|
||||
### `!admin query resolver destinations-cache`
|
||||
|
||||
Query the destinations or overrides cache, depending on the value of the `overrides` flag (default false)
|
||||
Query the destinations cache
|
||||
|
||||
### `!admin query resolver overrides-cache`
|
||||
|
||||
Query the overrides cache
|
||||
|
||||
### `!admin query resolver flush-cache`
|
||||
|
||||
|
||||
@@ -8,14 +8,14 @@ ## `!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
|
||||
|
||||
## `!admin users issue-password-reset-link`
|
||||
|
||||
Issue a self-service password reset link for a user
|
||||
|
||||
## `!admin users get-email`
|
||||
|
||||
Get a user's associated email address
|
||||
@@ -96,14 +96,6 @@ ## `!admin users list-users`
|
||||
|
||||
List local users in the database
|
||||
|
||||
## `!admin users list-invited-rooms`
|
||||
|
||||
Lists all the rooms (local and remote) that the specified user is invited to
|
||||
|
||||
## `!admin users reject-all-invites`
|
||||
|
||||
Manually make a user reject all current invites
|
||||
|
||||
## `!admin users list-joined-rooms`
|
||||
|
||||
Lists all the rooms (local and remote) that the specified user is joined in
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@ ## Continuwuity issues
|
||||
|
||||
### 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
|
||||
Some slowness is to be expected if you're the first person on your homserver 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
|
||||
@@ -62,11 +60,11 @@ ### DNS server overload
|
||||
|
||||
Matrix federation is extremely heavy and sends wild amounts of DNS requests. This makes normal resolvers like the ones above unsuitable for its activity. Ultimately, the best solution/fix for this is to selfhost a high quality caching DNS resolver such as Unbound, and configure Continuwuity to use it.
|
||||
|
||||
Follow the [**DNS tuning guide**](./guides/dns) for details on setting it up.
|
||||
Follow the [**DNS tuning guide**](./advanced/dns) for details on setting it up.
|
||||
|
||||
### 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
|
||||
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ cargo clippy \
|
||||
--locked \
|
||||
--profile test \
|
||||
--no-default-features \
|
||||
--features=console,systemd,element_hacks,direct_tls,perf_measurements,brotli_compression \
|
||||
--features=console,systemd,element_hacks,direct_tls,perf_measurements,brotli_compression,blurhashing \
|
||||
--color=always \
|
||||
-- \
|
||||
-D warnings
|
||||
|
||||
Generated
+24
-24
@@ -3,11 +3,11 @@
|
||||
"advisory-db": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1783840254,
|
||||
"narHash": "sha256-XjyvZk0f3YiinVHmkGOotmLBAzvK+LwEJYj2QqJ5pn8=",
|
||||
"lastModified": 1775907537,
|
||||
"narHash": "sha256-vbeLNgmsx1Z6TwnlDV0dKyeBCcon3UpkV9yLr/yc6HM=",
|
||||
"owner": "rustsec",
|
||||
"repo": "advisory-db",
|
||||
"rev": "6e3286f4efa8c142fb33e5ea4342c8db6693cf34",
|
||||
"rev": "d99f7b9eb81731bddebf80a355f8be7b2f8b1b28",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -18,11 +18,11 @@
|
||||
},
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1783203018,
|
||||
"narHash": "sha256-G6R9IT/xwFuu+CYBWDUAok6AdC4ERC4ZfPPFtEpxnZE=",
|
||||
"lastModified": 1775839657,
|
||||
"narHash": "sha256-SPm9ck7jh3Un9nwPuMGbRU04UroFmOHjLP56T10MOeM=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "80db5bdc391be8a1794f6d8a2d56e3a84ebcede2",
|
||||
"rev": "7cf72d978629469c4bd4206b95c402514c1f6000",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -39,11 +39,11 @@
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1783844668,
|
||||
"narHash": "sha256-3MOpw4y3reoErRLvFBDz0t9aG6FWXUj7leKvUns5eQA=",
|
||||
"lastModified": 1775891769,
|
||||
"narHash": "sha256-EOfVlTKw2n8w1uhfh46GS4hEGnQ7oWrIWQfIY6utIkI=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "4e49ef62eedaa5c149d62b63b3f53844e1cc45d7",
|
||||
"rev": "6fbc54dde15aee725bdc7aae5e478849685d5f56",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -74,11 +74,11 @@
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1782949081,
|
||||
"narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=",
|
||||
"lastModified": 1775087534,
|
||||
"narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e",
|
||||
"rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -89,11 +89,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1783776592,
|
||||
"narHash": "sha256-UgCQzxeWI75XM8G+hPrPh+MKzEPjG3SpAj7dtqSbksA=",
|
||||
"lastModified": 1775710090,
|
||||
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e7a3ca8092b61ff85b6a45bf863ea2b2d6a661b3",
|
||||
"rev": "4c1018dae018162ec878d42fec712642d214fdfa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -105,11 +105,11 @@
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1782614948,
|
||||
"narHash": "sha256-ePjCwr1sNm9NYUqywL7QfK3JnlS015msC+eBu2zKlp8=",
|
||||
"lastModified": 1774748309,
|
||||
"narHash": "sha256-+U7gF3qxzwD5TZuANzZPeJTZRHS29OFQgkQ2kiTJBIQ=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "db3f255737b94216eb71cce308e2912cf6bc2d7c",
|
||||
"rev": "333c4e0545a6da976206c74db8773a1645b5870a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -132,11 +132,11 @@
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1783779020,
|
||||
"narHash": "sha256-vpm418WZa9l1KUl6HRs+Ga+SIfE+D2/sV4olwTlilYc=",
|
||||
"lastModified": 1775843361,
|
||||
"narHash": "sha256-j53ZgyDvmYf3Sjh1IPvvTjqa614qUfVQSzj59+MpzkY=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "5be5e89cf0145d73a85c805726821b4adfc3af48",
|
||||
"rev": "9eb97ea96d8400e8957ddd56702e962614296583",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -153,11 +153,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1780220602,
|
||||
"narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=",
|
||||
"lastModified": 1775636079,
|
||||
"narHash": "sha256-pc20NRoMdiar8oPQceQT47UUZMBTiMdUuWrYu2obUP0=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "db947814a175b7ca6ded66e21383d938df01c227",
|
||||
"rev": "790751ff7fd3801feeaf96d7dc416a8d581265ba",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{ inputs, ... }:
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
pkgs,
|
||||
self',
|
||||
...
|
||||
}:
|
||||
{
|
||||
_module.args.craneLib = (inputs.crane.mkLib pkgs).overrideToolchain (
|
||||
pkgs: self'.packages.stable-toolchain
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
imports = [
|
||||
./rust.nix
|
||||
./crane.nix
|
||||
./packages
|
||||
./devshell.nix
|
||||
./fmt.nix
|
||||
|
||||
+28
-29
@@ -1,6 +1,7 @@
|
||||
{ inputs, ... }: {
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
craneLib,
|
||||
self',
|
||||
lib,
|
||||
pkgs,
|
||||
@@ -8,36 +9,34 @@
|
||||
}:
|
||||
{
|
||||
# basic nix shell containing all things necessary to build continuwuity in all flavors manually (on x86_64-linux)
|
||||
devShells.default =
|
||||
((inputs.crane.mkLib pkgs).overrideToolchain (pkgs: self'.packages.dev-toolchain)).devShell
|
||||
{
|
||||
packages = [
|
||||
self'.packages.rocksdb
|
||||
pkgs.nodejs
|
||||
pkgs.pkg-config
|
||||
devShells.default = craneLib.devShell {
|
||||
packages = [
|
||||
self'.packages.rocksdb
|
||||
pkgs.nodejs
|
||||
pkgs.pkg-config
|
||||
]
|
||||
++ lib.optionals pkgs.stdenv.isLinux [
|
||||
pkgs.liburing
|
||||
pkgs.rust-jemalloc-sys-unprefixed
|
||||
];
|
||||
|
||||
env = {
|
||||
LIBCLANG_PATH = lib.makeLibraryPath [ pkgs.llvmPackages.libclang.lib ];
|
||||
LD_LIBRARY_PATH = lib.makeLibraryPath (
|
||||
[
|
||||
pkgs.stdenv.cc.cc.lib
|
||||
]
|
||||
++ lib.optionals pkgs.stdenv.isLinux [
|
||||
pkgs.liburing
|
||||
pkgs.rust-jemalloc-sys-unprefixed
|
||||
];
|
||||
|
||||
env = {
|
||||
LIBCLANG_PATH = lib.makeLibraryPath [ pkgs.llvmPackages.libclang.lib ];
|
||||
LD_LIBRARY_PATH = lib.makeLibraryPath (
|
||||
[
|
||||
pkgs.stdenv.cc.cc.lib
|
||||
]
|
||||
++ lib.optionals pkgs.stdenv.isLinux [
|
||||
pkgs.liburing
|
||||
pkgs.jemalloc
|
||||
]
|
||||
);
|
||||
}
|
||||
// lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||
PKG_CONFIG_PATH = lib.makeSearchPath "lib/pkgconfig" [
|
||||
pkgs.liburing.dev
|
||||
];
|
||||
};
|
||||
};
|
||||
pkgs.jemalloc
|
||||
]
|
||||
);
|
||||
}
|
||||
// lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||
PKG_CONFIG_PATH = lib.makeSearchPath "lib/pkgconfig" [
|
||||
pkgs.liburing.dev
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -43,8 +43,6 @@ let
|
||||
env = {
|
||||
CARGO_PROFILE = profile;
|
||||
RUSTFLAGS = rustflags;
|
||||
GIT_COMMIT_HASH = self.rev or self.dirtyRev or "";
|
||||
GIT_COMMIT_HASH_SHORT = self.shortRev or self.dirtyShortRev or "";
|
||||
}
|
||||
// (lib.optionalAttrs (rocksdb != null) {
|
||||
ROCKSDB_INCLUDE_DIR = "${rocksdb}/include";
|
||||
|
||||
@@ -9,10 +9,8 @@
|
||||
self',
|
||||
lib,
|
||||
pkgs,
|
||||
inputs',
|
||||
system,
|
||||
craneLib,
|
||||
mkToolchain,
|
||||
...
|
||||
}:
|
||||
{
|
||||
@@ -21,7 +19,7 @@
|
||||
mkPackages =
|
||||
pkgs:
|
||||
let
|
||||
fnx = inputs'.fenix.packages;
|
||||
fnx = inputs.fenix.packages.${system};
|
||||
|
||||
isStatic = pkgs.stdenv.hostPlatform.isMusl;
|
||||
|
||||
@@ -30,22 +28,20 @@
|
||||
if isStatic then
|
||||
fnx.combine [
|
||||
self'.packages.stable-toolchain
|
||||
(mkToolchain fnx.targets.${pkgs.stdenv.hostPlatform.config}).rust-std
|
||||
(fnx.targets.${pkgs.stdenv.hostPlatform.config}.stable).rust-std
|
||||
]
|
||||
else
|
||||
self'.packages.stable-toolchain
|
||||
);
|
||||
|
||||
# extra features via `cargoExtraArgs`
|
||||
cargoExtraArgs = "-F http3";
|
||||
|
||||
default = pkgs.callPackage ./continuwuity.nix {
|
||||
inherit self craneLib;
|
||||
|
||||
liburing = (if isStatic then pkgs.pkgsStatic else pkgs).liburing;
|
||||
rocksdb = if isStatic then null else self'.packages.rocksdb;
|
||||
|
||||
inherit cargoExtraArgs;
|
||||
# extra features via `cargoExtraArgs`
|
||||
cargoExtraArgs = "-F http3";
|
||||
# extra RUSTFLAGS via `rustflags`
|
||||
# the stuff below is required for http3
|
||||
rustflags = "--cfg reqwest_unstable";
|
||||
@@ -57,7 +53,6 @@
|
||||
max-perf = default.override {
|
||||
# compiles slower but with more thorough optimizations
|
||||
profile = "release-max-perf";
|
||||
cargoExtraArgs = "${cargoExtraArgs} -F release_max_log_level";
|
||||
};
|
||||
|
||||
max-perf-haswell = max-perf.override {
|
||||
@@ -67,6 +62,7 @@
|
||||
in
|
||||
{
|
||||
inherit default max-perf max-perf-haswell;
|
||||
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
+10
-14
@@ -2,34 +2,30 @@
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
system,
|
||||
lib,
|
||||
inputs',
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
mkToolchain =
|
||||
target:
|
||||
target.fromToolchainName {
|
||||
name = (lib.importTOML "${inputs.self}/rust-toolchain.toml").toolchain.channel;
|
||||
sha256 = "sha256-A1abGIbOtcBSdrUMhDGrER3pRM1hQP4fp9gh3Y4PKc8=";
|
||||
};
|
||||
in
|
||||
{
|
||||
_module.args = { inherit mkToolchain; };
|
||||
|
||||
packages =
|
||||
let
|
||||
fnx = inputs'.fenix.packages;
|
||||
stable-toolchain = (mkToolchain fnx).toolchain;
|
||||
fnx = inputs.fenix.packages.${system};
|
||||
|
||||
stable-toolchain = fnx.fromToolchainFile {
|
||||
file = inputs.self + "/rust-toolchain.toml";
|
||||
|
||||
# See also `rust-toolchain.toml`
|
||||
sha256 = "sha256-sqSWJDUxc+zaz1nBWMAJKTAGBuGWP25GCftIOlCEAtA=";
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit stable-toolchain;
|
||||
|
||||
dev-toolchain = fnx.combine [
|
||||
stable-toolchain
|
||||
# use the nightly rustfmt because we use nightly features
|
||||
fnx.complete.rustfmt
|
||||
stable-toolchain
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
Generated
+273
-682
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -25,6 +25,6 @@
|
||||
"@rspress/core": "^2.0.0",
|
||||
"@rspress/plugin-client-redirects": "^2.0.0",
|
||||
"@rspress/plugin-sitemap": "^2.0.0",
|
||||
"typescript": "^7.0.0"
|
||||
"typescript": "^6.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
+3
-26
@@ -5,7 +5,7 @@
|
||||
"osvVulnerabilityAlerts": true,
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true,
|
||||
"schedule": ["* * * * 0,6"]
|
||||
"schedule": ["at any time"]
|
||||
},
|
||||
"platformAutomerge": true,
|
||||
"nix": {
|
||||
@@ -60,30 +60,12 @@
|
||||
"matchPackageNames": ["rust", "rustc", "cargo"],
|
||||
"groupName": "rust-toolchain"
|
||||
},
|
||||
{
|
||||
"description": "Delay major rust toolchain updates",
|
||||
"matchManagers": ["custom.regex"],
|
||||
"matchPackageNames": ["rust", "rustc", "cargo"],
|
||||
"matchUpdateTypes": ["major"],
|
||||
"minimumReleaseAge": "30 days"
|
||||
},
|
||||
{
|
||||
"description": "Batch minor and patch GitHub Actions updates",
|
||||
"matchManagers": ["github-actions"],
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"groupName": "github-actions-non-major"
|
||||
},
|
||||
{
|
||||
"description": "Batch GitHub Actions digest updates",
|
||||
"matchManagers": ["github-actions"],
|
||||
"matchUpdateTypes": ["digest"],
|
||||
"groupName": "github-actions-digest",
|
||||
"automerge": true,
|
||||
"automergeStrategy": "fast-forward",
|
||||
"schedule": [
|
||||
"* 0-7 * * 2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Batch patch-level Node.js dependency updates",
|
||||
"matchManagers": ["npm"],
|
||||
@@ -101,10 +83,7 @@
|
||||
"matchPackageNames": ["crate-ci/typos"],
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"automerge": true,
|
||||
"automergeStrategy": "fast-forward",
|
||||
"schedule": [
|
||||
"* 0-7 * * 3"
|
||||
]
|
||||
"automergeStrategy": "fast-forward"
|
||||
},
|
||||
{
|
||||
"description": "Auto-merge renovatebot docker image updates",
|
||||
@@ -112,9 +91,7 @@
|
||||
"matchPackageNames": ["ghcr.io/renovatebot/renovate"],
|
||||
"automerge": true,
|
||||
"automergeStrategy": "fast-forward",
|
||||
"schedule": [
|
||||
"* 0-7 * * 1"
|
||||
]
|
||||
"extends": ["schedule:earlyMondays"]
|
||||
}
|
||||
],
|
||||
"customManagers": [
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
[toolchain]
|
||||
profile = "minimal"
|
||||
channel = "1.97.1"
|
||||
channel = "1.92.0"
|
||||
components = [
|
||||
# For rust-analyzer
|
||||
"rust-src",
|
||||
|
||||
@@ -81,18 +81,15 @@ conduwuit-macros.workspace = true
|
||||
conduwuit-service.workspace = true
|
||||
const-str.workspace = true
|
||||
ctor.workspace = true
|
||||
dtor.workspace = true
|
||||
futures.workspace = true
|
||||
lettre.workspace = true
|
||||
log.workspace = true
|
||||
assign.workspace = true
|
||||
ruma.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde-saphyr.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
tracing.workspace = true
|
||||
resolvematrix.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
+11
-26
@@ -1,5 +1,5 @@
|
||||
use clap::Parser;
|
||||
use conduwuit::{Err, Result};
|
||||
use conduwuit::Result;
|
||||
|
||||
use crate::{
|
||||
appservice::{self, AppserviceCommand},
|
||||
@@ -8,7 +8,6 @@
|
||||
debug::{self, DebugCommand},
|
||||
federation::{self, FederationCommand},
|
||||
media::{self, MediaCommand},
|
||||
oidc::{self, OidcCommand},
|
||||
query::{self, QueryCommand},
|
||||
room::{self, RoomCommand},
|
||||
server::{self, ServerCommand},
|
||||
@@ -17,50 +16,46 @@
|
||||
};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = conduwuit_core::BRANDING, version = conduwuit_core::version())]
|
||||
#[command(name = conduwuit_core::name(), version = conduwuit_core::version())]
|
||||
pub enum AdminCommand {
|
||||
/// Commands for managing appservices
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing appservices
|
||||
Appservices(AppserviceCommand),
|
||||
|
||||
/// Commands for managing local users
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing local users
|
||||
Users(UserCommand),
|
||||
|
||||
/// Commands for managing registration tokens
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing registration tokens
|
||||
Token(TokenCommand),
|
||||
|
||||
/// Commands for managing OIDC
|
||||
#[command(subcommand)]
|
||||
Oidc(OidcCommand),
|
||||
|
||||
/// Commands for managing rooms
|
||||
#[command(subcommand)]
|
||||
Rooms(RoomCommand),
|
||||
|
||||
/// Commands for managing federation
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing federation
|
||||
Federation(FederationCommand),
|
||||
|
||||
/// Commands for managing the server
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing the server
|
||||
Server(ServerCommand),
|
||||
|
||||
/// Commands for managing media
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing media
|
||||
Media(MediaCommand),
|
||||
|
||||
/// Commands for checking integrity
|
||||
#[command(subcommand)]
|
||||
/// Commands for checking integrity
|
||||
Check(CheckCommand),
|
||||
|
||||
/// Commands for debugging things
|
||||
#[command(subcommand)]
|
||||
/// Commands for debugging things
|
||||
Debug(DebugCommand),
|
||||
|
||||
/// Low-level queries for database getters and iterators
|
||||
#[command(subcommand)]
|
||||
/// Low-level queries for database getters and iterators
|
||||
Query(QueryCommand),
|
||||
}
|
||||
|
||||
@@ -85,16 +80,6 @@ pub(super) async fn process(command: AdminCommand, context: &Context<'_>) -> Res
|
||||
context.bail_restricted()?;
|
||||
token::process(command, context).await
|
||||
},
|
||||
| Oidc(command) => {
|
||||
// OIDC commands are all restricted
|
||||
context.bail_restricted()?;
|
||||
|
||||
if !context.services.oidc.enabled() {
|
||||
return Err!("OIDC is not configured");
|
||||
}
|
||||
|
||||
oidc::process(command, context).await
|
||||
},
|
||||
| Rooms(command) => room::process(command, context).await,
|
||||
| Federation(command) => federation::process(command, context).await,
|
||||
| Server(command) => server::process(command, context).await,
|
||||
|
||||
@@ -1,101 +1,80 @@
|
||||
use conduwuit::{Err, Result, checked};
|
||||
use futures::{FutureExt, StreamExt, TryFutureExt};
|
||||
|
||||
impl crate::Context<'_> {
|
||||
pub(super) async fn register(&self) -> Result {
|
||||
let body = &self.body;
|
||||
let body_len = self.body.len();
|
||||
if body_len < 2
|
||||
|| !body[0].trim().starts_with("```")
|
||||
|| body.last().unwrap_or(&"").trim() != "```"
|
||||
{
|
||||
return Err!("Expected code block in command body. Add --help for details.");
|
||||
}
|
||||
use crate::admin_command;
|
||||
|
||||
let range = 1..checked!(body_len - 1)?;
|
||||
let appservice_config_body = body[range].join("\n");
|
||||
let parsed_config = serde_saphyr::from_str(&appservice_config_body);
|
||||
match parsed_config {
|
||||
| Err(e) => return Err!("Could not parse appservice config as YAML: {e}"),
|
||||
| Ok(registration) => match self
|
||||
.services
|
||||
.appservice
|
||||
.register_appservice(®istration, &appservice_config_body)
|
||||
.await
|
||||
.map(|()| registration.id)
|
||||
{
|
||||
| Err(e) => return Err!("Failed to register appservice: {e}"),
|
||||
| Ok(id) => write!(self, "Appservice registered with ID: {id}"),
|
||||
},
|
||||
}
|
||||
.await
|
||||
#[admin_command]
|
||||
pub(super) async fn register(&self) -> Result {
|
||||
let body = &self.body;
|
||||
let body_len = self.body.len();
|
||||
if body_len < 2
|
||||
|| !body[0].trim().starts_with("```")
|
||||
|| body.last().unwrap_or(&"").trim() != "```"
|
||||
{
|
||||
return Err!("Expected code block in command body. Add --help for details.");
|
||||
}
|
||||
|
||||
pub(super) async fn unregister(&self, appservice_identifier: String) -> Result {
|
||||
match self
|
||||
let range = 1..checked!(body_len - 1)?;
|
||||
let appservice_config_body = body[range].join("\n");
|
||||
let parsed_config = serde_saphyr::from_str(&appservice_config_body);
|
||||
match parsed_config {
|
||||
| Err(e) => return Err!("Could not parse appservice config as YAML: {e}"),
|
||||
| Ok(registration) => match self
|
||||
.services
|
||||
.appservice
|
||||
.unregister_appservice(&appservice_identifier)
|
||||
.register_appservice(®istration, &appservice_config_body)
|
||||
.await
|
||||
.map(|()| registration.id)
|
||||
{
|
||||
| Err(e) => return Err!("Failed to unregister appservice: {e}"),
|
||||
| Ok(()) => write!(self, "Appservice unregistered."),
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn show_appservice_config(&self, appservice_identifier: String) -> Result {
|
||||
match self
|
||||
.services
|
||||
.appservice
|
||||
.get_registration(&appservice_identifier)
|
||||
.await
|
||||
{
|
||||
| None => return Err!("Appservice does not exist."),
|
||||
| Some(config) => {
|
||||
let config_str = serde_saphyr::to_string(&config)?;
|
||||
write!(self, "Config for {appservice_identifier}:\n\n```yaml\n{config_str}\n```")
|
||||
},
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn list_registered(&self) -> Result {
|
||||
self.services
|
||||
.appservice
|
||||
.iter_ids()
|
||||
.collect()
|
||||
.map(Ok)
|
||||
.and_then(|appservices: Vec<_>| {
|
||||
let len = appservices.len();
|
||||
let list = appservices.join(", ");
|
||||
write!(self, "Appservices ({len}): {list}")
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn ensure_puppets_active(&self) -> Result {
|
||||
self.services
|
||||
.users
|
||||
.stream_local_users()
|
||||
.filter_map(async |user_id| {
|
||||
if self.services.appservice.is_user_id(&user_id).await {
|
||||
Some(user_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.for_each(async |user_id| {
|
||||
self.services
|
||||
.users
|
||||
.convert_to_shadow_account(&user_id)
|
||||
.await
|
||||
.expect("should be able to convert to shadow");
|
||||
})
|
||||
.await;
|
||||
|
||||
write!(self, "All appservice puppets have been marked as active.").await?;
|
||||
|
||||
Ok(())
|
||||
| Err(e) => return Err!("Failed to register appservice: {e}"),
|
||||
| Ok(id) => write!(self, "Appservice registered with ID: {id}"),
|
||||
},
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn unregister(&self, appservice_identifier: String) -> Result {
|
||||
match self
|
||||
.services
|
||||
.appservice
|
||||
.unregister_appservice(&appservice_identifier)
|
||||
.await
|
||||
{
|
||||
| Err(e) => return Err!("Failed to unregister appservice: {e}"),
|
||||
| Ok(()) => write!(self, "Appservice unregistered."),
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn show_appservice_config(&self, appservice_identifier: String) -> Result {
|
||||
match self
|
||||
.services
|
||||
.appservice
|
||||
.get_registration(&appservice_identifier)
|
||||
.await
|
||||
{
|
||||
| None => return Err!("Appservice does not exist."),
|
||||
| Some(config) => {
|
||||
let config_str = serde_saphyr::to_string(&config)?;
|
||||
write!(self, "Config for {appservice_identifier}:\n\n```yaml\n{config_str}\n```")
|
||||
},
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn list_registered(&self) -> Result {
|
||||
self.services
|
||||
.appservice
|
||||
.iter_ids()
|
||||
.collect()
|
||||
.map(Ok)
|
||||
.and_then(|appservices: Vec<_>| {
|
||||
let len = appservices.len();
|
||||
let list = appservices.join(", ");
|
||||
write!(self, "Appservices ({len}): {list}")
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -37,10 +37,4 @@ pub enum AppserviceCommand {
|
||||
/// List all the currently registered appservices
|
||||
#[clap(alias("list"))]
|
||||
ListRegistered,
|
||||
|
||||
/// Ensure no appservice puppets are marked as deactivated.
|
||||
/// This is a debug command to fix issues caused by a faulty database
|
||||
/// migration in Continuwuity 26.6.0.
|
||||
#[clap(hide = true)]
|
||||
EnsurePuppetsActive,
|
||||
}
|
||||
|
||||
+15
-20
@@ -1,28 +1,23 @@
|
||||
use conduwuit::Result;
|
||||
use conduwuit_macros::implement;
|
||||
use futures::StreamExt;
|
||||
|
||||
use crate::Context;
|
||||
|
||||
impl Context<'_> {
|
||||
pub(super) async fn check_all_users(&self) -> Result {
|
||||
let timer = tokio::time::Instant::now();
|
||||
let users = self
|
||||
.services
|
||||
.users
|
||||
.stream_local_users()
|
||||
.collect::<Vec<_>>()
|
||||
.await;
|
||||
let query_time = timer.elapsed();
|
||||
#[implement(Context, params = "<'_>")]
|
||||
pub(super) async fn check_all_users(&self) -> Result {
|
||||
let timer = tokio::time::Instant::now();
|
||||
let users = self.services.users.iter().collect::<Vec<_>>().await;
|
||||
let query_time = timer.elapsed();
|
||||
|
||||
let total = users.len();
|
||||
let err_count = users.iter().filter(|_user| false).count();
|
||||
let ok_count = users.iter().filter(|_user| true).count();
|
||||
let total = users.len();
|
||||
let err_count = users.iter().filter(|_user| false).count();
|
||||
let ok_count = users.iter().filter(|_user| true).count();
|
||||
|
||||
self.write_str(&format!(
|
||||
"Database query completed in {query_time:?}:\n\n```\nTotal entries: \
|
||||
{total:?}\nFailure/Invalid user count: {err_count:?}\nSuccess/Valid user count: \
|
||||
{ok_count:?}\n```"
|
||||
))
|
||||
.await
|
||||
}
|
||||
self.write_str(&format!(
|
||||
"Database query completed in {query_time:?}:\n\n```\nTotal entries: \
|
||||
{total:?}\nFailure/Invalid user count: {err_count:?}\nSuccess/Valid user count: \
|
||||
{ok_count:?}\n```"
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
+802
-1135
File diff suppressed because it is too large
Load Diff
+1
-23
@@ -17,21 +17,12 @@ pub enum DebugCommand {
|
||||
message: Vec<String>,
|
||||
},
|
||||
|
||||
/// Loads the auth_chain of a PDU, reporting how long it took.
|
||||
/// Get the auth_chain of a PDU
|
||||
GetAuthChain {
|
||||
/// An event ID (the $ character followed by the base64 reference hash)
|
||||
event_id: OwnedEventId,
|
||||
},
|
||||
|
||||
/// Walks & displays the auth_chain of a PDU in a mermaid graph format.
|
||||
///
|
||||
/// This is useless to basically anyone but developers, and is also probably
|
||||
/// slow and memory hungry.
|
||||
ShowAuthChain {
|
||||
/// The root event ID to start walking back from.
|
||||
event_id: OwnedEventId,
|
||||
},
|
||||
|
||||
/// Parse and print a PDU from a JSON
|
||||
///
|
||||
/// The PDU event is only checked for validity and is not added to the
|
||||
@@ -95,14 +86,6 @@ pub enum DebugCommand {
|
||||
room_id: OwnedRoomOrAliasId,
|
||||
},
|
||||
|
||||
/// Gets all the room state events at the specified event.
|
||||
///
|
||||
/// State at event might not be available for some PDUs, such as rejected
|
||||
/// ones.
|
||||
GetStateAt {
|
||||
event_id: OwnedEventId,
|
||||
},
|
||||
|
||||
/// Get and display signing keys from local cache or remote server.
|
||||
GetSigningKeys {
|
||||
server_name: Option<OwnedServerName>,
|
||||
@@ -245,11 +228,6 @@ pub enum DebugCommand {
|
||||
/// Send a test email to the invoking admin's email address
|
||||
SendTestEmail,
|
||||
|
||||
/// Lists room IDs by forward extremity count in descending order
|
||||
RoomsByExtremityCount {
|
||||
page: Option<usize>,
|
||||
},
|
||||
|
||||
/// Developer test stubs
|
||||
#[command(subcommand)]
|
||||
#[allow(non_snake_case)]
|
||||
|
||||
+28
-23
@@ -1,6 +1,6 @@
|
||||
use conduwuit::{Err, Result};
|
||||
|
||||
use crate::admin_command_dispatch;
|
||||
use crate::{admin_command, admin_command_dispatch};
|
||||
|
||||
#[admin_command_dispatch]
|
||||
#[derive(Debug, clap::Subcommand)]
|
||||
@@ -11,32 +11,37 @@ pub enum TesterCommand {
|
||||
Timer,
|
||||
}
|
||||
|
||||
impl crate::Context<'_> {
|
||||
#[rustfmt::skip]
|
||||
async fn panic(&self) -> Result {
|
||||
panic!("panicked")
|
||||
}
|
||||
#[rustfmt::skip]
|
||||
#[admin_command]
|
||||
async fn panic(&self) -> Result {
|
||||
|
||||
#[rustfmt::skip]
|
||||
async fn failure(&self) -> Result {
|
||||
Err!("failed")
|
||||
}
|
||||
panic!("panicked")
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[rustfmt::skip]
|
||||
async fn tester(&self) -> Result {
|
||||
self.write_str("Ok").await
|
||||
}
|
||||
#[rustfmt::skip]
|
||||
#[admin_command]
|
||||
async fn failure(&self) -> Result {
|
||||
|
||||
#[inline(never)]
|
||||
#[rustfmt::skip]
|
||||
async fn timer(&self) -> Result {
|
||||
let started = std::time::Instant::now();
|
||||
timed(self.body);
|
||||
Err!("failed")
|
||||
}
|
||||
|
||||
let elapsed = started.elapsed();
|
||||
self.write_str(&format!("completed in {elapsed:#?}")).await
|
||||
}
|
||||
#[inline(never)]
|
||||
#[rustfmt::skip]
|
||||
#[admin_command]
|
||||
async fn tester(&self) -> Result {
|
||||
|
||||
self.write_str("Ok").await
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[rustfmt::skip]
|
||||
#[admin_command]
|
||||
async fn timer(&self) -> Result {
|
||||
let started = std::time::Instant::now();
|
||||
timed(self.body);
|
||||
|
||||
let elapsed = started.elapsed();
|
||||
self.write_str(&format!("completed in {elapsed:#?}")).await
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
|
||||
+119
-119
@@ -4,131 +4,131 @@
|
||||
use futures::StreamExt;
|
||||
use ruma::{OwnedRoomId, OwnedServerName, OwnedUserId};
|
||||
|
||||
use crate::get_room_info;
|
||||
use crate::{admin_command, get_room_info};
|
||||
|
||||
impl crate::Context<'_> {
|
||||
pub(super) async fn disable_room(&self, room_id: OwnedRoomId) -> Result {
|
||||
self.bail_restricted()?;
|
||||
self.services.rooms.metadata.disable_room(&room_id, true);
|
||||
self.write_str("Room disabled.").await
|
||||
}
|
||||
#[admin_command]
|
||||
pub(super) async fn disable_room(&self, room_id: OwnedRoomId) -> Result {
|
||||
self.bail_restricted()?;
|
||||
self.services.rooms.metadata.disable_room(&room_id, true);
|
||||
self.write_str("Room disabled.").await
|
||||
}
|
||||
|
||||
pub(super) async fn enable_room(&self, room_id: OwnedRoomId) -> Result {
|
||||
self.bail_restricted()?;
|
||||
self.services.rooms.metadata.disable_room(&room_id, false);
|
||||
self.write_str("Room enabled.").await
|
||||
}
|
||||
#[admin_command]
|
||||
pub(super) async fn enable_room(&self, room_id: OwnedRoomId) -> Result {
|
||||
self.bail_restricted()?;
|
||||
self.services.rooms.metadata.disable_room(&room_id, false);
|
||||
self.write_str("Room enabled.").await
|
||||
}
|
||||
|
||||
pub(super) async fn incoming_federation(&self) -> Result {
|
||||
let msg = {
|
||||
let map = self
|
||||
.services
|
||||
.rooms
|
||||
.event_handler
|
||||
.federation_handletime
|
||||
.read();
|
||||
|
||||
let mut msg = format!(
|
||||
"Handling {} incoming PDUs across {} active transactions:\n",
|
||||
map.len(),
|
||||
self.services.transactions.txn_active_handle_count()
|
||||
);
|
||||
for (r, (e, i)) in map.iter() {
|
||||
let elapsed = i.elapsed();
|
||||
writeln!(
|
||||
msg,
|
||||
"{} {}: {}m{}s",
|
||||
r,
|
||||
e,
|
||||
elapsed.as_secs() / 60,
|
||||
elapsed.as_secs() % 60
|
||||
)?;
|
||||
}
|
||||
msg
|
||||
};
|
||||
|
||||
self.write_str(&msg).await
|
||||
}
|
||||
|
||||
pub(super) async fn fetch_support_well_known(&self, server_name: OwnedServerName) -> Result {
|
||||
let response = self
|
||||
.services
|
||||
.client
|
||||
.external_resource
|
||||
.get(format!("https://{server_name}/.well-known/matrix/support"))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let text = response
|
||||
.limit_read_text(
|
||||
self.services
|
||||
.config
|
||||
.max_request_size
|
||||
.try_into()
|
||||
.expect("u64 fits into usize"),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if text.is_empty() {
|
||||
return Err!("Response text/body is empty.");
|
||||
}
|
||||
|
||||
if text.len() > 1500 {
|
||||
return Err!(
|
||||
"Response text/body is over 1500 characters, assuming no support well-known.",
|
||||
);
|
||||
}
|
||||
|
||||
let json: serde_json::Value = match serde_json::from_str(&text) {
|
||||
| Ok(json) => json,
|
||||
| Err(_) => {
|
||||
return Err!("Response text/body is not valid JSON.",);
|
||||
},
|
||||
};
|
||||
|
||||
let pretty_json: String = match serde_json::to_string_pretty(&json) {
|
||||
| Ok(json) => json,
|
||||
| Err(_) => {
|
||||
return Err!("Response text/body is not valid JSON.",);
|
||||
},
|
||||
};
|
||||
|
||||
self.write_str(&format!("Got JSON response:\n\n```json\n{pretty_json}\n```"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn remote_user_in_rooms(&self, user_id: OwnedUserId) -> Result {
|
||||
if user_id.server_name() == self.services.server.name {
|
||||
return Err!(
|
||||
"User belongs to our server, please use `list-joined-rooms` user admin command \
|
||||
instead.",
|
||||
);
|
||||
}
|
||||
|
||||
let mut rooms: Vec<(OwnedRoomId, u64, String)> = self
|
||||
#[admin_command]
|
||||
pub(super) async fn incoming_federation(&self) -> Result {
|
||||
let msg = {
|
||||
let map = self
|
||||
.services
|
||||
.rooms
|
||||
.state_cache
|
||||
.rooms_joined(&user_id)
|
||||
.then(async |room_id| get_room_info(self.services, &room_id).await)
|
||||
.collect()
|
||||
.await;
|
||||
.event_handler
|
||||
.federation_handletime
|
||||
.read();
|
||||
|
||||
if rooms.is_empty() {
|
||||
return Err!("User is not in any rooms.");
|
||||
let mut msg = format!(
|
||||
"Handling {} incoming PDUs across {} active transactions:\n",
|
||||
map.len(),
|
||||
self.services.transactions.txn_active_handle_count()
|
||||
);
|
||||
for (r, (e, i)) in map.iter() {
|
||||
let elapsed = i.elapsed();
|
||||
writeln!(msg, "{} {}: {}m{}s", r, e, elapsed.as_secs() / 60, elapsed.as_secs() % 60)?;
|
||||
}
|
||||
msg
|
||||
};
|
||||
|
||||
rooms.sort_by_key(|r| r.1);
|
||||
rooms.reverse();
|
||||
|
||||
let num = rooms.len();
|
||||
let body = rooms
|
||||
.iter()
|
||||
.map(|(id, members, name)| format!("{id} | Members: {members} | Name: {name}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
self.write_str(&format!("Rooms {user_id} shares with us ({num}):\n```\n{body}\n```"))
|
||||
.await
|
||||
}
|
||||
self.write_str(&msg).await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn fetch_support_well_known(&self, server_name: OwnedServerName) -> Result {
|
||||
let response = self
|
||||
.services
|
||||
.client
|
||||
.default
|
||||
.get(format!("https://{server_name}/.well-known/matrix/support"))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let text = response
|
||||
.limit_read_text(
|
||||
self.services
|
||||
.config
|
||||
.max_request_size
|
||||
.try_into()
|
||||
.expect("u64 fits into usize"),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if text.is_empty() {
|
||||
return Err!("Response text/body is empty.");
|
||||
}
|
||||
|
||||
if text.len() > 1500 {
|
||||
return Err!(
|
||||
"Response text/body is over 1500 characters, assuming no support well-known.",
|
||||
);
|
||||
}
|
||||
|
||||
let json: serde_json::Value = match serde_json::from_str(&text) {
|
||||
| Ok(json) => json,
|
||||
| Err(_) => {
|
||||
return Err!("Response text/body is not valid JSON.",);
|
||||
},
|
||||
};
|
||||
|
||||
let pretty_json: String = match serde_json::to_string_pretty(&json) {
|
||||
| Ok(json) => json,
|
||||
| Err(_) => {
|
||||
return Err!("Response text/body is not valid JSON.",);
|
||||
},
|
||||
};
|
||||
|
||||
self.write_str(&format!("Got JSON response:\n\n```json\n{pretty_json}\n```"))
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn remote_user_in_rooms(&self, user_id: OwnedUserId) -> Result {
|
||||
if user_id.server_name() == self.services.server.name {
|
||||
return Err!(
|
||||
"User belongs to our server, please use `list-joined-rooms` user admin command \
|
||||
instead.",
|
||||
);
|
||||
}
|
||||
|
||||
if !self.services.users.exists(&user_id).await {
|
||||
return Err!("Remote user does not exist in our database.",);
|
||||
}
|
||||
|
||||
let mut rooms: Vec<(OwnedRoomId, u64, String)> = self
|
||||
.services
|
||||
.rooms
|
||||
.state_cache
|
||||
.rooms_joined(&user_id)
|
||||
.then(|room_id| get_room_info(self.services, room_id))
|
||||
.collect()
|
||||
.await;
|
||||
|
||||
if rooms.is_empty() {
|
||||
return Err!("User is not in any rooms.");
|
||||
}
|
||||
|
||||
rooms.sort_by_key(|r| r.1);
|
||||
rooms.reverse();
|
||||
|
||||
let num = rooms.len();
|
||||
let body = rooms
|
||||
.iter()
|
||||
.map(|(id, members, name)| format!("{id} | Members: {members} | Name: {name}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
self.write_str(&format!("Rooms {user_id} shares with us ({num}):\n```\n{body}\n```",))
|
||||
.await
|
||||
}
|
||||
|
||||
+353
-356
@@ -6,406 +6,403 @@
|
||||
warn,
|
||||
};
|
||||
use conduwuit_service::media::Dim;
|
||||
use ruma::{OwnedEventId, OwnedMxcUri, OwnedServerName};
|
||||
use service::media::mxc::Mxc;
|
||||
use ruma::{Mxc, OwnedEventId, OwnedMxcUri, OwnedServerName};
|
||||
|
||||
use crate::utils::parse_local_user_id;
|
||||
use crate::{admin_command, utils::parse_local_user_id};
|
||||
|
||||
impl crate::Context<'_> {
|
||||
pub(super) async fn delete(
|
||||
&self,
|
||||
mxc: Option<OwnedMxcUri>,
|
||||
event_id: Option<OwnedEventId>,
|
||||
) -> Result {
|
||||
self.bail_restricted()?;
|
||||
#[admin_command]
|
||||
pub(super) async fn delete(
|
||||
&self,
|
||||
mxc: Option<OwnedMxcUri>,
|
||||
event_id: Option<OwnedEventId>,
|
||||
) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if event_id.is_some() && mxc.is_some() {
|
||||
return Err!("Please specify either an MXC or an event ID, not both.",);
|
||||
}
|
||||
if event_id.is_some() && mxc.is_some() {
|
||||
return Err!("Please specify either an MXC or an event ID, not both.",);
|
||||
}
|
||||
|
||||
if let Some(mxc) = mxc {
|
||||
trace!("Got MXC URL: {mxc}");
|
||||
self.services
|
||||
.media
|
||||
.delete(&mxc.as_str().try_into()?)
|
||||
.await?;
|
||||
if let Some(mxc) = mxc {
|
||||
trace!("Got MXC URL: {mxc}");
|
||||
self.services
|
||||
.media
|
||||
.delete(&mxc.as_str().try_into()?)
|
||||
.await?;
|
||||
|
||||
return self
|
||||
.write_str("Deleted the MXC from our database and on our filesystem.")
|
||||
.await;
|
||||
}
|
||||
return self
|
||||
.write_str("Deleted the MXC from our database and on our filesystem.")
|
||||
.await;
|
||||
}
|
||||
|
||||
if let Some(event_id) = event_id {
|
||||
trace!("Got event ID to delete media from: {event_id}");
|
||||
if let Some(event_id) = event_id {
|
||||
trace!("Got event ID to delete media from: {event_id}");
|
||||
|
||||
let mut mxc_urls = Vec::with_capacity(4);
|
||||
let mut mxc_urls = Vec::with_capacity(4);
|
||||
|
||||
// parsing the PDU for any MXC URLs begins here
|
||||
match self.services.rooms.timeline.get_pdu_json(&event_id).await {
|
||||
| Ok(event_json) => {
|
||||
if let Some(content_key) = event_json.get("content") {
|
||||
debug!("Event ID has \"content\".");
|
||||
let content_obj = content_key.as_object();
|
||||
// parsing the PDU for any MXC URLs begins here
|
||||
match self.services.rooms.timeline.get_pdu_json(&event_id).await {
|
||||
| Ok(event_json) => {
|
||||
if let Some(content_key) = event_json.get("content") {
|
||||
debug!("Event ID has \"content\".");
|
||||
let content_obj = content_key.as_object();
|
||||
|
||||
if let Some(content) = content_obj {
|
||||
// 1. attempts to parse the "url" key
|
||||
debug!("Attempting to go into \"url\" key for main media file");
|
||||
if let Some(url) = content.get("url") {
|
||||
debug!("Got a URL in the event ID {event_id}: {url}");
|
||||
if let Some(content) = content_obj {
|
||||
// 1. attempts to parse the "url" key
|
||||
debug!("Attempting to go into \"url\" key for main media file");
|
||||
if let Some(url) = content.get("url") {
|
||||
debug!("Got a URL in the event ID {event_id}: {url}");
|
||||
|
||||
if url.to_string().starts_with("\"mxc://") {
|
||||
debug!("Pushing URL {url} to list of MXCs to delete");
|
||||
let final_url = url.to_string().replace('"', "");
|
||||
mxc_urls.push(final_url);
|
||||
if url.to_string().starts_with("\"mxc://") {
|
||||
debug!("Pushing URL {url} to list of MXCs to delete");
|
||||
let final_url = url.to_string().replace('"', "");
|
||||
mxc_urls.push(final_url);
|
||||
} else {
|
||||
info!(
|
||||
"Found a URL in the event ID {event_id} but did not start \
|
||||
with mxc://, ignoring"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. attempts to parse the "info" key
|
||||
debug!("Attempting to go into \"info\" key for thumbnails");
|
||||
if let Some(info_key) = content.get("info") {
|
||||
debug!("Event ID has \"info\".");
|
||||
let info_obj = info_key.as_object();
|
||||
|
||||
if let Some(info) = info_obj {
|
||||
if let Some(thumbnail_url) = info.get("thumbnail_url") {
|
||||
debug!("Found a thumbnail_url in info key: {thumbnail_url}");
|
||||
|
||||
if thumbnail_url.to_string().starts_with("\"mxc://") {
|
||||
debug!(
|
||||
"Pushing thumbnail URL {thumbnail_url} to list of \
|
||||
MXCs to delete"
|
||||
);
|
||||
let final_thumbnail_url =
|
||||
thumbnail_url.to_string().replace('"', "");
|
||||
mxc_urls.push(final_thumbnail_url);
|
||||
} else {
|
||||
info!(
|
||||
"Found a thumbnail URL in the event ID {event_id} \
|
||||
but did not start with mxc://, ignoring"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
info!(
|
||||
"Found a URL in the event ID {event_id} but did not \
|
||||
start with mxc://, ignoring"
|
||||
"No \"thumbnail_url\" key in \"info\" key, assuming no \
|
||||
thumbnails."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. attempts to parse the "info" key
|
||||
debug!("Attempting to go into \"info\" key for thumbnails");
|
||||
if let Some(info_key) = content.get("info") {
|
||||
debug!("Event ID has \"info\".");
|
||||
let info_obj = info_key.as_object();
|
||||
// 3. attempts to parse the "file" key
|
||||
debug!("Attempting to go into \"file\" key");
|
||||
if let Some(file_key) = content.get("file") {
|
||||
debug!("Event ID has \"file\".");
|
||||
let file_obj = file_key.as_object();
|
||||
|
||||
if let Some(info) = info_obj {
|
||||
if let Some(thumbnail_url) = info.get("thumbnail_url") {
|
||||
debug!(
|
||||
"Found a thumbnail_url in info key: {thumbnail_url}"
|
||||
);
|
||||
if let Some(file) = file_obj {
|
||||
if let Some(url) = file.get("url") {
|
||||
debug!("Found url in file key: {url}");
|
||||
|
||||
if thumbnail_url.to_string().starts_with("\"mxc://") {
|
||||
debug!(
|
||||
"Pushing thumbnail URL {thumbnail_url} to list \
|
||||
of MXCs to delete"
|
||||
);
|
||||
let final_thumbnail_url =
|
||||
thumbnail_url.to_string().replace('"', "");
|
||||
mxc_urls.push(final_thumbnail_url);
|
||||
} else {
|
||||
info!(
|
||||
"Found a thumbnail URL in the event ID \
|
||||
{event_id} but did not start with mxc://, \
|
||||
ignoring"
|
||||
);
|
||||
}
|
||||
if url.to_string().starts_with("\"mxc://") {
|
||||
debug!("Pushing URL {url} to list of MXCs to delete");
|
||||
let final_url = url.to_string().replace('"', "");
|
||||
mxc_urls.push(final_url);
|
||||
} else {
|
||||
info!(
|
||||
"No \"thumbnail_url\" key in \"info\" key, assuming \
|
||||
no thumbnails."
|
||||
warn!(
|
||||
"Found a URL in the event ID {event_id} but did not \
|
||||
start with mxc://, ignoring"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
error!("No \"url\" key in \"file\" key.");
|
||||
}
|
||||
}
|
||||
|
||||
// 3. attempts to parse the "file" key
|
||||
debug!("Attempting to go into \"file\" key");
|
||||
if let Some(file_key) = content.get("file") {
|
||||
debug!("Event ID has \"file\".");
|
||||
let file_obj = file_key.as_object();
|
||||
|
||||
if let Some(file) = file_obj {
|
||||
if let Some(url) = file.get("url") {
|
||||
debug!("Found url in file key: {url}");
|
||||
|
||||
if url.to_string().starts_with("\"mxc://") {
|
||||
debug!("Pushing URL {url} to list of MXCs to delete");
|
||||
let final_url = url.to_string().replace('"', "");
|
||||
mxc_urls.push(final_url);
|
||||
} else {
|
||||
warn!(
|
||||
"Found a URL in the event ID {event_id} but did \
|
||||
not start with mxc://, ignoring"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
error!("No \"url\" key in \"file\" key.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err!(
|
||||
"Event ID does not have a \"content\" key or failed parsing the \
|
||||
event ID JSON.",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return Err!(
|
||||
"Event ID does not have a \"content\" key, this is not a message or \
|
||||
an event type that contains media.",
|
||||
"Event ID does not have a \"content\" key or failed parsing the \
|
||||
event ID JSON.",
|
||||
);
|
||||
}
|
||||
},
|
||||
| _ => {
|
||||
return Err!("Event ID does not exist or is not known to us.",);
|
||||
},
|
||||
}
|
||||
|
||||
if mxc_urls.is_empty() {
|
||||
return Err!("Parsed event ID but found no MXC URLs.",);
|
||||
}
|
||||
|
||||
let mut mxc_deletion_count: usize = 0;
|
||||
|
||||
for mxc_url in mxc_urls {
|
||||
match self
|
||||
.services
|
||||
.media
|
||||
.delete(&mxc_url.as_str().try_into()?)
|
||||
.await
|
||||
{
|
||||
| Ok(()) => {
|
||||
debug_info!(
|
||||
"Successfully deleted {mxc_url} from filesystem and database"
|
||||
);
|
||||
mxc_deletion_count = mxc_deletion_count.saturating_add(1);
|
||||
},
|
||||
| Err(e) => {
|
||||
debug_warn!(
|
||||
"Failed to delete {mxc_url}, ignoring error and skipping: {e}"
|
||||
);
|
||||
continue;
|
||||
},
|
||||
} else {
|
||||
return Err!(
|
||||
"Event ID does not have a \"content\" key, this is not a message or an \
|
||||
event type that contains media.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return self
|
||||
.write_str(&format!(
|
||||
"Deleted {mxc_deletion_count} total MXCs from our database and the \
|
||||
filesystem from event ID {event_id}."
|
||||
))
|
||||
.await;
|
||||
},
|
||||
| _ => {
|
||||
return Err!("Event ID does not exist or is not known to us.",);
|
||||
},
|
||||
}
|
||||
|
||||
Err!(
|
||||
"Please specify either an MXC using --mxc or an event ID using --event-id of the \
|
||||
message containing an image. See --help for details."
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) async fn delete_list(&self) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if self.body.len() < 2
|
||||
|| !self.body[0].trim().starts_with("```")
|
||||
|| self.body.last().unwrap_or(&"").trim() != "```"
|
||||
{
|
||||
return Err!("Expected code block in command body. Add --help for details.",);
|
||||
if mxc_urls.is_empty() {
|
||||
return Err!("Parsed event ID but found no MXC URLs.",);
|
||||
}
|
||||
|
||||
let mut failed_parsed_mxcs: usize = 0;
|
||||
|
||||
let mxc_list = self
|
||||
.body
|
||||
.to_vec()
|
||||
.drain(1..self.body.len().checked_sub(1).unwrap())
|
||||
.filter_map(|mxc_s| {
|
||||
mxc_s
|
||||
.try_into()
|
||||
.inspect_err(|e| {
|
||||
debug_warn!("Failed to parse user-provided MXC URI: {e}");
|
||||
failed_parsed_mxcs = failed_parsed_mxcs.saturating_add(1);
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.collect::<Vec<Mxc<'_>>>();
|
||||
|
||||
let mut mxc_deletion_count: usize = 0;
|
||||
|
||||
for mxc in &mxc_list {
|
||||
trace!(%failed_parsed_mxcs, %mxc_deletion_count, "Deleting MXC {mxc} in bulk");
|
||||
match self.services.media.delete(mxc).await {
|
||||
for mxc_url in mxc_urls {
|
||||
match self
|
||||
.services
|
||||
.media
|
||||
.delete(&mxc_url.as_str().try_into()?)
|
||||
.await
|
||||
{
|
||||
| Ok(()) => {
|
||||
debug_info!("Successfully deleted {mxc} from filesystem and database");
|
||||
debug_info!("Successfully deleted {mxc_url} from filesystem and database");
|
||||
mxc_deletion_count = mxc_deletion_count.saturating_add(1);
|
||||
},
|
||||
| Err(e) => {
|
||||
debug_warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
|
||||
debug_warn!("Failed to delete {mxc_url}, ignoring error and skipping: {e}");
|
||||
continue;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
self.write_str(&format!(
|
||||
"Finished bulk MXC deletion, deleted {mxc_deletion_count} total MXCs from our \
|
||||
database and the filesystem. {failed_parsed_mxcs} MXCs failed to be parsed from \
|
||||
the database.",
|
||||
))
|
||||
.await
|
||||
return self
|
||||
.write_str(&format!(
|
||||
"Deleted {mxc_deletion_count} total MXCs from our database and the filesystem \
|
||||
from event ID {event_id}."
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
pub(super) async fn delete_past_remote_media(
|
||||
&self,
|
||||
duration: String,
|
||||
before: bool,
|
||||
after: bool,
|
||||
yes_i_want_to_delete_local_media: bool,
|
||||
) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if before && after {
|
||||
return Err!("Please only pick one argument, --before or --after.",);
|
||||
}
|
||||
assert!(!(before && after), "--before and --after should not be specified together");
|
||||
|
||||
let direction = if after {
|
||||
TimeDirection::After
|
||||
} else {
|
||||
TimeDirection::Before
|
||||
};
|
||||
|
||||
let time_boundary = parse_timepoint_ago(&duration)?;
|
||||
let deleted_count = self
|
||||
.services
|
||||
.media
|
||||
.delete_all_media_within_timeframe(
|
||||
time_boundary,
|
||||
direction,
|
||||
yes_i_want_to_delete_local_media,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.write_str(&format!("Deleted {deleted_count} total files."))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn delete_all_from_user(&self, username: String) -> Result {
|
||||
let user_id = parse_local_user_id(self.services, &username)?;
|
||||
|
||||
let deleted_count = self.services.media.delete_from_user(&user_id).await?;
|
||||
|
||||
self.write_str(&format!("Deleted {deleted_count} total files."))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn delete_all_from_server(
|
||||
&self,
|
||||
server_name: OwnedServerName,
|
||||
yes_i_want_to_delete_local_media: bool,
|
||||
) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if server_name == self.services.globals.server_name() && !yes_i_want_to_delete_local_media
|
||||
{
|
||||
return Err!("This command only works for remote media by default.",);
|
||||
}
|
||||
|
||||
let Ok(all_mxcs) = self
|
||||
.services
|
||||
.media
|
||||
.get_all_mxcs()
|
||||
.await
|
||||
.inspect_err(|e| error!("Failed to get MXC URIs from our database: {e}"))
|
||||
else {
|
||||
return Err!("Failed to get MXC URIs from our database",);
|
||||
};
|
||||
|
||||
let mut deleted_count: usize = 0;
|
||||
|
||||
for mxc in all_mxcs {
|
||||
let Ok(mxc_server_name) = mxc.server_name().inspect_err(|e| {
|
||||
debug_warn!(
|
||||
"Failed to parse MXC {mxc} server name from database, ignoring error and \
|
||||
skipping: {e}"
|
||||
);
|
||||
}) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if mxc_server_name != server_name
|
||||
|| (self.services.globals.server_is_ours(mxc_server_name)
|
||||
&& !yes_i_want_to_delete_local_media)
|
||||
{
|
||||
trace!("skipping MXC URI {mxc}");
|
||||
continue;
|
||||
}
|
||||
|
||||
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
|
||||
|
||||
match self.services.media.delete(&mxc).await {
|
||||
| Ok(()) => {
|
||||
deleted_count = deleted_count.saturating_add(1);
|
||||
},
|
||||
| Err(e) => {
|
||||
debug_warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
|
||||
continue;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
self.write_str(&format!("Deleted {deleted_count} total files."))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn get_file_info(&self, mxc: OwnedMxcUri) -> Result {
|
||||
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
|
||||
let metadata = self.services.media.get_metadata(&mxc).await;
|
||||
|
||||
self.write_str(&format!("```\n{metadata:#?}\n```")).await
|
||||
}
|
||||
|
||||
pub(super) async fn get_remote_file(
|
||||
&self,
|
||||
mxc: OwnedMxcUri,
|
||||
server: Option<OwnedServerName>,
|
||||
timeout: u32,
|
||||
) -> Result {
|
||||
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
|
||||
let timeout = Duration::from_millis(timeout.into());
|
||||
let mut result = self
|
||||
.services
|
||||
.media
|
||||
.fetch_remote_content(&mxc, None, server.as_deref(), timeout)
|
||||
.await?;
|
||||
|
||||
// Grab the length of the content before clearing it to not flood the output
|
||||
let len = result.content.as_ref().expect("content").len();
|
||||
result.content.as_mut().expect("content").clear();
|
||||
|
||||
self.write_str(&format!("```\n{result:#?}\nreceived {len} bytes for file content.\n```"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn get_remote_thumbnail(
|
||||
&self,
|
||||
mxc: OwnedMxcUri,
|
||||
server: Option<OwnedServerName>,
|
||||
timeout: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result {
|
||||
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
|
||||
let timeout = Duration::from_millis(timeout.into());
|
||||
let dim = Dim::new(width, height, None);
|
||||
let mut result = self
|
||||
.services
|
||||
.media
|
||||
.fetch_remote_thumbnail(&mxc, None, server.as_deref(), timeout, &dim)
|
||||
.await?;
|
||||
|
||||
// Grab the length of the content before clearing it to not flood the output
|
||||
let len = result.content.as_ref().expect("content").len();
|
||||
result.content.as_mut().expect("content").clear();
|
||||
|
||||
self.write_str(&format!("```\n{result:#?}\nreceived {len} bytes for file content.\n```"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn delete_url_preview(&self, url: Option<String>, all: bool) -> Result {
|
||||
if all {
|
||||
self.services.media.clear_url_previews().await;
|
||||
|
||||
return self.write_str("Deleted all cached URL previews.").await;
|
||||
}
|
||||
|
||||
let url = url.expect("clap enforces url is required unless --all");
|
||||
|
||||
self.services.media.remove_url_preview(&url).await?;
|
||||
|
||||
self.write_str(&format!("Deleted cached URL preview for: {url}"))
|
||||
.await
|
||||
}
|
||||
Err!(
|
||||
"Please specify either an MXC using --mxc or an event ID using --event-id of the \
|
||||
message containing an image. See --help for details."
|
||||
)
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn delete_list(&self) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if self.body.len() < 2
|
||||
|| !self.body[0].trim().starts_with("```")
|
||||
|| self.body.last().unwrap_or(&"").trim() != "```"
|
||||
{
|
||||
return Err!("Expected code block in command body. Add --help for details.",);
|
||||
}
|
||||
|
||||
let mut failed_parsed_mxcs: usize = 0;
|
||||
|
||||
let mxc_list = self
|
||||
.body
|
||||
.to_vec()
|
||||
.drain(1..self.body.len().checked_sub(1).unwrap())
|
||||
.filter_map(|mxc_s| {
|
||||
mxc_s
|
||||
.try_into()
|
||||
.inspect_err(|e| {
|
||||
debug_warn!("Failed to parse user-provided MXC URI: {e}");
|
||||
failed_parsed_mxcs = failed_parsed_mxcs.saturating_add(1);
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.collect::<Vec<Mxc<'_>>>();
|
||||
|
||||
let mut mxc_deletion_count: usize = 0;
|
||||
|
||||
for mxc in &mxc_list {
|
||||
trace!(%failed_parsed_mxcs, %mxc_deletion_count, "Deleting MXC {mxc} in bulk");
|
||||
match self.services.media.delete(mxc).await {
|
||||
| Ok(()) => {
|
||||
debug_info!("Successfully deleted {mxc} from filesystem and database");
|
||||
mxc_deletion_count = mxc_deletion_count.saturating_add(1);
|
||||
},
|
||||
| Err(e) => {
|
||||
debug_warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
|
||||
continue;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
self.write_str(&format!(
|
||||
"Finished bulk MXC deletion, deleted {mxc_deletion_count} total MXCs from our database \
|
||||
and the filesystem. {failed_parsed_mxcs} MXCs failed to be parsed from the database.",
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn delete_past_remote_media(
|
||||
&self,
|
||||
duration: String,
|
||||
before: bool,
|
||||
after: bool,
|
||||
yes_i_want_to_delete_local_media: bool,
|
||||
) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if before && after {
|
||||
return Err!("Please only pick one argument, --before or --after.",);
|
||||
}
|
||||
assert!(!(before && after), "--before and --after should not be specified together");
|
||||
|
||||
let direction = if after {
|
||||
TimeDirection::After
|
||||
} else {
|
||||
TimeDirection::Before
|
||||
};
|
||||
|
||||
let time_boundary = parse_timepoint_ago(&duration)?;
|
||||
let deleted_count = self
|
||||
.services
|
||||
.media
|
||||
.delete_all_media_within_timeframe(
|
||||
time_boundary,
|
||||
direction,
|
||||
yes_i_want_to_delete_local_media,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.write_str(&format!("Deleted {deleted_count} total files.",))
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn delete_all_from_user(&self, username: String) -> Result {
|
||||
let user_id = parse_local_user_id(self.services, &username)?;
|
||||
|
||||
let deleted_count = self.services.media.delete_from_user(&user_id).await?;
|
||||
|
||||
self.write_str(&format!("Deleted {deleted_count} total files.",))
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn delete_all_from_server(
|
||||
&self,
|
||||
server_name: OwnedServerName,
|
||||
yes_i_want_to_delete_local_media: bool,
|
||||
) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
if server_name == self.services.globals.server_name() && !yes_i_want_to_delete_local_media {
|
||||
return Err!("This command only works for remote media by default.",);
|
||||
}
|
||||
|
||||
let Ok(all_mxcs) = self
|
||||
.services
|
||||
.media
|
||||
.get_all_mxcs()
|
||||
.await
|
||||
.inspect_err(|e| error!("Failed to get MXC URIs from our database: {e}"))
|
||||
else {
|
||||
return Err!("Failed to get MXC URIs from our database",);
|
||||
};
|
||||
|
||||
let mut deleted_count: usize = 0;
|
||||
|
||||
for mxc in all_mxcs {
|
||||
let Ok(mxc_server_name) = mxc.server_name().inspect_err(|e| {
|
||||
debug_warn!(
|
||||
"Failed to parse MXC {mxc} server name from database, ignoring error and \
|
||||
skipping: {e}"
|
||||
);
|
||||
}) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if mxc_server_name != server_name
|
||||
|| (self.services.globals.server_is_ours(mxc_server_name)
|
||||
&& !yes_i_want_to_delete_local_media)
|
||||
{
|
||||
trace!("skipping MXC URI {mxc}");
|
||||
continue;
|
||||
}
|
||||
|
||||
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
|
||||
|
||||
match self.services.media.delete(&mxc).await {
|
||||
| Ok(()) => {
|
||||
deleted_count = deleted_count.saturating_add(1);
|
||||
},
|
||||
| Err(e) => {
|
||||
debug_warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
|
||||
continue;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
self.write_str(&format!("Deleted {deleted_count} total files.",))
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn get_file_info(&self, mxc: OwnedMxcUri) -> Result {
|
||||
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
|
||||
let metadata = self.services.media.get_metadata(&mxc).await;
|
||||
|
||||
self.write_str(&format!("```\n{metadata:#?}\n```")).await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn get_remote_file(
|
||||
&self,
|
||||
mxc: OwnedMxcUri,
|
||||
server: Option<OwnedServerName>,
|
||||
timeout: u32,
|
||||
) -> Result {
|
||||
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
|
||||
let timeout = Duration::from_millis(timeout.into());
|
||||
let mut result = self
|
||||
.services
|
||||
.media
|
||||
.fetch_remote_content(&mxc, None, server.as_deref(), timeout)
|
||||
.await?;
|
||||
|
||||
// Grab the length of the content before clearing it to not flood the output
|
||||
let len = result.content.as_ref().expect("content").len();
|
||||
result.content.as_mut().expect("content").clear();
|
||||
|
||||
self.write_str(&format!("```\n{result:#?}\nreceived {len} bytes for file content.\n```"))
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn get_remote_thumbnail(
|
||||
&self,
|
||||
mxc: OwnedMxcUri,
|
||||
server: Option<OwnedServerName>,
|
||||
timeout: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result {
|
||||
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
|
||||
let timeout = Duration::from_millis(timeout.into());
|
||||
let dim = Dim::new(width, height, None);
|
||||
let mut result = self
|
||||
.services
|
||||
.media
|
||||
.fetch_remote_thumbnail(&mxc, None, server.as_deref(), timeout, &dim)
|
||||
.await?;
|
||||
|
||||
// Grab the length of the content before clearing it to not flood the output
|
||||
let len = result.content.as_ref().expect("content").len();
|
||||
result.content.as_mut().expect("content").clear();
|
||||
|
||||
self.write_str(&format!("```\n{result:#?}\nreceived {len} bytes for file content.\n```"))
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn delete_url_preview(&self, url: Option<String>, all: bool) -> Result {
|
||||
if all {
|
||||
self.services.media.clear_url_previews().await;
|
||||
|
||||
return self.write_str("Deleted all cached URL previews.").await;
|
||||
}
|
||||
|
||||
let url = url.expect("clap enforces url is required unless --all");
|
||||
|
||||
self.services.media.remove_url_preview(&url).await?;
|
||||
|
||||
self.write_str(&format!("Deleted cached URL preview for: {url}"))
|
||||
.await
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user