Compare commits

..

12 Commits

Author SHA1 Message Date
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
15 changed files with 158 additions and 24 deletions
+53
View File
@@ -0,0 +1,53 @@
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 (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.');
}
+6 -3
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')
# VERSION is the package version, COMPONENT is used in
# apt's repository config like a git repo branch
if [[ "${{ forge.ref }}" == "refs/tags/"* ]]; then
# Use the "stable" component for tagged releases
VERSION=$BASE_VERSION
if [[ ${{ forge.ref_name }} =~ ^v+[0-9]\.+[0-9]\.+[0-9]$ ]]; then
# Use the "stable" component for tagged semver releases
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
# Use the "dev" component for development builds
SHA=$(echo "${{ forge.sha }}" | cut -c1-7)
Generated
+11 -11
View File
@@ -848,9 +848,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.6.0"
version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
dependencies = [
"clap_builder",
"clap_derive",
@@ -868,9 +868,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.6.0"
version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
dependencies = [
"heck",
"proc-macro2",
@@ -1906,7 +1906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@@ -3475,7 +3475,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.60.2",
]
[[package]]
@@ -4845,7 +4845,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@@ -5446,7 +5446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys 0.60.2",
]
[[package]]
@@ -5749,9 +5749,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.51.1"
version = "1.52.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c"
checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
dependencies = [
"bytes",
"libc",
@@ -6578,7 +6578,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
+1
View File
@@ -0,0 +1 @@
Users will now be prevented from removing their email if the server is configured to require an email when registering an account.
+1
View File
@@ -0,0 +1 @@
Fixed a situation where multiple email addresses could be associated with one user when that user changes their email address.
+3
View File
@@ -2104,6 +2104,9 @@
# Whether to require that users provide an email address when they
# 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
# Whether to require that users who register with a registration token
@@ -6,10 +6,10 @@
"message": "Welcome to Continuwuity! Important announcements about the project will appear here."
},
{
"id": 10,
"id": 11,
"mention_room": false,
"date": "2026-03-03",
"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."
"date": "2026-04-17",
"message": "[v0.5.7](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.7) is out! Email verification! Terms and Conditions! Deleting notification pushers! So much good stuff. Go grab the release and read the changelog!"
}
]
}
+4
View File
@@ -8,7 +8,9 @@
callPackage,
rustPlatform,
cargoExtraArgs ? "",
rustflags ? "",
rocksdb ? callPackage ./rocksdb.nix { },
profile ? "release",
}:
let
# see https://crane.dev/API.html#cranelibfiltercargosources
@@ -35,6 +37,8 @@ let
env = {
ROCKSDB_INCLUDE_DIR = "${rocksdb}/include";
ROCKSDB_LIB_DIR = "${rocksdb}/lib";
CARGO_PROFILE = profile;
RUSTFLAGS = rustflags;
};
};
in
+17 -1
View File
@@ -5,6 +5,7 @@
{
perSystem =
{
self',
pkgs,
craneLib,
...
@@ -12,7 +13,22 @@
{
packages = {
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";
};
};
};
}
+3 -1
View File
@@ -6,7 +6,9 @@ This document provides information about downloading and deploying the Debian pa
To add the Continuwuation apt repository:
```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"
# Import the Continuwuation signing key
sudo curl https://forgejo.ellis.link/api/packages/continuwuation/debian/repository.key -o /etc/apt/keyrings/forgejo-continuwuation.asc
+12
View File
@@ -53,6 +53,10 @@ pub(crate) async fn request_3pid_management_token_via_email_route(
State(services): State<crate::State>,
body: Ruma<request_3pid_management_token_via_email::v3::Request>,
) -> 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 {
return Err!(Request(InvalidParam("Invalid email address.")));
};
@@ -105,6 +109,10 @@ pub(crate) async fn add_3pid_route(
) -> Result<add_3pid::v3::Response> {
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
let _ = services
.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
.threepid
.disassociate_localpart_email(sender_user.localpart())
+1 -1
View File
@@ -32,7 +32,7 @@ pub(crate) async fn get_capabilities_route(
// Only allow 3pid changes if SMTP is configured
capabilities.thirdparty_id_changes = ThirdPartyIdChangesCapability {
enabled: services.mailer.mailer().is_some(),
enabled: services.threepid.email_requirement().may_change(),
};
capabilities.get_login_token = GetLoginTokenCapability {
+3 -1
View File
@@ -2516,6 +2516,9 @@ pub struct SmtpConfig {
/// Whether to require that users provide an email address when they
/// 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
#[serde(default)]
pub require_email_for_registration: bool,
@@ -2545,7 +2548,6 @@ const DEPRECATED_KEYS: &[&str] = &[
"well_known_support_role",
"well_known_support_email",
"well_known_support_mxid",
"registration_token_file",
"well_known.rtc_focus_server_urls",
];
+7 -3
View File
@@ -9,6 +9,7 @@ use std::{
};
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
use conduwuit::info;
use conduwuit_core::{
Error, Event, Result, at, debug, err, error,
result::LogErr,
@@ -866,9 +867,12 @@ impl Service {
for (event_id, result) in result.iter().flat_map(|resp| resp.pdus.iter()) {
if let Err(e) = result {
warn!(
%txn_id, %server,
"error sending PDU {event_id} to remote server: {e:?}"
info!(
%txn_id,
%server,
%event_id,
remote_error=?e,
"remote server encountered an error while processing an event"
);
}
}
+33
View File
@@ -25,6 +25,23 @@ pub struct Service {
ratelimiter: DefaultKeyedRateLimiter<Address>,
}
pub enum EmailRequirement {
/// Users may change their email, but cannot remove it entirely.
Required,
/// Users may change or remove their email.
Optional,
/// Users may not change their email at all.
Unavailable,
}
impl EmailRequirement {
#[must_use]
pub fn may_change(&self) -> bool { matches!(self, Self::Required | Self::Optional) }
#[must_use]
pub fn may_remove(&self) -> bool { matches!(self, Self::Optional) }
}
struct Data {
localpart_email: Arc<Map>,
email_localpart: Arc<Map>,
@@ -64,6 +81,19 @@ impl Service {
Quota::per_minute(nonzero!(10_u32)).allow_burst(nonzero!(2_u32));
const VALIDATION_URL_PATH: &str = "/_continuwuity/3pid/email/validate";
/// Check if users are required to have an email address.
pub fn email_requirement(&self) -> EmailRequirement {
if let Some(smtp) = &self.services.config.smtp {
if smtp.require_email_for_registration || smtp.require_email_for_token_registration {
EmailRequirement::Required
} else {
EmailRequirement::Optional
}
} else {
EmailRequirement::Unavailable
}
}
/// Send a validation message to an email address.
///
/// Returns the validation session ID on success.
@@ -234,6 +264,9 @@ impl Service {
| None => {
// The supplied email is not already in use.
// Remove the user's existing email first.
let _ = self.disassociate_localpart_email(localpart).await;
let email: &str = email.as_ref();
self.db.localpart_email.insert(localpart, email);
self.db.email_localpart.insert(email, localpart);