feat(auth): ways in for accounts without a working password

ADR 0017, step 3. Signing up takes an address a mailed code proves and
a password's setup, without a session (`passwordSignIn.signUp`): an
address nobody has becomes a new identified account, and an account
with the address but no password (codes by mail before; no keys exist,
so nothing waits) takes the password, keeping its ID. A setup never
finished signs in with its password and a code mailed to the address it
began with, until an authenticator is confirmed, which also calls off a
reset of the account waiting; any other account takes no code by mail
in place of its second factor and leaves the code unused. A reset of
the whole account waiting no longer counts as having had an
authenticator, so its owner isn't locked out until it completes.

Members forward both through the register; the tests' shared helpers
move into `support/password_support.dart`.

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 14:41:16 +02:00
commit f8076dcacf
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -175,7 +175,9 @@ abstract interface class AccountRegister {
});
/// A password sign-in's second step: the account it proved, for the
/// caller's session. Refusals as `completePasswordSignIn`'s.
/// caller's session; a [code] mailed for [request] in place of the second
/// factor of a setup never finished. Refusals as
/// `completePasswordSignIn`'s.
Future<PasswordProof> completePasswordSignIn(
Session session, {
required UuidValue challenge,
@ -183,6 +185,18 @@ abstract interface class AccountRegister {
required ByteData clientProof,
String? totpCode,
String? recoveryCode,
UuidValue? request,
String? code,
});
/// Signs up with the address [code] proves for [request] and the password
/// [setup] describes: the account, new or one with the address and no
/// password, for the caller's session. Refusals as `signUpWithCode`'s.
Future<UuidValue> signUpWithCode(
Session session, {
required UuidValue request,
required String code,
required PasswordSetup setup,
});
/// A new authenticator of [person]. Refusals as `enrolAuthenticator`'s.