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:
parent
2a21672b43
commit
56d7aac9a8
3 changed files with 53 additions and 1 deletions
|
|
@ -275,6 +275,14 @@ Future<AccountSessionsEnded> completeAccountReset(
|
|||
where: (t) => t.authUserId.equals(account),
|
||||
transaction: transaction,
|
||||
);
|
||||
// The codes refused before go with the authenticators they were tried
|
||||
// against (the re-review's sixth finding).
|
||||
// DELETE FROM "second_factor_failures" WHERE "authUserId" = $1
|
||||
await SecondFactorFailures.db.deleteWhere(
|
||||
session,
|
||||
where: (t) => t.authUserId.equals(account),
|
||||
transaction: transaction,
|
||||
);
|
||||
// DELETE FROM "account_reset" WHERE "authUserId" = $1
|
||||
await AccountReset.db.deleteWhere(
|
||||
session,
|
||||
|
|
|
|||
|
|
@ -1065,7 +1065,8 @@ Future<bool> _useRecoveryCode(
|
|||
}
|
||||
|
||||
/// Carries out the reset of [account]'s authenticators that took effect:
|
||||
/// they and the recovery codes go. The reset's row stays until an
|
||||
/// they, the recovery codes and the codes refused before go. The reset's
|
||||
/// row stays until an
|
||||
/// authenticator is confirmed: until then the password alone signs in.
|
||||
Future<void> _carryOutAuthenticatorReset(
|
||||
Session session,
|
||||
|
|
@ -1083,6 +1084,14 @@ Future<void> _carryOutAuthenticatorReset(
|
|||
where: (t) => t.authUserId.equals(account),
|
||||
transaction: transaction,
|
||||
);
|
||||
// The codes refused before go with the authenticators they were tried
|
||||
// against (the re-review's sixth finding).
|
||||
// DELETE FROM "second_factor_failures" WHERE "authUserId" = $1
|
||||
await SecondFactorFailures.db.deleteWhere(
|
||||
session,
|
||||
where: (t) => t.authUserId.equals(account),
|
||||
transaction: transaction,
|
||||
);
|
||||
});
|
||||
|
||||
/// Calls off the reset of [account] that a code by mail asked for: its
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue