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:
Tizian 「ティツィアーン」 2026-10-20 21:20:12 +02:00
commit dab2c80524
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -575,6 +575,7 @@ class _AccountRecoveryEndpoint {
String? code,
_is.UuidValue? keyChallenge,
_idt.ByteData? signature,
required String host,
}) async {
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
var _localUniqueSession =
@ -597,6 +598,7 @@ class _AccountRecoveryEndpoint {
'code': code,
'keyChallenge': keyChallenge,
'signature': signature,
'host': host,
}),
serializationManager: _serializationManager,
);
@ -651,6 +653,7 @@ class _AccountRecoveryEndpoint {
required _ijye8mcv.NewPassword password,
String? totpCode,
String? recoveryCode,
required String host,
}) async {
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
var _localUniqueSession =
@ -669,6 +672,7 @@ class _AccountRecoveryEndpoint {
'password': password,
'totpCode': totpCode,
'recoveryCode': recoveryCode,
'host': host,
}),
serializationManager: _serializationManager,
);
@ -1028,6 +1032,7 @@ class _PasswordEndpoint {
String? totpCode,
String? recoveryCode,
required _ijye8mcv.NewPassword password,
required String host,
}) async {
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
var _localUniqueSession =
@ -1047,6 +1052,7 @@ class _PasswordEndpoint {
'totpCode': totpCode,
'recoveryCode': recoveryCode,
'password': password,
'host': host,
}),
serializationManager: _serializationManager,
);
@ -1072,6 +1078,7 @@ class _PasswordEndpoint {
String? recoveryCode,
required _iji0wmu8.WrappedKeys recoveryKeys,
required _idt.ByteData recoveryProofKey,
required String host,
}) async {
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
var _localUniqueSession =
@ -1092,6 +1099,7 @@ class _PasswordEndpoint {
'recoveryCode': recoveryCode,
'recoveryKeys': recoveryKeys,
'recoveryProofKey': recoveryProofKey,
'host': host,
}),
serializationManager: _serializationManager,
);
@ -1159,6 +1167,7 @@ class _PasswordSignInEndpoint {
String? recoveryCode,
_is.UuidValue? request,
String? code,
required String host,
}) async {
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
var _localUniqueSession =
@ -1179,6 +1188,7 @@ class _PasswordSignInEndpoint {
'recoveryCode': recoveryCode,
'request': request,
'code': code,
'host': host,
}),
serializationManager: _serializationManager,
);