1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-07 17:03:01 +03:00

Move the account-related options out of experimental

This commit is contained in:
Quentin Gliech
2024-07-31 16:05:53 +02:00
parent cb8bfa466b
commit 8b3451d66f
8 changed files with 163 additions and 82 deletions

View File

@@ -145,6 +145,7 @@ impl Options {
&config.matrix, &config.matrix,
&config.experimental, &config.experimental,
&config.passwords, &config.passwords,
&config.account,
&config.captcha, &config.captcha,
)?; )?;

View File

@@ -17,8 +17,8 @@ use std::process::ExitCode;
use clap::Parser; use clap::Parser;
use figment::Figment; use figment::Figment;
use mas_config::{ use mas_config::{
BrandingConfig, CaptchaConfig, ConfigurationSection, ExperimentalConfig, MatrixConfig, AccountConfig, BrandingConfig, CaptchaConfig, ConfigurationSection, ExperimentalConfig,
PasswordsConfig, TemplatesConfig, MatrixConfig, PasswordsConfig, TemplatesConfig,
}; };
use mas_storage::{Clock, SystemClock}; use mas_storage::{Clock, SystemClock};
use rand::SeedableRng; use rand::SeedableRng;
@@ -50,6 +50,7 @@ impl Options {
let matrix_config = MatrixConfig::extract(figment)?; let matrix_config = MatrixConfig::extract(figment)?;
let experimental_config = ExperimentalConfig::extract(figment)?; let experimental_config = ExperimentalConfig::extract(figment)?;
let password_config = PasswordsConfig::extract(figment)?; let password_config = PasswordsConfig::extract(figment)?;
let account_config = AccountConfig::extract(figment)?;
let captcha_config = CaptchaConfig::extract(figment)?; let captcha_config = CaptchaConfig::extract(figment)?;
let clock = SystemClock::default(); let clock = SystemClock::default();
@@ -62,6 +63,7 @@ impl Options {
&matrix_config, &matrix_config,
&experimental_config, &experimental_config,
&password_config, &password_config,
&account_config,
&captcha_config, &captcha_config,
)?; )?;
let templates = let templates =

View File

@@ -54,6 +54,7 @@ impl Options {
&config.matrix, &config.matrix,
&config.experimental, &config.experimental,
&config.passwords, &config.passwords,
&config.account,
&config.captcha, &config.captcha,
)?; )?;

View File

@@ -16,8 +16,9 @@ use std::time::Duration;
use anyhow::Context; use anyhow::Context;
use mas_config::{ use mas_config::{
BrandingConfig, CaptchaConfig, DatabaseConfig, EmailConfig, EmailSmtpMode, EmailTransportKind, AccountConfig, BrandingConfig, CaptchaConfig, DatabaseConfig, EmailConfig, EmailSmtpMode,
ExperimentalConfig, MatrixConfig, PasswordsConfig, PolicyConfig, TemplatesConfig, EmailTransportKind, ExperimentalConfig, MatrixConfig, PasswordsConfig, PolicyConfig,
TemplatesConfig,
}; };
use mas_data_model::SiteConfig; use mas_data_model::SiteConfig;
use mas_email::{MailTransport, Mailer}; use mas_email::{MailTransport, Mailer};
@@ -152,6 +153,7 @@ pub fn site_config_from_config(
matrix_config: &MatrixConfig, matrix_config: &MatrixConfig,
experimental_config: &ExperimentalConfig, experimental_config: &ExperimentalConfig,
password_config: &PasswordsConfig, password_config: &PasswordsConfig,
account_config: &AccountConfig,
captcha_config: &CaptchaConfig, captcha_config: &CaptchaConfig,
) -> Result<SiteConfig, anyhow::Error> { ) -> Result<SiteConfig, anyhow::Error> {
let captcha = captcha_config_from_config(captcha_config)?; let captcha = captcha_config_from_config(captcha_config)?;
@@ -164,13 +166,13 @@ pub fn site_config_from_config(
imprint: branding_config.imprint.clone(), imprint: branding_config.imprint.clone(),
password_login_enabled: password_config.enabled(), password_login_enabled: password_config.enabled(),
password_registration_enabled: password_config.enabled() password_registration_enabled: password_config.enabled()
&& experimental_config.password_registration_enabled, && account_config.password_registration_enabled,
email_change_allowed: experimental_config.email_change_allowed, email_change_allowed: account_config.email_change_allowed,
displayname_change_allowed: experimental_config.displayname_change_allowed, displayname_change_allowed: account_config.displayname_change_allowed,
password_change_allowed: password_config.enabled() password_change_allowed: password_config.enabled()
&& experimental_config.password_change_allowed, && account_config.password_change_allowed,
account_recovery_allowed: password_config.enabled() account_recovery_allowed: password_config.enabled()
&& experimental_config.account_recovery_enabled, && account_config.password_recovery_enabled,
captcha, captcha,
minimum_password_complexity: password_config.minimum_complexity(), minimum_password_complexity: password_config.minimum_complexity(),
}) })

