fix(auth): every proof counts toward the address as it is checked

The ceiling of 30 proofs an hour per address was looked at only when a
sign-in began and counted only wrong passwords (the re-review's second
finding): sign-ins begun ahead from many networks got 60 wrong passwords
checked in an hour, and a right password, not counted, could be told from
a wrong one by whether the next sign-in still began. Every proof for an
address, of a password or of the recovery phrase, is now recorded before it
is checked, whatever its outcome, and refused past 30 an hour
(tooManyAttempts); the check at begin stays as an early refusal.

A change's proof is no longer counted toward the address (the fifth
finding: strangers' wrong passwords held a signed-in owner out of changing
the password, a new phrase and deletion). Its challenge has a purpose of
its own (change), counted per account as it begins (10 an hour), taken by
no sign-in, and a change takes no sign-in's challenge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-20 22:44:02 +02:00
commit 24d46a8503
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -18,7 +18,12 @@ enum SignInChallengePurpose implements _isc.SerializableModel {
password,
/// Proving the recovery phrase by signing a nonce with the account's key.
keyProof;
keyProof,
/// Proving the password while signed in, to change it, set a new phrase
/// or delete the account: counted per account, never toward the
/// address's proofs, so strangers' guesses hold no signed-in owner back.
change;
static SignInChallengePurpose fromJson(String name) {
switch (name) {
@ -26,6 +31,8 @@ enum SignInChallengePurpose implements _isc.SerializableModel {
return SignInChallengePurpose.password;
case 'keyProof':
return SignInChallengePurpose.keyProof;
case 'change':
return SignInChallengePurpose.change;
default:
throw ArgumentError(
'Value "$name" cannot be converted to "SignInChallengePurpose"',