Compare commits

..

54 Commits

Author SHA1 Message Date
nexy7574 6aae5ca525 Reset README back to HEAD 2025-04-19 20:26:59 +01:00
Jade Ellis b9525ae91f ci: Run builtin registry whenever secret is available 2025-04-19 12:13:47 -07:00
Jade Ellis da7bee5305 ci: Try invert condition for branch prefix 2025-04-19 12:13:47 -07:00
Jade Ellis f96ce20427 ci: Enable buildx caching 2025-04-19 12:13:47 -07:00
Jade Ellis 77a62215ea chore: Update git links 2025-04-19 12:13:47 -07:00
Jade Ellis b6420e7def ci: Use dind label 2025-04-19 12:13:47 -07:00
Jade Ellis e508c9f9cf ci: Remove non-functional cache steps 2025-04-19 12:13:47 -07:00
Jade Ellis ee71cf2008 fix: Disable buildkit caching
This is for tom's runners, whilst they're having network issues
2025-04-19 12:13:47 -07:00
Jade Ellis 8269a2fd1c ci: Only prefix non-default branches
AKA, tag image:main as the latest commit
2025-04-19 12:13:47 -07:00
Jade Ellis 3d27cce047 ci: Limit concurrency
Mainly to prevent runners from getting bogged down
2025-04-19 12:13:47 -07:00
Jade Ellis 7763b2479b fix: Replace rust cache with direct cache use, as Rust is not installed on CI image 2025-04-19 12:13:47 -07:00
Jade Ellis cd24a72078 ci: Prefix branch builds with branch- 2025-04-19 12:13:47 -07:00
Jade Ellis 9298c53a40 fix: Hardcode matrix 2025-04-19 12:13:47 -07:00
Jade Ellis 25378a4668 fix: Use forgejo patched artifact actions 2025-04-19 12:13:47 -07:00
Jade Ellis fdef36c47f fix: Allow specifying user & password for builtin registry 2025-04-19 12:13:47 -07:00
Jade Ellis 406f689301 build: Use hacks for a cached actions build
- Use cache dance for github actions caching
- Use timelord hack to avoid bad cache invalidation
2025-04-19 12:13:47 -07:00
Jade Ellis 7185d71827 feat: Docker images built with Forgejo Actions 2025-04-19 12:13:47 -07:00
Jade Ellis ff83e0c5b2 chore: Change branding string to continuwuity 2025-04-19 12:13:47 -07:00
Jade Ellis b26247e31e fix: Disambiguate appservices in lazy loading context
In the previous commit, app services would all appear to be the same
device when accessing the same user. This sets the device ID to be the
appservice ID when available to avoid possible clobbering.
2025-04-19 12:13:47 -07:00
nexy7574 814f321cab fix: Do not panic when sender_device is None in /messages route
The device ID is not always present when the appservice is the client.
This was causing 500 errors for some users, as appservices can lazy
load from `/messages`.

Fixes #738

