CW-599-Extract-Secure-Storage (#1353)

* feat: Modify app to depend on secure storage abstraction instead of the direct package * chore: Revert command * Update configure.dart [skip ci] * Update configure.dart * Fix conflicts * clean up and fixes * minor fix --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

Adegoke David committed May 8, 2024 at 21:23 UTC bfb78eded98085b8f0a65f233b332490d8e4e5a7
23 files changed +259 -199
.gitignore
+1
@@ -156,6 +156,7 @@ assets/images/app_logo.png
156 macos/Runner/Info.plist
157 macos/Runner/DebugProfile.entitlements
158 macos/Runner/Release.entitlements
159 +lib/core/secure_storage.dart
160
161 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
162 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
lib/core/auth_service.dart
+4 -10
@@ -1,5 +1,4 @@
1 import 'dart:async';
2 -import 'dart:io';
2
3 import 'package:cake_wallet/core/secure_storage.dart';
4 import 'package:cake_wallet/core/totp_request_details.dart';
@@ -7,7 +6,6 @@ import 'package:cake_wallet/routes.dart';
6 import 'package:cake_wallet/src/screens/auth/auth_page.dart';
7 import 'package:flutter/material.dart';
8 import 'package:mobx/mobx.dart';
10 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
9 import 'package:shared_preferences/shared_preferences.dart';
10 import 'package:cake_wallet/entities/preferences_key.dart';
11 import 'package:cake_wallet/entities/secret_store_key.dart';
@@ -35,14 +33,14 @@ class AuthService with Store {
33 Routes.restoreOptions,
34 ];
35
38 - final FlutterSecureStorage secureStorage;
36 + final SecureStorage secureStorage;
37 final SharedPreferences sharedPreferences;
38 final SettingsStore settingsStore;
39
40 Future<void> setPassword(String password) async {
41 final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
42 final encodedPassword = encodedPinCode(pin: password);
45 - await writeSecureStorage(secureStorage, key: key, value: encodedPassword);
43 + await secureStorage.write(key: key, value: encodedPassword);
44 }
45
46 Future<bool> canAuthenticate() async {
@@ -61,7 +59,7 @@ class AuthService with Store {
59
60 Future<bool> authenticate(String pin) async {
61 final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
64 - final encodedPin = await readSecureStorage(secureStorage, key);
62 + final encodedPin = await secureStorage.read(key: key);
63 final decodedPin = decodedPinCode(pin: encodedPin!);
64
65 return decodedPin == pin;
@@ -69,11 +67,7 @@ class AuthService with Store {
67
68 void saveLastAuthTime() {
69 int timestamp = DateTime.now().millisecondsSinceEpoch;
72 - writeSecureStorage(
73 - secureStorage,
74 - key: SecureKey.lastAuthTimeMilliseconds,
75 - value: timestamp.toString(),
76 - );
70 + secureStorage.write(key: SecureKey.lastAuthTimeMilliseconds, value: timestamp.toString());
71 }
72
73 Future<bool> requireAuth() async {
lib/core/backup_service.dart
+8 -11
@@ -7,7 +7,6 @@ import 'package:cake_wallet/utils/device_info.dart';
7 import 'package:cw_core/wallet_type.dart';
8 import 'package:flutter/foundation.dart';
9 import 'package:hive/hive.dart';
10 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
10 import 'package:path_provider/path_provider.dart';
11 import 'package:cryptography/cryptography.dart';
12 import 'package:shared_preferences/shared_preferences.dart';
@@ -25,7 +24,7 @@ import 'package:cake_backup/backup.dart' as cake_backup;
24
25 class BackupService {
26 BackupService(
28 - this._flutterSecureStorage, this._walletInfoSource, this._keyService, this._sharedPreferences)
27 + this._secureStorage, this._walletInfoSource, this._keyService, this._sharedPreferences)
28 : _cipher = Cryptography.instance.chacha20Poly1305Aead(),
29 _correctWallets = <WalletInfo>[];
30
@@ -35,7 +34,7 @@ class BackupService {
34 static const _v2 = 2;
35
36 final Cipher _cipher;
38 - final FlutterSecureStorage _flutterSecureStorage;
37 + final SecureStorage _secureStorage;
38 final SharedPreferences _sharedPreferences;
39 final Box<WalletInfo> _walletInfoSource;
40 final KeyService _keyService;
@@ -374,15 +373,14 @@ class BackupService {
373 final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
374 final backupPassword = keychainJSON[backupPasswordKey] as String;
375
377 - await writeSecureStorage(_flutterSecureStorage, key: backupPasswordKey, value: backupPassword);
376 + await _secureStorage.write(key: backupPasswordKey, value: backupPassword);
377
378 keychainWalletsInfo.forEach((dynamic rawInfo) async {
379 final info = rawInfo as Map<String, dynamic>;
380 await importWalletKeychainInfo(info);
381 });
382
384 - await writeSecureStorage(_flutterSecureStorage,
385 - key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
383 + await _secureStorage.write(key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
384
385 keychainDumpFile.deleteSync();
386 }
@@ -401,15 +399,14 @@ class BackupService {
399 final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
400 final backupPassword = keychainJSON[backupPasswordKey] as String;
401
404 - await writeSecureStorage(_flutterSecureStorage, key: backupPasswordKey, value: backupPassword);
402 + await _secureStorage.write(key: backupPasswordKey, value: backupPassword);
403
404 keychainWalletsInfo.forEach((dynamic rawInfo) async {
405 final info = rawInfo as Map<String, dynamic>;
406 await importWalletKeychainInfo(info);
407 });
408
411 - await writeSecureStorage(_flutterSecureStorage,
412 - key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
409 + await _secureStorage.write(key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
410
411 keychainDumpFile.deleteSync();
412 }
@@ -429,7 +426,7 @@ class BackupService {
426 Future<Uint8List> _exportKeychainDumpV2(String password,
427 {String keychainSalt = secrets.backupKeychainSalt}) async {
428 final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
432 - final encodedPin = await _flutterSecureStorage.read(key: key);
429 + final encodedPin = await _secureStorage.read(key: key);
430 final decodedPin = decodedPinCode(pin: encodedPin!);
431 final wallets = await Future.wait(_walletInfoSource.values.map((walletInfo) async {
432 return {
@@ -439,7 +436,7 @@ class BackupService {
436 };
437 }));
438 final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
442 - final backupPassword = await _flutterSecureStorage.read(key: backupPasswordKey);
439 + final backupPassword = await _secureStorage.read(key: backupPasswordKey);
440 final data = utf8.encode(
441 json.encode({'pin': decodedPin, 'wallets': wallets, backupPasswordKey: backupPassword}));
442 final encrypted = await _encryptV2(Uint8List.fromList(data), '$keychainSalt$password');
lib/core/key_service.dart
+9 -10
@@ -1,31 +1,30 @@
1 import 'package:cake_wallet/core/secure_storage.dart';
2 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2 import 'package:cake_wallet/entities/secret_store_key.dart';
3 import 'package:cake_wallet/entities/encrypt.dart';
4
5 class KeyService {
6 KeyService(this._secureStorage);
7
9 - final FlutterSecureStorage _secureStorage;
8 + final SecureStorage _secureStorage;
9
10 Future<String> getWalletPassword({required String walletName}) async {
12 - final key = generateStoreKeyFor(
13 - key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
14 - final encodedPassword = await readSecureStorage(_secureStorage, key);
11 + final key =
12 + generateStoreKeyFor(key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
13 + final encodedPassword = await _secureStorage.read(key: key);
14 return decodeWalletPassword(password: encodedPassword!);
15 }
16
17 Future<void> saveWalletPassword({required String walletName, required String password}) async {
19 - final key = generateStoreKeyFor(
20 - key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
18 + final key =
19 + generateStoreKeyFor(key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
20 final encodedPassword = encodeWalletPassword(password: password);
21
23 - await writeSecureStorage(_secureStorage, key: key, value: encodedPassword);
22 + await _secureStorage.write(key: key, value: encodedPassword);
23 }
24
25 Future<void> deleteWalletPassword({required String walletName}) async {
27 - final key = generateStoreKeyFor(
28 - key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
26 + final key =
27 + generateStoreKeyFor(key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
28
29 await _secureStorage.delete(key: key);
30 }
lib/core/secure_storage.dart deleted
-38
@@ -1,38 +0,0 @@
1 -import 'dart:async';
2 -import 'dart:io';
3 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
4 -// For now, we can create a utility function to handle this.
5 -//
6 -// However, we could look into abstracting the entire FlutterSecureStorage package
7 -// so the app doesn't depend on the package directly but an absraction.
8 -// It'll make these kind of modifications to read/write come from a single point.
9 -
10 -Future<String?> readSecureStorage(FlutterSecureStorage secureStorage, String key) async {
11 - String? result;
12 - const maxWait = Duration(seconds: 3);
13 - const checkInterval = Duration(milliseconds: 200);
14 -
15 - DateTime start = DateTime.now();
16 -
17 - while (result == null && DateTime.now().difference(start) < maxWait) {
18 - result = await secureStorage.read(key: key);
19 -
20 - if (result != null) {
21 - break;
22 - }
23 -
24 - await Future.delayed(checkInterval);
25 - }
26 -
27 - return result;
28 -}
29 -
30 -Future<void> writeSecureStorage(FlutterSecureStorage secureStorage,
31 - {required String key, required String value}) async {
32 - // delete the value before writing on macOS because of a weird bug
33 - // https://github.com/mogol/flutter_secure_storage/issues/581
34 - if (Platform.isMacOS) {
35 - await secureStorage.delete(key: key);
36 - }
37 - await secureStorage.write(key: key, value: value);
38 -}
lib/core/wallet_creation_service.dart
+2 -2
@@ -1,8 +1,8 @@
1 +import 'package:cake_wallet/core/secure_storage.dart';
2 import 'package:cake_wallet/di.dart';
3 import 'package:cake_wallet/store/settings_store.dart';
4 import 'package:cw_core/wallet_info.dart';
5 import 'package:cake_wallet/entities/preferences_key.dart';
5 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
6 import 'package:hive/hive.dart';
7 import 'package:shared_preferences/shared_preferences.dart';
8 import 'package:cake_wallet/core/key_service.dart';
@@ -25,7 +25,7 @@ class WalletCreationService {
25 }
26
27 WalletType type;
28 - final FlutterSecureStorage secureStorage;
28 + final SecureStorage secureStorage;
29 final SharedPreferences sharedPreferences;
30 final SettingsStore settingsStore;
31 final KeyService keyService;
lib/di.dart
+38 -12
@@ -236,6 +236,32 @@ import 'package:get_it/get_it.dart';
236 import 'package:hive/hive.dart';
237 import 'package:mobx/mobx.dart';
238 import 'package:shared_preferences/shared_preferences.dart';
239 +import 'package:cake_wallet/core/secure_storage.dart';
240 +import 'package:cake_wallet/core/wallet_creation_service.dart';
241 +import 'package:cake_wallet/store/app_store.dart';
242 +import 'package:cw_core/wallet_type.dart';
243 +import 'package:cake_wallet/view_model/wallet_new_vm.dart';
244 +import 'package:cake_wallet/store/authentication_store.dart';
245 +import 'package:cake_wallet/store/dashboard/trades_store.dart';
246 +import 'package:cake_wallet/store/dashboard/trade_filter_store.dart';
247 +import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart';
248 +import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
249 +import 'package:cake_wallet/store/templates/send_template_store.dart';
250 +import 'package:cake_wallet/store/templates/exchange_template_store.dart';
251 +import 'package:cake_wallet/entities/template.dart';
252 +import 'package:cake_wallet/exchange/exchange_template.dart';
253 +import 'package:cake_wallet/.secrets.g.dart' as secrets;
254 +import 'package:cake_wallet/src/screens/dashboard/pages/address_page.dart';
255 +import 'package:cake_wallet/anypay/anypay_api.dart';
256 +import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart';
257 +import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart';
258 +import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart';
259 +import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
260 +import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
261 +import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
262 +import 'package:cake_wallet/core/wallet_loading_service.dart';
263 +import 'package:cw_core/crypto_currency.dart';
264 +import 'package:cake_wallet/entities/qr_view_data.dart';
265
266 import 'buy/dfx/dfx_buy_provider.dart';
267 import 'core/totp_request_details.dart';
@@ -268,7 +294,7 @@ Future<void> setup({
294 required Box<Order> ordersSource,
295 required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
296 required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
271 - required FlutterSecureStorage secureStorage,
297 + required SecureStorage secureStorage,
298 required GlobalKey<NavigatorState> navigatorKey,
299 }) async {
300 _walletInfoSource = walletInfoSource;
@@ -285,7 +311,7 @@ Future<void> setup({
311
312 if (!_isSetupFinished) {
313 getIt.registerSingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance());
288 - getIt.registerSingleton<FlutterSecureStorage>(secureStorage);
314 + getIt.registerSingleton<SecureStorage>(secureStorage);
315 }
316 if (!_isSetupFinished) {
317 getIt.registerFactory(() => BackgroundTasks());
@@ -333,22 +359,22 @@ Future<void> setup({
359 getIt.registerSingleton<ExchangeTemplateStore>(
360 ExchangeTemplateStore(templateSource: _exchangeTemplates));
361 getIt.registerSingleton<YatStore>(
336 - YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<FlutterSecureStorage>())
362 + YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<SecureStorage>())
363 ..init());
364 getIt.registerSingleton<AnonpayTransactionsStore>(
365 AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
366
341 - final secretStore = await SecretStoreBase.load(getIt.get<FlutterSecureStorage>());
367 + final secretStore = await SecretStoreBase.load(getIt.get<SecureStorage>());
368
369 getIt.registerSingleton<SecretStore>(secretStore);
370
345 - getIt.registerFactory<KeyService>(() => KeyService(getIt.get<FlutterSecureStorage>()));
371 + getIt.registerFactory<KeyService>(() => KeyService(getIt.get<SecureStorage>()));
372
373 getIt.registerFactoryParam<WalletCreationService, WalletType, void>((type, _) =>
374 WalletCreationService(
375 initialType: type,
376 keyService: getIt.get<KeyService>(),
351 - secureStorage: getIt.get<FlutterSecureStorage>(),
377 + secureStorage: getIt.get<SecureStorage>(),
378 sharedPreferences: getIt.get<SharedPreferences>(),
379 settingsStore: getIt.get<SettingsStore>(),
380 walletInfoSource: _walletInfoSource));
@@ -403,7 +429,7 @@ Future<void> setup({
429
430 getIt.registerFactory<AuthService>(
431 () => AuthService(
406 - secureStorage: getIt.get<FlutterSecureStorage>(),
432 + secureStorage: getIt.get<SecureStorage>(),
433 sharedPreferences: getIt.get<SharedPreferences>(),
434 settingsStore: getIt.get<SettingsStore>(),
435 ),
@@ -980,16 +1006,16 @@ Future<void> setup({
1006 trades: _tradesSource,
1007 settingsStore: getIt.get<SettingsStore>()));
1008
983 - getIt.registerFactory(() => BackupService(getIt.get<FlutterSecureStorage>(), _walletInfoSource,
1009 + getIt.registerFactory(() => BackupService(getIt.get<SecureStorage>(), _walletInfoSource,
1010 getIt.get<KeyService>(), getIt.get<SharedPreferences>()));
1011
1012 getIt.registerFactory(() => BackupViewModel(
987 - getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>(), getIt.get<BackupService>()));
1013 + getIt.get<SecureStorage>(), getIt.get<SecretStore>(), getIt.get<BackupService>()));
1014
1015 getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>()));
1016
1017 getIt.registerFactory(() =>
992 - EditBackupPasswordViewModel(getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>()));
1018 + EditBackupPasswordViewModel(getIt.get<SecureStorage>(), getIt.get<SecretStore>()));
1019
1020 getIt.registerFactory(() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
1021
@@ -1038,7 +1064,7 @@ Future<void> setup({
1064 getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>()));
1065
1066 getIt.registerFactory(() => SupportChatPage(getIt.get<SupportViewModel>(),
1041 - secureStorage: getIt.get<FlutterSecureStorage>()));
1067 + secureStorage: getIt.get<SecureStorage>()));
1068
1069 getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>()));
1070
@@ -1080,7 +1106,7 @@ Future<void> setup({
1106 getIt.registerFactory(() => AnyPayApi());
1107
1108 getIt.registerFactory<IoniaService>(
1083 - () => IoniaService(getIt.get<FlutterSecureStorage>(), getIt.get<IoniaApi>()));
1109 + () => IoniaService(getIt.get<SecureStorage>(), getIt.get<IoniaApi>()));
1110
1111 getIt.registerFactory<IoniaAnyPay>(() => IoniaAnyPay(
1112 getIt.get<IoniaService>(), getIt.get<AnyPayApi>(), getIt.get<AppStore>().wallet!));
lib/entities/default_settings_migration.dart
+8 -7
@@ -1,10 +1,10 @@
1 import 'dart:io' show Directory, File, Platform;
2 import 'package:cake_wallet/bitcoin/bitcoin.dart';
3 +import 'package:cake_wallet/core/secure_storage.dart';
4 import 'package:cake_wallet/entities/exchange_api_mode.dart';
5 import 'package:cake_wallet/entities/fiat_api_mode.dart';
6 import 'package:cw_core/pathForWallet.dart';
7 import 'package:cake_wallet/entities/secret_store_key.dart';
7 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
8 import 'package:hive/hive.dart';
9 import 'package:path_provider/path_provider.dart';
10 import 'package:shared_preferences/shared_preferences.dart';
@@ -42,7 +42,7 @@ const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002';
42 Future<void> defaultSettingsMigration(
43 {required int version,
44 required SharedPreferences sharedPreferences,
45 - required FlutterSecureStorage secureStorage,
45 + required SecureStorage secureStorage,
46 required Box<Node> nodes,
47 required Box<Node> powNodes,
48 required Box<WalletInfo> walletInfoSource,
@@ -485,7 +485,7 @@ Node? getTronDefaultNode({required Box<Node> nodes}) {
485
486 Future<void> insecureStorageMigration({
487 required SharedPreferences sharedPreferences,
488 - required FlutterSecureStorage secureStorage,
488 + required SecureStorage secureStorage,
489 }) async {
490 bool? allowBiometricalAuthentication =
491 sharedPreferences.getBool(SecureKey.allowBiometricalAuthenticationKey);
@@ -559,7 +559,7 @@ Future<void> insecureStorageMigration({
559 }
560 }
561
562 -Future<void> rewriteSecureStoragePin({required FlutterSecureStorage secureStorage}) async {
562 +Future<void> rewriteSecureStoragePin({required SecureStorage secureStorage}) async {
563 // the bug only affects ios/mac:
564 if (!Platform.isIOS && !Platform.isMacOS) {
565 return;
@@ -585,8 +585,9 @@ Future<void> rewriteSecureStoragePin({required FlutterSecureStorage secureStorag
585 await secureStorage.write(
586 key: keyForPinCode,
587 value: encodedPin,
588 - iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
589 - mOptions: MacOsOptions(accessibility: KeychainAccessibility.first_unlock),
588 + // TODO: find a way to add those with the generated secure storage
589 + // iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
590 + // mOptions: MacOsOptions(accessibility: KeychainAccessibility.first_unlock),
591 );
592 }
593
@@ -720,7 +721,7 @@ Future<void> updateDisplayModes(SharedPreferences sharedPreferences) async {
721 await sharedPreferences.setInt(PreferencesKey.currentBalanceDisplayModeKey, balanceDisplayMode);
722 }
723
723 -Future<void> generateBackupPassword(FlutterSecureStorage secureStorage) async {
724 +Future<void> generateBackupPassword(SecureStorage secureStorage) async {
725 final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
726
727 if ((await secureStorage.read(key: key))?.isNotEmpty ?? false) {
lib/entities/fs_migration.dart
+24 -42
@@ -2,7 +2,6 @@ import 'dart:io';
2 import 'dart:convert';
3 import 'package:cake_wallet/core/secure_storage.dart';
4 import 'package:collection/collection.dart';
5 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
5 import 'package:shared_preferences/shared_preferences.dart';
6 import 'package:hive/hive.dart';
7 import 'package:path_provider/path_provider.dart';
@@ -11,8 +10,7 @@ import 'package:cake_wallet/entities/contact.dart';
10 import 'package:cw_core/crypto_currency.dart';
11 import 'package:cake_wallet/entities/encrypt.dart';
12 import 'package:cake_wallet/entities/fiat_currency.dart';
14 -import 'package:cake_wallet/entities/ios_legacy_helper.dart'
15 - as ios_legacy_helper;
13 +import 'package:cake_wallet/entities/ios_legacy_helper.dart' as ios_legacy_helper;
14 import 'package:cake_wallet/entities/preferences_key.dart';
15 import 'package:cake_wallet/entities/secret_store_key.dart';
16 import 'package:cw_core/wallet_info.dart';
@@ -30,8 +28,8 @@ Future<void> migrate_android_v1() async {
28 await android_migrate_wallets(appDocDir: appDocDir);
29 }
30
33 -Future<void> ios_migrate_v1(Box<WalletInfo> walletInfoSource,
34 - Box<Trade> tradeSource, Box<Contact> contactSource) async {
31 +Future<void> ios_migrate_v1(
32 + Box<WalletInfo> walletInfoSource, Box<Trade> tradeSource, Box<Contact> contactSource) async {
33 final prefs = await SharedPreferences.getInstance();
34
35 if (prefs.getBool('ios_migration_v1_completed') ?? false) {
@@ -67,10 +65,7 @@ Future<void> ios_migrate_user_defaults() async {
65 if (activeCurrency != null) {
66 final convertedCurrency = convertFiatLegacy(activeCurrency);
67
70 - if (convertedCurrency != null) {
71 - await prefs.setString(
72 - 'current_fiat_currency', convertedCurrency.serialize());
73 - }
68 + await prefs.setString('current_fiat_currency', convertedCurrency.serialize());
69 }
70
71 //translate fee priority
@@ -81,24 +76,21 @@ Future<void> ios_migrate_user_defaults() async {
76 }
77
78 //translate current balance mode
84 - final currentBalanceMode =
85 - await ios_legacy_helper.getInt('display_balance_mode');
79 + final currentBalanceMode = await ios_legacy_helper.getInt('display_balance_mode');
80 if (currentBalanceMode != null) {
81 await prefs.setInt('current_balance_display_mode', currentBalanceMode);
82 }
83
84 //translate should save recipient address
91 - final shouldSave =
92 - await ios_legacy_helper.getBool('should_save_recipient_address');
93 -
85 + final shouldSave = await ios_legacy_helper.getBool('should_save_recipient_address');
86 +
87 if (shouldSave != null) {
88 await prefs.setBool('save_recipient_address', shouldSave);
89 }
90
91 //translate biometric
99 - final biometricOn =
100 - await ios_legacy_helper.getBool('biometric_authentication_on');
101 -
92 + final biometricOn = await ios_legacy_helper.getBool('biometric_authentication_on');
93 +
94 if (biometricOn != null) {
95 await prefs.setBool('allow_biometrical_authentication', biometricOn);
96 }
@@ -137,9 +129,8 @@ Future<void> ios_migrate_pin() async {
129 return;
130 }
131
140 - final flutterSecureStorage = FlutterSecureStorage();
141 - final pinPassword = await flutterSecureStorage.read(
142 - key: 'pin_password', iOptions: IOSOptions());
132 + final flutterSecureStorage = secureStorageShared;
133 + final pinPassword = await flutterSecureStorage.readNoIOptions(key: 'pin_password');
134 // No pin
135 if (pinPassword == null) {
136 await prefs.setBool('ios_migration_pin_completed', true);
@@ -148,7 +139,7 @@ Future<void> ios_migrate_pin() async {
139
140 final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
141 final encodedPassword = encodedPinCode(pin: pinPassword);
151 - await writeSecureStorage(flutterSecureStorage, key: key, value: encodedPassword);
142 + await flutterSecureStorage.write(key: key, value: encodedPassword);
143
144 await prefs.setBool('ios_migration_pin_completed', true);
145 }
@@ -161,7 +152,7 @@ Future<void> ios_migrate_wallet_passwords() async {
152 }
153
154 final appDocDir = await getApplicationDocumentsDirectory();
164 - final flutterSecureStorage = FlutterSecureStorage();
155 + final flutterSecureStorage = secureStorageShared;
156 final keyService = KeyService(flutterSecureStorage);
157 final walletsDir = Directory('${appDocDir.path}/wallets');
158 final moneroWalletsDir = Directory('${walletsDir.path}/monero');
@@ -176,10 +167,8 @@ Future<void> ios_migrate_wallet_passwords() async {
167 if (item is Directory) {
168 final name = item.path.split('/').last;
169 final oldKey = 'wallet_monero_' + name + '_password';
179 - final password = await flutterSecureStorage.read(
180 - key: oldKey, iOptions: IOSOptions());
181 - await keyService.saveWalletPassword(
182 - walletName: name, password: password!);
170 + final password = await flutterSecureStorage.readNoIOptions(key: oldKey);
171 + await keyService.saveWalletPassword(walletName: name, password: password!);
172 }
173 } catch (e) {
174 print(e.toString());
@@ -311,18 +300,14 @@ Future<void> ios_migrate_wallet_info(Box<WalletInfo> walletsInfoSource) async {
300 return null;
301 }
302
314 - final config = json.decode(configFile.readAsStringSync())
315 - as Map<String, dynamic>;
316 - final isRecovery = config['isRecovery'] as bool ?? false;
303 + final config = json.decode(configFile.readAsStringSync()) as Map<String, dynamic>;
304 + final isRecovery = config['isRecovery'] as bool? ?? false;
305 final dateAsDouble = config['date'] as double;
306 final timestamp = dateAsDouble.toInt() * 1000;
307 final date = DateTime.fromMillisecondsSinceEpoch(timestamp);
320 - final id = walletTypeToString(WalletType.monero).toLowerCase() +
321 - '_' +
322 - name;
323 - final exist = walletsInfoSource.values
324 - .firstWhereOrNull((el) => el.id == id) != null;
325 -
308 + final id = walletTypeToString(WalletType.monero).toLowerCase() + '_' + name;
309 + final exist = walletsInfoSource.values.firstWhereOrNull((el) => el.id == id) != null;
310 +
311 if (exist) {
312 return null;
313 }
@@ -373,12 +358,10 @@ Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
358 }
359
360 final content = file.readAsBytesSync();
376 - final flutterSecureStorage = FlutterSecureStorage();
377 - final masterPassword = await flutterSecureStorage.read(
378 - key: 'master_password', iOptions: IOSOptions());
361 + final flutterSecureStorage = secureStorageShared;
362 + final masterPassword = await flutterSecureStorage.readNoIOptions(key: 'master_password');
363 final key = masterPassword!.replaceAll('-', '');
380 - final decoded =
381 - await ios_legacy_helper.decrypt(content, key: key, salt: secrets.salt);
364 + final decoded = await ios_legacy_helper.decrypt(content, key: key, salt: secrets.salt);
365 final decodedJson = json.decode(decoded) as List<dynamic>;
366 final trades = decodedJson.map((dynamic el) {
367 final elAsMap = el as Map<String, dynamic>;
@@ -441,8 +424,7 @@ Future<void> ios_migrate_address_book(Box<Contact> contactSource) async {
424 final address = _item["address"] as String;
425 final name = _item["name"] as String;
426
444 - return Contact(
445 - address: address, name: name, type: CryptoCurrency.fromString(type));
427 + return Contact(address: address, name: name, type: CryptoCurrency.fromString(type));
428 });
429
430 await contactSource.addAll(contacts);
lib/entities/get_encryption_key.dart
+2 -3
@@ -1,9 +1,8 @@
1 import 'package:cake_wallet/core/secure_storage.dart';
2 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2 import 'package:cw_core/cake_hive.dart';
3
4 Future<List<int>> getEncryptionKey(
6 - {required String forKey, required FlutterSecureStorage secureStorage}) async {
5 + {required String forKey, required SecureStorage secureStorage}) async {
6 final stringifiedKey = await secureStorage.read(key: 'transactionDescriptionsBoxKey');
7 List<int> key;
8
@@ -11,7 +10,7 @@ Future<List<int>> getEncryptionKey(
10 key = CakeHive.generateSecureKey();
11 final keyStringified = key.join(',');
12 String storageKey = 'transactionDescriptionsBoxKey';
14 - await writeSecureStorage(secureStorage, key: storageKey, value: keyStringified);
13 + await secureStorage.write(key: storageKey, value: keyStringified);
14 } else {
15 key = stringifiedKey.split(',').map((i) => int.parse(i)).toList();
16 }
lib/entities/preferences_key.dart
+3 -3
@@ -61,9 +61,9 @@ class PreferencesKey {
61 static const defaultBananoRep = 'default_banano_representative';
62 static const lookupsTwitter = 'looks_up_twitter';
63 static const lookupsMastodon = 'looks_up_mastodon';
64 - static const lookupsYatService = 'looks_up_mastodon';
65 - static const lookupsUnstoppableDomains = 'looks_up_mastodon';
66 - static const lookupsOpenAlias = 'looks_up_mastodon';
64 + static const lookupsYatService = 'looks_up_yat';
65 + static const lookupsUnstoppableDomains = 'looks_up_unstoppable_domain';
66 + static const lookupsOpenAlias = 'looks_up_open_alias';
67 static const lookupsENS = 'looks_up_ens';
68
69 static String moneroWalletUpdateV1Key(String name) =>
lib/entities/secret_store_key.dart
+4 -4
@@ -1,4 +1,4 @@
1 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
1 +import 'package:cake_wallet/core/secure_storage.dart';
2 import 'package:shared_preferences/shared_preferences.dart';
3
4 enum SecretStoreKey { moneroWalletPassword, pinCodePassword, backupPassword }
@@ -66,7 +66,7 @@ class SecureKey {
66 static const lastAuthTimeMilliseconds = 'last_auth_time_milliseconds';
67
68 static Future<int?> getInt({
69 - required FlutterSecureStorage secureStorage,
69 + required SecureStorage secureStorage,
70 required SharedPreferences sharedPreferences,
71 required String key,
72 }) async {
@@ -76,7 +76,7 @@ class SecureKey {
76 }
77
78 static Future<bool?> getBool({
79 - required FlutterSecureStorage secureStorage,
79 + required SecureStorage secureStorage,
80 required SharedPreferences sharedPreferences,
81 required String key,
82 }) async {
@@ -91,7 +91,7 @@ class SecureKey {
91 }
92
93 static Future<String?> getString({
94 - required FlutterSecureStorage secureStorage,
94 + required SecureStorage secureStorage,
95 required SharedPreferences sharedPreferences,
96 required String key,
97 }) async {
lib/ionia/ionia_service.dart
+2 -2
@@ -1,7 +1,7 @@
1 +import 'package:cake_wallet/core/secure_storage.dart';
2 import 'package:cake_wallet/ionia/ionia_merchant.dart';
3 import 'package:cake_wallet/ionia/ionia_order.dart';
4 import 'package:cake_wallet/ionia/ionia_virtual_card.dart';
4 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
5 import 'package:cake_wallet/.secrets.g.dart' as secrets;
6 import 'package:cake_wallet/ionia/ionia_api.dart';
7 import 'package:cake_wallet/ionia/ionia_gift_card.dart';
@@ -16,7 +16,7 @@ class IoniaService {
16
17 static String get clientId => secrets.ioniaClientId;
18
19 - final FlutterSecureStorage secureStorage;
19 + final SecureStorage secureStorage;
20 final IoniaApi ioniaApi;
21
22 // Create user
lib/main.dart
+4 -5
@@ -1,6 +1,7 @@
1 import 'dart:async';
2 import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
3 import 'package:cake_wallet/core/auth_service.dart';
4 +import 'package:cake_wallet/core/secure_storage.dart';
5 import 'package:cake_wallet/entities/language_service.dart';
6 import 'package:cake_wallet/buy/order.dart';
7 import 'package:cake_wallet/locales/locale.dart';
@@ -18,7 +19,6 @@ import 'package:hive/hive.dart';
19 import 'package:cake_wallet/di.dart';
20 import 'package:path_provider/path_provider.dart';
21 import 'package:shared_preferences/shared_preferences.dart';
21 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
22 import 'package:flutter_mobx/flutter_mobx.dart';
23 import 'package:cake_wallet/themes/theme_base.dart';
24 import 'package:cake_wallet/router.dart' as Router;
@@ -138,9 +138,8 @@ Future<void> initializeAppConfigs() async {
138 CakeHive.registerAdapter(AnonpayInvoiceInfoAdapter());
139 }
140
141 - final secureStorage = FlutterSecureStorage(
142 - iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
143 - );
141 + final secureStorage = secureStorageShared;
142 +
143 final transactionDescriptionsBoxKey =
144 await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
145 final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
@@ -191,7 +190,7 @@ Future<void> initialSetup(
190 required Box<Template> templates,
191 required Box<ExchangeTemplate> exchangeTemplates,
192 required Box<TransactionDescription> transactionDescriptions,
194 - required FlutterSecureStorage secureStorage,
193 + required SecureStorage secureStorage,
194 required Box<AnonpayInvoiceInfo> anonpayInvoiceInfo,
195 required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
196 int initialMigrationVersion = 15}) async {
lib/src/screens/support_chat/support_chat_page.dart
+2 -2
@@ -1,16 +1,16 @@
1 +import 'package:cake_wallet/core/secure_storage.dart';
2 import 'package:cake_wallet/generated/i18n.dart';
3 import 'package:cake_wallet/src/screens/base_page.dart';
4 import 'package:cake_wallet/src/screens/support_chat/widgets/chatwoot_widget.dart';
5 import 'package:cake_wallet/view_model/support_view_model.dart';
6 import 'package:flutter/material.dart';
6 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
7
8
9 class SupportChatPage extends BasePage {
10 SupportChatPage(this.supportViewModel, {required this.secureStorage});
11
12 final SupportViewModel supportViewModel;
13 - final FlutterSecureStorage secureStorage;
13 + final SecureStorage secureStorage;
14
15 @override
16 String get title => S.current.settings_support;
lib/src/screens/support_chat/widgets/chatwoot_widget.dart
+2 -3
@@ -3,14 +3,13 @@ import 'dart:convert';
3 import 'package:cake_wallet/core/secure_storage.dart';
4 import 'package:flutter/material.dart';
5 import 'package:flutter_inappwebview/flutter_inappwebview.dart';
6 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
6
7 const COOKIE_KEY = 'chatwootCookie';
8
9 class ChatwootWidget extends StatefulWidget {
10 ChatwootWidget(this.secureStorage, {required this.supportUrl});
11
13 - final FlutterSecureStorage secureStorage;
12 + final SecureStorage secureStorage;
13 final String supportUrl;
14
15 @override
@@ -59,6 +58,6 @@ class ChatwootWidgetState extends State<ChatwootWidget> {
58 }
59
60 Future<void> storeCookie(String value) async {
62 - await writeSecureStorage(widget.secureStorage, key: COOKIE_KEY, value: value);
61 + await widget.secureStorage.write(key: COOKIE_KEY, value: value);
62 }
63 }
lib/store/secret_store.dart
+2 -3
@@ -1,6 +1,5 @@
1 +import 'package:cake_wallet/core/secure_storage.dart';
2 import 'package:cake_wallet/entities/secret_store_key.dart';
2 -import 'package:flutter/foundation.dart';
3 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
3 import 'package:mobx/mobx.dart';
4
5 part 'secret_store.g.dart';
@@ -8,7 +7,7 @@ part 'secret_store.g.dart';
7 class SecretStore = SecretStoreBase with _$SecretStore;
8
9 abstract class SecretStoreBase with Store {
11 - static Future<SecretStore> load(FlutterSecureStorage storage) async {
10 + static Future<SecretStore> load(SecureStorage storage) async {
11 final secretStore = SecretStore();
12 final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
13 final backupPassword = await storage.read(key: backupPasswordKey);
lib/store/settings_store.dart
+21 -28
@@ -26,7 +26,6 @@ import 'package:cake_wallet/themes/theme_base.dart';
26 import 'package:cake_wallet/themes/theme_list.dart';
27 import 'package:device_info_plus/device_info_plus.dart';
28 import 'package:flutter/material.dart';
29 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
29 import 'package:hive/hive.dart';
30 import 'package:mobx/mobx.dart';
31 import 'package:package_info/package_info.dart';
@@ -48,7 +47,7 @@ class SettingsStore = SettingsStoreBase with _$SettingsStore;
47
48 abstract class SettingsStoreBase with Store {
49 SettingsStoreBase(
51 - {required FlutterSecureStorage secureStorage,
50 + {required SecureStorage secureStorage,
51 required BackgroundTasks backgroundTasks,
52 required SharedPreferences sharedPreferences,
53 required bool initialShouldShowMarketPlaceInDashboard,
@@ -398,10 +397,8 @@ abstract class SettingsStoreBase with Store {
397 (bool usePolygonScan) =>
398 _sharedPreferences.setBool(PreferencesKey.usePolygonScan, usePolygonScan));
399
401 - reaction(
402 - (_) => useTronGrid,
403 - (bool useTronGrid) =>
404 - _sharedPreferences.setBool(PreferencesKey.useTronGrid, useTronGrid));
400 + reaction((_) => useTronGrid,
401 + (bool useTronGrid) => _sharedPreferences.setBool(PreferencesKey.useTronGrid, useTronGrid));
402
403 reaction((_) => defaultNanoRep,
404 (String nanoRep) => _sharedPreferences.setString(PreferencesKey.defaultNanoRep, nanoRep));
@@ -441,83 +438,79 @@ abstract class SettingsStoreBase with Store {
438 // secure storage keys:
439 reaction(
440 (_) => allowBiometricalAuthentication,
444 - (bool biometricalAuthentication) => writeSecureStorage(secureStorage,
441 + (bool biometricalAuthentication) => secureStorage.write(
442 key: SecureKey.allowBiometricalAuthenticationKey,
443 value: biometricalAuthentication.toString()));
444
445 reaction(
446 (_) => selectedCake2FAPreset,
450 - (Cake2FAPresetsOptions selectedCake2FAPreset) => writeSecureStorage(secureStorage,
447 + (Cake2FAPresetsOptions selectedCake2FAPreset) => secureStorage.write(
448 key: SecureKey.selectedCake2FAPreset,
449 value: selectedCake2FAPreset.serialize().toString()));
450
451 reaction(
452 (_) => shouldRequireTOTP2FAForAccessingWallet,
456 - (bool requireTOTP2FAForAccessingWallet) => writeSecureStorage(secureStorage,
453 + (bool requireTOTP2FAForAccessingWallet) => secureStorage.write(
454 key: SecureKey.shouldRequireTOTP2FAForAccessingWallet,
455 value: requireTOTP2FAForAccessingWallet.toString()));
456
457 reaction(
458 (_) => shouldRequireTOTP2FAForSendsToContact,
462 - (bool requireTOTP2FAForSendsToContact) => writeSecureStorage(secureStorage,
459 + (bool requireTOTP2FAForSendsToContact) => secureStorage.write(
460 key: SecureKey.shouldRequireTOTP2FAForSendsToContact,
461 value: requireTOTP2FAForSendsToContact.toString()));
462
463 reaction(
464 (_) => shouldRequireTOTP2FAForSendsToNonContact,
468 - (bool requireTOTP2FAForSendsToNonContact) => writeSecureStorage(secureStorage,
465 + (bool requireTOTP2FAForSendsToNonContact) => secureStorage.write(
466 key: SecureKey.shouldRequireTOTP2FAForSendsToNonContact,
467 value: requireTOTP2FAForSendsToNonContact.toString()));
468
469 reaction(
470 (_) => shouldRequireTOTP2FAForSendsToInternalWallets,
474 - (bool requireTOTP2FAForSendsToInternalWallets) => writeSecureStorage(secureStorage,
471 + (bool requireTOTP2FAForSendsToInternalWallets) => secureStorage.write(
472 key: SecureKey.shouldRequireTOTP2FAForSendsToInternalWallets,
473 value: requireTOTP2FAForSendsToInternalWallets.toString()));
474
475 reaction(
476 (_) => shouldRequireTOTP2FAForExchangesToInternalWallets,
480 - (bool requireTOTP2FAForExchangesToInternalWallets) => writeSecureStorage(secureStorage,
477 + (bool requireTOTP2FAForExchangesToInternalWallets) => secureStorage.write(
478 key: SecureKey.shouldRequireTOTP2FAForExchangesToInternalWallets,
479 value: requireTOTP2FAForExchangesToInternalWallets.toString()));
480
481 reaction(
482 (_) => shouldRequireTOTP2FAForExchangesToExternalWallets,
486 - (bool requireTOTP2FAForExchangesToExternalWallets) => writeSecureStorage(secureStorage,
483 + (bool requireTOTP2FAForExchangesToExternalWallets) => secureStorage.write(
484 key: SecureKey.shouldRequireTOTP2FAForExchangesToExternalWallets,
485 value: requireTOTP2FAForExchangesToExternalWallets.toString()));
486
487 reaction(
488 (_) => shouldRequireTOTP2FAForAddingContacts,
492 - (bool requireTOTP2FAForAddingContacts) => writeSecureStorage(secureStorage,
489 + (bool requireTOTP2FAForAddingContacts) => secureStorage.write(
490 key: SecureKey.shouldRequireTOTP2FAForAddingContacts,
491 value: requireTOTP2FAForAddingContacts.toString()));
492
493 reaction(
494 (_) => shouldRequireTOTP2FAForCreatingNewWallets,
498 - (bool requireTOTP2FAForCreatingNewWallets) => writeSecureStorage(secureStorage,
495 + (bool requireTOTP2FAForCreatingNewWallets) => secureStorage.write(
496 key: SecureKey.shouldRequireTOTP2FAForCreatingNewWallets,
497 value: requireTOTP2FAForCreatingNewWallets.toString()));
498
499 reaction(
500 (_) => shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
504 - (bool requireTOTP2FAForAllSecurityAndBackupSettings) => writeSecureStorage(secureStorage,
501 + (bool requireTOTP2FAForAllSecurityAndBackupSettings) => secureStorage.write(
502 key: SecureKey.shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
503 value: requireTOTP2FAForAllSecurityAndBackupSettings.toString()));
504
508 - reaction(
509 - (_) => useTOTP2FA,
510 - (bool use) =>
511 - writeSecureStorage(secureStorage, key: SecureKey.useTOTP2FA, value: use.toString()));
505 + reaction((_) => useTOTP2FA,
506 + (bool use) => secureStorage.write(key: SecureKey.useTOTP2FA, value: use.toString()));
507
513 - reaction(
514 - (_) => totpSecretKey,
515 - (String totpKey) =>
516 - writeSecureStorage(secureStorage, key: SecureKey.totpSecretKey, value: totpKey));
508 + reaction((_) => totpSecretKey,
509 + (String totpKey) => secureStorage.write(key: SecureKey.totpSecretKey, value: totpKey));
510
511 reaction(
512 (_) => pinTimeOutDuration,
520 - (PinCodeRequiredDuration pinCodeInterval) => writeSecureStorage(secureStorage,
513 + (PinCodeRequiredDuration pinCodeInterval) => secureStorage.write(
514 key: SecureKey.pinTimeOutDuration, value: pinCodeInterval.value.toString()));
515
516 reaction(
@@ -720,7 +713,7 @@ abstract class SettingsStoreBase with Store {
713 @observable
714 int customBitcoinFeeRate;
715
723 - final FlutterSecureStorage _secureStorage;
716 + final SecureStorage _secureStorage;
717 final SharedPreferences _sharedPreferences;
718 final BackgroundTasks _backgroundTasks;
719
@@ -763,7 +756,7 @@ abstract class SettingsStoreBase with Store {
756 BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance,
757 ThemeBase? initialTheme}) async {
758 final sharedPreferences = await getIt.getAsync<SharedPreferences>();
766 - final secureStorage = await getIt.get<FlutterSecureStorage>();
759 + final secureStorage = await getIt.get<SecureStorage>();
760 final backgroundTasks = getIt.get<BackgroundTasks>();
761 final currentFiatCurrency = FiatCurrency.deserialize(
762 raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);
lib/store/yat/yat_store.dart
+2 -2
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/core/secure_storage.dart';
2 import 'package:cw_core/transaction_history.dart';
3 import 'package:cw_core/wallet_base.dart';
4 import 'package:cw_core/balance.dart';
@@ -10,7 +11,6 @@ import 'dart:convert';
11 import 'package:cake_wallet/store/yat/yat_exception.dart';
12 import 'package:http/http.dart';
13 import 'dart:async';
13 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
14
15 part 'yat_store.g.dart';
16
@@ -193,7 +193,7 @@ abstract class YatStoreBase with Store {
193
194 AppStore appStore;
195
196 - FlutterSecureStorage secureStorage;
196 + SecureStorage secureStorage;
197
198 @observable
199 String emoji;
lib/view_model/backup_view_model.dart
+2 -3
@@ -1,10 +1,9 @@
1 import 'dart:io';
2 import 'package:cake_wallet/core/backup_service.dart';
3 import 'package:cake_wallet/core/execution_state.dart';
4 +import 'package:cake_wallet/core/secure_storage.dart';
5 import 'package:cake_wallet/entities/secret_store_key.dart';
6 import 'package:cake_wallet/store/secret_store.dart';
6 -import 'package:flutter/foundation.dart';
7 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
7 import 'package:mobx/mobx.dart';
8 import 'package:intl/intl.dart';
9 import 'package:cake_wallet/wallet_type_utils.dart';
@@ -34,7 +33,7 @@ abstract class BackupViewModelBase with Store {
33 }, fireImmediately: true);
34 }
35
37 - final FlutterSecureStorage secureStorage;
36 + final SecureStorage secureStorage;
37 final SecretStore secretStore;
38 final BackupService backupService;
39
lib/view_model/edit_backup_password_view_model.dart
+2 -3
@@ -1,6 +1,5 @@
1 import 'package:cake_wallet/core/secure_storage.dart';
2 import 'package:mobx/mobx.dart';
3 -import 'package:flutter_secure_storage/flutter_secure_storage.dart';
3 import 'package:cake_wallet/entities/secret_store_key.dart';
4 import 'package:cake_wallet/store/secret_store.dart';
5
@@ -14,7 +13,7 @@ abstract class EditBackupPasswordViewModelBase with Store {
13 : backupPassword = secretStore.read(generateStoreKeyFor(key: SecretStoreKey.backupPassword)),
14 _originalPassword = '';
15
17 - final FlutterSecureStorage secureStorage;
16 + final SecureStorage secureStorage;
17 final SecretStore secretStore;
18
19 @observable
@@ -38,7 +37,7 @@ abstract class EditBackupPasswordViewModelBase with Store {
37 @action
38 Future<void> save() async {
39 final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
41 - await writeSecureStorage(secureStorage, key: key, value: backupPassword);
40 + await secureStorage.write(key: key, value: backupPassword);
41 secretStore.write(key: key, value: backupPassword);
42 }
43 }
pubspec_base.yaml
-6
@@ -11,12 +11,6 @@ dependencies:
11 ref: cake-4.0.2
12 version: 4.0.2
13 shared_preferences: ^2.0.15
14 - flutter_secure_storage:
15 - git:
16 - url: https://github.com/cake-tech/flutter_secure_storage.git
17 - path: flutter_secure_storage
18 - ref: cake-9.0.0
19 - version: 9.0.0
14 # provider: ^6.0.3
15 rxdart: ^0.27.4
16 yaml: ^3.1.1
tool/configure.dart
+117
@@ -10,6 +10,7 @@ const polygonOutputPath = 'lib/polygon/polygon.dart';
10 const solanaOutputPath = 'lib/solana/solana.dart';
11 const tronOutputPath = 'lib/tron/tron.dart';
12 const walletTypesPath = 'lib/wallet_types.g.dart';
13 +const secureStoragePath = 'lib/core/secure_storage.dart';
14 const pubspecDefaultPath = 'pubspec_default.yaml';
15 const pubspecOutputPath = 'pubspec.yaml';
16
@@ -25,6 +26,7 @@ Future<void> main(List<String> args) async {
26 final hasPolygon = args.contains('${prefix}polygon');
27 final hasSolana = args.contains('${prefix}solana');
28 final hasTron = args.contains('${prefix}tron');
29 + final excludeFlutterSecureStorage = args.contains('${prefix}excludeFlutterSecureStorage');
30
31 await generateBitcoin(hasBitcoin);
32 await generateMonero(hasMonero);
@@ -45,6 +47,7 @@ Future<void> main(List<String> args) async {
47 hasNano: hasNano,
48 hasBanano: hasBanano,
49 hasBitcoinCash: hasBitcoinCash,
50 + hasFlutterSecureStorage: !excludeFlutterSecureStorage,
51 hasPolygon: hasPolygon,
52 hasSolana: hasSolana,
53 hasTron: hasTron,
@@ -61,6 +64,7 @@ Future<void> main(List<String> args) async {
64 hasSolana: hasSolana,
65 hasTron: hasTron,
66 );
67 + await injectSecureStorage(!excludeFlutterSecureStorage);
68 }
69
70 Future<void> generateBitcoin(bool hasImplementation) async {
@@ -1142,6 +1146,7 @@ Future<void> generatePubspec(
1146 required bool hasNano,
1147 required bool hasBanano,
1148 required bool hasBitcoinCash,
1149 + required bool hasFlutterSecureStorage,
1150 required bool hasPolygon,
1151 required bool hasSolana,
1152 required bool hasTron}) async {
@@ -1165,6 +1170,14 @@ Future<void> generatePubspec(
1170 cw_shared_external:
1171 path: ./cw_shared_external
1172 """;
1173 + const flutterSecureStorage = """
1174 + flutter_secure_storage:
1175 + git:
1176 + url: https://github.com/cake-tech/flutter_secure_storage.git
1177 + path: flutter_secure_storage
1178 + ref: cake-9.0.0
1179 + version: 9.0.0
1180 + """;
1181 const cwEthereum = """
1182 cw_ethereum:
1183 path: ./cw_ethereum
@@ -1246,6 +1259,10 @@ Future<void> generatePubspec(
1259 output += '\n$cwHaven';
1260 }
1261
1262 + if (hasFlutterSecureStorage) {
1263 + output += '\n$flutterSecureStorage\n';
1264 + }
1265 +
1266 if (hasEthereum || hasPolygon) {
1267 output += '\n$cwEVM';
1268 }
@@ -1330,3 +1347,103 @@ Future<void> generateWalletTypes(
1347 outputContent += '];\n';
1348 await walletTypesFile.writeAsString(outputContent);
1349 }
1350 +
1351 +Future<void> injectSecureStorage(bool hasFlutterSecureStorage) async {
1352 + const flutterSecureStorageHeader = """
1353 +import 'dart:async';
1354 +import 'dart:io';
1355 +import 'package:flutter_secure_storage/flutter_secure_storage.dart';
1356 +""";
1357 + const abstractSecureStorage = """
1358 +abstract class SecureStorage {
1359 + Future<String?> read({required String key});
1360 + Future<void> write({required String key, required String? value});
1361 + Future<void> delete({required String key});
1362 + // Legacy
1363 + Future<String?> readNoIOptions({required String key});
1364 + }""";
1365 + const defaultSecureStorage = """
1366 +class DefaultSecureStorage extends SecureStorage {
1367 + DefaultSecureStorage._(this._secureStorage);
1368 +
1369 + factory DefaultSecureStorage() => _instance;
1370 +
1371 + static final _instance = DefaultSecureStorage._(FlutterSecureStorage(
1372 + iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
1373 + ));
1374 +
1375 + final FlutterSecureStorage _secureStorage;
1376 +
1377 + @override
1378 + Future<String?> read({required String key}) async => await _readInternal(key, false);
1379 +
1380 + @override
1381 + Future<void> write({required String key, required String? value}) async {
1382 + // delete the value before writing on macOS because of a weird bug
1383 + // https://github.com/mogol/flutter_secure_storage/issues/581
1384 + if (Platform.isMacOS) {
1385 + await _secureStorage.delete(key: key);
1386 + }
1387 + await _secureStorage.write(key: key, value: value);
1388 + }
1389 +
1390 + @override
1391 + Future<void> delete({required String key}) async => _secureStorage.delete(key: key);
1392 +
1393 + @override
1394 + Future<String?> readNoIOptions({required String key}) async => await _readInternal(key, true);
1395 +
1396 + Future<String?> _readInternal(String key, bool useNoIOptions) async {
1397 + String? result;
1398 +
1399 + const maxWait = Duration(seconds: 3);
1400 + const checkInterval = Duration(milliseconds: 200);
1401 +
1402 + DateTime start = DateTime.now();
1403 +
1404 + while (result == null && DateTime.now().difference(start) < maxWait) {
1405 + result = await _secureStorage.read(
1406 + key: key,
1407 + iOptions: useNoIOptions ? IOSOptions() : null,
1408 + );
1409 +
1410 + if (result != null) {
1411 + break;
1412 + }
1413 +
1414 + await Future.delayed(checkInterval);
1415 + }
1416 +
1417 + return result;
1418 + }
1419 + }""";
1420 + const fakeSecureStorage = """
1421 +class FakeSecureStorage extends SecureStorage {
1422 + @override
1423 + Future<String?> read({required String key}) async => null;
1424 + @override
1425 + Future<void> write({required String key, required String? value}) async {}
1426 + @override
1427 + Future<void> delete({required String key}) async {}
1428 + @override
1429 + Future<String?> readNoIOptions({required String key}) async => null;
1430 + }""";
1431 + final outputFile = File(secureStoragePath);
1432 + final header = hasFlutterSecureStorage
1433 + ? '${flutterSecureStorageHeader}\n\nfinal SecureStorage secureStorageShared = DefaultSecureStorage();\n'
1434 + : 'final SecureStorage secureStorageShared = FakeSecureStorage();\n';
1435 + var output = '';
1436 + if (outputFile.existsSync()) {
1437 + await outputFile.delete();
1438 + }
1439 +
1440 + output += '${header}\n${abstractSecureStorage}\n\n';
1441 +
1442 + if (hasFlutterSecureStorage) {
1443 + output += '${defaultSecureStorage}\n';
1444 + } else {
1445 + output += '${fakeSecureStorage}\n';
1446 + }
1447 +
1448 + await outputFile.writeAsString(output);
1449 +}