View File

@@ -0,0 +1,99 @@
// Copyright 2024 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::ConfigurationSection;
const fn default_true() -> bool {
true
}
#[allow(clippy::trivially_copy_pass_by_ref)]
const fn is_default_true(value: &bool) -> bool {
*value == default_true()
}
const fn default_false() -> bool {
false
}
#[allow(clippy::trivially_copy_pass_by_ref)]
const fn is_default_false(value: &bool) -> bool {
*value == default_false()
}
/// Configuration section to configure features related to account management
#[allow(clippy::struct_excessive_bools)]
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)]
pub struct AccountConfig {
/// Whether users are allowed to change their email addresses. Defaults to
/// `true`.
#[serde(default = "default_true", skip_serializing_if = "is_default_true")]
pub email_change_allowed: bool,
/// Whether users are allowed to change their display names. Defaults to
/// `true`.
///
/// This should be in sync with the policy in the homeserver configuration.
#[serde(default = "default_true", skip_serializing_if = "is_default_true")]
pub displayname_change_allowed: bool,
/// Whether to enable self-service password registration. Defaults to
/// `false` if password authentication is enabled.
///
/// This has no effect if password login is disabled.
#[serde(default = "default_false", skip_serializing_if = "is_default_false")]
pub password_registration_enabled: bool,
/// Whether users are allowed to change their passwords. Defaults to `true`.
///
/// This has no effect if password login is disabled.
#[serde(default = "default_true", skip_serializing_if = "is_default_true")]
pub password_change_allowed: bool,
/// Whether email-based password recovery is enabled. Defaults to `false`.
///
/// This has no effect if password login is disabled.
#[serde(default = "default_false", skip_serializing_if = "is_default_false")]
pub password_recovery_enabled: bool,
}
impl Default for AccountConfig {
fn default() -> Self {
Self {
email_change_allowed: default_true(),
displayname_change_allowed: default_true(),
password_registration_enabled: default_false(),
password_change_allowed: default_true(),
password_recovery_enabled: default_false(),
}
}
}
impl AccountConfig {
/// Returns true if the configuration is the default one
pub(crate) fn is_default(&self) -> bool {
is_default_false(&self.password_registration_enabled)
&& is_default_true(&self.email_change_allowed)
&& is_default_true(&self.displayname_change_allowed)
&& is_default_true(&self.password_change_allowed)
&& is_default_false(&self.password_recovery_enabled)
}
}
impl ConfigurationSection for AccountConfig {
const PATH: Option<&'static str> = Some("account");
}

View File

