mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-23 03:59:23 +00:00
[CW-225] Add pin timeout setting
This commit is contained in:
parent
c67e8c5037
commit
818a8afe20
25 changed files with 250 additions and 66 deletions
|
@ -4,6 +4,8 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||||
import 'package:cake_wallet/entities/encrypt.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 {
|
class AuthService with Store {
|
||||||
AuthService({required this.secureStorage, required this.sharedPreferences});
|
AuthService({required this.secureStorage, required this.sharedPreferences});
|
||||||
|
@ -39,4 +41,26 @@ class AuthService with Store {
|
||||||
|
|
||||||
return decodedPin == pin;
|
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<SettingsStore>().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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -440,7 +440,8 @@ Future setup(
|
||||||
getIt.registerFactory(() {
|
getIt.registerFactory(() {
|
||||||
final appStore = getIt.get<AppStore>();
|
final appStore = getIt.get<AppStore>();
|
||||||
final yatStore = getIt.get<YatStore>();
|
final yatStore = getIt.get<YatStore>();
|
||||||
return SettingsViewModel(appStore.settingsStore, yatStore, appStore.wallet!);
|
final authService = getIt.get<AuthService>();
|
||||||
|
return SettingsViewModel(appStore.settingsStore, yatStore, authService, appStore.wallet!);
|
||||||
});
|
});
|
||||||
|
|
||||||
getIt
|
getIt
|
||||||
|
|
32
lib/entities/pin_code_required_duration.dart
Normal file
32
lib/entities/pin_code_required_duration.dart
Normal file
|
@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,6 +23,9 @@ class PreferencesKey {
|
||||||
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||||
static const shouldShowYatPopup = 'should_show_yat_popup';
|
static const shouldShowYatPopup = 'should_show_yat_popup';
|
||||||
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
|
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)
|
static String moneroWalletUpdateV1Key(String name)
|
||||||
=> '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
=> '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.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/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_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/screens/settings/widgets/settings_switcher_cell.dart';
|
||||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
||||||
|
@ -20,27 +22,28 @@ class SecurityBackupPage extends BasePage {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.only(top: 10),
|
padding: EdgeInsets.only(top: 10),
|
||||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||||
SettingsCellWithArrow(
|
SettingsCellWithArrow(
|
||||||
title: S.current.show_keys,
|
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) {
|
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||||
if (isAuthenticatedSuccessfully) {
|
if (isAuthenticatedSuccessfully) {
|
||||||
auth.close(route: Routes.showKeys);
|
auth.close(route: Routes.showKeys);
|
||||||
}
|
}
|
||||||
}),
|
}) : Navigator.of(context).pushNamed(Routes.showKeys),
|
||||||
),
|
),
|
||||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||||
SettingsCellWithArrow(
|
SettingsCellWithArrow(
|
||||||
title: S.current.create_backup,
|
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) {
|
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||||
if (isAuthenticatedSuccessfully) {
|
if (isAuthenticatedSuccessfully) {
|
||||||
auth.close(route: Routes.backup);
|
auth.close(route: Routes.backup);
|
||||||
}
|
}
|
||||||
}),
|
}) : Navigator.of(context).pushNamed(Routes.backup),
|
||||||
),
|
),
|
||||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||||
SettingsCellWithArrow(
|
SettingsCellWithArrow(
|
||||||
|
@ -56,7 +59,9 @@ class SecurityBackupPage extends BasePage {
|
||||||
})),
|
})),
|
||||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||||
Observer(builder: (_) {
|
Observer(builder: (_) {
|
||||||
return SettingsSwitcherCell(
|
return Column(
|
||||||
|
children: [
|
||||||
|
SettingsSwitcherCell(
|
||||||
title: S.current.settings_allow_biometrical_authentication,
|
title: S.current.settings_allow_biometrical_authentication,
|
||||||
value: settingsViewModel.allowBiometricalAuthentication,
|
value: settingsViewModel.allowBiometricalAuthentication,
|
||||||
onValueChange: (BuildContext context, bool value) {
|
onValueChange: (BuildContext context, bool value) {
|
||||||
|
@ -76,8 +81,19 @@ class SecurityBackupPage extends BasePage {
|
||||||
} else {
|
} else {
|
||||||
settingsViewModel.setAllowBiometricalAuthentication(value);
|
settingsViewModel.setAllowBiometricalAuthentication(value);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}),
|
}),
|
||||||
|
SettingsPickerCell<PinCodeRequiredDuration>(
|
||||||
|
title: S.current.require_pin_after,
|
||||||
|
items: PinCodeRequiredDuration.values,
|
||||||
|
selectedItem: settingsViewModel.pinCodeRequiredDuration,
|
||||||
|
onItemSelected: (PinCodeRequiredDuration code) {
|
||||||
|
settingsViewModel.setPinCodeRequiredDuration(code);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,6 +220,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadWallet(WalletListItem wallet) async {
|
Future<void> _loadWallet(WalletListItem wallet) async {
|
||||||
|
if(await widget.walletListViewModel.checkIfAuthRequired()){
|
||||||
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||||
if (!isAuthenticatedSuccessfully) {
|
if (!isAuthenticatedSuccessfully) {
|
||||||
|
@ -241,17 +242,36 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
.wallet_list_failed_to_load(wallet.name, e.toString()));
|
.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<void> _removeWallet(WalletListItem wallet) async {
|
Future<void> _removeWallet(WalletListItem wallet) async {
|
||||||
|
if(widget.walletListViewModel.checkIfAuthRequired()){
|
||||||
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||||
if (!isAuthenticatedSuccessfully) {
|
if (!isAuthenticatedSuccessfully) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_onSuccessfulAuth(wallet, auth);
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
_onSuccessfulAuth(wallet, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onSuccessfulAuth(WalletListItem wallet, AuthPageState? auth)async{
|
||||||
bool confirmed = false;
|
bool confirmed = false;
|
||||||
|
|
||||||
await showPopUp<void>(
|
await showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
|
@ -270,18 +290,23 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
|
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
try {
|
try {
|
||||||
|
auth != null ?
|
||||||
auth.changeProcessText(
|
auth.changeProcessText(
|
||||||
S.of(context).wallet_list_removing_wallet(wallet.name));
|
S.of(context).wallet_list_removing_wallet(wallet.name))
|
||||||
|
: changeProcessText( S.of(context).wallet_list_removing_wallet(wallet.name));
|
||||||
await widget.walletListViewModel.remove(wallet);
|
await widget.walletListViewModel.remove(wallet);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
auth.changeProcessText(S
|
auth != null ?
|
||||||
.of(context)
|
auth.changeProcessText(
|
||||||
.wallet_list_failed_to_remove(wallet.name, e.toString()));
|
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) {
|
void changeProcessText(String text) {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
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:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cake_wallet/themes/theme_base.dart';
|
import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
import 'package:cake_wallet/themes/theme_list.dart';
|
import 'package:cake_wallet/themes/theme_list.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.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:cw_core/node.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/entities/action_list_display_mode.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';
|
part 'settings_store.g.dart';
|
||||||
|
|
||||||
|
@ -39,6 +38,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
required this.shouldShowYatPopup,
|
required this.shouldShowYatPopup,
|
||||||
required this.isBitcoinBuyEnabled,
|
required this.isBitcoinBuyEnabled,
|
||||||
required this.actionlistDisplayMode,
|
required this.actionlistDisplayMode,
|
||||||
|
required this.pinTimeOutDuration,
|
||||||
TransactionPriority? initialBitcoinTransactionPriority,
|
TransactionPriority? initialBitcoinTransactionPriority,
|
||||||
TransactionPriority? initialMoneroTransactionPriority})
|
TransactionPriority? initialMoneroTransactionPriority})
|
||||||
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
||||||
|
@ -108,6 +108,11 @@ abstract class SettingsStoreBase with Store {
|
||||||
(String languageCode) => sharedPreferences.setString(
|
(String languageCode) => sharedPreferences.setString(
|
||||||
PreferencesKey.currentLanguageCode, languageCode));
|
PreferencesKey.currentLanguageCode, languageCode));
|
||||||
|
|
||||||
|
reaction(
|
||||||
|
(_) => pinTimeOutDuration,
|
||||||
|
(PinCodeRequiredDuration pinCodeInterval) => sharedPreferences.setInt(
|
||||||
|
PreferencesKey.pinTimeOutDuration, pinCodeInterval.value));
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => balanceDisplayMode,
|
(_) => balanceDisplayMode,
|
||||||
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
||||||
|
@ -124,6 +129,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
|
|
||||||
static const defaultPinLength = 4;
|
static const defaultPinLength = 4;
|
||||||
static const defaultActionsMode = 11;
|
static const defaultActionsMode = 11;
|
||||||
|
static const defaultPinCodeTimeOutDuration = 10;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
FiatCurrency fiatCurrency;
|
FiatCurrency fiatCurrency;
|
||||||
|
@ -149,6 +155,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
@observable
|
@observable
|
||||||
int pinCodeLength;
|
int pinCodeLength;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
PinCodeRequiredDuration pinTimeOutDuration;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
ThemeData get theme => currentTheme.themeData;
|
ThemeData get theme => currentTheme.themeData;
|
||||||
|
|
||||||
|
@ -227,13 +236,15 @@ abstract class SettingsStoreBase with Store {
|
||||||
: ThemeType.bright.index;
|
: ThemeType.bright.index;
|
||||||
final savedTheme = ThemeList.deserialize(
|
final savedTheme = ThemeList.deserialize(
|
||||||
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ??
|
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ??
|
||||||
legacyTheme ??
|
legacyTheme);
|
||||||
0);
|
|
||||||
final actionListDisplayMode = ObservableList<ActionListDisplayMode>();
|
final actionListDisplayMode = ObservableList<ActionListDisplayMode>();
|
||||||
actionListDisplayMode.addAll(deserializeActionlistDisplayModes(
|
actionListDisplayMode.addAll(deserializeActionlistDisplayModes(
|
||||||
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ??
|
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ??
|
||||||
defaultActionsMode));
|
defaultActionsMode));
|
||||||
var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength);
|
var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength);
|
||||||
|
final pinCodeTimeOutDuration = PinCodeRequiredDuration.deserialize(raw: sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration)
|
||||||
|
?? defaultPinCodeTimeOutDuration);
|
||||||
|
|
||||||
// If no value
|
// If no value
|
||||||
if (pinLength == null || pinLength == 0) {
|
if (pinLength == null || pinLength == 0) {
|
||||||
pinLength = defaultPinLength;
|
pinLength = defaultPinLength;
|
||||||
|
@ -287,6 +298,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
initialTheme: savedTheme,
|
initialTheme: savedTheme,
|
||||||
actionlistDisplayMode: actionListDisplayMode,
|
actionlistDisplayMode: actionListDisplayMode,
|
||||||
initialPinLength: pinLength,
|
initialPinLength: pinLength,
|
||||||
|
pinTimeOutDuration: pinCodeTimeOutDuration,
|
||||||
initialLanguageCode: savedLanguageCode,
|
initialLanguageCode: savedLanguageCode,
|
||||||
initialMoneroTransactionPriority: moneroTransactionPriority,
|
initialMoneroTransactionPriority: moneroTransactionPriority,
|
||||||
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
|
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
|
||||||
|
|
|
@ -17,7 +17,9 @@ abstract class AuthViewModelBase with Store {
|
||||||
AuthViewModelBase(this._authService, this._sharedPreferences,
|
AuthViewModelBase(this._authService, this._sharedPreferences,
|
||||||
this._settingsStore, this._biometricAuth)
|
this._settingsStore, this._biometricAuth)
|
||||||
: _failureCounter = 0,
|
: _failureCounter = 0,
|
||||||
state = InitialExecutionState();
|
state = InitialExecutionState(){
|
||||||
|
reaction((_) => state, _saveLastAuthTime);
|
||||||
|
}
|
||||||
|
|
||||||
static const maxFailedLogins = 3;
|
static const maxFailedLogins = 3;
|
||||||
static const banTimeout = 180; // 3 minutes
|
static const banTimeout = 180; // 3 minutes
|
||||||
|
@ -118,4 +120,10 @@ abstract class AuthViewModelBase with Store {
|
||||||
state = FailureState(e.toString());
|
state = FailureState(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _saveLastAuthTime(ExecutionState state){
|
||||||
|
if(state is ExecutedSuccessfullyState){
|
||||||
|
_authService.saveLastAuthTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:cake_wallet/store/yat/yat_store.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:package_info/package_info.dart';
|
import 'package:package_info/package_info.dart';
|
||||||
|
@ -41,6 +43,7 @@ abstract class SettingsViewModelBase with Store {
|
||||||
SettingsViewModelBase(
|
SettingsViewModelBase(
|
||||||
this._settingsStore,
|
this._settingsStore,
|
||||||
this._yatStore,
|
this._yatStore,
|
||||||
|
this._authService,
|
||||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
|
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
|
||||||
TransactionInfo>
|
TransactionInfo>
|
||||||
wallet)
|
wallet)
|
||||||
|
@ -94,6 +97,10 @@ abstract class SettingsViewModelBase with Store {
|
||||||
@computed
|
@computed
|
||||||
FiatCurrency get fiatCurrency => _settingsStore.fiatCurrency;
|
FiatCurrency get fiatCurrency => _settingsStore.fiatCurrency;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
PinCodeRequiredDuration get pinCodeRequiredDuration =>
|
||||||
|
_settingsStore.pinTimeOutDuration;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
String get languageCode => _settingsStore.languageCode;
|
String get languageCode => _settingsStore.languageCode;
|
||||||
|
|
||||||
|
@ -135,6 +142,7 @@ abstract class SettingsViewModelBase with Store {
|
||||||
final Map<String, String> itemHeaders;
|
final Map<String, String> itemHeaders;
|
||||||
final SettingsStore _settingsStore;
|
final SettingsStore _settingsStore;
|
||||||
final YatStore _yatStore;
|
final YatStore _yatStore;
|
||||||
|
final AuthService _authService;
|
||||||
final WalletType walletType;
|
final WalletType walletType;
|
||||||
final BiometricAuth _biometricAuth;
|
final BiometricAuth _biometricAuth;
|
||||||
final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
|
final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
|
||||||
|
@ -207,6 +215,10 @@ abstract class SettingsViewModelBase with Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setPinCodeRequiredDuration(PinCodeRequiredDuration duration) =>
|
||||||
|
_settingsStore.pinTimeOutDuration = duration;
|
||||||
|
|
||||||
String getDisplayPriority(dynamic priority) {
|
String getDisplayPriority(dynamic priority) {
|
||||||
final _priority = priority as TransactionPriority;
|
final _priority = priority as TransactionPriority;
|
||||||
|
|
||||||
|
@ -222,4 +234,6 @@ abstract class SettingsViewModelBase with Store {
|
||||||
void onDisplayPrioritySelected(TransactionPriority priority) =>
|
void onDisplayPrioritySelected(TransactionPriority priority) =>
|
||||||
_settingsStore.priority[_wallet.type] = priority;
|
_settingsStore.priority[_wallet.type] = priority;
|
||||||
|
|
||||||
|
bool checkPinCodeRiquired() => _authService.requireAuth();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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/core/wallet_loading_service.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
|
@ -55,4 +55,8 @@ abstract class WalletListViewModelBase with Store {
|
||||||
info.type == _appStore.wallet!.type,
|
info.type == _appStore.wallet!.type,
|
||||||
isEnabled: availableWalletTypes.contains(info.type))));
|
isEnabled: availableWalletTypes.contains(info.type))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool checkIfAuthRequired(){
|
||||||
|
return getIt.get<AuthService>().requireAuth();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "Datenschutzeinstellungen",
|
"privacy_settings": "Datenschutzeinstellungen",
|
||||||
"privacy": "Datenschutz",
|
"privacy": "Datenschutz",
|
||||||
"display_settings": "Anzeigeeinstellungen",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -658,5 +658,8 @@
|
||||||
"privacy_settings": "Privacy settings",
|
"privacy_settings": "Privacy settings",
|
||||||
"privacy": "Privacy",
|
"privacy": "Privacy",
|
||||||
"display_settings": "Display settings",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "Configuración de privacidad",
|
"privacy_settings": "Configuración de privacidad",
|
||||||
"privacy": "Privacidad",
|
"privacy": "Privacidad",
|
||||||
"display_settings": "Configuración de pantalla",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -653,5 +653,8 @@
|
||||||
"privacy_settings": "Paramètres de confidentialité",
|
"privacy_settings": "Paramètres de confidentialité",
|
||||||
"privacy": "Confidentialité",
|
"privacy": "Confidentialité",
|
||||||
"display_settings": "Paramètres d'affichage",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "गोपनीयता सेटिंग्स",
|
"privacy_settings": "गोपनीयता सेटिंग्स",
|
||||||
"privacy": "गोपनीयता",
|
"privacy": "गोपनीयता",
|
||||||
"display_settings": "प्रदर्शन सेटिंग्स",
|
"display_settings": "प्रदर्शन सेटिंग्स",
|
||||||
"other_settings": "अन्य सेटिंग्स"
|
"other_settings": "अन्य सेटिंग्स",
|
||||||
|
"require_pin_after": "इसके बाद पिन आवश्यक है",
|
||||||
|
"always": "हमेशा",
|
||||||
|
"minutes_to_pin_code": "${minute} मिनट"
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "Postavke privatnosti",
|
"privacy_settings": "Postavke privatnosti",
|
||||||
"privacy": "Privatnost",
|
"privacy": "Privatnost",
|
||||||
"display_settings": "Postavke zaslona",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "Impostazioni privacy",
|
"privacy_settings": "Impostazioni privacy",
|
||||||
"privacy": "Privacy",
|
"privacy": "Privacy",
|
||||||
"display_settings": "Impostazioni di visualizzazione",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "プライバシー設定",
|
"privacy_settings": "プライバシー設定",
|
||||||
"privacy": "プライバシー",
|
"privacy": "プライバシー",
|
||||||
"display_settings": "表示設定",
|
"display_settings": "表示設定",
|
||||||
"other_settings": "その他の設定"
|
"other_settings": "その他の設定",
|
||||||
|
"require_pin_after": "後に PIN が必要",
|
||||||
|
"always": "いつも",
|
||||||
|
"minutes_to_pin_code": "${minute} 分"
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "개인정보 설정",
|
"privacy_settings": "개인정보 설정",
|
||||||
"privacy": "프라이버시",
|
"privacy": "프라이버시",
|
||||||
"display_settings": "디스플레이 설정",
|
"display_settings": "디스플레이 설정",
|
||||||
"other_settings": "기타 설정"
|
"other_settings": "기타 설정",
|
||||||
|
"require_pin_after": "다음 이후에 PIN 필요",
|
||||||
|
"always": "언제나",
|
||||||
|
"minutes_to_pin_code": "${minute}분"
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "Privacy-instellingen",
|
"privacy_settings": "Privacy-instellingen",
|
||||||
"privacy": "Privacy",
|
"privacy": "Privacy",
|
||||||
"display_settings": "Weergave-instellingen",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "Ustawienia prywatności",
|
"privacy_settings": "Ustawienia prywatności",
|
||||||
"privacy": "Prywatność",
|
"privacy": "Prywatność",
|
||||||
"display_settings": "Ustawienia wyświetlania",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "Configurações de privacidade",
|
"privacy_settings": "Configurações de privacidade",
|
||||||
"privacy": "Privacidade",
|
"privacy": "Privacidade",
|
||||||
"display_settings": "Configurações de exibição",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,5 +655,8 @@
|
||||||
"privacy_settings": "Настройки конфиденциальности",
|
"privacy_settings": "Настройки конфиденциальности",
|
||||||
"privacy": "Конфиденциальность",
|
"privacy": "Конфиденциальность",
|
||||||
"display_settings": "Настройки отображения",
|
"display_settings": "Настройки отображения",
|
||||||
"other_settings": "Другие настройки"
|
"other_settings": "Другие настройки",
|
||||||
|
"require_pin_after": "Требовать ПИН после",
|
||||||
|
"always": "всегда",
|
||||||
|
"minutes_to_pin_code": "${minute} минут"
|
||||||
}
|
}
|
||||||
|
|
|
@ -654,6 +654,9 @@
|
||||||
"privacy_settings": "Налаштування конфіденційності",
|
"privacy_settings": "Налаштування конфіденційності",
|
||||||
"privacy": "Конфіденційність",
|
"privacy": "Конфіденційність",
|
||||||
"display_settings": "Налаштування дисплея",
|
"display_settings": "Налаштування дисплея",
|
||||||
"other_settings": "Інші налаштування"
|
"other_settings": "Інші налаштування",
|
||||||
|
"require_pin_after": "Вимагати PIN після",
|
||||||
|
"always": "Завжди",
|
||||||
|
"minutes_to_pin_code": "${minute} хвилин"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -653,5 +653,8 @@
|
||||||
"privacy_settings": "隐私设置",
|
"privacy_settings": "隐私设置",
|
||||||
"privacy":"隐私",
|
"privacy":"隐私",
|
||||||
"display_settings": "显示设置",
|
"display_settings": "显示设置",
|
||||||
"other_settings": "其他设置"
|
"other_settings": "其他设置",
|
||||||
|
"require_pin_after": "之后需要 PIN",
|
||||||
|
"always": "总是",
|
||||||
|
"minutes_to_pin_code": "${minute} 分钟"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue