[mob][auth] Implemented Pin/Password hashing using ente_crypto
This commit is contained in:
14
auth/lib/events/app_lock_update_event.dart
Normal file
14
auth/lib/events/app_lock_update_event.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import "package:ente_auth/events/event.dart";
|
||||
|
||||
enum AppLockUpdateType {
|
||||
none,
|
||||
device,
|
||||
pin,
|
||||
password,
|
||||
}
|
||||
|
||||
class AppLockUpdateEvent extends Event {
|
||||
final AppLockUpdateType type;
|
||||
|
||||
AppLockUpdateEvent(this.type);
|
||||
}
|
||||
@@ -25,7 +25,11 @@ class LocalAuthenticationService {
|
||||
) async {
|
||||
if (await _isLocalAuthSupportedOnDevice()) {
|
||||
AppLock.of(context)!.setEnabled(false);
|
||||
final result = await requestAuthentication(context, infoMessage);
|
||||
final result = await requestAuthentication(
|
||||
context,
|
||||
infoMessage,
|
||||
isAuthenticatingForInAppChange: true,
|
||||
);
|
||||
AppLock.of(context)!.setEnabled(
|
||||
await Configuration.instance.shouldShowLockScreen(),
|
||||
);
|
||||
@@ -43,15 +47,17 @@ class LocalAuthenticationService {
|
||||
BuildContext context,
|
||||
String? savedPin,
|
||||
String? savedPassword, {
|
||||
bool isOnOpeningApp = false,
|
||||
bool isAuthenticatingOnAppLaunch = false,
|
||||
bool isAuthenticatingForInAppChange = false,
|
||||
}) async {
|
||||
if (savedPassword != null) {
|
||||
final result = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return LockScreenPassword(
|
||||
isAuthenticating: true,
|
||||
isOnOpeningApp: isOnOpeningApp,
|
||||
isChangingLockScreenSettings: true,
|
||||
isAuthenticatingForInAppChange: isAuthenticatingForInAppChange,
|
||||
isAuthenticatingOnAppLaunch: isAuthenticatingOnAppLaunch,
|
||||
authPass: savedPassword,
|
||||
);
|
||||
},
|
||||
@@ -66,8 +72,9 @@ class LocalAuthenticationService {
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return LockScreenPin(
|
||||
isAuthenticating: true,
|
||||
isOnOpeningApp: isOnOpeningApp,
|
||||
isChangingLockScreenSettings: true,
|
||||
isAuthenticatingForInAppChange: isAuthenticatingForInAppChange,
|
||||
isAuthenticatingOnAppLaunch: isAuthenticatingOnAppLaunch,
|
||||
authPin: savedPin,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -10,7 +10,6 @@ class CustomPinKeypad extends StatelessWidget {
|
||||
return SafeArea(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(2),
|
||||
// color: getEnteColorScheme(context).strokeFainter,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
|
||||
@@ -71,22 +71,13 @@ class _LockScreenConfirmPinState extends State<LockScreenConfirmPin> {
|
||||
),
|
||||
floatingActionButton: CustomPinKeypad(controller: _confirmPinController),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||
// body: OrientationBuilder(
|
||||
// builder: (context, orientation) {
|
||||
// return orientation == Orientation.portrait
|
||||
// ? _getBody(colorTheme, textTheme, isPortrait: true)
|
||||
// : SingleChildScrollView(
|
||||
// child: _getBody(colorTheme, textTheme, isPortrait: false),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
body: SingleChildScrollView(
|
||||
child: _getBody(colorTheme, textTheme, isPortrait: true),
|
||||
child: _getBody(colorTheme, textTheme),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getBody(colorTheme, textTheme, {required bool isPortrait}) {
|
||||
Widget _getBody(colorTheme, textTheme) {
|
||||
return Center(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
@@ -200,10 +191,6 @@ class _LockScreenConfirmPinState extends State<LockScreenConfirmPin> {
|
||||
await _confirmPinMatch();
|
||||
},
|
||||
),
|
||||
// isPortrait
|
||||
// ? const Spacer()
|
||||
// : const Padding(padding: EdgeInsets.all(12)),
|
||||
// CustomPinKeypad(controller: _confirmPinController),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import "dart:async";
|
||||
|
||||
import "package:ente_auth/core/configuration.dart";
|
||||
import "package:ente_auth/core/event_bus.dart";
|
||||
import "package:ente_auth/events/app_lock_update_event.dart";
|
||||
import "package:ente_auth/theme/ente_theme.dart";
|
||||
import "package:ente_auth/ui/components/captioned_text_widget.dart";
|
||||
import "package:ente_auth/ui/components/divider_widget.dart";
|
||||
@@ -29,15 +31,11 @@ class _LockScreenOptionsState extends State<LockScreenOptions> {
|
||||
late bool appLock;
|
||||
bool isPinEnabled = false;
|
||||
bool isPasswordEnabled = false;
|
||||
late String autoLockTime;
|
||||
late int autoLockTimeInMilliseconds;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
autoLockTime = _formatTime(
|
||||
Duration(
|
||||
milliseconds: _lockscreenSetting.getAutoLockTime(),
|
||||
),
|
||||
);
|
||||
autoLockTimeInMilliseconds = _lockscreenSetting.getAutoLockTime();
|
||||
_initializeSettings();
|
||||
appLock = isPinEnabled ||
|
||||
isPasswordEnabled ||
|
||||
@@ -56,6 +54,12 @@ class _LockScreenOptionsState extends State<LockScreenOptions> {
|
||||
Future<void> _deviceLock() async {
|
||||
await _lockscreenSetting.removePinAndPassword();
|
||||
await _initializeSettings();
|
||||
await _lockscreenSetting.setAppLockType("Device lock");
|
||||
Bus.instance.fire(
|
||||
AppLockUpdateEvent(
|
||||
AppLockUpdateType.device,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _pinLock() async {
|
||||
@@ -69,6 +73,12 @@ class _LockScreenOptionsState extends State<LockScreenOptions> {
|
||||
setState(() {
|
||||
_initializeSettings();
|
||||
if (result) {
|
||||
Bus.instance.fire(
|
||||
AppLockUpdateEvent(
|
||||
AppLockUpdateType.pin,
|
||||
),
|
||||
);
|
||||
_lockscreenSetting.setAppLockType("Pin");
|
||||
appLock = isPinEnabled ||
|
||||
isPasswordEnabled ||
|
||||
_configuration.shouldShowSystemLockScreen();
|
||||
@@ -87,6 +97,12 @@ class _LockScreenOptionsState extends State<LockScreenOptions> {
|
||||
setState(() {
|
||||
_initializeSettings();
|
||||
if (result) {
|
||||
Bus.instance.fire(
|
||||
AppLockUpdateEvent(
|
||||
AppLockUpdateType.password,
|
||||
),
|
||||
);
|
||||
_lockscreenSetting.setAppLockType("Password");
|
||||
appLock = isPinEnabled ||
|
||||
isPasswordEnabled ||
|
||||
_configuration.shouldShowSystemLockScreen();
|
||||
@@ -98,6 +114,12 @@ class _LockScreenOptionsState extends State<LockScreenOptions> {
|
||||
AppLock.of(context)!.setEnabled(!appLock);
|
||||
await _configuration.setSystemLockScreen(!appLock);
|
||||
await _lockscreenSetting.removePinAndPassword();
|
||||
await _lockscreenSetting.setAppLockType(appLock ? "None" : "Device lock");
|
||||
Bus.instance.fire(
|
||||
AppLockUpdateEvent(
|
||||
appLock ? AppLockUpdateType.none : AppLockUpdateType.device,
|
||||
),
|
||||
);
|
||||
setState(() {
|
||||
_initializeSettings();
|
||||
appLock = !appLock;
|
||||
@@ -111,11 +133,7 @@ class _LockScreenOptionsState extends State<LockScreenOptions> {
|
||||
).then(
|
||||
(value) {
|
||||
setState(() {
|
||||
autoLockTime = _formatTime(
|
||||
Duration(
|
||||
milliseconds: _lockscreenSetting.getAutoLockTime(),
|
||||
),
|
||||
);
|
||||
autoLockTimeInMilliseconds = _lockscreenSetting.getAutoLockTime();
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -123,11 +141,11 @@ class _LockScreenOptionsState extends State<LockScreenOptions> {
|
||||
|
||||
String _formatTime(Duration duration) {
|
||||
if (duration.inHours != 0) {
|
||||
return "${duration.inHours}hr";
|
||||
return "in ${duration.inHours} hour${duration.inHours > 1 ? 's' : ''}";
|
||||
} else if (duration.inMinutes != 0) {
|
||||
return "${duration.inMinutes}m";
|
||||
return "in ${duration.inMinutes} minute${duration.inMinutes > 1 ? 's' : ''}";
|
||||
} else if (duration.inSeconds != 0) {
|
||||
return "${duration.inSeconds}s";
|
||||
return "in ${duration.inSeconds} second${duration.inSeconds > 1 ? 's' : ''}";
|
||||
} else {
|
||||
return "Disable";
|
||||
}
|
||||
@@ -191,6 +209,7 @@ class _LockScreenOptionsState extends State<LockScreenOptions> {
|
||||
),
|
||||
appLock
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MenuItemWidget(
|
||||
captionedTextWidget:
|
||||
@@ -249,14 +268,32 @@ class _LockScreenOptionsState extends State<LockScreenOptions> {
|
||||
),
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: "Auto-lock",
|
||||
subTitle: autoLockTime,
|
||||
title: "Auto lock",
|
||||
subTitle: _formatTime(
|
||||
Duration(
|
||||
milliseconds:
|
||||
autoLockTimeInMilliseconds,
|
||||
),
|
||||
),
|
||||
),
|
||||
singleBorderRadius: 8,
|
||||
alignCaptionedTextToLeft: true,
|
||||
singleBorderRadius: 8,
|
||||
menuItemColor: colorTheme.fillFaint,
|
||||
trailingIconColor: colorTheme.textBase,
|
||||
onTap: () => _onAutoLock(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 14,
|
||||
left: 14,
|
||||
right: 12,
|
||||
),
|
||||
child: Text(
|
||||
"Require ${_lockscreenSetting.getAppLockType()} if away for some time .",
|
||||
style: textTheme.miniFaint,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Container(),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import "dart:convert";
|
||||
|
||||
import "package:ente_auth/theme/ente_theme.dart";
|
||||
import "package:ente_auth/ui/common/dynamic_fab.dart";
|
||||
import "package:ente_auth/ui/components/buttons/icon_button_widget.dart";
|
||||
@@ -5,20 +7,32 @@ import "package:ente_auth/ui/components/text_input_widget.dart";
|
||||
import "package:ente_auth/ui/settings/lock_screen/lock_screen_confirm_password.dart";
|
||||
import "package:ente_auth/ui/settings/lock_screen/lock_screen_options.dart";
|
||||
import "package:ente_auth/utils/lock_screen_settings.dart";
|
||||
import "package:ente_crypto_dart/ente_crypto_dart.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter/services.dart";
|
||||
|
||||
/// [isChangingLockScreenSettings] Authentication required for changing lock screen settings.
|
||||
/// Set to true when the app requires the user to authenticate before allowing
|
||||
/// changes to the lock screen settings.
|
||||
|
||||
/// [isAuthenticatingOnAppLaunch] Authentication required on app launch.
|
||||
/// Set to true when the app requires the user to authenticate immediately upon opening.
|
||||
|
||||
/// [isAuthenticatingForInAppChange] Authentication required for in-app changes (e.g., email, password).
|
||||
/// Set to true when the app requires the to authenticate for sensitive actions like email, password changes.
|
||||
|
||||
class LockScreenPassword extends StatefulWidget {
|
||||
const LockScreenPassword({
|
||||
super.key,
|
||||
this.isAuthenticating = false,
|
||||
this.isOnOpeningApp = false,
|
||||
this.isChangingLockScreenSettings = false,
|
||||
this.isAuthenticatingOnAppLaunch = false,
|
||||
this.isAuthenticatingForInAppChange = false,
|
||||
this.authPass,
|
||||
});
|
||||
|
||||
//Is false when setting a new password
|
||||
final bool isAuthenticating;
|
||||
final bool isOnOpeningApp;
|
||||
final bool isChangingLockScreenSettings;
|
||||
final bool isAuthenticatingOnAppLaunch;
|
||||
final bool isAuthenticatingForInAppChange;
|
||||
final String? authPass;
|
||||
@override
|
||||
State<LockScreenPassword> createState() => _LockScreenPasswordState();
|
||||
@@ -149,7 +163,9 @@ class _LockScreenPasswordState extends State<LockScreenPassword> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
widget.isAuthenticating ? "Enter Password" : "Set new Password",
|
||||
widget.isChangingLockScreenSettings
|
||||
? "Enter Password"
|
||||
: "Set new Password",
|
||||
textAlign: TextAlign.center,
|
||||
style: textTheme.bodyBold,
|
||||
),
|
||||
@@ -181,17 +197,19 @@ class _LockScreenPasswordState extends State<LockScreenPassword> {
|
||||
}
|
||||
|
||||
Future<bool> _confirmPasswordAuth(String inputtedPassword) async {
|
||||
// final Uint8List? salt = await _lockscreenSetting.getSalt();
|
||||
// final hash = cryptoPwHash({
|
||||
// "password": utf8.encode(inputtedPassword),
|
||||
// "salt": salt,
|
||||
// "opsLimit": Sodium.cryptoPwhashOpslimitInteractive,
|
||||
// "memLimit": Sodium.cryptoPwhashMemlimitInteractive,
|
||||
// });
|
||||
if (widget.authPass == inputtedPassword) {
|
||||
final Uint8List? salt = await _lockscreenSetting.getSalt();
|
||||
final hash = cryptoPwHash(
|
||||
utf8.encode(inputtedPassword),
|
||||
salt!,
|
||||
sodium.crypto.pwhash.memLimitSensitive,
|
||||
sodium.crypto.pwhash.opsLimitSensitive,
|
||||
sodium,
|
||||
);
|
||||
if (widget.authPass == base64Encode(hash)) {
|
||||
await _lockscreenSetting.setInvalidAttemptCount(0);
|
||||
|
||||
widget.isOnOpeningApp
|
||||
widget.isAuthenticatingOnAppLaunch ||
|
||||
widget.isAuthenticatingForInAppChange
|
||||
? Navigator.of(context).pop(true)
|
||||
: Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
@@ -200,7 +218,7 @@ class _LockScreenPasswordState extends State<LockScreenPassword> {
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
if (widget.isOnOpeningApp) {
|
||||
if (widget.isAuthenticatingOnAppLaunch) {
|
||||
invalidAttemptsCount++;
|
||||
await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount);
|
||||
if (invalidAttemptsCount > 4) {
|
||||
@@ -214,7 +232,7 @@ class _LockScreenPasswordState extends State<LockScreenPassword> {
|
||||
}
|
||||
|
||||
Future<void> _confirmPassword() async {
|
||||
if (widget.isAuthenticating) {
|
||||
if (widget.isChangingLockScreenSettings) {
|
||||
await _confirmPasswordAuth(_passwordController.text);
|
||||
return;
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import "dart:convert";
|
||||
|
||||
import "package:ente_auth/theme/colors.dart";
|
||||
import "package:ente_auth/theme/ente_theme.dart";
|
||||
import "package:ente_auth/theme/text_style.dart";
|
||||
@@ -5,21 +7,33 @@ import "package:ente_auth/ui/settings/lock_screen/custom_pin_keypad.dart";
|
||||
import "package:ente_auth/ui/settings/lock_screen/lock_screen_confirm_pin.dart";
|
||||
import "package:ente_auth/ui/settings/lock_screen/lock_screen_options.dart";
|
||||
import "package:ente_auth/utils/lock_screen_settings.dart";
|
||||
import "package:ente_crypto_dart/ente_crypto_dart.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter/services.dart";
|
||||
import 'package:pinput/pinput.dart';
|
||||
|
||||
/// [isChangingLockScreenSettings] Authentication required for changing lock screen settings.
|
||||
/// Set to true when the app requires the user to authenticate before allowing
|
||||
/// changes to the lock screen settings.
|
||||
|
||||
/// [isAuthenticatingOnAppLaunch] Authentication required on app launch.
|
||||
/// Set to true when the app requires the user to authenticate immediately upon opening.
|
||||
|
||||
/// [isAuthenticatingForInAppChange] Authentication required for in-app changes (e.g., email, password).
|
||||
/// Set to true when the app requires the to authenticate for sensitive actions like email, password changes.
|
||||
|
||||
class LockScreenPin extends StatefulWidget {
|
||||
const LockScreenPin({
|
||||
super.key,
|
||||
this.isAuthenticating = false,
|
||||
this.isOnOpeningApp = false,
|
||||
this.isChangingLockScreenSettings = false,
|
||||
this.isAuthenticatingOnAppLaunch = false,
|
||||
this.isAuthenticatingForInAppChange = false,
|
||||
this.authPin,
|
||||
});
|
||||
|
||||
//Is false when setting a new password
|
||||
final bool isAuthenticating;
|
||||
final bool isOnOpeningApp;
|
||||
final bool isAuthenticatingOnAppLaunch;
|
||||
final bool isChangingLockScreenSettings;
|
||||
final bool isAuthenticatingForInAppChange;
|
||||
final String? authPin;
|
||||
@override
|
||||
State<LockScreenPin> createState() => _LockScreenPinState();
|
||||
@@ -45,18 +59,19 @@ class _LockScreenPinState extends State<LockScreenPin> {
|
||||
}
|
||||
|
||||
Future<bool> confirmPinAuth(String inputtedPin) async {
|
||||
// final Uint8List? salt = await _lockscreenSetting.getSalt();
|
||||
// final hash = cryptoPwHash({
|
||||
// "password": utf8.encode(code),
|
||||
// "salt": salt,
|
||||
// "opsLimit": Sodium.cryptoPwhashOpslimitInteractive,
|
||||
// "memLimit": Sodium.cryptoPwhashMemlimitInteractive,
|
||||
// });
|
||||
// final String hashedPin = base64Encode(hash);
|
||||
if (widget.authPin == inputtedPin) {
|
||||
final Uint8List? salt = await _lockscreenSetting.getSalt();
|
||||
final hash = cryptoPwHash(
|
||||
utf8.encode(inputtedPin),
|
||||
salt!,
|
||||
sodium.crypto.pwhash.memLimitSensitive,
|
||||
sodium.crypto.pwhash.opsLimitSensitive,
|
||||
sodium,
|
||||
);
|
||||
if (widget.authPin == base64Encode(hash)) {
|
||||
invalidAttemptsCount = 0;
|
||||
await _lockscreenSetting.setInvalidAttemptCount(0);
|
||||
widget.isOnOpeningApp
|
||||
widget.isAuthenticatingOnAppLaunch ||
|
||||
widget.isAuthenticatingForInAppChange
|
||||
? Navigator.of(context).pop(true)
|
||||
: Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
@@ -75,7 +90,7 @@ class _LockScreenPinState extends State<LockScreenPin> {
|
||||
isPinValid = false;
|
||||
});
|
||||
|
||||
if (widget.isOnOpeningApp) {
|
||||
if (widget.isAuthenticatingOnAppLaunch) {
|
||||
invalidAttemptsCount++;
|
||||
await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount);
|
||||
if (invalidAttemptsCount > 4) {
|
||||
@@ -87,7 +102,7 @@ class _LockScreenPinState extends State<LockScreenPin> {
|
||||
}
|
||||
|
||||
Future<void> _confirmPin(String inputtedPin) async {
|
||||
if (widget.isAuthenticating) {
|
||||
if (widget.isChangingLockScreenSettings) {
|
||||
await confirmPinAuth(inputtedPin);
|
||||
return;
|
||||
} else {
|
||||
@@ -130,26 +145,16 @@ class _LockScreenPinState extends State<LockScreenPin> {
|
||||
),
|
||||
floatingActionButton: CustomPinKeypad(controller: _pinController),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||
// body: OrientationBuilder(
|
||||
// builder: (context, orientation) {
|
||||
// return orientation == Orientation.portrait
|
||||
// ? _getBody(colorTheme, textTheme, isPortrait: true)
|
||||
// : SingleChildScrollView(
|
||||
// child: _getBody(colorTheme, textTheme, isPortrait: false),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
body: SingleChildScrollView(
|
||||
child: _getBody(colorTheme, textTheme, isPortrait: true),
|
||||
child: _getBody(colorTheme, textTheme),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getBody(
|
||||
EnteColorScheme colorTheme,
|
||||
EnteTextTheme textTheme, {
|
||||
required bool isPortrait,
|
||||
}) {
|
||||
EnteTextTheme textTheme,
|
||||
) {
|
||||
return Center(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
@@ -219,7 +224,7 @@ class _LockScreenPinState extends State<LockScreenPin> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
widget.isAuthenticating ? "Enter PIN" : "Set new PIN",
|
||||
widget.isChangingLockScreenSettings ? "Enter PIN" : "Set new PIN",
|
||||
style: textTheme.bodyBold,
|
||||
),
|
||||
const Padding(padding: EdgeInsets.all(12)),
|
||||
@@ -263,10 +268,6 @@ class _LockScreenPinState extends State<LockScreenPin> {
|
||||
await _confirmPin(_pinController.text);
|
||||
},
|
||||
),
|
||||
// isPortrait
|
||||
// ? const Spacer()
|
||||
// : const Padding(padding: EdgeInsets.all(12)),
|
||||
// CustomPinKeypad(controller: _pinController),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -2,6 +2,8 @@ import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:ente_auth/core/configuration.dart';
|
||||
import 'package:ente_auth/core/event_bus.dart';
|
||||
import 'package:ente_auth/events/app_lock_update_event.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/models/user_details.dart';
|
||||
import 'package:ente_auth/services/local_authentication_service.dart';
|
||||
@@ -18,6 +20,7 @@ import 'package:ente_auth/ui/settings/common_settings.dart';
|
||||
import 'package:ente_auth/ui/settings/lock_screen/lock_screen_options.dart';
|
||||
import 'package:ente_auth/utils/auth_util.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/lock_screen_settings.dart';
|
||||
import 'package:ente_auth/utils/navigation_util.dart';
|
||||
import 'package:ente_auth/utils/platform_util.dart';
|
||||
import 'package:ente_auth/utils/toast_util.dart';
|
||||
@@ -37,15 +40,25 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
|
||||
final _config = Configuration.instance;
|
||||
late bool _hasLoggedIn;
|
||||
final Logger _logger = Logger('SecuritySectionWidget');
|
||||
|
||||
late String appLockSubtitle;
|
||||
late StreamSubscription<AppLockUpdateEvent> _appLockUpdateEvent;
|
||||
@override
|
||||
void initState() {
|
||||
_hasLoggedIn = _config.hasConfiguredAccount();
|
||||
appLockSubtitle = LockScreenSettings.instance.getAppLockType();
|
||||
_appLockUpdateEvent = Bus.instance.on<AppLockUpdateEvent>().listen((event) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
appLockSubtitle = LockScreenSettings.instance.getAppLockType();
|
||||
});
|
||||
}
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_appLockUpdateEvent.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -137,8 +150,9 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
|
||||
}
|
||||
children.addAll([
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: "App lock",
|
||||
subTitle: appLockSubtitle,
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
|
||||
@@ -14,6 +14,7 @@ Future<bool> requestAuthentication(
|
||||
BuildContext context,
|
||||
String reason, {
|
||||
bool isOpeningApp = false,
|
||||
bool isAuthenticatingForInAppChange = false,
|
||||
}) async {
|
||||
Logger("AuthUtil").info("Requesting authentication");
|
||||
|
||||
@@ -25,7 +26,8 @@ Future<bool> requestAuthentication(
|
||||
context,
|
||||
savedPin,
|
||||
savedPassword,
|
||||
isOnOpeningApp: isOpeningApp,
|
||||
isAuthenticatingOnAppLaunch: isOpeningApp,
|
||||
isAuthenticatingForInAppChange: isAuthenticatingForInAppChange,
|
||||
);
|
||||
}
|
||||
if (Platform.isMacOS || Platform.isLinux) {
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
import "dart:convert";
|
||||
import "dart:typed_data";
|
||||
|
||||
import "package:ente_crypto_dart/ente_crypto_dart.dart";
|
||||
import "package:flutter_secure_storage/flutter_secure_storage.dart";
|
||||
import "package:shared_preferences/shared_preferences.dart";
|
||||
|
||||
class LockScreenSettings {
|
||||
@@ -11,6 +16,7 @@ class LockScreenSettings {
|
||||
static const keyInvalidAttempts = "ls_invalid_attempts";
|
||||
static const lastInvalidAttemptTime = "ls_last_invalid_attempt_time";
|
||||
static const autoLockTime = "ls_auto_lock_time";
|
||||
static const appLockType = "ls_app_lock_type";
|
||||
final List<Duration> autoLockDurations = const [
|
||||
Duration(seconds: 0),
|
||||
Duration(seconds: 30),
|
||||
@@ -22,11 +28,20 @@ class LockScreenSettings {
|
||||
];
|
||||
|
||||
late SharedPreferences _preferences;
|
||||
|
||||
late FlutterSecureStorage _secureStorage;
|
||||
Future<void> init() async {
|
||||
_secureStorage = const FlutterSecureStorage();
|
||||
_preferences = await SharedPreferences.getInstance();
|
||||
}
|
||||
|
||||
Future<void> setAppLockType(String lockType) async {
|
||||
await _preferences.setString(appLockType, lockType);
|
||||
}
|
||||
|
||||
String getAppLockType() {
|
||||
return _preferences.getString(appLockType) ?? "None";
|
||||
}
|
||||
|
||||
Future<void> setAutoLockTime(Duration duration) async {
|
||||
await _preferences.setInt(autoLockTime, duration.inMilliseconds);
|
||||
}
|
||||
@@ -51,86 +66,85 @@ class LockScreenSettings {
|
||||
await _preferences.setInt(keyInvalidAttempts, count);
|
||||
}
|
||||
|
||||
// static Uint8List _generateSalt() {
|
||||
// return Sodium.randombytesBuf(Sodium.cryptoPwhashSaltbytes);
|
||||
// }
|
||||
static Uint8List _generateSalt() {
|
||||
return sodium.randombytes.buf(sodium.crypto.pwhash.saltBytes);
|
||||
}
|
||||
|
||||
Future<void> setPin(String userPin) async {
|
||||
//await _secureStorage.delete(key: saltKey);
|
||||
await _secureStorage.delete(key: saltKey);
|
||||
await _preferences.setString(pin, userPin);
|
||||
await _preferences.remove(password);
|
||||
// final salt = _generateSalt();
|
||||
// final hash = cryptoPwHash({
|
||||
// "password": utf8.encode(userPin),
|
||||
// "salt": salt,
|
||||
// "opsLimit": Sodium.cryptoPwhashOpslimitInteractive,
|
||||
// "memLimit": Sodium.cryptoPwhashMemlimitInteractive,
|
||||
// });
|
||||
final salt = _generateSalt();
|
||||
|
||||
// final String saltPin = base64Encode(salt);
|
||||
// final String hashedPin = base64Encode(hash);
|
||||
final hash = cryptoPwHash(
|
||||
utf8.encode(userPin),
|
||||
salt,
|
||||
sodium.crypto.pwhash.memLimitSensitive,
|
||||
sodium.crypto.pwhash.opsLimitSensitive,
|
||||
sodium,
|
||||
);
|
||||
final String saltPin = base64Encode(salt);
|
||||
final String hashedPin = base64Encode(hash);
|
||||
|
||||
// await _secureStorage.write(key: saltKey, value: saltPin);
|
||||
// await _secureStorage.write(key: pin, value: hashedPin);
|
||||
// await _secureStorage.delete(key: password);
|
||||
await _secureStorage.write(key: saltKey, value: saltPin);
|
||||
await _secureStorage.write(key: pin, value: hashedPin);
|
||||
await _secureStorage.delete(key: password);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Future<Uint8List?> getSalt() async {
|
||||
// final String? salt = await _secureStorage.read(key: saltKey);
|
||||
// if (salt == null) return null;
|
||||
// return base64Decode(salt);
|
||||
// }
|
||||
Future<Uint8List?> getSalt() async {
|
||||
final String? salt = await _secureStorage.read(key: saltKey);
|
||||
if (salt == null) return null;
|
||||
return base64Decode(salt);
|
||||
}
|
||||
|
||||
Future<String?> getPin() async {
|
||||
return _preferences.getString(pin);
|
||||
// return _secureStorage.read(key: pin);
|
||||
return _secureStorage.read(key: pin);
|
||||
}
|
||||
|
||||
Future<void> setPassword(String pass) async {
|
||||
await _preferences.setString(password, pass);
|
||||
await _preferences.remove(pin);
|
||||
// await _secureStorage.delete(key: saltKey);
|
||||
await _secureStorage.delete(key: saltKey);
|
||||
|
||||
// final salt = _generateSalt();
|
||||
// final hash = cryptoPwHash({
|
||||
// "password": utf8.encode(pass),
|
||||
// "salt": salt,
|
||||
// "opsLimit": Sodium.cryptoPwhashOpslimitInteractive,
|
||||
// "memLimit": Sodium.cryptoPwhashMemlimitInteractive,
|
||||
// });
|
||||
final salt = _generateSalt();
|
||||
|
||||
// final String saltPassword = base64Encode(salt);
|
||||
// final String hashPassword = base64Encode(hash);
|
||||
final hash = cryptoPwHash(
|
||||
utf8.encode(pass),
|
||||
salt,
|
||||
sodium.crypto.pwhash.memLimitSensitive,
|
||||
sodium.crypto.pwhash.opsLimitSensitive,
|
||||
sodium,
|
||||
);
|
||||
|
||||
// await _secureStorage.write(key: saltKey, value: saltPassword);
|
||||
// await _secureStorage.write(key: password, value: hashPassword);
|
||||
// await _secureStorage.delete(key: pin);
|
||||
final String saltPassword = base64Encode(salt);
|
||||
final String hashPassword = base64Encode(hash);
|
||||
|
||||
await _secureStorage.write(key: saltKey, value: saltPassword);
|
||||
await _secureStorage.write(key: password, value: hashPassword);
|
||||
await _secureStorage.delete(key: pin);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Future<String?> getPassword() async {
|
||||
return _preferences.getString(password);
|
||||
// return _secureStorage.read(key: password);
|
||||
return _secureStorage.read(key: password);
|
||||
}
|
||||
|
||||
Future<void> removePinAndPassword() async {
|
||||
await _preferences.remove(pin);
|
||||
await _preferences.remove(password);
|
||||
// await _secureStorage.delete(key: saltKey);
|
||||
// await _secureStorage.delete(key: pin);
|
||||
// await _secureStorage.delete(key: password);
|
||||
await _secureStorage.delete(key: saltKey);
|
||||
await _secureStorage.delete(key: pin);
|
||||
await _secureStorage.delete(key: password);
|
||||
}
|
||||
|
||||
Future<bool> isPinSet() async {
|
||||
return _preferences.containsKey(pin);
|
||||
// return await _secureStorage.containsKey(key: pin);
|
||||
return await _secureStorage.containsKey(key: pin);
|
||||
}
|
||||
|
||||
Future<bool> isPasswordSet() async {
|
||||
return _preferences.containsKey(password);
|
||||
// return await _secureStorage.containsKey(key: password);
|
||||
return await _secureStorage.containsKey(key: password);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user