mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-03-12 09:27:01 +00:00
prevent submit button activation when autopin is on and being checked and do not fetch pin from sec store unless min pin length met
This commit is contained in:
parent
816eb37477
commit
50bd3e52a3
3 changed files with 149 additions and 129 deletions
|
@ -12,6 +12,7 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
|
||||
import '../../notifications/show_flush_bar.dart';
|
||||
// import 'package:stackwallet/providers/global/has_authenticated_start_state_provider.dart';
|
||||
|
@ -70,6 +71,7 @@ class LockscreenView extends ConsumerStatefulWidget {
|
|||
|
||||
class _LockscreenViewState extends ConsumerState<LockscreenView> {
|
||||
late final ShakeController _shakeController;
|
||||
late final bool _autoPin;
|
||||
|
||||
late int _attempts;
|
||||
bool _attemptLock = false;
|
||||
|
@ -186,16 +188,18 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
|
|||
biometrics = widget.biometrics;
|
||||
_attempts = 0;
|
||||
_timeout = Duration.zero;
|
||||
|
||||
_autoPin = ref.read(prefsChangeNotifierProvider).autoPin;
|
||||
if (_autoPin) {
|
||||
_pinTextController.addListener(_onPinChangedAutologinCheck);
|
||||
}
|
||||
_checkUseBiometrics();
|
||||
_pinTextController.addListener(_onPinChanged);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
dispose() {
|
||||
// _shakeController.dispose();
|
||||
_pinTextController.removeListener(_onPinChanged);
|
||||
_pinTextController.removeListener(_onPinChangedAutologinCheck);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -218,16 +222,120 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
|
|||
|
||||
final _pinTextController = TextEditingController();
|
||||
|
||||
void _onPinChanged() async {
|
||||
String enteredPin = _pinTextController.text;
|
||||
final storedPin = await _secureStore.read(key: 'stack_pin');
|
||||
final autoPin = ref.read(prefsChangeNotifierProvider).autoPin;
|
||||
final Mutex _autoPinCheckLock = Mutex();
|
||||
void _onPinChangedAutologinCheck() async {
|
||||
if (mounted) {
|
||||
await _autoPinCheckLock.acquire();
|
||||
}
|
||||
|
||||
if (enteredPin.length >= 4 && autoPin && enteredPin == storedPin) {
|
||||
try {
|
||||
if (_autoPin && _pinTextController.text.length >= 4) {
|
||||
final storedPin = await _secureStore.read(key: 'stack_pin');
|
||||
if (_pinTextController.text == storedPin) {
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 200),
|
||||
);
|
||||
unawaited(_onUnlock());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
_autoPinCheckLock.release();
|
||||
}
|
||||
}
|
||||
|
||||
void _onSubmitPin(String pin) async {
|
||||
_attempts++;
|
||||
|
||||
if (_attempts > maxAttemptsBeforeThrottling) {
|
||||
_attemptLock = true;
|
||||
switch (_attempts) {
|
||||
case 4:
|
||||
_timeout = const Duration(seconds: 30);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
_timeout = const Duration(seconds: 60);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
_timeout = const Duration(minutes: 5);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
_timeout = const Duration(minutes: 10);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
_timeout = const Duration(minutes: 20);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
_timeout = const Duration(minutes: 30);
|
||||
break;
|
||||
|
||||
default:
|
||||
_timeout = const Duration(minutes: 60);
|
||||
}
|
||||
|
||||
_timer?.cancel();
|
||||
_timer = Timer(_timeout, () {
|
||||
_attemptLock = false;
|
||||
_attempts = 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (_attemptLock) {
|
||||
String prettyTime = "";
|
||||
if (_timeout.inSeconds >= 60) {
|
||||
prettyTime += "${_timeout.inMinutes} minutes";
|
||||
} else {
|
||||
prettyTime += "${_timeout.inSeconds} seconds";
|
||||
}
|
||||
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message:
|
||||
"Incorrect PIN entered too many times. Please wait $prettyTime",
|
||||
context: context,
|
||||
iconAsset: Assets.svg.alertCircle,
|
||||
),
|
||||
);
|
||||
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
);
|
||||
|
||||
_pinTextController.text = '';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final storedPin = await _secureStore.read(key: 'stack_pin');
|
||||
|
||||
if (storedPin == pin) {
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 200),
|
||||
);
|
||||
unawaited(_onUnlock());
|
||||
} else {
|
||||
unawaited(_shakeController.shake());
|
||||
if (mounted) {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Incorrect PIN. Please try again",
|
||||
context: context,
|
||||
iconAsset: Assets.svg.alertCircle,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
);
|
||||
|
||||
_pinTextController.text = '';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,98 +437,9 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
|
|||
isRandom: ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.randomizePIN,
|
||||
onSubmit: (String pin) async {
|
||||
_attempts++;
|
||||
|
||||
if (_attempts > maxAttemptsBeforeThrottling) {
|
||||
_attemptLock = true;
|
||||
switch (_attempts) {
|
||||
case 4:
|
||||
_timeout = const Duration(seconds: 30);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
_timeout = const Duration(seconds: 60);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
_timeout = const Duration(minutes: 5);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
_timeout = const Duration(minutes: 10);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
_timeout = const Duration(minutes: 20);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
_timeout = const Duration(minutes: 30);
|
||||
break;
|
||||
|
||||
default:
|
||||
_timeout = const Duration(minutes: 60);
|
||||
}
|
||||
|
||||
_timer?.cancel();
|
||||
_timer = Timer(_timeout, () {
|
||||
_attemptLock = false;
|
||||
_attempts = 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (_attemptLock) {
|
||||
String prettyTime = "";
|
||||
if (_timeout.inSeconds >= 60) {
|
||||
prettyTime += "${_timeout.inMinutes} minutes";
|
||||
} else {
|
||||
prettyTime += "${_timeout.inSeconds} seconds";
|
||||
}
|
||||
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message:
|
||||
"Incorrect PIN entered too many times. Please wait $prettyTime",
|
||||
context: context,
|
||||
iconAsset: Assets.svg.alertCircle,
|
||||
),
|
||||
);
|
||||
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
);
|
||||
|
||||
_pinTextController.text = '';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final storedPin =
|
||||
await _secureStore.read(key: 'stack_pin');
|
||||
|
||||
if (storedPin == pin) {
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 200),
|
||||
);
|
||||
unawaited(_onUnlock());
|
||||
} else {
|
||||
unawaited(_shakeController.shake());
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Incorrect PIN. Please try again",
|
||||
context: context,
|
||||
iconAsset: Assets.svg.alertCircle,
|
||||
),
|
||||
);
|
||||
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
);
|
||||
|
||||
_pinTextController.text = '';
|
||||
onSubmit: (pin) {
|
||||
if (!_autoPinCheckLock.isLocked) {
|
||||
_onSubmitPin(pin);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
|
||||
import '../../notifications/show_flush_bar.dart';
|
||||
import '../../providers/global/prefs_provider.dart';
|
||||
|
@ -38,6 +39,8 @@ class PinpadDialog extends ConsumerStatefulWidget {
|
|||
class _PinpadDialogState extends ConsumerState<PinpadDialog> {
|
||||
late final ShakeController _shakeController;
|
||||
|
||||
late final bool _autoPin;
|
||||
|
||||
late int _attempts;
|
||||
bool _attemptLock = false;
|
||||
late Duration _timeout;
|
||||
|
@ -63,16 +66,24 @@ class _PinpadDialogState extends ConsumerState<PinpadDialog> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> _onPinChanged() async {
|
||||
final enteredPin = _pinTextController.text;
|
||||
final storedPin = await _secureStore.read(key: 'stack_pin');
|
||||
final autoPin = ref.read(prefsChangeNotifierProvider).autoPin;
|
||||
final Mutex _autoPinCheckLock = Mutex();
|
||||
void _onPinChangedAutologinCheck() async {
|
||||
if (mounted) {
|
||||
await _autoPinCheckLock.acquire();
|
||||
}
|
||||
|
||||
if (enteredPin.length >= 4 && autoPin && enteredPin == storedPin) {
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 200),
|
||||
);
|
||||
unawaited(_onUnlock());
|
||||
try {
|
||||
if (_autoPin && _pinTextController.text.length >= 4) {
|
||||
final storedPin = await _secureStore.read(key: 'stack_pin');
|
||||
if (_pinTextController.text == storedPin) {
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 200),
|
||||
);
|
||||
unawaited(_onUnlock());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
_autoPinCheckLock.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,16 +226,19 @@ class _PinpadDialogState extends ConsumerState<PinpadDialog> {
|
|||
biometrics = widget.biometrics;
|
||||
_attempts = 0;
|
||||
_timeout = Duration.zero;
|
||||
_autoPin = ref.read(prefsChangeNotifierProvider).autoPin;
|
||||
if (_autoPin) {
|
||||
_pinTextController.addListener(_onPinChangedAutologinCheck);
|
||||
}
|
||||
|
||||
_checkUseBiometrics();
|
||||
_pinTextController.addListener(_onPinChanged);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
dispose() {
|
||||
// _shakeController.dispose();
|
||||
_pinTextController.removeListener(_onPinChanged);
|
||||
_pinTextController.removeListener(_onPinChangedAutologinCheck);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -276,7 +290,11 @@ class _PinpadDialogState extends ConsumerState<PinpadDialog> {
|
|||
submittedFieldDecoration: _pinPutDecoration,
|
||||
isRandom:
|
||||
ref.read(prefsChangeNotifierProvider).randomizePIN,
|
||||
onSubmit: _onSubmit,
|
||||
onSubmit: (pin) {
|
||||
if (!_autoPinCheckLock.isLocked) {
|
||||
_onSubmit(pin);
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 32,
|
||||
|
|
|
@ -61,12 +61,9 @@ class _ChangePinViewState extends ConsumerState<ChangePinView> {
|
|||
|
||||
int pinCount = 1;
|
||||
|
||||
final TextEditingController _pinTextController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_secureStore = ref.read(secureStoreProvider);
|
||||
_pinTextController.addListener(_onPinChanged);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -77,23 +74,9 @@ class _ChangePinViewState extends ConsumerState<ChangePinView> {
|
|||
_pinPutController2.dispose();
|
||||
_pinPutFocusNode1.dispose();
|
||||
_pinPutFocusNode2.dispose();
|
||||
_pinTextController.removeListener(_onPinChanged);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onPinChanged() async {
|
||||
String enteredPin = _pinTextController.text;
|
||||
final storedPin = await _secureStore.read(key: 'stack_pin');
|
||||
final autoPin = ref.read(prefsChangeNotifierProvider).autoPin;
|
||||
|
||||
if (enteredPin.length >= 4 && autoPin && enteredPin == storedPin) {
|
||||
await _pageController.nextPage(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.linear,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Background(
|
||||
|
|
Loading…
Reference in a new issue