fix(auth): a new recovery phrase takes the password too

password.setRecoveryKeys took a session and a TOTP code alone, so a phone
signed in with its authenticator beside it could set a phrase of its
holder's own and, through the phrase's reset, a new password, never
knowing the old one. It now takes the old password's SRP proof (from
beginChange, the caller's own) and a TOTP or recovery code, as changing
the password does: one owner proof for both (_proveOwner), forwarded by
members, asked for in the account section's New recovery phrase.

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 20:01:07 +02:00
commit 5fb28bd817
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -740,20 +740,28 @@ void main() {
nonce: ByteData(24),
cipherText: ByteData(wrappedKeysLength),
);
await remote.setRecoveryKeys(
session,
person: annaOnTodo,
code: codeOf(enrolment),
recoveryKeys: fresh,
);
await expectLater(
remote.setRecoveryKeys(
Future<void> newPhrase() async {
final challenge = await remote.beginPasswordChange(
session,
person: annaOnTodo,
code: codeOf(enrolment),
);
final answer = device.answer(challenge);
await remote.setRecoveryKeys(
session,
person: annaOnTodo,
challenge: challenge.challenge,
clientValue: answer.clientValue,
clientProof: answer.clientProof,
totpCode: codeOf(enrolment),
recoveryKeys: fresh,
),
refused(PasswordRefusal.wrongCode),
);
}
await newPhrase();
// The same step's code again.
await expectLater(
newPhrase(),
refused(PasswordRefusal.wrongCredentials),
);
final start = await remote.sendSignInCode(