fix(app): no sheet is left busy by an error nothing expected

An instance's salt of another length made the device's cryptography throw
an ArgumentError, a wrapping's nonce a RangeError, and libsodium or the
keyring may throw their own; none was a refusal, so the step's error
escaped and the sheet stayed busy, which can't be closed. halkyon_keys
now checks the lengths of what comes from elsewhere before libsodium sees
it (KeyRefusal.malformed: a salt, a wrapping, a sealed key's box, a sealed
payload), the device's cryptography turns anything else into the general
failure, and so does every password cubit, the error logged by its type
alone.

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

View file

@ -137,10 +137,6 @@ Future<void> main() async {
for (final tampered in [
WrappedAccountKeys(nonce: wrapped.nonce, cipherText: cipherText),
WrappedAccountKeys(nonce: nonce, cipherText: wrapped.cipherText),
WrappedAccountKeys(
nonce: wrapped.nonce,
cipherText: wrapped.cipherText.sublist(1),
),
]) {
expect(
() => unwrap(tampered, password.keyEncryptionKey),
@ -177,6 +173,33 @@ Future<void> main() async {
refusedFor(KeyRefusal.notTheAccountsKeys),
);
});
test('wrappings of other lengths, as an instance might send them, are '
'refused rather than thrown on', () {
for (final (nonce, cipherText) in [
(Uint8List(23), wrapped.cipherText),
(Uint8List(25), wrapped.cipherText),
(Uint8List(0), Uint8List(0)),
(wrapped.nonce, Uint8List(15)),
(wrapped.nonce, wrapped.cipherText.sublist(1)),
(wrapped.nonce, Uint8List(wrapped.cipherText.length + 1)),
]) {
expect(
() => unwrap(
WrappedAccountKeys(nonce: nonce, cipherText: cipherText),
password.keyEncryptionKey,
),
throwsA(
isA<KeyRefused>().having(
(refused) => refused.reason,
'reason',
KeyRefusal.malformed,
),
),
reason: '${nonce.length} / ${cipherText.length}',
);
}
});
});
test('wrapped again under the recovery key, the phrase opens them', () {