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

@ -1157,6 +1157,8 @@ class _PasswordSignInEndpoint {
required _idt.ByteData clientProof,
String? totpCode,
String? recoveryCode,
_is.UuidValue? request,
String? code,
}) async {
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
var _localUniqueSession =
@ -1175,6 +1177,8 @@ class _PasswordSignInEndpoint {
'clientProof': clientProof,
'totpCode': totpCode,
'recoveryCode': recoveryCode,
'request': request,
'code': code,
}),
serializationManager: _serializationManager,
);
@ -1190,6 +1194,43 @@ class _PasswordSignInEndpoint {
}
});
}
_ida.Future<_iacs.AuthSuccess> signUp(
_ist.TestSessionBuilder sessionBuilder, {
required _is.UuidValue request,
required String code,
required _ikhyee47.PasswordSetup setup,
}) async {
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
var _localUniqueSession =
(sessionBuilder as _ist.InternalTestSessionBuilder).internalBuild(
endpoint: 'passwordSignIn',
method: 'signUp',
);
try {
var _localCallContext = await _endpointDispatch.getMethodCallContext(
createSessionCallback: (_) => _localUniqueSession,
endpointPath: 'passwordSignIn',
methodName: 'signUp',
parameters: _ist.testObjectToJson({
'request': request,
'code': code,
'setup': setup,
}),
serializationManager: _serializationManager,
);
var _localReturnValue =
await (_localCallContext.method.call(
_localUniqueSession,
_localCallContext.arguments,
)
as _ida.Future<_iacs.AuthSuccess>);
return _localReturnValue;
} finally {
await _localUniqueSession.close();
}
});
}
}
class _ProfileEndpoint {