[mob][photos] Added time delay for invalid attempts
This commit is contained in:
@@ -212,7 +212,7 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
|
||||
CryptoUtil.init();
|
||||
|
||||
_logger.info("Lockscreen init");
|
||||
LockscreenSetting.instance.init(secureStorage);
|
||||
LockscreenSetting.instance.init(secureStorage, preferences);
|
||||
|
||||
_logger.info("Configuration init");
|
||||
await Configuration.instance.init();
|
||||
|
||||
@@ -3,8 +3,8 @@ import "dart:async";
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import "package:photos/ui/settings/lockscreen/lock_screen_option_password.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lock_screen_option_pin.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lockscreen_password.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lockscreen_pin.dart";
|
||||
import 'package:photos/ui/tools/app_lock.dart';
|
||||
import 'package:photos/utils/auth_util.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
@@ -38,14 +38,16 @@ class LocalAuthenticationService {
|
||||
Future<bool> requestEnteAuthForLockScreen(
|
||||
BuildContext context,
|
||||
String? savedPin,
|
||||
String? savedPassword,
|
||||
) async {
|
||||
String? savedPassword, {
|
||||
bool isLockscreenAuth = false,
|
||||
}) async {
|
||||
if (savedPassword != null) {
|
||||
final result = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return LockScreenOptionPassword(
|
||||
return LockScreenPassword(
|
||||
isAuthenticating: true,
|
||||
isLockscreenAuth: isLockscreenAuth,
|
||||
authPass: savedPassword,
|
||||
);
|
||||
},
|
||||
@@ -59,8 +61,9 @@ class LocalAuthenticationService {
|
||||
final result = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return LockScreenOptionPin(
|
||||
return LockScreenPin(
|
||||
isAuthenticating: true,
|
||||
isLockscreenAuth: isLockscreenAuth,
|
||||
authPin: savedPin,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -7,8 +7,8 @@ import "package:photos/ui/components/menu_item_widget/menu_item_widget.dart";
|
||||
import "package:photos/ui/components/title_bar_title_widget.dart";
|
||||
import "package:photos/ui/components/title_bar_widget.dart";
|
||||
import "package:photos/ui/components/toggle_switch_widget.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lock_screen_option_password.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lock_screen_option_pin.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lockscreen_password.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lockscreen_pin.dart";
|
||||
import "package:photos/ui/tools/app_lock.dart";
|
||||
import "package:photos/utils/lockscreen_setting.dart";
|
||||
|
||||
@@ -53,7 +53,7 @@ class _LockScreenOptionState extends State<LockScreenOption> {
|
||||
final bool result = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const LockScreenOptionPin();
|
||||
return const LockScreenPin();
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -71,7 +71,7 @@ class _LockScreenOptionState extends State<LockScreenOption> {
|
||||
final bool result = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const LockScreenOptionPassword();
|
||||
return const LockScreenPassword();
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -7,20 +7,19 @@ import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
||||
import "package:photos/ui/components/text_input_widget.dart";
|
||||
import "package:photos/utils/lockscreen_setting.dart";
|
||||
|
||||
class LockScreenOptionConfirmPassword extends StatefulWidget {
|
||||
const LockScreenOptionConfirmPassword({
|
||||
class LockScreenConfirmPassword extends StatefulWidget {
|
||||
const LockScreenConfirmPassword({
|
||||
super.key,
|
||||
required this.password,
|
||||
});
|
||||
final String password;
|
||||
|
||||
@override
|
||||
State<LockScreenOptionConfirmPassword> createState() =>
|
||||
_LockScreenOptionConfirmPasswordState();
|
||||
State<LockScreenConfirmPassword> createState() =>
|
||||
_LockScreenConfirmPasswordState();
|
||||
}
|
||||
|
||||
class _LockScreenOptionConfirmPasswordState
|
||||
extends State<LockScreenOptionConfirmPassword> {
|
||||
class _LockScreenConfirmPasswordState extends State<LockScreenConfirmPassword> {
|
||||
/// _confirmPasswordController is disposed by the [TextInputWidget]
|
||||
final _confirmPasswordController = TextEditingController(text: null);
|
||||
|
||||
@@ -7,16 +7,14 @@ import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
||||
import "package:photos/utils/lockscreen_setting.dart";
|
||||
import "package:pinput/pinput.dart";
|
||||
|
||||
class LockScreenOptionConfirmPin extends StatefulWidget {
|
||||
const LockScreenOptionConfirmPin({super.key, required this.pin});
|
||||
class LockScreenConfirmPin extends StatefulWidget {
|
||||
const LockScreenConfirmPin({super.key, required this.pin});
|
||||
final String pin;
|
||||
@override
|
||||
State<LockScreenOptionConfirmPin> createState() =>
|
||||
_LockScreenOptionConfirmPinState();
|
||||
State<LockScreenConfirmPin> createState() => _LockScreenConfirmPinState();
|
||||
}
|
||||
|
||||
class _LockScreenOptionConfirmPinState
|
||||
extends State<LockScreenOptionConfirmPin> {
|
||||
class _LockScreenConfirmPinState extends State<LockScreenConfirmPin> {
|
||||
final _confirmPinController = TextEditingController(text: null);
|
||||
|
||||
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
|
||||
@@ -8,37 +8,41 @@ import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/common/dynamic_fab.dart";
|
||||
import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
||||
import "package:photos/ui/components/text_input_widget.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lock_screen_option_confirm_password.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lockscreen_confirm_password.dart";
|
||||
import "package:photos/utils/crypto_util.dart";
|
||||
import "package:photos/utils/lockscreen_setting.dart";
|
||||
|
||||
class LockScreenOptionPassword extends StatefulWidget {
|
||||
const LockScreenOptionPassword({
|
||||
class LockScreenPassword extends StatefulWidget {
|
||||
const LockScreenPassword({
|
||||
super.key,
|
||||
this.isAuthenticating = false,
|
||||
this.isLockscreenAuth = false,
|
||||
this.authPass,
|
||||
});
|
||||
|
||||
/// If [isAuthenticating] is true then we are authenticating the user
|
||||
/// If [isLockscreenAuth] is true then we are authenticating the user at Lock screen
|
||||
/// If [isAuthenticating] is true then we are authenticating the user at Setting screen
|
||||
final bool isAuthenticating;
|
||||
final bool isLockscreenAuth;
|
||||
final String? authPass;
|
||||
@override
|
||||
State<LockScreenOptionPassword> createState() =>
|
||||
_LockScreenOptionPasswordState();
|
||||
State<LockScreenPassword> createState() => _LockScreenPasswordState();
|
||||
}
|
||||
|
||||
class _LockScreenOptionPasswordState extends State<LockScreenOptionPassword> {
|
||||
class _LockScreenPasswordState extends State<LockScreenPassword> {
|
||||
/// _passwordController is disposed by the [TextInputWidget]
|
||||
final _passwordController = TextEditingController(text: null);
|
||||
final _focusNode = FocusNode();
|
||||
final _isFormValid = ValueNotifier<bool>(false);
|
||||
final _submitNotifier = ValueNotifier(false);
|
||||
int invalidAttemptsCount = 0;
|
||||
|
||||
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
|
||||
late String hashedPassword;
|
||||
late String enteredHashedPassword;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
invalidAttemptsCount = _lockscreenSetting.getInvalidAttemptCount();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
_focusNode.requestFocus();
|
||||
});
|
||||
@@ -61,11 +65,20 @@ class _LockScreenOptionPasswordState extends State<LockScreenOptionPassword> {
|
||||
"memLimit": Sodium.cryptoPwhashMemlimitInteractive,
|
||||
});
|
||||
|
||||
hashedPassword = base64Encode(hash);
|
||||
if (widget.authPass == hashedPassword) {
|
||||
enteredHashedPassword = base64Encode(hash);
|
||||
if (widget.authPass == enteredHashedPassword) {
|
||||
await _lockscreenSetting.setInvalidAttemptCount(0);
|
||||
Navigator.of(context).pop(true);
|
||||
return true;
|
||||
} else {
|
||||
if (widget.isLockscreenAuth) {
|
||||
invalidAttemptsCount++;
|
||||
if (invalidAttemptsCount > 4) {
|
||||
await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount);
|
||||
Navigator.of(context).pop(false);
|
||||
}
|
||||
}
|
||||
|
||||
await HapticFeedback.vibrate();
|
||||
throw Exception("Incorrect password");
|
||||
}
|
||||
@@ -78,7 +91,7 @@ class _LockScreenOptionPasswordState extends State<LockScreenOptionPassword> {
|
||||
} else {
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) => LockScreenOptionConfirmPassword(
|
||||
builder: (BuildContext context) => LockScreenConfirmPassword(
|
||||
password: _passwordController.text,
|
||||
),
|
||||
),
|
||||
@@ -7,31 +7,41 @@ import "package:photos/theme/colors.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/theme/text_style.dart";
|
||||
import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lock_screen_option_confirm_pin.dart";
|
||||
import "package:photos/ui/settings/lockscreen/lockscreen_confirm_pin.dart";
|
||||
import "package:photos/utils/crypto_util.dart";
|
||||
import "package:photos/utils/lockscreen_setting.dart";
|
||||
import 'package:pinput/pinput.dart';
|
||||
|
||||
class LockScreenOptionPin extends StatefulWidget {
|
||||
const LockScreenOptionPin({
|
||||
class LockScreenPin extends StatefulWidget {
|
||||
const LockScreenPin({
|
||||
super.key,
|
||||
this.isAuthenticating = false,
|
||||
this.isLockscreenAuth = false,
|
||||
this.authPin,
|
||||
});
|
||||
|
||||
/// If [isAuthenticating] is true then we are authenticating the user
|
||||
/// If [isLockscreenAuth] is true then we are authenticating the user at the Lock screen
|
||||
/// If [isAuthenticating] is true then we are authenticating the user at the Setting screen
|
||||
final bool isAuthenticating;
|
||||
final bool isLockscreenAuth;
|
||||
final String? authPin;
|
||||
@override
|
||||
State<LockScreenOptionPin> createState() => _LockScreenOptionPinState();
|
||||
State<LockScreenPin> createState() => _LockScreenPinState();
|
||||
}
|
||||
|
||||
class _LockScreenOptionPinState extends State<LockScreenOptionPin> {
|
||||
class _LockScreenPinState extends State<LockScreenPin> {
|
||||
final _pinController = TextEditingController(text: null);
|
||||
|
||||
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
|
||||
late String enteredHashedPin;
|
||||
bool isPinValid = false;
|
||||
int invalidAttemptsCount = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
invalidAttemptsCount = _lockscreenSetting.getInvalidAttemptCount();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -63,19 +73,30 @@ class _LockScreenOptionPinState extends State<LockScreenOptionPin> {
|
||||
|
||||
enteredHashedPin = base64Encode(hash);
|
||||
if (widget.authPin == enteredHashedPin) {
|
||||
invalidAttemptsCount = 0;
|
||||
await _lockscreenSetting.setInvalidAttemptCount(0);
|
||||
Navigator.of(context).pop(true);
|
||||
return true;
|
||||
} else {
|
||||
setState(() {
|
||||
isPinValid = true;
|
||||
});
|
||||
await HapticFeedback.vibrate();
|
||||
await Future.delayed(const Duration(milliseconds: 75));
|
||||
_pinController.clear();
|
||||
setState(() {
|
||||
isPinValid = false;
|
||||
});
|
||||
|
||||
if (widget.isLockscreenAuth) {
|
||||
invalidAttemptsCount++;
|
||||
if (invalidAttemptsCount > 4) {
|
||||
await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount);
|
||||
Navigator.of(context).pop(false);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
setState(() {
|
||||
isPinValid = true;
|
||||
});
|
||||
await HapticFeedback.vibrate();
|
||||
await Future.delayed(const Duration(milliseconds: 75));
|
||||
_pinController.clear();
|
||||
setState(() {
|
||||
isPinValid = false;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<void> _confirmPin(String code) async {
|
||||
@@ -85,8 +106,7 @@ class _LockScreenOptionPinState extends State<LockScreenOptionPin> {
|
||||
} else {
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) =>
|
||||
LockScreenOptionConfirmPin(pin: code),
|
||||
builder: (BuildContext context) => LockScreenConfirmPin(pin: code),
|
||||
),
|
||||
);
|
||||
_pinController.clear();
|
||||
@@ -1,4 +1,6 @@
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
import "dart:math";
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
@@ -6,6 +8,7 @@ import "package:photos/l10n/l10n.dart";
|
||||
import 'package:photos/ui/common/gradient_button.dart';
|
||||
import 'package:photos/ui/tools/app_lock.dart';
|
||||
import 'package:photos/utils/auth_util.dart';
|
||||
import "package:photos/utils/lockscreen_setting.dart";
|
||||
|
||||
class LockScreen extends StatefulWidget {
|
||||
const LockScreen({Key? key}) : super(key: key);
|
||||
@@ -20,11 +23,17 @@ class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
|
||||
bool _hasPlacedAppInBackground = false;
|
||||
bool _hasAuthenticationFailed = false;
|
||||
int? lastAuthenticatingTime;
|
||||
bool isTimerRunning = false;
|
||||
int lockedTime = 0;
|
||||
int invalidAttemptCount = 0;
|
||||
int remainingTime = 0;
|
||||
final _lockscreenSetting = LockscreenSetting.instance;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_logger.info("initiatingState");
|
||||
super.initState();
|
||||
invalidAttemptCount = _lockscreenSetting.getInvalidAttemptCount();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
if (isNonMobileIOSDevice()) {
|
||||
@@ -53,11 +62,14 @@ class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
|
||||
SizedBox(
|
||||
width: 180,
|
||||
child: GradientButton(
|
||||
text: context.l10n.unlock,
|
||||
text: isTimerRunning
|
||||
? formatTime(remainingTime)
|
||||
: context.l10n.unlock,
|
||||
iconData: Icons.lock_open_outlined,
|
||||
onTap: () async {
|
||||
// ignore: unawaited_futures
|
||||
_showLockScreen(source: "tapUnlock");
|
||||
if (!isTimerRunning) {
|
||||
await _showLockScreen(source: "tapUnlock");
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
@@ -78,32 +90,38 @@ class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
|
||||
_logger.info(state.toString());
|
||||
if (state == AppLifecycleState.resumed && !_isShowingLockScreen) {
|
||||
// This is triggered either when the lock screen is dismissed or when
|
||||
// the app is brought to foreground
|
||||
_hasPlacedAppInBackground = false;
|
||||
final bool didAuthInLast5Seconds = lastAuthenticatingTime != null &&
|
||||
DateTime.now().millisecondsSinceEpoch - lastAuthenticatingTime! <
|
||||
5000;
|
||||
|
||||
if (!_hasAuthenticationFailed && !didAuthInLast5Seconds) {
|
||||
// Show the lock screen again only if the app is resuming from the
|
||||
// background, and not when the lock screen was explicitly dismissed
|
||||
Future.delayed(
|
||||
Duration.zero,
|
||||
() => _showLockScreen(source: "lifeCycle"),
|
||||
);
|
||||
if (_lockscreenSetting.getlastInvalidAttemptTime() >
|
||||
DateTime.now().millisecondsSinceEpoch &&
|
||||
!_isShowingLockScreen) {
|
||||
final int time = (_lockscreenSetting.getlastInvalidAttemptTime() -
|
||||
DateTime.now().millisecondsSinceEpoch) ~/
|
||||
1000;
|
||||
|
||||
Future.delayed(
|
||||
Duration.zero,
|
||||
() {
|
||||
startLockTimer(time);
|
||||
_showLockScreen(source: "lifeCycle");
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_hasAuthenticationFailed = false; // Reset failure state
|
||||
_hasAuthenticationFailed = false;
|
||||
}
|
||||
} else if (state == AppLifecycleState.paused ||
|
||||
state == AppLifecycleState.inactive) {
|
||||
// This is triggered either when the lock screen pops up or when
|
||||
// the app is pushed to background
|
||||
if (!_isShowingLockScreen) {
|
||||
_hasPlacedAppInBackground = true;
|
||||
_hasAuthenticationFailed = false; // reset failure state
|
||||
_hasAuthenticationFailed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,24 +133,83 @@ class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> startLockTimer(int time) async {
|
||||
if (isTimerRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
isTimerRunning = true;
|
||||
remainingTime = time;
|
||||
});
|
||||
|
||||
while (remainingTime > 0) {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
setState(() {
|
||||
remainingTime--;
|
||||
});
|
||||
}
|
||||
|
||||
setState(() {
|
||||
isTimerRunning = false;
|
||||
});
|
||||
}
|
||||
|
||||
String formatTime(int seconds) {
|
||||
final int hours = seconds ~/ 3600;
|
||||
final int minutes = (seconds % 3600) ~/ 60;
|
||||
final int remainingSeconds = seconds % 60;
|
||||
|
||||
if (hours > 0) {
|
||||
return "$hours hr $minutes min";
|
||||
} else if (minutes > 0) {
|
||||
return "$minutes min $remainingSeconds sec";
|
||||
} else {
|
||||
return "$remainingSeconds sec";
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showLockScreen({String source = ''}) async {
|
||||
final int id = DateTime.now().millisecondsSinceEpoch;
|
||||
_logger.info("Showing lock screen $source $id");
|
||||
try {
|
||||
if (id < _lockscreenSetting.getlastInvalidAttemptTime() &&
|
||||
!_isShowingLockScreen) {
|
||||
final int time =
|
||||
(_lockscreenSetting.getlastInvalidAttemptTime() - id) ~/ 1000;
|
||||
|
||||
await startLockTimer(time);
|
||||
}
|
||||
_isShowingLockScreen = true;
|
||||
final result = await requestAuthentication(
|
||||
context,
|
||||
context.l10n.authToViewYourMemories,
|
||||
);
|
||||
final result = isTimerRunning
|
||||
? false
|
||||
: await requestAuthentication(
|
||||
context,
|
||||
context.l10n.authToViewYourMemories,
|
||||
isLockscreenAuth: true,
|
||||
);
|
||||
_logger.finest("LockScreen Result $result $id");
|
||||
_isShowingLockScreen = false;
|
||||
if (result) {
|
||||
lastAuthenticatingTime = DateTime.now().millisecondsSinceEpoch;
|
||||
AppLock.of(context)!.didUnlock();
|
||||
await _lockscreenSetting.setInvalidAttemptCount(0);
|
||||
setState(() {
|
||||
lockedTime = 15;
|
||||
isTimerRunning = false;
|
||||
});
|
||||
} else {
|
||||
if (!_hasPlacedAppInBackground) {
|
||||
// Treat this as a failure only if user did not explicitly
|
||||
// put the app in background
|
||||
if (_lockscreenSetting.getInvalidAttemptCount() > 4 &&
|
||||
invalidAttemptCount !=
|
||||
_lockscreenSetting.getInvalidAttemptCount()) {
|
||||
invalidAttemptCount = _lockscreenSetting.getInvalidAttemptCount();
|
||||
lockedTime = pow(2, invalidAttemptCount - 5).toInt() * 30;
|
||||
await _lockscreenSetting.setLastInvalidAttemptTime(
|
||||
DateTime.now().millisecondsSinceEpoch + lockedTime * 1000,
|
||||
);
|
||||
await startLockTimer(lockedTime);
|
||||
}
|
||||
_hasAuthenticationFailed = true;
|
||||
_logger.info("Authentication failed");
|
||||
}
|
||||
|
||||
@@ -7,7 +7,11 @@ import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/services/local_authentication_service.dart";
|
||||
import "package:photos/utils/lockscreen_setting.dart";
|
||||
|
||||
Future<bool> requestAuthentication(BuildContext context, String reason) async {
|
||||
Future<bool> requestAuthentication(
|
||||
BuildContext context,
|
||||
String reason, {
|
||||
bool isLockscreenAuth = false,
|
||||
}) async {
|
||||
Logger("AuthUtil").info("Requesting authentication");
|
||||
await LocalAuthentication().stopAuthentication();
|
||||
|
||||
@@ -16,7 +20,12 @@ Future<bool> requestAuthentication(BuildContext context, String reason) async {
|
||||
final String? savedPassword = await lockscreenSetting.getPassword();
|
||||
if (savedPassword != null || savedPin != null) {
|
||||
return await LocalAuthenticationService.instance
|
||||
.requestEnteAuthForLockScreen(context, savedPin, savedPassword);
|
||||
.requestEnteAuthForLockScreen(
|
||||
context,
|
||||
savedPin,
|
||||
savedPassword,
|
||||
isLockscreenAuth: isLockscreenAuth,
|
||||
);
|
||||
} else {
|
||||
return await LocalAuthentication().authenticate(
|
||||
localizedReason: reason,
|
||||
|
||||
@@ -4,6 +4,7 @@ import "package:flutter/foundation.dart";
|
||||
import "package:flutter_secure_storage/flutter_secure_storage.dart";
|
||||
import "package:flutter_sodium/flutter_sodium.dart";
|
||||
import "package:photos/utils/crypto_util.dart";
|
||||
import "package:shared_preferences/shared_preferences.dart";
|
||||
|
||||
class LockscreenSetting {
|
||||
LockscreenSetting._privateConstructor();
|
||||
@@ -13,11 +14,30 @@ class LockscreenSetting {
|
||||
static const password = "user_pass";
|
||||
static const pin = "user_pin";
|
||||
static const saltKey = "user_salt";
|
||||
|
||||
static const keyInvalidAttempts = "invalid_attempts";
|
||||
static const lastInvalidAttemptTime = "last_invalid_attempt_time";
|
||||
late FlutterSecureStorage _secureStorage;
|
||||
late SharedPreferences _preferences;
|
||||
|
||||
void init(FlutterSecureStorage secureStorage) {
|
||||
void init(FlutterSecureStorage secureStorage, SharedPreferences prefs) async {
|
||||
_secureStorage = secureStorage;
|
||||
_preferences = prefs;
|
||||
}
|
||||
|
||||
Future<void> setLastInvalidAttemptTime(int time) async {
|
||||
await _preferences.setInt(lastInvalidAttemptTime, time);
|
||||
}
|
||||
|
||||
int getlastInvalidAttemptTime() {
|
||||
return _preferences.getInt(lastInvalidAttemptTime) ?? 0;
|
||||
}
|
||||
|
||||
int getInvalidAttemptCount() {
|
||||
return _preferences.getInt(keyInvalidAttempts) ?? 0;
|
||||
}
|
||||
|
||||
Future<void> setInvalidAttemptCount(int count) async {
|
||||
await _preferences.setInt(keyInvalidAttempts, count);
|
||||
}
|
||||
|
||||
static Uint8List generateSalt() {
|
||||
|
||||
Reference in New Issue
Block a user