Compare commits

...

61 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
Ginger
19204b097d chore: News fragments 2026-04-23 13:19:58 -04:00
Ginger
567d809efe fix: Forbid removing emails if they're required to register 2026-04-23 13:17:48 -04:00
Ginger
8171e3d614 fix: Remove a user's existing email before adding a new one 2026-04-23 13:05:21 -04:00
ginger
98b221096b fix(config): Remove registration_token_file from deprecated keys 2026-04-22 12:57:46 +00:00
aviac
027f6a4b02 feat(nix): allow override of RUSTFLAGS for certain features
- enabling the `http3` features requires unstable features, namely `reqwest_unstable`
- the main suggestion of cargo is to enable this through RUSTFLAGS
- we had no way to customize RUSTFLAGS, now we do
- changed the max-perf package to showcase this feature
- also turn on http3 by default in both max-perf and the default build
  (jade approved this)
2026-04-20 17:49:03 +00:00
aviac
42028f155b feat(nix): also add release-max-perf package build to flake outputs 2026-04-20 17:49:03 +00:00
Renovate Bot
6999246d19 chore(deps): update rust-non-major 2026-04-18 05:04:30 +00:00
timedout
01f6893c07 feat: Reduce verbosity of "remote server couldn't process pdu" warning
(cherry picked from commit 8b206564aa)
2026-04-18 01:11:48 +01:00
Jade
ed93a4ad9f chore: Admin announcement 2026-04-17 21:15:54 +00:00
Jade Ellis
cc8a4501b5 ci: Add basic CI auto-labeller 2026-04-17 21:41:01 +01:00
Sebastian Spaeth
cbb1632a1a docs: Describe Debian components
Describe "stable", "stable unstable" and "dev" components
2026-04-17 20:13:44 +00:00
Sebastian Spaeth
df59fc35b4 CI: Only publish releases into the Debian stable component
Previously, we would push all tagged releases into the stable component,
including alphas and rc's. Let's use some regex to only push stable
releases which conform to tag "^v+\d\.+\d\.+\d$"
so we ONLY get the manually published releases into the stable
component.

All pre-releases go into the "unstable" component for now. Nightly builds
go into the "dev" component (as before) and feature branches still get
their dedicated component named after the branch.

TODO: It would be nifty if stable releases would ALSO be published at the
unstable component.
2026-04-17 20:13:44 +00:00
Jade Ellis
c927bc7b30 chore: Release 2026-04-17 18:19:28 +01:00
Jade Ellis
c1ce40c008 docs: Changelog 2026-04-17 18:18:42 +01:00
ezera
66be11a978 docs(docs): update supported room versions
Updates supported room version to state we support 6-12, and sets 12
as default.
2026-04-17 16:10:05 +00:00
105 changed files with 1524 additions and 676 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

@@ -0,0 +1,56 @@
name: Auto Labeler
on:
pull_request_target:
types: [opened, reopened]
permissions:
contents: read
pull-requests: write
issues: write
jobs:
auto-label:
name: Apply labels based on changed files
runs-on: ubuntu-latest
steps:
- name: Apply PR Labels
uses: https://github.com/actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const allFiles = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
const fileNames = allFiles.map(f => f.filename);
const labelsToAdd = new Set();
for (const file of fileNames) {
if (file.startsWith('docs/') || file.startsWith('theme/') || file.endsWith('.md') || file == 'rspress.config.ts') {
labelsToAdd.add('Documentation');
}
if (file.startsWith('.forgejo/')) {
labelsToAdd.add('Meta/CI');
}
if (file.startsWith('pkg/') || file.startsWith('nix/') || file === 'flake.nix' || file === 'flake.lock' || file.startsWith('docker/')) {
labelsToAdd.add('Meta/Packaging');
}
if (file === 'Cargo.lock') {
labelsToAdd.add('Dependencies');
}
}
if (labelsToAdd.size > 0) {
const labelsArray = Array.from(labelsToAdd);
console.log('Adding labels:', labelsArray);
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: labelsArray,
});
} else {
console.log('No files changed that require auto-labeling.');
}

