diff --git a/lib/core/open_encrypted_box.dart b/lib/core/open_encrypted_box.dart deleted file mode 100644 index 1c276a21..00000000 --- a/lib/core/open_encrypted_box.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:fpdart/fpdart.dart'; -import 'package:hive_flutter/hive_flutter.dart'; - -/// The location of the Hive encryption key in FlutterSecureStorage. -const _secureStorageHiveEncryptionKey = 'hiveEncryptionKeyString'; - -/// Get an encrypted Hive box. -/// -/// The encryption key is stored in FlutterSecureStorage as a base64 encoded -/// string. If the key does not exist, a new key is generated and stored. -Task> getEncryptedBox(String boxKey) { - return Task(() async { - const secureStorage = FlutterSecureStorage(); - - // Get the Hive encryption key from FlutterSecureStorage, or generate a - // new key if it does not exist. - final maybeHiveEncryptionKeyString = Option.fromNullable( - await secureStorage.read(key: _secureStorageHiveEncryptionKey), - ); - - final hiveEncryptionKey = maybeHiveEncryptionKeyString - .map(base64Url.decode) - .map(HiveAesCipher.new) - .getOrElse(() => HiveAesCipher(Hive.generateSecureKey())); - - return Hive.openBox(boxKey, encryptionCipher: hiveEncryptionKey); - }); -} diff --git a/lib/core/store_utils.dart b/lib/core/store_utils.dart new file mode 100644 index 00000000..03284602 --- /dev/null +++ b/lib/core/store_utils.dart @@ -0,0 +1,56 @@ +import 'dart:convert'; + +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:fpdart/fpdart.dart'; +import 'package:hive_flutter/hive_flutter.dart'; + +extension FlutterSecureStorageFP on FlutterSecureStorage { + /// [TaskOption] wrapper around [read]. + TaskOption readAsTaskOption(String key) { + return TaskOption( + () async => Option.fromNullable(await read(key: key)), + ); + } + + /// [Task] wrapper around [write]. + Task writeAsTask({required String key, required String value}) { + return Task(() => write(key: key, value: value)).map((_) => unit); + } +} + +extension HiveFP on HiveInterface { + /// [Task] wrapper around [openBox]. + Task> openBoxAsTask(String name, {HiveCipher? encryptionCipher}) => + Task(() => openBox(name, encryptionCipher: encryptionCipher)); + + /// Open an encrypted box in a [Task]. + /// + /// The encryption key is stored in FlutterSecureStorage as a base64 encoded + /// string. If the key does not exist, a new key is generated and stored. + Task> openEncryptedBox(String boxName) { + const secureStorage = FlutterSecureStorage(); + + /// The location of the Hive encryption key in FlutterSecureStorage. + const secureStorageHiveEncryptionKey = 'hiveEncryptionKeyString'; + + Task saveHiveEncryptionKey(List encryptionKey) { + return secureStorage.writeAsTask( + key: secureStorageHiveEncryptionKey, + value: base64.encode(encryptionKey), + ); + } + + return secureStorage + .readAsTaskOption(secureStorageHiveEncryptionKey) + .map>(base64.decode) + .getOrElse(Hive.generateSecureKey) + .chainFirst(saveHiveEncryptionKey) + .map(HiveAesCipher.new) + .flatMap( + (cipher) => Hive.openBoxAsTask( + secureStorageHiveEncryptionKey, + encryptionCipher: cipher, + ), + ); + } +} diff --git a/lib/service_locator.dart b/lib/service_locator.dart index 2ebb9526..2d4e52d7 100644 --- a/lib/service_locator.dart +++ b/lib/service_locator.dart @@ -6,6 +6,7 @@ import 'package:coffeecard/core/external/screen_brightness.dart'; import 'package:coffeecard/core/firebase_analytics_event_logging.dart'; import 'package:coffeecard/core/ignore_value.dart'; import 'package:coffeecard/core/network/network_request_executor.dart'; +import 'package:coffeecard/core/store_utils.dart'; import 'package:coffeecard/env/env.dart'; import 'package:coffeecard/features/authentication.dart'; import 'package:coffeecard/features/contributor/data/datasources/contributor_local_data_source.dart'; @@ -123,7 +124,7 @@ void initAuthentication() { // repository sl.registerLazySingletonAsync( () async => AuthenticationRepository( - store: await Hive.openBox('authenticationInfo'), + store: await Hive.openEncryptedBox('auth').run(), logger: sl(), ), );