From 59b132edf886f62e92bca3d6467fe59bb670e1f2 Mon Sep 17 00:00:00 2001 From: Aman Raj Singh Mourya Date: Wed, 26 Jun 2024 14:02:27 +0530 Subject: [PATCH] [mob][photos] moved funtions to lockscreen_setting.dart from configuration.dart --- mobile/lib/core/configuration.dart | 96 +++---------------- mobile/lib/main.dart | 9 +- .../local_authentication_service.dart | 12 +-- .../lock_screen_option.dart | 30 +++--- .../lock_screen_option_confirm_password.dart | 7 +- .../lock_screen_option_confirm_pin.dart | 7 +- .../lock_screen_option_password.dart | 9 +- .../lock_screen_option_pin.dart | 9 +- .../ui/settings/security_section_widget.dart | 2 +- mobile/lib/utils/auth_util.dart | 9 +- mobile/lib/utils/lockscreen_setting.dart | 96 +++++++++++++++++++ 11 files changed, 161 insertions(+), 125 deletions(-) rename mobile/lib/ui/settings/{TEMP => lockscreen}/lock_screen_option.dart (91%) rename mobile/lib/ui/settings/{TEMP => lockscreen}/lock_screen_option_confirm_password.dart (96%) rename mobile/lib/ui/settings/{TEMP => lockscreen}/lock_screen_option_confirm_pin.dart (98%) rename mobile/lib/ui/settings/{TEMP => lockscreen}/lock_screen_option_password.dart (95%) rename mobile/lib/ui/settings/{TEMP => lockscreen}/lock_screen_option_pin.dart (97%) create mode 100644 mobile/lib/utils/lockscreen_setting.dart diff --git a/mobile/lib/core/configuration.dart b/mobile/lib/core/configuration.dart index 2be3b0fb53..571a9d0f19 100644 --- a/mobile/lib/core/configuration.dart +++ b/mobile/lib/core/configuration.dart @@ -5,7 +5,6 @@ import "dart:io"; import 'package:bip39/bip39.dart' as bip39; import "package:flutter/services.dart"; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import "package:flutter_sodium/flutter_sodium.dart"; import 'package:logging/logging.dart'; import 'package:path_provider/path_provider.dart'; import 'package:photos/core/constants.dart'; @@ -35,6 +34,7 @@ import 'package:photos/services/search_service.dart'; import 'package:photos/services/sync_service.dart'; import 'package:photos/utils/crypto_util.dart'; import 'package:photos/utils/file_uploader.dart'; +import "package:photos/utils/lockscreen_setting.dart"; import 'package:photos/utils/validator_util.dart'; import "package:photos/utils/wakelock_util.dart"; import 'package:shared_preferences/shared_preferences.dart'; @@ -60,7 +60,7 @@ class Configuration { // keyShouldKeepDeviceAwake is used to determine whether the device screen // should be kept on while the app is in foreground. static const keyShouldKeepDeviceAwake = "should_keep_device_awake"; - static const keyShouldShowLockScreen = "should_show_lock_screen"; + static const keyShowSystemLockScreen = "should_show_lock_screen"; static const keyHasSelectedAnyBackupFolder = "has_selected_any_folder_for_backup"; static const lastTempFolderClearTimeKey = "last_temp_folder_clear_time"; @@ -86,7 +86,7 @@ class Configuration { late FlutterSecureStorage _secureStorage; late String _tempDocumentsDirPath; late String _thumbnailCacheDirectory; - + final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance; // 6th July 22: Remove this after 3 months. Hopefully, active users // will migrate to newer version of the app, where shared media is stored // on appSupport directory which OS won't clean up automatically @@ -154,80 +154,6 @@ class Configuration { } } - static Uint8List generateSalt() { - return Sodium.randombytesBuf(Sodium.cryptoPwhashSaltbytes); - } - - Future setPin(String userPin) async { - await _secureStorage.delete(key: saltKey); - - final salt = generateSalt(); - final hash = cryptoPwHash({ - "password": utf8.encode(userPin), - "salt": salt, - "opsLimit": Sodium.cryptoPwhashOpslimitInteractive, - "memLimit": Sodium.cryptoPwhashMemlimitInteractive, - }); - - 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); - - return; - } - - Future getSalt() async { - final String? salt = await _secureStorage.read(key: saltKey); - if (salt == null) return null; - return base64Decode(salt); - } - - Future getPin() async { - return _secureStorage.read(key: pin); - } - - Future setPassword(String pass) async { - await _secureStorage.delete(key: saltKey); - - final salt = generateSalt(); - final hash = cryptoPwHash({ - "password": utf8.encode(pass), - "salt": salt, - "opsLimit": Sodium.cryptoPwhashOpslimitInteractive, - "memLimit": Sodium.cryptoPwhashMemlimitInteractive, - }); - - 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 getPassword() async { - return _secureStorage.read(key: password); - } - - Future removePinAndPassword() async { - await _secureStorage.delete(key: saltKey); - await _secureStorage.delete(key: pin); - await _secureStorage.delete(key: password); - } - - Future isPinSet() async { - return await _secureStorage.containsKey(key: pin); - } - - Future isPasswordSet() async { - return await _secureStorage.containsKey(key: password); - } - // _cleanUpStaleFiles deletes all files in the temp directory that are older // than kTempFolderDeletionTimeBuffer except the the temp encrypted files for upload. // Those file are deleted by file uploader after the upload is complete or those @@ -697,16 +623,22 @@ class Configuration { } } - bool shouldShowLockScreen() { - if (_preferences.containsKey(keyShouldShowLockScreen)) { - return _preferences.getBool(keyShouldShowLockScreen)!; + Future shouldShowLockScreen() async { + final bool isPin = await _lockscreenSetting.isPinSet(); + final bool isPass = await _lockscreenSetting.isPasswordSet(); + return isPin || isPass || shouldShowSystemLockScreen(); + } + + bool shouldShowSystemLockScreen() { + if (_preferences.containsKey(keyShowSystemLockScreen)) { + return _preferences.getBool(keyShowSystemLockScreen)!; } else { return false; } } - Future setShouldShowLockScreen(bool value) { - return _preferences.setBool(keyShouldShowLockScreen, value); + Future setSystemLockScreen(bool value) { + return _preferences.setBool(keyShowSystemLockScreen, value); } void setVolatilePassword(String volatilePassword) { diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index f180f2bfff..70a53224d9 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import "package:flutter/rendering.dart"; import "package:flutter_displaymode/flutter_displaymode.dart"; +import "package:flutter_secure_storage/flutter_secure_storage.dart"; import 'package:logging/logging.dart'; import "package:media_kit/media_kit.dart"; import 'package:path_provider/path_provider.dart'; @@ -53,6 +54,7 @@ import 'package:photos/utils/crypto_util.dart'; import "package:photos/utils/email_util.dart"; import 'package:photos/utils/file_uploader.dart'; import 'package:photos/utils/local_settings.dart'; +import "package:photos/utils/lockscreen_setting.dart"; import 'package:shared_preferences/shared_preferences.dart'; final _logger = Logger("main"); @@ -94,7 +96,7 @@ Future _runInForeground(AdaptiveThemeMode? savedThemeMode) async { builder: (args) => EnteApp(_runBackgroundTask, _killBGTask, locale, savedThemeMode), lockScreen: const LockScreen(), - enabled: Configuration.instance.shouldShowLockScreen(), + enabled: await Configuration.instance.shouldShowLockScreen(), locale: locale, lightTheme: lightThemeData, darkTheme: darkThemeData, @@ -195,7 +197,7 @@ Future _init(bool isBackground, {String via = ''}) async { _isProcessRunning = true; _logger.info("Initializing... inBG =$isBackground via: $via"); final SharedPreferences preferences = await SharedPreferences.getInstance(); - + const secureStorage = FlutterSecureStorage(); await _logFGHeartBeatInfo(); _logger.info("_logFGHeartBeatInfo done"); unawaited(_scheduleHeartBeat(preferences, isBackground)); @@ -209,6 +211,9 @@ Future _init(bool isBackground, {String via = ''}) async { Computer.shared().turnOn(workersCount: 4).ignore(); CryptoUtil.init(); + _logger.info("Lockscreen init"); + LockscreenSetting.instance.init(secureStorage); + _logger.info("Configuration init"); await Configuration.instance.init(); _logger.info("Configuration done"); diff --git a/mobile/lib/services/local_authentication_service.dart b/mobile/lib/services/local_authentication_service.dart index badf20775f..490b2b5dcc 100644 --- a/mobile/lib/services/local_authentication_service.dart +++ b/mobile/lib/services/local_authentication_service.dart @@ -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/TEMP/lock_screen_option_password.dart"; -import "package:photos/ui/settings/TEMP/lock_screen_option_pin.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/tools/app_lock.dart'; import 'package:photos/utils/auth_util.dart'; import 'package:photos/utils/dialog_util.dart'; @@ -23,7 +23,7 @@ class LocalAuthenticationService { AppLock.of(context)!.setEnabled(false); final result = await requestAuthentication(context, infoMessage); AppLock.of(context)!.setEnabled( - Configuration.instance.shouldShowLockScreen(), + await Configuration.instance.shouldShowLockScreen(), ); if (!result) { showToast(context, infoMessage); @@ -88,13 +88,13 @@ class LocalAuthenticationService { ); if (result) { AppLock.of(context)!.setEnabled(shouldEnableLockScreen); - await Configuration.instance - .setShouldShowLockScreen(shouldEnableLockScreen); + await Configuration.instance + .setSystemLockScreen(shouldEnableLockScreen); return true; } else { AppLock.of(context)! - .setEnabled(Configuration.instance.shouldShowLockScreen()); + .setEnabled(await Configuration.instance.shouldShowLockScreen()); } } else { unawaited( diff --git a/mobile/lib/ui/settings/TEMP/lock_screen_option.dart b/mobile/lib/ui/settings/lockscreen/lock_screen_option.dart similarity index 91% rename from mobile/lib/ui/settings/TEMP/lock_screen_option.dart rename to mobile/lib/ui/settings/lockscreen/lock_screen_option.dart index fa6827956b..59725f2fc6 100644 --- a/mobile/lib/ui/settings/TEMP/lock_screen_option.dart +++ b/mobile/lib/ui/settings/lockscreen/lock_screen_option.dart @@ -7,9 +7,10 @@ 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/TEMP/lock_screen_option_password.dart"; -import "package:photos/ui/settings/TEMP/lock_screen_option_pin.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/tools/app_lock.dart"; +import "package:photos/utils/lockscreen_setting.dart"; class LockScreenOption extends StatefulWidget { const LockScreenOption({super.key}); @@ -20,6 +21,7 @@ class LockScreenOption extends StatefulWidget { class _LockScreenOptionState extends State { final Configuration _configuration = Configuration.instance; + final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance; late bool appLock; bool isPinEnabled = false; bool isPasswordEnabled = false; @@ -30,12 +32,12 @@ class _LockScreenOptionState extends State { _initializeSettings(); appLock = isPinEnabled || isPasswordEnabled || - _configuration.shouldShowLockScreen(); + _configuration.shouldShowSystemLockScreen(); } Future _initializeSettings() async { - final bool passwordEnabled = await _configuration.isPasswordSet(); - final bool pinEnabled = await _configuration.isPinSet(); + final bool passwordEnabled = await _lockscreenSetting.isPasswordSet(); + final bool pinEnabled = await _lockscreenSetting.isPinSet(); setState(() { isPasswordEnabled = passwordEnabled; isPinEnabled = pinEnabled; @@ -43,7 +45,7 @@ class _LockScreenOptionState extends State { } Future _deviceLock() async { - await _configuration.removePinAndPassword(); + await _lockscreenSetting.removePinAndPassword(); await _initializeSettings(); } @@ -57,12 +59,10 @@ class _LockScreenOptionState extends State { ); setState(() { _initializeSettings(); - if (result == false) { - appLock = appLock; - } else { + if (result) { appLock = isPinEnabled || isPasswordEnabled || - _configuration.shouldShowLockScreen(); + _configuration.shouldShowSystemLockScreen(); } }); } @@ -77,20 +77,18 @@ class _LockScreenOptionState extends State { ); setState(() { _initializeSettings(); - if (result == false) { - appLock = appLock; - } else { + if (result) { appLock = isPinEnabled || isPasswordEnabled || - _configuration.shouldShowLockScreen(); + _configuration.shouldShowSystemLockScreen(); } }); } Future _onToggleSwitch() async { AppLock.of(context)!.setEnabled(!appLock); - await Configuration.instance.setShouldShowLockScreen(!appLock); - await _configuration.removePinAndPassword(); + await _configuration.setSystemLockScreen(!appLock); + await _lockscreenSetting.removePinAndPassword(); setState(() { _initializeSettings(); appLock = !appLock; diff --git a/mobile/lib/ui/settings/TEMP/lock_screen_option_confirm_password.dart b/mobile/lib/ui/settings/lockscreen/lock_screen_option_confirm_password.dart similarity index 96% rename from mobile/lib/ui/settings/TEMP/lock_screen_option_confirm_password.dart rename to mobile/lib/ui/settings/lockscreen/lock_screen_option_confirm_password.dart index ee59de455a..3b3840bd31 100644 --- a/mobile/lib/ui/settings/TEMP/lock_screen_option_confirm_password.dart +++ b/mobile/lib/ui/settings/lockscreen/lock_screen_option_confirm_password.dart @@ -1,11 +1,11 @@ import "package:flutter/material.dart"; import "package:flutter/services.dart"; -import "package:photos/core/configuration.dart"; import "package:photos/generated/l10n.dart"; 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/utils/lockscreen_setting.dart"; class LockScreenOptionConfirmPassword extends StatefulWidget { const LockScreenOptionConfirmPassword({ @@ -23,7 +23,8 @@ class _LockScreenOptionConfirmPasswordState extends State { /// _confirmPasswordController is disposed by the [TextInputWidget] final _confirmPasswordController = TextEditingController(text: null); - final Configuration _configuration = Configuration.instance; + + final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance; final _focusNode = FocusNode(); final _isFormValid = ValueNotifier(false); final _submitNotifier = ValueNotifier(false); @@ -45,7 +46,7 @@ class _LockScreenOptionConfirmPasswordState Future _confirmPasswordMatch() async { if (widget.password == _confirmPasswordController.text) { - await _configuration.setPassword(_confirmPasswordController.text); + await _lockscreenSetting.setPassword(_confirmPasswordController.text); Navigator.of(context).pop(true); Navigator.of(context).pop(true); diff --git a/mobile/lib/ui/settings/TEMP/lock_screen_option_confirm_pin.dart b/mobile/lib/ui/settings/lockscreen/lock_screen_option_confirm_pin.dart similarity index 98% rename from mobile/lib/ui/settings/TEMP/lock_screen_option_confirm_pin.dart rename to mobile/lib/ui/settings/lockscreen/lock_screen_option_confirm_pin.dart index 149cb54d66..2f8e9a20a2 100644 --- a/mobile/lib/ui/settings/TEMP/lock_screen_option_confirm_pin.dart +++ b/mobile/lib/ui/settings/lockscreen/lock_screen_option_confirm_pin.dart @@ -1,10 +1,10 @@ import "package:flutter/material.dart"; import "package:flutter/services.dart"; -import "package:photos/core/configuration.dart"; 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/utils/lockscreen_setting.dart"; import "package:pinput/pinput.dart"; class LockScreenOptionConfirmPin extends StatefulWidget { @@ -18,7 +18,8 @@ class LockScreenOptionConfirmPin extends StatefulWidget { class _LockScreenOptionConfirmPinState extends State { final _confirmPinController = TextEditingController(text: null); - final Configuration _configuration = Configuration.instance; + + final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance; final _pinPutDecoration = PinTheme( height: 48, width: 48, @@ -49,7 +50,7 @@ class _LockScreenOptionConfirmPinState Future _confirmPinMatch() async { if (widget.pin == _confirmPinController.text) { - await _configuration.setPin(_confirmPinController.text); + await _lockscreenSetting.setPin(_confirmPinController.text); Navigator.of(context).pop(true); Navigator.of(context).pop(true); diff --git a/mobile/lib/ui/settings/TEMP/lock_screen_option_password.dart b/mobile/lib/ui/settings/lockscreen/lock_screen_option_password.dart similarity index 95% rename from mobile/lib/ui/settings/TEMP/lock_screen_option_password.dart rename to mobile/lib/ui/settings/lockscreen/lock_screen_option_password.dart index d4c1c59cfb..5831a65337 100644 --- a/mobile/lib/ui/settings/TEMP/lock_screen_option_password.dart +++ b/mobile/lib/ui/settings/lockscreen/lock_screen_option_password.dart @@ -3,14 +3,14 @@ import "dart:convert"; import "package:flutter/material.dart"; import "package:flutter/services.dart"; import "package:flutter_sodium/flutter_sodium.dart"; -import "package:photos/core/configuration.dart"; import "package:photos/generated/l10n.dart"; 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/TEMP/lock_screen_option_confirm_password.dart"; +import "package:photos/ui/settings/lockscreen/lock_screen_option_confirm_password.dart"; import "package:photos/utils/crypto_util.dart"; +import "package:photos/utils/lockscreen_setting.dart"; class LockScreenOptionPassword extends StatefulWidget { const LockScreenOptionPassword({ @@ -31,7 +31,8 @@ class _LockScreenOptionPasswordState extends State { final _focusNode = FocusNode(); final _isFormValid = ValueNotifier(false); final _submitNotifier = ValueNotifier(false); - Configuration configuration = Configuration.instance; + + final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance; late String hashedPassword; @override void initState() { @@ -50,7 +51,7 @@ class _LockScreenOptionPasswordState extends State { } Future confirmPasswordAuth(String code) async { - final Uint8List? salt = await configuration.getSalt(); + final Uint8List? salt = await _lockscreenSetting.getSalt(); final hash = cryptoPwHash({ "password": utf8.encode(code), "salt": salt, diff --git a/mobile/lib/ui/settings/TEMP/lock_screen_option_pin.dart b/mobile/lib/ui/settings/lockscreen/lock_screen_option_pin.dart similarity index 97% rename from mobile/lib/ui/settings/TEMP/lock_screen_option_pin.dart rename to mobile/lib/ui/settings/lockscreen/lock_screen_option_pin.dart index bbc467f721..7f574dae1e 100644 --- a/mobile/lib/ui/settings/TEMP/lock_screen_option_pin.dart +++ b/mobile/lib/ui/settings/lockscreen/lock_screen_option_pin.dart @@ -3,13 +3,13 @@ import "dart:convert"; import "package:flutter/material.dart"; import "package:flutter/services.dart"; import "package:flutter_sodium/flutter_sodium.dart"; -import "package:photos/core/configuration.dart"; 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/TEMP/lock_screen_option_confirm_pin.dart"; +import "package:photos/ui/settings/lockscreen/lock_screen_option_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 { @@ -27,7 +27,8 @@ class LockScreenOptionPin extends StatefulWidget { class _LockScreenOptionPinState extends State { final _pinController = TextEditingController(text: null); - Configuration configuration = Configuration.instance; + + final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance; late String hashedPin; @override void dispose() { @@ -49,7 +50,7 @@ class _LockScreenOptionPinState extends State { } Future confirmPinAuth(String code) async { - final Uint8List? salt = await configuration.getSalt(); + final Uint8List? salt = await _lockscreenSetting.getSalt(); final hash = cryptoPwHash({ "password": utf8.encode(code), "salt": salt, diff --git a/mobile/lib/ui/settings/security_section_widget.dart b/mobile/lib/ui/settings/security_section_widget.dart index 478f1b2df9..a9e89c10c7 100644 --- a/mobile/lib/ui/settings/security_section_widget.dart +++ b/mobile/lib/ui/settings/security_section_widget.dart @@ -20,8 +20,8 @@ import 'package:photos/ui/components/captioned_text_widget.dart'; import 'package:photos/ui/components/expandable_menu_item_widget.dart'; import 'package:photos/ui/components/menu_item_widget/menu_item_widget.dart'; import 'package:photos/ui/components/toggle_switch_widget.dart'; -import "package:photos/ui/settings/TEMP/lock_screen_option.dart"; import 'package:photos/ui/settings/common_settings.dart'; +import "package:photos/ui/settings/lockscreen/lock_screen_option.dart"; import "package:photos/utils/auth_util.dart"; import "package:photos/utils/crypto_util.dart"; import "package:photos/utils/dialog_util.dart"; diff --git a/mobile/lib/utils/auth_util.dart b/mobile/lib/utils/auth_util.dart index ea86e72da2..b105376f7a 100644 --- a/mobile/lib/utils/auth_util.dart +++ b/mobile/lib/utils/auth_util.dart @@ -3,16 +3,17 @@ import 'package:local_auth/local_auth.dart'; import 'package:local_auth_android/local_auth_android.dart'; import 'package:local_auth_ios/local_auth_ios.dart'; import 'package:logging/logging.dart'; -import "package:photos/core/configuration.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/services/local_authentication_service.dart"; +import "package:photos/utils/lockscreen_setting.dart"; Future requestAuthentication(BuildContext context, String reason) async { Logger("AuthUtil").info("Requesting authentication"); await LocalAuthentication().stopAuthentication(); - final Configuration configuration = Configuration.instance; - final String? savedPin = await configuration.getPin(); - final String? savedPassword = await configuration.getPassword(); + + final LockscreenSetting lockscreenSetting = LockscreenSetting.instance; + final String? savedPin = await lockscreenSetting.getPin(); + final String? savedPassword = await lockscreenSetting.getPassword(); if (savedPassword != null || savedPin != null) { return await LocalAuthenticationService.instance .requestEnteAuthForLockScreen(context, savedPin, savedPassword); diff --git a/mobile/lib/utils/lockscreen_setting.dart b/mobile/lib/utils/lockscreen_setting.dart new file mode 100644 index 0000000000..fc5e435700 --- /dev/null +++ b/mobile/lib/utils/lockscreen_setting.dart @@ -0,0 +1,96 @@ +import "dart:convert"; + +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"; + +class LockscreenSetting { + LockscreenSetting._privateConstructor(); + + static final LockscreenSetting instance = + LockscreenSetting._privateConstructor(); + static const password = "user_pass"; + static const pin = "user_pin"; + static const saltKey = "user_salt"; + + late FlutterSecureStorage _secureStorage; + + void init(FlutterSecureStorage secureStorage) { + _secureStorage = secureStorage; + } + + static Uint8List generateSalt() { + return Sodium.randombytesBuf(Sodium.cryptoPwhashSaltbytes); + } + + Future setPin(String userPin) async { + await _secureStorage.delete(key: saltKey); + + final salt = generateSalt(); + final hash = cryptoPwHash({ + "password": utf8.encode(userPin), + "salt": salt, + "opsLimit": Sodium.cryptoPwhashOpslimitInteractive, + "memLimit": Sodium.cryptoPwhashMemlimitInteractive, + }); + + 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); + + return; + } + + Future getSalt() async { + final String? salt = await _secureStorage.read(key: saltKey); + if (salt == null) return null; + return base64Decode(salt); + } + + Future getPin() async { + return _secureStorage.read(key: pin); + } + + Future setPassword(String pass) async { + await _secureStorage.delete(key: saltKey); + + final salt = generateSalt(); + final hash = cryptoPwHash({ + "password": utf8.encode(pass), + "salt": salt, + "opsLimit": Sodium.cryptoPwhashOpslimitInteractive, + "memLimit": Sodium.cryptoPwhashMemlimitInteractive, + }); + + 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 getPassword() async { + return _secureStorage.read(key: password); + } + + Future removePinAndPassword() async { + await _secureStorage.delete(key: saltKey); + await _secureStorage.delete(key: pin); + await _secureStorage.delete(key: password); + } + + Future isPinSet() async { + return await _secureStorage.containsKey(key: pin); + } + + Future isPasswordSet() async { + return await _secureStorage.containsKey(key: password); + } +}