Compare commits

..

46 Commits

Author SHA1 Message Date
Renovate Bot
1192d8c846 chore(deps): update https://github.com/taiki-e/install-action digest to 787505c 2026-04-25 05:03:35 +00:00
ginger
5dcfff51cf chore: Admin announcement 2026-04-24 20:33:07 +00:00
Ginger
b9989f1713 chore: Release 2026-04-24 15:21:47 -04:00
Ginger
1d3e3e7e62 chore: Update changelog 2026-04-24 15:21:40 -04:00
Jade Ellis
0adf3aa956 fix: Revert 7b1aabda9f
Yeah that didn't work sadly.
2026-04-24 16:22:46 +01:00
Jade Ellis
7b1aabda9f feat: Re-enable http3
This required the previous commit, and relies on
the included flag to make fat LTO builds
work correctly.
2026-04-24 14:51:11 +01:00
Jade Ellis
e31c5997b7 fix: Explicitly set TLS backends
Dependency updates mean we have to set a custom TLS backend sooner.
Also some groundwork for being able to use aws-lc in future
2026-04-24 14:19:12 +01:00
Jade Ellis
7ca0d137c4 chore: Replace ring for sha256 with sha2 2026-04-24 12:56:05 +01:00
Jade Ellis
0344bf71d8 chore: Disable http3 by default
Unfortunately h3 requires aws-lc since the last version of reqwest.
aws-lc currently breaks the build.
2026-04-24 12:11:48 +01:00
Jade Ellis
a07d3e24ea fix(deps): corrext aws-lc-rs dependencies and direct-tls 2026-04-24 10:06:47 +01:00
Jade Ellis
1bc7950748 fix: Update direct-tls server handle 2026-04-24 09:34:16 +01:00
tokii
0fd43ff6fa docs: Update Nomad deployment docs to include volume configuration changes 2026-04-23 20:07:53 +00:00
tokii
796136f1a6 docs: Update Nomad deployment docs for HTTPS and Traefik changes 2026-04-23 20:07:53 +00:00
tokii
447608985b docs: Add deployment documentation for Nomad 2026-04-23 20:07:53 +00:00
timedout
5f4cd47d88 fix: Add workaround for handling malformed PDUs
Signed-off-by: timedout <git@nexy7574.co.uk>
Reviewed-On: https://forgejo.ellis.link/continuwuation/continuwuity-sec/pulls/7
Reviewed-By: Jade Ellis <jade@ellis.link>
2026-04-23 20:48:11 +01:00
stratself
a7244bdb68 docs(docker): Detailed port exposure docs for other reverse proxies 2026-04-23 19:47:46 +00:00
stratself
91f2900463 docs(docker): More compose cleanups
* Stringify and use long URLs for image names
* Use read-only docker socket in traefik mount
* Shorten some comments
2026-04-23 19:47:46 +00:00
stratself
e44ae3bac9 docs(delegation): Add compose examples
Previous projects used split-domain examples, so it's good to add back
2026-04-23 19:47:46 +00:00
stratself
b692f9e6e7 fix(docs): Fix one wrong config filename and title all the composes 2026-04-23 19:47:46 +00:00
stratself
695333fe5b chore: Renumber changelog PR and fix trailing whitespace 2026-04-23 19:47:31 +00:00
stratself
bc7a6c148f fix(docs): Small wording fixes 2026-04-23 19:47:31 +00:00
ky-bean
bd3944573b docs(docker): Add note for required config setting 2026-04-23 19:47:31 +00:00
ky-bean
21ac3c5a86 chore: Add news fragment for #1553 2026-04-23 19:47:31 +00:00
ky-bean
3976849b97 docs(docker): fix typos (psuedo=>pseudo, decleration=>declaration) 2026-04-23 19:47:31 +00:00
ky-bean
a1e3619291 docs(docker): update wording, implement suggestions from @lveneris 2026-04-23 19:47:31 +00:00
ky-bean
a92fc78a90 docs(docker): Detail how to access the server's console 2026-04-23 19:47:31 +00:00
ky-bean
fc429ea564 docs: explain admin console for docker deployments 2026-04-23 19:47:31 +00:00
stratself
69c931e18a docs(generic): Highlight important /_continuwuity features + typofixes 2026-04-23 19:46:57 +00:00
stratself
284e0ce1e5 chore: Add changelog for #1677 2026-04-23 19:46:57 +00:00
stratself
a13779a051 docs(generic): Remove Nix build section and further wording fixes
* Add spec link to well-known support endpoint
* Prioritize simpler "route everything" approach for other RProxies
2026-04-23 19:46:57 +00:00
stratself
7163714697 docs(generic): Fix links for CI binaries 2026-04-23 19:46:57 +00:00
stratself
3998a14c32 docs(generic): Rewrite sections on server initialization and testing
* Rename "You're done" to "Starting Your Server"
* Add instructions for initial registration token flow
* Shorten "How do I know it works" section
* Beautify "What's Next" section
2026-04-23 19:46:57 +00:00
stratself
c79f2a3057 docs(generic): Fix router + reverse proxy + docker build sections
* Link docker builds to section in dev pages
* Delete old section on port forwarding
* Create new section on port exposing, near reverse proxy section
* Rewrite Other Reverse Proxies section to update specified routes
* Move reverse proxy software caveats into its own subsection
* Other wording and structure fixes and improvements
2026-04-23 19:46:57 +00:00
stratself
17837c51a0 docs(generic): Various fixes for consistency with other pages
* Use indirect URLs
* Change your.server.name to canonical example.com
* Put Getting help section in a tip admonition
* Remove statement on Caddy preference
* Clean up "What's next" section
2026-04-23 19:46:57 +00:00
stratself
99a7be0222 fix(docs): Correct ports for LiveKit TURN range 2026-04-23 19:46:16 +00:00
stratself
41ed2eb167 docs(livekit): Add/correct client discovery paths and extra fixes
* Use de facto unstasble path instead of the standard one
* Document both the unstable and well-known paths as being exposed by
  Continuwuity when set
* Make curling said path one of the Testing steps
* Removing confusing console `~$` prefix symbols, move commands and
  response into separate code blocks