View File

@@ -92,10 +92,13 @@ jobs:
BASE_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r ".packages[] | select(.name == \"conduwuit\").version" | sed 's/[^a-zA-Z0-9.+]/~/g') BASE_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r ".packages[] | select(.name == \"conduwuit\").version" | sed 's/[^a-zA-Z0-9.+]/~/g')
# VERSION is the package version, COMPONENT is used in # VERSION is the package version, COMPONENT is used in
# apt's repository config like a git repo branch # apt's repository config like a git repo branch
if [[ "${{ forge.ref }}" == "refs/tags/"* ]]; then VERSION=$BASE_VERSION
# Use the "stable" component for tagged releases if [[ ${{ forge.ref_name }} =~ ^v+[0-9]\.+[0-9]\.+[0-9]$ ]]; then
# Use the "stable" component for tagged semver releases
COMPONENT="stable" COMPONENT="stable"
VERSION=$BASE_VERSION elif [[ ${{ forge.ref }} =~ ^refs/tags/^v+[0-9]\.+[0-9]\.+[0-9] ]]; then
# Use the "unstable" component for tagged semver pre-releases
COMPONENT="unstable"
else else
# Use the "dev" component for development builds # Use the "dev" component for development builds
SHA=$(echo "${{ forge.sha }}" | cut -c1-7) SHA=$(echo "${{ forge.sha }}" | cut -c1-7)

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,62 @@
# 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)
## Features
- Re-added support for reading registration tokens from a file. Contributed by @ginger and @benbot. (#1371)
- Add new config option to allow or disallow search engine indexing through a `<meta ../>` tag. Defaults to blocking indexing (`content="noindex"`). Contributed by @s1lv3r and @ginger. (#1527)
- Add new config option for [MSC4439](https://github.com/matrix-org/matrix-spec-proposals/pull/4439)
PGP key URIs. Contributed by LogN. (#1609)
- Added `!admin users reset-push-rules` command to reset the notification settings of users. Contributed by @nex. (#1613)
- Notification pushers are now automatically removed when their associated device is. Admin commands now exist for manual cleanup too. Contributed by @nex. (#1614)
- Implemented option to deprioritize servers for room join requests. Contributed by @ezera. (#1624)
- Added admin commands to get build information and features. Contributed by @Jade (#1629)
- Added support for associating email addresses with accounts, requiring email addresses for registration, and resetting passwords via email. Contributed by @ginger
- Added support for requiring users to accept terms and conditions when registering.
- Added support for using an admin command to issue self-service password reset links.
## Bugfixes
- Fixed corrupted appservice registrations causing the server to enter a crash loop. Contributed by @nex. (#1265)
- Prevent removing the admin room alias (`#admins`) to avoid accidentally breaking admin room functionality. Contributed by @0xnim (#1448)
- Stripped `join_authorised_via_users_server` from json if user is already in room (@partha:cxy.run) (#1542)
- Fixed internal server errors for fetching thumbnails. Contributed by @PerformativeJade (#1572)
- Fixed error 500 when joining non-existent rooms. Contributed by @ezera. (#1579)
- Refactored nix package. Breaking, since `all-features` package no longer exists. Continuwuity is now built with jemalloc and liburing by default. Contributed by @Henry-Hiles (QuadRadical). (#1596)
- Fixed resolving IP of servers that only use SRV delegation. Contributed by @tulir. (#1615)
- Fixed "Sender must be a local user" error for make_join, make_knock, and make_leave federation routes. Contributed by @nex. (#1623)
- Fixed restricted joins not being signed when we are being used as an authorising server. Contributed by @nex, reported by [vel](matrix:u/vel:nhjkl.com?action=chat). (#1630)
- Fixed room alias deletion so removing one local alias no longer removes other aliases from room alias listings.
- Stopped left rooms from being unconditionally sent on initial sync, hopefully fixing spurious appearances of left rooms in some clients (and making sync faster as a bonus). Contributed by @ginger
- Correct the response field name for MatrixRTC transports. Contributed by @spaetz
## Improved Documentation
- Added Testing and Troubleshooting instructions for Livekit documentation. Contributed by @stratself. (#1429)
- Refactored docker docs to include new initial token workflow, and add Caddyfile example. Contributed by @stratself. (#1594)
- Add DNS tuning guide for Continuwuity. Users are recommended to set up a local caching resolver following the guide's advice. Contributed by @stratself (#1601)
## Misc
- Fixed compiler warning in cf_opts.rs when building in release. Contributed by @ezera. (#1620)
# Continuwuity 0.5.6 (2026-03-03) # Continuwuity 0.5.6 (2026-03-03)
## Security ## Security

640
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-alpha.2" 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 @@
Added support for associating email addresses with accounts, requiring email addresses for registration, and resetting passwords via email. Contributed by @ginger

View File

@@ -1 +0,0 @@
Added support for using an admin command to issue self-service password reset links.

View File

@@ -1 +0,0 @@
Stopped left rooms from being unconditionally sent on initial sync, hopefully fixing spurious appearances of left rooms in some clients (and making sync faster as a bonus). Contributed by @ginger

View File

@@ -1 +0,0 @@
Added support for requiring users to accept terms and conditions when registering.

View File

@@ -1 +0,0 @@
Fixed room alias deletion so removing one local alias no longer removes other aliases from room alias listings.

View File

@@ -1 +0,0 @@
Fixed corrupted appservice registrations causing the server to enter a crash loop. Contributed by @nex.

View File

@@ -1 +0,0 @@
Re-added support for reading registration tokens from a file. Contributed by @ginger and @benbot.

View File

@@ -1 +0,0 @@
Added Testing and Troubleshooting instructions for Livekit documentation. Contributed by @stratself.

View File

@@ -1 +0,0 @@
Prevent removing the admin room alias (`#admins`) to avoid accidentally breaking admin room functionality. Contributed by @0xnim

View File

@@ -1 +0,0 @@
Add new config option to allow or disallow search engine indexing through a `<meta ../>` tag. Defaults to blocking indexing (`content="noindex"`). Contributed by @s1lv3r and @ginger.

View File

@@ -1 +0,0 @@
Stripped `join_authorised_via_users_server` from json if user is already in room (@partha:cxy.run)

View File

@@ -1 +0,0 @@
Fixed internal server errors for fetching thumbnails. Contributed by @PerformativeJade

View File

@@ -1 +0,0 @@
Fixed error 500 when joining non-existent rooms. Contributed by @ezera.

View File

@@ -1 +0,0 @@
Refactored docker docs to include new initial token workflow, and add Caddyfile example. Contributed by @stratself.

View File

@@ -1 +0,0 @@
Refactored nix package. Breaking, since `all-features` package no longer exists. Continuwuity is now built with jemalloc and liburing by default. Contributed by @Henry-Hiles (QuadRadical).

View File

@@ -1 +0,0 @@
Add DNS tuning guide for Continuwuity. Users are recommended to set up a local caching resolver following the guide's advice. Contributed by @stratself

View File

@@ -1,2 +0,0 @@
Add new config option for [MSC4439](https://github.com/matrix-org/matrix-spec-proposals/pull/4439)
PGP key URIs. Contributed by LogN.

View File

@@ -1 +0,0 @@
Added `!admin users reset-push-rules` command to reset the notification settings of users. Contributed by @nex.

View File

@@ -1 +0,0 @@
Notification pushers are now automatically removed when their associated device is. Admin commands now exist for manual cleanup too. Contributed by @nex.

View File

@@ -1 +0,0 @@
Fixed resolving IP of servers that only use SRV delegation. Contributed by @tulir.

View File

@@ -1 +0,0 @@
Fixed compiler warning in cf_opts.rs when building in release. Contributed by @ezera.

View File

@@ -1 +0,0 @@
Fixed "Sender must be a local user" error for make_join, make_knock, and make_leave federation routes. Contributed by @nex.

View File

@@ -1 +0,0 @@
Implemented option to deprioritize servers for room join requests. Contributed by @ezera.

View File

@@ -1 +0,0 @@
Added admin commands to get build information and features. Contributed by @Jade

View File

@@ -1 +0,0 @@
Fixed restricted joins not being signed when we are being used as an authorising server. Contributed by @nex, reported by [vel](matrix:u/vel:nhjkl.com?action=chat).

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

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

View File

@@ -619,7 +619,7 @@
# Set to false to disable users from joining or creating room versions # Set to false to disable users from joining or creating room versions
# that aren't officially supported by continuwuity. # that aren't officially supported by continuwuity.
# #
# continuwuity officially supports room versions 6 - 11. # continuwuity officially supports room versions 6 - 12.
# #
# continuwuity has slightly experimental (though works fine in practice) # continuwuity has slightly experimental (though works fine in practice)
# support for versions 3 - 5. # support for versions 3 - 5.
@@ -631,9 +631,9 @@
# rather than an integer. Forgetting the quotes will make the server fail # rather than an integer. Forgetting the quotes will make the server fail
# to start! # to start!
# #
# Per spec, room version "11" is the default. # Per spec, room version "12" is the default.
# #
#default_room_version = "11" #default_room_version = "12"
# Enable OpenTelemetry OTLP tracing export. This replaces the deprecated # Enable OpenTelemetry OTLP tracing export. This replaces the deprecated
# Jaeger exporter. Traces will be sent via OTLP to a collector (such as # Jaeger exporter. Traces will be sent via OTLP to a collector (such as
@@ -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"
@@ -2104,6 +2112,9 @@
# Whether to require that users provide an email address when they # Whether to require that users provide an email address when they
# register. # register.
# #
# If either this option or `require_email_for_token_registration` are set,
# users will not be allowed to remove their email address.
#
#require_email_for_registration = false #require_email_for_registration = false
# Whether to require that users who register with a registration token # Whether to require that users who register with a registration token

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": 10, "id": 12,
"mention_room": false, "mention_room": false,
"date": "2026-03-03", "date": "2026-04-24",
"message": "We've just released [v0.5.6](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.6), which contains a few security improvements - plus significant reliability and performance improvements. Please update as soon as possible. \n\nWe released [v0.5.5](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.5) two weeks ago, but it skipped your admin room straight to [our announcements channel](https://matrix.to/#/!jIdNjSM5X-V5JVx2h2kAhUZIIQ08GyzPL55NFZAH1vM?via=ellis.link&via=gingershaped.computer&via=matrix.org). Make sure you're there to get important information as soon as we announce it! [Our space](https://matrix.to/#/!8cR4g-i9ucof69E4JHNg9LbPVkGprHb3SzcrGBDDJgk?via=continuwuity.org&via=ellis.link&via=matrix.org) has also gained a bunch of new and interesting rooms - be there or be square." "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,10 +1,10 @@
# Continuwuity - Traefik Reverse Proxy Labels # Continuwuity - Traefik Reverse Proxy Labels (override file)
services: services:
homeserver: homeserver:
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=proxy" # Change this to the name of your Traefik docker proxy network - "traefik.docker.network=proxy" # Change this to the name of your Traefik docker proxy network
- "traefik.http.routers.to-continuwuity.rule=Host(`example.com`)" # Change to the address on which Continuwuity is hosted - "traefik.http.routers.to-continuwuity.rule=Host(`example.com`)" # Change to the address on which Continuwuity is hosted
- "traefik.http.routers.to-continuwuity.tls=true" - "traefik.http.routers.to-continuwuity.tls=true"
@@ -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

@@ -8,7 +8,9 @@
callPackage, callPackage,
rustPlatform, rustPlatform,
cargoExtraArgs ? "", cargoExtraArgs ? "",
rustflags ? "",
rocksdb ? callPackage ./rocksdb.nix { }, rocksdb ? callPackage ./rocksdb.nix { },
profile ? "release",
}: }:
let let
# see https://crane.dev/API.html#cranelibfiltercargosources # see https://crane.dev/API.html#cranelibfiltercargosources
@@ -35,6 +37,8 @@ let
env = { env = {
ROCKSDB_INCLUDE_DIR = "${rocksdb}/include"; ROCKSDB_INCLUDE_DIR = "${rocksdb}/include";
ROCKSDB_LIB_DIR = "${rocksdb}/lib"; ROCKSDB_LIB_DIR = "${rocksdb}/lib";
CARGO_PROFILE = profile;
RUSTFLAGS = rustflags;
}; };
}; };
in in

View File

@@ -5,6 +5,7 @@
{ {
perSystem = perSystem =
{ {
self',
pkgs, pkgs,
craneLib, craneLib,
... ...
@@ -12,7 +13,22 @@
{ {
packages = { packages = {
rocksdb = pkgs.callPackage ./rocksdb.nix { }; rocksdb = pkgs.callPackage ./rocksdb.nix { };
default = pkgs.callPackage ./continuwuity.nix { inherit self craneLib; }; default = pkgs.callPackage ./continuwuity.nix {
inherit self craneLib;
# extra features via `cargoExtraArgs`
cargoExtraArgs = "-F http3";
# extra RUSTFLAGS via `rustflags`
# the stuff below is required for http3
rustflags = "--cfg reqwest_unstable";
};
# users may also override this with other cargo profiles to build for other feature sets
#
# other examples include:
#
# - release-high-perf
max-perf = self'.packages.default.override {
profile = "release-max-perf";
};
}; };
}; };
} }

View File

@@ -6,7 +6,9 @@ ### Installation
To add the Continuwuation apt repository: To add the Continuwuation apt repository:
```bash ```bash
# Replace with `"dev"` for bleeding-edge builds at your own risk # Component `"stable"` contains all tagged releases. Use `"stable unstable"` to additionally include all pre-releases (alpha, beta, rc,...)
# Replace with `"dev"` for bleeding-edge builds at your own risk, these contain
# automatic nightly builds and might or might not work.
export COMPONENT="stable" export COMPONENT="stable"
# Import the Continuwuation signing key # Import the Continuwuation signing key
sudo curl https://forgejo.ellis.link/api/packages/continuwuation/debian/repository.key -o /etc/apt/keyrings/forgejo-continuwuation.asc sudo curl https://forgejo.ellis.link/api/packages/continuwuation/debian/repository.key -o /etc/apt/keyrings/forgejo-continuwuation.asc

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

@@ -53,6 +53,10 @@ pub(crate) async fn request_3pid_management_token_via_email_route(
State(services): State<crate::State>, State(services): State<crate::State>,
body: Ruma<request_3pid_management_token_via_email::v3::Request>, body: Ruma<request_3pid_management_token_via_email::v3::Request>,
) -> Result<request_3pid_management_token_via_email::v3::Response> { ) -> Result<request_3pid_management_token_via_email::v3::Response> {
if !services.threepid.email_requirement().may_change() {
return Err!(Request(Forbidden("You may not change your email address.")));
}
let Ok(email) = Address::try_from(body.email.clone()) else { let Ok(email) = Address::try_from(body.email.clone()) else {
return Err!(Request(InvalidParam("Invalid email address."))); return Err!(Request(InvalidParam("Invalid email address.")));
}; };
@@ -105,6 +109,10 @@ pub(crate) async fn add_3pid_route(
) -> Result<add_3pid::v3::Response> { ) -> Result<add_3pid::v3::Response> {
let sender_user = body.sender_user(); let sender_user = body.sender_user();
if !services.threepid.email_requirement().may_change() {
return Err!(Request(Forbidden("You may not change your email address.")));
}
// Require password auth to add an email // Require password auth to add an email
let _ = services let _ = services
.uiaa .uiaa
@@ -138,6 +146,10 @@ pub(crate) async fn delete_3pid_route(
}); });
} }
if !services.threepid.email_requirement().may_remove() {
return Err!(Request(Forbidden("You may not remove your email address.")));
}
if services if services
.threepid .threepid
.disassociate_localpart_email(sender_user.localpart()) .disassociate_localpart_email(sender_user.localpart())

View File

@@ -32,7 +32,7 @@ pub(crate) async fn get_capabilities_route(
// Only allow 3pid changes if SMTP is configured // Only allow 3pid changes if SMTP is configured
capabilities.thirdparty_id_changes = ThirdPartyIdChangesCapability { capabilities.thirdparty_id_changes = ThirdPartyIdChangesCapability {
enabled: services.mailer.mailer().is_some(), enabled: services.threepid.email_requirement().may_change(),
}; };
capabilities.get_login_token = GetLoginTokenCapability { capabilities.get_login_token = GetLoginTokenCapability {

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

@@ -753,7 +753,7 @@ pub struct Config {
/// Set to false to disable users from joining or creating room versions /// Set to false to disable users from joining or creating room versions
/// that aren't officially supported by continuwuity. /// that aren't officially supported by continuwuity.
/// ///
/// continuwuity officially supports room versions 6 - 11. /// continuwuity officially supports room versions 6 - 12.
/// ///
/// continuwuity has slightly experimental (though works fine in practice) /// continuwuity has slightly experimental (though works fine in practice)
/// support for versions 3 - 5. /// support for versions 3 - 5.
@@ -765,9 +765,9 @@ pub struct Config {
/// rather than an integer. Forgetting the quotes will make the server fail /// rather than an integer. Forgetting the quotes will make the server fail
/// to start! /// to start!
/// ///
/// Per spec, room version "11" is the default. /// Per spec, room version "12" is the default.
/// ///
/// default: "11" /// default: "12"
#[serde(default = "default_default_room_version")] #[serde(default = "default_default_room_version")]
pub default_room_version: RoomVersionId, pub default_room_version: RoomVersionId,
@@ -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"
@@ -2516,6 +2528,9 @@ pub struct SmtpConfig {
/// Whether to require that users provide an email address when they /// Whether to require that users provide an email address when they
/// register. /// register.
/// ///
/// If either this option or `require_email_for_token_registration` are set,
/// users will not be allowed to remove their email address.
///
/// default: false /// default: false
#[serde(default)] #[serde(default)]
pub require_email_for_registration: bool, pub require_email_for_registration: bool,
@@ -2545,7 +2560,6 @@ pub struct TermsDocument {
"well_known_support_role", "well_known_support_role",
"well_known_support_email", "well_known_support_email",
"well_known_support_mxid", "well_known_support_mxid",
"registration_token_file",
"well_known.rtc_focus_server_urls", "well_known.rtc_focus_server_urls",
]; ];
@@ -2828,7 +2842,7 @@ fn default_rocksdb_stats_level() -> u8 { 1 }
// I know, it's a great name // I know, it's a great name
#[must_use] #[must_use]
#[inline] #[inline]
pub fn default_default_room_version() -> RoomVersionId { RoomVersionId::V11 } pub fn default_default_room_version() -> RoomVersionId { RoomVersionId::V12 }
fn default_ip_range_denylist() -> Vec<String> { fn default_ip_range_denylist() -> Vec<String> {
vec![ vec![

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."

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