Co-authored-by: Jade Ellis <jade@ellis.link>
2025-04-19 12:13:47 -07:00
Tom Foster 904fa3c869 Add Forgejo CI workflow for Cloudflare Pages 2025-04-19 12:13:47 -07:00
Tom Foster b04a9469ae Add Matrix .well-known files 2025-04-19 12:13:47 -07:00
Tom Foster 6fbff4af6f Update mdBook config for continuwuity 2025-04-19 12:13:47 -07:00
Jade Ellis dede3323f6 chore: Add words to cspell dictionary 2025-04-19 12:13:47 -07:00
Jade Ellis a21d96d336 chore: Update Olivia Lee in mailmap 2025-04-19 12:13:47 -07:00
Jade Ellis f5622881b3 chore: Add Timo Kösters to the mailmap 2025-04-19 12:13:47 -07:00
Jade Ellis a869f06239 chore: Add mailmap 2025-04-19 12:13:47 -07:00
Jade Ellis 20c2091e5c ci: Delete all old CI files
Part of #753
2025-04-19 12:13:47 -07:00
Jade Ellis 04f7e26927 docs: Phrasing 2025-04-19 12:12:24 -07:00
Jade Ellis a9eba0e117 docs: New readme
It's a continuwuation!
2025-04-19 12:12:08 -07:00
Jacob Taylor eb2949d6d7 Fix spaces rooms list load error.
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-16 20:58:48 -07:00
Jacob Taylor de7842b470 Fix spaces limit/max_depth bug in response.
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-16 20:58:48 -07:00
Peter Gervai 937c5fc86a config: rocksdb_compaction help was inverted
probably old remnnant of an inverted option.
2025-04-15 08:09:21 -07:00
Jason Volk 79268bda1e Remove the default sentry endpoint.
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 07:28:14 +00:00
Jason Volk edb245a2ba Remove the updates service.
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 07:19:16 +00:00
Jason Volk ae2abab4c9 Remove some workflows.
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 07:18:26 +00:00
Jason Volk b9fd88b65a Update README [ci skip]
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 06:56:16 +00:00
Jason Volk 4094cd52ee reduce large stack frames 2025-04-13 05:13:00 +00:00
Jason Volk aa80e952d1 mitigate additional debuginfo expansions
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:13:00 +00:00
Jason Volk b0203818db add missing feature-projections between intra-workspace crates
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:13:00 +00:00
Jason Volk 1fd881bda5 eliminate Arc impl for trait Event
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:13:00 +00:00
Jason Volk 5b322561ce simplify database backup interface related
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:13:00 +00:00
Jason Volk 54fb48a983 replace admin command branches returning RoomMessageEventContent
rename admin Command back to Context

Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:13:00 +00:00
Jason Volk d82f00c31c misc async optimizations; macro reformatting
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:13:00 +00:00
Jason Volk cd4e6b61a9 improve appservice service async interfaces
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:13:00 +00:00
Jason Volk 04d7f7f626 remove box ids from admin room command arguments
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:13:00 +00:00
Jason Volk d9616c625d propagate better message from RustlsConfig load error. (#734)
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:13:00 +00:00
Jason Volk 75aadd5c6a slightly optimize user directory search loop
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:13:00 +00:00
Jason Volk e0508958b7 increase snake sync asynchronicity
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-13 05:12:52 +00:00
Jason Volk ccf10c6b47 modest cleanup of snake sync service related
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-09 03:40:44 +00:00
Jason Volk fd33f9aa79 modernize state_res w/ stream extensions
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-09 03:40:44 +00:00
Jason Volk 7c9d3f7e07 add ReadyEq future extension
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-09 03:40:44 +00:00
Jason Volk 7cf61b5b7b add ready_find() stream extension
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-09 03:40:44 +00:00
Jason Volk ce6e5e48de relax Send requirement on some drier stream extensions
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-09 03:40:44 +00:00
33 changed files with 155 additions and 479 deletions
-4
View File
@@ -36,13 +36,9 @@ jobs:
- name: Prepare static files for deployment
run: |
mkdir -p ./public/.well-known/matrix
mkdir -p ./public/.well-known/continuwuity
mkdir -p ./public/schema
# Copy the Matrix .well-known files
cp ./docs/static/server ./public/.well-known/matrix/server
cp ./docs/static/client ./public/.well-known/matrix/client
cp ./docs/static/announcements.json ./public/.well-known/continuwuity/announcements
cp ./docs/static/announcements.schema.json ./public/schema/announcements.schema.json
# Copy the custom headers file
cp ./docs/static/_headers ./public/_headers
echo "Copied .well-known files and _headers to ./public"
+1 -19
View File
@@ -89,13 +89,7 @@ jobs:
uses: actions/checkout@v4
with:
persist-credentials: false
- run: |
if ! command -v rustup &> /dev/null ; then
curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --default-toolchain none -y
echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH
fi
- uses: https://github.com/cargo-bins/cargo-binstall@main
- run: cargo binstall timelord-cli@3.0.1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Set up QEMU
@@ -129,18 +123,6 @@ jobs:
echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV
- name: Get Git commit timestamps
run: echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV
- name: Set up timelord
uses: actions/cache/restore@v3
with:
path: /timelord/
key: timelord-v0 # Cache is already split per runner
- name: Run timelord to set timestamps
run: timelord sync --source-dir . --cache-dir /timelord/
- name: Save timelord
uses: actions/cache/save@v3
with:
path: /timelord/
key: timelord-v0
- name: Build and push Docker image by digest
id: build
uses: docker/build-push-action@v6
Generated
+19 -19
View File
@@ -725,7 +725,7 @@ dependencies = [
[[package]]
name = "conduwuit"
version = "0.5.0-rc.5"
version = "0.5.0"
dependencies = [
"clap",
"conduwuit_admin",
@@ -754,7 +754,7 @@ dependencies = [
[[package]]
name = "conduwuit_admin"
version = "0.5.0-rc.5"
version = "0.5.0"
dependencies = [
"clap",
"conduwuit_api",
@@ -775,7 +775,7 @@ dependencies = [
[[package]]
name = "conduwuit_api"
version = "0.5.0-rc.5"
version = "0.5.0"
dependencies = [
"async-trait",
"axum",
@@ -807,7 +807,7 @@ dependencies = [
[[package]]
name = "conduwuit_core"
version = "0.5.0-rc.5"
version = "0.5.0"
dependencies = [
"argon2",
"arrayvec",
@@ -865,7 +865,7 @@ dependencies = [
[[package]]
name = "conduwuit_database"
version = "0.5.0-rc.5"
version = "0.5.0"
dependencies = [
"async-channel",
"conduwuit_core",
@@ -883,7 +883,7 @@ dependencies = [
[[package]]
name = "conduwuit_macros"
version = "0.5.0-rc.5"
version = "0.5.0"
dependencies = [
"itertools 0.14.0",
"proc-macro2",
@@ -893,7 +893,7 @@ dependencies = [
[[package]]
name = "conduwuit_router"
version = "0.5.0-rc.5"
version = "0.5.0"
dependencies = [
"axum",
"axum-client-ip",
@@ -926,7 +926,7 @@ dependencies = [
[[package]]
name = "conduwuit_service"
version = "0.5.0-rc.5"
version = "0.5.0"
dependencies = [
"async-trait",
"base64 0.22.1",
@@ -3652,7 +3652,7 @@ dependencies = [
[[package]]
name = "ruma"
version = "0.10.1"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"assign",
"js_int",
@@ -3672,7 +3672,7 @@ dependencies = [
[[package]]
name = "ruma-appservice-api"
version = "0.10.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"js_int",
"ruma-common",
@@ -3684,7 +3684,7 @@ dependencies = [
[[package]]
name = "ruma-client-api"
version = "0.18.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"as_variant",
"assign",
@@ -3707,7 +3707,7 @@ dependencies = [
[[package]]
name = "ruma-common"
version = "0.13.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"as_variant",
"base64 0.22.1",
@@ -3739,7 +3739,7 @@ dependencies = [
[[package]]
name = "ruma-events"
version = "0.28.1"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"as_variant",
"indexmap 2.8.0",
@@ -3764,7 +3764,7 @@ dependencies = [
[[package]]
name = "ruma-federation-api"
version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"bytes",
"headers",
@@ -3786,7 +3786,7 @@ dependencies = [
[[package]]
name = "ruma-identifiers-validation"
version = "0.9.5"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"js_int",
"thiserror 2.0.12",
@@ -3795,7 +3795,7 @@ dependencies = [
[[package]]
name = "ruma-identity-service-api"
version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"js_int",
"ruma-common",
@@ -3805,7 +3805,7 @@ dependencies = [
[[package]]
name = "ruma-macros"
version = "0.13.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"cfg-if",
"proc-macro-crate",
@@ -3820,7 +3820,7 @@ dependencies = [
[[package]]
name = "ruma-push-gateway-api"
version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"js_int",
"ruma-common",
@@ -3832,7 +3832,7 @@ dependencies = [
[[package]]
name = "ruma-signatures"
version = "0.15.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=fa3c868e5a1c049dc9472310dc4955289a96bb35#fa3c868e5a1c049dc9472310dc4955289a96bb35"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=920148dca1076454ca0ca5d43b5ce1aa708381d4#920148dca1076454ca0ca5d43b5ce1aa708381d4"
dependencies = [
"base64 0.22.1",
"ed25519-dalek",
+2 -2
View File
@@ -21,7 +21,7 @@ license = "Apache-2.0"
readme = "README.md"
repository = "https://forgejo.ellis.link/continuwuation/continuwuity"
rust-version = "1.86.0"
version = "0.5.0-rc.5"
version = "0.5.0"
[workspace.metadata.crane]
name = "conduwuit"
@@ -350,7 +350,7 @@ version = "0.1.2"
[workspace.dependencies.ruma]
git = "https://forgejo.ellis.link/continuwuation/ruwuma"
#branch = "conduwuit-changes"
rev = "fa3c868e5a1c049dc9472310dc4955289a96bb35"
rev = "920148dca1076454ca0ca5d43b5ce1aa708381d4"
features = [
"compat",
"rand",
+1
View File
@@ -111,3 +111,4 @@ When incorporating code from other forks:
[continuwuity]: https://forgejo.ellis.link/continuwuation/continuwuity
+3 -26
View File
@@ -112,12 +112,6 @@
#
#new_user_displayname_suffix = "🏳️‍⚧️"
# If enabled, conduwuit will send a simple GET request periodically to
# `https://continuwuity.org/.well-known/continuwuity/announcements` for any new
# announcements or major updates. This is not an update check endpoint.
#
#allow_announcements_check =
# Set this to any float value to multiply conduwuit's in-memory LRU caches
# with such as "auth_chain_cache_capacity".
#
@@ -966,8 +960,8 @@
#
#rocksdb_compaction_ioprio_idle = true
# Enables RocksDB compaction. You should never ever have to set this
# option to false. If you for some reason find yourself needing to use this
# Disables RocksDB compaction. You should never ever have to set this
# option to true. If you for some reason find yourself needing to use this
# option as part of troubleshooting or a bug, please reach out to us in
# the conduwuit Matrix room with information and details.
#
@@ -1193,33 +1187,16 @@
# incoming AND outgoing federation with, and block client room joins /
# remote user invites.
#
# Additionally, it will hide messages from these servers for all users
# on this server.
#
# Note that your messages can still make it to forbidden servers through
# backfilling. Events we receive from forbidden servers via backfill will
# be stored in the database, but will not be sent to the client.
#
# This check is applied on the room ID, room alias, sender server name,
# sender user's server name, inbound federation X-Matrix origin, and
# outbound federation handler.
#
# You can set this to ["*"] to block all servers by default, and then
# use `allowed_remote_server_names` to allow only specific servers.
# Basically "global" ACLs.
#
# example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"]
#
#forbidden_remote_server_names = []
# List of allowed server names via regex patterns that we will allow,
# regardless of if they match `forbidden_remote_server_names`.
#
# This option has no effect if `forbidden_remote_server_names` is empty.
#
# example: ["goodserver\.tld$", "goodphrase"]
#
#allowed_remote_server_names = []
# List of forbidden server names via regex patterns that we will block all
# outgoing federated room directory requests for. Useful for preventing
# our users from wandering into bad servers or spaces.
+8
View File
@@ -44,11 +44,15 @@ ENV CARGO_SBOM_VERSION=0.9.1
# renovate: datasource=crate depName=lddtree
ENV LDDTREE_VERSION=0.3.7
# renovate: datasource=crate depName=timelord-cli
ENV TIMELORD_VERSION=3.0.1
# Install unpackaged tools
RUN <<EOF
curl --retry 5 -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
cargo binstall --no-confirm cargo-sbom --version $CARGO_SBOM_VERSION
cargo binstall --no-confirm lddtree --version $LDDTREE_VERSION
cargo binstall --no-confirm timelord-cli --version $TIMELORD_VERSION
EOF
# Set up xx (cross-compilation scripts)
@@ -130,6 +134,10 @@ RUN xx-cargo --print-target-triple
# Get source
COPY . .
# Timelord sync
RUN --mount=type=cache,target=/timelord/ \
timelord sync --source-dir . --cache-dir /timelord/
# Build the binary
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git/db \
-3
View File
@@ -1,6 +1,3 @@
/.well-known/matrix/*
Access-Control-Allow-Origin: *
Content-Type: application/json
/.well-known/continuwuity/*
Access-Control-Allow-Origin: *
Content-Type: application/json
-9
View File
@@ -1,9 +0,0 @@
{
"$schema": "https://continuwuity.org/schema/announcements.schema.json",
"announcements": [
{
"id": 1,
"message": "Welcome to Continuwuity! Important announcements about the project will appear here."
}
]
}
-31
View File
@@ -1,31 +0,0 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$id": "https://continwuity.org/schema/announcements.schema.json",
"type": "object",
"properties": {
"updates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"message": {
"type": "string"
},
"date": {
"type": "string"
}
},
"required": [
"id",
"message"
]
}
}
},
"required": [
"updates"
]
}
-12
View File
@@ -11,8 +11,6 @@ pub(crate) enum GlobalsCommand {
CurrentCount,
LastCheckForAnnouncementsId,
/// - This returns an empty `Ok(BTreeMap<..>)` when there are no keys found
/// for the server.
SigningKeysFor {
@@ -39,16 +37,6 @@ pub(super) async fn process(subcommand: GlobalsCommand, context: &Context<'_>) -
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
| GlobalsCommand::LastCheckForAnnouncementsId => {
let timer = tokio::time::Instant::now();
let results = services
.announcements
.last_check_for_announcements_id()
.await;
let query_time = timer.elapsed();
write!(context, "Query completed in {query_time:?}:\n\n```rs\n{results:#?}\n```")
},
| GlobalsCommand::SigningKeysFor { origin } => {
let timer = tokio::time::Instant::now();
let results = services.server_keys.verify_keys_for(&origin).await;
+16 -3
View File
@@ -52,8 +52,13 @@ pub(crate) async fn get_public_rooms_filtered_route(
) -> Result<get_public_rooms_filtered::v3::Response> {
if let Some(server) = &body.server {
if services
.moderation
.is_remote_server_room_directory_forbidden(server)
.config
.forbidden_remote_room_directory_server_names
.is_match(server.host())
|| services
.config
.forbidden_remote_server_names
.is_match(server.host())
{
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
}
@@ -87,7 +92,15 @@ pub(crate) async fn get_public_rooms_route(
body: Ruma<get_public_rooms::v3::Request>,
) -> Result<get_public_rooms::v3::Response> {
if let Some(server) = &body.server {
if services.moderation.is_remote_server_forbidden(server) {
if services
.config
.forbidden_remote_room_directory_server_names
.is_match(server.host())
|| services
.config
.forbidden_remote_server_names
.is_match(server.host())
{
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
}
}
+3 -2
View File
@@ -83,8 +83,9 @@ async fn banned_room_check(
if let Some(room_id) = room_id {
if services.rooms.metadata.is_banned(room_id).await
|| services
.moderation
.is_remote_server_forbidden(room_id.server_name().expect("legacy room mxid"))
.config
.forbidden_remote_server_names
.is_match(room_id.server_name().expect("legacy room mxid").host())
{
warn!(
"User {user_id} who is not an admin attempted to send an invite for or \
+3 -2
View File
@@ -274,8 +274,9 @@ pub(crate) async fn is_ignored_pdu(
let ignored_type = IGNORED_MESSAGE_TYPES.binary_search(&pdu.kind).is_ok();
let ignored_server = services
.moderation
.is_remote_server_forbidden(pdu.sender().server_name());
.config
.forbidden_remote_server_names
.is_match(pdu.sender().server_name().host());
if ignored_type
&& (ignored_server || services.users.user_is_ignored(&pdu.sender, user_id).await)
+16 -26
View File
@@ -107,6 +107,7 @@ pub(crate) async fn create_room_route(
return Err!(Request(Forbidden("Publishing rooms to the room directory is not allowed")));
}
let _short_id = services
.rooms
.short
@@ -605,35 +606,24 @@ fn custom_room_id_check(services: &Services, custom_room_id: &str) -> Result<Own
return Err(Error::BadRequest(ErrorKind::Unknown, "Custom room ID is forbidden."));
}
let server_name = services.globals.server_name();
let mut room_id = custom_room_id.to_owned();
if custom_room_id.contains(':') {
if !custom_room_id.starts_with('!') {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Custom room ID contains an unexpected `:` which is not allowed.",
));
}
} else if custom_room_id.starts_with('!'){
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Room ID is prefixed with !, but is not fully qualified. You likely did not want this."));
} else {
room_id = format!("!{custom_room_id}:{server_name}");
ErrorKind::InvalidParam,
"Custom room ID contained `:` which is not allowed. Please note that this expects a \
localpart, not the full room ID.",
));
} else if custom_room_id.contains(char::is_whitespace) {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Custom room ID contained spaces which is not valid.",
));
}
OwnedRoomId::parse(room_id)
let server_name = services.globals.server_name();
let full_room_id = format!("!{custom_room_id}:{server_name}");
OwnedRoomId::parse(full_room_id)
.map_err(Into::into)
.and_then(
|full_room_id| {
if full_room_id.server_name().expect("failed to extract server name from room ID") != server_name {
Err(Error::BadRequest(ErrorKind::InvalidParam, "Custom room ID must be on this server."))
} else {
Ok(full_room_id)
}
}
)
.inspect(|full_room_id| {
debug_info!(?full_room_id, "Full custom room ID");
})
.inspect(|full_room_id| debug_info!(?full_room_id, "Full custom room ID"))
.inspect_err(|e| warn!(?e, ?custom_room_id, "Failed to create room with custom room ID",))
}
+5 -5
View File
@@ -121,7 +121,9 @@ where
.map(|(key, val)| (key, val.collect()))
.collect();
if !populate {
if populate {
rooms.push(summary_to_chunk(summary.clone()));
} else {
children = children
.iter()
.rev()
@@ -144,10 +146,8 @@ where
.collect();
}
if populate {
rooms.push(summary_to_chunk(summary.clone()));
} else if queue.is_empty() && children.is_empty() {
return Err!(Request(InvalidParam("Room IDs in token were not found.")));
if queue.is_empty() && children.is_empty() {
break;
}
parents.insert(current_room.clone());
+6 -2
View File
@@ -306,7 +306,7 @@ async fn auth_server(
}
fn auth_server_checks(services: &Services, x_matrix: &XMatrix) -> Result<()> {
if !services.config.allow_federation {
if !services.server.config.allow_federation {
return Err!(Config("allow_federation", "Federation is disabled."));
}
@@ -316,7 +316,11 @@ fn auth_server_checks(services: &Services, x_matrix: &XMatrix) -> Result<()> {
}
let origin = &x_matrix.origin;
if services.moderation.is_remote_server_forbidden(origin) {
if services
.config
.forbidden_remote_server_names
.is_match(origin.host())
{
return Err!(Request(Forbidden(debug_warn!(
"Federation requests from {origin} denied."
))));
+8 -3
View File
@@ -37,14 +37,19 @@ pub(crate) async fn create_invite_route(
}
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
if services
.config
.forbidden_remote_server_names
.is_match(server.host())
{
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
}
}
if services
.moderation
.is_remote_server_forbidden(body.origin())
.config
.forbidden_remote_server_names
.is_match(body.origin().host())
{
warn!(
"Received federated/remote invite from banned server {} for room ID {}. Rejecting.",
+8 -3
View File
@@ -42,8 +42,9 @@ pub(crate) async fn create_join_event_template_route(
.await?;
if services
.moderation
.is_remote_server_forbidden(body.origin())
.config
.forbidden_remote_server_names
.is_match(body.origin().host())
{
warn!(
"Server {} for remote user {} tried joining room ID {} which has a server name that \
@@ -56,7 +57,11 @@ pub(crate) async fn create_join_event_template_route(
}
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
if services
.config
.forbidden_remote_server_names
.is_match(server.host())
{
return Err!(Request(Forbidden(warn!(
"Room ID server name {server} is banned on this homeserver."
))));
+8 -3
View File
@@ -33,8 +33,9 @@ pub(crate) async fn create_knock_event_template_route(
.await?;
if services
.moderation
.is_remote_server_forbidden(body.origin())
.config
.forbidden_remote_server_names
.is_match(body.origin().host())
{
warn!(
"Server {} for remote user {} tried knocking room ID {} which has a server name \
@@ -47,7 +48,11 @@ pub(crate) async fn create_knock_event_template_route(
}
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
if services
.config
.forbidden_remote_server_names
.is_match(server.host())
{
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
}
}
+16 -6
View File
@@ -268,8 +268,9 @@ pub(crate) async fn create_join_event_v1_route(
body: Ruma<create_join_event::v1::Request>,
) -> Result<create_join_event::v1::Response> {
if services
.moderation
.is_remote_server_forbidden(body.origin())
.config
.forbidden_remote_server_names
.is_match(body.origin().host())
{
warn!(
"Server {} tried joining room ID {} through us who has a server name that is \
@@ -281,7 +282,11 @@ pub(crate) async fn create_join_event_v1_route(
}
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
if services
.config
.forbidden_remote_server_names
.is_match(server.host())
{
warn!(
"Server {} tried joining room ID {} through us which has a server name that is \
globally forbidden. Rejecting.",
@@ -309,14 +314,19 @@ pub(crate) async fn create_join_event_v2_route(
body: Ruma<create_join_event::v2::Request>,
) -> Result<create_join_event::v2::Response> {
if services
.moderation
.is_remote_server_forbidden(body.origin())
.config
.forbidden_remote_server_names
.is_match(body.origin().host())
{
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
}
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
if services
.config
.forbidden_remote_server_names
.is_match(server.host())
{
warn!(
"Server {} tried joining room ID {} through us which has a server name that is \
globally forbidden. Rejecting.",
+8 -3
View File
@@ -26,8 +26,9 @@ pub(crate) async fn create_knock_event_v1_route(
body: Ruma<send_knock::v1::Request>,
) -> Result<send_knock::v1::Response> {
if services
.moderation
.is_remote_server_forbidden(body.origin())
.config
.forbidden_remote_server_names
.is_match(body.origin().host())
{
warn!(
"Server {} tried knocking room ID {} who has a server name that is globally \
@@ -39,7 +40,11 @@ pub(crate) async fn create_knock_event_v1_route(
}
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
if services
.config
.forbidden_remote_server_names
.is_match(server.host())
{
warn!(
"Server {} tried knocking room ID {} which has a server name that is globally \
forbidden. Rejecting.",
+2 -27
View File
@@ -160,12 +160,6 @@ pub struct Config {
#[serde(default = "default_new_user_displayname_suffix")]
pub new_user_displayname_suffix: String,
/// If enabled, conduwuit will send a simple GET request periodically to
/// `https://continuwuity.org/.well-known/continuwuity/announcements` for any new
/// announcements or major updates. This is not an update check endpoint.
#[serde(alias = "allow_check_for_updates", default = "true_fn")]
pub allow_announcements_check: bool,
/// Set this to any float value to multiply conduwuit's in-memory LRU caches
/// with such as "auth_chain_cache_capacity".
///
@@ -1370,19 +1364,11 @@ pub struct Config {
/// incoming AND outgoing federation with, and block client room joins /
/// remote user invites.
///
/// Additionally, it will hide messages from these servers for all users
/// on this server.
///
/// Note that your messages can still make it to forbidden servers through
/// backfilling. Events we receive from forbidden servers via backfill will
/// be stored in the database, but will not be sent to the client.
///
/// This check is applied on the room ID, room alias, sender server name,
/// sender user's server name, inbound federation X-Matrix origin, and
/// outbound federation handler.
///
/// You can set this to ["*"] to block all servers by default, and then
/// use `allowed_remote_server_names` to allow only specific servers.
/// Basically "global" ACLs.
///
/// example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"]
///
@@ -1390,17 +1376,6 @@ pub struct Config {
#[serde(default, with = "serde_regex")]
pub forbidden_remote_server_names: RegexSet,
/// List of allowed server names via regex patterns that we will allow,
/// regardless of if they match `forbidden_remote_server_names`.
///
/// This option has no effect if `forbidden_remote_server_names` is empty.
///
/// example: ["goodserver\.tld$", "goodphrase"]
///
/// default: []
#[serde(default, with = "serde_regex")]
pub allowed_remote_server_names: RegexSet,
/// List of forbidden server names via regex patterns that we will block all
/// outgoing federated room directory requests for. Useful for preventing
/// our users from wandering into bad servers or spaces.
@@ -1969,7 +1944,7 @@ impl Config {
let mut addrs = Vec::with_capacity(
self.get_bind_hosts()
.len()
.saturating_mul(self.get_bind_ports().len()),
.saturating_add(self.get_bind_ports().len()),
);
for host in &self.get_bind_hosts() {
for port in &self.get_bind_ports() {
+1 -1
View File
@@ -114,11 +114,11 @@ ruma.workspace = true
rustls.workspace = true
rustls.optional = true
sentry.optional = true
sentry.workspace = true
sentry-tower.optional = true
sentry-tower.workspace = true
sentry-tracing.optional = true
sentry-tracing.workspace = true
sentry.workspace = true
serde_json.workspace = true
tokio.workspace = true
tower.workspace = true
-169
View File
@@ -1,169 +0,0 @@
//! # Announcements service
//!
//! This service is responsible for checking for announcements and sending them
//! to the client.
//!
//! It is used to send announcements to the admin room and logs.
//! Annuncements are stored in /docs/static/announcements right now.
//! The highest seen announcement id is stored in the database. When the
//! announcement check is run, all announcements with an ID higher than those
//! seen before are printed to the console and sent to the admin room.
//!
//! Old announcements should be deleted to avoid spamming the room on first
//! install.
//!
//! Announcements are displayed as markdown in the admin room, but plain text in
//! the console.
use std::{sync::Arc, time::Duration};
use async_trait::async_trait;
use conduwuit::{Result, Server, debug, info, warn};
use database::{Deserialized, Map};
use ruma::events::room::message::RoomMessageEventContent;
use serde::Deserialize;
use tokio::{
sync::Notify,
time::{MissedTickBehavior, interval},
};
use crate::{Dep, admin, client, globals};
pub struct Service {
interval: Duration,
interrupt: Notify,
db: Arc<Map>,
services: Services,
}
struct Services {
admin: Dep<admin::Service>,
client: Dep<client::Service>,
globals: Dep<globals::Service>,
server: Arc<Server>,
}
#[derive(Debug, Deserialize)]
struct CheckForAnnouncementsResponse {
announcements: Vec<CheckForAnnouncementsResponseEntry>,
}
#[derive(Debug, Deserialize)]
struct CheckForAnnouncementsResponseEntry {
id: u64,
date: Option<String>,
message: String,
}
const CHECK_FOR_ANNOUNCEMENTS_URL: &str =
"https://continuwuity.org/.well-known/continuwuity/announcements";
const CHECK_FOR_ANNOUNCEMENTS_INTERVAL: u64 = 7200; // 2 hours
const LAST_CHECK_FOR_ANNOUNCEMENTS_ID: &[u8; 25] = b"last_seen_announcement_id";
// In conduwuit, this was under b"a"
#[async_trait]
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
interval: Duration::from_secs(CHECK_FOR_ANNOUNCEMENTS_INTERVAL),
interrupt: Notify::new(),
db: args.db["global"].clone(),
services: Services {
globals: args.depend::<globals::Service>("globals"),
admin: args.depend::<admin::Service>("admin"),
client: args.depend::<client::Service>("client"),
server: args.server.clone(),
},
}))
}
#[tracing::instrument(skip_all, name = "announcements", level = "debug")]
async fn worker(self: Arc<Self>) -> Result<()> {
if !self.services.globals.allow_announcements_check() {
debug!("Disabling announcements check");
return Ok(());
}
let mut i = interval(self.interval);
i.set_missed_tick_behavior(MissedTickBehavior::Delay);
i.reset_after(self.interval);
loop {
tokio::select! {
() = self.interrupt.notified() => break,
_ = i.tick() => (),
}
if let Err(e) = self.check().await {
warn!(%e, "Failed to check for announcements");
}
}
Ok(())
}
fn interrupt(&self) { self.interrupt.notify_waiters(); }
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
#[tracing::instrument(skip_all)]
async fn check(&self) -> Result<()> {
debug_assert!(self.services.server.running(), "server must not be shutting down");
let response = self
.services
.client
.default
.get(CHECK_FOR_ANNOUNCEMENTS_URL)
.send()
.await?
.text()
.await?;
let response = serde_json::from_str::<CheckForAnnouncementsResponse>(&response)?;
for announcement in &response.announcements {
if announcement.id > self.last_check_for_announcements_id().await {
self.handle(announcement).await;
self.update_check_for_announcements_id(announcement.id);
}
}
Ok(())
}
#[tracing::instrument(skip_all)]
async fn handle(&self, announcement: &CheckForAnnouncementsResponseEntry) {
if let Some(date) = &announcement.date {
info!("[announcements] {date} {:#}", announcement.message);
} else {
info!("[announcements] {:#}", announcement.message);
}
self.services
.admin
.send_message(RoomMessageEventContent::text_markdown(format!(
"### New announcement{}\n\n{}",
announcement
.date
.as_ref()
.map_or_else(String::new, |date| format!(" - `{date}`")),
announcement.message
)))
.await
.ok();
}
#[inline]
pub fn update_check_for_announcements_id(&self, id: u64) {
self.db.raw_put(LAST_CHECK_FOR_ANNOUNCEMENTS_ID, id);
}
pub async fn last_check_for_announcements_id(&self) -> u64 {
self.db
.get(LAST_CHECK_FOR_ANNOUNCEMENTS_ID)
.await
.deserialized()
.unwrap_or(0_u64)
}
}
+7 -1
View File
@@ -64,7 +64,13 @@ where
return Err!(Config("allow_federation", "Federation is disabled."));
}
if self.services.moderation.is_remote_server_forbidden(dest) {
if self
.services
.server
.config
.forbidden_remote_server_names
.is_match(dest.host())
{
return Err!(Request(Forbidden(debug_warn!("Federation with {dest} is not allowed."))));
}
+1 -3
View File
@@ -4,7 +4,7 @@ use std::sync::Arc;
use conduwuit::{Result, Server};
use crate::{Dep, client, moderation, resolver, server_keys};
use crate::{Dep, client, resolver, server_keys};
pub struct Service {
services: Services,
@@ -15,7 +15,6 @@ struct Services {
client: Dep<client::Service>,
resolver: Dep<resolver::Service>,
server_keys: Dep<server_keys::Service>,
moderation: Dep<moderation::Service>,
}
impl crate::Service for Service {
@@ -26,7 +25,6 @@ impl crate::Service for Service {
client: args.depend::<client::Service>("client"),
resolver: args.depend::<resolver::Service>("resolver"),
server_keys: args.depend::<server_keys::Service>("server_keys"),
moderation: args.depend::<moderation::Service>("moderation"),
},
}))
}
-4
View File
@@ -127,10 +127,6 @@ impl Service {
&self.server.config.new_user_displayname_suffix
}
pub fn allow_announcements_check(&self) -> bool {
self.server.config.allow_announcements_check
}
pub fn trusted_servers(&self) -> &[OwnedServerName] { &self.server.config.trusted_servers }
pub fn turn_password(&self) -> &String { &self.server.config.turn_password }
+1 -3
View File
@@ -22,7 +22,7 @@ use tokio::{
use self::data::{Data, Metadata};
pub use self::thumbnail::Dim;
use crate::{Dep, client, globals, moderation, sending};
use crate::{Dep, client, globals, sending};
#[derive(Debug)]
pub struct FileMeta {
@@ -42,7 +42,6 @@ struct Services {
client: Dep<client::Service>,
globals: Dep<globals::Service>,
sending: Dep<sending::Service>,
moderation: Dep<moderation::Service>,
}
/// generated MXC ID (`media-id`) length
@@ -65,7 +64,6 @@ impl crate::Service for Service {
client: args.depend::<client::Service>("client"),
globals: args.depend::<globals::Service>("globals"),
sending: args.depend::<sending::Service>("sending"),
moderation: args.depend::<moderation::Service>("moderation"),
},
}))
}
+10 -2
View File
@@ -423,8 +423,16 @@ pub async fn fetch_remote_content_legacy(
fn check_fetch_authorized(&self, mxc: &Mxc<'_>) -> Result<()> {
if self
.services
.moderation
.is_remote_server_media_downloads_forbidden(mxc.server_name)
.server
.config
.prevent_media_downloads_from
.is_match(mxc.server_name.host())
|| self
.services
.server
.config
.forbidden_remote_server_names
.is_match(mxc.server_name.host())
{
// we'll lie to the client and say the blocked server's media was not found and
// log. the client has no way of telling anyways so this is a security bonus.
-2
View File
@@ -8,7 +8,6 @@ pub mod services;
pub mod account_data;
pub mod admin;
pub mod announcements;
pub mod appservice;
pub mod client;
pub mod config;
@@ -17,7 +16,6 @@ pub mod federation;
pub mod globals;
pub mod key_backups;
pub mod media;
pub mod moderation;
pub mod presence;
pub mod pusher;
pub mod resolver;
-77
View File
@@ -1,77 +0,0 @@
use std::sync::Arc;
use conduwuit::{Result, Server, implement};
use ruma::ServerName;
pub struct Service {
services: Services,
}
struct Services {
pub server: Arc<Server>,
}
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
services: Services { server: args.server.clone() },
}))
}
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
#[implement(Service)]
#[must_use]
pub fn is_remote_server_forbidden(&self, server_name: &ServerName) -> bool {
// We must never block federating with ourselves
if server_name == self.services.server.config.server_name {
return false;
}
// Check if server is explicitly allowed
if self
.services
.server
.config
.allowed_remote_server_names
.is_match(server_name.host())
{
return false;
}
// Check if server is explicitly forbidden
self.services
.server
.config
.forbidden_remote_server_names
.is_match(server_name.host())
}
#[implement(Service)]
#[must_use]
pub fn is_remote_server_room_directory_forbidden(&self, server_name: &ServerName) -> bool {
// Forbidden if NOT (allowed is empty OR allowed contains server OR is self)
// OR forbidden contains server
self.is_remote_server_forbidden(server_name)
|| self
.services
.server
.config
.forbidden_remote_room_directory_server_names
.is_match(server_name.host())
}
#[implement(Service)]
#[must_use]
pub fn is_remote_server_media_downloads_forbidden(&self, server_name: &ServerName) -> bool {
// Forbidden if NOT (allowed is empty OR allowed contains server OR is self)
// OR forbidden contains server
self.is_remote_server_forbidden(server_name)
|| self
.services
.server
.config
.prevent_media_downloads_from
.is_match(server_name.host())
}
+2 -7
View File
@@ -10,10 +10,9 @@ use futures::{Stream, StreamExt, TryStreamExt};
use tokio::sync::Mutex;
use crate::{
account_data, admin, announcements, appservice, client, config, emergency, federation,
globals, key_backups,
account_data, admin, appservice, client, config, emergency, federation, globals, key_backups,
manager::Manager,
media, moderation, presence, pusher, resolver, rooms, sending, server_keys, service,
media, presence, pusher, resolver, rooms, sending, server_keys, service,
service::{Args, Map, Service},
sync, transaction_ids, uiaa, users,
};
@@ -39,8 +38,6 @@ pub struct Services {
pub transaction_ids: Arc<transaction_ids::Service>,
pub uiaa: Arc<uiaa::Service>,
pub users: Arc<users::Service>,
pub moderation: Arc<moderation::Service>,
pub announcements: Arc<announcements::Service>,
manager: Mutex<Option<Arc<Manager>>>,
pub(crate) service: Arc<Map>,
@@ -107,8 +104,6 @@ impl Services {
transaction_ids: build!(transaction_ids::Service),
uiaa: build!(uiaa::Service),
users: build!(users::Service),
moderation: build!(moderation::Service),
announcements: build!(announcements::Service),
manager: Mutex::new(None),
service,