Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot] 39d6f5bac6 Update opentelemetry-rust monorepo 2024-07-15 19:18:11 +00:00
40 changed files with 550 additions and 670 deletions
+8 -11
View File
@@ -38,11 +38,8 @@ env:
# Custom nix binary cache if fork is being used
ATTIC_ENDPOINT: ${{ vars.ATTIC_ENDPOINT }}
ATTIC_PUBLIC_KEY: ${{ vars.ATTIC_PUBLIC_KEY }}
# Get error output from nix that we can actually use, and use our binary caches for the earlier CI steps
NIX_CONFIG: |
show-trace = true
extra-substituters = https://attic.kennel.juneis.dog/conduit https://attic.kennel.juneis.dog/conduwuit https://cache.lix.systems https://conduwuit.cachix.org
extra-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
# Get error output from nix that we can actually use
NIX_CONFIG: show-trace = true
permissions:
packages: write
@@ -60,7 +57,7 @@ jobs:
uses: actions/checkout@v4
- name: Tag comparison check
if: ${{ startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') }}
if: startsWith(github.ref, 'refs/tags/v')
run: |
# Tag mismatch with latest repo tag check to prevent potential downgrades
LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
@@ -118,7 +115,7 @@ jobs:
- name: Prepare build environment
run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
nix profile install --impure --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow
nix develop .#all-features --command true
@@ -240,7 +237,7 @@ jobs:
- name: Prepare build environment
run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
nix profile install --impure --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow
nix develop .#all-features --command true
@@ -296,15 +293,15 @@ jobs:
DOCKER_ARM64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
DOCKER_AMD64: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
DOCKER_TAG: docker.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
DOCKER_BRANCH: docker.io/${{ github.repository }}:${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
DOCKER_BRANCH: docker.io/${{ github.repository }}:${{ (startsWith(github.ref, 'refs/tags/v') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
GHCR_ARM64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
GHCR_AMD64: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
GHCR_TAG: ghcr.io/${{ github.repository }}:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
GHCR_BRANCH: ghcr.io/${{ github.repository }}:${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
GHCR_BRANCH: ghcr.io/${{ github.repository }}:${{ (startsWith(github.ref, 'refs/tags/v') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
GLCR_ARM64: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-arm64v8
GLCR_AMD64: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}-amd64
GLCR_TAG: registry.gitlab.com/conduwuit/conduwuit:${{ (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}-${{ github.sha }}
GLCR_BRANCH: registry.gitlab.com/conduwuit/conduwuit:${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-rc') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
GLCR_BRANCH: registry.gitlab.com/conduwuit/conduwuit:${{ (startsWith(github.ref, 'refs/tags/v') && 'latest') || (github.head_ref != '' && format('merge-{0}-{1}', github.event.number, github.event.pull_request.user.login)) || github.ref_name }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
+3 -6
View File
@@ -21,11 +21,8 @@ env:
# Custom nix binary cache if fork is being used
ATTIC_ENDPOINT: ${{ vars.ATTIC_ENDPOINT }}
ATTIC_PUBLIC_KEY: ${{ vars.ATTIC_PUBLIC_KEY }}
# Get error output from nix that we can actually use, and use our binary caches for the earlier CI steps
NIX_CONFIG: |
show-trace = true
extra-substituters = https://attic.kennel.juneis.dog/conduit https://attic.kennel.juneis.dog/conduwuit https://cache.lix.systems https://conduwuit.cachix.org
extra-trusted-public-keys = conduit:eEKoUwlQGDdYmAI/Q/0slVlegqh/QmAvQd7HBSm21Wk= conduwuit:BbycGUgTISsltcmH0qNjFR9dbrQNYgdIAcmViSGoVTE= cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o= conduwuit.cachix.org-1:MFRm6jcnfTf0jSAbmvLfhO3KBMt4px+1xaereWXp8Xg=
# Get error output from nix that we can actually use
NIX_CONFIG: show-trace = true
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
@@ -101,7 +98,7 @@ jobs:
- name: Prepare build environment
run: |
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' > "$HOME/.direnvrc"
nix profile install --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
nix profile install --impure --inputs-from . nixpkgs#direnv nixpkgs#nix-direnv
direnv allow
nix develop --command true
Generated
+22 -13
View File
@@ -769,7 +769,7 @@ dependencies = [
"regex",
"reqwest",
"ruma",
"ruma-identifiers-validation",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0)",
"rustyline-async",
"serde",
"serde_json",
@@ -2988,7 +2988,7 @@ dependencies = [
"percent-encoding",
"rand",
"regex",
"ruma-identifiers-validation",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"ruma-macros",
"serde",
"serde_html_form",
@@ -3015,7 +3015,7 @@ dependencies = [
"pulldown-cmark",
"regex",
"ruma-common",
"ruma-identifiers-validation",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"ruma-macros",
"serde",
"serde_json",
@@ -3046,6 +3046,15 @@ dependencies = [
"thiserror",
]
[[package]]
name = "ruma-identifiers-validation"
version = "0.9.5"
source = "git+https://github.com/girlbossceo/ruwuma?rev=fd686e77950680462377c9105dfb4136dd49c7a0#fd686e77950680462377c9105dfb4136dd49c7a0"
dependencies = [
"js_int",
"thiserror",
]
[[package]]
name = "ruma-identity-service-api"
version = "0.9.0"
@@ -3065,7 +3074,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"ruma-identifiers-validation",
"ruma-identifiers-validation 0.9.5 (git+https://github.com/girlbossceo/ruwuma?rev=c51ccb2c68d2e3557eb12b1a49036531711ec0e5)",
"serde",
"syn 2.0.71",
"toml",
@@ -3129,8 +3138,8 @@ dependencies = [
[[package]]
name = "rust-librocksdb-sys"
version = "0.24.0+9.4.0"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=4056a3b0f823013fec49f6d0b3e5698856e6476a#4056a3b0f823013fec49f6d0b3e5698856e6476a"
version = "0.23.1+9.3.1"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=db1ba33c2b78ad228e2525e8902d059c24fc81a1#db1ba33c2b78ad228e2525e8902d059c24fc81a1"
dependencies = [
"bindgen",
"bzip2-sys",
@@ -3146,8 +3155,8 @@ dependencies = [
[[package]]
name = "rust-rocksdb"
version = "0.28.0"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=4056a3b0f823013fec49f6d0b3e5698856e6476a#4056a3b0f823013fec49f6d0b3e5698856e6476a"
version = "0.27.1"
source = "git+https://github.com/zaidoon1/rust-rocksdb?rev=db1ba33c2b78ad228e2525e8902d059c24fc81a1#db1ba33c2b78ad228e2525e8902d059c24fc81a1"
dependencies = [
"libc",
"rust-librocksdb-sys",
@@ -4241,7 +4250,7 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]]
name = "tracing"
version = "0.1.40"
source = "git+https://github.com/girlbossceo/tracing?rev=4d78a14a5e03f539b8c6b475aefa08bb14e4de91#4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390261f60711c2af573c#b348dca742af641c47bc390261f60711c2af573c"
dependencies = [
"log",
"pin-project-lite",
@@ -4252,7 +4261,7 @@ dependencies = [
[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "git+https://github.com/girlbossceo/tracing?rev=4d78a14a5e03f539b8c6b475aefa08bb14e4de91#4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390261f60711c2af573c#b348dca742af641c47bc390261f60711c2af573c"
dependencies = [
"proc-macro2",
"quote",
@@ -4262,7 +4271,7 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.32"
source = "git+https://github.com/girlbossceo/tracing?rev=4d78a14a5e03f539b8c6b475aefa08bb14e4de91#4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390261f60711c2af573c#b348dca742af641c47bc390261f60711c2af573c"
dependencies = [
"once_cell",
"valuable",
@@ -4282,7 +4291,7 @@ dependencies = [
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "git+https://github.com/girlbossceo/tracing?rev=4d78a14a5e03f539b8c6b475aefa08bb14e4de91#4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390261f60711c2af573c#b348dca742af641c47bc390261f60711c2af573c"
dependencies = [
"log",
"once_cell",
@@ -4310,7 +4319,7 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.18"
source = "git+https://github.com/girlbossceo/tracing?rev=4d78a14a5e03f539b8c6b475aefa08bb14e4de91#4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
source = "git+https://github.com/girlbossceo/tracing?rev=b348dca742af641c47bc390261f60711c2af573c#b348dca742af641c47bc390261f60711c2af573c"
dependencies = [
"matchers",
"nu-ansi-term",
+10 -16
View File
@@ -309,7 +309,7 @@ features = [
[workspace.dependencies.ruma-identifiers-validation]
git = "https://github.com/girlbossceo/ruwuma"
rev = "c51ccb2c68d2e3557eb12b1a49036531711ec0e5"
rev = "fd686e77950680462377c9105dfb4136dd49c7a0"
[workspace.dependencies.rust-rocksdb]
path = "deps/rust-rocksdb"
@@ -333,7 +333,7 @@ version = "0.10.8"
# optional opentelemetry, performance measurements, flamegraphs, etc for performance measurements and monitoring
[workspace.dependencies.opentelemetry]
version = "0.21.0"
version = "0.24.0"
[workspace.dependencies.tracing-flame]
version = "0.2.0"
@@ -342,11 +342,11 @@ version = "0.2.0"
version = "0.22.0"
[workspace.dependencies.opentelemetry_sdk]
version = "0.21.2"
version = "0.24.0"
features = ["rt-tokio"]
[workspace.dependencies.opentelemetry-jaeger]
version = "0.20.0"
version = "0.22.0"
features = ["rt-tokio"]
# optional sentry metrics for crash/panic reporting
@@ -405,8 +405,8 @@ features = [
]
[workspace.dependencies.rustyline-async]
version = "0.4.2"
default-features = false
git = "https://github.com/girlbossceo/rustyline-async"
rev = "de26100b0db03e419a3d8e1dd26895d170d1fe50"
[workspace.dependencies.termimad]
version = "0.29.4"
@@ -425,16 +425,16 @@ version = "0.1"
# https://github.com/girlbossceo/tracing/commit/b348dca742af641c47bc390261f60711c2af573c
[patch.crates-io.tracing-subscriber]
git = "https://github.com/girlbossceo/tracing"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
rev = "b348dca742af641c47bc390261f60711c2af573c"
[patch.crates-io.tracing]
git = "https://github.com/girlbossceo/tracing"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
rev = "b348dca742af641c47bc390261f60711c2af573c"
[patch.crates-io.tracing-core]
git = "https://github.com/girlbossceo/tracing"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
rev = "b348dca742af641c47bc390261f60711c2af573c"
[patch.crates-io.tracing-log]
git = "https://github.com/girlbossceo/tracing"
rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
rev = "b348dca742af641c47bc390261f60711c2af573c"
# fixes hyper graceful shutdowns [https://github.com/programatik29/axum-server/issues/114]
# https://github.com/girlbossceo/axum-server/commit/8e3368d899079818934e61cc9c839abcbbcada8a
@@ -442,12 +442,6 @@ rev = "4d78a14a5e03f539b8c6b475aefa08bb14e4de91"
git = "https://github.com/girlbossceo/axum-server"
rev = "8e3368d899079818934e61cc9c839abcbbcada8a"
# adds a tab completion callback: https://github.com/girlbossceo/rustyline-async/commit/de26100b0db03e419a3d8e1dd26895d170d1fe50
# adds event for CTRL+\: https://github.com/girlbossceo/rustyline-async/commit/67d8c49aeac03a5ef4e818f663eaa94dd7bf339b
[patch.crates-io.rustyline-async]
git = "https://github.com/girlbossceo/rustyline-async"
rev = "de26100b0db03e419a3d8e1dd26895d170d1fe50"
#
# Our crates
#
+1 -4
View File
@@ -421,11 +421,8 @@ allow_profile_lookup_federation_requests = true
# Set this to any float value to multiply conduwuit's in-memory LRU caches with.
# May be useful if you have significant memory to spare to increase performance.
#
# This was previously called `conduit_cache_capacity_modifier`
#
# Defaults to 1.0.
#cache_capacity_modifier = 1.0
#conduit_cache_capacity_modifier = 1.0
# Set this to any float value in megabytes for conduwuit to tell the database engine that this much memory is available for database-related caches.
# May be useful if you have significant memory to spare to increase performance.
+1 -1
View File
@@ -27,7 +27,7 @@ malloc-usable-size = ["rust-rocksdb/malloc-usable-size"]
[dependencies.rust-rocksdb]
git = "https://github.com/zaidoon1/rust-rocksdb"
rev = "4056a3b0f823013fec49f6d0b3e5698856e6476a"
rev = "db1ba33c2b78ad228e2525e8902d059c24fc81a1"
#branch = "master"
default-features = false
+5 -3
View File
@@ -23,7 +23,7 @@ Otherwise, follow standard Rust project build guides (installing git and cloning
While conduwuit can run as any user it is better to use dedicated users for different services. This also allows
you to make sure that the file permissions are correctly set up.
In Debian or Fedora/RHEL, you can use this command to create a conduwuit user:
In Debian or RHEL, you can use this command to create a conduwuit user:
```bash
sudo adduser --system conduwuit --group --disabled-login --no-create-home
@@ -53,11 +53,13 @@ RocksDB is the only supported database backend.
## Setting the correct file permissions
If you are using a dedicated user for conduwuit, you will need to allow it to read the config. To do that you can run this:
If you are using a dedicated user for conduwuit, you will need to allow it to read the config. To do that you can run this command on
Debian or RHEL:
```bash
sudo chown -R root:root /etc/conduwuit
sudo chmod -R 755 /etc/conduwuit
sudo chmod 755 /etc/conduwuit
```
If you use the default database path you also need to run this:
+2 -6
View File
@@ -184,10 +184,6 @@ cargo test \
name = "nix-default"
group = "tests"
script = """
env DIRENV_DEVSHELL=dynamic \
direnv exec . \
bin/nix-build-and-cache just .#default
env DIRENV_DEVSHELL=dynamic \
direnv exec . \
nix run -L .#default -- --help
bin/nix-build-and-cache just .#default
nix run -L .#default -- --help
"""
Generated
+25 -25
View File
@@ -9,11 +9,11 @@
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1720542474,
"narHash": "sha256-aKjJ/4l2I9+wNGTaOGRsuS3M1+IoTibqgEMPDikXm04=",
"lastModified": 1717279440,
"narHash": "sha256-kH04ReTjxOpQumgWnqy40vvQLSnLGxWP6RF3nq5Esrk=",
"owner": "zhaofengli",
"repo": "attic",
"rev": "6139576a3ce6bb992e0f6c3022528ec233e45f00",
"rev": "717cc95983cdc357bc347d70be20ced21f935843",
"type": "github"
},
"original": {
@@ -81,11 +81,11 @@
"complement": {
"flake": false,
"locked": {
"lastModified": 1720637557,
"narHash": "sha256-oZz6nCmFmdJZpC+K1iOG2KkzTI6rlAmndxANPDVU7X0=",
"lastModified": 1719903368,
"narHash": "sha256-PPzgxM4Bir+Zh9FUV/v+RBxEYeJxYVmi/BYo3uqt268=",
"owner": "matrix-org",
"repo": "complement",
"rev": "0d14432e010482ea9e13a6f7c47c1533c0c9d62f",
"rev": "bc97f1ddc1cd7485faf80c8935ee2641f3e1b57c",
"type": "github"
},
"original": {
@@ -123,11 +123,11 @@
]
},
"locked": {
"lastModified": 1720546058,
"narHash": "sha256-iU2yVaPIZm5vMGdlT0+57vdB/aPq/V5oZFBRwYw+HBM=",
"lastModified": 1720226507,
"narHash": "sha256-yHVvNsgrpyNTXZBEokL8uyB2J6gB1wEx0KOJzoeZi1A=",
"owner": "ipetkov",
"repo": "crane",
"rev": "2d83156f23c43598cf44e152c33a59d3892f8b29",
"rev": "0aed560c5c0a61c9385bddff471a13036203e11c",
"type": "github"
},
"original": {
@@ -209,11 +209,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1720852044,
"narHash": "sha256-3NBYz8VuXuKU+8ONd9NFafCNjPEGHIZQ2Mdoam1a4mY=",
"lastModified": 1720420198,
"narHash": "sha256-OIuDb6pHDyGpo7YMFyuRzMLcHm7mRvlYOz0Ht7ps2sU=",
"owner": "nix-community",
"repo": "fenix",
"rev": "5087b12a595ee73131a944d922f24d81dae05725",
"rev": "abc0549e3560189462a7d394cc9d50af4608d103",
"type": "github"
},
"original": {
@@ -381,11 +381,11 @@
"liburing": {
"flake": false,
"locked": {
"lastModified": 1720798442,
"narHash": "sha256-gtPppAoksMLW4GuruQ36nf4EAqIA1Bs6V9Xcx8dBxrQ=",
"lastModified": 1719025212,
"narHash": "sha256-kD0yhjNStqC6uFqC1AxBwUpc/HlSFtiKrV+gwDyroDc=",
"owner": "axboe",
"repo": "liburing",
"rev": "1d674f83b7d0f07553ac44d99a401b05853d9dbe",
"rev": "7b3245583069bd481190c9da18f22e9fc8c3a805",
"type": "github"
},
"original": {
@@ -606,11 +606,11 @@
},
"nixpkgs_4": {
"locked": {
"lastModified": 1720768451,
"narHash": "sha256-EYekUHJE2gxeo2pM/zM9Wlqw1Uw2XTJXOSAO79ksc4Y=",
"lastModified": 1720418205,
"narHash": "sha256-cPJoFPXU44GlhWg4pUk9oUPqurPlCFZ11ZQPk21GTPU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7e7c39ea35c5cdd002cd4588b03a3fb9ece6fad9",
"rev": "655a58a72a6601292512670343087c2d75d859c1",
"type": "github"
},
"original": {
@@ -673,16 +673,16 @@
"rocksdb": {
"flake": false,
"locked": {
"lastModified": 1720900786,
"narHash": "sha256-Vta9Um/RRuWwZ46BjXftV06iWLm/j/9MX39emXUvSAY=",
"lastModified": 1719949653,
"narHash": "sha256-DYx7XHH2GEh17GukKhXs6laM6l+eugCmRkF0adpi9wk=",
"owner": "girlbossceo",
"repo": "rocksdb",
"rev": "911f4243e69c2e320a7a209bf1f5f3ff5f825495",
"rev": "a935c0273e1ba44eacf88ce3685a9b9831486155",
"type": "github"
},
"original": {
"owner": "girlbossceo",
"ref": "v9.4.0",
"ref": "v9.3.1",
"repo": "rocksdb",
"type": "github"
}
@@ -705,11 +705,11 @@
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1720717809,
"narHash": "sha256-6I+fm+nTLF/iaj7ffiFGlSY7POmubwUaPA/Wq0Bm53M=",
"lastModified": 1720344064,
"narHash": "sha256-STmaV9Zu74QtkGGrbr9uMhskwagfCjJqOAYapXabiuk=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "ffbc5ad993d5cd2f3b8bcf9a511165470944ab91",
"rev": "a5b21ea0aa644dffd7cf958b43f11f221d53404e",
"type": "github"
},
"original": {
+15 -58
View File
@@ -9,7 +9,8 @@
flake-utils.url = "github:numtide/flake-utils?ref=main";
nix-filter.url = "github:numtide/nix-filter?ref=main";
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
rocksdb = { url = "github:girlbossceo/rocksdb?ref=v9.4.0"; flake = false; };
# https://github.com/girlbossceo/rocksdb/commit/db6df0b185774778457dabfcbd822cb81760cade
rocksdb = { url = "github:girlbossceo/rocksdb?ref=v9.3.1"; flake = false; };
liburing = { url = "github:axboe/liburing?ref=master"; flake = false; };
};
@@ -44,34 +45,10 @@
# we have this already at https://github.com/girlbossceo/rocksdb/commit/a935c0273e1ba44eacf88ce3685a9b9831486155
# unsetting this so i don't have to revert it and make this nix exclusive
patches = [];
# no real reason to have snappy, no one uses this
cmakeFlags = pkgs.lib.subtractLists
[
# no real reason to have snappy, no one uses this
"-DWITH_SNAPPY=1"
# we dont need to use ldb or sst_dump (core_tools)
"-DWITH_CORE_TOOLS=1"
# we dont need to build rocksdb tests
"-DWITH_TESTS=1"
# we use rust-rocksdb via C interface and dont need C++ RTTI
"-DUSE_RTTI=1"
]
old.cmakeFlags
++ [
# we dont need to use ldb or sst_dump (core_tools)
"-DWITH_CORE_TOOLS=0"
# we dont need trace tools
"-DWITH_TRACE_TOOLS=0"
# we dont need to build rocksdb tests
"-DWITH_TESTS=0"
# we use rust-rocksdb via C interface and dont need C++ RTTI
"-DUSE_RTTI=0"
];
# outputs has "tools" which we dont need or use
outputs = [ "out" ];
# preInstall hooks has stuff for messing with ldb/sst_dump which we dont need or use
preInstall = "";
[ "-DWITH_SNAPPY=1" ]
old.cmakeFlags;
});
# TODO: remove once https://github.com/NixOS/nixpkgs/pull/314945 is available
liburing = pkgs.liburing.overrideAttrs (old: {
@@ -146,12 +123,8 @@
default = scopeHost.main;
all-features = scopeHost.main.override {
all_features = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
# this is non-functional on nix for some reason
disable_features = ["hardened_malloc"];
};
hmalloc = scopeHost.main.override { features = ["hardened_malloc"]; };
@@ -159,12 +132,8 @@
oci-image-all-features = scopeHost.oci-image.override {
main = scopeHost.main.override {
all_features = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
# this is non-functional on nix for some reason
disable_features = ["hardened_malloc"];
};
};
oci-image-hmalloc = scopeHost.oci-image.override {
@@ -206,12 +175,8 @@
name = "${binaryName}-all-features";
value = scopeCrossStatic.main.override {
all_features = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
# this is non-functional on nix for some reason
disable_features = ["hardened_malloc"];
};
}
@@ -235,12 +200,8 @@
value = scopeCrossStatic.oci-image.override {
main = scopeCrossStatic.main.override {
all_features = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
# this is non-functional on nix for some reason
disable_features = ["hardened_malloc"];
};
};
}
@@ -268,12 +229,8 @@
(scopeHostStatic.overrideScope (final: prev: {
main = prev.main.override {
all_features = true;
disable_features = [
# this is non-functional on nix for some reason
"hardened_malloc"
# dont include experimental features
"experimental"
];
# this is non-functional on nix for some reason
disable_features = ["hardened_malloc"];
};
}));
devShells.no-features = mkDevShell
-6
View File
@@ -13,12 +13,6 @@ lib.optionalAttrs stdenv.hostPlatform.isStatic {
lib.concatStringsSep
" "
([]
++ lib.optionals
stdenv.targetPlatform.isx86_64
[ "-C" "target-cpu=x86-64-v2" ]
++ lib.optionals
stdenv.targetPlatform.isAarch64
[ "-C" "target-cpu=cortex-a55" ] # cortex-a55 == ARMv8.2-a
# This disables PIE for static builds, which isn't great in terms
# of security. Unfortunately, my hand is forced because nixpkgs'
# `libstdc++.a` is built without `-fPIE`, which precludes us from
+2 -27
View File
@@ -71,29 +71,10 @@ buildDepsOnlyEnv =
# which breaks Darwin entirely
enableLiburing = enableLiburing;
}).overrideAttrs (old: {
# TODO: static rocksdb fails to build on darwin, also see <https://github.com/NixOS/nixpkgs/issues/320448>
# TODO: static rocksdb fails to build on darwin
# build log at <https://girlboss.ceo/~strawberry/pb/JjGH>
meta.broken = stdenv.hostPlatform.isStatic && stdenv.isDarwin;
enableLiburing = enableLiburing;
sse42Support = stdenv.targetPlatform.isx86_64;
cmakeFlags = if stdenv.targetPlatform.isx86_64
then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags
++ lib.optionals stdenv.targetPlatform.isx86_64 [
"-DPORTABLE=x86-64-v2"
"-DUSE_SSE=1"
"-DHAVE_SSE=1"
"-DHAVE_SSE42=1"
]
else if stdenv.targetPlatform.isAarch64
then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags
++ lib.optionals stdenv.targetPlatform.isAarch64 [
# cortex-a55 == ARMv8.2-a
"-DPORTABLE=armv8.2-a"
]
else old.cmakeFlags;
});
in
{
@@ -120,11 +101,7 @@ buildPackageEnv = {
# Only needed in static stdenv because these are transitive dependencies of rocksdb
CARGO_BUILD_RUSTFLAGS = buildDepsOnlyEnv.CARGO_BUILD_RUSTFLAGS
+ lib.optionalString (enableLiburing && stdenv.hostPlatform.isStatic)
" -L${lib.getLib liburing}/lib -luring"
+ lib.optionalString stdenv.targetPlatform.isx86_64
" -Ctarget-cpu=x86-64-v2"
+ lib.optionalString stdenv.targetPlatform.isAarch64
" -Ctarget-cpu=cortex-a55"; # cortex-a55 == ARMv8.2-a
" -L${lib.getLib liburing}/lib -luring";
};
@@ -149,8 +126,6 @@ commonAttrs = {
];
};
dontStrip = profile == "dev";
buildInputs = lib.optional (featureEnabled "jemalloc") rust-jemalloc-sys';
nativeBuildInputs = [
+3 -8
View File
@@ -117,12 +117,7 @@ pub(crate) async fn set_room_visibility_route(
return Err(Error::BadRequest(ErrorKind::NotFound, "Room not found"));
}
if !user_can_publish_room(sender_user, &body.room_id)? {
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"User is not allowed to publish this room",
));
}
user_can_publish_room(sender_user, &body.room_id)?;
match &body.visibility {
room::Visibility::Public => {
@@ -382,8 +377,8 @@ fn user_can_publish_room(user_id: &UserId, room_id: &RoomId) -> Result<bool> {
Ok(event.sender == user_id)
} else {
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"User is not allowed to publish this room",
ErrorKind::Unauthorized,
"You are not allowed to publish this room to the room directory",
));
}
}
+3 -6
View File
@@ -200,13 +200,12 @@ pub(crate) async fn get_content_route(
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
if let Some(FileMeta {
content,
content_type,
file,
content_disposition,
}) = services().media.get(&mxc).await?
{
let content_disposition = Some(make_content_disposition(&content_type, content_disposition, None));
let file = content.expect("content");
Ok(get_content::v3::Response {
file,
@@ -283,8 +282,8 @@ pub(crate) async fn get_content_as_filename_route(
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
if let Some(FileMeta {
content,
content_type,
file,
content_disposition,
}) = services().media.get(&mxc).await?
{
@@ -294,7 +293,6 @@ pub(crate) async fn get_content_as_filename_route(
Some(body.filename.clone()),
));
let file = content.expect("content");
Ok(get_content_as_filename::v3::Response {
file,
content_type,
@@ -373,8 +371,8 @@ pub(crate) async fn get_content_thumbnail_route(
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
if let Some(FileMeta {
content,
content_type,
file,
content_disposition,
}) = services()
.media
@@ -390,7 +388,6 @@ pub(crate) async fn get_content_thumbnail_route(
.await?
{
let content_disposition = Some(make_content_disposition(&content_type, content_disposition, None));
let file = content.expect("content");
Ok(get_content_thumbnail::v3::Response {
file,
+5 -5
View File
@@ -1,15 +1,15 @@
pub mod client;
pub mod router;
mod router;
pub mod routes;
pub mod server;
extern crate conduit_core as conduit;
extern crate conduit_service as service;
pub(crate) use conduit::{debug_info, debug_warn, pdu::PduEvent, utils, Error, Result};
pub(crate) use service::{services, user_is_local};
pub(crate) use conduit::{debug_info, debug_warn, utils, Error, Result};
pub(crate) use service::{pdu::PduEvent, services, user_is_local};
pub use crate::router::State;
pub(crate) use crate::router::{Ruma, RumaResponse};
pub(crate) use self::router::{Ruma, RumaResponse};
conduit::mod_ctor! {}
conduit::mod_dtor! {}
+8 -8
View File
@@ -10,7 +10,7 @@ use conduit::Result;
use http::Method;
use ruma::api::IncomingRequest;
use super::{Ruma, RumaResponse, State};
use super::{Ruma, RumaResponse};
pub(in super::super) trait RouterExt {
fn ruma_route<H, T>(self, handler: H) -> Self
@@ -18,7 +18,7 @@ pub(in super::super) trait RouterExt {
H: RumaHandler<T>;
}
impl RouterExt for Router<State> {
impl RouterExt for Router {
fn ruma_route<H, T>(self, handler: H) -> Self
where
H: RumaHandler<T>,
@@ -28,9 +28,9 @@ impl RouterExt for Router<State> {
}
pub(in super::super) trait RumaHandler<T> {
fn add_routes(&self, router: Router<State>) -> Router<State>;
fn add_routes(&self, router: Router) -> Router;
fn add_route(&self, router: Router<State>, path: &str) -> Router<State>;
fn add_route(&self, router: Router, path: &str) -> Router;
}
macro_rules! ruma_handler {
@@ -41,17 +41,17 @@ macro_rules! ruma_handler {
Req: IncomingRequest + Send + 'static,
Ret: IntoResponse,
Fut: Future<Output = Result<Req::OutgoingResponse, Ret>> + Send,
Fun: FnOnce($($tx,)* Ruma<Req>,) -> Fut + Clone + Send + Sync + 'static,
$( $tx: FromRequestParts<State> + Send + 'static, )*
Fun: FnOnce($($tx,)* Ruma<Req>) -> Fut + Clone + Send + Sync + 'static,
$( $tx: FromRequestParts<()> + Send + 'static, )*
{
fn add_routes(&self, router: Router<State>) -> Router<State> {
fn add_routes(&self, router: Router) -> Router {
Req::METADATA
.history
.all_paths()
.fold(router, |router, path| self.add_route(router, path))
}
fn add_route(&self, router: Router<State>, path: &str) -> Router<State> {
fn add_route(&self, router: Router, path: &str) -> Router {
let handle = self.clone();
let method = method_to_filter(&Req::METADATA.method);
let action = |$($tx,)* req| async { handle($($tx,)* req).await.map(RumaResponse) };
@@ -1,15 +1,24 @@
mod auth;
mod handler;
mod request;
mod response;
use std::{mem, ops::Deref};
use axum::{async_trait, body::Body, extract::FromRequest};
use bytes::{BufMut, BytesMut};
use conduit::{debug, err, trace, Error, Result};
use ruma::{api::IncomingRequest, CanonicalJsonValue, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId};
use conduit::{debug, debug_warn, trace, warn};
use ruma::{
api::{client::error::ErrorKind, IncomingRequest},
CanonicalJsonValue, OwnedDeviceId, OwnedServerName, OwnedUserId, UserId,
};
use super::{auth, auth::Auth, request, request::Request};
use crate::{service::appservice::RegistrationInfo, services};
use self::{auth::Auth, request::Request};
pub(super) use self::{handler::RouterExt, response::RumaResponse};
use crate::{service::appservice::RegistrationInfo, services, Error, Result};
/// Extractor for Ruma request structs
pub(crate) struct Args<T> {
pub(crate) struct Ruma<T> {
/// Request struct body
pub(crate) body: T,
@@ -35,7 +44,7 @@ pub(crate) struct Args<T> {
}
#[async_trait]
impl<T, S> FromRequest<S, Body> for Args<T>
impl<T, S> FromRequest<S, Body> for Ruma<T>
where
T: IncomingRequest,
{
@@ -56,7 +65,7 @@ where
}
}
impl<T> Deref for Args<T> {
impl<T> Deref for Ruma<T> {
type Target = T;
fn deref(&self) -> &Self::Target { &self.body }
@@ -100,14 +109,21 @@ where
let mut http_request = hyper::Request::builder()
.uri(request.parts.uri.clone())
.method(request.parts.method.clone());
*http_request.headers_mut().expect("mutable http headers") = request.parts.headers.clone();
let http_request = http_request.body(body).expect("http request body");
*http_request.headers_mut().unwrap() = request.parts.headers.clone();
let http_request = http_request.body(body).unwrap();
debug!(
"{:?} {:?} {:?}",
http_request.method(),
http_request.uri(),
http_request.headers()
);
let headers = http_request.headers();
let method = http_request.method();
let uri = http_request.uri();
debug!("{method:?} {uri:?} {headers:?}");
trace!("{method:?} {uri:?} {json_body:?}");
trace!("{:?} {:?} {:?}", http_request.method(), http_request.uri(), json_body);
let body = T::try_from_http_request(http_request, &request.path).map_err(|e| {
warn!("try_from_http_request failed: {e:?}",);
debug_warn!("JSON body: {:?}", json_body);
Error::BadRequest(ErrorKind::BadJson, "Failed to deserialize request.")
})?;
T::try_from_http_request(http_request, &request.path).map_err(|e| err!(Request(BadJson(debug_warn!("{e}")))))
Ok(body)
}
+5 -6
View File
@@ -2,11 +2,11 @@ use std::str;
use axum::{extract::Path, RequestExt, RequestPartsExt};
use bytes::Bytes;
use conduit::err;
use http::request::Parts;
use ruma::api::client::error::ErrorKind;
use serde::Deserialize;
use crate::{services, Result};
use crate::{services, Error, Result};
#[derive(Deserialize)]
pub(super) struct QueryParams {
@@ -26,15 +26,14 @@ pub(super) async fn from(request: hyper::Request<axum::body::Body>) -> Result<Re
let (mut parts, body) = limited.into_parts();
let path: Path<Vec<String>> = parts.extract().await?;
let query = parts.uri.query().unwrap_or_default();
let query =
serde_html_form::from_str(query).map_err(|e| err!(Request(Unknown("Failed to read query parameters: {e}"))))?;
let query = serde_html_form::from_str(parts.uri.query().unwrap_or_default())
.map_err(|_| Error::BadRequest(ErrorKind::Unknown, "Failed to read query parameters"))?;
let max_body_size = services().globals.config.max_request_size;
let body = axum::body::to_bytes(body, max_body_size)
.await
.map_err(|e| err!(Request(TooLarge("Request body too large: {e}"))))?;
.map_err(|_| Error::BadRequest(ErrorKind::TooLarge, "Request body too large"))?;
Ok(Request {
path,
+15 -24
View File
@@ -1,24 +1,15 @@
mod args;
mod auth;
mod handler;
mod request;
mod response;
use axum::{
response::IntoResponse,
routing::{any, get, post},
Router,
};
use conduit::{err, Server};
use conduit::{err, Error, Server};
use http::Uri;
use ruma::api::client::error::ErrorKind;
use self::handler::RouterExt;
pub(super) use self::{args::Args as Ruma, response::RumaResponse};
use crate::{client, server};
use crate::{client, router::RouterExt, server};
pub type State = &'static service::Services;
pub fn build(router: Router<State>, server: &Server) -> Router<State> {
pub fn build(router: Router, server: &Server) -> Router {
let config = &server.config;
let router = router
.ruma_route(client::get_supported_versions_route)
@@ -104,7 +95,7 @@ pub fn build(router: Router<State>, server: &Server) -> Router<State> {
.ruma_route(client::get_member_events_route)
.ruma_route(client::get_protocols_route)
.route("/_matrix/client/unstable/thirdparty/protocols",
get(client::get_protocols_route_unstable))
get(client::get_protocols_route_unstable))
.ruma_route(client::send_message_event_route)
.ruma_route(client::send_state_event_for_key_route)
.ruma_route(client::get_state_events_route)
@@ -189,15 +180,15 @@ pub fn build(router: Router<State>, server: &Server) -> Router<State> {
.ruma_route(client::get_relating_events_with_rel_type_route)
.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))
.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))
.route("/_matrix/client/r0/rooms/:room_id/initialSync", get(initial_sync))
.route("/_matrix/client/v3/rooms/:room_id/initialSync", get(initial_sync))
.route("/client/server.json", get(client::syncv3_client_server_json));
@@ -242,7 +233,7 @@ pub fn build(router: Router<State>, server: &Server) -> Router<State> {
}
async fn initial_sync(_uri: Uri) -> impl IntoResponse {
err!(Request(GuestAccessForbidden("Guest access not implemented")))
Error::BadRequest(ErrorKind::GuestAccessForbidden, "Guest access not implemented")
}
async fn federation_disabled() -> impl IntoResponse { err!(Config("allow_federation", "Federation is disabled.")) }
+59 -59
View File
@@ -1,8 +1,7 @@
use std::{collections::BTreeMap, net::IpAddr, time::Instant};
use axum::extract::State;
use axum_client_ip::InsecureClientIp;
use conduit::{debug, debug_warn, err, trace, warn, Err};
use conduit::debug_warn;
use ruma::{
api::{
client::error::ErrorKind,
@@ -19,10 +18,11 @@ use ruma::{
OwnedEventId, ServerName,
};
use tokio::sync::RwLock;
use tracing::{debug, error, trace, warn};
use crate::{
service::rooms::event_handler::parse_incoming_pdu,
services::Services,
services,
utils::{self},
Error, Result, Ruma,
};
@@ -34,23 +34,29 @@ type ResolvedMap = BTreeMap<OwnedEventId, Result<(), Error>>;
/// Push EDUs and PDUs to this server.
#[tracing::instrument(skip_all, fields(%client), name = "send")]
pub(crate) async fn send_transaction_message_route(
State(services): State<&Services>, InsecureClientIp(client): InsecureClientIp,
body: Ruma<send_transaction_message::v1::Request>,
InsecureClientIp(client): InsecureClientIp, body: Ruma<send_transaction_message::v1::Request>,
) -> Result<send_transaction_message::v1::Response> {
let origin = body.origin.as_ref().expect("server is authenticated");
if *origin != body.body.origin {
return Err!(Request(Forbidden(
"Not allowed to send transactions on behalf of other servers"
)));
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Not allowed to send transactions on behalf of other servers",
));
}
if body.pdus.len() > 50_usize {
return Err!(Request(Forbidden("Not allowed to send more than 50 PDUs in one transaction")));
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Not allowed to send more than 50 PDUs in one transaction",
));
}
if body.edus.len() > 100_usize {
return Err!(Request(Forbidden("Not allowed to send more than 100 EDUs in one transaction")));
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Not allowed to send more than 100 EDUs in one transaction",
));
}
let txn_start_time = Instant::now();
@@ -63,8 +69,8 @@ pub(crate) async fn send_transaction_message_route(
"Starting txn",
);
let resolved_map = handle_pdus(services, &client, &body, origin, &txn_start_time).await?;
handle_edus(services, &client, &body, origin).await?;
let resolved_map = handle_pdus(&client, &body, origin, &txn_start_time).await?;
handle_edus(&client, &body, origin).await?;
debug!(
pdus = ?body.pdus.len(),
@@ -84,8 +90,7 @@ pub(crate) async fn send_transaction_message_route(
}
async fn handle_pdus(
services: &Services, _client: &IpAddr, body: &Ruma<send_transaction_message::v1::Request>, origin: &ServerName,
txn_start_time: &Instant,
_client: &IpAddr, body: &Ruma<send_transaction_message::v1::Request>, origin: &ServerName, txn_start_time: &Instant,
) -> Result<ResolvedMap> {
let mut parsed_pdus = Vec::with_capacity(body.pdus.len());
for pdu in &body.pdus {
@@ -105,7 +110,7 @@ async fn handle_pdus(
// corresponding signing keys
let pub_key_map = RwLock::new(BTreeMap::new());
if !parsed_pdus.is_empty() {
services
services()
.rooms
.event_handler
.fetch_required_signing_keys(parsed_pdus.iter().map(|(_event_id, event, _room_id)| event), &pub_key_map)
@@ -121,7 +126,7 @@ async fn handle_pdus(
let mut resolved_map = BTreeMap::new();
for (event_id, value, room_id) in parsed_pdus {
let pdu_start_time = Instant::now();
let mutex_lock = services
let mutex_lock = services()
.rooms
.event_handler
.mutex_federation
@@ -129,7 +134,7 @@ async fn handle_pdus(
.await;
resolved_map.insert(
event_id.clone(),
services
services()
.rooms
.event_handler
.handle_incoming_pdu(origin, &room_id, &event_id, value, true, &pub_key_map)
@@ -157,7 +162,7 @@ async fn handle_pdus(
}
async fn handle_edus(
services: &Services, client: &IpAddr, body: &Ruma<send_transaction_message::v1::Request>, origin: &ServerName,
client: &IpAddr, body: &Ruma<send_transaction_message::v1::Request>, origin: &ServerName,
) -> Result<()> {
for edu in body
.edus
@@ -165,12 +170,12 @@ async fn handle_edus(
.filter_map(|edu| serde_json::from_str::<Edu>(edu.json().get()).ok())
{
match edu {
Edu::Presence(presence) => handle_edu_presence(services, client, origin, presence).await?,
Edu::Receipt(receipt) => handle_edu_receipt(services, client, origin, receipt).await?,
Edu::Typing(typing) => handle_edu_typing(services, client, origin, typing).await?,
Edu::DeviceListUpdate(content) => handle_edu_device_list_update(services, client, origin, content).await?,
Edu::DirectToDevice(content) => handle_edu_direct_to_device(services, client, origin, content).await?,
Edu::SigningKeyUpdate(content) => handle_edu_signing_key_update(services, client, origin, content).await?,
Edu::Presence(presence) => handle_edu_presence(client, origin, presence).await?,
Edu::Receipt(receipt) => handle_edu_receipt(client, origin, receipt).await?,
Edu::Typing(typing) => handle_edu_typing(client, origin, typing).await?,
Edu::DeviceListUpdate(content) => handle_edu_device_list_update(client, origin, content).await?,
Edu::DirectToDevice(content) => handle_edu_direct_to_device(client, origin, content).await?,
Edu::SigningKeyUpdate(content) => handle_edu_signing_key_update(client, origin, content).await?,
Edu::_Custom(ref _custom) => {
debug_warn!(?body.edus, "received custom/unknown EDU");
},
@@ -180,10 +185,8 @@ async fn handle_edus(
Ok(())
}
async fn handle_edu_presence(
services: &Services, _client: &IpAddr, origin: &ServerName, presence: PresenceContent,
) -> Result<()> {
if !services.globals.allow_incoming_presence() {
async fn handle_edu_presence(_client: &IpAddr, origin: &ServerName, presence: PresenceContent) -> Result<()> {
if !services().globals.allow_incoming_presence() {
return Ok(());
}
@@ -196,7 +199,7 @@ async fn handle_edu_presence(
continue;
}
services.presence.set_presence(
services().presence.set_presence(
&update.user_id,
&update.presence,
Some(update.currently_active),
@@ -208,15 +211,13 @@ async fn handle_edu_presence(
Ok(())
}
async fn handle_edu_receipt(
services: &Services, _client: &IpAddr, origin: &ServerName, receipt: ReceiptContent,
) -> Result<()> {
if !services.globals.allow_incoming_read_receipts() {
async fn handle_edu_receipt(_client: &IpAddr, origin: &ServerName, receipt: ReceiptContent) -> Result<()> {
if !services().globals.allow_incoming_read_receipts() {
return Ok(());
}
for (room_id, room_updates) in receipt.receipts {
if services
if services()
.rooms
.event_handler
.acl_check(origin, &room_id)
@@ -238,7 +239,7 @@ async fn handle_edu_receipt(
continue;
}
if services
if services()
.rooms
.state_cache
.room_members(&room_id)
@@ -254,7 +255,7 @@ async fn handle_edu_receipt(
room_id: room_id.clone(),
};
services
services()
.rooms
.read_receipt
.readreceipt_update(&user_id, &room_id, &event)?;
@@ -272,10 +273,8 @@ async fn handle_edu_receipt(
Ok(())
}
async fn handle_edu_typing(
services: &Services, _client: &IpAddr, origin: &ServerName, typing: TypingContent,
) -> Result<()> {
if !services.globals.config.allow_incoming_typing {
async fn handle_edu_typing(_client: &IpAddr, origin: &ServerName, typing: TypingContent) -> Result<()> {
if !services().globals.config.allow_incoming_typing {
return Ok(());
}
@@ -287,7 +286,7 @@ async fn handle_edu_typing(
return Ok(());
}
if services
if services()
.rooms
.event_handler
.acl_check(typing.user_id.server_name(), &typing.room_id)
@@ -300,26 +299,26 @@ async fn handle_edu_typing(
return Ok(());
}
if services
if services()
.rooms
.state_cache
.is_joined(&typing.user_id, &typing.room_id)?
{
if typing.typing {
let timeout = utils::millis_since_unix_epoch().saturating_add(
services
services()
.globals
.config
.typing_federation_timeout_s
.saturating_mul(1000),
);
services
services()
.rooms
.typing
.typing_add(&typing.user_id, &typing.room_id, timeout)
.await?;
} else {
services
services()
.rooms
.typing
.typing_remove(&typing.user_id, &typing.room_id)
@@ -337,7 +336,7 @@ async fn handle_edu_typing(
}
async fn handle_edu_device_list_update(
services: &Services, _client: &IpAddr, origin: &ServerName, content: DeviceListUpdateContent,
_client: &IpAddr, origin: &ServerName, content: DeviceListUpdateContent,
) -> Result<()> {
let DeviceListUpdateContent {
user_id,
@@ -352,13 +351,13 @@ async fn handle_edu_device_list_update(
return Ok(());
}
services.users.mark_device_key_update(&user_id)?;
services().users.mark_device_key_update(&user_id)?;
Ok(())
}
async fn handle_edu_direct_to_device(
services: &Services, _client: &IpAddr, origin: &ServerName, content: DirectDeviceContent,
_client: &IpAddr, origin: &ServerName, content: DirectDeviceContent,
) -> Result<()> {
let DirectDeviceContent {
sender,
@@ -376,7 +375,7 @@ async fn handle_edu_direct_to_device(
}
// Check if this is a new transaction id
if services
if services()
.transaction_ids
.existing_txnid(&sender, None, &message_id)?
.is_some()
@@ -388,27 +387,28 @@ async fn handle_edu_direct_to_device(
for (target_device_id_maybe, event) in map {
match target_device_id_maybe {
DeviceIdOrAllDevices::DeviceId(target_device_id) => {
services.users.add_to_device_event(
services().users.add_to_device_event(
&sender,
target_user_id,
target_device_id,
&ev_type.to_string(),
event
.deserialize_as()
.map_err(|e| err!(Request(InvalidParam(error!("To-Device event is invalid: {e}")))))?,
event.deserialize_as().map_err(|e| {
error!("To-Device event is invalid: {event:?} {e}");
Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid")
})?,
)?;
},
DeviceIdOrAllDevices::AllDevices => {
for target_device_id in services.users.all_device_ids(target_user_id) {
services.users.add_to_device_event(
for target_device_id in services().users.all_device_ids(target_user_id) {
services().users.add_to_device_event(
&sender,
target_user_id,
&target_device_id?,
&ev_type.to_string(),
event
.deserialize_as()
.map_err(|e| err!(Request(InvalidParam("Event is invalid: {e}"))))?,
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid"))?,
)?;
}
},
@@ -417,7 +417,7 @@ async fn handle_edu_direct_to_device(
}
// Save transaction id with empty data
services
services()
.transaction_ids
.add_txnid(&sender, None, &message_id, &[])?;
@@ -425,7 +425,7 @@ async fn handle_edu_direct_to_device(
}
async fn handle_edu_signing_key_update(
services: &Services, _client: &IpAddr, origin: &ServerName, content: SigningKeyUpdateContent,
_client: &IpAddr, origin: &ServerName, content: SigningKeyUpdateContent,
) -> Result<()> {
let SigningKeyUpdateContent {
user_id,
@@ -442,7 +442,7 @@ async fn handle_edu_signing_key_update(
}
if let Some(master_key) = master_key {
services
services()
.users
.add_cross_signing_keys(&user_id, &master_key, &self_signing_key, &None, true)?;
}
+5 -6
View File
@@ -58,8 +58,8 @@ pub struct Config {
#[serde(default = "default_pdu_cache_capacity")]
pub pdu_cache_capacity: u32,
#[serde(default = "default_cache_capacity_modifier", alias = "conduit_cache_capacity_modifier")]
pub cache_capacity_modifier: f64,
#[serde(default = "default_conduit_cache_capacity_modifier")]
pub conduit_cache_capacity_modifier: f64,
#[serde(default = "default_auth_chain_cache_capacity")]
pub auth_chain_cache_capacity: u32,
#[serde(default = "default_shorteventid_cache_capacity")]
@@ -391,9 +391,8 @@ struct ListeningAddr {
addrs: Either<IpAddr, Vec<IpAddr>>,
}
const DEPRECATED_KEYS: &[&str; 9] = &[
const DEPRECATED_KEYS: &[&str] = &[
"cache_capacity",
"conduit_cache_capacity_modifier",
"max_concurrent_requests",
"well_known_client",
"well_known_server",
@@ -485,7 +484,7 @@ impl fmt::Display for Config {
);
line("Database backups to keep", &self.database_backups_to_keep.to_string());
line("Database cache capacity (MB)", &self.db_cache_capacity_mb.to_string());
line("Cache capacity modifier", &self.cache_capacity_modifier.to_string());
line("Cache capacity modifier", &self.conduit_cache_capacity_modifier.to_string());
line("PDU cache capacity", &self.pdu_cache_capacity.to_string());
line("Auth chain cache capacity", &self.auth_chain_cache_capacity.to_string());
line("Short eventid cache capacity", &self.shorteventid_cache_capacity.to_string());
@@ -848,7 +847,7 @@ fn default_db_cache_capacity_mb() -> f64 { 256.0 }
fn default_pdu_cache_capacity() -> u32 { 150_000 }
fn default_cache_capacity_modifier() -> f64 { 1.0 }
fn default_conduit_cache_capacity_modifier() -> f64 { 1.0 }
fn default_auth_chain_cache_capacity() -> u32 { 100_000 }
+4 -9
View File
@@ -31,7 +31,6 @@
//! Err(Database(error!("problem with db: {msg}")))` logs the error at the
//! callsite and then returns the error with the same string. Caller has the
//! option of replacing `error!` with `debug_error!`.
#[macro_export]
macro_rules! Err {
($($args:tt)*) => {
@@ -50,16 +49,14 @@ macro_rules! err {
$crate::$level!($($args),*);
$crate::error::Error::Request(
::ruma::api::client::error::ErrorKind::forbidden(),
$crate::format_maybe!($($args),*),
::http::StatusCode::BAD_REQUEST
$crate::format_maybe!($($args),*)
)
}};
(Request(Forbidden($($args:expr),*))) => {
$crate::error::Error::Request(
::ruma::api::client::error::ErrorKind::forbidden(),
$crate::format_maybe!($($args),*),
::http::StatusCode::BAD_REQUEST
$crate::format_maybe!($($args),*)
)
};
@@ -67,16 +64,14 @@ macro_rules! err {
$crate::$level!($($args),*);
$crate::error::Error::Request(
::ruma::api::client::error::ErrorKind::$variant,
$crate::format_maybe!($($args),*),
::http::StatusCode::BAD_REQUEST
$crate::format_maybe!($($args),*)
)
}};
(Request($variant:ident($($args:expr),*))) => {
$crate::error::Error::Request(
::ruma::api::client::error::ErrorKind::$variant,
$crate::format_maybe!($($args),*),
::http::StatusCode::BAD_REQUEST
$crate::format_maybe!($($args),*)
)
};
+4 -5
View File
@@ -68,7 +68,7 @@ pub enum Error {
#[error("{0}: {1}")]
BadRequest(ruma::api::client::error::ErrorKind, &'static str), //TODO: remove
#[error("{0}: {1}")]
Request(ruma::api::client::error::ErrorKind, Cow<'static, str>, http::StatusCode),
Request(ruma::api::client::error::ErrorKind, Cow<'static, str>),
#[error("from {0}: {1}")]
Redaction(ruma::OwnedServerName, ruma::canonical_json::RedactionError),
#[error("Remote server {0} responded with: {1}")]
@@ -78,7 +78,7 @@ pub enum Error {
// conduwuit
#[error("Arithmetic operation failed: {0}")]
Arithmetic(Cow<'static, str>),
Arithmetic(&'static str),
#[error("There was a problem with the '{0}' directive in your configuration: {1}")]
Config(&'static str, Cow<'static, str>),
#[error("{0}")]
@@ -120,7 +120,7 @@ impl Error {
match self {
Self::Federation(_, error) => response::ruma_error_kind(error).clone(),
Self::BadRequest(kind, ..) | Self::Request(kind, ..) => kind.clone(),
Self::BadRequest(kind, _) | Self::Request(kind, _) => kind.clone(),
_ => Unknown,
}
}
@@ -128,8 +128,7 @@ impl Error {
pub fn status_code(&self) -> http::StatusCode {
match self {
Self::Federation(_, ref error) | Self::RumaError(ref error) => error.status_code,
Self::Request(ref kind, _, code) => response::status_code(kind, *code),
Self::BadRequest(ref kind, ..) => response::bad_request_code(kind),
Self::BadRequest(ref kind, _) | Self::Request(ref kind, _) => response::bad_request_code(kind),
Self::Conflict(_) => http::StatusCode::CONFLICT,
_ => http::StatusCode::INTERNAL_SERVER_ERROR,
}
+16 -38
View File
@@ -1,13 +1,7 @@
use bytes::BytesMut;
use http::StatusCode;
use http_body_util::Full;
use ruma::api::{
client::{
error::{ErrorBody, ErrorKind},
uiaa::UiaaResponse,
},
OutgoingResponse,
};
use ruma::api::{client::uiaa::UiaaResponse, OutgoingResponse};
use super::Error;
use crate::error;
@@ -31,7 +25,7 @@ impl From<Error> for UiaaResponse {
return Self::AuthResponse(uiaainfo);
}
let body = ErrorBody::Standard {
let body = ruma::api::client::error::ErrorBody::Standard {
kind: error.kind(),
message: error.message(),
};
@@ -43,33 +37,10 @@ impl From<Error> for UiaaResponse {
}
}
pub(super) fn status_code(kind: &ErrorKind, hint: StatusCode) -> StatusCode {
if hint == StatusCode::BAD_REQUEST {
bad_request_code(kind)
} else {
hint
}
}
pub(super) fn bad_request_code(kind: &ErrorKind) -> StatusCode {
use ErrorKind::*;
pub(super) fn bad_request_code(kind: &ruma::api::client::error::ErrorKind) -> StatusCode {
use ruma::api::client::error::ErrorKind::*;
match kind {
// 429
LimitExceeded {
..
} => StatusCode::TOO_MANY_REQUESTS,
// 413
TooLarge => StatusCode::PAYLOAD_TOO_LARGE,
// 405
Unrecognized => StatusCode::METHOD_NOT_ALLOWED,
// 404
NotFound => StatusCode::NOT_FOUND,
// 403
GuestAccessForbidden
| ThreepidAuthFailed
| UserDeactivated
@@ -81,20 +52,26 @@ pub(super) fn bad_request_code(kind: &ErrorKind) -> StatusCode {
..
} => StatusCode::FORBIDDEN,
// 401
UnknownToken {
..
}
| MissingToken
| Unauthorized => StatusCode::UNAUTHORIZED,
// 400
LimitExceeded {
..
} => StatusCode::TOO_MANY_REQUESTS,
TooLarge => StatusCode::PAYLOAD_TOO_LARGE,
NotFound | Unrecognized => StatusCode::NOT_FOUND,
_ => StatusCode::BAD_REQUEST,
}
}
pub(super) fn ruma_error_message(error: &ruma::api::client::error::Error) -> String {
if let ErrorBody::Standard {
if let ruma::api::client::error::ErrorBody::Standard {
message,
..
} = &error.body
@@ -105,6 +82,7 @@ pub(super) fn ruma_error_message(error: &ruma::api::client::error::Error) -> Str
format!("{error}")
}
pub(super) fn ruma_error_kind(e: &ruma::api::client::error::Error) -> &ErrorKind {
e.error_kind().unwrap_or(&ErrorKind::Unknown)
pub(super) fn ruma_error_kind(e: &ruma::api::client::error::Error) -> &ruma::api::client::error::ErrorKind {
e.error_kind()
.unwrap_or(&ruma::api::client::error::ErrorKind::Unknown)
}
+4 -4
View File
@@ -2,14 +2,14 @@ use std::{cmp, time::Duration};
pub use checked_ops::checked_ops;
use crate::{Err, Error, Result};
use crate::{Error, Result};
/// Checked arithmetic expression. Returns a Result<R, Error::Arithmetic>
#[macro_export]
macro_rules! checked {
($($input:tt)*) => {
$crate::utils::math::checked_ops!($($input)*)
.ok_or_else(|| $crate::err!(Arithmetic("operation overflowed or result invalid")))
.ok_or_else(|| $crate::Error::Arithmetic("operation overflowed or result invalid"))
}
}
@@ -21,7 +21,7 @@ macro_rules! validated {
($($input:tt)*) => {
//#[allow(clippy::arithmetic_side_effects)] {
//Some($($input)*)
// .ok_or_else(|| $crate::err!(Arithmetic("this error should never been seen")))
// .ok_or_else(|| $crate::Error::Arithmetic("this error should never been seen"))
//}
//NOTE: remove me when stmt_expr_attributes is stable
@@ -57,7 +57,7 @@ pub fn continue_exponential_backoff(min: Duration, max: Duration, elapsed: Durat
#[allow(clippy::as_conversions)]
pub fn usize_from_f64(val: f64) -> Result<usize, Error> {
if val < 0.0 {
return Err!(Arithmetic("Converting negative float to unsigned integer"));
return Err(Error::Arithmetic("Converting negative float to unsigned integer"));
}
//SAFETY: <https://doc.rust-lang.org/std/primitive.f64.html#method.to_int_unchecked>
+1 -1
View File
@@ -310,7 +310,7 @@ fn set_table_with_shared_cache(
}
fn cache_size(config: &Config, base_size: u32, entity_size: usize) -> usize {
let ents = f64::from(base_size) * config.cache_capacity_modifier;
let ents = f64::from(base_size) * config.conduit_cache_capacity_modifier;
#[allow(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
(ents as usize)
+5 -5
View File
@@ -5,7 +5,7 @@ use axum::{
Router,
};
use axum_client_ip::SecureClientIpSource;
use conduit::{error, Result, Server};
use conduit::{Result, Server};
use http::{
header::{self, HeaderName},
HeaderValue, Method, StatusCode,
@@ -149,7 +149,7 @@ fn cors_layer(_server: &Server) -> CorsLayer {
fn body_limit_layer(server: &Server) -> DefaultBodyLimit { DefaultBodyLimit::max(server.config.max_request_size) }
#[allow(clippy::needless_pass_by_value)]
#[tracing::instrument(skip_all, name = "panic")]
#[tracing::instrument(skip_all)]
fn catch_panic(err: Box<dyn Any + Send + 'static>) -> http::Response<http_body_util::Full<bytes::Bytes>> {
conduit_service::services()
.server
@@ -165,17 +165,17 @@ fn catch_panic(err: Box<dyn Any + Send + 'static>) -> http::Response<http_body_u
"Unknown internal server error occurred.".to_owned()
};
error!("{details:#}");
let body = serde_json::json!({
"errcode": "M_UNKNOWN",
"error": "M_UNKNOWN: Internal server error occurred",
"details": details,
});
})
.to_string();
http::Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.header(header::CONTENT_TYPE, "application/json")
.body(http_body_util::Full::from(body.to_string()))
.body(http_body_util::Full::from(body))
.expect("Failed to create response for our panic catcher?")
}
+23 -8
View File
@@ -4,8 +4,9 @@ use axum::{
extract::State,
response::{IntoResponse, Response},
};
use conduit::{debug, debug_error, debug_warn, defer, err, error, trace, Result, Server};
use conduit::{debug, debug_error, debug_warn, defer, error, trace, Error, Result, Server};
use http::{Method, StatusCode, Uri};
use ruma::api::client::error::{Error as RumaError, ErrorBody, ErrorKind};
#[tracing::instrument(skip_all, level = "debug")]
pub(crate) async fn spawn(
@@ -57,13 +58,33 @@ pub(crate) async fn handle(
trace!(active, finished, "leave");
}};
let uri = req.uri().clone();
let method = req.method().clone();
let uri = req.uri().clone();
let result = next.run(req).await;
handle_result(&method, &uri, result)
}
fn handle_result(method: &Method, uri: &Uri, result: Response) -> Result<Response, StatusCode> {
handle_result_log(method, uri, &result);
match result.status() {
StatusCode::METHOD_NOT_ALLOWED => handle_result_405(method, uri, &result),
_ => Ok(result),
}
}
fn handle_result_405(_method: &Method, _uri: &Uri, result: &Response) -> Result<Response, StatusCode> {
let error = Error::RumaError(RumaError {
status_code: result.status(),
body: ErrorBody::Standard {
kind: ErrorKind::Unrecognized,
message: "M_UNRECOGNIZED: Method not allowed for endpoint".to_owned(),
},
});
Ok(error.into_response())
}
fn handle_result_log(method: &Method, uri: &Uri, result: &Response) {
let status = result.status();
let reason = status.canonical_reason().unwrap_or("Unknown Reason");
let code = status.as_u16();
@@ -76,10 +97,4 @@ fn handle_result(method: &Method, uri: &Uri, result: Response) -> Result<Respons
} else {
trace!(method = ?method, uri = ?uri, "{code} {reason}");
}
if status == StatusCode::METHOD_NOT_ALLOWED {
return Ok(err!(Request(Unrecognized("Method Not Allowed"))).into_response());
}
Ok(result)
}
+8 -7
View File
@@ -2,23 +2,24 @@ use std::sync::Arc;
use axum::{response::IntoResponse, routing::get, Router};
use conduit::{Error, Server};
use http::{StatusCode, Uri};
use conduit_service as service;
use http::Uri;
use ruma::api::client::error::ErrorKind;
extern crate conduit_api as api;
extern crate conduit_service as service;
pub(crate) fn build(server: &Arc<Server>) -> Router {
let router = Router::<api::State>::new();
api::router::build(router, server)
let state = service::services();
let router = Router::new()
.route("/", get(it_works))
.fallback(not_found)
.with_state(service::services())
.with_state(state);
api::routes::build(router, server)
}
async fn not_found(_uri: Uri) -> impl IntoResponse {
Error::Request(ErrorKind::Unrecognized, "Not Found".into(), StatusCode::NOT_FOUND)
Error::BadRequest(ErrorKind::Unrecognized, "Unrecognized request")
}
async fn it_works() -> &'static str { "hewwo from conduwuit woof!" }
+2 -2
View File
@@ -127,8 +127,8 @@ async fn fini(server: &Arc<Server>, listener: UnixListener, mut tasks: JoinSet<(
debug!("Waiting for requests to finish...");
while server.metrics.requests_spawn_active.load(Ordering::Relaxed) > 0 {
tokio::select! {
task = tasks.join_next() => if task.is_none() { break; },
() = sleep(FINI_POLL_INTERVAL) => {},
_ = tasks.join_next() => {}
() = sleep(FINI_POLL_INTERVAL) => {}
}
}
+4 -4
View File
@@ -9,7 +9,7 @@ use std::{
};
use async_trait::async_trait;
use conduit::{debug, error, error::default_log, Error, Result};
use conduit::{debug, error, Error, Result};
pub use create::create_admin_room;
pub use grant::make_user_admin;
use loole::{Receiver, Sender};
@@ -239,9 +239,9 @@ async fn respond_to_room(content: RoomMessageEventContent, room_id: &RoomId, use
.build_and_append_pdu(response_pdu, user_id, room_id, &state_lock)
.await
{
handle_response_error(e, room_id, user_id, &state_lock)
.await
.unwrap_or_else(default_log);
if let Err(e) = handle_response_error(e, room_id, user_id, &state_lock).await {
error!("{e}");
}
}
}
+4 -14
View File
@@ -12,13 +12,6 @@ pub(crate) struct Data {
url_previews: Arc<Map>,
}
#[derive(Debug)]
pub(super) struct Metadata {
pub(super) content_disposition: Option<String>,
pub(super) content_type: Option<String>,
pub(super) key: Vec<u8>,
}
impl Data {
pub(super) fn new(db: &Arc<Database>) -> Self {
Self {
@@ -111,7 +104,9 @@ impl Data {
Ok(keys)
}
pub(super) fn search_file_metadata(&self, mxc: &str, width: u32, height: u32) -> Result<Metadata> {
pub(super) fn search_file_metadata(
&self, mxc: &str, width: u32, height: u32,
) -> Result<(Option<String>, Option<String>, Vec<u8>)> {
let mut prefix = mxc.as_bytes().to_vec();
prefix.push(0xFF);
prefix.extend_from_slice(&width.to_be_bytes());
@@ -146,12 +141,7 @@ impl Data {
.map_err(|_| Error::bad_database("Content Disposition in mediaid_file is invalid unicode."))?,
)
};
Ok(Metadata {
content_disposition,
content_type,
key,
})
Ok((content_disposition, content_type, key))
}
/// Gets all the media keys in our database (this includes all the metadata
+183 -33
View File
@@ -1,13 +1,13 @@
mod data;
mod tests;
mod thumbnail;
use std::{collections::HashMap, path::PathBuf, sync::Arc, time::SystemTime};
use std::{collections::HashMap, io::Cursor, num::Saturating as Sat, path::PathBuf, sync::Arc, time::SystemTime};
use async_trait::async_trait;
use base64::{engine::general_purpose, Engine as _};
use conduit::{debug, debug_error, err, error, utils, Err, Result, Server};
use data::{Data, Metadata};
use conduit::{checked, debug, debug_error, error, utils, Error, Result, Server};
use data::Data;
use image::imageops::FilterType;
use ruma::{OwnedMxcUri, OwnedUserId};
use serde::Serialize;
use tokio::{
@@ -20,9 +20,10 @@ use crate::services;
#[derive(Debug)]
pub struct FileMeta {
pub content: Option<Vec<u8>>,
pub content_type: Option<String>,
#[allow(dead_code)]
pub content_disposition: Option<String>,
pub content_type: Option<String>,
pub file: Vec<u8>,
}
#[derive(Serialize, Default)]
@@ -100,30 +101,47 @@ impl Service {
Ok(())
} else {
Err!(Database(error!(
"Failed to find any media keys for MXC {mxc:?} in our database."
)))
error!("Failed to find any media keys for MXC \"{mxc}\" in our database (MXC does not exist)");
Err(Error::bad_database(
"Failed to find any media keys for the provided MXC in our database (MXC does not exist)",
))
}
}
/// Uploads or replaces a file thumbnail.
#[allow(clippy::too_many_arguments)]
pub async fn upload_thumbnail(
&self, sender_user: Option<OwnedUserId>, mxc: &str, content_disposition: Option<&str>,
content_type: Option<&str>, width: u32, height: u32, file: &[u8],
) -> Result<()> {
let key = if let Some(user) = sender_user {
self.db
.create_file_metadata(Some(user.as_str()), mxc, width, height, content_disposition, content_type)?
} else {
self.db
.create_file_metadata(None, mxc, width, height, content_disposition, content_type)?
};
//TODO: Dangling metadata in database if creation fails
let mut f = self.create_media_file(&key).await?;
f.write_all(file).await?;
Ok(())
}
/// Downloads a file.
pub async fn get(&self, mxc: &str) -> Result<Option<FileMeta>> {
if let Ok(Metadata {
content_disposition,
content_type,
key,
}) = self.db.search_file_metadata(mxc, 0, 0)
{
let mut content = Vec::new();
if let Ok((content_disposition, content_type, key)) = self.db.search_file_metadata(mxc, 0, 0) {
let mut file = Vec::new();
let path = self.get_media_file(&key);
BufReader::new(fs::File::open(path).await?)
.read_to_end(&mut content)
.read_to_end(&mut file)
.await?;
Ok(Some(FileMeta {
content: Some(content),
content_type,
content_disposition,
content_type,
file,
}))
} else {
Ok(None)
@@ -136,16 +154,23 @@ impl Service {
let all_keys = self.db.get_all_media_keys();
let user_duration: SystemTime = match cyborgtime::parse_duration(&time) {
Err(e) => return Err!(Database(error!("Failed to parse specified time duration: {e}"))),
Ok(duration) => SystemTime::now()
.checked_sub(duration)
.ok_or(err!(Arithmetic("Duration {duration:?} is too large")))?,
Ok(duration) => {
debug!("Parsed duration: {:?}", duration);
debug!("System time now: {:?}", SystemTime::now());
SystemTime::now().checked_sub(duration).ok_or_else(|| {
Error::bad_database("Duration specified is not valid against the current system time")
})?
},
Err(e) => {
error!("Failed to parse user-specified time duration: {}", e);
return Err(Error::bad_database("Failed to parse user-specified time duration."));
},
};
let mut remote_mxcs: Vec<String> = vec![];
for key in all_keys {
debug!("Full MXC key from database: {key:?}");
debug!("Full MXC key from database: {:?}", key);
// we need to get the MXC URL from the first part of the key (the first 0xff /
// 255 push). this is all necessary because of conduit using magic keys for
@@ -154,19 +179,24 @@ impl Service {
let mxc = parts
.next()
.map(|bytes| {
utils::string_from_bytes(bytes)
.map_err(|e| err!(Database(error!("Failed to parse MXC unicode bytes from our database: {e}"))))
utils::string_from_bytes(bytes).map_err(|e| {
error!("Failed to parse MXC unicode bytes from our database: {}", e);
Error::bad_database("Failed to parse MXC unicode bytes from our database")
})
})
.transpose()?;
let Some(mxc_s) = mxc else {
return Err!(Database("Parsed MXC URL unicode bytes from database but still is None"));
return Err(Error::bad_database(
"Parsed MXC URL unicode bytes from database but still is None",
));
};
debug!("Parsed MXC key to URL: {mxc_s}");
debug!("Parsed MXC key to URL: {}", mxc_s);
let mxc = OwnedMxcUri::from(mxc_s);
if mxc.server_name() == Ok(services().globals.server_name()) {
debug!("Ignoring local media MXC: {mxc}");
debug!("Ignoring local media MXC: {}", mxc);
// ignore our own MXC URLs as this would be local media.
continue;
}
@@ -185,14 +215,14 @@ impl Service {
},
Err(err) => {
if force {
error!("Could not delete MXC path {path:?}: {err:?}. Skipping...");
error!("Could not delete MXC path {:?}: {:?}. Skipping...", path, err);
continue;
}
return Err(err.into());
},
};
debug!("File created at: {:?}", file_created_at);
debug!("File created at: {file_created_at:?}");
if file_created_at <= user_duration {
debug!("File is within user duration, pushing to list of file paths and keys to delete.");
remote_mxcs.push(mxc.to_string());
@@ -202,12 +232,15 @@ impl Service {
debug!(
"Finished going through all our media in database for eligible keys to delete, checking if these are empty"
);
if remote_mxcs.is_empty() {
return Err!(Database("Did not found any eligible MXCs to delete."));
return Err(Error::bad_database("Did not found any eligible MXCs to delete."));
}
debug!("Deleting media now in the past {user_duration:?}.");
debug!("Deleting media now in the past \"{:?}\".", user_duration);
let mut deletion_count: usize = 0;
for mxc in remote_mxcs {
debug!("Deleting MXC {mxc} from database and filesystem");
self.delete(&mxc).await?;
@@ -217,6 +250,123 @@ impl Service {
Ok(deletion_count)
}
/// Returns width, height of the thumbnail and whether it should be cropped.
/// Returns None when the server should send the original file.
pub fn thumbnail_properties(&self, width: u32, height: u32) -> Option<(u32, u32, bool)> {
match (width, height) {
(0..=32, 0..=32) => Some((32, 32, true)),
(0..=96, 0..=96) => Some((96, 96, true)),
(0..=320, 0..=240) => Some((320, 240, false)),
(0..=640, 0..=480) => Some((640, 480, false)),
(0..=800, 0..=600) => Some((800, 600, false)),
_ => None,
}
}
/// Downloads a file's thumbnail.
///
/// Here's an example on how it works:
///
/// - Client requests an image with width=567, height=567
/// - Server rounds that up to (800, 600), so it doesn't have to save too
/// many thumbnails
/// - Server rounds that up again to (958, 600) to fix the aspect ratio
/// (only for width,height>96)
/// - Server creates the thumbnail and sends it to the user
///
/// For width,height <= 96 the server uses another thumbnailing algorithm
/// which crops the image afterwards.
pub async fn get_thumbnail(&self, mxc: &str, width: u32, height: u32) -> Result<Option<FileMeta>> {
let (width, height, crop) = self
.thumbnail_properties(width, height)
.unwrap_or((0, 0, false)); // 0, 0 because that's the original file
if let Ok((content_disposition, content_type, key)) = self.db.search_file_metadata(mxc, width, height) {
// Using saved thumbnail
let mut file = Vec::new();
let path = self.get_media_file(&key);
fs::File::open(path).await?.read_to_end(&mut file).await?;
Ok(Some(FileMeta {
content_disposition,
content_type,
file: file.clone(),
}))
} else if let Ok((content_disposition, content_type, key)) = self.db.search_file_metadata(mxc, 0, 0) {
// Generate a thumbnail
let mut file = Vec::new();
let path = self.get_media_file(&key);
fs::File::open(path).await?.read_to_end(&mut file).await?;
if let Ok(image) = image::load_from_memory(&file) {
let original_width = image.width();
let original_height = image.height();
if width > original_width || height > original_height {
return Ok(Some(FileMeta {
content_disposition,
content_type,
file: file.clone(),
}));
}
let thumbnail = if crop {
image.resize_to_fill(width, height, FilterType::CatmullRom)
} else {
let (exact_width, exact_height) = {
let ratio = Sat(original_width) * Sat(height);
let nratio = Sat(width) * Sat(original_height);
let use_width = nratio <= ratio;
let intermediate = if use_width {
Sat(original_height) * Sat(checked!(width / original_width)?)
} else {
Sat(original_width) * Sat(checked!(height / original_height)?)
};
if use_width {
(width, intermediate.0)
} else {
(intermediate.0, height)
}
};
image.thumbnail_exact(exact_width, exact_height)
};
let mut thumbnail_bytes = Vec::new();
thumbnail.write_to(&mut Cursor::new(&mut thumbnail_bytes), image::ImageFormat::Png)?;
// Save thumbnail in database so we don't have to generate it again next time
let thumbnail_key = self.db.create_file_metadata(
None,
mxc,
width,
height,
content_disposition.as_deref(),
content_type.as_deref(),
)?;
let mut f = self.create_media_file(&thumbnail_key).await?;
f.write_all(&thumbnail_bytes).await?;
Ok(Some(FileMeta {
content_disposition,
content_type,
file: thumbnail_bytes.clone(),
}))
} else {
// Couldn't parse file to generate thumbnail, send original
Ok(Some(FileMeta {
content_disposition,
content_type,
file: file.clone(),
}))
}
} else {
Ok(None)
}
}
pub async fn get_url_preview(&self, url: &str) -> Option<UrlPreviewData> { self.db.get_url_preview(url) }
/// TODO: use this?
-174
View File
@@ -1,174 +0,0 @@
use std::{cmp, io::Cursor, num::Saturating as Sat};
use conduit::{checked, Result};
use image::{imageops::FilterType, DynamicImage};
use ruma::OwnedUserId;
use tokio::{
fs,
io::{AsyncReadExt, AsyncWriteExt},
};
use super::{data::Metadata, FileMeta};
impl super::Service {
/// Uploads or replaces a file thumbnail.
#[allow(clippy::too_many_arguments)]
pub async fn upload_thumbnail(
&self, sender_user: Option<OwnedUserId>, mxc: &str, content_disposition: Option<&str>,
content_type: Option<&str>, width: u32, height: u32, file: &[u8],
) -> Result<()> {
let key = if let Some(user) = sender_user {
self.db
.create_file_metadata(Some(user.as_str()), mxc, width, height, content_disposition, content_type)?
} else {
self.db
.create_file_metadata(None, mxc, width, height, content_disposition, content_type)?
};
//TODO: Dangling metadata in database if creation fails
let mut f = self.create_media_file(&key).await?;
f.write_all(file).await?;
Ok(())
}
/// Downloads a file's thumbnail.
///
/// Here's an example on how it works:
///
/// - Client requests an image with width=567, height=567
/// - Server rounds that up to (800, 600), so it doesn't have to save too
/// many thumbnails
/// - Server rounds that up again to (958, 600) to fix the aspect ratio
/// (only for width,height>96)
/// - Server creates the thumbnail and sends it to the user
///
/// For width,height <= 96 the server uses another thumbnailing algorithm
/// which crops the image afterwards.
#[tracing::instrument(skip(self), name = "thumbnail", level = "debug")]
pub async fn get_thumbnail(&self, mxc: &str, width: u32, height: u32) -> Result<Option<FileMeta>> {
// 0, 0 because that's the original file
let (width, height, crop) = thumbnail_properties(width, height).unwrap_or((0, 0, false));
if let Ok(metadata) = self.db.search_file_metadata(mxc, width, height) {
self.get_thumbnail_saved(metadata).await
} else if let Ok(metadata) = self.db.search_file_metadata(mxc, 0, 0) {
self.get_thumbnail_generate(mxc, width, height, crop, metadata)
.await
} else {
Ok(None)
}
}
/// Using saved thumbnail
#[tracing::instrument(skip(self), name = "saved", level = "debug")]
async fn get_thumbnail_saved(&self, data: Metadata) -> Result<Option<FileMeta>> {
let mut content = Vec::new();
let path = self.get_media_file(&data.key);
fs::File::open(path)
.await?
.read_to_end(&mut content)
.await?;
Ok(Some(into_filemeta(data, content)))
}
/// Generate a thumbnail
#[tracing::instrument(skip(self), name = "generate", level = "debug")]
async fn get_thumbnail_generate(
&self, mxc: &str, width: u32, height: u32, crop: bool, data: Metadata,
) -> Result<Option<FileMeta>> {
let mut content = Vec::new();
let path = self.get_media_file(&data.key);
fs::File::open(path)
.await?
.read_to_end(&mut content)
.await?;
let Ok(image) = image::load_from_memory(&content) else {
// Couldn't parse file to generate thumbnail, send original
return Ok(Some(into_filemeta(data, content)));
};
if width > image.width() || height > image.height() {
return Ok(Some(into_filemeta(data, content)));
}
let mut thumbnail_bytes = Vec::new();
let thumbnail = thumbnail_generate(&image, width, height, crop)?;
thumbnail.write_to(&mut Cursor::new(&mut thumbnail_bytes), image::ImageFormat::Png)?;
// Save thumbnail in database so we don't have to generate it again next time
let thumbnail_key = self.db.create_file_metadata(
None,
mxc,
width,
height,
data.content_disposition.as_deref(),
data.content_type.as_deref(),
)?;
let mut f = self.create_media_file(&thumbnail_key).await?;
f.write_all(&thumbnail_bytes).await?;
Ok(Some(into_filemeta(data, thumbnail_bytes)))
}
}
fn thumbnail_generate(image: &DynamicImage, width: u32, height: u32, crop: bool) -> Result<DynamicImage> {
let thumbnail = if crop {
image.resize_to_fill(width, height, FilterType::CatmullRom)
} else {
let (exact_width, exact_height) = thumbnail_dimension(image, width, height)?;
image.thumbnail_exact(exact_width, exact_height)
};
Ok(thumbnail)
}
fn thumbnail_dimension(image: &DynamicImage, width: u32, height: u32) -> Result<(u32, u32)> {
let image_width = image.width();
let image_height = image.height();
let width = cmp::min(width, image_width);
let height = cmp::min(height, image_height);
let use_width = Sat(width) * Sat(image_height) < Sat(height) * Sat(image_width);
let x = if use_width {
let dividend = (Sat(height) * Sat(image_width)).0;
checked!(dividend / image_height)?
} else {
width
};
let y = if !use_width {
let dividend = (Sat(width) * Sat(image_height)).0;
checked!(dividend / image_width)?
} else {
height
};
Ok((x, y))
}
/// Returns width, height of the thumbnail and whether it should be cropped.
/// Returns None when the server should send the original file.
fn thumbnail_properties(width: u32, height: u32) -> Option<(u32, u32, bool)> {
match (width, height) {
(0..=32, 0..=32) => Some((32, 32, true)),
(0..=96, 0..=96) => Some((96, 96, true)),
(0..=320, 0..=240) => Some((320, 240, false)),
(0..=640, 0..=480) => Some((640, 480, false)),
(0..=800, 0..=600) => Some((800, 600, false)),
_ => None,
}
}
fn into_filemeta(data: Metadata, content: Vec<u8>) -> FileMeta {
FileMeta {
content: Some(content),
content_type: data.content_type,
content_disposition: data.content_disposition,
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ impl Data {
pub(super) fn new(server: &Arc<Server>, db: &Arc<Database>) -> Self {
let config = &server.config;
let cache_size = f64::from(config.auth_chain_cache_capacity);
let cache_size = usize_from_f64(cache_size * config.cache_capacity_modifier).expect("valid cache size");
let cache_size = usize_from_f64(cache_size * config.conduit_cache_capacity_modifier).expect("valid cache size");
Self {
shorteventid_authchain: db["shorteventid_authchain"].clone(),
auth_chain_cache: Mutex::new(LruCache::new(cache_size)),
+1 -1
View File
@@ -161,7 +161,7 @@ impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &args.server.config;
let cache_size = f64::from(config.roomid_spacehierarchy_cache_capacity);
let cache_size = cache_size * config.cache_capacity_modifier;
let cache_size = cache_size * config.conduit_cache_capacity_modifier;
Ok(Arc::new(Self {
roomid_spacehierarchy_cache: Mutex::new(LruCache::new(usize_from_f64(cache_size)?)),
}))
+2 -2
View File
@@ -45,9 +45,9 @@ impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &args.server.config;
let server_visibility_cache_capacity =
f64::from(config.server_visibility_cache_capacity) * config.cache_capacity_modifier;
f64::from(config.server_visibility_cache_capacity) * config.conduit_cache_capacity_modifier;
let user_visibility_cache_capacity =
f64::from(config.user_visibility_cache_capacity) * config.cache_capacity_modifier;
f64::from(config.user_visibility_cache_capacity) * config.conduit_cache_capacity_modifier;
Ok(Arc::new(Self {
db: Data::new(args.db),
+1 -1
View File
@@ -55,7 +55,7 @@ pub struct Service {
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let config = &args.server.config;
let cache_capacity = f64::from(config.stateinfo_cache_capacity) * config.cache_capacity_modifier;
let cache_capacity = f64::from(config.stateinfo_cache_capacity) * config.conduit_cache_capacity_modifier;
Ok(Arc::new(Self {
db: Data::new(args.db),
stateinfo_cache: StdMutex::new(LruCache::new(usize_from_f64(cache_capacity)?)),
+2 -6
View File
@@ -443,9 +443,7 @@ impl crate::globals::resolver::Resolver {
impl CachedDest {
#[inline]
#[must_use]
pub fn valid(&self) -> bool { true }
//pub fn valid(&self) -> bool { self.expire > SystemTime::now() }
pub fn valid(&self) -> bool { self.expire > SystemTime::now() }
#[must_use]
pub(crate) fn default_expire() -> SystemTime { rand::timepoint_secs(60 * 60 * 18..60 * 60 * 36) }
@@ -454,9 +452,7 @@ impl CachedDest {
impl CachedOverride {
#[inline]
#[must_use]
pub fn valid(&self) -> bool { true }
//pub fn valid(&self) -> bool { self.expire > SystemTime::now() }
pub fn valid(&self) -> bool { self.expire > SystemTime::now() }
#[must_use]
pub(crate) fn default_expire() -> SystemTime { rand::timepoint_secs(60 * 60 * 6..60 * 60 * 12) }
+57 -42
View File
@@ -1,6 +1,6 @@
use std::{collections::BTreeMap, mem::size_of, sync::Arc};
use conduit::{debug_info, err, utils, warn, Err, Error, Result};
use conduit::{debug_info, utils, warn, Error, Result};
use database::{Database, Map};
use ruma::{
api::client::{device::Device, error::ErrorKind, filter::FilterDefinition},
@@ -87,19 +87,19 @@ impl Data {
let mut parts = bytes.split(|&b| b == 0xFF);
let user_bytes = parts
.next()
.ok_or_else(|| err!(Database("User ID in token_userdeviceid is invalid.")))?;
.ok_or_else(|| Error::bad_database("User ID in token_userdeviceid is invalid."))?;
let device_bytes = parts
.next()
.ok_or_else(|| err!(Database("Device ID in token_userdeviceid is invalid.")))?;
.ok_or_else(|| Error::bad_database("Device ID in token_userdeviceid is invalid."))?;
Ok(Some((
UserId::parse(
utils::string_from_bytes(user_bytes)
.map_err(|e| err!(Database("User ID in token_userdeviceid is invalid unicode. {e}")))?,
.map_err(|_| Error::bad_database("User ID in token_userdeviceid is invalid unicode."))?,
)
.map_err(|e| err!(Database("User ID in token_userdeviceid is invalid. {e}")))?,
.map_err(|_| Error::bad_database("User ID in token_userdeviceid is invalid."))?,
utils::string_from_bytes(device_bytes)
.map_err(|e| err!(Database("Device ID in token_userdeviceid is invalid. {e}")))?,
.map_err(|_| Error::bad_database("Device ID in token_userdeviceid is invalid."))?,
)))
})
}
@@ -109,9 +109,9 @@ impl Data {
Box::new(self.userid_password.iter().map(|(bytes, _)| {
UserId::parse(
utils::string_from_bytes(&bytes)
.map_err(|e| err!(Database("User ID in userid_password is invalid unicode. {e}")))?,
.map_err(|_| Error::bad_database("User ID in userid_password is invalid unicode."))?,
)
.map_err(|e| err!(Database("User ID in userid_password is invalid. {e}")))
.map_err(|_| Error::bad_database("User ID in userid_password is invalid."))
}))
}
@@ -165,7 +165,7 @@ impl Data {
.map_or(Ok(None), |bytes| {
Ok(Some(
utils::string_from_bytes(&bytes)
.map_err(|e| err!(Database("Displayname in db is invalid. {e}")))?,
.map_err(|_| Error::bad_database("Displayname in db is invalid."))?,
))
})
}
@@ -188,8 +188,10 @@ impl Data {
self.userid_avatarurl
.get(user_id.as_bytes())?
.map(|bytes| {
let s_bytes = utils::string_from_bytes(&bytes)
.map_err(|e| err!(Database(warn!("Avatar URL in db is invalid: {e}"))))?;
let s_bytes = utils::string_from_bytes(&bytes).map_err(|e| {
warn!("Avatar URL in db is invalid: {}", e);
Error::bad_database("Avatar URL in db is invalid.")
})?;
let mxc_uri: OwnedMxcUri = s_bytes.into();
Ok(mxc_uri)
})
@@ -213,7 +215,10 @@ impl Data {
self.userid_blurhash
.get(user_id.as_bytes())?
.map(|bytes| {
utils::string_from_bytes(&bytes).map_err(|e| err!(Database("Avatar URL in db is invalid. {e}")))
let s = utils::string_from_bytes(&bytes)
.map_err(|_| Error::bad_database("Avatar URL in db is invalid."))?;
Ok(s)
})
.transpose()
}
@@ -309,9 +314,9 @@ impl Data {
bytes
.rsplit(|&b| b == 0xFF)
.next()
.ok_or_else(|| err!(Database("UserDevice ID in db is invalid.")))?,
.ok_or_else(|| Error::bad_database("UserDevice ID in db is invalid."))?,
)
.map_err(|e| err!(Database("Device ID in userdeviceid_metadata is invalid. {e}")))?
.map_err(|_| Error::bad_database("Device ID in userdeviceid_metadata is invalid."))?
.into())
}),
)
@@ -325,9 +330,13 @@ impl Data {
// should not be None, but we shouldn't assert either lol...
if self.userdeviceid_metadata.get(&userdeviceid)?.is_none() {
return Err!(Database(error!(
"User {user_id:?} does not exist or device ID {device_id:?} has no metadata."
)));
warn!(
"Called set_token for a non-existent user \"{}\" and/or device ID \"{}\" with no metadata in database",
user_id, device_id
);
return Err(Error::bad_database(
"User does not exist or device ID has no metadata in database.",
));
}
// Remove old token
@@ -357,9 +366,14 @@ impl Data {
// Only existing devices should be able to call this, but we shouldn't assert
// either...
if self.userdeviceid_metadata.get(&key)?.is_none() {
return Err!(Database(error!(
"User {user_id:?} does not exist or device ID {device_id:?} has no metadata."
)));
warn!(
"Called add_one_time_key for a non-existent user \"{}\" and/or device ID \"{}\" with no metadata in \
database",
user_id, device_id
);
return Err(Error::bad_database(
"User does not exist or device ID has no metadata in database.",
));
}
key.push(0xFF);
@@ -387,7 +401,7 @@ impl Data {
.get(user_id.as_bytes())?
.map_or(Ok(0), |bytes| {
utils::u64_from_bytes(&bytes)
.map_err(|e| err!(Database("Count in roomid_lastroomactiveupdate is invalid. {e}")))
.map_err(|_| Error::bad_database("Count in roomid_lastroomactiveupdate is invalid."))
})
}
@@ -415,10 +429,11 @@ impl Data {
serde_json::from_slice(
key.rsplit(|&b| b == 0xFF)
.next()
.ok_or_else(|| err!(Database("OneTimeKeyId in db is invalid.")))?,
.ok_or_else(|| Error::bad_database("OneTimeKeyId in db is invalid."))?,
)
.map_err(|e| err!(Database("OneTimeKeyId in db is invalid. {e}")))?,
serde_json::from_slice(&value).map_err(|e| err!(Database("OneTimeKeys in db are invalid. {e}")))?,
.map_err(|_| Error::bad_database("OneTimeKeyId in db is invalid."))?,
serde_json::from_slice(&value)
.map_err(|_| Error::bad_database("OneTimeKeys in db are invalid."))?,
))
})
.transpose()
@@ -442,9 +457,9 @@ impl Data {
bytes
.rsplit(|&b| b == 0xFF)
.next()
.ok_or_else(|| err!(Database("OneTimeKey ID in db is invalid.")))?,
.ok_or_else(|| Error::bad_database("OneTimeKey ID in db is invalid."))?,
)
.map_err(|e| err!(Database("DeviceKeyId in db is invalid. {e}")))?
.map_err(|_| Error::bad_database("DeviceKeyId in db is invalid."))?
.algorithm(),
)
}) {
@@ -566,19 +581,19 @@ impl Data {
.get(&key)?
.ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Tried to sign nonexistent key."))?,
)
.map_err(|e| err!(Database("key in keyid_key is invalid. {e}")))?;
.map_err(|_| Error::bad_database("key in keyid_key is invalid."))?;
let signatures = cross_signing_key
.get_mut("signatures")
.ok_or_else(|| err!(Database("key in keyid_key has no signatures field.")))?
.ok_or_else(|| Error::bad_database("key in keyid_key has no signatures field."))?
.as_object_mut()
.ok_or_else(|| err!(Database("key in keyid_key has invalid signatures field.")))?
.ok_or_else(|| Error::bad_database("key in keyid_key has invalid signatures field."))?
.entry(sender_id.to_string())
.or_insert_with(|| serde_json::Map::new().into());
signatures
.as_object_mut()
.ok_or_else(|| err!(Database("signatures in keyid_key for a user is invalid.")))?
.ok_or_else(|| Error::bad_database("signatures in keyid_key for a user is invalid."))?
.insert(signature.0, signature.1.into());
self.keyid_key.insert(
@@ -625,7 +640,7 @@ impl Data {
Error::bad_database("User ID in devicekeychangeid_userid is invalid unicode.")
})?,
)
.map_err(|e| err!(Database("User ID in devicekeychangeid_userid is invalid. {e}")))
.map_err(|_| Error::bad_database("User ID in devicekeychangeid_userid is invalid."))
}),
)
}
@@ -670,7 +685,7 @@ impl Data {
self.keyid_key.get(&key)?.map_or(Ok(None), |bytes| {
Ok(Some(
serde_json::from_slice(&bytes).map_err(|e| err!(Database("DeviceKeys in db are invalid. {e}")))?,
serde_json::from_slice(&bytes).map_err(|_| Error::bad_database("DeviceKeys in db are invalid."))?,
))
})
}
@@ -704,7 +719,7 @@ impl Data {
) -> Result<Option<Raw<CrossSigningKey>>> {
self.keyid_key.get(key)?.map_or(Ok(None), |bytes| {
let mut cross_signing_key = serde_json::from_slice::<serde_json::Value>(&bytes)
.map_err(|e| err!(Database("CrossSigningKey in db is invalid. {e}")))?;
.map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?;
clean_signatures(&mut cross_signing_key, sender_user, user_id, allowed_signatures)?;
Ok(Some(Raw::from_json(
@@ -736,7 +751,7 @@ impl Data {
self.keyid_key.get(&key)?.map_or(Ok(None), |bytes| {
Ok(Some(
serde_json::from_slice(&bytes)
.map_err(|e| err!(Database("CrossSigningKey in db is invalid. {e}")))?,
.map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?,
))
})
})
@@ -777,7 +792,7 @@ impl Data {
for (_, value) in self.todeviceid_events.scan_prefix(prefix) {
events.push(
serde_json::from_slice(&value)
.map_err(|e| err!(Database("Event in todeviceid_events is invalid. {e}")))?,
.map_err(|_| Error::bad_database("Event in todeviceid_events is invalid."))?,
);
}
@@ -801,7 +816,7 @@ impl Data {
Ok::<_, Error>((
key.clone(),
utils::u64_from_bytes(&key[key.len().saturating_sub(size_of::<u64>())..key.len()])
.map_err(|e| err!(Database("ToDeviceId has invalid count bytes. {e}")))?,
.map_err(|_| Error::bad_database("ToDeviceId has invalid count bytes."))?,
))
})
.filter_map(Result::ok)
@@ -862,7 +877,7 @@ impl Data {
.get(user_id.as_bytes())?
.map_or(Ok(None), |bytes| {
utils::u64_from_bytes(&bytes)
.map_err(|e| err!(Database("Invalid devicelistversion in db. {e}")))
.map_err(|_| Error::bad_database("Invalid devicelistversion in db."))
.map(Some)
})
}
@@ -878,7 +893,7 @@ impl Data {
.scan_prefix(key)
.map(|(_, bytes)| {
serde_json::from_slice::<Device>(&bytes)
.map_err(|e| err!(Database("Device in userdeviceid_metadata is invalid. {e}")))
.map_err(|_| Error::bad_database("Device in userdeviceid_metadata is invalid."))
}),
)
}
@@ -905,7 +920,7 @@ impl Data {
let raw = self.userfilterid_filter.get(&key)?;
if let Some(raw) = raw {
serde_json::from_slice(&raw).map_err(|e| err!(Database("Invalid filter event in db. {e}")))
serde_json::from_slice(&raw).map_err(|_| Error::bad_database("Invalid filter event in db."))
} else {
Ok(None)
}
@@ -939,7 +954,7 @@ impl Data {
let expires_at = u64::from_be_bytes(
expires_at_bytes
.try_into()
.map_err(|e| err!(Database("expires_at in openid_userid is invalid u64. {e}")))?,
.map_err(|_| Error::bad_database("expires_at in openid_userid is invalid u64."))?,
);
if expires_at < utils::millis_since_unix_epoch() {
@@ -951,9 +966,9 @@ impl Data {
UserId::parse(
utils::string_from_bytes(user_bytes)
.map_err(|e| err!(Database("User ID in openid_userid is invalid unicode. {e}")))?,
.map_err(|_| Error::bad_database("User ID in openid_userid is invalid unicode."))?,
)
.map_err(|e| err!(Database("User ID in openid_userid is invalid. {e}")))
.map_err(|_| Error::bad_database("User ID in openid_userid is invalid."))
}
}