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>
This commit is contained in:
Adegoke David 2024-05-08 21:23:27 +01:00 committed by GitHub
parent c35929f28e
commit bfb78eded9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 259 additions and 199 deletions

1
.gitignore vendored
View file

@ -156,6 +156,7 @@ assets/images/app_logo.png
macos/Runner/Info.plist macos/Runner/Info.plist
macos/Runner/DebugProfile.entitlements macos/Runner/DebugProfile.entitlements
macos/Runner/Release.entitlements macos/Runner/Release.entitlements
lib/core/secure_storage.dart
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png

View file

@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/core/totp_request_details.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:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart';
@ -35,14 +33,14 @@ class AuthService with Store {
Routes.restoreOptions, Routes.restoreOptions,
]; ];
final FlutterSecureStorage secureStorage; final SecureStorage secureStorage;
final SharedPreferences sharedPreferences; final SharedPreferences sharedPreferences;
final SettingsStore settingsStore; final SettingsStore settingsStore;
Future<void> setPassword(String password) async { Future<void> setPassword(String password) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final encodedPassword = encodedPinCode(pin: password); final encodedPassword = encodedPinCode(pin: password);
await writeSecureStorage(secureStorage, key: key, value: encodedPassword); await secureStorage.write(key: key, value: encodedPassword);
} }
Future<bool> canAuthenticate() async { Future<bool> canAuthenticate() async {
@ -61,7 +59,7 @@ class AuthService with Store {
Future<bool> authenticate(String pin) async { Future<bool> authenticate(String pin) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final encodedPin = await readSecureStorage(secureStorage, key); final encodedPin = await secureStorage.read(key: key);
final decodedPin = decodedPinCode(pin: encodedPin!); final decodedPin = decodedPinCode(pin: encodedPin!);
return decodedPin == pin; return decodedPin == pin;
@ -69,11 +67,7 @@ class AuthService with Store {
void saveLastAuthTime() { void saveLastAuthTime() {
int timestamp = DateTime.now().millisecondsSinceEpoch; int timestamp = DateTime.now().millisecondsSinceEpoch;
writeSecureStorage( secureStorage.write(key: SecureKey.lastAuthTimeMilliseconds, value: timestamp.toString());
secureStorage,
key: SecureKey.lastAuthTimeMilliseconds,
value: timestamp.toString(),
);
} }
Future<bool> requireAuth() async { Future<bool> requireAuth() async {

View file

@ -7,7 +7,6 @@ import 'package:cake_wallet/utils/device_info.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:cryptography/cryptography.dart'; import 'package:cryptography/cryptography.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -25,7 +24,7 @@ import 'package:cake_backup/backup.dart' as cake_backup;
class BackupService { class BackupService {
BackupService( BackupService(
this._flutterSecureStorage, this._walletInfoSource, this._keyService, this._sharedPreferences) this._secureStorage, this._walletInfoSource, this._keyService, this._sharedPreferences)
: _cipher = Cryptography.instance.chacha20Poly1305Aead(), : _cipher = Cryptography.instance.chacha20Poly1305Aead(),
_correctWallets = <WalletInfo>[]; _correctWallets = <WalletInfo>[];
@ -35,7 +34,7 @@ class BackupService {
static const _v2 = 2; static const _v2 = 2;
final Cipher _cipher; final Cipher _cipher;
final FlutterSecureStorage _flutterSecureStorage; final SecureStorage _secureStorage;
final SharedPreferences _sharedPreferences; final SharedPreferences _sharedPreferences;
final Box<WalletInfo> _walletInfoSource; final Box<WalletInfo> _walletInfoSource;
final KeyService _keyService; final KeyService _keyService;
@ -374,15 +373,14 @@ class BackupService {
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword); final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
final backupPassword = keychainJSON[backupPasswordKey] as String; 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 { keychainWalletsInfo.forEach((dynamic rawInfo) async {
final info = rawInfo as Map<String, dynamic>; final info = rawInfo as Map<String, dynamic>;
await importWalletKeychainInfo(info); await importWalletKeychainInfo(info);
}); });
await writeSecureStorage(_flutterSecureStorage, await _secureStorage.write(key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
keychainDumpFile.deleteSync(); keychainDumpFile.deleteSync();
} }
@ -401,15 +399,14 @@ class BackupService {
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword); final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
final backupPassword = keychainJSON[backupPasswordKey] as String; 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 { keychainWalletsInfo.forEach((dynamic rawInfo) async {
final info = rawInfo as Map<String, dynamic>; final info = rawInfo as Map<String, dynamic>;
await importWalletKeychainInfo(info); await importWalletKeychainInfo(info);
}); });
await writeSecureStorage(_flutterSecureStorage, await _secureStorage.write(key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
keychainDumpFile.deleteSync(); keychainDumpFile.deleteSync();
} }
@ -429,7 +426,7 @@ class BackupService {
Future<Uint8List> _exportKeychainDumpV2(String password, Future<Uint8List> _exportKeychainDumpV2(String password,
{String keychainSalt = secrets.backupKeychainSalt}) async { {String keychainSalt = secrets.backupKeychainSalt}) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); 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 decodedPin = decodedPinCode(pin: encodedPin!);
final wallets = await Future.wait(_walletInfoSource.values.map((walletInfo) async { final wallets = await Future.wait(_walletInfoSource.values.map((walletInfo) async {
return { return {
@ -439,7 +436,7 @@ class BackupService {
}; };
})); }));
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword); final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
final backupPassword = await _flutterSecureStorage.read(key: backupPasswordKey); final backupPassword = await _secureStorage.read(key: backupPasswordKey);
final data = utf8.encode( final data = utf8.encode(
json.encode({'pin': decodedPin, 'wallets': wallets, backupPasswordKey: backupPassword})); json.encode({'pin': decodedPin, 'wallets': wallets, backupPasswordKey: backupPassword}));
final encrypted = await _encryptV2(Uint8List.fromList(data), '$keychainSalt$password'); final encrypted = await _encryptV2(Uint8List.fromList(data), '$keychainSalt$password');

View file

@ -1,31 +1,30 @@
import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/core/secure_storage.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:cake_wallet/entities/encrypt.dart'; import 'package:cake_wallet/entities/encrypt.dart';
class KeyService { class KeyService {
KeyService(this._secureStorage); KeyService(this._secureStorage);
final FlutterSecureStorage _secureStorage; final SecureStorage _secureStorage;
Future<String> getWalletPassword({required String walletName}) async { Future<String> getWalletPassword({required String walletName}) async {
final key = generateStoreKeyFor( final key =
key: SecretStoreKey.moneroWalletPassword, walletName: walletName); generateStoreKeyFor(key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
final encodedPassword = await readSecureStorage(_secureStorage, key); final encodedPassword = await _secureStorage.read(key: key);
return decodeWalletPassword(password: encodedPassword!); return decodeWalletPassword(password: encodedPassword!);
} }
Future<void> saveWalletPassword({required String walletName, required String password}) async { Future<void> saveWalletPassword({required String walletName, required String password}) async {
final key = generateStoreKeyFor( final key =
key: SecretStoreKey.moneroWalletPassword, walletName: walletName); generateStoreKeyFor(key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
final encodedPassword = encodeWalletPassword(password: password); final encodedPassword = encodeWalletPassword(password: password);
await writeSecureStorage(_secureStorage, key: key, value: encodedPassword); await _secureStorage.write(key: key, value: encodedPassword);
} }
Future<void> deleteWalletPassword({required String walletName}) async { Future<void> deleteWalletPassword({required String walletName}) async {
final key = generateStoreKeyFor( final key =
key: SecretStoreKey.moneroWalletPassword, walletName: walletName); generateStoreKeyFor(key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
await _secureStorage.delete(key: key); await _secureStorage.delete(key: key);
} }

View file

@ -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<String?> 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<void> 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);
}

View file

@ -1,8 +1,8 @@
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/core/key_service.dart'; import 'package:cake_wallet/core/key_service.dart';
@ -25,7 +25,7 @@ class WalletCreationService {
} }
WalletType type; WalletType type;
final FlutterSecureStorage secureStorage; final SecureStorage secureStorage;
final SharedPreferences sharedPreferences; final SharedPreferences sharedPreferences;
final SettingsStore settingsStore; final SettingsStore settingsStore;
final KeyService keyService; final KeyService keyService;

View file

@ -236,6 +236,32 @@ import 'package:get_it/get_it.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.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 'buy/dfx/dfx_buy_provider.dart';
import 'core/totp_request_details.dart'; import 'core/totp_request_details.dart';
@ -268,7 +294,7 @@ Future<void> setup({
required Box<Order> ordersSource, required Box<Order> ordersSource,
required Box<UnspentCoinsInfo> unspentCoinsInfoSource, required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource, required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
required FlutterSecureStorage secureStorage, required SecureStorage secureStorage,
required GlobalKey<NavigatorState> navigatorKey, required GlobalKey<NavigatorState> navigatorKey,
}) async { }) async {
_walletInfoSource = walletInfoSource; _walletInfoSource = walletInfoSource;
@ -285,7 +311,7 @@ Future<void> setup({
if (!_isSetupFinished) { if (!_isSetupFinished) {
getIt.registerSingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance()); getIt.registerSingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance());
getIt.registerSingleton<FlutterSecureStorage>(secureStorage); getIt.registerSingleton<SecureStorage>(secureStorage);
} }
if (!_isSetupFinished) { if (!_isSetupFinished) {
getIt.registerFactory(() => BackgroundTasks()); getIt.registerFactory(() => BackgroundTasks());
@ -333,22 +359,22 @@ Future<void> setup({
getIt.registerSingleton<ExchangeTemplateStore>( getIt.registerSingleton<ExchangeTemplateStore>(
ExchangeTemplateStore(templateSource: _exchangeTemplates)); ExchangeTemplateStore(templateSource: _exchangeTemplates));
getIt.registerSingleton<YatStore>( getIt.registerSingleton<YatStore>(
YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<FlutterSecureStorage>()) YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<SecureStorage>())
..init()); ..init());
getIt.registerSingleton<AnonpayTransactionsStore>( getIt.registerSingleton<AnonpayTransactionsStore>(
AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource)); AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
final secretStore = await SecretStoreBase.load(getIt.get<FlutterSecureStorage>()); final secretStore = await SecretStoreBase.load(getIt.get<SecureStorage>());
getIt.registerSingleton<SecretStore>(secretStore); getIt.registerSingleton<SecretStore>(secretStore);
getIt.registerFactory<KeyService>(() => KeyService(getIt.get<FlutterSecureStorage>())); getIt.registerFactory<KeyService>(() => KeyService(getIt.get<SecureStorage>()));
getIt.registerFactoryParam<WalletCreationService, WalletType, void>((type, _) => getIt.registerFactoryParam<WalletCreationService, WalletType, void>((type, _) =>
WalletCreationService( WalletCreationService(
initialType: type, initialType: type,
keyService: getIt.get<KeyService>(), keyService: getIt.get<KeyService>(),
secureStorage: getIt.get<FlutterSecureStorage>(), secureStorage: getIt.get<SecureStorage>(),
sharedPreferences: getIt.get<SharedPreferences>(), sharedPreferences: getIt.get<SharedPreferences>(),
settingsStore: getIt.get<SettingsStore>(), settingsStore: getIt.get<SettingsStore>(),
walletInfoSource: _walletInfoSource)); walletInfoSource: _walletInfoSource));
@ -403,7 +429,7 @@ Future<void> setup({
getIt.registerFactory<AuthService>( getIt.registerFactory<AuthService>(
() => AuthService( () => AuthService(
secureStorage: getIt.get<FlutterSecureStorage>(), secureStorage: getIt.get<SecureStorage>(),
sharedPreferences: getIt.get<SharedPreferences>(), sharedPreferences: getIt.get<SharedPreferences>(),
settingsStore: getIt.get<SettingsStore>(), settingsStore: getIt.get<SettingsStore>(),
), ),
@ -980,16 +1006,16 @@ Future<void> setup({
trades: _tradesSource, trades: _tradesSource,
settingsStore: getIt.get<SettingsStore>())); settingsStore: getIt.get<SettingsStore>()));
getIt.registerFactory(() => BackupService(getIt.get<FlutterSecureStorage>(), _walletInfoSource, getIt.registerFactory(() => BackupService(getIt.get<SecureStorage>(), _walletInfoSource,
getIt.get<KeyService>(), getIt.get<SharedPreferences>())); getIt.get<KeyService>(), getIt.get<SharedPreferences>()));
getIt.registerFactory(() => BackupViewModel( getIt.registerFactory(() => BackupViewModel(
getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>(), getIt.get<BackupService>())); getIt.get<SecureStorage>(), getIt.get<SecretStore>(), getIt.get<BackupService>()));
getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>())); getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>()));
getIt.registerFactory(() => getIt.registerFactory(() =>
EditBackupPasswordViewModel(getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>())); EditBackupPasswordViewModel(getIt.get<SecureStorage>(), getIt.get<SecretStore>()));
getIt.registerFactory(() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>())); getIt.registerFactory(() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
@ -1038,7 +1064,7 @@ Future<void> setup({
getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>())); getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>()));
getIt.registerFactory(() => SupportChatPage(getIt.get<SupportViewModel>(), getIt.registerFactory(() => SupportChatPage(getIt.get<SupportViewModel>(),
secureStorage: getIt.get<FlutterSecureStorage>())); secureStorage: getIt.get<SecureStorage>()));
getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>())); getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>()));
@ -1080,7 +1106,7 @@ Future<void> setup({
getIt.registerFactory(() => AnyPayApi()); getIt.registerFactory(() => AnyPayApi());
getIt.registerFactory<IoniaService>( getIt.registerFactory<IoniaService>(
() => IoniaService(getIt.get<FlutterSecureStorage>(), getIt.get<IoniaApi>())); () => IoniaService(getIt.get<SecureStorage>(), getIt.get<IoniaApi>()));
getIt.registerFactory<IoniaAnyPay>(() => IoniaAnyPay( getIt.registerFactory<IoniaAnyPay>(() => IoniaAnyPay(
getIt.get<IoniaService>(), getIt.get<AnyPayApi>(), getIt.get<AppStore>().wallet!)); getIt.get<IoniaService>(), getIt.get<AnyPayApi>(), getIt.get<AppStore>().wallet!));

View file

@ -1,10 +1,10 @@
import 'dart:io' show Directory, File, Platform; import 'dart:io' show Directory, File, Platform;
import 'package:cake_wallet/bitcoin/bitcoin.dart'; 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/exchange_api_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -42,7 +42,7 @@ const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002';
Future<void> defaultSettingsMigration( Future<void> defaultSettingsMigration(
{required int version, {required int version,
required SharedPreferences sharedPreferences, required SharedPreferences sharedPreferences,
required FlutterSecureStorage secureStorage, required SecureStorage secureStorage,
required Box<Node> nodes, required Box<Node> nodes,
required Box<Node> powNodes, required Box<Node> powNodes,
required Box<WalletInfo> walletInfoSource, required Box<WalletInfo> walletInfoSource,
@ -485,7 +485,7 @@ Node? getTronDefaultNode({required Box<Node> nodes}) {
Future<void> insecureStorageMigration({ Future<void> insecureStorageMigration({
required SharedPreferences sharedPreferences, required SharedPreferences sharedPreferences,
required FlutterSecureStorage secureStorage, required SecureStorage secureStorage,
}) async { }) async {
bool? allowBiometricalAuthentication = bool? allowBiometricalAuthentication =
sharedPreferences.getBool(SecureKey.allowBiometricalAuthenticationKey); sharedPreferences.getBool(SecureKey.allowBiometricalAuthenticationKey);
@ -559,7 +559,7 @@ Future<void> insecureStorageMigration({
} }
} }
Future<void> rewriteSecureStoragePin({required FlutterSecureStorage secureStorage}) async { Future<void> rewriteSecureStoragePin({required SecureStorage secureStorage}) async {
// the bug only affects ios/mac: // the bug only affects ios/mac:
if (!Platform.isIOS && !Platform.isMacOS) { if (!Platform.isIOS && !Platform.isMacOS) {
return; return;
@ -585,8 +585,9 @@ Future<void> rewriteSecureStoragePin({required FlutterSecureStorage secureStorag
await secureStorage.write( await secureStorage.write(
key: keyForPinCode, key: keyForPinCode,
value: encodedPin, value: encodedPin,
iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock), // TODO: find a way to add those with the generated secure storage
mOptions: MacOsOptions(accessibility: KeychainAccessibility.first_unlock), // iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
// mOptions: MacOsOptions(accessibility: KeychainAccessibility.first_unlock),
); );
} }
@ -720,7 +721,7 @@ Future<void> updateDisplayModes(SharedPreferences sharedPreferences) async {
await sharedPreferences.setInt(PreferencesKey.currentBalanceDisplayModeKey, balanceDisplayMode); await sharedPreferences.setInt(PreferencesKey.currentBalanceDisplayModeKey, balanceDisplayMode);
} }
Future<void> generateBackupPassword(FlutterSecureStorage secureStorage) async { Future<void> generateBackupPassword(SecureStorage secureStorage) async {
final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword); final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
if ((await secureStorage.read(key: key))?.isNotEmpty ?? false) { if ((await secureStorage.read(key: key))?.isNotEmpty ?? false) {

View file

@ -2,7 +2,6 @@ import 'dart:io';
import 'dart:convert'; import 'dart:convert';
import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/core/secure_storage.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.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:cw_core/crypto_currency.dart';
import 'package:cake_wallet/entities/encrypt.dart'; import 'package:cake_wallet/entities/encrypt.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/ios_legacy_helper.dart' import 'package:cake_wallet/entities/ios_legacy_helper.dart' as ios_legacy_helper;
as ios_legacy_helper;
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
@ -30,8 +28,8 @@ Future<void> migrate_android_v1() async {
await android_migrate_wallets(appDocDir: appDocDir); await android_migrate_wallets(appDocDir: appDocDir);
} }
Future<void> ios_migrate_v1(Box<WalletInfo> walletInfoSource, Future<void> ios_migrate_v1(
Box<Trade> tradeSource, Box<Contact> contactSource) async { Box<WalletInfo> walletInfoSource, Box<Trade> tradeSource, Box<Contact> contactSource) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
if (prefs.getBool('ios_migration_v1_completed') ?? false) { if (prefs.getBool('ios_migration_v1_completed') ?? false) {
@ -67,10 +65,7 @@ Future<void> ios_migrate_user_defaults() async {
if (activeCurrency != null) { if (activeCurrency != null) {
final convertedCurrency = convertFiatLegacy(activeCurrency); 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 //translate fee priority
@ -81,24 +76,21 @@ Future<void> ios_migrate_user_defaults() async {
} }
//translate current balance mode //translate current balance mode
final currentBalanceMode = final currentBalanceMode = await ios_legacy_helper.getInt('display_balance_mode');
await ios_legacy_helper.getInt('display_balance_mode');
if (currentBalanceMode != null) { if (currentBalanceMode != null) {
await prefs.setInt('current_balance_display_mode', currentBalanceMode); await prefs.setInt('current_balance_display_mode', currentBalanceMode);
} }
//translate should save recipient address //translate should save recipient address
final shouldSave = final shouldSave = await ios_legacy_helper.getBool('should_save_recipient_address');
await ios_legacy_helper.getBool('should_save_recipient_address');
if (shouldSave != null) { if (shouldSave != null) {
await prefs.setBool('save_recipient_address', shouldSave); await prefs.setBool('save_recipient_address', shouldSave);
} }
//translate biometric //translate biometric
final biometricOn = final biometricOn = await ios_legacy_helper.getBool('biometric_authentication_on');
await ios_legacy_helper.getBool('biometric_authentication_on');
if (biometricOn != null) { if (biometricOn != null) {
await prefs.setBool('allow_biometrical_authentication', biometricOn); await prefs.setBool('allow_biometrical_authentication', biometricOn);
} }
@ -137,9 +129,8 @@ Future<void> ios_migrate_pin() async {
return; return;
} }
final flutterSecureStorage = FlutterSecureStorage(); final flutterSecureStorage = secureStorageShared;
final pinPassword = await flutterSecureStorage.read( final pinPassword = await flutterSecureStorage.readNoIOptions(key: 'pin_password');
key: 'pin_password', iOptions: IOSOptions());
// No pin // No pin
if (pinPassword == null) { if (pinPassword == null) {
await prefs.setBool('ios_migration_pin_completed', true); await prefs.setBool('ios_migration_pin_completed', true);
@ -148,7 +139,7 @@ Future<void> ios_migrate_pin() async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final encodedPassword = encodedPinCode(pin: pinPassword); 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); await prefs.setBool('ios_migration_pin_completed', true);
} }
@ -161,7 +152,7 @@ Future<void> ios_migrate_wallet_passwords() async {
} }
final appDocDir = await getApplicationDocumentsDirectory(); final appDocDir = await getApplicationDocumentsDirectory();
final flutterSecureStorage = FlutterSecureStorage(); final flutterSecureStorage = secureStorageShared;
final keyService = KeyService(flutterSecureStorage); final keyService = KeyService(flutterSecureStorage);
final walletsDir = Directory('${appDocDir.path}/wallets'); final walletsDir = Directory('${appDocDir.path}/wallets');
final moneroWalletsDir = Directory('${walletsDir.path}/monero'); final moneroWalletsDir = Directory('${walletsDir.path}/monero');
@ -176,10 +167,8 @@ Future<void> ios_migrate_wallet_passwords() async {
if (item is Directory) { if (item is Directory) {
final name = item.path.split('/').last; final name = item.path.split('/').last;
final oldKey = 'wallet_monero_' + name + '_password'; final oldKey = 'wallet_monero_' + name + '_password';
final password = await flutterSecureStorage.read( final password = await flutterSecureStorage.readNoIOptions(key: oldKey);
key: oldKey, iOptions: IOSOptions()); await keyService.saveWalletPassword(walletName: name, password: password!);
await keyService.saveWalletPassword(
walletName: name, password: password!);
} }
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
@ -311,18 +300,14 @@ Future<void> ios_migrate_wallet_info(Box<WalletInfo> walletsInfoSource) async {
return null; return null;
} }
final config = json.decode(configFile.readAsStringSync()) final config = json.decode(configFile.readAsStringSync()) as Map<String, dynamic>;
as Map<String, dynamic>; final isRecovery = config['isRecovery'] as bool? ?? false;
final isRecovery = config['isRecovery'] as bool ?? false;
final dateAsDouble = config['date'] as double; final dateAsDouble = config['date'] as double;
final timestamp = dateAsDouble.toInt() * 1000; final timestamp = dateAsDouble.toInt() * 1000;
final date = DateTime.fromMillisecondsSinceEpoch(timestamp); final date = DateTime.fromMillisecondsSinceEpoch(timestamp);
final id = walletTypeToString(WalletType.monero).toLowerCase() + final id = walletTypeToString(WalletType.monero).toLowerCase() + '_' + name;
'_' + final exist = walletsInfoSource.values.firstWhereOrNull((el) => el.id == id) != null;
name;
final exist = walletsInfoSource.values
.firstWhereOrNull((el) => el.id == id) != null;
if (exist) { if (exist) {
return null; return null;
} }
@ -373,12 +358,10 @@ Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
} }
final content = file.readAsBytesSync(); final content = file.readAsBytesSync();
final flutterSecureStorage = FlutterSecureStorage(); final flutterSecureStorage = secureStorageShared;
final masterPassword = await flutterSecureStorage.read( final masterPassword = await flutterSecureStorage.readNoIOptions(key: 'master_password');
key: 'master_password', iOptions: IOSOptions());
final key = masterPassword!.replaceAll('-', ''); final key = masterPassword!.replaceAll('-', '');
final decoded = final decoded = await ios_legacy_helper.decrypt(content, key: key, salt: secrets.salt);
await ios_legacy_helper.decrypt(content, key: key, salt: secrets.salt);
final decodedJson = json.decode(decoded) as List<dynamic>; final decodedJson = json.decode(decoded) as List<dynamic>;
final trades = decodedJson.map((dynamic el) { final trades = decodedJson.map((dynamic el) {
final elAsMap = el as Map<String, dynamic>; final elAsMap = el as Map<String, dynamic>;
@ -441,8 +424,7 @@ Future<void> ios_migrate_address_book(Box<Contact> contactSource) async {
final address = _item["address"] as String; final address = _item["address"] as String;
final name = _item["name"] as String; final name = _item["name"] as String;
return Contact( return Contact(address: address, name: name, type: CryptoCurrency.fromString(type));
address: address, name: name, type: CryptoCurrency.fromString(type));
}); });
await contactSource.addAll(contacts); await contactSource.addAll(contacts);

View file

@ -1,9 +1,8 @@
import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/core/secure_storage.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:cw_core/cake_hive.dart'; import 'package:cw_core/cake_hive.dart';
Future<List<int>> getEncryptionKey( Future<List<int>> getEncryptionKey(
{required String forKey, required FlutterSecureStorage secureStorage}) async { {required String forKey, required SecureStorage secureStorage}) async {
final stringifiedKey = await secureStorage.read(key: 'transactionDescriptionsBoxKey'); final stringifiedKey = await secureStorage.read(key: 'transactionDescriptionsBoxKey');
List<int> key; List<int> key;
@ -11,7 +10,7 @@ Future<List<int>> getEncryptionKey(
key = CakeHive.generateSecureKey(); key = CakeHive.generateSecureKey();
final keyStringified = key.join(','); final keyStringified = key.join(',');
String storageKey = 'transactionDescriptionsBoxKey'; String storageKey = 'transactionDescriptionsBoxKey';
await writeSecureStorage(secureStorage, key: storageKey, value: keyStringified); await secureStorage.write(key: storageKey, value: keyStringified);
} else { } else {
key = stringifiedKey.split(',').map((i) => int.parse(i)).toList(); key = stringifiedKey.split(',').map((i) => int.parse(i)).toList();
} }

View file

@ -61,9 +61,9 @@ class PreferencesKey {
static const defaultBananoRep = 'default_banano_representative'; static const defaultBananoRep = 'default_banano_representative';
static const lookupsTwitter = 'looks_up_twitter'; static const lookupsTwitter = 'looks_up_twitter';
static const lookupsMastodon = 'looks_up_mastodon'; static const lookupsMastodon = 'looks_up_mastodon';
static const lookupsYatService = 'looks_up_mastodon'; static const lookupsYatService = 'looks_up_yat';
static const lookupsUnstoppableDomains = 'looks_up_mastodon'; static const lookupsUnstoppableDomains = 'looks_up_unstoppable_domain';
static const lookupsOpenAlias = 'looks_up_mastodon'; static const lookupsOpenAlias = 'looks_up_open_alias';
static const lookupsENS = 'looks_up_ens'; static const lookupsENS = 'looks_up_ens';
static String moneroWalletUpdateV1Key(String name) => static String moneroWalletUpdateV1Key(String name) =>

View file

@ -1,4 +1,4 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:cake_wallet/core/secure_storage.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
enum SecretStoreKey { moneroWalletPassword, pinCodePassword, backupPassword } enum SecretStoreKey { moneroWalletPassword, pinCodePassword, backupPassword }
@ -66,7 +66,7 @@ class SecureKey {
static const lastAuthTimeMilliseconds = 'last_auth_time_milliseconds'; static const lastAuthTimeMilliseconds = 'last_auth_time_milliseconds';
static Future<int?> getInt({ static Future<int?> getInt({
required FlutterSecureStorage secureStorage, required SecureStorage secureStorage,
required SharedPreferences sharedPreferences, required SharedPreferences sharedPreferences,
required String key, required String key,
}) async { }) async {
@ -76,7 +76,7 @@ class SecureKey {
} }
static Future<bool?> getBool({ static Future<bool?> getBool({
required FlutterSecureStorage secureStorage, required SecureStorage secureStorage,
required SharedPreferences sharedPreferences, required SharedPreferences sharedPreferences,
required String key, required String key,
}) async { }) async {
@ -91,7 +91,7 @@ class SecureKey {
} }
static Future<String?> getString({ static Future<String?> getString({
required FlutterSecureStorage secureStorage, required SecureStorage secureStorage,
required SharedPreferences sharedPreferences, required SharedPreferences sharedPreferences,
required String key, required String key,
}) async { }) async {

View file

@ -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_merchant.dart';
import 'package:cake_wallet/ionia/ionia_order.dart'; import 'package:cake_wallet/ionia/ionia_order.dart';
import 'package:cake_wallet/ionia/ionia_virtual_card.dart'; import 'package:cake_wallet/ionia/ionia_virtual_card.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/ionia/ionia_api.dart'; import 'package:cake_wallet/ionia/ionia_api.dart';
import 'package:cake_wallet/ionia/ionia_gift_card.dart'; import 'package:cake_wallet/ionia/ionia_gift_card.dart';
@ -16,7 +16,7 @@ class IoniaService {
static String get clientId => secrets.ioniaClientId; static String get clientId => secrets.ioniaClientId;
final FlutterSecureStorage secureStorage; final SecureStorage secureStorage;
final IoniaApi ioniaApi; final IoniaApi ioniaApi;
// Create user // Create user

View file

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart'; import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
import 'package:cake_wallet/core/auth_service.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/entities/language_service.dart';
import 'package:cake_wallet/buy/order.dart'; import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/locales/locale.dart'; import 'package:cake_wallet/locales/locale.dart';
@ -18,7 +19,6 @@ import 'package:hive/hive.dart';
import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/di.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/router.dart' as Router; import 'package:cake_wallet/router.dart' as Router;
@ -138,9 +138,8 @@ Future<void> initializeAppConfigs() async {
CakeHive.registerAdapter(AnonpayInvoiceInfoAdapter()); CakeHive.registerAdapter(AnonpayInvoiceInfoAdapter());
} }
final secureStorage = FlutterSecureStorage( final secureStorage = secureStorageShared;
iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
);
final transactionDescriptionsBoxKey = final transactionDescriptionsBoxKey =
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey); await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey); final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
@ -191,7 +190,7 @@ Future<void> initialSetup(
required Box<Template> templates, required Box<Template> templates,
required Box<ExchangeTemplate> exchangeTemplates, required Box<ExchangeTemplate> exchangeTemplates,
required Box<TransactionDescription> transactionDescriptions, required Box<TransactionDescription> transactionDescriptions,
required FlutterSecureStorage secureStorage, required SecureStorage secureStorage,
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfo, required Box<AnonpayInvoiceInfo> anonpayInvoiceInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfoSource, required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
int initialMigrationVersion = 15}) async { int initialMigrationVersion = 15}) async {

View file

@ -1,16 +1,16 @@
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.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/src/screens/support_chat/widgets/chatwoot_widget.dart';
import 'package:cake_wallet/view_model/support_view_model.dart'; import 'package:cake_wallet/view_model/support_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SupportChatPage extends BasePage { class SupportChatPage extends BasePage {
SupportChatPage(this.supportViewModel, {required this.secureStorage}); SupportChatPage(this.supportViewModel, {required this.secureStorage});
final SupportViewModel supportViewModel; final SupportViewModel supportViewModel;
final FlutterSecureStorage secureStorage; final SecureStorage secureStorage;
@override @override
String get title => S.current.settings_support; String get title => S.current.settings_support;

View file

@ -3,14 +3,13 @@ import 'dart:convert';
import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/core/secure_storage.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
const COOKIE_KEY = 'chatwootCookie'; const COOKIE_KEY = 'chatwootCookie';
class ChatwootWidget extends StatefulWidget { class ChatwootWidget extends StatefulWidget {
ChatwootWidget(this.secureStorage, {required this.supportUrl}); ChatwootWidget(this.secureStorage, {required this.supportUrl});
final FlutterSecureStorage secureStorage; final SecureStorage secureStorage;
final String supportUrl; final String supportUrl;
@override @override
@ -59,6 +58,6 @@ class ChatwootWidgetState extends State<ChatwootWidget> {
} }
Future<void> storeCookie(String value) async { Future<void> storeCookie(String value) async {
await writeSecureStorage(widget.secureStorage, key: COOKIE_KEY, value: value); await widget.secureStorage.write(key: COOKIE_KEY, value: value);
} }
} }

View file

@ -1,6 +1,5 @@
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
part 'secret_store.g.dart'; part 'secret_store.g.dart';
@ -8,7 +7,7 @@ part 'secret_store.g.dart';
class SecretStore = SecretStoreBase with _$SecretStore; class SecretStore = SecretStoreBase with _$SecretStore;
abstract class SecretStoreBase with Store { abstract class SecretStoreBase with Store {
static Future<SecretStore> load(FlutterSecureStorage storage) async { static Future<SecretStore> load(SecureStorage storage) async {
final secretStore = SecretStore(); final secretStore = SecretStore();
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword); final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
final backupPassword = await storage.read(key: backupPasswordKey); final backupPassword = await storage.read(key: backupPasswordKey);

View file

@ -26,7 +26,6 @@ import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/themes/theme_list.dart'; import 'package:cake_wallet/themes/theme_list.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info/package_info.dart';
@ -48,7 +47,7 @@ class SettingsStore = SettingsStoreBase with _$SettingsStore;
abstract class SettingsStoreBase with Store { abstract class SettingsStoreBase with Store {
SettingsStoreBase( SettingsStoreBase(
{required FlutterSecureStorage secureStorage, {required SecureStorage secureStorage,
required BackgroundTasks backgroundTasks, required BackgroundTasks backgroundTasks,
required SharedPreferences sharedPreferences, required SharedPreferences sharedPreferences,
required bool initialShouldShowMarketPlaceInDashboard, required bool initialShouldShowMarketPlaceInDashboard,
@ -398,10 +397,8 @@ abstract class SettingsStoreBase with Store {
(bool usePolygonScan) => (bool usePolygonScan) =>
_sharedPreferences.setBool(PreferencesKey.usePolygonScan, usePolygonScan)); _sharedPreferences.setBool(PreferencesKey.usePolygonScan, usePolygonScan));
reaction( reaction((_) => useTronGrid,
(_) => useTronGrid, (bool useTronGrid) => _sharedPreferences.setBool(PreferencesKey.useTronGrid, useTronGrid));
(bool useTronGrid) =>
_sharedPreferences.setBool(PreferencesKey.useTronGrid, useTronGrid));
reaction((_) => defaultNanoRep, reaction((_) => defaultNanoRep,
(String nanoRep) => _sharedPreferences.setString(PreferencesKey.defaultNanoRep, nanoRep)); (String nanoRep) => _sharedPreferences.setString(PreferencesKey.defaultNanoRep, nanoRep));
@ -441,83 +438,79 @@ abstract class SettingsStoreBase with Store {
// secure storage keys: // secure storage keys:
reaction( reaction(
(_) => allowBiometricalAuthentication, (_) => allowBiometricalAuthentication,
(bool biometricalAuthentication) => writeSecureStorage(secureStorage, (bool biometricalAuthentication) => secureStorage.write(
key: SecureKey.allowBiometricalAuthenticationKey, key: SecureKey.allowBiometricalAuthenticationKey,
value: biometricalAuthentication.toString())); value: biometricalAuthentication.toString()));
reaction( reaction(
(_) => selectedCake2FAPreset, (_) => selectedCake2FAPreset,
(Cake2FAPresetsOptions selectedCake2FAPreset) => writeSecureStorage(secureStorage, (Cake2FAPresetsOptions selectedCake2FAPreset) => secureStorage.write(
key: SecureKey.selectedCake2FAPreset, key: SecureKey.selectedCake2FAPreset,
value: selectedCake2FAPreset.serialize().toString())); value: selectedCake2FAPreset.serialize().toString()));
reaction( reaction(
(_) => shouldRequireTOTP2FAForAccessingWallet, (_) => shouldRequireTOTP2FAForAccessingWallet,
(bool requireTOTP2FAForAccessingWallet) => writeSecureStorage(secureStorage, (bool requireTOTP2FAForAccessingWallet) => secureStorage.write(
key: SecureKey.shouldRequireTOTP2FAForAccessingWallet, key: SecureKey.shouldRequireTOTP2FAForAccessingWallet,
value: requireTOTP2FAForAccessingWallet.toString())); value: requireTOTP2FAForAccessingWallet.toString()));
reaction( reaction(
(_) => shouldRequireTOTP2FAForSendsToContact, (_) => shouldRequireTOTP2FAForSendsToContact,
(bool requireTOTP2FAForSendsToContact) => writeSecureStorage(secureStorage, (bool requireTOTP2FAForSendsToContact) => secureStorage.write(
key: SecureKey.shouldRequireTOTP2FAForSendsToContact, key: SecureKey.shouldRequireTOTP2FAForSendsToContact,
value: requireTOTP2FAForSendsToContact.toString())); value: requireTOTP2FAForSendsToContact.toString()));
reaction( reaction(
(_) => shouldRequireTOTP2FAForSendsToNonContact, (_) => shouldRequireTOTP2FAForSendsToNonContact,
(bool requireTOTP2FAForSendsToNonContact) => writeSecureStorage(secureStorage, (bool requireTOTP2FAForSendsToNonContact) => secureStorage.write(
key: SecureKey.shouldRequireTOTP2FAForSendsToNonContact, key: SecureKey.shouldRequireTOTP2FAForSendsToNonContact,
value: requireTOTP2FAForSendsToNonContact.toString())); value: requireTOTP2FAForSendsToNonContact.toString()));
reaction( reaction(
(_) => shouldRequireTOTP2FAForSendsToInternalWallets, (_) => shouldRequireTOTP2FAForSendsToInternalWallets,
(bool requireTOTP2FAForSendsToInternalWallets) => writeSecureStorage(secureStorage, (bool requireTOTP2FAForSendsToInternalWallets) => secureStorage.write(
key: SecureKey.shouldRequireTOTP2FAForSendsToInternalWallets, key: SecureKey.shouldRequireTOTP2FAForSendsToInternalWallets,
value: requireTOTP2FAForSendsToInternalWallets.toString())); value: requireTOTP2FAForSendsToInternalWallets.toString()));
reaction( reaction(
(_) => shouldRequireTOTP2FAForExchangesToInternalWallets, (_) => shouldRequireTOTP2FAForExchangesToInternalWallets,
(bool requireTOTP2FAForExchangesToInternalWallets) => writeSecureStorage(secureStorage, (bool requireTOTP2FAForExchangesToInternalWallets) => secureStorage.write(
key: SecureKey.shouldRequireTOTP2FAForExchangesToInternalWallets, key: SecureKey.shouldRequireTOTP2FAForExchangesToInternalWallets,
value: requireTOTP2FAForExchangesToInternalWallets.toString())); value: requireTOTP2FAForExchangesToInternalWallets.toString()));
reaction( reaction(
(_) => shouldRequireTOTP2FAForExchangesToExternalWallets, (_) => shouldRequireTOTP2FAForExchangesToExternalWallets,
(bool requireTOTP2FAForExchangesToExternalWallets) => writeSecureStorage(secureStorage, (bool requireTOTP2FAForExchangesToExternalWallets) => secureStorage.write(
key: SecureKey.shouldRequireTOTP2FAForExchangesToExternalWallets, key: SecureKey.shouldRequireTOTP2FAForExchangesToExternalWallets,
value: requireTOTP2FAForExchangesToExternalWallets.toString())); value: requireTOTP2FAForExchangesToExternalWallets.toString()));
reaction( reaction(
(_) => shouldRequireTOTP2FAForAddingContacts, (_) => shouldRequireTOTP2FAForAddingContacts,
(bool requireTOTP2FAForAddingContacts) => writeSecureStorage(secureStorage, (bool requireTOTP2FAForAddingContacts) => secureStorage.write(
key: SecureKey.shouldRequireTOTP2FAForAddingContacts, key: SecureKey.shouldRequireTOTP2FAForAddingContacts,
value: requireTOTP2FAForAddingContacts.toString())); value: requireTOTP2FAForAddingContacts.toString()));
reaction( reaction(
(_) => shouldRequireTOTP2FAForCreatingNewWallets, (_) => shouldRequireTOTP2FAForCreatingNewWallets,
(bool requireTOTP2FAForCreatingNewWallets) => writeSecureStorage(secureStorage, (bool requireTOTP2FAForCreatingNewWallets) => secureStorage.write(
key: SecureKey.shouldRequireTOTP2FAForCreatingNewWallets, key: SecureKey.shouldRequireTOTP2FAForCreatingNewWallets,
value: requireTOTP2FAForCreatingNewWallets.toString())); value: requireTOTP2FAForCreatingNewWallets.toString()));
reaction( reaction(
(_) => shouldRequireTOTP2FAForAllSecurityAndBackupSettings, (_) => shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
(bool requireTOTP2FAForAllSecurityAndBackupSettings) => writeSecureStorage(secureStorage, (bool requireTOTP2FAForAllSecurityAndBackupSettings) => secureStorage.write(
key: SecureKey.shouldRequireTOTP2FAForAllSecurityAndBackupSettings, key: SecureKey.shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
value: requireTOTP2FAForAllSecurityAndBackupSettings.toString())); value: requireTOTP2FAForAllSecurityAndBackupSettings.toString()));
reaction( reaction((_) => useTOTP2FA,
(_) => useTOTP2FA, (bool use) => secureStorage.write(key: SecureKey.useTOTP2FA, value: use.toString()));
(bool use) =>
writeSecureStorage(secureStorage, key: SecureKey.useTOTP2FA, value: use.toString()));
reaction( reaction((_) => totpSecretKey,
(_) => totpSecretKey, (String totpKey) => secureStorage.write(key: SecureKey.totpSecretKey, value: totpKey));
(String totpKey) =>
writeSecureStorage(secureStorage, key: SecureKey.totpSecretKey, value: totpKey));
reaction( reaction(
(_) => pinTimeOutDuration, (_) => pinTimeOutDuration,
(PinCodeRequiredDuration pinCodeInterval) => writeSecureStorage(secureStorage, (PinCodeRequiredDuration pinCodeInterval) => secureStorage.write(
key: SecureKey.pinTimeOutDuration, value: pinCodeInterval.value.toString())); key: SecureKey.pinTimeOutDuration, value: pinCodeInterval.value.toString()));
reaction( reaction(
@ -720,7 +713,7 @@ abstract class SettingsStoreBase with Store {
@observable @observable
int customBitcoinFeeRate; int customBitcoinFeeRate;
final FlutterSecureStorage _secureStorage; final SecureStorage _secureStorage;
final SharedPreferences _sharedPreferences; final SharedPreferences _sharedPreferences;
final BackgroundTasks _backgroundTasks; final BackgroundTasks _backgroundTasks;
@ -763,7 +756,7 @@ abstract class SettingsStoreBase with Store {
BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance, BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance,
ThemeBase? initialTheme}) async { ThemeBase? initialTheme}) async {
final sharedPreferences = await getIt.getAsync<SharedPreferences>(); final sharedPreferences = await getIt.getAsync<SharedPreferences>();
final secureStorage = await getIt.get<FlutterSecureStorage>(); final secureStorage = await getIt.get<SecureStorage>();
final backgroundTasks = getIt.get<BackgroundTasks>(); final backgroundTasks = getIt.get<BackgroundTasks>();
final currentFiatCurrency = FiatCurrency.deserialize( final currentFiatCurrency = FiatCurrency.deserialize(
raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!); raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/balance.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:cake_wallet/store/yat/yat_exception.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'dart:async'; import 'dart:async';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
part 'yat_store.g.dart'; part 'yat_store.g.dart';
@ -193,7 +193,7 @@ abstract class YatStoreBase with Store {
AppStore appStore; AppStore appStore;
FlutterSecureStorage secureStorage; SecureStorage secureStorage;
@observable @observable
String emoji; String emoji;

View file

@ -1,10 +1,9 @@
import 'dart:io'; import 'dart:io';
import 'package:cake_wallet/core/backup_service.dart'; import 'package:cake_wallet/core/backup_service.dart';
import 'package:cake_wallet/core/execution_state.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/entities/secret_store_key.dart';
import 'package:cake_wallet/store/secret_store.dart'; import 'package:cake_wallet/store/secret_store.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/wallet_type_utils.dart';
@ -34,7 +33,7 @@ abstract class BackupViewModelBase with Store {
}, fireImmediately: true); }, fireImmediately: true);
} }
final FlutterSecureStorage secureStorage; final SecureStorage secureStorage;
final SecretStore secretStore; final SecretStore secretStore;
final BackupService backupService; final BackupService backupService;

View file

@ -1,6 +1,5 @@
import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/core/secure_storage.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:cake_wallet/store/secret_store.dart'; import 'package:cake_wallet/store/secret_store.dart';
@ -14,7 +13,7 @@ abstract class EditBackupPasswordViewModelBase with Store {
: backupPassword = secretStore.read(generateStoreKeyFor(key: SecretStoreKey.backupPassword)), : backupPassword = secretStore.read(generateStoreKeyFor(key: SecretStoreKey.backupPassword)),
_originalPassword = ''; _originalPassword = '';
final FlutterSecureStorage secureStorage; final SecureStorage secureStorage;
final SecretStore secretStore; final SecretStore secretStore;
@observable @observable
@ -38,7 +37,7 @@ abstract class EditBackupPasswordViewModelBase with Store {
@action @action
Future<void> save() async { Future<void> save() async {
final key = generateStoreKeyFor(key: SecretStoreKey.backupPassword); 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); secretStore.write(key: key, value: backupPassword);
} }
} }

View file

@ -11,12 +11,6 @@ dependencies:
ref: cake-4.0.2 ref: cake-4.0.2
version: 4.0.2 version: 4.0.2
shared_preferences: ^2.0.15 shared_preferences: ^2.0.15
flutter_secure_storage:
git:
url: https://github.com/cake-tech/flutter_secure_storage.git
path: flutter_secure_storage
ref: cake-9.0.0
version: 9.0.0
# provider: ^6.0.3 # provider: ^6.0.3
rxdart: ^0.27.4 rxdart: ^0.27.4
yaml: ^3.1.1 yaml: ^3.1.1

View file

@ -10,6 +10,7 @@ const polygonOutputPath = 'lib/polygon/polygon.dart';
const solanaOutputPath = 'lib/solana/solana.dart'; const solanaOutputPath = 'lib/solana/solana.dart';
const tronOutputPath = 'lib/tron/tron.dart'; const tronOutputPath = 'lib/tron/tron.dart';
const walletTypesPath = 'lib/wallet_types.g.dart'; const walletTypesPath = 'lib/wallet_types.g.dart';
const secureStoragePath = 'lib/core/secure_storage.dart';
const pubspecDefaultPath = 'pubspec_default.yaml'; const pubspecDefaultPath = 'pubspec_default.yaml';
const pubspecOutputPath = 'pubspec.yaml'; const pubspecOutputPath = 'pubspec.yaml';
@ -25,6 +26,7 @@ Future<void> main(List<String> args) async {
final hasPolygon = args.contains('${prefix}polygon'); final hasPolygon = args.contains('${prefix}polygon');
final hasSolana = args.contains('${prefix}solana'); final hasSolana = args.contains('${prefix}solana');
final hasTron = args.contains('${prefix}tron'); final hasTron = args.contains('${prefix}tron');
final excludeFlutterSecureStorage = args.contains('${prefix}excludeFlutterSecureStorage');
await generateBitcoin(hasBitcoin); await generateBitcoin(hasBitcoin);
await generateMonero(hasMonero); await generateMonero(hasMonero);
@ -45,6 +47,7 @@ Future<void> main(List<String> args) async {
hasNano: hasNano, hasNano: hasNano,
hasBanano: hasBanano, hasBanano: hasBanano,
hasBitcoinCash: hasBitcoinCash, hasBitcoinCash: hasBitcoinCash,
hasFlutterSecureStorage: !excludeFlutterSecureStorage,
hasPolygon: hasPolygon, hasPolygon: hasPolygon,
hasSolana: hasSolana, hasSolana: hasSolana,
hasTron: hasTron, hasTron: hasTron,
@ -61,6 +64,7 @@ Future<void> main(List<String> args) async {
hasSolana: hasSolana, hasSolana: hasSolana,
hasTron: hasTron, hasTron: hasTron,
); );
await injectSecureStorage(!excludeFlutterSecureStorage);
} }
Future<void> generateBitcoin(bool hasImplementation) async { Future<void> generateBitcoin(bool hasImplementation) async {
@ -1142,6 +1146,7 @@ Future<void> generatePubspec(
required bool hasNano, required bool hasNano,
required bool hasBanano, required bool hasBanano,
required bool hasBitcoinCash, required bool hasBitcoinCash,
required bool hasFlutterSecureStorage,
required bool hasPolygon, required bool hasPolygon,
required bool hasSolana, required bool hasSolana,
required bool hasTron}) async { required bool hasTron}) async {
@ -1165,6 +1170,14 @@ Future<void> generatePubspec(
cw_shared_external: cw_shared_external:
path: ./cw_shared_external path: ./cw_shared_external
"""; """;
const flutterSecureStorage = """
flutter_secure_storage:
git:
url: https://github.com/cake-tech/flutter_secure_storage.git
path: flutter_secure_storage
ref: cake-9.0.0
version: 9.0.0
""";
const cwEthereum = """ const cwEthereum = """
cw_ethereum: cw_ethereum:
path: ./cw_ethereum path: ./cw_ethereum
@ -1246,6 +1259,10 @@ Future<void> generatePubspec(
output += '\n$cwHaven'; output += '\n$cwHaven';
} }
if (hasFlutterSecureStorage) {
output += '\n$flutterSecureStorage\n';
}
if (hasEthereum || hasPolygon) { if (hasEthereum || hasPolygon) {
output += '\n$cwEVM'; output += '\n$cwEVM';
} }
@ -1330,3 +1347,103 @@ Future<void> generateWalletTypes(
outputContent += '];\n'; outputContent += '];\n';
await walletTypesFile.writeAsString(outputContent); await walletTypesFile.writeAsString(outputContent);
} }
Future<void> injectSecureStorage(bool hasFlutterSecureStorage) async {
const flutterSecureStorageHeader = """
import 'dart:async';
import 'dart:io';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
""";
const abstractSecureStorage = """
abstract class SecureStorage {
Future<String?> read({required String key});
Future<void> write({required String key, required String? value});
Future<void> delete({required String key});
// Legacy
Future<String?> readNoIOptions({required String key});
}""";
const defaultSecureStorage = """
class DefaultSecureStorage extends SecureStorage {
DefaultSecureStorage._(this._secureStorage);
factory DefaultSecureStorage() => _instance;
static final _instance = DefaultSecureStorage._(FlutterSecureStorage(
iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
));
final FlutterSecureStorage _secureStorage;
@override
Future<String?> read({required String key}) async => await _readInternal(key, false);
@override
Future<void> 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<void> delete({required String key}) async => _secureStorage.delete(key: key);
@override
Future<String?> readNoIOptions({required String key}) async => await _readInternal(key, true);
Future<String?> _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<String?> read({required String key}) async => null;
@override
Future<void> write({required String key, required String? value}) async {}
@override
Future<void> delete({required String key}) async {}
@override
Future<String?> 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';
var output = '';
if (outputFile.existsSync()) {
await outputFile.delete();
}
output += '${header}\n${abstractSecureStorage}\n\n';
if (hasFlutterSecureStorage) {
output += '${defaultSecureStorage}\n';
} else {
output += '${fakeSecureStorage}\n';
}
await outputFile.writeAsString(output);
}