@@ -27,24 +27,6 @@ fn is_default_token_ttl(value: &Duration) -> bool {
*value == default_token_ttl() *value == default_token_ttl()
} }
const fn default_true() -> bool {
true
}
#[allow(clippy::trivially_copy_pass_by_ref)]
const fn is_default_true(value: &bool) -> bool {
*value == default_true()
}
const fn default_false() -> bool {
false
}
#[allow(clippy::trivially_copy_pass_by_ref)]
const fn is_default_false(value: &bool) -> bool {
*value == default_false()
}
/// Configuration sections for experimental options /// Configuration sections for experimental options
/// ///
/// Do not change these options unless you know what you are doing. /// Do not change these options unless you know what you are doing.
@@ -70,29 +52,6 @@ pub struct ExperimentalConfig {
)] )]
#[serde_as(as = "serde_with::DurationSeconds<i64>")] #[serde_as(as = "serde_with::DurationSeconds<i64>")]
pub compat_token_ttl: Duration, pub compat_token_ttl: Duration,
/// Whether to enable self-service password registration. Defaults to `true`
/// if password authentication is enabled.
#[serde(default = "default_true", skip_serializing_if = "is_default_true")]
pub password_registration_enabled: bool,
/// Whether users are allowed to change their email addresses. Defaults to
/// `true`.
#[serde(default = "default_true", skip_serializing_if = "is_default_true")]
pub email_change_allowed: bool,
/// Whether users are allowed to change their display names. Defaults to
/// `true`.
#[serde(default = "default_true", skip_serializing_if = "is_default_true")]
pub displayname_change_allowed: bool,
/// Whether users are allowed to change their passwords. Defaults to `true`.
#[serde(default = "default_true", skip_serializing_if = "is_default_true")]
pub password_change_allowed: bool,
/// Whether email-based account recovery is enabled. Defaults to `false`.
#[serde(default = "default_false", skip_serializing_if = "is_default_false")]
pub account_recovery_enabled: bool,
} }
impl Default for ExperimentalConfig { impl Default for ExperimentalConfig {
@@ -100,24 +59,13 @@ impl Default for ExperimentalConfig {
Self { Self {
access_token_ttl: default_token_ttl(), access_token_ttl: default_token_ttl(),
compat_token_ttl: default_token_ttl(), compat_token_ttl: default_token_ttl(),
password_registration_enabled: default_true(),
email_change_allowed: default_true(),
displayname_change_allowed: default_true(),
password_change_allowed: default_true(),
account_recovery_enabled: default_false(),
} }
} }
} }
impl ExperimentalConfig { impl ExperimentalConfig {
pub(crate) fn is_default(&self) -> bool { pub(crate) fn is_default(&self) -> bool {
is_default_token_ttl(&self.access_token_ttl) is_default_token_ttl(&self.access_token_ttl) && is_default_token_ttl(&self.compat_token_ttl)
&& is_default_token_ttl(&self.compat_token_ttl)
&& is_default_true(&self.password_registration_enabled)
&& is_default_true(&self.email_change_allowed)
&& is_default_true(&self.displayname_change_allowed)
&& is_default_true(&self.password_change_allowed)
&& is_default_false(&self.account_recovery_enabled)
} }
} }

View File

