Make the SCRAM verifier the sole password credential; finish the account-registration relay
All checks were successful
CI / check (push) Successful in 4m1s

Credentials: the SCRAM-SHA-256 verifier is now the only password
credential. PLAIN and IDENTIFY verify the plaintext against it via
scram::verify_plain, exactly as a SCRAM login proves knowledge of it, so
an account provisioned from a verifier alone (external authority) works
over every mechanism, not only SCRAM. Removed the redundant argon2 hash
entirely: the field, the Credentials member, the AccountPasswordSet
field, hash_password/verify_password, and the argon2 crate. SASL SCRAM
already forces a PBKDF2 verifier into the store, so the hash never raised
the at-rest floor. OS RNG now comes from rand_core.

Registration: finished draft/account-registration over the ircd relay.
VERIFY confirms the emailed code, RESEND reissues it, STATUS reports
state, and REGISTER now emails the code and replies verification_required
on the relay path too, not only through NickServ.
This commit is contained in:
Jean Chevronnet 2026-07-15 15:47:41 +00:00
parent 9ed40a2e7f
commit 994e8c7347
No known key found for this signature in database
12 changed files with 221 additions and 101 deletions

View file

@ -252,7 +252,7 @@ impl Accounts for AccountsService {
if let Err(status) = self.engine.lock().await.authority_pre_check(&msg.name) {
return Ok(Response::new(reply(status, "cannot register that name right now")));
}
// Expensive Argon2/SCRAM derivation runs off the shared engine lock, same
// Expensive SCRAM verifier derivation runs off the shared engine lock, same
// as an IRC-originated REGISTER (see link.rs's DeferRegister handling).
let iterations = self.engine.lock().await.scram_iterations();
let password = msg.password.clone();
@ -441,7 +441,6 @@ mod tests {
fn to_wire_filters_credentials_and_maps_directory_events() {
let acct = Account {
name: "alice".into(),
password_hash: "secret-hash".into(),
email: Some("alice@example.com".into()),
ts: 111,
home: "A".into(),
@ -473,7 +472,7 @@ mod tests {
let pw_change = LogEntry::for_test(
"A", 1, 2,
Event::AccountPasswordSet { account: "alice".into(), password_hash: "x".into(), scram256: "x".into(), scram512: "x".into() },
Event::AccountPasswordSet { account: "alice".into(), scram256: "x".into(), scram512: "x".into() },
);
assert!(to_wire(&pw_change).is_none(), "credential changes must never replicate");