From f528b1533fd1713fc24c19d128f33a69927d15ea Mon Sep 17 00:00:00 2001 From: Thiago Carvalho <32248947+thiagocarvalhodev@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:34:57 -0300 Subject: [PATCH] fix: ensure drive keys are properly cleared during logout --- lib/authentication/ardrive_auth.dart | 6 ++++++ lib/main.dart | 1 + lib/models/daos/drive_dao/drive_dao.dart | 9 +++++++++ lib/models/database/database_helpers.dart | 12 +++++++----- test/authentication/ardrive_auth_test.dart | 16 ++++++++++++++-- 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/lib/authentication/ardrive_auth.dart b/lib/authentication/ardrive_auth.dart index e75db8abbb..59ef356375 100644 --- a/lib/authentication/ardrive_auth.dart +++ b/lib/authentication/ardrive_auth.dart @@ -46,6 +46,7 @@ abstract class ArDriveAuth { required SecureKeyValueStore secureKeyValueStore, required ArConnectService arConnectService, required DatabaseHelpers databaseHelpers, + required DriveDao driveDao, MetadataCache? metadataCache, }) => ArDriveAuthImpl( @@ -57,6 +58,7 @@ abstract class ArDriveAuth { secureKeyValueStore: secureKeyValueStore, arConnectService: arConnectService, metadataCache: metadataCache, + driveDao: driveDao, ); } @@ -69,10 +71,12 @@ class ArDriveAuthImpl implements ArDriveAuth { required SecureKeyValueStore secureKeyValueStore, required ArConnectService arConnectService, required DatabaseHelpers databaseHelpers, + required DriveDao driveDao, MetadataCache? metadataCache, }) : _arweave = arweave, _crypto = crypto, _databaseHelpers = databaseHelpers, + _driveDao = driveDao, _arConnectService = arConnectService, _secureKeyValueStore = secureKeyValueStore, _biometricAuthentication = biometricAuthentication, @@ -86,6 +90,7 @@ class ArDriveAuthImpl implements ArDriveAuth { final SecureKeyValueStore _secureKeyValueStore; final ArConnectService _arConnectService; final DatabaseHelpers _databaseHelpers; + final DriveDao _driveDao; MetadataCache? _maybeMetadataCache; User? _currentUser; @@ -266,6 +271,7 @@ class ArDriveAuthImpl implements ArDriveAuth { } await _databaseHelpers.deleteAllTables(); + await _driveDao.removeAllDriveKeys(); currentUser = null; _userStreamController.add(null); } catch (e, stacktrace) { diff --git a/lib/main.dart b/lib/main.dart index e5fc285436..0bf10355ce 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -427,6 +427,7 @@ class AppState extends State { ), RepositoryProvider( create: (context) => ArDriveAuth( + driveDao: context.read(), databaseHelpers: DatabaseHelpers( context.read(), ), diff --git a/lib/models/daos/drive_dao/drive_dao.dart b/lib/models/daos/drive_dao/drive_dao.dart index 7ca6b6eb3c..b3cac2c0a3 100644 --- a/lib/models/daos/drive_dao/drive_dao.dart +++ b/lib/models/daos/drive_dao/drive_dao.dart @@ -51,6 +51,15 @@ class DriveDao extends DatabaseAccessor with _$DriveDaoMixin { _previewVault = await store.vault(name: 'previewVault'); } + Future removeAllDriveKeys() async { + try { + logger.i('Removing all drive keys'); + await _driveKeyVault.clear(); + } catch (e) { + throw _handleError('Error removing all drive keys', e); + } + } + Future deleteSharedPrivateDrives(String? owner) async { try { final drives = (await allDrives().get()).where( diff --git a/lib/models/database/database_helpers.dart b/lib/models/database/database_helpers.dart index b9c871c558..8be32ac62d 100644 --- a/lib/models/database/database_helpers.dart +++ b/lib/models/database/database_helpers.dart @@ -9,11 +9,13 @@ class DatabaseHelpers { Future deleteAllTables() async { try { logger.d('Deleting all tables'); - await _db.transaction(() async { - for (final table in _db.allTables) { - await _db.delete(table).go(); - } - }); + await _db.transaction( + () async { + for (final table in _db.allTables) { + await _db.delete(table).go(); + } + }, + ); } catch (e) { logger.e('Error deleting all tables', e); } diff --git a/test/authentication/ardrive_auth_test.dart b/test/authentication/ardrive_auth_test.dart index 1e0b8b915e..8de92a3066 100644 --- a/test/authentication/ardrive_auth_test.dart +++ b/test/authentication/ardrive_auth_test.dart @@ -25,7 +25,7 @@ void main() { late MockSecureKeyValueStore mockSecureKeyValueStore; late MockArConnectService mockArConnectService; late MockDatabaseHelpers mockDatabaseHelpers; - + late MockDriveDao mockDriveDao; final wallet = getTestWallet(); setUp(() async { @@ -36,6 +36,7 @@ void main() { mockSecureKeyValueStore = MockSecureKeyValueStore(); mockArConnectService = MockArConnectService(); mockDatabaseHelpers = MockDatabaseHelpers(); + mockDriveDao = MockDriveDao(); final metadataCache = await MetadataCache.fromCacheStore( await newMemoryCacheStore(), @@ -50,6 +51,7 @@ void main() { biometricAuthentication: mockBiometricAuthentication, secureKeyValueStore: mockSecureKeyValueStore, metadataCache: metadataCache, + driveDao: mockDriveDao, ); registerFallbackValue(DriveEntity( @@ -583,6 +585,8 @@ void main() { .thenAnswer((invocation) => Future.value(true)); when(() => mockDatabaseHelpers.deleteAllTables()) .thenAnswer((invocation) async {}); + when(() => mockDriveDao.removeAllDriveKeys()) + .thenAnswer((invocation) async {}); await arDriveAuth.logout(); @@ -592,6 +596,7 @@ void main() { verify(() => mockSecureKeyValueStore.remove('biometricEnabled')) .called(1); verify(() => mockDatabaseHelpers.deleteAllTables()).called(1); + verify(() => mockDriveDao.removeAllDriveKeys()).called(1); }); /// This is for the case when has user is true but the user is not logged in @@ -605,12 +610,15 @@ void main() { .thenAnswer((invocation) async {}); when(() => mockUserRepository.deleteUser()) .thenAnswer((invocation) async {}); + when(() => mockDriveDao.removeAllDriveKeys()) + .thenAnswer((invocation) async {}); await arDriveAuth.logout(); verifyNever(() => mockSecureKeyValueStore.remove('password')); verifyNever(() => mockSecureKeyValueStore.remove('biometricEnabled')); verify(() => mockDatabaseHelpers.deleteAllTables()).called(1); + verify(() => mockDriveDao.removeAllDriveKeys()).called(1); verify(() => mockUserRepository.deleteUser()).called(1); expect(() => arDriveAuth.currentUser, throwsA(isA())); @@ -674,6 +682,8 @@ void main() { .thenAnswer((invocation) => Future.value(true)); when(() => mockDatabaseHelpers.deleteAllTables()) .thenAnswer((invocation) async {}); + when(() => mockDriveDao.removeAllDriveKeys()) + .thenAnswer((invocation) async {}); await arDriveAuth.login(wallet, 'password', ProfileType.json); @@ -687,6 +697,7 @@ void main() { verify(() => mockSecureKeyValueStore.remove('biometricEnabled')) .called(1); verify(() => mockDatabaseHelpers.deleteAllTables()).called(1); + verify(() => mockDriveDao.removeAllDriveKeys()).called(1); verify(() => mockUserRepository.deleteUser()).called(1); }); }); @@ -738,7 +749,8 @@ void main() { when(() => mockUserRepository.saveUser( 'password', ProfileType.json, wallet)) .thenAnswer((invocation) => Future.value(null)); - + when(() => mockDriveDao.removeAllDriveKeys()) + .thenAnswer((invocation) async {}); when(() => mockUserRepository.getUser('password')) .thenAnswer((invocation) async => loggedUser);