fix(auth): a reset forgets the codes refused before it

Neither the account's reset nor the authenticators' reset, carried out,
cleared the account's refused codes (the re-review's sixth finding): after
the owner's way out, the new authenticator's codes could still meet a wait
of up to a day, and the doubling went on. Both now delete them with the
authenticators they were tried against.

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 23:09:39 +02:00
commit 56d7aac9a8
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -1586,6 +1586,24 @@ void main() {
);
});
test("carried out, forgets the codes refused before: the new "
"authenticator's codes wait for nothing of the old", () async {
await annaComplete();
for (var i = 0; i < 10; i++) {
await expectLater(
signIn(totpCode: '000000'),
refused(PasswordRefusal.wrongCredentials),
);
}
expect(await SecondFactorFailures.db.count(session), 1);
now = now.add(const Duration(hours: 1, seconds: 1));
await resetByMail();
now = now.add(resetDelay);
expect((await signIn()).needsAuthenticator, isTrue);
expect(await SecondFactorFailures.db.count(session), 0);
});
test('is reset 72 hours after the password and a code by mail ask, '
'with a mail at the start; then the password alone signs in '
'until an authenticator is confirmed', () async {
@ -2341,6 +2359,23 @@ void main() {
);
});
test('carried out, forgets the codes refused before', () async {
await annaComplete();
for (var i = 0; i < 10; i++) {
await expectLater(
signIn(totpCode: '000000'),
refused(PasswordRefusal.wrongCredentials),
);
}
expect(await SecondFactorFailures.db.count(session), 1);
now = now.add(const Duration(hours: 1, seconds: 1));
await start();
now = now.add(resetDelay);
await finish(await PasswordDevice.make());
expect(await SecondFactorFailures.db.count(session), 0);
});
test('resets the account 72 hours after a code by mail asks, with a '
'mail at the start: new keys, no authenticator, every session '
'ended', () async {