From 7a1fa6dfb8c865acfe3ed68a45ad8a0c58abdcc9 Mon Sep 17 00:00:00 2001 From: Christien Rioux Date: Sat, 14 Jun 2025 15:31:15 -0400 Subject: [PATCH] update for api fixes --- assets/i18n/en.json | 3 ++- .../cubits/contact_invitation_list_cubit.dart | 11 ++++++++++ .../views/invitation_dialog.dart | 11 ++++++++++ .../src/dht_record/dht_record.dart | 20 +++++++++++-------- .../lib/identity_support/super_identity.dart | 10 ++++++---- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/assets/i18n/en.json b/assets/i18n/en.json index 206c0b0..f3348b5 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -209,7 +209,8 @@ "protected_with_pin": "Contact invitation is protected with a PIN", "protected_with_password": "Contact invitation is protected with a password", "invalid_pin": "Invalid PIN", - "invalid_password": "Invalid password" + "invalid_password": "Invalid password", + "invalid_identity": "Contact invitation is for an missing or unavailable identity" }, "waiting_invitation": { "accepted": "Contact invitation accepted from {name}", diff --git a/lib/contact_invitation/cubits/contact_invitation_list_cubit.dart b/lib/contact_invitation/cubits/contact_invitation_list_cubit.dart index b31c453..4875263 100644 --- a/lib/contact_invitation/cubits/contact_invitation_list_cubit.dart +++ b/lib/contact_invitation/cubits/contact_invitation_list_cubit.dart @@ -20,6 +20,13 @@ class ContactInviteInvalidKeyException implements Exception { final EncryptionKeyType type; } +class ContactInviteInvalidIdentityException implements Exception { + const ContactInviteInvalidIdentityException( + this.contactSuperIdentityRecordKey) + : super(); + final TypedKey contactSuperIdentityRecordKey; +} + typedef GetEncryptionKeyCallback = Future Function( VeilidCryptoSystem cs, EncryptionKeyType encryptionKeyType, @@ -301,6 +308,10 @@ class ContactInvitationListCubit final contactSuperIdentity = await SuperIdentity.open( superRecordKey: contactSuperIdentityRecordKey) .withCancel(cancelRequest); + if (contactSuperIdentity == null) { + throw ContactInviteInvalidIdentityException( + contactSuperIdentityRecordKey); + } // Verify final idcs = await contactSuperIdentity.currentInstance.cryptoSystem; diff --git a/lib/contact_invitation/views/invitation_dialog.dart b/lib/contact_invitation/views/invitation_dialog.dart index a5a7fad..f4c7fcc 100644 --- a/lib/contact_invitation/views/invitation_dialog.dart +++ b/lib/contact_invitation/views/invitation_dialog.dart @@ -216,6 +216,17 @@ class InvitationDialogState extends State { _isValidating = false; _validInvitation = validatedContactInvitation; }); + } on ContactInviteInvalidIdentityException catch (_) { + if (mounted) { + context + .read() + .error(text: translate('invitation_dialog.invalid_identity')); + } + setState(() { + _isValidating = false; + _validInvitation = null; + widget.onValidationFailed(); + }); } on ContactInviteInvalidKeyException catch (e) { String errorText; switch (e.type) { diff --git a/packages/veilid_support/lib/dht_support/src/dht_record/dht_record.dart b/packages/veilid_support/lib/dht_support/src/dht_record/dht_record.dart index 893cb80..6fb9d9e 100644 --- a/packages/veilid_support/lib/dht_support/src/dht_record/dht_record.dart +++ b/packages/veilid_support/lib/dht_support/src/dht_record/dht_record.dart @@ -226,7 +226,7 @@ class DHTRecord implements DHTDeleteable { Future tryWriteBytes(Uint8List newValue, {int subkey = -1, VeilidCrypto? crypto, - KeyPair? writer, + SetDHTValueOptions? options, Output? outSeqNum}) => _wrapStats('tryWriteBytes', () async { subkey = subkeyOrDefault(subkey); @@ -236,7 +236,9 @@ class DHTRecord implements DHTDeleteable { // Set the new data if possible var newValueData = await _routingContext.setDHTValue( key, subkey, encryptedNewValue, - writer: writer ?? _writer); + options: SetDHTValueOptions( + writer: options?.writer ?? _writer, + allowOffline: options?.allowOffline)); if (newValueData == null) { // A newer value wasn't found on the set, but we may get a newer value // when getting the value for the sequence number @@ -292,7 +294,8 @@ class DHTRecord implements DHTDeleteable { // Set the new data newValueData = await _routingContext.setDHTValue( key, subkey, encryptedNewValue, - writer: writer ?? _writer); + options: SetDHTValueOptions( + writer: writer ?? _writer, allowOffline: false)); // Repeat if newer data on the network was found } while (newValueData != null); @@ -351,7 +354,8 @@ class DHTRecord implements DHTDeleteable { oldValue = await tryWriteBytes(updatedValue, subkey: subkey, crypto: crypto, - writer: writer, + options: SetDHTValueOptions( + writer: writer ?? _writer, allowOffline: false), outSeqNum: outSeqNum); // Repeat update if newer data on the network was found @@ -362,12 +366,12 @@ class DHTRecord implements DHTDeleteable { Future tryWriteJson(T Function(dynamic) fromJson, T newValue, {int subkey = -1, VeilidCrypto? crypto, - KeyPair? writer, + SetDHTValueOptions? options, Output? outSeqNum}) => tryWriteBytes(jsonEncodeBytes(newValue), subkey: subkey, crypto: crypto, - writer: writer, + options: options, outSeqNum: outSeqNum) .then((out) { if (out == null) { @@ -381,12 +385,12 @@ class DHTRecord implements DHTDeleteable { T Function(List) fromBuffer, T newValue, {int subkey = -1, VeilidCrypto? crypto, - KeyPair? writer, + SetDHTValueOptions? options, Output? outSeqNum}) => tryWriteBytes(newValue.writeToBuffer(), subkey: subkey, crypto: crypto, - writer: writer, + options: options, outSeqNum: outSeqNum) .then((out) { if (out == null) { diff --git a/packages/veilid_support/lib/identity_support/super_identity.dart b/packages/veilid_support/lib/identity_support/super_identity.dart index c8fd59d..008967d 100644 --- a/packages/veilid_support/lib/identity_support/super_identity.dart +++ b/packages/veilid_support/lib/identity_support/super_identity.dart @@ -98,18 +98,20 @@ sealed class SuperIdentity with _$SuperIdentity { } /// Opens an existing super identity, validates it, and returns it - static Future open({required TypedKey superRecordKey}) async { + static Future open({required TypedKey superRecordKey}) async { final pool = DHTRecordPool.instance; // SuperIdentity DHT record is public/unencrypted return (await pool.openRecordRead(superRecordKey, debugName: 'SuperIdentity::openSuperIdentity::SuperIdentityRecord')) .deleteScope((superRec) async { - final superIdentity = (await superRec.getJson(SuperIdentity.fromJson, - refreshMode: DHTRecordRefreshMode.network))!; + final superIdentity = await superRec.getJson(SuperIdentity.fromJson, + refreshMode: DHTRecordRefreshMode.network); + if (superIdentity == null) { + return null; + } await superIdentity.validate(superRecordKey: superRecordKey); - return superIdentity; }); }