diff --git a/.gitignore b/.gitignore index 060139668..ff7f52574 100644 --- a/.gitignore +++ b/.gitignore @@ -156,6 +156,7 @@ assets/images/app_logo.png macos/Runner/Info.plist macos/Runner/DebugProfile.entitlements macos/Runner/Release.entitlements +lib/core/secure_storage.dart lib/core/secure_storage.dart diff --git a/lib/core/auth_service.dart b/lib/core/auth_service.dart index 08a45cada..791701395 100644 --- a/lib/core/auth_service.dart +++ b/lib/core/auth_service.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:io'; import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/core/totp_request_details.dart'; @@ -7,7 +6,6 @@ import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart'; import 'package:flutter/material.dart'; import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/core/secure_storage.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart'; @@ -42,7 +40,7 @@ class AuthService with Store { Future setPassword(String password) async { final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); final encodedPassword = encodedPinCode(pin: password); - await writeSecureStorage(secureStorage, key: key, value: encodedPassword); + await secureStorage.write(key: key, value: encodedPassword); } Future canAuthenticate() async { @@ -69,11 +67,7 @@ class AuthService with Store { void saveLastAuthTime() { int timestamp = DateTime.now().millisecondsSinceEpoch; - writeSecureStorage( - secureStorage, - key: SecureKey.lastAuthTimeMilliseconds, - value: timestamp.toString(), - ); + secureStorage.write(key: SecureKey.lastAuthTimeMilliseconds, value: timestamp.toString()); } Future requireAuth() async { diff --git a/lib/core/backup_service.dart b/lib/core/backup_service.dart index 7c9dc0580..73c2e047e 100644 --- a/lib/core/backup_service.dart +++ b/lib/core/backup_service.dart @@ -8,7 +8,6 @@ import 'package:cake_wallet/utils/device_info.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; -import 'package:cake_wallet/core/secure_storage.dart'; import 'package:path_provider/path_provider.dart'; import 'package:cryptography/cryptography.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -25,7 +24,7 @@ import 'package:cake_backup/backup.dart' as cake_backup; class BackupService { BackupService( - this._flutterSecureStorage, this._walletInfoSource, this._keyService, this._sharedPreferences) + this._secureStorage, this._walletInfoSource, this._keyService, this._sharedPreferences) : _cipher = Cryptography.instance.chacha20Poly1305Aead(), _correctWallets = []; @@ -35,7 +34,7 @@ class BackupService { static const _v2 = 2; final Cipher _cipher; - final SecureStorage _flutterSecureStorage; + final SecureStorage _secureStorage; final SharedPreferences _sharedPreferences; final Box _walletInfoSource; final KeyService _keyService; @@ -376,15 +375,14 @@ class BackupService { final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword); final backupPassword = keychainJSON[backupPasswordKey] as String; - await writeSecureStorage(_flutterSecureStorage, key: backupPasswordKey, value: backupPassword); + await _secureStorage.write(key: backupPasswordKey, value: backupPassword); keychainWalletsInfo.forEach((dynamic rawInfo) async { final info = rawInfo as Map; await importWalletKeychainInfo(info); }); - await writeSecureStorage(_flutterSecureStorage, - key: pinCodeKey, value: encodedPinCode(pin: decodedPin)); + await _secureStorage.write(key: pinCodeKey, value: encodedPinCode(pin: decodedPin)); keychainDumpFile.deleteSync(); } @@ -403,15 +401,14 @@ class BackupService { final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword); final backupPassword = keychainJSON[backupPasswordKey] as String; - await writeSecureStorage(_flutterSecureStorage, key: backupPasswordKey, value: backupPassword); + await _secureStorage.write(key: backupPasswordKey, value: backupPassword); keychainWalletsInfo.forEach((dynamic rawInfo) async { final info = rawInfo as Map; await importWalletKeychainInfo(info); }); - await writeSecureStorage(_flutterSecureStorage, - key: pinCodeKey, value: encodedPinCode(pin: decodedPin)); + await _secureStorage.write(key: pinCodeKey, value: encodedPinCode(pin: decodedPin)); keychainDumpFile.deleteSync(); } @@ -431,7 +428,7 @@ class BackupService { Future _exportKeychainDumpV2(String password, {String keychainSalt = secrets.backupKeychainSalt}) async { final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); - final encodedPin = await _flutterSecureStorage.read(key: key); + final encodedPin = await _secureStorage.read(key: key); final decodedPin = decodedPinCode(pin: encodedPin!); final wallets = await Future.wait(_walletInfoSource.values.map((walletInfo) async { return { @@ -441,7 +438,7 @@ class BackupService { }; })); final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword); - final backupPassword = await _flutterSecureStorage.read(key: backupPasswordKey); + final backupPassword = await _secureStorage.read(key: backupPasswordKey); final data = utf8.encode( json.encode({'pin': decodedPin, 'wallets': wallets, backupPasswordKey: backupPassword})); final encrypted = await _encryptV2(Uint8List.fromList(data), '$keychainSalt$password'); diff --git a/lib/core/key_service.dart b/lib/core/key_service.dart index 2062ee01e..71fb5a4fc 100644 --- a/lib/core/key_service.dart +++ b/lib/core/key_service.dart @@ -8,23 +8,23 @@ class KeyService { final SecureStorage _secureStorage; Future getWalletPassword({required String walletName}) async { - final key = generateStoreKeyFor( - key: SecretStoreKey.moneroWalletPassword, walletName: walletName); + final key = + generateStoreKeyFor(key: SecretStoreKey.moneroWalletPassword, walletName: walletName); final encodedPassword = await _secureStorage.read(key: key); return decodeWalletPassword(password: encodedPassword!); } Future saveWalletPassword({required String walletName, required String password}) async { - final key = generateStoreKeyFor( - key: SecretStoreKey.moneroWalletPassword, walletName: walletName); + final key = + generateStoreKeyFor(key: SecretStoreKey.moneroWalletPassword, walletName: walletName); final encodedPassword = encodeWalletPassword(password: password); - await writeSecureStorage(_secureStorage, key: key, value: encodedPassword); + await _secureStorage.write(key: key, value: encodedPassword); } Future deleteWalletPassword({required String walletName}) async { - final key = generateStoreKeyFor( - key: SecretStoreKey.moneroWalletPassword, walletName: walletName); + final key = + generateStoreKeyFor(key: SecretStoreKey.moneroWalletPassword, walletName: walletName); await _secureStorage.delete(key: key); } diff --git a/lib/core/secure_storage.dart b/lib/core/secure_storage.dart deleted file mode 100644 index 5afb36d29..000000000 --- a/lib/core/secure_storage.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -// For now, we can create a utility function to handle this. -// -// However, we could look into abstracting the entire FlutterSecureStorage package -// so the app doesn't depend on the package directly but an absraction. -// It'll make these kind of modifications to read/write come from a single point. - -Future readSecureStorage(FlutterSecureStorage secureStorage, String key) async { - String? result; - const maxWait = Duration(seconds: 3); - const checkInterval = Duration(milliseconds: 200); - - DateTime start = DateTime.now(); - - while (result == null && DateTime.now().difference(start) < maxWait) { - result = await secureStorage.read(key: key); - - if (result != null) { - break; - } - - await Future.delayed(checkInterval); - } - - return result; -} - -Future writeSecureStorage(FlutterSecureStorage secureStorage, - {required String key, required String value}) async { - // delete the value before writing on macOS because of a weird bug - // https://github.com/mogol/flutter_secure_storage/issues/581 - if (Platform.isMacOS) { - await secureStorage.delete(key: key); - } - await secureStorage.write(key: key, value: value); -} diff --git a/lib/core/wallet_creation_service.dart b/lib/core/wallet_creation_service.dart index 2cd018756..ba4052248 100644 --- a/lib/core/wallet_creation_service.dart +++ b/lib/core/wallet_creation_service.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cw_core/wallet_info.dart'; diff --git a/lib/di.dart b/lib/di.dart index c83f424af..38a7b3508 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -357,6 +357,32 @@ import 'package:cake_wallet/core/wallet_loading_service.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_page.dart'; import 'package:cake_wallet/entities/qr_view_data.dart'; +import 'package:cake_wallet/core/secure_storage.dart'; +import 'package:cake_wallet/core/wallet_creation_service.dart'; +import 'package:cake_wallet/store/app_store.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:cake_wallet/view_model/wallet_new_vm.dart'; +import 'package:cake_wallet/store/authentication_store.dart'; +import 'package:cake_wallet/store/dashboard/trades_store.dart'; +import 'package:cake_wallet/store/dashboard/trade_filter_store.dart'; +import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart'; +import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; +import 'package:cake_wallet/store/templates/send_template_store.dart'; +import 'package:cake_wallet/store/templates/exchange_template_store.dart'; +import 'package:cake_wallet/entities/template.dart'; +import 'package:cake_wallet/exchange/exchange_template.dart'; +import 'package:cake_wallet/.secrets.g.dart' as secrets; +import 'package:cake_wallet/src/screens/dashboard/pages/address_page.dart'; +import 'package:cake_wallet/anypay/anypay_api.dart'; +import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart'; +import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart'; +import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart'; +import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; +import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; +import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart'; +import 'package:cake_wallet/core/wallet_loading_service.dart'; +import 'package:cw_core/crypto_currency.dart'; +import 'package:cake_wallet/entities/qr_view_data.dart'; import 'buy/dfx/dfx_buy_provider.dart'; import 'core/totp_request_details.dart'; @@ -389,6 +415,7 @@ Future setup({ required Box ordersSource, required Box unspentCoinsInfoSource, required Box anonpayInvoiceInfoSource, + required SecureStorage secureStorage, required GlobalKey navigatorKey, }) async { _walletInfoSource = walletInfoSource; @@ -405,7 +432,7 @@ Future setup({ if (!_isSetupFinished) { getIt.registerSingletonAsync(() => SharedPreferences.getInstance()); - getIt.registerSingleton(secureStorageShared); + getIt.registerSingleton(secureStorage); } if (!_isSetupFinished) { getIt.registerFactory(() => BackgroundTasks()); @@ -453,7 +480,8 @@ Future setup({ getIt.registerSingleton( ExchangeTemplateStore(templateSource: _exchangeTemplates)); getIt.registerSingleton( - YatStore(appStore: getIt.get(), secureStorage: getIt.get())..init()); + YatStore(appStore: getIt.get(), secureStorage: getIt.get()) + ..init()); getIt.registerSingleton( AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource)); @@ -1113,8 +1141,8 @@ Future setup({ getIt.registerFactory(() => BackupPage(getIt.get())); - getIt.registerFactory( - () => EditBackupPasswordViewModel(getIt.get(), getIt.get())); + getIt.registerFactory(() => + EditBackupPasswordViewModel(getIt.get(), getIt.get())); getIt.registerFactory(() => EditBackupPasswordPage(getIt.get())); @@ -1162,8 +1190,8 @@ Future setup({ getIt.registerFactory(() => SupportPage(getIt.get())); - getIt.registerFactory(() => - SupportChatPage(getIt.get(), secureStorage: getIt.get())); + getIt.registerFactory(() => SupportChatPage(getIt.get(), + secureStorage: getIt.get())); getIt.registerFactory(() => SupportOtherLinksPage(getIt.get())); diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index b8ce16318..0d76a0a9a 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -1,10 +1,10 @@ import 'dart:io' show Directory, File, Platform; import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cake_wallet/entities/secret_store_key.dart'; -import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cw_core/root_dir.dart'; import 'package:hive/hive.dart'; import 'package:shared_preferences/shared_preferences.dart'; diff --git a/lib/entities/fs_migration.dart b/lib/entities/fs_migration.dart index 2ad26e1c8..14237f080 100644 --- a/lib/entities/fs_migration.dart +++ b/lib/entities/fs_migration.dart @@ -2,7 +2,6 @@ import 'dart:io'; import 'dart:convert'; import 'package:cake_wallet/core/secure_storage.dart'; import 'package:collection/collection.dart'; -import 'package:cake_wallet/core/secure_storage.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:hive/hive.dart'; import 'package:path_provider/path_provider.dart'; @@ -11,8 +10,7 @@ import 'package:cake_wallet/entities/contact.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/entities/encrypt.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; -import 'package:cake_wallet/entities/ios_legacy_helper.dart' - as ios_legacy_helper; +import 'package:cake_wallet/entities/ios_legacy_helper.dart' as ios_legacy_helper; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cw_core/wallet_info.dart'; @@ -30,8 +28,8 @@ Future migrate_android_v1() async { await android_migrate_wallets(appDocDir: appDocDir); } -Future ios_migrate_v1(Box walletInfoSource, - Box tradeSource, Box contactSource) async { +Future ios_migrate_v1( + Box walletInfoSource, Box tradeSource, Box contactSource) async { final prefs = await SharedPreferences.getInstance(); if (prefs.getBool('ios_migration_v1_completed') ?? false) { @@ -67,10 +65,7 @@ Future ios_migrate_user_defaults() async { if (activeCurrency != null) { final convertedCurrency = convertFiatLegacy(activeCurrency); - if (convertedCurrency != null) { - await prefs.setString( - 'current_fiat_currency', convertedCurrency.serialize()); - } + await prefs.setString('current_fiat_currency', convertedCurrency.serialize()); } //translate fee priority @@ -81,24 +76,21 @@ Future ios_migrate_user_defaults() async { } //translate current balance mode - final currentBalanceMode = - await ios_legacy_helper.getInt('display_balance_mode'); + final currentBalanceMode = await ios_legacy_helper.getInt('display_balance_mode'); if (currentBalanceMode != null) { await prefs.setInt('current_balance_display_mode', currentBalanceMode); } //translate should save recipient address - final shouldSave = - await ios_legacy_helper.getBool('should_save_recipient_address'); - + final shouldSave = await ios_legacy_helper.getBool('should_save_recipient_address'); + if (shouldSave != null) { await prefs.setBool('save_recipient_address', shouldSave); } //translate biometric - final biometricOn = - await ios_legacy_helper.getBool('biometric_authentication_on'); - + final biometricOn = await ios_legacy_helper.getBool('biometric_authentication_on'); + if (biometricOn != null) { await prefs.setBool('allow_biometrical_authentication', biometricOn); } @@ -147,7 +139,7 @@ Future ios_migrate_pin() async { final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); final encodedPassword = encodedPinCode(pin: pinPassword); - await writeSecureStorage(flutterSecureStorage, key: key, value: encodedPassword); + await flutterSecureStorage.write(key: key, value: encodedPassword); await prefs.setBool('ios_migration_pin_completed', true); } @@ -176,8 +168,7 @@ Future ios_migrate_wallet_passwords() async { final name = item.path.split('/').last; final oldKey = 'wallet_monero_' + name + '_password'; final password = await flutterSecureStorage.readNoIOptions(key: oldKey); - await keyService.saveWalletPassword( - walletName: name, password: password!); + await keyService.saveWalletPassword(walletName: name, password: password!); } } catch (e) { print(e.toString()); @@ -309,18 +300,14 @@ Future ios_migrate_wallet_info(Box walletsInfoSource) async { return null; } - final config = json.decode(configFile.readAsStringSync()) - as Map; - final isRecovery = config['isRecovery'] as bool ?? false; + final config = json.decode(configFile.readAsStringSync()) as Map; + final isRecovery = config['isRecovery'] as bool? ?? false; final dateAsDouble = config['date'] as double; final timestamp = dateAsDouble.toInt() * 1000; final date = DateTime.fromMillisecondsSinceEpoch(timestamp); - final id = walletTypeToString(WalletType.monero).toLowerCase() + - '_' + - name; - final exist = walletsInfoSource.values - .firstWhereOrNull((el) => el.id == id) != null; - + final id = walletTypeToString(WalletType.monero).toLowerCase() + '_' + name; + final exist = walletsInfoSource.values.firstWhereOrNull((el) => el.id == id) != null; + if (exist) { return null; } @@ -374,8 +361,7 @@ Future ios_migrate_trades_list(Box tradeSource) async { final flutterSecureStorage = secureStorageShared; final masterPassword = await flutterSecureStorage.readNoIOptions(key: 'master_password'); final key = masterPassword!.replaceAll('-', ''); - final decoded = - await ios_legacy_helper.decrypt(content, key: key, salt: secrets.salt); + final decoded = await ios_legacy_helper.decrypt(content, key: key, salt: secrets.salt); final decodedJson = json.decode(decoded) as List; final trades = decodedJson.map((dynamic el) { final elAsMap = el as Map; @@ -438,8 +424,7 @@ Future ios_migrate_address_book(Box contactSource) async { final address = _item["address"] as String; final name = _item["name"] as String; - return Contact( - address: address, name: name, type: CryptoCurrency.fromString(type)); + return Contact(address: address, name: name, type: CryptoCurrency.fromString(type)); }); await contactSource.addAll(contacts); diff --git a/lib/entities/get_encryption_key.dart b/lib/entities/get_encryption_key.dart index db03c76ae..618066cb8 100644 --- a/lib/entities/get_encryption_key.dart +++ b/lib/entities/get_encryption_key.dart @@ -3,15 +3,14 @@ import 'package:cw_core/cake_hive.dart'; Future> getEncryptionKey( {required String forKey, required SecureStorage secureStorage}) async { - final stringifiedKey = - await secureStorage.read(key: 'transactionDescriptionsBoxKey'); + final stringifiedKey = await secureStorage.read(key: 'transactionDescriptionsBoxKey'); List key; if (stringifiedKey == null) { key = CakeHive.generateSecureKey(); final keyStringified = key.join(','); String storageKey = 'transactionDescriptionsBoxKey'; - await writeSecureStorage(secureStorage, key: storageKey, value: keyStringified); + await secureStorage.write(key: storageKey, value: keyStringified); } else { key = stringifiedKey.split(',').map((i) => int.parse(i)).toList(); } diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index cf9ae3019..79177178c 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -61,9 +61,9 @@ class PreferencesKey { static const defaultBananoRep = 'default_banano_representative'; static const lookupsTwitter = 'looks_up_twitter'; static const lookupsMastodon = 'looks_up_mastodon'; - static const lookupsYatService = 'looks_up_mastodon'; - static const lookupsUnstoppableDomains = 'looks_up_mastodon'; - static const lookupsOpenAlias = 'looks_up_mastodon'; + static const lookupsYatService = 'looks_up_yat'; + static const lookupsUnstoppableDomains = 'looks_up_unstoppable_domain'; + static const lookupsOpenAlias = 'looks_up_open_alias'; static const lookupsENS = 'looks_up_ens'; static String moneroWalletUpdateV1Key(String name) => diff --git a/lib/ionia/ionia_service.dart b/lib/ionia/ionia_service.dart index 2beca6458..883133717 100644 --- a/lib/ionia/ionia_service.dart +++ b/lib/ionia/ionia_service.dart @@ -1,7 +1,7 @@ +import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/ionia/ionia_merchant.dart'; import 'package:cake_wallet/ionia/ionia_order.dart'; import 'package:cake_wallet/ionia/ionia_virtual_card.dart'; -import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/ionia/ionia_api.dart'; import 'package:cake_wallet/ionia/ionia_gift_card.dart'; diff --git a/lib/main.dart b/lib/main.dart index 8b8f0d4f8..86b2614e0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart'; import 'package:cake_wallet/core/auth_service.dart'; +import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/entities/language_service.dart'; import 'package:cake_wallet/buy/order.dart'; import 'package:cake_wallet/locales/locale.dart'; @@ -20,7 +21,6 @@ import 'package:hive/hive.dart'; import 'package:cake_wallet/di.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:cake_wallet/core/secure_storage.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/router.dart' as Router; diff --git a/lib/src/screens/support_chat/support_chat_page.dart b/lib/src/screens/support_chat/support_chat_page.dart index c7aa3a881..97d59a2d9 100644 --- a/lib/src/screens/support_chat/support_chat_page.dart +++ b/lib/src/screens/support_chat/support_chat_page.dart @@ -1,9 +1,9 @@ +import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/support_chat/widgets/chatwoot_widget.dart'; import 'package:cake_wallet/view_model/support_view_model.dart'; import 'package:flutter/material.dart'; -import 'package:cake_wallet/core/secure_storage.dart'; class SupportChatPage extends BasePage { diff --git a/lib/src/screens/support_chat/widgets/chatwoot_widget.dart b/lib/src/screens/support_chat/widgets/chatwoot_widget.dart index 66bdfd02f..b49993f7f 100644 --- a/lib/src/screens/support_chat/widgets/chatwoot_widget.dart +++ b/lib/src/screens/support_chat/widgets/chatwoot_widget.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'package:cake_wallet/core/secure_storage.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:cake_wallet/core/secure_storage.dart'; const COOKIE_KEY = 'chatwootCookie'; @@ -59,6 +58,6 @@ class ChatwootWidgetState extends State { } Future storeCookie(String value) async { - await writeSecureStorage(widget.secureStorage, key: COOKIE_KEY, value: value); + await widget.secureStorage.write(key: COOKIE_KEY, value: value); } } diff --git a/lib/store/secret_store.dart b/lib/store/secret_store.dart index fc66a0f74..aa185ae3d 100644 --- a/lib/store/secret_store.dart +++ b/lib/store/secret_store.dart @@ -1,6 +1,5 @@ -import 'package:cake_wallet/entities/secret_store_key.dart'; -import 'package:flutter/foundation.dart'; import 'package:cake_wallet/core/secure_storage.dart'; +import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:mobx/mobx.dart'; part 'secret_store.g.dart'; diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index 6f9b57dfb..5a9040cef 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -397,10 +397,8 @@ abstract class SettingsStoreBase with Store { (bool usePolygonScan) => _sharedPreferences.setBool(PreferencesKey.usePolygonScan, usePolygonScan)); - reaction( - (_) => useTronGrid, - (bool useTronGrid) => - _sharedPreferences.setBool(PreferencesKey.useTronGrid, useTronGrid)); + reaction((_) => useTronGrid, + (bool useTronGrid) => _sharedPreferences.setBool(PreferencesKey.useTronGrid, useTronGrid)); reaction((_) => defaultNanoRep, (String nanoRep) => _sharedPreferences.setString(PreferencesKey.defaultNanoRep, nanoRep)); @@ -440,83 +438,79 @@ abstract class SettingsStoreBase with Store { // secure storage keys: reaction( (_) => allowBiometricalAuthentication, - (bool biometricalAuthentication) => writeSecureStorage(secureStorage, + (bool biometricalAuthentication) => secureStorage.write( key: SecureKey.allowBiometricalAuthenticationKey, value: biometricalAuthentication.toString())); reaction( (_) => selectedCake2FAPreset, - (Cake2FAPresetsOptions selectedCake2FAPreset) => writeSecureStorage(secureStorage, + (Cake2FAPresetsOptions selectedCake2FAPreset) => secureStorage.write( key: SecureKey.selectedCake2FAPreset, value: selectedCake2FAPreset.serialize().toString())); reaction( (_) => shouldRequireTOTP2FAForAccessingWallet, - (bool requireTOTP2FAForAccessingWallet) => writeSecureStorage(secureStorage, + (bool requireTOTP2FAForAccessingWallet) => secureStorage.write( key: SecureKey.shouldRequireTOTP2FAForAccessingWallet, value: requireTOTP2FAForAccessingWallet.toString())); reaction( (_) => shouldRequireTOTP2FAForSendsToContact, - (bool requireTOTP2FAForSendsToContact) => writeSecureStorage(secureStorage, + (bool requireTOTP2FAForSendsToContact) => secureStorage.write( key: SecureKey.shouldRequireTOTP2FAForSendsToContact, value: requireTOTP2FAForSendsToContact.toString())); reaction( (_) => shouldRequireTOTP2FAForSendsToNonContact, - (bool requireTOTP2FAForSendsToNonContact) => writeSecureStorage(secureStorage, + (bool requireTOTP2FAForSendsToNonContact) => secureStorage.write( key: SecureKey.shouldRequireTOTP2FAForSendsToNonContact, value: requireTOTP2FAForSendsToNonContact.toString())); reaction( (_) => shouldRequireTOTP2FAForSendsToInternalWallets, - (bool requireTOTP2FAForSendsToInternalWallets) => writeSecureStorage(secureStorage, + (bool requireTOTP2FAForSendsToInternalWallets) => secureStorage.write( key: SecureKey.shouldRequireTOTP2FAForSendsToInternalWallets, value: requireTOTP2FAForSendsToInternalWallets.toString())); reaction( (_) => shouldRequireTOTP2FAForExchangesToInternalWallets, - (bool requireTOTP2FAForExchangesToInternalWallets) => writeSecureStorage(secureStorage, + (bool requireTOTP2FAForExchangesToInternalWallets) => secureStorage.write( key: SecureKey.shouldRequireTOTP2FAForExchangesToInternalWallets, value: requireTOTP2FAForExchangesToInternalWallets.toString())); reaction( (_) => shouldRequireTOTP2FAForExchangesToExternalWallets, - (bool requireTOTP2FAForExchangesToExternalWallets) => writeSecureStorage(secureStorage, + (bool requireTOTP2FAForExchangesToExternalWallets) => secureStorage.write( key: SecureKey.shouldRequireTOTP2FAForExchangesToExternalWallets, value: requireTOTP2FAForExchangesToExternalWallets.toString())); reaction( (_) => shouldRequireTOTP2FAForAddingContacts, - (bool requireTOTP2FAForAddingContacts) => writeSecureStorage(secureStorage, + (bool requireTOTP2FAForAddingContacts) => secureStorage.write( key: SecureKey.shouldRequireTOTP2FAForAddingContacts, value: requireTOTP2FAForAddingContacts.toString())); reaction( (_) => shouldRequireTOTP2FAForCreatingNewWallets, - (bool requireTOTP2FAForCreatingNewWallets) => writeSecureStorage(secureStorage, + (bool requireTOTP2FAForCreatingNewWallets) => secureStorage.write( key: SecureKey.shouldRequireTOTP2FAForCreatingNewWallets, value: requireTOTP2FAForCreatingNewWallets.toString())); reaction( (_) => shouldRequireTOTP2FAForAllSecurityAndBackupSettings, - (bool requireTOTP2FAForAllSecurityAndBackupSettings) => writeSecureStorage(secureStorage, + (bool requireTOTP2FAForAllSecurityAndBackupSettings) => secureStorage.write( key: SecureKey.shouldRequireTOTP2FAForAllSecurityAndBackupSettings, value: requireTOTP2FAForAllSecurityAndBackupSettings.toString())); - reaction( - (_) => useTOTP2FA, - (bool use) => - writeSecureStorage(secureStorage, key: SecureKey.useTOTP2FA, value: use.toString())); + reaction((_) => useTOTP2FA, + (bool use) => secureStorage.write(key: SecureKey.useTOTP2FA, value: use.toString())); - reaction( - (_) => totpSecretKey, - (String totpKey) => - writeSecureStorage(secureStorage, key: SecureKey.totpSecretKey, value: totpKey)); + reaction((_) => totpSecretKey, + (String totpKey) => secureStorage.write(key: SecureKey.totpSecretKey, value: totpKey)); reaction( (_) => pinTimeOutDuration, - (PinCodeRequiredDuration pinCodeInterval) => writeSecureStorage(secureStorage, + (PinCodeRequiredDuration pinCodeInterval) => secureStorage.write( key: SecureKey.pinTimeOutDuration, value: pinCodeInterval.value.toString())); reaction( diff --git a/lib/store/yat/yat_store.dart b/lib/store/yat/yat_store.dart index 57cae088c..81c5de3b5 100644 --- a/lib/store/yat/yat_store.dart +++ b/lib/store/yat/yat_store.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/balance.dart'; @@ -10,7 +11,6 @@ import 'dart:convert'; import 'package:cake_wallet/store/yat/yat_exception.dart'; import 'package:http/http.dart'; import 'dart:async'; -import 'package:cake_wallet/core/secure_storage.dart'; part 'yat_store.g.dart'; diff --git a/lib/view_model/backup_view_model.dart b/lib/view_model/backup_view_model.dart index 41f8f8dc5..3f21df501 100644 --- a/lib/view_model/backup_view_model.dart +++ b/lib/view_model/backup_view_model.dart @@ -1,11 +1,10 @@ import 'dart:io'; import 'package:cake_wallet/core/backup_service.dart'; import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/store/secret_store.dart'; import 'package:cw_core/root_dir.dart'; -import 'package:flutter/foundation.dart'; -import 'package:cake_wallet/core/secure_storage.dart'; import 'package:mobx/mobx.dart'; import 'package:intl/intl.dart'; import 'package:cake_wallet/wallet_type_utils.dart'; diff --git a/lib/view_model/edit_backup_password_view_model.dart b/lib/view_model/edit_backup_password_view_model.dart index fcc808f4d..64c6c166a 100644 --- a/lib/view_model/edit_backup_password_view_model.dart +++ b/lib/view_model/edit_backup_password_view_model.dart @@ -1,6 +1,5 @@ import 'package:cake_wallet/core/secure_storage.dart'; import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/store/secret_store.dart'; @@ -38,7 +37,7 @@ abstract class EditBackupPasswordViewModelBase with Store { @action Future save() async { final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword); - await writeSecureStorage(secureStorage, key: key, value: backupPassword); + await secureStorage.write(key: key, value: backupPassword); secretStore.write(key: key, value: backupPassword); } } diff --git a/tool/configure.dart b/tool/configure.dart index 17b979eb0..e3aa704aa 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -26,6 +26,7 @@ Future main(List args) async { final hasPolygon = args.contains('${prefix}polygon'); final hasSolana = args.contains('${prefix}solana'); final hasTron = args.contains('${prefix}tron'); + final excludeFlutterSecureStorage = args.contains('${prefix}excludeFlutterSecureStorage'); final excludeFlutterSecureStorage = args.contains('${prefix}excludeFlutterSecureStorage'); await generateBitcoin(hasBitcoin); @@ -1146,7 +1147,7 @@ Future generatePubspec( required bool hasNano, required bool hasBanano, required bool hasBitcoinCash, - required bool hasFlutterSecureStorage, + required bool hasFlutterSecureStorage, required bool hasPolygon, required bool hasSolana, required bool hasTron}) async { @@ -1175,8 +1176,8 @@ Future generatePubspec( git: url: https://github.com/cake-tech/flutter_secure_storage.git path: flutter_secure_storage - ref: cake-8.0.0 - version: 8.0.0 + ref: cake-9.0.0 + version: 9.0.0 """; const cwEthereum = """ cw_ethereum: @@ -1349,7 +1350,11 @@ Future generateWalletTypes( } Future injectSecureStorage(bool hasFlutterSecureStorage) async { - const flutterSecureStorageHeader = "import 'package:flutter_secure_storage/flutter_secure_storage.dart';"; + const flutterSecureStorageHeader = """ +import 'dart:async'; +import 'dart:io'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +"""; const abstractSecureStorage = """ abstract class SecureStorage { Future read({required String key}); @@ -1357,51 +1362,77 @@ abstract class SecureStorage { Future delete({required String key}); // Legacy Future readNoIOptions({required String key}); -}"""; + }"""; const defaultSecureStorage = """ class DefaultSecureStorage extends SecureStorage { DefaultSecureStorage._(this._secureStorage); factory DefaultSecureStorage() => _instance; - static final _instance = DefaultSecureStorage._(FlutterSecureStorage()); - + static final _instance = DefaultSecureStorage._(FlutterSecureStorage( + iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock), + )); + final FlutterSecureStorage _secureStorage; @override - Future read({required String key}) async - => _secureStorage.read(key: key); + Future read({required String key}) async => await _readInternal(key, false); @override - Future write({required String key, required String? value}) async - => _secureStorage.write(key: key, value: value); + Future write({required String key, required String? value}) async { + // delete the value before writing on macOS because of a weird bug + // https://github.com/mogol/flutter_secure_storage/issues/581 + if (Platform.isMacOS) { + await _secureStorage.delete(key: key); + } + await _secureStorage.write(key: key, value: value); + } @override - Future delete({required String key}) async - => _secureStorage.delete(key: key); + Future delete({required String key}) async => _secureStorage.delete(key: key); @override - Future readNoIOptions({required String key}) async - => _secureStorage.read(key: key, iOptions: IOSOptions()); -}"""; + Future readNoIOptions({required String key}) async => await _readInternal(key, true); + + Future _readInternal(String key, bool useNoIOptions) async { + String? result; + + const maxWait = Duration(seconds: 3); + const checkInterval = Duration(milliseconds: 200); + + DateTime start = DateTime.now(); + + while (result == null && DateTime.now().difference(start) < maxWait) { + result = await _secureStorage.read( + key: key, + iOptions: useNoIOptions ? IOSOptions() : null, + ); + + if (result != null) { + break; + } + + await Future.delayed(checkInterval); + } + + return result; + } + }"""; const fakeSecureStorage = """ class FakeSecureStorage extends SecureStorage { @override Future read({required String key}) async => null; - @override Future write({required String key, required String? value}) async {} - @override Future delete({required String key}) async {} - @override Future readNoIOptions({required String key}) async => null; -}"""; + }"""; final outputFile = File(secureStoragePath); final header = hasFlutterSecureStorage - ? '${flutterSecureStorageHeader}\n\nfinal SecureStorage secureStorageShared = DefaultSecureStorage();\n' - : 'final SecureStorage secureStorageShared = FakeSecureStorage();\n'; + ? '${flutterSecureStorageHeader}\n\nfinal SecureStorage secureStorageShared = DefaultSecureStorage();\n' + : 'final SecureStorage secureStorageShared = FakeSecureStorage();\n'; var output = ''; if (outputFile.existsSync()) { await outputFile.delete(); @@ -1416,4 +1447,4 @@ class FakeSecureStorage extends SecureStorage { } await outputFile.writeAsString(output); -} \ No newline at end of file +}