feat: Allow self-service deactivation to be disabled

This commit is contained in:
Ginger
2026-05-06 14:48:07 -04:00
parent 5ca1341bf7
commit 66aba9d5d0
6 changed files with 42 additions and 1 deletions
+1
View File
@@ -0,0 +1 @@
Users may now be forbidden from deactivating their own accounts with the new `allow_deactivation` config option.
+10
View File
@@ -521,6 +521,16 @@
#
#recaptcha_private_site_key =
# Controls whether users are allowed to deactivate their own accounts
# through the account management panel or their Matrix clients. Server
# admins can always deactivate users using the relevant admin commands.
#
# Note that, in some jurisdictions, you may be legally required to honor
# users who request to deactivate their accounts if you set this option
# to `false`.
#
#allow_deactivation = true
# Controls whether encrypted rooms and events are allowed.
#
#allow_encryption = true
+7
View File
@@ -283,6 +283,13 @@ pub(crate) async fn deactivate_route(
let sender_user = identity.sender_user();
if !services.config.allow_deactivation {
return Err!(Request(Unauthorized(
"You may not deactivate your own account. Contact your server's administrator for \
assistance."
)));
}
// Prompt the user to confirm with their password using UIAA
let _ = services
.uiaa
+11
View File
@@ -663,6 +663,17 @@ pub struct Config {
#[serde(default)]
pub oauth: OauthConfig,
/// Controls whether users are allowed to deactivate their own accounts
/// through the account management panel or their Matrix clients. Server
/// admins can always deactivate users using the relevant admin commands.
///
/// Note that, in some jurisdictions, you may be legally required to honor
/// users who request to deactivate their accounts if you set this option
/// to `false`.
///
/// default: true
pub allow_deactivation: bool,
/// Controls whether encrypted rooms and events are allowed.
#[serde(default = "true_fn")]
pub allow_encryption: bool,
+4 -1
View File
@@ -30,6 +30,7 @@ template! {
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
enum DeactivateBody {
Unavailable,
Form {
user_id: OwnedUserId,
user_card: UserCard,
@@ -67,7 +68,9 @@ async fn route_deactivate(
let user_card = UserCard::for_local_user(&services, user_id.clone()).await;
let body = {
if let Some(form) = form {
if !services.config.allow_deactivation {
DeactivateBody::Unavailable
} else if let Some(form) = form {
if let Err(err) = validate_deactivate_form(&services, &user_id, form).await {
DeactivateBody::Form {
user_id,
@@ -5,9 +5,18 @@ Deactivate your account
{%- endblock -%}
{%- block content -%}
{% match body %}
{% when DeactivateBody::Form { .. } | DeactivateBody::Success %}
<div class="panel">
{% when DeactivateBody::Unavailable %}
<div class="panel middle"/>
{% endmatch %}
<h1>Deactivate your account <a class="back" href="{{ crate::ROUTE_PREFIX }}/account/">Back</a></h1>
{% match body %}
{% when DeactivateBody::Unavailable %}
<p>
To deactivate your account, contact your homeserver's administrator.
</p>
{% when DeactivateBody::Form { user_id, user_card, form } %}
{{ user_card }}
<p>