fix: Forbid removing emails if they're required to register

This commit is contained in:
Ginger
2026-04-23 13:17:48 -04:00
parent 8171e3d614
commit 567d809efe
5 changed files with 30 additions and 4 deletions
+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
+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
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,
+11 -3
View File
@@ -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<Map>,
email_localpart: Arc<Map>,
@@ -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
}