Compare commits

...

49 Commits

Author SHA1 Message Date
Ginger e3a9549824 fix: Correctly sync newly created rooms 2026-06-16 23:41:51 -04:00
Ginger 073c033ab8 fix: Don't panic on missing SSH in sliding sync 2026-06-16 23:41:51 -04:00
Ginger 6e42be95bc fix: Additional sync logic fixes 2026-06-16 23:41:51 -04:00
Ginger 1a77f57af5 fix: Upgrade warning on room load failures to error 2026-06-16 23:41:51 -04:00
Ginger d427df0238 fix: Don't panic on missing SSH 2026-06-16 23:41:51 -04:00
Ginger f9f3ebe571 fix: Calculate state at end of last sync correctly 2026-06-16 23:41:51 -04:00
Ginger 5969c1ae94 chore: News fragments 2026-06-16 23:41:51 -04:00
Ginger 523016a42b feat: Add support for state_after 2026-06-16 23:41:51 -04:00
Ginger 7c42f6075b feat: Remove all uses of roomsynctoken_shortstatehash 2026-06-16 23:41:51 -04:00
Renovate Bot bc37f7fc5b chore(deps): update rust crate serde-saphyr to 0.0.27 2026-06-16 18:29:02 +00:00
Ginger 0932c929c3 chore: Clippy fixes >:( 2026-06-16 12:36:24 -04:00
Ginger 8f4e95b4b9 fix: Fix compile errors caused by hickory upgrade 2026-06-16 12:19:37 -04:00
Renovate Bot e84d1f02af chore(deps): lock file maintenance 2026-06-16 12:57:54 +00:00
Renovate Bot 772a326ac1 chore(deps): update hickory-dns monorepo to 0.26.0 2026-06-16 12:51:12 +00:00
Renovate Bot 6276a632cc chore(deps): update github-actions-digest 2026-06-16 05:02:02 +00:00
ginger bb48bd50bb chore: Prek fixes 2026-06-15 16:59:57 +00:00
Cease 3fb7586875 docs: remove network tags from config and improve clarity on comments 2026-06-15 16:59:57 +00:00
Cease e8cfde49ae docs: additional livekit caddy-docker-proxy cleanup 2026-06-15 16:59:57 +00:00
Cease 7af4b392b3 docs: clean up caddy-docker-proxy section as requested 2026-06-15 16:59:57 +00:00
Cease 2bdc498f18 docs: add example caddy-docker-proxy configuration 2026-06-15 16:59:57 +00:00
Renovate Bot 9dfd143cc6 chore(deps): update dependency cargo-bins/cargo-binstall to v1.20.0 2026-06-15 13:01:48 +00:00
Renovate Bot 721ebbf340 chore(deps): update rust-non-major 2026-06-15 13:01:35 +00:00
Renovate Bot 0a5d136a32 chore(deps): update github-actions-non-major to v43.222.1 2026-06-15 05:03:07 +00:00
Jonathan Bouligny 0ece17b6a0 fix: Trim whitespace in is_admin_command
Lets users run commands even with a space before the !admin prefix.
2026-06-11 15:20:34 +00:00
Renovate Bot 7d945bbd5d chore(deps): update rust-zerover-patch-updates 2026-06-08 13:31:37 +00:00
Renovate Bot 42039b2090 chore(deps): update rust crate serde_regex to v1.2.0 2026-06-08 13:31:07 +00:00
Renovate Bot dd7ca6b12e chore(deps): update node-patch-updates to v2.0.14 2026-06-08 05:09:52 +00:00
Renovate Bot b1c6be012a chore(deps): update ghcr.io/renovatebot/renovate docker tag to v43.214.6 2026-06-08 05:03:29 +00:00
Renovate Bot 835308628e chore(deps): update pre-commit hook crate-ci/typos to v1.47.2 2026-06-04 05:03:57 +00:00
renovate c1486f425e chore(Nix): Updated flake hashes 2026-06-03 03:15:35 +00:00
Renovate Bot c80896dcb0 chore(deps): update rust to v1.96.0 2026-06-03 03:15:35 +00:00
Renovate Bot 77b12692bb chore(deps): update rust-non-major 2026-06-03 03:12:24 +00:00
Renovate Bot 57237e831a chore(deps): update rust-zerover-patch-updates 2026-06-03 03:11:53 +00:00
nex d62c48ebf7 chore: Update GitHub username in FUNDING.yml 2026-06-02 18:28:09 +00:00
timedout e2e85b962a style: Resolve lint failure 2026-06-02 16:35:32 +01:00
Helix K 788697d563 chore: News fragment 2026-06-02 16:35:32 +01:00
Helix K 64ecd762be chore: Remove MSC4373 support 2026-06-02 16:35:31 +01:00
Renovate Bot 5cb0db6f31 chore(deps): update github-actions-digest 2026-06-02 05:03:05 +00:00
Henry-Hiles 58e41d48c7 fix: grammar in delete all media command not found error 2026-06-01 13:40:44 -04:00
Renovate Bot 67466b015b chore(deps): update ghcr.io/renovatebot/renovate docker tag to v43.205.3 2026-06-01 05:03:05 +00:00
Renovate Bot 0ea68f27a2 chore(deps): update pre-commit hook crate-ci/typos to v1.47.0 2026-05-29 05:06:07 +00:00
Ginger a3e57dbab4 fix: Add unstable feature flag 2026-05-28 20:14:22 +00:00
Ginger 7ece15bb1a chore: News fragment 2026-05-28 20:14:22 +00:00
Ginger 336b32dead feat: Add support for MSC4466 2026-05-28 20:14:22 +00:00
timedout 1faa09b6ce fix: Don't ping presence for devices which claim to be offline
Fixes https://github.com/gomuks/gomuks/issues/722.

Reviewed-by: Ginger <ginger@gingershaped.computer>
2026-05-28 09:38:32 -04:00
Ginger d7a51c7107 refactor: Allow for client identities with no user ID 2026-05-27 12:15:16 -04:00
Ginger 30c9d6d2df chore: Clippy fixes 2026-05-26 18:26:02 +00:00
Ginger 74841b6711 refactor: Represent route auth information in the type system 2026-05-26 18:26:02 +00:00
timedout dabbdc7517 fix: Don't be so aggressive when validating policy server signatures 2026-05-26 16:16:48 +01:00
121 changed files with 1459 additions and 1273 deletions
@@ -75,7 +75,7 @@ runs:
- name: Set up QEMU
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4
- name: Login to builtin registry
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
+1 -1
View File
@@ -71,7 +71,7 @@ runs:
- name: Install timelord-cli and git-warp-time
if: steps.check-binaries.outputs.need-install == 'true'
uses: https://github.com/taiki-e/install-action@920ab1831fbf4fb3ef75c8ead83556c918bb7290 # v2
uses: https://github.com/taiki-e/install-action@15449e3094499af05d8d964a1c884208e4b8b595 # v2
with:
tool: git-warp-time,timelord-cli@3.0.1
+1 -1
View File
@@ -54,7 +54,7 @@ jobs:
fi
- name: Checkout repository with full history
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 0
ref: ${{ github.ref_name }}
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
echo "Fedora version: $VERSION"
- name: Checkout repository with full history
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 0
ref: ${{ github.ref_name }}
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Sync repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
fetch-depth: 0
+2 -2
View File
@@ -41,7 +41,7 @@ jobs:
DOCKER_MIRROR_TOKEN: ${{ secrets.DOCKER_MIRROR_TOKEN }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
@@ -55,7 +55,7 @@ jobs:
# repositories: continuwuity
- name: Install regsync
uses: https://github.com/regclient/actions/regsync-installer@c70ad64367908075211b10dcd2ab9fad4bfa1816 # main
uses: https://github.com/regclient/actions/regsync-installer@14f9d37db17b5dc41fefd1ffdd1af4b9e2490560 # main
- name: Check what images need mirroring
run: |
+3 -3
View File
@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
@@ -48,7 +48,7 @@ jobs:
rust: ${{ steps.filter.outputs.rust }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
@@ -70,7 +70,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
+4 -4
View File
@@ -46,7 +46,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
- name: Prepare Docker build environment
@@ -100,7 +100,7 @@ jobs:
needs: build-release
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
- name: Create multi-platform manifest
@@ -133,7 +133,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
- name: Prepare max-perf Docker build environment
@@ -187,7 +187,7 @@ jobs:
needs: build-maxperf
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
- name: Create max-perf manifest
+2 -2
View File
@@ -43,11 +43,11 @@ jobs:
name: Renovate
runs-on: ubuntu-latest
container:
image: ghcr.io/renovatebot/renovate:43.195.3@sha256:868dffc3d6a46f42dfefe48b6978cc063d8df9c1d58a93a694c8989afa503e34
image: ghcr.io/renovatebot/renovate:43.222.1@sha256:b9af3f59f3f4d92b2c41e9f4ca3ffe92400503f20158d0bd67d07a3fdbe781d2
options: --tmpfs /tmp:exec
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
show-progress: false
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
update-flake-hashes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: true
token: ${{ secrets.FORGEJO_TOKEN }}
+1 -1
View File
@@ -1,4 +1,4 @@
github: [JadedBlueEyes, nexy7574, gingershaped]
github: [JadedBlueEyes, timedoutuk, gingershaped]
custom:
- https://timedout.uk/donate.html
- https://jade.ellis.link/sponsors
+1 -1
View File
@@ -24,7 +24,7 @@ repos:
- id: check-added-large-files
- repo: https://github.com/crate-ci/typos
rev: v1.46.2
rev: v1.47.2
hooks:
- id: typos
- id: typos
Generated
+223 -159
View File
@@ -47,9 +47,9 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
[[package]]
name = "alloc-stdlib"
version = "0.2.2"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195"
dependencies = [
"alloc-no-stdlib",
]
@@ -461,15 +461,15 @@ dependencies = [
"quote",
"regex",
"rustc-hash",
"shlex",
"shlex 1.3.0",
"syn",
]
[[package]]
name = "bitflags"
version = "2.11.1"
version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
[[package]]
name = "blake2"
@@ -491,9 +491,9 @@ dependencies = [
[[package]]
name = "block-buffer"
version = "0.12.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be"
checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
dependencies = [
"hybrid-array",
]
@@ -509,9 +509,9 @@ dependencies = [
[[package]]
name = "brotli"
version = "8.0.2"
version = "8.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560"
checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -520,9 +520,9 @@ dependencies = [
[[package]]
name = "brotli-decompressor"
version = "5.0.0"
version = "5.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -566,9 +566,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "bytesize"
version = "2.3.1"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3"
checksum = "49e78e506b9d7633710dab98996f22f95f3d0f488e8f1aa162830556ed9fc14d"
[[package]]
name = "bzip2-sys"
@@ -625,14 +625,14 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.62"
version = "1.2.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f"
dependencies = [
"find-msvc-tools",
"jobserver",
"libc",
"shlex",
"shlex 2.0.1",
]
[[package]]
@@ -678,9 +678,9 @@ dependencies = [
[[package]]
name = "chrono"
version = "0.4.44"
version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
dependencies = [
"num-traits",
]
@@ -754,9 +754,9 @@ dependencies = [
[[package]]
name = "cmov"
version = "0.5.3"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746"
checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
[[package]]
name = "color_quant"
@@ -827,7 +827,7 @@ dependencies = [
"opentelemetry-otlp",
"opentelemetry_sdk",
"parking_lot",
"reqwest 0.13.3",
"reqwest 0.13.4",
"rustls",
"sentry",
"sentry-tower",
@@ -893,7 +893,7 @@ dependencies = [
"lettre",
"log",
"rand 0.10.1",
"reqwest 0.13.3",
"reqwest 0.13.4",
"ruma",
"ruminuwuity",
"serde",
@@ -955,7 +955,7 @@ dependencies = [
"rand 0.10.1",
"rand_core 0.6.4",
"regex",
"reqwest 0.13.3",
"reqwest 0.13.4",
"ruma",
"sanitize-filename",
"serde",
@@ -1080,7 +1080,7 @@ dependencies = [
"recaptcha-verify",
"regex",
"reqwest 0.12.28",
"reqwest 0.13.3",
"reqwest 0.13.4",
"ruma",
"ruminuwuity",
"rustyline-async",
@@ -1212,6 +1212,16 @@ dependencies = [
"crossterm",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation"
version = "0.10.1"
@@ -1402,9 +1412,9 @@ dependencies = [
[[package]]
name = "ctor"
version = "1.0.6"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d765eb1c0bda10d31e0ea185f5ee15da532d60b0912d2bd1441783439e749c5"
checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a"
dependencies = [
"link-section",
"linktime-proc-macro",
@@ -1524,9 +1534,6 @@ name = "deranged"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
dependencies = [
"powerfmt",
]
[[package]]
name = "derive_more"
@@ -1567,7 +1574,7 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
dependencies = [
"block-buffer 0.12.0",
"block-buffer 0.12.1",
"crypto-common 0.2.2",
"ctutils",
]
@@ -1584,9 +1591,9 @@ dependencies = [
[[package]]
name = "displaydoc"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [
"proc-macro2",
"quote",
@@ -1604,9 +1611,9 @@ dependencies = [
[[package]]
name = "dtor"
version = "1.0.3"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2137ce22f50d4c43ce098daf41c904cc700de1ce8bc2daf53ed4e702180a464"
checksum = "6d738e43aa64edab57c983d56de890d65fea7dc05605490c74451ce721dfd84b"
dependencies = [
"linktime-proc-macro",
]
@@ -1684,18 +1691,6 @@ dependencies = [
"encoding_rs",
]
[[package]]
name = "enum-as-inner"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "equivalent"
version = "1.0.2"
@@ -2041,9 +2036,9 @@ dependencies = [
[[package]]
name = "granit-parser"
version = "0.0.2"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e736dfe3881c53a7dce0685eb18202d0d9fe6911782f9870946eb9ee89d778"
checksum = "f50ba32164f9e098d5da618776a32afbb32270adcbe3d3d006107dae11e37c91"
dependencies = [
"arraydeque",
"smallvec",
@@ -2051,9 +2046,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.4.14"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733"
checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155"
dependencies = [
"atomic-waker",
"bytes",
@@ -2184,24 +2179,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hickory-proto"
version = "0.25.2"
name = "hickory-net"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502"
checksum = "e2295ed2f9c31e471e1428a8f88a3f0e1f4b27c15049592138d1eebe9c35b183"
dependencies = [
"async-trait",
"cfg-if",
"data-encoding",
"enum-as-inner",
"futures-channel",
"futures-io",
"futures-util",
"hickory-proto",
"idna",
"ipnet",
"once_cell",
"rand 0.9.4",
"ring",
"serde",
"jni",
"rand 0.10.1",
"thiserror",
"tinyvec",
"tokio",
@@ -2210,22 +2203,48 @@ dependencies = [
]
[[package]]
name = "hickory-resolver"
version = "0.25.2"
name = "hickory-proto"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a"
checksum = "0bab31817bfb44672a252e97fe81cd0c18d1b2cf892108922f6818820df8c643"
dependencies = [
"data-encoding",
"idna",
"ipnet",
"jni",
"once_cell",
"prefix-trie",
"rand 0.10.1",
"ring",
"serde",
"thiserror",
"tinyvec",
"tracing",
"url",
]
[[package]]
name = "hickory-resolver"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d58d28879ceecde6607729660c2667a081ccdc082e082675042793960f178c"
dependencies = [
"cfg-if",
"futures-util",
"hickory-net",
"hickory-proto",
"ipconfig",
"ipnet",
"jni",
"moka",
"ndk-context",
"once_cell",
"parking_lot",
"rand 0.9.4",
"rand 0.10.1",
"resolv-conf",
"serde",
"smallvec",
"system-configuration",
"thiserror",
"tokio",
"tracing",
@@ -2267,9 +2286,9 @@ dependencies = [
[[package]]
name = "http"
version = "1.4.0"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425"
dependencies = [
"bytes",
"itoa",
@@ -2336,9 +2355,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.9.0"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498"
dependencies = [
"atomic-waker",
"bytes",
@@ -2600,6 +2619,9 @@ name = "ipnet"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
dependencies = [
"serde",
]
[[package]]
name = "itertools"
@@ -2686,13 +2708,12 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.99"
version = "0.3.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
dependencies = [
"cfg-if",
"futures-util",
"once_cell",
"wasm-bindgen",
]
@@ -2817,9 +2838,9 @@ dependencies = [
[[package]]
name = "libz-sys"
version = "1.1.28"
version = "1.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc3a226e576f50782b3305c5ccf458698f92798987f551c6a02efe8276721e22"
checksum = "85bc9657773828b90eeb625adff10eeac83cc21bbfd8e23a03eaa8a33c9e28d9"
dependencies = [
"cc",
"pkg-config",
@@ -2828,9 +2849,9 @@ dependencies = [
[[package]]
name = "link-section"
version = "0.17.2"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d1e908a416d6e9f725743b84a36feea40c4c131e805fbc26d61f9f451f36080"
checksum = "c2b1dd6fe32e55c0fc0ea9493aa57459ca3cf4ff3c857c7d0302290150da6e4f"
[[package]]
name = "linked-hash-map"
@@ -2840,9 +2861,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linktime-proc-macro"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44cd706ff0d503ee32b2071166510ca27e281228de10cd3aa8d35ff94560f81"
checksum = "8c7b0a3383c2a1002d11349c92c85a666a5fb679e96c79d782cf0dbe557fd6ee"
[[package]]
name = "linux-raw-sys"
@@ -2873,9 +2894,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.29"
version = "0.4.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
[[package]]
name = "loole"
@@ -2967,9 +2988,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
[[package]]
name = "memory-serve"
@@ -3046,9 +3067,9 @@ dependencies = [
[[package]]
name = "mio"
version = "1.2.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
dependencies = [
"libc",
"log",
@@ -3083,6 +3104,12 @@ dependencies = [
"pxfm",
]
[[package]]
name = "ndk-context"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
[[package]]
name = "new_debug_unreachable"
version = "1.0.6"
@@ -3438,7 +3465,7 @@ dependencies = [
"bytes",
"http",
"opentelemetry",
"reqwest 0.13.3",
"reqwest 0.13.4",
]
[[package]]
@@ -3453,7 +3480,7 @@ dependencies = [
"opentelemetry-proto",
"opentelemetry_sdk",
"prost",
"reqwest 0.13.3",
"reqwest 0.13.4",
"thiserror",
"tokio",
"tonic",
@@ -3475,9 +3502,9 @@ dependencies = [
[[package]]
name = "opentelemetry_sdk"
version = "0.32.0"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368afaed344110f40b179bb8fbe54bc52d98f9bd2b281799ef32487c2650c956"
checksum = "9b59f80e1ac4d5ff7a2db8fb6c80badb7f0f3f858211fba08dd9aaec750894f9"
dependencies = [
"futures-channel",
"futures-executor",
@@ -3723,6 +3750,17 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "prefix-trie"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cf6e3177f0684016a5c209b00882e15f8bdd3f3bb48f0491df10cd102d0c6e7"
dependencies = [
"either",
"ipnet",
"num-traits",
]
[[package]]
name = "prettyplease"
version = "0.2.37"
@@ -3739,7 +3777,7 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
"toml_edit 0.25.11+spec-1.1.0",
"toml_edit 0.25.12+spec-1.1.0",
]
[[package]]
@@ -3788,9 +3826,9 @@ dependencies = [
[[package]]
name = "prost"
version = "0.14.3"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568"
checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1"
dependencies = [
"bytes",
"prost-derive",
@@ -3798,9 +3836,9 @@ dependencies = [
[[package]]
name = "prost-derive"
version = "0.14.3"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -3811,9 +3849,9 @@ dependencies = [
[[package]]
name = "prost-types"
version = "0.14.3"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7"
checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a"
dependencies = [
"prost",
]
@@ -4018,9 +4056,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.12.3"
version = "1.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
dependencies = [
"aho-corasick",
"memchr",
@@ -4041,9 +4079,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.10"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "reqwest"
@@ -4084,9 +4122,9 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.13.3"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0"
checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -4151,7 +4189,7 @@ dependencies = [
[[package]]
name = "ruma"
version = "0.15.1"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"assign",
"js_int",
@@ -4170,7 +4208,7 @@ dependencies = [
[[package]]
name = "ruma-appservice-api"
version = "0.15.0"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"js_int",
"ruma-common",
@@ -4182,7 +4220,7 @@ dependencies = [
[[package]]
name = "ruma-client-api"
version = "0.23.1"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"as_variant",
"assign",
@@ -4204,7 +4242,7 @@ dependencies = [
[[package]]
name = "ruma-common"
version = "0.18.0"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"as_variant",
"base64 0.22.1",
@@ -4237,7 +4275,7 @@ dependencies = [
[[package]]
name = "ruma-events"
version = "0.33.0"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"as_variant",
"indexmap",
@@ -4258,7 +4296,7 @@ dependencies = [
[[package]]
name = "ruma-federation-api"
version = "0.14.0"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"bytes",
"headers",
@@ -4281,7 +4319,7 @@ dependencies = [
[[package]]
name = "ruma-identifiers-validation"
version = "0.12.1"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"js_int",
"thiserror",
@@ -4290,7 +4328,7 @@ dependencies = [
[[package]]
name = "ruma-macros"
version = "0.18.0"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"as_variant",
"cfg-if",
@@ -4306,7 +4344,7 @@ dependencies = [
[[package]]
name = "ruma-push-gateway-api"
version = "0.14.0"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"js_int",
"ruma-common",
@@ -4318,7 +4356,7 @@ dependencies = [
[[package]]
name = "ruma-signatures"
version = "0.20.0"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"base64 0.22.1",
"ed25519-dalek",
@@ -4334,7 +4372,7 @@ dependencies = [
[[package]]
name = "ruma-state-res"
version = "0.16.0"
source = "git+https://github.com/ruma/ruma.git?rev=9c9dccc93f054bbd28f23f630223fffa6289ecbc#9c9dccc93f054bbd28f23f630223fffa6289ecbc"
source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
dependencies = [
"js_int",
"ruma-common",
@@ -4436,9 +4474,9 @@ dependencies = [
[[package]]
name = "rustls-native-certs"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
dependencies = [
"openssl-probe",
"rustls-pki-types",
@@ -4462,7 +4500,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
dependencies = [
"core-foundation",
"core-foundation 0.10.1",
"core-foundation-sys",
"jni",
"log",
@@ -4570,7 +4608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation 0.10.1",
"core-foundation-sys",
"libc",
"security-framework-sys",
@@ -4604,7 +4642,7 @@ checksum = "931a20b0da02350676e3d6d3c9028d58eaa448cf42a866712eec5845a505421e"
dependencies = [
"cfg_aliases",
"httpdate",
"reqwest 0.13.3",
"reqwest 0.13.4",
"sentry-backtrace",
"sentry-contexts",
"sentry-core",
@@ -4741,9 +4779,9 @@ dependencies = [
[[package]]
name = "serde-saphyr"
version = "0.0.26"
version = "0.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc7fe48e34d02a97bc8e6253b8b91e5a47fe2c47eaacb5149cefbb69922eaf0"
checksum = "5897b4c3faadadd35fdb6689f015641f3bc481d5adaaac56231ea15aeb243db3"
dependencies = [
"ahash",
"annotate-snippets",
@@ -4817,9 +4855,9 @@ dependencies = [
[[package]]
name = "serde_regex"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf"
checksum = "bafc8d0c5330cecff10f16b459b479fd9acaa5b4acd7167301414e21b0057012"
dependencies = [
"regex",
"serde",
@@ -4927,6 +4965,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "shlex"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
name = "signal-hook"
version = "0.3.18"
@@ -5013,18 +5057,18 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.15.1"
version = "1.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
dependencies = [
"serde",
]
[[package]]
name = "socket2"
version = "0.6.3"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
dependencies = [
"libc",
"windows-sys 0.61.2",
@@ -5129,6 +5173,27 @@ dependencies = [
"syn",
]
[[package]]
name = "system-configuration"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
dependencies = [
"bitflags",
"core-foundation 0.9.4",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "tagptr"
version = "0.2.0"
@@ -5231,12 +5296,11 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.47"
version = "0.3.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
checksum = "711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde_core",
@@ -5246,15 +5310,15 @@ dependencies = [
[[package]]
name = "time-core"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
[[package]]
name = "time-macros"
version = "0.2.27"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
checksum = "71c652a3727a9cbb9a02f707f530b618ce00d0ccd762009c8c23bd191df3c17d"
dependencies = [
"num-conv",
"time-core",
@@ -5442,9 +5506,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.25.11+spec-1.1.0"
version = "0.25.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
dependencies = [
"indexmap",
"toml_datetime 1.1.1+spec-1.1.0",
@@ -5699,9 +5763,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "typenum"
version = "1.20.0"
version = "1.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]]
name = "typewit"
@@ -5741,9 +5805,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-segmentation"
version = "1.13.2"
version = "1.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
[[package]]
name = "unicode-width"
@@ -5802,9 +5866,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "uuid"
version = "1.23.1"
version = "1.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7"
dependencies = [
"getrandom 0.4.2",
"js-sys",
@@ -5887,9 +5951,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasip2"
version = "1.0.3+wasi-0.2.9"
version = "1.0.4+wasi-0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
dependencies = [
"wit-bindgen 0.57.1",
]
@@ -5905,9 +5969,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.122"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
dependencies = [
"cfg-if",
"once_cell",
@@ -5918,9 +5982,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.72"
version = "0.4.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f"
checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -5928,9 +5992,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.122"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -5938,9 +6002,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.122"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -5951,9 +6015,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.122"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
dependencies = [
"unicode-ident",
]
@@ -6007,9 +6071,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.99"
version = "0.3.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436"
checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -6434,9 +6498,9 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "yoke"
version = "0.8.2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
dependencies = [
"stable_deref_trait",
"yoke-derive",
@@ -6457,18 +6521,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.48"
version = "0.8.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.48"
version = "0.8.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
dependencies = [
"proc-macro2",
"quote",
@@ -6498,9 +6562,9 @@ dependencies = [
[[package]]
name = "zeroize"
version = "1.8.2"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
[[package]]
name = "zerotrie"
+4 -4
View File
@@ -164,7 +164,7 @@ features = ["raw_value"]
# Used for appservice registration files
[workspace.dependencies.serde-saphyr]
version = "0.0.26"
version = "0.0.27"
# Used to load forbidden room/user regex from config
[workspace.dependencies.serde_regex]
@@ -296,7 +296,7 @@ default-features = false
features = ["env", "toml"]
[workspace.dependencies.hickory-resolver]
version = "0.25.2"
version = "0.26.0"
default-features = false
features = [
"serde",
@@ -344,7 +344,7 @@ version = "1.1.1"
[workspace.dependencies.ruma]
# version = "0.14.1"
git = "https://github.com/ruma/ruma.git"
rev = "9c9dccc93f054bbd28f23f630223fffa6289ecbc"
rev = "3ecd80b92794d2d93f657a7b3db62d4be237526b"
features = [
"appservice-api-c",
"client-api",
@@ -373,12 +373,12 @@ features = [
"unstable-msc4195",
"unstable-msc4203",
"unstable-msc4310",
"unstable-msc4373",
"unstable-msc4380",
"unstable-msc4143",
"unstable-msc4293",
"unstable-msc4406",
"unstable-msc4439",
"unstable-msc4466",
"unstable-extensible-events",
]
+1
View File
@@ -0,0 +1 @@
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.
+1
View File
@@ -0,0 +1 @@
Added support for MSC4466, which allows clients to customize how changes to a user's global profile are propagated. Contributed by @ginger.
+1
View File
@@ -0,0 +1 @@
Devices which set their presence as "offline" will no longer be considered for presence updates. Contributed by @timedout.
+1
View File
@@ -0,0 +1 @@
Added example configuration using caddy-docker-proxy in the livekit setup section of the docs. Contributed by @Cease
+1
View File
@@ -0,0 +1 @@
Fixed admin commands being ignored when they had leading whitespace before admin commands. Contributed by @kitvonsnookerz.
+1
View File
@@ -0,0 +1 @@
Remove support for MSC4373, as the MSC is now closed. Contributed by @vel.
+1
View File
@@ -0,0 +1 @@
Adjusted legacy sync logic to no longer use the `roomsynctoken_shortstatehash` database column. Once this change has been confirmed to be stable and reliable, a future update will remove it entirely, significantly decreasing database sizes. Contributed by @ginger.
+1 -1
View File
@@ -50,7 +50,7 @@ EOF
# Developer tool versions
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
ENV BINSTALL_VERSION=1.19.1
ENV BINSTALL_VERSION=1.20.0
# renovate: datasource=github-releases depName=psastras/sbom-rs
ENV CARGO_SBOM_VERSION=0.9.1
# renovate: datasource=crate depName=lddtree
+1 -1
View File
@@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/etc/apk/cache apk add \
# Developer tool versions
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
ENV BINSTALL_VERSION=1.19.1
ENV BINSTALL_VERSION=1.20.0
# renovate: datasource=github-releases depName=psastras/sbom-rs
ENV CARGO_SBOM_VERSION=0.9.1
# renovate: datasource=crate depName=lddtree
+69
View File
@@ -187,6 +187,75 @@ ### 4. Configure your Reverse Proxy
```
</details>
<details>
<summary>Example docker compose file with caddy-docker-proxy labels</summary>
```yaml
# This setup assumes all containers share the same bridge network
services:
lk-jwt-service:
image: ghcr.io/element-hq/lk-jwt-service:latest
container_name: lk-jwt-service
# lk-jwt-service environment config here..
labels:
caddy: livekit.example.com
caddy.@lk-jwt-service.path: "/sfu/get* /healthz* /get_token*"
caddy.reverse_proxy: "@lk-jwt-service {{upstreams 8081}}"
livekit:
image: livekit/livekit-server:latest
container_name: livekit
command: --config /etc/livekit.yaml
restart: unless-stopped
labels:
caddy: livekit.example.com
caddy.reverse_proxy: "{{upstreams 7880}}"
volumes:
- ./livekit.yaml:/etc/livekit.yaml:ro
ports:
- "127.0.0.1:7880:7880/tcp"
- "7881:7881/tcp"
- "50100-50200:50100-50200/udp"
caddy:
image: lucaslorentz/caddy-docker-proxy:ci-alpine
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=caddy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
restart: unless-stopped
labels:
# If you already configured `[global.well_known]` with Continuwuity,
# comment out the *_respond labels and add this line
# caddy.reverse_proxy: /.well-known/matrix/* homeserver:8008
caddy.1_respond: /.well-known/matrix/server {"m.server":"matrix.example.com:443"}
caddy.2_respond: /.well-known/matrix/client {"m.server":{"base_url":"https://matrix.example.com"},"m.homeserver":{"base_url":"https://matrix.example.com"},"org.matrix.msc4143.rtc_foci":[{"type":"livekit","livekit_service_url":"https://livekit.example.com"}]}
# If you are having problems with continuwuity serving headers uncomment
# the header section below.
# caddy: example.com
# caddy.0_header: "*"
# caddy.0_header.Access-Control-Allow-Origin: "*"
# caddy.0_header.Access-Control-Allow-Methods: "GET, POST, OPTIONS"
# caddy.0_header.Access-Control-Allow-Headers: "Authorization"
# caddy.0_header.Content-Type: "application/json"
homeserver:
image: forgejo.ellis.link/continuwuation/continuwuity:latest
restart: unless-stopped
# add additional environment, volume, and network config here...
labels:
caddy: matrix.example.com
caddy.reverse_proxy: "{{upstreams 8008}}"
```
</details>
### 6. Start Everything
Generated
+18 -18
View File
@@ -3,11 +3,11 @@
"advisory-db": {
"flake": false,
"locked": {
"lastModified": 1779575509,
"narHash": "sha256-wXKYURZz76ZC5lbuDA1oVQA/MxSB3pSJ1raF1HG0oIc=",
"lastModified": 1781566179,
"narHash": "sha256-Tqv8I586fYzWpEW/Smq/JqESFa3DVVzVWsnAMtvhy/I=",
"owner": "rustsec",
"repo": "advisory-db",
"rev": "831c50f4a4304068f125e603add6a8839f08b3eb",
"rev": "74e084413d979d52d2f93b1d93b1ab7b9ee648f5",
"type": "github"
},
"original": {
@@ -18,11 +18,11 @@
},
"crane": {
"locked": {
"lastModified": 1779130139,
"narHash": "sha256-BLrtr42azquO7MdGFU5a7KiMl3YpFlTeIXqy1fT5GlQ=",
"lastModified": 1780532242,
"narHash": "sha256-D+BsdpxmtUwtqGoY0IXPhHgTlmqgcZKCEo1oMyn7ep0=",
"owner": "ipetkov",
"repo": "crane",
"rev": "edb38893982a3338972bb4a2ec7ce7c29ba10fd9",
"rev": "59a82a1222dd3b2080b5cc52a1a2e8d5f1b77f37",
"type": "github"
},
"original": {
@@ -39,11 +39,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1779612045,
"narHash": "sha256-+7lfNVnmXJDkiRYHd5NoNwYoyUcc0LcXPaIJqjO7VWM=",
"lastModified": 1781527054,
"narHash": "sha256-1fX9ev2Fh5QoKQ41G9dYutjo5j/jywu6tZse5Eb1Ck4=",
"owner": "nix-community",
"repo": "fenix",
"rev": "d7be747f0a65af378de515fc3cee131bf99a008f",
"rev": "8c2e51dffefc040a21975da7abf6f252c8c9b783",
"type": "github"
},
"original": {
@@ -89,11 +89,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1779508470,
"narHash": "sha256-Ap9KJX+5xHIn3bPIpfNgT6MEXdAECECwo4/rmlQD74M=",
"lastModified": 1781074563,
"narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "29916453413845e54a65b8a1cf996842300cd299",
"rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca",
"type": "github"
},
"original": {
@@ -132,11 +132,11 @@
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1779569060,
"narHash": "sha256-NSnk5D+3KEfRdbgPijs33N2RAKSG6A74SwfnynLcouo=",
"lastModified": 1781453968,
"narHash": "sha256-+V3nK4pCngbmgyVGXY6Kkrlevp4ocPkJJLf2aqwkDNA=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "987ea33645ab1c709b1df6823038abcb2fe8973e",
"rev": "cc272809a173c2c11d0e479d639c811c1eacf049",
"type": "github"
},
"original": {
@@ -153,11 +153,11 @@
]
},
"locked": {
"lastModified": 1775636079,
"narHash": "sha256-pc20NRoMdiar8oPQceQT47UUZMBTiMdUuWrYu2obUP0=",
"lastModified": 1780220602,
"narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "790751ff7fd3801feeaf96d7dc416a8d581265ba",
"rev": "db947814a175b7ca6ded66e21383d938df01c227",
"type": "github"
},
"original": {
+1 -1
View File
@@ -16,7 +16,7 @@
file = inputs.self + "/rust-toolchain.toml";
# See also `rust-toolchain.toml`
sha256 = "sha256-gh/xTkxKHL4eiRXzWv8KP7vfjSk61Iq48x47BEDFgfk=";
sha256 = "sha256-mvUGEOHYJpn3ikC5hckneuGixaC+yGrkMM/liDIDgoU=";
};
in
{
+198 -149
View File
@@ -125,14 +125,14 @@
}
},
"node_modules/@rsbuild/core": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.0.7.tgz",
"integrity": "sha512-LsBONEzsjzOAqO72ot39eI7g53zSfF9QuDXTu4ks8IUX+EZsxRSniQfc+1zVA6a6y3b9KUUtG96avoMLKbWklQ==",
"version": "2.0.15",
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.0.15.tgz",
"integrity": "sha512-O8vmMhZu1YImO6jOqt/K/vlJSvkq7UtSq5YM1DIlcEd9LW8Gf6/dkQ1B2KPI6F+hSMFBnTTTumdcIowSLCw97g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rspack/core": "~2.0.4",
"@swc/helpers": "^0.5.21"
"@rspack/core": "~2.0.8",
"@swc/helpers": "^0.5.23"
},
"bin": {
"rsbuild": "bin/rsbuild.js"
@@ -150,9 +150,9 @@
}
},
"node_modules/@rsbuild/plugin-react": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@rsbuild/plugin-react/-/plugin-react-2.0.0.tgz",
"integrity": "sha512-/1gzt39EGUSFEqB83g46QoOwsgv172HI18i6au1b6lgIaX4sv9stuX4ijdHbHCp8PqYEq+MyQ99jIQMO6I+etg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@rsbuild/plugin-react/-/plugin-react-2.0.1.tgz",
"integrity": "sha512-n5m3VxEm6m3Dv1VkI0WnxsildySJ6M+QjGIzkZDy5UebRCIJ1Q/hlQVyhofBL6C+AcsF9fGjlHQkeiteXJSr3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -169,28 +169,28 @@
}
},
"node_modules/@rspack/binding": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-2.0.4.tgz",
"integrity": "sha512-/QeJDPUw/lWkBJESG264KA9u6/rAjvoJhKncU4rkTi5Ap45kue5HTgOzr0ufxKdd2Xl72fjFBuqlKmtFDD5LiQ==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-2.0.8.tgz",
"integrity": "sha512-3uZ+y8aQxq33ty2srMxg2Nu0XuBI6vVrG50rkDaXqwWqOohfgGUSfFuQK7EnSUNy4aFUQlCG6NHialQHJov0wg==",
"dev": true,
"license": "MIT",
"optionalDependencies": {
"@rspack/binding-darwin-arm64": "2.0.4",
"@rspack/binding-darwin-x64": "2.0.4",
"@rspack/binding-linux-arm64-gnu": "2.0.4",
"@rspack/binding-linux-arm64-musl": "2.0.4",
"@rspack/binding-linux-x64-gnu": "2.0.4",
"@rspack/binding-linux-x64-musl": "2.0.4",
"@rspack/binding-wasm32-wasi": "2.0.4",
"@rspack/binding-win32-arm64-msvc": "2.0.4",
"@rspack/binding-win32-ia32-msvc": "2.0.4",
"@rspack/binding-win32-x64-msvc": "2.0.4"
"@rspack/binding-darwin-arm64": "2.0.8",
"@rspack/binding-darwin-x64": "2.0.8",
"@rspack/binding-linux-arm64-gnu": "2.0.8",
"@rspack/binding-linux-arm64-musl": "2.0.8",
"@rspack/binding-linux-x64-gnu": "2.0.8",
"@rspack/binding-linux-x64-musl": "2.0.8",
"@rspack/binding-wasm32-wasi": "2.0.8",
"@rspack/binding-win32-arm64-msvc": "2.0.8",
"@rspack/binding-win32-ia32-msvc": "2.0.8",
"@rspack/binding-win32-x64-msvc": "2.0.8"
}
},
"node_modules/@rspack/binding-darwin-arm64": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-2.0.4.tgz",
"integrity": "sha512-0Q1QXFEsZfDc4opiDnb8q50KlBbC2VovViDaYlMJZBzvjAo325mh3itXPfz7YZ31M+TxRE7TUiJXH3ltiV1Hdg==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-2.0.8.tgz",
"integrity": "sha512-vCgbgH7B7qom+uID+RCZsTCOYFb9wC4/4+1U6rMfytrXGVJ72eNQs2tbdjOl0lb18CT3N/n+VkWynUiLk84GwA==",
"cpu": [
"arm64"
],
@@ -202,9 +202,9 @@
]
},
"node_modules/@rspack/binding-darwin-x64": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-2.0.4.tgz",
"integrity": "sha512-oO5J2QYf7+H+aYRj85EiGrDOoDEE9EDDl7NgXv46iWvIF0wXowEHXqnjMFxHxRq2Vf6scT+0yYQX9blWcvMWAA==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-2.0.8.tgz",
"integrity": "sha512-satPm2PD4B7jDTVlVAdvMVdUszwLvWUEnUDzLb77mvVkezKNDZmuhb+e8s+FfKs8hJpNbZ9VAejuA2rr8o985w==",
"cpu": [
"x64"
],
@@ -216,9 +216,9 @@
]
},
"node_modules/@rspack/binding-linux-arm64-gnu": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-2.0.4.tgz",
"integrity": "sha512-BEk6mIYBK4BihW9qXXITJORrVXecTlkRjrqhgefili4xjXtLdcUnxAm9sN/2oJ8m378n2h33qDh4gr2orPBFWQ==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-2.0.8.tgz",
"integrity": "sha512-pSI+npPQE/uDtiboqvcOIRJbEV2+B+H1xffmko/gw50la92oTUW60kVULFwsb6L0+GVCzIcwX3yq60GtYIn+Ug==",
"cpu": [
"arm64"
],
@@ -233,9 +233,9 @@
]
},
"node_modules/@rspack/binding-linux-arm64-musl": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-2.0.4.tgz",
"integrity": "sha512-Hyt3z1RwNcSMIoaoWLN4Hb/696/O5JPukf8rXQASvf2UkC+X3ij7tr+8lMSYi3Zysi1QL375CnT4fNoABEW0JA==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-2.0.8.tgz",
"integrity": "sha512-igjJ43yxWQ72GZqjDDZSSHax9/Vg+6rLMmOvFglTJUkQpB4Tyvu/YjW+WRjYj2xRw6blOjLxUSJWASvuSqqlvg==",
"cpu": [
"arm64"
],
@@ -250,9 +250,9 @@
]
},
"node_modules/@rspack/binding-linux-x64-gnu": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-2.0.4.tgz",
"integrity": "sha512-xHorBPBZAg0Pn9Q0k9dWZ9euowieDxcSOzQ9JhTCmhDY6wZH5M/kCBFlCs/OQeW5/NUArW3x3MwEdO/0QJHMxg==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-2.0.8.tgz",
"integrity": "sha512-zrkoEOnqj1hOEBO5T2I/2Ts2HSJsYFh1qXwMpK4dMJFGGNWDfNeUa6/LF5uq3VINF3JUl7RL47AgrucoSZJXPA==",
"cpu": [
"x64"
],
@@ -267,9 +267,9 @@
]
},
"node_modules/@rspack/binding-linux-x64-musl": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-2.0.4.tgz",
"integrity": "sha512-QLxEGUXofF0kVNU12Y2NT3Qi9lGs+WbnYpapVeb+2IXtrAXJfU7Rhy7lAp5GLMzYMQNrKKL9SVnTWKbODbNW9Q==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-2.0.8.tgz",
"integrity": "sha512-6CtDaGZjNDvJd9TBp7a9zABbrPORO21W96+3ZcGBn0YNUPUk4ARxIxrTTpeJ/1F41QDM8AYIkGDdqEYMqTYBsA==",
"cpu": [
"x64"
],
@@ -284,9 +284,9 @@
]
},
"node_modules/@rspack/binding-wasm32-wasi": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-2.0.4.tgz",
"integrity": "sha512-YhN8HkiH46ONU9tm5dyoXDImDWGpU7E4SPqGI4OyAVF0445uIChurIUmTIOYcD6cg81GGeIjozWJOcb635Dcqw==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-2.0.8.tgz",
"integrity": "sha512-Yf4SiqTUroT5Ju+te0YAY2xxKOb35tECsO21v7hYyGa705wrgoAK/MmF7enOvs9GR1iZIqgiLD/wxsIxl8GjJw==",
"cpu": [
"wasm32"
],
@@ -300,9 +300,9 @@
}
},
"node_modules/@rspack/binding-win32-arm64-msvc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.0.4.tgz",
"integrity": "sha512-MUlYIz82xQRN0aoiXXyEBrNVUwiOSSFRi7nuCgUKduaSdlbPWzCY31IdtOygZ06LVp5JIGUEtyqSrjQq4FrMRw==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.0.8.tgz",
"integrity": "sha512-8NCuiQsAhXrwRBy57QZoypqrws/zLBkaQVGiB8hksr6v++8hNigNjqpQARLbd0iyMuHsQQ++8+auGk6xlDXmzw==",
"cpu": [
"arm64"
],
@@ -314,9 +314,9 @@
]
},
"node_modules/@rspack/binding-win32-ia32-msvc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-2.0.4.tgz",
"integrity": "sha512-D7UcIFMzlY2yhhyuW4Ej15gBWmTwUM5DxuObl3Kv31qRv/pmV3MsqUeG5m2dqLbUxzqPH87qnp0cArbkJQ1b+w==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-2.0.8.tgz",
"integrity": "sha512-bxiekytbX7V9KFAra+HkwtNWC6pYfHEBBZFpiT0xUs3mCFOmAAFVBsBSQsoCP9AdCEXoMAvNdnrHNw3iov4OZw==",
"cpu": [
"ia32"
],
@@ -328,9 +328,9 @@
]
},
"node_modules/@rspack/binding-win32-x64-msvc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-2.0.4.tgz",
"integrity": "sha512-MnYKPfdrAEbtpKg/1SZ6cNtzreIRyQJK4APbxLLPXENdTH5QXQkaTjLMKEeJcJ51FRhI/+yNpOUm2oTHdCQ1Og==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-2.0.8.tgz",
"integrity": "sha512-7zPs8YCe/ZVJTwd+5lpB0CP0tkn2pONf/T1ycmVY76u21Nrwt8mXQGc/2yH2eWP4B7fikYBr3hGr7mpR2fajqQ==",
"cpu": [
"x64"
],
@@ -342,20 +342,20 @@
]
},
"node_modules/@rspack/core": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-2.0.4.tgz",
"integrity": "sha512-OuxdQeeKWQpNvFBRDOcnoSaQvp6E4APM/6JJMM/k0p6oL1TEFQVGdNu3VGY4mRAsebnNBXapMVMhj+v66Bn2pg==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-2.0.8.tgz",
"integrity": "sha512-+NLGJf8gZxihDmMFzjlly3toc2SMjeDmuvz0/Cai9AMdV4F+Pqcnt2BA9V4e3SY2jmhJQtPwgyyLtR1RiJO77g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rspack/binding": "2.0.4"
"@rspack/binding": "2.0.8"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"peerDependencies": {
"@module-federation/runtime-tools": "^0.24.1 || ^2.0.0",
"@swc/helpers": ">=0.5.1"
"@swc/helpers": "^0.5.23"
},
"peerDependenciesMeta": {
"@module-federation/runtime-tools": {
@@ -383,17 +383,17 @@
}
},
"node_modules/@rspress/core": {
"version": "2.0.13",
"resolved": "https://registry.npmjs.org/@rspress/core/-/core-2.0.13.tgz",
"integrity": "sha512-lbaBA5eqh7wKdH98TUQEI+SfS3Z6YgaNCup3X+ttrYVLOrxN8PJvbedo6fFAcl+wP3XLy6D0pcnnzAgu8y3tdg==",
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/@rspress/core/-/core-2.0.14.tgz",
"integrity": "sha512-k59i08zwBGgHrjHw8CK1m4CeTrKPvZRmV54bxubQl6AdDdmhJK6WrNg3UthwWmd38scKtqF40ATXDE8RMiNcNA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@mdx-js/mdx": "^3.1.1",
"@mdx-js/react": "^3.1.1",
"@rsbuild/core": "^2.0.7",
"@rsbuild/plugin-react": "~2.0.0",
"@rspress/shared": "2.0.13",
"@rsbuild/core": "^2.0.9",
"@rsbuild/plugin-react": "~2.0.1",
"@rspress/shared": "2.0.14",
"@shikijs/rehype": "^4.0.2",
"@types/unist": "^3.0.3",
"@unhead/react": "^2.1.15",
@@ -436,9 +436,9 @@
}
},
"node_modules/@rspress/plugin-client-redirects": {
"version": "2.0.13",
"resolved": "https://registry.npmjs.org/@rspress/plugin-client-redirects/-/plugin-client-redirects-2.0.13.tgz",
"integrity": "sha512-dP753ASTvH6eDtSEulcqq2lE/kTSdOWSCw0nzvXG+7atTWTHDp6z47uH3CGD8E78cBuKyEi4OH+U7V0EtCTc0Q==",
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/@rspress/plugin-client-redirects/-/plugin-client-redirects-2.0.14.tgz",
"integrity": "sha512-/WpbWUiepQglpPeplxCnELe2c7VdBUxPiICPAVnS1ZxAFdYkIpW0C+Vbk1t08kZqx8EAZGu+s6Zy43zyQpjdxg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -449,9 +449,9 @@
}
},
"node_modules/@rspress/plugin-sitemap": {
"version": "2.0.13",
"resolved": "https://registry.npmjs.org/@rspress/plugin-sitemap/-/plugin-sitemap-2.0.13.tgz",
"integrity": "sha512-JtkNlxNuA7BzknKIrLvLQkSk0XVi7OXzrE76ma/cLvleccNWr8LGrHtrac4IrDr+HauK4WKTM2JaHGGHUdOUKw==",
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/@rspress/plugin-sitemap/-/plugin-sitemap-2.0.14.tgz",
"integrity": "sha512-Gpone22PvXGfGRSyi/WM8IXgsvKhNspXqHjtPD3g62jX8SJL3kpj2YZ2V28WEkg672fICauUYXrpre74Rddcsw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -462,26 +462,26 @@
}
},
"node_modules/@rspress/shared": {
"version": "2.0.13",
"resolved": "https://registry.npmjs.org/@rspress/shared/-/shared-2.0.13.tgz",
"integrity": "sha512-LmDfr7+MDNWRBbxcNoWkW68A35oRonpDJq2Jlx3L8GCzG4sAsyd6Yw0DebTWAxx7hVOXGMf37nEf1J4aOLEZfg==",
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/@rspress/shared/-/shared-2.0.14.tgz",
"integrity": "sha512-sCe9tAo+s9tR4DmFSjMyHOxQvhzTSYXkkMUfVEo5w+uMCNXXGAIC6D0xAVDMHq1jIFF9ix47VxzlCo+CYNS14g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rsbuild/core": "^2.0.7",
"@rsbuild/core": "^2.0.9",
"@shikijs/rehype": "^4.0.2",
"unified": "^11.0.5"
}
},
"node_modules/@shikijs/core": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.1.0.tgz",
"integrity": "sha512-jLJtSJeuFffqX6/inRE1zqU5aFv2hrszvYgq3OjbAgFRZiWv7abKMDdQzYxuSDfmUPQozZvI/kuy6VMTvnvqTQ==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.2.0.tgz",
"integrity": "sha512-Hc87Ab1Ld/vEbZRCbwx344I5v+4RU8CVToUTRkqXL1+TjbuOp9U5Xa0M23V4GEWHxVn+yO5otb+HkQVm3ptWQQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/primitive": "4.1.0",
"@shikijs/types": "4.1.0",
"@shikijs/primitive": "4.2.0",
"@shikijs/types": "4.2.0",
"@shikijs/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4",
"hast-util-to-html": "^9.0.5"
@@ -491,13 +491,13 @@
}
},
"node_modules/@shikijs/engine-javascript": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.1.0.tgz",
"integrity": "sha512-YquhawCUgaBfhsS72e2Y/dI59gCBNPHu3fEO/tvLaXrTssxZrY5ddjtNLTwndrMgPo8b3IscE+xoICDzpTmlFQ==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.2.0.tgz",
"integrity": "sha512-fjETeq1k5ffyXqRgS6+3hpvqseLalp1kjNfRbXpUgWR8FpZ1CmQfiNHovc5lncYjt/Vg5JK/WJEmLahjwMa0og==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "4.1.0",
"@shikijs/types": "4.2.0",
"@shikijs/vscode-textmate": "^10.0.2",
"oniguruma-to-es": "^4.3.6"
},
@@ -506,13 +506,13 @@
}
},
"node_modules/@shikijs/engine-oniguruma": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.1.0.tgz",
"integrity": "sha512-axLpjVs45YBvvINa+dJF+NPW+KtFkNXsFr4SDw2BMj9GdeMnGxVB9PQb2xXlJYovslt/nz6giedAyOANkfc7hg==",
"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==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "4.1.0",
"@shikijs/types": "4.2.0",
"@shikijs/vscode-textmate": "^10.0.2"
},
"engines": {
@@ -520,26 +520,26 @@
}
},
"node_modules/@shikijs/langs": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.1.0.tgz",
"integrity": "sha512-nwOMruEkbgdZfQ/b8CgpNBVOpvG1k0N5tbmgiFeqsan401+x3ILqlzZJowSla4Agmq4hG2Uf2wh5jLTEhR8VSg==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.2.0.tgz",
"integrity": "sha512-bwrVRlJ0wUhZxAbVdvBbv2TTC9yLsh4C/IO5Ofz0T8MQntgDvyVnkbjw9vi50r1kx7RCIJdnJnjZAwmAsXFLZQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "4.1.0"
"@shikijs/types": "4.2.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@shikijs/primitive": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.1.0.tgz",
"integrity": "sha512-zx2/2Uwj2q9X3KSyYREEhXO23xBw5WUhP4orK2lE4r+t9JGITmEe0JH+wPmJhqHpOT2bRRs6lAL945+LDvOAGw==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.2.0.tgz",
"integrity": "sha512-NOq+DtUkVBJtZMVXL5A0vI0Xk8nvDYaXetFHSJFlOqjDZIVhIPRYFdGkSoElDqNuegikcc3A76SNUa8dTqtAYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "4.1.0",
"@shikijs/types": "4.2.0",
"@shikijs/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4"
},
@@ -548,16 +548,16 @@
}
},
"node_modules/@shikijs/rehype": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@shikijs/rehype/-/rehype-4.1.0.tgz",
"integrity": "sha512-HQwltCcO2/UiFz44/8whyji4rP1VghLu++MgvQn+lQA8/gvuycGkay8DH8o8VAOvLBDKGOkBEw7cC1Cm33GObQ==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/rehype/-/rehype-4.2.0.tgz",
"integrity": "sha512-ST3EWye/dwF1gWskczJNBnwFtDzEQ9ceytXZtyc/GfwR5V0qJrkoSGZO55O3SAKDDsXkTDcsfwd9pVe7ROlAHg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "4.1.0",
"@shikijs/types": "4.2.0",
"@types/hast": "^3.0.4",
"hast-util-to-string": "^3.0.1",
"shiki": "4.1.0",
"shiki": "4.2.0",
"unified": "^11.0.5",
"unist-util-visit": "^5.1.0"
},
@@ -566,22 +566,22 @@
}
},
"node_modules/@shikijs/themes": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.1.0.tgz",
"integrity": "sha512-emCcTnUM7yO2wltYbaxm+yLvcCI4+h8XBKc4KmJ7EZUXoSGjcCHifkI//R4OFit9ewpg7H2/9tjOuXrT2v/Knw==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.2.0.tgz",
"integrity": "sha512-RX8IHYeLv8Cu2W6ruc3RxUqWn0IYCqSrMBzi/uRGAmfyDNOnNO5BF/Px7o97n4XTpmFTo5GbRaazuOWj+2ak2w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "4.1.0"
"@shikijs/types": "4.2.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@shikijs/types": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.1.0.tgz",
"integrity": "sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.2.0.tgz",
"integrity": "sha512-VT/MKtlpOhEPZloSH3Pb9WCZEBDoQVMa9jedp5UAwmJOar1DVc9DRODAxmYPW9M93IK4ryuqRejFfmlvlVDemw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -600,9 +600,9 @@
"license": "MIT"
},
"node_modules/@swc/helpers": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.21.tgz",
"integrity": "sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==",
"version": "0.5.23",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz",
"integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -668,9 +668,9 @@
}
},
"node_modules/@types/mdx": {
"version": "2.0.13",
"resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz",
"integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==",
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.14.tgz",
"integrity": "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==",
"dev": true,
"license": "MIT"
},
@@ -682,9 +682,9 @@
"license": "MIT"
},
"node_modules/@types/react": {
"version": "19.2.15",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz",
"integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==",
"version": "19.2.17",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
"integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -723,9 +723,9 @@
}
},
"node_modules/acorn": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"version": "8.17.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz",
"integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
"dev": true,
"license": "MIT",
"bin": {
@@ -1821,6 +1821,53 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/mdast-util-to-markdown-cjk-friendly": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mdast-util-to-markdown-cjk-friendly/-/mdast-util-to-markdown-cjk-friendly-1.0.0.tgz",
"integrity": "sha512-BoaAm8mlJ+LAYz0Qs532Y3ciTuQYgBUPZcSFbvC/ZKmEMAKgulw84YvQK1gI34t/vL2euSfuaWlqczkTBgamkw==",
"dev": true,
"license": "MIT",
"dependencies": {
"mdast-util-to-markdown": "^2.1.2",
"micromark-extension-cjk-friendly-util": "3.0.1",
"micromark-util-symbol": "^2.0.1"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/mdast": "*"
},
"peerDependenciesMeta": {
"@types/mdast": {
"optional": true
}
}
},
"node_modules/mdast-util-to-markdown-cjk-friendly-gfm-strikethrough": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mdast-util-to-markdown-cjk-friendly-gfm-strikethrough/-/mdast-util-to-markdown-cjk-friendly-gfm-strikethrough-1.0.0.tgz",
"integrity": "sha512-1ePVfB4P/vz3xSsm6H3D32r6VYGErxclnuLLFK02/2ReF+UdEKm7caulK6Vm0LBIp5gPRtB2Z1OYDznCkX3k2w==",
"dev": true,
"license": "MIT",
"dependencies": {
"mdast-util-gfm-strikethrough": "^2.0.0",
"mdast-util-to-markdown": "^2.1.2",
"micromark-extension-cjk-friendly-util": "3.0.1",
"micromark-util-symbol": "^2.0.1"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/mdast": "*"
},
"peerDependenciesMeta": {
"@types/mdast": {
"optional": true
}
}
},
"node_modules/mdast-util-to-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
@@ -2742,9 +2789,9 @@
}
},
"node_modules/property-information": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
"integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz",
"integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==",
"dev": true,
"license": "MIT",
"funding": {
@@ -2753,9 +2800,9 @@
}
},
"node_modules/react": {
"version": "19.2.6",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz",
"integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==",
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
"integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2763,16 +2810,16 @@
}
},
"node_modules/react-dom": {
"version": "19.2.6",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz",
"integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==",
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
"integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"scheduler": "^0.27.0"
},
"peerDependencies": {
"react": "^19.2.6"
"react": "^19.2.7"
}
},
"node_modules/react-lazy-with-preload": {
@@ -2822,9 +2869,9 @@
}
},
"node_modules/react-router": {
"version": "7.15.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.15.1.tgz",
"integrity": "sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A==",
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.17.0.tgz",
"integrity": "sha512-FDELK7rTMlCHO5+reyXsPlmfr7N1F91lPHsWYfMEGQm/KQ+F4JFM8jGoeQDmDvdTs93Fw9aSilH+uKRb4/jXvQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2845,13 +2892,13 @@
}
},
"node_modules/react-router-dom": {
"version": "7.15.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.15.1.tgz",
"integrity": "sha512-AzF62gjY6U9rkMq4RfP/r2EVtQ7DMfNMjyOp/flLTCrtRylLiK4wT4pSq6O8rOXZ2eXdZYJPEYe+ifomiv+Igg==",
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.17.0.tgz",
"integrity": "sha512-fyU2yjGups/hE6Xz0I5ZYbVL8Gx29eCjgpHaRaTaVU+OOAdfRX05KsvyRm0GO8YQwOkhpU3MurW1jyMUJn+zSw==",
"dev": true,
"license": "MIT",
"dependencies": {
"react-router": "7.15.1"
"react-router": "7.17.0"
},
"engines": {
"node": ">=20.0.0"
@@ -3011,12 +3058,13 @@
}
},
"node_modules/remark-cjk-friendly": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/remark-cjk-friendly/-/remark-cjk-friendly-2.0.1.tgz",
"integrity": "sha512-6WwkoQyZf/4j5k53zdFYrR8Ca+UVn992jXdLUSBDZR4eBpFhKyVxmA4gUHra/5fesjGIxrDhHesNr/sVoiiysA==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/remark-cjk-friendly/-/remark-cjk-friendly-2.1.0.tgz",
"integrity": "sha512-ZWGDfTJNLEZ1gap+pd33K13ZhRAWgVDqxKA7JIlBs5IDu+qvbiWl/pEbeuxzRrWyrrkeFFoTnvNw00iW9mBcow==",
"dev": true,
"license": "MIT",
"dependencies": {
"mdast-util-to-markdown-cjk-friendly": "1.0.0",
"micromark-extension-cjk-friendly": "2.0.1"
},
"engines": {
@@ -3033,12 +3081,13 @@
}
},
"node_modules/remark-cjk-friendly-gfm-strikethrough": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/remark-cjk-friendly-gfm-strikethrough/-/remark-cjk-friendly-gfm-strikethrough-2.0.1.tgz",
"integrity": "sha512-pWKj25O2eLXIL1aBupayl1fKhco+Brw8qWUWJPVB9EBzbQNd7nGLj0nLmJpggWsGLR5j5y40PIdjxby9IEYTuA==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/remark-cjk-friendly-gfm-strikethrough/-/remark-cjk-friendly-gfm-strikethrough-2.1.0.tgz",
"integrity": "sha512-3Kyq2hjY7V7eU8MbVbWW6QQLN81pjJcIvKHvPxr8hZZmcq/9wqm3MJ3iUG34Ch9QTM4WHN+a1JVAVC1fSi5mig==",
"dev": true,
"license": "MIT",
"dependencies": {
"mdast-util-to-markdown-cjk-friendly-gfm-strikethrough": "1.0.0",
"micromark-extension-cjk-friendly-gfm-strikethrough": "2.0.1"
},
"engines": {
@@ -3164,18 +3213,18 @@
"license": "MIT"
},
"node_modules/shiki": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-4.1.0.tgz",
"integrity": "sha512-l/ABZPUR5v70jI10EzqfMS/I96vjSGv2y0ihUV+WYFzv0EfvW4s54m0Lg8wCrrL+2IkwBzFTuxkZjPf8b2NX9Q==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-4.2.0.tgz",
"integrity": "sha512-hjNax6o/ylDy9lefQEaSDtzaT3iVNtZ3WmpQnbuQNoG4xvnSKf2kSKbihZVO4JRG1TTMejs7CmNRYlWgAL66pQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/core": "4.1.0",
"@shikijs/engine-javascript": "4.1.0",
"@shikijs/engine-oniguruma": "4.1.0",
"@shikijs/langs": "4.1.0",
"@shikijs/themes": "4.1.0",
"@shikijs/types": "4.1.0",
"@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/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4"
},
+1 -1
View File
@@ -10,7 +10,7 @@
[toolchain]
profile = "minimal"
channel = "1.95.0"
channel = "1.96.0"
components = [
# For rust-analyzer
"rust-src",
+1 -1
View File
@@ -13,7 +13,7 @@ pub(crate) async fn ban_room(
State(services): State<crate::State>,
body: Ruma<rooms::ban::v1::Request>,
) -> Result<rooms::ban::v1::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if !services.users.is_admin(sender_user).await {
return Err!(Request(Forbidden("Only server administrators can use this endpoint")));
}
+1 -1
View File
@@ -13,7 +13,7 @@ pub(crate) async fn list_rooms(
State(services): State<crate::State>,
body: Ruma<rooms::list::v1::Request>,
) -> Result<rooms::list::v1::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if !services.users.is_admin(sender_user).await {
return Err!(Request(Forbidden("Only server administrators can use this endpoint")));
}
+32 -16
View File
@@ -27,7 +27,7 @@
use service::{mailer::messages, uiaa::Identity, users::HashedPassword};
use super::{DEVICE_ID_LENGTH, TOKEN_LENGTH};
use crate::Ruma;
use crate::{Ruma, router::ClientIdentity};
pub(crate) mod register;
pub(crate) mod threepid;
@@ -75,13 +75,11 @@ pub(crate) async fn get_register_available_route(
return Err!(Request(UserInUse("User ID is not available.")));
}
if let Some(ref info) = body.appservice_info {
if !info.is_user_match(&user_id) {
return Err!(Request(Exclusive("Username is not in an appservice namespace.")));
}
}
if services.appservice.is_exclusive_user_id(&user_id).await {
if let Some(ClientIdentity::Appservice { appservice_info, .. }) = &body.identity
&& !appservice_info.is_user_match(&user_id)
{
return Err!(Request(Exclusive("Username is not in an appservice namespace.")));
} else if services.appservice.is_exclusive_user_id(&user_id).await {
return Err!(Request(Exclusive("Username is reserved by an appservice.")));
}
@@ -111,7 +109,12 @@ pub(crate) async fn change_password_route(
ClientIp(client): ClientIp,
body: Ruma<change_password::v3::Request>,
) -> Result<change_password::v3::Response> {
let identity = if let Some(ref user_id) = body.sender_user {
let identity = if let Some(user_id) = body
.identity
.as_ref()
.map(ClientIdentity::expect_sender_user)
.transpose()?
{
// A signed-in user is trying to change their password, prompt them for their
// existing one
@@ -157,7 +160,12 @@ pub(crate) async fn change_password_route(
services
.users
.all_device_ids(&sender_user)
.ready_filter(|id| *id != body.sender_device())
.ready_filter(|id| {
body.identity
.as_ref()
.and_then(|identity| identity.sender_device())
.is_none_or(|sender_device| sender_device != *id)
})
.for_each(async |id| services.users.remove_device(&sender_user, &id).await)
.await;
@@ -173,7 +181,12 @@ pub(crate) async fn change_password_route(
.await
.ok()
.as_ref()
.is_some_and(|pusher_device| pusher_device != body.sender_device())
.is_some_and(|pusher_device| {
body.identity
.as_ref()
.and_then(|identity| identity.sender_device())
.is_none_or(|sender_device| sender_device != *pusher_device)
})
.then_some(pushkey)
})
.for_each(async |pushkey| {
@@ -241,9 +254,11 @@ pub(crate) async fn whoami_route(
State(_): State<crate::State>,
body: Ruma<whoami::v3::Request>,
) -> Result<whoami::v3::Response> {
Ok(assign!(whoami::v3::Response::new(body.sender_user().to_owned(), false), {
device_id: body.sender_device,
}))
Ok(
assign!(whoami::v3::Response::new(body.identity.expect_sender_user()?.to_owned(), false), {
device_id: body.identity.sender_device().map(ToOwned::to_owned),
}),
)
}
/// # `POST /_matrix/client/r0/account/deactivate`
@@ -266,9 +281,10 @@ pub(crate) async fn deactivate_route(
// Authentication for this endpoint is technically optional,
// but we require the user to be logged in
let sender_user = body
.sender_user
.identity
.as_ref()
.ok_or_else(|| err!(Request(MissingToken("Missing access token."))))?;
.map(ClientIdentity::expect_sender_user)
.ok_or_else(|| err!(Request(MissingToken("Missing access token."))))??;
// Prompt the user to confirm with their password using UIAA
let _ = services
+7 -9
View File
@@ -59,7 +59,7 @@ pub(crate) async fn register_route(
let allow_registration =
services.config.allow_registration || services.firstrun.is_first_run();
if !allow_registration && body.appservice_info.is_none() {
if !allow_registration && body.identity.is_none() {
info!(
?body.username,
?body.initial_device_display_name,
@@ -71,7 +71,7 @@ pub(crate) async fn register_route(
)));
}
let identity = if body.appservice_info.is_some() {
let identity = if body.identity.is_some() {
// Appservices can skip auth
None
} else {
@@ -107,7 +107,7 @@ pub(crate) async fn register_route(
// For appservice logins, make sure that the user ID is in the appservice's
// namespace
match body.appservice_info {
match body.identity {
| Some(ref info) =>
if !info.is_user_match(&user_id) && !emergency_mode_enabled {
return Err!(Request(Exclusive(
@@ -125,7 +125,7 @@ pub(crate) async fn register_route(
return Err!(Request(Exclusive("Username is reserved by an appservice.")));
}
let password = if body.appservice_info.is_some() {
let password = if body.identity.is_some() {
None
} else if let Some(password) = body.password.as_deref() {
Some(HashedPassword::new(password)?)
@@ -140,9 +140,7 @@ pub(crate) async fn register_route(
let mut displayname = user_id.localpart().to_owned();
// Apply the new user displayname suffix, if it's set
if !services.globals.new_user_displayname_suffix().is_empty()
&& body.appservice_info.is_none()
{
if !services.globals.new_user_displayname_suffix().is_empty() && body.identity.is_none() {
write!(displayname, " {}", services.server.config.new_user_displayname_suffix)?;
}
@@ -209,7 +207,7 @@ pub(crate) async fn register_route(
let device_display_name = body.initial_device_display_name.as_deref().unwrap_or("");
if body.appservice_info.is_none() {
if body.identity.is_none() {
if !device_display_name.is_empty() {
let notice = format!(
"New user \"{user_id}\" registered on this server from IP {client} and device \
@@ -255,7 +253,7 @@ pub(crate) async fn register_route(
}
}
if body.appservice_info.is_none() && !services.server.config.auto_join_rooms.is_empty() {
if body.identity.is_none() && !services.server.config.auto_join_rooms.is_empty() {
for room in &services.server.config.auto_join_rooms {
let Ok(room_id) = services.rooms.alias.resolve(room).await else {
error!(
+17 -10
View File
@@ -13,7 +13,7 @@
};
use service::{mailer::messages, uiaa::Identity};
use crate::Ruma;
use crate::{Ruma, router::ClientIdentity};
/// # `GET _matrix/client/v3/account/3pid`
///
@@ -22,7 +22,7 @@ pub(crate) async fn third_party_route(
State(services): State<crate::State>,
body: Ruma<get_3pids::v3::Request>,
) -> Result<get_3pids::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let mut threepids = vec![];
if let Some(email) = services
@@ -53,6 +53,14 @@ 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."))))??;
if !services.threepid.email_requirement().may_change() {
return Err!(Request(Forbidden("You may not change your email address.")));
}
@@ -76,7 +84,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: body.sender_user.as_deref(),
user_id: Some(sender_user),
verification_link,
},
&body.client_secret,
@@ -107,8 +115,6 @@ pub(crate) async fn add_3pid_route(
State(services): State<crate::State>,
body: Ruma<add_3pid::v3::Request>,
) -> Result<add_3pid::v3::Response> {
let sender_user = body.sender_user();
if !services.threepid.email_requirement().may_change() {
return Err!(Request(Forbidden("You may not change your email address.")));
}
@@ -116,7 +122,10 @@ pub(crate) async fn add_3pid_route(
// Require password auth to add an email
let _ = services
.uiaa
.authenticate_password(&body.auth, Some(Identity::from_user_id(sender_user)))
.authenticate_password(
&body.auth,
Some(Identity::from_user_id(body.identity.expect_sender_user()?)),
)
.await?;
let email = services
@@ -127,7 +136,7 @@ pub(crate) async fn add_3pid_route(
services
.threepid
.associate_localpart_email(sender_user.localpart(), &email)
.associate_localpart_email(body.identity.expect_sender_user()?.localpart(), &email)
.await?;
Ok(add_3pid::v3::Response::new())
@@ -138,8 +147,6 @@ pub(crate) async fn delete_3pid_route(
State(services): State<crate::State>,
body: Ruma<delete_3pid::v3::Request>,
) -> Result<delete_3pid::v3::Response> {
let sender_user = body.sender_user();
if body.medium != Medium::Email {
return Ok(delete_3pid::v3::Response::new(ThirdPartyIdRemovalStatus::NoSupport));
}
@@ -150,7 +157,7 @@ pub(crate) async fn delete_3pid_route(
if services
.threepid
.disassociate_localpart_email(sender_user.localpart())
.disassociate_localpart_email(body.identity.expect_sender_user()?.localpart())
.await
.is_none()
{
+8 -8
View File
@@ -22,9 +22,9 @@ pub(crate) async fn set_global_account_data_route(
State(services): State<crate::State>,
body: Ruma<set_global_account_data::v3::Request>,
) -> Result<set_global_account_data::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if sender_user != body.user_id && body.appservice_info.is_none() {
if sender_user != body.user_id && !body.identity.is_appservice() {
return Err!(Request(Forbidden("You cannot set account data for other users.")));
}
@@ -47,9 +47,9 @@ pub(crate) async fn set_room_account_data_route(
State(services): State<crate::State>,
body: Ruma<set_room_account_data::v3::Request>,
) -> Result<set_room_account_data::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if sender_user != body.user_id && body.appservice_info.is_none() {
if sender_user != body.user_id && !body.identity.is_appservice() {
return Err!(Request(Forbidden("You cannot set account data for other users.")));
}
@@ -72,9 +72,9 @@ pub(crate) async fn get_global_account_data_route(
State(services): State<crate::State>,
body: Ruma<get_global_account_data::v3::Request>,
) -> Result<get_global_account_data::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if sender_user != body.user_id && body.appservice_info.is_none() {
if sender_user != body.user_id && !body.identity.is_appservice() {
return Err!(Request(Forbidden("You cannot get account data of other users.")));
}
@@ -94,9 +94,9 @@ pub(crate) async fn get_room_account_data_route(
State(services): State<crate::State>,
body: Ruma<get_room_account_data::v3::Request>,
) -> Result<get_room_account_data::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if sender_user != body.user_id && body.appservice_info.is_none() {
if sender_user != body.user_id && !body.identity.is_appservice() {
return Err!(Request(Forbidden("You cannot get account data of other users.")));
}
+6 -5
View File
@@ -12,10 +12,11 @@ pub(crate) async fn get_suspended_status(
State(services): State<crate::State>,
body: Ruma<get_suspended::v1::Request>,
) -> Result<get_suspended::v1::Response> {
let sender_user = body.sender_user();
let (admin, active) =
join(services.users.is_admin(sender_user), services.users.is_active(&body.user_id)).await;
let (admin, active) = join(
services.users.is_admin(body.identity.expect_sender_user()?),
services.users.is_active(&body.user_id),
)
.await;
if !admin {
return Err!(Request(Forbidden("Only server administrators can use this endpoint")));
}
@@ -37,7 +38,7 @@ pub(crate) async fn put_suspended_status(
State(services): State<crate::State>,
body: Ruma<set_suspended::v1::Request>,
) -> Result<set_suspended::v1::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let (sender_admin, active, target_admin) = join3(
services.users.is_admin(sender_user),
+6 -4
View File
@@ -11,7 +11,8 @@ pub(crate) async fn create_alias_route(
State(services): State<crate::State>,
body: Ruma<create_alias::v3::Request>,
) -> Result<create_alias::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
@@ -19,7 +20,7 @@ pub(crate) async fn create_alias_route(
services
.rooms
.alias
.appservice_checks(&body.room_alias, &body.appservice_info)
.appservice_checks(&body.room_alias, body.identity.appservice_info())
.await?;
// this isn't apart of alias_checks or delete alias route because we should
@@ -59,7 +60,8 @@ pub(crate) async fn delete_alias_route(
State(services): State<crate::State>,
body: Ruma<delete_alias::v3::Request>,
) -> Result<delete_alias::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
@@ -67,7 +69,7 @@ pub(crate) async fn delete_alias_route(
services
.rooms
.alias
.appservice_checks(&body.room_alias, &body.appservice_info)
.appservice_checks(&body.room_alias, body.identity.appservice_info())
.await?;
services
+2 -4
View File
@@ -1,5 +1,5 @@
use axum::extract::State;
use conduwuit::{Err, Result, err};
use conduwuit::{Err, Result};
use ruma::{
api::{appservice::ping, client::appservice::request_ping},
assign,
@@ -15,9 +15,7 @@ pub(crate) async fn appservice_ping(
State(services): State<crate::State>,
body: Ruma<request_ping::v1::Request>,
) -> Result<request_ping::v1::Response> {
let appservice_info = body.appservice_info.as_ref().ok_or_else(|| {
err!(Request(Forbidden("This endpoint can only be called by appservices.")))
})?;
let appservice_info = &body.identity;
if body.appservice_id != appservice_info.registration.id {
return Err!(Request(Forbidden(
+47 -26
View File
@@ -25,7 +25,7 @@ pub(crate) async fn create_backup_version_route(
) -> Result<create_backup_version::v3::Response> {
let version = services
.key_backups
.create_backup(body.sender_user(), &body.algorithm)?;
.create_backup(body.identity.expect_sender_user()?, &body.algorithm)?;
Ok(create_backup_version::v3::Response::new(version))
}
@@ -40,7 +40,7 @@ pub(crate) async fn update_backup_version_route(
) -> Result<update_backup_version::v3::Response> {
services
.key_backups
.update_backup(body.sender_user(), &body.version, &body.algorithm)
.update_backup(body.identity.expect_sender_user()?, &body.version, &body.algorithm)
.await?;
Ok(update_backup_version::v3::Response::new())
@@ -53,13 +53,15 @@ pub(crate) async fn get_latest_backup_info_route(
State(services): State<crate::State>,
body: Ruma<get_latest_backup_info::v3::Request>,
) -> Result<get_latest_backup_info::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
let (version, algorithm) = services
.key_backups
.get_latest_backup(body.sender_user())
.get_latest_backup(sender_user)
.await
.map_err(|_| err!(Request(NotFound("Key backup does not exist."))))?;
let (count, etag) = get_count_etag(&services, body.sender_user(), &version).await;
let (count, etag) = get_count_etag(&services, sender_user, &version).await;
Ok(get_latest_backup_info::v3::Response::new(algorithm, count, etag, version))
}
@@ -71,15 +73,17 @@ pub(crate) async fn get_backup_info_route(
State(services): State<crate::State>,
body: Ruma<get_backup_info::v3::Request>,
) -> Result<get_backup_info::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
let algorithm = services
.key_backups
.get_backup(body.sender_user(), &body.version)
.get_backup(sender_user, &body.version)
.await
.map_err(|_| {
err!(Request(NotFound("Key backup does not exist at version {:?}", body.version)))
})?;
let (count, etag) = get_count_etag(&services, body.sender_user(), &body.version).await;
let (count, etag) = get_count_etag(&services, sender_user, &body.version).await;
Ok(get_backup_info::v3::Response::new(algorithm, count, etag, body.version.clone()))
}
@@ -96,7 +100,7 @@ pub(crate) async fn delete_backup_version_route(
) -> Result<delete_backup_version::v3::Response> {
services
.key_backups
.delete_backup(body.sender_user(), &body.version)
.delete_backup(body.identity.expect_sender_user()?, &body.version)
.await;
Ok(delete_backup_version::v3::Response::new())
@@ -114,9 +118,11 @@ pub(crate) async fn add_backup_keys_route(
State(services): State<crate::State>,
body: Ruma<add_backup_keys::v3::Request>,
) -> Result<add_backup_keys::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
if services
.key_backups
.get_latest_backup_version(body.sender_user())
.get_latest_backup_version(sender_user)
.await
.is_ok_and(|version| version != body.version)
{
@@ -129,12 +135,12 @@ pub(crate) async fn add_backup_keys_route(
for (session_id, key_data) in &room.sessions {
services
.key_backups
.add_key(body.sender_user(), &body.version, room_id, session_id, key_data)
.add_key(sender_user, &body.version, room_id, session_id, key_data)
.await?;
}
}
let (count, etag) = get_count_etag(&services, body.sender_user(), &body.version).await;
let (count, etag) = get_count_etag(&services, sender_user, &body.version).await;
Ok(add_backup_keys::v3::Response::new(etag, count))
}
@@ -151,9 +157,11 @@ pub(crate) async fn add_backup_keys_for_room_route(
State(services): State<crate::State>,
body: Ruma<add_backup_keys_for_room::v3::Request>,
) -> Result<add_backup_keys_for_room::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
if services
.key_backups
.get_latest_backup_version(body.sender_user())
.get_latest_backup_version(sender_user)
.await
.is_ok_and(|version| version != body.version)
{
@@ -165,11 +173,11 @@ pub(crate) async fn add_backup_keys_for_room_route(
for (session_id, key_data) in &body.sessions {
services
.key_backups
.add_key(body.sender_user(), &body.version, &body.room_id, session_id, key_data)
.add_key(sender_user, &body.version, &body.room_id, session_id, key_data)
.await?;
}
let (count, etag) = get_count_etag(&services, body.sender_user(), &body.version).await;
let (count, etag) = get_count_etag(&services, sender_user, &body.version).await;
Ok(add_backup_keys_for_room::v3::Response::new(etag, count))
}
@@ -186,9 +194,11 @@ pub(crate) async fn add_backup_keys_for_session_route(
State(services): State<crate::State>,
body: Ruma<add_backup_keys_for_session::v3::Request>,
) -> Result<add_backup_keys_for_session::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
if services
.key_backups
.get_latest_backup_version(body.sender_user())
.get_latest_backup_version(sender_user)
.await
.is_ok_and(|version| version != body.version)
{
@@ -201,7 +211,7 @@ pub(crate) async fn add_backup_keys_for_session_route(
let mut ok_to_replace = true;
if let Some(old_key) = &services
.key_backups
.get_session(body.sender_user(), &body.version, &body.room_id, &body.session_id)
.get_session(sender_user, &body.version, &body.room_id, &body.session_id)
.await
.ok()
{
@@ -260,7 +270,7 @@ pub(crate) async fn add_backup_keys_for_session_route(
services
.key_backups
.add_key(
body.sender_user(),
sender_user,
&body.version,
&body.room_id,
&body.session_id,
@@ -269,7 +279,7 @@ pub(crate) async fn add_backup_keys_for_session_route(
.await?;
}
let (count, etag) = get_count_etag(&services, body.sender_user(), &body.version).await;
let (count, etag) = get_count_etag(&services, sender_user, &body.version).await;
Ok(add_backup_keys_for_session::v3::Response::new(etag, count))
}
@@ -283,7 +293,7 @@ pub(crate) async fn get_backup_keys_route(
) -> Result<get_backup_keys::v3::Response> {
let rooms = services
.key_backups
.get_all(body.sender_user(), &body.version)
.get_all(body.identity.expect_sender_user()?, &body.version)
.await;
Ok(get_backup_keys::v3::Response::new(rooms))
@@ -298,7 +308,7 @@ pub(crate) async fn get_backup_keys_for_room_route(
) -> Result<get_backup_keys_for_room::v3::Response> {
let sessions = services
.key_backups
.get_room(body.sender_user(), &body.version, &body.room_id)
.get_room(body.identity.expect_sender_user()?, &body.version, &body.room_id)
.await;
Ok(get_backup_keys_for_room::v3::Response::new(sessions))
@@ -313,7 +323,12 @@ pub(crate) async fn get_backup_keys_for_session_route(
) -> Result<get_backup_keys_for_session::v3::Response> {
let key_data = services
.key_backups
.get_session(body.sender_user(), &body.version, &body.room_id, &body.session_id)
.get_session(
body.identity.expect_sender_user()?,
&body.version,
&body.room_id,
&body.session_id,
)
.await
.map_err(|_| {
err!(Request(NotFound(debug_error!("Backup key not found for this user's session."))))
@@ -329,12 +344,14 @@ pub(crate) async fn delete_backup_keys_route(
State(services): State<crate::State>,
body: Ruma<delete_backup_keys::v3::Request>,
) -> Result<delete_backup_keys::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
services
.key_backups
.delete_all_keys(body.sender_user(), &body.version)
.delete_all_keys(sender_user, &body.version)
.await;
let (count, etag) = get_count_etag(&services, body.sender_user(), &body.version).await;
let (count, etag) = get_count_etag(&services, sender_user, &body.version).await;
Ok(delete_backup_keys::v3::Response::new(etag, count))
}
@@ -346,12 +363,14 @@ pub(crate) async fn delete_backup_keys_for_room_route(
State(services): State<crate::State>,
body: Ruma<delete_backup_keys_for_room::v3::Request>,
) -> Result<delete_backup_keys_for_room::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
services
.key_backups
.delete_room_keys(body.sender_user(), &body.version, &body.room_id)
.delete_room_keys(sender_user, &body.version, &body.room_id)
.await;
let (count, etag) = get_count_etag(&services, body.sender_user(), &body.version).await;
let (count, etag) = get_count_etag(&services, sender_user, &body.version).await;
Ok(delete_backup_keys_for_room::v3::Response::new(etag, count))
}
@@ -363,12 +382,14 @@ pub(crate) async fn delete_backup_keys_for_session_route(
State(services): State<crate::State>,
body: Ruma<delete_backup_keys_for_session::v3::Request>,
) -> Result<delete_backup_keys_for_session::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
services
.key_backups
.delete_room_key(body.sender_user(), &body.version, &body.room_id, &body.session_id)
.delete_room_key(sender_user, &body.version, &body.room_id, &body.session_id)
.await;
let (count, etag) = get_count_etag(&services, body.sender_user(), &body.version).await;
let (count, etag) = get_count_etag(&services, sender_user, &body.version).await;
Ok(delete_backup_keys_for_session::v3::Response::new(etag, count))
}
+1 -1
View File
@@ -50,7 +50,7 @@ pub(crate) async fn get_capabilities_route(
if services
.users
.is_admin(body.sender_user.as_ref().unwrap())
.is_admin(body.identity.expect_sender_user()?)
.await
{
// Advertise suspension API
+3 -3
View File
@@ -37,8 +37,8 @@ pub(crate) async fn get_context_route(
State(services): State<crate::State>,
body: Ruma<get_context::v3::Request>,
) -> Result<get_context::v3::Response> {
let sender = body.sender();
let (sender_user, sender_device) = sender;
let sender_user = body.identity.expect_sender_user()?;
let sender_device = body.identity.sender_device();
let room_id = &body.room_id;
let event_id = &body.event_id;
let filter = &body.filter;
@@ -143,7 +143,7 @@ pub(crate) async fn get_context_route(
let lazy_loading_context = lazy_loading::Context {
user_id: sender_user,
device_id: Some(sender_device),
device_id: sender_device,
room_id,
token: Some(base_count.into_unsigned()),
options: Some(&filter.lazy_load_options),
+5 -10
View File
@@ -25,16 +25,11 @@ pub(crate) async fn put_dehydrated_device_route(
ClientIp(client): ClientIp,
body: Ruma<put_dehydrated_device::Request>,
) -> Result<put_dehydrated_device::Response> {
let sender_user = body
.sender_user
.as_deref()
.expect("AccessToken authentication required");
let device_id = body.body.device_id.clone();
let device_id = body.device_id.clone();
services
.users
.set_dehydrated_device(sender_user, body.body)
.set_dehydrated_device(body.identity.expect_sender_user()?, body.body)
.await?;
Ok(put_dehydrated_device::Response::new(device_id))
@@ -49,7 +44,7 @@ pub(crate) async fn delete_dehydrated_device_route(
ClientIp(client): ClientIp,
body: Ruma<delete_dehydrated_device::Request>,
) -> Result<delete_dehydrated_device::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let device_id = services.users.get_dehydrated_device_id(sender_user).await?;
@@ -67,7 +62,7 @@ pub(crate) async fn get_dehydrated_device_route(
ClientIp(client): ClientIp,
body: Ruma<get_dehydrated_device::Request>,
) -> Result<get_dehydrated_device::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let device = services.users.get_dehydrated_device(sender_user).await?;
@@ -83,7 +78,7 @@ pub(crate) async fn get_dehydrated_events_route(
ClientIp(client): ClientIp,
body: Ruma<get_events::Request>,
) -> Result<get_events::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let device_id = &body.body.device_id;
let existing_id = services.users.get_dehydrated_device_id(sender_user).await;
+8 -8
View File
@@ -21,7 +21,7 @@ pub(crate) async fn get_devices_route(
) -> Result<get_devices::v3::Response> {
let devices: Vec<device::Device> = services
.users
.all_devices_metadata(body.sender_user())
.all_devices_metadata(body.identity.expect_sender_user()?)
.collect()
.await;
@@ -37,7 +37,7 @@ pub(crate) async fn get_device_route(
) -> Result<get_device::v3::Response> {
let device = services
.users
.get_device_metadata(body.sender_user(), &body.body.device_id)
.get_device_metadata(body.identity.expect_sender_user()?, &body.body.device_id)
.await
.map_err(|_| err!(Request(NotFound("Device not found."))))?;
@@ -53,8 +53,8 @@ pub(crate) async fn update_device_route(
ClientIp(client): ClientIp,
body: Ruma<update_device::v3::Request>,
) -> Result<update_device::v3::Response> {
let sender_user = body.sender_user();
let appservice = body.appservice_info.as_ref();
let sender_user = body.identity.expect_sender_user()?;
let appservice = body.identity.appservice_info();
match services
.users
@@ -118,8 +118,8 @@ pub(crate) async fn delete_device_route(
State(services): State<crate::State>,
body: Ruma<delete_device::v3::Request>,
) -> Result<delete_device::v3::Response> {
let sender_user = body.sender_user();
let appservice = body.appservice_info.as_ref();
let sender_user = body.identity.expect_sender_user()?;
let appservice = body.identity.appservice_info();
// Appservices get to skip UIAA for this endpoint
if appservice.is_none() {
@@ -154,8 +154,8 @@ pub(crate) async fn delete_devices_route(
State(services): State<crate::State>,
body: Ruma<delete_devices::v3::Request>,
) -> Result<delete_devices::v3::Response> {
let sender_user = body.sender_user();
let appservice = body.appservice_info.as_ref();
let sender_user = body.identity.expect_sender_user()?;
let appservice = body.identity.appservice_info();
// Appservices get to skip UIAA for this endpoint
if appservice.is_none() {
+2 -2
View File
@@ -112,7 +112,7 @@ pub(crate) async fn set_room_visibility_route(
ClientIp(client): ClientIp,
body: Ruma<set_room_visibility::v3::Request>,
) -> Result<set_room_visibility::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if !services.rooms.metadata.exists(&body.room_id).await {
// Return 404 if the room doesn't exist
@@ -130,7 +130,7 @@ pub(crate) async fn set_room_visibility_route(
| room::Visibility::Public => {
if services.server.config.lockdown_public_room_directory
&& !services.users.is_admin(sender_user).await
&& body.appservice_info.is_none()
&& !body.identity.is_appservice()
{
info!(
"Non-admin user {sender_user} tried to publish {0} to the room directory \
+2 -2
View File
@@ -15,7 +15,7 @@ pub(crate) async fn get_filter_route(
) -> Result<get_filter::v3::Response> {
services
.users
.get_filter(body.sender_user(), &body.filter_id)
.get_filter(body.identity.expect_sender_user()?, &body.filter_id)
.await
.map(get_filter::v3::Response::new)
.map_err(|_| err!(Request(NotFound("Filter not found."))))
@@ -30,7 +30,7 @@ pub(crate) async fn create_filter_route(
) -> Result<create_filter::v3::Response> {
let filter_id = services
.users
.create_filter(body.sender_user(), &body.filter);
.create_filter(body.identity.expect_sender_user()?, &body.filter);
Ok(create_filter::v3::Response::new(filter_id))
}
+6 -5
View File
@@ -41,7 +41,8 @@ pub(crate) async fn upload_keys_route(
State(services): State<crate::State>,
body: Ruma<upload_keys::v3::Request>,
) -> Result<upload_keys::v3::Response> {
let (sender_user, sender_device) = body.sender();
let sender_user = body.identity.expect_sender_user()?;
let sender_device = body.identity.expect_sender_device()?;
for (key_id, one_time_key) in &body.one_time_keys {
if one_time_key
@@ -154,7 +155,7 @@ pub(crate) async fn get_keys_route(
State(services): State<crate::State>,
body: Ruma<get_keys::v3::Request>,
) -> Result<get_keys::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
get_keys_helper(
&services,
@@ -191,7 +192,7 @@ pub(crate) async fn upload_signing_keys_route(
State(services): State<crate::State>,
body: Ruma<upload_signing_keys::v3::Request>,
) -> Result<upload_signing_keys::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if uiaa_needed_to_upload_keys(
services,
@@ -287,7 +288,7 @@ pub(crate) async fn upload_signatures_route(
return Ok(upload_signatures::v3::Response::new());
}
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
for (user_id, keys) in &body.signed_keys {
for (key_id, key) in keys {
@@ -340,7 +341,7 @@ pub(crate) async fn get_key_changes_route(
State(services): State<crate::State>,
body: Ruma<get_key_changes::v3::Request>,
) -> Result<get_key_changes::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let mut device_list_updates = HashSet::new();
+5 -5
View File
@@ -53,7 +53,7 @@ pub(crate) async fn create_content_route(
ClientIp(client): ClientIp,
body: Ruma<create_content::v3::Request>,
) -> Result<create_content::v3::Response> {
let user = body.sender_user();
let user = body.identity.expect_sender_user()?;
if services.users.is_suspended(user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
@@ -92,7 +92,7 @@ pub(crate) async fn get_content_thumbnail_route(
ClientIp(client): ClientIp,
body: Ruma<get_content_thumbnail::v1::Request>,
) -> Result<get_content_thumbnail::v1::Response> {
let user = body.sender_user();
let user = body.identity.expect_sender_user()?;
let dim = Dim::from_ruma(body.width, body.height, body.method.clone())?;
let mxc = Mxc {
@@ -142,7 +142,7 @@ pub(crate) async fn get_content_route(
ClientIp(client): ClientIp,
body: Ruma<get_content::v1::Request>,
) -> Result<get_content::v1::Response> {
let user = body.sender_user();
let user = body.identity.expect_sender_user()?;
let mxc = Mxc {
server_name: &body.server_name,
@@ -189,7 +189,7 @@ pub(crate) async fn get_content_as_filename_route(
ClientIp(client): ClientIp,
body: Ruma<get_content_as_filename::v1::Request>,
) -> Result<get_content_as_filename::v1::Response> {
let user = body.sender_user();
let user = body.identity.expect_sender_user()?;
let mxc = Mxc {
server_name: &body.server_name,
@@ -240,7 +240,7 @@ pub(crate) async fn get_media_preview_route(
ClientIp(client): ClientIp,
body: Ruma<get_media_preview::v1::Request>,
) -> Result<get_media_preview::v1::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let url = &body.url;
let url = Url::parse(&body.url).map_err(|e| {
+1 -1
View File
@@ -56,7 +56,7 @@ pub(crate) async fn get_media_preview_legacy_route(
ClientIp(client): ClientIp,
body: Ruma<get_media_preview::v3::Request>,
) -> Result<get_media_preview::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let url = &body.url;
let url = Url::parse(&body.url).map_err(|e| {
+1 -1
View File
@@ -15,7 +15,7 @@ pub(crate) async fn ban_user_route(
State(services): State<crate::State>,
body: Ruma<ban_user::v3::Request>,
) -> Result<ban_user::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if sender_user == body.user_id {
return Err!(Request(Forbidden("You cannot ban yourself.")));
+1 -1
View File
@@ -18,7 +18,7 @@ pub(crate) async fn forget_room_route(
State(services): State<crate::State>,
body: Ruma<forget_room::v3::Request>,
) -> Result<forget_room::v3::Response> {
let user_id = body.sender_user();
let user_id = body.identity.expect_sender_user()?;
let room_id = &body.room_id;
let joined = services.rooms.state_cache.is_joined(user_id, room_id);
+1 -1
View File
@@ -29,7 +29,7 @@ pub(crate) async fn invite_user_route(
ClientIp(client): ClientIp,
body: Ruma<invite_user::v3::Request>,
) -> Result<invite_user::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
+2 -2
View File
@@ -28,7 +28,7 @@ pub(crate) async fn join_room_by_id_route(
ClientIp(client): ClientIp,
body: Ruma<join_room_by_id::v3::Request>,
) -> Result<join_room_by_id::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
@@ -97,7 +97,7 @@ pub(crate) async fn join_room_by_id_or_alias_route(
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.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let body = &body.body;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
+1 -1
View File
@@ -15,7 +15,7 @@ pub(crate) async fn kick_user_route(
State(services): State<crate::State>,
body: Ruma<kick_user::v3::Request>,
) -> Result<kick_user::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
+1 -1
View File
@@ -51,7 +51,7 @@ pub(crate) async fn knock_room_route(
ClientIp(client): ClientIp,
body: Ruma<knock_room::v3::Request>,
) -> Result<knock_room::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let body = &body.body;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
+9 -4
View File
@@ -32,10 +32,15 @@ pub(crate) async fn leave_room_route(
State(services): State<crate::State>,
body: Ruma<leave_room::v3::Request>,
) -> Result<leave_room::v3::Response> {
leave_room(&services, body.sender_user(), &body.room_id, body.reason.clone())
.boxed()
.await
.map(|()| leave_room::v3::Response::new())
leave_room(
&services,
body.identity.expect_sender_user()?,
&body.room_id,
body.reason.clone(),
)
.boxed()
.await
.map(|()| leave_room::v3::Response::new())
}
// Make a user leave all their joined rooms, rescinds knocks, forgets all rooms,
+2 -2
View File
@@ -30,7 +30,7 @@ pub(crate) async fn get_member_events_route(
State(services): State<crate::State>,
body: Ruma<get_member_events::v3::Request>,
) -> Result<get_member_events::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let membership = body.membership.as_ref();
let not_membership = body.not_membership.as_ref();
@@ -72,7 +72,7 @@ pub(crate) async fn joined_members_route(
if !services
.rooms
.state_accessor
.user_can_see_state_events(body.sender_user(), &body.room_id)
.user_can_see_state_events(body.identity.expect_sender_user()?, &body.room_id)
.await
{
return Err!(Request(Forbidden("You don't have permission to view this room.")));
+1 -1
View File
@@ -40,7 +40,7 @@ pub(crate) async fn joined_rooms_route(
let joined_rooms = services
.rooms
.state_cache
.rooms_joined(body.sender_user())
.rooms_joined(body.identity.expect_sender_user()?)
.collect()
.await;
+1 -1
View File
@@ -14,7 +14,7 @@ pub(crate) async fn unban_user_route(
State(services): State<crate::State>,
body: Ruma<unban_user::v3::Request>,
) -> Result<unban_user::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
+4 -15
View File
@@ -23,7 +23,7 @@
};
use futures::{FutureExt, StreamExt, TryFutureExt, future::OptionFuture, pin_mut};
use ruma::{
DeviceId, RoomId, UserId,
RoomId, UserId,
api::{
Direction,
client::{filter::RoomEventFilter, message::get_message_events},
@@ -37,7 +37,6 @@
serde::Raw,
};
use ruminuwuity::invite_permission_config::FilterLevel;
use tracing::warn;
use crate::Ruma;
@@ -76,8 +75,8 @@ pub(crate) async fn get_message_events_route(
ClientIp(client_ip): ClientIp,
body: Ruma<get_message_events::v3::Request>,
) -> Result<get_message_events::v3::Response> {
let sender_user = body.sender_user();
let sender_device = body.sender_device.as_deref();
let sender_user = body.identity.expect_sender_user()?;
let sender_device = body.identity.sender_device();
let room_id = &body.room_id;
let filter = &body.filter;
@@ -158,17 +157,7 @@ pub(crate) async fn get_message_events_route(
let lazy_loading_context = lazy_loading::Context {
user_id: sender_user,
device_id: sender_device.or_else(|| {
if let Some(registration) = body.appservice_info.as_ref() {
Some(<&DeviceId>::from(registration.registration.id.as_str()))
} else {
warn!(
"No device_id provided and no appservice registration found, this should be \
unreachable"
);
None
}
}),
device_id: sender_device,
room_id,
token: Some(from.into_unsigned()),
options: Some(&filter.lazy_load_options),
+1 -1
View File
@@ -15,7 +15,7 @@ pub(crate) async fn get_mutual_rooms_route(
State(services): State<crate::State>,
body: Ruma<mutual_rooms::unstable::Request>,
) -> Result<mutual_rooms::unstable::Response> {
let sender_user = body.sender_user();
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.")));
+1 -1
View File
@@ -16,7 +16,7 @@ pub(crate) async fn create_openid_token_route(
State(services): State<crate::State>,
body: Ruma<account::request_openid_token::v3::Request>,
) -> Result<account::request_openid_token::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if sender_user != body.user_id {
return Err!(Request(InvalidParam(
+5 -3
View File
@@ -16,17 +16,19 @@ pub(crate) async fn set_presence_route(
State(services): State<crate::State>,
body: Ruma<set_presence::v3::Request>,
) -> Result<set_presence::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
if !services.config.allow_local_presence {
return Err!(Request(Forbidden("Presence is disabled on this server")));
}
if body.sender_user() != body.user_id && body.appservice_info.is_none() {
if sender_user != body.user_id && !body.identity.is_appservice() {
return Err!(Request(InvalidParam("Not allowed to set presence of other users")));
}
services
.presence
.set_presence(body.sender_user(), &body.presence, None, None, body.status_msg.clone())
.set_presence(sender_user, &body.presence, None, None, body.status_msg.clone())
.await?;
Ok(set_presence::v3::Response::new())
@@ -49,7 +51,7 @@ pub(crate) async fn get_presence_route(
let has_shared_rooms = services
.rooms
.state_cache
.user_sees_user(body.sender_user(), &body.user_id)
.user_sees_user(body.identity.expect_sender_user()?, &body.user_id)
.await;
if has_shared_rooms {
+135 -53
View File
@@ -8,12 +8,12 @@
UserId,
api::{
client::profile::{
delete_profile_field, get_profile, get_profile_field, set_profile_field,
PropagateTo, delete_profile_field, get_profile, get_profile_field, set_profile_field,
},
federation,
},
assign,
events::room::member::{MembershipState, RoomMemberEventContent},
events::room::member::MembershipState,
presence::PresenceState,
profile::{ProfileFieldName, ProfileFieldValue},
};
@@ -51,9 +51,12 @@ pub(crate) async fn set_profile_field_route(
State(services): State<crate::State>,
body: Ruma<set_profile_field::v3::Request>,
) -> Result<set_profile_field::v3::Response> {
if body.user_id != body.sender_user()
&& !(body.appservice_info.is_some()
|| services.admin.user_is_admin(body.sender_user()).await)
if body.user_id != body.identity.expect_sender_user()?
&& !(body.identity.is_appservice()
|| services
.admin
.user_is_admin(body.identity.expect_sender_user()?)
.await)
{
return Err!(Request(Forbidden("You may not change other users' profile data.")));
}
@@ -62,8 +65,13 @@ pub(crate) async fn set_profile_field_route(
return Err!(Request(InvalidParam("You may not change a remote user's profile data.")));
}
set_profile_field(&services, &body.user_id, ProfileFieldChange::Set(body.value.clone()))
.await?;
set_profile_field(
&services,
&body.user_id,
ProfileFieldChange::Set(body.value.clone()),
body.propagate_to.clone(),
)
.await?;
Ok(set_profile_field::v3::Response::new())
}
@@ -72,9 +80,12 @@ pub(crate) async fn delete_profile_field_route(
State(services): State<crate::State>,
body: Ruma<delete_profile_field::v3::Request>,
) -> Result<delete_profile_field::v3::Response> {
if body.user_id != body.sender_user()
&& !(body.appservice_info.is_some()
|| services.admin.user_is_admin(body.sender_user()).await)
if body.user_id != body.identity.expect_sender_user()?
&& !(body.identity.is_appservice()
|| services
.admin
.user_is_admin(body.identity.expect_sender_user()?)
.await)
{
return Err!(Request(Forbidden("You may not change other users' profile data.")));
}
@@ -83,8 +94,13 @@ pub(crate) async fn delete_profile_field_route(
return Err!(Request(InvalidParam("You may not change a remote user's profile data.")));
}
set_profile_field(&services, &body.user_id, ProfileFieldChange::Delete(body.field.clone()))
.await?;
set_profile_field(
&services,
&body.user_id,
ProfileFieldChange::Delete(body.field.clone()),
body.propagate_to.clone(),
)
.await?;
Ok(delete_profile_field::v3::Response::new())
}
@@ -119,7 +135,13 @@ async fn fetch_full_profile(
continue;
};
let _ = set_profile_field(services, user_id, ProfileFieldChange::Set(value)).await;
let _ = set_profile_field(
services,
user_id,
ProfileFieldChange::Set(value),
PropagateTo::None,
)
.await;
}
Some(BTreeMap::from_iter(response))
@@ -153,8 +175,13 @@ async fn fetch_profile_field(
if let Some(value) = response.get(field.as_str()).map(ToOwned::to_owned) {
if let Ok(value) = ProfileFieldValue::new(field.as_str(), value) {
let _ = set_profile_field(services, user_id, ProfileFieldChange::Set(value.clone()))
.await;
let _ = set_profile_field(
services,
user_id,
ProfileFieldChange::Set(value.clone()),
PropagateTo::None,
)
.await;
Ok(Some(value))
} else {
@@ -163,7 +190,13 @@ async fn fetch_profile_field(
)))
}
} else {
let _ = set_profile_field(services, user_id, ProfileFieldChange::Delete(field)).await;
let _ = set_profile_field(
services,
user_id,
ProfileFieldChange::Delete(field),
PropagateTo::None,
)
.await;
Ok(None)
}
@@ -256,6 +289,7 @@ async fn set_profile_field(
services: &Services,
user_id: &UserId,
change: ProfileFieldChange,
propagate_to: PropagateTo,
) -> Result<()> {
const MAX_KEY_LENGTH_BYTES: usize = 255;
const MAX_PROFILE_LENGTH_BYTES: usize = 65536;
@@ -303,6 +337,91 @@ async fn set_profile_field(
}
}
// If the user is local and changed their displayname or avatar_url, update it
// in all their joined rooms. This is done before updating their profile data
// so we can check the old value of the field if `propagate_to` is `unchanged`.
if matches!(field_name, ProfileFieldName::AvatarUrl | ProfileFieldName::DisplayName)
&& matches!(propagate_to, PropagateTo::All | PropagateTo::Unchanged)
&& services.globals.user_is_local(user_id)
{
let current_displayname = services.users.displayname(user_id).await.ok();
let current_avatar_url = services.users.avatar_url(user_id).await.ok();
let mut all_joined_rooms = services.rooms.state_cache.rooms_joined(user_id);
while let Some(room_id) = all_joined_rooms.next().await {
// TODO: this clobbers any custom fields on the event content
let mut current_membership = services
.rooms
.state_accessor
.get_member(&room_id, user_id)
.await
.expect("should be able to fetch membership event for joined room");
assert_eq!(
current_membership.membership,
MembershipState::Join,
"user should be joined"
);
// If `propagate_to` is `unchanged`, and the current value of the field we're
// updating was changed from its global value in this room, skip it.
if matches!(propagate_to, PropagateTo::Unchanged) {
let field_changed_from_global = match field_name {
| ProfileFieldName::AvatarUrl =>
current_membership.avatar_url.as_ref() != current_avatar_url.as_ref(),
| ProfileFieldName::DisplayName =>
current_membership.displayname.as_ref() != current_displayname.as_ref(),
| _ => unreachable!(),
};
if field_changed_from_global {
continue;
}
}
let state_lock = services.rooms.state.mutex.lock(room_id.as_str()).await;
// Preserve keys in accordance with the key copying rules
current_membership.reason = None;
current_membership.join_authorized_via_users_server = None;
match &change {
| ProfileFieldChange::Set(ProfileFieldValue::AvatarUrl(avatar_url)) => {
current_membership.avatar_url = Some(avatar_url.clone());
},
| ProfileFieldChange::Set(ProfileFieldValue::DisplayName(displayname)) => {
current_membership.displayname = Some(displayname.clone());
},
| ProfileFieldChange::Delete(ProfileFieldName::AvatarUrl) => {
current_membership.avatar_url = None;
},
| ProfileFieldChange::Delete(ProfileFieldName::DisplayName) => {
current_membership.displayname = None;
},
| _ => unreachable!(),
}
let _ = services
.rooms
.timeline
.build_and_append_pdu(
PartialPdu::state(user_id.to_string(), &current_membership),
user_id,
Some(&room_id),
&state_lock,
)
.await;
}
if services.config.allow_local_presence {
// Send a presence EDU to indicate the profile changed
let _ = services
.presence
.ping_presence(user_id, &PresenceState::Online)
.await;
}
}
match change {
| ProfileFieldChange::Set(ProfileFieldValue::DisplayName(displayname)) => {
services
@@ -326,42 +445,5 @@ async fn set_profile_field(
.set_profile_key(user_id, other.field_name().as_str(), other.value()),
}
// If the user is local and changed their displayname or avatar_url, update it
// in all their joined rooms
if matches!(field_name, ProfileFieldName::AvatarUrl | ProfileFieldName::DisplayName)
&& services.globals.user_is_local(user_id)
{
let displayname = services.users.displayname(user_id).await.ok();
let avatar_url = services.users.avatar_url(user_id).await.ok();
let membership_content = assign!(
RoomMemberEventContent::new(MembershipState::Join), { displayname, avatar_url }
);
let mut all_joined_rooms = services.rooms.state_cache.rooms_joined(user_id);
while let Some(room_id) = all_joined_rooms.next().await {
let state_lock = services.rooms.state.mutex.lock(room_id.as_str()).await;
let _ = services
.rooms
.timeline
.build_and_append_pdu(
PartialPdu::state(user_id.to_string(), &membership_content),
user_id,
Some(&room_id),
&state_lock,
)
.await;
}
if services.config.allow_local_presence {
// Send a presence EDU to indicate the profile changed
let _ = services
.presence
.ping_presence(user_id, &PresenceState::Online)
.await;
}
}
Ok(())
}
+13 -12
View File
@@ -30,7 +30,7 @@ pub(crate) async fn get_pushrules_all_route(
State(services): State<crate::State>,
body: Ruma<get_pushrules_all::v3::Request>,
) -> Result<get_pushrules_all::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let Some(content_value) = services
.account_data
@@ -101,7 +101,7 @@ pub(crate) async fn get_pushrules_global_route(
State(services): State<crate::State>,
body: Ruma<get_pushrules_global_scope::v3::Request>,
) -> Result<get_pushrules_global_scope::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let Some(content_value) = services
.account_data
@@ -189,7 +189,7 @@ pub(crate) async fn get_pushrule_route(
State(services): State<crate::State>,
body: Ruma<get_pushrule::v3::Request>,
) -> Result<get_pushrule::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_user = body.identity.expect_sender_user()?;
// remove old deprecated mentions push rules as per MSC4210
#[allow(deprecated)]
@@ -226,7 +226,7 @@ pub(crate) async fn set_pushrule_route(
State(services): State<crate::State>,
body: Ruma<set_pushrule::v3::Request>,
) -> Result<set_pushrule::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let body = &body.body;
let mut account_data: PushRulesEvent = services
.account_data
@@ -282,7 +282,7 @@ pub(crate) async fn get_pushrule_actions_route(
State(services): State<crate::State>,
body: Ruma<get_pushrule_actions::v3::Request>,
) -> Result<get_pushrule_actions::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
// remove old deprecated mentions push rules as per MSC4210
#[allow(deprecated)]
@@ -316,7 +316,7 @@ pub(crate) async fn set_pushrule_actions_route(
State(services): State<crate::State>,
body: Ruma<set_pushrule_actions::v3::Request>,
) -> Result<set_pushrule_actions::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let mut account_data: PushRulesEvent = services
.account_data
@@ -349,7 +349,7 @@ pub(crate) async fn get_pushrule_enabled_route(
State(services): State<crate::State>,
body: Ruma<get_pushrule_enabled::v3::Request>,
) -> Result<get_pushrule_enabled::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
// remove old deprecated mentions push rules as per MSC4210
#[allow(deprecated)]
@@ -383,7 +383,7 @@ pub(crate) async fn set_pushrule_enabled_route(
State(services): State<crate::State>,
body: Ruma<set_pushrule_enabled::v3::Request>,
) -> Result<set_pushrule_enabled::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let mut account_data: PushRulesEvent = services
.account_data
@@ -416,7 +416,7 @@ pub(crate) async fn delete_pushrule_route(
State(services): State<crate::State>,
body: Ruma<delete_pushrule::v3::Request>,
) -> Result<delete_pushrule::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let mut account_data: PushRulesEvent = services
.account_data
@@ -458,7 +458,7 @@ pub(crate) async fn get_pushers_route(
State(services): State<crate::State>,
body: Ruma<get_pushers::v3::Request>,
) -> Result<get_pushers::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
Ok(get_pushers::v3::Response::new(services.pusher.get_pushers(sender_user).await))
}
@@ -472,11 +472,12 @@ pub(crate) async fn set_pushers_route(
State(services): State<crate::State>,
body: Ruma<set_pusher::v3::Request>,
) -> Result<set_pusher::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let sender_device = body.identity.expect_sender_device()?;
services
.pusher
.set_pusher(sender_user, body.sender_device(), &body.action)
.set_pusher(sender_user, sender_device, &body.action)
.await?;
Ok(set_pusher::v3::Response::new())
+4 -3
View File
@@ -26,7 +26,7 @@ pub(crate) async fn set_read_marker_route(
State(services): State<crate::State>,
body: Ruma<set_read_marker::v3::Request>,
) -> Result<set_read_marker::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if let Some(event) = &body.fully_read {
let fully_read_event = FullyReadEvent::new(FullyReadEventContent::new(event.to_owned()));
@@ -118,10 +118,11 @@ pub(crate) async fn create_receipt_route(
ClientIp(client_ip): ClientIp,
body: Ruma<create_receipt::v3::Request>,
) -> Result<create_receipt::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
services
.users
.update_device_last_seen(sender_user, body.sender_device.as_deref(), client_ip)
.update_device_last_seen(sender_user, body.identity.sender_device(), client_ip)
.await;
if matches!(
+2 -2
View File
@@ -17,10 +17,10 @@ pub(crate) async fn redact_event_route(
ClientIp(client_ip): ClientIp,
body: Ruma<redact_event::v3::Request>,
) -> Result<redact_event::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
services
.users
.update_device_last_seen(sender_user, body.sender_device.as_deref(), client_ip)
.update_device_last_seen(sender_user, body.identity.sender_device(), client_ip)
.await;
let body = &body.body;
if services.users.is_suspended(sender_user).await? {
+3 -3
View File
@@ -28,7 +28,7 @@ pub(crate) async fn get_relating_events_with_rel_type_and_event_type_route(
) -> Result<get_relating_events_with_rel_type_and_event_type::v1::Response> {
paginate_relations_with_filter(
&services,
body.sender_user(),
body.identity.expect_sender_user()?,
&body.room_id,
&body.event_id,
body.event_type.clone().into(),
@@ -56,7 +56,7 @@ pub(crate) async fn get_relating_events_with_rel_type_route(
) -> Result<get_relating_events_with_rel_type::v1::Response> {
paginate_relations_with_filter(
&services,
body.sender_user(),
body.identity.expect_sender_user()?,
&body.room_id,
&body.event_id,
None,
@@ -84,7 +84,7 @@ pub(crate) async fn get_relating_events_route(
) -> Result<get_relating_events::v1::Response> {
paginate_relations_with_filter(
&services,
body.sender_user(),
body.identity.expect_sender_user()?,
&body.room_id,
&body.event_id,
None,
+4 -4
View File
@@ -36,7 +36,7 @@ pub(crate) async fn report_room_route(
ClientIp(client): ClientIp,
body: Ruma<report_room::v3::Request>,
) -> Result<report_room::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
@@ -92,7 +92,7 @@ pub(crate) async fn report_event_route(
body: Ruma<report_content::v3::Request>,
) -> Result<report_content::v3::Response> {
// user authentication
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
@@ -135,8 +135,8 @@ pub(crate) async fn report_user_route(
ClientIp(client): ClientIp,
body: Ruma<report_user::v3::Request>,
) -> Result<report_user::v3::Response> {
// user authentication
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_user = body.identity.expect_sender_user()?;
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
+1 -1
View File
@@ -15,7 +15,7 @@ pub(crate) async fn get_room_aliases_route(
State(services): State<crate::State>,
body: Ruma<aliases::v3::Request>,
) -> Result<aliases::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if !services
.rooms
+4 -4
View File
@@ -61,10 +61,10 @@ pub(crate) async fn create_room_route(
) -> Result<create_room::v3::Response> {
use create_room::v3::RoomPreset;
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if !services.globals.allow_room_creation()
&& body.appservice_info.is_none()
&& !body.identity.is_appservice()
&& !services.users.is_admin(sender_user).await
{
return Err!(Request(Forbidden("Room creation has been disabled.",)));
@@ -130,7 +130,7 @@ pub(crate) async fn create_room_route(
if body.visibility == room::Visibility::Public
&& services.server.config.lockdown_public_room_directory
&& !services.users.is_admin(sender_user).await
&& body.appservice_info.is_none()
&& !body.identity.is_appservice()
{
warn!(
"Non-admin user {sender_user} tried to publish {room_id:?} to the room directory \
@@ -186,7 +186,7 @@ pub(crate) async fn create_room_route(
let alias: Option<OwnedRoomAliasId> = match body.room_alias_name.as_ref() {
| Some(alias) =>
Some(room_alias_check(&services, alias, body.appservice_info.as_ref()).await?),
Some(room_alias_check(&services, alias, body.identity.appservice_info()).await?),
| _ => None,
};
+5 -4
View File
@@ -12,6 +12,7 @@ pub(crate) async fn get_room_event_route(
State(ref services): State<crate::State>,
ref body: Ruma<get_room_event::v3::Request>,
) -> Result<get_room_event::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
let event_id = &body.event_id;
let room_id = &body.room_id;
@@ -24,25 +25,25 @@ pub(crate) async fn get_room_event_route(
let visible = services
.rooms
.state_accessor
.user_can_see_event(body.sender_user(), room_id, event_id)
.user_can_see_event(sender_user, room_id, event_id)
.map(Ok);
let (mut event, visible) = try_join(event, visible).await?;
if !visible || is_ignored_pdu(services, &event, body.sender_user()).await? {
if !visible || is_ignored_pdu(services, &event, sender_user).await? {
return Err!(Request(Forbidden("You don't have permission to view this event.")));
}
if let Err(e) = services
.rooms
.pdu_metadata
.add_bundled_aggregations_to_pdu(body.sender_user(), &mut event)
.add_bundled_aggregations_to_pdu(sender_user, &mut event)
.await
{
debug_warn!("Failed to add bundled aggregations to event: {e}");
}
event.set_unsigned(body.sender_user.as_deref());
event.set_unsigned(Some(body.identity.expect_sender_user()?));
Ok(get_room_event::v3::Response::new(event.into_format()))
}
+11 -12
View File
@@ -17,12 +17,13 @@ pub(crate) async fn room_initial_sync_route(
State(services): State<crate::State>,
body: Ruma<Request>,
) -> Result<Response> {
let sender_user = body.identity.expect_sender_user()?;
let room_id = &body.room_id;
if !services
.rooms
.state_accessor
.user_can_see_state_events(body.sender_user(), room_id)
.user_can_see_state_events(sender_user, room_id)
.await
{
return Err!(Request(Forbidden("No room preview available.")));
@@ -31,7 +32,7 @@ pub(crate) async fn room_initial_sync_route(
let membership = services
.rooms
.state_cache
.user_membership(body.sender_user(), room_id)
.user_membership(sender_user, room_id)
.map(Ok);
let visibility = services.rooms.directory.visibility(room_id).map(Ok);
@@ -52,16 +53,14 @@ pub(crate) async fn room_initial_sync_route(
.pdus_rev(room_id, None)
.try_take(limit)
.and_then(async |mut pdu| {
pdu.1.set_unsigned(body.sender_user.as_deref());
if let Some(sender_user) = body.sender_user.as_deref() {
if let Err(e) = services
.rooms
.pdu_metadata
.add_bundled_aggregations_to_pdu(sender_user, &mut pdu.1)
.await
{
debug_warn!("Failed to add bundled aggregations: {e}");
}
pdu.1.set_unsigned(Some(sender_user));
if let Err(e) = services
.rooms
.pdu_metadata
.add_bundled_aggregations_to_pdu(sender_user, &mut pdu.1)
.await
{
debug_warn!("Failed to add bundled aggregations: {e}");
}
Ok(pdu)
})
+9 -2
View File
@@ -4,7 +4,7 @@
use ruma::api::client::room::get_summary;
use service::rooms::summary::Accessibility;
use crate::Ruma;
use crate::{Ruma, router::ClientIdentity};
/// # `GET /_matrix/client/v1/room_summary/{roomIdOrAlias}`
///
@@ -28,7 +28,14 @@ pub(crate) async fn get_room_summary(
let summary = services
.rooms
.summary
.get_room_summary_for_user(body.sender_user.as_deref(), &room_id, &servers)
.get_room_summary_for_user(
body.identity
.as_ref()
.map(ClientIdentity::expect_sender_user)
.transpose()?,
&room_id,
&servers,
)
.await?;
match summary {
+1 -1
View File
@@ -277,7 +277,7 @@ pub(crate) async fn upgrade_room_route(
State(services): State<crate::State>,
body: Ruma<upgrade_room::v3::Request>,
) -> Result<upgrade_room::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let (supported, forbid_unstable, is_unstable) = (
services.server.supported_room_version(&body.new_version),
+1 -1
View File
@@ -43,7 +43,7 @@ pub(crate) async fn search_events_route(
State(services): State<crate::State>,
body: Ruma<Request>,
) -> Result<Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let next_batch = body.next_batch.as_deref();
let mut result_categories = ResultCategories::new();
+9 -5
View File
@@ -22,16 +22,16 @@ pub(crate) async fn send_message_event_route(
ClientIp(client_ip): ClientIp,
body: Ruma<send_message_event::v3::Request>,
) -> Result<send_message_event::v3::Response> {
let sender_user = body.sender_user();
let sender_device = body.sender_device.as_deref();
let appservice_info = body.appservice_info.as_ref();
let sender_user = body.identity.expect_sender_user()?;
let sender_device = body.identity.sender_device();
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
services
.users
.update_device_last_seen(sender_user, body.sender_device.as_deref(), client_ip)
.update_device_last_seen(sender_user, sender_device, client_ip)
.await;
// Forbid m.room.encrypted if encryption is disabled
@@ -83,7 +83,11 @@ pub(crate) async fn send_message_event_route(
event_type: body.event_type.clone().into(),
content,
unsigned: Some(unsigned),
timestamp: appservice_info.and(body.timestamp),
timestamp: if body.identity.is_appservice() {
body.timestamp
} else {
None
},
..Default::default()
},
sender_user,
+6 -4
View File
@@ -146,7 +146,7 @@ pub(crate) async fn login_route(
}) => {
debug!("Got appservice login type");
let Some(ref info) = body.appservice_info else {
let Some(ref info) = body.identity else {
return Err!(Request(MissingToken("Missing appservice token.")));
};
@@ -254,7 +254,7 @@ pub(crate) async fn login_token_route(
return Err!(Request(Forbidden("Login via an existing session is not enabled")));
}
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
// Prompt the user to confirm with their password using UIAA
let _ = services
@@ -286,7 +286,9 @@ pub(crate) async fn logout_route(
ClientIp(client): ClientIp,
body: Ruma<logout::v3::Request>,
) -> Result<logout::v3::Response> {
let (sender_user, sender_device) = body.sender();
let sender_user = body.identity.expect_sender_user()?;
let sender_device = body.identity.expect_sender_device()?;
services
.users
.remove_device(sender_user, sender_device)
@@ -332,7 +334,7 @@ pub(crate) async fn logout_all_route(
ClientIp(client): ClientIp,
body: Ruma<logout_all::v3::Request>,
) -> Result<logout_all::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
services
.users
.all_device_ids(sender_user)
+1 -1
View File
@@ -27,7 +27,7 @@ pub(crate) async fn get_hierarchy_route(
.rooms
.summary
.get_room_hierarchy_for_user(
body.sender_user(),
body.identity.expect_sender_user()?,
body.room_id.clone(),
max_depth,
body.suggested_only,
+5 -5
View File
@@ -38,10 +38,10 @@ pub(crate) async fn send_state_event_for_key_route(
ClientIp(ip): ClientIp,
body: Ruma<send_state_event::v3::Request>,
) -> Result<send_state_event::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
services
.users
.update_device_last_seen(sender_user, body.sender_device.as_deref(), ip)
.update_device_last_seen(sender_user, body.identity.sender_device(), ip)
.await;
if services.users.is_suspended(sender_user).await? {
@@ -55,7 +55,7 @@ pub(crate) async fn send_state_event_for_key_route(
&body.event_type,
&body.body.body,
&body.state_key,
if body.appservice_info.is_some() {
if body.identity.is_appservice() {
body.timestamp
} else {
None
@@ -91,7 +91,7 @@ pub(crate) async fn get_state_events_route(
State(services): State<crate::State>,
body: Ruma<get_state_events::v3::Request>,
) -> Result<get_state_events::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if !services
.rooms
@@ -125,7 +125,7 @@ pub(crate) async fn get_state_event_for_key_route(
State(services): State<crate::State>,
body: Ruma<get_state_event_for_key::v3::Request>,
) -> Result<get_state_event_for_key::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
if !services
.rooms
+7
View File
@@ -48,6 +48,13 @@ async fn load_timeline(
ending_count: Option<PduCount>,
limit: usize,
) -> Result<TimelinePdus> {
if let (Some(starting_count), Some(ending_count)) = (starting_count, ending_count) {
debug_assert!(
starting_count <= ending_count,
"starting count {starting_count} > ending count {ending_count}"
);
}
let mut pdu_stream = match starting_count {
| Some(starting_count) => {
let last_timeline_count = services
+74 -81
View File
@@ -38,6 +38,7 @@
uint,
};
use service::{account_data::AnyRawAccountDataEvent, rooms::short::ShortStateHash};
use tokio::pin;
use super::{load_timeline, share_encrypted_room};
use crate::client::{
@@ -96,12 +97,19 @@ pub(super) async fn load_joined_room(
);
}
let state_events =
StateEvents::with_events(state_events.into_iter().map(Event::into_format).collect());
let joined_room = assign!(JoinedRoom::new(), {
account_data,
summary: summary.unwrap_or_default(),
unread_notifications: notification_counts.unwrap_or_default(),
timeline,
state: RoomState::Before(StateEvents::with_events(state_events.into_iter().map(Event::into_format).collect())),
state: if sync_context.use_state_after {
RoomState::After(state_events)
} else {
RoomState::Before(state_events)
},
ephemeral,
unread_thread_notifications: BTreeMap::new(),
});
@@ -344,7 +352,7 @@ struct ShortStateHashes {
#[tracing::instrument(level = "debug", skip_all)]
async fn fetch_shortstatehashes(
services: &Services,
SyncContext { last_sync_end_count, current_count, .. }: SyncContext<'_>,
SyncContext { last_sync_end_count, .. }: SyncContext<'_>,
room_id: &RoomId,
) -> Result<ShortStateHashes> {
// the room state currently.
@@ -354,46 +362,45 @@ async fn fetch_shortstatehashes(
.rooms
.state
.get_room_shortstatehash(room_id)
.map_err(|_| err!(Database(error!("Room {room_id} has no state"))));
.map_err(|_| err!(Database(error!("Room {room_id} has no state"))))
.await?;
// the room state as of the end of the last sync.
// this will be None if we are doing an initial sync or if we just joined this
// room.
// The room state as of the end of the last sync.
// This will be None if we are doing an initial sync.
let last_sync_end_shortstatehash =
OptionFuture::from(last_sync_end_count.map(|last_sync_end_count| {
// look up the shortstatehash saved by the last sync's call to
// `associate_token_shortstatehash`
services
.rooms
.user
.get_token_shortstatehash(room_id, last_sync_end_count)
.inspect_err(move |_| {
debug_warn!(
token = last_sync_end_count,
"Room has no shortstatehash for this token"
);
})
.ok()
OptionFuture::from(last_sync_end_count.map(async |last_sync_end_count| {
pin! {
let pdus = services
.rooms
.timeline
.pdus(room_id, Some(PduCount::Normal(last_sync_end_count)))
.ignore_err();
}
match pdus.next().await {
| Some((_, pdu_after_last_sync_end)) => {
trace!(?pdu_after_last_sync_end.event_id, "pdu at last sync end");
Some(
services
.rooms
.state_accessor
.pdu_shortstatehash(&pdu_after_last_sync_end.event_id)
.await
.map_err(|err| {
err!("Last sync end PDU has no shortstatehash: {err}")
}),
)
},
| None => {
// No events have been sent since the last sync, or we just joined this room
None
},
}
}))
.map(Option::flatten)
.map(Ok);
let (current_shortstatehash, last_sync_end_shortstatehash) =
try_join(current_shortstatehash, last_sync_end_shortstatehash).await?;
/*
associate the `current_count` with the `current_shortstatehash`, so we can
use it on the next sync as the `last_sync_end_shortstatehash`.
TODO: the table written to by this call grows extremely fast, gaining one new entry for each
joined room on _every single sync request_. we need to find a better way to remember the shortstatehash
between syncs.
*/
services
.rooms
.user
.associate_token_shortstatehash(room_id, current_count, current_shortstatehash)
.await;
.await
.flatten()
.transpose()?;
Ok(ShortStateHashes {
current_shortstatehash,
@@ -452,6 +459,7 @@ async fn build_state_events(
syncing_user,
last_sync_end_count,
full_state,
use_state_after,
..
} = sync_context;
@@ -460,32 +468,15 @@ async fn build_state_events(
last_sync_end_shortstatehash,
} = shortstatehashes;
// the spec states that the `state` property only includes state events up to
// the beginning of the timeline, so we determine the state of the syncing room
// as of the first timeline event. NOTE: this explanation is not entirely
// accurate; see the implementation of `build_state_incremental`.
let timeline_start_shortstatehash = async {
if let Some((_, pdu)) = timeline.pdus.front() {
if let Ok(shortstatehash) = services
.rooms
.state_accessor
.pdu_shortstatehash(&pdu.event_id)
.await
{
return shortstatehash;
}
}
current_shortstatehash
};
if timeline.pdus.is_empty() {
// If the timeline is empty there can't possibly be any changes to the state
return Ok(vec![]);
}
// the user IDs of members whose membership needs to be sent to the client, if
// lazy-loading is enabled.
let lazily_loaded_members =
prepare_lazily_loaded_members(services, sync_context, room_id, timeline.senders());
let (timeline_start_shortstatehash, lazily_loaded_members) =
join(timeline_start_shortstatehash, lazily_loaded_members).await;
prepare_lazily_loaded_members(services, sync_context, room_id, timeline.senders()).await;
// compute the state delta between the previous sync and this sync.
match (last_sync_end_count, last_sync_end_shortstatehash) {
@@ -494,16 +485,14 @@ async fn build_state_events(
is Some (meaning the syncing user didn't just join this room for the first time ever), and `full_state` is false,
then use `build_state_incremental`.
*/
| (Some(last_sync_end_count), Some(last_sync_end_shortstatehash)) if !full_state =>
| (Some(_), Some(last_sync_end_shortstatehash)) if !full_state =>
build_state_incremental(
services,
syncing_user,
room_id,
PduCount::Normal(last_sync_end_count),
last_sync_end_shortstatehash,
timeline_start_shortstatehash,
current_shortstatehash,
timeline,
use_state_after,
lazily_loaded_members.as_ref(),
)
.boxed()
@@ -517,7 +506,9 @@ async fn build_state_events(
build_state_initial(
services,
syncing_user,
timeline_start_shortstatehash,
current_shortstatehash,
timeline,
use_state_after,
lazily_loaded_members.as_ref(),
)
.boxed()
@@ -598,23 +589,25 @@ async fn check_joined_since_last_sync(
ShortStateHashes { last_sync_end_shortstatehash, .. }: ShortStateHashes,
SyncContext { syncing_user, .. }: SyncContext<'_>,
) -> Result<bool> {
// fetch the syncing user's membership event during the last sync.
// this will be None if `previous_sync_end_shortstatehash` is None.
let membership_during_previous_sync = match last_sync_end_shortstatehash {
| Some(last_sync_end_shortstatehash) => services
.rooms
.state_accessor
.state_get_content(
last_sync_end_shortstatehash,
&StateEventType::RoomMember,
syncing_user.as_str(),
)
.await
.inspect_err(|_| debug_warn!("User has no previous membership"))
.ok(),
| None => None,
let Some(last_sync_end_shortstatehash) = last_sync_end_shortstatehash else {
// For initial syncs always return false, since there's no "last sync" for the
// user to have joined since.
return Ok(false);
};
// Fetch the syncing user's membership event during the last sync.
let membership_during_previous_sync = services
.rooms
.state_accessor
.state_get_content(
last_sync_end_shortstatehash,
&StateEventType::RoomMember,
syncing_user.as_str(),
)
.await
.inspect_err(|_| debug_warn!("User has no previous membership"))
.ok();
// TODO: If the requesting user got state-reset out of the room, this
// will be `true` when it shouldn't be. this function should never be called
// in that situation, but it may be if the membership cache didn't get updated.
+13 -25
View File
@@ -4,7 +4,7 @@
trace,
utils::{self, IterStream, future::ReadyEqExt, stream::WidebandExt as _},
};
use futures::{StreamExt, future::join};
use futures::StreamExt;
use ruma::{
EventId, OwnedRoomId, RoomId,
api::client::sync::sync_events::v3::{
@@ -181,6 +181,9 @@ pub(super) async fn load_left_room(
.collect::<Vec<_>>()
.await;
let state_events =
StateEvents::with_events(state_events.into_iter().map(Event::into_format).collect());
Ok(Some(assign!(LeftRoom::new(), {
account_data: RoomAccountData::new(),
timeline: assign!(Timeline::new(), {
@@ -188,7 +191,11 @@ pub(super) async fn load_left_room(
prev_batch: Some(current_count.to_string()),
events: raw_timeline_pdus,
}),
state: State::Before(StateEvents::with_events(state_events.into_iter().map(Event::into_format).collect())),
state: if sync_context.use_state_after {
State::After(state_events)
} else {
State::Before(state_events)
},
})))
}
@@ -233,29 +240,8 @@ async fn build_left_state_and_timeline(
)
.await?;
let timeline_start_shortstatehash = async {
if let Some((_, pdu)) = timeline.pdus.front() {
if let Ok(shortstatehash) = services
.rooms
.state_accessor
.pdu_shortstatehash(&pdu.event_id)
.await
{
return shortstatehash;
}
}
// the timeline generally should not be empty (see the TODO further down),
// but in case it is we use `leave_shortstatehash` as the state to
// send
leave_shortstatehash
};
let lazily_loaded_members =
prepare_lazily_loaded_members(services, sync_context, room_id, timeline.senders());
let (timeline_start_shortstatehash, lazily_loaded_members) =
join(timeline_start_shortstatehash, lazily_loaded_members).await;
prepare_lazily_loaded_members(services, sync_context, room_id, timeline.senders()).await;
// TODO: calculate incremental state for incremental syncs.
// always calculating initial state _works_ but returns more data and does
@@ -263,7 +249,9 @@ async fn build_left_state_and_timeline(
let mut state = build_state_initial(
services,
syncing_user,
timeline_start_shortstatehash,
leave_shortstatehash,
&timeline,
sync_context.use_state_after,
lazily_loaded_members.as_ref(),
)
.await?;
+13 -7
View File
@@ -11,12 +11,11 @@
use axum::extract::State;
use axum_client_ip::ClientIp;
use conduwuit::{
Err, Result, at, extract_variant,
Err, Result, at, error, extract_variant,
utils::{
ReadyExt, TryFutureExtExt,
stream::{BroadbandExt, Tools, WidebandExt},
},
warn,
};
use conduwuit_service::Services;
use futures::{FutureExt, StreamExt, TryFutureExt, future::OptionFuture};
@@ -34,6 +33,7 @@
},
assign,
events::presence::{PresenceEvent, PresenceEventContent},
presence::PresenceState,
serde::Raw,
};
use service::{
@@ -110,6 +110,9 @@ struct SyncContext<'a> {
/// The sync filter, which the client uses to specify what data should be
/// included in the sync response.
filter: &'a FilterDefinition,
/// Whether the state at the end of the timeline should be used when
/// calculating state diffs for sync.
use_state_after: bool,
}
impl<'a> SyncContext<'a> {
@@ -181,10 +184,11 @@ pub(crate) async fn sync_events_route(
ClientIp(client_ip): ClientIp,
body: Ruma<sync_events::v3::Request>,
) -> Result<sync_events::v3::Response> {
let (sender_user, sender_device) = body.sender();
let sender_user = body.identity.expect_sender_user()?;
let sender_device = body.identity.expect_sender_device()?;
// Presence update
if services.config.allow_local_presence {
if services.config.allow_local_presence && body.set_presence != PresenceState::Offline {
services
.presence
.ping_presence(sender_user, &body.body.set_presence)
@@ -225,7 +229,8 @@ pub(crate) async fn build_sync_events(
services: &Services,
body: &Ruma<sync_events::v3::Request>,
) -> Result<sync_events::v3::Response> {
let (syncing_user, syncing_device) = body.sender();
let syncing_user = body.identity.sender_user().expect("should have a user");
let syncing_device = body.identity.sender_device().expect("should have a device");
let current_count = services.globals.current_count()?;
@@ -261,6 +266,7 @@ pub(crate) async fn build_sync_events(
current_count,
full_state,
filter: &filter,
use_state_after: body.use_state_after,
};
let joined_rooms = services
@@ -273,7 +279,7 @@ pub(crate) async fn build_sync_events(
match joined_room {
| Ok((room, updates)) => Some((room_id, room, updates)),
| Err(err) => {
warn!(?err, %room_id, "error loading joined room");
error!(?err, %room_id, "error loading joined room");
None
},
}
@@ -302,7 +308,7 @@ pub(crate) async fn build_sync_events(
| Ok(Some(left_room)) => Some((room_id, left_room)),
| Ok(None) => None,
| Err(err) => {
warn!(?err, %room_id, "error loading joined room");
error!(?err, %room_id, "error loading joined room");
None
},
}
+63 -146
View File
@@ -1,11 +1,8 @@
use std::{collections::BTreeSet, ops::ControlFlow};
use std::collections::HashSet;
use conduwuit::{
Result, at, is_equal_to,
matrix::{
Event,
pdu::{PduCount, PduEvent},
},
Result, at,
matrix::{Event, pdu::PduEvent},
utils::{
BoolExt, IterStream, ReadyExt, TryFutureExtExt,
stream::{BroadbandExt, TryIgnore},
@@ -16,9 +13,7 @@
rooms::{lazy_loading::MemberSet, short::ShortStateHash},
};
use futures::{FutureExt, StreamExt};
use itertools::Itertools;
use ruma::{OwnedEventId, RoomId, UserId, events::StateEventType};
use service::rooms::short::ShortEventId;
use ruma::{OwnedEventId, UserId, events::StateEventType};
use tracing::trace;
use crate::client::TimelinePdus;
@@ -38,14 +33,22 @@
pub(super) async fn build_state_initial(
services: &Services,
sender_user: &UserId,
timeline_start_shortstatehash: ShortStateHash,
timeline_end_shortstatehash: ShortStateHash,
timeline: &TimelinePdus,
use_state_after: bool,
lazily_loaded_members: Option<&MemberSet>,
) -> Result<Vec<PduEvent>> {
let event_ids_in_timeline: HashSet<_> =
timeline.pdus.iter().map(|pdu| &pdu.1.event_id).collect();
// load the keys and event IDs of the state events at the start of the timeline
let (shortstatekeys, event_ids): (Vec<_>, Vec<_>) = services
.rooms
.state_accessor
.state_full_ids(timeline_start_shortstatehash)
.state_full_ids(timeline_end_shortstatehash)
.ready_filter(|(_, event_id)| {
use_state_after || !event_ids_in_timeline.contains(event_id)
})
.unzip()
.await;
@@ -92,82 +95,32 @@ pub(super) async fn build_state_initial(
pub(super) async fn build_state_incremental<'a>(
services: &Services,
sender_user: &'a UserId,
room_id: &RoomId,
last_sync_end_count: PduCount,
last_sync_end_shortstatehash: ShortStateHash,
timeline_start_shortstatehash: ShortStateHash,
timeline_end_shortstatehash: ShortStateHash,
timeline: &TimelinePdus,
use_state_after: bool,
lazily_loaded_members: Option<&'a MemberSet>,
) -> Result<Vec<PduEvent>> {
/*
NB: a limited sync is one where `timeline.limited == true`. Synapse calls this a "gappy" sync internally.
let mut state_event_ids: HashSet<OwnedEventId> = HashSet::new();
The algorithm implemented in this function is, currently, quite different from the algorithm vaguely described
by the Matrix specification. This is because the specification's description of the `state` property does not accurately
reflect how Synapse behaves, and therefore how client SDKs behave. Notable differences include:
1. We do not compute the delta using the naive approach of "every state event from the end of the last sync
up to the start of this sync's timeline". see below for details.
2. If lazy-loading is enabled, we include lazily-loaded membership events. The specific users to include are determined
elsewhere and supplied to this function in the `lazily_loaded_members` parameter.
*/
trace!(
%use_state_after,
%last_sync_end_shortstatehash,
%timeline_end_shortstatehash,
"computing state for incremental sync"
);
/*
the `state` property of an incremental sync which isn't limited are _usually_ empty.
(note: the specification says that the `state` property is _always_ empty for limited syncs, which is incorrect.)
however, if an event in the timeline (`timeline.pdus`) merges a split in the room's DAG (i.e. has multiple `prev_events`),
the state at the _end_ of the timeline may include state events which were merged in and don't exist in the state
at the _start_ of the timeline. because this is uncommon, we check here to see if any events in the timeline
merged a split in the DAG.
// Fetch lazy-loaded membership events if lazy-loading is enabled
if let Some(lazily_loaded_members) = lazily_loaded_members
&& !lazily_loaded_members.is_empty()
{
trace!("including lazy membership events for members: {:?}", lazily_loaded_members);
see: https://github.com/element-hq/synapse/issues/16941
*/
let timeline_is_linear = timeline.pdus.is_empty() || {
let last_pdu_of_last_sync = services
services
.rooms
.timeline
.pdus_rev(room_id, Some(last_sync_end_count.saturating_add(1)))
.boxed()
.next()
.await
.transpose()
.expect("last sync should have had some PDUs")
.map(at!(1));
// make sure the prev_events of each pdu in the timeline refer only to the
// previous pdu
timeline
.pdus
.iter()
.try_fold(last_pdu_of_last_sync.map(|pdu| pdu.event_id), |prev_event_id, (_, pdu)| {
if let Ok(pdu_prev_event_id) = pdu.prev_events.iter().exactly_one() {
if prev_event_id
.as_ref()
.is_none_or(is_equal_to!(pdu_prev_event_id))
{
return ControlFlow::Continue(Some(pdu_prev_event_id.to_owned()));
}
}
trace!(
"pdu {:?} has split prev_events (expected {:?}): {:?}",
pdu.event_id, prev_event_id, pdu.prev_events
);
ControlFlow::Break(())
})
.is_continue()
};
if timeline_is_linear && !timeline.limited {
// if there are no splits in the DAG and the timeline isn't limited, then
// `state` will always be empty unless lazy loading is enabled.
if let Some(lazily_loaded_members) = lazily_loaded_members {
if !timeline.pdus.is_empty() {
// lazy loading is enabled, so we return the membership events which were
// requested by the caller.
let lazy_membership_events: Vec<_> = lazily_loaded_members
.short
.multi_get_eventid_from_short::<'_, OwnedEventId, _>(
lazily_loaded_members
.iter()
.stream()
.broad_filter_map(|user_id| async move {
@@ -178,71 +131,24 @@ pub(super) async fn build_state_incremental<'a>(
services
.rooms
.state_accessor
.state_get(
timeline_start_shortstatehash,
.state_get_shortid(
timeline_end_shortstatehash,
&StateEventType::RoomMember,
user_id.as_str(),
)
.ok()
.await
})
.collect()
.await;
if !lazy_membership_events.is_empty() {
trace!(
"syncing lazy membership events for members: {:?}",
lazy_membership_events
.iter()
.map(|pdu| pdu.state_key().unwrap())
.collect::<Vec<_>>()
);
}
return Ok(lazy_membership_events);
}
}
// lazy loading is disabled, `state` is empty.
return Ok(vec![]);
}),
)
.ignore_err()
.ready_for_each(|event_id| {
state_event_ids.insert(event_id);
})
.await;
}
/*
at this point, either the timeline is `limited` or the DAG has a split in it. this necessitates
computing the incremental state (which may be empty).
NOTE: this code path does not use the `lazy_membership_events` parameter. any changes to membership will be included
in the incremental state. therefore, the incremental state may include "redundant" membership events,
which we do not filter out because A. the spec forbids lazy-load filtering if the timeline is `limited`,
and B. DAG splits which require sending extra membership state events are (probably) uncommon enough that
the performance penalty is acceptable.
*/
trace!(%timeline_is_linear, %timeline.limited, "computing state for incremental sync");
// fetch the shorteventids of state events in the timeline
let state_events_in_timeline: BTreeSet<ShortEventId> = services
.rooms
.short
.multi_get_or_create_shorteventid(timeline.pdus.iter().filter_map(|(_, pdu)| {
if pdu.state_key().is_some() {
Some(pdu.event_id.as_ref())
} else {
None
}
}))
.collect()
.await;
trace!("{} state events in timeline", state_events_in_timeline.len());
/*
fetch the state events which were added since the last sync.
specifically we fetch the difference between the state at the last sync and the state at the _end_
of the timeline, and then we filter out state events in the timeline itself using the shorteventids we fetched.
this is necessary to account for splits in the DAG, as explained above.
*/
let state_diff = services
// Fetch the state events added since the last sync.
services
.rooms
.short
.multi_get_eventid_from_short::<'_, OwnedEventId, _>(
@@ -252,18 +158,29 @@ pub(super) async fn build_state_incremental<'a>(
.state_added((last_sync_end_shortstatehash, timeline_end_shortstatehash))
.await?
.stream()
.ready_filter_map(|(_, shorteventid)| {
if state_events_in_timeline.contains(&shorteventid) {
None
} else {
Some(shorteventid)
}
}),
.map(at!(1)),
)
.ignore_err();
.ignore_err()
.ready_for_each(|event_id| {
state_event_ids.insert(event_id);
})
.await;
// finally, fetch the PDU contents and collect them into a vec
let state_diff_pdus = state_diff
if !use_state_after {
// If state_after isn't enabled, filter out state events which also exist
// in the timeline. If splits exist in the DAG, this may not be exactly the same
// thing as the state diff ending at the start of the timeline, but Synapse
// also does this and it's technically more useful behavior anyway.
// See: https://github.com/element-hq/synapse/issues/16941
for (_, pdu) in &timeline.pdus {
state_event_ids.remove(pdu.event_id());
}
}
// Finally, fetch the PDU contents and collect them into a vec
let state_diff_pdus = state_event_ids
.stream()
.broad_filter_map(|event_id| async move {
services
.rooms
+30 -10
View File
@@ -15,7 +15,7 @@
BoolExt, FutureBoolExt, IterStream, ReadyExt, TryFutureExtExt,
future::ReadyEqExt,
math::{ruma_from_usize, usize_from_ruma},
stream::WidebandExt,
stream::{TryIgnore, WidebandExt},
},
warn,
};
@@ -41,6 +41,7 @@
uint,
};
use service::account_data::AnyRawAccountDataEvent;
use tokio::pin;
use super::share_encrypted_room;
use crate::{
@@ -70,8 +71,8 @@ pub(crate) async fn sync_events_v5_route(
body: Ruma<sync_events::v5::Request>,
) -> Result<sync_events::v5::Response> {
debug_assert!(DEFAULT_BUMP_TYPES.is_sorted(), "DEFAULT_BUMP_TYPES is not sorted");
let ref sender_user = body.sender_user().to_owned();
let ref sender_device = body.sender_device().to_owned();
let sender_user = body.identity.expect_sender_user()?;
let sender_device = body.identity.expect_sender_device()?;
services
.users
@@ -93,7 +94,7 @@ pub(crate) async fn sync_events_v5_route(
.and_then(|string| string.parse().ok())
.unwrap_or(0);
let snake_key = into_snake_key(sender_user.as_ref(), sender_device.as_str(), conn_id);
let snake_key = into_snake_key(sender_user, sender_device.as_str(), conn_id);
if globalsince != 0 && !services.sync.snake_connection_cached(&snake_key) {
return Err!(Request(UnknownPos(
@@ -858,12 +859,31 @@ async fn collect_e2ee<'a, Rooms>(
continue;
};
let since_shortstatehash = services
.rooms
.user
.get_token_shortstatehash(room_id, globalsince)
.await
.ok();
let since_shortstatehash = async {
pin! {
let pdus_rev = services
.rooms
.timeline
.pdus_rev(room_id, Some(PduCount::Normal(globalsince.saturating_sub(1))))
.ignore_err();
}
let (count, pdu_at_last_sync_end) = pdus_rev.next().await?;
if matches!(count, PduCount::Backfilled(_)) {
None
} else {
Some(
services
.rooms
.state_accessor
.pdu_shortstatehash(&pdu_at_last_sync_end.event_id)
.await
.expect("pdu should have a shortstatehash"),
)
}
}
.await;
let encrypted_room = services
.rooms
+3 -3
View File
@@ -21,7 +21,7 @@ pub(crate) async fn update_tag_route(
State(services): State<crate::State>,
body: Ruma<create_tag::v3::Request>,
) -> Result<create_tag::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let mut tags_event = services
.account_data
@@ -56,7 +56,7 @@ pub(crate) async fn delete_tag_route(
State(services): State<crate::State>,
body: Ruma<delete_tag::v3::Request>,
) -> Result<delete_tag::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let mut tags_event = services
.account_data
@@ -88,7 +88,7 @@ pub(crate) async fn get_tags_route(
State(services): State<crate::State>,
body: Ruma<get_tags::v3::Request>,
) -> Result<get_tags::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let tags_event = services
.account_data
+5 -3
View File
@@ -16,6 +16,8 @@ pub(crate) async fn get_threads_route(
State(services): State<crate::State>,
ref body: Ruma<get_threads::v1::Request>,
) -> Result<get_threads::v1::Response> {
let sender_user = body.identity.expect_sender_user()?;
// Use limit or else 10, with maximum 100
let limit = body
.limit
@@ -34,14 +36,14 @@ pub(crate) async fn get_threads_route(
let threads: Vec<(PduCount, PduEvent)> = services
.rooms
.threads
.threads_until(body.sender_user(), &body.room_id, from, &body.include)
.threads_until(sender_user, &body.room_id, from, &body.include)
.await?
.take(limit)
.filter_map(|(count, pdu)| async move {
services
.rooms
.state_accessor
.user_can_see_event(body.sender_user(), &body.room_id, &pdu.event_id)
.user_can_see_event(sender_user, &body.room_id, &pdu.event_id)
.await
.then_some((count, pdu))
})
@@ -49,7 +51,7 @@ pub(crate) async fn get_threads_route(
if let Err(e) = services
.rooms
.pdu_metadata
.add_bundled_aggregations_to_pdu(body.sender_user(), &mut pdu)
.add_bundled_aggregations_to_pdu(sender_user, &mut pdu)
.await
{
debug_warn!("Failed to add bundled aggregations to thread: {e}");
+2 -2
View File
@@ -22,8 +22,8 @@ pub(crate) async fn send_event_to_device_route(
State(services): State<crate::State>,
body: Ruma<send_event_to_device::v3::Request>,
) -> Result<send_event_to_device::v3::Response> {
let sender_user = body.sender_user();
let sender_device = body.sender_device.as_deref();
let sender_user = body.identity.expect_sender_user()?;
let sender_device = body.identity.sender_device();
// Check if this is a new transaction id
if services
+4 -3
View File
@@ -14,13 +14,14 @@ pub(crate) async fn create_typing_event_route(
body: Ruma<create_typing_event::v3::Request>,
) -> Result<create_typing_event::v3::Response> {
use create_typing_event::v3::Typing;
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
services
.users
.update_device_last_seen(sender_user, body.sender_device.as_deref(), ip)
.update_device_last_seen(sender_user, body.identity.sender_device(), ip)
.await;
if sender_user != body.user_id && body.appservice_info.is_none() {
if sender_user != body.user_id && !body.identity.is_appservice() {
return Err!(Request(Forbidden("You cannot update typing status of other users.")));
}
+1 -1
View File
@@ -26,7 +26,7 @@ pub(crate) async fn search_users_route(
State(services): State<crate::State>,
body: Ruma<search_users::v3::Request>,
) -> Result<search_users::v3::Response> {
let sender_user = body.sender_user();
let sender_user = body.identity.expect_sender_user()?;
let limit = usize::try_from(body.limit)
.map_or(LIMIT_DEFAULT, usize::from)
.min(LIMIT_MAX);
+4 -13
View File
@@ -2,15 +2,13 @@
use axum::extract::State;
use base64::{Engine as _, engine::general_purpose};
use conduwuit::{Err, Result, utils};
use conduwuit::{Err, Result};
use hmac::{Hmac, KeyInit, Mac};
use ruma::{SecondsSinceUnixEpoch, UserId, api::client::voip::get_turn_server_info};
use ruma::{SecondsSinceUnixEpoch, api::client::voip::get_turn_server_info};
use sha1::Sha1;
use crate::Ruma;
const RANDOM_USER_ID_LENGTH: usize = 10;
type HmacSha1 = Hmac<Sha1>;
/// # `GET /_matrix/client/r0/voip/turnServer`
@@ -35,15 +33,8 @@ pub(crate) async fn turn_server_route(
)
.expect("time is valid");
let user = body.sender_user.unwrap_or_else(|| {
UserId::parse_with_server_name(
utils::random_string(RANDOM_USER_ID_LENGTH).to_lowercase(),
&services.server.name,
)
.unwrap()
});
let username: String = format!("{}:{}", expiry.get(), user);
let username: String =
format!("{}:{}", expiry.get(), body.identity.expect_sender_user()?);
let mut mac = HmacSha1::new_from_slice(turn_secret.as_bytes())
.expect("HMAC can take key of any size");
+1 -2
View File
@@ -15,7 +15,7 @@
use http::{Uri, uri};
use self::handler::RouterExt;
pub(super) use self::{args::Args as Ruma, response::RumaResponse};
pub(super) use self::{args::Args as Ruma, auth::ClientIdentity, response::RumaResponse};
use crate::{admin, client, server};
pub fn build(router: Router<State>, server: &Server) -> Router<State> {
@@ -225,7 +225,6 @@ pub fn build(router: Router<State>, server: &Server) -> Router<State> {
.ruma_route(&server::well_known_server)
.ruma_route(&server::get_content_route)
.ruma_route(&server::get_content_thumbnail_route)
.ruma_route(&server::get_edutypes_route)
.route("/_conduwuit/local_user_count", get(client::conduwuit_local_user_count))
.route("/_continuwuity/local_user_count", get(client::conduwuit_local_user_count));
} else {
+13 -68
View File
@@ -6,17 +6,14 @@
extract::{FromRequest, Path, Query},
};
use conduwuit::{Error, Result, err};
use ruma::{
CanonicalJsonObject, DeviceId, OwnedDeviceId, OwnedServerName, OwnedUserId, ServerName,
UserId, api::IncomingRequest,
};
use ruma::{CanonicalJsonObject, api::IncomingRequest};
use serde::Deserialize;
use crate::{State, router::auth::CheckAuth, service::appservice::RegistrationInfo};
use crate::{State, router::auth::CheckAuth};
/// Query parameters needed to authenticate requests
#[derive(Deserialize)]
pub(super) struct AuthQueryParams {
pub(crate) struct AuthQueryParams {
pub(super) user_id: Option<String>,
/// Device ID for appservice device masquerading (MSC3202/MSC4190).
/// Can be provided as `device_id` or `org.matrix.msc3202.device_id`.
@@ -25,67 +22,22 @@ pub(super) struct AuthQueryParams {
}
/// Extractor for Ruma request structs
pub(crate) struct Args<T> {
pub(crate) struct Args<R: IncomingRequest<Authentication: CheckAuth> + Send + Sync + 'static> {
/// Request struct body
pub(crate) body: T,
pub(crate) body: R,
/// Federation server authentication: X-Matrix origin
/// None when not a federation server.
pub(crate) origin: Option<OwnedServerName>,
/// Local user authentication: user_id.
/// None when not an authenticated local user.
pub(crate) sender_user: Option<OwnedUserId>,
/// Local user authentication: device_id.
/// None when not an authenticated local user or no device.
pub(crate) sender_device: Option<OwnedDeviceId>,
/// Appservice authentication; registration info.
/// None when not an appservice.
pub(crate) appservice_info: Option<RegistrationInfo>,
/// Parsed JSON content.
/// None when body is not a valid string
/// Parsed JSON body. None when body is not JSON.
pub(crate) json_body: Option<CanonicalJsonObject>,
/// Identity of the requesting entity
pub(crate) identity: <R::Authentication as CheckAuth>::Identity,
}
impl<T> Args<T>
impl<R> Deref for Args<R>
where
T: IncomingRequest + Send + Sync + 'static,
R: IncomingRequest<Authentication: CheckAuth> + Send + Sync + 'static,
{
#[inline]
pub(crate) fn sender(&self) -> (&UserId, &DeviceId) {
(self.sender_user(), self.sender_device())
}
#[inline]
pub(crate) fn sender_user(&self) -> &UserId {
self.sender_user
.as_deref()
.expect("user must be authenticated for this handler")
}
#[inline]
pub(crate) fn sender_device(&self) -> &DeviceId {
self.sender_device
.as_deref()
.expect("user must be authenticated and device identified")
}
#[inline]
pub(crate) fn origin(&self) -> &ServerName {
self.origin
.as_deref()
.expect("server must be authenticated for this handler")
}
}
impl<T> Deref for Args<T>
where
T: IncomingRequest + Send + Sync + 'static,
{
type Target = T;
type Target = R;
fn deref(&self) -> &Self::Target { &self.body }
}
@@ -145,13 +97,6 @@ async fn from_request(
let body = R::try_from_http_request(request, &path)
.map_err(|e| err!(Request(BadJson(debug_warn!("{e}")))))?;
Ok(Self {
body,
origin: auth.origin,
sender_user: auth.sender_user,
sender_device: auth.sender_device,
appservice_info: auth.appservice_info,
json_body,
})
Ok(Self { body, json_body, identity: auth })
}
}
+145 -98
View File
@@ -2,7 +2,7 @@
use conduwuit::{Err, Result, err};
use ruma::{
OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
DeviceId, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
api::{
IncomingRequest,
auth_scheme::{
@@ -20,20 +20,66 @@
use crate::{router::args::AuthQueryParams, service::appservice::RegistrationInfo};
#[derive(Default)]
pub(super) struct Auth {
pub(super) origin: Option<OwnedServerName>,
pub(super) sender_user: Option<OwnedUserId>,
pub(super) sender_device: Option<OwnedDeviceId>,
pub(super) appservice_info: Option<RegistrationInfo>,
pub(crate) enum ClientIdentity {
User {
sender_user: OwnedUserId,
sender_device: OwnedDeviceId,
},
Appservice {
sender_user: OwnedUserId,
sender_device: Option<OwnedDeviceId>,
appservice_info: Box<RegistrationInfo>,
},
}
pub(super) trait CheckAuth: AuthScheme {
impl ClientIdentity {
pub(crate) fn sender_user(&self) -> Option<&UserId> {
match self {
| Self::User { sender_user, .. } | Self::Appservice { sender_user, .. } =>
Some(sender_user),
}
}
pub(crate) fn expect_sender_user(&self) -> Result<&UserId> {
match self {
| Self::User { sender_user, .. } | Self::Appservice { sender_user, .. } =>
Ok(sender_user),
}
}
pub(crate) fn sender_device(&self) -> Option<&DeviceId> {
match self {
| Self::User { sender_device, .. } => Some(sender_device),
| Self::Appservice { sender_device, .. } => sender_device.as_deref(),
}
}
pub(crate) fn expect_sender_device(&self) -> Result<&DeviceId> {
match self {
| Self::User { sender_device, .. } => Ok(sender_device),
| Self::Appservice { .. } =>
Err!(Request(Forbidden("Appservices must masquerade to use this endpoint."))),
}
}
pub(crate) fn appservice_info(&self) -> Option<&RegistrationInfo> {
match self {
| Self::User { .. } => None,
| Self::Appservice { appservice_info, .. } => Some(appservice_info),
}
}
pub(crate) fn is_appservice(&self) -> bool { matches!(self, Self::Appservice { .. }) }
}
pub(crate) trait CheckAuth: AuthScheme {
type Identity: Send;
fn authenticate<R: IncomingRequest + Any, B: AsRef<[u8]> + Sync>(
services: &Services,
incoming_request: &hyper::Request<B>,
query: AuthQueryParams,
) -> impl Future<Output = Result<Auth>> + Send {
) -> impl Future<Output = Result<Self::Identity>> + Send {
async move {
let route = TypeId::of::<R>();
@@ -54,17 +100,19 @@ fn verify<B: AsRef<[u8]> + Sync>(
request: &hyper::Request<B>,
query: AuthQueryParams,
route: TypeId,
) -> impl Future<Output = Result<Auth>> + Send;
) -> impl Future<Output = Result<Self::Identity>> + Send;
}
impl CheckAuth for ServerSignatures {
type Identity = OwnedServerName;
async fn verify<B: AsRef<[u8]> + Sync>(
services: &Services,
output: Self::Output,
request: &hyper::Request<B>,
_query: AuthQueryParams,
_route: TypeId,
) -> Result<Auth> {
) -> Result<Self::Identity> {
let destination = services.globals.server_name();
if output
.destination
@@ -96,10 +144,7 @@ async fn verify<B: AsRef<[u8]> + Sync>(
)));
}
Ok(Auth {
origin: Some(output.origin.clone()),
..Default::default()
})
Ok(output.origin)
},
| Err(err) =>
Err!(Request(Unauthorized(warn!("Failed to verify X-Matrix header: {err}")))),
@@ -108,162 +153,164 @@ async fn verify<B: AsRef<[u8]> + Sync>(
}
impl CheckAuth for AccessToken {
type Identity = ClientIdentity;
async fn verify<B: AsRef<[u8]> + Sync>(
services: &Services,
output: Self::Output,
_request: &hyper::Request<B>,
query: AuthQueryParams,
route: TypeId,
) -> Result<Auth> {
// Check for appservice tokens first
let (sender_user, sender_device, appservice_info) = {
if let Ok((sender_user, sender_device)) =
services.users.find_from_token(&output).await
) -> Result<Self::Identity> {
if let Ok((sender_user, sender_device)) = services.users.find_from_token(&output).await {
// Locked users can only use /logout and /logout/all
if services
.users
.is_locked(&sender_user)
.await
.is_ok_and(std::convert::identity)
{
// Locked users can only use /logout and /logout/all
if services
.users
.is_locked(&sender_user)
.await
.is_ok_and(std::convert::identity)
if !(route == TypeId::of::<client::session::logout::v3::Request>()
|| route == TypeId::of::<client::session::logout_all::v3::Request>())
{
if !(route == TypeId::of::<client::session::logout::v3::Request>()
|| route == TypeId::of::<client::session::logout_all::v3::Request>())
{
return Err!(Request(Unauthorized("Your account is locked.")));
}
return Err!(Request(Unauthorized("Your account is locked.")));
}
}
(Some(sender_user), Some(sender_device), None)
} else if let Ok(appservice_info) = services.appservice.find_from_token(&output).await
{
let Ok(sender_user) = query.user_id.clone().map_or_else(
|| {
UserId::parse_with_server_name(
appservice_info.registration.sender_localpart.as_str(),
services.globals.server_name(),
)
},
UserId::parse,
) else {
return Err!(Request(InvalidUsername("Username is invalid.")));
Ok(ClientIdentity::User { sender_user, sender_device })
} else if let Ok(appservice_info) = services.appservice.find_from_token(&output).await {
let Ok(sender_user) = query.user_id.clone().map_or_else(
|| {
UserId::parse_with_server_name(
appservice_info.registration.sender_localpart.as_str(),
services.globals.server_name(),
)
},
UserId::parse,
) else {
return Err!(Request(InvalidUsername("Username is invalid.")));
};
if !appservice_info.is_user_match(&sender_user) {
return Err!(Request(Exclusive("User is not in namespace.")));
}
// MSC3202/MSC4190: Handle device_id masquerading for appservices.
// The device_id can be provided via `device_id` or
// `org.matrix.msc3202.device_id` query parameter.
let sender_device =
if let Some(device_id) = query.device_id.as_deref().map(Into::into) {
// Verify the device exists for this user
if services
.users
.get_device_metadata(&sender_user, device_id)
.await
.is_err()
{
return Err!(Request(Forbidden(
"Device does not exist for user or appservice cannot masquerade as \
this device."
)));
}
Some(device_id.to_owned())
} else {
None
};
if !appservice_info.is_user_match(&sender_user) {
return Err!(Request(Exclusive("User is not in namespace.")));
}
// MSC3202/MSC4190: Handle device_id masquerading for appservices.
// The device_id can be provided via `device_id` or
// `org.matrix.msc3202.device_id` query parameter.
let sender_device =
if let Some(device_id) = query.device_id.as_deref().map(Into::into) {
// Verify the device exists for this user
if services
.users
.get_device_metadata(&sender_user, device_id)
.await
.is_err()
{
return Err!(Request(Forbidden(
"Device does not exist for user or appservice cannot masquerade \
as this device."
)));
}
Some(device_id.to_owned())
} else {
None
};
(Some(sender_user), sender_device, Some(appservice_info))
} else {
return Err!(Request(Unauthorized("Invalid access token.")));
}
};
Ok(Auth {
sender_user,
sender_device,
appservice_info,
..Default::default()
})
Ok(ClientIdentity::Appservice {
sender_user,
sender_device,
appservice_info: Box::new(appservice_info),
})
} else {
Err!(Request(Unauthorized("Invalid access token.")))
}
}
}
impl CheckAuth for AccessTokenOptional {
type Identity = Option<ClientIdentity>;
async fn verify<B: AsRef<[u8]> + Sync>(
services: &Services,
output: Self::Output,
request: &hyper::Request<B>,
query: AuthQueryParams,
route: TypeId,
) -> Result<Auth> {
) -> Result<Self::Identity> {
match output {
| Some(token) =>
<AccessToken as CheckAuth>::verify(services, token, request, query, route).await,
| None => Ok(Auth::default()),
<AccessToken as CheckAuth>::verify(services, token, request, query, route)
.await
.map(Some),
| None => Ok(None),
}
}
}
impl CheckAuth for AppserviceToken {
type Identity = RegistrationInfo;
async fn verify<B: AsRef<[u8]> + Sync>(
services: &Services,
output: Self::Output,
_request: &hyper::Request<B>,
_query: AuthQueryParams,
_route: TypeId,
) -> Result<Auth> {
) -> Result<Self::Identity> {
let Ok(appservice_info) = services.appservice.find_from_token(&output).await else {
return Err!(Request(Unauthorized("Invalid appservice token.")));
};
Ok(Auth {
appservice_info: Some(appservice_info),
..Default::default()
})
Ok(appservice_info)
}
}
impl CheckAuth for AppserviceTokenOptional {
type Identity = Option<RegistrationInfo>;
async fn verify<B: AsRef<[u8]> + Sync>(
services: &Services,
output: Self::Output,
request: &hyper::Request<B>,
query: AuthQueryParams,
route: TypeId,
) -> Result<Auth> {
) -> Result<Self::Identity> {
match output {
| Some(token) =>
<AppserviceToken as CheckAuth>::verify(services, token, request, query, route)
.await,
| None => Ok(Auth::default()),
.await
.map(Some),
| None => Ok(None),
}
}
}
impl CheckAuth for NoAuthentication {
type Identity = ();
async fn verify<B: AsRef<[u8]> + Sync>(
_services: &Services,
_output: Self::Output,
_request: &hyper::Request<B>,
_query: AuthQueryParams,
_route: TypeId,
) -> Result<Auth> {
Ok(Auth::default())
) -> Result<Self::Identity> {
Ok(())
}
}
impl CheckAuth for NoAccessToken {
type Identity = Option<ClientIdentity>;
async fn verify<B: AsRef<[u8]> + Sync>(
services: &Services,
_output: Self::Output,
request: &hyper::Request<B>,
query: AuthQueryParams,
route: TypeId,
) -> Result<Auth> {
) -> Result<Self::Identity> {
// We handle these the same as AccessTokenOptional
let token = AccessTokenOptional::extract_authentication(request).map_err(|err| {
err!(Request(Unauthorized(warn!("Failed to extract authorization: {}", err))))
+3 -3
View File
@@ -28,7 +28,7 @@ pub(crate) async fn get_backfill_route(
) -> Result<get_backfill::v1::Response> {
AccessCheck {
services: &services,
origin: body.origin(),
origin: &body.identity,
room_id: &body.room_id,
event_id: None,
}
@@ -41,7 +41,7 @@ pub(crate) async fn get_backfill_route(
.await
{
info!(
origin = body.origin().as_str(),
origin = body.identity.as_str(),
"Refusing to serve backfill for room we aren't participating in"
);
return Err!(Request(NotFound("This server is not participating in that room.")));
@@ -76,7 +76,7 @@ pub(crate) async fn get_backfill_route(
Ok(services
.rooms
.state_accessor
.server_can_see_event(body.origin(), &pdu.room_id_or_hash(), &pdu.event_id)
.server_can_see_event(&body.identity, &pdu.room_id_or_hash(), &pdu.event_id)
.await
.then_some(pdu))
})
-19
View File
@@ -1,19 +0,0 @@
use axum::extract::State;
use conduwuit::Result;
use ruma::{api::federation::query::get_edu_types, assign};
use crate::Ruma;
/// # `GET /_matrix/federation/v1/edutypes`
///
/// Lists EDU types we wish to receive
pub(crate) async fn get_edutypes_route(
State(services): State<crate::State>,
_body: Ruma<get_edu_types::unstable::Request>,
) -> Result<get_edu_types::unstable::Response> {
Ok(assign!(get_edu_types::unstable::Response::new(), {
typing: services.config.allow_incoming_typing,
presence: services.config.allow_incoming_presence,
receipt: services.config.allow_incoming_read_receipts,
}))
}
+2 -2
View File
@@ -40,7 +40,7 @@ pub(crate) async fn get_event_route(
AccessCheck {
services: &services,
origin: body.origin(),
origin: &body.identity,
room_id,
event_id: Some(&body.event_id),
}
@@ -54,7 +54,7 @@ pub(crate) async fn get_event_route(
.await
{
info!(
origin = body.origin().as_str(),
origin = body.identity.as_str(),
"Refusing to serve state for room we aren't participating in"
);
return Err!(Request(NotFound("This server is not participating in that room.")));
+2 -2
View File
@@ -19,7 +19,7 @@ pub(crate) async fn get_event_authorization_route(
) -> Result<get_event_authorization::v1::Response> {
AccessCheck {
services: &services,
origin: body.origin(),
origin: &body.identity,
room_id: &body.room_id,
event_id: None,
}
@@ -42,7 +42,7 @@ pub(crate) async fn get_event_authorization_route(
.await
{
info!(
origin = body.origin().as_str(),
origin = body.identity.as_str(),
"Refusing to serve state for room we aren't participating in"
);
return Err!(Request(NotFound("This server is not participating in that room.")));
+4 -4
View File
@@ -22,7 +22,7 @@ pub(crate) async fn get_missing_events_route(
) -> Result<get_missing_events::v1::Response> {
AccessCheck {
services: &services,
origin: body.origin(),
origin: &body.identity,
room_id: &body.room_id,
event_id: None,
}
@@ -36,7 +36,7 @@ pub(crate) async fn get_missing_events_route(
.await
{
info!(
origin = body.origin().as_str(),
origin = body.identity.as_str(),
"Refusing to serve state for room we aren't participating in"
);
return Err!(Request(NotFound("This server is not participating in that room.")));
@@ -91,10 +91,10 @@ pub(crate) async fn get_missing_events_route(
if !services
.rooms
.state_accessor
.server_can_see_event(body.origin(), &body.room_id, pdu.event_id())
.server_can_see_event(&body.identity, &body.room_id, pdu.event_id())
.await
{
debug!(%next_event_id, origin = %body.origin(), "redacting event origin cannot see");
debug!(%next_event_id, origin = %body.identity, "redacting event origin cannot see");
pdu.redact(&room_version, json!({}))?;
}
+2 -2
View File
@@ -20,7 +20,7 @@ pub(crate) async fn get_hierarchy_route(
.await
{
info!(
origin = body.origin().as_str(),
origin = body.identity.as_str(),
"Refusing to serve state for room we aren't participating in"
);
return Err!(Request(NotFound("This server is not participating in that room.")));
@@ -29,7 +29,7 @@ pub(crate) async fn get_hierarchy_route(
let response = services
.rooms
.summary
.get_local_room_summary_for_server(body.origin(), &body.room_id, body.suggested_only)
.get_local_room_summary_for_server(&body.identity, &body.room_id, body.suggested_only)
.await;
if let Accessibility::Accessible(response) = response {

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