From 567d809efe2a6b5f72a2d394bde90380397ab679 Mon Sep 17 00:00:00 2001 From: Ginger Date: Thu, 23 Apr 2026 13:17:48 -0400 Subject: [PATCH] fix: Forbid removing emails if they're required to register --- conduwuit-example.toml | 3 +++ src/api/client/account/threepid.rs | 12 ++++++++++++ src/api/client/capabilities.rs | 2 +- src/core/config/mod.rs | 3 +++ src/service/threepid/mod.rs | 14 +++++++++++--- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/conduwuit-example.toml b/conduwuit-example.toml index dde9eda63..87a6b8df0 100644 --- a/conduwuit-example.toml +++ b/conduwuit-example.toml @@ -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 diff --git a/src/api/client/account/threepid.rs b/src/api/client/account/threepid.rs index b08f8246c..bcbd05cb2 100644 --- a/src/api/client/account/threepid.rs +++ b/src/api/client/account/threepid.rs @@ -53,6 +53,10 @@ pub(crate) async fn request_3pid_management_token_via_email_route( State(services): State, body: Ruma, ) -> Result { + 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 { 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()) diff --git a/src/api/client/capabilities.rs b/src/api/client/capabilities.rs index 405d11a0e..18708ce02 100644 --- a/src/api/client/capabilities.rs +++ b/src/api/client/capabilities.rs @@ -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 { diff --git a/src/core/config/mod.rs b/src/core/config/mod.rs index 3908edb85..a099dd7c4 100644 --- a/src/core/config/mod.rs +++ b/src/core/config/mod.rs @@ -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, diff --git a/src/service/threepid/mod.rs b/src/service/threepid/mod.rs index 1d0654db5..dcc0b58ab 100644 --- a/src/service/threepid/mod.rs +++ b/src/service/threepid/mod.rs @@ -27,13 +27,21 @@ pub struct Service { pub enum EmailRequirement { /// Users may change their email, but cannot remove it entirely. - Always, + Required, /// Users may change or remove their email. Optional, - /// SMTP is not configured. + /// 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, email_localpart: Arc, @@ -77,7 +85,7 @@ impl Service { 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::Always + EmailRequirement::Required } else { EmailRequirement::Optional }