From d9523b2516d8a9a7008bfaca3bd231732bdf00a0 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Sun, 30 Apr 2023 04:02:20 +0530 Subject: [PATCH 01/24] feat: introduce isSecondaryReset() in AtClientSpec --- packages/at_client/lib/src/client/at_client_spec.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/at_client/lib/src/client/at_client_spec.dart b/packages/at_client/lib/src/client/at_client_spec.dart index 02f865e66..232c57be7 100644 --- a/packages/at_client/lib/src/client/at_client_spec.dart +++ b/packages/at_client/lib/src/client/at_client_spec.dart @@ -518,6 +518,8 @@ abstract class AtClient { Function streamCompletionCallBack, Function streamReceiveCallBack); + Future isSecondaryReset(); + /// Uploads list of [files] to filebin and shares the file download url with [sharedWithAtSigns] /// returns map containing key of each sharedWithAtSign and value of [FileTransferObject] @Deprecated( From fc7306cb63f7b5f5946ad59c75378e70d2722073 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Sun, 30 Apr 2023 04:02:59 +0530 Subject: [PATCH 02/24] feat: implement isSecondaryReset() and deleteLocalSecondaryStorageWithConsent() --- .../lib/src/client/at_client_impl.dart | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index f9d125554..09e88550b 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -868,6 +868,111 @@ class AtClientImpl implements AtClient, AtSignChangeListener { } } + @override + Future isSecondaryReset() async { + _logger.finer('Performing Remote Secondary reset check'); + var localPublicKey = + await getLocalSecondary()?.getEncryptionPublicKey(getCurrentAtSign()!); + + PLookupVerbBuilder lookupBuilder = PLookupVerbBuilder() + ..atKey = 'publickey' //AT_ENCRYPTION_PUBLIC_KEY + ..sharedBy = getCurrentAtSign(); + var remotePublicKey = + await getRemoteSecondary()?.executeVerb(lookupBuilder); + // secondary response is in format 'data:publickey'. Removing 'data:' from response + remotePublicKey = remotePublicKey?.replaceFirst('data:', ''); + + if (localPublicKey.isNull) { + _logger.info('Could not fetch EncryptionPublicKey from LocalSecondary.' + ' Unable to complete reset check'); + return; + } + + //TODO should there be a check for remote enc_key being null ? + + if (localPublicKey != remotePublicKey) { + _logger.info('EncryptionPublicKey on LocalSecondary: $localPublicKey'); + _logger.info('EncryptionPublicKey on RemoteSecondary: $remotePublicKey'); + _logger.shout( + 'AtEncryptionPublicKey on local secondary and remote secondary are different.' + '\nThis indicates remote secondary has been reset.' + '\nPlease delete localStorage and restart the client'); + _logger.info('To delete localSecondary,' + ' call AtClientImpl.deleteLocalSecondary() with user consent'); + throw AtResetException('Remote secondary has been reset'); + } + _logger.finest('Secondary is not reset. Status ok'); + } + + void deleteLocalSecondaryStorageWithConsent( + String commitLogDirectoryPath, String hiveStorageDirectoryPath, + {required bool userConsentToDeleteLocalSecondaryStorage}) { + _logger.shout( + 'Consent to delete LocalSecondary storage received: $userConsentToDeleteLocalSecondaryStorage'); + if (userConsentToDeleteLocalSecondaryStorage) { + _logger + .info('Deleting CommitLog local storage at: $commitLogDirectoryPath'); + _deleteLocalCommitLog(commitLogDirectoryPath); + _logger.info('Deleting hive local storage at: $hiveStorageDirectoryPath'); + _deleteLocalHiveStorage(hiveStorageDirectoryPath); + } + } + + void _deleteLocalCommitLog(String commitLogDirectoryPath) { + String fileName = + 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hive'; + String lockFileName = + 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.lock'; + + File commitLogFile = File('$commitLogDirectoryPath/$fileName'); + File lockFile = File('$commitLogDirectoryPath/$lockFileName'); + + if (commitLogFile.existsSync()) { + commitLogFile.deleteSync(); + lockFile.deleteSync(); + _logger.info('Successfully deleted commitLog storage'); + // Since recursive delete is true by default, If the directory is empty + // the directory will be deleted too + Directory(commitLogDirectoryPath).deleteSync(); + return; + } + throw AtClientException.message( + 'CommitLog storage not found at path: $commitLogFile.' + ' Please provide a valid CommitLog directory path'); + } + + void _deleteLocalHiveStorage(String hiveStorageDirectoryPath) { + String hashFileName = + '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hash'; + String hiveFileName = + '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hive'; + String hiveLockFileName = + '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.lock'; + + File hiveFile = File('$hiveStorageDirectoryPath/$hiveFileName'); + File hiveLockFile = File('$hiveStorageDirectoryPath/$hiveLockFileName'); + File hashFile = File('$hiveStorageDirectoryPath/$hashFileName'); + + if (hashFile.existsSync() && hiveFile.existsSync()) { + hashFile.deleteSync(); + hiveFile.deleteSync(); + hiveLockFile.deleteSync(); + _logger.info('Successfully deleted hive storage'); + // Since recursive delete is true by default, If the directory is empty + // the directory will be deleted too + Directory(hiveStorageDirectoryPath).deleteSync(); + } else { + if (!hiveFile.existsSync()) { + throw AtClientException.message( + 'hive file not found at path: $hiveFile.' + ' Please provide a valid hive storage directory path'); + } + throw AtClientException.message( + 'hive hash file not found at path: $hiveFile.' + ' Please provide a valid hive storage directory path'); + } + } + // TODO v4 - remove the follow methods in version 4 of at_client package @override From aec9bda008bf4903cd38ac245cab10863e10d454 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Sun, 30 Apr 2023 04:03:41 +0530 Subject: [PATCH 03/24] test: added tests for the new methods --- .../at_client/test/at_client_impl_test.dart | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/packages/at_client/test/at_client_impl_test.dart b/packages/at_client/test/at_client_impl_test.dart index e19543a0b..90a297e46 100644 --- a/packages/at_client/test/at_client_impl_test.dart +++ b/packages/at_client/test/at_client_impl_test.dart @@ -1,8 +1,11 @@ +import 'dart:io'; + import 'package:at_client/at_client.dart'; import 'package:at_client/src/compaction/at_commit_log_compaction.dart'; import 'package:at_client/src/service/notification_service_impl.dart'; import 'package:at_client/src/service/sync_service.dart'; import 'package:at_client/src/service/sync_service_impl.dart'; +import 'package:at_commons/at_builders.dart'; import 'package:at_persistence_secondary_server/at_persistence_secondary_server.dart'; import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; @@ -21,6 +24,10 @@ class MockAtCompactionJob extends Mock implements AtCompactionJob { } } +class MockRemoteSecondary extends Mock implements RemoteSecondary {} + +class MockSecondaryKeystore extends Mock implements SecondaryKeyStore {} + void main() { group('A group of at client impl create tests', () { final String atSign = '@alice'; @@ -251,4 +258,44 @@ void main() { expect(key.key, 'uppercase'); //key should be converted to lower case }); }); + + group('Group of tests verify client behaviour on remote secondary reset', () { + registerFallbackValue(MockRemoteSecondary()); + registerFallbackValue(LookupVerbBuilder()); + + RemoteSecondary mockRemoteSecondary = MockRemoteSecondary(); + SecondaryKeyStore mockKeystore = MockSecondaryKeystore(); + AtClient client; + + test('Verify isSecondaryReset() functionality - negative case', () async { + AtData responseObj = AtData()..data = 'incorrectLocalEncPublicKey'; + when(() => mockRemoteSecondary.executeVerb(any())).thenAnswer( + (invocation) => Future.value('data:incorrectRemoteEncPublicKey')); + when(() => mockKeystore.get(any())).thenAnswer( + (invocation) => Future.value(responseObj)); + + client = await AtClientImpl.create('@alice47', 'resetLocalTest', + AtClientPreference()..isLocalStoreRequired = true, + remoteSecondary: mockRemoteSecondary, + localSecondaryKeyStore: mockKeystore); + expect(client.isSecondaryReset(), + throwsA(predicate((dynamic e) => e is AtResetException))); + }); + + test('Verify isSecondaryReset() functionality - positive case', () async { + AtData responseObj = AtData()..data = 'correctEncPublicKey'; + when(() => mockRemoteSecondary.executeVerb(any())).thenAnswer( + (invocation) => Future.value('data:correctEncPublicKey')); + when(() => mockKeystore.get(any())).thenAnswer( + (invocation) => Future.value(responseObj)); + + client = await AtClientImpl.create('@alice47', 'resetLocalTest', + AtClientPreference()..isLocalStoreRequired = true, + remoteSecondary: mockRemoteSecondary, + localSecondaryKeyStore: mockKeystore); + // errorless execution test + // if the method call below triggers any errors/exceptions this test will fail + await client.isSecondaryReset(); + }); + }); } From 7daf11b65a39fd0b5e6ae44969a779a80afe75ad Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Mon, 15 May 2023 16:14:49 +0530 Subject: [PATCH 04/24] build: add dependency_ovveride for at_commons --- packages/at_client/lib/src/client/at_client_spec.dart | 2 ++ packages/at_client/pubspec.yaml | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/packages/at_client/lib/src/client/at_client_spec.dart b/packages/at_client/lib/src/client/at_client_spec.dart index 232c57be7..2d81d0e42 100644 --- a/packages/at_client/lib/src/client/at_client_spec.dart +++ b/packages/at_client/lib/src/client/at_client_spec.dart @@ -518,6 +518,8 @@ abstract class AtClient { Function streamCompletionCallBack, Function streamReceiveCallBack); + /// Performs a check to see if RemoteSecondary has been reset + /// throws [AtResetException] if the RemoteSecondary has been reset Future isSecondaryReset(); /// Uploads list of [files] to filebin and shares the file download url with [sharedWithAtSigns] diff --git a/packages/at_client/pubspec.yaml b/packages/at_client/pubspec.yaml index 3316acf9e..1af898f35 100644 --- a/packages/at_client/pubspec.yaml +++ b/packages/at_client/pubspec.yaml @@ -39,6 +39,14 @@ dependencies: at_chops: ^1.0.3 version: ^3.0.2 +dependency_overrides: + at_commons: + git: + url: https://github.com/atsign-foundation/at_tools + path: packages/at_commons + ref: at_reset_exception + + dev_dependencies: lints: ^2.0.0 test: ^1.21.4 From e24604a8bd39c733d39bf2d0ea53bb379ea0faae Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Mon, 10 Jul 2023 02:08:15 +0530 Subject: [PATCH 05/24] use lookup verb builder instead of PLookup verb builder --- packages/at_client/lib/src/client/at_client_impl.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index 2a35c5ed2..63d497305 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -887,7 +887,7 @@ class AtClientImpl implements AtClient, AtSignChangeListener { var localPublicKey = await getLocalSecondary()?.getEncryptionPublicKey(getCurrentAtSign()!); - PLookupVerbBuilder lookupBuilder = PLookupVerbBuilder() + LookupVerbBuilder lookupBuilder = LookupVerbBuilder() ..atKey = 'publickey' //AT_ENCRYPTION_PUBLIC_KEY ..sharedBy = getCurrentAtSign(); var remotePublicKey = From 518dc63a31545f34eab8838b3586df979645e750 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Mon, 10 Jul 2023 02:11:19 +0530 Subject: [PATCH 06/24] fix analyzer issues --- packages/at_client/lib/src/client/at_client_impl.dart | 2 +- packages/at_client/test/at_client_impl_test.dart | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index 63d497305..21a2c7850 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -914,7 +914,7 @@ class AtClientImpl implements AtClient, AtSignChangeListener { ' call AtClientImpl.deleteLocalSecondary() with user consent'); throw AtResetException('Remote secondary has been reset'); } - _logger.finest('Secondary is not reset. Status ok'); + _logger.finer('Secondary is not reset. Status ok'); } void deleteLocalSecondaryStorageWithConsent( diff --git a/packages/at_client/test/at_client_impl_test.dart b/packages/at_client/test/at_client_impl_test.dart index eb71a8d06..526fe3799 100644 --- a/packages/at_client/test/at_client_impl_test.dart +++ b/packages/at_client/test/at_client_impl_test.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:at_client/at_client.dart'; import 'package:at_client/src/compaction/at_commit_log_compaction.dart'; import 'package:at_client/src/service/notification_service_impl.dart'; From 1f35536e76015845fa44f88d97a32f4425128a33 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Mon, 10 Jul 2023 03:07:22 +0530 Subject: [PATCH 07/24] run dart formatter --- .../at_client/lib/src/client/at_client_impl.dart | 10 ++++++---- packages/at_client/test/at_client_impl_test.dart | 14 +++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index 21a2c7850..bfb096a56 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -890,7 +890,7 @@ class AtClientImpl implements AtClient, AtSignChangeListener { LookupVerbBuilder lookupBuilder = LookupVerbBuilder() ..atKey = 'publickey' //AT_ENCRYPTION_PUBLIC_KEY ..sharedBy = getCurrentAtSign(); - var remotePublicKey = + String? remotePublicKey = await getRemoteSecondary()?.executeVerb(lookupBuilder); // secondary response is in format 'data:publickey'. Removing 'data:' from response remotePublicKey = remotePublicKey?.replaceFirst('data:', ''); @@ -901,7 +901,7 @@ class AtClientImpl implements AtClient, AtSignChangeListener { return; } - //TODO should there be a check for remote enc_key being null ? + // TODO should there be a check for remote enc_key being null ? if (localPublicKey != remotePublicKey) { _logger.info('EncryptionPublicKey on LocalSecondary: $localPublicKey'); @@ -938,14 +938,16 @@ class AtClientImpl implements AtClient, AtSignChangeListener { 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.lock'; File commitLogFile = File('$commitLogDirectoryPath/$fileName'); + + // Todo: Do windows/mac have lock files ? File lockFile = File('$commitLogDirectoryPath/$lockFileName'); if (commitLogFile.existsSync()) { commitLogFile.deleteSync(); lockFile.deleteSync(); _logger.info('Successfully deleted commitLog storage'); - // Since recursive delete is true by default, If the directory is empty - // the directory will be deleted too + // Since recursive delete is false by default, If the directory is empty + // the directory will also be deleted Directory(commitLogDirectoryPath).deleteSync(); return; } diff --git a/packages/at_client/test/at_client_impl_test.dart b/packages/at_client/test/at_client_impl_test.dart index 526fe3799..54571ff5d 100644 --- a/packages/at_client/test/at_client_impl_test.dart +++ b/packages/at_client/test/at_client_impl_test.dart @@ -267,9 +267,9 @@ void main() { test('Verify isSecondaryReset() functionality - negative case', () async { AtData responseObj = AtData()..data = 'incorrectLocalEncPublicKey'; when(() => mockRemoteSecondary.executeVerb(any())).thenAnswer( - (invocation) => Future.value('data:incorrectRemoteEncPublicKey')); - when(() => mockKeystore.get(any())).thenAnswer( - (invocation) => Future.value(responseObj)); + (invocation) => Future.value('data:incorrectRemoteEncPublicKey')); + when(() => mockKeystore.get(any())) + .thenAnswer((invocation) => Future.value(responseObj)); client = await AtClientImpl.create('@alice47', 'resetLocalTest', AtClientPreference()..isLocalStoreRequired = true, @@ -281,10 +281,10 @@ void main() { test('Verify isSecondaryReset() functionality - positive case', () async { AtData responseObj = AtData()..data = 'correctEncPublicKey'; - when(() => mockRemoteSecondary.executeVerb(any())).thenAnswer( - (invocation) => Future.value('data:correctEncPublicKey')); - when(() => mockKeystore.get(any())).thenAnswer( - (invocation) => Future.value(responseObj)); + when(() => mockRemoteSecondary.executeVerb(any())) + .thenAnswer((invocation) => Future.value('data:correctEncPublicKey')); + when(() => mockKeystore.get(any())) + .thenAnswer((invocation) => Future.value(responseObj)); client = await AtClientImpl.create('@alice47', 'resetLocalTest', AtClientPreference()..isLocalStoreRequired = true, From 005c6e875559f35fbc9f9ca6bcc42583d05c6058 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Mon, 10 Jul 2023 03:23:37 +0530 Subject: [PATCH 08/24] build: introduce at_commons dependency overrides for tests --- packages/at_client/pubspec.yaml | 2 +- tests/at_end2end_test/pubspec.yaml | 7 +++++++ tests/at_functional_test/pubspec.yaml | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/at_client/pubspec.yaml b/packages/at_client/pubspec.yaml index 4fac96ac4..344ad9d4d 100644 --- a/packages/at_client/pubspec.yaml +++ b/packages/at_client/pubspec.yaml @@ -42,7 +42,7 @@ dependencies: dependency_overrides: at_commons: git: - url: https://github.com/atsign-foundation/at_tools + url: https://github.com/atsign-foundation/at_libraries path: packages/at_commons ref: at_reset_exception diff --git a/tests/at_end2end_test/pubspec.yaml b/tests/at_end2end_test/pubspec.yaml index fc1723877..174231632 100644 --- a/tests/at_end2end_test/pubspec.yaml +++ b/tests/at_end2end_test/pubspec.yaml @@ -12,6 +12,13 @@ dependencies: at_client: path: ../../packages/at_client +dependency_overrides: + at_commons: + git: + url: https://github.com/atsign-foundation/at_libraries + path: packages/at_commons + ref: at_reset_exception + dev_dependencies: pedantic: ^1.11.1 test: ^1.21.4 diff --git a/tests/at_functional_test/pubspec.yaml b/tests/at_functional_test/pubspec.yaml index 8107f5798..733cece7e 100644 --- a/tests/at_functional_test/pubspec.yaml +++ b/tests/at_functional_test/pubspec.yaml @@ -11,6 +11,13 @@ dependencies: at_client: path: ../../packages/at_client +dependency_overrides: + at_commons: + git: + url: https://github.com/atsign-foundation/at_libraries + path: packages/at_commons + ref: at_reset_exception + dev_dependencies: test: ^1.24.3 lints: ^2.0.0 From 191dfc07c7249699dd6d128bbf6774a4b3753e4f Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Wed, 19 Jul 2023 12:33:15 +0530 Subject: [PATCH 09/24] refactor: merge methods _deleteHiveStorage() and _deleteCommitLogStorage --- .../lib/src/client/at_client_impl.dart | 83 ++++++++++--------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index bfb096a56..17ebec9a8 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -884,9 +884,10 @@ class AtClientImpl implements AtClient, AtSignChangeListener { @override Future isSecondaryReset() async { _logger.finer('Performing Remote Secondary reset check'); + // Fetch EncryptionPublicKey from LocalSecondary var localPublicKey = await getLocalSecondary()?.getEncryptionPublicKey(getCurrentAtSign()!); - + // Fetch EncryptionPublicKey from RemoteSecondary LookupVerbBuilder lookupBuilder = LookupVerbBuilder() ..atKey = 'publickey' //AT_ENCRYPTION_PUBLIC_KEY ..sharedBy = getCurrentAtSign(); @@ -908,55 +909,56 @@ class AtClientImpl implements AtClient, AtSignChangeListener { _logger.info('EncryptionPublicKey on RemoteSecondary: $remotePublicKey'); _logger.shout( 'AtEncryptionPublicKey on local secondary and remote secondary are different.' - '\nThis indicates remote secondary has been reset.' - '\nPlease delete localStorage and restart the client'); - _logger.info('To delete localSecondary,' - ' call AtClientImpl.deleteLocalSecondary() with user consent'); + 'This indicates remote secondary has been reset.' + 'Please delete localStorage and restart the client'); + _logger.info('To delete localSecondary, call ' + 'AtClientImpl.deleteLocalSecondaryStorageWithConsent() with user consent'); throw AtResetException('Remote secondary has been reset'); } - _logger.finer('Secondary is not reset. Status ok'); + _logger.finer('Remote Secondary is NOT reset. Status ok'); } void deleteLocalSecondaryStorageWithConsent( String commitLogDirectoryPath, String hiveStorageDirectoryPath, - {required bool userConsentToDeleteLocalSecondaryStorage}) { + {required bool userConsentToDeleteLocalStorage}) { _logger.shout( - 'Consent to delete LocalSecondary storage received: $userConsentToDeleteLocalSecondaryStorage'); - if (userConsentToDeleteLocalSecondaryStorage) { - _logger - .info('Deleting CommitLog local storage at: $commitLogDirectoryPath'); - _deleteLocalCommitLog(commitLogDirectoryPath); - _logger.info('Deleting hive local storage at: $hiveStorageDirectoryPath'); - _deleteLocalHiveStorage(hiveStorageDirectoryPath); + 'Consent to delete LocalSecondary storage received: $userConsentToDeleteLocalStorage'); + if (!userConsentToDeleteLocalStorage) { + throw AtClientException.message( + 'User consent not provided. Unable to delete local storage without consent'); } - } - - void _deleteLocalCommitLog(String commitLogDirectoryPath) { - String fileName = + // Deleting commit log storage + _logger + .info('Deleting CommitLog local storage at: $commitLogDirectoryPath'); + String commitLogFileName = 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hive'; - String lockFileName = + String commitLogLockFileName = 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.lock'; - File commitLogFile = File('$commitLogDirectoryPath/$fileName'); + File commitLogFile = File('$commitLogDirectoryPath/$commitLogFileName'); // Todo: Do windows/mac have lock files ? - File lockFile = File('$commitLogDirectoryPath/$lockFileName'); + File lockFile = File('$commitLogDirectoryPath/$commitLogLockFileName'); - if (commitLogFile.existsSync()) { + if (!commitLogFile.existsSync()) { + throw AtClientException.message( + 'CommitLog storage not found at path: $commitLogFile.' + ' Please provide a valid CommitLog directory path'); + } + try { commitLogFile.deleteSync(); lockFile.deleteSync(); - _logger.info('Successfully deleted commitLog storage'); // Since recursive delete is false by default, If the directory is empty // the directory will also be deleted Directory(commitLogDirectoryPath).deleteSync(); - return; + _logger.info('Successfully deleted commitLog storage'); + } on Exception catch (e) { + _logger.finer('Unable to delete CommitLog storage | Cause: $e'); + throw AtIOException(e.toString()); } - throw AtClientException.message( - 'CommitLog storage not found at path: $commitLogFile.' - ' Please provide a valid CommitLog directory path'); - } - void _deleteLocalHiveStorage(String hiveStorageDirectoryPath) { + // Deleting hive storage + _logger.info('Deleting hive local storage at: $hiveStorageDirectoryPath'); String hashFileName = '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hash'; String hiveFileName = @@ -968,15 +970,7 @@ class AtClientImpl implements AtClient, AtSignChangeListener { File hiveLockFile = File('$hiveStorageDirectoryPath/$hiveLockFileName'); File hashFile = File('$hiveStorageDirectoryPath/$hashFileName'); - if (hashFile.existsSync() && hiveFile.existsSync()) { - hashFile.deleteSync(); - hiveFile.deleteSync(); - hiveLockFile.deleteSync(); - _logger.info('Successfully deleted hive storage'); - // Since recursive delete is true by default, If the directory is empty - // the directory will be deleted too - Directory(hiveStorageDirectoryPath).deleteSync(); - } else { + if (!(hashFile.existsSync() && hiveFile.existsSync())) { if (!hiveFile.existsSync()) { throw AtClientException.message( 'hive file not found at path: $hiveFile.' @@ -986,10 +980,21 @@ class AtClientImpl implements AtClient, AtSignChangeListener { 'hive hash file not found at path: $hiveFile.' ' Please provide a valid hive storage directory path'); } + try { + hashFile.deleteSync(); + hiveFile.deleteSync(); + hiveLockFile.deleteSync(); + // Since recursive delete is true by default, only if the directory is + // empty the directory will be deleted too + Directory(hiveStorageDirectoryPath).deleteSync(); + _logger.info('Successfully deleted hive storage'); + } on Exception catch (e) { + _logger.finer('Unable to delete hive storage | Cause: $e'); + throw AtIOException(e.toString()); + } } // TODO v4 - remove the follow methods in version 4 of at_client package - @override @Deprecated("Use AtClient.syncService") SyncManager? getSyncManager() { From bf92190a023eb83447a4c3af7722e1de2ba6b3b6 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Wed, 19 Jul 2023 20:42:27 +0530 Subject: [PATCH 10/24] refactor: isSecondaryReset() now returns Future --- packages/at_client/lib/src/client/at_client_impl.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index 17ebec9a8..525cfa930 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -882,7 +882,7 @@ class AtClientImpl implements AtClient, AtSignChangeListener { } @override - Future isSecondaryReset() async { + Future isSecondaryReset() async { _logger.finer('Performing Remote Secondary reset check'); // Fetch EncryptionPublicKey from LocalSecondary var localPublicKey = @@ -899,7 +899,7 @@ class AtClientImpl implements AtClient, AtSignChangeListener { if (localPublicKey.isNull) { _logger.info('Could not fetch EncryptionPublicKey from LocalSecondary.' ' Unable to complete reset check'); - return; + return false; } // TODO should there be a check for remote enc_key being null ? @@ -913,9 +913,10 @@ class AtClientImpl implements AtClient, AtSignChangeListener { 'Please delete localStorage and restart the client'); _logger.info('To delete localSecondary, call ' 'AtClientImpl.deleteLocalSecondaryStorageWithConsent() with user consent'); - throw AtResetException('Remote secondary has been reset'); + return true; } _logger.finer('Remote Secondary is NOT reset. Status ok'); + return false; } void deleteLocalSecondaryStorageWithConsent( From 216eec84d8aea46658f684aa511a3da875c22d85 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Wed, 19 Jul 2023 21:04:33 +0530 Subject: [PATCH 11/24] feat: introduce deleteLocalStorageWithConsent in at_client_spec --- .../at_client/lib/src/client/at_client_spec.dart | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/at_client/lib/src/client/at_client_spec.dart b/packages/at_client/lib/src/client/at_client_spec.dart index 269dc18eb..3f23727e8 100644 --- a/packages/at_client/lib/src/client/at_client_spec.dart +++ b/packages/at_client/lib/src/client/at_client_spec.dart @@ -530,8 +530,18 @@ abstract class AtClient { Function streamReceiveCallBack); /// Performs a check to see if RemoteSecondary has been reset - /// throws [AtResetException] if the RemoteSecondary has been reset - Future isSecondaryReset(); + /// returns true if the RemoteSecondary has been reset, false otherwise + Future isSecondaryReset(); + + /// Deletes a client's local secondary storage + /// + /// [To be used when remote secondary has been reset] + /// + /// Requires user consent passed as a method parameter. + /// + /// Performs deletion only if consent is true + void deleteLocalSecondaryStorageWithConsent( + {required bool userConsentToDeleteLocalStorage}); /// Uploads list of [files] to filebin and shares the file download url with [sharedWithAtSigns] /// returns map containing key of each sharedWithAtSign and value of [FileTransferObject] From 6b0efb847d7cd4d3e5e080a026622bb83b9402ad Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Wed, 19 Jul 2023 21:05:17 +0530 Subject: [PATCH 12/24] feat: deleteLocalStorageWithConsent now fetches hiveStoragePath and commitLogStoragePath from AtClientPrefs --- .../lib/src/client/at_client_impl.dart | 106 ++++++++++-------- 1 file changed, 57 insertions(+), 49 deletions(-) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index 525cfa930..853bb6f7a 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -919,9 +919,8 @@ class AtClientImpl implements AtClient, AtSignChangeListener { return false; } - void deleteLocalSecondaryStorageWithConsent( - String commitLogDirectoryPath, String hiveStorageDirectoryPath, - {required bool userConsentToDeleteLocalStorage}) { + @override + void deleteLocalSecondaryStorageWithConsent({required bool userConsentToDeleteLocalStorage}) { _logger.shout( 'Consent to delete LocalSecondary storage received: $userConsentToDeleteLocalStorage'); if (!userConsentToDeleteLocalStorage) { @@ -930,68 +929,77 @@ class AtClientImpl implements AtClient, AtSignChangeListener { } // Deleting commit log storage _logger - .info('Deleting CommitLog local storage at: $commitLogDirectoryPath'); - String commitLogFileName = - 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hive'; - String commitLogLockFileName = - 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.lock'; - - File commitLogFile = File('$commitLogDirectoryPath/$commitLogFileName'); - - // Todo: Do windows/mac have lock files ? - File lockFile = File('$commitLogDirectoryPath/$commitLogLockFileName'); - - if (!commitLogFile.existsSync()) { - throw AtClientException.message( - 'CommitLog storage not found at path: $commitLogFile.' - ' Please provide a valid CommitLog directory path'); - } + .info('Deleting CommitLog local storage at: ${_preference?.commitLogPath}'); try { - commitLogFile.deleteSync(); - lockFile.deleteSync(); - // Since recursive delete is false by default, If the directory is empty - // the directory will also be deleted - Directory(commitLogDirectoryPath).deleteSync(); - _logger.info('Successfully deleted commitLog storage'); + _deleteLocalStorage(_preference!.commitLogPath!, isHiveStorage: false); } on Exception catch (e) { _logger.finer('Unable to delete CommitLog storage | Cause: $e'); throw AtIOException(e.toString()); } // Deleting hive storage - _logger.info('Deleting hive local storage at: $hiveStorageDirectoryPath'); - String hashFileName = - '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hash'; - String hiveFileName = - '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hive'; - String hiveLockFileName = - '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.lock'; - - File hiveFile = File('$hiveStorageDirectoryPath/$hiveFileName'); - File hiveLockFile = File('$hiveStorageDirectoryPath/$hiveLockFileName'); - File hashFile = File('$hiveStorageDirectoryPath/$hashFileName'); - - if (!(hashFile.existsSync() && hiveFile.existsSync())) { - if (!hiveFile.existsSync()) { + _logger.info('Deleting hive local storage at: ${_preference?.hiveStoragePath}'); + try { + _deleteLocalStorage(_preference!.hiveStoragePath!, isHiveStorage: true); + } on Exception catch (e) { + _logger.finer('Unable to delete hive storage | Cause: $e'); + throw AtIOException(e.toString()); + } + } + + void _deleteLocalStorage(String storageDirectory, + {bool isHiveStorage = false}) { + if (isHiveStorage) { + String hashFileName = + '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hash'; + String hiveFileName = + '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hive'; + String hiveLockFileName = + '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.lock'; + + File hiveFile = File('$storageDirectory/$hiveFileName'); + File hiveLockFile = File('$storageDirectory/$hiveLockFileName'); + File hashFile = File('$storageDirectory/$hashFileName'); + + if (!(hashFile.existsSync() && hiveFile.existsSync())) { + if (!hiveFile.existsSync()) { + throw AtClientException.message( + 'hive file not found at path: $hiveFile.' + ' Please provide a valid hive storage directory path'); + } throw AtClientException.message( - 'hive file not found at path: $hiveFile.' + 'hive hash file not found at path: $hiveFile.' ' Please provide a valid hive storage directory path'); } - throw AtClientException.message( - 'hive hash file not found at path: $hiveFile.' - ' Please provide a valid hive storage directory path'); - } - try { hashFile.deleteSync(); hiveFile.deleteSync(); hiveLockFile.deleteSync(); // Since recursive delete is true by default, only if the directory is // empty the directory will be deleted too - Directory(hiveStorageDirectoryPath).deleteSync(); + Directory(storageDirectory).deleteSync(); _logger.info('Successfully deleted hive storage'); - } on Exception catch (e) { - _logger.finer('Unable to delete hive storage | Cause: $e'); - throw AtIOException(e.toString()); + } else { + String commitLogFileName = + 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hive'; + String commitLogLockFileName = + 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.lock'; + + File commitLogFile = File('$storageDirectory/$commitLogFileName'); + + // Todo: Do windows/mac have lock files ? + File lockFile = File('$storageDirectory/$commitLogLockFileName'); + + if (!commitLogFile.existsSync()) { + throw AtClientException.message( + 'CommitLog storage not found at path: $commitLogFile.' + ' Please provide a valid CommitLog directory path'); + } + commitLogFile.deleteSync(); + lockFile.deleteSync(); + // Since recursive delete is false by default, If the directory is empty + // the directory will also be deleted + Directory(storageDirectory).deleteSync(); + _logger.info('Successfully deleted commitLog storage'); } } From eccd6249970ac367ee2d6317f8469960a817545f Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Thu, 20 Jul 2023 04:20:03 +0530 Subject: [PATCH 13/24] test: modify test according to new changes --- packages/at_client/test/at_client_impl_test.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/at_client/test/at_client_impl_test.dart b/packages/at_client/test/at_client_impl_test.dart index 54571ff5d..a08a965b8 100644 --- a/packages/at_client/test/at_client_impl_test.dart +++ b/packages/at_client/test/at_client_impl_test.dart @@ -275,8 +275,7 @@ void main() { AtClientPreference()..isLocalStoreRequired = true, remoteSecondary: mockRemoteSecondary, localSecondaryKeyStore: mockKeystore); - expect(client.isSecondaryReset(), - throwsA(predicate((dynamic e) => e is AtResetException))); + expect(await client.isSecondaryReset(), false); }); test('Verify isSecondaryReset() functionality - positive case', () async { From ac018d05e9b7259a27b66d618f887c65eef3330e Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Thu, 20 Jul 2023 04:21:18 +0530 Subject: [PATCH 14/24] test: modify test according to new changes --- packages/at_client/test/at_client_impl_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/at_client/test/at_client_impl_test.dart b/packages/at_client/test/at_client_impl_test.dart index a08a965b8..b276c8752 100644 --- a/packages/at_client/test/at_client_impl_test.dart +++ b/packages/at_client/test/at_client_impl_test.dart @@ -291,7 +291,7 @@ void main() { localSecondaryKeyStore: mockKeystore); // errorless execution test // if the method call below triggers any errors/exceptions this test will fail - await client.isSecondaryReset(); + expect(await client.isSecondaryReset(), true); }); }); } From f7349c9ca28887700380b1d61e879f2c9d4fcbbc Mon Sep 17 00:00:00 2001 From: srieteja Date: Mon, 31 Jul 2023 16:26:02 +0530 Subject: [PATCH 15/24] tests: fix unit tests --- packages/at_client/test/at_client_impl_test.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/at_client/test/at_client_impl_test.dart b/packages/at_client/test/at_client_impl_test.dart index b276c8752..71a91c399 100644 --- a/packages/at_client/test/at_client_impl_test.dart +++ b/packages/at_client/test/at_client_impl_test.dart @@ -275,7 +275,7 @@ void main() { AtClientPreference()..isLocalStoreRequired = true, remoteSecondary: mockRemoteSecondary, localSecondaryKeyStore: mockKeystore); - expect(await client.isSecondaryReset(), false); + expect(await client.isSecondaryReset(), true); }); test('Verify isSecondaryReset() functionality - positive case', () async { @@ -289,9 +289,7 @@ void main() { AtClientPreference()..isLocalStoreRequired = true, remoteSecondary: mockRemoteSecondary, localSecondaryKeyStore: mockKeystore); - // errorless execution test - // if the method call below triggers any errors/exceptions this test will fail - expect(await client.isSecondaryReset(), true); + expect(await client.isSecondaryReset(), false); }); }); } From 80e5ab97c79b435fe15234c7f0c6012b533f5337 Mon Sep 17 00:00:00 2001 From: srieteja Date: Mon, 31 Jul 2023 16:26:32 +0530 Subject: [PATCH 16/24] feat: introduce and consume menthod to stop instances of commitLog and hive --- .../lib/src/client/at_client_impl.dart | 76 +++++++------------ .../lib/src/manager/storage_manager.dart | 20 +++++ 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index 853bb6f7a..285e51080 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -52,6 +52,7 @@ class AtClientImpl implements AtClient, AtSignChangeListener { RemoteSecondary? _remoteSecondary; AtClientCommitLogCompaction? _atClientCommitLogCompaction; AtClientConfig? _atClientConfig; + StorageManager? _storageManager; static final upperCaseRegex = RegExp(r'[A-Z]'); PutRequestTransformer putRequestTransformer = PutRequestTransformer(); @@ -181,8 +182,8 @@ class AtClientImpl implements AtClient, AtSignChangeListener { Future _init() async { if (_preference!.isLocalStoreRequired) { if (_localSecondaryKeyStore == null) { - var storageManager = StorageManager(preference); - await storageManager.init(_atSign, preference!.keyStoreSecret); + _storageManager = StorageManager(preference); + await _storageManager?.init(_atSign, preference!.keyStoreSecret); } _localSecondary = LocalSecondary(this, keyStore: _localSecondaryKeyStore); @@ -526,7 +527,9 @@ class AtClientImpl implements AtClient, AtSignChangeListener { // will not be null. if (verbBuilder.value.length > _preference!.maxDataSize) { throw BufferOverFlowException( - 'The length of value exceeds the maximum allowed length. Maximum buffer size is ${_preference!.maxDataSize} bytes. Found ${value.toString().length} bytes'); + 'The length of value exceeds the maximum allowed length.' + ' Maximum buffer size is ${_preference!.maxDataSize} bytes.' + ' Found ${value.toString().length} bytes'); } Secondary secondary = SecondaryManager.getSecondary(this, verbBuilder); @@ -901,8 +904,11 @@ class AtClientImpl implements AtClient, AtSignChangeListener { ' Unable to complete reset check'); return false; } - - // TODO should there be a check for remote enc_key being null ? + if (remotePublicKey.isNull) { + _logger.info('Could not fetch EncryptionPublicKey from RemoteSecondary.' + ' Unable to complete reset check'); + return false; + } if (localPublicKey != remotePublicKey) { _logger.info('EncryptionPublicKey on LocalSecondary: $localPublicKey'); @@ -920,16 +926,18 @@ class AtClientImpl implements AtClient, AtSignChangeListener { } @override - void deleteLocalSecondaryStorageWithConsent({required bool userConsentToDeleteLocalStorage}) { + Future deleteLocalSecondaryStorageWithConsent( + {required bool userConsentToDeleteLocalStorage}) async { _logger.shout( 'Consent to delete LocalSecondary storage received: $userConsentToDeleteLocalStorage'); if (!userConsentToDeleteLocalStorage) { throw AtClientException.message( 'User consent not provided. Unable to delete local storage without consent'); } + await _storageManager?.stopInstances(_atSign); // Deleting commit log storage - _logger - .info('Deleting CommitLog local storage at: ${_preference?.commitLogPath}'); + _logger.info( + 'Deleting CommitLog local storage at: ${_preference?.commitLogPath}'); try { _deleteLocalStorage(_preference!.commitLogPath!, isHiveStorage: false); } on Exception catch (e) { @@ -938,7 +946,8 @@ class AtClientImpl implements AtClient, AtSignChangeListener { } // Deleting hive storage - _logger.info('Deleting hive local storage at: ${_preference?.hiveStoragePath}'); + _logger.info( + 'Deleting hive local storage at: ${_preference?.hiveStoragePath}'); try { _deleteLocalStorage(_preference!.hiveStoragePath!, isHiveStorage: true); } on Exception catch (e) { @@ -950,55 +959,24 @@ class AtClientImpl implements AtClient, AtSignChangeListener { void _deleteLocalStorage(String storageDirectory, {bool isHiveStorage = false}) { if (isHiveStorage) { - String hashFileName = - '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hash'; - String hiveFileName = - '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hive'; - String hiveLockFileName = - '${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.lock'; - - File hiveFile = File('$storageDirectory/$hiveFileName'); - File hiveLockFile = File('$storageDirectory/$hiveLockFileName'); - File hashFile = File('$storageDirectory/$hashFileName'); - - if (!(hashFile.existsSync() && hiveFile.existsSync())) { - if (!hiveFile.existsSync()) { - throw AtClientException.message( - 'hive file not found at path: $hiveFile.' - ' Please provide a valid hive storage directory path'); - } + Directory hiveDir = Directory(storageDirectory); + + if (!(hiveDir.existsSync())) { throw AtClientException.message( - 'hive hash file not found at path: $hiveFile.' + 'hive directory not found at path: $storageDirectory.' ' Please provide a valid hive storage directory path'); } - hashFile.deleteSync(); - hiveFile.deleteSync(); - hiveLockFile.deleteSync(); - // Since recursive delete is true by default, only if the directory is - // empty the directory will be deleted too - Directory(storageDirectory).deleteSync(); + hiveDir.deleteSync(); _logger.info('Successfully deleted hive storage'); } else { - String commitLogFileName = - 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.hive'; - String commitLogLockFileName = - 'commit_log_${AtUtils.getShaForAtSign(getCurrentAtSign()!)}.lock'; - - File commitLogFile = File('$storageDirectory/$commitLogFileName'); - - // Todo: Do windows/mac have lock files ? - File lockFile = File('$storageDirectory/$commitLogLockFileName'); + Directory commitLogDir = Directory(storageDirectory); - if (!commitLogFile.existsSync()) { + if (!commitLogDir.existsSync()) { throw AtClientException.message( - 'CommitLog storage not found at path: $commitLogFile.' + 'CommitLog storage not found at path: $storageDirectory.' ' Please provide a valid CommitLog directory path'); } - commitLogFile.deleteSync(); - lockFile.deleteSync(); - // Since recursive delete is false by default, If the directory is empty - // the directory will also be deleted - Directory(storageDirectory).deleteSync(); + commitLogDir.deleteSync(); _logger.info('Successfully deleted commitLog storage'); } } diff --git a/packages/at_client/lib/src/manager/storage_manager.dart b/packages/at_client/lib/src/manager/storage_manager.dart index 645f6e4a9..b1f6d3d1b 100644 --- a/packages/at_client/lib/src/manager/storage_manager.dart +++ b/packages/at_client/lib/src/manager/storage_manager.dart @@ -43,4 +43,24 @@ class StorageManager { keyStoreManager.keyStore = hiveKeyStore; isStorageInitialized = true; } + + Future stopInstances(String currentAtSign) async { + AtCommitLog? atCommitLog = await AtCommitLogManagerImpl.getInstance() + .getCommitLog(currentAtSign, + commitLogPath: preferences?.commitLogPath, enableCommitId: false); + + HivePersistenceManager hiveManager = + SecondaryPersistenceStoreFactory.getInstance() + .getSecondaryPersistenceStore(currentAtSign)! + .getHivePersistenceManager()!; + + SecondaryKeyStore hiveKeyStore = + SecondaryPersistenceStoreFactory.getInstance() + .getSecondaryPersistenceStore(currentAtSign)! + .getSecondaryKeyStore()!; + + await (hiveKeyStore.commitLog as AtCommitLog).close(); + await hiveManager.close(); + await atCommitLog?.close(); + } } From 4263b827e4a956951f8c01c79494969a82925535 Mon Sep 17 00:00:00 2001 From: Sri Teja T <50960424+srieteja@users.noreply.github.com> Date: Thu, 17 Aug 2023 03:47:13 +0530 Subject: [PATCH 17/24] Update pubspec.yaml --- tests/at_functional_test/pubspec.yaml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/at_functional_test/pubspec.yaml b/tests/at_functional_test/pubspec.yaml index 733cece7e..20f5b509b 100644 --- a/tests/at_functional_test/pubspec.yaml +++ b/tests/at_functional_test/pubspec.yaml @@ -11,15 +11,8 @@ dependencies: at_client: path: ../../packages/at_client -dependency_overrides: - at_commons: - git: - url: https://github.com/atsign-foundation/at_libraries - path: packages/at_commons - ref: at_reset_exception - dev_dependencies: test: ^1.24.3 lints: ^2.0.0 at_demo_data: ^1.0.0 - coverage: ^1.5.0 \ No newline at end of file + coverage: ^1.5.0 From 17e346fe853523cb84d812c2d506612d49ec8275 Mon Sep 17 00:00:00 2001 From: Sri Teja T <50960424+srieteja@users.noreply.github.com> Date: Thu, 17 Aug 2023 03:47:34 +0530 Subject: [PATCH 18/24] Update pubspec.yaml --- tests/at_end2end_test/pubspec.yaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/at_end2end_test/pubspec.yaml b/tests/at_end2end_test/pubspec.yaml index 174231632..fc1723877 100644 --- a/tests/at_end2end_test/pubspec.yaml +++ b/tests/at_end2end_test/pubspec.yaml @@ -12,13 +12,6 @@ dependencies: at_client: path: ../../packages/at_client -dependency_overrides: - at_commons: - git: - url: https://github.com/atsign-foundation/at_libraries - path: packages/at_commons - ref: at_reset_exception - dev_dependencies: pedantic: ^1.11.1 test: ^1.21.4 From a8ec40e53735684b470a1142f3787dd9ea1b781b Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Thu, 17 Aug 2023 04:00:01 +0530 Subject: [PATCH 19/24] refactor: introduce option to close storage manager --- .../lib/src/manager/storage_manager.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/at_client/lib/src/manager/storage_manager.dart b/packages/at_client/lib/src/manager/storage_manager.dart index b1f6d3d1b..91b87b6d6 100644 --- a/packages/at_client/lib/src/manager/storage_manager.dart +++ b/packages/at_client/lib/src/manager/storage_manager.dart @@ -63,4 +63,21 @@ class StorageManager { await hiveManager.close(); await atCommitLog?.close(); } + + Future close(String currentAtSign) async { + var storagePath = preferences!.hiveStoragePath; + var commitLogPath = preferences!.commitLogPath; + + var atCommitLog = await AtCommitLogManagerImpl.getInstance().getCommitLog( + currentAtSign, + commitLogPath: commitLogPath, + enableCommitId: false); + + await atCommitLog?.close; + + var manager = SecondaryPersistenceStoreFactory.getInstance() + .getSecondaryPersistenceStore(currentAtSign)! + .getHivePersistenceManager()!; + await manager.close(); + } } From 5babc71161ef93b186215f6ab19653150205f4a2 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Thu, 17 Aug 2023 04:00:27 +0530 Subject: [PATCH 20/24] feat: consume stop storage_manager and improve isReset check --- .../lib/src/client/at_client_impl.dart | 94 ++++++++++--------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index 285e51080..6e727536e 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -886,42 +886,65 @@ class AtClientImpl implements AtClient, AtSignChangeListener { @override Future isSecondaryReset() async { + String? localPublicKey, remotePublicKey; _logger.finer('Performing Remote Secondary reset check'); // Fetch EncryptionPublicKey from LocalSecondary - var localPublicKey = - await getLocalSecondary()?.getEncryptionPublicKey(getCurrentAtSign()!); + try { + localPublicKey = await getLocalSecondary() + ?.getEncryptionPublicKey(getCurrentAtSign()!); + } on Exception catch (e) { + _logger.severe( + 'Exception caused fetch EncryptionPublicKey from LocalSecondary.' + ' Unable to complete reset check | Cause $e'); + return false; + } // Fetch EncryptionPublicKey from RemoteSecondary - LookupVerbBuilder lookupBuilder = LookupVerbBuilder() - ..atKey = 'publickey' //AT_ENCRYPTION_PUBLIC_KEY - ..sharedBy = getCurrentAtSign(); - String? remotePublicKey = - await getRemoteSecondary()?.executeVerb(lookupBuilder); + try { + PLookupVerbBuilder plookup = PLookupVerbBuilder() + ..atKey = 'publickey' + ..sharedBy = getCurrentAtSign(); + remotePublicKey = await getRemoteSecondary()?.executeVerb(plookup); + } on Exception catch (e) { + _logger.info('Caught exception during public key lookup | $e'); + _logger.info('Retrying fetch public key'); + // try fetching the ENCRYPTION_PUB_KEY using lookup verb + // this fallback is for when reset status check is performed on an + //unauthenticated connection + LookupVerbBuilder lookup = LookupVerbBuilder() + ..atKey = 'publickey' //AT_ENCRYPTION_PUBLIC_KEY + ..sharedBy = getCurrentAtSign(); + remotePublicKey = await getRemoteSecondary()?.executeVerb(lookup); + } + // secondary response is in format 'data:publickey'. Removing 'data:' from response - remotePublicKey = remotePublicKey?.replaceFirst('data:', ''); + if (remotePublicKey!.contains('data:')) { + remotePublicKey = remotePublicKey.replaceFirst('data:', ''); + } else { + remotePublicKey = null; + } if (localPublicKey.isNull) { - _logger.info('Could not fetch EncryptionPublicKey from LocalSecondary.' + _logger.severe('Could not fetch EncryptionPublicKey from LocalSecondary.' ' Unable to complete reset check'); return false; - } - if (remotePublicKey.isNull) { - _logger.info('Could not fetch EncryptionPublicKey from RemoteSecondary.' + } else if (remotePublicKey.isNull) { + _logger.severe('Could not fetch EncryptionPublicKey from RemoteSecondary.' ' Unable to complete reset check'); return false; } if (localPublicKey != remotePublicKey) { - _logger.info('EncryptionPublicKey on LocalSecondary: $localPublicKey'); - _logger.info('EncryptionPublicKey on RemoteSecondary: $remotePublicKey'); _logger.shout( 'AtEncryptionPublicKey on local secondary and remote secondary are different.' 'This indicates remote secondary has been reset.' 'Please delete localStorage and restart the client'); _logger.info('To delete localSecondary, call ' 'AtClientImpl.deleteLocalSecondaryStorageWithConsent() with user consent'); + _logger.finer('EncryptionPublicKey on LocalSecondary: $localPublicKey'); + _logger.finer('EncryptionPublicKey on RemoteSecondary: $remotePublicKey'); return true; } - _logger.finer('Remote Secondary is NOT reset. Status ok'); + _logger.info('Remote Secondary is NOT reset. Status ok'); return false; } @@ -934,20 +957,14 @@ class AtClientImpl implements AtClient, AtSignChangeListener { throw AtClientException.message( 'User consent not provided. Unable to delete local storage without consent'); } - await _storageManager?.stopInstances(_atSign); - // Deleting commit log storage - _logger.info( - 'Deleting CommitLog local storage at: ${_preference?.commitLogPath}'); + await StorageManager(_preference).close(_atSign); try { _deleteLocalStorage(_preference!.commitLogPath!, isHiveStorage: false); } on Exception catch (e) { _logger.finer('Unable to delete CommitLog storage | Cause: $e'); throw AtIOException(e.toString()); } - - // Deleting hive storage - _logger.info( - 'Deleting hive local storage at: ${_preference?.hiveStoragePath}'); + // Delete hive storage try { _deleteLocalStorage(_preference!.hiveStoragePath!, isHiveStorage: true); } on Exception catch (e) { @@ -957,31 +974,22 @@ class AtClientImpl implements AtClient, AtSignChangeListener { } void _deleteLocalStorage(String storageDirectory, - {bool isHiveStorage = false}) { - if (isHiveStorage) { - Directory hiveDir = Directory(storageDirectory); - - if (!(hiveDir.existsSync())) { - throw AtClientException.message( - 'hive directory not found at path: $storageDirectory.' - ' Please provide a valid hive storage directory path'); - } - hiveDir.deleteSync(); - _logger.info('Successfully deleted hive storage'); - } else { - Directory commitLogDir = Directory(storageDirectory); + {required bool isHiveStorage}) { + String storageType = isHiveStorage ? 'hive' : 'commitLog'; + _logger.info('Deleting $storageType storage at path: $storageDirectory'); - if (!commitLogDir.existsSync()) { - throw AtClientException.message( - 'CommitLog storage not found at path: $storageDirectory.' - ' Please provide a valid CommitLog directory path'); - } - commitLogDir.deleteSync(); - _logger.info('Successfully deleted commitLog storage'); + Directory storageDir = Directory(storageDirectory); + if (!storageDir.existsSync()) { + throw AtClientException.message( + '$storageType storage not found at path: $storageDirectory.' + ' Please provide a valid $storageType storage directory path'); } + Directory(storageDirectory).deleteSync(recursive: true); + _logger.info('Successfully deleted $storageType storage'); } // TODO v4 - remove the follow methods in version 4 of at_client package + @override @Deprecated("Use AtClient.syncService") SyncManager? getSyncManager() { From 572db9f430d4b94146b9eca9919a566f6e5b45a0 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Thu, 17 Aug 2023 11:55:31 +0530 Subject: [PATCH 21/24] fix: analyzer issues --- packages/at_client/lib/src/client/at_client_impl.dart | 2 ++ packages/at_client/lib/src/manager/storage_manager.dart | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index 6e727536e..e87b94356 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -920,6 +920,8 @@ class AtClientImpl implements AtClient, AtSignChangeListener { if (remotePublicKey!.contains('data:')) { remotePublicKey = remotePublicKey.replaceFirst('data:', ''); } else { + _logger.info( + 'Fetched potential invalid remote Public encryption key: $remotePublicKey'); remotePublicKey = null; } diff --git a/packages/at_client/lib/src/manager/storage_manager.dart b/packages/at_client/lib/src/manager/storage_manager.dart index 91b87b6d6..268df8e23 100644 --- a/packages/at_client/lib/src/manager/storage_manager.dart +++ b/packages/at_client/lib/src/manager/storage_manager.dart @@ -65,7 +65,6 @@ class StorageManager { } Future close(String currentAtSign) async { - var storagePath = preferences!.hiveStoragePath; var commitLogPath = preferences!.commitLogPath; var atCommitLog = await AtCommitLogManagerImpl.getInstance().getCommitLog( @@ -73,6 +72,7 @@ class StorageManager { commitLogPath: commitLogPath, enableCommitId: false); + // ignore: await_only_futures await atCommitLog?.close; var manager = SecondaryPersistenceStoreFactory.getInstance() From 12ea910f308ad0d4d0f2620ba739d45805c7d9b3 Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Tue, 31 Oct 2023 11:26:07 +0530 Subject: [PATCH 22/24] build: remove at_commons dependency override --- packages/at_client/pubspec.yaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/at_client/pubspec.yaml b/packages/at_client/pubspec.yaml index 2bd552c72..3938b9ead 100644 --- a/packages/at_client/pubspec.yaml +++ b/packages/at_client/pubspec.yaml @@ -40,13 +40,6 @@ dependencies: meta: ^1.8.0 version: ^3.0.2 -dependency_overrides: - at_commons: - git: - url: https://github.com/atsign-foundation/at_libraries - path: packages/at_commons - ref: at_reset_exception - dev_dependencies: lints: ^2.1.1 From b12f479c0aea19e4e064958b9c6caf46bd036f1e Mon Sep 17 00:00:00 2001 From: Srie Teja Date: Tue, 31 Oct 2023 11:30:01 +0530 Subject: [PATCH 23/24] chore: fix dart analyzer issues --- packages/at_client/test/at_client_impl_test.dart | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/at_client/test/at_client_impl_test.dart b/packages/at_client/test/at_client_impl_test.dart index 297b65806..9d1873e60 100644 --- a/packages/at_client/test/at_client_impl_test.dart +++ b/packages/at_client/test/at_client_impl_test.dart @@ -265,32 +265,37 @@ void main() { AtClient client; test('Verify isSecondaryReset() functionality - negative case', () async { - AtData responseObj = AtData()..data = 'incorrectLocalEncPublicKey'; + AtData responseObj = AtData() + ..data = 'incorrectLocalEncPublicKey'; when(() => mockRemoteSecondary.executeVerb(any())).thenAnswer( - (invocation) => Future.value('data:incorrectRemoteEncPublicKey')); + (invocation) => Future.value('data:incorrectRemoteEncPublicKey')); when(() => mockKeystore.get(any())) .thenAnswer((invocation) => Future.value(responseObj)); client = await AtClientImpl.create('@alice47', 'resetLocalTest', - AtClientPreference()..isLocalStoreRequired = true, + AtClientPreference() + ..isLocalStoreRequired = true, remoteSecondary: mockRemoteSecondary, localSecondaryKeyStore: mockKeystore); expect(await client.isSecondaryReset(), true); }); test('Verify isSecondaryReset() functionality - positive case', () async { - AtData responseObj = AtData()..data = 'correctEncPublicKey'; + AtData responseObj = AtData() + ..data = 'correctEncPublicKey'; when(() => mockRemoteSecondary.executeVerb(any())) .thenAnswer((invocation) => Future.value('data:correctEncPublicKey')); when(() => mockKeystore.get(any())) .thenAnswer((invocation) => Future.value(responseObj)); client = await AtClientImpl.create('@alice47', 'resetLocalTest', - AtClientPreference()..isLocalStoreRequired = true, + AtClientPreference() + ..isLocalStoreRequired = true, remoteSecondary: mockRemoteSecondary, localSecondaryKeyStore: mockKeystore); expect(await client.isSecondaryReset(), false); }); + }); group('A group of tests related to setting enrollmentId', () { test( From db4e12ab0702c17600e1968c08ce6f18538693fc Mon Sep 17 00:00:00 2001 From: Sri Teja T Date: Thu, 12 Sep 2024 15:32:25 +0530 Subject: [PATCH 24/24] fix: update usage of PLookupBuilder --- packages/at_client/lib/src/client/at_client_impl.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/at_client/lib/src/client/at_client_impl.dart b/packages/at_client/lib/src/client/at_client_impl.dart index 3ab0d1b11..b6da43892 100644 --- a/packages/at_client/lib/src/client/at_client_impl.dart +++ b/packages/at_client/lib/src/client/at_client_impl.dart @@ -984,10 +984,10 @@ class AtClientImpl implements AtClient, AtSignChangeListener { return false; } // Fetch EncryptionPublicKey from RemoteSecondary + AtKey encPublicKey = AtKey.fromString('publickey$getCurrentAtSign()'); try { PLookupVerbBuilder plookup = PLookupVerbBuilder() - ..atKey = 'publickey' - ..sharedBy = getCurrentAtSign(); + ..atKey = encPublicKey; remotePublicKey = await getRemoteSecondary()?.executeVerb(plookup); } on Exception catch (e) { _logger.info('Caught exception during public key lookup | $e'); @@ -996,8 +996,7 @@ class AtClientImpl implements AtClient, AtSignChangeListener { // this fallback is for when reset status check is performed on an //unauthenticated connection LookupVerbBuilder lookup = LookupVerbBuilder() - ..atKey = 'publickey' //AT_ENCRYPTION_PUBLIC_KEY - ..sharedBy = getCurrentAtSign(); + ..atKey = encPublicKey; remotePublicKey = await getRemoteSecondary()?.executeVerb(lookup); }