From eccc878ee9a605de738c42d6f375e21d80b56504 Mon Sep 17 00:00:00 2001 From: Ginger Date: Mon, 6 Apr 2026 12:19:08 -0400 Subject: [PATCH] feat: Add support for terms and conditions when registering --- conduwuit-example.toml | 12 ++++++++++++ src/api/client/account/register.rs | 25 +++++++++++++++++++++++++ src/core/config/mod.rs | 23 +++++++++++++++++++++-- src/service/uiaa/mod.rs | 1 + 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/conduwuit-example.toml b/conduwuit-example.toml index 7cd462326..8c95d84a3 100644 --- a/conduwuit-example.toml +++ b/conduwuit-example.toml @@ -523,6 +523,18 @@ # #recaptcha_private_site_key = +# Policy documents, such as terms and conditions or a privacy policy, +# which users must agree to when registering an account. +# +# Example: +# ``` +# [global.registration_terms.privacy_policy] +# en = { name = "Privacy Policy", url = "https://homeserver.example/en/privacy_policy.html" } +# es = { name = "Política de Privacidad", url = "https://homeserver.example/es/privacy_policy.html" } +# ``` +# +#registration_terms = false + # Controls whether encrypted rooms and events are allowed. # #allow_encryption = true diff --git a/src/api/client/account/register.rs b/src/api/client/account/register.rs index 7166733d7..3fd7e4418 100644 --- a/src/api/client/account/register.rs +++ b/src/api/client/account/register.rs @@ -462,6 +462,31 @@ async fn create_registration_uiaa_session( flows.push(untrusted_flow); } + // Require all users to agree to the terms and conditions, if configured + let terms = &services.config.registration_terms; + if !terms.is_empty() { + let mut terms = + serde_json::to_value(terms.clone()).expect("failed to serialize terms"); + + // Insert a dummy `version` field + for (_, documents) in terms.as_object_mut().unwrap() { + let documents = documents.as_object_mut().unwrap(); + + documents.insert("version".to_owned(), "latest".into()); + } + + params.insert( + AuthType::Terms.as_str().to_owned(), + serde_json::json!({ + "policies": terms, + }), + ); + + for flow in &mut flows { + flow.stages.insert(0, AuthType::Terms); + } + } + if flows.is_empty() { // No flows are configured. Bail out by default // unless open registration was explicitly enabled. diff --git a/src/core/config/mod.rs b/src/core/config/mod.rs index 738e1761f..40c3b9708 100644 --- a/src/core/config/mod.rs +++ b/src/core/config/mod.rs @@ -4,7 +4,7 @@ pub mod manager; pub mod proxy; use std::{ - collections::{BTreeMap, BTreeSet}, + collections::{BTreeMap, BTreeSet, HashMap}, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, path::PathBuf, }; @@ -22,7 +22,7 @@ use ruma::{ OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, OwnedUserId, RoomVersionId, api::client::discovery::{discover_homeserver::RtcFocusInfo, discover_support::ContactRole}, }; -use serde::{Deserialize, de::IgnoredAny}; +use serde::{Deserialize, Serialize, de::IgnoredAny}; use url::Url; use self::proxy::ProxyConfig; @@ -655,6 +655,18 @@ pub struct Config { /// even if `recaptcha_site_key` is set. pub recaptcha_private_site_key: Option, + /// Policy documents, such as terms and conditions or a privacy policy, + /// which users must agree to when registering an account. + /// + /// Example: + /// ``` + /// [global.registration_terms.privacy_policy] + /// en = { name = "Privacy Policy", url = "https://homeserver.example/en/privacy_policy.html" } + /// es = { name = "Política de Privacidad", url = "https://homeserver.example/es/privacy_policy.html" } + /// ``` + #[serde(default)] + pub registration_terms: HashMap>, + /// Controls whether encrypted rooms and events are allowed. #[serde(default = "true_fn")] pub allow_encryption: bool, @@ -2498,6 +2510,13 @@ pub struct SmtpConfig { pub require_email_for_token_registration: bool, } +/// A policy document for use with a m.login.terms stage. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct TermsDocument { + pub name: String, + pub url: String, +} + const DEPRECATED_KEYS: &[&str] = &[ "cache_capacity", "conduit_cache_capacity_modifier", diff --git a/src/service/uiaa/mod.rs b/src/service/uiaa/mod.rs index 2c62e511b..7d068a207 100644 --- a/src/service/uiaa/mod.rs +++ b/src/service/uiaa/mod.rs @@ -309,6 +309,7 @@ impl Service { match auth { | AuthData::Dummy(_) => Ok(AuthType::Dummy), + | AuthData::Terms(_) => Ok(AuthType::Terms), | AuthData::EmailIdentity(EmailIdentity { thirdparty_id_creds: ThirdpartyIdCredentials { client_secret, sid, .. }, ..