fix(auth)!: proofs are bound to the instance the device addresses
Nothing tied a sign-in's proof to the instance it was made for: an instance a person was lured into adding could pass A, M1 and the code on to the real register and get a session there, and pass a phrase's proof on with a password of its own in place of the person's (the second reading's M6). SRP's identity is now a label, the challenge's ID and the host the device addressed (passwordIdentity, in halkyon_base_client and halkyon_base_server alike), and the phrase's proof signs that host, what it is for (an authenticator's reset or a new password) and the new password's digest (key proof v2). Every proving call carries the host; in production it must be the server's apiServer.publicHost (otherwise otherInstance, which the app shows as an instance it can't trust), in development any; a member forwards its own. The tests prove that a relayed sign-in, a proof for another host or purpose, and a swapped password are refused, nothing changing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
009970faab
commit
dab2c80524
1 changed files with 966 additions and 137 deletions
|
|
@ -555,6 +555,7 @@ void main() {
|
|||
clientValue: answer.clientValue,
|
||||
clientProof: answer.clientProof,
|
||||
totpCode: codeOf(enrolment, at: now),
|
||||
host: testHost,
|
||||
);
|
||||
expect(proof.account, annaOnTodo);
|
||||
expect(answer.verifiesServer(proof.serverProof), isTrue);
|
||||
|
|
@ -572,6 +573,7 @@ void main() {
|
|||
clientValue: againAnswer.clientValue,
|
||||
clientProof: againAnswer.clientProof,
|
||||
totpCode: codeOf(enrolment, at: now),
|
||||
host: testHost,
|
||||
),
|
||||
refused(PasswordRefusal.wrongCredentials),
|
||||
);
|
||||
|
|
@ -596,13 +598,18 @@ void main() {
|
|||
device.recoveryKeys.toJson(),
|
||||
);
|
||||
now = now.add(totpPeriod);
|
||||
final newPassword = device.newPassword();
|
||||
expect(
|
||||
await remote.resetPasswordWithPhrase(
|
||||
session,
|
||||
challenge: keyChallenge.challenge,
|
||||
signature: await device.sign(keyChallenge),
|
||||
password: device.newPassword(),
|
||||
signature: await device.sign(
|
||||
keyChallenge,
|
||||
password: newPassword,
|
||||
),
|
||||
password: newPassword,
|
||||
totpCode: codeOf(enrolment, at: now),
|
||||
host: testHost,
|
||||
),
|
||||
(account: annaOnTodo, endedBefore: now),
|
||||
);
|
||||
|
|
@ -630,6 +637,7 @@ void main() {
|
|||
language: 'en',
|
||||
request: resetRequest,
|
||||
code: mailbox.codeFor('anna@example.org'),
|
||||
host: testHost,
|
||||
);
|
||||
expect(pending.takesEffectAt, now.add(resetDelay));
|
||||
|
||||
|
|
@ -727,6 +735,7 @@ void main() {
|
|||
totpCode: codeOf(enrolment),
|
||||
password: device.newPassword(),
|
||||
keepSession: annasPhone,
|
||||
host: testHost,
|
||||
);
|
||||
expect(members.sessionsTold.single, (
|
||||
_todo,
|
||||
|
|
@ -757,6 +766,7 @@ void main() {
|
|||
recoveryProofKey: ByteData.sublistView(
|
||||
device.recoveryProofKey,
|
||||
),
|
||||
host: testHost,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -861,6 +871,7 @@ void main() {
|
|||
clientProof: answer.clientProof,
|
||||
request: await code(),
|
||||
code: mailbox.codeFor('carla@example.org'),
|
||||
host: testHost,
|
||||
);
|
||||
expect(proof.account, carla);
|
||||
expect(proof.needsAuthenticator, isTrue);
|
||||
|
|
|
|||
Loading…
Reference in a new issue