@@ -16,6 +16,7 @@ use rand::Rng;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
mod account;
mod branding; mod branding;
mod captcha; mod captcha;
mod clients; mod clients;
@@ -32,6 +33,7 @@ mod templates;
mod upstream_oauth2; mod upstream_oauth2;
pub use self::{ pub use self::{
account::AccountConfig,
branding::BrandingConfig, branding::BrandingConfig,
captcha::{CaptchaConfig, CaptchaServiceKind}, captcha::{CaptchaConfig, CaptchaServiceKind},
clients::{ClientAuthMethodConfig, ClientConfig, ClientsConfig}, clients::{ClientAuthMethodConfig, ClientConfig, ClientsConfig},
@@ -113,6 +115,11 @@ pub struct RootConfig {
#[serde(default, skip_serializing_if = "CaptchaConfig::is_default")] #[serde(default, skip_serializing_if = "CaptchaConfig::is_default")]
pub captcha: CaptchaConfig, pub captcha: CaptchaConfig,
/// Configuration section to configure features related to account
/// management
#[serde(default, skip_serializing_if = "AccountConfig::is_default")]
pub account: AccountConfig,
/// Experimental configuration options /// Experimental configuration options
#[serde(default, skip_serializing_if = "ExperimentalConfig::is_default")] #[serde(default, skip_serializing_if = "ExperimentalConfig::is_default")]
pub experimental: ExperimentalConfig, pub experimental: ExperimentalConfig,
@@ -133,6 +140,7 @@ impl ConfigurationSection for RootConfig {
self.upstream_oauth2.validate(figment)?; self.upstream_oauth2.validate(figment)?;
self.branding.validate(figment)?; self.branding.validate(figment)?;
self.captcha.validate(figment)?; self.captcha.validate(figment)?;
self.account.validate(figment)?;
self.experimental.validate(figment)?; self.experimental.validate(figment)?;
Ok(()) Ok(())
@@ -163,6 +171,7 @@ impl RootConfig {
upstream_oauth2: UpstreamOAuth2Config::default(), upstream_oauth2: UpstreamOAuth2Config::default(),
branding: BrandingConfig::default(), branding: BrandingConfig::default(),
captcha: CaptchaConfig::default(), captcha: CaptchaConfig::default(),
account: AccountConfig::default(),
experimental: ExperimentalConfig::default(), experimental: ExperimentalConfig::default(),
}) })
} }
@@ -184,6 +193,7 @@ impl RootConfig {
upstream_oauth2: UpstreamOAuth2Config::default(), upstream_oauth2: UpstreamOAuth2Config::default(),
branding: BrandingConfig::default(), branding: BrandingConfig::default(),
captcha: CaptchaConfig::default(), captcha: CaptchaConfig::default(),
account: AccountConfig::default(),
experimental: ExperimentalConfig::default(), experimental: ExperimentalConfig::default(),
} }
} }
@@ -221,6 +231,9 @@ pub struct AppConfig {
#[serde(default)] #[serde(default)]
pub captcha: CaptchaConfig, pub captcha: CaptchaConfig,
#[serde(default)]
pub account: AccountConfig,
#[serde(default)] #[serde(default)]
pub experimental: ExperimentalConfig, pub experimental: ExperimentalConfig,
} }
@@ -237,6 +250,7 @@ impl ConfigurationSection for AppConfig {
self.policy.validate(figment)?; self.policy.validate(figment)?;
self.branding.validate(figment)?; self.branding.validate(figment)?;
self.captcha.validate(figment)?; self.captcha.validate(figment)?;
self.account.validate(figment)?;
self.experimental.validate(figment)?; self.experimental.validate(figment)?;
Ok(()) Ok(())

View File

@@ -193,6 +193,14 @@
} }
] ]
}, },
"account": {
"description": "Configuration section to configure features related to account management",
"allOf": [
{
"$ref": "#/definitions/AccountConfig"
}
]
},
"experimental": { "experimental": {
"description": "Experimental configuration options", "description": "Experimental configuration options",
"allOf": [ "allOf": [
@@ -2107,6 +2115,32 @@
} }
] ]
}, },
"AccountConfig": {
"description": "Configuration section to configure features related to account management",
"type": "object",
"properties": {
"email_change_allowed": {
"description": "Whether users are allowed to change their email addresses. Defaults to `true`.",
"type": "boolean"
},
"displayname_change_allowed": {
"description": "Whether users are allowed to change their display names. Defaults to `true`.\n\nThis should be in sync with the policy in the homeserver configuration.",
"type": "boolean"
},
"password_registration_enabled": {
"description": "Whether to enable self-service password registration. Defaults to `false` if password authentication is enabled.\n\nThis has no effect if password login is disabled.",
"type": "boolean"
},
"password_change_allowed": {
"description": "Whether users are allowed to change their passwords. Defaults to `true`.\n\nThis has no effect if password login is disabled.",
"type": "boolean"
},
"password_recovery_enabled": {
"description": "Whether email-based password recovery is enabled. Defaults to `false`.\n\nThis has no effect if password login is disabled.",
"type": "boolean"
}
}
},
"ExperimentalConfig": { "ExperimentalConfig": {
"description": "Configuration sections for experimental options\n\nDo not change these options unless you know what you are doing.", "description": "Configuration sections for experimental options\n\nDo not change these options unless you know what you are doing.",
"type": "object", "type": "object",
@@ -2124,26 +2158,6 @@
"format": "uint64", "format": "uint64",
"maximum": 86400.0, "maximum": 86400.0,
"minimum": 60.0 "minimum": 60.0
},
"password_registration_enabled": {
"description": "Whether to enable self-service password registration. Defaults to `true` if password authentication is enabled.",
"type": "boolean"
},
"email_change_allowed": {
"description": "Whether users are allowed to change their email addresses. Defaults to `true`.",
"type": "boolean"
},
"displayname_change_allowed": {
"description": "Whether users are allowed to change their display names. Defaults to `true`.",
"type": "boolean"
},
"password_change_allowed": {
"description": "Whether users are allowed to change their passwords. Defaults to `true`.",
"type": "boolean"
},
"account_recovery_enabled": {
"description": "Whether email-based account recovery is enabled. Defaults to `false`.",
"type": "boolean"
} }
} }
} }