Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 17a3ed4c56 | |||
| 2dd68d3fa5 | |||
| dc18f89c0b | |||
| eaf1cf38a5 | |||
| eeda96d94a | |||
| 1e8b8cce0f | |||
| db46d6dd6b | |||
| 08274150e5 | |||
| e125af620e | |||
| 177c9e8bfa | |||
| 4f5c6de853 | |||
| 25c004f08c | |||
| f104ced55d | |||
| 0cea64309a | |||
| 229f2fde7a | |||
| 9a0ffd55da | |||
| d1b3faf4bd | |||
| 4014cb4413 | |||
| b2dbc3bc10 | |||
| e2033fb6c1 | |||
| 6b433392a4 | |||
| 0832c28a40 | |||
| b0eec60724 | |||
| 82acc7c0b0 | |||
| c9384e9c78 | |||
| 3502e6ef87 | |||
| deca2c52c6 | |||
| daa46a0dc4 | |||
| 74791642c1 | |||
| 1a64e42cfe |
+6
-1
@@ -11,5 +11,10 @@ indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
|
||||
[*.{md,txt}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 80
|
||||
|
||||
[*.nix]
|
||||
indent_size = 2
|
||||
indent_size = 2
|
||||
|
||||
@@ -50,6 +50,9 @@ jobs:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
|
||||
- name: Sync repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -74,7 +77,7 @@ jobs:
|
||||
cachix use nix-community
|
||||
|
||||
- name: Restore and cache Nix store
|
||||
uses: nix-community/cache-nix-action@v5.2.1
|
||||
uses: nix-community/cache-nix-action@v5.1.0
|
||||
with:
|
||||
# restore and save a cache using this key
|
||||
primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/.lock') }}
|
||||
@@ -119,7 +122,7 @@ jobs:
|
||||
- name: Cache CI dependencies
|
||||
run: |
|
||||
bin/nix-build-and-cache ci
|
||||
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Run CI tests
|
||||
@@ -199,7 +202,7 @@ jobs:
|
||||
cachix use nix-community
|
||||
|
||||
- name: Restore and cache Nix store
|
||||
uses: nix-community/cache-nix-action@v5.2.1
|
||||
uses: nix-community/cache-nix-action@v5.1.0
|
||||
with:
|
||||
# restore and save a cache using this key
|
||||
primary-key: nix-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('**/*.nix', '**/.lock') }}
|
||||
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
cachix use nix-community
|
||||
|
||||
- name: Restore and cache Nix store
|
||||
uses: nix-community/cache-nix-action@v5.2.1
|
||||
uses: nix-community/cache-nix-action@v5.1.0
|
||||
with:
|
||||
# restore and save a cache using this key
|
||||
primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/.lock') }}
|
||||
@@ -106,6 +106,11 @@ jobs:
|
||||
run: |
|
||||
bin/nix-build-and-cache ci
|
||||
|
||||
- name: Run lychee and markdownlint
|
||||
run: |
|
||||
direnv exec . engage just lints lychee
|
||||
direnv exec . engage just lints markdownlint
|
||||
|
||||
- name: Build documentation (book)
|
||||
run: |
|
||||
./bin/nix-build-and-cache just .#book
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
.gitignore
|
||||
+1
-2
@@ -61,7 +61,7 @@ representative at an online or offline event.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement over email at
|
||||
strawberry@puppygock.gay or over Matrix at @strawberry:puppygock.gay.
|
||||
<strawberry@puppygock.gay> or over Matrix at @strawberry:puppygock.gay.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
@@ -131,4 +131,3 @@ For answers to common questions about this code of conduct, see the FAQ at
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ To test, format, lint, etc that CI would do, install engage, allow the `.envrc`
|
||||
All of the tasks are defined at the [engage.toml][engage.toml] file. You can view all of them neatly by running `engage list`
|
||||
|
||||
If you would like to run only a specific engage task group, use `just`:
|
||||
|
||||
- `engage just <group>`
|
||||
- Example: `engage just lints`
|
||||
|
||||
@@ -37,6 +38,7 @@ The following binaries are used in [`engage.toml`][engage.toml]:
|
||||
- [`cargo-audit`][cargo-audit]
|
||||
- [`cargo-deb`][cargo-deb]
|
||||
- [`lychee`][lychee]
|
||||
- [`markdownlint-cli`][markdownlint-cli]
|
||||
|
||||
### Matrix tests
|
||||
|
||||
@@ -86,6 +88,7 @@ By sending a pull request or patch, you are agreeing that your changes are allow
|
||||
[sytest]: https://github.com/matrix-org/sytest/
|
||||
[cargo-deb]: https://github.com/kornelski/cargo-deb
|
||||
[lychee]: https://github.com/lycheeverse/lychee
|
||||
[markdownlint-cli]: https://github.com/igorshubovych/markdownlint-cli
|
||||
[cargo-audit]: https://github.com/RustSec/rustsec/tree/main/cargo-audit
|
||||
[direnv]: https://direnv.net/
|
||||
[mdbook]: https://rust-lang.github.io/mdBook/
|
||||
|
||||
Generated
+47
-24
@@ -570,7 +570,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "conduit"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"conduit_admin",
|
||||
@@ -598,7 +598,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduit_admin"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"conduit_api",
|
||||
@@ -620,7 +620,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduit_api"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
dependencies = [
|
||||
"axum 0.7.5",
|
||||
"axum-client-ip",
|
||||
@@ -653,7 +653,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduit_core"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"axum 0.7.5",
|
||||
@@ -692,7 +692,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduit_database"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
dependencies = [
|
||||
"conduit_core",
|
||||
"log",
|
||||
@@ -704,7 +704,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduit_router"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
dependencies = [
|
||||
"axum 0.7.5",
|
||||
"axum-client-ip",
|
||||
@@ -737,7 +737,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduit_service"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
@@ -1552,6 +1552,15 @@ dependencies = [
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-auth"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "643c9bbf6a4ea8a656d6b4cd53d34f79e3f841ad5203c1a55fb7d761923bc255"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.6"
|
||||
@@ -2894,7 +2903,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma"
|
||||
version = "0.10.1"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"assign",
|
||||
"js_int",
|
||||
@@ -2906,6 +2915,7 @@ dependencies = [
|
||||
"ruma-federation-api",
|
||||
"ruma-identity-service-api",
|
||||
"ruma-push-gateway-api",
|
||||
"ruma-server-util",
|
||||
"ruma-signatures",
|
||||
"ruma-state-res",
|
||||
"web-time 1.1.0",
|
||||
@@ -2914,7 +2924,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-appservice-api"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
@@ -2926,7 +2936,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-client-api"
|
||||
version = "0.18.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"as_variant",
|
||||
"assign",
|
||||
@@ -2949,7 +2959,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-common"
|
||||
version = "0.13.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"as_variant",
|
||||
"base64 0.22.1",
|
||||
@@ -2962,7 +2972,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"regex",
|
||||
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0)",
|
||||
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
|
||||
"ruma-macros",
|
||||
"serde",
|
||||
"serde_html_form",
|
||||
@@ -2979,7 +2989,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-events"
|
||||
version = "0.28.1"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"as_variant",
|
||||
"indexmap 2.2.6",
|
||||
@@ -2989,7 +2999,7 @@ dependencies = [
|
||||
"pulldown-cmark",
|
||||
"regex",
|
||||
"ruma-common",
|
||||
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0)",
|
||||
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
|
||||
"ruma-macros",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -3002,7 +3012,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-federation-api"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
@@ -3014,7 +3024,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-identifiers-validation"
|
||||
version = "0.9.5"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"thiserror",
|
||||
@@ -3032,7 +3042,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-identity-service-api"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
@@ -3042,13 +3052,13 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-macros"
|
||||
version = "0.13.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0)",
|
||||
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
|
||||
"serde",
|
||||
"syn 2.0.68",
|
||||
"toml",
|
||||
@@ -3057,7 +3067,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-push-gateway-api"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
@@ -3066,10 +3076,23 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruma-server-util"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"headers",
|
||||
"http 1.1.0",
|
||||
"http-auth",
|
||||
"ruma-common",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruma-signatures"
|
||||
version = "0.15.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"ed25519-dalek",
|
||||
@@ -3085,7 +3108,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-state-res"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"js_int",
|
||||
@@ -3307,9 +3330,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sd-notify"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "621e3680f3e07db4c9c2c3fb07c6223ab2fab2e54bd3c04c3ae037990f428c32"
|
||||
checksum = "4646d6f919800cd25c50edb49438a1381e2cd4833c027e75e8897981c50b8b5e"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
|
||||
+5
-3
@@ -20,7 +20,7 @@ license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/girlbossceo/conduwuit"
|
||||
rust-version = "1.77.0"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
|
||||
[workspace.metadata.crane]
|
||||
name = "conduit"
|
||||
@@ -208,7 +208,7 @@ features = ["serde"]
|
||||
# standard date and time tools
|
||||
[workspace.dependencies.chrono]
|
||||
version = "0.4.38"
|
||||
features = ["alloc"]
|
||||
features = ["alloc", "std"]
|
||||
default-features = false
|
||||
|
||||
[workspace.dependencies.hyper]
|
||||
@@ -274,7 +274,7 @@ version = "0.1.2"
|
||||
[workspace.dependencies.ruma]
|
||||
git = "https://github.com/girlbossceo/ruwuma"
|
||||
#branch = "conduwuit-changes"
|
||||
rev = "9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
|
||||
rev = "c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
|
||||
features = [
|
||||
"compat",
|
||||
"rand",
|
||||
@@ -284,6 +284,7 @@ features = [
|
||||
"markdown",
|
||||
"push-gateway-api-c",
|
||||
"state-res",
|
||||
"server-util",
|
||||
"unstable-exhaustive-types",
|
||||
"ring-compat",
|
||||
"unstable-unspecified",
|
||||
@@ -293,6 +294,7 @@ features = [
|
||||
"unstable-msc2870",
|
||||
"unstable-msc3026",
|
||||
"unstable-msc3061",
|
||||
"unstable-msc3266",
|
||||
"unstable-msc3575",
|
||||
"unstable-msc4121",
|
||||
"unstable-msc4125",
|
||||
|
||||
@@ -43,6 +43,7 @@ from time to time.
|
||||
#### Contact
|
||||
|
||||
If you run into any question, feel free to
|
||||
|
||||
- Ask us in `#conduwuit:puppygock.gay` on Matrix
|
||||
- [Open an issue on GitHub](https://github.com/girlbossceo/conduwuit/issues/new)
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ OCI_IMAGE="complement-conduit:main"
|
||||
# Complement itself induced based on various open issues)
|
||||
#
|
||||
# According to Go docs, these are separated by forward slashes and not pipes (why)
|
||||
SKIPPED_COMPLEMENT_TESTS='-skip=TestJumpToDateEndpoint.*|TestJoinFederatedRoomFromApplicationServiceBridgeUser.*|TestFederationRoomsInvite.*|TestClientSpacesSummary.*'
|
||||
SKIPPED_COMPLEMENT_TESTS='-skip=TestClientSpacesSummary.*|TestJoinFederatedRoomFromApplicationServiceBridgeUser.*|TestJumpToDateEndpoint.*'
|
||||
|
||||
toplevel="$(git rev-parse --show-toplevel)"
|
||||
|
||||
|
||||
@@ -378,6 +378,8 @@ allow_profile_lookup_federation_requests = true
|
||||
# Enable backward-compatibility with Conduit's media directory by creating symlinks of media. This
|
||||
# option is only necessary if you plan on using Conduit again. Otherwise setting this to false
|
||||
# reduces filesystem clutter and overhead for managing these symlinks in the directory.
|
||||
#
|
||||
# Enabled by default.
|
||||
#media_compat_file_link = true
|
||||
|
||||
# Checks consistency of the media directory at startup:
|
||||
@@ -387,8 +389,23 @@ allow_profile_lookup_federation_requests = true
|
||||
#
|
||||
# If none of these checks apply to your use cases, and your media directory is significantly large
|
||||
# setting this to false may reduce startup time.
|
||||
#
|
||||
# Enabled by default.
|
||||
#media_statup_check = true
|
||||
|
||||
# OpenID token expiration/TTL in seconds
|
||||
#
|
||||
# These are the OpenID tokens that are primarily used for Matrix account integrations, *not* OIDC/OpenID Connect/etc
|
||||
#
|
||||
# Defaults to 3600 (1 hour)
|
||||
#openid_token_ttl = 3600
|
||||
|
||||
# Emergency password feature. This password set here will let you login to the server service account (e.g. `@conduit`)
|
||||
# and let you run admin commands, invite yourself to the admin room, etc.
|
||||
#
|
||||
# no default.
|
||||
#emergency_password = ""
|
||||
|
||||
|
||||
### Generic database options
|
||||
|
||||
|
||||
+9
-9
@@ -3,19 +3,19 @@
|
||||
- [Introduction](introduction.md)
|
||||
- [Differences from upstream Conduit](differences.md)
|
||||
- [Configuration](configuration.md)
|
||||
- [Examples](configuration/examples.md)
|
||||
- [Examples](configuration/examples.md)
|
||||
- [Deploying](deploying.md)
|
||||
- [Generic](deploying/generic.md)
|
||||
- [NixOS](deploying/nixos.md)
|
||||
- [Docker](deploying/docker.md)
|
||||
- [Arch Linux](deploying/arch-linux.md)
|
||||
- [Debian](deploying/debian.md)
|
||||
- [Generic](deploying/generic.md)
|
||||
- [NixOS](deploying/nixos.md)
|
||||
- [Docker](deploying/docker.md)
|
||||
- [Arch Linux](deploying/arch-linux.md)
|
||||
- [Debian](deploying/debian.md)
|
||||
- [TURN](turn.md)
|
||||
- [Appservices](appservices.md)
|
||||
- [Maintenance](maintenance.md)
|
||||
- [Troubleshooting](troubleshooting.md)
|
||||
- [Development](development.md)
|
||||
- [Contributing](contributing.md)
|
||||
- [Testing](development/testing.md)
|
||||
- [Hot Reloading ("Live" Development)](development/hot_reload.md)
|
||||
- [Contributing](contributing.md)
|
||||
- [Testing](development/testing.md)
|
||||
- [Hot Reloading ("Live" Development)](development/hot_reload.md)
|
||||
- [conduwuit Community Code of Conduct](conduwuit_coc.md)
|
||||
|
||||
@@ -24,9 +24,11 @@ OCI images for conduwuit are available in the registries listed below.
|
||||
[shield-main]: https://img.shields.io/docker/image-size/girlbossceo/conduwuit/main
|
||||
|
||||
Use
|
||||
|
||||
```bash
|
||||
docker image pull <link>
|
||||
```
|
||||
|
||||
to pull it to your machine.
|
||||
|
||||
### Run
|
||||
@@ -55,6 +57,7 @@ If you just want to test conduwuit for a short time, you can use the `--rm` flag
|
||||
If the `docker run` command is not for you or your setup, you can also use one of the provided `docker-compose` files.
|
||||
|
||||
Depending on your proxy setup, you can use one of the following files;
|
||||
|
||||
- If you already have a `traefik` instance set up, use [`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml)
|
||||
- If you don't have a `traefik` instance set up (or any other reverse proxy), use [`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)
|
||||
- For any other reverse proxy, use [`docker-compose.yml`](docker-compose.yml)
|
||||
@@ -100,7 +103,6 @@ either expose ports `443` and `8448` or serve two endpoints `.well-known/matrix/
|
||||
|
||||
With the service `well-known` we use a single `nginx` container that will serve those two files.
|
||||
|
||||
|
||||
## Voice communication
|
||||
|
||||
See the [TURN](../turn.md) page.
|
||||
|
||||
@@ -93,21 +93,21 @@ your.server.name, your.server.name:8448 {
|
||||
That's it! Just start and enable the service and you're set.
|
||||
|
||||
```bash
|
||||
$ sudo systemctl enable --now caddy
|
||||
sudo systemctl enable --now caddy
|
||||
```
|
||||
|
||||
## You're done!
|
||||
## You're done
|
||||
|
||||
Now you can start conduwuit with:
|
||||
|
||||
```bash
|
||||
$ sudo systemctl start conduwuit
|
||||
sudo systemctl start conduwuit
|
||||
```
|
||||
|
||||
Set it to start automatically when your system boots with:
|
||||
|
||||
```bash
|
||||
$ sudo systemctl enable conduwuit
|
||||
sudo systemctl enable conduwuit
|
||||
```
|
||||
|
||||
## How do I know it works?
|
||||
|
||||
@@ -8,6 +8,7 @@ conduwuit can be acquired by [Lix][lix] from various places:
|
||||
|
||||
A binary cache for conduwuit that the CI/CD publishes to is available at the
|
||||
following places (both are the same just different names):
|
||||
|
||||
```
|
||||
https://attic.kennel.juneis.dog/conduit
|
||||
conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk=
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ look like this:
|
||||
RUSTFLAGS="--cfg tokio_unstable" cargo build \
|
||||
--release \
|
||||
--no-default-features \
|
||||
--features=rocksdb,systemd,element_hacks,gzip_compression,brotli_compression,zstd_compression,tokio_console
|
||||
--features=systemd,element_hacks,gzip_compression,brotli_compression,zstd_compression,tokio_console
|
||||
```
|
||||
|
||||
[1]: https://docs.rs/tokio-console/latest/tokio_console/
|
||||
|
||||
@@ -65,14 +65,17 @@ When a symbol is referenced between crates they become bound: **crates cannot be
|
||||
Proper resource management is essential for reliable reloading to occur. This is a very basic ask in RAII-idiomatic Rust and the exposure to reloading hazards is remarkably low, generally stemming from poor patterns and practices. Unfortunately static analysis doesn't enforce reload-safety programmatically (though it could one day), for now hazards can be avoided by knowing a few basic do's and dont's:
|
||||
|
||||
1. Understand that code is memory. Just like one is forbidden from referencing free'd memory, one must not transfer control to free'd code. Exposure to this is primarily from two things:
|
||||
|
||||
- Callbacks, which this project makes very little use of.
|
||||
- Async tasks, which are addressed below.
|
||||
|
||||
2. Tie all resources to a scope or object lifetime with greatest possible symmetry (locality). For our purposes this applies to code resources, which means async blocks and tokio tasks.
|
||||
|
||||
- **Never spawn a task without receiving and storing its JoinHandle**.
|
||||
- **Always wait on join handles** before leaving a scope or in another cleanup function called by an owning scope.
|
||||
|
||||
3. Know any minor specific quirks documented in code or here:
|
||||
|
||||
- Don't use `tokio::spawn`, instead use our `Handle` in `core/server.rs`, which is reachable in most of the codebase via `services()` or other state. This is due to some bugs or assumptions made in tokio, as it happens in `unsafe {}` blocks, which are mitigated by circumventing some thread-local variables. Using runtime handles is good practice in any case.
|
||||
|
||||
The initial implementation PR is available [here][1].
|
||||
|
||||
+17
-13
@@ -1,10 +1,11 @@
|
||||
#### **Note: This list may not up to date. There are rapidly more and more improvements, fixes, changes, etc being made that it is becoming more difficult to maintain this list. I recommend that you give conduwuit a try and see the differences for yourself. If you have any concerns, feel free to join the conduwuit Matrix room and ask any pre-usage questions.**
|
||||
|
||||
### list of features, bug fixes, etc that conduwuit does that Conduit does not:
|
||||
### list of features, bug fixes, etc that conduwuit does that Conduit does not
|
||||
|
||||
Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
||||
|
||||
## Performance:
|
||||
## Performance
|
||||
|
||||
- Concurrency support for individual homeserver key fetching for faster remote room joins and room joins that will error less frequently
|
||||
- Send `Cache-Control` response header with `immutable` and 1 year cache length for all media requests (download and thumbnail) to instruct clients to cache media, and reduce server load from media requests that could be otherwise cached
|
||||
- Add feature flags and config options to enable/build with zstd, brotli, and/or gzip HTTP body compression (response and request)
|
||||
@@ -25,9 +26,10 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
||||
- Use `tracing`/`log`'s `release_max_level_info` feature to improve performance, build speeds, binary size, and CPU usage in release builds by avoid compiling debug/trace log level macros that users will generally never use (can be disabled with a build-time feature flag)
|
||||
- Remove some unnecessary checks on EDU handling for incoming transactions, effectively speeding them up
|
||||
- Simplify, dedupe, etc huge chunks of the codebase, including some that were unnecessary overhead, binary bloats, or preventing compiler/linker optimisations
|
||||
- Implement zero-copy RocksDB database accessors, substantially improving performance caused by unnecessary memory allocations
|
||||
|
||||
## General Fixes/Features
|
||||
|
||||
## General Fixes/Features:
|
||||
- Add legacy Element client hack fixing password changes and deactivations on legacy Element Android/iOS due to usage of an unspecced `user` field for UIAA
|
||||
- Raise and improve all the various request timeouts making some things like room joins and client bugs error less or none at all than they should, and make them all user configurable
|
||||
- Add missing `reason` field to user ban events (`/ban`)
|
||||
@@ -56,11 +58,11 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
||||
- Explicitly define support for sliding sync at `/_matrix/client/versions` (`org.matrix.msc3575`)
|
||||
- Fix seeing empty status messages on user presences
|
||||
|
||||
## Moderation
|
||||
|
||||
## Moderation:
|
||||
- (Also see [Admin Room](#admin-room) for all the admin commands pertaining to moderation, there's a lot!)
|
||||
- Add support for room banning/blocking by ID using admin command
|
||||
- Add support for serving `support` well-known from `[well_known.support]` (MSC1929)
|
||||
- Add support for serving `support` well-known from `[global.well_known]` (MSC1929) (`/.well-known/matrix/support`)
|
||||
- Config option to forbid publishing rooms to the room directory (`lockdown_public_room_directory`) except for admins
|
||||
- Admin commands to delete room aliases and unpublish rooms from our room directory
|
||||
- For all [`/report`](https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3roomsroomidreporteventid) requests: check if the reported event ID belongs to the reported room ID, raise report reasoning character limit to 750, fix broken formatting, make a small delayed random response per spec suggestion on privacy, and check if the sender user is in the reported room.
|
||||
@@ -73,8 +75,8 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
||||
- Deactivating users will remove their profile picture, blurhash, display name, and leave all rooms by default just like Synapse and for additional privacy
|
||||
- Reject some EDUs from ACL'd users such as read receipts and typing indicators
|
||||
|
||||
## Privacy/Security
|
||||
|
||||
## Privacy/Security:
|
||||
- Add config option for device name federation with a privacy-friendly default (disabled)
|
||||
- Add config option for requiring authentication to the `/publicRooms` endpoint (room directory) with a default enabled for privacy
|
||||
- Add config option for federating `/publicRooms` endpoint (room directory) to other servers with a default disabled for privacy
|
||||
@@ -89,8 +91,8 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
||||
- Media repository on handling `Content-Disposition` and `Content-Type` is fully spec compliant and secured
|
||||
- Send secure default HTTP headers such as a strong restrictive CSP (see MSC4149), deny iframes, disable `X-XSS-Protection`, disable interest cohort in `Permission-Policy`, etc to mitigate any potential attack surface such as from untrusted media
|
||||
|
||||
## Administration/Logging
|
||||
|
||||
## Administration/Logging:
|
||||
- Commandline argument to specify the path to a config file instead of relying on `CONDUIT_CONFIG`
|
||||
- Revamped admin room infrastructure and commands
|
||||
- Substantially clean up, improve, and fix logging (less noisy dead server logging, registration attempts, more useful troubleshooting logging, proper error propagation, etc)
|
||||
@@ -108,8 +110,8 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
||||
- Log the client IP on various requests such as registrations, banned room join attempts, logins, deactivations, federation transactions, etc
|
||||
- Fix Conduit dropping some remote server federation response errors
|
||||
|
||||
## Maintenance/Stability
|
||||
|
||||
## Maintenance/Stability:
|
||||
- GitLab CI ported to GitHub Actions
|
||||
- Add support for the Matrix spec compliance test suite [Complement](https://github.com/matrix-org/complement/) via the Nix flake and various other fixes for it
|
||||
- Implement running and diff'ing Complement results in CI and error if any mismatch occurs to prevent large cases of conduwuit regressions
|
||||
@@ -119,19 +121,21 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
||||
- Fixed every single clippy (default lints) and rustc warnings, including some that were performance related or potential safety issues / unsoundness
|
||||
- Add a **lot** of other clippy and rustc lints and a rustfmt.toml file
|
||||
- Repo uses [Renovate](https://docs.renovatebot.com/), [Trivy](https://github.com/aquasecurity/trivy-action), and keeps ALL dependencies as up to date as possible
|
||||
- Attempts and interest in removing extreme and unnecessary panics/unwraps/expects that can lead to denial of service or such (upstream and upstream contributors want this unusual behaviour for some reason)
|
||||
- Purge unmaintained/irrelevant/broken database backends (heed, sled, persy) and other unnecessary code or overhead
|
||||
- webp support for images
|
||||
- Add cargo audit support to CI
|
||||
- Add documentation lints via lychee and markdownlint-cli to CI
|
||||
- CI tests for all sorts of feature matrixes (jemalloc, non-defaullt, all features, etc)
|
||||
- Add static and dynamic linking smoke tests in CI to prevent any potential linking regressions for Complement, static binaries, Nix devshells, etc
|
||||
- Add timestamp by commit date when building OCI images for keeping image build reproducibility and still have a meaningful "last modified date" for OCI image
|
||||
- Add timestamp by commit date via `SOURCE_DATE_EPOCH` for Debian packages
|
||||
- Startup check if conduwuit running in a container and is listening on 127.0.0.1 (generally containers are using NAT networking and 0.0.0.0 is the intended listening address)
|
||||
- Add a panic catcher layer to return panic messages in HTTP responses if a panic occurs
|
||||
- Add full compatibility support for SHA256 media file names instead of base64 file names to overcome filesystem file name length limitations (OS error file name too long) while still retaining upstream database compatibility
|
||||
- Remove SQLite support due to being very poor performance, difficult to maintain against RocksDB, and is a blocker to significantly improved database code
|
||||
|
||||
## Admin Room
|
||||
|
||||
## Admin Room:
|
||||
- Add support for a console CLI interface that can issue admin commands and output them in your terminal
|
||||
- Add support for an admin-user-only commandline admin room interface that can be issued in any room with the `\\!admin` or `\!admin` prefix and returns the response as yourself in the same room
|
||||
- Add admin commands for uptime, server startup, server shutdown, and server restart
|
||||
@@ -165,12 +169,11 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
||||
- Extend memory usage admin server command to support showing memory allocator stats such as jemalloc's
|
||||
- Add admin debug command to see memory allocator's full extended debug statistics such as jemalloc's
|
||||
|
||||
## Misc
|
||||
|
||||
## Misc:
|
||||
- Add guest support for accessing TURN servers via `turn_allow_guests` like Synapse
|
||||
- Support for creating rooms with custom room IDs like Maunium Synapse (`room_id` request body field to `/createRoom`)
|
||||
- Query parameter `?format=event|content` for returning either the room state event's content (default) for the full room state event on ` /_matrix/client/v3/rooms/{roomId}/state/{eventType}[/{stateKey}]` requests (see https://github.com/matrix-org/matrix-spec/issues/1047)
|
||||
- Add **optional** feature flag to use SHA256 key names for media instead of base64 to overcome filesystem file name length limitations (OS error file name too long)
|
||||
- Query parameter `?format=event|content` for returning either the room state event's content (default) for the full room state event on `/_matrix/client/v3/rooms/{roomId}/state/{eventType}[/{stateKey}]` requests (see <https://github.com/matrix-org/matrix-spec/issues/1047>)
|
||||
- Send a User-Agent on all of our requests
|
||||
- Send `avatar_url` on invite room membership events/changes
|
||||
- Support sending [`well_known` response to client login responses](https://spec.matrix.org/v1.10/client-server-api/#post_matrixclientv3login) if using config option `[well_known.client]`
|
||||
@@ -179,6 +182,7 @@ Outgoing typing indicators, outgoing read receipts, **and** outgoing presence!
|
||||
- Implement legacy Matrix `/v1/` media endpoints that some clients and servers may still call
|
||||
- Config option to change Conduit's behaviour of homeserver key fetching (`query_trusted_key_servers_first`). This option sets whether conduwuit will query trusted notary key servers first before the individual homeserver(s), or vice versa which may help in joining certain rooms.
|
||||
- Implement unstable MSC2666 support for querying mutual rooms with a user
|
||||
- Implement unstable MSC3266 room summary API support
|
||||
- Implement unstable MSC4125 support for specifying servers to join via on federated invites
|
||||
- Make conduwuit build and be functional under Nix + macOS
|
||||
- Log out all sessions after unsetting the emergency password
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
conduwuit has moderation through admin room commands. "binary commands" (medium priority) and an admin API (low priority) is planned. Some moderation-related config options are available in the example config such as "global ACLs" and blocking media requests to certain servers. See the example config for the moderation config options under the "Moderation / Privacy / Security" section.
|
||||
|
||||
conduwuit has moderation admin commands for:
|
||||
|
||||
- managing room aliases (`!admin rooms alias`)
|
||||
- managing room directory (`!admin rooms directory`)
|
||||
- managing room banning/blocking and user removal (`!admin rooms moderation`)
|
||||
@@ -37,6 +38,7 @@ RocksDB troubleshooting can be found [in the RocksDB section of troubleshooting]
|
||||
Currently only RocksDB supports online backups. If you'd like to backup your database online without any downtime, see the `!admin server` command for the backup commands and the `database_backup_path` config options in the example config. Please note that the format of the database backup is not the exact same. This is unfortunately a bad design choice by Facebook as we are using the database backup engine API from RocksDB, however the data is still there and can still be joined together.
|
||||
|
||||
To restore a backup from an online RocksDB backup:
|
||||
|
||||
- shutdown conduwuit
|
||||
- create a new directory for merging together the data
|
||||
- in the online backup created, copy all `.sst` files in `$DATABASE_BACKUP_PATH/shared_checksum` to your new directory
|
||||
@@ -52,6 +54,7 @@ Backing up media is also just copying the `media/` directory from your database
|
||||
## Media
|
||||
|
||||
Media still needs various work, however conduwuit implements media deletion via:
|
||||
|
||||
- MXC URI or Event ID (unencrypted and attempts to find the MXC URI in the event)
|
||||
- Delete list of MXC URIs
|
||||
- Delete remote media in the past `N` seconds/minutes via filesystem metadata on the file created time (`btime`) or file modified time (`mtime`)
|
||||
|
||||
@@ -40,10 +40,6 @@ With this in mind:
|
||||
|
||||
## Media
|
||||
|
||||
#### "File name too long"
|
||||
|
||||
If you are running into the "file name is too long" OS error for media requests, your filesystem cannot handle file name lengths >=255 characters. This is unfortuntely due to Conduit (upstream) using base64 for file name keys which is very problematic for some filesystems as the base64 input is untrusted and long file names or specific inputs can cause this. If you would like to avoid this, you may build conduwuit yourself with the `sha256_media` feature. **This will lose database compatibility with upstream**.
|
||||
|
||||
## Debugging
|
||||
|
||||
Note that users should not really be debugging things. If you find yourself debugging and find the issue, please let us know and/or how we can fix it. Various debug commands can be found in `!admin debug`.
|
||||
|
||||
@@ -11,12 +11,15 @@ use-auth-secret
|
||||
static-auth-secret=<a secret key>
|
||||
realm=<your server domain>
|
||||
```
|
||||
|
||||
A common way to generate a suitable alphanumeric secret key is by using `pwgen -s 64 1`.
|
||||
|
||||
These same values need to be set in conduwuit. See the [example config](configuration/examples.md) in the TURN section for configuring these and restart conduwuit after.
|
||||
|
||||
### Run
|
||||
|
||||
Run the [Coturn](https://hub.docker.com/r/coturn/coturn) image using
|
||||
|
||||
```bash
|
||||
docker run -d --network=host -v $(pwd)/coturn.conf:/etc/coturn/turnserver.conf coturn/coturn
|
||||
```
|
||||
|
||||
+10
@@ -55,6 +55,11 @@ name = "lychee"
|
||||
group = "versions"
|
||||
script = "lychee --version"
|
||||
|
||||
[[task]]
|
||||
name = "markdownlint"
|
||||
group = "versions"
|
||||
script = "markdownlint --version"
|
||||
|
||||
[[task]]
|
||||
name = "cargo-audit"
|
||||
group = "security"
|
||||
@@ -138,6 +143,11 @@ name = "lychee"
|
||||
group = "lints"
|
||||
script = "lychee --verbose --offline docs *.md --exclude development.md"
|
||||
|
||||
[[task]]
|
||||
name = "markdownlint"
|
||||
group = "lints"
|
||||
script = "markdownlint docs *.md || true" # TODO: fix the ton of markdown lints so we can drop `|| true`
|
||||
|
||||
[[task]]
|
||||
name = "cargo/all"
|
||||
group = "tests"
|
||||
|
||||
@@ -108,6 +108,9 @@
|
||||
# Needed for finding broken markdown links
|
||||
lychee
|
||||
|
||||
# Needed for linting markdown files
|
||||
markdownlint-cli
|
||||
|
||||
# Useful for editing the book locally
|
||||
mdbook
|
||||
])
|
||||
|
||||
@@ -15,7 +15,7 @@ use ruma::{
|
||||
events::room::message::RoomMessageEventContent,
|
||||
CanonicalJsonObject, EventId, OwnedRoomOrAliasId, RoomId, RoomVersionId, ServerName,
|
||||
};
|
||||
use service::{rooms::event_handler::parse_incoming_pdu, sending::resolve::resolve_actual_dest, services, PduEvent};
|
||||
use service::{rooms::event_handler::parse_incoming_pdu, sending::resolve_actual_dest, services, PduEvent};
|
||||
use tokio::sync::RwLock;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
@@ -614,15 +614,16 @@ pub(super) async fn resolve_true_destination(
|
||||
let state = &services().server.log.capture;
|
||||
let logs = Arc::new(Mutex::new(String::new()));
|
||||
let capture = Capture::new(state, Some(filter), capture::fmt_markdown(logs.clone()));
|
||||
let (actual_dest, hostname_uri);
|
||||
{
|
||||
let _capture_scope = capture.start();
|
||||
(actual_dest, hostname_uri) = resolve_actual_dest(&server_name, !no_cache).await?;
|
||||
};
|
||||
|
||||
let capture_scope = capture.start();
|
||||
let actual = resolve_actual_dest(&server_name, !no_cache).await?;
|
||||
drop(capture_scope);
|
||||
|
||||
let msg = format!(
|
||||
"{}\nDestination: {actual_dest}\nHostname URI: {hostname_uri}",
|
||||
logs.lock().expect("locked")
|
||||
"{}\nDestination: {}\nHostname URI: {}",
|
||||
logs.lock().expect("locked"),
|
||||
actual.dest,
|
||||
actual.host,
|
||||
);
|
||||
Ok(RoomMessageEventContent::text_markdown(msg))
|
||||
}
|
||||
|
||||
@@ -15,14 +15,18 @@ pub(super) async fn enable_room(_body: Vec<&str>, room_id: Box<RoomId>) -> Resul
|
||||
}
|
||||
|
||||
pub(super) async fn incoming_federation(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
|
||||
let map = services().globals.roomid_federationhandletime.read().await;
|
||||
let map = services()
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.read()
|
||||
.expect("locked");
|
||||
let mut msg = format!("Handling {} incoming pdus:\n", map.len());
|
||||
|
||||
for (r, (e, i)) in map.iter() {
|
||||
let elapsed = i.elapsed();
|
||||
writeln!(msg, "{} {}: {}m{}s", r, e, elapsed.as_secs() / 60, elapsed.as_secs() % 60,)
|
||||
.expect("should be able to write to string buffer");
|
||||
writeln!(msg, "{} {}: {}m{}s", r, e, elapsed.as_secs() / 60, elapsed.as_secs() % 60)?;
|
||||
}
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain(&msg))
|
||||
}
|
||||
|
||||
|
||||
+24
-3
@@ -2,6 +2,7 @@ mod account_data;
|
||||
mod appservice;
|
||||
mod globals;
|
||||
mod presence;
|
||||
mod resolver;
|
||||
mod room_alias;
|
||||
mod room_state_cache;
|
||||
mod sending;
|
||||
@@ -12,12 +13,12 @@ use conduit::Result;
|
||||
use room_state_cache::room_state_cache;
|
||||
use ruma::{
|
||||
events::{room::message::RoomMessageEventContent, RoomAccountDataEventType},
|
||||
RoomAliasId, RoomId, ServerName, UserId,
|
||||
OwnedServerName, RoomAliasId, RoomId, ServerName, UserId,
|
||||
};
|
||||
|
||||
use self::{
|
||||
account_data::account_data, appservice::appservice, globals::globals, presence::presence, room_alias::room_alias,
|
||||
sending::sending, users::users,
|
||||
account_data::account_data, appservice::appservice, globals::globals, presence::presence, resolver::resolver,
|
||||
room_alias::room_alias, sending::sending, users::users,
|
||||
};
|
||||
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
@@ -55,6 +56,10 @@ pub(super) enum QueryCommand {
|
||||
/// - users.rs iterators and getters
|
||||
#[command(subcommand)]
|
||||
Users(Users),
|
||||
|
||||
/// - resolver service
|
||||
#[command(subcommand)]
|
||||
Resolver(Resolver),
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
@@ -287,6 +292,21 @@ pub(super) enum Users {
|
||||
Iter,
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
#[derive(Subcommand)]
|
||||
/// Resolver service and caches
|
||||
pub(super) enum Resolver {
|
||||
/// Query the destinations cache
|
||||
DestinationsCache {
|
||||
server_name: Option<OwnedServerName>,
|
||||
},
|
||||
|
||||
/// Query the overrides cache
|
||||
OverridesCache {
|
||||
name: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Processes admin query commands
|
||||
pub(super) async fn process(command: QueryCommand, _body: Vec<&str>) -> Result<RoomMessageEventContent> {
|
||||
Ok(match command {
|
||||
@@ -298,5 +318,6 @@ pub(super) async fn process(command: QueryCommand, _body: Vec<&str>) -> Result<R
|
||||
QueryCommand::Globals(command) => globals(command).await?,
|
||||
QueryCommand::Sending(command) => sending(command).await?,
|
||||
QueryCommand::Users(command) => users(command).await?,
|
||||
QueryCommand::Resolver(command) => resolver(command).await?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use conduit::{utils::time, Result};
|
||||
use ruma::{events::room::message::RoomMessageEventContent, OwnedServerName};
|
||||
|
||||
use super::Resolver;
|
||||
use crate::services;
|
||||
|
||||
/// All the getters and iterators in key_value/users.rs
|
||||
pub(super) async fn resolver(subcommand: Resolver) -> Result<RoomMessageEventContent> {
|
||||
match subcommand {
|
||||
Resolver::DestinationsCache {
|
||||
server_name,
|
||||
} => destinations_cache(server_name).await,
|
||||
Resolver::OverridesCache {
|
||||
name,
|
||||
} => overrides_cache(name).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn destinations_cache(server_name: Option<OwnedServerName>) -> Result<RoomMessageEventContent> {
|
||||
use service::sending::CachedDest;
|
||||
|
||||
let mut out = String::new();
|
||||
writeln!(out, "| Server Name | Destination | Hostname | Expires |")?;
|
||||
writeln!(out, "| ----------- | ----------- | -------- | ------- |")?;
|
||||
let row = |(
|
||||
name,
|
||||
&CachedDest {
|
||||
ref dest,
|
||||
ref host,
|
||||
expire,
|
||||
},
|
||||
)| {
|
||||
let expire = time::format(expire, "%+");
|
||||
writeln!(out, "| {name} | {dest} | {host} | {expire} |").expect("wrote line");
|
||||
};
|
||||
|
||||
let map = services()
|
||||
.globals
|
||||
.resolver
|
||||
.destinations
|
||||
.read()
|
||||
.expect("locked");
|
||||
|
||||
if let Some(server_name) = server_name.as_ref() {
|
||||
map.get_key_value(server_name).map(row);
|
||||
} else {
|
||||
map.iter().for_each(row);
|
||||
}
|
||||
|
||||
Ok(RoomMessageEventContent::notice_markdown(out))
|
||||
}
|
||||
|
||||
async fn overrides_cache(server_name: Option<String>) -> Result<RoomMessageEventContent> {
|
||||
use service::sending::CachedOverride;
|
||||
|
||||
let mut out = String::new();
|
||||
writeln!(out, "| Server Name | IP | Port | Expires |")?;
|
||||
writeln!(out, "| ----------- | --- | ----:| ------- |")?;
|
||||
let row = |(
|
||||
name,
|
||||
&CachedOverride {
|
||||
ref ips,
|
||||
port,
|
||||
expire,
|
||||
},
|
||||
)| {
|
||||
let expire = time::format(expire, "%+");
|
||||
writeln!(out, "| {name} | {ips:?} | {port} | {expire} |").expect("wrote line");
|
||||
};
|
||||
|
||||
let map = services()
|
||||
.globals
|
||||
.resolver
|
||||
.overrides
|
||||
.read()
|
||||
.expect("locked");
|
||||
|
||||
if let Some(server_name) = server_name.as_ref() {
|
||||
map.get_key_value(server_name).map(row);
|
||||
} else {
|
||||
map.iter().for_each(row);
|
||||
}
|
||||
|
||||
Ok(RoomMessageEventContent::notice_markdown(out))
|
||||
}
|
||||
@@ -27,12 +27,12 @@ pub(super) async fn show_config(_body: Vec<&str>) -> Result<RoomMessageEventCont
|
||||
}
|
||||
|
||||
pub(super) async fn memory_usage(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
|
||||
let response0 = services().memory_usage().await;
|
||||
let response1 = services().globals.db.memory_usage();
|
||||
let response0 = services().memory_usage().await?;
|
||||
let response1 = services().db.db.memory_usage()?;
|
||||
let response2 = conduit::alloc::memory_usage();
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Services:\n{response0}\n\nDatabase:\n{response1}\n{}",
|
||||
"Services:\n{response0}\nDatabase:\n{response1}\n{}",
|
||||
if !response2.is_empty() {
|
||||
format!("Allocator:\n {response2}")
|
||||
} else {
|
||||
@@ -41,14 +41,8 @@ pub(super) async fn memory_usage(_body: Vec<&str>) -> Result<RoomMessageEventCon
|
||||
)))
|
||||
}
|
||||
|
||||
pub(super) async fn clear_database_caches(_body: Vec<&str>, amount: u32) -> Result<RoomMessageEventContent> {
|
||||
services().globals.db.clear_caches(amount);
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain("Done."))
|
||||
}
|
||||
|
||||
pub(super) async fn clear_service_caches(_body: Vec<&str>, amount: u32) -> Result<RoomMessageEventContent> {
|
||||
services().clear_caches(amount).await;
|
||||
pub(super) async fn clear_caches(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
|
||||
services().clear_cache().await;
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain("Done."))
|
||||
}
|
||||
|
||||
+3
-17
@@ -18,17 +18,8 @@ pub(super) enum ServerCommand {
|
||||
/// - Print database memory usage statistics
|
||||
MemoryUsage,
|
||||
|
||||
/// - Clears all of Conduit's database caches with index smaller than the
|
||||
/// amount
|
||||
ClearDatabaseCaches {
|
||||
amount: u32,
|
||||
},
|
||||
|
||||
/// - Clears all of Conduit's service caches with index smaller than the
|
||||
/// amount
|
||||
ClearServiceCaches {
|
||||
amount: u32,
|
||||
},
|
||||
/// - Clears all of Conduwuit's caches
|
||||
ClearCaches,
|
||||
|
||||
/// - Performs an online backup of the database (only available for RocksDB
|
||||
/// at the moment)
|
||||
@@ -65,12 +56,7 @@ pub(super) async fn process(command: ServerCommand, body: Vec<&str>) -> Result<R
|
||||
ServerCommand::Uptime => uptime(body).await?,
|
||||
ServerCommand::ShowConfig => show_config(body).await?,
|
||||
ServerCommand::MemoryUsage => memory_usage(body).await?,
|
||||
ServerCommand::ClearDatabaseCaches {
|
||||
amount,
|
||||
} => clear_database_caches(body, amount).await?,
|
||||
ServerCommand::ClearServiceCaches {
|
||||
amount,
|
||||
} => clear_service_caches(body, amount).await?,
|
||||
ServerCommand::ClearCaches => clear_caches(body).await?,
|
||||
ServerCommand::ListBackups => list_backups(body).await?,
|
||||
ServerCommand::BackupDatabase => backup_database(body).await?,
|
||||
ServerCommand::ListDatabaseFiles => list_database_files(body).await?,
|
||||
|
||||
@@ -10,11 +10,7 @@ use ruma::{
|
||||
},
|
||||
directory::{Filter, PublicRoomJoinRule, PublicRoomsChunk, RoomNetwork},
|
||||
events::{
|
||||
room::{
|
||||
avatar::RoomAvatarEventContent,
|
||||
create::RoomCreateEventContent,
|
||||
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
||||
},
|
||||
room::join_rules::{JoinRule, RoomJoinRulesEventContent},
|
||||
StateEventType,
|
||||
},
|
||||
uint, ServerName, UInt,
|
||||
@@ -256,15 +252,10 @@ pub(crate) async fn get_public_rooms_filtered_helper(
|
||||
avatar_url: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(&room_id, &StateEventType::RoomAvatar, "")?
|
||||
.map(|s| {
|
||||
serde_json::from_str(s.content.get())
|
||||
.map(|c: RoomAvatarEventContent| c.url)
|
||||
.map_err(|_| Error::bad_database("Invalid room avatar event in database."))
|
||||
})
|
||||
.transpose()?
|
||||
// url is now an Option<String> so we must flatten
|
||||
.flatten(),
|
||||
.get_avatar(&room_id)?
|
||||
.into_option()
|
||||
.unwrap_or_default()
|
||||
.url,
|
||||
join_rule: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
@@ -287,15 +278,7 @@ pub(crate) async fn get_public_rooms_filtered_helper(
|
||||
room_type: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.room_state_get(&room_id, &StateEventType::RoomCreate, "")?
|
||||
.map(|s| {
|
||||
serde_json::from_str::<RoomCreateEventContent>(s.content.get()).map_err(|e| {
|
||||
error!("Invalid room create event in database: {}", e);
|
||||
Error::BadDatabase("Invalid room create event in database.")
|
||||
})
|
||||
})
|
||||
.transpose()?
|
||||
.and_then(|e| e.room_type),
|
||||
.get_room_type(&room_id)?,
|
||||
room_id,
|
||||
};
|
||||
Ok(chunk)
|
||||
|
||||
@@ -334,7 +334,7 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool + Send>(
|
||||
.globals
|
||||
.bad_query_ratelimiter
|
||||
.write()
|
||||
.await
|
||||
.expect("locked")
|
||||
.entry(id)
|
||||
{
|
||||
hash_map::Entry::Vacant(e) => {
|
||||
@@ -353,7 +353,7 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool + Send>(
|
||||
.globals
|
||||
.bad_query_ratelimiter
|
||||
.read()
|
||||
.await
|
||||
.expect("locked")
|
||||
.get(server)
|
||||
{
|
||||
// Exponential backoff
|
||||
|
||||
@@ -33,6 +33,7 @@ use ruma::{
|
||||
OwnedUserId, RoomId, RoomVersionId, ServerName, UserId,
|
||||
};
|
||||
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
|
||||
use service::sending::convert_to_outgoing_federation_event;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{debug, error, info, trace, warn};
|
||||
|
||||
@@ -779,7 +780,7 @@ async fn join_room_by_id_helper_remote(
|
||||
federation::membership::create_join_event::v2::Request {
|
||||
room_id: room_id.to_owned(),
|
||||
event_id: event_id.to_owned(),
|
||||
pdu: PduEvent::convert_to_outgoing_federation_event(join_event.clone()),
|
||||
pdu: convert_to_outgoing_federation_event(join_event.clone()),
|
||||
omit_members: false,
|
||||
},
|
||||
)
|
||||
@@ -1207,7 +1208,7 @@ async fn join_room_by_id_helper_local(
|
||||
federation::membership::create_join_event::v2::Request {
|
||||
room_id: room_id.to_owned(),
|
||||
event_id: event_id.to_owned(),
|
||||
pdu: PduEvent::convert_to_outgoing_federation_event(join_event.clone()),
|
||||
pdu: convert_to_outgoing_federation_event(join_event.clone()),
|
||||
omit_members: false,
|
||||
},
|
||||
)
|
||||
@@ -1342,7 +1343,7 @@ pub async fn validate_and_add_event_id(
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.write()
|
||||
.await
|
||||
.expect("locked")
|
||||
.entry(id)
|
||||
{
|
||||
Entry::Vacant(e) => {
|
||||
@@ -1358,7 +1359,7 @@ pub async fn validate_and_add_event_id(
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.read()
|
||||
.await
|
||||
.expect("locked")
|
||||
.get(&event_id)
|
||||
{
|
||||
// Exponential backoff
|
||||
@@ -1438,7 +1439,7 @@ pub(crate) async fn invite_helper(
|
||||
room_id: room_id.to_owned(),
|
||||
event_id: (*pdu.event_id).to_owned(),
|
||||
room_version: room_version_id.clone(),
|
||||
event: PduEvent::convert_to_outgoing_federation_event(pdu_json.clone()),
|
||||
event: convert_to_outgoing_federation_event(pdu_json.clone()),
|
||||
invite_room_state,
|
||||
via: services().rooms.state_cache.servers_route_via(room_id).ok(),
|
||||
},
|
||||
@@ -1775,7 +1776,7 @@ async fn remote_leave_room(user_id: &UserId, room_id: &RoomId) -> Result<()> {
|
||||
federation::membership::create_leave_event::v2::Request {
|
||||
room_id: room_id.to_owned(),
|
||||
event_id,
|
||||
pdu: PduEvent::convert_to_outgoing_federation_event(leave_event.clone()),
|
||||
pdu: convert_to_outgoing_federation_event(leave_event.clone()),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -11,6 +11,7 @@ pub(super) mod keys;
|
||||
pub(super) mod media;
|
||||
pub(super) mod membership;
|
||||
pub(super) mod message;
|
||||
pub(super) mod openid;
|
||||
pub(super) mod presence;
|
||||
pub(super) mod profile;
|
||||
pub(super) mod push;
|
||||
@@ -48,6 +49,7 @@ pub(super) use media::*;
|
||||
pub(super) use membership::*;
|
||||
pub use membership::{join_room_by_id_helper, leave_all_rooms, leave_room, validate_and_add_event_id};
|
||||
pub(super) use message::*;
|
||||
pub(super) use openid::*;
|
||||
pub(super) use presence::*;
|
||||
pub(super) use profile::*;
|
||||
pub use profile::{update_all_rooms, update_avatar_url, update_displayname};
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use conduit::utils;
|
||||
use ruma::{
|
||||
api::client::{account, error::ErrorKind},
|
||||
authentication::TokenType,
|
||||
};
|
||||
|
||||
use super::TOKEN_LENGTH;
|
||||
use crate::{services, Error, Result, Ruma};
|
||||
|
||||
/// # `POST /_matrix/client/v3/user/{userId}/openid/request_token`
|
||||
///
|
||||
/// Request an OpenID token to verify identity with third-party services.
|
||||
///
|
||||
/// - The token generated is only valid for the OpenID API
|
||||
pub(crate) async fn create_openid_token_route(
|
||||
body: Ruma<account::request_openid_token::v3::Request>,
|
||||
) -> Result<account::request_openid_token::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
if sender_user != &body.user_id {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Not allowed to request OpenID tokens on behalf of other users",
|
||||
));
|
||||
}
|
||||
|
||||
let access_token = utils::random_string(TOKEN_LENGTH);
|
||||
|
||||
let expires_in = services()
|
||||
.users
|
||||
.create_openid_token(&body.user_id, &access_token)?;
|
||||
|
||||
Ok(account::request_openid_token::v3::Response {
|
||||
access_token,
|
||||
token_type: TokenType::Bearer,
|
||||
matrix_server_name: services().globals.config.server_name.clone(),
|
||||
expires_in: Duration::from_secs(expires_in),
|
||||
})
|
||||
}
|
||||
+120
-2
@@ -1,5 +1,8 @@
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use conduit::{warn, RumaResponse};
|
||||
use ruma::{
|
||||
api::client::{error::ErrorKind, membership::mutual_rooms},
|
||||
api::client::{error::ErrorKind, membership::mutual_rooms, room::get_summary},
|
||||
events::room::member::MembershipState,
|
||||
OwnedRoomId,
|
||||
};
|
||||
|
||||
@@ -12,8 +15,9 @@ use crate::{services, Error, Result, Ruma};
|
||||
/// TODO: Implement pagination, currently this just returns everything
|
||||
///
|
||||
/// An implementation of [MSC2666](https://github.com/matrix-org/matrix-spec-proposals/pull/2666)
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "mutual_rooms")]
|
||||
pub(crate) async fn get_mutual_rooms_route(
|
||||
body: Ruma<mutual_rooms::unstable::Request>,
|
||||
InsecureClientIp(client): InsecureClientIp, body: Ruma<mutual_rooms::unstable::Request>,
|
||||
) -> Result<mutual_rooms::unstable::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
|
||||
@@ -43,3 +47,117 @@ pub(crate) async fn get_mutual_rooms_route(
|
||||
next_batch_token: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/unstable/im.nheko.summary/rooms/{roomIdOrAlias}/summary`
|
||||
///
|
||||
/// Returns a short description of the state of a room.
|
||||
///
|
||||
/// This is the "wrong" endpoint that some implementations/clients may use
|
||||
/// according to the MSC. Request and response bodies are the same as
|
||||
/// `get_room_summary`.
|
||||
///
|
||||
/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266)
|
||||
pub(crate) async fn get_room_summary_legacy(
|
||||
InsecureClientIp(client): InsecureClientIp, body: Ruma<get_summary::msc3266::Request>,
|
||||
) -> Result<RumaResponse<get_summary::msc3266::Response>> {
|
||||
get_room_summary(InsecureClientIp(client), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/unstable/im.nheko.summary/summary/{roomIdOrAlias}`
|
||||
///
|
||||
/// Returns a short description of the state of a room.
|
||||
///
|
||||
/// TODO: support fetching remote room info if we don't know the room
|
||||
///
|
||||
/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266)
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "room_summary")]
|
||||
pub(crate) async fn get_room_summary(
|
||||
InsecureClientIp(client): InsecureClientIp, body: Ruma<get_summary::msc3266::Request>,
|
||||
) -> Result<get_summary::msc3266::Response> {
|
||||
let sender_user = body.sender_user.as_ref();
|
||||
|
||||
let room_id = services()
|
||||
.rooms
|
||||
.alias
|
||||
.resolve(&body.room_id_or_alias)
|
||||
.await?;
|
||||
|
||||
if !services().rooms.metadata.exists(&room_id)? {
|
||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Room is unknown to this server"));
|
||||
}
|
||||
|
||||
if sender_user.is_none()
|
||||
&& !services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.is_world_readable(&room_id)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::forbidden(),
|
||||
"Room is not world readable, authentication is required",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(get_summary::msc3266::Response {
|
||||
room_id: room_id.clone(),
|
||||
canonical_alias: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_canonical_alias(&room_id)
|
||||
.unwrap_or(None),
|
||||
avatar_url: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_avatar(&room_id)?
|
||||
.into_option()
|
||||
.unwrap_or_default()
|
||||
.url,
|
||||
guest_can_join: services().rooms.state_accessor.guest_can_join(&room_id)?,
|
||||
name: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_name(&room_id)
|
||||
.unwrap_or(None),
|
||||
num_joined_members: services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_joined_count(&room_id)
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_else(|| {
|
||||
warn!("Room {room_id} has no member count");
|
||||
0
|
||||
})
|
||||
.try_into()
|
||||
.expect("user count should not be that big"),
|
||||
topic: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_room_topic(&room_id)
|
||||
.unwrap_or(None),
|
||||
world_readable: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.is_world_readable(&room_id)
|
||||
.unwrap_or(false),
|
||||
join_rule: services().rooms.state_accessor.get_join_rule(&room_id)?.0,
|
||||
room_type: services().rooms.state_accessor.get_room_type(&room_id)?,
|
||||
room_version: Some(services().rooms.state.get_room_version(&room_id)?),
|
||||
membership: if let Some(sender_user) = sender_user {
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_member(&room_id, sender_user)?
|
||||
.map_or_else(|| Some(MembershipState::Leave), |content| Some(content.membership))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
encryption: services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_room_encryption(&room_id)
|
||||
.unwrap_or_else(|_e| None),
|
||||
})
|
||||
}
|
||||
|
||||
+34
-10
@@ -9,11 +9,12 @@ use axum_extra::{
|
||||
use http::uri::PathAndQuery;
|
||||
use ruma::{
|
||||
api::{client::error::ErrorKind, AuthScheme, Metadata},
|
||||
server_util::authorization::XMatrix,
|
||||
CanonicalJsonValue, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
|
||||
};
|
||||
use tracing::warn;
|
||||
|
||||
use super::{request::Request, xmatrix::XMatrix};
|
||||
use super::request::Request;
|
||||
use crate::{service::appservice::RegistrationInfo, services, Error, Result};
|
||||
|
||||
enum Token {
|
||||
@@ -76,12 +77,26 @@ pub(super) async fn auth(
|
||||
}
|
||||
|
||||
match (metadata.authentication, token) {
|
||||
(_, Token::Invalid) => Err(Error::BadRequest(
|
||||
ErrorKind::UnknownToken {
|
||||
soft_logout: false,
|
||||
},
|
||||
"Unknown access token.",
|
||||
)),
|
||||
(_, Token::Invalid) => {
|
||||
// OpenID endpoint uses a query param with the same name, drop this once query
|
||||
// params for user auth are removed from the spec. This is required to make
|
||||
// integration manager work.
|
||||
if request.query.access_token.is_some() && request.parts.uri.path().contains("/openid/") {
|
||||
Ok(Auth {
|
||||
origin: None,
|
||||
sender_user: None,
|
||||
sender_device: None,
|
||||
appservice_info: None,
|
||||
})
|
||||
} else {
|
||||
Err(Error::BadRequest(
|
||||
ErrorKind::UnknownToken {
|
||||
soft_logout: false,
|
||||
},
|
||||
"Unknown access token.",
|
||||
))
|
||||
}
|
||||
},
|
||||
(AuthScheme::AccessToken, Token::Appservice(info)) => Ok(auth_appservice(request, info)?),
|
||||
(AuthScheme::None | AuthScheme::AccessTokenOptional | AuthScheme::AppserviceToken, Token::Appservice(info)) => {
|
||||
Ok(Auth {
|
||||
@@ -188,8 +203,17 @@ async fn auth_server(request: &mut Request, json_body: &Option<CanonicalJsonValu
|
||||
})?;
|
||||
|
||||
let origin = &x_matrix.origin;
|
||||
let signatures = BTreeMap::from_iter([(x_matrix.key.clone(), CanonicalJsonValue::String(x_matrix.sig))]);
|
||||
let signatures = BTreeMap::from_iter([(origin.as_str().to_owned(), CanonicalJsonValue::Object(signatures))]);
|
||||
let signatures =
|
||||
BTreeMap::from_iter([(x_matrix.key.clone(), CanonicalJsonValue::String(x_matrix.sig.to_string()))]);
|
||||
let signatures = BTreeMap::from_iter([(
|
||||
origin.as_str().to_owned(),
|
||||
CanonicalJsonValue::Object(
|
||||
signatures
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_string(), v))
|
||||
.collect(),
|
||||
),
|
||||
)]);
|
||||
|
||||
let server_destination = services().globals.server_name().as_str().to_owned();
|
||||
if let Some(destination) = x_matrix.destination.as_ref() {
|
||||
@@ -225,7 +249,7 @@ async fn auth_server(request: &mut Request, json_body: &Option<CanonicalJsonValu
|
||||
let keys_result = services()
|
||||
.rooms
|
||||
.event_handler
|
||||
.fetch_signing_keys_for_server(origin, vec![x_matrix.key.clone()])
|
||||
.fetch_signing_keys_for_server(origin, vec![x_matrix.key.to_string()])
|
||||
.await;
|
||||
|
||||
let keys = keys_result.map_err(|e| {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
mod auth;
|
||||
mod handler;
|
||||
mod request;
|
||||
mod xmatrix;
|
||||
|
||||
use std::{mem, ops::Deref};
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
use std::str;
|
||||
|
||||
use axum_extra::headers::authorization::Credentials;
|
||||
use ruma::OwnedServerName;
|
||||
use tracing::debug;
|
||||
|
||||
pub(crate) struct XMatrix {
|
||||
pub(crate) origin: OwnedServerName,
|
||||
pub(crate) destination: Option<String>,
|
||||
pub(crate) key: String, // KeyName?
|
||||
pub(crate) sig: String,
|
||||
}
|
||||
|
||||
impl Credentials for XMatrix {
|
||||
const SCHEME: &'static str = "X-Matrix";
|
||||
|
||||
fn decode(value: &http::HeaderValue) -> Option<Self> {
|
||||
debug_assert!(
|
||||
value.as_bytes().starts_with(b"X-Matrix "),
|
||||
"HeaderValue to decode should start with \"X-Matrix ..\", received = {value:?}",
|
||||
);
|
||||
|
||||
let parameters = str::from_utf8(&value.as_bytes()["X-Matrix ".len()..])
|
||||
.ok()?
|
||||
.trim_start();
|
||||
|
||||
let mut origin = None;
|
||||
let mut destination = None;
|
||||
let mut key = None;
|
||||
let mut sig = None;
|
||||
|
||||
for entry in parameters.split_terminator(',') {
|
||||
let (name, value) = entry.split_once('=')?;
|
||||
|
||||
// It's not at all clear why some fields are quoted and others not in the spec,
|
||||
// let's simply accept either form for every field.
|
||||
let value = value
|
||||
.strip_prefix('"')
|
||||
.and_then(|rest| rest.strip_suffix('"'))
|
||||
.unwrap_or(value);
|
||||
|
||||
// FIXME: Catch multiple fields of the same name
|
||||
match name {
|
||||
"origin" => origin = Some(value.try_into().ok()?),
|
||||
"key" => key = Some(value.to_owned()),
|
||||
"sig" => sig = Some(value.to_owned()),
|
||||
"destination" => destination = Some(value.to_owned()),
|
||||
_ => debug!("Unexpected field `{name}` in X-Matrix Authorization header"),
|
||||
}
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
origin: origin?,
|
||||
key: key?,
|
||||
sig: sig?,
|
||||
destination,
|
||||
})
|
||||
}
|
||||
|
||||
fn encode(&self) -> http::HeaderValue { todo!() }
|
||||
}
|
||||
+7
-1
@@ -39,6 +39,7 @@ pub fn build(router: Router, server: &Server) -> Router {
|
||||
.ruma_route(client::get_room_aliases_route)
|
||||
.ruma_route(client::get_filter_route)
|
||||
.ruma_route(client::create_filter_route)
|
||||
.ruma_route(client::create_openid_token_route)
|
||||
.ruma_route(client::set_global_account_data_route)
|
||||
.ruma_route(client::set_room_account_data_route)
|
||||
.ruma_route(client::get_global_account_data_route)
|
||||
@@ -171,7 +172,6 @@ pub fn build(router: Router, server: &Server) -> Router {
|
||||
.ruma_route(client::get_key_changes_route)
|
||||
.ruma_route(client::get_pushers_route)
|
||||
.ruma_route(client::set_pushers_route)
|
||||
// .ruma_route(client::third_party_route)
|
||||
.ruma_route(client::upgrade_room_route)
|
||||
.ruma_route(client::get_threads_route)
|
||||
.ruma_route(client::get_relating_events_with_rel_type_and_event_type_route)
|
||||
@@ -179,6 +179,11 @@ pub fn build(router: Router, server: &Server) -> Router {
|
||||
.ruma_route(client::get_relating_events_route)
|
||||
.ruma_route(client::get_hierarchy_route)
|
||||
.ruma_route(client::get_mutual_rooms_route)
|
||||
.ruma_route(client::get_room_summary)
|
||||
.route(
|
||||
"/_matrix/client/unstable/im.nheko.summary/rooms/:room_id_or_alias/summary",
|
||||
get(client::get_room_summary_legacy)
|
||||
)
|
||||
.ruma_route(client::well_known_support)
|
||||
.ruma_route(client::well_known_client)
|
||||
.route("/_conduwuit/server_version", get(client::conduwuit_server_version))
|
||||
@@ -212,6 +217,7 @@ pub fn build(router: Router, server: &Server) -> Router {
|
||||
.ruma_route(server::get_profile_information_route)
|
||||
.ruma_route(server::get_keys_route)
|
||||
.ruma_route(server::claim_keys_route)
|
||||
.ruma_route(server::get_openid_userinfo_route)
|
||||
.ruma_route(server::get_hierarchy_route)
|
||||
.ruma_route(server::well_known_server)
|
||||
.route("/_conduwuit/local_user_count", get(client::conduwuit_local_user_count))
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use conduit::{Error, Result};
|
||||
use ruma::{
|
||||
api::{client::error::ErrorKind, federation::backfill::get_backfill},
|
||||
uint, user_id, MilliSecondsSinceUnixEpoch,
|
||||
};
|
||||
use service::{sending::convert_to_outgoing_federation_event, services};
|
||||
|
||||
use crate::{services, Error, PduEvent, Result, Ruma};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `GET /_matrix/federation/v1/backfill/<room_id>`
|
||||
///
|
||||
@@ -62,7 +64,7 @@ pub(crate) async fn get_backfill_route(body: Ruma<get_backfill::v1::Request>) ->
|
||||
})
|
||||
.map(|(_, pdu)| services().rooms.timeline.get_pdu_json(&pdu.event_id))
|
||||
.filter_map(|r| r.ok().flatten())
|
||||
.map(PduEvent::convert_to_outgoing_federation_event)
|
||||
.map(convert_to_outgoing_federation_event)
|
||||
.collect();
|
||||
|
||||
Ok(get_backfill::v1::Response {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use conduit::{Error, Result};
|
||||
use ruma::{
|
||||
api::{client::error::ErrorKind, federation::event::get_event},
|
||||
MilliSecondsSinceUnixEpoch, RoomId,
|
||||
};
|
||||
use service::{sending::convert_to_outgoing_federation_event, services};
|
||||
|
||||
use crate::{services, Error, PduEvent, Result, Ruma};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `GET /_matrix/federation/v1/event/{eventId}`
|
||||
///
|
||||
@@ -48,6 +50,6 @@ pub(crate) async fn get_event_route(body: Ruma<get_event::v1::Request>) -> Resul
|
||||
Ok(get_event::v1::Response {
|
||||
origin: services().globals.server_name().to_owned(),
|
||||
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
|
||||
pdu: PduEvent::convert_to_outgoing_federation_event(event),
|
||||
pdu: convert_to_outgoing_federation_event(event),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::{Error, Result};
|
||||
use ruma::{
|
||||
api::{client::error::ErrorKind, federation::authorization::get_event_authorization},
|
||||
RoomId,
|
||||
};
|
||||
use service::{sending::convert_to_outgoing_federation_event, services};
|
||||
|
||||
use crate::{services, Error, PduEvent, Result, Ruma};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `GET /_matrix/federation/v1/event_auth/{roomId}/{eventId}`
|
||||
///
|
||||
@@ -57,7 +59,7 @@ pub(crate) async fn get_event_authorization_route(
|
||||
Ok(get_event_authorization::v1::Response {
|
||||
auth_chain: auth_chain_ids
|
||||
.filter_map(|id| services().rooms.timeline.get_pdu_json(&id).ok()?)
|
||||
.map(PduEvent::convert_to_outgoing_federation_event)
|
||||
.map(convert_to_outgoing_federation_event)
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use conduit::{Error, Result};
|
||||
use ruma::{
|
||||
api::{client::error::ErrorKind, federation::event::get_missing_events},
|
||||
OwnedEventId, RoomId,
|
||||
};
|
||||
use service::{sending::convert_to_outgoing_federation_event, services};
|
||||
|
||||
use crate::{services, Error, PduEvent, Result, Ruma};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/federation/v1/get_missing_events/{roomId}`
|
||||
///
|
||||
@@ -79,7 +81,7 @@ pub(crate) async fn get_missing_events_route(
|
||||
)
|
||||
.map_err(|_| Error::bad_database("Invalid prev_events in event in database."))?,
|
||||
);
|
||||
events.push(PduEvent::convert_to_outgoing_federation_event(pdu));
|
||||
events.push(convert_to_outgoing_federation_event(pdu));
|
||||
}
|
||||
i = i.saturating_add(1);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use conduit::{utils, warn, Error, PduEvent, Result};
|
||||
use ruma::{
|
||||
api::{client::error::ErrorKind, federation::membership::create_invite},
|
||||
events::room::member::{MembershipState, RoomMemberEventContent},
|
||||
serde::JsonObject,
|
||||
CanonicalJsonValue, EventId, OwnedUserId,
|
||||
};
|
||||
use tracing::warn;
|
||||
use service::{sending::convert_to_outgoing_federation_event, server_is_ours, services};
|
||||
|
||||
use crate::{
|
||||
service::server_is_ours,
|
||||
services,
|
||||
utils::{self},
|
||||
Error, PduEvent, Result, Ruma,
|
||||
};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`
|
||||
///
|
||||
@@ -176,6 +172,6 @@ pub(crate) async fn create_invite_route(
|
||||
}
|
||||
|
||||
Ok(create_invite::v2::Response {
|
||||
event: PduEvent::convert_to_outgoing_federation_event(signed_event),
|
||||
event: convert_to_outgoing_federation_event(signed_event),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ pub(super) mod invite;
|
||||
pub(super) mod key;
|
||||
pub(super) mod make_join;
|
||||
pub(super) mod make_leave;
|
||||
pub(super) mod openid;
|
||||
pub(super) mod publicrooms;
|
||||
pub(super) mod query;
|
||||
pub(super) mod send;
|
||||
@@ -27,6 +28,7 @@ pub(super) use invite::*;
|
||||
pub(super) use key::*;
|
||||
pub(super) use make_join::*;
|
||||
pub(super) use make_leave::*;
|
||||
pub(super) use openid::*;
|
||||
pub(super) use publicrooms::*;
|
||||
pub(super) use query::*;
|
||||
pub(super) use send::*;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
use ruma::api::federation::openid::get_openid_userinfo;
|
||||
|
||||
use crate::{services, Result, Ruma};
|
||||
|
||||
/// # `GET /_matrix/federation/v1/openid/userinfo`
|
||||
///
|
||||
/// Get information about the user that generated the OpenID token.
|
||||
pub(crate) async fn get_openid_userinfo_route(
|
||||
body: Ruma<get_openid_userinfo::v1::Request>,
|
||||
) -> Result<get_openid_userinfo::v1::Response> {
|
||||
Ok(get_openid_userinfo::v1::Response::new(
|
||||
services()
|
||||
.users
|
||||
.find_from_openid_token(&body.access_token)?,
|
||||
))
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use conduit::{Error, Result};
|
||||
use ruma::{
|
||||
api::{client::error::ErrorKind, federation::membership::create_join_event},
|
||||
events::{
|
||||
@@ -11,11 +12,13 @@ use ruma::{
|
||||
CanonicalJsonValue, OwnedServerName, OwnedUserId, RoomId, ServerName,
|
||||
};
|
||||
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
|
||||
use service::user_is_local;
|
||||
use service::{
|
||||
pdu::gen_event_id_canonical_json, sending::convert_to_outgoing_federation_event, services, user_is_local,
|
||||
};
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::{service::pdu::gen_event_id_canonical_json, services, Error, PduEvent, Result, Ruma};
|
||||
use crate::Ruma;
|
||||
|
||||
/// helper method for /send_join v1 and v2
|
||||
async fn create_join_event(
|
||||
@@ -181,12 +184,12 @@ async fn create_join_event(
|
||||
Ok(create_join_event::v1::RoomState {
|
||||
auth_chain: auth_chain_ids
|
||||
.filter_map(|id| services().rooms.timeline.get_pdu_json(&id).ok().flatten())
|
||||
.map(PduEvent::convert_to_outgoing_federation_event)
|
||||
.map(convert_to_outgoing_federation_event)
|
||||
.collect(),
|
||||
state: state_ids
|
||||
.iter()
|
||||
.filter_map(|(_, id)| services().rooms.timeline.get_pdu_json(id).ok().flatten())
|
||||
.map(PduEvent::convert_to_outgoing_federation_event)
|
||||
.map(convert_to_outgoing_federation_event)
|
||||
.collect(),
|
||||
// Event field is required if the room version supports restricted join rules.
|
||||
event: Some(
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::{Error, Result};
|
||||
use ruma::api::{client::error::ErrorKind, federation::event::get_room_state};
|
||||
use service::{sending::convert_to_outgoing_federation_event, services};
|
||||
|
||||
use crate::{services, Error, PduEvent, Result, Ruma};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `GET /_matrix/federation/v1/state/{roomId}`
|
||||
///
|
||||
@@ -42,7 +44,7 @@ pub(crate) async fn get_room_state_route(
|
||||
.await?
|
||||
.into_values()
|
||||
.map(|id| {
|
||||
PduEvent::convert_to_outgoing_federation_event(
|
||||
convert_to_outgoing_federation_event(
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
@@ -67,7 +69,7 @@ pub(crate) async fn get_room_state_route(
|
||||
.timeline
|
||||
.get_pdu_json(&id)
|
||||
.ok()?
|
||||
.map(PduEvent::convert_to_outgoing_federation_event)
|
||||
.map(convert_to_outgoing_federation_event)
|
||||
})
|
||||
.collect(),
|
||||
pdus,
|
||||
|
||||
@@ -45,6 +45,10 @@ zstd_compression =[]
|
||||
perf_measurements = []
|
||||
sentry_telemetry = []
|
||||
|
||||
# these do nothing, these are purely for informing users to update their build scripts if they use one
|
||||
rocksdb = []
|
||||
sha256_media = []
|
||||
|
||||
[dependencies]
|
||||
argon2.workspace = true
|
||||
axum.workspace = true
|
||||
|
||||
@@ -19,7 +19,7 @@ pub fn memory_usage() -> String {
|
||||
let resident = stats::resident::read().unwrap_or_default() as f64 / 1024.0 / 1024.0;
|
||||
let retained = stats::retained::read().unwrap_or_default() as f64 / 1024.0 / 1024.0;
|
||||
format!(
|
||||
" allocated: {allocated:.2} MiB\n active: {active:.2} MiB\n mapped: {mapped:.2} MiB\n metadata: {metadata:.2} \
|
||||
"allocated: {allocated:.2} MiB\n active: {active:.2} MiB\n mapped: {mapped:.2} MiB\n metadata: {metadata:.2} \
|
||||
MiB\n resident: {resident:.2} MiB\n retained: {retained:.2} MiB\n "
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,17 @@ use tracing::{debug, error, info, warn};
|
||||
use crate::{error::Error, Config};
|
||||
|
||||
pub fn check(config: &Config) -> Result<(), Error> {
|
||||
#[cfg(feature = "rocksdb")]
|
||||
warn!(
|
||||
"Note the rocksdb feature was deleted from conduwuit, sqlite was deleted and RocksDB is the only supported \
|
||||
backend now. Please update your build script to remove this feature."
|
||||
);
|
||||
#[cfg(feature = "sha256_media")]
|
||||
warn!(
|
||||
"Note the sha256_media feature was deleted from conduwuit, it is now fully integrated in a \
|
||||
forwards-compatible way. Please update your build script to remove this feature."
|
||||
);
|
||||
|
||||
config.warn_deprecated();
|
||||
config.warn_unknown_key();
|
||||
|
||||
|
||||
@@ -201,6 +201,8 @@ pub struct Config {
|
||||
pub query_trusted_key_servers_first: bool,
|
||||
#[serde(default = "default_log")]
|
||||
pub log: String,
|
||||
#[serde(default = "default_openid_token_ttl")]
|
||||
pub openid_token_ttl: u64,
|
||||
#[serde(default)]
|
||||
pub turn_username: String,
|
||||
#[serde(default)]
|
||||
@@ -671,6 +673,7 @@ impl fmt::Display for Config {
|
||||
"Query Trusted Key Servers First",
|
||||
&self.query_trusted_key_servers_first.to_string(),
|
||||
),
|
||||
("OpenID Token TTL", &self.openid_token_ttl.to_string()),
|
||||
(
|
||||
"TURN username",
|
||||
if self.turn_username.is_empty() {
|
||||
@@ -984,6 +987,8 @@ pub fn default_log() -> String {
|
||||
|
||||
fn default_notification_push_path() -> String { "/_matrix/push/v1/notify".to_owned() }
|
||||
|
||||
fn default_openid_token_ttl() -> u64 { 60 * 60 }
|
||||
|
||||
fn default_turn_ttl() -> u64 { 60 * 60 * 24 }
|
||||
|
||||
fn default_presence_idle_timeout_s() -> u64 { 5 * 60 }
|
||||
|
||||
@@ -92,6 +92,7 @@ impl Error {
|
||||
}
|
||||
|
||||
/// Returns the Matrix error code / error kind
|
||||
#[inline]
|
||||
pub fn error_code(&self) -> ruma::api::client::error::ErrorKind {
|
||||
if let Self::Federation(_, error) = self {
|
||||
return error.error_kind().unwrap_or_else(|| &Unknown).clone();
|
||||
|
||||
@@ -8,5 +8,6 @@ pub struct Guard {
|
||||
}
|
||||
|
||||
impl Drop for Guard {
|
||||
#[inline]
|
||||
fn drop(&mut self) { self.capture.stop(); }
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ struct Visitor {
|
||||
}
|
||||
|
||||
impl Layer {
|
||||
#[inline]
|
||||
pub fn new(state: &Arc<State>) -> Self {
|
||||
Self {
|
||||
state: state.clone(),
|
||||
@@ -25,6 +26,7 @@ impl Layer {
|
||||
}
|
||||
|
||||
impl fmt::Debug for Layer {
|
||||
#[inline]
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.debug_struct("capture::Layer").finish()
|
||||
}
|
||||
|
||||
+2
-2
@@ -4,14 +4,14 @@ pub mod debug;
|
||||
pub mod error;
|
||||
pub mod log;
|
||||
pub mod mods;
|
||||
pub mod pducount;
|
||||
pub mod pdu;
|
||||
pub mod server;
|
||||
pub mod utils;
|
||||
pub mod version;
|
||||
|
||||
pub use config::Config;
|
||||
pub use error::{Error, RumaResponse};
|
||||
pub use pducount::PduCount;
|
||||
pub use pdu::{PduBuilder, PduCount, PduEvent};
|
||||
pub use server::Server;
|
||||
pub use version::version;
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
use ruma::{events::TimelineEventType, EventId};
|
||||
use serde::Deserialize;
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
|
||||
/// Build the start of a PDU in order to add it to the Database.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PduBuilder {
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: TimelineEventType,
|
||||
pub content: Box<RawJsonValue>,
|
||||
pub unsigned: Option<BTreeMap<String, serde_json::Value>>,
|
||||
pub state_key: Option<String>,
|
||||
pub redacts: Option<Arc<EventId>>,
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
mod builder;
|
||||
mod count;
|
||||
|
||||
use std::{cmp::Ordering, collections::BTreeMap, sync::Arc};
|
||||
|
||||
use conduit::{warn, Error};
|
||||
pub use builder::PduBuilder;
|
||||
pub use count::PduCount;
|
||||
use ruma::{
|
||||
canonical_json::redact_content_in_place,
|
||||
events::{
|
||||
@@ -19,7 +23,7 @@ use serde_json::{
|
||||
value::{to_raw_value, RawValue as RawJsonValue},
|
||||
};
|
||||
|
||||
use crate::services;
|
||||
use crate::{warn, Error};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ExtractRedactedBecause {
|
||||
@@ -336,42 +340,6 @@ impl PduEvent {
|
||||
serde_json::from_value(json).expect("Raw::from_value always works")
|
||||
}
|
||||
|
||||
/// This does not return a full `Pdu` it is only to satisfy ruma's types.
|
||||
#[tracing::instrument]
|
||||
pub fn convert_to_outgoing_federation_event(mut pdu_json: CanonicalJsonObject) -> Box<RawJsonValue> {
|
||||
if let Some(unsigned) = pdu_json
|
||||
.get_mut("unsigned")
|
||||
.and_then(|val| val.as_object_mut())
|
||||
{
|
||||
unsigned.remove("transaction_id");
|
||||
}
|
||||
|
||||
// room v3 and above removed the "event_id" field from remote PDU format
|
||||
if let Some(room_id) = pdu_json
|
||||
.get("room_id")
|
||||
.and_then(|val| RoomId::parse(val.as_str()?).ok())
|
||||
{
|
||||
match services().rooms.state.get_room_version(&room_id) {
|
||||
Ok(room_version_id) => match room_version_id {
|
||||
RoomVersionId::V1 | RoomVersionId::V2 => {},
|
||||
_ => _ = pdu_json.remove("event_id"),
|
||||
},
|
||||
Err(_) => _ = pdu_json.remove("event_id"),
|
||||
}
|
||||
} else {
|
||||
pdu_json.remove("event_id");
|
||||
}
|
||||
|
||||
// TODO: another option would be to convert it to a canonical string to validate
|
||||
// size and return a Result<Raw<...>>
|
||||
// serde_json::from_str::<Raw<_>>(
|
||||
// ruma::serde::to_canonical_json_string(pdu_json).expect("CanonicalJson is
|
||||
// valid serde_json::Value"), )
|
||||
// .expect("Raw::from_value always works")
|
||||
|
||||
to_raw_value(&pdu_json).expect("CanonicalJson is valid serde_json::Value")
|
||||
}
|
||||
|
||||
pub fn from_id_val(event_id: &EventId, mut json: CanonicalJsonObject) -> Result<Self, serde_json::Error> {
|
||||
json.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.as_str().to_owned()));
|
||||
|
||||
@@ -438,14 +406,3 @@ pub fn gen_event_id_canonical_json(
|
||||
|
||||
Ok((event_id, value))
|
||||
}
|
||||
|
||||
/// Build the start of a PDU in order to add it to the Database.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PduBuilder {
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: TimelineEventType,
|
||||
pub content: Box<RawJsonValue>,
|
||||
pub unsigned: Option<BTreeMap<String, serde_json::Value>>,
|
||||
pub state_key: Option<String>,
|
||||
pub redacts: Option<Arc<EventId>>,
|
||||
}
|
||||
+15
-14
@@ -3,27 +3,28 @@ use crate::Result;
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn increment(old: Option<&[u8]>) -> [u8; 8] {
|
||||
old.map(TryInto::try_into)
|
||||
.map_or(0_u64, |val| val.map_or(0_u64, u64::from_be_bytes))
|
||||
old.map_or(0_u64, u64_from_bytes_or_zero)
|
||||
.wrapping_add(1)
|
||||
.to_be_bytes()
|
||||
}
|
||||
|
||||
/// Parses the big-endian bytes into an u64.
|
||||
#[inline]
|
||||
pub fn u64_from_bytes(bytes: &[u8]) -> Result<u64> {
|
||||
let array: [u8; 8] = bytes.try_into()?;
|
||||
Ok(u64_from_u8x8(array))
|
||||
}
|
||||
|
||||
/// Parses the 8 big-endian bytes into an u64.
|
||||
/// Parses 8 big-endian bytes into an u64; panic on invalid argument
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn u64_from_u8(bytes: &[u8]) -> u64 {
|
||||
let bytes: &[u8; 8] = bytes.try_into().expect("must slice at least 8 bytes");
|
||||
u64_from_u8x8(*bytes)
|
||||
}
|
||||
pub fn u64_from_u8(bytes: &[u8]) -> u64 { u64_from_bytes(bytes).expect("must slice at least 8 bytes") }
|
||||
|
||||
/// Parses the big-endian bytes into an u64.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn u64_from_bytes_or_zero(bytes: &[u8]) -> u64 { u64_from_bytes(bytes).unwrap_or(0) }
|
||||
|
||||
/// Parses the big-endian bytes into an u64.
|
||||
#[inline]
|
||||
pub fn u64_from_bytes(bytes: &[u8]) -> Result<u64> { Ok(u64_from_u8x8(*u8x8_from_bytes(bytes)?)) }
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn u64_from_u8x8(bytes: [u8; 8]) -> u64 { u64::from_be_bytes(bytes) }
|
||||
|
||||
#[inline]
|
||||
pub fn u8x8_from_bytes(bytes: &[u8]) -> Result<&[u8; 8]> { Ok(bytes.try_into()?) }
|
||||
|
||||
@@ -3,14 +3,11 @@ mod sha256;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
#[inline]
|
||||
pub fn password(password: &str) -> Result<String> { argon::password(password) }
|
||||
|
||||
#[inline]
|
||||
pub fn verify_password(password: &str, password_hash: &str) -> Result<()> {
|
||||
argon::verify_password(password, password_hash)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn calculate_hash(keys: &[&[u8]]) -> Vec<u8> { sha256::hash(keys) }
|
||||
|
||||
@@ -6,6 +6,7 @@ pub mod hash;
|
||||
pub mod html;
|
||||
pub mod json;
|
||||
pub mod mutex_map;
|
||||
pub mod rand;
|
||||
pub mod string;
|
||||
pub mod sys;
|
||||
mod tests;
|
||||
@@ -19,9 +20,10 @@ pub use hash::calculate_hash;
|
||||
pub use html::Escape as HtmlEscape;
|
||||
pub use json::{deserialize_from_str, to_canonical_object};
|
||||
pub use mutex_map::MutexMap;
|
||||
pub use string::{random_string, str_from_bytes, string_from_bytes};
|
||||
pub use rand::string as random_string;
|
||||
pub use string::{str_from_bytes, string_from_bytes};
|
||||
pub use sys::available_parallelism;
|
||||
pub use time::millis_since_unix_epoch;
|
||||
pub use time::now_millis as millis_since_unix_epoch;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
@@ -31,7 +33,6 @@ pub fn clamp<T: Ord>(val: T, min: T, max: T) -> T { cmp::min(cmp::max(val, min),
|
||||
///
|
||||
/// * <https://doc.rust-lang.org/std/convert/enum.Infallible.html>
|
||||
#[must_use]
|
||||
#[inline(always)]
|
||||
pub fn unwrap_infallible<T>(result: Result<T, std::convert::Infallible>) -> T {
|
||||
match result {
|
||||
Ok(val) => val,
|
||||
@@ -41,7 +42,7 @@ pub fn unwrap_infallible<T>(result: Result<T, std::convert::Infallible>) -> T {
|
||||
|
||||
#[must_use]
|
||||
pub fn generate_keypair() -> Vec<u8> {
|
||||
let mut value = random_string(8).as_bytes().to_vec();
|
||||
let mut value = rand::string(8).as_bytes().to_vec();
|
||||
value.push(0xFF);
|
||||
value.extend_from_slice(
|
||||
&ruma::signatures::Ed25519KeyPair::generate().expect("Ed25519KeyPair generation always works (?)"),
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
use std::{
|
||||
ops::Range,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
pub fn string(length: usize) -> String {
|
||||
thread_rng()
|
||||
.sample_iter(&rand::distributions::Alphanumeric)
|
||||
.take(length)
|
||||
.map(char::from)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn timepoint_secs(range: Range<u64>) -> SystemTime { SystemTime::now() + secs(range) }
|
||||
|
||||
#[must_use]
|
||||
pub fn secs(range: Range<u64>) -> Duration {
|
||||
let mut rng = thread_rng();
|
||||
Duration::from_secs(rng.gen_range(range))
|
||||
}
|
||||
@@ -1,17 +1,14 @@
|
||||
use rand::prelude::*;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
pub fn random_string(length: usize) -> String {
|
||||
thread_rng()
|
||||
.sample_iter(&rand::distributions::Alphanumeric)
|
||||
.take(length)
|
||||
.map(char::from)
|
||||
.collect()
|
||||
pub const EMPTY: &str = "";
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn split_once_infallible<'a>(input: &'a str, delim: &'_ str) -> (&'a str, &'a str) {
|
||||
input.split_once(delim).unwrap_or((input, EMPTY))
|
||||
}
|
||||
|
||||
/// Parses the bytes into a string.
|
||||
#[inline]
|
||||
pub fn string_from_bytes(bytes: &[u8]) -> Result<String> {
|
||||
let str: &str = str_from_bytes(bytes)?;
|
||||
Ok(str.to_owned())
|
||||
|
||||
+12
-4
@@ -3,10 +3,10 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[allow(clippy::as_conversions)]
|
||||
pub fn millis_since_unix_epoch() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("time is valid")
|
||||
pub fn now_millis() -> u64 {
|
||||
UNIX_EPOCH
|
||||
.elapsed()
|
||||
.expect("positive duration after epoch")
|
||||
.as_millis() as u64
|
||||
}
|
||||
|
||||
@@ -18,3 +18,11 @@ pub fn rfc2822_from_seconds(epoch: i64) -> String {
|
||||
.unwrap_or_default()
|
||||
.to_rfc2822()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn format(ts: SystemTime, str: &str) -> String {
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
let dt: DateTime<Utc> = ts.into();
|
||||
dt.format(str).to_string()
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ pub struct Cork {
|
||||
}
|
||||
|
||||
impl Cork {
|
||||
#[inline]
|
||||
pub(super) fn new(db: &Arc<Engine>, flush: bool, sync: bool) -> Self {
|
||||
db.cork();
|
||||
Self {
|
||||
|
||||
@@ -19,12 +19,15 @@ impl Database {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn cork(&self) -> Cork { Cork::new(&self.db, false, false) }
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn cork_and_flush(&self) -> Cork { Cork::new(&self.db, true, false) }
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn cork_and_sync(&self) -> Cork { Cork::new(&self.db, true, true) }
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ impl Engine {
|
||||
|
||||
pub fn sync(&self) -> Result<()> { result(DBCommon::flush_wal(&self.db, true)) }
|
||||
|
||||
#[inline]
|
||||
pub fn corked(&self) -> bool { self.corks.load(std::sync::atomic::Ordering::Relaxed) > 0 }
|
||||
|
||||
pub(crate) fn cork(&self) {
|
||||
@@ -242,6 +243,7 @@ impl Engine {
|
||||
}
|
||||
|
||||
impl Drop for Engine {
|
||||
#[cold]
|
||||
fn drop(&mut self) {
|
||||
const BLOCKING: bool = true;
|
||||
|
||||
|
||||
@@ -17,9 +17,11 @@ impl<'a> From<DBPinnableSlice<'a>> for Handle<'a> {
|
||||
impl Deref for Handle<'_> {
|
||||
type Target = [u8];
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target { &self.val }
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Handle<'_> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] { &self.val }
|
||||
}
|
||||
|
||||
@@ -199,6 +199,7 @@ impl<'a> IntoIterator for &'a Map {
|
||||
type IntoIter = Box<dyn Iterator<Item = Self::Item> + Send + 'a>;
|
||||
type Item = OwnedKeyValPair;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter { self.iter() }
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ pub const MAPS: &[&str] = &[
|
||||
"userid_presenceid",
|
||||
"userid_selfsigningkeyid",
|
||||
"userid_usersigningkeyid",
|
||||
"openidtoken_expiresatuserid",
|
||||
"userroomid_highlightcount",
|
||||
"userroomid_invitestate",
|
||||
"userroomid_joined",
|
||||
|
||||
@@ -11,21 +11,19 @@ pub type Key = [Byte];
|
||||
pub(crate) type Byte = u8;
|
||||
|
||||
impl OwnedKeyVal {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn as_slice(&self) -> KeyVal<'_> { KeyVal(&self.0, &self.1) }
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn to_tuple(self) -> OwnedKeyValPair { (self.0, self.1) }
|
||||
}
|
||||
|
||||
impl From<OwnedKeyValPair> for OwnedKeyVal {
|
||||
#[inline]
|
||||
fn from((key, val): OwnedKeyValPair) -> Self { Self(key, val) }
|
||||
}
|
||||
|
||||
impl From<&KeyVal<'_>> for OwnedKeyVal {
|
||||
#[inline]
|
||||
fn from(slice: &KeyVal<'_>) -> Self { slice.to_owned() }
|
||||
}
|
||||
|
||||
@@ -34,7 +32,6 @@ impl From<KeyValPair<'_>> for OwnedKeyVal {
|
||||
}
|
||||
|
||||
impl From<OwnedKeyVal> for OwnedKeyValPair {
|
||||
#[inline]
|
||||
fn from(val: OwnedKeyVal) -> Self { val.to_tuple() }
|
||||
}
|
||||
|
||||
@@ -43,22 +40,18 @@ impl KeyVal<'_> {
|
||||
#[must_use]
|
||||
pub fn to_owned(&self) -> OwnedKeyVal { OwnedKeyVal::from(self) }
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn as_tuple(&self) -> KeyValPair<'_> { (self.0, self.1) }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a OwnedKeyVal> for KeyVal<'a> {
|
||||
#[inline]
|
||||
fn from(owned: &'a OwnedKeyVal) -> Self { owned.as_slice() }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a OwnedKeyValPair> for KeyVal<'a> {
|
||||
#[inline]
|
||||
fn from((key, val): &'a OwnedKeyValPair) -> Self { KeyVal(key.as_slice(), val.as_slice()) }
|
||||
}
|
||||
|
||||
impl<'a> From<KeyValPair<'a>> for KeyVal<'a> {
|
||||
#[inline]
|
||||
fn from((key, val): KeyValPair<'a>) -> Self { KeyVal(key, val) }
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::{env, os::unix::process::CommandExt, process::Command};
|
||||
|
||||
use conduit::{debug, info, utils};
|
||||
|
||||
#[cold]
|
||||
pub(super) fn restart() -> ! {
|
||||
// SAFETY: We have allowed an override for the case where the current_exe() has
|
||||
// been replaced or removed. By default the server will fail to restart if the
|
||||
|
||||
@@ -2,9 +2,8 @@ mod data;
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use conduit::{Result, Server};
|
||||
use conduit::Result;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{
|
||||
events::{AnyEphemeralRoomEvent, RoomAccountDataEventType},
|
||||
serde::Raw,
|
||||
@@ -15,13 +14,17 @@ pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// Places one event in the account data of the user and removes the
|
||||
/// previous entry.
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
|
||||
@@ -4,9 +4,9 @@ mod grant;
|
||||
|
||||
use std::{future::Future, pin::Pin, sync::Arc};
|
||||
|
||||
use conduit::{error, utils::mutex_map, Error, Result, Server};
|
||||
use async_trait::async_trait;
|
||||
use conduit::{error, utils::mutex_map, Error, Result};
|
||||
pub use create::create_admin_room;
|
||||
use database::Database;
|
||||
pub use grant::make_user_admin;
|
||||
use loole::{Receiver, Sender};
|
||||
use ruma::{
|
||||
@@ -43,8 +43,9 @@ pub struct Command {
|
||||
pub reply_id: Option<OwnedEventId>,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, _db: &Arc<Database>) -> Result<Arc<Self>> {
|
||||
#[async_trait]
|
||||
impl crate::Service for Service {
|
||||
fn build(_args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
let (sender, receiver) = loole::bounded(COMMAND_QUEUE_LIMIT);
|
||||
Ok(Arc::new(Self {
|
||||
sender,
|
||||
@@ -56,8 +57,8 @@ impl Service {
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn start_handler(self: &Arc<Self>) {
|
||||
let self_ = Arc::clone(self);
|
||||
async fn start(self: Arc<Self>) -> Result<()> {
|
||||
let self_ = Arc::clone(&self);
|
||||
let handle = services().server.runtime().spawn(async move {
|
||||
self_
|
||||
.handler()
|
||||
@@ -66,9 +67,11 @@ impl Service {
|
||||
});
|
||||
|
||||
_ = self.handler_join.lock().await.insert(handle);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn interrupt(&self) {
|
||||
fn interrupt(&self) {
|
||||
#[cfg(feature = "console")]
|
||||
self.console.interrupt();
|
||||
|
||||
@@ -77,7 +80,7 @@ impl Service {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn close(&self) {
|
||||
async fn stop(&self) {
|
||||
self.interrupt();
|
||||
|
||||
#[cfg(feature = "console")]
|
||||
@@ -90,6 +93,10 @@ impl Service {
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub async fn send_text(&self, body: &str) {
|
||||
self.send_message(RoomMessageEventContent::text_markdown(body))
|
||||
.await;
|
||||
|
||||
@@ -2,9 +2,8 @@ mod data;
|
||||
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
use conduit::{Result, Server};
|
||||
use conduit::Result;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use futures_util::Future;
|
||||
use regex::RegexSet;
|
||||
use ruma::{
|
||||
@@ -24,6 +23,7 @@ pub struct NamespaceRegex {
|
||||
|
||||
impl NamespaceRegex {
|
||||
/// Checks if this namespace has rights to a namespace
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_match(&self, heystack: &str) -> bool {
|
||||
if self.is_exclusive_match(heystack) {
|
||||
@@ -39,6 +39,7 @@ impl NamespaceRegex {
|
||||
}
|
||||
|
||||
/// Checks if this namespace has exlusive rights to a namespace
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_exclusive_match(&self, heystack: &str) -> bool {
|
||||
if let Some(exclusive) = &self.exclusive {
|
||||
@@ -56,6 +57,7 @@ impl RegistrationInfo {
|
||||
self.users.is_match(user_id.as_str()) || self.registration.sender_localpart == user_id.localpart()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_exclusive_user_match(&self, user_id: &UserId) -> bool {
|
||||
self.users.is_exclusive_match(user_id.as_str()) || self.registration.sender_localpart == user_id.localpart()
|
||||
@@ -119,10 +121,10 @@ pub struct Service {
|
||||
registration_info: RwLock<BTreeMap<String, RegistrationInfo>>,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
let mut registration_info = BTreeMap::new();
|
||||
let db = Data::new(db);
|
||||
let db = Data::new(args.db);
|
||||
// Inserting registrations into cache
|
||||
for appservice in iter_ids(&db)? {
|
||||
registration_info.insert(
|
||||
@@ -134,12 +136,17 @@ impl Service {
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
Ok(Arc::new(Self {
|
||||
db,
|
||||
registration_info: RwLock::new(registration_info),
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
#[inline]
|
||||
pub fn all(&self) -> Result<Vec<(String, Registration)>> { iter_ids(&self.db) }
|
||||
|
||||
/// Registers an appservice and returns the ID to the caller
|
||||
|
||||
+14
-37
@@ -57,6 +57,7 @@ impl Data {
|
||||
}
|
||||
|
||||
pub fn next_count(&self) -> Result<u64> {
|
||||
let _cork = self.db.cork();
|
||||
let mut lock = self.counter.write().expect("locked");
|
||||
let counter: &mut u64 = &mut lock;
|
||||
debug_assert!(
|
||||
@@ -98,6 +99,7 @@ impl Data {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn update_check_for_updates_id(&self, id: u64) -> Result<()> {
|
||||
self.global
|
||||
.insert(LAST_CHECK_FOR_UPDATES_COUNT, &id.to_be_bytes())?;
|
||||
@@ -206,43 +208,6 @@ impl Data {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cleanup(&self) -> Result<()> { self.db.db.cleanup() }
|
||||
|
||||
pub fn memory_usage(&self) -> String {
|
||||
let (auth_chain_cache, max_auth_chain_cache) = services().rooms.auth_chain.get_cache_usage();
|
||||
let (appservice_in_room_cache, max_appservice_in_room_cache) = services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.get_appservice_in_room_cache_usage();
|
||||
let (lasttimelinecount_cache, max_lasttimelinecount_cache) = services()
|
||||
.rooms
|
||||
.timeline
|
||||
.get_lasttimelinecount_cache_usage();
|
||||
|
||||
format!(
|
||||
"auth_chain_cache: {auth_chain_cache} / {max_auth_chain_cache}\nappservice_in_room_cache: \
|
||||
{appservice_in_room_cache} / {max_appservice_in_room_cache}\nlasttimelinecount_cache: \
|
||||
{lasttimelinecount_cache} / {max_lasttimelinecount_cache}\n\n{}",
|
||||
self.db.db.memory_usage().unwrap_or_default()
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
pub fn clear_caches(&self, amount: u32) {
|
||||
if amount > 1 {
|
||||
services().rooms.auth_chain.clear_cache();
|
||||
}
|
||||
if amount > 2 {
|
||||
services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.clear_appservice_in_room_cache();
|
||||
}
|
||||
if amount > 3 {
|
||||
services().rooms.timeline.clear_lasttimelinecount_cache();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_keypair(&self) -> Result<Ed25519KeyPair> {
|
||||
let keypair_bytes = self.global.get(b"keypair")?.map_or_else(
|
||||
|| {
|
||||
@@ -275,8 +240,16 @@ impl Data {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remove_keypair(&self) -> Result<()> { self.global.remove(b"keypair") }
|
||||
|
||||
/// TODO: the key valid until timestamp (`valid_until_ts`) is only honored
|
||||
/// in room version > 4
|
||||
///
|
||||
/// Remove the outdated keys and insert the new ones.
|
||||
///
|
||||
/// This doesn't actually check that the keys provided are newer than the
|
||||
/// old set.
|
||||
pub fn add_signing_key(
|
||||
&self, origin: &ServerName, new_keys: ServerSigningKeys,
|
||||
) -> Result<BTreeMap<OwnedServerSigningKeyId, VerifyKey>> {
|
||||
@@ -340,14 +313,18 @@ impl Data {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bump_database_version(&self, new_version: u64) -> Result<()> {
|
||||
self.global.insert(b"version", &new_version.to_be_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn backup(&self) -> Result<(), Box<dyn std::error::Error>> { self.db.db.backup() }
|
||||
|
||||
#[inline]
|
||||
pub fn backup_list(&self) -> Result<String> { self.db.db.backup_list() }
|
||||
|
||||
#[inline]
|
||||
pub fn file_list(&self) -> Result<String> { self.db.db.file_list() }
|
||||
}
|
||||
|
||||
@@ -50,7 +50,10 @@ pub(crate) async fn migrations(db: &Arc<Database>, config: &Config) -> Result<()
|
||||
}
|
||||
|
||||
async fn fresh(db: &Arc<Database>, config: &Config) -> Result<()> {
|
||||
services().globals.bump_database_version(DATABASE_VERSION)?;
|
||||
services()
|
||||
.globals
|
||||
.db
|
||||
.bump_database_version(DATABASE_VERSION)?;
|
||||
|
||||
db["global"].insert(b"fix_bad_double_separator_in_state_cache", &[])?;
|
||||
db["global"].insert(b"retroactively_fix_bad_data_from_roomuserid_joined", &[])?;
|
||||
@@ -68,57 +71,57 @@ async fn fresh(db: &Arc<Database>, config: &Config) -> Result<()> {
|
||||
|
||||
/// Apply any migrations
|
||||
async fn migrate(db: &Arc<Database>, config: &Config) -> Result<()> {
|
||||
if services().globals.database_version()? < 1 {
|
||||
if services().globals.db.database_version()? < 1 {
|
||||
db_lt_1(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 2 {
|
||||
if services().globals.db.database_version()? < 2 {
|
||||
db_lt_2(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 3 {
|
||||
if services().globals.db.database_version()? < 3 {
|
||||
db_lt_3(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 4 {
|
||||
if services().globals.db.database_version()? < 4 {
|
||||
db_lt_4(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 5 {
|
||||
if services().globals.db.database_version()? < 5 {
|
||||
db_lt_5(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 6 {
|
||||
if services().globals.db.database_version()? < 6 {
|
||||
db_lt_6(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 7 {
|
||||
if services().globals.db.database_version()? < 7 {
|
||||
db_lt_7(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 8 {
|
||||
if services().globals.db.database_version()? < 8 {
|
||||
db_lt_8(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 9 {
|
||||
if services().globals.db.database_version()? < 9 {
|
||||
db_lt_9(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 10 {
|
||||
if services().globals.db.database_version()? < 10 {
|
||||
db_lt_10(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 11 {
|
||||
if services().globals.db.database_version()? < 11 {
|
||||
db_lt_11(db, config).await?;
|
||||
}
|
||||
|
||||
if services().globals.database_version()? < 12 {
|
||||
if services().globals.db.database_version()? < 12 {
|
||||
db_lt_12(db, config).await?;
|
||||
}
|
||||
|
||||
// This migration can be reused as-is anytime the server-default rules are
|
||||
// updated.
|
||||
if services().globals.database_version()? < 13 {
|
||||
if services().globals.db.database_version()? < 13 {
|
||||
db_lt_13(db, config).await?;
|
||||
}
|
||||
|
||||
@@ -143,10 +146,10 @@ async fn migrate(db: &Arc<Database>, config: &Config) -> Result<()> {
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
services().globals.database_version().unwrap(),
|
||||
services().globals.db.database_version().unwrap(),
|
||||
DATABASE_VERSION,
|
||||
"Failed asserting local database version {} is equal to known latest conduwuit database version {}",
|
||||
services().globals.database_version().unwrap(),
|
||||
services().globals.db.database_version().unwrap(),
|
||||
DATABASE_VERSION,
|
||||
);
|
||||
|
||||
@@ -225,7 +228,7 @@ async fn db_lt_1(db: &Arc<Database>, _config: &Config) -> Result<()> {
|
||||
serverroomids.insert(&serverroomid, &[])?;
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(1)?;
|
||||
services().globals.db.bump_database_version(1)?;
|
||||
info!("Migration: 0 -> 1 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -242,7 +245,7 @@ async fn db_lt_2(db: &Arc<Database>, _config: &Config) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(2)?;
|
||||
services().globals.db.bump_database_version(2)?;
|
||||
info!("Migration: 1 -> 2 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -262,7 +265,7 @@ async fn db_lt_3(db: &Arc<Database>, _config: &Config) -> Result<()> {
|
||||
mediaid_file.insert(&key, &[])?;
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(3)?;
|
||||
services().globals.db.bump_database_version(3)?;
|
||||
info!("Migration: 2 -> 3 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -285,7 +288,7 @@ async fn db_lt_4(_db: &Arc<Database>, config: &Config) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(4)?;
|
||||
services().globals.db.bump_database_version(4)?;
|
||||
info!("Migration: 3 -> 4 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -309,7 +312,7 @@ async fn db_lt_5(db: &Arc<Database>, _config: &Config) -> Result<()> {
|
||||
roomusertype_roomuserdataid.insert(&key, &roomuserdataid)?;
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(5)?;
|
||||
services().globals.db.bump_database_version(5)?;
|
||||
info!("Migration: 4 -> 5 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -323,7 +326,7 @@ async fn db_lt_6(db: &Arc<Database>, _config: &Config) -> Result<()> {
|
||||
services().rooms.state_cache.update_joined_count(room_id)?;
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(6)?;
|
||||
services().globals.db.bump_database_version(6)?;
|
||||
info!("Migration: 5 -> 6 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -448,7 +451,7 @@ async fn db_lt_7(db: &Arc<Database>, _config: &Config) -> Result<()> {
|
||||
)?;
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(7)?;
|
||||
services().globals.db.bump_database_version(7)?;
|
||||
info!("Migration: 6 -> 7 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -514,7 +517,7 @@ async fn db_lt_8(db: &Arc<Database>, _config: &Config) -> Result<()> {
|
||||
|
||||
eventid_pduid.insert_batch(batch2.iter().map(database::KeyVal::from))?;
|
||||
|
||||
services().globals.bump_database_version(8)?;
|
||||
services().globals.db.bump_database_version(8)?;
|
||||
info!("Migration: 7 -> 8 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -571,7 +574,7 @@ async fn db_lt_9(db: &Arc<Database>, _config: &Config) -> Result<()> {
|
||||
tokenids.remove(&key)?;
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(9)?;
|
||||
services().globals.db.bump_database_version(9)?;
|
||||
info!("Migration: 8 -> 9 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -590,7 +593,7 @@ async fn db_lt_10(db: &Arc<Database>, _config: &Config) -> Result<()> {
|
||||
services().users.mark_device_key_update(&user_id)?;
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(10)?;
|
||||
services().globals.db.bump_database_version(10)?;
|
||||
info!("Migration: 9 -> 10 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -601,7 +604,7 @@ async fn db_lt_11(_db: &Arc<Database>, _config: &Config) -> Result<()> {
|
||||
//let userdevicesessionid_uiaarequest = &db["userdevicesessionid_uiaarequest"];
|
||||
//userdevicesessionid_uiaarequest.clear()?;
|
||||
|
||||
services().globals.bump_database_version(11)?;
|
||||
services().globals.db.bump_database_version(11)?;
|
||||
info!("Migration: 10 -> 11 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -669,7 +672,7 @@ async fn db_lt_12(_db: &Arc<Database>, config: &Config) -> Result<()> {
|
||||
)?;
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(12)?;
|
||||
services().globals.db.bump_database_version(12)?;
|
||||
info!("Migration: 11 -> 12 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -706,7 +709,7 @@ async fn db_lt_13(_db: &Arc<Database>, config: &Config) -> Result<()> {
|
||||
)?;
|
||||
}
|
||||
|
||||
services().globals.bump_database_version(13)?;
|
||||
services().globals.db.bump_database_version(13)?;
|
||||
info!("Migration: 12 -> 13 finished");
|
||||
Ok(())
|
||||
}
|
||||
@@ -736,8 +739,8 @@ async fn migrate_sha256_media(db: &Arc<Database>, _config: &Config) -> Result<()
|
||||
|
||||
// Apply fix from when sha256_media was backward-incompat and bumped the schema
|
||||
// version from 13 to 14. For users satisfying these conditions we can go back.
|
||||
if services().globals.database_version()? == 14 && DATABASE_VERSION == 13 {
|
||||
services().globals.bump_database_version(13)?;
|
||||
if services().globals.db.database_version()? == 14 && DATABASE_VERSION == 13 {
|
||||
services().globals.db.bump_database_version(13)?;
|
||||
}
|
||||
|
||||
db["global"].insert(b"feat_sha256_media", &[])?;
|
||||
|
||||
+63
-37
@@ -2,34 +2,27 @@ mod client;
|
||||
mod data;
|
||||
pub(super) mod emerg_access;
|
||||
pub(super) mod migrations;
|
||||
mod resolver;
|
||||
pub(crate) mod resolver;
|
||||
pub(super) mod updates;
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
sync::Arc,
|
||||
fmt::Write,
|
||||
sync::{Arc, RwLock},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use conduit::{error, trace, utils::MutexMap, Config, Result, Server};
|
||||
use conduit::{error, trace, utils::MutexMap, Config, Result};
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use hickory_resolver::TokioAsyncResolver;
|
||||
use ipaddress::IPAddress;
|
||||
use regex::RegexSet;
|
||||
use ruma::{
|
||||
api::{
|
||||
client::discovery::discover_support::ContactRole,
|
||||
federation::discovery::{ServerSigningKeys, VerifyKey},
|
||||
},
|
||||
api::{client::discovery::discover_support::ContactRole, federation::discovery::VerifyKey},
|
||||
serde::Base64,
|
||||
DeviceId, OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId,
|
||||
RoomAliasId, RoomVersionId, ServerName, UserId,
|
||||
};
|
||||
use tokio::{
|
||||
sync::{Mutex, RwLock},
|
||||
task::JoinHandle,
|
||||
};
|
||||
use tokio::{sync::Mutex, task::JoinHandle};
|
||||
use url::Url;
|
||||
|
||||
use crate::services;
|
||||
@@ -60,10 +53,10 @@ pub struct Service {
|
||||
pub admin_alias: OwnedRoomAliasId,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
let config = &server.config;
|
||||
let db = Data::new(db);
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
let config = &args.server.config;
|
||||
let db = Data::new(args.db);
|
||||
let keypair = db.load_keypair();
|
||||
|
||||
let keypair = match keypair {
|
||||
@@ -134,9 +127,59 @@ impl Service {
|
||||
s.config.default_room_version = crate::config::default_default_room_version();
|
||||
};
|
||||
|
||||
Ok(s)
|
||||
Ok(Arc::new(s))
|
||||
}
|
||||
|
||||
fn memory_usage(&self, out: &mut dyn Write) -> Result<()> {
|
||||
self.resolver.memory_usage(out)?;
|
||||
|
||||
let bad_event_ratelimiter = self
|
||||
.bad_event_ratelimiter
|
||||
.read()
|
||||
.expect("locked for reading")
|
||||
.len();
|
||||
writeln!(out, "bad_event_ratelimiter: {bad_event_ratelimiter}")?;
|
||||
|
||||
let bad_query_ratelimiter = self
|
||||
.bad_query_ratelimiter
|
||||
.read()
|
||||
.expect("locked for reading")
|
||||
.len();
|
||||
writeln!(out, "bad_query_ratelimiter: {bad_query_ratelimiter}")?;
|
||||
|
||||
let bad_signature_ratelimiter = self
|
||||
.bad_signature_ratelimiter
|
||||
.read()
|
||||
.expect("locked for reading")
|
||||
.len();
|
||||
writeln!(out, "bad_signature_ratelimiter: {bad_signature_ratelimiter}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear_cache(&self) {
|
||||
self.resolver.clear_cache();
|
||||
|
||||
self.bad_event_ratelimiter
|
||||
.write()
|
||||
.expect("locked for writing")
|
||||
.clear();
|
||||
|
||||
self.bad_query_ratelimiter
|
||||
.write()
|
||||
.expect("locked for writing")
|
||||
.clear();
|
||||
|
||||
self.bad_signature_ratelimiter
|
||||
.write()
|
||||
.expect("locked for writing")
|
||||
.clear();
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// Returns this server's keypair.
|
||||
pub fn keypair(&self) -> &ruma::signatures::Ed25519KeyPair { &self.keypair }
|
||||
|
||||
@@ -184,6 +227,7 @@ impl Service {
|
||||
|
||||
pub fn allow_unstable_room_versions(&self) -> bool { self.config.allow_unstable_room_versions }
|
||||
|
||||
#[inline]
|
||||
pub fn default_room_version(&self) -> RoomVersionId { self.config.default_room_version.clone() }
|
||||
|
||||
pub fn new_user_displayname_suffix(&self) -> &String { &self.config.new_user_displayname_suffix }
|
||||
@@ -194,8 +238,6 @@ impl Service {
|
||||
|
||||
pub fn query_trusted_key_servers_first(&self) -> bool { self.config.query_trusted_key_servers_first }
|
||||
|
||||
pub fn dns_resolver(&self) -> &TokioAsyncResolver { &self.resolver.resolver }
|
||||
|
||||
pub fn jwt_decoding_key(&self) -> Option<&jsonwebtoken::DecodingKey> { self.jwt_decoding_key.as_ref() }
|
||||
|
||||
pub fn turn_password(&self) -> &String { &self.config.turn_password }
|
||||
@@ -273,19 +315,6 @@ impl Service {
|
||||
room_versions
|
||||
}
|
||||
|
||||
/// TODO: the key valid until timestamp (`valid_until_ts`) is only honored
|
||||
/// in room version > 4
|
||||
///
|
||||
/// Remove the outdated keys and insert the new ones.
|
||||
///
|
||||
/// This doesn't actually check that the keys provided are newer than the
|
||||
/// old set.
|
||||
pub fn add_signing_key(
|
||||
&self, origin: &ServerName, new_keys: ServerSigningKeys,
|
||||
) -> Result<BTreeMap<OwnedServerSigningKeyId, VerifyKey>> {
|
||||
self.db.add_signing_key(origin, new_keys)
|
||||
}
|
||||
|
||||
/// This returns an empty `Ok(BTreeMap<..>)` when there are no keys found
|
||||
/// for the server.
|
||||
pub fn signing_keys_for(&self, origin: &ServerName) -> Result<BTreeMap<OwnedServerSigningKeyId, VerifyKey>> {
|
||||
@@ -304,14 +333,11 @@ impl Service {
|
||||
Ok(keys)
|
||||
}
|
||||
|
||||
pub fn database_version(&self) -> Result<u64> { self.db.database_version() }
|
||||
|
||||
pub fn bump_database_version(&self, new_version: u64) -> Result<()> { self.db.bump_database_version(new_version) }
|
||||
|
||||
pub fn well_known_client(&self) -> &Option<Url> { &self.config.well_known.client }
|
||||
|
||||
pub fn well_known_server(&self) -> &Option<OwnedServerName> { &self.config.well_known.server }
|
||||
|
||||
#[inline]
|
||||
pub fn valid_cidr_range(&self, ip: &IPAddress) -> bool {
|
||||
for cidr in &self.cidr_range_denylist {
|
||||
if cidr.includes(ip) {
|
||||
|
||||
@@ -1,36 +1,37 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::Write,
|
||||
future, iter,
|
||||
net::{IpAddr, SocketAddr},
|
||||
sync::{Arc, RwLock},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use conduit::{error, Config, Error};
|
||||
use conduit::{error, Config, Error, Result};
|
||||
use hickory_resolver::TokioAsyncResolver;
|
||||
use reqwest::dns::{Addrs, Name, Resolve, Resolving};
|
||||
use ruma::OwnedServerName;
|
||||
|
||||
use crate::sending::FedDest;
|
||||
use crate::sending::{CachedDest, CachedOverride};
|
||||
|
||||
type WellKnownMap = HashMap<OwnedServerName, (FedDest, String)>;
|
||||
type TlsNameMap = HashMap<String, (Vec<IpAddr>, u16)>;
|
||||
type WellKnownMap = HashMap<OwnedServerName, CachedDest>;
|
||||
type TlsNameMap = HashMap<String, CachedOverride>;
|
||||
|
||||
pub struct Resolver {
|
||||
pub destinations: Arc<RwLock<WellKnownMap>>, // actual_destination, host
|
||||
pub overrides: Arc<RwLock<TlsNameMap>>,
|
||||
pub resolver: Arc<TokioAsyncResolver>,
|
||||
pub hooked: Arc<Hooked>,
|
||||
pub(crate) resolver: Arc<TokioAsyncResolver>,
|
||||
pub(crate) hooked: Arc<Hooked>,
|
||||
}
|
||||
|
||||
pub struct Hooked {
|
||||
pub overrides: Arc<RwLock<TlsNameMap>>,
|
||||
pub resolver: Arc<TokioAsyncResolver>,
|
||||
pub(crate) struct Hooked {
|
||||
overrides: Arc<RwLock<TlsNameMap>>,
|
||||
resolver: Arc<TokioAsyncResolver>,
|
||||
}
|
||||
|
||||
impl Resolver {
|
||||
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
|
||||
pub fn new(config: &Config) -> Self {
|
||||
pub(super) fn new(config: &Config) -> Self {
|
||||
let (sys_conf, mut opts) = hickory_resolver::system_conf::read_system_conf()
|
||||
.map_err(|e| {
|
||||
error!("Failed to set up hickory dns resolver with system config: {e}");
|
||||
@@ -92,6 +93,22 @@ impl Resolver {
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn memory_usage(&self, out: &mut dyn Write) -> Result<()> {
|
||||
let resolver_overrides_cache = self.overrides.read().expect("locked for reading").len();
|
||||
writeln!(out, "resolver_overrides_cache: {resolver_overrides_cache}")?;
|
||||
|
||||
let resolver_destinations_cache = self.destinations.read().expect("locked for reading").len();
|
||||
writeln!(out, "resolver_destinations_cache: {resolver_destinations_cache}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn clear_cache(&self) {
|
||||
self.overrides.write().expect("write locked").clear();
|
||||
self.destinations.write().expect("write locked").clear();
|
||||
self.resolver.clear_cache();
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve for Resolver {
|
||||
@@ -100,15 +117,16 @@ impl Resolve for Resolver {
|
||||
|
||||
impl Resolve for Hooked {
|
||||
fn resolve(&self, name: Name) -> Resolving {
|
||||
let addr_port = self
|
||||
let cached = self
|
||||
.overrides
|
||||
.read()
|
||||
.expect("locked for reading")
|
||||
.get(name.as_str())
|
||||
.filter(|cached| cached.valid())
|
||||
.cloned();
|
||||
|
||||
if let Some((addr, port)) = addr_port {
|
||||
cached_to_reqwest(&addr, port)
|
||||
if let Some(cached) = cached {
|
||||
cached_to_reqwest(&cached.ips, cached.port)
|
||||
} else {
|
||||
resolve_to_reqwest(self.resolver.clone(), name)
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ mod data;
|
||||
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
use conduit::{Result, Server};
|
||||
use conduit::Result;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{
|
||||
api::client::backup::{BackupAlgorithm, KeyBackupData, RoomKeyBackup},
|
||||
serde::Raw,
|
||||
@@ -15,13 +14,17 @@ pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn create_backup(&self, user_id: &UserId, backup_metadata: &Raw<BackupAlgorithm>) -> Result<String> {
|
||||
self.db.create_backup(user_id, backup_metadata)
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ impl Data {
|
||||
/// associated with it such as width, height, content-type, etc)
|
||||
pub(crate) fn get_all_media_keys(&self) -> Vec<Vec<u8>> { self.mediaid_file.iter().map(|(key, _)| key).collect() }
|
||||
|
||||
#[inline]
|
||||
pub(super) fn remove_url_preview(&self, url: &str) -> Result<()> { self.url_previews.remove(url.as_bytes()) }
|
||||
|
||||
pub(super) fn set_url_preview(
|
||||
|
||||
@@ -6,7 +6,6 @@ use std::{collections::HashMap, io::Cursor, path::PathBuf, sync::Arc, time::Syst
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use conduit::{debug, debug_error, error, utils, Error, Result, Server};
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use image::imageops::FilterType;
|
||||
use ruma::{OwnedMxcUri, OwnedUserId};
|
||||
use serde::Serialize;
|
||||
@@ -48,15 +47,19 @@ pub struct Service {
|
||||
pub url_preview_mutex: RwLock<HashMap<String, Arc<Mutex<()>>>>,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
server: server.clone(),
|
||||
db: Data::new(db),
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
server: args.server.clone(),
|
||||
db: Data::new(args.db),
|
||||
url_preview_mutex: RwLock::new(HashMap::new()),
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// Uploads a file.
|
||||
pub async fn create(
|
||||
&self, sender_user: Option<OwnedUserId>, mxc: &str, content_disposition: Option<&str>,
|
||||
|
||||
+7
-4
@@ -1,4 +1,6 @@
|
||||
pub mod pdu;
|
||||
#![allow(refining_impl_trait)]
|
||||
|
||||
mod service;
|
||||
pub mod services;
|
||||
|
||||
pub mod account_data;
|
||||
@@ -20,12 +22,13 @@ extern crate conduit_database as database;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
pub(crate) use conduit::{config, debug_error, debug_info, debug_warn, utils, Config, Error, PduCount, Result, Server};
|
||||
pub(crate) use conduit::{config, debug_error, debug_info, debug_warn, utils, Config, Error, Result, Server};
|
||||
pub use conduit::{pdu, PduBuilder, PduCount, PduEvent};
|
||||
use database::Database;
|
||||
pub(crate) use service::{Args, Service};
|
||||
|
||||
pub use crate::{
|
||||
globals::{server_is_ours, user_is_local},
|
||||
pdu::PduEvent,
|
||||
services::Services,
|
||||
};
|
||||
|
||||
@@ -37,7 +40,7 @@ static SERVICES: RwLock<Option<&Services>> = RwLock::new(None);
|
||||
#[allow(clippy::let_underscore_must_use)]
|
||||
pub async fn init(server: &Arc<Server>) -> Result<()> {
|
||||
let d = Arc::new(Database::open(server).await?);
|
||||
let s = Box::new(Services::build(server.clone(), d.clone()).await?);
|
||||
let s = Box::new(Services::build(server.clone(), d)?);
|
||||
_ = SERVICES.write().expect("write locked").insert(Box::leak(s));
|
||||
|
||||
Ok(())
|
||||
|
||||
+21
-10
@@ -2,9 +2,9 @@ mod data;
|
||||
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use conduit::{debug, error, utils, Error, Result, Server};
|
||||
use async_trait::async_trait;
|
||||
use conduit::{debug, error, utils, Error, Result};
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use futures_util::{stream::FuturesUnordered, StreamExt};
|
||||
use ruma::{
|
||||
events::presence::{PresenceEvent, PresenceEventContent},
|
||||
@@ -81,12 +81,13 @@ pub struct Service {
|
||||
timeout_remote_users: bool,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Arc<Self>> {
|
||||
let config = &server.config;
|
||||
#[async_trait]
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
let config = &args.server.config;
|
||||
let (timer_sender, timer_receiver) = loole::unbounded();
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(db),
|
||||
db: Data::new(args.db),
|
||||
timer_sender,
|
||||
timer_receiver: Mutex::new(timer_receiver),
|
||||
handler_join: Mutex::new(None),
|
||||
@@ -94,8 +95,10 @@ impl Service {
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn start_handler(self: &Arc<Self>) {
|
||||
let self_ = Arc::clone(self);
|
||||
async fn start(self: Arc<Self>) -> Result<()> {
|
||||
//TODO: if self.globals.config.allow_local_presence { return; }
|
||||
|
||||
let self_ = Arc::clone(&self);
|
||||
let handle = services().server.runtime().spawn(async move {
|
||||
self_
|
||||
.handler()
|
||||
@@ -104,9 +107,11 @@ impl Service {
|
||||
});
|
||||
|
||||
_ = self.handler_join.lock().await.insert(handle);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn close(&self) {
|
||||
async fn stop(&self) {
|
||||
self.interrupt();
|
||||
if let Some(handler_join) = self.handler_join.lock().await.take() {
|
||||
if let Err(e) = handler_join.await {
|
||||
@@ -115,13 +120,18 @@ impl Service {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interrupt(&self) {
|
||||
fn interrupt(&self) {
|
||||
if !self.timer_sender.is_closed() {
|
||||
self.timer_sender.close();
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// Returns the latest presence event for the given user.
|
||||
#[inline]
|
||||
pub fn get_presence(&self, user_id: &UserId) -> Result<Option<PresenceEvent>> {
|
||||
if let Some((_, presence)) = self.db.get_presence(user_id)? {
|
||||
Ok(Some(presence))
|
||||
@@ -198,6 +208,7 @@ impl Service {
|
||||
|
||||
/// Returns the most recent presence updates that happened after the event
|
||||
/// with id `since`.
|
||||
#[inline]
|
||||
pub fn presence_since(&self, since: u64) -> Box<dyn Iterator<Item = (OwnedUserId, u64, Vec<u8>)> + '_> {
|
||||
self.db.presence_since(since)
|
||||
}
|
||||
|
||||
@@ -3,9 +3,8 @@ mod data;
|
||||
use std::{fmt::Debug, mem, sync::Arc};
|
||||
|
||||
use bytes::BytesMut;
|
||||
use conduit::{debug_info, info, trace, warn, Error, Result, Server};
|
||||
use conduit::{debug_info, info, trace, warn, Error, Result};
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ipaddress::IPAddress;
|
||||
use ruma::{
|
||||
api::{
|
||||
@@ -30,13 +29,17 @@ pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn set_pusher(&self, sender: &UserId, pusher: &set_pusher::v3::PusherAction) -> Result<()> {
|
||||
self.db.set_pusher(sender, pusher)
|
||||
}
|
||||
|
||||
@@ -3,9 +3,8 @@ mod remote;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::{Error, Result, Server};
|
||||
use conduit::{Error, Result};
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{
|
||||
api::{appservice, client::error::ErrorKind},
|
||||
events::{
|
||||
@@ -21,13 +20,17 @@ pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn set_alias(&self, alias: &RoomAliasId, room_id: &RoomId, user_id: &UserId) -> Result<()> {
|
||||
if alias == services().globals.admin_alias && user_id != services().globals.server_user {
|
||||
|
||||
@@ -5,9 +5,8 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use conduit::{debug, error, trace, warn, Error, Result, Server};
|
||||
use conduit::{debug, error, trace, warn, Error, Result};
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{api::client::error::ErrorKind, EventId, RoomId};
|
||||
|
||||
use crate::services;
|
||||
@@ -16,13 +15,17 @@ pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(server, db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.server, args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub async fn event_ids_iter<'a>(
|
||||
&self, room_id: &RoomId, starting_events_: Vec<Arc<EventId>>,
|
||||
) -> Result<impl Iterator<Item = Arc<EventId>> + 'a> {
|
||||
|
||||
@@ -2,9 +2,7 @@ mod data;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::Server;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{OwnedRoomId, RoomId};
|
||||
|
||||
use crate::Result;
|
||||
@@ -13,13 +11,17 @@ pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn set_public(&self, room_id: &RoomId) -> Result<()> { self.db.set_public(room_id) }
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use conduit::{debug_error, debug_info, Error, Result, Server};
|
||||
use database::Database;
|
||||
use conduit::{debug_error, debug_info, Error, Result};
|
||||
use futures_util::Future;
|
||||
pub use parse_incoming_pdu::parse_incoming_pdu;
|
||||
use ruma::{
|
||||
@@ -45,9 +44,13 @@ type AsyncRecursiveCanonicalJsonVec<'a> =
|
||||
type AsyncRecursiveCanonicalJsonResult<'a> =
|
||||
AsyncRecursiveType<'a, Result<(Arc<PduEvent>, BTreeMap<String, CanonicalJsonValue>)>>;
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, _db: &Arc<Database>) -> Result<Self> { Ok(Self {}) }
|
||||
impl crate::Service for Service {
|
||||
fn build(_args: crate::Args<'_>) -> Result<Arc<Self>> { Ok(Arc::new(Self {})) }
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// When receiving an event one needs to:
|
||||
/// 0. Check the server is in the room
|
||||
/// 1. Skip the PDU if we already know about it
|
||||
@@ -180,7 +183,7 @@ impl Service {
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.write()
|
||||
.await
|
||||
.expect("locked")
|
||||
.entry((*prev_id).to_owned())
|
||||
{
|
||||
hash_map::Entry::Vacant(e) => {
|
||||
@@ -200,7 +203,7 @@ impl Service {
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.write()
|
||||
.await
|
||||
.expect("locked")
|
||||
.insert(room_id.to_owned(), (event_id.to_owned(), start_time));
|
||||
|
||||
let r = self
|
||||
@@ -211,7 +214,7 @@ impl Service {
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.write()
|
||||
.await
|
||||
.expect("locked")
|
||||
.remove(&room_id.to_owned());
|
||||
|
||||
r
|
||||
@@ -245,7 +248,7 @@ impl Service {
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.read()
|
||||
.await
|
||||
.expect("locked")
|
||||
.get(prev_id)
|
||||
{
|
||||
// Exponential backoff
|
||||
@@ -274,7 +277,7 @@ impl Service {
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.write()
|
||||
.await
|
||||
.expect("locked")
|
||||
.insert(room_id.to_owned(), ((*prev_id).to_owned(), start_time));
|
||||
|
||||
self.upgrade_outlier_to_timeline_pdu(pdu, json, create_event, origin, room_id, pub_key_map)
|
||||
@@ -284,7 +287,7 @@ impl Service {
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.write()
|
||||
.await
|
||||
.expect("locked")
|
||||
.remove(&room_id.to_owned());
|
||||
|
||||
debug!(
|
||||
@@ -1043,7 +1046,7 @@ impl Service {
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.write()
|
||||
.await
|
||||
.expect("locked")
|
||||
.entry(id)
|
||||
{
|
||||
hash_map::Entry::Vacant(e) => {
|
||||
@@ -1076,7 +1079,7 @@ impl Service {
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.read()
|
||||
.await
|
||||
.expect("locked")
|
||||
.get(&*next_id)
|
||||
{
|
||||
// Exponential backoff
|
||||
@@ -1184,7 +1187,7 @@ impl Service {
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.read()
|
||||
.await
|
||||
.expect("locked")
|
||||
.get(&**next_id)
|
||||
{
|
||||
// Exponential backoff
|
||||
@@ -1378,6 +1381,7 @@ impl Service {
|
||||
Ok(create_event_content.room_version)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_room_version(room_version_id: &RoomVersionId) -> RoomVersion {
|
||||
RoomVersion::new(room_version_id).expect("room version is supported")
|
||||
}
|
||||
|
||||
@@ -201,6 +201,7 @@ impl super::Service {
|
||||
|
||||
let result = services()
|
||||
.globals
|
||||
.db
|
||||
.add_signing_key(&k.server_name, k.clone())?
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_string(), v.key))
|
||||
@@ -249,6 +250,7 @@ impl super::Service {
|
||||
if let Ok(key) = get_keys_response.server_key.deserialize() {
|
||||
let result: BTreeMap<_, _> = services()
|
||||
.globals
|
||||
.db
|
||||
.add_signing_key(&origin, key)?
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_string(), v.key))
|
||||
@@ -392,7 +394,7 @@ impl super::Service {
|
||||
}) {
|
||||
debug!("Got signing keys: {:?}", server_keys);
|
||||
for k in server_keys {
|
||||
services().globals.add_signing_key(origin, k.clone())?;
|
||||
services().globals.db.add_signing_key(origin, k.clone())?;
|
||||
result.extend(
|
||||
k.verify_keys
|
||||
.into_iter()
|
||||
@@ -421,6 +423,7 @@ impl super::Service {
|
||||
{
|
||||
services()
|
||||
.globals
|
||||
.db
|
||||
.add_signing_key(origin, server_key.clone())?;
|
||||
|
||||
result.extend(
|
||||
@@ -453,6 +456,7 @@ impl super::Service {
|
||||
{
|
||||
services()
|
||||
.globals
|
||||
.db
|
||||
.add_signing_key(origin, server_key.clone())?;
|
||||
|
||||
result.extend(
|
||||
@@ -499,7 +503,7 @@ impl super::Service {
|
||||
}) {
|
||||
debug!("Got signing keys: {:?}", server_keys);
|
||||
for k in server_keys {
|
||||
services().globals.add_signing_key(origin, k.clone())?;
|
||||
services().globals.db.add_signing_key(origin, k.clone())?;
|
||||
result.extend(
|
||||
k.verify_keys
|
||||
.into_iter()
|
||||
|
||||
@@ -2,14 +2,12 @@ mod data;
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
fmt::Write,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use conduit::Server;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{DeviceId, OwnedDeviceId, OwnedRoomId, OwnedUserId, RoomId, UserId};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{PduCount, Result};
|
||||
|
||||
@@ -20,14 +18,27 @@ pub struct Service {
|
||||
pub lazy_load_waiting: Mutex<HashMap<(OwnedUserId, OwnedDeviceId, OwnedRoomId, PduCount), HashSet<OwnedUserId>>>,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
lazy_load_waiting: Mutex::new(HashMap::new()),
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn memory_usage(&self, out: &mut dyn Write) -> Result<()> {
|
||||
let lazy_load_waiting = self.lazy_load_waiting.lock().expect("locked").len();
|
||||
writeln!(out, "lazy_load_waiting: {lazy_load_waiting}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear_cache(&self) { self.lazy_load_waiting.lock().expect("locked").clear(); }
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn lazy_load_was_sent_before(
|
||||
&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, ll_user: &UserId,
|
||||
@@ -43,7 +54,7 @@ impl Service {
|
||||
) {
|
||||
self.lazy_load_waiting
|
||||
.lock()
|
||||
.await
|
||||
.expect("locked")
|
||||
.insert((user_id.to_owned(), device_id.to_owned(), room_id.to_owned(), count), lazy_load);
|
||||
}
|
||||
|
||||
@@ -51,7 +62,7 @@ impl Service {
|
||||
pub async fn lazy_load_confirm_delivery(
|
||||
&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, since: PduCount,
|
||||
) -> Result<()> {
|
||||
if let Some(user_ids) = self.lazy_load_waiting.lock().await.remove(&(
|
||||
if let Some(user_ids) = self.lazy_load_waiting.lock().expect("locked").remove(&(
|
||||
user_id.to_owned(),
|
||||
device_id.to_owned(),
|
||||
room_id.to_owned(),
|
||||
|
||||
@@ -48,10 +48,12 @@ impl Data {
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn is_disabled(&self, room_id: &RoomId) -> Result<bool> {
|
||||
Ok(self.disabledroomids.get(room_id.as_bytes())?.is_some())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn disable_room(&self, room_id: &RoomId, disabled: bool) -> Result<()> {
|
||||
if disabled {
|
||||
self.disabledroomids.insert(room_id.as_bytes(), &[])?;
|
||||
@@ -62,10 +64,12 @@ impl Data {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn is_banned(&self, room_id: &RoomId) -> Result<bool> {
|
||||
Ok(self.bannedroomids.get(room_id.as_bytes())?.is_some())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn ban_room(&self, room_id: &RoomId, banned: bool) -> Result<()> {
|
||||
if banned {
|
||||
self.bannedroomids.insert(room_id.as_bytes(), &[])?;
|
||||
|
||||
@@ -2,39 +2,47 @@ mod data;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::{Result, Server};
|
||||
use conduit::Result;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{OwnedRoomId, RoomId};
|
||||
|
||||
pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// Checks if a room exists.
|
||||
#[tracing::instrument(skip(self))]
|
||||
#[inline]
|
||||
pub fn exists(&self, room_id: &RoomId) -> Result<bool> { self.db.exists(room_id) }
|
||||
|
||||
#[must_use]
|
||||
pub fn iter_ids<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> { self.db.iter_ids() }
|
||||
|
||||
#[inline]
|
||||
pub fn is_disabled(&self, room_id: &RoomId) -> Result<bool> { self.db.is_disabled(room_id) }
|
||||
|
||||
#[inline]
|
||||
pub fn disable_room(&self, room_id: &RoomId, disabled: bool) -> Result<()> {
|
||||
self.db.disable_room(room_id, disabled)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_banned(&self, room_id: &RoomId) -> Result<bool> { self.db.is_banned(room_id) }
|
||||
|
||||
#[inline]
|
||||
pub fn ban_room(&self, room_id: &RoomId, banned: bool) -> Result<()> { self.db.ban_room(room_id, banned) }
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn list_banned_rooms<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
|
||||
self.db.list_banned_rooms()
|
||||
|
||||
+22
-20
@@ -19,25 +19,27 @@ pub mod timeline;
|
||||
pub mod typing;
|
||||
pub mod user;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct Service {
|
||||
pub alias: alias::Service,
|
||||
pub auth_chain: auth_chain::Service,
|
||||
pub directory: directory::Service,
|
||||
pub event_handler: event_handler::Service,
|
||||
pub lazy_loading: lazy_loading::Service,
|
||||
pub metadata: metadata::Service,
|
||||
pub outlier: outlier::Service,
|
||||
pub pdu_metadata: pdu_metadata::Service,
|
||||
pub read_receipt: read_receipt::Service,
|
||||
pub search: search::Service,
|
||||
pub short: short::Service,
|
||||
pub state: state::Service,
|
||||
pub state_accessor: state_accessor::Service,
|
||||
pub state_cache: state_cache::Service,
|
||||
pub state_compressor: state_compressor::Service,
|
||||
pub timeline: timeline::Service,
|
||||
pub threads: threads::Service,
|
||||
pub typing: typing::Service,
|
||||
pub spaces: spaces::Service,
|
||||
pub user: user::Service,
|
||||
pub alias: Arc<alias::Service>,
|
||||
pub auth_chain: Arc<auth_chain::Service>,
|
||||
pub directory: Arc<directory::Service>,
|
||||
pub event_handler: Arc<event_handler::Service>,
|
||||
pub lazy_loading: Arc<lazy_loading::Service>,
|
||||
pub metadata: Arc<metadata::Service>,
|
||||
pub outlier: Arc<outlier::Service>,
|
||||
pub pdu_metadata: Arc<pdu_metadata::Service>,
|
||||
pub read_receipt: Arc<read_receipt::Service>,
|
||||
pub search: Arc<search::Service>,
|
||||
pub short: Arc<short::Service>,
|
||||
pub state: Arc<state::Service>,
|
||||
pub state_accessor: Arc<state_accessor::Service>,
|
||||
pub state_cache: Arc<state_cache::Service>,
|
||||
pub state_compressor: Arc<state_compressor::Service>,
|
||||
pub timeline: Arc<timeline::Service>,
|
||||
pub threads: Arc<threads::Service>,
|
||||
pub typing: Arc<typing::Service>,
|
||||
pub spaces: Arc<spaces::Service>,
|
||||
pub user: Arc<user::Service>,
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ mod data;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::{Result, Server};
|
||||
use conduit::Result;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{CanonicalJsonObject, EventId};
|
||||
|
||||
use crate::PduEvent;
|
||||
@@ -13,13 +12,17 @@ pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// Returns the pdu from the outlier tree.
|
||||
pub fn get_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
|
||||
self.db.get_outlier_pdu_json(event_id)
|
||||
|
||||
@@ -2,9 +2,8 @@ mod data;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::{Result, Server};
|
||||
use conduit::Result;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{
|
||||
api::{client::relations::get_relating_events, Direction},
|
||||
events::{relation::RelationType, TimelineEventType},
|
||||
@@ -28,13 +27,17 @@ struct ExtractRelatesToEventId {
|
||||
relates_to: ExtractRelType,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
#[tracing::instrument(skip(self, from, to))]
|
||||
pub fn add_relation(&self, from: PduCount, to: PduCount) -> Result<()> {
|
||||
match (from, to) {
|
||||
|
||||
@@ -2,9 +2,8 @@ mod data;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::{Result, Server};
|
||||
use conduit::Result;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{events::receipt::ReceiptEvent, serde::Raw, OwnedUserId, RoomId, UserId};
|
||||
|
||||
use crate::services;
|
||||
@@ -13,13 +12,17 @@ pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// Replaces the previous read receipt.
|
||||
pub fn readreceipt_update(&self, user_id: &UserId, room_id: &RoomId, event: &ReceiptEvent) -> Result<()> {
|
||||
self.db.readreceipt_update(user_id, room_id, event)?;
|
||||
|
||||
@@ -2,22 +2,25 @@ mod data;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::{Result, Server};
|
||||
use conduit::Result;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::RoomId;
|
||||
|
||||
pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn index_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> Result<()> {
|
||||
self.db.index_pdu(shortroomid, pdu_id, message_body)
|
||||
|
||||
@@ -2,22 +2,25 @@ mod data;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use conduit::{Result, Server};
|
||||
use conduit::Result;
|
||||
use data::Data;
|
||||
use database::Database;
|
||||
use ruma::{events::StateEventType, EventId, RoomId};
|
||||
|
||||
pub struct Service {
|
||||
db: Data,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
db: Data::new(db),
|
||||
})
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn get_or_create_shorteventid(&self, event_id: &EventId) -> Result<u64> {
|
||||
self.db.get_or_create_shorteventid(event_id)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user