echo/nickserv/src/password.rs
Jean 5d1bfb3144
BotServ: DONTKICKVOICES, plus neutral code comments
KICK <#channel> DONTKICKVOICES <on|off> exempts voiced users from the
kickers. The network view now tracks +v the same way it tracks +o: a new
ChannelVoice event is parsed from FMODE +v/-v and from +v join prefixes,
and set_voice/is_voiced mirror set_op/is_op (voice is cleared on part and
quit). scan_ops generalised to scan_status for any status letter.

Also scrubbed third-party project name-drops from code comments.
2026-07-13 18:19:37 +00:00

50 lines
1.7 KiB
Rust

// Password policy for REGISTER and SET PASSWORD: a minimum length and forbidding
// the password matching the nick, plus an upper bound so a huge password can't
// be used to burn CPU in the key
// derivation. Length is measured in characters, the cap in bytes (what the
// hasher actually processes).
pub const MIN_PASSWORD_CHARS: usize = 8;
pub const MAX_PASSWORD_BYTES: usize = 300;
// Validate a new password for the account/nick it will protect. On rejection,
// returns the message to show the user.
pub fn validate_password(password: &str, owner: &str) -> Result<(), &'static str> {
if password.chars().count() < MIN_PASSWORD_CHARS {
return Err("That password is too short — please use at least 8 characters.");
}
if password.len() > MAX_PASSWORD_BYTES {
return Err("That password is too long.");
}
if password.eq_ignore_ascii_case(owner) {
return Err("Your password can't be the same as your nick. Please choose another.");
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn accepts_a_reasonable_password() {
assert!(validate_password("correct horse", "alice").is_ok());
}
#[test]
fn rejects_short_password() {
assert!(validate_password("short", "alice").is_err());
assert!(validate_password("1234567", "alice").is_err()); // 7 chars
assert!(validate_password("12345678", "alice").is_ok()); // 8 chars
}
#[test]
fn rejects_password_equal_to_nick() {
assert!(validate_password("Password", "password").is_err()); // case-insensitive
}
#[test]
fn rejects_overlong_password() {
assert!(validate_password(&"x".repeat(MAX_PASSWORD_BYTES + 1), "alice").is_err());
}
}