Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot] c02d77207c Update nix-community/cache-nix-action action to v5.2.1 2024-07-03 09:04:17 +00:00
123 changed files with 1042 additions and 1735 deletions
+1 -6
View File
@@ -11,10 +11,5 @@ 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
+3 -6
View File
@@ -50,9 +50,6 @@ 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
@@ -77,7 +74,7 @@ jobs:
cachix use nix-community
- name: Restore and cache Nix store
uses: nix-community/cache-nix-action@v5.1.0
uses: nix-community/cache-nix-action@v5.2.1
with:
# restore and save a cache using this key
primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/.lock') }}
@@ -122,7 +119,7 @@ jobs:
- name: Cache CI dependencies
run: |
bin/nix-build-and-cache ci
- uses: Swatinem/rust-cache@v2
- name: Run CI tests
@@ -202,7 +199,7 @@ jobs:
cachix use nix-community
- name: Restore and cache Nix store
uses: nix-community/cache-nix-action@v5.1.0
uses: nix-community/cache-nix-action@v5.2.1
with:
# restore and save a cache using this key
primary-key: nix-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('**/*.nix', '**/.lock') }}
+1 -6
View File
@@ -60,7 +60,7 @@ jobs:
cachix use nix-community
- name: Restore and cache Nix store
uses: nix-community/cache-nix-action@v5.1.0
uses: nix-community/cache-nix-action@v5.2.1
with:
# restore and save a cache using this key
primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/.lock') }}
@@ -106,11 +106,6 @@ 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
-1
View File
@@ -1 +0,0 @@
.gitignore
+2 -1
View File
@@ -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,3 +131,4 @@ 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
-3
View File
@@ -19,7 +19,6 @@ 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`
@@ -38,7 +37,6 @@ 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
@@ -88,7 +86,6 @@ 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
+24 -47
View File
@@ -570,7 +570,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "conduit"
version = "0.4.4"
version = "0.4.3"
dependencies = [
"clap",
"conduit_admin",
@@ -598,7 +598,7 @@ dependencies = [
[[package]]
name = "conduit_admin"
version = "0.4.4"
version = "0.4.3"
dependencies = [
"clap",
"conduit_api",
@@ -620,7 +620,7 @@ dependencies = [
[[package]]
name = "conduit_api"
version = "0.4.4"
version = "0.4.3"
dependencies = [
"axum 0.7.5",
"axum-client-ip",
@@ -653,7 +653,7 @@ dependencies = [
[[package]]
name = "conduit_core"
version = "0.4.4"
version = "0.4.3"
dependencies = [
"argon2",
"axum 0.7.5",
@@ -692,7 +692,7 @@ dependencies = [
[[package]]
name = "conduit_database"
version = "0.4.4"
version = "0.4.3"
dependencies = [
"conduit_core",
"log",
@@ -704,7 +704,7 @@ dependencies = [
[[package]]
name = "conduit_router"
version = "0.4.4"
version = "0.4.3"
dependencies = [
"axum 0.7.5",
"axum-client-ip",
@@ -737,7 +737,7 @@ dependencies = [
[[package]]
name = "conduit_service"
version = "0.4.4"
version = "0.4.3"
dependencies = [
"async-trait",
"base64 0.22.1",
@@ -1552,15 +1552,6 @@ 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"
@@ -2903,7 +2894,7 @@ dependencies = [
[[package]]
name = "ruma"
version = "0.10.1"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"assign",
"js_int",
@@ -2915,7 +2906,6 @@ 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",
@@ -2924,7 +2914,7 @@ dependencies = [
[[package]]
name = "ruma-appservice-api"
version = "0.10.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"js_int",
"ruma-common",
@@ -2936,7 +2926,7 @@ dependencies = [
[[package]]
name = "ruma-client-api"
version = "0.18.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"as_variant",
"assign",
@@ -2959,7 +2949,7 @@ dependencies = [
[[package]]
name = "ruma-common"
version = "0.13.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"as_variant",
"base64 0.22.1",
@@ -2972,7 +2962,7 @@ dependencies = [
"percent-encoding",
"rand",
"regex",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0)",
"ruma-macros",
"serde",
"serde_html_form",
@@ -2989,7 +2979,7 @@ dependencies = [
[[package]]
name = "ruma-events"
version = "0.28.1"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"as_variant",
"indexmap 2.2.6",
@@ -2999,7 +2989,7 @@ dependencies = [
"pulldown-cmark",
"regex",
"ruma-common",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0)",
"ruma-macros",
"serde",
"serde_json",
@@ -3012,7 +3002,7 @@ dependencies = [
[[package]]
name = "ruma-federation-api"
version = "0.9.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"js_int",
"ruma-common",
@@ -3024,7 +3014,7 @@ dependencies = [
[[package]]
name = "ruma-identifiers-validation"
version = "0.9.5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"js_int",
"thiserror",
@@ -3042,7 +3032,7 @@ dependencies = [
[[package]]
name = "ruma-identity-service-api"
version = "0.9.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"js_int",
"ruma-common",
@@ -3052,13 +3042,13 @@ dependencies = [
[[package]]
name = "ruma-macros"
version = "0.13.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"once_cell",
"proc-macro-crate",
"proc-macro2",
"quote",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0)",
"serde",
"syn 2.0.68",
"toml",
@@ -3067,7 +3057,7 @@ dependencies = [
[[package]]
name = "ruma-push-gateway-api"
version = "0.9.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"js_int",
"ruma-common",
@@ -3076,23 +3066,10 @@ 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=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"base64 0.22.1",
"ed25519-dalek",
@@ -3108,7 +3085,7 @@ dependencies = [
[[package]]
name = "ruma-state-res"
version = "0.11.0"
source = "git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5#c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=9a5bfad8494b7a4e6c40421c3d0675db4b434ec0#9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
dependencies = [
"itertools 0.12.1",
"js_int",
@@ -3330,9 +3307,9 @@ dependencies = [
[[package]]
name = "sd-notify"
version = "0.4.2"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4646d6f919800cd25c50edb49438a1381e2cd4833c027e75e8897981c50b8b5e"
checksum = "621e3680f3e07db4c9c2c3fb07c6223ab2fab2e54bd3c04c3ae037990f428c32"
[[package]]
name = "security-framework"
+3 -5
View File
@@ -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.4"
version = "0.4.3"
[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", "std"]
features = ["alloc"]
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 = "c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
rev = "9a5bfad8494b7a4e6c40421c3d0675db4b434ec0"
features = [
"compat",
"rand",
@@ -284,7 +284,6 @@ features = [
"markdown",
"push-gateway-api-c",
"state-res",
"server-util",
"unstable-exhaustive-types",
"ring-compat",
"unstable-unspecified",
@@ -294,7 +293,6 @@ features = [
"unstable-msc2870",
"unstable-msc3026",
"unstable-msc3061",
"unstable-msc3266",
"unstable-msc3575",
"unstable-msc4121",
"unstable-msc4125",
-1
View File
@@ -43,7 +43,6 @@ 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
View File
@@ -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=TestClientSpacesSummary.*|TestJoinFederatedRoomFromApplicationServiceBridgeUser.*|TestJumpToDateEndpoint.*'
SKIPPED_COMPLEMENT_TESTS='-skip=TestJumpToDateEndpoint.*|TestJoinFederatedRoomFromApplicationServiceBridgeUser.*|TestFederationRoomsInvite.*|TestClientSpacesSummary.*'
toplevel="$(git rev-parse --show-toplevel)"
-17
View File
@@ -378,8 +378,6 @@ 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:
@@ -389,23 +387,8 @@ 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
View File
@@ -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)
+1 -3
View File
@@ -24,11 +24,9 @@ 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
@@ -57,7 +55,6 @@ 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)
@@ -103,6 +100,7 @@ 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.
+4 -4
View File
@@ -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?
-1
View File
@@ -8,7 +8,6 @@ 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
View File
@@ -16,7 +16,7 @@ look like this:
RUSTFLAGS="--cfg tokio_unstable" cargo build \
--release \
--no-default-features \
--features=systemd,element_hacks,gzip_compression,brotli_compression,zstd_compression,tokio_console
--features=rocksdb,systemd,element_hacks,gzip_compression,brotli_compression,zstd_compression,tokio_console
```
[1]: https://docs.rs/tokio-console/latest/tokio_console/
-3
View File
@@ -65,17 +65,14 @@ 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].
+13 -17
View File
@@ -1,11 +1,10 @@
#### **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)
@@ -26,10 +25,9 @@ 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`)
@@ -58,11 +56,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 `[global.well_known]` (MSC1929) (`/.well-known/matrix/support`)
- Add support for serving `support` well-known from `[well_known.support]` (MSC1929)
- 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.
@@ -75,8 +73,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
@@ -91,8 +89,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)
@@ -110,8 +108,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
@@ -121,21 +119,19 @@ 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
@@ -169,11 +165,12 @@ 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>)
- 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)
- 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]`
@@ -182,7 +179,6 @@ 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
-3
View File
@@ -5,7 +5,6 @@
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`)
@@ -38,7 +37,6 @@ 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
@@ -54,7 +52,6 @@ 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`)
+4
View File
@@ -40,6 +40,10 @@ 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`.
-3
View File
@@ -11,15 +11,12 @@ 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
View File
@@ -55,11 +55,6 @@ name = "lychee"
group = "versions"
script = "lychee --version"
[[task]]
name = "markdownlint"
group = "versions"
script = "markdownlint --version"
[[task]]
name = "cargo-audit"
group = "security"
@@ -143,11 +138,6 @@ 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"
-3
View File
@@ -108,9 +108,6 @@
# Needed for finding broken markdown links
lychee
# Needed for linting markdown files
markdownlint-cli
# Useful for editing the book locally
mdbook
])
+8 -9
View File
@@ -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_actual_dest, services, PduEvent};
use service::{rooms::event_handler::parse_incoming_pdu, sending::resolve::resolve_actual_dest, services, PduEvent};
use tokio::sync::RwLock;
use tracing_subscriber::EnvFilter;
@@ -614,16 +614,15 @@ 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 capture_scope = capture.start();
let actual = resolve_actual_dest(&server_name, !no_cache).await?;
drop(capture_scope);
let (actual_dest, hostname_uri);
{
let _capture_scope = capture.start();
(actual_dest, hostname_uri) = resolve_actual_dest(&server_name, !no_cache).await?;
};
let msg = format!(
"{}\nDestination: {}\nHostname URI: {}",
logs.lock().expect("locked"),
actual.dest,
actual.host,
"{}\nDestination: {actual_dest}\nHostname URI: {hostname_uri}",
logs.lock().expect("locked")
);
Ok(RoomMessageEventContent::text_markdown(msg))
}
+3 -7
View File
@@ -15,18 +15,14 @@ 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()
.expect("locked");
let map = services().globals.roomid_federationhandletime.read().await;
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)?;
writeln!(msg, "{} {}: {}m{}s", r, e, elapsed.as_secs() / 60, elapsed.as_secs() % 60,)
.expect("should be able to write to string buffer");
}
Ok(RoomMessageEventContent::text_plain(&msg))
}
+3 -24
View File
@@ -2,7 +2,6 @@ mod account_data;
mod appservice;
mod globals;
mod presence;
mod resolver;
mod room_alias;
mod room_state_cache;
mod sending;
@@ -13,12 +12,12 @@ use conduit::Result;
use room_state_cache::room_state_cache;
use ruma::{
events::{room::message::RoomMessageEventContent, RoomAccountDataEventType},
OwnedServerName, RoomAliasId, RoomId, ServerName, UserId,
RoomAliasId, RoomId, ServerName, UserId,
};
use self::{
account_data::account_data, appservice::appservice, globals::globals, presence::presence, resolver::resolver,
room_alias::room_alias, sending::sending, users::users,
account_data::account_data, appservice::appservice, globals::globals, presence::presence, room_alias::room_alias,
sending::sending, users::users,
};
#[cfg_attr(test, derive(Debug))]
@@ -56,10 +55,6 @@ pub(super) enum QueryCommand {
/// - users.rs iterators and getters
#[command(subcommand)]
Users(Users),
/// - resolver service
#[command(subcommand)]
Resolver(Resolver),
}
#[cfg_attr(test, derive(Debug))]
@@ -292,21 +287,6 @@ 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 {
@@ -318,6 +298,5 @@ 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?,
})
}
-87
View File
@@ -1,87 +0,0 @@
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))
}
+11 -5
View File
@@ -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().db.db.memory_usage()?;
let response0 = services().memory_usage().await;
let response1 = services().globals.db.memory_usage();
let response2 = conduit::alloc::memory_usage();
Ok(RoomMessageEventContent::text_plain(format!(
"Services:\n{response0}\nDatabase:\n{response1}\n{}",
"Services:\n{response0}\n\nDatabase:\n{response1}\n{}",
if !response2.is_empty() {
format!("Allocator:\n {response2}")
} else {
@@ -41,8 +41,14 @@ pub(super) async fn memory_usage(_body: Vec<&str>) -> Result<RoomMessageEventCon
)))
}
pub(super) async fn clear_caches(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
services().clear_cache().await;
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;
Ok(RoomMessageEventContent::text_plain("Done."))
}
+17 -3
View File
@@ -18,8 +18,17 @@ pub(super) enum ServerCommand {
/// - Print database memory usage statistics
MemoryUsage,
/// - Clears all of Conduwuit's caches
ClearCaches,
/// - 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,
},
/// - Performs an online backup of the database (only available for RocksDB
/// at the moment)
@@ -56,7 +65,12 @@ 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::ClearCaches => clear_caches(body).await?,
ServerCommand::ClearDatabaseCaches {
amount,
} => clear_database_caches(body, amount).await?,
ServerCommand::ClearServiceCaches {
amount,
} => clear_service_caches(body, amount).await?,
ServerCommand::ListBackups => list_backups(body).await?,
ServerCommand::BackupDatabase => backup_database(body).await?,
ServerCommand::ListDatabaseFiles => list_database_files(body).await?,
+23 -6
View File
@@ -10,7 +10,11 @@ use ruma::{
},
directory::{Filter, PublicRoomJoinRule, PublicRoomsChunk, RoomNetwork},
events::{
room::join_rules::{JoinRule, RoomJoinRulesEventContent},
room::{
avatar::RoomAvatarEventContent,
create::RoomCreateEventContent,
join_rules::{JoinRule, RoomJoinRulesEventContent},
},
StateEventType,
},
uint, ServerName, UInt,
@@ -252,10 +256,15 @@ pub(crate) async fn get_public_rooms_filtered_helper(
avatar_url: services()
.rooms
.state_accessor
.get_avatar(&room_id)?
.into_option()
.unwrap_or_default()
.url,
.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(),
join_rule: services()
.rooms
.state_accessor
@@ -278,7 +287,15 @@ pub(crate) async fn get_public_rooms_filtered_helper(
room_type: services()
.rooms
.state_accessor
.get_room_type(&room_id)?,
.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),
room_id,
};
Ok(chunk)
+2 -2
View File
@@ -334,7 +334,7 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool + Send>(
.globals
.bad_query_ratelimiter
.write()
.expect("locked")
.await
.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()
.expect("locked")
.await
.get(server)
{
// Exponential backoff
+6 -7
View File
@@ -33,7 +33,6 @@ 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};
@@ -780,7 +779,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: convert_to_outgoing_federation_event(join_event.clone()),
pdu: PduEvent::convert_to_outgoing_federation_event(join_event.clone()),
omit_members: false,
},
)
@@ -1208,7 +1207,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: convert_to_outgoing_federation_event(join_event.clone()),
pdu: PduEvent::convert_to_outgoing_federation_event(join_event.clone()),
omit_members: false,
},
)
@@ -1343,7 +1342,7 @@ pub async fn validate_and_add_event_id(
.globals
.bad_event_ratelimiter
.write()
.expect("locked")
.await
.entry(id)
{
Entry::Vacant(e) => {
@@ -1359,7 +1358,7 @@ pub async fn validate_and_add_event_id(
.globals
.bad_event_ratelimiter
.read()
.expect("locked")
.await
.get(&event_id)
{
// Exponential backoff
@@ -1439,7 +1438,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: convert_to_outgoing_federation_event(pdu_json.clone()),
event: PduEvent::convert_to_outgoing_federation_event(pdu_json.clone()),
invite_room_state,
via: services().rooms.state_cache.servers_route_via(room_id).ok(),
},
@@ -1776,7 +1775,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: convert_to_outgoing_federation_event(leave_event.clone()),
pdu: PduEvent::convert_to_outgoing_federation_event(leave_event.clone()),
},
)
.await?;
-2
View File
@@ -11,7 +11,6 @@ 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;
@@ -49,7 +48,6 @@ 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};
-41
View File
@@ -1,41 +0,0 @@
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),
})
}
+2 -120
View File
@@ -1,8 +1,5 @@
use axum_client_ip::InsecureClientIp;
use conduit::{warn, RumaResponse};
use ruma::{
api::client::{error::ErrorKind, membership::mutual_rooms, room::get_summary},
events::room::member::MembershipState,
api::client::{error::ErrorKind, membership::mutual_rooms},
OwnedRoomId,
};
@@ -15,9 +12,8 @@ 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(
InsecureClientIp(client): InsecureClientIp, body: Ruma<mutual_rooms::unstable::Request>,
body: Ruma<mutual_rooms::unstable::Request>,
) -> Result<mutual_rooms::unstable::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
@@ -47,117 +43,3 @@ 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),
})
}
+10 -34
View File
@@ -9,12 +9,11 @@ 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;
use super::{request::Request, xmatrix::XMatrix};
use crate::{service::appservice::RegistrationInfo, services, Error, Result};
enum Token {
@@ -77,26 +76,12 @@ pub(super) async fn auth(
}
match (metadata.authentication, 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.",
))
}
},
(_, Token::Invalid) => 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 {
@@ -203,17 +188,8 @@ 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.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 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 server_destination = services().globals.server_name().as_str().to_owned();
if let Some(destination) = x_matrix.destination.as_ref() {
@@ -249,7 +225,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.to_string()])
.fetch_signing_keys_for_server(origin, vec![x_matrix.key.clone()])
.await;
let keys = keys_result.map_err(|e| {
+1
View File
@@ -1,6 +1,7 @@
mod auth;
mod handler;
mod request;
mod xmatrix;
use std::{mem, ops::Deref};
+61
View File
@@ -0,0 +1,61 @@
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!() }
}
+1 -7
View File
@@ -39,7 +39,6 @@ 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)
@@ -172,6 +171,7 @@ 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,11 +179,6 @@ 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))
@@ -217,7 +212,6 @@ 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))
+2 -4
View File
@@ -1,11 +1,9 @@
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::Ruma;
use crate::{services, Error, PduEvent, Result, Ruma};
/// # `GET /_matrix/federation/v1/backfill/<room_id>`
///
@@ -64,7 +62,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(convert_to_outgoing_federation_event)
.map(PduEvent::convert_to_outgoing_federation_event)
.collect();
Ok(get_backfill::v1::Response {
+2 -4
View File
@@ -1,11 +1,9 @@
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::Ruma;
use crate::{services, Error, PduEvent, Result, Ruma};
/// # `GET /_matrix/federation/v1/event/{eventId}`
///
@@ -50,6 +48,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: convert_to_outgoing_federation_event(event),
pdu: PduEvent::convert_to_outgoing_federation_event(event),
})
}
+2 -4
View File
@@ -1,13 +1,11 @@
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::Ruma;
use crate::{services, Error, PduEvent, Result, Ruma};
/// # `GET /_matrix/federation/v1/event_auth/{roomId}/{eventId}`
///
@@ -59,7 +57,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(convert_to_outgoing_federation_event)
.map(PduEvent::convert_to_outgoing_federation_event)
.collect(),
})
}
+2 -4
View File
@@ -1,11 +1,9 @@
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::Ruma;
use crate::{services, Error, PduEvent, Result, Ruma};
/// # `POST /_matrix/federation/v1/get_missing_events/{roomId}`
///
@@ -81,7 +79,7 @@ pub(crate) async fn get_missing_events_route(
)
.map_err(|_| Error::bad_database("Invalid prev_events in event in database."))?,
);
events.push(convert_to_outgoing_federation_event(pdu));
events.push(PduEvent::convert_to_outgoing_federation_event(pdu));
}
i = i.saturating_add(1);
}
+8 -4
View File
@@ -1,14 +1,18 @@
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 service::{sending::convert_to_outgoing_federation_event, server_is_ours, services};
use tracing::warn;
use crate::Ruma;
use crate::{
service::server_is_ours,
services,
utils::{self},
Error, PduEvent, Result, Ruma,
};
/// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`
///
@@ -172,6 +176,6 @@ pub(crate) async fn create_invite_route(
}
Ok(create_invite::v2::Response {
event: convert_to_outgoing_federation_event(signed_event),
event: PduEvent::convert_to_outgoing_federation_event(signed_event),
})
}
-2
View File
@@ -7,7 +7,6 @@ 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;
@@ -28,7 +27,6 @@ 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::*;
-16
View File
@@ -1,16 +0,0 @@
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)?,
))
}
+4 -7
View File
@@ -2,7 +2,6 @@
use std::collections::BTreeMap;
use conduit::{Error, Result};
use ruma::{
api::{client::error::ErrorKind, federation::membership::create_join_event},
events::{
@@ -12,13 +11,11 @@ use ruma::{
CanonicalJsonValue, OwnedServerName, OwnedUserId, RoomId, ServerName,
};
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
use service::{
pdu::gen_event_id_canonical_json, sending::convert_to_outgoing_federation_event, services, user_is_local,
};
use service::user_is_local;
use tokio::sync::RwLock;
use tracing::warn;
use crate::Ruma;
use crate::{service::pdu::gen_event_id_canonical_json, services, Error, PduEvent, Result, Ruma};
/// helper method for /send_join v1 and v2
async fn create_join_event(
@@ -184,12 +181,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(convert_to_outgoing_federation_event)
.map(PduEvent::convert_to_outgoing_federation_event)
.collect(),
state: state_ids
.iter()
.filter_map(|(_, id)| services().rooms.timeline.get_pdu_json(id).ok().flatten())
.map(convert_to_outgoing_federation_event)
.map(PduEvent::convert_to_outgoing_federation_event)
.collect(),
// Event field is required if the room version supports restricted join rules.
event: Some(
+3 -5
View File
@@ -1,10 +1,8 @@
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::Ruma;
use crate::{services, Error, PduEvent, Result, Ruma};
/// # `GET /_matrix/federation/v1/state/{roomId}`
///
@@ -44,7 +42,7 @@ pub(crate) async fn get_room_state_route(
.await?
.into_values()
.map(|id| {
convert_to_outgoing_federation_event(
PduEvent::convert_to_outgoing_federation_event(
services()
.rooms
.timeline
@@ -69,7 +67,7 @@ pub(crate) async fn get_room_state_route(
.timeline
.get_pdu_json(&id)
.ok()?
.map(convert_to_outgoing_federation_event)
.map(PduEvent::convert_to_outgoing_federation_event)
})
.collect(),
pdus,
-4
View File
@@ -45,10 +45,6 @@ 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
+1 -1
View File
@@ -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 "
)
}
-11
View File
@@ -6,17 +6,6 @@ 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();
-5
View File
@@ -201,8 +201,6 @@ 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)]
@@ -673,7 +671,6 @@ 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() {
@@ -987,8 +984,6 @@ 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 }
-1
View File
@@ -92,7 +92,6 @@ 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();
-1
View File
@@ -8,6 +8,5 @@ pub struct Guard {
}
impl Drop for Guard {
#[inline]
fn drop(&mut self) { self.capture.stop(); }
}
-2
View File
@@ -17,7 +17,6 @@ struct Visitor {
}
impl Layer {
#[inline]
pub fn new(state: &Arc<State>) -> Self {
Self {
state: state.clone(),
@@ -26,7 +25,6 @@ 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
View File
@@ -4,14 +4,14 @@ pub mod debug;
pub mod error;
pub mod log;
pub mod mods;
pub mod pdu;
pub mod pducount;
pub mod server;
pub mod utils;
pub mod version;
pub use config::Config;
pub use error::{Error, RumaResponse};
pub use pdu::{PduBuilder, PduCount, PduEvent};
pub use pducount::PduCount;
pub use server::Server;
pub use version::version;
-16
View File
@@ -1,16 +0,0 @@
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>>,
}
+12 -13
View File
@@ -3,28 +3,27 @@ use crate::Result;
#[inline]
#[must_use]
pub fn increment(old: Option<&[u8]>) -> [u8; 8] {
old.map_or(0_u64, u64_from_bytes_or_zero)
old.map(TryInto::try_into)
.map_or(0_u64, |val| val.map_or(0_u64, u64::from_be_bytes))
.wrapping_add(1)
.to_be_bytes()
}
/// Parses 8 big-endian bytes into an u64; panic on invalid argument
#[inline]
#[must_use]
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) }
pub fn u64_from_bytes(bytes: &[u8]) -> Result<u64> {
let array: [u8; 8] = bytes.try_into()?;
Ok(u64_from_u8x8(array))
}
/// Parses the big-endian bytes into an u64.
/// Parses the 8 big-endian bytes into an u64.
#[inline]
pub fn u64_from_bytes(bytes: &[u8]) -> Result<u64> { Ok(u64_from_u8x8(*u8x8_from_bytes(bytes)?)) }
#[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)
}
#[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
View File
@@ -3,11 +3,14 @@ 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) }
+4 -5
View File
@@ -6,7 +6,6 @@ pub mod hash;
pub mod html;
pub mod json;
pub mod mutex_map;
pub mod rand;
pub mod string;
pub mod sys;
mod tests;
@@ -20,10 +19,9 @@ 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 rand::string as random_string;
pub use string::{str_from_bytes, string_from_bytes};
pub use string::{random_string, str_from_bytes, string_from_bytes};
pub use sys::available_parallelism;
pub use time::now_millis as millis_since_unix_epoch;
pub use time::millis_since_unix_epoch;
use crate::Result;
@@ -33,6 +31,7 @@ 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,
@@ -42,7 +41,7 @@ pub fn unwrap_infallible<T>(result: Result<T, std::convert::Infallible>) -> T {
#[must_use]
pub fn generate_keypair() -> Vec<u8> {
let mut value = rand::string(8).as_bytes().to_vec();
let mut value = random_string(8).as_bytes().to_vec();
value.push(0xFF);
value.extend_from_slice(
&ruma::signatures::Ed25519KeyPair::generate().expect("Ed25519KeyPair generation always works (?)"),
-24
View File
@@ -1,24 +0,0 @@
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))
}
+9 -6
View File
@@ -1,14 +1,17 @@
use rand::prelude::*;
use crate::Result;
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))
pub fn random_string(length: usize) -> String {
thread_rng()
.sample_iter(&rand::distributions::Alphanumeric)
.take(length)
.map(char::from)
.collect()
}
/// 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())
+4 -12
View File
@@ -3,10 +3,10 @@ use std::time::{SystemTime, UNIX_EPOCH};
#[inline]
#[must_use]
#[allow(clippy::as_conversions)]
pub fn now_millis() -> u64 {
UNIX_EPOCH
.elapsed()
.expect("positive duration after epoch")
pub fn millis_since_unix_epoch() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("time is valid")
.as_millis() as u64
}
@@ -18,11 +18,3 @@ 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()
}
-1
View File
@@ -9,7 +9,6 @@ pub struct Cork {
}
impl Cork {
#[inline]
pub(super) fn new(db: &Arc<Engine>, flush: bool, sync: bool) -> Self {
db.cork();
Self {
-3
View File
@@ -19,15 +19,12 @@ 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) }
}
-2
View File
@@ -121,7 +121,6 @@ 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) {
@@ -243,7 +242,6 @@ impl Engine {
}
impl Drop for Engine {
#[cold]
fn drop(&mut self) {
const BLOCKING: bool = true;
-2
View File
@@ -17,11 +17,9 @@ 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 }
}
-1
View File
@@ -199,7 +199,6 @@ 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() }
}
-1
View File
@@ -91,7 +91,6 @@ pub const MAPS: &[&str] = &[
"userid_presenceid",
"userid_selfsigningkeyid",
"userid_usersigningkeyid",
"openidtoken_expiresatuserid",
"userroomid_highlightcount",
"userroomid_invitestate",
"userroomid_joined",
+8 -1
View File
@@ -11,19 +11,21 @@ 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() }
}
@@ -32,6 +34,7 @@ impl From<KeyValPair<'_>> for OwnedKeyVal {
}
impl From<OwnedKeyVal> for OwnedKeyValPair {
#[inline]
fn from(val: OwnedKeyVal) -> Self { val.to_tuple() }
}
@@ -40,18 +43,22 @@ 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) }
}
-1
View File
@@ -4,7 +4,6 @@ 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
+7 -10
View File
@@ -2,8 +2,9 @@ mod data;
use std::{collections::HashMap, sync::Arc};
use conduit::Result;
use conduit::{Result, Server};
use data::Data;
use database::Database;
use ruma::{
events::{AnyEphemeralRoomEvent, RoomAccountDataEventType},
serde::Raw,
@@ -14,17 +15,13 @@ pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(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)]
+8 -15
View File
@@ -4,9 +4,9 @@ mod grant;
use std::{future::Future, pin::Pin, sync::Arc};
use async_trait::async_trait;
use conduit::{error, utils::mutex_map, Error, Result};
use conduit::{error, utils::mutex_map, Error, Result, Server};
pub use create::create_admin_room;
use database::Database;
pub use grant::make_user_admin;
use loole::{Receiver, Sender};
use ruma::{
@@ -43,9 +43,8 @@ pub struct Command {
pub reply_id: Option<OwnedEventId>,
}
#[async_trait]
impl crate::Service for Service {
fn build(_args: crate::Args<'_>) -> Result<Arc<Self>> {
impl Service {
pub fn build(_server: &Arc<Server>, _db: &Arc<Database>) -> Result<Arc<Self>> {
let (sender, receiver) = loole::bounded(COMMAND_QUEUE_LIMIT);
Ok(Arc::new(Self {
sender,
@@ -57,8 +56,8 @@ impl crate::Service for Service {
}))
}
async fn start(self: Arc<Self>) -> Result<()> {
let self_ = Arc::clone(&self);
pub async fn start_handler(self: &Arc<Self>) {
let self_ = Arc::clone(self);
let handle = services().server.runtime().spawn(async move {
self_
.handler()
@@ -67,11 +66,9 @@ impl crate::Service for Service {
});
_ = self.handler_join.lock().await.insert(handle);
Ok(())
}
fn interrupt(&self) {
pub fn interrupt(&self) {
#[cfg(feature = "console")]
self.console.interrupt();
@@ -80,7 +77,7 @@ impl crate::Service for Service {
}
}
async fn stop(&self) {
pub async fn close(&self) {
self.interrupt();
#[cfg(feature = "console")]
@@ -93,10 +90,6 @@ impl crate::Service for 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;
+7 -14
View File
@@ -2,8 +2,9 @@ mod data;
use std::{collections::BTreeMap, sync::Arc};
use conduit::Result;
use conduit::{Result, Server};
use data::Data;
use database::Database;
use futures_util::Future;
use regex::RegexSet;
use ruma::{
@@ -23,7 +24,6 @@ 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,7 +39,6 @@ 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 {
@@ -57,7 +56,6 @@ 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()
@@ -121,10 +119,10 @@ pub struct Service {
registration_info: RwLock<BTreeMap<String, RegistrationInfo>>,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
let mut registration_info = BTreeMap::new();
let db = Data::new(args.db);
let db = Data::new(db);
// Inserting registrations into cache
for appservice in iter_ids(&db)? {
registration_info.insert(
@@ -136,17 +134,12 @@ impl crate::Service for Service {
);
}
Ok(Arc::new(Self {
Ok(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
+37 -14
View File
@@ -57,7 +57,6 @@ 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!(
@@ -99,7 +98,6 @@ 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())?;
@@ -208,6 +206,43 @@ 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(
|| {
@@ -240,16 +275,8 @@ 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>> {
@@ -313,18 +340,14 @@ 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() }
}
+31 -34
View File
@@ -50,10 +50,7 @@ pub(crate) async fn migrations(db: &Arc<Database>, config: &Config) -> Result<()
}
async fn fresh(db: &Arc<Database>, config: &Config) -> Result<()> {
services()
.globals
.db
.bump_database_version(DATABASE_VERSION)?;
services().globals.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", &[])?;
@@ -71,57 +68,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.db.database_version()? < 1 {
if services().globals.database_version()? < 1 {
db_lt_1(db, config).await?;
}
if services().globals.db.database_version()? < 2 {
if services().globals.database_version()? < 2 {
db_lt_2(db, config).await?;
}
if services().globals.db.database_version()? < 3 {
if services().globals.database_version()? < 3 {
db_lt_3(db, config).await?;
}
if services().globals.db.database_version()? < 4 {
if services().globals.database_version()? < 4 {
db_lt_4(db, config).await?;
}
if services().globals.db.database_version()? < 5 {
if services().globals.database_version()? < 5 {
db_lt_5(db, config).await?;
}
if services().globals.db.database_version()? < 6 {
if services().globals.database_version()? < 6 {
db_lt_6(db, config).await?;
}
if services().globals.db.database_version()? < 7 {
if services().globals.database_version()? < 7 {
db_lt_7(db, config).await?;
}
if services().globals.db.database_version()? < 8 {
if services().globals.database_version()? < 8 {
db_lt_8(db, config).await?;
}
if services().globals.db.database_version()? < 9 {
if services().globals.database_version()? < 9 {
db_lt_9(db, config).await?;
}
if services().globals.db.database_version()? < 10 {
if services().globals.database_version()? < 10 {
db_lt_10(db, config).await?;
}
if services().globals.db.database_version()? < 11 {
if services().globals.database_version()? < 11 {
db_lt_11(db, config).await?;
}
if services().globals.db.database_version()? < 12 {
if services().globals.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.db.database_version()? < 13 {
if services().globals.database_version()? < 13 {
db_lt_13(db, config).await?;
}
@@ -146,10 +143,10 @@ async fn migrate(db: &Arc<Database>, config: &Config) -> Result<()> {
}
assert_eq!(
services().globals.db.database_version().unwrap(),
services().globals.database_version().unwrap(),
DATABASE_VERSION,
"Failed asserting local database version {} is equal to known latest conduwuit database version {}",
services().globals.db.database_version().unwrap(),
services().globals.database_version().unwrap(),
DATABASE_VERSION,
);
@@ -228,7 +225,7 @@ async fn db_lt_1(db: &Arc<Database>, _config: &Config) -> Result<()> {
serverroomids.insert(&serverroomid, &[])?;
}
services().globals.db.bump_database_version(1)?;
services().globals.bump_database_version(1)?;
info!("Migration: 0 -> 1 finished");
Ok(())
}
@@ -245,7 +242,7 @@ async fn db_lt_2(db: &Arc<Database>, _config: &Config) -> Result<()> {
}
}
services().globals.db.bump_database_version(2)?;
services().globals.bump_database_version(2)?;
info!("Migration: 1 -> 2 finished");
Ok(())
}
@@ -265,7 +262,7 @@ async fn db_lt_3(db: &Arc<Database>, _config: &Config) -> Result<()> {
mediaid_file.insert(&key, &[])?;
}
services().globals.db.bump_database_version(3)?;
services().globals.bump_database_version(3)?;
info!("Migration: 2 -> 3 finished");
Ok(())
}
@@ -288,7 +285,7 @@ async fn db_lt_4(_db: &Arc<Database>, config: &Config) -> Result<()> {
}
}
services().globals.db.bump_database_version(4)?;
services().globals.bump_database_version(4)?;
info!("Migration: 3 -> 4 finished");
Ok(())
}
@@ -312,7 +309,7 @@ async fn db_lt_5(db: &Arc<Database>, _config: &Config) -> Result<()> {
roomusertype_roomuserdataid.insert(&key, &roomuserdataid)?;
}
services().globals.db.bump_database_version(5)?;
services().globals.bump_database_version(5)?;
info!("Migration: 4 -> 5 finished");
Ok(())
}
@@ -326,7 +323,7 @@ async fn db_lt_6(db: &Arc<Database>, _config: &Config) -> Result<()> {
services().rooms.state_cache.update_joined_count(room_id)?;
}
services().globals.db.bump_database_version(6)?;
services().globals.bump_database_version(6)?;
info!("Migration: 5 -> 6 finished");
Ok(())
}
@@ -451,7 +448,7 @@ async fn db_lt_7(db: &Arc<Database>, _config: &Config) -> Result<()> {
)?;
}
services().globals.db.bump_database_version(7)?;
services().globals.bump_database_version(7)?;
info!("Migration: 6 -> 7 finished");
Ok(())
}
@@ -517,7 +514,7 @@ async fn db_lt_8(db: &Arc<Database>, _config: &Config) -> Result<()> {
eventid_pduid.insert_batch(batch2.iter().map(database::KeyVal::from))?;
services().globals.db.bump_database_version(8)?;
services().globals.bump_database_version(8)?;
info!("Migration: 7 -> 8 finished");
Ok(())
}
@@ -574,7 +571,7 @@ async fn db_lt_9(db: &Arc<Database>, _config: &Config) -> Result<()> {
tokenids.remove(&key)?;
}
services().globals.db.bump_database_version(9)?;
services().globals.bump_database_version(9)?;
info!("Migration: 8 -> 9 finished");
Ok(())
}
@@ -593,7 +590,7 @@ async fn db_lt_10(db: &Arc<Database>, _config: &Config) -> Result<()> {
services().users.mark_device_key_update(&user_id)?;
}
services().globals.db.bump_database_version(10)?;
services().globals.bump_database_version(10)?;
info!("Migration: 9 -> 10 finished");
Ok(())
}
@@ -604,7 +601,7 @@ async fn db_lt_11(_db: &Arc<Database>, _config: &Config) -> Result<()> {
//let userdevicesessionid_uiaarequest = &db["userdevicesessionid_uiaarequest"];
//userdevicesessionid_uiaarequest.clear()?;
services().globals.db.bump_database_version(11)?;
services().globals.bump_database_version(11)?;
info!("Migration: 10 -> 11 finished");
Ok(())
}
@@ -672,7 +669,7 @@ async fn db_lt_12(_db: &Arc<Database>, config: &Config) -> Result<()> {
)?;
}
services().globals.db.bump_database_version(12)?;
services().globals.bump_database_version(12)?;
info!("Migration: 11 -> 12 finished");
Ok(())
}
@@ -709,7 +706,7 @@ async fn db_lt_13(_db: &Arc<Database>, config: &Config) -> Result<()> {
)?;
}
services().globals.db.bump_database_version(13)?;
services().globals.bump_database_version(13)?;
info!("Migration: 12 -> 13 finished");
Ok(())
}
@@ -739,8 +736,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.db.database_version()? == 14 && DATABASE_VERSION == 13 {
services().globals.db.bump_database_version(13)?;
if services().globals.database_version()? == 14 && DATABASE_VERSION == 13 {
services().globals.bump_database_version(13)?;
}
db["global"].insert(b"feat_sha256_media", &[])?;
+37 -63
View File
@@ -2,27 +2,34 @@ mod client;
mod data;
pub(super) mod emerg_access;
pub(super) mod migrations;
pub(crate) mod resolver;
mod resolver;
pub(super) mod updates;
use std::{
collections::{BTreeMap, HashMap},
fmt::Write,
sync::{Arc, RwLock},
sync::Arc,
time::Instant,
};
use conduit::{error, trace, utils::MutexMap, Config, Result};
use conduit::{error, trace, utils::MutexMap, Config, Result, Server};
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::VerifyKey},
api::{
client::discovery::discover_support::ContactRole,
federation::discovery::{ServerSigningKeys, VerifyKey},
},
serde::Base64,
DeviceId, OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId,
RoomAliasId, RoomVersionId, ServerName, UserId,
};
use tokio::{sync::Mutex, task::JoinHandle};
use tokio::{
sync::{Mutex, RwLock},
task::JoinHandle,
};
use url::Url;
use crate::services;
@@ -53,10 +60,10 @@ pub struct Service {
pub admin_alias: OwnedRoomAliasId,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &args.server.config;
let db = Data::new(args.db);
impl Service {
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
let config = &server.config;
let db = Data::new(db);
let keypair = db.load_keypair();
let keypair = match keypair {
@@ -127,59 +134,9 @@ impl crate::Service for Service {
s.config.default_room_version = crate::config::default_default_room_version();
};
Ok(Arc::new(s))
Ok(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 }
@@ -227,7 +184,6 @@ 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 }
@@ -238,6 +194,8 @@ 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 }
@@ -315,6 +273,19 @@ 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>> {
@@ -333,11 +304,14 @@ 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) {
+13 -31
View File
@@ -1,37 +1,36 @@
use std::{
collections::HashMap,
fmt::Write,
future, iter,
net::{IpAddr, SocketAddr},
sync::{Arc, RwLock},
time::Duration,
};
use conduit::{error, Config, Error, Result};
use conduit::{error, Config, Error};
use hickory_resolver::TokioAsyncResolver;
use reqwest::dns::{Addrs, Name, Resolve, Resolving};
use ruma::OwnedServerName;
use crate::sending::{CachedDest, CachedOverride};
use crate::sending::FedDest;
type WellKnownMap = HashMap<OwnedServerName, CachedDest>;
type TlsNameMap = HashMap<String, CachedOverride>;
type WellKnownMap = HashMap<OwnedServerName, (FedDest, String)>;
type TlsNameMap = HashMap<String, (Vec<IpAddr>, u16)>;
pub struct Resolver {
pub destinations: Arc<RwLock<WellKnownMap>>, // actual_destination, host
pub overrides: Arc<RwLock<TlsNameMap>>,
pub(crate) resolver: Arc<TokioAsyncResolver>,
pub(crate) hooked: Arc<Hooked>,
pub resolver: Arc<TokioAsyncResolver>,
pub hooked: Arc<Hooked>,
}
pub(crate) struct Hooked {
overrides: Arc<RwLock<TlsNameMap>>,
resolver: Arc<TokioAsyncResolver>,
pub struct Hooked {
pub overrides: Arc<RwLock<TlsNameMap>>,
pub resolver: Arc<TokioAsyncResolver>,
}
impl Resolver {
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
pub(super) fn new(config: &Config) -> Self {
pub 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}");
@@ -93,22 +92,6 @@ 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 {
@@ -117,16 +100,15 @@ impl Resolve for Resolver {
impl Resolve for Hooked {
fn resolve(&self, name: Name) -> Resolving {
let cached = self
let addr_port = self
.overrides
.read()
.expect("locked for reading")
.get(name.as_str())
.filter(|cached| cached.valid())
.cloned();
if let Some(cached) = cached {
cached_to_reqwest(&cached.ips, cached.port)
if let Some((addr, port)) = addr_port {
cached_to_reqwest(&addr, port)
} else {
resolve_to_reqwest(self.resolver.clone(), name)
}
+7 -10
View File
@@ -2,8 +2,9 @@ mod data;
use std::{collections::BTreeMap, sync::Arc};
use conduit::Result;
use conduit::{Result, Server};
use data::Data;
use database::Database;
use ruma::{
api::client::backup::{BackupAlgorithm, KeyBackupData, RoomKeyBackup},
serde::Raw,
@@ -14,17 +15,13 @@ pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(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)
}
-1
View File
@@ -148,7 +148,6 @@ 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(
+7 -10
View File
@@ -6,6 +6,7 @@ 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;
@@ -47,19 +48,15 @@ pub struct Service {
pub url_preview_mutex: RwLock<HashMap<String, Arc<Mutex<()>>>>,
}
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),
impl Service {
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
server: server.clone(),
db: Data::new(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>,
+4 -7
View File
@@ -1,6 +1,4 @@
#![allow(refining_impl_trait)]
mod service;
pub mod pdu;
pub mod services;
pub mod account_data;
@@ -22,13 +20,12 @@ 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, Result, Server};
pub use conduit::{pdu, PduBuilder, PduCount, PduEvent};
pub(crate) use conduit::{config, debug_error, debug_info, debug_warn, utils, Config, Error, PduCount, Result, Server};
use database::Database;
pub(crate) use service::{Args, Service};
pub use crate::{
globals::{server_is_ours, user_is_local},
pdu::PduEvent,
services::Services,
};
@@ -40,7 +37,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)?);
let s = Box::new(Services::build(server.clone(), d.clone()).await?);
_ = SERVICES.write().expect("write locked").insert(Box::leak(s));
Ok(())
+49 -6
View File
@@ -1,10 +1,6 @@
mod builder;
mod count;
use std::{cmp::Ordering, collections::BTreeMap, sync::Arc};
pub use builder::PduBuilder;
pub use count::PduCount;
use conduit::{warn, Error};
use ruma::{
canonical_json::redact_content_in_place,
events::{
@@ -23,7 +19,7 @@ use serde_json::{
value::{to_raw_value, RawValue as RawJsonValue},
};
use crate::{warn, Error};
use crate::services;
#[derive(Deserialize)]
struct ExtractRedactedBecause {
@@ -340,6 +336,42 @@ 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()));
@@ -406,3 +438,14 @@ 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>>,
}
+10 -21
View File
@@ -2,9 +2,9 @@ mod data;
use std::{sync::Arc, time::Duration};
use async_trait::async_trait;
use conduit::{debug, error, utils, Error, Result};
use conduit::{debug, error, utils, Error, Result, Server};
use data::Data;
use database::Database;
use futures_util::{stream::FuturesUnordered, StreamExt};
use ruma::{
events::presence::{PresenceEvent, PresenceEventContent},
@@ -81,13 +81,12 @@ pub struct Service {
timeout_remote_users: bool,
}
#[async_trait]
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &args.server.config;
impl Service {
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Arc<Self>> {
let config = &server.config;
let (timer_sender, timer_receiver) = loole::unbounded();
Ok(Arc::new(Self {
db: Data::new(args.db),
db: Data::new(db),
timer_sender,
timer_receiver: Mutex::new(timer_receiver),
handler_join: Mutex::new(None),
@@ -95,10 +94,8 @@ impl crate::Service for Service {
}))
}
async fn start(self: Arc<Self>) -> Result<()> {
//TODO: if self.globals.config.allow_local_presence { return; }
let self_ = Arc::clone(&self);
pub async fn start_handler(self: &Arc<Self>) {
let self_ = Arc::clone(self);
let handle = services().server.runtime().spawn(async move {
self_
.handler()
@@ -107,11 +104,9 @@ impl crate::Service for Service {
});
_ = self.handler_join.lock().await.insert(handle);
Ok(())
}
async fn stop(&self) {
pub async fn close(&self) {
self.interrupt();
if let Some(handler_join) = self.handler_join.lock().await.take() {
if let Err(e) = handler_join.await {
@@ -120,18 +115,13 @@ impl crate::Service for Service {
}
}
fn interrupt(&self) {
pub 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))
@@ -208,7 +198,6 @@ 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)
}
+7 -10
View File
@@ -3,8 +3,9 @@ mod data;
use std::{fmt::Debug, mem, sync::Arc};
use bytes::BytesMut;
use conduit::{debug_info, info, trace, warn, Error, Result};
use conduit::{debug_info, info, trace, warn, Error, Result, Server};
use data::Data;
use database::Database;
use ipaddress::IPAddress;
use ruma::{
api::{
@@ -29,17 +30,13 @@ pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(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)
}
+7 -10
View File
@@ -3,8 +3,9 @@ mod remote;
use std::sync::Arc;
use conduit::{Error, Result};
use conduit::{Error, Result, Server};
use data::Data;
use database::Database;
use ruma::{
api::{appservice, client::error::ErrorKind},
events::{
@@ -20,17 +21,13 @@ pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(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 {
+7 -10
View File
@@ -5,8 +5,9 @@ use std::{
sync::Arc,
};
use conduit::{debug, error, trace, warn, Error, Result};
use conduit::{debug, error, trace, warn, Error, Result, Server};
use data::Data;
use database::Database;
use ruma::{api::client::error::ErrorKind, EventId, RoomId};
use crate::services;
@@ -15,17 +16,13 @@ pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.server, args.db),
}))
impl Service {
pub fn build(server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(server, 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> {
+7 -9
View File
@@ -2,7 +2,9 @@ mod data;
use std::sync::Arc;
use conduit::Server;
use data::Data;
use database::Database;
use ruma::{OwnedRoomId, RoomId};
use crate::Result;
@@ -11,17 +13,13 @@ pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(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) }
+13 -17
View File
@@ -9,7 +9,8 @@ use std::{
time::{Duration, Instant},
};
use conduit::{debug_error, debug_info, Error, Result};
use conduit::{debug_error, debug_info, Error, Result, Server};
use database::Database;
use futures_util::Future;
pub use parse_incoming_pdu::parse_incoming_pdu;
use ruma::{
@@ -44,13 +45,9 @@ type AsyncRecursiveCanonicalJsonVec<'a> =
type AsyncRecursiveCanonicalJsonResult<'a> =
AsyncRecursiveType<'a, Result<(Arc<PduEvent>, BTreeMap<String, CanonicalJsonValue>)>>;
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 {
pub fn build(_server: &Arc<Server>, _db: &Arc<Database>) -> Result<Self> { Ok(Self {}) }
/// 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
@@ -183,7 +180,7 @@ impl Service {
.globals
.bad_event_ratelimiter
.write()
.expect("locked")
.await
.entry((*prev_id).to_owned())
{
hash_map::Entry::Vacant(e) => {
@@ -203,7 +200,7 @@ impl Service {
.globals
.roomid_federationhandletime
.write()
.expect("locked")
.await
.insert(room_id.to_owned(), (event_id.to_owned(), start_time));
let r = self
@@ -214,7 +211,7 @@ impl Service {
.globals
.roomid_federationhandletime
.write()
.expect("locked")
.await
.remove(&room_id.to_owned());
r
@@ -248,7 +245,7 @@ impl Service {
.globals
.bad_event_ratelimiter
.read()
.expect("locked")
.await
.get(prev_id)
{
// Exponential backoff
@@ -277,7 +274,7 @@ impl Service {
.globals
.roomid_federationhandletime
.write()
.expect("locked")
.await
.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)
@@ -287,7 +284,7 @@ impl Service {
.globals
.roomid_federationhandletime
.write()
.expect("locked")
.await
.remove(&room_id.to_owned());
debug!(
@@ -1046,7 +1043,7 @@ impl Service {
.globals
.bad_event_ratelimiter
.write()
.expect("locked")
.await
.entry(id)
{
hash_map::Entry::Vacant(e) => {
@@ -1079,7 +1076,7 @@ impl Service {
.globals
.bad_event_ratelimiter
.read()
.expect("locked")
.await
.get(&*next_id)
{
// Exponential backoff
@@ -1187,7 +1184,7 @@ impl Service {
.globals
.bad_event_ratelimiter
.read()
.expect("locked")
.await
.get(&**next_id)
{
// Exponential backoff
@@ -1381,7 +1378,6 @@ 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,7 +201,6 @@ 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))
@@ -250,7 +249,6 @@ 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))
@@ -394,7 +392,7 @@ impl super::Service {
}) {
debug!("Got signing keys: {:?}", server_keys);
for k in server_keys {
services().globals.db.add_signing_key(origin, k.clone())?;
services().globals.add_signing_key(origin, k.clone())?;
result.extend(
k.verify_keys
.into_iter()
@@ -423,7 +421,6 @@ impl super::Service {
{
services()
.globals
.db
.add_signing_key(origin, server_key.clone())?;
result.extend(
@@ -456,7 +453,6 @@ impl super::Service {
{
services()
.globals
.db
.add_signing_key(origin, server_key.clone())?;
result.extend(
@@ -503,7 +499,7 @@ impl super::Service {
}) {
debug!("Got signing keys: {:?}", server_keys);
for k in server_keys {
services().globals.db.add_signing_key(origin, k.clone())?;
services().globals.add_signing_key(origin, k.clone())?;
result.extend(
k.verify_keys
.into_iter()
+13 -24
View File
@@ -2,12 +2,14 @@ mod data;
use std::{
collections::{HashMap, HashSet},
fmt::Write,
sync::{Arc, Mutex},
sync::Arc,
};
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};
@@ -18,27 +20,14 @@ pub struct Service {
pub lazy_load_waiting: Mutex<HashMap<(OwnedUserId, OwnedDeviceId, OwnedRoomId, PduCount), HashSet<OwnedUserId>>>,
}
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 {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
lazy_load_waiting: Mutex::new(HashMap::new()),
})
}
#[tracing::instrument(skip(self))]
pub fn lazy_load_was_sent_before(
&self, user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, ll_user: &UserId,
@@ -54,7 +43,7 @@ impl Service {
) {
self.lazy_load_waiting
.lock()
.expect("locked")
.await
.insert((user_id.to_owned(), device_id.to_owned(), room_id.to_owned(), count), lazy_load);
}
@@ -62,7 +51,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().expect("locked").remove(&(
if let Some(user_ids) = self.lazy_load_waiting.lock().await.remove(&(
user_id.to_owned(),
device_id.to_owned(),
room_id.to_owned(),
-4
View File
@@ -48,12 +48,10 @@ 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(), &[])?;
@@ -64,12 +62,10 @@ 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(), &[])?;
+8 -16
View File
@@ -2,47 +2,39 @@ mod data;
use std::sync::Arc;
use conduit::Result;
use conduit::{Result, Server};
use data::Data;
use database::Database;
use ruma::{OwnedRoomId, RoomId};
pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(db),
})
}
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
/// Checks if a room exists.
#[inline]
#[tracing::instrument(skip(self))]
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()
+20 -22
View File
@@ -19,27 +19,25 @@ pub mod timeline;
pub mod typing;
pub mod user;
use std::sync::Arc;
pub struct 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>,
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,
}
+7 -10
View File
@@ -2,8 +2,9 @@ mod data;
use std::sync::Arc;
use conduit::Result;
use conduit::{Result, Server};
use data::Data;
use database::Database;
use ruma::{CanonicalJsonObject, EventId};
use crate::PduEvent;
@@ -12,17 +13,13 @@ pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(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)
+7 -10
View File
@@ -2,8 +2,9 @@ mod data;
use std::sync::Arc;
use conduit::Result;
use conduit::{Result, Server};
use data::Data;
use database::Database;
use ruma::{
api::{client::relations::get_relating_events, Direction},
events::{relation::RelationType, TimelineEventType},
@@ -27,17 +28,13 @@ struct ExtractRelatesToEventId {
relates_to: ExtractRelType,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(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) {
+7 -10
View File
@@ -2,8 +2,9 @@ mod data;
use std::sync::Arc;
use conduit::Result;
use conduit::{Result, Server};
use data::Data;
use database::Database;
use ruma::{events::receipt::ReceiptEvent, serde::Raw, OwnedUserId, RoomId, UserId};
use crate::services;
@@ -12,17 +13,13 @@ pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(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)?;
+7 -10
View File
@@ -2,25 +2,22 @@ mod data;
use std::sync::Arc;
use conduit::Result;
use conduit::{Result, Server};
use data::Data;
use database::Database;
use ruma::RoomId;
pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(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)
+7 -10
View File
@@ -2,25 +2,22 @@ mod data;
use std::sync::Arc;
use conduit::Result;
use conduit::{Result, Server};
use data::Data;
use database::Database;
use ruma::{events::StateEventType, EventId, RoomId};
pub struct Service {
db: Data,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
db: Data::new(args.db),
}))
impl Service {
pub fn build(_server: &Arc<Server>, db: &Arc<Database>) -> Result<Self> {
Ok(Self {
db: Data::new(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