* Number the MSCs
2026-04-23 19:46:16 +00:00
Renovate Bot
2b08460b16 chore(deps): update https://github.com/actions/setup-node digest to 48b55a0 2026-04-23 19:45:52 +00:00
Renovate Bot
4cf8f6e05b chore(deps): update https://github.com/taiki-e/install-action digest to 74e87cb 2026-04-23 19:45:46 +00:00
Jade Ellis
ae37acb228 ci: Don't run clippy & tests if rust files haven't changed 2026-04-23 20:44:57 +01:00
Jade Ellis
10c3045f5f ci: Run Renovate on resolvematrix 2026-04-23 20:44:56 +01:00
Jade Ellis
8242718571 ci: Label PRs touching dependencies 2026-04-23 20:44:56 +01:00
Renovate Bot
03db067aab chore(deps): update ghcr.io/renovatebot/renovate docker tag to v43.140.0 2026-04-23 19:23:09 +00:00
Jade Ellis
b28ddde1eb chore: Update lockfile 2026-04-23 20:04:05 +01:00
Jade Ellis
0134f69bf9 chore: Update incompatible dependenceis 2026-04-23 20:02:48 +01:00
Jade Ellis
15878371bf chore: Update reqwest 2026-04-23 18:53:25 +01:00
Getz Mikalsen
980bd475b6 feat: Add TLS options for LDAP (#1389)
Optional StartTLS for LDAP and add option to skip TLS verification.

Co-authored-by: Jade Ellis <jade@ellis.link>
Reviewed-on: https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1389
Reviewed-by: Jade Ellis <jade@ellis.link>
2026-04-23 17:39:25 +00:00
75 changed files with 1332 additions and 635 deletions

View File

@@ -71,7 +71,7 @@ runs:
- name: Install timelord-cli and git-warp-time - name: Install timelord-cli and git-warp-time
if: steps.check-binaries.outputs.need-install == 'true' if: steps.check-binaries.outputs.need-install == 'true'
uses: https://github.com/taiki-e/install-action@a2352fc6ce487f030a3aa709482d57823eadfb37 # v2 uses: https://github.com/taiki-e/install-action@787505cde8a44ea468a00478fe52baf23b15bccd # v2
with: with:
tool: git-warp-time,timelord-cli@3.0.1 tool: git-warp-time,timelord-cli@3.0.1

View File

@@ -37,6 +37,9 @@ jobs:
if (file.startsWith('pkg/') || file.startsWith('nix/') || file === 'flake.nix' || file === 'flake.lock' || file.startsWith('docker/')) { if (file.startsWith('pkg/') || file.startsWith('nix/') || file === 'flake.nix' || file === 'flake.lock' || file.startsWith('docker/')) {
labelsToAdd.add('Meta/Packaging'); labelsToAdd.add('Meta/Packaging');
} }
if (file === 'Cargo.lock') {
labelsToAdd.add('Dependencies');
}
} }
if (labelsToAdd.size > 0) { if (labelsToAdd.size > 0) {

View File

@@ -32,7 +32,7 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
if: steps.runner-env.outputs.node_major == '' || steps.runner-env.outputs.node_major < '20' if: steps.runner-env.outputs.node_major == '' || steps.runner-env.outputs.node_major < '20'
uses: https://github.com/actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 uses: https://github.com/actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version: 22 node-version: 22

View File

@@ -24,7 +24,7 @@ jobs:
steps: steps:
- name: 📦 Setup Node.js - name: 📦 Setup Node.js
uses: https://github.com/actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 uses: https://github.com/actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version: "22" node-version: "22"

View File

@@ -9,6 +9,7 @@ on:
permissions: permissions:
contents: read contents: read
pull-requests: read
jobs: jobs:
fast-checks: fast-checks:
@@ -40,10 +41,32 @@ jobs:
cargo +nightly fmt --all -- --check && \ cargo +nightly fmt --all -- --check && \
echo "✅ Formatting check passed" || \ echo "✅ Formatting check passed" || \
exit 1 exit 1
check-changes:
name: Check changed files
runs-on: ubuntu-latest
outputs:
rust: ${{ steps.filter.outputs.rust }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Check for file changes
uses: https://github.com/dorny/paths-filter@v4
id: filter
with:
filters: |
rust:
- '**/*.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
clippy-and-tests: clippy-and-tests:
name: Clippy and Cargo Tests name: Clippy and Cargo Tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: check-changes
if: needs.check-changes.outputs.rust == 'true'
steps: steps:
- name: Checkout repository - name: Checkout repository

View File

@@ -43,7 +43,7 @@ jobs:
name: Renovate name: Renovate
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/renovatebot/renovate:43.111.0@sha256:da5fcac20c48d9792aac9c61fd234531bfa8df61263a39387cd8920263ca4768 image: ghcr.io/renovatebot/renovate:43.140.0@sha256:61303c28b10a491c559529fb6f41745850e4755a43a54c04c3ae6848d6eaf5cc
options: --tmpfs /tmp:exec options: --tmpfs /tmp:exec
steps: steps:
- name: Checkout - name: Checkout
@@ -90,12 +90,12 @@ jobs:
RENOVATE_PLATFORM: forgejo RENOVATE_PLATFORM: forgejo
RENOVATE_ENDPOINT: ${{ github.server_url }} RENOVATE_ENDPOINT: ${{ github.server_url }}
RENOVATE_AUTODISCOVER: 'false' RENOVATE_AUTODISCOVER: 'false'
RENOVATE_REPOSITORIES: '["${{ github.repository }}"]' RENOVATE_REPOSITORIES: '["${{ github.repository }}", "continuwuation/resolvematrix"]'
RENOVATE_GIT_TIMEOUT: 60000 RENOVATE_GIT_TIMEOUT: 60000
RENOVATE_REQUIRE_CONFIG: 'required' RENOVATE_REQUIRE_CONFIG: 'required'
RENOVATE_ONBOARDING: 'false' # RENOVATE_ONBOARDING: 'false'
RENOVATE_INHERIT_CONFIG: 'true' RENOVATE_INHERIT_CONFIG: 'true'
RENOVATE_GITHUB_TOKEN_WARN: 'false' RENOVATE_GITHUB_TOKEN_WARN: 'false'

View File

@@ -1,3 +1,20 @@
# Continuwuity 0.5.8 (2026-04-24)
## Features
- LDAP can now optionally be connected to using StartTLS, and you may unsafely skip verification. Contributed by @getz (#1389)
- Users will now be prevented from removing their email if the server is configured to require an email when registering an account.
## Bugfixes
- Fixed a situation where multiple email addresses could be associated with one user when that user changes their email address.
## Improved Documentation
- Updated config docs to state we support room version 12, and set it as default. Contributed by @ezera. (#1622)
- Improve instructions for generic deployments, removing unnecessary parts and documenting the new initial registration token flow. Contributed by @stratself (#1677)
# Continuwuity v0.5.7 (2026-04-17) # Continuwuity v0.5.7 (2026-04-17)
## Features ## Features

638
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ license = "Apache-2.0"
# See also `rust-toolchain.toml` # See also `rust-toolchain.toml`
readme = "README.md" readme = "README.md"
repository = "https://forgejo.ellis.link/continuwuation/continuwuity" repository = "https://forgejo.ellis.link/continuwuation/continuwuity"
version = "0.5.7" version = "0.5.8"
[workspace.metadata.crane] [workspace.metadata.crane]
name = "conduwuit" name = "conduwuit"
@@ -36,7 +36,7 @@ version = "0.3"
features = ["ffi", "std", "union"] features = ["ffi", "std", "union"]
[workspace.dependencies.const-str] [workspace.dependencies.const-str]
version = "0.7.0" version = "1.1.0"
[workspace.dependencies.ctor] [workspace.dependencies.ctor]
version = "0.10.0" version = "0.10.0"
@@ -47,9 +47,9 @@ default-features = false
features = ["features"] features = ["features"]
[workspace.dependencies.toml] [workspace.dependencies.toml]
version = "0.9.5" version = "1.1.2"
default-features = false default-features = false
features = ["parse"] features = ["parse", "serde"]
[workspace.dependencies.sanitize-filename] [workspace.dependencies.sanitize-filename]
version = "0.6.0" version = "0.6.0"
@@ -102,15 +102,18 @@ default-features = false
features = ["typed-header", "tracing", "cookie"] features = ["typed-header", "tracing", "cookie"]
[workspace.dependencies.axum-server] [workspace.dependencies.axum-server]
version = "0.7.2" version = "0.8.0"
default-features = false default-features = false
# to listen on both HTTP and HTTPS if listening on TLS dierctly from conduwuit for complement or sytest # to listen on both HTTP and HTTPS if listening on TLS dierctly from conduwuit for complement or sytest
[workspace.dependencies.axum-server-dual-protocol] [workspace.dependencies.axum-server-dual-protocol]
version = "0.7" # version = "0.7"
git = "https://github.com/vinchona/axum-server-dual-protocol.git"
rev = "ca6db055254255b74238673ce4135698e347d71c" # feat!: bump axum_server to 0.8.0
default-features = false
[workspace.dependencies.axum-client-ip] [workspace.dependencies.axum-client-ip]
version = "0.7" version = "1.3"
[workspace.dependencies.tower] [workspace.dependencies.tower]
version = "0.5.2" version = "0.5.2"
@@ -134,13 +137,12 @@ features = [
[workspace.dependencies.rustls] [workspace.dependencies.rustls]
version = "0.23.25" version = "0.23.25"
default-features = false default-features = false
features = ["aws_lc_rs"]
[workspace.dependencies.reqwest] [workspace.dependencies.reqwest]
version = "0.12.15" version = "0.13.2"
default-features = false default-features = false
features = [ features = [
"rustls-tls-native-roots", "rustls-no-provider",
"socks", "socks",
"hickory-dns", "hickory-dns",
"http2", "http2",
@@ -159,7 +161,7 @@ features = ["raw_value"]
# Used for appservice registration files # Used for appservice registration files
[workspace.dependencies.serde-saphyr] [workspace.dependencies.serde-saphyr]
version = "0.0.23" version = "0.0.24"
# Used to load forbidden room/user regex from config # Used to load forbidden room/user regex from config
[workspace.dependencies.serde_regex] [workspace.dependencies.serde_regex]
@@ -167,7 +169,7 @@ version = "1.1.0"
# Used for ruma wrapper # Used for ruma wrapper
[workspace.dependencies.serde_html_form] [workspace.dependencies.serde_html_form]
version = "0.2.6" version = "0.4.0"
# Used for password hashing # Used for password hashing
[workspace.dependencies.argon2] [workspace.dependencies.argon2]
@@ -251,7 +253,7 @@ features = [
] ]
[workspace.dependencies.tokio-metrics] [workspace.dependencies.tokio-metrics]
version = "0.4.0" version = "0.5.0"
[workspace.dependencies.libloading] [workspace.dependencies.libloading]
version = "0.9.0" version = "0.9.0"
@@ -429,14 +431,13 @@ features = ["http", "grpc-tonic", "trace", "logs", "metrics"]
# optional sentry metrics for crash/panic reporting # optional sentry metrics for crash/panic reporting
[workspace.dependencies.sentry] [workspace.dependencies.sentry]
version = "0.46.0" version = "0.47.0"
default-features = false default-features = false
features = [ features = [
"backtrace", "backtrace",
"contexts", "contexts",
"debug-images", "debug-images",
"panic", "panic",
"rustls",
"tower", "tower",
"tower-http", "tower-http",
"tracing", "tracing",
@@ -445,9 +446,9 @@ features = [
] ]
[workspace.dependencies.sentry-tracing] [workspace.dependencies.sentry-tracing]
version = "0.46.0" version = "0.47.0"
[workspace.dependencies.sentry-tower] [workspace.dependencies.sentry-tower]
version = "0.46.0" version = "0.47.0"
# jemalloc usage # jemalloc usage
[workspace.dependencies.tikv-jemalloc-sys] [workspace.dependencies.tikv-jemalloc-sys]
@@ -560,7 +561,7 @@ version = "0.15.0"
[workspace.dependencies.lettre] [workspace.dependencies.lettre]
version = "0.11.19" version = "0.11.19"
default-features = false default-features = false
features = ["smtp-transport", "pool", "hostname", "builder", "rustls", "rustls-native-certs", "tokio1", "ring", "tokio1-rustls", "tracing", "serde"] features = ["smtp-transport", "pool", "hostname", "builder", "rustls", "rustls-native-certs", "tokio1", "rustls-no-provider", "tokio1-rustls", "tracing", "serde"]
[workspace.dependencies.governor] [workspace.dependencies.governor]
version = "0.10.4" version = "0.10.4"

View File

@@ -1 +0,0 @@
Users will now be prevented from removing their email if the server is configured to require an email when registering an account.

View File

@@ -1 +0,0 @@
Fixed a situation where multiple email addresses could be associated with one user when that user changes their email address.

View File

@@ -1 +0,0 @@
Updated config docs to state we support room version 12, and set it as default. Contributed by @ezera.

1
changelog.d/1671.docs Normal file
View File

@@ -0,0 +1 @@
Explain accessing Continuwuity's server console when deployed via Docker.

View File

@@ -1966,6 +1966,14 @@
# #
#uri = "" #uri = ""
# StartTLS for LDAP connections.
#
#use_starttls = false
# Skip TLS certificate verification, possibly dangerous.
#
#disable_tls_verification = false
# Root of the searches. # Root of the searches.
# #
# example: "ou=users,dc=example,dc=org" # example: "ou=users,dc=example,dc=org"

View File

@@ -17,12 +17,14 @@ ARG LLVM_VERSION=21
# Line one: compiler tools # Line one: compiler tools
# Line two: curl, for downloading binaries and wget because llvm.sh is broken with curl # Line two: curl, for downloading binaries and wget because llvm.sh is broken with curl
# Line three: for xx-verify # Line three: for xx-verify
# golang, cmake: For aws-lc-rs bindgen
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && apt-get install -y \ apt-get update && apt-get install -y \
pkg-config make jq \ pkg-config make jq \
wget curl git software-properties-common \ wget curl git software-properties-common \
file file
# golang cmake
# LLVM packages # LLVM packages
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
@@ -162,7 +164,7 @@ ENV CONDUWUIT_VERSION_EXTRA=$CONDUWUIT_VERSION_EXTRA
ENV CONTINUWUITY_VERSION_EXTRA=$CONTINUWUITY_VERSION_EXTRA ENV CONTINUWUITY_VERSION_EXTRA=$CONTINUWUITY_VERSION_EXTRA
ARG RUST_PROFILE=release ARG RUST_PROFILE=release
ARG CARGO_FEATURES="default,http3" ARG CARGO_FEATURES="default"
# Build the binary # Build the binary
RUN --mount=type=cache,target=/usr/local/cargo/registry \ RUN --mount=type=cache,target=/usr/local/cargo/registry \

View File

@@ -50,8 +50,6 @@ # Defaults to members of the admin room if unset
# CONTINUWUITY_WELL_KNOWN__SERVER: matrix.example.com:443 # CONTINUWUITY_WELL_KNOWN__SERVER: matrix.example.com:443
``` ```
## Reverse proxying well-known files to Continuwuity
After doing the steps above, Continuwuity will serve these 3 JSON files: After doing the steps above, Continuwuity will serve these 3 JSON files:
- `/.well-known/matrix/client`: for Client-Server discovery - `/.well-known/matrix/client`: for Client-Server discovery
@@ -60,9 +58,11 @@ ## Reverse proxying well-known files to Continuwuity
To enable full discovery, you will need to reverse proxy these paths from the base domain back to Continuwuity. To enable full discovery, you will need to reverse proxy these paths from the base domain back to Continuwuity.
## Reverse proxying well-known files to Continuwuity
<details> <details>
<summary>For Caddy</summary> <summary>For **Caddy**</summary>
``` ```
matrix.example.com:443 { matrix.example.com:443 {
@@ -78,7 +78,7 @@ ## Reverse proxying well-known files to Continuwuity
<details> <details>
<summary>For Traefik (via Docker labels)</summary> <summary>For **Traefik** (via Docker labels)</summary>
``` ```
services: services:
@@ -93,7 +93,10 @@ ## Reverse proxying well-known files to Continuwuity
</details> </details>
Restart Continuwuity and your reverse proxy. Once that's done, visit these routes and check that the responses match the examples below:
For **Docker** users, consult the compose files in the [Appendix section](#docker-compose-examples).
After applying these changes, restart Continuwuity and your reverse proxy.Visit these routes and check that the responses match the examples below:
<details open> <details open>
@@ -253,3 +256,45 @@ ## Related Documentation
- [Server-to-Server resolution](https://spec.matrix.org/v1.17/server-server-api/#resolving-server-names) (see this for more information on SRV records) - [Server-to-Server resolution](https://spec.matrix.org/v1.17/server-server-api/#resolving-server-names) (see this for more information on SRV records)
- [Client-to-Server resolution](https://spec.matrix.org/v1.17/client-server-api/#server-discovery) - [Client-to-Server resolution](https://spec.matrix.org/v1.17/client-server-api/#server-discovery)
- [MSC1929: Homeserver Admin Contact and Support page](https://github.com/matrix-org/matrix-spec-proposals/pull/1929) - [MSC1929: Homeserver Admin Contact and Support page](https://github.com/matrix-org/matrix-spec-proposals/pull/1929)
## Appendix
### Docker Compose examples
The following Compose files are taken from [Docker instructions](../deploying/docker.mdx) and reconfigured to support split-domain delegation. Note the updated `CONTINUWUITY_WELL_KNOWN` variable and relevant changes in reverse proxy rules.
<details>
<summary>Caddy (using Caddyfile) - delegated.docker-compose.with-caddy.yml ([view raw](/advanced/delegated.docker-compose.with-caddy.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.with-caddy.yml"
```
</details>
<details>
<summary>Caddy (using labels) - delegated.docker-compose.with-caddy-labels.yml ([view raw](/advanced/delegated.docker-compose.with-caddy-labels.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.with-caddy-labels.yml"
```
</details>
<details>
<summary>Traefik (for existing setup) - delegated.docker-compose.for-traefik.yml ([view raw](/advanced/delegated.docker-compose.for-traefik.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.for-traefik.yml"
```
</details>
<details>
<summary>Traefik included - delegated.docker-compose.with-traefik.yml ([view raw](/advanced/delegated.docker-compose.with-traefik.yml))</summary>
```yaml file="../public/advanced/delegated.docker-compose.with-traefik.yml"
```
</details>

View File

@@ -91,7 +91,7 @@ ### 3. Telling clients where to find LiveKit
To tell clients where to find LiveKit, you need to add the address of your `lk-jwt-service` to the `[global.matrix_rtc]` config section using the `foci` option. To tell clients where to find LiveKit, you need to add the address of your `lk-jwt-service` to the `[global.matrix_rtc]` config section using the `foci` option.
The variable should be a list of servers serving as MatrixRTC endpoints. Clients discover these via the `/_matrix/client/v1/rtc/transports` endpoint (MSC4143). The variable should be a list of servers serving as MatrixRTC endpoints. Replace the URL with the address you are deploying your instance of lk-jwt-service to:
```toml ```toml
[global.matrix_rtc] [global.matrix_rtc]
@@ -100,7 +100,10 @@ ### 3. Telling clients where to find LiveKit
] ]
``` ```
Remember to replace the URL with the address you are deploying your instance of lk-jwt-service to. This will expose LiveKit information on the following endpoints for clients to discover:
- `/_matrix/client/unstable/org.matrix.msc4143/rtc/transports` (MSC4143 unstable, behind auth)
- `/.well-known/matrix/client` (fallback, not behind auth. Only enabled if `[global.well_known].client` is set)
### 4. Configure your Reverse Proxy ### 4. Configure your Reverse Proxy
@@ -114,6 +117,7 @@ ### 4. Configure your Reverse Proxy
<details> <details>
<summary>Example caddy config</summary> <summary>Example caddy config</summary>
``` ```
livekit.example.com { livekit.example.com {
@@ -127,10 +131,12 @@ ### 4. Configure your Reverse Proxy
reverse_proxy 127.0.0.1:7880 reverse_proxy 127.0.0.1:7880
} }
``` ```
</details> </details>
<details> <details>
<summary>Example nginx config</summary> <summary>Example nginx config</summary>
``` ```
server { server {
server_name livekit.example.com; server_name livekit.example.com;
@@ -167,16 +173,19 @@ ### 4. Configure your Reverse Proxy
'' close; '' close;
} }
``` ```
</details> </details>
<details> <details>
<summary>Example traefik router</summary> <summary>Example traefik router</summary>
``` ```
# on LiveKit itself # on LiveKit itself
traefik.http.routers.livekit.rule=Host(`livekit.example.com`) traefik.http.routers.livekit.rule=Host(`livekit.example.com`)
# on the JWT service # on the JWT service
traefik.http.routers.livekit-jwt.rule=Host(`livekit.example.com`) && (PathPrefix(`/sfu/get`) || PathPrefix(`/healthz`) || PathPrefix(`/get_token`)) traefik.http.routers.livekit-jwt.rule=Host(`livekit.example.com`) && (PathPrefix(`/sfu/get`) || PathPrefix(`/healthz`) || PathPrefix(`/get_token`))
``` ```
</details> </details>
@@ -210,7 +219,7 @@ ### add these to livekit's docker-compose ###
### if you're using `network_mode: host`, you can skip this part ### if you're using `network_mode: host`, you can skip this part
``` ```
Recreate the LiveKit container (with `docker-compose up -d livekit`) to apply these changes. Remember to allow the new `3478/udp` and `50100:50200/udp` ports through your firewall. Recreate the LiveKit container (with `docker-compose up -d livekit`) to apply these changes. Remember to allow the new `3478/udp` and `50300:50400/udp` ports through your firewall.
### Integration with an external TURN server ### Integration with an external TURN server
@@ -257,11 +266,25 @@ ## Testing
First, you will need an access token for your current login session. These can be found in your client's settings or obtained via [this website](https://timedout.uk/mxtoken.html). First, you will need an access token for your current login session. These can be found in your client's settings or obtained via [this website](https://timedout.uk/mxtoken.html).
Then, using that token, request another OpenID token for use with the lk-jwt-service: Then, using that token, fetch the discovery endpoints for MatrixRTC services
```bash ```bash
~$ curl -X POST -H "Authorization: Bearer <session-access-token>" \ curl -X POST -H "Authorization: Bearer <session-access-token>" \
https://matrix.example.com/_matrix/client/unstable/org.matrix.msc4143/rtc/transports
```
In the output, you should see the LiveKit URL matching the one [configured above](#3-telling-clients-where-to-find-livekit).
With the same token, request another OpenID token for use with the lk-jwt-service:
```bash
curl -X POST -H "Authorization: Bearer <session-access-token>" \
https://matrix.example.com/_matrix/client/v3/user/@user:example.com/openid/request_token https://matrix.example.com/_matrix/client/v3/user/@user:example.com/openid/request_token
```
You will see a response as below:
```json
{"access_token":"<openid_access_token>","token_type":"Bearer","matrix_server_name":"example.com","expires_in":3600} {"access_token":"<openid_access_token>","token_type":"Bearer","matrix_server_name":"example.com","expires_in":3600}
``` ```
@@ -296,10 +319,15 @@ ## Testing
```bash ```bash
~$ curl -X POST -d @payload.json https://livekit.example.com/get_token ~$ curl -X POST -d @payload.json https://livekit.example.com/get_token
```
The lk-jwt-service will, after checking against Continuwuity, answer with a `jwt` token to create a LiveKit media room:
```json
{"url":"wss://livekit.example.com","jwt":"a_really_really_long_string"} {"url":"wss://livekit.example.com","jwt":"a_really_really_long_string"}
``` ```
The lk-jwt-service will, after checking against Continuwuity, answer with a `jwt` token to create a LiveKit media room. Use this token to test at the [LiveKit Connection Tester](https://livekit.io/connection-test). If everything works there, then you have set up LiveKit successfully! Use this token to test at the [LiveKit Connection Tester](https://livekit.io/connection-test). If everything works there, then you have set up LiveKit successfully!
## Troubleshooting ## Troubleshooting
@@ -363,8 +391,8 @@ ## Related Documentation
Specifications: Specifications:
- [MatrixRTC proposal](https://github.com/matrix-org/matrix-spec-proposals/pull/4143) - [MSC4143 - MatrixRTC proposal](https://github.com/matrix-org/matrix-spec-proposals/pull/4143)
- [LiveKit proposal](https://github.com/matrix-org/matrix-spec-proposals/pull/4195) - [MSC4195 - LiveKit proposal](https://github.com/matrix-org/matrix-spec-proposals/pull/4195)
Source code: Source code:

View File

@@ -34,6 +34,11 @@
"name": "kubernetes", "name": "kubernetes",
"label": "Kubernetes" "label": "Kubernetes"
}, },
{
"type": "file",
"name": "nomad",
"label": "Nomad"
},
{ {
"type": "file", "type": "file",
"name": "freebsd", "name": "freebsd",

View File

@@ -148,7 +148,7 @@ #### For other reverse proxies
</details> </details>
You will then need to point your reverse proxy towards Continuwuity at `127.0.0.1:8008`. See the [Other reverse proxies](generic.mdx#setting-up-the-reverse-proxy) section of the Generic page for further routing details. See the [Other reverse proxies](generic.mdx#setting-up-the-reverse-proxy) section of the Generic page for further routing details.
### Starting Your Server ### Starting Your Server
@@ -243,9 +243,30 @@ ### (Optional) Building Custom Images
[Building Docker Images](../development/index.mdx#building-docker-images) [Building Docker Images](../development/index.mdx#building-docker-images)
section in the development documentation. section in the development documentation.
### Accessing the Server's Console
Before you can access the server's console and [send admin commands](../reference/admin/index.md) from the CLI, you will need to make the container interactive and allocate a pseudo-tty. Make sure you set `admin_console_automatic` to `true` in [the config](../reference/config.mdx) as well for Continuwuity to activate the CLI on startup.
For Docker Compose deployments this means adding `stdin_open: true` and `tty: true` to the container's declaration:
```yaml
services:
homeserver:
stdin_open: true
tty: true
# ...
```
If you choose to deploy via `docker run`, add the flags `-i`/`--interactive` and `-t`/`--tty` to the command.
From there you can access the server's console by running `docker attach <container-name>`, which will show the server's prompt `uwu> `. To exit `docker attach`, press `CTRL+p` then `CTRL+q`.
Note that using `CTRL+c` within `docker attach`'s context will forward the signal to the server, stopping it. See [Docker's reference][docker-attach-reference] for more information.
[docker-attach-reference]: https://docs.docker.com/reference/cli/docker/container/attach/
## Next steps ## Next steps
- For smooth federation, set up a caching resolver according to the [**DNS tuning guide**](../advanced/dns.mdx) (recommended) - For smooth federation, set up a caching resolver according to the [**DNS tuning guide**](../advanced/dns.mdx) (recommended)
- To set up Audio/Video communication, see the [**Calls**](../calls.mdx) page. - To set up Audio/Video communication, see the [**Calls**](../calls.mdx) page.
- If you want to set up an appservice, take a look at the [**Appservice - If you want to set up an appservice, take a look at the [**Appservice Guide**](../appservices.mdx).
Guide**](../appservices.mdx).

View File

@@ -1,10 +1,12 @@
# Generic deployment documentation # Generic deployment documentation
> ### Getting help :::tip Getting help
> If you run into any problems while setting up Continuwuity, ask us in
> If you run into any problems while setting up Continuwuity, ask us in `#continuwuity:continuwuity.org` or [open an issue on
> `#continuwuity:continuwuity.org` or [open an issue on Forgejo][forgejo-new-issue].
> Forgejo](https://forgejo.ellis.link/continuwuation/continuwuity/issues/new). :::
[forgejo-new-issue]: https://forgejo.ellis.link/continuwuation/continuwuity/issues/new
## Installing Continuwuity ## Installing Continuwuity
@@ -15,17 +17,16 @@ ### Prebuilt binary
Prebuilt binaries are available from: Prebuilt binaries are available from:
- **Tagged releases**: [Latest release page](https://forgejo.ellis.link/continuwuation/continuwuity/releases/latest) - **Tagged releases**: [see Release page][release-page]
- **Development builds**: CI artifacts from the `main` branch - **Development builds**: CI artifacts from the `main` branch,
(includes Debian/Ubuntu packages) [see `release-image.yml` for details][release-image]
When browsing CI artifacts, `ci-bins` contains binaries organised
by commit hash, while `releases` contains tagged versions. Sort
by last modified date to find the most recent builds.
The binaries require jemalloc and io_uring on the host system. Currently The binaries require jemalloc and io_uring on the host system. Currently
we can't cross-build static binaries - contributions are welcome here. we can't cross-build static binaries - contributions are welcome here.
[release-page]: https://forgejo.ellis.link/continuwuation/continuwuity/releases/
[release-image]: https://forgejo.ellis.link/continuwuation/continuwuity/actions/?workflow=release-image.yml
#### Performance-optimised builds #### Performance-optimised builds
For x86_64 systems with CPUs from the last ~15 years, use the For x86_64 systems with CPUs from the last ~15 years, use the
@@ -38,11 +39,12 @@ #### Performance-optimised builds
If you're using Docker instead, equivalent performance-optimised If you're using Docker instead, equivalent performance-optimised
images are available with the `-maxperf` suffix (e.g. images are available with the `-maxperf` suffix (e.g.
`forgejo.ellis.link/continuwuation/continuwuity:latest-maxperf`). `forgejo.ellis.link/continuwuation/continuwuity:latest-maxperf`).
These images use the `release-max-perf` These images use the `release-max-perf` build profile with
build profile with [link-time optimisation (LTO)][lto-rust-docs]
[link-time optimisation (LTO)](https://doc.rust-lang.org/cargo/reference/profiles.html#lto)
and, for amd64, target the haswell CPU architecture. and, for amd64, target the haswell CPU architecture.
[lto-rust-docs]: https://doc.rust-lang.org/cargo/reference/profiles.html#lto
### Nix ### Nix
Theres a Nix package defined in our flake, available for Linux and MacOS. Add continuwuity as an input to your flake, and use `inputs.continuwuity.packages.${system}.default` to get a working Continuwuity package. Theres a Nix package defined in our flake, available for Linux and MacOS. Add continuwuity as an input to your flake, and use `inputs.continuwuity.packages.${system}.default` to get a working Continuwuity package.
@@ -55,7 +57,8 @@ ### Compiling
#### Using Docker #### Using Docker
If you would like to build using docker, you can run the command `docker build -f ./docker/Dockerfile -t forgejo.ellis.link/continuwuation/continuwuity:main .` to compile continuwuity. See the [Building Docker Images](../development/index.mdx#building-docker-images)
section in the development documentation.
#### Manual #### Manual
@@ -69,7 +72,7 @@ ##### Dependencies
##### Build ##### Build
You can build Continuwuity using `cargo build --release`. You can now build Continuwuity using `cargo build --release`.
Continuwuity supports various optional features that can be enabled during compilation. Please see the Cargo.toml file for a comprehensive list, or ask in our rooms. Continuwuity supports various optional features that can be enabled during compilation. Please see the Cargo.toml file for a comprehensive list, or ask in our rooms.
@@ -91,27 +94,6 @@ ## Adding a Continuwuity user
sudo useradd -r --shell /usr/bin/nologin --no-create-home continuwuity sudo useradd -r --shell /usr/bin/nologin --no-create-home continuwuity
``` ```
## Forwarding ports in the firewall or the router
Matrix's default federation port is 8448, and clients must use port 443.
If you would like to use only port 443 or a different port, you will need to set up
delegation. Continuwuity has configuration options for delegation, or you can configure
your reverse proxy to manually serve the necessary JSON files for delegation
(see the `[global.well_known]` config section).
If Continuwuity runs behind a router or in a container and has a different public
IP address than the host system, you need to forward these public ports directly
or indirectly to the port mentioned in the configuration.
Note for NAT users: if you have trouble connecting to your server from inside
your network, check if your router supports "NAT
hairpinning" or "NAT loopback".
If your router does not support this feature, you need to research doing local
DNS overrides and force your Matrix DNS records to use your local IP internally.
This can be done at the host level using `/etc/hosts`. If you need this to be
on the network level, consider something like NextDNS or Pi-Hole.
## Setting up a systemd service ## Setting up a systemd service
You can find an example unit for continuwuity below. You can find an example unit for continuwuity below.
@@ -123,7 +105,7 @@ ## Setting up a systemd service
`/etc/rsyslog.conf` to allow color in logs. `/etc/rsyslog.conf` to allow color in logs.
If you are using a different `database_path` than the systemd unit's If you are using a different `database_path` than the systemd unit's
configured default `/var/lib/conduwuit`, you need to add your path to the configured default (`/var/lib/conduwuit`), you need to add your path to the
systemd unit's `ReadWritePaths=`. You can do this by either directly editing systemd unit's `ReadWritePaths=`. You can do this by either directly editing
`conduwuit.service` and reloading systemd, or by running `systemctl edit conduwuit.service` `conduwuit.service` and reloading systemd, or by running `systemctl edit conduwuit.service`
and entering the following: and entering the following:
@@ -144,7 +126,9 @@ ### Example systemd Unit File
</details> </details>
You can also [view the file on Foregejo](https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/pkg/conduwuit.service). You can also [view the file on Foregejo][systemd-file].
[systemd-file]: https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/pkg/conduwuit.service
## Creating the Continuwuity configuration file ## Creating the Continuwuity configuration file
@@ -155,9 +139,7 @@ ## Creating the Continuwuity configuration file
**Please take a moment to read the config. You need to change at least the **Please take a moment to read the config. You need to change at least the
server name.** server name.**
RocksDB is the only supported database backend. ### Setting the correct file permissions
## Setting the correct file permissions
If you are using a dedicated user for Continuwuity, you need to allow it to If you are using a dedicated user for Continuwuity, you need to allow it to
read the configuration. To do this, run: read the configuration. To do this, run:
@@ -175,22 +157,29 @@ ## Setting the correct file permissions
sudo chmod 700 /var/lib/conduwuit/ sudo chmod 700 /var/lib/conduwuit/
``` ```
## Setting up the Reverse Proxy ## Exposing ports in the firewall or the router
We recommend Caddy as a reverse proxy because it is trivial to use and handles TLS certificates, reverse proxy headers, etc. transparently with proper defaults. Matrix's default federation port is **:8448**, and clients use port **:443**. You will need to
For other software, please refer to their respective documentation or online guides. expose these ports on your firewall or router. If you use UFW, the commands to allow them
are: `ufw allow 8448/tcp` and `ufw allow 443/tcp`.
:::tip Alternative port/domain setups
If you would like to use only port 443, a different port, or a subdomain for the homeserver, you will need to set up `.well-known` delegation. Consult the `[global.well_known]` section of the config file, and the [**Delegation/Split-domain**](../advanced/delegation) page to learn more about these kinds of deployments.
:::
## Setting up the Reverse Proxy
### Caddy ### Caddy
After installing Caddy via your preferred method, create `/etc/caddy/conf.d/conduwuit_caddyfile` Caddy is the recommended reverse proxy as it is easy to use, has good defaults,
and enter the following (substitute your actual server name): and handle TLS certificates automatically. After installing Caddy via your preferred
method, create `/etc/caddy/conf.d/conduwuit_caddyfile` and enter the following
(substitute `example.com` with your actual server name):
``` ```
your.server.name, your.server.name:8448 { example.com, example.com:8448 {
# TCP reverse_proxy # TCP reverse_proxy
reverse_proxy 127.0.0.1:6167 reverse_proxy 127.0.0.1:8008
# UNIX socket
#reverse_proxy unix//run/conduwuit/conduwuit.sock
} }
``` ```
@@ -202,51 +191,45 @@ ### Caddy
### Other Reverse Proxies ### Other Reverse Proxies
As we prefer our users to use Caddy, we do not provide configuration files for other proxies. Normally, your reverse proxy should route everything from port :8448 and :443 back to Continuwuity.
You will need to reverse proxy everything under the following routes: For more granular controls, you will need to proxy everything under these following routes:
- `/_matrix/` - core Matrix C-S and S-S APIs - `/_matrix/` - core Matrix APIs, which includes:
- `/_conduwuit/` and/or `/_continuwuity/` - ad-hoc Continuwuity routes such as `/local_user_count` and
`/server_version` - `/_matrix/federation` and `/_matrix/key` - core Server-Server APIs. These should be available on port :8448
- `/_matrix/client` - core Client-Server APIs. These should be available on port :443
- `/_conduwuit/` and `/_continuwuity/` - ad-hoc Continuwuity routes for password resets, email verification, and server details such as `/local_user_count` and `/server_version`.
You can optionally reverse proxy the following individual routes: You can optionally reverse proxy the following individual routes:
- `/.well-known/matrix/client` and `/.well-known/matrix/server` if using - `/.well-known/matrix/client` and `/.well-known/matrix/server` if using
Continuwuity to perform delegation (see the `[global.well_known]` config section) Continuwuity to perform delegation (see the `[global.well_known]` config section)
- `/.well-known/matrix/support` if using Continuwuity to send the homeserver admin - `/.well-known/matrix/support` if using Continuwuity to send the homeserver admin
contact and support page (formerly known as MSC1929) [contact and support page][well-known-support]
- `/` if you would like to see `hewwo from conduwuit woof!` at the root - `/` and `/_continuwuity/logo.svg` if you would like to see the Continuwuity landing page
See the following spec pages for more details on these files: Refer to the respective software's documentation and online guides on how to do so.
- [`/.well-known/matrix/server`](https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixserver) [well-known-support]: https://spec.matrix.org/v1.18/client-server-api/#getwell-knownmatrixsupport
- [`/.well-known/matrix/client`](https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixclient)
- [`/.well-known/matrix/support`](https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixsupport)
Examples of delegation: #### Caveats for specific reverse proxies
- https://continuwuity.org/.well-known/matrix/server - Lighttpd is not supported as it appears to interfere with the `X-Matrix` Authorization
- https://continuwuity.org/.well-known/matrix/client
- https://ellis.link/.well-known/matrix/server
- https://ellis.link/.well-known/matrix/client
For Apache and Nginx there are many examples available online.
Lighttpd is not supported as it appears to interfere with the `X-Matrix` Authorization
header, making federation non-functional. If you find a workaround, please share it so we can add it to this documentation. header, making federation non-functional. If you find a workaround, please share it so we can add it to this documentation.
If using Apache, you need to use `nocanon` in your `ProxyPass` directive to prevent httpd from interfering with the `X-Matrix` header (note that Apache is not ideal as a general reverse proxy, so we discourage using it if alternatives are available). - If using Apache, you need to use `nocanon` in your `ProxyPass` directive to prevent httpd from interfering with the `X-Matrix` header (note that Apache is not ideal as a general reverse proxy, so we discourage using it if alternatives are available).
If using Nginx, you need to pass the request URI to Continuwuity using `$request_uri`, like this: - If using Nginx, you need to pass the request URI to Continuwuity using `$request_uri`, like this:
- `proxy_pass http://127.0.0.1:6167$request_uri;` - `proxy_pass http://127.0.0.1:6167$request_uri;`
- `proxy_pass http://127.0.0.1:6167;` - `proxy_pass http://127.0.0.1:6167;`
Nginx users need to increase the `client_max_body_size` setting (default is 1M) to match the Furthermore, Nginx users need to increase the `client_max_body_size` setting (default is 1M) to match the `max_request_size` defined in conduwuit.toml.
`max_request_size` defined in conduwuit.toml.
## You're done ## Starting Your Server
Now you can start Continuwuity with: Now you can start Continuwuity with:
@@ -260,36 +243,53 @@ ## You're done
sudo systemctl enable conduwuit sudo systemctl enable conduwuit
``` ```
## How do I know it works? Check Continuwuity logs with the following command:
You can open [a Matrix client](https://matrix.org/ecosystem/clients), enter your
homeserver address, and try to register.
You can also use these commands as a quick health check (replace
`your.server.name`).
```bash ```bash
curl https://your.server.name/_conduwuit/server_version sudo journalctl -u conduwuit.service
# If using port 8448
curl https://your.server.name:8448/_conduwuit/server_version
# If federation is enabled
curl https://your.server.name:8448/_matrix/federation/v1/version
``` ```
- To check if your server can communicate with other homeservers, use the If Continuwuity has successfully initialized, you'll see output as below.
[Matrix Federation Tester](https://federationtester.mtrnord.blog/). If you can
register but cannot join federated rooms, check your configuration and verify ```
that port 8448 is open and forwarded correctly. In order to use your new homeserver, you need to create its
first user account.
Open your Matrix client of choice and register an account
on example.com using registration token x5keUZ811RqvLsNa .
Pick your own username and password!
```
You can then open [a Matrix client][matrix-clients],
enter your homeserver address, and try to register with the provided token.
By default, the first user is the instance's first admin. They will be added
to the `#admin:example.com` room and be able to [issue admin commands](../reference/admin/index.md).
[matrix-clients]: https://matrix.org/ecosystem/clients
## How do I know it works?
To check if your server can communicate with other homeservers, use the
[Matrix Federation Tester](https://federationtester.mtrnord.blog/). If you can
register your account but cannot join federated rooms, check your configuration
and verify that your federation endpoints are opened and forwarded correctly.
As a quick health check, you can also use these cURL commands:
```bash
curl https://example.com/_conduwuit/server_version
# If using port 8448
curl https://example.com:8448/_conduwuit/server_version
# If federation is enabled
curl https://example.com:8448/_matrix/federation/v1/version
# For client-server endpoints
curl https://example.com/_matrix/client/versions
```
## What's next? ## What's next?
### Audio/Video calls - For smooth federation, set up a caching resolver according to the [**DNS tuning guide**](../advanced/dns.mdx) (recommended)
- For Audio/Video call functionality see the [**Calls**](../calls.md) page.
For Audio/Video call functionality see the [Calls](../calls.md) page. - If you want to set up an appservice, take a look at the [**Appservice Guide**](../appservices.md).
### Appservices
If you want to set up an appservice, take a look at the [Appservice
Guide](../appservices.md).

118
docs/deploying/nomad.mdx Normal file
View File

@@ -0,0 +1,118 @@
# Continuwuity for Nomad
You can either pass the configuration as environment variables or mount a file containing the configuration from consul.
This given configuration assumes that you have a traefik reverse proxy running.
## Persistence
The database being a RockDB file, it is recommended to use a volume to persist the data.
The example below uses a volume, you need to configure the CSI driver on your cluster.
| Volume Name | Mount Path | Purpose |
|-------------|------------|---------|
| continuwuity-volume | `/var/lib/continuwuity` | Store the database |
| continuwuity-media-volume | `/var/lib/continuwuity/media` | Store uploaded media |
## Configuration
### Using environment variables
```hcl
job "continuwuity" {
datacenters = ["dc1"]
type = "service"
node_pool = "default"
group "continuwuity" {
count = 1
network {
port "http" {
static = 6167
}
}
service {
name = "continuwuity"
port = "http"
tags = [
"traefik.enable=true",
"traefik.http.routers.continuwuity.rule=(Host(`matrix.example.com`) || (Host(`example.com`) && PathPrefix(`/.well-known/matrix`)))",
"traefik.http.routers.continuwuity.entrypoints=https",
"traefik.http.routers.continuwuity.tls=true",
"traefik.http.routers.continuwuity.tls.certresolver=letsencrypt",
"traefik.http.routers.continuwuity-http.rule=(Host(`matrix.example.com`) || (Host(`example.com`) && PathPrefix(`/.well-known/matrix`)))",
"traefik.http.routers.continuwuity-http.entrypoints=http",
"traefik.http.routers.continuwuity-http.middlewares=continuwuity-redirect",
"traefik.http.middlewares.continuwuity-redirect.redirectscheme.scheme=https",
"traefik.http.middlewares.continuwuity-redirect.redirectscheme.permanent=true",
]
}
volume "continuwuity-volume" {
type = "csi"
read_only = false
source = "continuwuity-volume"
attachment_mode = "file-system"
access_mode = "single-node-writer"
per_alloc = false
}
volume "continuwuity-media-volume" {
type = "csi"
read_only = false
source = "continuwuity-media-volume"
attachment_mode = "file-system"
access_mode = "single-node-writer"
per_alloc = false
mount_options {
mount_flags = []
}
}
task "continuwuity" {
driver = "docker"
env {
CONTINUWUITY_SERVER_NAME = "matrix.example.com"
CONTINUWUITY_TRUSTED_SERVERS = "[\"matrix.org\", \"mozilla.org\"]"
CONTINUWUITY_ALLOW_REGISTRATION = false
CONTINUWUITY_ADDRESS = "0.0.0.0"
CONTINUWUITY_PORT = 6167
CONTINUWUITY_DATABASE_PATH = "/var/lib/continuwuity"
CONTINUWUITY_WELL_KNOWN = <<EOF
{
client=https://matrix.example.com,
server=matrix.example.com:443
}
EOF
}
config {
image = "forgejo.ellis.link/continuwuation/continuwuity:latest"
ports = ["http"]
}
volume_mount {
volume = "continuwuity-volume"
destination = "/var/lib/continuwuity"
}
volume_mount {
volume = "continuwuity-media-volume"
destination = "/var/lib/continuwuity/media"
}
}
}
}
```
### Using consul
```hcl
...
template {
data = <<EOF
{{key "config/continuwuity"}}
EOF
destination = "local/conduwuit.toml"
}
...
```

View File

@@ -6,10 +6,10 @@
"message": "Welcome to Continuwuity! Important announcements about the project will appear here." "message": "Welcome to Continuwuity! Important announcements about the project will appear here."
}, },
{ {
"id": 11, "id": 12,
"mention_room": false, "mention_room": false,
"date": "2026-04-17", "date": "2026-04-24",
"message": "[v0.5.7](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.7) is out! Email verification! Terms and Conditions! Deleting notification pushers! So much good stuff. Go grab the release and read the changelog!" "message": "[v0.5.8](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.8) is out! This is a patch release which fixes a bug in 0.5.7's email support -- upgrade soon if you use that feature."
} }
] ]
} }

View File

@@ -0,0 +1,43 @@
# Continuwuity - Behind Traefik Reverse Proxy
services:
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
#- ./continuwuity.toml:/etc/continuwuity.toml
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.continuwuity.rule=(Host(`matrix.example.com`) || (Host(`example.com`) && PathPrefix(`/.well-known/matrix`)))"
- "traefik.http.routers.continuwuity.entrypoints=websecure" # your HTTPS entry point
- "traefik.http.routers.continuwuity.tls=true"
- "traefik.http.routers.continuwuity.service=continuwuity"
- "traefik.http.services.continuwuity.loadbalancer.server.port=8008"
# possibly, depending on your config:
# - "traefik.http.routers.continuwuity.tls.certresolver=letsencrypt"
environment:
CONTINUWUITY_SERVER_NAME: example.com # EDIT THIS
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008 # This must match with traefik's loadbalancer label
#CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
# Serve .well-known files to tell others to reach Continuwuity on port :443
CONTINUWUITY_WELL_KNOWN: |
{
client=https://matrix.example.com,
server=matrix.example.com:443
}
volumes:
db:
networks:
# This must match the network name that Traefik listens on
proxy:
external: true

View File

@@ -0,0 +1,54 @@
# Continuwuity - With Caddy Labels
services:
caddy:
# This compose file uses caddy-docker-proxy as the reverse proxy for Continuwuity!
# For more info, visit https://github.com/lucaslorentz/caddy-docker-proxy
image: "docker.io/lucaslorentz/caddy-docker-proxy:ci-alpine"
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=caddy
networks:
- caddy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
restart: unless-stopped
labels:
caddy: example.com
caddy.reverse_proxy: /.well-known/matrix/* homeserver:8008
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
#- ./continuwuity.toml:/etc/continuwuity.toml
environment:
CONTINUWUITY_SERVER_NAME: example.com # EDIT THIS
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
#CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
# Serve .well-known files to tell others to reach Continuwuity on port :443
CONTINUWUITY_WELL_KNOWN: |
{
client=https://matrix.example.com,
server=matrix.example.com:443
}
networks:
- caddy
labels:
caddy: matrix.example.com
caddy.reverse_proxy: "{{upstreams 8008}}"
volumes:
db:
networks:
caddy:

View File

@@ -0,0 +1,57 @@
# Continuwuity - Using Caddy Docker Image
services:
caddy:
image: "docker.io/caddy:latest"
ports:
- 80:80
- 443:443
networks:
- caddy
volumes:
- ./data:/data
restart: unless-stopped
configs:
- source: Caddyfile
target: /etc/caddy/Caddyfile
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
#- ./continuwuity.toml:/etc/continuwuity.toml
environment:
CONTINUWUITY_SERVER_NAME: example.com
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
#CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
## Serve .well-known files to tell others to reach Continuwuity on port :443
CONTINUWUITY_WELL_KNOWN: |
{
client=https://matrix.example.com,
server=matrix.example.com:443
}
networks:
- caddy
networks:
caddy:
volumes:
db:
configs:
Caddyfile:
content: |
https://matrix.example.com:443 {
reverse_proxy http://homeserver:8008
}
https://example.com:443 {
reverse_proxy /.well-known/matrix* http://homeserver:8008
}

View File

@@ -0,0 +1,85 @@
# Continuwuity - With Traefik Reverse Proxy
services:
homeserver:
image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped
command: /sbin/conduwuit
volumes:
- db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
#- ./continuwuity.toml:/etc/continuwuity.toml
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.continuwuity.rule=(Host(`matrix.example.com`) || (Host(`example.com`) && PathPrefix(`/.well-known/matrix`)))"
- "traefik.http.routers.continuwuity.entrypoints=websecure"
- "traefik.http.routers.continuwuity.tls.certresolver=letsencrypt"
- "traefik.http.services.continuwuity.loadbalancer.server.port=8008"
environment:
CONTINUWUITY_SERVER_NAME: example.com # EDIT THIS
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008 # This must match with traefik's loadbalancer label
#CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
# Serve .well-known files to tell others to reach Continuwuity on port :443
CONTINUWUITY_WELL_KNOWN: |
{
client=https://matrix.example.com,
server=matrix.example.com:443
}
traefik:
image: "docker.io/traefik:latest"
container_name: "traefik"
restart: "unless-stopped"
ports:
- "80:80"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "acme:/etc/traefik/acme"
labels:
- "traefik.enable=true"
# middleware redirect
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
# global redirect to https
- "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.redirs.entrypoints=web"
- "traefik.http.routers.redirs.middlewares=redirect-to-https"
environment:
TRAEFIK_LOG_LEVEL: DEBUG
TRAEFIK_ENTRYPOINTS_WEB: true
TRAEFIK_ENTRYPOINTS_WEB_ADDRESS: ":80"
TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_TO: websecure
TRAEFIK_ENTRYPOINTS_WEBSECURE: true
TRAEFIK_ENTRYPOINTS_WEBSECURE_ADDRESS: ":443"
TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_TLS_CERTRESOLVER: letsencrypt
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT: true
# CHANGE THIS to desired email for ACME
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_EMAIL: user@example.com
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_HTTPCHALLENGE: true
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_HTTPCHALLENGE_ENTRYPOINT: web
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_STORAGE: "/etc/traefik/acme/acme.json"
# Since Traefik 3.6.3, paths with certain "encoded characters" are now blocked by default; we need a couple, or else things *will* break
TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDSLASH: true
TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDHASH: true
TRAEFIK_PROVIDERS_DOCKER: true
TRAEFIK_PROVIDERS_DOCKER_ENDPOINT: "unix:///var/run/docker.sock"
TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT: false
volumes:
db:
acme:
networks:
proxy:

View File

@@ -2,7 +2,7 @@
services: services:
homeserver: homeserver:
image: forgejo.ellis.link/continuwuation/continuwuity:latest image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped restart: unless-stopped
command: /sbin/conduwuit command: /sbin/conduwuit
volumes: volumes:
@@ -38,7 +38,6 @@ volumes:
db: db:
networks: networks:
# This is the network Traefik listens to, if your network has a different # This must match the network name that Traefik listens on
# name, don't forget to change it here and in the docker-compose.override.yml
proxy: proxy:
external: true external: true

View File

@@ -1,4 +1,4 @@
# Continuwuity - Traefik Reverse Proxy Labels # Continuwuity - Traefik Reverse Proxy Labels (override file)
services: services:
homeserver: homeserver:
@@ -14,13 +14,10 @@ services:
# This must match with CONTINUWUITY_PORT (default: 8008) # This must match with CONTINUWUITY_PORT (default: 8008)
- "traefik.http.services.to_continuwuity.loadbalancer.server.port=8008" - "traefik.http.services.to_continuwuity.loadbalancer.server.port=8008"
- "traefik.http.middlewares.cors-headers.headers.accessControlAllowOriginList=*"
- "traefik.http.middlewares.cors-headers.headers.accessControlAllowHeaders=Origin, X-Requested-With, Content-Type, Accept, Authorization"
- "traefik.http.middlewares.cors-headers.headers.accessControlAllowMethods=GET, POST, PUT, DELETE, OPTIONS"
# If you want to have your account on <DOMAIN>, but host Continuwuity on a subdomain, # If you want to have your account on <DOMAIN>, but host Continuwuity on a subdomain,
# you can let it only handle the well known file on that domain instead # you can let it only handle the well known file on the base domain instead
#- "traefik.http.routers.to-matrix-wellknown.rule=Host(`example.com`) && PathPrefix(`/.well-known/matrix`)" #
# - "traefik.http.routers.to-matrix-wellknown.rule=Host(`example.com`) && PathPrefix(`/.well-known/matrix`)"
#- "traefik.http.routers.to-matrix-wellknown.tls=true" #- "traefik.http.routers.to-matrix-wellknown.tls=true"
#- "traefik.http.routers.to-matrix-wellknown.tls.certresolver=letsencrypt" #- "traefik.http.routers.to-matrix-wellknown.tls.certresolver=letsencrypt"
#- "traefik.http.routers.to-matrix-wellknown.middlewares=cors-headers@docker" #- "traefik.http.routers.to-matrix-wellknown.middlewares=cors-headers@docker"

View File

@@ -1,8 +1,10 @@
# Continuwuity - With Caddy Labels
services: services:
caddy: caddy:
# This compose file uses caddy-docker-proxy as the reverse proxy for Continuwuity! # This compose file uses caddy-docker-proxy as the reverse proxy for Continuwuity!
# For more info, visit https://github.com/lucaslorentz/caddy-docker-proxy # For more info, visit https://github.com/lucaslorentz/caddy-docker-proxy
image: lucaslorentz/caddy-docker-proxy:ci-alpine image: "docker.io/lucaslorentz/caddy-docker-proxy:ci-alpine"
ports: ports:
- 80:80 - 80:80
- 443:443 - 443:443
@@ -16,7 +18,7 @@ services:
restart: unless-stopped restart: unless-stopped
homeserver: homeserver:
image: forgejo.ellis.link/continuwuation/continuwuity:latest image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped restart: unless-stopped
command: /sbin/conduwuit command: /sbin/conduwuit
volumes: volumes:

View File

@@ -1,6 +1,8 @@
# Continuwuity - Using Caddy Docker Image
services: services:
caddy: caddy:
image: docker.io/caddy:latest image: "docker.io/caddy:latest"
ports: ports:
- 80:80 - 80:80
- 443:443 - 443:443
@@ -15,7 +17,7 @@ services:
target: /etc/caddy/Caddyfile target: /etc/caddy/Caddyfile
homeserver: homeserver:
image: forgejo.ellis.link/continuwuation/continuwuity:latest image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped restart: unless-stopped
command: /sbin/conduwuit command: /sbin/conduwuit
volumes: volumes:
@@ -37,7 +39,6 @@ services:
# server=example.com:443 # server=example.com:443
# } # }
networks: networks:
- caddy - caddy
@@ -48,8 +49,8 @@ volumes:
db: db:
configs: configs:
dynamic.yml: Caddyfile:
content: | content: |
https://example.com, https://example.com:8448 { https://example.com:443, https://example.com:8448 {
reverse_proxy http://homeserver:8008 reverse_proxy http://homeserver:8008
} }

View File

@@ -1,8 +1,8 @@
# Continuwuity - Behind Traefik Reverse Proxy # Continuwuity - With Traefik Reverse Proxy
services: services:
homeserver: homeserver:
image: forgejo.ellis.link/continuwuation/continuwuity:latest image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped restart: unless-stopped
command: /sbin/conduwuit command: /sbin/conduwuit
volumes: volumes:
@@ -32,14 +32,14 @@ services:
} }
traefik: traefik:
image: "traefik:latest" image: "docker.io/traefik:latest"
container_name: "traefik" container_name: "traefik"
restart: "unless-stopped" restart: "unless-stopped"
ports: ports:
- "80:80" - "80:80"
- "443:443" - "443:443"
volumes: volumes:
- "/var/run/docker.sock:/var/run/docker.sock:z" - "/var/run/docker.sock:/var/run/docker.sock:ro"
- "acme:/etc/traefik/acme" - "acme:/etc/traefik/acme"
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
@@ -52,6 +52,7 @@ services:
- "traefik.http.routers.redirs.middlewares=redirect-to-https" - "traefik.http.routers.redirs.middlewares=redirect-to-https"
environment: environment:
TRAEFIK_LOG_LEVEL: DEBUG TRAEFIK_LOG_LEVEL: DEBUG
TRAEFIK_ENTRYPOINTS_WEB: true TRAEFIK_ENTRYPOINTS_WEB: true
TRAEFIK_ENTRYPOINTS_WEB_ADDRESS: ":80" TRAEFIK_ENTRYPOINTS_WEB_ADDRESS: ":80"

View File

@@ -1,12 +1,23 @@
# Continuwuity # Continuwuity - Bare Configuration (for other reverse proxies)
services: services:
homeserver: homeserver:
image: forgejo.ellis.link/continuwuation/continuwuity:latest image: "forgejo.ellis.link/continuwuation/continuwuity:latest"
restart: unless-stopped restart: unless-stopped
command: /sbin/conduwuit command: /sbin/conduwuit
ports: ports:
# If your reverse proxy is on the host, use this
# and configure it to connect to `127.0.0.1:8008`
- 127.0.0.1:8008:8008 - 127.0.0.1:8008:8008
# If your reverse proxy is on another machine, use this
# and configure it to connect to <this-machine-ip>:8008
# - 8008:8008
# If your reverse proxy is a docker container on the same network,
# comment out the entire `ports` section, and configure it to connect to `continuwuity:8008`
volumes: volumes:
- db:/var/lib/continuwuity - db:/var/lib/continuwuity
- ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's - ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
@@ -26,6 +37,5 @@ services:
# server=example.com:443 # server=example.com:443
# } # }
volumes: volumes:
db: db:

View File

@@ -7,7 +7,7 @@ ## Running commands
* All commands listed here may be used by server administrators in the admin room by sending them as messages. * All commands listed here may be used by server administrators in the admin room by sending them as messages.
* If the `admin_escape_commands` configuration option is enabled, server administrators may run certain commands in public rooms by prefixing them with a single backslash. These commands will only run on _their_ homeserver, even if they are a member of another homeserver's admin room. Some sensitive commands cannot be used outside the admin room and will return an error. * If the `admin_escape_commands` configuration option is enabled, server administrators may run certain commands in public rooms by prefixing them with a single backslash. These commands will only run on _their_ homeserver, even if they are a member of another homeserver's admin room. Some sensitive commands cannot be used outside the admin room and will return an error.
* All commands listed here may be used in the server's console, if it is enabled. Commands entered in the console do not require the `!admin` prefix. * All commands listed here may be used in the server's console, if it is enabled. Commands entered in the console do not require the `!admin` prefix. If Continuwuity is deployed via Docker, be sure to set the appropriate options detailed in [the Docker deployment guide](../../deploying/docker.mdx#accessing-the-servers-console) to enable access to the server's console.
## Categories ## Categories

View File

@@ -20,7 +20,11 @@ export default defineConfig({
'/deploying/docker-compose.for-traefik.yml', '/deploying/docker-compose.for-traefik.yml',
'/deploying/docker-compose.with-traefik.yml', '/deploying/docker-compose.with-traefik.yml',
`/deploying/docker-compose.override.yml`, `/deploying/docker-compose.override.yml`,
`/deploying/docker-compose.yml` `/deploying/docker-compose.yml`,
'/advanced/delegated.docker-compose.with-caddy.yml',
'/advanced/delegated.docker-compose.with-caddy-labels.yml',
'/advanced/delegated.docker-compose.for-traefik.yml',
'/advanced/delegated.docker-compose.with-traefik.yml',
] ]
}, },
}, },

View File

@@ -29,10 +29,6 @@ gzip_compression = [
"conduwuit-service/gzip_compression", "conduwuit-service/gzip_compression",
"reqwest/gzip", "reqwest/gzip",
] ]
http3 = [
"conduwuit-core/http3",
"conduwuit-service/http3",
]
io_uring = [ io_uring = [
"conduwuit-service/io_uring", "conduwuit-service/io_uring",
] ]

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Event, Result, err, info, Err, Event, Result, err, info,
pdu::PduBuilder, pdu::PduBuilder,
@@ -48,7 +48,7 @@
#[tracing::instrument(skip_all, fields(%client), name = "register_available", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "register_available", level = "info")]
pub(crate) async fn get_register_available_route( pub(crate) async fn get_register_available_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_username_availability::v3::Request>, body: Ruma<get_username_availability::v3::Request>,
) -> Result<get_username_availability::v3::Response> { ) -> Result<get_username_availability::v3::Response> {
// Validate user id // Validate user id
@@ -110,7 +110,7 @@ pub(crate) async fn get_register_available_route(
#[tracing::instrument(skip_all, fields(%client), name = "change_password", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "change_password", level = "info")]
pub(crate) async fn change_password_route( pub(crate) async fn change_password_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<change_password::v3::Request>, body: Ruma<change_password::v3::Request>,
) -> Result<change_password::v3::Response> { ) -> Result<change_password::v3::Response> {
let identity = if let Some(ref user_id) = body.sender_user { let identity = if let Some(ref user_id) = body.sender_user {
@@ -272,7 +272,7 @@ pub(crate) async fn whoami_route(
#[tracing::instrument(skip_all, fields(%client), name = "deactivate", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "deactivate", level = "info")]
pub(crate) async fn deactivate_route( pub(crate) async fn deactivate_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<deactivate::v3::Request>, body: Ruma<deactivate::v3::Request>,
) -> Result<deactivate::v3::Response> { ) -> Result<deactivate::v3::Response> {
// Authentication for this endpoint is technically optional, // Authentication for this endpoint is technically optional,

View File

@@ -1,7 +1,7 @@
use std::{collections::HashMap, fmt::Write}; use std::{collections::HashMap, fmt::Write};
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Result, debug_info, error, info, Err, Result, debug_info, error, info,
utils::{self}, utils::{self},
@@ -52,7 +52,7 @@
#[tracing::instrument(skip_all, fields(%client), name = "register", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "register", level = "info")]
pub(crate) async fn register_route( pub(crate) async fn register_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<register::v3::Request>, body: Ruma<register::v3::Request>,
) -> Result<register::v3::Response> { ) -> Result<register::v3::Response> {
let is_guest = body.kind == RegistrationKind::Guest; let is_guest = body.kind == RegistrationKind::Guest;

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{Err, Result, at}; use conduwuit::{Err, Result, at};
use futures::StreamExt; use futures::StreamExt;
use ruma::api::client::dehydrated_device::{ use ruma::api::client::dehydrated_device::{
@@ -18,7 +18,7 @@
#[tracing::instrument(skip_all, fields(%client))] #[tracing::instrument(skip_all, fields(%client))]
pub(crate) async fn put_dehydrated_device_route( pub(crate) async fn put_dehydrated_device_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<put_dehydrated_device::Request>, body: Ruma<put_dehydrated_device::Request>,
) -> Result<put_dehydrated_device::Response> { ) -> Result<put_dehydrated_device::Response> {
let sender_user = body let sender_user = body
@@ -42,7 +42,7 @@ pub(crate) async fn put_dehydrated_device_route(
#[tracing::instrument(skip_all, fields(%client))] #[tracing::instrument(skip_all, fields(%client))]
pub(crate) async fn delete_dehydrated_device_route( pub(crate) async fn delete_dehydrated_device_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<delete_dehydrated_device::Request>, body: Ruma<delete_dehydrated_device::Request>,
) -> Result<delete_dehydrated_device::Response> { ) -> Result<delete_dehydrated_device::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();
@@ -60,7 +60,7 @@ pub(crate) async fn delete_dehydrated_device_route(
#[tracing::instrument(skip_all, fields(%client))] #[tracing::instrument(skip_all, fields(%client))]
pub(crate) async fn get_dehydrated_device_route( pub(crate) async fn get_dehydrated_device_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_dehydrated_device::Request>, body: Ruma<get_dehydrated_device::Request>,
) -> Result<get_dehydrated_device::Response> { ) -> Result<get_dehydrated_device::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();
@@ -79,7 +79,7 @@ pub(crate) async fn get_dehydrated_device_route(
#[tracing::instrument(skip_all, fields(%client))] #[tracing::instrument(skip_all, fields(%client))]
pub(crate) async fn get_dehydrated_events_route( pub(crate) async fn get_dehydrated_events_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_events::Request>, body: Ruma<get_events::Request>,
) -> Result<get_events::Response> { ) -> Result<get_events::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{Err, Result, debug, err, utils}; use conduwuit::{Err, Result, debug, err, utils};
use futures::StreamExt; use futures::StreamExt;
use ruma::{ use ruma::{
@@ -50,7 +50,7 @@ pub(crate) async fn get_device_route(
#[tracing::instrument(skip_all, fields(%client), name = "update_device", level = "debug")] #[tracing::instrument(skip_all, fields(%client), name = "update_device", level = "debug")]
pub(crate) async fn update_device_route( pub(crate) async fn update_device_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<update_device::v3::Request>, body: Ruma<update_device::v3::Request>,
) -> Result<update_device::v3::Response> { ) -> Result<update_device::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,7 +1,7 @@
use std::iter::once; use std::iter::once;
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Event, Result, RoomVersion, err, info, Err, Event, Result, RoomVersion, err, info,
utils::{ utils::{
@@ -51,7 +51,7 @@
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "publicrooms", level = "info")]
pub(crate) async fn get_public_rooms_filtered_route( pub(crate) async fn get_public_rooms_filtered_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_public_rooms_filtered::v3::Request>, body: Ruma<get_public_rooms_filtered::v3::Request>,
) -> Result<get_public_rooms_filtered::v3::Response> { ) -> Result<get_public_rooms_filtered::v3::Response> {
if let Some(server) = &body.server { if let Some(server) = &body.server {
@@ -87,7 +87,7 @@ pub(crate) async fn get_public_rooms_filtered_route(
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "publicrooms", level = "info")]
pub(crate) async fn get_public_rooms_route( pub(crate) async fn get_public_rooms_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_public_rooms::v3::Request>, body: Ruma<get_public_rooms::v3::Request>,
) -> Result<get_public_rooms::v3::Response> { ) -> Result<get_public_rooms::v3::Response> {
if let Some(server) = &body.server { if let Some(server) = &body.server {
@@ -123,7 +123,7 @@ pub(crate) async fn get_public_rooms_route(
#[tracing::instrument(skip_all, fields(%client), name = "room_directory", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "room_directory", level = "info")]
pub(crate) async fn set_room_visibility_route( pub(crate) async fn set_room_visibility_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<set_room_visibility::v3::Request>, body: Ruma<set_room_visibility::v3::Request>,
) -> Result<set_room_visibility::v3::Response> { ) -> Result<set_room_visibility::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,7 +1,7 @@
use std::time::Duration; use std::time::Duration;
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Result, err, Err, Result, err,
utils::{self, content_disposition::make_content_disposition, math::ruma_from_usize}, utils::{self, content_disposition::make_content_disposition, math::ruma_from_usize},
@@ -49,7 +49,7 @@ pub(crate) async fn get_media_config_route(
)] )]
pub(crate) async fn create_content_route( pub(crate) async fn create_content_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<create_content::v3::Request>, body: Ruma<create_content::v3::Request>,
) -> Result<create_content::v3::Response> { ) -> Result<create_content::v3::Response> {
let user = body.sender_user(); let user = body.sender_user();
@@ -99,7 +99,7 @@ pub(crate) async fn create_content_route(
)] )]
pub(crate) async fn get_content_thumbnail_route( pub(crate) async fn get_content_thumbnail_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content_thumbnail::v1::Request>, body: Ruma<get_content_thumbnail::v1::Request>,
) -> Result<get_content_thumbnail::v1::Response> { ) -> Result<get_content_thumbnail::v1::Response> {
let user = body.sender_user(); let user = body.sender_user();
@@ -148,7 +148,7 @@ pub(crate) async fn get_content_thumbnail_route(
)] )]
pub(crate) async fn get_content_route( pub(crate) async fn get_content_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content::v1::Request>, body: Ruma<get_content::v1::Request>,
) -> Result<get_content::v1::Response> { ) -> Result<get_content::v1::Response> {
let user = body.sender_user(); let user = body.sender_user();
@@ -194,7 +194,7 @@ pub(crate) async fn get_content_route(
)] )]
pub(crate) async fn get_content_as_filename_route( pub(crate) async fn get_content_as_filename_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content_as_filename::v1::Request>, body: Ruma<get_content_as_filename::v1::Request>,
) -> Result<get_content_as_filename::v1::Response> { ) -> Result<get_content_as_filename::v1::Response> {
let user = body.sender_user(); let user = body.sender_user();
@@ -241,7 +241,7 @@ pub(crate) async fn get_content_as_filename_route(
)] )]
pub(crate) async fn get_media_preview_route( pub(crate) async fn get_media_preview_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_media_preview::v1::Request>, body: Ruma<get_media_preview::v1::Request>,
) -> Result<get_media_preview::v1::Response> { ) -> Result<get_media_preview::v1::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,7 +1,7 @@
#![allow(deprecated)] #![allow(deprecated)]
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Result, err, Err, Result, err,
utils::{content_disposition::make_content_disposition, math::ruma_from_usize}, utils::{content_disposition::make_content_disposition, math::ruma_from_usize},
@@ -52,7 +52,7 @@ pub(crate) async fn get_media_config_legacy_legacy_route(
#[tracing::instrument(skip_all, fields(%client), name = "url_preview_legacy", level = "debug")] #[tracing::instrument(skip_all, fields(%client), name = "url_preview_legacy", level = "debug")]
pub(crate) async fn get_media_preview_legacy_route( pub(crate) async fn get_media_preview_legacy_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_media_preview::v3::Request>, body: Ruma<get_media_preview::v3::Request>,
) -> Result<get_media_preview::v3::Response> { ) -> Result<get_media_preview::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();
@@ -94,10 +94,10 @@ pub(crate) async fn get_media_preview_legacy_route(
/// Returns URL preview. /// Returns URL preview.
pub(crate) async fn get_media_preview_legacy_legacy_route( pub(crate) async fn get_media_preview_legacy_legacy_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_media_preview::v3::Request>, body: Ruma<get_media_preview::v3::Request>,
) -> Result<RumaResponse<get_media_preview::v3::Response>> { ) -> Result<RumaResponse<get_media_preview::v3::Response>> {
get_media_preview_legacy_route(State(services), InsecureClientIp(client), body) get_media_preview_legacy_route(State(services), ClientIp(client), body)
.await .await
.map(RumaResponse) .map(RumaResponse)
} }
@@ -114,10 +114,10 @@ pub(crate) async fn get_media_preview_legacy_legacy_route(
/// - Media will be saved in the media/ directory /// - Media will be saved in the media/ directory
pub(crate) async fn create_content_legacy_route( pub(crate) async fn create_content_legacy_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<create_content::v3::Request>, body: Ruma<create_content::v3::Request>,
) -> Result<RumaResponse<create_content::v3::Response>> { ) -> Result<RumaResponse<create_content::v3::Response>> {
create_content_route(State(services), InsecureClientIp(client), body) create_content_route(State(services), ClientIp(client), body)
.await .await
.map(RumaResponse) .map(RumaResponse)
} }
@@ -133,7 +133,7 @@ pub(crate) async fn create_content_legacy_route(
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")] #[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")]
pub(crate) async fn get_content_legacy_route( pub(crate) async fn get_content_legacy_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content::v3::Request>, body: Ruma<get_content::v3::Request>,
) -> Result<get_content::v3::Response> { ) -> Result<get_content::v3::Response> {
let mxc = Mxc { let mxc = Mxc {
@@ -205,10 +205,10 @@ pub(crate) async fn get_content_legacy_route(
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")] #[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")]
pub(crate) async fn get_content_legacy_legacy_route( pub(crate) async fn get_content_legacy_legacy_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content::v3::Request>, body: Ruma<get_content::v3::Request>,
) -> Result<RumaResponse<get_content::v3::Response>> { ) -> Result<RumaResponse<get_content::v3::Response>> {
get_content_legacy_route(State(services), InsecureClientIp(client), body) get_content_legacy_route(State(services), ClientIp(client), body)
.await .await
.map(RumaResponse) .map(RumaResponse)
} }
@@ -224,7 +224,7 @@ pub(crate) async fn get_content_legacy_legacy_route(
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")] #[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")]
pub(crate) async fn get_content_as_filename_legacy_route( pub(crate) async fn get_content_as_filename_legacy_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content_as_filename::v3::Request>, body: Ruma<get_content_as_filename::v3::Request>,
) -> Result<get_content_as_filename::v3::Response> { ) -> Result<get_content_as_filename::v3::Response> {
let mxc = Mxc { let mxc = Mxc {
@@ -295,10 +295,10 @@ pub(crate) async fn get_content_as_filename_legacy_route(
/// seconds /// seconds
pub(crate) async fn get_content_as_filename_legacy_legacy_route( pub(crate) async fn get_content_as_filename_legacy_legacy_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content_as_filename::v3::Request>, body: Ruma<get_content_as_filename::v3::Request>,
) -> Result<RumaResponse<get_content_as_filename::v3::Response>> { ) -> Result<RumaResponse<get_content_as_filename::v3::Response>> {
get_content_as_filename_legacy_route(State(services), InsecureClientIp(client), body) get_content_as_filename_legacy_route(State(services), ClientIp(client), body)
.await .await
.map(RumaResponse) .map(RumaResponse)
} }
@@ -314,7 +314,7 @@ pub(crate) async fn get_content_as_filename_legacy_legacy_route(
#[tracing::instrument(skip_all, fields(%client), name = "media_thumbnail_get_legacy", level = "debug")] #[tracing::instrument(skip_all, fields(%client), name = "media_thumbnail_get_legacy", level = "debug")]
pub(crate) async fn get_content_thumbnail_legacy_route( pub(crate) async fn get_content_thumbnail_legacy_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content_thumbnail::v3::Request>, body: Ruma<get_content_thumbnail::v3::Request>,
) -> Result<get_content_thumbnail::v3::Response> { ) -> Result<get_content_thumbnail::v3::Response> {
let mxc = Mxc { let mxc = Mxc {
@@ -386,10 +386,10 @@ pub(crate) async fn get_content_thumbnail_legacy_route(
/// seconds /// seconds
pub(crate) async fn get_content_thumbnail_legacy_legacy_route( pub(crate) async fn get_content_thumbnail_legacy_legacy_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content_thumbnail::v3::Request>, body: Ruma<get_content_thumbnail::v3::Request>,
) -> Result<RumaResponse<get_content_thumbnail::v3::Response>> { ) -> Result<RumaResponse<get_content_thumbnail::v3::Response>> {
get_content_thumbnail_legacy_route(State(services), InsecureClientIp(client), body) get_content_thumbnail_legacy_route(State(services), ClientIp(client), body)
.await .await
.map(RumaResponse) .map(RumaResponse)
} }

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Result, debug_error, err, info, Err, Result, debug_error, err, info,
matrix::{event::gen_event_id_canonical_json, pdu::PduBuilder}, matrix::{event::gen_event_id_canonical_json, pdu::PduBuilder},
@@ -25,7 +25,7 @@
#[tracing::instrument(skip_all, fields(%client), name = "invite", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "invite", level = "info")]
pub(crate) async fn invite_user_route( pub(crate) async fn invite_user_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<invite_user::v3::Request>, body: Ruma<invite_user::v3::Request>,
) -> Result<invite_user::v3::Response> { ) -> Result<invite_user::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,7 +1,7 @@
use std::{borrow::Borrow, collections::HashMap, iter::once, sync::Arc}; use std::{borrow::Borrow, collections::HashMap, iter::once, sync::Arc};
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Result, debug, debug_info, debug_warn, err, error, info, is_true, Err, Result, debug, debug_info, debug_warn, err, error, info, is_true,
matrix::{ matrix::{
@@ -67,7 +67,7 @@
#[tracing::instrument(skip_all, fields(%client), name = "join", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "join", level = "info")]
pub(crate) async fn join_room_by_id_route( pub(crate) async fn join_room_by_id_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<join_room_by_id::v3::Request>, body: Ruma<join_room_by_id::v3::Request>,
) -> Result<join_room_by_id::v3::Response> { ) -> Result<join_room_by_id::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();
@@ -139,7 +139,7 @@ pub(crate) async fn join_room_by_id_route(
#[tracing::instrument(skip_all, fields(%client), name = "join", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "join", level = "info")]
pub(crate) async fn join_room_by_id_or_alias_route( pub(crate) async fn join_room_by_id_or_alias_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<join_room_by_id_or_alias::v3::Request>, body: Ruma<join_room_by_id_or_alias::v3::Request>,
) -> Result<join_room_by_id_or_alias::v3::Response> { ) -> Result<join_room_by_id_or_alias::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,7 +1,7 @@
use std::{borrow::Borrow, collections::HashMap, iter::once, sync::Arc}; use std::{borrow::Borrow, collections::HashMap, iter::once, sync::Arc};
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Result, debug, debug_info, debug_warn, err, info, Err, Result, debug, debug_info, debug_warn, err, info,
matrix::{ matrix::{
@@ -47,7 +47,7 @@
#[tracing::instrument(skip_all, fields(%client), name = "knock", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "knock", level = "info")]
pub(crate) async fn knock_room_route( pub(crate) async fn knock_room_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<knock_room::v3::Request>, body: Ruma<knock_room::v3::Request>,
) -> Result<knock_room::v3::Response> { ) -> Result<knock_room::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Error, Result, at, debug_warn, Err, Error, Result, at, debug_warn,
matrix::{ matrix::{
@@ -71,7 +71,7 @@
/// where the user was joined, depending on `history_visibility`) /// where the user was joined, depending on `history_visibility`)
pub(crate) async fn get_message_events_route( pub(crate) async fn get_message_events_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client_ip): InsecureClientIp, ClientIp(client_ip): ClientIp,
body: Ruma<get_message_events::v3::Request>, body: Ruma<get_message_events::v3::Request>,
) -> Result<get_message_events::v3::Response> { ) -> Result<get_message_events::v3::Response> {
debug_assert!(IGNORED_MESSAGE_TYPES.is_sorted(), "IGNORED_MESSAGE_TYPES is not sorted"); debug_assert!(IGNORED_MESSAGE_TYPES.is_sorted(), "IGNORED_MESSAGE_TYPES is not sorted");

View File

@@ -1,7 +1,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{Err, PduCount, Result, err}; use conduwuit::{Err, PduCount, Result, err};
use ruma::{ use ruma::{
MilliSecondsSinceUnixEpoch, MilliSecondsSinceUnixEpoch,
@@ -119,7 +119,7 @@ pub(crate) async fn set_read_marker_route(
/// Sets private read marker and public read receipt EDU. /// Sets private read marker and public read receipt EDU.
pub(crate) async fn create_receipt_route( pub(crate) async fn create_receipt_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client_ip): InsecureClientIp, ClientIp(client_ip): ClientIp,
body: Ruma<create_receipt::v3::Request>, body: Ruma<create_receipt::v3::Request>,
) -> Result<create_receipt::v3::Response> { ) -> Result<create_receipt::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{Err, Result, matrix::pdu::PduBuilder}; use conduwuit::{Err, Result, matrix::pdu::PduBuilder};
use ruma::{ use ruma::{
api::client::redact::redact_event, events::room::redaction::RoomRedactionEventContent, api::client::redact::redact_event, events::room::redaction::RoomRedactionEventContent,
@@ -14,7 +14,7 @@
/// - TODO: Handle txn id /// - TODO: Handle txn id
pub(crate) async fn redact_event_route( pub(crate) async fn redact_event_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client_ip): InsecureClientIp, ClientIp(client_ip): ClientIp,
body: Ruma<redact_event::v3::Request>, body: Ruma<redact_event::v3::Request>,
) -> Result<redact_event::v3::Response> { ) -> Result<redact_event::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,7 +1,7 @@
use std::{fmt::Write as _, time::Duration}; use std::{fmt::Write as _, time::Duration};
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{Err, Event, Result, debug_info, info, matrix::pdu::PduEvent, utils::ReadyExt}; use conduwuit::{Err, Event, Result, debug_info, info, matrix::pdu::PduEvent, utils::ReadyExt};
use conduwuit_service::Services; use conduwuit_service::Services;
use ruma::{ use ruma::{
@@ -31,7 +31,7 @@ struct Report {
#[tracing::instrument(skip_all, fields(%client), name = "report_room", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "report_room", level = "info")]
pub(crate) async fn report_room_route( pub(crate) async fn report_room_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<report_room::v3::Request>, body: Ruma<report_room::v3::Request>,
) -> Result<report_room::v3::Response> { ) -> Result<report_room::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();
@@ -87,7 +87,7 @@ pub(crate) async fn report_room_route(
#[tracing::instrument(skip_all, fields(%client), name = "report_event", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "report_event", level = "info")]
pub(crate) async fn report_event_route( pub(crate) async fn report_event_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<report_content::v3::Request>, body: Ruma<report_content::v3::Request>,
) -> Result<report_content::v3::Response> { ) -> Result<report_content::v3::Response> {
// user authentication // user authentication
@@ -135,7 +135,7 @@ pub(crate) async fn report_event_route(
#[tracing::instrument(skip_all, fields(%client), name = "report_user", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "report_user", level = "info")]
pub(crate) async fn report_user_route( pub(crate) async fn report_user_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<report_user::v3::Request>, body: Ruma<report_user::v3::Request>,
) -> Result<report_user::v3::Response> { ) -> Result<report_user::v3::Response> {
// user authentication // user authentication

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Result, debug, debug_warn, info, trace, Err, Result, debug, debug_warn, info, trace,
utils::{IterStream, future::TryExtExt}, utils::{IterStream, future::TryExtExt},
@@ -33,10 +33,10 @@
/// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266) /// An implementation of [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266)
pub(crate) async fn get_room_summary_legacy( pub(crate) async fn get_room_summary_legacy(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_summary::msc3266::Request>, body: Ruma<get_summary::msc3266::Request>,
) -> Result<RumaResponse<get_summary::msc3266::Response>> { ) -> Result<RumaResponse<get_summary::msc3266::Response>> {
get_room_summary(State(services), InsecureClientIp(client), body) get_room_summary(State(services), ClientIp(client), body)
.boxed() .boxed()
.await .await
.map(RumaResponse) .map(RumaResponse)
@@ -49,7 +49,7 @@ pub(crate) async fn get_room_summary_legacy(
#[tracing::instrument(skip_all, fields(%client), name = "room_summary", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "room_summary", level = "info")]
pub(crate) async fn get_room_summary( pub(crate) async fn get_room_summary(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_summary::msc3266::Request>, body: Ruma<get_summary::msc3266::Request>,
) -> Result<get_summary::msc3266::Response> { ) -> Result<get_summary::msc3266::Response> {
let (room_id, servers) = services let (room_id, servers) = services

View File

@@ -1,7 +1,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{Err, Result, err, matrix::pdu::PduBuilder, utils}; use conduwuit::{Err, Result, err, matrix::pdu::PduBuilder, utils};
use ruma::{api::client::message::send_message_event, events::MessageLikeEventType}; use ruma::{api::client::message::send_message_event, events::MessageLikeEventType};
use serde_json::from_str; use serde_json::from_str;
@@ -19,7 +19,7 @@
/// allowed /// allowed
pub(crate) async fn send_message_event_route( pub(crate) async fn send_message_event_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client_ip): InsecureClientIp, ClientIp(client_ip): ClientIp,
body: Ruma<send_message_event::v3::Request>, body: Ruma<send_message_event::v3::Request>,
) -> Result<send_message_event::v3::Response> { ) -> Result<send_message_event::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,7 +1,7 @@
use std::time::Duration; use std::time::Duration;
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Error, Result, debug, err, info, Err, Error, Result, debug, err, info,
utils::{self, ReadyExt, hash, stream::BroadbandExt}, utils::{self, ReadyExt, hash, stream::BroadbandExt},
@@ -42,7 +42,7 @@
#[tracing::instrument(skip_all, fields(%client), name = "login", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "login", level = "info")]
pub(crate) async fn get_login_types_route( pub(crate) async fn get_login_types_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
_body: Ruma<get_login_types::v3::Request>, _body: Ruma<get_login_types::v3::Request>,
) -> Result<get_login_types::v3::Response> { ) -> Result<get_login_types::v3::Response> {
Ok(get_login_types::v3::Response::new(vec![ Ok(get_login_types::v3::Response::new(vec![
@@ -242,7 +242,7 @@ pub(crate) async fn handle_login(
#[tracing::instrument(skip_all, fields(%client), name = "login", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "login", level = "info")]
pub(crate) async fn login_route( pub(crate) async fn login_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<login::v3::Request>, body: Ruma<login::v3::Request>,
) -> Result<login::v3::Response> { ) -> Result<login::v3::Response> {
let emergency_mode_enabled = services.config.emergency_password.is_some(); let emergency_mode_enabled = services.config.emergency_password.is_some();
@@ -375,7 +375,7 @@ pub(crate) async fn login_route(
#[tracing::instrument(skip_all, fields(%client), name = "login_token", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "login_token", level = "info")]
pub(crate) async fn login_token_route( pub(crate) async fn login_token_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_login_token::v1::Request>, body: Ruma<get_login_token::v1::Request>,
) -> Result<get_login_token::v1::Response> { ) -> Result<get_login_token::v1::Response> {
if !services.server.config.login_via_existing_session { if !services.server.config.login_via_existing_session {
@@ -411,7 +411,7 @@ pub(crate) async fn login_token_route(
#[tracing::instrument(skip_all, fields(%client), name = "logout", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "logout", level = "info")]
pub(crate) async fn logout_route( pub(crate) async fn logout_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<logout::v3::Request>, body: Ruma<logout::v3::Request>,
) -> Result<logout::v3::Response> { ) -> Result<logout::v3::Response> {
let (sender_user, sender_device) = body.sender(); let (sender_user, sender_device) = body.sender();
@@ -457,7 +457,7 @@ pub(crate) async fn logout_route(
#[tracing::instrument(skip_all, fields(%client), name = "logout", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "logout", level = "info")]
pub(crate) async fn logout_all_route( pub(crate) async fn logout_all_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<logout_all::v3::Request>, body: Ruma<logout_all::v3::Request>,
) -> Result<logout_all::v3::Response> { ) -> Result<logout_all::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,7 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Result, err, Err, Result, err,
matrix::{Event, pdu::PduBuilder}, matrix::{Event, pdu::PduBuilder},
@@ -33,7 +33,7 @@
/// Sends a state event into the room. /// Sends a state event into the room.
pub(crate) async fn send_state_event_for_key_route( pub(crate) async fn send_state_event_for_key_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(ip): InsecureClientIp, ClientIp(ip): ClientIp,
body: Ruma<send_state_event::v3::Request>, body: Ruma<send_state_event::v3::Request>,
) -> Result<send_state_event::v3::Response> { ) -> Result<send_state_event::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();
@@ -70,10 +70,10 @@ pub(crate) async fn send_state_event_for_key_route(
/// Sends a state event into the room. /// Sends a state event into the room.
pub(crate) async fn send_state_event_for_empty_key_route( pub(crate) async fn send_state_event_for_empty_key_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(ip): InsecureClientIp, ClientIp(ip): ClientIp,
body: Ruma<send_state_event::v3::Request>, body: Ruma<send_state_event::v3::Request>,
) -> Result<RumaResponse<send_state_event::v3::Response>> { ) -> Result<RumaResponse<send_state_event::v3::Response>> {
send_state_event_for_key_route(State(services), InsecureClientIp(ip), body) send_state_event_for_key_route(State(services), ClientIp(ip), body)
.boxed() .boxed()
.await .await
.map(RumaResponse) .map(RumaResponse)

View File

@@ -9,7 +9,7 @@
}; };
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Result, at, extract_variant, Result, at, extract_variant,
utils::{ utils::{
@@ -181,7 +181,7 @@ fn lazy_loading_enabled(&self) -> bool {
)] )]
pub(crate) async fn sync_events_route( pub(crate) async fn sync_events_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client_ip): InsecureClientIp, ClientIp(client_ip): ClientIp,
body: Ruma<sync_events::v3::Request>, body: Ruma<sync_events::v3::Request>,
) -> Result<sync_events::v3::Response, RumaResponse<UiaaResponse>> { ) -> Result<sync_events::v3::Response, RumaResponse<UiaaResponse>> {
let (sender_user, sender_device) = body.sender(); let (sender_user, sender_device) = body.sender();

View File

@@ -6,7 +6,7 @@
}; };
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Error, Result, at, error, extract_variant, is_equal_to, Err, Error, Result, at, error, extract_variant, is_equal_to,
matrix::{Event, TypeStateKey, pdu::PduCount}, matrix::{Event, TypeStateKey, pdu::PduCount},
@@ -63,7 +63,7 @@
/// [MSC4186]: https://github.com/matrix-org/matrix-spec-proposals/pull/4186 /// [MSC4186]: https://github.com/matrix-org/matrix-spec-proposals/pull/4186
pub(crate) async fn sync_events_v5_route( pub(crate) async fn sync_events_v5_route(
State(ref services): State<crate::State>, State(ref services): State<crate::State>,
InsecureClientIp(client_ip): InsecureClientIp, ClientIp(client_ip): ClientIp,
body: Ruma<sync_events::v5::Request>, body: Ruma<sync_events::v5::Request>,
) -> Result<sync_events::v5::Response> { ) -> Result<sync_events::v5::Response> {
debug_assert!(DEFAULT_BUMP_TYPES.is_sorted(), "DEFAULT_BUMP_TYPES is not sorted"); debug_assert!(DEFAULT_BUMP_TYPES.is_sorted(), "DEFAULT_BUMP_TYPES is not sorted");

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{Err, Result, utils, utils::math::Tried}; use conduwuit::{Err, Result, utils, utils::math::Tried};
use ruma::api::client::typing::create_typing_event; use ruma::api::client::typing::create_typing_event;
@@ -10,7 +10,7 @@
/// Sets the typing state of the sender user. /// Sets the typing state of the sender user.
pub(crate) async fn create_typing_event_route( pub(crate) async fn create_typing_event_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(ip): InsecureClientIp, ClientIp(ip): ClientIp,
body: Ruma<create_typing_event::v3::Request>, body: Ruma<create_typing_event::v3::Request>,
) -> Result<create_typing_event::v3::Response> { ) -> Result<create_typing_event::v3::Response> {
use create_typing_event::v3::Typing; use create_typing_event::v3::Typing;

View File

@@ -1,7 +1,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{Err, Result}; use conduwuit::{Err, Result};
use futures::{FutureExt, StreamExt}; use futures::{FutureExt, StreamExt};
use ruma::{ use ruma::{
@@ -29,7 +29,7 @@
#[tracing::instrument(skip_all, fields(%client), name = "mutual_rooms", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "mutual_rooms", level = "info")]
pub(crate) async fn get_mutual_rooms_route( pub(crate) async fn get_mutual_rooms_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<mutual_rooms::unstable::Request>, body: Ruma<mutual_rooms::unstable::Request>,
) -> Result<mutual_rooms::unstable::Response> { ) -> Result<mutual_rooms::unstable::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use base64::{Engine as _, engine::general_purpose}; use base64::{Engine as _, engine::general_purpose};
use conduwuit::{ use conduwuit::{
Err, Error, PduEvent, Result, err, error, Err, Error, PduEvent, Result, err, error,
@@ -22,7 +22,7 @@
#[tracing::instrument(skip_all, fields(%client), name = "invite", level = "info")] #[tracing::instrument(skip_all, fields(%client), name = "invite", level = "info")]
pub(crate) async fn create_invite_route( pub(crate) async fn create_invite_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<create_invite::v2::Request>, body: Ruma<create_invite::v2::Request>,
) -> Result<create_invite::v2::Response> { ) -> Result<create_invite::v2::Response> {
// ACL check origin // ACL check origin

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{Err, Result, utils::content_disposition::make_content_disposition}; use conduwuit::{Err, Result, utils::content_disposition::make_content_disposition};
use conduwuit_service::media::{Dim, FileMeta}; use conduwuit_service::media::{Dim, FileMeta};
use ruma::{ use ruma::{
@@ -22,7 +22,7 @@
)] )]
pub(crate) async fn get_content_route( pub(crate) async fn get_content_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content::v1::Request>, body: Ruma<get_content::v1::Request>,
) -> Result<get_content::v1::Response> { ) -> Result<get_content::v1::Response> {
let mxc = Mxc { let mxc = Mxc {
@@ -64,7 +64,7 @@ pub(crate) async fn get_content_route(
)] )]
pub(crate) async fn get_content_thumbnail_route( pub(crate) async fn get_content_thumbnail_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_content_thumbnail::v1::Request>, body: Ruma<get_content_thumbnail::v1::Request>,
) -> Result<get_content_thumbnail::v1::Response> { ) -> Result<get_content_thumbnail::v1::Response> {
let dim = Dim::from_ruma(body.width, body.height, body.method.clone())?; let dim = Dim::from_ruma(body.width, body.height, body.method.clone())?;

View File

@@ -1,5 +1,5 @@
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{Error, Result}; use conduwuit::{Error, Result};
use ruma::{ use ruma::{
api::{ api::{
@@ -17,7 +17,7 @@
#[tracing::instrument(name = "publicrooms", level = "debug", skip_all, fields(%client))] #[tracing::instrument(name = "publicrooms", level = "debug", skip_all, fields(%client))]
pub(crate) async fn get_public_rooms_filtered_route( pub(crate) async fn get_public_rooms_filtered_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_public_rooms_filtered::v1::Request>, body: Ruma<get_public_rooms_filtered::v1::Request>,
) -> Result<get_public_rooms_filtered::v1::Response> { ) -> Result<get_public_rooms_filtered::v1::Response> {
if !services if !services
@@ -55,7 +55,7 @@ pub(crate) async fn get_public_rooms_filtered_route(
#[tracing::instrument(name = "publicrooms", level = "debug", skip_all, fields(%client))] #[tracing::instrument(name = "publicrooms", level = "debug", skip_all, fields(%client))]
pub(crate) async fn get_public_rooms_route( pub(crate) async fn get_public_rooms_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<get_public_rooms::v1::Request>, body: Ruma<get_public_rooms::v1::Request>,
) -> Result<get_public_rooms::v1::Response> { ) -> Result<get_public_rooms::v1::Response> {
if !services if !services

View File

@@ -5,7 +5,7 @@
}; };
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::ClientIp;
use conduwuit::{ use conduwuit::{
Err, Error, Result, debug, debug_warn, err, error, Err, Error, Result, debug, debug_warn, err, error,
result::LogErr, result::LogErr,
@@ -15,6 +15,7 @@
IterStream, ReadyExt, millis_since_unix_epoch, IterStream, ReadyExt, millis_since_unix_epoch,
stream::{BroadbandExt, TryBroadbandExt, automatic_width}, stream::{BroadbandExt, TryBroadbandExt, automatic_width},
}, },
warn,
}; };
use conduwuit_service::{ use conduwuit_service::{
Services, Services,
@@ -59,7 +60,7 @@
/// Push EDUs and PDUs to this server. /// Push EDUs and PDUs to this server.
pub(crate) async fn send_transaction_message_route( pub(crate) async fn send_transaction_message_route(
State(services): State<crate::State>, State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp, ClientIp(client): ClientIp,
body: Ruma<send_transaction_message::v1::Request>, body: Ruma<send_transaction_message::v1::Request>,
) -> Result<send_transaction_message::v1::Response> { ) -> Result<send_transaction_message::v1::Response> {
if body.origin() != body.body.origin { if body.origin() != body.body.origin {
@@ -152,7 +153,7 @@ async fn process_inbound_transaction(
.iter() .iter()
.stream() .stream()
.broad_then(|pdu| services.rooms.event_handler.parse_incoming_pdu(pdu)) .broad_then(|pdu| services.rooms.event_handler.parse_incoming_pdu(pdu))
.inspect_err(|e| debug_warn!("Could not parse PDU: {e}")) .inspect_err(|e| warn!("Could not parse incoming PDU: {e}"))
.ready_filter_map(Result::ok); .ready_filter_map(Result::ok);
let edus = body let edus = body
@@ -283,17 +284,16 @@ async fn build_local_dag(
let mut dag: HashMap<OwnedEventId, HashSet<OwnedEventId>> = HashMap::new(); let mut dag: HashMap<OwnedEventId, HashSet<OwnedEventId>> = HashMap::new();
for (event_id, value) in pdu_map { for (event_id, value) in pdu_map {
// We already checked that these properties are correct in parse_incoming_pdu,
// so it's safe to unwrap here.
let prev_events = value let prev_events = value
.get("prev_events") .get("prev_events")
.expect("pdu must have prev_events") .unwrap()
.as_array() .as_array()
.expect("prev_events must be an array") .unwrap()
.iter() .iter()
.map(|v| { .map(|v| OwnedEventId::parse(v.as_str().unwrap()).unwrap())
OwnedEventId::parse(v.as_str().expect("prev_events values must be strings")) .collect();
.expect("prev_events must be valid event IDs")
})
.collect::<HashSet<OwnedEventId>>();
dag.insert(event_id.clone(), prev_events); dag.insert(event_id.clone(), prev_events);
} }

View File

@@ -25,9 +25,6 @@ conduwuit_mods = [
gzip_compression = [ gzip_compression = [
"reqwest/gzip", "reqwest/gzip",
] ]
http3 = [
"reqwest/http3",
]
hardened_malloc = [ hardened_malloc = [
"dep:hardened_malloc-rs" "dep:hardened_malloc-rs"
] ]
@@ -88,10 +85,11 @@ log.workspace = true
lettre.workspace = true lettre.workspace = true
num-traits.workspace = true num-traits.workspace = true
rand.workspace = true rand.workspace = true
# tied to passwordhash 0.5.0
rand_core = { version = "0.6.4", features = ["getrandom"] } rand_core = { version = "0.6.4", features = ["getrandom"] }
regex.workspace = true regex.workspace = true
reqwest.workspace = true reqwest.workspace = true
ring.workspace = true sha2.workspace = true
ruma.workspace = true ruma.workspace = true
sanitize-filename.workspace = true sanitize-filename.workspace = true
serde_json.workspace = true serde_json.workspace = true

View File

@@ -2324,6 +2324,18 @@ pub struct LdapConfig {
#[serde(default)] #[serde(default)]
pub uri: Option<Url>, pub uri: Option<Url>,
/// StartTLS for LDAP connections.
///
/// default: false
#[serde(default)]
pub use_starttls: bool,
/// Skip TLS certificate verification, possibly dangerous.
///
/// default: false
#[serde(default)]
pub disable_tls_verification: bool,
/// Root of the searches. /// Root of the searches.
/// ///
/// example: "ou=users,dc=example,dc=org" /// example: "ou=users,dc=example,dc=org"

View File

@@ -1,19 +1,16 @@
use ring::{ use sha2::{Digest, Sha256};
digest,
digest::{Context, SHA256, SHA256_OUTPUT_LEN},
};
pub type Digest = [u8; SHA256_OUTPUT_LEN]; pub type DigestOut = [u8; 256 / 8];
/// Sha256 hash (input gather joined by 0xFF bytes) /// Sha256 hash (input gather joined by 0xFF bytes)
#[must_use] #[must_use]
#[tracing::instrument(skip(inputs), level = "trace")] #[tracing::instrument(skip(inputs), level = "trace")]
pub fn delimited<'a, T, I>(mut inputs: I) -> Digest pub fn delimited<'a, T, I>(mut inputs: I) -> DigestOut
where where
I: Iterator<Item = T> + 'a, I: Iterator<Item = T> + 'a,
T: AsRef<[u8]> + 'a, T: AsRef<[u8]> + 'a,
{ {
let mut ctx = Context::new(&SHA256); let mut ctx = Sha256::new();
if let Some(input) = inputs.next() { if let Some(input) = inputs.next() {
ctx.update(input.as_ref()); ctx.update(input.as_ref());
for input in inputs { for input in inputs {
@@ -22,8 +19,7 @@ pub fn delimited<'a, T, I>(mut inputs: I) -> Digest
} }
} }
ctx.finish() ctx.finalize()
.as_ref()
.try_into() .try_into()
.expect("failed to return Digest buffer") .expect("failed to return Digest buffer")
} }
@@ -31,18 +27,17 @@ pub fn delimited<'a, T, I>(mut inputs: I) -> Digest
/// Sha256 hash (input gather) /// Sha256 hash (input gather)
#[must_use] #[must_use]
#[tracing::instrument(skip(inputs), level = "trace")] #[tracing::instrument(skip(inputs), level = "trace")]
pub fn concat<'a, T, I>(inputs: I) -> Digest pub fn concat<'a, T, I>(inputs: I) -> DigestOut
where where
I: Iterator<Item = T> + 'a, I: Iterator<Item = T> + 'a,
T: AsRef<[u8]> + 'a, T: AsRef<[u8]> + 'a,
{ {
inputs inputs
.fold(Context::new(&SHA256), |mut ctx, input| { .fold(Sha256::new(), |mut ctx, input| {
ctx.update(input.as_ref()); ctx.update(input.as_ref());
ctx ctx
}) })
.finish() .finalize()
.as_ref()
.try_into() .try_into()
.expect("failed to return Digest buffer") .expect("failed to return Digest buffer")
} }
@@ -51,12 +46,11 @@ pub fn concat<'a, T, I>(inputs: I) -> Digest
#[inline] #[inline]
#[must_use] #[must_use]
#[tracing::instrument(skip(input), level = "trace")] #[tracing::instrument(skip(input), level = "trace")]
pub fn hash<T>(input: T) -> Digest pub fn hash<T>(input: T) -> DigestOut
where where
T: AsRef<[u8]>, T: AsRef<[u8]>,
{ {
digest::digest(&SHA256, input.as_ref()) Sha256::digest(input)
.as_ref()
.try_into() .try_into()
.expect("failed to return Digest buffer") .expect("failed to return Digest buffer")
} }

View File

@@ -43,6 +43,7 @@ assets = [
default = [ default = [
"standard", "standard",
"release_max_log_level", "release_max_log_level",
"ring",
"bindgen-runtime", # replace with bindgen-static on alpine "bindgen-runtime", # replace with bindgen-static on alpine
] ]
standard = [ standard = [
@@ -100,9 +101,14 @@ hardened_malloc = [
"conduwuit-core/hardened_malloc", "conduwuit-core/hardened_malloc",
] ]
http3 = [ http3 = [
"conduwuit-api/http3", "reqwest/http3"
"conduwuit-core/http3", ]
"conduwuit-service/http3", ring = [
"rustls/ring"
]
aws_lc_rs = [
"rustls/aws_lc_rs",
"dep:aws-lc-rs"
] ]
io_uring = [ io_uring = [
"conduwuit-database/io_uring", "conduwuit-database/io_uring",
@@ -238,6 +244,9 @@ tracing-subscriber.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-journald = { workspace = true, optional = true } tracing-journald = { workspace = true, optional = true }
parking_lot.workspace = true parking_lot.workspace = true
reqwest = { workspace = true, default-features = false }
rustls = { workspace = true, default-features = false }
aws-lc-rs = { version = "1.16.3", default-features = false, optional = true }
[target.'cfg(all(not(target_env = "msvc"), target_os = "linux"))'.dependencies] [target.'cfg(all(not(target_env = "msvc"), target_os = "linux"))'.dependencies]

View File

@@ -33,6 +33,18 @@ pub fn run_with_args(args: &Args) -> Result<()> {
// Spawn deadlock detection thread // Spawn deadlock detection thread
deadlock::spawn(); deadlock::spawn();
// Because we're not using rustls default-tls, we have to initialise a TLS
// provider
#[cfg(feature = "aws_lc_rs")]
rustls::crypto::aws_lc_rs::default_provider()
.install_default()
.expect("failed to initialise ring rustls crypto provider");
#[cfg(all(feature = "ring", not(feature = "aws_lc_rs")))]
rustls::crypto::ring::default_provider()
.install_default()
.expect("failed to initialise ring rustls crypto provider");
let runtime = runtime::new(args)?; let runtime = runtime::new(args)?;
let server = Server::new(args, Some(runtime.handle()))?; let server = Server::new(args, Some(runtime.handle()))?;

View File

@@ -24,7 +24,7 @@ brotli_compression = [
"tower-http/compression-br", "tower-http/compression-br",
] ]
direct_tls = [ direct_tls = [
"axum-server/tls-rustls", "axum-server/tls-rustls-no-provider",
"dep:rustls", "dep:rustls",
"dep:axum-server-dual-protocol", "dep:axum-server-dual-protocol",
] ]

View File

@@ -4,7 +4,7 @@
Router, Router,
extract::{DefaultBodyLimit, MatchedPath}, extract::{DefaultBodyLimit, MatchedPath},
}; };
use axum_client_ip::SecureClientIpSource; use axum_client_ip::ClientIpSource;
use conduwuit::{Result, Server, debug, error}; use conduwuit::{Result, Server, debug, error};
use conduwuit_service::{Services, state::Guard}; use conduwuit_service::{Services, state::Guard};
use http::{ use http::{
@@ -59,7 +59,7 @@ pub(crate) fn build(services: &Arc<Services>) -> Result<(Router, Guard)> {
.on_response(DefaultOnResponse::new().level(Level::DEBUG)), .on_response(DefaultOnResponse::new().level(Level::DEBUG)),
) )
.layer(axum::middleware::from_fn_with_state(Arc::clone(services), request::handle)) .layer(axum::middleware::from_fn_with_state(Arc::clone(services), request::handle))
.layer(SecureClientIpSource::ConnectInfo.into_extension()) .layer(ClientIpSource::ConnectInfo.into_extension())
.layer(ResponseBodyTimeoutLayer::new(Duration::from_secs( .layer(ResponseBodyTimeoutLayer::new(Duration::from_secs(
server.config.client_response_timeout, server.config.client_response_timeout,
))) )))

View File

@@ -7,7 +7,7 @@
time::Duration, time::Duration,
}; };
use axum_server::Handle as ServerHandle; use axum_server::{Address, Handle as ServerHandle};
use conduwuit::{Error, Result, Server, debug, debug_error, debug_info, error, info}; use conduwuit::{Error, Result, Server, debug, debug_error, debug_info, error, info};
use futures::FutureExt; use futures::FutureExt;
use service::Services; use service::Services;
@@ -117,7 +117,7 @@ pub(crate) async fn stop(services: Arc<Services>) -> Result<()> {
} }
#[tracing::instrument(skip_all, level = "info")] #[tracing::instrument(skip_all, level = "info")]
async fn signal(server: Arc<Server>, tx: Sender<()>, handle: axum_server::Handle) { async fn signal<A: Address>(server: Arc<Server>, tx: Sender<()>, handle: axum_server::Handle<A>) {
server server
.clone() .clone()
.until_shutdown() .until_shutdown()
@@ -125,7 +125,11 @@ async fn signal(server: Arc<Server>, tx: Sender<()>, handle: axum_server::Handle
.await; .await;
} }
async fn handle_shutdown(server: Arc<Server>, tx: Sender<()>, handle: axum_server::Handle) { async fn handle_shutdown<A: Address>(
server: Arc<Server>,
tx: Sender<()>,
handle: axum_server::Handle<A>,
) {
if let Err(e) = tx.send(()) { if let Err(e) = tx.send(()) {
error!("failed sending shutdown transaction to channel: {e}"); error!("failed sending shutdown transaction to channel: {e}");
} }

View File

@@ -15,7 +15,7 @@
/// Serve clients /// Serve clients
pub(super) async fn serve( pub(super) async fn serve(
services: Arc<Services>, services: Arc<Services>,
handle: ServerHandle, handle: ServerHandle<std::net::SocketAddr>,
mut shutdown: broadcast::Receiver<()>, mut shutdown: broadcast::Receiver<()>,
) -> Result { ) -> Result {
let server = &services.server; let server = &services.server;

View File

@@ -11,7 +11,7 @@
pub(super) async fn serve( pub(super) async fn serve(
server: &Arc<Server>, server: &Arc<Server>,
app: Router, app: Router,
handle: ServerHandle, handle: ServerHandle<SocketAddr>,
addrs: Vec<SocketAddr>, addrs: Vec<SocketAddr>,
) -> Result<()> { ) -> Result<()> {
let app = app.into_make_service_with_connect_info::<SocketAddr>(); let app = app.into_make_service_with_connect_info::<SocketAddr>();

View File

@@ -13,7 +13,7 @@
pub(super) async fn serve( pub(super) async fn serve(
server: &Arc<Server>, server: &Arc<Server>,
app: Router, app: Router,
handle: ServerHandle, handle: ServerHandle<SocketAddr>,
addrs: Vec<SocketAddr>, addrs: Vec<SocketAddr>,
) -> Result { ) -> Result {
let tls = &server.config.tls; let tls = &server.config.tls;
@@ -24,13 +24,6 @@ pub(super) async fn serve(
.key .key
.as_ref() .as_ref()
.ok_or_else(|| err!(Config("tls.key", "Missing required value in tls config section")))?; .ok_or_else(|| err!(Config("tls.key", "Missing required value in tls config section")))?;
// we use ring for ruma and hashing state, but aws-lc-rs is the new default.
// without this, TLS mode will panic.
rustls::crypto::aws_lc_rs::default_provider()
.install_default()
.expect("failed to initialise aws-lc-rs rustls crypto provider");
info!( info!(
"Note: It is strongly recommended that you use a reverse proxy instead of running \ "Note: It is strongly recommended that you use a reverse proxy instead of running \
conduwuit directly with TLS." conduwuit directly with TLS."

View File

@@ -33,9 +33,6 @@ gzip_compression = [
"conduwuit-core/gzip_compression", "conduwuit-core/gzip_compression",
"reqwest/gzip", "reqwest/gzip",
] ]
http3 = [
"conduwuit-core/http3",
]
io_uring = [ io_uring = [
"conduwuit-database/io_uring", "conduwuit-database/io_uring",
] ]

View File

@@ -1,12 +1,95 @@
use std::str::FromStr;
use conduwuit::{ use conduwuit::{
Result, RoomVersion, err, implement, matrix::event::gen_event_id_canonical_json, Err, Result, err, implement,
result::FlatOk, matrix::event::{gen_event_id, gen_event_id_canonical_json},
}; };
use itertools::Itertools;
use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, OwnedRoomId, RoomVersionId}; use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, OwnedRoomId, RoomVersionId};
use serde_json::value::RawValue as RawJsonValue; use serde_json::value::RawValue as RawJsonValue;
type Parsed = (OwnedRoomId, OwnedEventId, CanonicalJsonObject); type Parsed = (OwnedRoomId, OwnedEventId, CanonicalJsonObject);
/// Extracts the expected room ID from the PDU. If the PDU claims its own room
/// ID, that is returned. Since `m.room.create` in v12 and onward lacks this
/// field over federation, it will be calculated if not provided, otherwise a
/// validation error will be returned.
fn extract_room_id(event_type: &str, pdu: &CanonicalJsonObject) -> Result<OwnedRoomId> {
use RoomVersionId::*;
if let Some(room_id) = pdu.get("room_id").and_then(CanonicalJsonValue::as_str) {
return OwnedRoomId::parse(room_id)
.map_err(|e| err!(Request(BadJson("Invalid room_id {room_id:?} in pdu: {e}"))));
}
// If there's no room ID, and this is not a create event, it is illegal.
if event_type != "m.room.create" || pdu.get("state_key").is_none() {
return Err!(Request(BadJson("Missing room_id in pdu")));
}
// Room versions 11 and below require the room ID is present.
let room_version_id = RoomVersionId::from_str(
pdu.get("content")
.and_then(CanonicalJsonValue::as_object)
.ok_or_else(|| err!(Request(InvalidParam("Missing or invalid content in pdu"))))?
.get("room_version")
.and_then(CanonicalJsonValue::as_str)
.unwrap_or("1"), // Omitted room versions default to v1
)
.map_err(|e| err!(Request(BadJson("Invalid room_version in pdu: {e}"))))?;
if matches!(room_version_id, V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 | V11) {
return Err!(Request(BadJson("Missing room_id in pdu")));
}
let event_id = gen_event_id(pdu, &room_version_id)?;
Ok(OwnedRoomId::parse(event_id.as_str().replace('$', "!"))
.expect("constructed room ID has to be valid"))
}
/// Parses every entry in an array as an event ID, returning an error if any
/// step fails.
fn expect_event_id_array(value: &CanonicalJsonObject, field: &str) -> Result<Vec<OwnedEventId>> {
value
.get(field)
.ok_or_else(|| err!(Request(BadJson("missing field `{field}` on PDU"))))?
.as_array()
.ok_or_else(|| err!(Request(BadJson("expected an array PDU field `{field}`"))))?
.iter()
.map(|v| {
v.as_str()
.ok_or_else(|| {
err!(Request(BadJson("expected an array of event IDs for `{field}`")))
})
.and_then(|s| {
OwnedEventId::parse(s)
.map_err(|e| err!(Request(BadJson("invalid event ID in `{field}`: {e}"))))
})
})
.try_collect()
}
/// Performs some basic validation on the PDU to make sure it's not obviously
/// malformed. This is not a full validation, but guards against extreme errors.
///
/// Currently, this just validates that prev/auth events are within acceptable
/// ranges. Other servers do some additional things like checking depth range,
/// but serde will do that later when converting the object to a PduEvent.
#[implement(super::Service)]
pub fn validate_pdu(&self, pdu: &CanonicalJsonObject) -> Result {
// Since v3:
// `event_id` should not be present on the PDU.
// NOTE: The above is ignored since technically it's still allowed to be
// included, but should be ignored instead.
// `auth_events` and `prev_events` must be an array of event IDs
let auth_events = expect_event_id_array(pdu, "auth_events")?;
if auth_events.len() > 10 {
return Err!(Request(BadJson("PDU has too many auth events")));
}
let prev_events = expect_event_id_array(pdu, "prev_events")?;
if prev_events.len() > 20 {
return Err!(Request(BadJson("PDU has too many prev events")));
}
Ok(())
}
#[implement(super::Service)] #[implement(super::Service)]
pub async fn parse_incoming_pdu(&self, pdu: &RawJsonValue) -> Result<Parsed> { pub async fn parse_incoming_pdu(&self, pdu: &RawJsonValue) -> Result<Parsed> {
let value = serde_json::from_str::<CanonicalJsonObject>(pdu.get()).map_err(|e| { let value = serde_json::from_str::<CanonicalJsonObject>(pdu.get()).map_err(|e| {
@@ -17,39 +100,7 @@ pub async fn parse_incoming_pdu(&self, pdu: &RawJsonValue) -> Result<Parsed> {
.and_then(CanonicalJsonValue::as_str) .and_then(CanonicalJsonValue::as_str)
.ok_or_else(|| err!(Request(InvalidParam("Missing or invalid type in pdu"))))?; .ok_or_else(|| err!(Request(InvalidParam("Missing or invalid type in pdu"))))?;
let room_id: OwnedRoomId = if event_type != "m.room.create" { let room_id = extract_room_id(event_type, &value)?;
value
.get("room_id")
.and_then(CanonicalJsonValue::as_str)
.map(OwnedRoomId::parse)
.flat_ok_or(err!(Request(InvalidParam("Invalid room_id in pdu"))))?
} else {
// v12 rooms might have no room_id in the create event. We'll need to check the
// content.room_version
let content = value
.get("content")
.and_then(CanonicalJsonValue::as_object)
.ok_or_else(|| err!(Request(InvalidParam("Missing or invalid content in pdu"))))?;
let room_version = content
.get("room_version")
.and_then(CanonicalJsonValue::as_str)
.unwrap_or("1");
let vi = RoomVersionId::try_from(room_version).unwrap_or(RoomVersionId::V1);
let vf = RoomVersion::new(&vi).expect("supported room version");
if vf.room_ids_as_hashes {
let (event_id, _) = gen_event_id_canonical_json(pdu, &vi).map_err(|e| {
err!(Request(InvalidParam("Could not convert event to canonical json: {e}")))
})?;
OwnedRoomId::parse(event_id.as_str().replace('$', "!")).expect("valid room ID")
} else {
// V11 or below room, room_id must be present
value
.get("room_id")
.and_then(CanonicalJsonValue::as_str)
.map(OwnedRoomId::parse)
.flat_ok_or(err!(Request(InvalidParam("Invalid or missing room_id in pdu"))))?
}
};
let room_version_id = self let room_version_id = self
.services .services
@@ -60,5 +111,6 @@ pub async fn parse_incoming_pdu(&self, pdu: &RawJsonValue) -> Result<Parsed> {
let (event_id, value) = gen_event_id_canonical_json(pdu, &room_version_id).map_err(|e| { let (event_id, value) = gen_event_id_canonical_json(pdu, &room_version_id).map_err(|e| {
err!(Request(InvalidParam("Could not convert event to canonical json: {e}"))) err!(Request(InvalidParam("Could not convert event to canonical json: {e}")))
})?; })?;
self.validate_pdu(&value)?;
Ok((room_id, event_id, value)) Ok((room_id, event_id, value))
} }

View File

@@ -15,7 +15,7 @@
use database::{Deserialized, Ignore, Interfix, Json, Map}; use database::{Deserialized, Ignore, Interfix, Json, Map};
use futures::{Stream, StreamExt, TryFutureExt}; use futures::{Stream, StreamExt, TryFutureExt};
#[cfg(feature = "ldap")] #[cfg(feature = "ldap")]
use ldap3::{LdapConnAsync, Scope, SearchEntry}; use ldap3::{LdapConnAsync, LdapConnSettings, Scope, SearchEntry};
use ruma::{ use ruma::{
DeviceId, KeyId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm, OneTimeKeyId, DeviceId, KeyId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm, OneTimeKeyId,
OneTimeKeyName, OwnedDeviceId, OwnedKeyId, OwnedMxcUri, OwnedUserId, RoomId, UInt, UserId, OneTimeKeyName, OwnedDeviceId, OwnedKeyId, OwnedMxcUri, OwnedUserId, RoomId, UInt, UserId,
@@ -1285,6 +1285,24 @@ pub fn set_profile_key(
} }
} }
#[cfg(feature = "ldap")]
async fn create_ldap_connection(
config: &conduwuit_core::config::LdapConfig,
uri: &str,
) -> Result<(LdapConnAsync, ldap3::Ldap), ldap3::LdapError> {
let mut settings = LdapConnSettings::new();
if config.use_starttls {
settings = settings.set_starttls(true);
}
if config.disable_tls_verification {
settings = settings.set_no_tls_verify(true);
}
LdapConnAsync::with_settings(settings, uri).await
}
#[cfg(not(feature = "ldap"))] #[cfg(not(feature = "ldap"))]
pub async fn search_ldap(&self, _user_id: &UserId) -> Result<Vec<(String, Option<bool>)>> { pub async fn search_ldap(&self, _user_id: &UserId) -> Result<Vec<(String, Option<bool>)>> {
Err!(FeatureDisabled("ldap")) Err!(FeatureDisabled("ldap"))
@@ -1302,7 +1320,7 @@ pub async fn search_ldap(&self, user_id: &UserId) -> Result<Vec<(String, Option<
.ok_or_else(|| err!(Ldap(error!("LDAP URI is not configured."))))?; .ok_or_else(|| err!(Ldap(error!("LDAP URI is not configured."))))?;
debug!(?uri, "LDAP creating connection..."); debug!(?uri, "LDAP creating connection...");
let (conn, mut ldap) = LdapConnAsync::new(uri.as_str()) let (conn, mut ldap) = Self::create_ldap_connection(config, uri.as_str())
.await .await
.map_err(|e| err!(Ldap(error!(%user_id, "LDAP connection setup error: {e}"))))?; .map_err(|e| err!(Ldap(error!(%user_id, "LDAP connection setup error: {e}"))))?;
@@ -1411,9 +1429,9 @@ pub async fn auth_ldap(&self, user_dn: &str, password: &str) -> Result {
.ok_or_else(|| err!(Ldap(error!("LDAP URI is not configured."))))?; .ok_or_else(|| err!(Ldap(error!("LDAP URI is not configured."))))?;
debug!(?uri, "LDAP creating connection..."); debug!(?uri, "LDAP creating connection...");
let (conn, mut ldap) = LdapConnAsync::new(uri.as_str()) let (conn, mut ldap) = Self::create_ldap_connection(config, uri.as_str())
.await .await
.map_err(|e| err!(Ldap(error!(?user_dn, "LDAP connection setup error: {e}"))))?; .map_err(|e| err!(Ldap(error!(%user_dn, "LDAP connection setup error: {e}"))))?;
let driver = self.services.server.runtime().spawn(async move { let driver = self.services.server.runtime().spawn(async move {
match conn.drive().await { match conn.drive().await {