fix(auth): a proof the register couldn't answer counts; the sign-up mail says it gives a password

Two of the fourth reading's lows:

- A signed-in proof whose call to the register failed
  (RegisterUnavailableException, a member's call timing out after the
  register checked it) stays counted against the session, rather than
  taken back: a guess never goes uncounted.
- A sign-up code also gives an existing account with that address its
  first password, which its mail now says in the subject too ("create an
  account or give it a password").

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-21 11:46:01 +02:00
commit f154b7ea7c
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -727,6 +727,33 @@ void main() {
expect(left.single.createdAt.isBefore(endedBefore), isFalse);
});
test("count a proof whose answer the register couldn't give, as it "
'may have checked it (the fourth reading)', () async {
register.failing = RegisterUnavailableException('test');
await expectLater(
endpoints.authenticator.newRecoveryCodes(
asAnna(),
proof: OwnerProof(
challenge: const Uuid().v7obj(),
clientValue: ByteData(384),
clientProof: ByteData(32),
host: testHost,
totpCode: '123456',
),
),
throwsA(isA<RegisterUnavailableException>()),
);
expect(
(await SessionCodeFailures.db.findFirstRow(
session,
where: (t) => t.sessionId.equals(annasPhone),
))?.failures,
1,
);
});
test('sign up at the register, the new account signed in here, '
'identified', () async {
final device = await PasswordDevice.make();