From 1caf270c4ff944ff66bf3526f621030cb7f32dba Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Mon, 6 Nov 2023 14:43:31 +0100 Subject: [PATCH 1/5] [Re-login] Upgrade the new implementation of FlutterSecureStorage for iOS --- pubspec.lock | 63 ++++++++++++++++++++++++++++------------------------ pubspec.yaml | 29 ++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 31 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index f130f1c8f..4ce97e56b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -981,43 +981,48 @@ packages: flutter_secure_storage: dependency: "direct main" description: - name: flutter_secure_storage - sha256: f2afec1f1762c040a349ea2a588e32f442da5d0db3494a52a929a97c9e550bc5 - url: "https://pub.dev" - source: hosted - version: "7.0.1" + path: flutter_secure_storage + ref: develop + resolved-ref: "3bb93366161a787b07c45d8ce98c7405b40fbf1f" + url: "https://github.com/mogol/flutter_secure_storage.git" + source: git + version: "9.0.0" flutter_secure_storage_linux: - dependency: transitive + dependency: "direct overridden" description: - name: flutter_secure_storage_linux - sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3" - url: "https://pub.dev" - source: hosted - version: "1.1.3" + path: flutter_secure_storage_linux + ref: develop + resolved-ref: "3bb93366161a787b07c45d8ce98c7405b40fbf1f" + url: "https://github.com/mogol/flutter_secure_storage.git" + source: git + version: "1.2.0" flutter_secure_storage_macos: - dependency: transitive + dependency: "direct overridden" description: - name: flutter_secure_storage_macos - sha256: ff0768a6700ea1d9620e03518e2e25eac86a8bd07ca3556e9617bfa5ace4bd00 - url: "https://pub.dev" - source: hosted - version: "2.0.1" + path: flutter_secure_storage_macos + ref: develop + resolved-ref: "3bb93366161a787b07c45d8ce98c7405b40fbf1f" + url: "https://github.com/mogol/flutter_secure_storage.git" + source: git + version: "3.0.1" flutter_secure_storage_platform_interface: - dependency: transitive + dependency: "direct overridden" description: - name: flutter_secure_storage_platform_interface - sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b - url: "https://pub.dev" - source: hosted - version: "1.0.1" + path: flutter_secure_storage_platform_interface + ref: develop + resolved-ref: "3bb93366161a787b07c45d8ce98c7405b40fbf1f" + url: "https://github.com/mogol/flutter_secure_storage.git" + source: git + version: "1.0.2" flutter_secure_storage_web: - dependency: transitive + dependency: "direct overridden" description: - name: flutter_secure_storage_web - sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" - url: "https://pub.dev" - source: hosted - version: "1.1.1" + path: flutter_secure_storage_web + ref: patch-1 + resolved-ref: bd5db8cb928dbaca33e5551c1edae17d6d547306 + url: "https://github.com/hoangdat/flutter_secure_storage.git" + source: git + version: "1.1.2" flutter_secure_storage_windows: dependency: "direct overridden" description: diff --git a/pubspec.yaml b/pubspec.yaml index 818513571..24e90065c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,7 +41,12 @@ dependencies: flutter_olm: ^1.2.0 flutter_openssl_crypto: ^0.1.0 flutter_ringtone_player: ^3.1.1 - flutter_secure_storage: ^7.0.1 + # FIXME: change to pub.dev package when the fix for keychain iOS releases + flutter_secure_storage: + git: + url: https://github.com/mogol/flutter_secure_storage.git + path: flutter_secure_storage + ref: develop flutter_svg: ^0.22.0 # FIXME: change to upstream when https://github.com/AbdulRahmanAlHamali/flutter_typeahead/pull/528 is merge flutter_typeahead: @@ -246,7 +251,27 @@ dependency_overrides: git: url: https://github.com/linagora/matrix_link_text.git ref: twake-supported - + # FIXME: remove it when the fix in flutter_secure_storage for iOS releases + flutter_secure_storage_platform_interface: + git: + url: https://github.com/mogol/flutter_secure_storage.git + path: flutter_secure_storage_platform_interface + ref: develop + flutter_secure_storage_web: + git: + url: https://github.com/hoangdat/flutter_secure_storage.git + path: flutter_secure_storage_web + ref: patch-1 + flutter_secure_storage_linux: + git: + url: https://github.com/mogol/flutter_secure_storage.git + path: flutter_secure_storage_linux + ref: develop + flutter_secure_storage_macos: + git: + url: https://github.com/mogol/flutter_secure_storage.git + path: flutter_secure_storage_macos + ref: develop cider: link_template: tag: https://github.com/linagora/twake-on-matrix/releases/tag/%tag% # initial release link template From f2b9b5f326ebd63f1de34eafa8f6344d9ef0fb70 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Mon, 6 Nov 2023 14:45:08 +0100 Subject: [PATCH 2/5] [Re-login] Pod install for iOS --- ios/Podfile | 4 ++-- ios/Runner.xcodeproj/project.pbxproj | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index 90a88d685..e349e37e0 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '11.0' +platform :ios, '11.3' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -49,7 +49,7 @@ post_install do |installer| config.build_settings['ENABLE_BITCODE'] = 'NO' # see https://github.com/flutter-webrtc/flutter-webrtc/issues/1054 - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.3' config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = 'arm64 i386' config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index a5ede7eac..55847c39c 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -660,7 +660,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -757,7 +757,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -807,7 +807,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; From 1a9415609e65ad65fd9200e7d737bce63699dc08 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Mon, 6 Nov 2023 15:15:05 +0100 Subject: [PATCH 3/5] [Re-login] Wrapped Secure Storage for Twake with new synchronization read for protected data in iOS --- .../twake_secure_storage.dart | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 lib/utils/matrix_sdk_extensions/twake_secure_storage.dart diff --git a/lib/utils/matrix_sdk_extensions/twake_secure_storage.dart b/lib/utils/matrix_sdk_extensions/twake_secure_storage.dart new file mode 100644 index 000000000..95cb34e7c --- /dev/null +++ b/lib/utils/matrix_sdk_extensions/twake_secure_storage.dart @@ -0,0 +1,110 @@ +import 'dart:async'; + +import 'package:fluffychat/utils/famedlysdk_store.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:matrix/matrix.dart'; + +class TwakeSecureStorage { + final String _databaseBuiltKey = 'db_built_key'; + + TwakeSecureStorage._(); + + static final TwakeSecureStorage _instance = TwakeSecureStorage._(); + + factory TwakeSecureStorage() => _instance; + + Store? _store; + + Store get store => _store ??= Store(); + + final FlutterSecureStorage _flutterSecureStorage = const FlutterSecureStorage( + iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock), + ); + + Future markDatabaseBuilt() { + return store.setItemBool(_databaseBuiltKey, true); + } + + Future markDatabaseNotBuilt() { + return store.setItemBool(_databaseBuiltKey, false); + } + + Future isDatabaseBuilt() async { + return await store.getItemBool(_databaseBuiltKey, false); + } + + Future deleteEncryptionKey({ + required String key, + }) async { + await markDatabaseNotBuilt(); + await _flutterSecureStorage.delete(key: key); + } + + Future writeEncryptionKey({ + required String key, + required String value, + }) async { + await _flutterSecureStorage.write(key: key, value: value); + await markDatabaseBuilt(); + } + + Future containsEncryptionKey(String key) async { + final dbBuilt = await isDatabaseBuilt(); + if (dbBuilt) { + return await _platformContainsEncryptionKey(key); + } else { + return false; + } + } + + Future _platformContainsEncryptionKey(String key) async { + if (PlatformInfos.isIOS) { + final isAvailable = + await _flutterSecureStorage.isCupertinoProtectedDataAvailable(); + if (isAvailable) { + final value = await _flutterSecureStorage.read(key: key); + return value != null; + } + + Logs().wtf('Cupertino protected data is not available'); + final completer = Completer(); + late StreamSubscription subscription; + subscription = _flutterSecureStorage + .onCupertinoProtectedDataAvailabilityChanged + .listen((protectedDataAvailable) { + Logs().wtf( + 'onCupertinoProtectedDataAvailabilityChanged: $protectedDataAvailable'); + if (protectedDataAvailable) { + completer.complete(_flutterSecureStorage.read(key: key)); + subscription.cancel(); + } + }); + final value = await completer.future; + Logs().wtf('onCupertinoProtectedDataAvailabilityChanged: done'); + return value != null; + } else { + final value = await _flutterSecureStorage.read(key: key); + return value != null; + } + } + + Future read({ + required String key, + }) async { + return _flutterSecureStorage.read(key: key); + } + + Future write({ + required String key, + required String? value, + }) async { + await _flutterSecureStorage.write(key: key, value: value); + } + + Future delete({ + required String key, + }) async { + await _flutterSecureStorage.delete(key: key); + } +} From 18a90819731868b81dbd92c4882343de2ac9c909 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Mon, 6 Nov 2023 15:15:31 +0100 Subject: [PATCH 4/5] [Re-login] Apply Twake Secure Storage for all the usage --- .../hive/hive_collection_tom_database.dart | 18 +++++++++--------- lib/main.dart | 8 ++++---- lib/pages/bootstrap/bootstrap_dialog.dart | 6 +++--- .../settings_security/settings_security.dart | 13 ++++++------- .../flutter_hive_collections_database.dart | 12 ++++++------ lib/widgets/lock_screen.dart | 12 ++++++------ lib/widgets/matrix.dart | 5 ++--- 7 files changed, 36 insertions(+), 38 deletions(-) diff --git a/lib/data/hive/hive_collection_tom_database.dart b/lib/data/hive/hive_collection_tom_database.dart index 93c01c477..8a91def5a 100644 --- a/lib/data/hive/hive_collection_tom_database.dart +++ b/lib/data/hive/hive_collection_tom_database.dart @@ -1,10 +1,11 @@ import 'dart:convert'; import 'dart:io'; + import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart'; +import 'package:fluffychat/utils/matrix_sdk_extensions/twake_secure_storage.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hive/hive.dart'; import 'package:matrix/matrix.dart'; import 'package:path_provider/path_provider.dart'; @@ -31,11 +32,10 @@ class HiveCollectionToMDatabase { throw MissingPluginException(); } - const secureStorage = FlutterSecureStorage(); - final containsEncryptionKey = await secureStorage.read( - key: FlutterHiveCollectionsDatabase.cipherStorageKey, - ) != - null; + final secureStorage = TwakeSecureStorage(); + final containsEncryptionKey = await secureStorage.containsEncryptionKey( + FlutterHiveCollectionsDatabase.cipherStorageKey, + ); if (!containsEncryptionKey) { // do not try to create a buggy secure storage for new Linux users if (Platform.isLinux) throw MissingPluginException(); @@ -54,12 +54,12 @@ class HiveCollectionToMDatabase { hiverCipher = HiveAesCipher(base64Url.decode(rawEncryptionKey)); } on MissingPluginException catch (_) { - const FlutterSecureStorage() + TwakeSecureStorage() .delete(key: FlutterHiveCollectionsDatabase.cipherStorageKey) .catchError((_) {}); Logs().i('Hive encryption is not supported on this platform'); } catch (e, s) { - const FlutterSecureStorage() + TwakeSecureStorage() .delete(key: FlutterHiveCollectionsDatabase.cipherStorageKey) .catchError((_) {}); Logs().w('Unable to init Hive encryption', e, s); @@ -74,7 +74,7 @@ class HiveCollectionToMDatabase { await db.open(); } catch (e, s) { Logs().w('Unable to open ToM Hive.', e, s); - const FlutterSecureStorage() + TwakeSecureStorage() .delete(key: FlutterHiveCollectionsDatabase.cipherStorageKey); await db.clear().catchError((_) {}); await Hive.deleteFromDisk(); diff --git a/lib/main.dart b/lib/main.dart index f25be1051..1b2c2ebf3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,16 +3,17 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/di/global/get_it_initializer.dart'; import 'package:fluffychat/utils/client_manager.dart'; +import 'package:fluffychat/utils/matrix_sdk_extensions/twake_secure_storage.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app_lock/flutter_app_lock.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; import 'package:media_kit/media_kit.dart'; + import 'utils/background_push.dart'; -import 'widgets/twake_app.dart'; import 'widgets/lock_screen.dart'; +import 'widgets/twake_app.dart'; void main() async { // Our background push shared isolate accesses flutter-internal things very early in the startup proccess @@ -60,8 +61,7 @@ Future startGui(List clients) async { String? pin; if (PlatformInfos.isMobile) { try { - pin = - await const FlutterSecureStorage().read(key: SettingKeys.appLockKey); + pin = await TwakeSecureStorage().read(key: SettingKeys.appLockKey); } catch (e, s) { Logs().d('Unable to read PIN from Secure storage', e, s); } diff --git a/lib/pages/bootstrap/bootstrap_dialog.dart b/lib/pages/bootstrap/bootstrap_dialog.dart index cdccb7c3b..dee1c4092 100644 --- a/lib/pages/bootstrap/bootstrap_dialog.dart +++ b/lib/pages/bootstrap/bootstrap_dialog.dart @@ -1,12 +1,12 @@ import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/bootstrap/tom_bootstrap_dialog.dart'; +import 'package:fluffychat/utils/matrix_sdk_extensions/twake_secure_storage.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/adaptive_flat_button.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:matrix/encryption.dart'; @@ -90,7 +90,7 @@ class BootstrapDialogState extends State { _recoveryKeyStored = false; bootstrap = widget.client.encryption!.bootstrap(onUpdate: (_) => setState(() {})); - final key = await const FlutterSecureStorage().read(key: _secureStorageKey); + final key = await TwakeSecureStorage().read(key: _secureStorageKey); if (key == null) return; _recoveryKeyTextEditingController.text = key; } @@ -188,7 +188,7 @@ class BootstrapDialogState extends State { (_recoveryKeyCopied || _storeInSecureStorage == true) ? () { if (_storeInSecureStorage == true) { - const FlutterSecureStorage().write( + TwakeSecureStorage().write( key: _secureStorageKey, value: key, ); diff --git a/lib/pages/settings_dashboard/settings_security/settings_security.dart b/lib/pages/settings_dashboard/settings_security/settings_security.dart index 45ac6a703..1f7471e88 100644 --- a/lib/pages/settings_dashboard/settings_security/settings_security.dart +++ b/lib/pages/settings_dashboard/settings_security/settings_security.dart @@ -1,21 +1,20 @@ import 'dart:convert'; import 'dart:typed_data'; +import 'package:adaptive_dialog/adaptive_dialog.dart'; +import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/pages/bootstrap/bootstrap_dialog.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart'; +import 'package:fluffychat/utils/matrix_sdk_extensions/twake_secure_storage.dart'; import 'package:fluffychat/utils/twake_snackbar.dart'; +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; - -import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flutter_app_lock/flutter_app_lock.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:intl/intl.dart'; import 'package:matrix/matrix.dart'; -import 'package:fluffychat/config/setting_keys.dart'; -import 'package:fluffychat/widgets/matrix.dart'; import 'settings_security_view.dart'; class SettingsSecurity extends StatefulWidget { @@ -62,7 +61,7 @@ class SettingsSecurityController extends State { void setAppLockAction() async { final currentLock = - await const FlutterSecureStorage().read(key: SettingKeys.appLockKey); + await TwakeSecureStorage().read(key: SettingKeys.appLockKey); if (currentLock?.isNotEmpty ?? false) { await AppLock.of(context)!.showLockScreen(); } @@ -89,7 +88,7 @@ class SettingsSecurityController extends State { ], ); if (newLock != null) { - await const FlutterSecureStorage() + await TwakeSecureStorage() .write(key: SettingKeys.appLockKey, value: newLock.single); if (newLock.single.isEmpty) { AppLock.of(context)!.disable(); diff --git a/lib/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart b/lib/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart index ddcd97de2..583f7522e 100644 --- a/lib/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart +++ b/lib/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:fluffychat/utils/matrix_sdk_extensions/twake_secure_storage.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/foundation.dart' hide Key; import 'package:flutter/services.dart'; @@ -34,14 +35,14 @@ class FlutterHiveCollectionsDatabase extends HiveCollectionsDatabase { throw MissingPluginException(); } - const secureStorage = FlutterSecureStorage(); + final secureStorage = TwakeSecureStorage(); final containsEncryptionKey = - await secureStorage.read(key: cipherStorageKey) != null; + await secureStorage.containsEncryptionKey(cipherStorageKey); if (!containsEncryptionKey) { // do not try to create a buggy secure storage for new Linux users if (Platform.isLinux) throw MissingPluginException(); final key = Hive.generateSecureKey(); - await secureStorage.write( + await secureStorage.writeEncryptionKey( key: cipherStorageKey, value: base64UrlEncode(key), ); @@ -58,8 +59,7 @@ class FlutterHiveCollectionsDatabase extends HiveCollectionsDatabase { .catchError((_) {}); Logs().i('Hive encryption is not supported on this platform'); } catch (e, s) { - const FlutterSecureStorage() - .delete(key: cipherStorageKey) + TwakeSecureStorage().delete(key: cipherStorageKey) .catchError((_) {}); Logs().w('Unable to init Hive encryption', e, s); } @@ -74,7 +74,7 @@ class FlutterHiveCollectionsDatabase extends HiveCollectionsDatabase { await db.open(); } catch (e, s) { Logs().w('Unable to open Hive. Delete database and storage key...', e, s); - const FlutterSecureStorage().delete(key: cipherStorageKey); + TwakeSecureStorage().delete(key: cipherStorageKey); await db .clear(supportDeleteCollections: !PlatformInfos.isWeb) .catchError((_) {}); diff --git a/lib/widgets/lock_screen.dart b/lib/widgets/lock_screen.dart index 07d55f405..cd1540691 100644 --- a/lib/widgets/lock_screen.dart +++ b/lib/widgets/lock_screen.dart @@ -1,14 +1,13 @@ +import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/config/setting_keys.dart'; +import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/utils/matrix_sdk_extensions/twake_secure_storage.dart'; import 'package:flutter/material.dart'; - import 'package:flutter_app_lock/flutter_app_lock.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:pin_code_text_field/pin_code_text_field.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/config/setting_keys.dart'; -import 'package:fluffychat/config/themes.dart'; import 'layouts/login_scaffold.dart'; class LockScreen extends StatefulWidget { @@ -22,6 +21,7 @@ class LockScreenState extends State { final TextEditingController _textEditingController = TextEditingController(); final FocusNode _focusNode = FocusNode(); bool _wrongInput = false; + @override Widget build(BuildContext context) { return MaterialApp( @@ -74,7 +74,7 @@ class LockScreenState extends State { ? SharedPreferences.getInstance().then( (prefs) => prefs.getString(SettingKeys.appLockKey), ) - : const FlutterSecureStorage() + : TwakeSecureStorage() .read(key: SettingKeys.appLockKey))) { AppLock.of(context)!.didUnlock(); } else { diff --git a/lib/widgets/matrix.dart b/lib/widgets/matrix.dart index 39bd7784a..630725d6f 100644 --- a/lib/widgets/matrix.dart +++ b/lib/widgets/matrix.dart @@ -17,6 +17,7 @@ import 'package:fluffychat/domain/repository/tom_configurations_repository.dart' import 'package:fluffychat/pages/chat_list/receive_sharing_intent_mixin.dart'; import 'package:fluffychat/utils/client_manager.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; +import 'package:fluffychat/utils/matrix_sdk_extensions/twake_secure_storage.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/twake_snackbar.dart'; import 'package:fluffychat/utils/uia_request_manager.dart'; @@ -27,7 +28,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app_lock/flutter_app_lock.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:http/http.dart' as http; import 'package:image_picker/image_picker.dart'; @@ -404,8 +404,7 @@ class MatrixState extends State ([TargetPlatform.linux].contains(Theme.of(context).platform) ? SharedPreferences.getInstance() .then((prefs) => prefs.getString(SettingKeys.appLockKey)) - : const FlutterSecureStorage() - .read(key: SettingKeys.appLockKey)) + : TwakeSecureStorage().read(key: SettingKeys.appLockKey)) .then((lock) { if (lock?.isNotEmpty ?? false) { AppLock.of(context)!.enable(); From 24fbdf99da8459eb62ec5fd5eedec6e2c02a9134 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Wed, 8 Nov 2023 16:35:38 +0100 Subject: [PATCH 5/5] [Re-login] Catch the exception of iOS platform write duplicated key --- .../twake_secure_storage.dart | 50 ++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/lib/utils/matrix_sdk_extensions/twake_secure_storage.dart b/lib/utils/matrix_sdk_extensions/twake_secure_storage.dart index 95cb34e7c..2e1203ca6 100644 --- a/lib/utils/matrix_sdk_extensions/twake_secure_storage.dart +++ b/lib/utils/matrix_sdk_extensions/twake_secure_storage.dart @@ -2,10 +2,12 @@ import 'dart:async'; import 'package:fluffychat/utils/famedlysdk_store.dart'; import 'package:fluffychat/utils/platform_infos.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:matrix/matrix.dart'; class TwakeSecureStorage { + final String _iOSDuplicatedKeyExceptionCode = '-25299'; final String _databaseBuiltKey = 'db_built_key'; TwakeSecureStorage._(); @@ -45,13 +47,27 @@ class TwakeSecureStorage { required String key, required String value, }) async { - await _flutterSecureStorage.write(key: key, value: value); - await markDatabaseBuilt(); + try { + await _flutterSecureStorage.write(key: key, value: value); + await markDatabaseBuilt(); + } on PlatformException catch (e, s) { + Logs().e('TwakeSecureStorage::writeEncryptionKey() $e $s'); + if (PlatformInfos.isIOS) { + if (_isDuplicatedIOSKeyException(e)) { + await delete(key: key); + await _flutterSecureStorage.write(key: key, value: value); + await markDatabaseBuilt(); + } + } + rethrow; + } } Future containsEncryptionKey(String key) async { final dbBuilt = await isDatabaseBuilt(); if (dbBuilt) { + Logs() + .i('TwakeSecureStorage::containsEncryptionKey() database was built'); return await _platformContainsEncryptionKey(key); } else { return false; @@ -63,18 +79,22 @@ class TwakeSecureStorage { final isAvailable = await _flutterSecureStorage.isCupertinoProtectedDataAvailable(); if (isAvailable) { + Logs().i( + 'TwakeSecureStorage::_platformContainsEncryptionKey() Cupertino protected data is available'); final value = await _flutterSecureStorage.read(key: key); return value != null; } - Logs().wtf('Cupertino protected data is not available'); + Logs().i( + 'TwakeSecureStorage::_platformContainsEncryptionKey() Cupertino protected data is not available'); final completer = Completer(); late StreamSubscription subscription; subscription = _flutterSecureStorage .onCupertinoProtectedDataAvailabilityChanged .listen((protectedDataAvailable) { - Logs().wtf( - 'onCupertinoProtectedDataAvailabilityChanged: $protectedDataAvailable'); + Logs().i( + 'TwakeSecureStorage::_platformContainsEncryptionKey() onCupertinoProtectedDataAvailabilityChanged: $protectedDataAvailable', + ); if (protectedDataAvailable) { completer.complete(_flutterSecureStorage.read(key: key)); subscription.cancel(); @@ -99,7 +119,18 @@ class TwakeSecureStorage { required String key, required String? value, }) async { - await _flutterSecureStorage.write(key: key, value: value); + try { + await _flutterSecureStorage.write(key: key, value: value); + } on PlatformException catch (e, s) { + Logs().e('TwakeSecureStorage::write() $e $s'); + if (PlatformInfos.isIOS) { + if (_isDuplicatedIOSKeyException(e)) { + await delete(key: key); + await _flutterSecureStorage.write(key: key, value: value); + } + } + rethrow; + } } Future delete({ @@ -107,4 +138,11 @@ class TwakeSecureStorage { }) async { await _flutterSecureStorage.delete(key: key); } + + bool _isDuplicatedIOSKeyException(PlatformException platformException) { + if (platformException.code == _iOSDuplicatedKeyExceptionCode) { + return true; + } + return false; + } }