From a061db35d7c45758ebd2cd5cda2ed2efdb0c8328 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 18 Apr 2025 18:24:35 +0200 Subject: [PATCH] Make a few password-related options public in the config crate It also adds docs to a few of those options --- crates/config/src/sections/mod.rs | 4 +++- crates/config/src/sections/passwords.rs | 30 +++++++++++++++++-------- docs/config.schema.json | 12 +++++++++- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/crates/config/src/sections/mod.rs b/crates/config/src/sections/mod.rs index d415f646a..9a9fc9de8 100644 --- a/crates/config/src/sections/mod.rs +++ b/crates/config/src/sections/mod.rs @@ -38,7 +38,9 @@ pub use self::{ Resource as HttpResource, TlsConfig as HttpTlsConfig, UnixOrTcp, }, matrix::{HomeserverKind, MatrixConfig}, - passwords::{Algorithm as PasswordAlgorithm, PasswordsConfig}, + passwords::{ + Algorithm as PasswordAlgorithm, HashingScheme as PasswordHashingScheme, PasswordsConfig, + }, policy::PolicyConfig, rate_limiting::RateLimitingConfig, secrets::SecretsConfig, diff --git a/crates/config/src/sections/passwords.rs b/crates/config/src/sections/passwords.rs index 455dbfd61..07ea71b0e 100644 --- a/crates/config/src/sections/passwords.rs +++ b/crates/config/src/sections/passwords.rs @@ -16,7 +16,7 @@ use crate::ConfigurationSection; fn default_schemes() -> Vec { vec![HashingScheme { version: 1, - algorithm: Algorithm::Argon2id, + algorithm: Algorithm::default(), cost: None, secret: None, secret_file: None, @@ -36,10 +36,14 @@ fn default_minimum_complexity() -> u8 { pub struct PasswordsConfig { /// Whether password-based authentication is enabled #[serde(default = "default_enabled")] - enabled: bool, + pub enabled: bool, + /// The hashing schemes to use for hashing and validating passwords + /// + /// The hashing scheme with the highest version number will be used for + /// hashing new passwords. #[serde(default = "default_schemes")] - schemes: Vec, + pub schemes: Vec, /// Score between 0 and 4 determining the minimum allowed password /// complexity. Scores are based on the ESTIMATED number of guesses @@ -154,23 +158,30 @@ impl PasswordsConfig { } } +/// Parameters for a password hashing scheme #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] pub struct HashingScheme { - version: u16, + /// The version of the hashing scheme. They must be unique, and the highest + /// version will be used for hashing new passwords. + pub version: u16, - algorithm: Algorithm, + /// The hashing algorithm to use + pub algorithm: Algorithm, /// Cost for the bcrypt algorithm #[serde(skip_serializing_if = "Option::is_none")] #[schemars(default = "default_bcrypt_cost")] - cost: Option, + pub cost: Option, + /// An optional secret to use when hashing passwords. This makes it harder + /// to brute-force the passwords in case of a database leak. #[serde(skip_serializing_if = "Option::is_none")] - secret: Option, + pub secret: Option, + /// Same as `secret`, but read from a file. #[serde(skip_serializing_if = "Option::is_none")] #[schemars(with = "Option")] - secret_file: Option, + pub secret_file: Option, } #[allow(clippy::unnecessary_wraps)] @@ -179,13 +190,14 @@ fn default_bcrypt_cost() -> Option { } /// A hashing algorithm -#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)] #[serde(rename_all = "lowercase")] pub enum Algorithm { /// bcrypt Bcrypt, /// argon2id + #[default] Argon2id, /// PBKDF2 diff --git a/docs/config.schema.json b/docs/config.schema.json index 165cf947d..9a1184bfd 100644 --- a/docs/config.schema.json +++ b/docs/config.schema.json @@ -1566,6 +1566,7 @@ "type": "boolean" }, "schemes": { + "description": "The hashing schemes to use for hashing and validating passwords\n\nThe hashing scheme with the highest version number will be used for hashing new passwords.", "default": [ { "version": 1, @@ -1587,6 +1588,7 @@ } }, "HashingScheme": { + "description": "Parameters for a password hashing scheme", "type": "object", "required": [ "algorithm", @@ -1594,12 +1596,18 @@ ], "properties": { "version": { + "description": "The version of the hashing scheme. They must be unique, and the highest version will be used for hashing new passwords.", "type": "integer", "format": "uint16", "minimum": 0.0 }, "algorithm": { - "$ref": "#/definitions/Algorithm" + "description": "The hashing algorithm to use", + "allOf": [ + { + "$ref": "#/definitions/Algorithm" + } + ] }, "cost": { "description": "Cost for the bcrypt algorithm", @@ -1609,9 +1617,11 @@ "minimum": 0.0 }, "secret": { + "description": "An optional secret to use when hashing passwords. This makes it harder to brute-force the passwords in case of a database leak.", "type": "string" }, "secret_file": { + "description": "Same as `secret`, but read from a file.", "type": "string" } }