From 818a8afe208418136cfa49cdf801be928d0a1d74 Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Tue, 22 Nov 2022 22:52:28 +0200 Subject: [PATCH 01/12] [CW-225] Add pin timeout setting --- lib/core/auth_service.dart | 24 +++++++ lib/di.dart | 3 +- lib/entities/pin_code_required_duration.dart | 32 ++++++++++ lib/entities/preferences_key.dart | 3 + .../settings/security_backup_page.dart | 64 ++++++++++++------- .../screens/wallet_list/wallet_list_page.dart | 47 ++++++++++---- lib/store/settings_store.dart | 20 ++++-- lib/view_model/auth_view_model.dart | 12 +++- .../settings/settings_view_model.dart | 30 ++++++--- .../wallet_list/wallet_list_view_model.dart | 6 +- res/values/strings_de.arb | 5 +- res/values/strings_en.arb | 5 +- res/values/strings_es.arb | 5 +- res/values/strings_fr.arb | 5 +- res/values/strings_hi.arb | 5 +- res/values/strings_hr.arb | 5 +- res/values/strings_it.arb | 5 +- res/values/strings_ja.arb | 5 +- res/values/strings_ko.arb | 5 +- res/values/strings_nl.arb | 5 +- res/values/strings_pl.arb | 5 +- res/values/strings_pt.arb | 5 +- res/values/strings_ru.arb | 5 +- res/values/strings_uk.arb | 5 +- res/values/strings_zh.arb | 5 +- 25 files changed, 250 insertions(+), 66 deletions(-) create mode 100644 lib/entities/pin_code_required_duration.dart diff --git a/lib/core/auth_service.dart b/lib/core/auth_service.dart index 2ae37e2b0..6b167fa40 100644 --- a/lib/core/auth_service.dart +++ b/lib/core/auth_service.dart @@ -4,6 +4,8 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/entities/encrypt.dart'; +import 'package:cake_wallet/di.dart'; +import 'package:cake_wallet/store/settings_store.dart'; class AuthService with Store { AuthService({required this.secureStorage, required this.sharedPreferences}); @@ -39,4 +41,26 @@ class AuthService with Store { return decodedPin == pin; } + + void saveLastAuthTime(){ + int timestamp = DateTime.now().millisecondsSinceEpoch; + sharedPreferences.setInt(PreferencesKey.lastAuthTimeMilliseconds, timestamp); + } + + bool requireAuth(){ + final timestamp = sharedPreferences.getInt(PreferencesKey.lastAuthTimeMilliseconds); + final duration = _durationToRequireAuth(timestamp ?? 0); + final requiredPinInterval = getIt.get().pinTimeOutDuration; + + return duration >= requiredPinInterval.value; + } + + int _durationToRequireAuth(int timestamp){ + + DateTime before = DateTime.fromMillisecondsSinceEpoch(timestamp); + DateTime now = DateTime.now(); + Duration timeDifference = now.difference(before); + + return timeDifference.inMinutes; + } } diff --git a/lib/di.dart b/lib/di.dart index 815a3740e..fe8032513 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -440,7 +440,8 @@ Future setup( getIt.registerFactory(() { final appStore = getIt.get(); final yatStore = getIt.get(); - return SettingsViewModel(appStore.settingsStore, yatStore, appStore.wallet!); + final authService = getIt.get(); + return SettingsViewModel(appStore.settingsStore, yatStore, authService, appStore.wallet!); }); getIt diff --git a/lib/entities/pin_code_required_duration.dart b/lib/entities/pin_code_required_duration.dart new file mode 100644 index 000000000..fef5715b5 --- /dev/null +++ b/lib/entities/pin_code_required_duration.dart @@ -0,0 +1,32 @@ +import 'package:cake_wallet/generated/i18n.dart'; + +enum PinCodeRequiredDuration { + always(0), + tenminutes(10), + onehour(60); + + const PinCodeRequiredDuration(this.value); + final int value; + + static PinCodeRequiredDuration deserialize({required int raw}) => + PinCodeRequiredDuration.values.firstWhere((e) => e.value == raw); + + @override + String toString(){ + String label = ''; + switch (this) { + case PinCodeRequiredDuration.always: + label = S.current.always; + break; + case PinCodeRequiredDuration.tenminutes: + label = S.current.minutes_to_pin_code('10'); + break; + case PinCodeRequiredDuration.onehour: + label = S.current.minutes_to_pin_code('60'); + break; + } + return label; + + } + +} \ No newline at end of file diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index 6cf7e5608..36394d936 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -23,6 +23,9 @@ class PreferencesKey { static const shouldShowReceiveWarning = 'should_show_receive_warning'; static const shouldShowYatPopup = 'should_show_yat_popup'; static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1'; + static const pinTimeOutDuration = 'pin_timeout_duration'; + static const lastAuthTimeMilliseconds = 'last_auth_time_milliseconds'; + static String moneroWalletUpdateV1Key(String name) => '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}'; diff --git a/lib/src/screens/settings/security_backup_page.dart b/lib/src/screens/settings/security_backup_page.dart index d950597f0..a3babb0bb 100644 --- a/lib/src/screens/settings/security_backup_page.dart +++ b/lib/src/screens/settings/security_backup_page.dart @@ -1,9 +1,11 @@ +import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart'; +import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/view_model/settings/settings_view_model.dart'; @@ -20,27 +22,28 @@ class SecurityBackupPage extends BasePage { @override Widget body(BuildContext context) { + return Container( padding: EdgeInsets.only(top: 10), child: Column(mainAxisSize: MainAxisSize.min, children: [ SettingsCellWithArrow( title: S.current.show_keys, - handler: (_) => Navigator.of(context).pushNamed(Routes.auth, + handler: (_) => settingsViewModel.checkPinCodeRiquired() ? Navigator.of(context).pushNamed(Routes.auth, arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) { if (isAuthenticatedSuccessfully) { auth.close(route: Routes.showKeys); } - }), + }) : Navigator.of(context).pushNamed(Routes.showKeys), ), StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)), SettingsCellWithArrow( title: S.current.create_backup, - handler: (_) => Navigator.of(context).pushNamed(Routes.auth, + handler: (_) => settingsViewModel.checkPinCodeRiquired() ? Navigator.of(context).pushNamed(Routes.auth, arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) { if (isAuthenticatedSuccessfully) { auth.close(route: Routes.backup); } - }), + }) : Navigator.of(context).pushNamed(Routes.backup), ), StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)), SettingsCellWithArrow( @@ -56,28 +59,41 @@ class SecurityBackupPage extends BasePage { })), StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)), Observer(builder: (_) { - return SettingsSwitcherCell( - title: S.current.settings_allow_biometrical_authentication, - value: settingsViewModel.allowBiometricalAuthentication, - onValueChange: (BuildContext context, bool value) { - if (value) { - Navigator.of(context).pushNamed(Routes.auth, - arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async { - if (isAuthenticatedSuccessfully) { - if (await settingsViewModel.biometricAuthenticated()) { - settingsViewModel.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully); - } - } else { - settingsViewModel.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully); - } + return Column( + children: [ + SettingsSwitcherCell( + title: S.current.settings_allow_biometrical_authentication, + value: settingsViewModel.allowBiometricalAuthentication, + onValueChange: (BuildContext context, bool value) { + if (value) { + Navigator.of(context).pushNamed(Routes.auth, + arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async { + if (isAuthenticatedSuccessfully) { + if (await settingsViewModel.biometricAuthenticated()) { + settingsViewModel.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully); + } + } else { + settingsViewModel.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully); + } - auth.close(); - }); - } else { - settingsViewModel.setAllowBiometricalAuthentication(value); - } - }); + auth.close(); + }); + } else { + settingsViewModel.setAllowBiometricalAuthentication(value); + } + }), + SettingsPickerCell( + title: S.current.require_pin_after, + items: PinCodeRequiredDuration.values, + selectedItem: settingsViewModel.pinCodeRequiredDuration, + onItemSelected: (PinCodeRequiredDuration code) { + settingsViewModel.setPinCodeRequiredDuration(code); + }, + ), + ], + ); }), + ]), ); } diff --git a/lib/src/screens/wallet_list/wallet_list_page.dart b/lib/src/screens/wallet_list/wallet_list_page.dart index c1a7ea953..5d9650ef2 100644 --- a/lib/src/screens/wallet_list/wallet_list_page.dart +++ b/lib/src/screens/wallet_list/wallet_list_page.dart @@ -220,7 +220,8 @@ class WalletListBodyState extends State { } Future _loadWallet(WalletListItem wallet) async { - await Navigator.of(context).pushNamed(Routes.auth, arguments: + if(await widget.walletListViewModel.checkIfAuthRequired()){ + await Navigator.of(context).pushNamed(Routes.auth, arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async { if (!isAuthenticatedSuccessfully) { return; @@ -241,17 +242,36 @@ class WalletListBodyState extends State { .wallet_list_failed_to_load(wallet.name, e.toString())); } }); + }else{ + try { + changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name)); + await widget.walletListViewModel.loadWallet(wallet); + hideProgressText(); + Navigator.of(context).pop(); + } catch (e) { + changeProcessText(S + .of(context) + .wallet_list_failed_to_load(wallet.name, e.toString())); + } + } } Future _removeWallet(WalletListItem wallet) async { - await Navigator.of(context).pushNamed(Routes.auth, arguments: + if(widget.walletListViewModel.checkIfAuthRequired()){ + await Navigator.of(context).pushNamed(Routes.auth, arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async { if (!isAuthenticatedSuccessfully) { return; } + _onSuccessfulAuth(wallet, auth); + }); + }else{ + _onSuccessfulAuth(wallet, null); + } + } - bool confirmed = false; - + _onSuccessfulAuth(WalletListItem wallet, AuthPageState? auth)async{ + bool confirmed = false; await showPopUp( context: context, builder: (BuildContext context) { @@ -270,18 +290,23 @@ class WalletListBodyState extends State { if (confirmed) { try { - auth.changeProcessText( - S.of(context).wallet_list_removing_wallet(wallet.name)); + auth != null ? + auth.changeProcessText( + S.of(context).wallet_list_removing_wallet(wallet.name)) + : changeProcessText( S.of(context).wallet_list_removing_wallet(wallet.name)); await widget.walletListViewModel.remove(wallet); } catch (e) { - auth.changeProcessText(S - .of(context) - .wallet_list_failed_to_remove(wallet.name, e.toString())); + auth != null ? + auth.changeProcessText( + S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()), + ) + : changeProcessText( + S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()), + ); } } - auth.close(); - }); + auth?.close(); } void changeProcessText(String text) { diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index 2b3105a34..c6534bcea 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -1,9 +1,9 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_list.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; @@ -17,7 +17,6 @@ import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cw_core/node.dart'; import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/entities/action_list_display_mode.dart'; -import 'package:cake_wallet/.secrets.g.dart' as secrets; part 'settings_store.g.dart'; @@ -39,6 +38,7 @@ abstract class SettingsStoreBase with Store { required this.shouldShowYatPopup, required this.isBitcoinBuyEnabled, required this.actionlistDisplayMode, + required this.pinTimeOutDuration, TransactionPriority? initialBitcoinTransactionPriority, TransactionPriority? initialMoneroTransactionPriority}) : nodes = ObservableMap.of(nodes), @@ -108,6 +108,11 @@ abstract class SettingsStoreBase with Store { (String languageCode) => sharedPreferences.setString( PreferencesKey.currentLanguageCode, languageCode)); + reaction( + (_) => pinTimeOutDuration, + (PinCodeRequiredDuration pinCodeInterval) => sharedPreferences.setInt( + PreferencesKey.pinTimeOutDuration, pinCodeInterval.value)); + reaction( (_) => balanceDisplayMode, (BalanceDisplayMode mode) => sharedPreferences.setInt( @@ -124,6 +129,7 @@ abstract class SettingsStoreBase with Store { static const defaultPinLength = 4; static const defaultActionsMode = 11; + static const defaultPinCodeTimeOutDuration = 10; @observable FiatCurrency fiatCurrency; @@ -149,6 +155,9 @@ abstract class SettingsStoreBase with Store { @observable int pinCodeLength; + @observable + PinCodeRequiredDuration pinTimeOutDuration; + @computed ThemeData get theme => currentTheme.themeData; @@ -227,13 +236,15 @@ abstract class SettingsStoreBase with Store { : ThemeType.bright.index; final savedTheme = ThemeList.deserialize( raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? - legacyTheme ?? - 0); + legacyTheme); final actionListDisplayMode = ObservableList(); actionListDisplayMode.addAll(deserializeActionlistDisplayModes( sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode)); var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength); + final pinCodeTimeOutDuration = PinCodeRequiredDuration.deserialize(raw: sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration) + ?? defaultPinCodeTimeOutDuration); + // If no value if (pinLength == null || pinLength == 0) { pinLength = defaultPinLength; @@ -287,6 +298,7 @@ abstract class SettingsStoreBase with Store { initialTheme: savedTheme, actionlistDisplayMode: actionListDisplayMode, initialPinLength: pinLength, + pinTimeOutDuration: pinCodeTimeOutDuration, initialLanguageCode: savedLanguageCode, initialMoneroTransactionPriority: moneroTransactionPriority, initialBitcoinTransactionPriority: bitcoinTransactionPriority, diff --git a/lib/view_model/auth_view_model.dart b/lib/view_model/auth_view_model.dart index 29ef46b47..42201ddab 100644 --- a/lib/view_model/auth_view_model.dart +++ b/lib/view_model/auth_view_model.dart @@ -17,7 +17,9 @@ abstract class AuthViewModelBase with Store { AuthViewModelBase(this._authService, this._sharedPreferences, this._settingsStore, this._biometricAuth) : _failureCounter = 0, - state = InitialExecutionState(); + state = InitialExecutionState(){ + reaction((_) => state, _saveLastAuthTime); + } static const maxFailedLogins = 3; static const banTimeout = 180; // 3 minutes @@ -57,7 +59,7 @@ abstract class AuthViewModelBase with Store { if (isSuccessfulAuthenticated) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - state = ExecutedSuccessfullyState(); + state = ExecutedSuccessfullyState(); _failureCounter = 0; }); } else { @@ -118,4 +120,10 @@ abstract class AuthViewModelBase with Store { state = FailureState(e.toString()); } } + + void _saveLastAuthTime(ExecutionState state){ + if(state is ExecutedSuccessfullyState){ + _authService.saveLastAuthTime(); + } + } } diff --git a/lib/view_model/settings/settings_view_model.dart b/lib/view_model/settings/settings_view_model.dart index 9caacb211..96f11e82e 100644 --- a/lib/view_model/settings/settings_view_model.dart +++ b/lib/view_model/settings/settings_view_model.dart @@ -1,3 +1,5 @@ +import 'package:cake_wallet/core/auth_service.dart'; +import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/store/yat/yat_store.dart'; import 'package:mobx/mobx.dart'; import 'package:package_info/package_info.dart'; @@ -41,6 +43,7 @@ abstract class SettingsViewModelBase with Store { SettingsViewModelBase( this._settingsStore, this._yatStore, + this._authService, WalletBase, TransactionInfo> wallet) @@ -94,6 +97,10 @@ abstract class SettingsViewModelBase with Store { @computed FiatCurrency get fiatCurrency => _settingsStore.fiatCurrency; + @computed + PinCodeRequiredDuration get pinCodeRequiredDuration => + _settingsStore.pinTimeOutDuration; + @computed String get languageCode => _settingsStore.languageCode; @@ -135,6 +142,7 @@ abstract class SettingsViewModelBase with Store { final Map itemHeaders; final SettingsStore _settingsStore; final YatStore _yatStore; + final AuthService _authService; final WalletType walletType; final BiometricAuth _biometricAuth; final WalletBase, @@ -207,19 +215,25 @@ abstract class SettingsViewModelBase with Store { } } + @action + setPinCodeRequiredDuration(PinCodeRequiredDuration duration) => + _settingsStore.pinTimeOutDuration = duration; + String getDisplayPriority(dynamic priority) { - final _priority = priority as TransactionPriority; + final _priority = priority as TransactionPriority; - if (_wallet.type == WalletType.bitcoin - || _wallet.type == WalletType.litecoin) { - final rate = bitcoin!.getFeeRate(_wallet, _priority); - return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate); - } + if (_wallet.type == WalletType.bitcoin + || _wallet.type == WalletType.litecoin) { + final rate = bitcoin!.getFeeRate(_wallet, _priority); + return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate); + } - return priority.toString(); + return priority.toString(); } void onDisplayPrioritySelected(TransactionPriority priority) => - _settingsStore.priority[_wallet.type] = priority; + _settingsStore.priority[_wallet.type] = priority; + + bool checkPinCodeRiquired() => _authService.requireAuth(); } diff --git a/lib/view_model/wallet_list/wallet_list_view_model.dart b/lib/view_model/wallet_list/wallet_list_view_model.dart index 0bbc68748..50908f24e 100644 --- a/lib/view_model/wallet_list/wallet_list_view_model.dart +++ b/lib/view_model/wallet_list/wallet_list_view_model.dart @@ -1,5 +1,5 @@ +import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/core/wallet_loading_service.dart'; -import 'package:cake_wallet/view_model/wallet_new_vm.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/di.dart'; @@ -55,4 +55,8 @@ abstract class WalletListViewModelBase with Store { info.type == _appStore.wallet!.type, isEnabled: availableWalletTypes.contains(info.type)))); } + + bool checkIfAuthRequired(){ + return getIt.get().requireAuth(); + } } diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index cea889b15..eacc8e618 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -655,5 +655,8 @@ "privacy_settings": "Datenschutzeinstellungen", "privacy": "Datenschutz", "display_settings": "Anzeigeeinstellungen", - "other_settings": "Andere Einstellungen" + "other_settings": "Andere Einstellungen", + "require_pin_after": "PIN anfordern nach", + "always": "immer", + "minutes_to_pin_code": "${minute} Minuten" } diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index e764a0b90..65b72f5c6 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -658,5 +658,8 @@ "privacy_settings": "Privacy settings", "privacy": "Privacy", "display_settings": "Display settings", - "other_settings": "Other settings" + "other_settings": "Other settings", + "require_pin_after": "Require PIN after", + "always": "Always", + "minutes_to_pin_code": "${minute} minutes" } diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index bd43abe58..903e6c380 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -655,5 +655,8 @@ "privacy_settings": "Configuración de privacidad", "privacy": "Privacidad", "display_settings": "Configuración de pantalla", - "other_settings": "Otras configuraciones" + "other_settings": "Otras configuraciones", + "require_pin_after": "Requerir PIN después de", + "always": "siempre", + "minutes_to_pin_code": "${minute} minutos" } diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index df43f41a6..d82f1d2de 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -653,5 +653,8 @@ "privacy_settings": "Paramètres de confidentialité", "privacy": "Confidentialité", "display_settings": "Paramètres d'affichage", - "other_settings": "Autres paramètres" + "other_settings": "Autres paramètres", + "require_pin_after": "NIP requis après", + "always": "toujours", + "minutes_to_pin_code": "${minute} minutes" } diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 06d95d3b2..9175cb17c 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -655,5 +655,8 @@ "privacy_settings": "गोपनीयता सेटिंग्स", "privacy": "गोपनीयता", "display_settings": "प्रदर्शन सेटिंग्स", - "other_settings": "अन्य सेटिंग्स" + "other_settings": "अन्य सेटिंग्स", + "require_pin_after": "इसके बाद पिन आवश्यक है", + "always": "हमेशा", + "minutes_to_pin_code": "${minute} मिनट" } diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 7c25928e5..e60bedd74 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -655,5 +655,8 @@ "privacy_settings": "Postavke privatnosti", "privacy": "Privatnost", "display_settings": "Postavke zaslona", - "other_settings": "Ostale postavke" + "other_settings": "Ostale postavke", + "require_pin_after": "Zahtijevaj PIN nakon", + "always": "Uvijek", + "minutes_to_pin_code": "${minute} minuta" } diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 45d9d8164..548c51b22 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -655,5 +655,8 @@ "privacy_settings": "Impostazioni privacy", "privacy": "Privacy", "display_settings": "Impostazioni di visualizzazione", - "other_settings": "Altre impostazioni" + "other_settings": "Altre impostazioni", + "require_pin_after": "Richiedi PIN dopo", + "always": "sempre", + "minutes_to_pin_code": "${minute} minuti" } diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index ffb2cbb71..7fc1f5105 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -655,5 +655,8 @@ "privacy_settings": "プライバシー設定", "privacy": "プライバシー", "display_settings": "表示設定", - "other_settings": "その他の設定" + "other_settings": "その他の設定", + "require_pin_after": "後に PIN が必要", + "always": "いつも", + "minutes_to_pin_code": "${minute} 分" } diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 598fe2f56..471d9ed11 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -655,5 +655,8 @@ "privacy_settings": "개인정보 설정", "privacy": "프라이버시", "display_settings": "디스플레이 설정", - "other_settings": "기타 설정" + "other_settings": "기타 설정", + "require_pin_after": "다음 이후에 PIN 필요", + "always": "언제나", + "minutes_to_pin_code": "${minute}분" } diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 12e2f5569..1eb16e051 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -655,5 +655,8 @@ "privacy_settings": "Privacy-instellingen", "privacy": "Privacy", "display_settings": "Weergave-instellingen", - "other_settings": "Andere instellingen" + "other_settings": "Andere instellingen", + "require_pin_after": "Pincode vereist na", + "always": "altijd", + "minutes_to_pin_code": "${minute} minuten" } diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index fd092d332..78793c074 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -655,5 +655,8 @@ "privacy_settings": "Ustawienia prywatności", "privacy": "Prywatność", "display_settings": "Ustawienia wyświetlania", - "other_settings": "Inne ustawienia" + "other_settings": "Inne ustawienia", + "require_pin_after": "Wymagaj kodu PIN po", + "always": "zawsze", + "minutes_to_pin_code": "${minute} minut" } diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index e4d7ef647..e7fc9aa92 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -655,5 +655,8 @@ "privacy_settings": "Configurações de privacidade", "privacy": "Privacidade", "display_settings": "Configurações de exibição", - "other_settings": "Outras configurações" + "other_settings": "Outras configurações", + "require_pin_after": "Exigir PIN após", + "always": "sempre", + "minutes_to_pin_code": "${minute} minutos" } diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 786f11e36..34fe7a145 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -655,5 +655,8 @@ "privacy_settings": "Настройки конфиденциальности", "privacy": "Конфиденциальность", "display_settings": "Настройки отображения", - "other_settings": "Другие настройки" + "other_settings": "Другие настройки", + "require_pin_after": "Требовать ПИН после", + "always": "всегда", + "minutes_to_pin_code": "${minute} минут" } diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 48951e806..fab6ed71e 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -654,6 +654,9 @@ "privacy_settings": "Налаштування конфіденційності", "privacy": "Конфіденційність", "display_settings": "Налаштування дисплея", - "other_settings": "Інші налаштування" + "other_settings": "Інші налаштування", + "require_pin_after": "Вимагати PIN після", + "always": "Завжди", + "minutes_to_pin_code": "${minute} хвилин" } diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 29d7351d5..8f89f7b63 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -653,5 +653,8 @@ "privacy_settings": "隐私设置", "privacy":"隐私", "display_settings": "显示设置", - "other_settings": "其他设置" + "other_settings": "其他设置", + "require_pin_after": "之后需要 PIN", + "always": "总是", + "minutes_to_pin_code": "${minute} 分钟" } From 0c28d83cbcb17a20053e6787732c0c291a292c23 Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Wed, 30 Nov 2022 22:50:42 +0200 Subject: [PATCH 02/12] Fix authentication required when minimize app --- android/.project | 11 ++++++ .../org.eclipse.buildship.core.prefs | 13 ++++++- cw_monero/android/.project | 11 ++++++ ios/Podfile | 2 +- ios/Podfile.lock | 34 +++++++++---------- lib/src/screens/root/root.dart | 11 +++++- 6 files changed, 62 insertions(+), 20 deletions(-) diff --git a/android/.project b/android/.project index 17c95d4b1..93e645b27 100644 --- a/android/.project +++ b/android/.project @@ -14,4 +14,15 @@ org.eclipse.buildship.core.gradleprojectnature + + + 1668366526072 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs index 9d2efc8e7..52768efe3 100644 --- a/android/.settings/org.eclipse.buildship.core.prefs +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -1,2 +1,13 @@ +arguments=--init-script /var/folders/_g/6xnbffg10l741qh63jr5cds80000gp/T/d146c9752a26f79b52047fb6dc6ed385d064e120494f96f08ca63a317c41f94c.gradle --init-script /var/folders/_g/6xnbffg10l741qh63jr5cds80000gp/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) connection.project.dir= -eclipse.preferences.version=1 \ No newline at end of file +eclipse.preferences.version=1 +gradle.user.home= +java.home=/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/cw_monero/android/.project b/cw_monero/android/.project index e0799208f..15eb18708 100644 --- a/cw_monero/android/.project +++ b/cw_monero/android/.project @@ -20,4 +20,15 @@ org.eclipse.jdt.core.javanature org.eclipse.buildship.core.gradleprojectnature + + + 1668366526081 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/ios/Podfile b/ios/Podfile index b29d40484..d02ce2d3f 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '11.0' +platform :ios, '14.0' source 'https://github.com/CocoaPods/Specs.git' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3a810430d..28ee07db9 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -7,7 +7,7 @@ PODS: - connectivity (0.0.1): - Flutter - Reachability - - CryptoSwift (1.3.2) + - CryptoSwift (1.6.0) - cw_haven (0.0.1): - cw_haven/Boost (= 0.0.1) - cw_haven/Haven (= 0.0.1) @@ -67,14 +67,14 @@ PODS: - Flutter - devicelocale (0.0.1): - Flutter - - DKImagePickerController/Core (4.3.2): + - DKImagePickerController/Core (4.3.4): - DKImagePickerController/ImageDataManager - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.2) - - DKImagePickerController/PhotoGallery (4.3.2): + - DKImagePickerController/ImageDataManager (4.3.4) + - DKImagePickerController/PhotoGallery (4.3.4): - DKImagePickerController/Core - DKPhotoGallery - - DKImagePickerController/Resource (4.3.2) + - DKImagePickerController/Resource (4.3.4) - DKPhotoGallery (0.0.17): - DKPhotoGallery/Core (= 0.0.17) - DKPhotoGallery/Model (= 0.0.17) @@ -116,15 +116,15 @@ PODS: - platform_device_id (0.0.1): - Flutter - Reachability (3.2) - - SDWebImage (5.9.1): - - SDWebImage/Core (= 5.9.1) - - SDWebImage/Core (5.9.1) + - SDWebImage (5.13.5): + - SDWebImage/Core (= 5.13.5) + - SDWebImage/Core (5.13.5) - share_plus (0.0.1): - Flutter - shared_preferences_ios (0.0.1): - Flutter - - SwiftProtobuf (1.18.0) - - SwiftyGif (5.3.0) + - SwiftProtobuf (1.20.2) + - SwiftyGif (5.4.3) - uni_links (0.0.1): - Flutter - UnstoppableDomainsResolution (4.0.0): @@ -221,14 +221,14 @@ SPEC CHECKSUMS: barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0 BigInt: f668a80089607f521586bbe29513d708491ef2f7 connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 - CryptoSwift: 093499be1a94b0cae36e6c26b70870668cb56060 + CryptoSwift: 562f8eceb40e80796fffc668b0cad9313284cfa6 cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a cw_monero: 4cf3b96f2da8e95e2ef7d6703dd4d2c509127b7d cw_shared_external: 2972d872b8917603478117c9957dfca611845a92 device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7 device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 devicelocale: b22617f40038496deffba44747101255cee005b0 - DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d + DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 @@ -240,16 +240,16 @@ SPEC CHECKSUMS: permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5 Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 - SDWebImage: a990c053fff71e388a10f3357edb0be17929c9c5 + SDWebImage: 23d714cd599354ee7906dbae26dff89b421c4370 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad - SwiftProtobuf: c3c12645230d9b09c72267e0de89468c5543bd86 - SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 + SwiftProtobuf: 9f458aaa7844a2fc0b910053e66578bc4e2da9c1 + SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 uni_links: d97da20c7701486ba192624d99bffaaffcfc298a UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f -PODFILE CHECKSUM: ae71bdf0eb731a1ffc399c122f6aa4dea0cb5f6f +PODFILE CHECKSUM: f2068ffd90d0bcc7e39f94a818dbbbbdbe8cda3e -COCOAPODS: 1.11.3 +COCOAPODS: 1.11.2 diff --git a/lib/src/screens/root/root.dart b/lib/src/screens/root/root.dart index c507f6e1f..8d2b61a65 100644 --- a/lib/src/screens/root/root.dart +++ b/lib/src/screens/root/root.dart @@ -1,4 +1,6 @@ import 'dart:async'; +import 'package:cake_wallet/core/auth_service.dart'; +import 'package:cake_wallet/di.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart'; @@ -28,15 +30,18 @@ class RootState extends State with WidgetsBindingObserver { RootState() : _isInactiveController = StreamController.broadcast(), _isInactive = false, + _requestAuth = getIt.get().requireAuth(), _postFrameCallback = false; Stream get isInactive => _isInactiveController.stream; StreamController _isInactiveController; bool _isInactive; bool _postFrameCallback; + bool _requestAuth; @override void initState() { + _isInactiveController = StreamController.broadcast(); _isInactive = false; _postFrameCallback = false; @@ -52,6 +57,10 @@ class RootState extends State with WidgetsBindingObserver { return; } + setState(() { + _requestAuth = getIt.get().requireAuth(); + }); + if (!_isInactive && widget.authenticationStore.state == AuthenticationState.allowed) { setState(() => _setInactive(true)); @@ -65,7 +74,7 @@ class RootState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { - if (_isInactive && !_postFrameCallback) { + if (_isInactive && !_postFrameCallback && _requestAuth) { _postFrameCallback = true; WidgetsBinding.instance.addPostFrameCallback((_) { widget.navigatorKey.currentState?.pushNamed(Routes.unlock, From 34cfe7591f7917150c0191af92cf9412f75fe561 Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Wed, 30 Nov 2022 22:57:48 +0200 Subject: [PATCH 03/12] Fix authentication required when minimize app --- lib/src/screens/root/root.dart | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/src/screens/root/root.dart b/lib/src/screens/root/root.dart index c507f6e1f..8d2b61a65 100644 --- a/lib/src/screens/root/root.dart +++ b/lib/src/screens/root/root.dart @@ -1,4 +1,6 @@ import 'dart:async'; +import 'package:cake_wallet/core/auth_service.dart'; +import 'package:cake_wallet/di.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart'; @@ -28,15 +30,18 @@ class RootState extends State with WidgetsBindingObserver { RootState() : _isInactiveController = StreamController.broadcast(), _isInactive = false, + _requestAuth = getIt.get().requireAuth(), _postFrameCallback = false; Stream get isInactive => _isInactiveController.stream; StreamController _isInactiveController; bool _isInactive; bool _postFrameCallback; + bool _requestAuth; @override void initState() { + _isInactiveController = StreamController.broadcast(); _isInactive = false; _postFrameCallback = false; @@ -52,6 +57,10 @@ class RootState extends State with WidgetsBindingObserver { return; } + setState(() { + _requestAuth = getIt.get().requireAuth(); + }); + if (!_isInactive && widget.authenticationStore.state == AuthenticationState.allowed) { setState(() => _setInactive(true)); @@ -65,7 +74,7 @@ class RootState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { - if (_isInactive && !_postFrameCallback) { + if (_isInactive && !_postFrameCallback && _requestAuth) { _postFrameCallback = true; WidgetsBinding.instance.addPostFrameCallback((_) { widget.navigatorKey.currentState?.pushNamed(Routes.unlock, From 23d2e54c464569742c70b9498137ba265621f344 Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Wed, 30 Nov 2022 23:08:31 +0200 Subject: [PATCH 04/12] Revert commit --- android/.project | 11 ------ .../org.eclipse.buildship.core.prefs | 13 +------ cw_monero/android/.project | 11 ------ ios/Podfile | 2 +- ios/Podfile.lock | 34 +++++++++---------- 5 files changed, 19 insertions(+), 52 deletions(-) diff --git a/android/.project b/android/.project index 93e645b27..17c95d4b1 100644 --- a/android/.project +++ b/android/.project @@ -14,15 +14,4 @@ org.eclipse.buildship.core.gradleprojectnature - - - 1668366526072 - - 30 - - org.eclipse.core.resources.regexFilterMatcher - node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ - - - diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs index 52768efe3..9d2efc8e7 100644 --- a/android/.settings/org.eclipse.buildship.core.prefs +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -1,13 +1,2 @@ -arguments=--init-script /var/folders/_g/6xnbffg10l741qh63jr5cds80000gp/T/d146c9752a26f79b52047fb6dc6ed385d064e120494f96f08ca63a317c41f94c.gradle --init-script /var/folders/_g/6xnbffg10l741qh63jr5cds80000gp/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle -auto.sync=false -build.scans.enabled=false -connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) connection.project.dir= -eclipse.preferences.version=1 -gradle.user.home= -java.home=/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home -jvm.arguments= -offline.mode=false -override.workspace.settings=true -show.console.view=true -show.executions.view=true +eclipse.preferences.version=1 \ No newline at end of file diff --git a/cw_monero/android/.project b/cw_monero/android/.project index 15eb18708..e0799208f 100644 --- a/cw_monero/android/.project +++ b/cw_monero/android/.project @@ -20,15 +20,4 @@ org.eclipse.jdt.core.javanature org.eclipse.buildship.core.gradleprojectnature - - - 1668366526081 - - 30 - - org.eclipse.core.resources.regexFilterMatcher - node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ - - - diff --git a/ios/Podfile b/ios/Podfile index d02ce2d3f..b29d40484 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '14.0' +platform :ios, '11.0' source 'https://github.com/CocoaPods/Specs.git' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 28ee07db9..3a810430d 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -7,7 +7,7 @@ PODS: - connectivity (0.0.1): - Flutter - Reachability - - CryptoSwift (1.6.0) + - CryptoSwift (1.3.2) - cw_haven (0.0.1): - cw_haven/Boost (= 0.0.1) - cw_haven/Haven (= 0.0.1) @@ -67,14 +67,14 @@ PODS: - Flutter - devicelocale (0.0.1): - Flutter - - DKImagePickerController/Core (4.3.4): + - DKImagePickerController/Core (4.3.2): - DKImagePickerController/ImageDataManager - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.4) - - DKImagePickerController/PhotoGallery (4.3.4): + - DKImagePickerController/ImageDataManager (4.3.2) + - DKImagePickerController/PhotoGallery (4.3.2): - DKImagePickerController/Core - DKPhotoGallery - - DKImagePickerController/Resource (4.3.4) + - DKImagePickerController/Resource (4.3.2) - DKPhotoGallery (0.0.17): - DKPhotoGallery/Core (= 0.0.17) - DKPhotoGallery/Model (= 0.0.17) @@ -116,15 +116,15 @@ PODS: - platform_device_id (0.0.1): - Flutter - Reachability (3.2) - - SDWebImage (5.13.5): - - SDWebImage/Core (= 5.13.5) - - SDWebImage/Core (5.13.5) + - SDWebImage (5.9.1): + - SDWebImage/Core (= 5.9.1) + - SDWebImage/Core (5.9.1) - share_plus (0.0.1): - Flutter - shared_preferences_ios (0.0.1): - Flutter - - SwiftProtobuf (1.20.2) - - SwiftyGif (5.4.3) + - SwiftProtobuf (1.18.0) + - SwiftyGif (5.3.0) - uni_links (0.0.1): - Flutter - UnstoppableDomainsResolution (4.0.0): @@ -221,14 +221,14 @@ SPEC CHECKSUMS: barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0 BigInt: f668a80089607f521586bbe29513d708491ef2f7 connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 - CryptoSwift: 562f8eceb40e80796fffc668b0cad9313284cfa6 + CryptoSwift: 093499be1a94b0cae36e6c26b70870668cb56060 cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a cw_monero: 4cf3b96f2da8e95e2ef7d6703dd4d2c509127b7d cw_shared_external: 2972d872b8917603478117c9957dfca611845a92 device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7 device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 devicelocale: b22617f40038496deffba44747101255cee005b0 - DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac + DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 @@ -240,16 +240,16 @@ SPEC CHECKSUMS: permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5 Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 - SDWebImage: 23d714cd599354ee7906dbae26dff89b421c4370 + SDWebImage: a990c053fff71e388a10f3357edb0be17929c9c5 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad - SwiftProtobuf: 9f458aaa7844a2fc0b910053e66578bc4e2da9c1 - SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 + SwiftProtobuf: c3c12645230d9b09c72267e0de89468c5543bd86 + SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 uni_links: d97da20c7701486ba192624d99bffaaffcfc298a UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f -PODFILE CHECKSUM: f2068ffd90d0bcc7e39f94a818dbbbbdbe8cda3e +PODFILE CHECKSUM: ae71bdf0eb731a1ffc399c122f6aa4dea0cb5f6f -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 From dd9e48558e63d0af448654439609600ff03ebc5d Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Wed, 30 Nov 2022 23:21:56 +0200 Subject: [PATCH 05/12] Attempt to fix test by upgrading ubuntu version --- .github/workflows/pr_test_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml index 190b891e1..c98e9604a 100644 --- a/.github/workflows/pr_test_build.yml +++ b/.github/workflows/pr_test_build.yml @@ -7,7 +7,7 @@ on: jobs: test: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04(ubuntu-latest) steps: - uses: actions/checkout@v2 From 57382ef7dc1f0bde5a2e009bfb70c4b5560cf4fb Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Wed, 30 Nov 2022 23:34:32 +0200 Subject: [PATCH 06/12] revert ubuntu version --- .github/workflows/pr_test_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml index c98e9604a..190b891e1 100644 --- a/.github/workflows/pr_test_build.yml +++ b/.github/workflows/pr_test_build.yml @@ -7,7 +7,7 @@ on: jobs: test: - runs-on: ubuntu-20.04(ubuntu-latest) + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 From 23358e131876b4f4535e3074492da83df9fc1c2d Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Mon, 5 Dec 2022 13:38:29 +0100 Subject: [PATCH 07/12] Update security settings view model --- lib/di.dart | 2 +- .../security_settings_view_model.dart | 20 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/di.dart b/lib/di.dart index d55a147ca..35a1b4d1a 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -434,7 +434,7 @@ Future setup( }); getIt.registerFactory(() { - return SecuritySettingsViewModel(getIt.get()); + return SecuritySettingsViewModel(getIt.get(), getIt.get()); }); getIt.registerFactory(() => WalletSeedViewModel(getIt.get().wallet!)); diff --git a/lib/view_model/settings/security_settings_view_model.dart b/lib/view_model/settings/security_settings_view_model.dart index 4a88b633f..c48223af6 100644 --- a/lib/view_model/settings/security_settings_view_model.dart +++ b/lib/view_model/settings/security_settings_view_model.dart @@ -1,4 +1,6 @@ +import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/entities/biometric_auth.dart'; +import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:mobx/mobx.dart'; @@ -7,19 +9,33 @@ part 'security_settings_view_model.g.dart'; class SecuritySettingsViewModel = SecuritySettingsViewModelBase with _$SecuritySettingsViewModel; abstract class SecuritySettingsViewModelBase with Store { - SecuritySettingsViewModelBase(this._settingsStore) : _biometricAuth = BiometricAuth(); + SecuritySettingsViewModelBase( + this._settingsStore, + this._authService, + ) : _biometricAuth = BiometricAuth(); final BiometricAuth _biometricAuth; final SettingsStore _settingsStore; + final AuthService _authService; @computed bool get allowBiometricalAuthentication => _settingsStore.allowBiometricalAuthentication; + @computed + PinCodeRequiredDuration get pinCodeRequiredDuration => _settingsStore.pinTimeOutDuration; + @action Future biometricAuthenticated() async { return await _biometricAuth.canCheckBiometrics() && await _biometricAuth.isAuthenticated(); } @action - void setAllowBiometricalAuthentication(bool value) => _settingsStore.allowBiometricalAuthentication = value; + void setAllowBiometricalAuthentication(bool value) => + _settingsStore.allowBiometricalAuthentication = value; + + @action + setPinCodeRequiredDuration(PinCodeRequiredDuration duration) => + _settingsStore.pinTimeOutDuration = duration; + + bool checkPinCodeRiquired() => _authService.requireAuth(); } From c156691e09139a36688d992911873ff9efb92b7c Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Mon, 5 Dec 2022 20:14:46 +0100 Subject: [PATCH 08/12] [skip ci] undo formatting in di --- lib/di.dart | 398 ++++++++++-------- .../security_settings_view_model.dart | 20 +- 2 files changed, 235 insertions(+), 183 deletions(-) diff --git a/lib/di.dart b/lib/di.dart index d55a147ca..bf926cbda 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -194,7 +194,8 @@ Future setup( _unspentCoinsInfoSource = unspentCoinsInfoSource; if (!_isSetupFinished) { - getIt.registerSingletonAsync(() => SharedPreferences.getInstance()); + getIt.registerSingletonAsync( + () => SharedPreferences.getInstance()); } final isBitcoinBuyEnabled = (secrets.wyreSecretKey?.isNotEmpty ?? false) && @@ -220,64 +221,73 @@ Future setup( walletList: getIt.get(), settingsStore: getIt.get(), nodeListStore: getIt.get())); - getIt.registerSingleton( - TradesStore(tradesSource: _tradesSource, settingsStore: getIt.get())); - getIt.registerSingleton( - OrdersStore(ordersSource: _ordersSource, settingsStore: getIt.get())); + getIt.registerSingleton(TradesStore( + tradesSource: _tradesSource, settingsStore: getIt.get())); + getIt.registerSingleton(OrdersStore( + ordersSource: _ordersSource, settingsStore: getIt.get())); getIt.registerSingleton(TradeFilterStore()); getIt.registerSingleton(TransactionFilterStore()); getIt.registerSingleton(FiatConversionStore()); - getIt.registerSingleton(SendTemplateStore(templateSource: _templates)); + getIt.registerSingleton( + SendTemplateStore(templateSource: _templates)); getIt.registerSingleton( ExchangeTemplateStore(templateSource: _exchangeTemplates)); - getIt.registerSingleton( - YatStore(appStore: getIt.get(), secureStorage: getIt.get()) - ..init()); + getIt.registerSingleton(YatStore( + appStore: getIt.get(), + secureStorage: getIt.get()) + ..init()); - final secretStore = await SecretStoreBase.load(getIt.get()); + final secretStore = + await SecretStoreBase.load(getIt.get()); getIt.registerSingleton(secretStore); - getIt.registerFactory(() => KeyService(getIt.get())); + getIt.registerFactory( + () => KeyService(getIt.get())); - getIt.registerFactoryParam((type, _) => - WalletCreationService( + getIt.registerFactoryParam( + (type, _) => WalletCreationService( initialType: type, keyService: getIt.get(), secureStorage: getIt.get(), sharedPreferences: getIt.get(), walletInfoSource: _walletInfoSource)); - getIt.registerFactory(() => WalletLoadingService( + getIt.registerFactory( + () => WalletLoadingService( getIt.get(), getIt.get(), (WalletType type) => getIt.get(param1: type))); - getIt.registerFactoryParam((type, _) => WalletNewVM( - getIt.get(), getIt.get(param1: type), _walletInfoSource, - type: type)); + getIt.registerFactoryParam((type, _) => + WalletNewVM(getIt.get(), + getIt.get(param1: type), _walletInfoSource, + type: type)); - getIt.registerFactoryParam((args, _) { + getIt + .registerFactoryParam((args, _) { final type = args.first as WalletType; final language = args[1] as String; final mnemonic = args[2] as String; - return WalletRestorationFromSeedVM( - getIt.get(), getIt.get(param1: type), _walletInfoSource, + return WalletRestorationFromSeedVM(getIt.get(), + getIt.get(param1: type), _walletInfoSource, type: type, language: language, seed: mnemonic); }); - getIt.registerFactoryParam((args, _) { + getIt + .registerFactoryParam((args, _) { final type = args.first as WalletType; final language = args[1] as String; - return WalletRestorationFromKeysVM( - getIt.get(), getIt.get(param1: type), _walletInfoSource, + return WalletRestorationFromKeysVM(getIt.get(), + getIt.get(param1: type), _walletInfoSource, type: type, language: language); }); getIt.registerFactory(() => - WalletAddressListViewModel(appStore: getIt.get(), yatStore: getIt.get())); + WalletAddressListViewModel( + appStore: getIt.get(), yatStore: getIt.get())); getIt.registerFactory(() => BalanceViewModel( appStore: getIt.get(), @@ -298,12 +308,15 @@ Future setup( secureStorage: getIt.get(), sharedPreferences: getIt.get())); - getIt.registerFactory(() => AuthViewModel(getIt.get(), - getIt.get(), getIt.get(), BiometricAuth())); + getIt.registerFactory(() => AuthViewModel( + getIt.get(), + getIt.get(), + getIt.get(), + BiometricAuth())); getIt.registerFactory( - () => AuthPage(getIt.get(), - onAuthenticationFinished: (isAuthenticated, AuthPageState authPageState) { + () => AuthPage(getIt.get(), onAuthenticationFinished: + (isAuthenticated, AuthPageState authPageState) { if (!isAuthenticated) { return; } @@ -318,7 +331,8 @@ Future setup( authPageState.changeProcessText('Loading the wallet'); if (loginError != null) { - authPageState.changeProcessText('ERROR: ${loginError.toString()}'); + authPageState + .changeProcessText('ERROR: ${loginError.toString()}'); } ReactionDisposer? _reaction; @@ -329,29 +343,28 @@ Future setup( }, closable: false), instanceName: 'login'); - getIt.registerFactoryParam( - (onAuthFinished, closable) => AuthPage(getIt.get(), - onAuthenticationFinished: onAuthFinished, closable: closable ?? false)); + getIt + .registerFactoryParam( + (onAuthFinished, closable) => AuthPage(getIt.get(), + onAuthenticationFinished: onAuthFinished, + closable: closable ?? false)); - getIt.registerFactory(() => BalancePage( - dashboardViewModel: getIt.get(), - settingsStore: getIt.get())); + getIt.registerFactory(() => + BalancePage(dashboardViewModel: getIt.get(), settingsStore: getIt.get())); - getIt.registerFactory(() => DashboardPage( - balancePage: getIt.get(), - walletViewModel: getIt.get(), + getIt.registerFactory(() => DashboardPage( balancePage: getIt.get(), walletViewModel: getIt.get(), addressListViewModel: getIt.get())); + getIt.registerFactory(() => ReceivePage( addressListViewModel: getIt.get())); - getIt.registerFactory( - () => ReceivePage(addressListViewModel: getIt.get())); getIt.registerFactory(() => AddressPage( addressListViewModel: getIt.get(), walletViewModel: getIt.get())); - getIt.registerFactoryParam((dynamic item, _) => - WalletAddressEditOrCreateViewModel(wallet: getIt.get().wallet!, item: item)); + getIt.registerFactoryParam( + (dynamic item, _) => WalletAddressEditOrCreateViewModel( + wallet: getIt.get().wallet!, item: item)); - getIt.registerFactoryParam((dynamic item, _) => - AddressEditOrCreatePage( + getIt.registerFactoryParam( + (dynamic item, _) => AddressEditOrCreatePage( addressEditOrCreateViewModel: getIt.get(param1: item))); @@ -369,16 +382,19 @@ Future setup( getIt.get(), _transactionDescriptionBox)); - getIt.registerFactory(() => SendPage(sendViewModel: getIt.get())); - getIt.registerFactory( - () => SendTemplatePage(sendTemplateViewModel: getIt.get())); + () => SendPage(sendViewModel: getIt.get())); + + getIt.registerFactory(() => SendTemplatePage( + sendTemplateViewModel: getIt.get())); getIt.registerFactory(() => WalletListViewModel( - _walletInfoSource, getIt.get(), getIt.get())); + _walletInfoSource, + getIt.get(), + getIt.get())); - getIt - .registerFactory(() => WalletListPage(walletListViewModel: getIt.get())); + getIt.registerFactory(() => + WalletListPage(walletListViewModel: getIt.get())); getIt.registerFactory(() { final wallet = getIt.get().wallet!; @@ -387,12 +403,11 @@ Future setup( return MoneroAccountListViewModel(wallet); } - throw Exception( - 'Unexpected wallet type: ${wallet.type} for generate MoneroAccountListViewModel'); + throw Exception('Unexpected wallet type: ${wallet.type} for generate MoneroAccountListViewModel'); }); - getIt.registerFactory( - () => MoneroAccountListPage(accountListViewModel: getIt.get())); + getIt.registerFactory(() => MoneroAccountListPage( + accountListViewModel: getIt.get())); /*getIt.registerFactory(() { final wallet = getIt.get().wallet; @@ -409,14 +424,16 @@ Future setup( moneroAccountCreationViewModel: getIt.get()));*/ - getIt.registerFactoryParam( + getIt.registerFactoryParam( (AccountListItem? account, _) => MoneroAccountEditOrCreateViewModel( monero!.getAccountList(getIt.get().wallet!), haven?.getAccountList(getIt.get().wallet!), wallet: getIt.get().wallet!, accountListItem: account)); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (AccountListItem? account, _) => MoneroAccountEditOrCreatePage( moneroAccountCreationViewModel: getIt.get(param1: account))); @@ -434,36 +451,44 @@ Future setup( }); getIt.registerFactory(() { - return SecuritySettingsViewModel(getIt.get()); + return SecuritySettingsViewModel(getIt.get(), getIt.get()); }); - getIt.registerFactory(() => WalletSeedViewModel(getIt.get().wallet!)); + getIt + .registerFactory(() => WalletSeedViewModel(getIt.get().wallet!)); - getIt.registerFactoryParam((bool isWalletCreated, _) => - WalletSeedPage(getIt.get(), isNewWalletCreated: isWalletCreated)); + getIt.registerFactoryParam( + (bool isWalletCreated, _) => WalletSeedPage( + getIt.get(), + isNewWalletCreated: isWalletCreated)); - getIt.registerFactory(() => WalletKeysViewModel(getIt.get().wallet!)); + getIt + .registerFactory(() => WalletKeysViewModel(getIt.get().wallet!)); getIt.registerFactory(() => WalletKeysPage(getIt.get())); getIt.registerFactoryParam( - (ContactRecord? contact, _) => ContactViewModel(_contactSource, contact: contact)); + (ContactRecord? contact, _) => + ContactViewModel(_contactSource, contact: contact)); - getIt.registerFactory(() => ContactListViewModel(_contactSource, _walletInfoSource)); + getIt.registerFactory( + () => ContactListViewModel(_contactSource, _walletInfoSource)); - getIt.registerFactoryParam((bool isEditable, _) => - ContactListPage(getIt.get(), isEditable: isEditable)); + getIt.registerFactoryParam( + (bool isEditable, _) => ContactListPage(getIt.get(), + isEditable: isEditable)); getIt.registerFactoryParam( - (ContactRecord? contact, _) => ContactPage(getIt.get(param1: contact))); + (ContactRecord? contact, _) => + ContactPage(getIt.get(param1: contact))); getIt.registerFactory(() { final appStore = getIt.get(); - return NodeListViewModel(_nodeSource, appStore.wallet!, appStore.settingsStore); + return NodeListViewModel( + _nodeSource, appStore.wallet!, appStore.settingsStore); }); - getIt.registerFactory( - () => ConnectionSyncPage(getIt.get(), getIt.get())); + getIt.registerFactory(() => ConnectionSyncPage(getIt.get(), getIt.get())); getIt.registerFactory(() => SecurityBackupPage(getIt.get())); @@ -473,22 +498,24 @@ Future setup( getIt.registerFactory(() => OtherSettingsPage(getIt.get())); - getIt - .registerFactory(() => NodeCreateOrEditViewModel(_nodeSource, getIt.get().wallet!)); + getIt.registerFactory(() => + NodeCreateOrEditViewModel(_nodeSource, getIt.get().wallet!)); - getIt.registerFactory(() => NodeCreateOrEditPage(getIt.get())); + getIt.registerFactory( + () => NodeCreateOrEditPage(getIt.get())); getIt.registerFactory(() => OnRamperPage( - settingsStore: getIt.get().settingsStore, wallet: getIt.get().wallet!)); + settingsStore: getIt.get().settingsStore, + wallet: getIt.get().wallet!)); getIt.registerFactory(() => ExchangeViewModel( - getIt.get().wallet!, - _tradesSource, - getIt.get(), - getIt.get(), - getIt.get().settingsStore, - getIt.get(), - )); + getIt.get().wallet!, + _tradesSource, + getIt.get(), + getIt.get(), + getIt.get().settingsStore, + getIt.get(), + )); getIt.registerFactory(() => ExchangeTradeViewModel( wallet: getIt.get().wallet!, @@ -498,34 +525,40 @@ Future setup( getIt.registerFactory(() => ExchangePage(getIt.get())); - getIt.registerFactory(() => ExchangeConfirmPage(tradesStore: getIt.get())); + getIt.registerFactory( + () => ExchangeConfirmPage(tradesStore: getIt.get())); + + getIt.registerFactory(() => ExchangeTradePage( + exchangeTradeViewModel: getIt.get())); getIt.registerFactory( - () => ExchangeTradePage(exchangeTradeViewModel: getIt.get())); + () => ExchangeTemplatePage(getIt.get())); - getIt.registerFactory(() => ExchangeTemplatePage(getIt.get())); - - getIt.registerFactoryParam((WalletType param1, __) { + getIt.registerFactoryParam( + (WalletType param1, __) { switch (param1) { case WalletType.haven: return haven!.createHavenWalletService(_walletInfoSource); case WalletType.monero: return monero!.createMoneroWalletService(_walletInfoSource); case WalletType.bitcoin: - return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!); + return bitcoin!.createBitcoinWalletService( + _walletInfoSource, _unspentCoinsInfoSource!); case WalletType.litecoin: - return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!); + return bitcoin!.createLitecoinWalletService( + _walletInfoSource, _unspentCoinsInfoSource!); default: throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService'); } }); - getIt.registerFactory( - () => SetupPinCodeViewModel(getIt.get(), getIt.get())); + getIt.registerFactory(() => SetupPinCodeViewModel( + getIt.get(), getIt.get())); - getIt.registerFactoryParam, String), - void>( - (onSuccessfulPinSetup, _) => SetupPinCodePage(getIt.get(), + getIt.registerFactoryParam, String), void>( + (onSuccessfulPinSetup, _) => SetupPinCodePage( + getIt.get(), onSuccessfulPinSetup: onSuccessfulPinSetup)); getIt.registerFactory(() => RescanViewModel(getIt.get().wallet!)); @@ -534,16 +567,17 @@ Future setup( getIt.registerFactory(() => FaqPage(getIt.get())); - getIt.registerFactoryParam((type, _) => - WalletRestoreViewModel( - getIt.get(), getIt.get(param1: type), _walletInfoSource, + getIt.registerFactoryParam( + (type, _) => WalletRestoreViewModel(getIt.get(), + getIt.get(param1: type), _walletInfoSource, type: type)); - getIt.registerFactoryParam( - (type, _) => WalletRestorePage(getIt.get(param1: type))); + getIt.registerFactoryParam((type, _) => + WalletRestorePage(getIt.get(param1: type))); - getIt.registerFactoryParam( - (TransactionInfo transactionInfo, _) { + getIt + .registerFactoryParam( + (TransactionInfo transactionInfo, _) { final wallet = getIt.get().wallet!; return TransactionDetailsViewModel( transactionInfo: transactionInfo, @@ -557,47 +591,52 @@ Future setup( transactionDetailsViewModel: getIt.get(param1: transactionInfo))); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (param1, _) => NewWalletTypePage(onTypeSelected: param1)); getIt.registerFactoryParam( (WalletType type, _) => PreSeedPage(type)); getIt.registerFactoryParam((trade, _) => - TradeDetailsViewModel( - tradeForDetails: trade, - trades: _tradesSource, + TradeDetailsViewModel(tradeForDetails: trade, trades: _tradesSource, settingsStore: getIt.get())); - getIt.registerFactory(() => BackupService(getIt.get(), _walletInfoSource, - getIt.get(), getIt.get())); + getIt.registerFactory(() => BackupService( + getIt.get(), + _walletInfoSource, + getIt.get(), + getIt.get())); - getIt.registerFactory(() => BackupViewModel( - getIt.get(), getIt.get(), getIt.get())); + getIt.registerFactory(() => BackupViewModel(getIt.get(), + getIt.get(), getIt.get())); getIt.registerFactory(() => BackupPage(getIt.get())); - getIt.registerFactory(() => - EditBackupPasswordViewModel(getIt.get(), getIt.get())); + getIt.registerFactory( + () => EditBackupPasswordViewModel(getIt.get(), getIt.get())); - getIt.registerFactory(() => EditBackupPasswordPage(getIt.get())); + getIt.registerFactory( + () => EditBackupPasswordPage(getIt.get())); getIt.registerFactory(() => RestoreOptionsPage()); - getIt.registerFactory(() => RestoreFromBackupViewModel(getIt.get())); + getIt.registerFactory( + () => RestoreFromBackupViewModel(getIt.get())); - getIt.registerFactory(() => RestoreFromBackupPage(getIt.get())); + getIt.registerFactory( + () => RestoreFromBackupPage(getIt.get())); - getIt.registerFactoryParam( - (Trade trade, _) => TradeDetailsPage(getIt.get(param1: trade))); + getIt.registerFactoryParam((Trade trade, _) => + TradeDetailsPage(getIt.get(param1: trade))); getIt.registerFactory(() => BuyAmountViewModel()); getIt.registerFactory(() { final wallet = getIt.get().wallet; - return BuyViewModel(_ordersSource, getIt.get(), getIt.get(), - getIt.get(), + return BuyViewModel(_ordersSource, getIt.get(), + getIt.get(), getIt.get(), wallet: wallet!); }); @@ -609,8 +648,7 @@ Future setup( final url = args.first as String; final buyViewModel = args[1] as BuyViewModel; - return BuyWebViewPage( - buyViewModel: buyViewModel, ordersStore: getIt.get(), url: url); + return BuyWebViewPage(buyViewModel: buyViewModel, ordersStore: getIt.get(), url: url); }); getIt.registerFactoryParam((order, _) { @@ -619,8 +657,8 @@ Future setup( return OrderDetailsViewModel(wallet: wallet!, orderForDetails: order); }); - getIt.registerFactoryParam( - (Order order, _) => OrderDetailsPage(getIt.get(param1: order))); + getIt.registerFactoryParam((Order order, _) => + OrderDetailsPage(getIt.get(param1: order))); getIt.registerFactory(() => SupportViewModel()); @@ -629,18 +667,20 @@ Future setup( getIt.registerFactory(() { final wallet = getIt.get().wallet; - return UnspentCoinsListViewModel(wallet: wallet!, unspentCoinsInfo: _unspentCoinsInfoSource!); + return UnspentCoinsListViewModel( + wallet: wallet!, unspentCoinsInfo: _unspentCoinsInfoSource!); }); - getIt.registerFactory(() => - UnspentCoinsListPage(unspentCoinsListViewModel: getIt.get())); + getIt.registerFactory(() => UnspentCoinsListPage( + unspentCoinsListViewModel: getIt.get())); getIt.registerFactoryParam( - (item, model) => - UnspentCoinsDetailsViewModel(unspentCoinsItem: item, unspentCoinsListViewModel: model)); + (item, model) => UnspentCoinsDetailsViewModel( + unspentCoinsItem: item, unspentCoinsListViewModel: model)); - getIt.registerFactoryParam((List args, _) { + getIt.registerFactoryParam( + (List args, _) { final item = args.first as UnspentCoinsItem; final unspentCoinsListViewModel = args[1] as UnspentCoinsListViewModel; @@ -653,15 +693,12 @@ Future setup( getIt.registerFactory(() => YatService()); - getIt.registerFactory(() => AddressResolver( - yatService: getIt.get(), walletType: getIt.get().wallet!.type)); + getIt.registerFactory(() => AddressResolver(yatService: getIt.get(), + walletType: getIt.get().wallet!.type)); getIt.registerFactoryParam( - (String qrData, bool isLight) => FullscreenQRPage( - qrData: qrData, - isLight: isLight, - )); - + (String qrData, bool isLight) => FullscreenQRPage(qrData: qrData, isLight: isLight,)); + getIt.registerFactory(() => IoniaApi()); getIt.registerFactory(() => AnyPayApi()); @@ -669,24 +706,26 @@ Future setup( getIt.registerFactory( () => IoniaService(getIt.get(), getIt.get())); - getIt.registerFactory(() => IoniaAnyPay( - getIt.get(), getIt.get(), getIt.get().wallet!)); + getIt.registerFactory( + () => IoniaAnyPay( + getIt.get(), + getIt.get(), + getIt.get().wallet!)); getIt.registerFactory(() => IoniaGiftCardsListViewModel(ioniaService: getIt.get())); getIt.registerFactory(() => IoniaAuthViewModel(ioniaService: getIt.get())); - getIt.registerFactoryParam( - (double amount, merchant) { + getIt.registerFactoryParam((double amount, merchant) { return IoniaMerchPurchaseViewModel( - ioniaAnyPayService: getIt.get(), - amount: amount, - ioniaMerchant: merchant, - sendViewModel: getIt.get()); + ioniaAnyPayService: getIt.get(), + amount: amount, + ioniaMerchant: merchant, + sendViewModel: getIt.get() + ); }); - getIt.registerFactoryParam( - (IoniaMerchant merchant, _) { + getIt.registerFactoryParam((IoniaMerchant merchant, _) { return IoniaBuyCardViewModel(ioniaMerchant: merchant); }); @@ -714,44 +753,42 @@ Future setup( getIt.registerFactoryParam((List args, _) { final amount = args.first as double; final merchant = args.last as IoniaMerchant; - return IoniaBuyGiftCardDetailPage( - getIt.get(param1: amount, param2: merchant)); + return IoniaBuyGiftCardDetailPage(getIt.get(param1: amount, param2: merchant)); }); - getIt.registerFactoryParam( - (IoniaGiftCard giftCard, _) { - return IoniaGiftCardDetailsViewModel( - ioniaService: getIt.get(), giftCard: giftCard); + getIt.registerFactoryParam((IoniaGiftCard giftCard, _) { + return IoniaGiftCardDetailsViewModel( + ioniaService: getIt.get(), + giftCard: giftCard); + }); + + getIt.registerFactoryParam((List args, _) { + final amount = args[0] as double; + final merchant = args[1] as IoniaMerchant; + final tip = args[2] as IoniaTip; + + return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant); + }); + + getIt.registerFactoryParam((IoniaGiftCard giftCard, _) { + return IoniaGiftCardDetailPage(getIt.get(param1: giftCard)); }); - getIt.registerFactoryParam((List args, _) { - final amount = args[0] as double; - final merchant = args[1] as IoniaMerchant; - final tip = args[2] as IoniaTip; - - return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant); - }); - - getIt.registerFactoryParam( - (IoniaGiftCard giftCard, _) { - return IoniaGiftCardDetailPage(getIt.get(param1: giftCard)); - }); - - getIt.registerFactoryParam((List args, _) { + getIt.registerFactoryParam((List args, _){ final giftCard = args.first as IoniaGiftCard; - - return IoniaMoreOptionsPage(giftCard); + + return IoniaMoreOptionsPage(giftCard); }); - getIt.registerFactoryParam( - (IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard)); + getIt.registerFactoryParam((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard)); - getIt.registerFactoryParam((List args, _) { + getIt.registerFactoryParam((List args, _){ final giftCard = args.first as IoniaGiftCard; - - return IoniaCustomRedeemPage(getIt.get(param1: giftCard)); + + return IoniaCustomRedeemPage(getIt.get(param1: giftCard) ); }); + getIt.registerFactoryParam((List args, _) { return IoniaCustomTipPage(getIt.get(param1: args)); }); @@ -766,17 +803,16 @@ Future setup( getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get())); - getIt.registerFactoryParam( - (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) => - IoniaPaymentStatusViewModel(getIt.get(), - paymentInfo: paymentInfo, committedInfo: committedInfo)); + getIt.registerFactoryParam( + (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) + => IoniaPaymentStatusViewModel( + getIt.get(), + paymentInfo: paymentInfo, + committedInfo: committedInfo)); - getIt.registerFactoryParam( - (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) => - IoniaPaymentStatusPage( - getIt.get(param1: paymentInfo, param2: committedInfo))); + getIt.registerFactoryParam( + (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) + => IoniaPaymentStatusPage(getIt.get(param1: paymentInfo, param2: committedInfo))); _isSetupFinished = true; -} +} \ No newline at end of file diff --git a/lib/view_model/settings/security_settings_view_model.dart b/lib/view_model/settings/security_settings_view_model.dart index 4a88b633f..c48223af6 100644 --- a/lib/view_model/settings/security_settings_view_model.dart +++ b/lib/view_model/settings/security_settings_view_model.dart @@ -1,4 +1,6 @@ +import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/entities/biometric_auth.dart'; +import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:mobx/mobx.dart'; @@ -7,19 +9,33 @@ part 'security_settings_view_model.g.dart'; class SecuritySettingsViewModel = SecuritySettingsViewModelBase with _$SecuritySettingsViewModel; abstract class SecuritySettingsViewModelBase with Store { - SecuritySettingsViewModelBase(this._settingsStore) : _biometricAuth = BiometricAuth(); + SecuritySettingsViewModelBase( + this._settingsStore, + this._authService, + ) : _biometricAuth = BiometricAuth(); final BiometricAuth _biometricAuth; final SettingsStore _settingsStore; + final AuthService _authService; @computed bool get allowBiometricalAuthentication => _settingsStore.allowBiometricalAuthentication; + @computed + PinCodeRequiredDuration get pinCodeRequiredDuration => _settingsStore.pinTimeOutDuration; + @action Future biometricAuthenticated() async { return await _biometricAuth.canCheckBiometrics() && await _biometricAuth.isAuthenticated(); } @action - void setAllowBiometricalAuthentication(bool value) => _settingsStore.allowBiometricalAuthentication = value; + void setAllowBiometricalAuthentication(bool value) => + _settingsStore.allowBiometricalAuthentication = value; + + @action + setPinCodeRequiredDuration(PinCodeRequiredDuration duration) => + _settingsStore.pinTimeOutDuration = duration; + + bool checkPinCodeRiquired() => _authService.requireAuth(); } From 9ef1186c453256de7e3e6a2ac48a0ab0a239e336 Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Fri, 9 Dec 2022 17:08:52 +0100 Subject: [PATCH 09/12] Fix issues from code review --- lib/core/auth_service.dart | 26 +-- lib/src/screens/root/root.dart | 12 +- .../screens/wallet_list/wallet_list_page.dart | 157 +++++++++--------- lib/view_model/auth_view_model.dart | 4 +- 4 files changed, 99 insertions(+), 100 deletions(-) diff --git a/lib/core/auth_service.dart b/lib/core/auth_service.dart index 6b167fa40..c493cddcb 100644 --- a/lib/core/auth_service.dart +++ b/lib/core/auth_service.dart @@ -42,25 +42,27 @@ class AuthService with Store { return decodedPin == pin; } - void saveLastAuthTime(){ + void saveLastAuthTime() { + int timestamp = DateTime.now().millisecondsSinceEpoch; sharedPreferences.setInt(PreferencesKey.lastAuthTimeMilliseconds, timestamp); } - bool requireAuth(){ - final timestamp = sharedPreferences.getInt(PreferencesKey.lastAuthTimeMilliseconds); - final duration = _durationToRequireAuth(timestamp ?? 0); - final requiredPinInterval = getIt.get().pinTimeOutDuration; + bool requireAuth() { + + final timestamp = sharedPreferences.getInt(PreferencesKey.lastAuthTimeMilliseconds); + final duration = _durationToRequireAuth(timestamp ?? 0); + final requiredPinInterval = getIt.get().pinTimeOutDuration; - return duration >= requiredPinInterval.value; - } + return duration >= requiredPinInterval.value; + } - int _durationToRequireAuth(int timestamp){ + int _durationToRequireAuth(int timestamp) { - DateTime before = DateTime.fromMillisecondsSinceEpoch(timestamp); - DateTime now = DateTime.now(); - Duration timeDifference = now.difference(before); + DateTime before = DateTime.fromMillisecondsSinceEpoch(timestamp); + DateTime now = DateTime.now(); + Duration timeDifference = now.difference(before); - return timeDifference.inMinutes; + return timeDifference.inMinutes; } } diff --git a/lib/src/screens/root/root.dart b/lib/src/screens/root/root.dart index 8d2b61a65..206f485dd 100644 --- a/lib/src/screens/root/root.dart +++ b/lib/src/screens/root/root.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'package:cake_wallet/core/auth_service.dart'; -import 'package:cake_wallet/di.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart'; @@ -14,12 +13,15 @@ class Root extends StatefulWidget { required this.authenticationStore, required this.appStore, required this.child, - required this.navigatorKey}) + required this.navigatorKey, + required this.authService, + }) : super(key: key); final AuthenticationStore authenticationStore; final AppStore appStore; final GlobalKey navigatorKey; + final AuthService authService; final Widget child; @override @@ -30,7 +32,7 @@ class RootState extends State with WidgetsBindingObserver { RootState() : _isInactiveController = StreamController.broadcast(), _isInactive = false, - _requestAuth = getIt.get().requireAuth(), + _requestAuth = true, _postFrameCallback = false; Stream get isInactive => _isInactiveController.stream; @@ -41,7 +43,7 @@ class RootState extends State with WidgetsBindingObserver { @override void initState() { - + _requestAuth = widget.authService.requireAuth(); _isInactiveController = StreamController.broadcast(); _isInactive = false; _postFrameCallback = false; @@ -58,7 +60,7 @@ class RootState extends State with WidgetsBindingObserver { } setState(() { - _requestAuth = getIt.get().requireAuth(); + _requestAuth = widget.authService.requireAuth(); }); if (!_isInactive && diff --git a/lib/src/screens/wallet_list/wallet_list_page.dart b/lib/src/screens/wallet_list/wallet_list_page.dart index 5d9650ef2..d76631b3f 100644 --- a/lib/src/screens/wallet_list/wallet_list_page.dart +++ b/lib/src/screens/wallet_list/wallet_list_page.dart @@ -220,93 +220,88 @@ class WalletListBodyState extends State { } Future _loadWallet(WalletListItem wallet) async { - if(await widget.walletListViewModel.checkIfAuthRequired()){ - await Navigator.of(context).pushNamed(Routes.auth, arguments: - (bool isAuthenticatedSuccessfully, AuthPageState auth) async { - if (!isAuthenticatedSuccessfully) { - return; - } + if (await widget.walletListViewModel.checkIfAuthRequired()) { + await Navigator.of(context).pushNamed(Routes.auth, + arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async { + if (!isAuthenticatedSuccessfully) { + return; + } - try { - auth.changeProcessText( - S.of(context).wallet_list_loading_wallet(wallet.name)); - await widget.walletListViewModel.loadWallet(wallet); - auth.hideProgressText(); - auth.close(); - WidgetsBinding.instance.addPostFrameCallback((_) { - Navigator.of(context).pop(); - }); - } catch (e) { - auth.changeProcessText(S - .of(context) - .wallet_list_failed_to_load(wallet.name, e.toString())); - } - }); - }else{ + try { + auth.changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name)); + await widget.walletListViewModel.loadWallet(wallet); + auth.hideProgressText(); + auth.close(); + WidgetsBinding.instance.addPostFrameCallback((_) { + Navigator.of(context).pop(); + }); + } catch (e) { + auth.changeProcessText( + S.of(context).wallet_list_failed_to_load(wallet.name, e.toString())); + } + }); + } else { try { changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name)); await widget.walletListViewModel.loadWallet(wallet); hideProgressText(); - Navigator.of(context).pop(); + Navigator.of(context).pop(); } catch (e) { - changeProcessText(S - .of(context) - .wallet_list_failed_to_load(wallet.name, e.toString())); + changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString())); } } } Future _removeWallet(WalletListItem wallet) async { - if(widget.walletListViewModel.checkIfAuthRequired()){ - await Navigator.of(context).pushNamed(Routes.auth, arguments: - (bool isAuthenticatedSuccessfully, AuthPageState auth) async { - if (!isAuthenticatedSuccessfully) { - return; - } - _onSuccessfulAuth(wallet, auth); - }); - }else{ + if (widget.walletListViewModel.checkIfAuthRequired()) { + await Navigator.of(context).pushNamed(Routes.auth, + arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async { + if (!isAuthenticatedSuccessfully) { + return; + } + _onSuccessfulAuth(wallet, auth); + }); + } else { _onSuccessfulAuth(wallet, null); } } - _onSuccessfulAuth(WalletListItem wallet, AuthPageState? auth)async{ + void _onSuccessfulAuth(WalletListItem wallet, AuthPageState? auth) async { bool confirmed = false; - await showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithTwoActions( - alertTitle: S.of(context).delete_wallet, - alertContent: S.of(context).delete_wallet_confirm_message(wallet.name), - leftButtonText: S.of(context).cancel, - rightButtonText: S.of(context).delete, - actionLeftButton: () => Navigator.of(context).pop(), - actionRightButton: () { - confirmed = true; - Navigator.of(context).pop(); - }, - ); - }); - - if (confirmed) { - try { - auth != null ? - auth.changeProcessText( - S.of(context).wallet_list_removing_wallet(wallet.name)) - : changeProcessText( S.of(context).wallet_list_removing_wallet(wallet.name)); - await widget.walletListViewModel.remove(wallet); - } catch (e) { - auth != null ? - auth.changeProcessText( - S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()), - ) - : changeProcessText( - S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()), + await showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: S.of(context).delete_wallet, + alertContent: S.of(context).delete_wallet_confirm_message(wallet.name), + leftButtonText: S.of(context).cancel, + rightButtonText: S.of(context).delete, + actionLeftButton: () => Navigator.of(context).pop(), + actionRightButton: () { + confirmed = true; + Navigator.of(context).pop(); + }, ); - } - } + }); - auth?.close(); + if (confirmed) { + try { + auth != null + ? auth.changeProcessText(S.of(context).wallet_list_removing_wallet(wallet.name)) + : changeProcessText(S.of(context).wallet_list_removing_wallet(wallet.name)); + await widget.walletListViewModel.remove(wallet); + } catch (e) { + auth != null + ? auth.changeProcessText( + S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()), + ) + : changeProcessText( + S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()), + ); + } + } + + auth?.close(); } void changeProcessText(String text) { @@ -319,16 +314,16 @@ class WalletListBodyState extends State { } ActionPane _actionPane(WalletListItem wallet) => ActionPane( - motion: const ScrollMotion(), - extentRatio: 0.3, - children: [ - SlidableAction( - onPressed: (_) => _removeWallet(wallet), - backgroundColor: Colors.red, - foregroundColor: Colors.white, - icon: CupertinoIcons.delete, - label: S.of(context).delete, - ), - ], - ); + motion: const ScrollMotion(), + extentRatio: 0.3, + children: [ + SlidableAction( + onPressed: (_) => _removeWallet(wallet), + backgroundColor: Colors.red, + foregroundColor: Colors.white, + icon: CupertinoIcons.delete, + label: S.of(context).delete, + ), + ], + ); } diff --git a/lib/view_model/auth_view_model.dart b/lib/view_model/auth_view_model.dart index 42201ddab..d45873230 100644 --- a/lib/view_model/auth_view_model.dart +++ b/lib/view_model/auth_view_model.dart @@ -121,8 +121,8 @@ abstract class AuthViewModelBase with Store { } } - void _saveLastAuthTime(ExecutionState state){ - if(state is ExecutedSuccessfullyState){ + void _saveLastAuthTime(ExecutionState state) { + if(state is ExecutedSuccessfullyState) { _authService.saveLastAuthTime(); } } From 6836ac6d1ac2374b4586b7ac3bd643909ed14fbe Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Fri, 9 Dec 2022 20:18:36 +0100 Subject: [PATCH 10/12] Fix formatting --- lib/core/auth_service.dart | 14 +++++--------- lib/view_model/auth_view_model.dart | 21 ++++++++++----------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/lib/core/auth_service.dart b/lib/core/auth_service.dart index c493cddcb..569db5700 100644 --- a/lib/core/auth_service.dart +++ b/lib/core/auth_service.dart @@ -21,8 +21,7 @@ class AuthService with Store { Future canAuthenticate() async { final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); - final walletName = - sharedPreferences.getString(PreferencesKey.currentWalletName) ?? ''; + final walletName = sharedPreferences.getString(PreferencesKey.currentWalletName) ?? ''; var password = ''; try { @@ -43,26 +42,23 @@ class AuthService with Store { } void saveLastAuthTime() { - int timestamp = DateTime.now().millisecondsSinceEpoch; sharedPreferences.setInt(PreferencesKey.lastAuthTimeMilliseconds, timestamp); } - bool requireAuth() { - + bool requireAuth() { final timestamp = sharedPreferences.getInt(PreferencesKey.lastAuthTimeMilliseconds); - final duration = _durationToRequireAuth(timestamp ?? 0); + final duration = _durationToRequireAuth(timestamp ?? 0); final requiredPinInterval = getIt.get().pinTimeOutDuration; - + return duration >= requiredPinInterval.value; } int _durationToRequireAuth(int timestamp) { - DateTime before = DateTime.fromMillisecondsSinceEpoch(timestamp); DateTime now = DateTime.now(); Duration timeDifference = now.difference(before); - return timeDifference.inMinutes; + return timeDifference.inMinutes; } } diff --git a/lib/view_model/auth_view_model.dart b/lib/view_model/auth_view_model.dart index d45873230..e50f4db0c 100644 --- a/lib/view_model/auth_view_model.dart +++ b/lib/view_model/auth_view_model.dart @@ -14,12 +14,12 @@ part 'auth_view_model.g.dart'; class AuthViewModel = AuthViewModelBase with _$AuthViewModel; abstract class AuthViewModelBase with Store { - AuthViewModelBase(this._authService, this._sharedPreferences, - this._settingsStore, this._biometricAuth) + AuthViewModelBase( + this._authService, this._sharedPreferences, this._settingsStore, this._biometricAuth) : _failureCounter = 0, - state = InitialExecutionState(){ - reaction((_) => state, _saveLastAuthTime); - } + state = InitialExecutionState() { + reaction((_) => state, _saveLastAuthTime); + } static const maxFailedLogins = 3; static const banTimeout = 180; // 3 minutes @@ -30,8 +30,7 @@ abstract class AuthViewModelBase with Store { int get pinLength => _settingsStore.pinCodeLength; - bool get isBiometricalAuthenticationAllowed => - _settingsStore.allowBiometricalAuthentication; + bool get isBiometricalAuthenticationAllowed => _settingsStore.allowBiometricalAuthentication; @observable int _failureCounter; @@ -59,7 +58,7 @@ abstract class AuthViewModelBase with Store { if (isSuccessfulAuthenticated) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - state = ExecutedSuccessfullyState(); + state = ExecutedSuccessfullyState(); _failureCounter = 0; }); } else { @@ -116,14 +115,14 @@ abstract class AuthViewModelBase with Store { state = ExecutedSuccessfullyState(); } } - } catch(e) { + } catch (e) { state = FailureState(e.toString()); } } void _saveLastAuthTime(ExecutionState state) { - if(state is ExecutedSuccessfullyState) { - _authService.saveLastAuthTime(); + if (state is ExecutedSuccessfullyState) { + _authService.saveLastAuthTime(); } } } From 59484e5b9165ed01454bf63438013c64037df21c Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Fri, 9 Dec 2022 20:19:23 +0100 Subject: [PATCH 11/12] Fix formatting --- lib/src/screens/root/root.dart | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/src/screens/root/root.dart b/lib/src/screens/root/root.dart index 206f485dd..d217789e8 100644 --- a/lib/src/screens/root/root.dart +++ b/lib/src/screens/root/root.dart @@ -8,15 +8,14 @@ import 'package:cake_wallet/store/authentication_store.dart'; import 'package:cake_wallet/entities/qr_scanner.dart'; class Root extends StatefulWidget { - Root( - {required Key key, - required this.authenticationStore, - required this.appStore, - required this.child, - required this.navigatorKey, - required this.authService, - }) - : super(key: key); + Root({ + required Key key, + required this.authenticationStore, + required this.appStore, + required this.child, + required this.navigatorKey, + required this.authService, + }) : super(key: key); final AuthenticationStore authenticationStore; final AppStore appStore; @@ -30,10 +29,10 @@ class Root extends StatefulWidget { class RootState extends State with WidgetsBindingObserver { RootState() - : _isInactiveController = StreamController.broadcast(), - _isInactive = false, - _requestAuth = true, - _postFrameCallback = false; + : _isInactiveController = StreamController.broadcast(), + _isInactive = false, + _requestAuth = true, + _postFrameCallback = false; Stream get isInactive => _isInactiveController.stream; StreamController _isInactiveController; @@ -63,8 +62,7 @@ class RootState extends State with WidgetsBindingObserver { _requestAuth = widget.authService.requireAuth(); }); - if (!_isInactive && - widget.authenticationStore.state == AuthenticationState.allowed) { + if (!_isInactive && widget.authenticationStore.state == AuthenticationState.allowed) { setState(() => _setInactive(true)); } From f15bc2821960d6d780d11dec793aa115abda90ed Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Tue, 13 Dec 2022 16:19:31 +0100 Subject: [PATCH 12/12] [skip ci] fix issues from code review --- lib/core/auth_service.dart | 9 ++- lib/di.dart | 10 ++- lib/main.dart | 3 + .../settings/security_backup_page.dart | 62 +++++++++---------- lib/store/settings_store.dart | 9 +-- .../wallet_list/wallet_list_view_model.dart | 32 ++++++---- 6 files changed, 73 insertions(+), 52 deletions(-) diff --git a/lib/core/auth_service.dart b/lib/core/auth_service.dart index 569db5700..54f89437a 100644 --- a/lib/core/auth_service.dart +++ b/lib/core/auth_service.dart @@ -8,10 +8,15 @@ import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/store/settings_store.dart'; class AuthService with Store { - AuthService({required this.secureStorage, required this.sharedPreferences}); + AuthService({ + required this.secureStorage, + required this.sharedPreferences, + required this.settingsStore, + }); final FlutterSecureStorage secureStorage; final SharedPreferences sharedPreferences; + final SettingsStore settingsStore; Future setPassword(String password) async { final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); @@ -49,7 +54,7 @@ class AuthService with Store { bool requireAuth() { final timestamp = sharedPreferences.getInt(PreferencesKey.lastAuthTimeMilliseconds); final duration = _durationToRequireAuth(timestamp ?? 0); - final requiredPinInterval = getIt.get().pinTimeOutDuration; + final requiredPinInterval = settingsStore.pinTimeOutDuration; return duration >= requiredPinInterval.value; } diff --git a/lib/di.dart b/lib/di.dart index b506700f3..aa6514f0e 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -308,7 +308,10 @@ Future setup( getIt.registerFactory(() => AuthService( secureStorage: getIt.get(), - sharedPreferences: getIt.get())); + sharedPreferences: getIt.get(), + settingsStore: getIt.get(), + ), + ); getIt.registerFactory(() => AuthViewModel( getIt.get(), @@ -393,7 +396,10 @@ Future setup( getIt.registerFactory(() => WalletListViewModel( _walletInfoSource, getIt.get(), - getIt.get())); + getIt.get(), + getIt.get(), + ), + ); getIt.registerFactory(() => WalletListPage(walletListViewModel: getIt.get())); diff --git a/lib/main.dart b/lib/main.dart index 11eee146b..ccabf84fe 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/entities/language_service.dart'; import 'package:cake_wallet/buy/order.dart'; import 'package:cake_wallet/ionia/ionia_category.dart'; @@ -257,6 +258,7 @@ class AppState extends State with SingleTickerProviderStateMixin { Widget build(BuildContext context) { return Observer(builder: (BuildContext context) { final appStore = getIt.get(); + final authService = getIt.get(); final settingsStore = appStore.settingsStore; final statusBarColor = Colors.transparent; final authenticationStore = getIt.get(); @@ -281,6 +283,7 @@ class AppState extends State with SingleTickerProviderStateMixin { appStore: appStore, authenticationStore: authenticationStore, navigatorKey: navigatorKey, + authService: authService, child: MaterialApp( navigatorKey: navigatorKey, debugShowCheckedModeBanner: false, diff --git a/lib/src/screens/settings/security_backup_page.dart b/lib/src/screens/settings/security_backup_page.dart index 7040816d9..102a94b36 100644 --- a/lib/src/screens/settings/security_backup_page.dart +++ b/lib/src/screens/settings/security_backup_page.dart @@ -62,40 +62,38 @@ class SecurityBackupPage extends BasePage { })), StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)), Observer(builder: (_) { - return Column( - children: [ - SettingsSwitcherCell( - title: S.current.settings_allow_biometrical_authentication, - value: _securitySettingsViewModel.allowBiometricalAuthentication, - onValueChange: (BuildContext context, bool value) { - if (value) { - Navigator.of(context).pushNamed(Routes.auth, - arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async { - if (isAuthenticatedSuccessfully) { - if (await _securitySettingsViewModel.biometricAuthenticated()) { - _securitySettingsViewModel - .setAllowBiometricalAuthentication(isAuthenticatedSuccessfully); - } - } else { - _securitySettingsViewModel - .setAllowBiometricalAuthentication(isAuthenticatedSuccessfully); - } - - auth.close(); - }); + return SettingsSwitcherCell( + title: S.current.settings_allow_biometrical_authentication, + value: _securitySettingsViewModel.allowBiometricalAuthentication, + onValueChange: (BuildContext context, bool value) { + if (value) { + Navigator.of(context).pushNamed(Routes.auth, + arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async { + if (isAuthenticatedSuccessfully) { + if (await _securitySettingsViewModel.biometricAuthenticated()) { + _securitySettingsViewModel + .setAllowBiometricalAuthentication(isAuthenticatedSuccessfully); + } } else { - _securitySettingsViewModel.setAllowBiometricalAuthentication(value); + _securitySettingsViewModel + .setAllowBiometricalAuthentication(isAuthenticatedSuccessfully); } - }), - SettingsPickerCell( - title: S.current.require_pin_after, - items: PinCodeRequiredDuration.values, - selectedItem: _securitySettingsViewModel.pinCodeRequiredDuration, - onItemSelected: (PinCodeRequiredDuration code) { - _securitySettingsViewModel.setPinCodeRequiredDuration(code); - }, - ), - ], + + auth.close(); + }); + } else { + _securitySettingsViewModel.setAllowBiometricalAuthentication(value); + } + }); + }), + Observer(builder: (_) { + return SettingsPickerCell( + title: S.current.require_pin_after, + items: PinCodeRequiredDuration.values, + selectedItem: _securitySettingsViewModel.pinCodeRequiredDuration, + onItemSelected: (PinCodeRequiredDuration code) { + _securitySettingsViewModel.setPinCodeRequiredDuration(code); + }, ); }), ]), diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index 18379c466..b10e0d08d 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -18,7 +18,6 @@ import 'package:cw_core/node.dart'; import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/entities/action_list_display_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart'; -import 'package:cake_wallet/.secrets.g.dart' as secrets; part 'settings_store.g.dart'; @@ -169,7 +168,7 @@ abstract class SettingsStoreBase with Store { static const defaultPinLength = 4; static const defaultActionsMode = 11; - static const defaultPinCodeTimeOutDuration = 10; + static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenminutes; @observable FiatCurrency fiatCurrency; @@ -299,8 +298,10 @@ abstract class SettingsStoreBase with Store { sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode)); var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength); - final pinCodeTimeOutDuration = PinCodeRequiredDuration.deserialize(raw: sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration) - ?? defaultPinCodeTimeOutDuration); + final timeOutDuration = sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration); + final pinCodeTimeOutDuration = timeOutDuration != null + ? PinCodeRequiredDuration.deserialize(raw: timeOutDuration) + : defaultPinCodeTimeOutDuration; // If no value if (pinLength == null || pinLength == 0) { diff --git a/lib/view_model/wallet_list/wallet_list_view_model.dart b/lib/view_model/wallet_list/wallet_list_view_model.dart index 50908f24e..6d63675ba 100644 --- a/lib/view_model/wallet_list/wallet_list_view_model.dart +++ b/lib/view_model/wallet_list/wallet_list_view_model.dart @@ -15,9 +15,12 @@ part 'wallet_list_view_model.g.dart'; class WalletListViewModel = WalletListViewModelBase with _$WalletListViewModel; abstract class WalletListViewModelBase with Store { - WalletListViewModelBase(this._walletInfoSource, this._appStore, - this._walletLoadingService) - : wallets = ObservableList() { + WalletListViewModelBase( + this._walletInfoSource, + this._appStore, + this._walletLoadingService, + this._authService, + ) : wallets = ObservableList() { _updateList(); } @@ -27,6 +30,7 @@ abstract class WalletListViewModelBase with Store { final AppStore _appStore; final Box _walletInfoSource; final WalletLoadingService _walletLoadingService; + final AuthService _authService; WalletType get currentWalletType => _appStore.wallet!.type; @@ -47,16 +51,20 @@ abstract class WalletListViewModelBase with Store { void _updateList() { wallets.clear(); - wallets.addAll(_walletInfoSource.values.map((info) => WalletListItem( - name: info.name, - type: info.type, - key: info.key, - isCurrent: info.name == _appStore.wallet!.name && - info.type == _appStore.wallet!.type, - isEnabled: availableWalletTypes.contains(info.type)))); + wallets.addAll( + _walletInfoSource.values.map( + (info) => WalletListItem( + name: info.name, + type: info.type, + key: info.key, + isCurrent: info.name == _appStore.wallet!.name && info.type == _appStore.wallet!.type, + isEnabled: availableWalletTypes.contains(info.type), + ), + ), + ); } - bool checkIfAuthRequired(){ - return getIt.get().requireAuth(); + bool checkIfAuthRequired() { + return _authService.requireAuth(); } }