mirror of
https://forgejo.ellis.link/continuwuation/continuwuity/
synced 2026-08-07 05:09:45 +00:00
Compare commits
141
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba14b06448 | ||
|
|
7aa7e9abc1 | ||
|
|
d046e349c8 | ||
|
|
44d7e6cf4f | ||
|
|
4e001abe92 | ||
|
|
4a40290514 | ||
|
|
226a3917af | ||
|
|
7920127391 | ||
|
|
65ff23bd48 | ||
|
|
3e8bf4a3c7 | ||
|
|
399005abc6 | ||
|
|
7fdc7f9216 | ||
|
|
c677847e29 | ||
|
|
795cdd3740 | ||
|
|
9894e2a6d1 | ||
|
|
c8a9eb41c5 | ||
|
|
e431a13a1a | ||
|
|
9a3496ae70 | ||
|
|
4cf743883a | ||
|
|
2d719e45fb | ||
|
|
0b456e3492 | ||
|
|
eee7a22e26 | ||
|
|
bc3168ef31 | ||
|
|
a6fd464f32 | ||
|
|
8addb41b5a | ||
|
|
3e10875f86 | ||
|
|
e161b5f01e | ||
|
|
a0fa4cf0fe | ||
|
|
08c22b5fcc | ||
|
|
a7892b296f | ||
|
|
7f8c2aedc8 | ||
|
|
8cde2ad0cc | ||
|
|
64b14cfad2 | ||
|
|
7cc5e44093 | ||
|
|
a838d59cfc | ||
|
|
fb7a378d63 | ||
|
|
4727f07e26 | ||
|
|
aa612baef3 | ||
|
|
b144b18aef | ||
|
|
4f1af01bdc | ||
|
|
1ff0d8d5a4 | ||
|
|
bee92b58e7 | ||
|
|
b9c6d5956f | ||
|
|
480e975877 | ||
|
|
6ce0d63733 | ||
|
|
e54252651b | ||
|
|
8f60648009 | ||
|
|
4c9426a13f | ||
|
|
25264308ab | ||
|
|
bcd57b9598 | ||
|
|
b2dee05ccf | ||
|
|
8b3be67860 | ||
|
|
153ef3a173 | ||
|
|
2441dfe436 | ||
|
|
d149833b7a | ||
|
|
b1632ee60b | ||
|
|
789589ef37 | ||
|
|
1e47090f5d | ||
|
|
3e55d08488 | ||
|
|
3a74ce6151 | ||
|
|
eff454218c | ||
|
|
e2eb980b5e | ||
|
|
8945cc9e10 | ||
|
|
78adeccda1 | ||
|
|
8195373d81 | ||
|
|
1ac05838dd | ||
|
|
7ecd2aa5e2 | ||
|
|
69a3145983 | ||
|
|
73b7553b1e | ||
|
|
232ec3f620 | ||
|
|
e52bbeaf94 | ||
|
|
ad1c194fb0 | ||
|
|
5e2dcd8e79 | ||
|
|
24c6474bd1 | ||
|
|
642d05048b | ||
|
|
446ae93ad7 | ||
|
|
9ca0774b2d | ||
|
|
ce494eb0c0 | ||
|
|
1f5e178c3f | ||
|
|
ddd050d402 | ||
|
|
6ad3e679bc | ||
|
|
65812bb246 | ||
|
|
9f3a7994c7 | ||
|
|
baef3289fe | ||
|
|
9a94b93ddd | ||
|
|
0ac0bd93ae | ||
|
|
fe9f718c6e | ||
|
|
e333f5a8e5 | ||
|
|
b8c64a68d4 | ||
|
|
163f049757 | ||
|
|
f48125c37a | ||
|
|
4001b99261 | ||
|
|
b6e5a106ff | ||
|
|
e1eea45fd6 | ||
|
|
7cb53f41d6 | ||
|
|
fbf81fcdeb | ||
|
|
87030a3a22 | ||
|
|
4f509fa113 | ||
|
|
aa7ed885c0 | ||
|
|
d5e6e617d1 | ||
|
|
1f7680ad5f | ||
|
|
0c37a542d4 | ||
|
|
efd07da0d7 | ||
|
|
f0590e882a | ||
|
|
7225bf25ae | ||
|
|
e52bb5db69 | ||
|
|
995726923b | ||
|
|
556141b404 | ||
|
|
6858e1b893 | ||
|
|
07e241f616 | ||
|
|
cfbe590f1c | ||
|
|
d9c2f04d73 | ||
|
|
ada0b3184b | ||
|
|
1d6ad485f6 | ||
|
|
9d2ce72f73 | ||
|
|
13bcb5af13 | ||
|
|
5868510df1 | ||
|
|
c34d1fe76e | ||
|
|
838764b0ac | ||
|
|
b51a34c1c1 | ||
|
|
2fbb779d12 | ||
|
|
e16a62e1ed | ||
|
|
64a08262ca | ||
|
|
70a3905761 | ||
|
|
cf9179e8f6 | ||
|
|
6b899b7f80 | ||
|
|
ad57fa06fc | ||
|
|
ec9efbada5 | ||
|
|
318d2b205a | ||
|
|
99a5f2a9fb | ||
|
|
ace0d52074 | ||
|
|
0b1e24a9ad | ||
|
|
f55207d5c7 | ||
|
|
3f2fae4ca7 | ||
|
|
081f865705 | ||
|
|
0d6608a2f8 | ||
|
|
abf96140b2 | ||
|
|
35fb56aafd | ||
|
|
03bde0e5fa | ||
|
|
5e306f160a | ||
|
|
fb2eedd5fd |
@@ -71,7 +71,7 @@ runs:
|
||||
|
||||
- name: Install timelord-cli and git-warp-time
|
||||
if: steps.check-binaries.outputs.need-install == 'true'
|
||||
uses: https://github.com/taiki-e/install-action@50414676f9f5d50a65992c6dd2ed02641263226c # v2
|
||||
uses: https://github.com/taiki-e/install-action@a6b2e2dcd845ddd7f509ce4f3ed3d922b80cc5d9 # v2
|
||||
with:
|
||||
tool: git-warp-time,timelord-cli@3.0.1
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
container: [ "ubuntu-latest", "ubuntu-previous", "debian-latest", "debian-oldstable" ]
|
||||
arch: ["amd64", "arm64"]
|
||||
container:
|
||||
image: "ghcr.io/tcpipuk/act-runner:${{ matrix.container }}"
|
||||
|
||||
@@ -43,7 +44,7 @@ jobs:
|
||||
# fi
|
||||
|
||||
- name: Checkout repository with full history
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref_name }}
|
||||
@@ -54,9 +55,9 @@ jobs:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: cargo-debian-${{ steps.debian-version.outputs.distribution }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
key: cargo-debian-${{ steps.debian-version.outputs.distribution }}-${{ matrix.arch }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
cargo-debian-${{ steps.debian-version.outputs.distribution }}-
|
||||
cargo-debian-${{ steps.debian-version.outputs.distribution }}-${{ matrix.arch }}-
|
||||
|
||||
- name: Setup sccache
|
||||
uses: https://git.tomfos.tr/tom/sccache-action@v1
|
||||
@@ -70,11 +71,55 @@ 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: |
|
||||
@@ -124,17 +169,16 @@ jobs:
|
||||
- name: Run cargo-deb
|
||||
id: cargo-deb
|
||||
run: |
|
||||
DEB_PATH=$(cargo deb --deb-version ${{ steps.package-meta.outputs.version }})
|
||||
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 }})
|
||||
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"
|
||||
@@ -142,7 +186,7 @@ jobs:
|
||||
- name: Upload deb artifact
|
||||
uses: forgejo/upload-artifact@v4
|
||||
with:
|
||||
name: continuwuity-${{ steps.debian-version.outputs.distribution }}
|
||||
name: continuwuity-${{ steps.debian-version.outputs.distribution }}-${{ matrix.arch }}
|
||||
path: ${{ steps.cargo-deb.outputs.path }}
|
||||
|
||||
- name: Publish to Forgejo package registry
|
||||
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
path: binaries
|
||||
merge-multiple: true
|
||||
- name: Create Release and Upload
|
||||
uses: https://github.com/softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3
|
||||
uses: https://github.com/softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3
|
||||
with:
|
||||
draft: true
|
||||
files: binaries/*
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Sync repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
@@ -32,7 +32,7 @@ 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
uses: https://github.com/actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 📦 Setup Node.js
|
||||
uses: https://github.com/actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
uses: https://github.com/actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
DOCKER_MIRROR_TOKEN: ${{ secrets.DOCKER_MIRROR_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
# repositories: continuwuity
|
||||
|
||||
- name: Install regsync
|
||||
uses: https://github.com/regclient/actions/regsync-installer@39bf30ced4be9d147faaabbde2682e9725fb8bd1 # main
|
||||
uses: https://github.com/regclient/actions/regsync-installer@c48159175b58fb90cccd0f98410927a81e04a166 # main
|
||||
|
||||
- name: Check what images need mirroring
|
||||
run: |
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
rust: ${{ steps.filter.outputs.rust }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Prepare Docker build environment
|
||||
@@ -101,7 +101,7 @@ jobs:
|
||||
needs: build-release
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Create multi-platform manifest
|
||||
@@ -134,7 +134,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Prepare max-perf Docker build environment
|
||||
@@ -189,7 +189,7 @@ jobs:
|
||||
needs: build-maxperf
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Create max-perf manifest
|
||||
@@ -218,7 +218,7 @@ jobs:
|
||||
path: binaries
|
||||
merge-multiple: true
|
||||
- name: Create Release and Upload
|
||||
uses: https://github.com/softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3
|
||||
uses: https://github.com/softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3
|
||||
with:
|
||||
draft: true
|
||||
files: binaries/*
|
||||
|
||||
@@ -43,11 +43,11 @@ jobs:
|
||||
name: Renovate
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/renovatebot/renovate:43.252.1@sha256:121eb04ef758537019fb58f587aa53c99e5fda4e703993ce2ca01bd4b3926bd4
|
||||
image: ghcr.io/renovatebot/renovate:43.281.1@sha256:34c2dd58f58e8976be2024a24fec23bbee805f0bf887837d9aaee7daeb09ccfc
|
||||
options: --tmpfs /tmp:exec
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
update-flake-hashes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
with:
|
||||
persist-credentials: true
|
||||
token: ${{ secrets.FORGEJO_TOKEN }}
|
||||
|
||||
+16
-54
@@ -1,65 +1,25 @@
|
||||
# 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.
|
||||
# Continuwuity 26.6.2 (2026-07-12)
|
||||
|
||||
## 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
|
||||
- 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.
|
||||
|
||||
## Improved Documentation
|
||||
|
||||
- Add performance tuning documentation. Contributed by @stratself. (#1498)
|
||||
- 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)
|
||||
# Continuwuity 26.6.1 (2026-07-12)
|
||||
|
||||
## Deprecations and Removals
|
||||
## Features
|
||||
|
||||
- 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.
|
||||
- Added enforcement for new federated invite checks and corrected a bunch of related spec compliance issues along the way. Contributed by @nex. (#1952)
|
||||
|
||||
## Misc
|
||||
## Bugfixes
|
||||
|
||||
- #1829, #1933
|
||||
- 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 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)
|
||||
@@ -108,6 +68,8 @@ ## Bugfixes
|
||||
## 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)
|
||||
|
||||
@@ -121,7 +83,7 @@ ## Deprecations and Removals
|
||||
|
||||
## Misc
|
||||
|
||||
- #1829, #1933
|
||||
- #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
|
||||
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ ### Pre-commit Checks
|
||||
|
||||
|
||||
```bash
|
||||
# Install prek using cargo-binstall
|
||||
# Install prek using cargo-binstall https://github.com/cargo-bins/cargo-binstall
|
||||
cargo binstall prek
|
||||
|
||||
# Install git hooks to run checks automatically
|
||||
@@ -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](/development/code_style.md)
|
||||
2. Your code follows the [code style guide](docs/development/code_style.mdx)
|
||||
3. Your commit messages follow the conventional commits format
|
||||
4. Tests are added for new functionality
|
||||
5. Documentation is updated if needed
|
||||
|
||||
Generated
+310
-408
File diff suppressed because it is too large
Load Diff
+7
-15
@@ -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.6.0"
|
||||
version = "26.6.2"
|
||||
|
||||
[workspace.metadata.crane]
|
||||
name = "conduwuit"
|
||||
@@ -115,8 +115,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.axum-client-ip]
|
||||
version = "1.3"
|
||||
[workspace.dependencies.client-ip]
|
||||
version = "0.2"
|
||||
|
||||
[workspace.dependencies.tower]
|
||||
version = "0.5.2"
|
||||
@@ -141,12 +141,6 @@ features = [
|
||||
version = "0.23.25"
|
||||
default-features = false
|
||||
|
||||
[workspace.dependencies.aws-lc-sys]
|
||||
version = "0.41.0"
|
||||
|
||||
[workspace.dependencies.aws-lc-rs]
|
||||
version = "1.17.0"
|
||||
|
||||
[workspace.dependencies.reqwest]
|
||||
version = "0.13.2"
|
||||
default-features = false
|
||||
@@ -348,9 +342,8 @@ version = "1.1.1"
|
||||
|
||||
# Used for matrix spec type definitions and helpers
|
||||
[workspace.dependencies.ruma]
|
||||
# version = "0.14.1"
|
||||
git = "https://github.com/ruma/ruma.git"
|
||||
rev = "fca1dbc060f730c1aaf84c9c2fb1e8a587455be8"
|
||||
rev = "e7284c31da289f0a3b885191f5b2b6b307fa059f"
|
||||
features = [
|
||||
"appservice-api-c",
|
||||
"client-api",
|
||||
@@ -363,7 +356,6 @@ features = [
|
||||
"compat-upload-signatures",
|
||||
"compat-optional-txn-pdus",
|
||||
"compat-get-3pids",
|
||||
"unstable-msc2666",
|
||||
"unstable-msc2867",
|
||||
"unstable-msc2870",
|
||||
"unstable-msc3061",
|
||||
@@ -502,14 +494,14 @@ version = "0.4.9"
|
||||
default-features = false
|
||||
|
||||
[workspace.dependencies.termimad]
|
||||
version = "0.34.0"
|
||||
version = "0.35.0"
|
||||
default-features = false
|
||||
|
||||
[workspace.dependencies.checked_ops]
|
||||
version = "0.1"
|
||||
|
||||
[workspace.dependencies.syn]
|
||||
version = "2.0"
|
||||
version = "3.0"
|
||||
default-features = false
|
||||
features = ["full", "extra-traits"]
|
||||
|
||||
@@ -570,7 +562,7 @@ features = ["std"]
|
||||
version = "0.3.0"
|
||||
|
||||
[workspace.dependencies.resolvematrix]
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
|
||||
[workspace.dependencies.serde_urlencoded]
|
||||
version = "0.7.1"
|
||||
|
||||
+68
-24
@@ -1,47 +1,90 @@
|
||||
# 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.
|
||||
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".
|
||||
|
||||
## 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 it has been addressed
|
||||
- [@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.
|
||||
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
|
||||
- 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.**
|
||||
|
||||
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.
|
||||
|
||||
### What to Expect
|
||||
### 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
|
||||
|
||||
When you report a security vulnerability:
|
||||
|
||||
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
|
||||
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.
|
||||
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)
|
||||
|
||||
@@ -51,7 +94,8 @@ ## 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
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Added support for the OAuth2 device authorization flow. Contributed by @ginger
|
||||
@@ -0,0 +1 @@
|
||||
Fixed requests returning `500 Internal Server Error` when the header selected by `request_ip_source` is absent, duplicated, or malformed (for example Envoy omitting `X-Envoy-External-Address` on internal requests). The client IP now falls back to the connection peer address instead of failing the request. Contributed by @eleboucher
|
||||
@@ -0,0 +1 @@
|
||||
Added support for the stable mutual rooms query endpoint. Contributed by @ginger
|
||||
@@ -0,0 +1 @@
|
||||
Appservices are now properly able to create devices for E2EE.
|
||||
@@ -0,0 +1 @@
|
||||
Resolve alias service by correct name for auto-join. Contributed by @eleboucher
|
||||
@@ -0,0 +1 @@
|
||||
Fixed newly created rooms failing to sync properly in clients using legacy sync.
|
||||
@@ -0,0 +1 @@
|
||||
Fixed newly joined rooms failing to sync their full state (including the room name) to clients using legacy sync.
|
||||
@@ -0,0 +1 @@
|
||||
Fixed `roomuserid_lastnotificationread` being aliased to the highlight count table, which clobbered highlight counts when setting a read marker. Contributed by @eleboucher
|
||||
@@ -0,0 +1 @@
|
||||
Fixed freshly left room failing to sync.
|
||||
@@ -0,0 +1 @@
|
||||
Appservices may now specify both the unstable and stable `device_id` query parameters in a request. The stable parameter will take priority. Contributed by @ginger.
|
||||
@@ -0,0 +1 @@
|
||||
Fetch the joined member count once per event instead of once per notified user.
|
||||
@@ -0,0 +1 @@
|
||||
Build and publish arm64 .deb packages alongside amd64 for all supported Debian and Ubuntu releases.
|
||||
@@ -1 +0,0 @@
|
||||
Rewrite the resolver service to use [resolvematrix](https://forgejo.ellis.link/continuwuation/resolvematrix) for server resolution. Rewrite by @s1lv3r, crate by @Jade
|
||||
@@ -1 +0,0 @@
|
||||
Explain accessing Continuwuity's server console when deployed via Docker.
|
||||
@@ -1 +0,0 @@
|
||||
Clarified in the config that `max_request_size` affects federated media as well.
|
||||
@@ -1 +0,0 @@
|
||||
Move resolver service into client service, and remove deprecated and unused code. Contributed by @s1lv3r.
|
||||
@@ -1 +0,0 @@
|
||||
Replace DNS resolution and caching system with [resolvematrix](https://forgejo.ellis.link/continuwuation/resolvematrix)' built-in one for more correct server resolution. Contributed by @s1lv3r.
|
||||
@@ -0,0 +1 @@
|
||||
Fixed the deeplink redirect for deleting devices. Contributed by @koen
|
||||
@@ -0,0 +1 @@
|
||||
Dehydrated devices are now visible in the account panel. Contributed by @ginger.
|
||||
@@ -0,0 +1 @@
|
||||
Fix status code for oauth registration. Contributed by @n00byking
|
||||
@@ -0,0 +1 @@
|
||||
Introduce `accepted_ip_sources` as a multiple options variant of `request_ip_source`, allowing for more advanced deployments and making fallbacks an explicit choice. Contributed by @Omar007
|
||||
@@ -0,0 +1 @@
|
||||
Exempt m.room.create from auth_events check. Contributed by @eleboucher
|
||||
@@ -0,0 +1 @@
|
||||
Fixed `create` being returned as a supported prompt value regardless of if registration is enabled or not. Contributed by @ginger
|
||||
@@ -0,0 +1 @@
|
||||
Updated an out-of-date statement about Oracle Linux release cadences.
|
||||
@@ -0,0 +1 @@
|
||||
Fixed high CPU usage when multiple clients from the same account were connected at once. Each sync woke the account's other sync loops, causing them to wake each other in a loop.
|
||||
@@ -0,0 +1 @@
|
||||
Fixed MSC4190 appservice device creation registering a random device ID instead of the requested one (and dropping the requested display name), which prevented encrypted mautrix bridges from starting on OIDC-enabled servers and leaked an orphan device on the bridge bot per startup attempt.
|
||||
@@ -0,0 +1 @@
|
||||
Deactivated users and appservice puppets are no longer counted by `/_continuwuity/local_user_count`. Contributed by @ginger.
|
||||
@@ -0,0 +1 @@
|
||||
Added an admin command to issue an access token for a bot account, to allow legacy bots to function while legacy authentication is disabled.
|
||||
@@ -0,0 +1 @@
|
||||
Re-introduced admin room registration alerts that were accidentally removed in the OAuth2 update.
|
||||
@@ -0,0 +1 @@
|
||||
Fix joining restricted rooms over federation failing with signature verification error.
|
||||
@@ -0,0 +1 @@
|
||||
Fixed the client space hierarchy endpoint returning a 500 "Space hierarchy is unreasonably large" error for cyclic space graphs (e.g. a space containing itself). Rooms are now deduplicated during traversal as required by the spec, and the traversal depth is bounded even when the client does not specify `max_depth`.
|
||||
@@ -0,0 +1 @@
|
||||
Fixed simplified sliding sync holding account data for up to 30 seconds, which made encryption setup and cross-signing resets appear to hang.
|
||||
@@ -0,0 +1 @@
|
||||
Fixed local invites and invite acceptances not being reflected in sync promptly. Contributed by @eleboucher
|
||||
+33
-2
@@ -290,7 +290,7 @@
|
||||
#
|
||||
#ip_lookup_strategy = 5
|
||||
|
||||
# The source to use for discovering the real connecting client IP.
|
||||
# The preferred source to use for getting the real client IP.
|
||||
#
|
||||
# Takes any of the following options:
|
||||
#
|
||||
@@ -301,16 +301,47 @@
|
||||
# "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.
|
||||
#
|
||||
# Defaults to the IP address actually making the connection.
|
||||
# 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.
|
||||
#
|
||||
|
||||
+4
-2
@@ -50,7 +50,7 @@ EOF
|
||||
|
||||
# Developer tool versions
|
||||
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
|
||||
ENV BINSTALL_VERSION=1.20.1
|
||||
ENV BINSTALL_VERSION=1.21.1
|
||||
# renovate: datasource=github-releases depName=psastras/sbom-rs
|
||||
ENV CARGO_SBOM_VERSION=0.9.1
|
||||
# renovate: datasource=crate depName=lddtree
|
||||
@@ -171,6 +171,7 @@ 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
|
||||
@@ -191,7 +192,7 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
jq -r ".target_directory"))
|
||||
mkdir /out/sbin
|
||||
PACKAGE=conduwuit
|
||||
xx-cargo build --locked --profile ${RUST_PROFILE} \
|
||||
CARGO_LOG=debug xx-cargo build --locked --profile ${RUST_PROFILE} \
|
||||
--no-default-features --features ${CARGO_FEATURES} \
|
||||
-p $PACKAGE;
|
||||
BINARIES=($(cargo metadata --no-deps --format-version 1 | \
|
||||
@@ -207,6 +208,7 @@ 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.20.1
|
||||
ENV BINSTALL_VERSION=1.21.1
|
||||
# renovate: datasource=github-releases depName=psastras/sbom-rs
|
||||
ENV CARGO_SBOM_VERSION=0.9.1
|
||||
# renovate: datasource=crate depName=lddtree
|
||||
|
||||
@@ -15,8 +15,8 @@ ## Overview
|
||||
|
||||
:::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, as of the time of writing, 10.2 has been
|
||||
available for over a month through other ELs, but Oracle has not yet released corresponding updates—so you may encounter further compatibility issues with EPEL.
|
||||
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.**
|
||||
:::
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
"message": "Welcome to Continuwuity! Important announcements about the project will appear here."
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"id": 16,
|
||||
"mention_room": true,
|
||||
"date": "2026-06-20",
|
||||
"message": "[v0.5.10](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.10) has been released. It is a security release, so we suggest you update as soon as possible. Don't forget to also join [our announcements room](https://matrix.to/#/!jIdNjSM5X-V5JVx2h2kAhUZIIQ08GyzPL55NFZAH1vM/%24K1ISNKIqfNiZzsNVCaTt2E7ZtNeP6Dsy6sbz9l3rO0A?via=ellis.link&via=gingershaped.computer&via=matrix.org)."
|
||||
"date": "2026-07-13",
|
||||
"message": "[Continuwuity 26.6.2](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v26.6.1) has just been released! This release fixes a severe bug with OIDC that could cause users' accounts to be flagged as deactivated. If you use OIDC, please update as soon as possible."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -27,3 +27,7 @@ ## `!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
|
||||
|
||||
@@ -146,6 +146,10 @@ ## `!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
|
||||
|
||||
@@ -106,9 +106,7 @@ ## `!admin query resolver`
|
||||
|
||||
### `!admin query resolver cache`
|
||||
|
||||
Query the destinations or overrides cache
|
||||
|
||||
Shows entire cache by default, but can be narrowed to only show overrides with `-o/--overrides true`, or to exclude them with `false`
|
||||
Query the destinations or overrides cache, depending on the value of the `overrides` flag (default false)
|
||||
|
||||
### `!admin query resolver flush-cache`
|
||||
|
||||
|
||||
Generated
+21
-21
@@ -3,11 +3,11 @@
|
||||
"advisory-db": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1781566179,
|
||||
"narHash": "sha256-Tqv8I586fYzWpEW/Smq/JqESFa3DVVzVWsnAMtvhy/I=",
|
||||
"lastModified": 1783840254,
|
||||
"narHash": "sha256-XjyvZk0f3YiinVHmkGOotmLBAzvK+LwEJYj2QqJ5pn8=",
|
||||
"owner": "rustsec",
|
||||
"repo": "advisory-db",
|
||||
"rev": "74e084413d979d52d2f93b1d93b1ab7b9ee648f5",
|
||||
"rev": "6e3286f4efa8c142fb33e5ea4342c8db6693cf34",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -18,11 +18,11 @@
|
||||
},
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1780532242,
|
||||
"narHash": "sha256-D+BsdpxmtUwtqGoY0IXPhHgTlmqgcZKCEo1oMyn7ep0=",
|
||||
"lastModified": 1783203018,
|
||||
"narHash": "sha256-G6R9IT/xwFuu+CYBWDUAok6AdC4ERC4ZfPPFtEpxnZE=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "59a82a1222dd3b2080b5cc52a1a2e8d5f1b77f37",
|
||||
"rev": "80db5bdc391be8a1794f6d8a2d56e3a84ebcede2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -39,11 +39,11 @@
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1781527054,
|
||||
"narHash": "sha256-1fX9ev2Fh5QoKQ41G9dYutjo5j/jywu6tZse5Eb1Ck4=",
|
||||
"lastModified": 1783844668,
|
||||
"narHash": "sha256-3MOpw4y3reoErRLvFBDz0t9aG6FWXUj7leKvUns5eQA=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "8c2e51dffefc040a21975da7abf6f252c8c9b783",
|
||||
"rev": "4e49ef62eedaa5c149d62b63b3f53844e1cc45d7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -74,11 +74,11 @@
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1778716662,
|
||||
"narHash": "sha256-m1Yf0wZ8j1OHjTc2UwHwyQRSnNeSgLJOd7q5Y45hzi4=",
|
||||
"lastModified": 1782949081,
|
||||
"narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb",
|
||||
"rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -89,11 +89,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1781074563,
|
||||
"narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=",
|
||||
"lastModified": 1783776592,
|
||||
"narHash": "sha256-UgCQzxeWI75XM8G+hPrPh+MKzEPjG3SpAj7dtqSbksA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca",
|
||||
"rev": "e7a3ca8092b61ff85b6a45bf863ea2b2d6a661b3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -105,11 +105,11 @@
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1777168982,
|
||||
"narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=",
|
||||
"lastModified": 1782614948,
|
||||
"narHash": "sha256-ePjCwr1sNm9NYUqywL7QfK3JnlS015msC+eBu2zKlp8=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "f5901329dade4a6ea039af1433fb087bd9c1fe14",
|
||||
"rev": "db3f255737b94216eb71cce308e2912cf6bc2d7c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -132,11 +132,11 @@
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1781453968,
|
||||
"narHash": "sha256-+V3nK4pCngbmgyVGXY6Kkrlevp4ocPkJJLf2aqwkDNA=",
|
||||
"lastModified": 1783779020,
|
||||
"narHash": "sha256-vpm418WZa9l1KUl6HRs+Ga+SIfE+D2/sV4olwTlilYc=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "cc272809a173c2c11d0e479d639c811c1eacf049",
|
||||
"rev": "5be5e89cf0145d73a85c805726821b4adfc3af48",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
{
|
||||
# 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.stable-toolchain)).devShell
|
||||
((inputs.crane.mkLib pkgs).overrideToolchain (pkgs: self'.packages.dev-toolchain)).devShell
|
||||
{
|
||||
packages = [
|
||||
self'.packages.rocksdb
|
||||
|
||||
@@ -43,6 +43,8 @@ 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";
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@
|
||||
target:
|
||||
target.fromToolchainName {
|
||||
name = (lib.importTOML "${inputs.self}/rust-toolchain.toml").toolchain.channel;
|
||||
sha256 = "sha256-h+t2xTBz5yt2YIO+1VMIIGlCU7gyp2LYOFvaV1nwOXU=";
|
||||
sha256 = "sha256-A1abGIbOtcBSdrUMhDGrER3pRM1hQP4fp9gh3Y4PKc8=";
|
||||
};
|
||||
in
|
||||
{
|
||||
@@ -27,9 +27,9 @@
|
||||
inherit stable-toolchain;
|
||||
|
||||
dev-toolchain = fnx.combine [
|
||||
stable-toolchain
|
||||
# use the nightly rustfmt because we use nightly features
|
||||
fnx.complete.rustfmt
|
||||
stable-toolchain
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
Generated
+429
-68
@@ -12,7 +12,7 @@
|
||||
"@rspress/core": "^2.0.0",
|
||||
"@rspress/plugin-client-redirects": "^2.0.0",
|
||||
"@rspress/plugin-sitemap": "^2.0.0",
|
||||
"typescript": "^6.0.0"
|
||||
"typescript": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
@@ -419,9 +419,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rspress/core": {
|
||||
"version": "2.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/core/-/core-2.0.17.tgz",
|
||||
"integrity": "sha512-oynYHE2aBj7BFzD/UgqKnrj/PyYxfWGrmRPlTmjLL22UPcocdUdFYLb/6nijyseAST59VMr5Gj4wOfFUeJT5vw==",
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/core/-/core-2.0.18.tgz",
|
||||
"integrity": "sha512-DBpsr/6XAItQkZPL5FSjthLGuzdG9ks/7EOxkqaaXp93uAT54LO0PD5Dkoy6ydup1PnvkpHyiHpUyDcnHHTVhg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -429,7 +429,7 @@
|
||||
"@mdx-js/react": "^3.1.1",
|
||||
"@rsbuild/core": "^2.1.5",
|
||||
"@rsbuild/plugin-react": "~2.1.0",
|
||||
"@rspress/shared": "2.0.17",
|
||||
"@rspress/shared": "2.0.18",
|
||||
"@shikijs/rehype": "^4.2.0",
|
||||
"@types/unist": "^3.0.3",
|
||||
"@unhead/react": "^2.1.15",
|
||||
@@ -472,9 +472,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rspress/plugin-client-redirects": {
|
||||
"version": "2.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/plugin-client-redirects/-/plugin-client-redirects-2.0.17.tgz",
|
||||
"integrity": "sha512-HJMlW5xsQe2cAFYNHw3LhMy8WcuqRb4l0ey3E3OIu121ymbSLqIQJVPS/IF/NuoyPoxCAmV58LYIaCxGEriUww==",
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/plugin-client-redirects/-/plugin-client-redirects-2.0.18.tgz",
|
||||
"integrity": "sha512-q70ufN0S125kl0QlucO7JuiZ0WJaxFOtPPoGu7eWwam9fb+i4YsWnOWtAKSKGH4JP5+897mgpDPP+dmfl9DPCw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -485,9 +485,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rspress/plugin-sitemap": {
|
||||
"version": "2.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/plugin-sitemap/-/plugin-sitemap-2.0.17.tgz",
|
||||
"integrity": "sha512-MpNxF+hFK7zsk8t+Ta7KYI/Py6Csjyw0AMGrWf3XG/kr0+fisVxbT/jUanXRLSoj2m9VX9CVsi180rPnezUpbQ==",
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/plugin-sitemap/-/plugin-sitemap-2.0.18.tgz",
|
||||
"integrity": "sha512-XfaXzZx+ASN9OMTc0fOvW8QmbmyCyDWkO8xJj4XF4E0YJtsu7j/65+v8/KXXdwpywOfUIQ6M94/meRTy2urNmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -498,9 +498,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rspress/shared": {
|
||||
"version": "2.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/shared/-/shared-2.0.17.tgz",
|
||||
"integrity": "sha512-ZzpZ4hm5svgwU0w5CpTLZy4vFD3uPo8+gXtWMOREYMzwfzJeHqwOyXwxHf6byGpx85mVK5DQqMDi61meAS7ZUw==",
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/shared/-/shared-2.0.18.tgz",
|
||||
"integrity": "sha512-GJswqJQCPSxvBt5r+gJzz8Em8EEK/sOmCQjTpemTvldvxr1Lva85BGVnSQZOgofnM0nrjt18kn4mmnuuSstbpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -510,14 +510,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/core": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.2.0.tgz",
|
||||
"integrity": "sha512-Hc87Ab1Ld/vEbZRCbwx344I5v+4RU8CVToUTRkqXL1+TjbuOp9U5Xa0M23V4GEWHxVn+yO5otb+HkQVm3ptWQQ==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.3.1.tgz",
|
||||
"integrity": "sha512-ANMDxuaPsNMdDC1m4vfvhlDmJweMwkE5XitTwrq2rWHx5jM+dlm4MmHt2PP6t0uejfR77SuhrhJ0zEijIF/uhA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/primitive": "4.2.0",
|
||||
"@shikijs/types": "4.2.0",
|
||||
"@shikijs/primitive": "4.3.1",
|
||||
"@shikijs/types": "4.3.1",
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"@types/hast": "^3.0.4",
|
||||
"hast-util-to-html": "^9.0.5"
|
||||
@@ -527,13 +527,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/engine-javascript": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.2.0.tgz",
|
||||
"integrity": "sha512-fjETeq1k5ffyXqRgS6+3hpvqseLalp1kjNfRbXpUgWR8FpZ1CmQfiNHovc5lncYjt/Vg5JK/WJEmLahjwMa0og==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.3.1.tgz",
|
||||
"integrity": "sha512-JBItcnPuYq7jVJdZo/vMj94r+szT7XEjHFX+mvFDGSEIbVAXAGyHAHzhbWzpGOwYidCZrErJLLgn2PVeiokHnQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "4.2.0",
|
||||
"@shikijs/types": "4.3.1",
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"oniguruma-to-es": "^4.3.6"
|
||||
},
|
||||
@@ -542,13 +542,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/engine-oniguruma": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.2.0.tgz",
|
||||
"integrity": "sha512-hTorK1dffPkpbMUk6Z+828PgRo7d07HbnizoP0hNPFjhxMHctj0Px/qoHeGMYafc6ju+u9iMldN4JbVzNQM++g==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.3.1.tgz",
|
||||
"integrity": "sha512-OXyNMzg0pews+msMj4cHeqT4xiYKKvbnn6VbdAXxfoFl3SSx4fJTc8FadECuc5/H9p3BzhNAoAUXKwAu9rWYhg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "4.2.0",
|
||||
"@shikijs/types": "4.3.1",
|
||||
"@shikijs/vscode-textmate": "^10.0.2"
|
||||
},
|
||||
"engines": {
|
||||
@@ -556,26 +556,26 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/langs": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.2.0.tgz",
|
||||
"integrity": "sha512-bwrVRlJ0wUhZxAbVdvBbv2TTC9yLsh4C/IO5Ofz0T8MQntgDvyVnkbjw9vi50r1kx7RCIJdnJnjZAwmAsXFLZQ==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.3.1.tgz",
|
||||
"integrity": "sha512-m0l9nsDqgBHvbZbk7A0/kXz/impK3uB/c6rAn6Gpg/uPtdZRQ+alsN/17MU5thb68XTj/4DxkZAotrM0GGSpDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "4.2.0"
|
||||
"@shikijs/types": "4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/primitive": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.2.0.tgz",
|
||||
"integrity": "sha512-NOq+DtUkVBJtZMVXL5A0vI0Xk8nvDYaXetFHSJFlOqjDZIVhIPRYFdGkSoElDqNuegikcc3A76SNUa8dTqtAYA==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.3.1.tgz",
|
||||
"integrity": "sha512-CXQRQOYy1leqQ8ceTeJdmXv/bsUY++6QyLpXJ94LZAAYj5X2SKRdc5ipguv4NPyGVKItB2PPwUpRNe0Sjh5S1A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "4.2.0",
|
||||
"@shikijs/types": "4.3.1",
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"@types/hast": "^3.0.4"
|
||||
},
|
||||
@@ -584,16 +584,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/rehype": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/rehype/-/rehype-4.2.0.tgz",
|
||||
"integrity": "sha512-ST3EWye/dwF1gWskczJNBnwFtDzEQ9ceytXZtyc/GfwR5V0qJrkoSGZO55O3SAKDDsXkTDcsfwd9pVe7ROlAHg==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/rehype/-/rehype-4.3.1.tgz",
|
||||
"integrity": "sha512-oshrlfUF3VPUJfnp5K1lLwsS/SRBKrIxONpdWebSKZXdBE3UsZnxgqpvRUA8UsofS7vmjFOCAHIT71ECbmOxTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "4.2.0",
|
||||
"@shikijs/types": "4.3.1",
|
||||
"@types/hast": "^3.0.4",
|
||||
"hast-util-to-string": "^3.0.1",
|
||||
"shiki": "4.2.0",
|
||||
"shiki": "4.3.1",
|
||||
"unified": "^11.0.5",
|
||||
"unist-util-visit": "^5.1.0"
|
||||
},
|
||||
@@ -602,22 +602,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/themes": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.2.0.tgz",
|
||||
"integrity": "sha512-RX8IHYeLv8Cu2W6ruc3RxUqWn0IYCqSrMBzi/uRGAmfyDNOnNO5BF/Px7o97n4XTpmFTo5GbRaazuOWj+2ak2w==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.3.1.tgz",
|
||||
"integrity": "sha512-dgpoJ4WqNi2yTmizQHBJ5zcX6j2lE6icN/0yt4l1kkf16jrY/pwPLoTb1ETsWMz0OBLf9ZNvwmxft+cH+N9qSA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "4.2.0"
|
||||
"@shikijs/types": "4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/types": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.2.0.tgz",
|
||||
"integrity": "sha512-VT/MKtlpOhEPZloSH3Pb9WCZEBDoQVMa9jedp5UAwmJOar1DVc9DRODAxmYPW9M93IK4ryuqRejFfmlvlVDemw==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.1.tgz",
|
||||
"integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -684,9 +684,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/hast": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
|
||||
"integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz",
|
||||
"integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -735,10 +735,350 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript/typescript-aix-ppc64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz",
|
||||
"integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-darwin-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-darwin-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-freebsd-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-freebsd-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-arm": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz",
|
||||
"integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-loong64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz",
|
||||
"integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-mips64el": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz",
|
||||
"integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-ppc64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz",
|
||||
"integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-riscv64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz",
|
||||
"integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-s390x": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz",
|
||||
"integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-netbsd-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-netbsd-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-openbsd-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-openbsd-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-sunos-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-win32-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-win32-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ungap/structured-clone": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz",
|
||||
"integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==",
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz",
|
||||
"integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@@ -3249,18 +3589,18 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/shiki": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-4.2.0.tgz",
|
||||
"integrity": "sha512-hjNax6o/ylDy9lefQEaSDtzaT3iVNtZ3WmpQnbuQNoG4xvnSKf2kSKbihZVO4JRG1TTMejs7CmNRYlWgAL66pQ==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-4.3.1.tgz",
|
||||
"integrity": "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/core": "4.2.0",
|
||||
"@shikijs/engine-javascript": "4.2.0",
|
||||
"@shikijs/engine-oniguruma": "4.2.0",
|
||||
"@shikijs/langs": "4.2.0",
|
||||
"@shikijs/themes": "4.2.0",
|
||||
"@shikijs/types": "4.2.0",
|
||||
"@shikijs/core": "4.3.1",
|
||||
"@shikijs/engine-javascript": "4.3.1",
|
||||
"@shikijs/engine-oniguruma": "4.3.1",
|
||||
"@shikijs/langs": "4.3.1",
|
||||
"@shikijs/themes": "4.3.1",
|
||||
"@shikijs/types": "4.3.1",
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"@types/hast": "^3.0.4"
|
||||
},
|
||||
@@ -3361,17 +3701,38 @@
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz",
|
||||
"integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
"tsc": "bin/tsc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
"node": ">=16.20.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@typescript/typescript-aix-ppc64": "7.0.2",
|
||||
"@typescript/typescript-darwin-arm64": "7.0.2",
|
||||
"@typescript/typescript-darwin-x64": "7.0.2",
|
||||
"@typescript/typescript-freebsd-arm64": "7.0.2",
|
||||
"@typescript/typescript-freebsd-x64": "7.0.2",
|
||||
"@typescript/typescript-linux-arm": "7.0.2",
|
||||
"@typescript/typescript-linux-arm64": "7.0.2",
|
||||
"@typescript/typescript-linux-loong64": "7.0.2",
|
||||
"@typescript/typescript-linux-mips64el": "7.0.2",
|
||||
"@typescript/typescript-linux-ppc64": "7.0.2",
|
||||
"@typescript/typescript-linux-riscv64": "7.0.2",
|
||||
"@typescript/typescript-linux-s390x": "7.0.2",
|
||||
"@typescript/typescript-linux-x64": "7.0.2",
|
||||
"@typescript/typescript-netbsd-arm64": "7.0.2",
|
||||
"@typescript/typescript-netbsd-x64": "7.0.2",
|
||||
"@typescript/typescript-openbsd-arm64": "7.0.2",
|
||||
"@typescript/typescript-openbsd-x64": "7.0.2",
|
||||
"@typescript/typescript-sunos-x64": "7.0.2",
|
||||
"@typescript/typescript-win32-arm64": "7.0.2",
|
||||
"@typescript/typescript-win32-x64": "7.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/unhead": {
|
||||
|
||||
+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": "^6.0.0"
|
||||
"typescript": "^7.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,13 @@
|
||||
"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"],
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
[toolchain]
|
||||
profile = "minimal"
|
||||
channel = "1.96.1"
|
||||
channel = "1.97.1"
|
||||
components = [
|
||||
# For rust-analyzer
|
||||
"rust-src",
|
||||
|
||||
@@ -73,4 +73,29 @@ pub(super) async fn list_registered(&self) -> Result {
|
||||
})
|
||||
.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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,4 +37,10 @@ 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,
|
||||
}
|
||||
|
||||
@@ -486,7 +486,7 @@ pub(super) async fn get_remote_pdu(
|
||||
.services
|
||||
.rooms
|
||||
.event_handler
|
||||
.parse_incoming_pdu(&response.pdu)
|
||||
.parse_incoming_pdu(&response.pdu, None)
|
||||
.boxed()
|
||||
.await;
|
||||
|
||||
@@ -832,7 +832,7 @@ pub(super) async fn force_set_room_state_from_server(
|
||||
.services
|
||||
.rooms
|
||||
.event_handler
|
||||
.parse_incoming_pdu(&pdu)
|
||||
.parse_incoming_pdu(&pdu, Some(&room_version_rules))
|
||||
.await
|
||||
{
|
||||
| Ok(t) => t,
|
||||
@@ -1014,7 +1014,7 @@ pub(super) async fn resolve_true_destination(
|
||||
let resolver: &MatrixResolver = if no_cache {
|
||||
&MatrixResolverBuilder::new()
|
||||
.dangerous_tls_accept_invalid_certs(self.services.server.config.allow_invalid_tls_certificates_yes_i_know_what_the_fuck_i_am_doing_with_this_and_i_know_this_is_insecure)
|
||||
.http_client(self.services.client.default.clone())
|
||||
.http_client(self.services.client.dns.clone())
|
||||
.build()?
|
||||
} else {
|
||||
&self.services.client.matrix_resolver
|
||||
|
||||
@@ -54,7 +54,7 @@ pub(super) async fn fetch_support_well_known(&self, server_name: OwnedServerName
|
||||
let response = self
|
||||
.services
|
||||
.client
|
||||
.default
|
||||
.external_resource
|
||||
.get(format!("https://{server_name}/.well-known/matrix/support"))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use service::registration_tokens::TokenExpires;
|
||||
|
||||
impl crate::Context<'_> {
|
||||
pub(super) async fn issue_token(&self, expires: super::TokenExpires) -> Result {
|
||||
pub(super) async fn issue_registration_token(&self, expires: super::TokenExpires) -> Result {
|
||||
let expires = {
|
||||
if expires.immortal {
|
||||
None
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
pub enum TokenCommand {
|
||||
/// Issue a new registration token
|
||||
#[clap(name = "issue")]
|
||||
IssueToken {
|
||||
IssueRegistrationToken {
|
||||
/// When this token will expire.
|
||||
#[command(flatten)]
|
||||
expires: TokenExpires,
|
||||
|
||||
+31
-14
@@ -20,7 +20,7 @@
|
||||
tag::{TagEvent, TagEventContent, TagInfo},
|
||||
},
|
||||
};
|
||||
use service::users::{AccountStatus, HashedPassword};
|
||||
use service::users::{AccountStatus, DeviceToken, HashedPassword};
|
||||
|
||||
use crate::{
|
||||
get_room_info,
|
||||
@@ -59,13 +59,42 @@ pub(super) async fn create_user(&self, username: String, password: Option<String
|
||||
|
||||
self.services
|
||||
.users
|
||||
.create_local_account(&user_id, Some(HashedPassword::new(password)?), None)
|
||||
.create_local_account(
|
||||
&user_id,
|
||||
Some(HashedPassword::new(password)?),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.write_str(&format!("Created user {user_id} with password `{password}`"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn issue_access_token(&self, username: String, password: String) -> Result {
|
||||
let user_id = parse_active_local_user_id(self.services, &username).await?;
|
||||
|
||||
let user_id = self
|
||||
.services
|
||||
.users
|
||||
.check_password(&user_id, &password)
|
||||
.await?;
|
||||
let token = DeviceToken::new_random();
|
||||
|
||||
let device_id = self
|
||||
.services
|
||||
.users
|
||||
.create_device(&user_id, None, Some(token.clone()), None, None)
|
||||
.await?;
|
||||
|
||||
self.write_str(&format!(
|
||||
"Created device `{device_id}` with access token `{}` for {user_id}",
|
||||
token.into_token()
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn deactivate(&self, no_leave_rooms: bool, user_id: String) -> Result {
|
||||
// Validate user id
|
||||
let user_id = parse_local_user_id(self.services, &user_id)?;
|
||||
@@ -102,7 +131,6 @@ pub(super) async fn deactivate(&self, no_leave_rooms: bool, user_id: String) ->
|
||||
}
|
||||
|
||||
pub(super) async fn suspend(&self, user_id: String) -> Result {
|
||||
self.bail_restricted()?;
|
||||
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
|
||||
|
||||
if user_id == self.services.globals.server_user {
|
||||
@@ -123,7 +151,6 @@ pub(super) async fn suspend(&self, user_id: String) -> Result {
|
||||
}
|
||||
|
||||
pub(super) async fn unsuspend(&self, user_id: String) -> Result {
|
||||
self.bail_restricted()?;
|
||||
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
|
||||
|
||||
if user_id == self.services.globals.server_user {
|
||||
@@ -935,7 +962,6 @@ pub(super) async fn force_leave_remote_room(
|
||||
}
|
||||
|
||||
pub(super) async fn lock(&self, user_id: String) -> Result {
|
||||
self.bail_restricted()?;
|
||||
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
|
||||
|
||||
if user_id == self.services.globals.server_user {
|
||||
@@ -956,7 +982,6 @@ pub(super) async fn lock(&self, user_id: String) -> Result {
|
||||
}
|
||||
|
||||
pub(super) async fn unlock(&self, user_id: String) -> Result {
|
||||
self.bail_restricted()?;
|
||||
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
|
||||
|
||||
self.services.users.unlock_account(&user_id).await;
|
||||
@@ -966,7 +991,6 @@ pub(super) async fn unlock(&self, user_id: String) -> Result {
|
||||
}
|
||||
|
||||
pub(super) async fn logout(&self, user_id: String) -> Result {
|
||||
self.bail_restricted()?;
|
||||
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
|
||||
|
||||
if user_id == self.services.globals.server_user {
|
||||
@@ -992,7 +1016,6 @@ pub(super) async fn logout(&self, user_id: String) -> Result {
|
||||
}
|
||||
|
||||
pub(super) async fn disable_login(&self, user_id: String) -> Result {
|
||||
self.bail_restricted()?;
|
||||
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
|
||||
|
||||
if user_id == self.services.globals.server_user {
|
||||
@@ -1011,7 +1034,6 @@ pub(super) async fn disable_login(&self, user_id: String) -> Result {
|
||||
}
|
||||
|
||||
pub(super) async fn enable_login(&self, user_id: String) -> Result {
|
||||
self.bail_restricted()?;
|
||||
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
|
||||
|
||||
self.services.users.enable_login(&user_id);
|
||||
@@ -1020,7 +1042,6 @@ pub(super) async fn enable_login(&self, user_id: String) -> Result {
|
||||
}
|
||||
|
||||
pub(super) async fn get_email(&self, user_id: String) -> Result {
|
||||
self.bail_restricted()?;
|
||||
let user_id = parse_local_user_id(self.services, &user_id)?;
|
||||
|
||||
match self
|
||||
@@ -1039,8 +1060,6 @@ pub(super) async fn get_email(&self, user_id: String) -> Result {
|
||||
}
|
||||
|
||||
pub(super) async fn get_user_by_email(&self, email: String) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
let Ok(email) = Address::try_from(email) else {
|
||||
return Err!("Invalid email address.");
|
||||
};
|
||||
@@ -1063,8 +1082,6 @@ pub(super) async fn get_user_by_email(&self, email: String) -> Result {
|
||||
}
|
||||
|
||||
pub(super) async fn change_email(&self, user_id: String, email: Option<String>) -> Result {
|
||||
self.bail_restricted()?;
|
||||
|
||||
let user_id = parse_local_user_id(self.services, &user_id)?;
|
||||
let Ok(new_email) = email.map(Address::try_from).transpose() else {
|
||||
return Err!("Invalid email address.");
|
||||
|
||||
@@ -18,6 +18,15 @@ pub enum UserCommand {
|
||||
password: Option<String>,
|
||||
},
|
||||
|
||||
/// Issue an access token for a user. This command will not work on
|
||||
/// shadow users, such as appservice puppets or accounts imported from
|
||||
/// an identity provider.
|
||||
#[clap(name = "issue-token")]
|
||||
IssueAccessToken {
|
||||
username: String,
|
||||
password: String,
|
||||
},
|
||||
|
||||
/// Reset user password
|
||||
ResetPassword {
|
||||
/// Log out existing sessions
|
||||
|
||||
+1
-1
@@ -64,11 +64,11 @@ zstd_compression = [
|
||||
|
||||
[dependencies]
|
||||
async-trait.workspace = true
|
||||
axum-client-ip.workspace = true
|
||||
axum-extra.workspace = true
|
||||
axum.workspace = true
|
||||
base64.workspace = true
|
||||
bytes.workspace = true
|
||||
client-ip.workspace = true
|
||||
conduwuit-core.workspace = true
|
||||
conduwuit-macros.workspace = true
|
||||
conduwuit-service.workspace = true
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, err, info,
|
||||
pdu::PartialPdu,
|
||||
@@ -26,7 +25,6 @@
|
||||
};
|
||||
use service::{mailer::messages, uiaa::UiaaInitiator, users::HashedPassword};
|
||||
|
||||
use super::{DEVICE_ID_LENGTH, TOKEN_LENGTH};
|
||||
use crate::{Ruma, router::ClientIdentity};
|
||||
|
||||
pub(crate) mod register;
|
||||
@@ -43,10 +41,9 @@
|
||||
///
|
||||
/// Note: This will not reserve the username, so the username might become
|
||||
/// invalid when trying to register
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "register_available", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "register_available", level = "info")]
|
||||
pub(crate) async fn get_register_available_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_username_availability::v3::Request>,
|
||||
) -> Result<get_username_availability::v3::Response> {
|
||||
let _ = services
|
||||
@@ -80,10 +77,9 @@ pub(crate) async fn get_register_available_route(
|
||||
/// last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "change_password", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "change_password", level = "info")]
|
||||
pub(crate) async fn change_password_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<change_password::v3::Request>,
|
||||
) -> Result<change_password::v3::Response> {
|
||||
let identity = if let Some(identity) = body.identity.as_ref() {
|
||||
@@ -248,10 +244,9 @@ pub(crate) async fn whoami_route(
|
||||
/// - Forgets all to-device events
|
||||
/// - Triggers device list updates
|
||||
/// - Removes ability to log in again
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "deactivate", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "deactivate", level = "info")]
|
||||
pub(crate) async fn deactivate_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<deactivate::v3::Request>,
|
||||
) -> Result<deactivate::v3::Response> {
|
||||
// Authentication for this endpoint is technically optional,
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug_info, info,
|
||||
utils::{self},
|
||||
};
|
||||
use conduwuit::{Err, Result, debug_info, info};
|
||||
use conduwuit_service::Services;
|
||||
use futures::StreamExt;
|
||||
use lettre::{Address, message::Mailbox};
|
||||
@@ -20,10 +16,12 @@
|
||||
assign,
|
||||
};
|
||||
use serde_json::value::RawValue;
|
||||
use service::{mailer::messages, users::HashedPassword};
|
||||
use service::{
|
||||
mailer::messages,
|
||||
users::{DeviceToken, HashedPassword},
|
||||
};
|
||||
|
||||
use super::{DEVICE_ID_LENGTH, TOKEN_LENGTH};
|
||||
use crate::Ruma;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
|
||||
/// # `POST /_matrix/client/v3/register`
|
||||
///
|
||||
@@ -33,10 +31,10 @@
|
||||
/// /_matrix/client/v3/register/available`](fn.get_register_available_route.
|
||||
/// html) to check if the user id is valid and available.
|
||||
#[allow(clippy::doc_markdown)]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "register", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "register", level = "info")]
|
||||
pub(crate) async fn register_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
ClientIp(client): ClientIp, // NOTE: Required for metadata.
|
||||
body: Ruma<register::v3::Request>,
|
||||
) -> Result<register::v3::Response> {
|
||||
if body.kind != RegistrationKind::User {
|
||||
@@ -97,7 +95,13 @@ pub(crate) async fn register_route(
|
||||
|
||||
services
|
||||
.users
|
||||
.create_local_account(&user_id, Some(password), identity.email)
|
||||
.create_local_account(
|
||||
&user_id,
|
||||
Some(password),
|
||||
identity.email,
|
||||
Some(&client),
|
||||
body.initial_device_display_name.as_deref(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
user_id
|
||||
@@ -112,27 +116,21 @@ pub(crate) async fn register_route(
|
||||
)));
|
||||
}
|
||||
|
||||
// Generate new device id if the user didn't specify one
|
||||
let device_id = body
|
||||
.device_id
|
||||
.clone()
|
||||
.unwrap_or_else(|| utils::random_string(DEVICE_ID_LENGTH).into());
|
||||
|
||||
// Generate new token for the device
|
||||
let new_token = utils::random_string(TOKEN_LENGTH);
|
||||
let new_token = DeviceToken::new_random();
|
||||
|
||||
// Create device for this account
|
||||
services
|
||||
let device_id = services
|
||||
.users
|
||||
.create_device(
|
||||
&user_id,
|
||||
&device_id,
|
||||
&new_token,
|
||||
None,
|
||||
body.device_id.clone(),
|
||||
Some(new_token.clone()),
|
||||
body.initial_device_display_name.clone(),
|
||||
Some(client.to_string()),
|
||||
)
|
||||
.await?;
|
||||
|
||||
(Some(new_token), Some(device_id))
|
||||
} else {
|
||||
// Don't create a device for inhibited logins
|
||||
@@ -142,7 +140,7 @@ pub(crate) async fn register_route(
|
||||
debug_info!(%user_id, ?device, "New account created via legacy registration");
|
||||
|
||||
Ok(assign!(register::v3::Response::new(user_id), {
|
||||
access_token: token,
|
||||
access_token: token.map(DeviceToken::into_token),
|
||||
device_id: device,
|
||||
refresh_token: None,
|
||||
expires_in: None,
|
||||
|
||||
@@ -57,13 +57,11 @@ pub(crate) async fn request_3pid_management_token_via_email_route(
|
||||
State(services): State<crate::State>,
|
||||
body: Ruma<request_3pid_management_token_via_email::v3::Request>,
|
||||
) -> Result<request_3pid_management_token_via_email::v3::Response> {
|
||||
// Authentication for this endpoint is technically optional,
|
||||
// but we require the user to be logged in
|
||||
let sender_user = body
|
||||
.identity
|
||||
.as_ref()
|
||||
.map(ClientIdentity::expect_sender_user)
|
||||
.ok_or_else(|| err!(Request(MissingToken("Missing access token."))))??;
|
||||
.transpose()?;
|
||||
|
||||
if !services.threepid.email_requirement().may_change() {
|
||||
return Err!(Request(Forbidden("You may not change your email address.")));
|
||||
@@ -88,7 +86,7 @@ pub(crate) async fn request_3pid_management_token_via_email_route(
|
||||
Mailbox::new(None, email),
|
||||
|verification_link| messages::ChangeEmail {
|
||||
server_name: services.config.server_name.as_str(),
|
||||
user_id: Some(sender_user),
|
||||
user_id: sender_user,
|
||||
verification_link,
|
||||
},
|
||||
&body.client_secret,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, at};
|
||||
use futures::StreamExt;
|
||||
use ruma::{
|
||||
@@ -19,10 +18,9 @@
|
||||
/// # `PUT /_matrix/client/../dehydrated_device`
|
||||
///
|
||||
/// Creates or overwrites the user's dehydrated device.
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) async fn put_dehydrated_device_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<put_dehydrated_device::Request>,
|
||||
) -> Result<put_dehydrated_device::Response> {
|
||||
let device_id = body.device_id.clone();
|
||||
@@ -38,10 +36,9 @@ pub(crate) async fn put_dehydrated_device_route(
|
||||
/// # `DELETE /_matrix/client/../dehydrated_device`
|
||||
///
|
||||
/// Deletes the user's dehydrated device without replacement.
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) async fn delete_dehydrated_device_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<delete_dehydrated_device::Request>,
|
||||
) -> Result<delete_dehydrated_device::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -56,10 +53,9 @@ pub(crate) async fn delete_dehydrated_device_route(
|
||||
/// # `GET /_matrix/client/../dehydrated_device`
|
||||
///
|
||||
/// Gets the user's dehydrated device
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) async fn get_dehydrated_device_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_dehydrated_device::Request>,
|
||||
) -> Result<get_dehydrated_device::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -72,10 +68,9 @@ pub(crate) async fn get_dehydrated_device_route(
|
||||
/// # `GET /_matrix/client/../dehydrated_device/{device_id}/events`
|
||||
///
|
||||
/// Paginates the events of the dehydrated device.
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) async fn get_dehydrated_events_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_events::Request>,
|
||||
) -> Result<get_events::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, debug, err, utils};
|
||||
use conduwuit::{Err, Result, debug, err};
|
||||
use futures::StreamExt;
|
||||
use ruma::{
|
||||
MilliSecondsSinceUnixEpoch, OwnedDeviceId,
|
||||
MilliSecondsSinceUnixEpoch,
|
||||
api::client::device::{
|
||||
self, delete_device, delete_devices, get_device, get_devices, update_device,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{Ruma, client::DEVICE_ID_LENGTH};
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
|
||||
/// # `GET /_matrix/client/r0/devices`
|
||||
///
|
||||
@@ -46,10 +45,10 @@ pub(crate) async fn get_device_route(
|
||||
/// # `PUT /_matrix/client/r0/devices/{deviceId}`
|
||||
///
|
||||
/// Updates the metadata on a given device of the sender user.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "update_device", level = "debug")]
|
||||
#[tracing::instrument(skip_all, name = "update_device", level = "debug")]
|
||||
pub(crate) async fn update_device_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
ClientIp(client): ClientIp, // NOTE: Required for updating device metadata
|
||||
body: Ruma<update_device::v3::Request>,
|
||||
) -> Result<update_device::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -85,16 +84,13 @@ pub(crate) async fn update_device_route(
|
||||
appservice.registration.id
|
||||
);
|
||||
|
||||
let device_id = OwnedDeviceId::from(utils::random_string(DEVICE_ID_LENGTH));
|
||||
|
||||
services
|
||||
.users
|
||||
.create_device(
|
||||
sender_user,
|
||||
&device_id,
|
||||
&appservice.registration.as_token,
|
||||
None,
|
||||
Some(body.device_id.clone()),
|
||||
None,
|
||||
body.display_name.clone(),
|
||||
Some(client.to_string()),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, err, info,
|
||||
utils::{
|
||||
@@ -35,10 +34,9 @@
|
||||
/// Lists the public rooms on this server.
|
||||
///
|
||||
/// - Rooms are ordered by the number of joined members
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "publicrooms", level = "info")]
|
||||
pub(crate) async fn get_public_rooms_filtered_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_public_rooms_filtered::v3::Request>,
|
||||
) -> Result<get_public_rooms_filtered::v3::Response> {
|
||||
if let Some(server) = &body.server {
|
||||
@@ -71,10 +69,9 @@ pub(crate) async fn get_public_rooms_filtered_route(
|
||||
/// Lists the public rooms on this server.
|
||||
///
|
||||
/// - Rooms are ordered by the number of joined members
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "publicrooms", level = "info")]
|
||||
pub(crate) async fn get_public_rooms_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_public_rooms::v3::Request>,
|
||||
) -> Result<get_public_rooms::v3::Response> {
|
||||
if let Some(server) = &body.server {
|
||||
@@ -106,10 +103,9 @@ pub(crate) async fn get_public_rooms_route(
|
||||
/// # `PUT /_matrix/client/r0/directory/list/room/{roomId}`
|
||||
///
|
||||
/// Sets the visibility of a given room in the room directory.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "room_directory", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "room_directory", level = "info")]
|
||||
pub(crate) async fn set_room_visibility_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<set_room_visibility::v3::Request>,
|
||||
) -> Result<set_room_visibility::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, err,
|
||||
utils::{self, content_disposition::make_content_disposition, math::ruma_from_usize},
|
||||
@@ -42,15 +41,8 @@ pub(crate) async fn get_media_config_route(
|
||||
///
|
||||
/// - Some metadata will be saved in the database
|
||||
/// - Media will be saved in the media/ directory
|
||||
#[tracing::instrument(
|
||||
name = "media_upload",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client),
|
||||
)]
|
||||
pub(crate) async fn create_content_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<create_content::v3::Request>,
|
||||
) -> Result<create_content::v3::Response> {
|
||||
let user = body.identity.expect_sender_user()?;
|
||||
@@ -81,15 +73,8 @@ pub(crate) async fn create_content_route(
|
||||
/// # `GET /_matrix/client/v1/media/thumbnail/{serverName}/{mediaId}`
|
||||
///
|
||||
/// Load media thumbnail from our server or over federation.
|
||||
#[tracing::instrument(
|
||||
name = "media_thumbnail_get",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client),
|
||||
)]
|
||||
pub(crate) async fn get_content_thumbnail_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_thumbnail::v1::Request>,
|
||||
) -> Result<get_content_thumbnail::v1::Response> {
|
||||
let user = body.identity.expect_sender_user()?;
|
||||
@@ -131,15 +116,8 @@ pub(crate) async fn get_content_thumbnail_route(
|
||||
/// # `GET /_matrix/client/v1/media/download/{serverName}/{mediaId}`
|
||||
///
|
||||
/// Load media from our server or over federation.
|
||||
#[tracing::instrument(
|
||||
name = "media_get",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client),
|
||||
)]
|
||||
pub(crate) async fn get_content_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content::v1::Request>,
|
||||
) -> Result<get_content::v1::Response> {
|
||||
let user = body.identity.expect_sender_user()?;
|
||||
@@ -178,15 +156,8 @@ pub(crate) async fn get_content_route(
|
||||
/// # `GET /_matrix/client/v1/media/download/{serverName}/{mediaId}/{fileName}`
|
||||
///
|
||||
/// Load media from our server or over federation as fileName.
|
||||
#[tracing::instrument(
|
||||
name = "media_get_af",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client),
|
||||
)]
|
||||
pub(crate) async fn get_content_as_filename_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_as_filename::v1::Request>,
|
||||
) -> Result<get_content_as_filename::v1::Response> {
|
||||
let user = body.identity.expect_sender_user()?;
|
||||
@@ -229,15 +200,8 @@ pub(crate) async fn get_content_as_filename_route(
|
||||
/// # `GET /_matrix/client/v1/media/preview_url`
|
||||
///
|
||||
/// Returns URL preview.
|
||||
#[tracing::instrument(
|
||||
name = "url_preview",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client),
|
||||
)]
|
||||
pub(crate) async fn get_media_preview_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_media_preview::v1::Request>,
|
||||
) -> Result<get_media_preview::v1::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#![allow(deprecated)]
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, err,
|
||||
utils::{content_disposition::make_content_disposition, math::ruma_from_usize},
|
||||
@@ -50,10 +49,8 @@ pub(crate) async fn get_media_config_legacy_legacy_route(
|
||||
/// # `GET /_matrix/media/v3/preview_url`
|
||||
///
|
||||
/// Returns URL preview.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "url_preview_legacy", level = "debug")]
|
||||
pub(crate) async fn get_media_preview_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_media_preview::v3::Request>,
|
||||
) -> Result<get_media_preview::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -95,10 +92,9 @@ pub(crate) async fn get_media_preview_legacy_route(
|
||||
/// Returns URL preview.
|
||||
pub(crate) async fn get_media_preview_legacy_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_media_preview::v3::Request>,
|
||||
) -> Result<RumaResponse<get_media_preview::v3::Response>> {
|
||||
get_media_preview_legacy_route(State(services), ClientIp(client), body)
|
||||
get_media_preview_legacy_route(State(services), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
@@ -115,10 +111,9 @@ pub(crate) async fn get_media_preview_legacy_legacy_route(
|
||||
/// - Media will be saved in the media/ directory
|
||||
pub(crate) async fn create_content_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<create_content::v3::Request>,
|
||||
) -> Result<RumaResponse<create_content::v3::Response>> {
|
||||
create_content_route(State(services), ClientIp(client), body)
|
||||
create_content_route(State(services), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
@@ -131,10 +126,8 @@ pub(crate) async fn create_content_legacy_route(
|
||||
/// - Only redirects if `allow_redirect` is true
|
||||
/// - Uses client-provided `timeout_ms` if available, else defaults to 20
|
||||
/// seconds
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")]
|
||||
pub(crate) async fn get_content_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content::v3::Request>,
|
||||
) -> Result<get_content::v3::Response> {
|
||||
let mxc = Mxc {
|
||||
@@ -209,13 +202,11 @@ pub(crate) async fn get_content_legacy_route(
|
||||
/// - Only redirects if `allow_redirect` is true
|
||||
/// - Uses client-provided `timeout_ms` if available, else defaults to 20
|
||||
/// seconds
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")]
|
||||
pub(crate) async fn get_content_legacy_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content::v3::Request>,
|
||||
) -> Result<RumaResponse<get_content::v3::Response>> {
|
||||
get_content_legacy_route(State(services), ClientIp(client), body)
|
||||
get_content_legacy_route(State(services), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
@@ -228,10 +219,8 @@ pub(crate) async fn get_content_legacy_legacy_route(
|
||||
/// - Only redirects if `allow_redirect` is true
|
||||
/// - Uses client-provided `timeout_ms` if available, else defaults to 20
|
||||
/// seconds
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")]
|
||||
pub(crate) async fn get_content_as_filename_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_as_filename::v3::Request>,
|
||||
) -> Result<get_content_as_filename::v3::Response> {
|
||||
let mxc = Mxc {
|
||||
@@ -307,10 +296,9 @@ pub(crate) async fn get_content_as_filename_legacy_route(
|
||||
/// seconds
|
||||
pub(crate) async fn get_content_as_filename_legacy_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_as_filename::v3::Request>,
|
||||
) -> Result<RumaResponse<get_content_as_filename::v3::Response>> {
|
||||
get_content_as_filename_legacy_route(State(services), ClientIp(client), body)
|
||||
get_content_as_filename_legacy_route(State(services), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
@@ -323,10 +311,8 @@ pub(crate) async fn get_content_as_filename_legacy_legacy_route(
|
||||
/// - Only redirects if `allow_redirect` is true
|
||||
/// - Uses client-provided `timeout_ms` if available, else defaults to 20
|
||||
/// seconds
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "media_thumbnail_get_legacy", level = "debug")]
|
||||
pub(crate) async fn get_content_thumbnail_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_thumbnail::v3::Request>,
|
||||
) -> Result<get_content_thumbnail::v3::Response> {
|
||||
let mxc = Mxc {
|
||||
@@ -404,10 +390,9 @@ pub(crate) async fn get_content_thumbnail_legacy_route(
|
||||
/// seconds
|
||||
pub(crate) async fn get_content_thumbnail_legacy_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_thumbnail::v3::Request>,
|
||||
) -> Result<RumaResponse<get_content_thumbnail::v3::Response>> {
|
||||
get_content_thumbnail_legacy_route(State(services), ClientIp(client), body)
|
||||
get_content_thumbnail_legacy_route(State(services), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug_error, err, info,
|
||||
matrix::{event::gen_event_id_canonical_json, pdu::PartialPdu},
|
||||
warn,
|
||||
trace, warn,
|
||||
};
|
||||
use futures::FutureExt;
|
||||
use ruma::{
|
||||
@@ -23,10 +22,9 @@
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/invite`
|
||||
///
|
||||
/// Tries to send an invite event into the room.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "invite", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "invite", level = "info")]
|
||||
pub(crate) async fn invite_user_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<invite_user::v3::Request>,
|
||||
) -> Result<invite_user::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -42,14 +40,8 @@ pub(crate) async fn invite_user_route(
|
||||
return Err!(Request(Forbidden("Invites are not allowed on this server.")));
|
||||
}
|
||||
|
||||
banned_room_check(
|
||||
&services,
|
||||
sender_user,
|
||||
Some(&body.room_id),
|
||||
body.room_id.server_name(),
|
||||
client,
|
||||
)
|
||||
.await?;
|
||||
banned_room_check(&services, sender_user, Some(&body.room_id), body.room_id.server_name())
|
||||
.await?;
|
||||
|
||||
match &body.recipient {
|
||||
| invite_user::v3::InvitationRecipient::UserId(InviteUserId {
|
||||
@@ -166,7 +158,7 @@ pub(crate) async fn invite_helper(
|
||||
let invite_room_state = services
|
||||
.rooms
|
||||
.state
|
||||
.summary_stripped(&pdu, room_id, recipient_user)
|
||||
.summary_stripped(&pdu, room_id, recipient_user, true)
|
||||
.await;
|
||||
|
||||
drop(state_lock);
|
||||
@@ -193,6 +185,7 @@ pub(crate) async fn invite_helper(
|
||||
.await
|
||||
.ok();
|
||||
|
||||
trace!(?request, "Sending invite");
|
||||
let response = services
|
||||
.sending
|
||||
.send_federation_request(recipient_user.server_name(), request)
|
||||
@@ -221,7 +214,7 @@ pub(crate) async fn invite_helper(
|
||||
let pdu_id = services
|
||||
.rooms
|
||||
.event_handler
|
||||
.handle_incoming_pdu(recipient_user.server_name(), room_id, &event_id, value, true)
|
||||
.handle_incoming_pdu(recipient_user.server_name(), room_id, &event_id, value, false)
|
||||
.boxed()
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug,
|
||||
result::FlatOk,
|
||||
@@ -22,10 +21,9 @@
|
||||
/// rules locally
|
||||
/// - If the server does not know about the room: asks other servers over
|
||||
/// federation
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "join", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "join", level = "info")]
|
||||
pub(crate) async fn join_room_by_id_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<join_room_by_id::v3::Request>,
|
||||
) -> Result<join_room_by_id::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -33,14 +31,8 @@ pub(crate) async fn join_room_by_id_route(
|
||||
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
|
||||
}
|
||||
|
||||
banned_room_check(
|
||||
&services,
|
||||
sender_user,
|
||||
Some(&body.room_id),
|
||||
body.room_id.server_name(),
|
||||
client,
|
||||
)
|
||||
.await?;
|
||||
banned_room_check(&services, sender_user, Some(&body.room_id), body.room_id.server_name())
|
||||
.await?;
|
||||
|
||||
// There is no body.server_name for /roomId/join
|
||||
let mut servers: Vec<_> = services
|
||||
@@ -91,10 +83,9 @@ pub(crate) async fn join_room_by_id_route(
|
||||
/// - If the server does not know about the room: use the server name query
|
||||
/// param if specified. if not specified, asks other servers over federation
|
||||
/// via room alias server name and room ID server name
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "join", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "join", level = "info")]
|
||||
pub(crate) async fn join_room_by_id_or_alias_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<join_room_by_id_or_alias::v3::Request>,
|
||||
) -> Result<join_room_by_id_or_alias::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -105,15 +96,9 @@ pub(crate) async fn join_room_by_id_or_alias_route(
|
||||
|
||||
let (servers, room_id) = match OwnedRoomId::try_from(body.room_id_or_alias.clone()) {
|
||||
| Ok(room_id) => {
|
||||
banned_room_check(
|
||||
&services,
|
||||
sender_user,
|
||||
Some(&room_id),
|
||||
room_id.server_name(),
|
||||
client,
|
||||
)
|
||||
.boxed()
|
||||
.await?;
|
||||
banned_room_check(&services, sender_user, Some(&room_id), room_id.server_name())
|
||||
.boxed()
|
||||
.await?;
|
||||
|
||||
let mut servers = body.via.clone();
|
||||
if servers.is_empty() {
|
||||
@@ -159,7 +144,6 @@ pub(crate) async fn join_room_by_id_or_alias_route(
|
||||
sender_user,
|
||||
Some(&room_id),
|
||||
Some(room_alias.server_name()),
|
||||
client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::{borrow::Borrow, collections::HashMap, iter::once, sync::Arc};
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug, debug_info, debug_warn, err, info,
|
||||
matrix::{
|
||||
@@ -45,10 +44,9 @@
|
||||
/// # `POST /_matrix/client/*/knock/{roomIdOrAlias}`
|
||||
///
|
||||
/// Tries to knock the room to ask permission to join for the sender user.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "knock", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "knock", level = "info")]
|
||||
pub(crate) async fn knock_room_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<knock_room::v3::Request>,
|
||||
) -> Result<knock_room::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -59,14 +57,8 @@ pub(crate) async fn knock_room_route(
|
||||
|
||||
let (servers, room_id) = match OwnedRoomId::try_from(body.room_id_or_alias.clone()) {
|
||||
| Ok(room_id) => {
|
||||
banned_room_check(
|
||||
&services,
|
||||
sender_user,
|
||||
Some(&room_id),
|
||||
room_id.server_name(),
|
||||
client,
|
||||
)
|
||||
.await?;
|
||||
banned_room_check(&services, sender_user, Some(&room_id), room_id.server_name())
|
||||
.await?;
|
||||
|
||||
let mut servers = body.via.clone();
|
||||
servers.extend(
|
||||
@@ -109,7 +101,6 @@ pub(crate) async fn knock_room_route(
|
||||
sender_user,
|
||||
Some(&room_id),
|
||||
Some(room_alias.server_name()),
|
||||
client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
mod members;
|
||||
mod unban;
|
||||
|
||||
use std::net::IpAddr;
|
||||
|
||||
use axum::extract::State;
|
||||
use conduwuit::{Err, Result, warn};
|
||||
use futures::{FutureExt, StreamExt};
|
||||
@@ -58,7 +56,6 @@ pub(crate) async fn banned_room_check(
|
||||
user_id: &UserId,
|
||||
room_id: Option<&RoomId>,
|
||||
server_name: Option<&ServerName>,
|
||||
client_ip: IpAddr,
|
||||
) -> Result {
|
||||
if services.users.is_admin(user_id).await {
|
||||
return Ok(());
|
||||
@@ -85,7 +82,7 @@ pub(crate) async fn banned_room_check(
|
||||
.admin
|
||||
.send_text(&format!(
|
||||
"Automatically deactivating user {user_id} due to attempted banned \
|
||||
room join from IP {client_ip}"
|
||||
room join"
|
||||
))
|
||||
.await;
|
||||
}
|
||||
@@ -121,7 +118,7 @@ pub(crate) async fn banned_room_check(
|
||||
.admin
|
||||
.send_text(&format!(
|
||||
"Automatically deactivating user {user_id} due to attempted banned \
|
||||
room join from IP {client_ip}"
|
||||
room join"
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Error, Result, at, debug_warn,
|
||||
matrix::{
|
||||
@@ -38,7 +37,7 @@
|
||||
};
|
||||
use ruminuwuity::invite_permission_config::FilterLevel;
|
||||
|
||||
use crate::Ruma;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
|
||||
/// list of safe and common non-state events to ignore if the user is ignored
|
||||
const IGNORED_MESSAGE_TYPES: &[TimelineEventType] = &[
|
||||
@@ -72,7 +71,7 @@
|
||||
/// where the user was joined, depending on `history_visibility`)
|
||||
pub(crate) async fn get_message_events_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client_ip): ClientIp,
|
||||
ClientIp(client_ip): ClientIp, // NOTE: Required for updating device metadata
|
||||
body: Ruma<get_message_events::v3::Request>,
|
||||
) -> Result<get_message_events::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -90,8 +90,5 @@
|
||||
pub(super) use voip::*;
|
||||
pub(super) use well_known::*;
|
||||
|
||||
/// generated device ID length
|
||||
const DEVICE_ID_LENGTH: usize = 10;
|
||||
|
||||
/// generated user access token length
|
||||
const TOKEN_LENGTH: usize = 32;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use axum::extract::State;
|
||||
use conduwuit::{Err, Result};
|
||||
use futures::StreamExt;
|
||||
use ruma::api::client::membership::mutual_rooms;
|
||||
use ruma::{OwnedRoomId, api::client::membership::mutual_rooms};
|
||||
|
||||
use crate::Ruma;
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
///
|
||||
/// An implementation of [MSC2666](https://github.com/matrix-org/matrix-spec-proposals/pull/2666)
|
||||
#[tracing::instrument(skip_all, name = "mutual_rooms", level = "info")]
|
||||
pub(crate) async fn get_mutual_rooms_route(
|
||||
pub(crate) async fn get_mutual_rooms_unstable_route(
|
||||
State(services): State<crate::State>,
|
||||
body: Ruma<mutual_rooms::unstable::Request>,
|
||||
) -> Result<mutual_rooms::unstable::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
if sender_user == body.user_id {
|
||||
return Err!(Request(Unknown("You cannot request rooms in common with yourself.")));
|
||||
return Err!(Request(InvalidParam("You cannot request rooms in common with yourself.")));
|
||||
}
|
||||
|
||||
let mutual_rooms = services
|
||||
@@ -30,3 +30,33 @@ pub(crate) async fn get_mutual_rooms_route(
|
||||
|
||||
Ok(mutual_rooms::unstable::Response::new(mutual_rooms))
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/v1/mutual_rooms`
|
||||
///
|
||||
/// Gets all the rooms the sender shares with the specified user.
|
||||
#[tracing::instrument(skip_all, name = "mutual_rooms", level = "info")]
|
||||
pub(crate) async fn get_mutual_rooms_route(
|
||||
State(services): State<crate::State>,
|
||||
body: Ruma<mutual_rooms::v1::Request>,
|
||||
) -> Result<mutual_rooms::v1::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
if sender_user == body.user_id {
|
||||
return Err!(Request(InvalidParam("You cannot request rooms in common with yourself.")));
|
||||
}
|
||||
|
||||
let mutual_rooms: Vec<OwnedRoomId> = services
|
||||
.rooms
|
||||
.state_cache
|
||||
.get_shared_rooms(sender_user, &body.user_id)
|
||||
.collect()
|
||||
.await;
|
||||
|
||||
Ok(mutual_rooms::v1::Response::new(
|
||||
mutual_rooms
|
||||
.len()
|
||||
.try_into()
|
||||
.expect("user should be in fewer than 9.1 quadrillion rooms"),
|
||||
mutual_rooms,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
use axum::{Form, Json, extract::State, response::IntoResponse};
|
||||
use http::StatusCode;
|
||||
use service::oauth::grant::DeviceCodeRequest;
|
||||
|
||||
pub(crate) async fn device_authorization_route(
|
||||
State(services): State<crate::State>,
|
||||
Form(request): Form<DeviceCodeRequest>,
|
||||
) -> impl IntoResponse {
|
||||
match services.oauth.request_device_code(request).await {
|
||||
| Ok(response) => Ok(Json(response)),
|
||||
| Err(err) => Err((StatusCode::BAD_REQUEST, Json(err))),
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
use serde_json::json;
|
||||
pub(crate) use server_metadata::*;
|
||||
|
||||
mod device;
|
||||
mod register_client;
|
||||
mod server_metadata;
|
||||
mod token;
|
||||
@@ -20,6 +21,7 @@
|
||||
const CLIENT_REGISTER_PATH: &str = "client/register";
|
||||
const TOKEN_REVOKE_PATH: &str = "client/revoke";
|
||||
const TOKEN_PATH: &str = "grant/token";
|
||||
const DEVICE_AUTHORIZATION_PATH: &str = "device";
|
||||
const ACCOUNT_MANAGEMENT_PATH: &str = concat!(conduwuit_core::ROUTE_PREFIX, "/account/deeplink");
|
||||
|
||||
pub(crate) fn router(state: crate::State) -> Router<crate::State> {
|
||||
@@ -53,4 +55,5 @@ fn oauth_router() -> Router<crate::State> {
|
||||
.route(concat!("/", JWKS_URI_PATH), get(async || Json(json!({"keys": []}))))
|
||||
.route(concat!("/", TOKEN_PATH), post(token::token_route))
|
||||
.route(concat!("/", TOKEN_REVOKE_PATH), post(token::revoke_token_route))
|
||||
.route(concat!("/", DEVICE_AUTHORIZATION_PATH), post(device::device_authorization_route))
|
||||
}
|
||||
|
||||
@@ -24,5 +24,5 @@ pub(crate) async fn register_client_route(
|
||||
.await
|
||||
.map_err(|err| (StatusCode::BAD_REQUEST, Json(err)).into_response())?;
|
||||
|
||||
Ok(Json(RegisteredClient { client_id, metadata }).into_response())
|
||||
Ok((StatusCode::CREATED, Json(RegisteredClient { client_id, metadata })).into_response())
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
use crate::{
|
||||
Ruma,
|
||||
client::oauth::{
|
||||
ACCOUNT_MANAGEMENT_PATH, AUTH_CODE_PATH, CLIENT_REGISTER_PATH, JWKS_URI_PATH, TOKEN_PATH,
|
||||
TOKEN_REVOKE_PATH,
|
||||
ACCOUNT_MANAGEMENT_PATH, AUTH_CODE_PATH, CLIENT_REGISTER_PATH, DEVICE_AUTHORIZATION_PATH,
|
||||
JWKS_URI_PATH, TOKEN_PATH, TOKEN_REVOKE_PATH,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -37,6 +37,17 @@ pub(crate) async fn authorization_server_metadata(services: &Services) -> Value
|
||||
.join(super::BASE_PATH)
|
||||
.unwrap();
|
||||
|
||||
let prompt_values_supported = if services
|
||||
.uiaa
|
||||
.registration_flow_status()
|
||||
.await
|
||||
.any_available()
|
||||
{
|
||||
json!(["create"])
|
||||
} else {
|
||||
json!([])
|
||||
};
|
||||
|
||||
json!({
|
||||
"account_management_uri": endpoint_base.join(ACCOUNT_MANAGEMENT_PATH).unwrap(),
|
||||
"account_management_actions_supported": [
|
||||
@@ -49,10 +60,11 @@ pub(crate) async fn authorization_server_metadata(services: &Services) -> Value
|
||||
],
|
||||
"authorization_endpoint": endpoint_base.join(AUTH_CODE_PATH).unwrap(),
|
||||
"code_challenge_methods_supported": ["S256"],
|
||||
"grant_types_supported": ["authorization_code", "refresh_token"],
|
||||
"device_authorization_endpoint": endpoint_base.join(DEVICE_AUTHORIZATION_PATH).unwrap(),
|
||||
"grant_types_supported": ["authorization_code", "refresh_token", "urn:ietf:params:oauth:grant-type:device_code"],
|
||||
"issuer": services.config.get_client_domain(),
|
||||
"jwks_uri": endpoint_base.join(JWKS_URI_PATH).unwrap(),
|
||||
"prompt_values_supported": ["create"],
|
||||
"prompt_values_supported": prompt_values_supported,
|
||||
"registration_endpoint": endpoint_base.join(CLIENT_REGISTER_PATH).unwrap(),
|
||||
"response_modes_supported": ["query", "fragment"],
|
||||
"response_types_supported": ["code"],
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, PduCount, Result, err};
|
||||
use ruma::{
|
||||
MilliSecondsSinceUnixEpoch,
|
||||
@@ -13,7 +12,7 @@
|
||||
},
|
||||
};
|
||||
|
||||
use crate::Ruma;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/read_markers`
|
||||
///
|
||||
@@ -117,7 +116,7 @@ pub(crate) async fn set_read_marker_route(
|
||||
/// Sets private read marker and public read receipt EDU.
|
||||
pub(crate) async fn create_receipt_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client_ip): ClientIp,
|
||||
ClientIp(client_ip): ClientIp, // NOTE: Required for updating device metadata
|
||||
body: Ruma<create_receipt::v3::Request>,
|
||||
) -> Result<create_receipt::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, matrix::pdu::PartialPdu};
|
||||
use ruma::{
|
||||
api::client::redact::redact_event, assign, events::room::redaction::RoomRedactionEventContent,
|
||||
};
|
||||
|
||||
use crate::Ruma;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
|
||||
/// # `PUT /_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}`
|
||||
///
|
||||
@@ -14,7 +13,7 @@
|
||||
/// - TODO: Handle txn id
|
||||
pub(crate) async fn redact_event_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client_ip): ClientIp,
|
||||
ClientIp(client_ip): ClientIp, // NOTE: required for updating device metadata
|
||||
body: Ruma<redact_event::v3::Request>,
|
||||
) -> Result<redact_event::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::{fmt::Write as _, time::Duration};
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Event, Result, debug_info, info, matrix::pdu::PduEvent, utils::ReadyExt};
|
||||
use conduwuit_service::Services;
|
||||
use ruma::{
|
||||
@@ -30,10 +29,9 @@ struct Report {
|
||||
/// # `POST /_matrix/client/v3/rooms/{roomId}/report`
|
||||
///
|
||||
/// Reports an abusive room to homeserver admins
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_room", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "report_room", level = "info")]
|
||||
pub(crate) async fn report_room_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<report_room::v3::Request>,
|
||||
) -> Result<report_room::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -85,10 +83,9 @@ pub(crate) async fn report_room_route(
|
||||
/// # `POST /_matrix/client/v3/rooms/{roomId}/report/{eventId}`
|
||||
///
|
||||
/// Reports an inappropriate event to homeserver admins
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_event", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "report_event", level = "info")]
|
||||
pub(crate) async fn report_event_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<report_content::v3::Request>,
|
||||
) -> Result<report_content::v3::Response> {
|
||||
// user authentication
|
||||
@@ -129,10 +126,9 @@ pub(crate) async fn report_event_route(
|
||||
Ok(report_content::v3::Response::new())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_user", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "report_user", level = "info")]
|
||||
pub(crate) async fn report_user_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<report_user::v3::Request>,
|
||||
) -> Result<report_user::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use axum::extract::State;
|
||||
use conduwuit::{
|
||||
Err, Result, debug, debug_info, err, info,
|
||||
Err, Error, Result, debug, debug_info, err, info,
|
||||
matrix::{StateKey, pdu::PartialPdu},
|
||||
trace, warn,
|
||||
};
|
||||
@@ -11,10 +11,13 @@
|
||||
use ruma::{
|
||||
CanonicalJsonObject, CanonicalJsonValue, Int, MilliSecondsSinceUnixEpoch, OwnedRoomAliasId,
|
||||
OwnedUserId, RoomAliasId, RoomId, RoomVersionId, UserId,
|
||||
api::client::room::{self, create_room},
|
||||
api::{
|
||||
client::room::{self, create_room},
|
||||
error::ErrorKind::Forbidden,
|
||||
},
|
||||
assign,
|
||||
events::{
|
||||
TimelineEventType,
|
||||
AnyStateEventContent, StateEventType, TimelineEventType,
|
||||
room::{
|
||||
canonical_alias::RoomCanonicalAliasEventContent,
|
||||
create::RoomCreateEventContent,
|
||||
@@ -512,30 +515,42 @@ pub(crate) async fn create_room_route(
|
||||
|
||||
// 7. Events listed in initial_state
|
||||
for event in &body.initial_state {
|
||||
let mut partial_pdu = event
|
||||
.deserialize_as_unchecked::<PartialPdu>()
|
||||
.map_err(|e| {
|
||||
err!(Request(InvalidParam(warn!("Invalid initial state event: {e:?}"))))
|
||||
let event_type: StateEventType = event.get_field("type")?.ok_or_else(|| {
|
||||
err!(Request(InvalidParam(warn!(
|
||||
r#"Invalid initial state event: missing "type" field "#
|
||||
))))
|
||||
})?;
|
||||
|
||||
let content: Raw<AnyStateEventContent> =
|
||||
event.get_field("content")?.ok_or_else(|| {
|
||||
err!(Request(InvalidParam(warn!(
|
||||
r#"Invalid initial state event: missing "content" field "#
|
||||
))))
|
||||
})?;
|
||||
|
||||
debug_info!("Room creation initial state event: {event:?}");
|
||||
let state_key: String = event.get_field("state_key")?.unwrap_or_default();
|
||||
|
||||
// Implicit state key defaults to ""
|
||||
partial_pdu.state_key.get_or_insert_with(StateKey::new);
|
||||
|
||||
// Silently skip encryption events if they are not allowed
|
||||
if partial_pdu.event_type == TimelineEventType::RoomEncryption
|
||||
&& !services.config.allow_encryption
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
services
|
||||
match services
|
||||
.rooms
|
||||
.timeline
|
||||
.build_and_append_pdu(partial_pdu, sender_user, Some(&room_id), &state_lock)
|
||||
.send_state_event_for_key(
|
||||
sender_user,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
&event_type,
|
||||
&content,
|
||||
&state_key,
|
||||
None,
|
||||
)
|
||||
.boxed()
|
||||
.await?;
|
||||
.await
|
||||
{
|
||||
| Err(Error::Request(Forbidden, ..)) => {
|
||||
// Silently skip forbidden events
|
||||
continue;
|
||||
},
|
||||
| r => r,
|
||||
}?;
|
||||
}
|
||||
|
||||
// 8. Events implied by name and topic
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result};
|
||||
use ruma::api::client::room::get_summary;
|
||||
use service::rooms::summary::Accessibility;
|
||||
@@ -9,10 +8,9 @@
|
||||
/// # `GET /_matrix/client/v1/room_summary/{roomIdOrAlias}`
|
||||
///
|
||||
/// Returns a short description of the state of a room.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "room_summary", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "room_summary", level = "info")]
|
||||
pub(crate) async fn get_room_summary(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_summary::v1::Request>,
|
||||
) -> Result<get_summary::v1::Response> {
|
||||
let (room_id, servers) = services
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, err, matrix::pdu::PartialPdu, utils};
|
||||
use ruma::{api::client::message::send_message_event, events::MessageLikeEventType};
|
||||
use serde_json::from_str;
|
||||
|
||||
use crate::Ruma;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
|
||||
/// # `PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`
|
||||
///
|
||||
@@ -19,7 +18,7 @@
|
||||
/// allowed
|
||||
pub(crate) async fn send_message_event_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client_ip): ClientIp,
|
||||
ClientIp(client_ip): ClientIp, // NOTE: required for updating device metadata
|
||||
body: Ruma<send_message_event::v3::Request>,
|
||||
) -> Result<send_message_event::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
+24
-34
@@ -1,10 +1,9 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug, err, info,
|
||||
utils::{self, ReadyExt, stream::BroadbandExt},
|
||||
utils::{ReadyExt, stream::BroadbandExt},
|
||||
warn,
|
||||
};
|
||||
use conduwuit_service::Services;
|
||||
@@ -29,18 +28,17 @@
|
||||
},
|
||||
assign,
|
||||
};
|
||||
use service::users::DeviceToken;
|
||||
|
||||
use super::{DEVICE_ID_LENGTH, TOKEN_LENGTH};
|
||||
use crate::Ruma;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
|
||||
/// # `GET /_matrix/client/v3/login`
|
||||
///
|
||||
/// Get the supported login types of this server. One of these should be used as
|
||||
/// the `type` field when logging in.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "login", level = "info")]
|
||||
pub(crate) async fn get_login_types_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
_body: Ruma<get_login_types::v3::Request>,
|
||||
) -> Result<get_login_types::v3::Response> {
|
||||
if !services.config.oauth.compatibility_mode().uiaa_available() {
|
||||
@@ -114,10 +112,10 @@ pub async fn handle_login(
|
||||
/// Note: You can use [`GET
|
||||
/// /_matrix/client/r0/login`](fn.get_supported_versions_route.html) to see
|
||||
/// supported login types.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "login", level = "info")]
|
||||
pub(crate) async fn login_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
ClientIp(client): ClientIp, // NOTE: Required for device metadata
|
||||
body: Ruma<login::v3::Request>,
|
||||
) -> Result<login::v3::Response> {
|
||||
if !services.config.oauth.compatibility_mode().uiaa_available() {
|
||||
@@ -190,44 +188,39 @@ pub(crate) async fn login_route(
|
||||
},
|
||||
};
|
||||
|
||||
// Generate new device id if the user didn't specify one
|
||||
let device_id = body
|
||||
.device_id
|
||||
.clone()
|
||||
.unwrap_or_else(|| utils::random_string(DEVICE_ID_LENGTH).into());
|
||||
|
||||
// Generate a new token for the device (ensuring no collisions)
|
||||
let token = services.users.generate_unique_token().await;
|
||||
// Generate a new token for the device
|
||||
let token = DeviceToken::new_random();
|
||||
|
||||
// Determine if device_id was provided and exists in the db for this user
|
||||
let device_exists = if body.device_id.is_some() {
|
||||
let existing_device_id = if let Some(device_id) = &body.device_id {
|
||||
services
|
||||
.users
|
||||
.all_device_ids(&user_id)
|
||||
.ready_any(|v| v == device_id)
|
||||
.ready_find(|v| v == device_id)
|
||||
.await
|
||||
} else {
|
||||
false
|
||||
None
|
||||
};
|
||||
|
||||
if device_exists {
|
||||
let device_id = if let Some(existing_device_id) = existing_device_id {
|
||||
services
|
||||
.users
|
||||
.set_token(&user_id, &device_id, &token, None)
|
||||
.set_token(&user_id, &existing_device_id, token.clone())
|
||||
.await?;
|
||||
|
||||
existing_device_id
|
||||
} else {
|
||||
services
|
||||
.users
|
||||
.create_device(
|
||||
&user_id,
|
||||
&device_id,
|
||||
&token,
|
||||
None,
|
||||
body.device_id.clone(),
|
||||
Some(token.clone()),
|
||||
body.initial_device_display_name.clone(),
|
||||
Some(client.to_string()),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
.await?
|
||||
};
|
||||
|
||||
// send client well-known if specified so the client knows to reconfigure itself
|
||||
let client_discovery_info: Option<DiscoveryInfo> = services
|
||||
@@ -241,7 +234,7 @@ pub(crate) async fn login_route(
|
||||
info!("{user_id} logged in");
|
||||
|
||||
#[allow(deprecated)]
|
||||
Ok(assign!(login::v3::Response::new(user_id, token, device_id), {
|
||||
Ok(assign!(login::v3::Response::new(user_id, token.into_token(), device_id), {
|
||||
well_known: client_discovery_info,
|
||||
expires_in: None,
|
||||
home_server: Some(services.config.server_name.clone()),
|
||||
@@ -255,10 +248,9 @@ pub(crate) async fn login_route(
|
||||
/// to log in with the m.login.token flow.
|
||||
///
|
||||
/// <https://spec.matrix.org/v1.13/client-server-api/#post_matrixclientv1loginget_token>
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login_token", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "login_token", level = "info")]
|
||||
pub(crate) async fn login_token_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_login_token::v1::Request>,
|
||||
) -> Result<get_login_token::v1::Response> {
|
||||
if !services.config.login_via_existing_session {
|
||||
@@ -273,7 +265,7 @@ pub(crate) async fn login_token_route(
|
||||
.authenticate_password(&body.auth, sender_user, body.identity.sender_device(), None)
|
||||
.await?;
|
||||
|
||||
let login_token = utils::random_string(TOKEN_LENGTH);
|
||||
let login_token = DeviceToken::new_random().into_token();
|
||||
let expires_in = services.users.create_login_token(sender_user, &login_token);
|
||||
|
||||
Ok(get_login_token::v1::Response::new(
|
||||
@@ -291,10 +283,9 @@ pub(crate) async fn login_token_route(
|
||||
/// last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "logout", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "logout", level = "info")]
|
||||
pub(crate) async fn logout_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<logout::v3::Request>,
|
||||
) -> Result<logout::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -339,10 +330,9 @@ pub(crate) async fn logout_route(
|
||||
/// Note: This is equivalent to calling [`GET
|
||||
/// /_matrix/client/r0/logout`](fn.logout_route.html) from each device of this
|
||||
/// user.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "logout", level = "info")]
|
||||
#[tracing::instrument(skip_all, name = "logout", level = "info")]
|
||||
pub(crate) async fn logout_all_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<logout_all::v3::Request>,
|
||||
) -> Result<logout_all::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -19,9 +19,10 @@ pub(crate) async fn get_hierarchy_route(
|
||||
// there's no reasonable way to handle a space hierarchy changing during
|
||||
// pagination.
|
||||
|
||||
let max_depth = body
|
||||
.max_depth
|
||||
.map(|max_depth| max_depth.min(UInt::from(MAX_MAX_DEPTH)));
|
||||
// Default to MAX_MAX_DEPTH when the client doesn't specify one, so an
|
||||
// unbounded traversal can never happen.
|
||||
let max_max_depth = UInt::from(MAX_MAX_DEPTH);
|
||||
let max_depth = Some(body.max_depth.unwrap_or(max_max_depth).min(max_max_depth));
|
||||
|
||||
let hierarchy = services
|
||||
.rooms
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user