From 48509a7c45d6898f31cb396f6e46b38598b9571f Mon Sep 17 00:00:00 2001 From: Sitaram Kalluri Date: Fri, 15 Nov 2024 07:36:57 +0530 Subject: [PATCH 01/21] feat: Uptake public key hash changes --- .../shared_key_decryption.dart | 28 +++++--- .../abstract_atkey_encryption.dart | 9 ++- .../lib/src/response/at_notification.dart | 6 ++ .../lib/src/service/sync_service_impl.dart | 20 ++++++ .../notify_request_transformer.dart | 4 +- .../lib/src/util/at_client_util.dart | 2 + packages/at_client/pubspec.yaml | 13 +++- .../test/decryption_service_test.dart | 72 +++++++++++++++++-- .../test/encryption_service_test.dart | 4 ++ .../test/atclient_sharedkey_test.dart | 1 + 10 files changed, 141 insertions(+), 18 deletions(-) diff --git a/packages/at_client/lib/src/decryption_service/shared_key_decryption.dart b/packages/at_client/lib/src/decryption_service/shared_key_decryption.dart index 0e372ea94..db222dc3c 100644 --- a/packages/at_client/lib/src/decryption_service/shared_key_decryption.dart +++ b/packages/at_client/lib/src/decryption_service/shared_key_decryption.dart @@ -1,3 +1,4 @@ +import 'package:at_chops/at_chops.dart'; import 'package:at_client/src/client/at_client_spec.dart'; import 'package:at_client/src/decryption_service/decryption.dart'; import 'package:at_client/src/response/default_response_parser.dart'; @@ -5,7 +6,6 @@ import 'package:at_client/src/util/encryption_util.dart'; import 'package:at_commons/at_builders.dart'; import 'package:at_commons/at_commons.dart'; import 'package:at_utils/at_logger.dart'; -import 'package:at_chops/at_chops.dart'; /// Class responsible for decrypting the value of shared key's that are not owned /// by currentAtSign @@ -50,14 +50,26 @@ class SharedKeyDecryption implements AtKeyDecryption { intent: Intent.fetchEncryptionPublicKey, exceptionScenario: ExceptionScenario.localVerbExecutionFailed); } - if (currentAtSignPublicKey != null && - (atKey.metadata.pubKeyCS != null && - atKey.metadata.pubKeyCS != - EncryptionUtil.md5CheckSum(currentAtSignPublicKey))) { + if (currentAtSignPublicKey.isNullOrEmpty) { + throw AtPublicKeyNotFoundException('Public key cannot be null or empty'); + } + + final isPubKeyHashMismatch = atKey.metadata.pubKeyHash != null && + atKey.metadata.pubKeyHash?.hash != + AtChops.hashWith(HashingAlgoType.fromString( + atKey.metadata.pubKeyHash!.hashingAlgo)) + .hash(currentAtSignPublicKey!.codeUnits); + + final isPubKeyCSMismatch = atKey.metadata.pubKeyCS != null && + atKey.metadata.pubKeyCS != + EncryptionUtil.md5CheckSum(currentAtSignPublicKey!); + + if (isPubKeyHashMismatch || isPubKeyCSMismatch) { throw AtPublicKeyChangeException( - 'Public key has changed. Cannot decrypt shared key ${atKey.toString()}', - intent: Intent.fetchEncryptionPublicKey, - exceptionScenario: ExceptionScenario.decryptionFailed); + 'Public key has changed. Cannot decrypt shared key ${atKey.toString()}', + intent: Intent.fetchEncryptionPublicKey, + exceptionScenario: ExceptionScenario.decryptionFailed, + ); } AtEncryptionResult decryptionResultFromAtChops; diff --git a/packages/at_client/lib/src/encryption_service/abstract_atkey_encryption.dart b/packages/at_client/lib/src/encryption_service/abstract_atkey_encryption.dart index 6158b2827..bb7b52eb1 100644 --- a/packages/at_client/lib/src/encryption_service/abstract_atkey_encryption.dart +++ b/packages/at_client/lib/src/encryption_service/abstract_atkey_encryption.dart @@ -1,3 +1,4 @@ +import 'package:at_chops/at_chops.dart'; import 'package:at_client/at_client.dart'; import 'package:at_client/src/client/secondary.dart'; import 'package:at_client/src/encryption_service/encryption.dart'; @@ -9,7 +10,6 @@ import 'package:at_commons/at_builders.dart'; import 'package:at_persistence_secondary_server/at_persistence_secondary_server.dart'; import 'package:at_utils/at_logger.dart'; import 'package:meta/meta.dart'; -import 'package:at_chops/at_chops.dart'; /// Contains the common code for [SharedKeyEncryption] and [StreamEncryption] abstract class AbstractAtKeyEncryption implements AtKeyEncryption { @@ -49,8 +49,15 @@ abstract class AbstractAtKeyEncryption implements AtKeyEncryption { if (storeSharedKeyEncryptedWithData) { atKey.metadata.sharedKeyEnc = theirEncryptedSymmetricKeyCopy; + // This is a legacy checksum with MD5 algo. atKey.metadata.pubKeyCS = EncryptionUtil.md5CheckSum(await _getSharedWithPublicKey(atKey)); + // Hashed the encryption public key with sha512. This is to ensure the encryption + // public key of the receiver are same during encryption and decryption process. + String hash = await AtChops.hashWith(HashingAlgoType.sha512) + .hash((await _getSharedWithPublicKey(atKey)).codeUnits); + atKey.metadata.pubKeyHash = + PublicKeyHash(hash, HashingAlgoType.sha512.name); } } diff --git a/packages/at_client/lib/src/response/at_notification.dart b/packages/at_client/lib/src/response/at_notification.dart index 05f7bab0b..4382c3621 100644 --- a/packages/at_client/lib/src/response/at_notification.dart +++ b/packages/at_client/lib/src/response/at_notification.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:at_client/at_client.dart'; class AtNotification { @@ -34,6 +36,10 @@ class AtNotification { metadata.skeEncAlgo = json['metadata'][AtConstants.sharedKeyEncryptedEncryptingAlgo]; metadata.sharedKeyEnc = json['metadata'][AtConstants.sharedKeyEncrypted]; + var publicKeyHash = + jsonDecode(json['metadata'][AtConstants.sharedWithPublicKeyHash]); + metadata.pubKeyHash = + PublicKeyHash(publicKeyHash['hash'], publicKeyHash['hashingAlgo']); } return AtNotification(json['id'], json['key'], json['from'], json['to'], diff --git a/packages/at_client/lib/src/service/sync_service_impl.dart b/packages/at_client/lib/src/service/sync_service_impl.dart index 93eb93110..68ff54ef7 100644 --- a/packages/at_client/lib/src/service/sync_service_impl.dart +++ b/packages/at_client/lib/src/service/sync_service_impl.dart @@ -740,6 +740,13 @@ class SyncServiceImpl implements SyncService, AtSignChangeListener { if (metadata.pubKeyCS != null) { metadataStr += ':pubKeyCS:${metadata.pubKeyCS}'; } + if (metadata.pubKeyHash != null) { + metadataStr += + ':${AtConstants.sharedWithPublicKeyHash}:${metadata.pubKeyHash?.hash}'; + metadataStr += + ':${AtConstants.sharedWithPublicKeyHashingAlgo}:${metadata.pubKeyHash?.hashingAlgo}'; + } + if (metadata.encoding != null) { metadataStr += ':encoding:${metadata.encoding}'; } @@ -971,6 +978,12 @@ class SyncServiceImpl implements SyncService, AtSignChangeListener { builder.atKey.metadata.pubKeyCS = metaData[AtConstants.sharedWithPublicKeyCheckSum]; } + if (metaData[AtConstants.sharedWithPublicKeyHash] != null) { + Map pubKeyHash = + jsonDecode(metaData[AtConstants.sharedWithPublicKeyHash]); + builder.atKey.metadata.pubKeyHash = + PublicKeyHash(pubKeyHash['hash'], pubKeyHash['hashingAlgo']); + } if (metaData[AtConstants.encoding] != null) { builder.atKey.metadata.encoding = metaData[AtConstants.encoding]; } @@ -992,6 +1005,13 @@ class SyncServiceImpl implements SyncService, AtSignChangeListener { builder.atKey.metadata.skeEncAlgo = metaData[AtConstants.sharedKeyEncryptedEncryptingAlgo]; } + + if (metaData[AtConstants.sharedWithPublicKeyHash] != null && + metaData[AtConstants.sharedWithPublicKeyHashingAlgo] != null) { + builder.atKey.metadata.pubKeyHash = PublicKeyHash( + metaData[AtConstants.sharedWithPublicKeyHash], + metaData[AtConstants.sharedWithPublicKeyHashingAlgo]); + } } } diff --git a/packages/at_client/lib/src/transformer/request_transformer/notify_request_transformer.dart b/packages/at_client/lib/src/transformer/request_transformer/notify_request_transformer.dart index 5fd9df181..6ad1a359d 100644 --- a/packages/at_client/lib/src/transformer/request_transformer/notify_request_transformer.dart +++ b/packages/at_client/lib/src/transformer/request_transformer/notify_request_transformer.dart @@ -2,13 +2,13 @@ import 'dart:async'; +import 'package:at_client/src/encryption_service/encryption.dart'; import 'package:at_client/src/preference/at_client_preference.dart'; import 'package:at_client/src/service/notification_service.dart'; import 'package:at_client/src/transformer/at_transformer.dart'; import 'package:at_client/src/util/at_client_util.dart'; import 'package:at_commons/at_builders.dart'; import 'package:at_commons/at_commons.dart'; -import 'package:at_client/src/encryption_service/encryption.dart'; /// Class is responsible for taking the [NotificationParams] and converting into [NotifyVerbBuilder] class NotificationRequestTransformer @@ -96,6 +96,8 @@ class NotificationRequestTransformer notificationParams.atKey.metadata.skeEncKeyName; builder.atKey.metadata.skeEncAlgo = notificationParams.atKey.metadata.skeEncAlgo; + builder.atKey.metadata.pubKeyHash = + notificationParams.atKey.metadata.pubKeyHash; } Future _encryptNotificationValue(AtKey atKey, String value) async { diff --git a/packages/at_client/lib/src/util/at_client_util.dart b/packages/at_client/lib/src/util/at_client_util.dart index a571c5329..20f7c658d 100644 --- a/packages/at_client/lib/src/util/at_client_util.dart +++ b/packages/at_client/lib/src/util/at_client_util.dart @@ -105,6 +105,8 @@ class AtClientUtil { metadataMap[AtConstants.sharedKeyEncryptedEncryptingAlgo]; metadata.isPublic = isPublic; metadata.isCached = isCached; + metadata.pubKeyHash = PublicKeyHash.fromJson( + metadataMap[AtConstants.sharedWithPublicKeyHash]); return metadata; } diff --git a/packages/at_client/pubspec.yaml b/packages/at_client/pubspec.yaml index 31a5ac28f..518e62899 100644 --- a/packages/at_client/pubspec.yaml +++ b/packages/at_client/pubspec.yaml @@ -31,16 +31,23 @@ dependencies: async: ^2.9.0 at_utf7: ^1.0.0 at_base2e15: ^1.0.0 - at_commons: ^5.0.0 + at_commons: ^5.0.2 at_utils: ^3.0.19 - at_chops: ^2.0.1 + at_chops: ^2.2.0 at_lookup: ^3.0.49 - at_auth: ^2.0.7 + at_auth: ^2.0.8 at_persistence_spec: ^2.0.14 at_persistence_secondary_server: ^3.0.64 meta: ^1.8.0 version: ^3.0.2 +dependency_overrides: + at_persistence_secondary_server: + git: + url: https://github.com/atsign-foundation/at_server.git + path: packages/at_persistence_secondary_server + ref: 2121-uptake-public-key-hash-at-persistence_secondary-server + dev_dependencies: lints: ^4.0.0 test: ^1.21.4 diff --git a/packages/at_client/test/decryption_service_test.dart b/packages/at_client/test/decryption_service_test.dart index c2ed1ed7d..5a5c232cf 100644 --- a/packages/at_client/test/decryption_service_test.dart +++ b/packages/at_client/test/decryption_service_test.dart @@ -1,15 +1,15 @@ +import 'package:at_chops/at_chops.dart'; import 'package:at_client/at_client.dart'; import 'package:at_client/src/client/verb_builder_manager.dart'; -import 'package:at_client/src/decryption_service/shared_key_decryption.dart'; -import 'package:at_client/src/transformer/request_transformer/get_request_transformer.dart'; import 'package:at_client/src/decryption_service/decryption_manager.dart'; import 'package:at_client/src/decryption_service/local_key_decryption.dart'; import 'package:at_client/src/decryption_service/self_key_decryption.dart'; +import 'package:at_client/src/decryption_service/shared_key_decryption.dart'; +import 'package:at_client/src/transformer/request_transformer/get_request_transformer.dart'; import 'package:at_commons/at_builders.dart'; import 'package:at_lookup/at_lookup.dart'; -import 'package:test/test.dart'; import 'package:mocktail/mocktail.dart'; -import 'package:at_chops/at_chops.dart'; +import 'package:test/test.dart'; class MockRemoteSecondary extends Mock implements RemoteSecondary {} @@ -55,7 +55,8 @@ void main() { }); group('A group of positive test mock test to verify decryption service', () { - test('A test to verify decryption is successful when all keys are found', + test( + 'A test to verify decryption is successful when all keys are found - with publicKeyCS set', () async { var encryptionPrivateKey = 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrGPCsZtFf1xhALzrtnfjRlr9p6RdKMNPd2Z5RkOvUsvZuK56aR2Sc7Yl6HqPFi5rr1Xd4SwNXTfZIgVxpU4QoTyNjyFUWrWHoo2NQ0lUX75HAWYIzQf706HfkGmmDBOGoUEVJPLvQv9vPMpIofZYj9WTiWo9zBTRT8EbPNTF1RJHWQNfgs3xYkX16FfutBvS/B5TYZWDXpwVFwuGh0FF2gL3/wZvp6Qq5PXnV/iiF3mrF46kXXE04WAeizsF1u2nP8OuwdLkSk0I1zka81Xrpey/yRcbOEwK9zG5c6XsgqwCILEhLIBvYX/LRacllkxBci5ivZaSBsx41Jsc+Hw69AgMBAAECggEAOO8jpzrPkUTSHQmaYlee5J91MpkN1vJIjhpMRHglAbJLrn11WYFISbABf1GSzbmW48M07iKIChU3Twk85w+TepZbAGk5Z0Jqwi8cbViQWFav+YHPgZ8EaBqzSoQ/eAm3zXpok+ZR2TT+wAPj/vVLcMvHtkrMUUn6D7R0256nxo1u+fdJ5vsBefhSKR23zNfp+ynU54s20Gc4ejqDujbIow+aiJZv9y/asPG5UdSWN6ykhoPlOCv+VqAlGT7OWFKAMTUfIZb1UsqCIYKN+BNbwFBkFcuzr8AM5Xxd1DoNcBVdLOY6j+6k2kd4U0XxvLAhE0FZDVt5J82jGtmDJQyRQQKBgQDjFixG3XnXArYnM8667+LrdIK2UGbxu94pMjRR16g7v+miShASdcxzmBr/oDAHJrSwYg4t6QIyarj0nIfUqUNefQS28qjDBuQRMHwAcYcZZ5QwynJZsyHu5KP/Hqm2V4C7mU84jpKygiDQl9GSXIsIldQ+5ADrAvpFVkyNOwGFpwKBgQDA4dCHpFFmW2BcFIHXn3fpg2JPNSnXBmVl64QRVKUj30As5KMpgULiP5qP9KfogYArm+S+p6uK5s6kqdLDNOMwqCGLD21n8EOzOjtd1bbzxuC/OUu1SCmmqMd64Y+StNj5lxx1FmkbGT96kAM20QnvUdz1U1KeCODprL5z4L9c+wKBgQCztaBklHEPjr3IWF+J4L2byCCJVyegtiQiRfDRs/EXF9E09ZeyhDbAY+c51PMtNZxY2cCO5I8whvTH3/g+e5Us+ZL5lR+o95MVZ2E6mJ1ppWbJFe1Yv0JjY93Ez+dOvgDKdZEUGQBO9Fwzt3HKeiItMSU+gAGZ+klFBf6e5ctWkQKBgFckbpspwOD2vaU8WqE5Weq1QjA4+6s7J4qRijxuOqHnVk4yCglRbg9b3w/U4BtqjqalKwZ8KEN8HbZFR4SMG2y7OVRjZvGDmoKZ94JgcOTYYGfkkfDYJoE2VdGNoNkOPc0d2WyI8HmewZA1Ck60yMFIAgUQXQ4rQrowImemDa8LAoGAYc8Tp8LUNj4fYzTA0zE7YwBga0eTB8F9eHYhimAhBRScG5FYQHlGgNvwfAATclJfX2ikBRHidWUYGM/4+z10ZX+98uwGEwPgUWJCy8mLJ6CJb88a0j7LQjOYd5ZT+Qi96X5Y4RRYj7/2CHaq1KvoywqsGoaVaiTK1opj33c7F64='; @@ -86,6 +87,41 @@ void main() { expect(await sharedKeyDecryption.decrypt(atKey, encryptedValue), 'hello'); }); + + test( + 'A test to verify decryption is successful when all keys are found - with publicKeyHash set', + () async { + var encryptionPrivateKey = + 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrGPCsZtFf1xhALzrtnfjRlr9p6RdKMNPd2Z5RkOvUsvZuK56aR2Sc7Yl6HqPFi5rr1Xd4SwNXTfZIgVxpU4QoTyNjyFUWrWHoo2NQ0lUX75HAWYIzQf706HfkGmmDBOGoUEVJPLvQv9vPMpIofZYj9WTiWo9zBTRT8EbPNTF1RJHWQNfgs3xYkX16FfutBvS/B5TYZWDXpwVFwuGh0FF2gL3/wZvp6Qq5PXnV/iiF3mrF46kXXE04WAeizsF1u2nP8OuwdLkSk0I1zka81Xrpey/yRcbOEwK9zG5c6XsgqwCILEhLIBvYX/LRacllkxBci5ivZaSBsx41Jsc+Hw69AgMBAAECggEAOO8jpzrPkUTSHQmaYlee5J91MpkN1vJIjhpMRHglAbJLrn11WYFISbABf1GSzbmW48M07iKIChU3Twk85w+TepZbAGk5Z0Jqwi8cbViQWFav+YHPgZ8EaBqzSoQ/eAm3zXpok+ZR2TT+wAPj/vVLcMvHtkrMUUn6D7R0256nxo1u+fdJ5vsBefhSKR23zNfp+ynU54s20Gc4ejqDujbIow+aiJZv9y/asPG5UdSWN6ykhoPlOCv+VqAlGT7OWFKAMTUfIZb1UsqCIYKN+BNbwFBkFcuzr8AM5Xxd1DoNcBVdLOY6j+6k2kd4U0XxvLAhE0FZDVt5J82jGtmDJQyRQQKBgQDjFixG3XnXArYnM8667+LrdIK2UGbxu94pMjRR16g7v+miShASdcxzmBr/oDAHJrSwYg4t6QIyarj0nIfUqUNefQS28qjDBuQRMHwAcYcZZ5QwynJZsyHu5KP/Hqm2V4C7mU84jpKygiDQl9GSXIsIldQ+5ADrAvpFVkyNOwGFpwKBgQDA4dCHpFFmW2BcFIHXn3fpg2JPNSnXBmVl64QRVKUj30As5KMpgULiP5qP9KfogYArm+S+p6uK5s6kqdLDNOMwqCGLD21n8EOzOjtd1bbzxuC/OUu1SCmmqMd64Y+StNj5lxx1FmkbGT96kAM20QnvUdz1U1KeCODprL5z4L9c+wKBgQCztaBklHEPjr3IWF+J4L2byCCJVyegtiQiRfDRs/EXF9E09ZeyhDbAY+c51PMtNZxY2cCO5I8whvTH3/g+e5Us+ZL5lR+o95MVZ2E6mJ1ppWbJFe1Yv0JjY93Ez+dOvgDKdZEUGQBO9Fwzt3HKeiItMSU+gAGZ+klFBf6e5ctWkQKBgFckbpspwOD2vaU8WqE5Weq1QjA4+6s7J4qRijxuOqHnVk4yCglRbg9b3w/U4BtqjqalKwZ8KEN8HbZFR4SMG2y7OVRjZvGDmoKZ94JgcOTYYGfkkfDYJoE2VdGNoNkOPc0d2WyI8HmewZA1Ck60yMFIAgUQXQ4rQrowImemDa8LAoGAYc8Tp8LUNj4fYzTA0zE7YwBga0eTB8F9eHYhimAhBRScG5FYQHlGgNvwfAATclJfX2ikBRHidWUYGM/4+z10ZX+98uwGEwPgUWJCy8mLJ6CJb88a0j7LQjOYd5ZT+Qi96X5Y4RRYj7/2CHaq1KvoywqsGoaVaiTK1opj33c7F64='; + var encryptedValue = 'xTdYWFLRc2Gv2ACnMZbP4A=='; + var sharedKeyEnc = + 'T3VaG/MMd7ZFnKMCCQUqIOM4dDiLiZXeIZkXJ3p13jn4EXU6FWgygCbG/8aUrMr3riPO+Il4CwIvGrulGXsKzx9sjBxsFAhTDczzvOt0a52UJFxIjJGkC7mAuprLa23dRI/zUfvxEd6fgXVDT5k8itOO0ykOcb9syEtvzg+vZhniVODz7yu9gh0R1iQDxebM5mCPbGKNlEkdGJq6wGBvn26p2fq5CaPyIBHRU2B+DIaBEKnVmK2WomJnrCbLtYFlGGmtsMkCVfllBJSW3i6SZ1m080Yt07qtjnsWobK1FT+2i07Q+uGEaSjIr5eUyPeN4V5L1ZmsnXk92w+vhD0k0w=='; + var atKey = (AtKey.shared('phone', namespace: 'wavi', sharedBy: '@bob') + ..sharedWith('@alice')) + .build(); + atKey.metadata = Metadata() + ..sharedKeyEnc = sharedKeyEnc + ..pubKeyHash = PublicKeyHash( + '6ba753ba818686f6a1a91e27012518e398a4880533fefadd596dfd151d4661b848ab0438e01eaf5a5b6de1f4da4ed011812b3e57390f963b29a1fe023f265207', + HashingAlgoType.sha512.name); + + when(() => mockLocalSecondary.getEncryptionPrivateKey()) + .thenAnswer((_) => Future.value(encryptionPrivateKey)); + + when(() => mockAtClientImpl.getPreferences()) + .thenAnswer((_) => atClientPreferenceWithAtChops); + final atChopsKeys = AtChopsKeys.create( + AtEncryptionKeyPair.create('', encryptionPrivateKey), null); + when(() => mockAtClientImpl.atChops) + .thenAnswer((_) => AtChopsImpl(atChopsKeys)); + var sharedKeyDecryption = SharedKeyDecryption(mockAtClientImpl); + var result = await sharedKeyDecryption.decrypt(atKey, encryptedValue); + expect(result, 'hello'); + when(() => mockAtClientImpl.getPreferences()) + .thenAnswer((_) => atClientPreferenceWithAtChops); + + expect(await sharedKeyDecryption.decrypt(atKey, encryptedValue), 'hello'); + }); }); group('A group of tests to verify exceptions in decryption service', () { @@ -135,6 +171,32 @@ void main() { throwsA(predicate((dynamic e) => e is Exception))); }); + test('A test to verify exception is thrown when publicKeyHash mismatch', + () { + var atKey = (AtKey.shared('phone', namespace: 'wavi', sharedBy: '@xyz') + ..sharedWith('@bob')) + .build(); + atKey.metadata = Metadata() + ..sharedKeyEnc = 'dummy_shared_key' + ..pubKeyCS = 'd4f6d9483907286a0563b9fdeb01aa61' + ..pubKeyHash = PublicKeyHash('dummy_hash', HashingAlgoType.sha512.name); + + when(() => mockAtClientImpl.getPreferences()) + .thenAnswer((_) => atClientPreferenceWithAtChops); + var sharedKeyDecryptionWithAtChops = + SharedKeyDecryption(mockAtClientImpl); + final atChopsKeys = + AtChopsKeys.create(AtEncryptionKeyPair.create('', ''), null); + when(() => mockAtClientImpl.atChops) + .thenAnswer((_) => AtChopsImpl(atChopsKeys)); + when(() => mockLocalSecondary.getEncryptionPublicKey('@xyz')) + .thenAnswer((_) => Future.value('dummy_encryption_public_key')); + expect( + () async => + await sharedKeyDecryptionWithAtChops.decrypt(atKey, '123'), + throwsA(predicate((dynamic e) => e is AtPublicKeyChangeException))); + }); + // The AtLookup verb throws exception is stacked by the executeVerb in remote secondary test( 'Test to verify exception gets stacked in remote secondary executeVerb', diff --git a/packages/at_client/test/encryption_service_test.dart b/packages/at_client/test/encryption_service_test.dart index c266ec1da..dcd7120ae 100644 --- a/packages/at_client/test/encryption_service_test.dart +++ b/packages/at_client/test/encryption_service_test.dart @@ -392,6 +392,8 @@ void main() { expect(decryptedValue, value); expect(atKey.metadata.sharedKeyEnc.isNotNull, true); expect(atKey.metadata.pubKeyCS.isNotNull, true); + expect(atKey.metadata.pubKeyHash?.hash.isNotNullOrEmpty, true); + expect(atKey.metadata.pubKeyHash?.hashingAlgo.isNotNullOrEmpty, true); }); test('test to verify legacy encryption when a new shared key is generated', @@ -492,6 +494,8 @@ void main() { originalValue); expect(atKey.metadata.sharedKeyEnc.isNotNull, true); expect(atKey.metadata.pubKeyCS.isNotNull, true); + expect(atKey.metadata.pubKeyHash?.hash.isNotNullOrEmpty, true); + expect(atKey.metadata.pubKeyHash?.hashingAlgo.isNotNullOrEmpty, true); }); test( diff --git a/tests/at_functional_test/test/atclient_sharedkey_test.dart b/tests/at_functional_test/test/atclient_sharedkey_test.dart index dbcbf3f3f..e33f645d1 100644 --- a/tests/at_functional_test/test/atclient_sharedkey_test.dart +++ b/tests/at_functional_test/test/atclient_sharedkey_test.dart @@ -3,6 +3,7 @@ import 'package:at_client/src/encryption_service/encryption_manager.dart'; import 'package:at_functional_test/src/config_util.dart'; import 'package:at_functional_test/src/sync_service.dart'; import 'package:test/test.dart'; + import 'test_utils.dart'; void main() { From f6ed18811b22e45d31bc395f65ab4046212df65f Mon Sep 17 00:00:00 2001 From: Sitaram Kalluri Date: Mon, 25 Nov 2024 16:58:31 +0530 Subject: [PATCH 02/21] fix: Override at_persistence_secondary_server package to consume publicKeyHash changes --- tests/at_end2end_test/pubspec.yaml | 10 +++++++++- tests/at_functional_test/pubspec.yaml | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/at_end2end_test/pubspec.yaml b/tests/at_end2end_test/pubspec.yaml index fd1a4f012..4d02d9dba 100644 --- a/tests/at_end2end_test/pubspec.yaml +++ b/tests/at_end2end_test/pubspec.yaml @@ -14,7 +14,15 @@ dependencies: at_client: path: ../../packages/at_client +dependency_overrides: + at_commons: ^5.0.2 + at_persistence_secondary_server: + git: + url: https://github.com/atsign-foundation/at_server.git + path: packages/at_persistence_secondary_server + ref: 2121-uptake-public-key-hash-at-persistence_secondary-server + dev_dependencies: - test: ^1.24.3 + test: ^1.25.8 lints: ^2.0.0 coverage: ^1.5.0 diff --git a/tests/at_functional_test/pubspec.yaml b/tests/at_functional_test/pubspec.yaml index bd4a441a4..c432f29e3 100644 --- a/tests/at_functional_test/pubspec.yaml +++ b/tests/at_functional_test/pubspec.yaml @@ -14,6 +14,14 @@ dependencies: at_auth: ^2.0.7 at_lookup: ^3.0.49 +dependency_overrides: + at_commons: ^5.0.2 + at_persistence_secondary_server: + git: + url: https://github.com/atsign-foundation/at_server.git + path: packages/at_persistence_secondary_server + ref: 2121-uptake-public-key-hash-at-persistence_secondary-server + dev_dependencies: test: ^1.24.3 lints: ^2.0.0 From 03a027640f01a6242e1f17b3673d9094d8b85d8d Mon Sep 17 00:00:00 2001 From: Murali Date: Tue, 10 Dec 2024 14:14:16 +0530 Subject: [PATCH 03/21] fix: isInSync bug --- .../lib/src/service/sync_service_impl.dart | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/packages/at_client/lib/src/service/sync_service_impl.dart b/packages/at_client/lib/src/service/sync_service_impl.dart index 93eb93110..3ed450851 100644 --- a/packages/at_client/lib/src/service/sync_service_impl.dart +++ b/packages/at_client/lib/src/service/sync_service_impl.dart @@ -539,6 +539,7 @@ class SyncServiceImpl implements SyncService, AtSignChangeListener { /// commit-id to sync into the local keystore. Future> _getEntriesToSyncFromServer( int lastReceivedServerCommitId) async { + // Sync verb syntax has to be changed before removing these deprecations var syncBuilder = SyncVerbBuilder() ..commitId = lastReceivedServerCommitId ..regex = _atClient.getPreferences()!.syncRegex @@ -767,13 +768,8 @@ class SyncServiceImpl implements SyncService, AtSignChangeListener { ///Throws [AtClientException] if cloud secondary is not reachable @override Future isInSync() async { - late RemoteSecondary remoteSecondary; try { - remoteSecondary = RemoteSecondary( - _atClient.getCurrentAtSign()!, _atClient.getPreferences()!, - atChops: _atClient.atChops); - var serverCommitId = - await _getServerCommitId(remoteSecondary: remoteSecondary); + var serverCommitId = await _getServerCommitId(); var lastReceivedServerCommitId = await getLastReceivedServerCommitId(); @@ -794,8 +790,6 @@ class SyncServiceImpl implements SyncService, AtSignChangeListener { var cause = (e is AtException) ? e.getTraceMessage() : e.toString(); _logger.severe('exception in isInSync $cause'); throw AtClientException.message(e.toString()); - } finally { - unawaited(remoteSecondary.atLookUp.close()); } } @@ -804,8 +798,7 @@ class SyncServiceImpl implements SyncService, AtSignChangeListener { _logger.finest('*** isInSync..sync in progress'); return true; } - var serverCommitId = - await _getServerCommitId(remoteSecondary: _remoteSecondary); + var serverCommitId = await _getServerCommitId(); var lastReceivedServerCommitId = await getLastReceivedServerCommitId(); var lastSyncedEntry = await syncUtil.getLastSyncedEntry( _atClient.getPreferences()!.syncRegex, @@ -823,11 +816,10 @@ class SyncServiceImpl implements SyncService, AtSignChangeListener { /// Returns the cloud secondary latest commit id. if null, returns -1. ///Throws [AtLookUpException] if secondary is not reachable - Future _getServerCommitId({RemoteSecondary? remoteSecondary}) async { - remoteSecondary ??= _remoteSecondary; + Future _getServerCommitId() async { // ignore: no_leading_underscores_for_local_identifiers var _serverCommitId = await syncUtil.getLatestServerCommitId( - remoteSecondary, _atClient.getPreferences()!.syncRegex); + _remoteSecondary, _atClient.getPreferences()!.syncRegex); // If server commit id is null, set to -1; _serverCommitId ??= -1; _logger.info(_logger.getLogMessageWithClientParticulars( From 002519b7acad7a2db461d6eee5cdc608ed82f5f9 Mon Sep 17 00:00:00 2001 From: Murali Date: Wed, 11 Dec 2024 12:59:42 +0530 Subject: [PATCH 04/21] fix: pubspec and changelog --- packages/at_client/CHANGELOG.md | 2 ++ packages/at_client/lib/src/preference/at_client_config.dart | 2 +- packages/at_client/pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/at_client/CHANGELOG.md b/packages/at_client/CHANGELOG.md index ff0c84071..101ebc2c3 100644 --- a/packages/at_client/CHANGELOG.md +++ b/packages/at_client/CHANGELOG.md @@ -1,3 +1,5 @@ +# 3.3.1 +- fix: isInSync bug fix for apkam connection ## 3.3.0 - feat: add the AtClientBindings mixin which was initially added to the noports_core package but has broader applicability. diff --git a/packages/at_client/lib/src/preference/at_client_config.dart b/packages/at_client/lib/src/preference/at_client_config.dart index 8a5ce5bc7..e91ea7ac7 100644 --- a/packages/at_client/lib/src/preference/at_client_config.dart +++ b/packages/at_client/lib/src/preference/at_client_config.dart @@ -10,7 +10,7 @@ class AtClientConfig { /// Represents the at_client version. /// Must always be the same as the actual version in pubspec.yaml - final String atClientVersion = '3.3.0'; + final String atClientVersion = '3.3.1'; /// Represents the client commit log compaction time interval /// diff --git a/packages/at_client/pubspec.yaml b/packages/at_client/pubspec.yaml index 31a5ac28f..620b39adc 100644 --- a/packages/at_client/pubspec.yaml +++ b/packages/at_client/pubspec.yaml @@ -4,7 +4,7 @@ description: The at_client library is the non-platform specific Client SDK which ## ## ## NB: When incrementing the version, please also increment the version in AtClientConfig file -version: 3.3.0 +version: 3.3.1 ## NB: When incrementing the version, please also increment the version in AtClientConfig file ## From 1f9b1ba6065e428a56dd47072884f597352c39e8 Mon Sep 17 00:00:00 2001 From: Murali Date: Wed, 11 Dec 2024 21:04:26 +0530 Subject: [PATCH 05/21] fix: remove sync verb builder deprecated params --- packages/at_client/lib/src/service/sync_service_impl.dart | 4 +--- packages/at_client/pubspec.yaml | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/at_client/lib/src/service/sync_service_impl.dart b/packages/at_client/lib/src/service/sync_service_impl.dart index 3ed450851..36c08256b 100644 --- a/packages/at_client/lib/src/service/sync_service_impl.dart +++ b/packages/at_client/lib/src/service/sync_service_impl.dart @@ -542,9 +542,7 @@ class SyncServiceImpl implements SyncService, AtSignChangeListener { // Sync verb syntax has to be changed before removing these deprecations var syncBuilder = SyncVerbBuilder() ..commitId = lastReceivedServerCommitId - ..regex = _atClient.getPreferences()!.syncRegex - ..limit = _atClient.getPreferences()!.syncPageLimit - ..isPaginated = true; + ..regex = _atClient.getPreferences()!.syncRegex; _logger.finer(_logger.getLogMessageWithClientParticulars( _atClient.getPreferences()!.atClientParticulars, 'syncBuilder ${syncBuilder.buildCommand()}')); diff --git a/packages/at_client/pubspec.yaml b/packages/at_client/pubspec.yaml index 620b39adc..9ae3a3223 100644 --- a/packages/at_client/pubspec.yaml +++ b/packages/at_client/pubspec.yaml @@ -41,6 +41,13 @@ dependencies: meta: ^1.8.0 version: ^3.0.2 +dependency_overrides: + at_lookup: + git: + url: https://github.com/atsign-foundation/at_libraries.git + path: packages/at_lookup + ref: atlookup_add_default_values_sync_builder + dev_dependencies: lints: ^4.0.0 test: ^1.21.4 From 8e1ac5e256e83f10de35c40cd6d870219507600c Mon Sep 17 00:00:00 2001 From: Sitaram Kalluri Date: Wed, 11 Dec 2024 12:29:43 +0530 Subject: [PATCH 06/21] fix: Update the unit tests and version in pubspec.yaml --- .../lib/src/response/at_notification.dart | 13 +- packages/at_client/pubspec.yaml | 13 +- .../test/decryption_service_test.dart | 72 +------- .../test/encryption_decryption_test.dart | 170 ++++++++++++++++++ .../test/encryption_service_test.dart | 4 - tests/at_end2end_test/pubspec.yaml | 8 - tests/at_functional_test/pubspec.yaml | 12 +- 7 files changed, 189 insertions(+), 103 deletions(-) create mode 100644 packages/at_client/test/encryption_decryption_test.dart diff --git a/packages/at_client/lib/src/response/at_notification.dart b/packages/at_client/lib/src/response/at_notification.dart index 4382c3621..0e1948088 100644 --- a/packages/at_client/lib/src/response/at_notification.dart +++ b/packages/at_client/lib/src/response/at_notification.dart @@ -36,10 +36,15 @@ class AtNotification { metadata.skeEncAlgo = json['metadata'][AtConstants.sharedKeyEncryptedEncryptingAlgo]; metadata.sharedKeyEnc = json['metadata'][AtConstants.sharedKeyEncrypted]; - var publicKeyHash = - jsonDecode(json['metadata'][AtConstants.sharedWithPublicKeyHash]); - metadata.pubKeyHash = - PublicKeyHash(publicKeyHash['hash'], publicKeyHash['hashingAlgo']); + // AtContants.sharedWithPublicKeyHash will be sent by the server starting v3.0.52 + // Notifications received from Secondary server before 3.0.52 does not contain + // AtConstants.sharedWithPublicKeyHash. Therefore, check for null. + if (json['metadata'][AtConstants.sharedWithPublicKeyHash] != null) { + var publicKeyHash = + jsonDecode(json['metadata'][AtConstants.sharedWithPublicKeyHash]); + metadata.pubKeyHash = + PublicKeyHash(publicKeyHash['hash'], publicKeyHash['hashingAlgo']); + } } return AtNotification(json['id'], json['key'], json['from'], json['to'], diff --git a/packages/at_client/pubspec.yaml b/packages/at_client/pubspec.yaml index 518e62899..35aa6bd9e 100644 --- a/packages/at_client/pubspec.yaml +++ b/packages/at_client/pubspec.yaml @@ -37,20 +37,13 @@ dependencies: at_lookup: ^3.0.49 at_auth: ^2.0.8 at_persistence_spec: ^2.0.14 - at_persistence_secondary_server: ^3.0.64 + at_persistence_secondary_server: ^3.1.0 meta: ^1.8.0 version: ^3.0.2 -dependency_overrides: - at_persistence_secondary_server: - git: - url: https://github.com/atsign-foundation/at_server.git - path: packages/at_persistence_secondary_server - ref: 2121-uptake-public-key-hash-at-persistence_secondary-server - dev_dependencies: - lints: ^4.0.0 - test: ^1.21.4 + lints: ^5.0.0 + test: ^1.25.8 at_demo_data: ^1.0.1 coverage: ^1.5.0 mocktail: ^1.0.3 diff --git a/packages/at_client/test/decryption_service_test.dart b/packages/at_client/test/decryption_service_test.dart index 5a5c232cf..c2ed1ed7d 100644 --- a/packages/at_client/test/decryption_service_test.dart +++ b/packages/at_client/test/decryption_service_test.dart @@ -1,15 +1,15 @@ -import 'package:at_chops/at_chops.dart'; import 'package:at_client/at_client.dart'; import 'package:at_client/src/client/verb_builder_manager.dart'; +import 'package:at_client/src/decryption_service/shared_key_decryption.dart'; +import 'package:at_client/src/transformer/request_transformer/get_request_transformer.dart'; import 'package:at_client/src/decryption_service/decryption_manager.dart'; import 'package:at_client/src/decryption_service/local_key_decryption.dart'; import 'package:at_client/src/decryption_service/self_key_decryption.dart'; -import 'package:at_client/src/decryption_service/shared_key_decryption.dart'; -import 'package:at_client/src/transformer/request_transformer/get_request_transformer.dart'; import 'package:at_commons/at_builders.dart'; import 'package:at_lookup/at_lookup.dart'; -import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:at_chops/at_chops.dart'; class MockRemoteSecondary extends Mock implements RemoteSecondary {} @@ -55,8 +55,7 @@ void main() { }); group('A group of positive test mock test to verify decryption service', () { - test( - 'A test to verify decryption is successful when all keys are found - with publicKeyCS set', + test('A test to verify decryption is successful when all keys are found', () async { var encryptionPrivateKey = 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrGPCsZtFf1xhALzrtnfjRlr9p6RdKMNPd2Z5RkOvUsvZuK56aR2Sc7Yl6HqPFi5rr1Xd4SwNXTfZIgVxpU4QoTyNjyFUWrWHoo2NQ0lUX75HAWYIzQf706HfkGmmDBOGoUEVJPLvQv9vPMpIofZYj9WTiWo9zBTRT8EbPNTF1RJHWQNfgs3xYkX16FfutBvS/B5TYZWDXpwVFwuGh0FF2gL3/wZvp6Qq5PXnV/iiF3mrF46kXXE04WAeizsF1u2nP8OuwdLkSk0I1zka81Xrpey/yRcbOEwK9zG5c6XsgqwCILEhLIBvYX/LRacllkxBci5ivZaSBsx41Jsc+Hw69AgMBAAECggEAOO8jpzrPkUTSHQmaYlee5J91MpkN1vJIjhpMRHglAbJLrn11WYFISbABf1GSzbmW48M07iKIChU3Twk85w+TepZbAGk5Z0Jqwi8cbViQWFav+YHPgZ8EaBqzSoQ/eAm3zXpok+ZR2TT+wAPj/vVLcMvHtkrMUUn6D7R0256nxo1u+fdJ5vsBefhSKR23zNfp+ynU54s20Gc4ejqDujbIow+aiJZv9y/asPG5UdSWN6ykhoPlOCv+VqAlGT7OWFKAMTUfIZb1UsqCIYKN+BNbwFBkFcuzr8AM5Xxd1DoNcBVdLOY6j+6k2kd4U0XxvLAhE0FZDVt5J82jGtmDJQyRQQKBgQDjFixG3XnXArYnM8667+LrdIK2UGbxu94pMjRR16g7v+miShASdcxzmBr/oDAHJrSwYg4t6QIyarj0nIfUqUNefQS28qjDBuQRMHwAcYcZZ5QwynJZsyHu5KP/Hqm2V4C7mU84jpKygiDQl9GSXIsIldQ+5ADrAvpFVkyNOwGFpwKBgQDA4dCHpFFmW2BcFIHXn3fpg2JPNSnXBmVl64QRVKUj30As5KMpgULiP5qP9KfogYArm+S+p6uK5s6kqdLDNOMwqCGLD21n8EOzOjtd1bbzxuC/OUu1SCmmqMd64Y+StNj5lxx1FmkbGT96kAM20QnvUdz1U1KeCODprL5z4L9c+wKBgQCztaBklHEPjr3IWF+J4L2byCCJVyegtiQiRfDRs/EXF9E09ZeyhDbAY+c51PMtNZxY2cCO5I8whvTH3/g+e5Us+ZL5lR+o95MVZ2E6mJ1ppWbJFe1Yv0JjY93Ez+dOvgDKdZEUGQBO9Fwzt3HKeiItMSU+gAGZ+klFBf6e5ctWkQKBgFckbpspwOD2vaU8WqE5Weq1QjA4+6s7J4qRijxuOqHnVk4yCglRbg9b3w/U4BtqjqalKwZ8KEN8HbZFR4SMG2y7OVRjZvGDmoKZ94JgcOTYYGfkkfDYJoE2VdGNoNkOPc0d2WyI8HmewZA1Ck60yMFIAgUQXQ4rQrowImemDa8LAoGAYc8Tp8LUNj4fYzTA0zE7YwBga0eTB8F9eHYhimAhBRScG5FYQHlGgNvwfAATclJfX2ikBRHidWUYGM/4+z10ZX+98uwGEwPgUWJCy8mLJ6CJb88a0j7LQjOYd5ZT+Qi96X5Y4RRYj7/2CHaq1KvoywqsGoaVaiTK1opj33c7F64='; @@ -87,41 +86,6 @@ void main() { expect(await sharedKeyDecryption.decrypt(atKey, encryptedValue), 'hello'); }); - - test( - 'A test to verify decryption is successful when all keys are found - with publicKeyHash set', - () async { - var encryptionPrivateKey = - 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrGPCsZtFf1xhALzrtnfjRlr9p6RdKMNPd2Z5RkOvUsvZuK56aR2Sc7Yl6HqPFi5rr1Xd4SwNXTfZIgVxpU4QoTyNjyFUWrWHoo2NQ0lUX75HAWYIzQf706HfkGmmDBOGoUEVJPLvQv9vPMpIofZYj9WTiWo9zBTRT8EbPNTF1RJHWQNfgs3xYkX16FfutBvS/B5TYZWDXpwVFwuGh0FF2gL3/wZvp6Qq5PXnV/iiF3mrF46kXXE04WAeizsF1u2nP8OuwdLkSk0I1zka81Xrpey/yRcbOEwK9zG5c6XsgqwCILEhLIBvYX/LRacllkxBci5ivZaSBsx41Jsc+Hw69AgMBAAECggEAOO8jpzrPkUTSHQmaYlee5J91MpkN1vJIjhpMRHglAbJLrn11WYFISbABf1GSzbmW48M07iKIChU3Twk85w+TepZbAGk5Z0Jqwi8cbViQWFav+YHPgZ8EaBqzSoQ/eAm3zXpok+ZR2TT+wAPj/vVLcMvHtkrMUUn6D7R0256nxo1u+fdJ5vsBefhSKR23zNfp+ynU54s20Gc4ejqDujbIow+aiJZv9y/asPG5UdSWN6ykhoPlOCv+VqAlGT7OWFKAMTUfIZb1UsqCIYKN+BNbwFBkFcuzr8AM5Xxd1DoNcBVdLOY6j+6k2kd4U0XxvLAhE0FZDVt5J82jGtmDJQyRQQKBgQDjFixG3XnXArYnM8667+LrdIK2UGbxu94pMjRR16g7v+miShASdcxzmBr/oDAHJrSwYg4t6QIyarj0nIfUqUNefQS28qjDBuQRMHwAcYcZZ5QwynJZsyHu5KP/Hqm2V4C7mU84jpKygiDQl9GSXIsIldQ+5ADrAvpFVkyNOwGFpwKBgQDA4dCHpFFmW2BcFIHXn3fpg2JPNSnXBmVl64QRVKUj30As5KMpgULiP5qP9KfogYArm+S+p6uK5s6kqdLDNOMwqCGLD21n8EOzOjtd1bbzxuC/OUu1SCmmqMd64Y+StNj5lxx1FmkbGT96kAM20QnvUdz1U1KeCODprL5z4L9c+wKBgQCztaBklHEPjr3IWF+J4L2byCCJVyegtiQiRfDRs/EXF9E09ZeyhDbAY+c51PMtNZxY2cCO5I8whvTH3/g+e5Us+ZL5lR+o95MVZ2E6mJ1ppWbJFe1Yv0JjY93Ez+dOvgDKdZEUGQBO9Fwzt3HKeiItMSU+gAGZ+klFBf6e5ctWkQKBgFckbpspwOD2vaU8WqE5Weq1QjA4+6s7J4qRijxuOqHnVk4yCglRbg9b3w/U4BtqjqalKwZ8KEN8HbZFR4SMG2y7OVRjZvGDmoKZ94JgcOTYYGfkkfDYJoE2VdGNoNkOPc0d2WyI8HmewZA1Ck60yMFIAgUQXQ4rQrowImemDa8LAoGAYc8Tp8LUNj4fYzTA0zE7YwBga0eTB8F9eHYhimAhBRScG5FYQHlGgNvwfAATclJfX2ikBRHidWUYGM/4+z10ZX+98uwGEwPgUWJCy8mLJ6CJb88a0j7LQjOYd5ZT+Qi96X5Y4RRYj7/2CHaq1KvoywqsGoaVaiTK1opj33c7F64='; - var encryptedValue = 'xTdYWFLRc2Gv2ACnMZbP4A=='; - var sharedKeyEnc = - 'T3VaG/MMd7ZFnKMCCQUqIOM4dDiLiZXeIZkXJ3p13jn4EXU6FWgygCbG/8aUrMr3riPO+Il4CwIvGrulGXsKzx9sjBxsFAhTDczzvOt0a52UJFxIjJGkC7mAuprLa23dRI/zUfvxEd6fgXVDT5k8itOO0ykOcb9syEtvzg+vZhniVODz7yu9gh0R1iQDxebM5mCPbGKNlEkdGJq6wGBvn26p2fq5CaPyIBHRU2B+DIaBEKnVmK2WomJnrCbLtYFlGGmtsMkCVfllBJSW3i6SZ1m080Yt07qtjnsWobK1FT+2i07Q+uGEaSjIr5eUyPeN4V5L1ZmsnXk92w+vhD0k0w=='; - var atKey = (AtKey.shared('phone', namespace: 'wavi', sharedBy: '@bob') - ..sharedWith('@alice')) - .build(); - atKey.metadata = Metadata() - ..sharedKeyEnc = sharedKeyEnc - ..pubKeyHash = PublicKeyHash( - '6ba753ba818686f6a1a91e27012518e398a4880533fefadd596dfd151d4661b848ab0438e01eaf5a5b6de1f4da4ed011812b3e57390f963b29a1fe023f265207', - HashingAlgoType.sha512.name); - - when(() => mockLocalSecondary.getEncryptionPrivateKey()) - .thenAnswer((_) => Future.value(encryptionPrivateKey)); - - when(() => mockAtClientImpl.getPreferences()) - .thenAnswer((_) => atClientPreferenceWithAtChops); - final atChopsKeys = AtChopsKeys.create( - AtEncryptionKeyPair.create('', encryptionPrivateKey), null); - when(() => mockAtClientImpl.atChops) - .thenAnswer((_) => AtChopsImpl(atChopsKeys)); - var sharedKeyDecryption = SharedKeyDecryption(mockAtClientImpl); - var result = await sharedKeyDecryption.decrypt(atKey, encryptedValue); - expect(result, 'hello'); - when(() => mockAtClientImpl.getPreferences()) - .thenAnswer((_) => atClientPreferenceWithAtChops); - - expect(await sharedKeyDecryption.decrypt(atKey, encryptedValue), 'hello'); - }); }); group('A group of tests to verify exceptions in decryption service', () { @@ -171,32 +135,6 @@ void main() { throwsA(predicate((dynamic e) => e is Exception))); }); - test('A test to verify exception is thrown when publicKeyHash mismatch', - () { - var atKey = (AtKey.shared('phone', namespace: 'wavi', sharedBy: '@xyz') - ..sharedWith('@bob')) - .build(); - atKey.metadata = Metadata() - ..sharedKeyEnc = 'dummy_shared_key' - ..pubKeyCS = 'd4f6d9483907286a0563b9fdeb01aa61' - ..pubKeyHash = PublicKeyHash('dummy_hash', HashingAlgoType.sha512.name); - - when(() => mockAtClientImpl.getPreferences()) - .thenAnswer((_) => atClientPreferenceWithAtChops); - var sharedKeyDecryptionWithAtChops = - SharedKeyDecryption(mockAtClientImpl); - final atChopsKeys = - AtChopsKeys.create(AtEncryptionKeyPair.create('', ''), null); - when(() => mockAtClientImpl.atChops) - .thenAnswer((_) => AtChopsImpl(atChopsKeys)); - when(() => mockLocalSecondary.getEncryptionPublicKey('@xyz')) - .thenAnswer((_) => Future.value('dummy_encryption_public_key')); - expect( - () async => - await sharedKeyDecryptionWithAtChops.decrypt(atKey, '123'), - throwsA(predicate((dynamic e) => e is AtPublicKeyChangeException))); - }); - // The AtLookup verb throws exception is stacked by the executeVerb in remote secondary test( 'Test to verify exception gets stacked in remote secondary executeVerb', diff --git a/packages/at_client/test/encryption_decryption_test.dart b/packages/at_client/test/encryption_decryption_test.dart new file mode 100644 index 000000000..f91e12f79 --- /dev/null +++ b/packages/at_client/test/encryption_decryption_test.dart @@ -0,0 +1,170 @@ +import 'dart:io'; + +import 'package:at_chops/at_chops.dart'; +import 'package:at_client/at_client.dart'; +import 'package:at_client/src/decryption_service/shared_key_decryption.dart'; +import 'package:at_client/src/encryption_service/shared_key_encryption.dart'; +import 'package:at_commons/at_builders.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +class MockRemoteSecondary extends Mock implements RemoteSecondary {} + +void main() { + String currentAtSign = '@alice'; + String namespace = 'unit.test'; + + MockRemoteSecondary mockRemoteSecondary = MockRemoteSecondary(); + + late AtChops atChops; + late AtClient atClient; + + setUp(() async { + AtClientPreference atClientPreference = AtClientPreference() + ..isLocalStoreRequired = true + ..hiveStoragePath = 'test/unit_test_storage/hive' + ..commitLogPath = 'test/unit_test_storage/commit'; + + AtEncryptionKeyPair atEncryptionKeyPair = + AtChopsUtil.generateAtEncryptionKeyPair(); + AtPkamKeyPair atPkamKeyPair = AtChopsUtil.generateAtPkamKeyPair(); + AtChopsKeys atChopsKeys = + AtChopsKeys.create(atEncryptionKeyPair, atPkamKeyPair); + atChopsKeys.selfEncryptionKey = + AtChopsUtil.generateSymmetricKey(EncryptionKeyType.aes256); + atChops = AtChopsImpl(atChopsKeys); + + atClient = await AtClientImpl.create( + currentAtSign, namespace, atClientPreference, + remoteSecondary: mockRemoteSecondary, atChops: atChops); + + // During decryption, fetches the encryption public key from local keystore. + // So, store the encryption public key into local secondary keystore. + await atClient.getLocalSecondary()?.putValue( + 'public:publickey$currentAtSign', + atEncryptionKeyPair.atPublicKey.publicKey); + }); + + tearDown(() { + Directory('test/unit_test_storage').deleteSync(recursive: true); + }); + + group('A group of tests related to encryption and decryption of shared keys', + () { + test( + 'A test to verify encryption and decryption of shared key is successful - with publicKeyHash', + () async { + registerFallbackValue(LLookupVerbBuilder()); + AtKey sharedKey = + (AtKey.shared('email', namespace: namespace, sharedBy: currentAtSign) + ..sharedWith('@bob')) + .build(); + String value = 'alice@atsign.com'; + + when(() => mockRemoteSecondary + .executeVerb(any(that: EncryptedSharedKeyMatcher()))) + .thenAnswer((_) => Future.value('data:null')); + + // Returns encryption public key of sharedWith atSign. + // For unit test, reusing the current AtSign encryptionPublicKey. + when(() => mockRemoteSecondary + .executeVerb(any(that: EncryptionPublicKeyMatcher()))) + .thenAnswer((_) => Future.value( + atChops.atChopsKeys.atEncryptionKeyPair?.atPublicKey.publicKey)); + + // Encryption + SharedKeyEncryption sharedKeyEncryption = SharedKeyEncryption(atClient); + String encryptedValue = + await sharedKeyEncryption.encrypt(sharedKey, value); + expect(sharedKey.metadata.pubKeyHash?.hash.isNotEmpty, true); + expect(sharedKey.metadata.pubKeyHash?.hashingAlgo, 'sha512'); + expect(sharedKey.metadata.sharedKeyEnc?.isNotEmpty, true); + expect(sharedKey.metadata.pubKeyCS?.isNotEmpty, true); + + // Explicitly setting pubKeyCS to null, so that pubKeyHash will only be used + // during decryption. + sharedKey.metadata.pubKeyCS = null; + expect(sharedKey.metadata.pubKeyCS, null); + + // Decryption + SharedKeyDecryption sharedKeyDecryption = SharedKeyDecryption(atClient); + String decryptedValue = + await sharedKeyDecryption.decrypt(sharedKey, encryptedValue); + expect(decryptedValue, value); + }); + + test('A test to verify exception is thrown when publicKeyHash mismatch', + () async { + registerFallbackValue(LLookupVerbBuilder()); + AtKey sharedKey = + (AtKey.shared('email', namespace: namespace, sharedBy: currentAtSign) + ..sharedWith('@bob')) + .build(); + String value = 'alice@atsign.com'; + + when(() => mockRemoteSecondary + .executeVerb(any(that: EncryptedSharedKeyMatcher()))) + .thenAnswer((_) => Future.value('data:null')); + + // Returns encryption public key of sharedWith atSign. + // For unit test, reusing the current AtSign encryptionPublicKey. + when(() => mockRemoteSecondary + .executeVerb(any(that: EncryptionPublicKeyMatcher()))) + .thenAnswer((_) => Future.value( + atChops.atChopsKeys.atEncryptionKeyPair?.atPublicKey.publicKey)); + + // Encryption + SharedKeyEncryption sharedKeyEncryption = SharedKeyEncryption(atClient); + String encryptedValue = + await sharedKeyEncryption.encrypt(sharedKey, value); + expect(sharedKey.metadata.pubKeyHash?.hash.isNotEmpty, true); + expect(sharedKey.metadata.pubKeyHash?.hashingAlgo, 'sha512'); + expect(sharedKey.metadata.sharedKeyEnc?.isNotEmpty, true); + expect(sharedKey.metadata.pubKeyCS?.isNotEmpty, true); + + // Explicitly setting pubKeyCS to null, so that pubKeyHash will only be used + // during decryption. + sharedKey.metadata.pubKeyCS = null; + expect(sharedKey.metadata.pubKeyCS, null); + // Explicity changing the publicKeyHash value to mimic change in publicKeyHash + // value. + sharedKey.metadata.pubKeyHash = + PublicKeyHash('dummy_hash_value', HashingAlgoType.sha512.name); + + // Decryption + SharedKeyDecryption sharedKeyDecryption = SharedKeyDecryption(atClient); + expect( + () async => + await sharedKeyDecryption.decrypt(sharedKey, encryptedValue), + throwsA(predicate((dynamic e) => + e is AtPublicKeyChangeException && + e.message == + 'Public key has changed. Cannot decrypt shared key ${sharedKey.toString()}'))); + }); + }); +} + +class EncryptedSharedKeyMatcher extends Matcher { + @override + Description describe(Description description) { + return description; + } + + @override + bool matches(item, Map matchState) { + return item.atKey.key.startsWith(AtConstants.atEncryptionSharedKey); + } +} + +class EncryptionPublicKeyMatcher extends Matcher { + @override + Description describe(Description description) { + // TODO: implement describe + throw UnimplementedError(); + } + + @override + bool matches(item, Map matchState) { + return item.atKey.key.startsWith('publickey'); + } +} diff --git a/packages/at_client/test/encryption_service_test.dart b/packages/at_client/test/encryption_service_test.dart index dcd7120ae..c266ec1da 100644 --- a/packages/at_client/test/encryption_service_test.dart +++ b/packages/at_client/test/encryption_service_test.dart @@ -392,8 +392,6 @@ void main() { expect(decryptedValue, value); expect(atKey.metadata.sharedKeyEnc.isNotNull, true); expect(atKey.metadata.pubKeyCS.isNotNull, true); - expect(atKey.metadata.pubKeyHash?.hash.isNotNullOrEmpty, true); - expect(atKey.metadata.pubKeyHash?.hashingAlgo.isNotNullOrEmpty, true); }); test('test to verify legacy encryption when a new shared key is generated', @@ -494,8 +492,6 @@ void main() { originalValue); expect(atKey.metadata.sharedKeyEnc.isNotNull, true); expect(atKey.metadata.pubKeyCS.isNotNull, true); - expect(atKey.metadata.pubKeyHash?.hash.isNotNullOrEmpty, true); - expect(atKey.metadata.pubKeyHash?.hashingAlgo.isNotNullOrEmpty, true); }); test( diff --git a/tests/at_end2end_test/pubspec.yaml b/tests/at_end2end_test/pubspec.yaml index 4d02d9dba..33fb13150 100644 --- a/tests/at_end2end_test/pubspec.yaml +++ b/tests/at_end2end_test/pubspec.yaml @@ -14,14 +14,6 @@ dependencies: at_client: path: ../../packages/at_client -dependency_overrides: - at_commons: ^5.0.2 - at_persistence_secondary_server: - git: - url: https://github.com/atsign-foundation/at_server.git - path: packages/at_persistence_secondary_server - ref: 2121-uptake-public-key-hash-at-persistence_secondary-server - dev_dependencies: test: ^1.25.8 lints: ^2.0.0 diff --git a/tests/at_functional_test/pubspec.yaml b/tests/at_functional_test/pubspec.yaml index c432f29e3..d7cfd2647 100644 --- a/tests/at_functional_test/pubspec.yaml +++ b/tests/at_functional_test/pubspec.yaml @@ -14,15 +14,7 @@ dependencies: at_auth: ^2.0.7 at_lookup: ^3.0.49 -dependency_overrides: - at_commons: ^5.0.2 - at_persistence_secondary_server: - git: - url: https://github.com/atsign-foundation/at_server.git - path: packages/at_persistence_secondary_server - ref: 2121-uptake-public-key-hash-at-persistence_secondary-server - dev_dependencies: - test: ^1.24.3 - lints: ^2.0.0 + test: ^1.25.8 + lints: ^5.0.0 coverage: ^1.5.0 \ No newline at end of file From f3937729ad402a390a84c2ba17576219bddb534e Mon Sep 17 00:00:00 2001 From: Murali Date: Wed, 11 Dec 2024 21:27:28 +0530 Subject: [PATCH 07/21] fix: add atlookup dependency override to end2end and functional test --- tests/at_end2end_test/pubspec.yaml | 7 +++++++ tests/at_functional_test/pubspec.yaml | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/tests/at_end2end_test/pubspec.yaml b/tests/at_end2end_test/pubspec.yaml index fd1a4f012..6cf60107c 100644 --- a/tests/at_end2end_test/pubspec.yaml +++ b/tests/at_end2end_test/pubspec.yaml @@ -14,6 +14,13 @@ dependencies: at_client: path: ../../packages/at_client +dependency_overrides: + at_lookup: + git: + url: https://github.com/atsign-foundation/at_libraries.git + path: packages/at_lookup + ref: atlookup_add_default_values_sync_builder + dev_dependencies: test: ^1.24.3 lints: ^2.0.0 diff --git a/tests/at_functional_test/pubspec.yaml b/tests/at_functional_test/pubspec.yaml index bd4a441a4..4a2e06bdc 100644 --- a/tests/at_functional_test/pubspec.yaml +++ b/tests/at_functional_test/pubspec.yaml @@ -14,6 +14,13 @@ dependencies: at_auth: ^2.0.7 at_lookup: ^3.0.49 +dependency_overrides: + at_lookup: + git: + url: https://github.com/atsign-foundation/at_libraries.git + path: packages/at_lookup + ref: atlookup_add_default_values_sync_builder + dev_dependencies: test: ^1.24.3 lints: ^2.0.0 From bc3ed752e99f771623aab6998f93607b204f2763 Mon Sep 17 00:00:00 2001 From: Sitaram Kalluri Date: Thu, 12 Dec 2024 16:49:25 +0530 Subject: [PATCH 08/21] fix: Modify existing functional tests to assert on publicKeyHash --- packages/at_client/lib/src/response/at_notification.dart | 4 ++-- packages/at_client/pubspec.yaml | 2 +- packages/at_client/test/encryption_decryption_test.dart | 2 +- tests/at_functional_test/test/atclient_sharedkey_test.dart | 6 +++++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/at_client/lib/src/response/at_notification.dart b/packages/at_client/lib/src/response/at_notification.dart index 0e1948088..9e14df2d2 100644 --- a/packages/at_client/lib/src/response/at_notification.dart +++ b/packages/at_client/lib/src/response/at_notification.dart @@ -38,8 +38,8 @@ class AtNotification { metadata.sharedKeyEnc = json['metadata'][AtConstants.sharedKeyEncrypted]; // AtContants.sharedWithPublicKeyHash will be sent by the server starting v3.0.52 // Notifications received from Secondary server before 3.0.52 does not contain - // AtConstants.sharedWithPublicKeyHash. Therefore, check for null. - if (json['metadata'][AtConstants.sharedWithPublicKeyHash] != null) { + // AtConstants.sharedWithPublicKeyHash. Therefore, check for null String. + if (json['metadata'][AtConstants.sharedWithPublicKeyHash] != "null") { var publicKeyHash = jsonDecode(json['metadata'][AtConstants.sharedWithPublicKeyHash]); metadata.pubKeyHash = diff --git a/packages/at_client/pubspec.yaml b/packages/at_client/pubspec.yaml index 0dc42d46f..99ceb8ec2 100644 --- a/packages/at_client/pubspec.yaml +++ b/packages/at_client/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: at_utils: ^3.0.19 at_chops: ^2.2.0 at_lookup: ^3.0.49 - at_auth: ^2.0.8 + at_auth: ^2.0.10 at_persistence_spec: ^2.0.14 at_persistence_secondary_server: ^3.1.0 meta: ^1.8.0 diff --git a/packages/at_client/test/encryption_decryption_test.dart b/packages/at_client/test/encryption_decryption_test.dart index f91e12f79..58f6a4494 100644 --- a/packages/at_client/test/encryption_decryption_test.dart +++ b/packages/at_client/test/encryption_decryption_test.dart @@ -45,7 +45,7 @@ void main() { atEncryptionKeyPair.atPublicKey.publicKey); }); - tearDown(() { + tearDownAll(() { Directory('test/unit_test_storage').deleteSync(recursive: true); }); diff --git a/tests/at_functional_test/test/atclient_sharedkey_test.dart b/tests/at_functional_test/test/atclient_sharedkey_test.dart index e33f645d1..e8411d96a 100644 --- a/tests/at_functional_test/test/atclient_sharedkey_test.dart +++ b/tests/at_functional_test/test/atclient_sharedkey_test.dart @@ -30,6 +30,8 @@ void main() { var metadata = await atClient.getMeta(phoneKey); expect(metadata!.sharedKeyEnc, isNotEmpty); expect(metadata.pubKeyCS, isNotEmpty); + expect(metadata.pubKeyHash?.hash, isNotEmpty); + expect(metadata.pubKeyHash?.hashingAlgo, isNotEmpty); }); test('sharedKey and checksum metadata sync to local storage', () async { @@ -43,7 +45,7 @@ void main() { AtKeyEncryptionManager(atClient).get(phoneKey, currentAtSign); var encryptedValue = await encryptionService.encrypt(phoneKey, value); var result = await atClient.getRemoteSecondary()!.executeCommand( - 'update:sharedKeyEnc:${phoneKey.metadata.sharedKeyEnc}:pubKeyCS:${phoneKey.metadata.pubKeyCS}:${phoneKey.sharedWith}:${phoneKey.key}.$namespace$currentAtSign $encryptedValue\n', + 'update:sharedKeyEnc:${phoneKey.metadata.sharedKeyEnc}:pubKeyCS:${phoneKey.metadata.pubKeyCS}:pubKeyHash:${phoneKey.metadata.pubKeyHash?.hash}:hashingAlgo:${phoneKey.metadata.pubKeyHash?.hashingAlgo}:${phoneKey.sharedWith}:${phoneKey.key}.$namespace$currentAtSign $encryptedValue\n', auth: true); expect(result != null, true); await FunctionalTestSyncService.getInstance() @@ -51,5 +53,7 @@ void main() { var metadata = await atClient.getMeta(phoneKey); expect(metadata?.sharedKeyEnc, isNotEmpty); expect(metadata?.pubKeyCS, isNotEmpty); + expect(metadata?.pubKeyHash?.hash, isNotEmpty); + expect(metadata?.pubKeyHash?.hashingAlgo, isNotEmpty); }); } From edaf07cfed20577e22d4dbe91738faf1f7ee3772 Mon Sep 17 00:00:00 2001 From: Murali Date: Thu, 12 Dec 2024 17:41:06 +0530 Subject: [PATCH 09/21] fix: change at_lookup depedency override to at_commons --- packages/at_client/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/at_client/pubspec.yaml b/packages/at_client/pubspec.yaml index 9ae3a3223..cbe41b6bc 100644 --- a/packages/at_client/pubspec.yaml +++ b/packages/at_client/pubspec.yaml @@ -42,10 +42,10 @@ dependencies: version: ^3.0.2 dependency_overrides: - at_lookup: + at_commons: git: url: https://github.com/atsign-foundation/at_libraries.git - path: packages/at_lookup + path: packages/at_commons ref: atlookup_add_default_values_sync_builder dev_dependencies: From 15d68c505d72b714d5d4ef8d310a92107284591f Mon Sep 17 00:00:00 2001 From: Murali Date: Thu, 12 Dec 2024 17:47:17 +0530 Subject: [PATCH 10/21] fix: change dependency overrides from at_lookup to at_commons --- tests/at_end2end_test/pubspec.yaml | 4 ++-- tests/at_functional_test/pubspec.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/at_end2end_test/pubspec.yaml b/tests/at_end2end_test/pubspec.yaml index 6cf60107c..f69ac3364 100644 --- a/tests/at_end2end_test/pubspec.yaml +++ b/tests/at_end2end_test/pubspec.yaml @@ -15,10 +15,10 @@ dependencies: path: ../../packages/at_client dependency_overrides: - at_lookup: + at_commons: git: url: https://github.com/atsign-foundation/at_libraries.git - path: packages/at_lookup + path: packages/at_commons ref: atlookup_add_default_values_sync_builder dev_dependencies: diff --git a/tests/at_functional_test/pubspec.yaml b/tests/at_functional_test/pubspec.yaml index 4a2e06bdc..16d86861a 100644 --- a/tests/at_functional_test/pubspec.yaml +++ b/tests/at_functional_test/pubspec.yaml @@ -15,10 +15,10 @@ dependencies: at_lookup: ^3.0.49 dependency_overrides: - at_lookup: + at_commons: git: url: https://github.com/atsign-foundation/at_libraries.git - path: packages/at_lookup + path: packages/at_commons ref: atlookup_add_default_values_sync_builder dev_dependencies: From 02242b3360565fe16791fd162f2573939c1402ed Mon Sep 17 00:00:00 2001 From: Sitaram Kalluri Date: Thu, 12 Dec 2024 19:06:42 +0530 Subject: [PATCH 11/21] fix: Use random IVs in enrollment_setup.dart replacing legacy IVs --- tests/at_end2end_test/test/enrollment_setup.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/at_end2end_test/test/enrollment_setup.dart b/tests/at_end2end_test/test/enrollment_setup.dart index 666c14770..bc678b071 100644 --- a/tests/at_end2end_test/test/enrollment_setup.dart +++ b/tests/at_end2end_test/test/enrollment_setup.dart @@ -191,6 +191,7 @@ Future getDefaultEncryptionPrivateKey( var privateKeyCommand = 'keys:get:keyName:$enrollmentIdFromServer.${AtConstants.defaultEncryptionPrivateKey}.__manage$atSign'; String encryptionPrivateKeyFromServer; + String encryptionPrivateKeyIV; try { var getPrivateKeyResult = await atLookUp.executeCommand('$privateKeyCommand\n', auth: true); @@ -200,13 +201,15 @@ Future getDefaultEncryptionPrivateKey( getPrivateKeyResult = getPrivateKeyResult.replaceFirst('data:', ''); var privateKeyResultJson = jsonDecode(getPrivateKeyResult); encryptionPrivateKeyFromServer = privateKeyResultJson['value']; + encryptionPrivateKeyIV = privateKeyResultJson['iv']; } on Exception catch (e) { throw AtEnrollmentException( 'Exception while getting encrypted private key/self key from server: $e'); } AtEncryptionResult? atEncryptionResult = atLookUp.atChops?.decryptString( encryptionPrivateKeyFromServer, EncryptionKeyType.aes256, - keyName: 'apkamSymmetricKey', iv: AtChopsUtil.generateIVLegacy()); + keyName: 'apkamSymmetricKey', + iv: AtChopsUtil.generateIVFromBase64String(encryptionPrivateKeyIV)); return atEncryptionResult?.result; } @@ -218,6 +221,7 @@ Future getDefaultSelfEncryptionKey( var selfEncryptionKeyCommand = 'keys:get:keyName:$enrollmentIdFromServer.${AtConstants.defaultSelfEncryptionKey}.__manage$atSign'; String selfEncryptionKeyFromServer; + String selfEncryptionKeyIV; try { String? encryptedSelfEncryptionKey = await atLookUp .executeCommand('$selfEncryptionKeyCommand\n', auth: true); @@ -230,12 +234,14 @@ Future getDefaultSelfEncryptionKey( encryptedSelfEncryptionKey.replaceFirst('data:', ''); var selfEncryptionKeyResultJson = jsonDecode(encryptedSelfEncryptionKey); selfEncryptionKeyFromServer = selfEncryptionKeyResultJson['value']; + selfEncryptionKeyIV = selfEncryptionKeyResultJson['iv']; } on Exception catch (e) { throw AtEnrollmentException( 'Exception while getting encrypted private key/self key from server: $e'); } AtEncryptionResult? atEncryptionResult = atLookUp.atChops?.decryptString( selfEncryptionKeyFromServer, EncryptionKeyType.aes256, - keyName: 'apkamSymmetricKey', iv: AtChopsUtil.generateIVLegacy()); + keyName: 'apkamSymmetricKey', + iv: AtChopsUtil.generateIVFromBase64String(selfEncryptionKeyIV)); return atEncryptionResult?.result; } From 0daafbcb358260a011a361bd70489af47f083b3d Mon Sep 17 00:00:00 2001 From: Sitaram Kalluri Date: Thu, 12 Dec 2024 19:38:47 +0530 Subject: [PATCH 12/21] fix: Replace legacy IVs with random IVs for encrypting "defaultEncryptionPrivateKey" and "selfEncryptionKey" in APKAM flow --- tests/at_end2end_test/test/enrollment_setup.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/at_end2end_test/test/enrollment_setup.dart b/tests/at_end2end_test/test/enrollment_setup.dart index 666c14770..bc678b071 100644 --- a/tests/at_end2end_test/test/enrollment_setup.dart +++ b/tests/at_end2end_test/test/enrollment_setup.dart @@ -191,6 +191,7 @@ Future getDefaultEncryptionPrivateKey( var privateKeyCommand = 'keys:get:keyName:$enrollmentIdFromServer.${AtConstants.defaultEncryptionPrivateKey}.__manage$atSign'; String encryptionPrivateKeyFromServer; + String encryptionPrivateKeyIV; try { var getPrivateKeyResult = await atLookUp.executeCommand('$privateKeyCommand\n', auth: true); @@ -200,13 +201,15 @@ Future getDefaultEncryptionPrivateKey( getPrivateKeyResult = getPrivateKeyResult.replaceFirst('data:', ''); var privateKeyResultJson = jsonDecode(getPrivateKeyResult); encryptionPrivateKeyFromServer = privateKeyResultJson['value']; + encryptionPrivateKeyIV = privateKeyResultJson['iv']; } on Exception catch (e) { throw AtEnrollmentException( 'Exception while getting encrypted private key/self key from server: $e'); } AtEncryptionResult? atEncryptionResult = atLookUp.atChops?.decryptString( encryptionPrivateKeyFromServer, EncryptionKeyType.aes256, - keyName: 'apkamSymmetricKey', iv: AtChopsUtil.generateIVLegacy()); + keyName: 'apkamSymmetricKey', + iv: AtChopsUtil.generateIVFromBase64String(encryptionPrivateKeyIV)); return atEncryptionResult?.result; } @@ -218,6 +221,7 @@ Future getDefaultSelfEncryptionKey( var selfEncryptionKeyCommand = 'keys:get:keyName:$enrollmentIdFromServer.${AtConstants.defaultSelfEncryptionKey}.__manage$atSign'; String selfEncryptionKeyFromServer; + String selfEncryptionKeyIV; try { String? encryptedSelfEncryptionKey = await atLookUp .executeCommand('$selfEncryptionKeyCommand\n', auth: true); @@ -230,12 +234,14 @@ Future getDefaultSelfEncryptionKey( encryptedSelfEncryptionKey.replaceFirst('data:', ''); var selfEncryptionKeyResultJson = jsonDecode(encryptedSelfEncryptionKey); selfEncryptionKeyFromServer = selfEncryptionKeyResultJson['value']; + selfEncryptionKeyIV = selfEncryptionKeyResultJson['iv']; } on Exception catch (e) { throw AtEnrollmentException( 'Exception while getting encrypted private key/self key from server: $e'); } AtEncryptionResult? atEncryptionResult = atLookUp.atChops?.decryptString( selfEncryptionKeyFromServer, EncryptionKeyType.aes256, - keyName: 'apkamSymmetricKey', iv: AtChopsUtil.generateIVLegacy()); + keyName: 'apkamSymmetricKey', + iv: AtChopsUtil.generateIVFromBase64String(selfEncryptionKeyIV)); return atEncryptionResult?.result; } From b7f5ec62614bc519d1072aa60128ca87082a043c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 00:25:00 +0000 Subject: [PATCH 13/21] build(deps): bump the github-actions group with 2 updates Bumps the github-actions group with 2 updates: [actions/setup-go](https://github.com/actions/setup-go) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/setup-go` from 5.1.0 to 5.2.0 - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed...3041bf56c941b39c61721a86cd11f3bb1338122a) Updates `github/codeql-action` from 3.27.7 to 3.27.9 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/babb554ede22fd5605947329c4d04d8e7a0b8155...df409f7d9260372bd5f19e5b04e83cb3c43714ae) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/at_client_sdk.yaml | 2 +- .github/workflows/scorecards.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/at_client_sdk.yaml b/.github/workflows/at_client_sdk.yaml index 2629343d0..0facd5ff8 100644 --- a/.github/workflows/at_client_sdk.yaml +++ b/.github/workflows/at_client_sdk.yaml @@ -30,7 +30,7 @@ jobs: with: sdk: ${{ matrix.dart-channel}} - - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + - uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 with: go-version: 'stable' cache-dependency-path: tools/osv-scanner/go.sum diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index b9e391883..707003c17 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 + uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 with: sarif_file: results.sarif From 0400a93ae6121784f6f473faf3f5e2ab6daaa2d7 Mon Sep 17 00:00:00 2001 From: Murali Date: Fri, 13 Dec 2024 11:32:29 +0530 Subject: [PATCH 14/21] fix: revoke removing limit param in sync service impl --- packages/at_client/lib/src/preference/at_client_preference.dart | 2 +- packages/at_client/lib/src/service/sync_service_impl.dart | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/at_client/lib/src/preference/at_client_preference.dart b/packages/at_client/lib/src/preference/at_client_preference.dart index 5eeaa8a95..e37b59912 100644 --- a/packages/at_client/lib/src/preference/at_client_preference.dart +++ b/packages/at_client/lib/src/preference/at_client_preference.dart @@ -59,7 +59,7 @@ class AtClientPreference { int syncBatchSize = 5; /// The number of keys to pull from cloud secondary to local secondary in a single call. - int syncPageLimit = 10; + int syncPageLimit = 25; // Default chunk size for file encryption and decryption int fileEncryptionChunkSize = 4096; diff --git a/packages/at_client/lib/src/service/sync_service_impl.dart b/packages/at_client/lib/src/service/sync_service_impl.dart index 36c08256b..240fd865c 100644 --- a/packages/at_client/lib/src/service/sync_service_impl.dart +++ b/packages/at_client/lib/src/service/sync_service_impl.dart @@ -542,6 +542,7 @@ class SyncServiceImpl implements SyncService, AtSignChangeListener { // Sync verb syntax has to be changed before removing these deprecations var syncBuilder = SyncVerbBuilder() ..commitId = lastReceivedServerCommitId + ..limit = _atClient.getPreferences()!.syncPageLimit ..regex = _atClient.getPreferences()!.syncRegex; _logger.finer(_logger.getLogMessageWithClientParticulars( _atClient.getPreferences()!.atClientParticulars, From f07888fa459861e66d7c24b084be4b3b39509fb9 Mon Sep 17 00:00:00 2001 From: Murali Date: Fri, 13 Dec 2024 11:35:28 +0530 Subject: [PATCH 15/21] fix: add changelog --- packages/at_client/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/at_client/CHANGELOG.md b/packages/at_client/CHANGELOG.md index 101ebc2c3..2aaec3ca5 100644 --- a/packages/at_client/CHANGELOG.md +++ b/packages/at_client/CHANGELOG.md @@ -1,5 +1,6 @@ # 3.3.1 - fix: isInSync bug fix for apkam connection +- fix: remove deprecated isPaginated param from SyncVerbBuilder in SyncServiceImpl ## 3.3.0 - feat: add the AtClientBindings mixin which was initially added to the noports_core package but has broader applicability. From 1d2a20d822db73073c09de8c6efa425ce8004d9f Mon Sep 17 00:00:00 2001 From: "library-action[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 15 Dec 2024 12:52:53 +0000 Subject: [PATCH 16/21] chore: Update cert in testdata --- .../at_functional_test/test/testData/cert.pem | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/at_functional_test/test/testData/cert.pem b/tests/at_functional_test/test/testData/cert.pem index 977346257..0804758f7 100644 --- a/tests/at_functional_test/test/testData/cert.pem +++ b/tests/at_functional_test/test/testData/cert.pem @@ -1,29 +1,29 @@ -----BEGIN CERTIFICATE----- -MIIE9DCCA9ygAwIBAgISBFBi+UyQHPsb/1Vc2QCE5PX/MA0GCSqGSIb3DQEBCwUA +MIIE9DCCA9ygAwIBAgISBELcApaZJtnZgeL+C/pC47SHMA0GCSqGSIb3DQEBCwUA MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD -EwNSMTEwHhcNMjQxMTE1MDY0MjI1WhcNMjUwMjEzMDY0MjI0WjAdMRswGQYDVQQD +EwNSMTEwHhcNMjQxMjE1MDY0MjIyWhcNMjUwMzE1MDY0MjIxWjAdMRswGQYDVQQD ExJ2aXAudmUuYXRzaWduLnpvbmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC1lHvQhYRRAyRLYy6HhDhB9AuhS7Cj22+AUB2vTQa/ANgYM5on6sfGTH3b -1g59cGccgabd2449l46tX/w6D33yYctlaCv55j0lA+XMAyFtxe1cvGSPTqX5rUwC -JDFORz7q+JcHKfNW60Lt1bWSwF/z+ojSSP4zlJj1Z5MP5POAEsYjWmoZEichrqq4 -XAl0JJUmaa9K9EK7Biekx3fUIN0gcviz6oiIiUXUWQbiX/WJsqEIFWvbbYh4lNG8 -3LMY/yA7iA6f+w8k65tdLpnL/KUueomOZll2LBqoiYW9A+KNraSzh8+j3EGkY5e8 -OZqNGJXcKVq0oje0LJ4vacWTi77pAgMBAAGjggIWMIICEjAOBgNVHQ8BAf8EBAMC +AoIBAQC6L8igR+Q3HtmI95PTifuFGVGS6ri6NjSl3GnPNc27GKOLJ9QKBvrBosFG +F3Hg37D4mbbB4aZTof+pvXsBur5sqLSGhA9lUqoIixTew/HFow4hBGQz7e+RtUdC +UqxdecBil6twpM5x1I2F79hOFlEiXjtikEiabiEcZfF59mJliyGf4X+e7BOFoJyE +sE6/RHax9QKkKV5o2aTnktzmYaePAi7W7GaV67ArRKIB373/12QSrTprb30lBSIp +LNvnbXWOsP+JHGtCfaYc1XokOLeGoNYViScMHaqNdzxbW68olAvobUN6MpmLfAct +B0Mw0gObZ9cUq43OMgQ71TiIQj4ZAgMBAAGjggIWMIICEjAOBgNVHQ8BAf8EBAMC BaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAw -HQYDVR0OBBYEFAMc86RjrDksTVHT+isdAg4PkB4MMB8GA1UdIwQYMBaAFMXPRqTq +HQYDVR0OBBYEFLBI5eHHrmVB5PHFRfW5yxPlnQwCMB8GA1UdIwQYMBaAFMXPRqTq 9MPAemyVxC2wXpIvJuO5MFcGCCsGAQUFBwEBBEswSTAiBggrBgEFBQcwAYYWaHR0 cDovL3IxMS5vLmxlbmNyLm9yZzAjBggrBgEFBQcwAoYXaHR0cDovL3IxMS5pLmxl bmNyLm9yZy8wHQYDVR0RBBYwFIISdmlwLnZlLmF0c2lnbi56b25lMBMGA1UdIAQM -MAowCAYGZ4EMAQIBMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYAE0rfGrWYQgl4 -DG/vTHqRpBa3I0nOWFdq367ap8Kr4CIAAAGTLsSVqwAABAMARzBFAiA9Ht0mWsrn -s+MYacCMLckbYIQwDZyhjOcvOIBXtSL0EwIhANwP1JcHH+Q1YM3xQjoBNKVxlW/o -92R4DJ/cyMBId1AZAHYAzxFW7tUufK/zh1vZaS6b6RpxZ0qwF+ysAdJbd87MOwgA -AAGTLsSc+gAABAMARzBFAiEApRZLzvF4G6KBQCUBx1A2HIXRlxMYEMn3vlyvsaS1 -ON0CIEXIKRTNae05gqyEIxxTx52s3BFRNYhs75b1vRL4/SWlMA0GCSqGSIb3DQEB -CwUAA4IBAQBEUPPpnAuA3OzxDn1WqPla26MO5J43xR+naxB1R51wKGgx9Gb+YUDZ -w2TBzwYIfrne6++6o21d8Xd9d/OzcnOphW9zKpObYLrY5EkSRrR9j7zpJyAdk219 -3NQ5BgxYthzlnQUPFY1lYYPQ2wGa7oZzdWEkvLbQn7EL/tC71BR4WjuMsa4Fd3rf -7W7G+51VsOiRSNhjcU9wjsP4BFCiyg8QAJ4CpkOdUOf7vlYrtJxroJYF9/P1Az/C -aSKEuzHbe7uEPYTvgKa5tz89/nM5afxhheVlxNE+6HKsB6LHqMRdP0VElL7bc6nX -u9qdIVKAbK+1cN15HYJ5jG0pXrOsBTbr +MAowCAYGZ4EMAQIBMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYAzPsPaoVxCWX+ +lZtTzumyfCLphVwNl422qX5UwP5MDbAAAAGTyUNR5wAABAMARzBFAiEA+qSCaeFM +SdWNtOBMFlHJqd8KuaXE03TW0lkAwXmilvYCIGsvyis+wdeiI6U/0fXO3aSfQLw1 +BVUuEdbQzTxrAvN1AHYAE0rfGrWYQgl4DG/vTHqRpBa3I0nOWFdq367ap8Kr4CIA +AAGTyUNSnAAABAMARzBFAiBtvdHsFEXPsU2E2SgLoZhhuOK8K3tDRuBtQ3PqZJMq +ogIhAI8jQXRm3dg0WRvPoxnp72gcg0yKRHvAH6L/9qwo067JMA0GCSqGSIb3DQEB +CwUAA4IBAQBrbAzdOo8akOc1s0jevoTFyn11cPSkkjnic0x93tcuoGkbs5oqJpVh +PuLDSXOy+xJ/TXUIDGFbCLA/SWC7/b1vViqwasEBGohJJ7ZM/27j/fIL+6Nc/u7Y +f37L5J32WcGRKKoxxA9MoaKqn5GVZTW8UIy/K+llfRaSptQCloyOPcq0h9uTyFci +sIDhVb5qj9hMmgkcz0BfZZHqH+45vtnFV0v+jeLGRkijcxN2LxpXIHCFTDivl0tS +/o2XXHuXZCkZ6q1eeDF7kC6fccXLOJnsbiNwmwiEQb/0WeX/lDQzA31sv4yOVfZr +Ne1IRWUsZfbo8jKSnnUOCwCKgOoNq81z -----END CERTIFICATE----- From d870f6774360d48c355c380864d4f4b5f660a267 Mon Sep 17 00:00:00 2001 From: Murali Date: Tue, 17 Dec 2024 19:28:04 +0530 Subject: [PATCH 17/21] fix: remove at_commons dependency overrides --- packages/at_client/pubspec.yaml | 9 +-------- tests/at_end2end_test/pubspec.yaml | 7 ------- tests/at_functional_test/pubspec.yaml | 7 ------- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/packages/at_client/pubspec.yaml b/packages/at_client/pubspec.yaml index cbe41b6bc..ac0a672c5 100644 --- a/packages/at_client/pubspec.yaml +++ b/packages/at_client/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: async: ^2.9.0 at_utf7: ^1.0.0 at_base2e15: ^1.0.0 - at_commons: ^5.0.0 + at_commons: ^5.1.2 at_utils: ^3.0.19 at_chops: ^2.0.1 at_lookup: ^3.0.49 @@ -41,13 +41,6 @@ dependencies: meta: ^1.8.0 version: ^3.0.2 -dependency_overrides: - at_commons: - git: - url: https://github.com/atsign-foundation/at_libraries.git - path: packages/at_commons - ref: atlookup_add_default_values_sync_builder - dev_dependencies: lints: ^4.0.0 test: ^1.21.4 diff --git a/tests/at_end2end_test/pubspec.yaml b/tests/at_end2end_test/pubspec.yaml index f69ac3364..fd1a4f012 100644 --- a/tests/at_end2end_test/pubspec.yaml +++ b/tests/at_end2end_test/pubspec.yaml @@ -14,13 +14,6 @@ dependencies: at_client: path: ../../packages/at_client -dependency_overrides: - at_commons: - git: - url: https://github.com/atsign-foundation/at_libraries.git - path: packages/at_commons - ref: atlookup_add_default_values_sync_builder - dev_dependencies: test: ^1.24.3 lints: ^2.0.0 diff --git a/tests/at_functional_test/pubspec.yaml b/tests/at_functional_test/pubspec.yaml index 16d86861a..bd4a441a4 100644 --- a/tests/at_functional_test/pubspec.yaml +++ b/tests/at_functional_test/pubspec.yaml @@ -14,13 +14,6 @@ dependencies: at_auth: ^2.0.7 at_lookup: ^3.0.49 -dependency_overrides: - at_commons: - git: - url: https://github.com/atsign-foundation/at_libraries.git - path: packages/at_commons - ref: atlookup_add_default_values_sync_builder - dev_dependencies: test: ^1.24.3 lints: ^2.0.0 From e4d340764d328f4095734aa575550742fafebc82 Mon Sep 17 00:00:00 2001 From: Murali Date: Tue, 17 Dec 2024 19:31:19 +0530 Subject: [PATCH 18/21] fix: changelog --- packages/at_client/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/at_client/CHANGELOG.md b/packages/at_client/CHANGELOG.md index 2aaec3ca5..fcdff225f 100644 --- a/packages/at_client/CHANGELOG.md +++ b/packages/at_client/CHANGELOG.md @@ -1,6 +1,8 @@ # 3.3.1 - fix: isInSync bug fix for apkam connection - fix: remove deprecated isPaginated param from SyncVerbBuilder in SyncServiceImpl +- build[deps]: Upgraded dependencies for the following packages: + - at_commons to v5.1.2 ## 3.3.0 - feat: add the AtClientBindings mixin which was initially added to the noports_core package but has broader applicability. From 44aade2926ee4a0aabd834be797065f90ced914a Mon Sep 17 00:00:00 2001 From: Sitaram Kalluri Date: Tue, 17 Dec 2024 21:14:56 +0530 Subject: [PATCH 19/21] fix: In at_notification.dart check for "publicKeyHash" for null check --- packages/at_client/lib/src/response/at_notification.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/at_client/lib/src/response/at_notification.dart b/packages/at_client/lib/src/response/at_notification.dart index 9e14df2d2..0e1948088 100644 --- a/packages/at_client/lib/src/response/at_notification.dart +++ b/packages/at_client/lib/src/response/at_notification.dart @@ -38,8 +38,8 @@ class AtNotification { metadata.sharedKeyEnc = json['metadata'][AtConstants.sharedKeyEncrypted]; // AtContants.sharedWithPublicKeyHash will be sent by the server starting v3.0.52 // Notifications received from Secondary server before 3.0.52 does not contain - // AtConstants.sharedWithPublicKeyHash. Therefore, check for null String. - if (json['metadata'][AtConstants.sharedWithPublicKeyHash] != "null") { + // AtConstants.sharedWithPublicKeyHash. Therefore, check for null. + if (json['metadata'][AtConstants.sharedWithPublicKeyHash] != null) { var publicKeyHash = jsonDecode(json['metadata'][AtConstants.sharedWithPublicKeyHash]); metadata.pubKeyHash = From 086721a20d6bcee94b3911e2b0644d257a9568ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 00:21:07 +0000 Subject: [PATCH 20/21] build(deps): bump actions/upload-artifact in the github-actions group Bumps the github-actions group with 1 update: [actions/upload-artifact](https://github.com/actions/upload-artifact). Updates `actions/upload-artifact` from 4.4.3 to 4.5.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882...6f51ac03b9356f520e9adb1b1b7802705f340c2b) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 707003c17..9bf5d8c89 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: name: SARIF file path: results.sarif From 6cda881541d3d9209e0c6540dfaa866aa08a52a3 Mon Sep 17 00:00:00 2001 From: Sitaram Kalluri Date: Wed, 18 Dec 2024 20:01:18 +0530 Subject: [PATCH 21/21] chore: at_client Update CHANGELOG.md --- packages/at_client/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/at_client/CHANGELOG.md b/packages/at_client/CHANGELOG.md index fcdff225f..5efe7beb6 100644 --- a/packages/at_client/CHANGELOG.md +++ b/packages/at_client/CHANGELOG.md @@ -3,6 +3,7 @@ - fix: remove deprecated isPaginated param from SyncVerbBuilder in SyncServiceImpl - build[deps]: Upgraded dependencies for the following packages: - at_commons to v5.1.2 +- feat: Introduce "publicKeyHash" which uses SHA hashing to verify change in the encryption public key ## 3.3.0 - feat: add the AtClientBindings mixin which was initially added to the noports_core package but has broader applicability.