From 510331140867c017e3eaf79f026d7b0d96bd0322 Mon Sep 17 00:00:00 2001 From: luckyrat Date: Mon, 6 Dec 2021 22:06:38 +0000 Subject: [PATCH] Add deleteAndDispose API method To allow runtime reconfiguration of storage options. After calling the new method, you must call getStorage again, perhaps with new authentication parameters. --- example/lib/main.dart | 133 +++++++++++++++++---------- lib/src/biometric_storage.dart | 22 +++++ lib/src/biometric_storage_web.dart | 5 + lib/src/biometric_storage_win32.dart | 5 + 4 files changed, 118 insertions(+), 47 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index a607995f..e3e4ade4 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -120,53 +120,92 @@ class MyAppState extends State { body: Column( children: [ const Text('Methods:'), - ElevatedButton( - child: const Text('init'), - onPressed: () async { - _logger.finer('Initializing $baseName'); - final authStorageSupport = - await _checkAuthenticate(_authStorageInitOptions); - if (authStorageSupport == CanAuthenticateResponse.unsupported) { - _logger.severe( - 'Unable to use authenticate. Unable to get storage.'); - return; - } - final supportsAuthenticated = authStorageSupport == - CanAuthenticateResponse.success || - authStorageSupport == CanAuthenticateResponse.statusUnknown; - if (supportsAuthenticated) { - _authStorage = await BiometricStorage().getStorage( - '${baseName}_authenticated', - options: _authStorageInitOptions, - ); - } - _storage = await BiometricStorage() - .getStorage('${baseName}_unauthenticated', - options: StorageFileInitOptions( - authenticationRequired: false, - )); - final supportsCustomPrompt = - await _checkAuthenticate(_customPromptInitOptions); - if (supportsCustomPrompt == CanAuthenticateResponse.success) { - _customPrompt = await BiometricStorage() - .getStorage('${baseName}_customPrompt', - options: _customPromptInitOptions, - promptInfo: const PromptInfo( - iosPromptInfo: IosPromptInfo( - saveTitle: 'Custom save title', - accessTitle: 'Custom access title.', - ), - androidPromptInfo: AndroidPromptInfo( - title: 'Custom title', - subtitle: 'Custom subtitle', - description: 'Custom description', - negativeButton: 'Nope!', - ), - )); - } - setState(() {}); - _logger.info('initiailzed $baseName'); - }, + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ElevatedButton( + child: const Text('init'), + onPressed: () async { + _logger.finer('Initializing $baseName'); + final authStorageSupport = + await _checkAuthenticate(_authStorageInitOptions); + if (authStorageSupport == + CanAuthenticateResponse.unsupported) { + _logger.severe( + 'Unable to use authenticate. Unable to get storage.'); + return; + } + final supportsAuthenticated = + authStorageSupport == CanAuthenticateResponse.success || + authStorageSupport == + CanAuthenticateResponse.statusUnknown; + if (supportsAuthenticated) { + _authStorage = await BiometricStorage().getStorage( + '${baseName}_authenticated', + options: _authStorageInitOptions, + ); + } + _storage = await BiometricStorage() + .getStorage('${baseName}_unauthenticated', + options: StorageFileInitOptions( + authenticationRequired: false, + )); + final supportsCustomPrompt = + await _checkAuthenticate(_customPromptInitOptions); + if (supportsCustomPrompt == + CanAuthenticateResponse.success) { + _customPrompt = await BiometricStorage() + .getStorage('${baseName}_customPrompt', + options: _customPromptInitOptions, + promptInfo: const PromptInfo( + iosPromptInfo: IosPromptInfo( + saveTitle: 'Custom save title', + accessTitle: 'Custom access title.', + ), + androidPromptInfo: AndroidPromptInfo( + title: 'Custom title', + subtitle: 'Custom subtitle', + description: 'Custom description', + negativeButton: 'Nope!', + ), + )); + } + setState(() {}); + _logger.info('initialized $baseName'); + }, + ), + ElevatedButton( + child: const Text('Delete and dispose all'), + onPressed: () async { + _logger.info('Deleting and disposing all storages'); + try { + if (_authStorage != null) { + await _authStorage!.deleteAndDispose(); + _authStorage = null; + _logger.finer( + 'Deleted and disposed authenticated storage'); + } + if (_storage != null) { + await _storage!.deleteAndDispose(); + _storage = null; + _logger.finer( + 'Deleted and disposed unauthenticated storage'); + } + if (_customPrompt != null) { + await _customPrompt!.deleteAndDispose(); + _customPrompt = null; + _logger.finer( + 'Deleted and disposed custom prompt storage'); + } + setState(() {}); + _logger.info('All storages deleted and disposed'); + } catch (e) { + _logger + .severe('Error deleting and disposing storages: $e'); + } + }, + ), + ], ), ...?_appArmorButton(), ...(_authStorage == null diff --git a/lib/src/biometric_storage.dart b/lib/src/biometric_storage.dart index d296c3b0..e5e37616 100644 --- a/lib/src/biometric_storage.dart +++ b/lib/src/biometric_storage.dart @@ -290,6 +290,12 @@ abstract class BiometricStorage extends PlatformInterface { String content, PromptInfo promptInfo, ); + + @protected + Future dispose( + String name, + PromptInfo promptInfo, + ); } class MethodChannelBiometricStorage extends BiometricStorage { @@ -425,6 +431,14 @@ class MethodChannelBiometricStorage extends BiometricStorage { ..._promptInfoForCurrentPlatform(promptInfo), })); + @override + Future dispose(String name, PromptInfo promptInfo) => _transformErrors( + _channel.invokeMethod('dispose', { + 'name': name, + ..._promptInfoForCurrentPlatform(promptInfo), + }), + ); + Map _promptInfoForCurrentPlatform(PromptInfo promptInfo) { // Don't expose Android configurations to other platforms if (Platform.isAndroid) { @@ -501,4 +515,12 @@ class BiometricStorageFile { /// Delete the content of this storage. Future delete({PromptInfo? promptInfo}) => _plugin.delete(name, promptInfo ?? defaultPromptInfo); + + /// Delete the content of this storage and dispose of the storage instance. + /// After calling this method, this BiometricStorageFile instance should not be used. + /// A subsequent call to BiometricStorage().getStorage() with the same name will create a new instance. + Future deleteAndDispose({PromptInfo? promptInfo}) async { + await delete(promptInfo: promptInfo); + await _plugin.dispose(name, promptInfo ?? defaultPromptInfo); + } } diff --git a/lib/src/biometric_storage_web.dart b/lib/src/biometric_storage_web.dart index e4409c94..c5af9310 100644 --- a/lib/src/biometric_storage_web.dart +++ b/lib/src/biometric_storage_web.dart @@ -59,4 +59,9 @@ class BiometricStoragePluginWeb extends BiometricStorage { ) async { web.window.localStorage.setItem(name, content); } + + @override + Future dispose(String name, PromptInfo promptInfo) async { + // Nothing to dispose for web implementation + } } diff --git a/lib/src/biometric_storage_win32.dart b/lib/src/biometric_storage_win32.dart index 27754c18..1c041336 100644 --- a/lib/src/biometric_storage_win32.dart +++ b/lib/src/biometric_storage_win32.dart @@ -133,4 +133,9 @@ class Win32BiometricStoragePlugin extends BiometricStorage { _logger.fine('free done'); } } + + @override + Future dispose(String name, PromptInfo promptInfo) async { + // Nothing to dispose for Win32 implementation + } }