From d4eef1eb2a509b1cc40d6b50a064c26216960e0d Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 14 Aug 2023 13:54:52 +0530 Subject: [PATCH 1/4] generated changes --- lib/generated/intl/messages_it.dart | 50 +++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/lib/generated/intl/messages_it.dart b/lib/generated/intl/messages_it.dart index baeb6ca6a..9f3d770d0 100644 --- a/lib/generated/intl/messages_it.dart +++ b/lib/generated/intl/messages_it.dart @@ -217,10 +217,15 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Aggiungi una nuova email"), "addCollaborator": MessageLookupByLibrary.simpleMessage("Aggiungi collaboratore"), + "addFromDevice": + MessageLookupByLibrary.simpleMessage("Aggiungi dal dispositivo"), "addItem": m0, "addLocation": MessageLookupByLibrary.simpleMessage("Aggiungi luogo"), "addLocationButton": MessageLookupByLibrary.simpleMessage("Aggiungi"), "addMore": MessageLookupByLibrary.simpleMessage("Aggiungi altri"), + "addPhotos": MessageLookupByLibrary.simpleMessage("Aggiungi foto"), + "addSelected": + MessageLookupByLibrary.simpleMessage("Aggiungi selezionate"), "addToAlbum": MessageLookupByLibrary.simpleMessage("Aggiungi all\'album"), "addToEnte": MessageLookupByLibrary.simpleMessage("Aggiungi su ente"), @@ -309,6 +314,9 @@ class MessageLookup extends MessageLookupByLibrary { "Invita amici, amiche e parenti su ente"), "atAFalloutShelter": MessageLookupByLibrary.simpleMessage("in un rifugio antiatomico"), + "authToChangeEmailVerificationSetting": + MessageLookupByLibrary.simpleMessage( + "Autenticati per modificare la verifica email"), "authToChangeLockscreenSetting": MessageLookupByLibrary.simpleMessage( "Autenticati per modificare le impostazioni della schermata di blocco"), "authToChangeYourEmail": MessageLookupByLibrary.simpleMessage( @@ -435,6 +443,8 @@ class MessageLookup extends MessageLookupByLibrary { "continueLabel": MessageLookupByLibrary.simpleMessage("Continua"), "continueOnFreeTrial": MessageLookupByLibrary.simpleMessage("Continua la prova gratuita"), + "convertToAlbum": + MessageLookupByLibrary.simpleMessage("Converti in album"), "copyEmailAddress": MessageLookupByLibrary.simpleMessage("Copia indirizzo email"), "copyLink": MessageLookupByLibrary.simpleMessage("Copia link"), @@ -448,6 +458,9 @@ class MessageLookup extends MessageLookupByLibrary { "couldNotUpdateSubscription": MessageLookupByLibrary.simpleMessage( "Impossibile aggiornare l\'abbonamento"), "count": MessageLookupByLibrary.simpleMessage("Conteggio"), + "crashReporting": + MessageLookupByLibrary.simpleMessage("Segnalazione di crash"), + "create": MessageLookupByLibrary.simpleMessage("Crea"), "createAccount": MessageLookupByLibrary.simpleMessage("Crea account"), "createAlbumActionHint": MessageLookupByLibrary.simpleMessage( "Premi a lungo per selezionare le foto e fai clic su + per creare un album"), @@ -570,6 +583,8 @@ class MessageLookup extends MessageLookupByLibrary { "email": MessageLookupByLibrary.simpleMessage("Email"), "emailChangedTo": m15, "emailNoEnteAccount": m16, + "emailVerificationToggle": + MessageLookupByLibrary.simpleMessage("Verifica Email"), "emailYourLogs": MessageLookupByLibrary.simpleMessage( "Invia una mail con i tuoi log"), "empty": MessageLookupByLibrary.simpleMessage("Vuoto"), @@ -633,8 +648,8 @@ class MessageLookup extends MessageLookupByLibrary { "Impossibile applicare il codice"), "failedToCancel": MessageLookupByLibrary.simpleMessage("Impossibile annullare"), - "failedToDownloadVideo": - MessageLookupByLibrary.simpleMessage("Failed to download video"), + "failedToDownloadVideo": MessageLookupByLibrary.simpleMessage( + "Download del video non riuscito"), "failedToFetchOriginalForEdit": MessageLookupByLibrary.simpleMessage( "Impossibile recuperare l\'originale per la modifica"), "failedToFetchReferralDetails": MessageLookupByLibrary.simpleMessage( @@ -735,7 +750,7 @@ class MessageLookup extends MessageLookupByLibrary { "inviteYourFriends": MessageLookupByLibrary.simpleMessage("Invita i tuoi amici"), "inviteYourFriendsToEnte": - MessageLookupByLibrary.simpleMessage("Invite your friends to ente"), + MessageLookupByLibrary.simpleMessage("Invita i tuoi amici a ente"), "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": MessageLookupByLibrary.simpleMessage( "Sembra che qualcosa sia andato storto. Riprova tra un po\'. Se l\'errore persiste, contatta il nostro team di supporto."), @@ -853,8 +868,8 @@ class MessageLookup extends MessageLookupByLibrary { "newToEnte": MessageLookupByLibrary.simpleMessage("Nuovo utente"), "newest": MessageLookupByLibrary.simpleMessage("Più recenti"), "no": MessageLookupByLibrary.simpleMessage("No"), - "noAlbumsSharedByYouYet": - MessageLookupByLibrary.simpleMessage("No albums shared by you yet"), + "noAlbumsSharedByYouYet": MessageLookupByLibrary.simpleMessage( + "Ancora nessun album condiviso da te"), "noDeviceThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( "Non hai file su questo dispositivo che possono essere eliminati"), "noDuplicates": @@ -862,9 +877,13 @@ class MessageLookup extends MessageLookupByLibrary { "noExifData": MessageLookupByLibrary.simpleMessage("Nessun dato EXIF"), "noHiddenPhotosOrVideos": MessageLookupByLibrary.simpleMessage( "Nessuna foto o video nascosti"), + "noImagesWithLocation": MessageLookupByLibrary.simpleMessage( + "Nessuna immagine con posizione"), "noPhotosAreBeingBackedUpRightNow": MessageLookupByLibrary.simpleMessage( "Il backup delle foto attualmente non viene eseguito"), + "noPhotosFoundHere": + MessageLookupByLibrary.simpleMessage("Nessuna foto trovata"), "noRecoveryKey": MessageLookupByLibrary.simpleMessage("Nessuna chiave di recupero?"), "noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage( @@ -872,8 +891,8 @@ class MessageLookup extends MessageLookupByLibrary { "noResults": MessageLookupByLibrary.simpleMessage("Nessun risultato"), "noResultsFound": MessageLookupByLibrary.simpleMessage("Nessun risultato trovato"), - "nothingSharedWithYouYet": - MessageLookupByLibrary.simpleMessage("Nothing shared with you yet"), + "nothingSharedWithYouYet": MessageLookupByLibrary.simpleMessage( + "Ancora nulla di condiviso con te"), "nothingToSeeHere": MessageLookupByLibrary.simpleMessage("Nulla da vedere qui! 👀"), "notifications": MessageLookupByLibrary.simpleMessage("Notifiche"), @@ -967,6 +986,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Link pubblico creato"), "publicLinkEnabled": MessageLookupByLibrary.simpleMessage("Link pubblico abilitato"), + "quickLinks": + MessageLookupByLibrary.simpleMessage("Collegamenti rapidi"), "radius": MessageLookupByLibrary.simpleMessage("Raggio"), "raiseTicket": MessageLookupByLibrary.simpleMessage("Invia ticket"), "rateTheApp": MessageLookupByLibrary.simpleMessage("Valuta l\'app"), @@ -1049,6 +1070,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ripristina i file ignorati"), "resetPasswordTitle": MessageLookupByLibrary.simpleMessage("Reimposta password"), + "resetToDefault": + MessageLookupByLibrary.simpleMessage("Ripristina predefinita"), "restore": MessageLookupByLibrary.simpleMessage("Ripristina"), "restoreToAlbum": MessageLookupByLibrary.simpleMessage("Ripristina l\'album"), @@ -1084,6 +1107,8 @@ class MessageLookup extends MessageLookupByLibrary { "selectAll": MessageLookupByLibrary.simpleMessage("Seleziona tutto"), "selectFoldersForBackup": MessageLookupByLibrary.simpleMessage( "Seleziona cartelle per il backup"), + "selectItemsToAdd": MessageLookupByLibrary.simpleMessage( + "Seleziona gli elementi da aggiungere"), "selectLanguage": MessageLookupByLibrary.simpleMessage("Seleziona una lingua"), "selectReason": @@ -1138,7 +1163,7 @@ class MessageLookup extends MessageLookupByLibrary { "sharedAlbumSectionDescription": MessageLookupByLibrary.simpleMessage( "Crea album condivisi e collaborativi con altri utenti ente, inclusi utenti su piani gratuiti."), "sharedByMe": MessageLookupByLibrary.simpleMessage("Condiviso da me"), - "sharedByYou": MessageLookupByLibrary.simpleMessage("Shared by you"), + "sharedByYou": MessageLookupByLibrary.simpleMessage("Condivise da te"), "sharedPhotoNotifications": MessageLookupByLibrary.simpleMessage("Nuove foto condivise"), "sharedPhotoNotificationsExplanation": MessageLookupByLibrary.simpleMessage( @@ -1147,7 +1172,7 @@ class MessageLookup extends MessageLookupByLibrary { "sharedWithMe": MessageLookupByLibrary.simpleMessage("Condivisi con me"), "sharedWithYou": - MessageLookupByLibrary.simpleMessage("Shared with you"), + MessageLookupByLibrary.simpleMessage("Condivise con te"), "sharing": MessageLookupByLibrary.simpleMessage("Condivisione in corso..."), "signUpTerms": MessageLookupByLibrary.simpleMessage( @@ -1273,6 +1298,8 @@ class MessageLookup extends MessageLookupByLibrary { "time": MessageLookupByLibrary.simpleMessage("Ora"), "toHideAPhotoOrVideo": MessageLookupByLibrary.simpleMessage( "Per nascondere una foto o un video"), + "toResetVerifyEmail": MessageLookupByLibrary.simpleMessage( + "Per reimpostare la tua password, verifica prima la tua email."), "todaysLogs": MessageLookupByLibrary.simpleMessage("Log di oggi"), "total": MessageLookupByLibrary.simpleMessage("totale"), "totalSize": MessageLookupByLibrary.simpleMessage("Dimensioni totali"), @@ -1350,6 +1377,7 @@ class MessageLookup extends MessageLookupByLibrary { "videoSmallCase": MessageLookupByLibrary.simpleMessage("video"), "viewActiveSessions": MessageLookupByLibrary.simpleMessage("Visualizza sessioni attive"), + "viewAll": MessageLookupByLibrary.simpleMessage("Visualizza tutte"), "viewAllExifData": MessageLookupByLibrary.simpleMessage("Mostra tutti i dati EXIF"), "viewLogs": MessageLookupByLibrary.simpleMessage("Visualizza i log"), @@ -1422,6 +1450,8 @@ class MessageLookup extends MessageLookupByLibrary { "Non hai file duplicati che possono essere cancellati"), "youveNoFilesInThisAlbumThatCanBeDeleted": MessageLookupByLibrary.simpleMessage( - "Non hai file in questo album che possono essere eliminati") + "Non hai file in questo album che possono essere eliminati"), + "zoomOutToSeePhotos": MessageLookupByLibrary.simpleMessage( + "Zoom indietro per visualizzare le foto") }; } From 1793f4b61f88a6c6a6f5be4cf902209d7feed7b7 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 14 Aug 2023 13:58:42 +0530 Subject: [PATCH 2/4] LoginV2: Remove redundant screen pop --- lib/core/configuration.dart | 7 ++++--- lib/services/user_service.dart | 15 +++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/core/configuration.dart b/lib/core/configuration.dart index 075264564..a71fa37e0 100644 --- a/lib/core/configuration.dart +++ b/lib/core/configuration.dart @@ -271,8 +271,9 @@ class Configuration { // SRP setup for existing users. Future decryptSecretsAndGetKeyEncKey( String password, - KeyAttributes attributes, - ) async { + KeyAttributes attributes, { + Uint8List? keyEncryptionKey, + }) async { validatePreVerificationStateCheck( attributes, password, @@ -280,7 +281,7 @@ class Configuration { ); // Derive key-encryption-key from the entered password and existing // mem and ops limits - final keyEncryptionKey = await CryptoUtil.deriveKey( + keyEncryptionKey ??= await CryptoUtil.deriveKey( utf8.encode(password) as Uint8List, CryptoUtil.base642bin(attributes.kekSalt), attributes.memLimit!, diff --git a/lib/services/user_service.dart b/lib/services/user_service.dart index 07162f896..f25fca88b 100644 --- a/lib/services/user_service.dart +++ b/lib/services/user_service.dart @@ -34,6 +34,7 @@ import 'package:photos/ui/account/two_factor_authentication_page.dart'; import 'package:photos/ui/account/two_factor_recovery_page.dart'; import 'package:photos/ui/account/two_factor_setup_page.dart'; import "package:photos/ui/components/buttons/button_widget.dart"; +import "package:photos/ui/tabs/home_widget.dart"; import 'package:photos/utils/crypto_util.dart'; import 'package:photos/utils/dialog_util.dart'; import "package:photos/utils/email_util.dart"; @@ -569,14 +570,15 @@ class UserService { isDismissible: true, ); await dialog.show(); + late Uint8List keyEncryptionKey; try { - final kek = await CryptoUtil.deriveKey( + keyEncryptionKey = await CryptoUtil.deriveKey( utf8.encode(userPassword) as Uint8List, CryptoUtil.base642bin(srpAttributes.kekSalt), srpAttributes.memLimit, srpAttributes.opsLimit, ); - final loginKey = await CryptoUtil.deriveLoginKey(kek); + final loginKey = await CryptoUtil.deriveLoginKey(keyEncryptionKey); final Uint8List identity = Uint8List.fromList( utf8.encode(srpAttributes.srpUserID), ); @@ -614,7 +616,6 @@ class UserService { }, ); if (response.statusCode == 200) { - await dialog.hide(); Widget page; final String twoFASessionID = response.data["twoFactorSessionID"]; Configuration.instance.setVolatilePassword(userPassword); @@ -624,11 +625,17 @@ class UserService { } else { await _saveConfiguration(response); if (Configuration.instance.getEncryptedToken() != null) { - page = const PasswordReentryPage(); + await Configuration.instance.decryptSecretsAndGetKeyEncKey( + userPassword, + Configuration.instance.getKeyAttributes()!, + keyEncryptionKey: keyEncryptionKey, + ); + page = const HomeWidget(); } else { throw Exception("unexpected response during email verification"); } } + await dialog.hide(); Navigator.of(context).pushAndRemoveUntil( MaterialPageRoute( builder: (BuildContext context) { From 9a7e24759db6b5508cf8c28e8aacec3ef9e2c14d Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Mon, 14 Aug 2023 14:05:11 +0530 Subject: [PATCH 3/4] Show disable email verification for all users --- .../request_pwd_verification_page.dart | 216 ++++++++++++++++++ lib/ui/settings/security_section_widget.dart | 56 +++-- 2 files changed, 247 insertions(+), 25 deletions(-) create mode 100644 lib/ui/account/request_pwd_verification_page.dart diff --git a/lib/ui/account/request_pwd_verification_page.dart b/lib/ui/account/request_pwd_verification_page.dart new file mode 100644 index 000000000..2bc9c5a3d --- /dev/null +++ b/lib/ui/account/request_pwd_verification_page.dart @@ -0,0 +1,216 @@ +import "dart:convert"; +import "dart:typed_data"; + +import 'package:flutter/material.dart'; +import "package:flutter_sodium/flutter_sodium.dart"; +import "package:logging/logging.dart"; +import 'package:photos/core/configuration.dart'; +import "package:photos/l10n/l10n.dart"; +import "package:photos/theme/ente_theme.dart"; +import 'package:photos/ui/common/dynamic_fab.dart'; +import "package:photos/utils/crypto_util.dart"; +import "package:photos/utils/dialog_util.dart"; + +typedef OnPasswordVerifiedFn = Future Function(Uint8List bytes); + +class RequestPasswordVerificationPage extends StatefulWidget { + final OnPasswordVerifiedFn onPasswordVerified; + final Function? onPasswordError; + + const RequestPasswordVerificationPage( + {super.key, required this.onPasswordVerified, this.onPasswordError,}); + + @override + State createState() => + _RequestPasswordVerificationPageState(); +} + +class _RequestPasswordVerificationPageState + extends State { + final _logger = Logger((_RequestPasswordVerificationPageState).toString()); + final _passwordController = TextEditingController(); + final FocusNode _passwordFocusNode = FocusNode(); + String? email; + bool _passwordInFocus = false; + bool _passwordVisible = false; + + @override + void initState() { + super.initState(); + email = Configuration.instance.getEmail(); + _passwordFocusNode.addListener(() { + setState(() { + _passwordInFocus = _passwordFocusNode.hasFocus; + }); + }); + } + + @override + Widget build(BuildContext context) { + final isKeypadOpen = MediaQuery.of(context).viewInsets.bottom > 100; + + FloatingActionButtonLocation? fabLocation() { + if (isKeypadOpen) { + return null; + } else { + return FloatingActionButtonLocation.centerFloat; + } + } + + return Scaffold( + resizeToAvoidBottomInset: isKeypadOpen, + appBar: AppBar( + elevation: 0, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + color: Theme.of(context).iconTheme.color, + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + body: _getBody(), + floatingActionButton: DynamicFAB( + key: const ValueKey("verifyPasswordButton"), + isKeypadOpen: isKeypadOpen, + isFormValid: _passwordController.text.isNotEmpty, + buttonText: context.l10n.verifyPassword, + onPressedFunction: () async { + FocusScope.of(context).unfocus(); + final dialog = createProgressDialog(context, context.l10n.pleaseWait); + dialog.show(); + try { + final attributes = Configuration.instance.getKeyAttributes()!; + final Uint8List keyEncryptionKey = await CryptoUtil.deriveKey( + utf8.encode(_passwordController.text) as Uint8List, + Sodium.base642bin(attributes.kekSalt), + attributes.memLimit!, + attributes.opsLimit!, + ); + CryptoUtil.decryptSync( + Sodium.base642bin(attributes.encryptedKey), + keyEncryptionKey, + Sodium.base642bin(attributes.keyDecryptionNonce), + ); + dialog.show(); + // pop + await widget.onPasswordVerified(keyEncryptionKey); + dialog.hide(); + Navigator.of(context).pop(true); + } catch (e, s) { + _logger.severe("Error while verifying password", e, s); + dialog.hide(); + if (widget.onPasswordError != null) { + widget.onPasswordError!(); + } else { + showErrorDialog( + context, + context.l10n.incorrectPasswordTitle, + context.l10n.pleaseTryAgain, + ); + } + } + }, + ), + floatingActionButtonLocation: fabLocation(), + floatingActionButtonAnimator: NoScalingAnimation(), + ); + } + + Widget _getBody() { + return Column( + children: [ + Expanded( + child: AutofillGroup( + child: ListView( + children: [ + Padding( + padding: const EdgeInsets.only(top: 30, left: 20, right: 20), + child: Text( + context.l10n.enterPassword, + style: Theme.of(context).textTheme.headlineMedium, + ), + ), + Padding( + padding: const EdgeInsets.only( + bottom: 30, + left: 22, + right: 20, + ), + child: Text( + email ?? '', + style: getEnteTextTheme(context).smallMuted, + ), + ), + Visibility( + // hidden textForm for suggesting auto-fill service for saving + // password + visible: false, + child: TextFormField( + autofillHints: const [ + AutofillHints.email, + ], + autocorrect: false, + keyboardType: TextInputType.emailAddress, + initialValue: email, + textInputAction: TextInputAction.next, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(20, 24, 20, 0), + child: TextFormField( + key: const ValueKey("passwordInputField"), + autofillHints: const [AutofillHints.password], + decoration: InputDecoration( + hintText: context.l10n.enterYourPassword, + filled: true, + contentPadding: const EdgeInsets.all(20), + border: UnderlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(6), + ), + suffixIcon: _passwordInFocus + ? IconButton( + icon: Icon( + _passwordVisible + ? Icons.visibility + : Icons.visibility_off, + color: Theme.of(context).iconTheme.color, + size: 20, + ), + onPressed: () { + setState(() { + _passwordVisible = !_passwordVisible; + }); + }, + ) + : null, + ), + style: const TextStyle( + fontSize: 14, + ), + controller: _passwordController, + autofocus: true, + autocorrect: false, + obscureText: !_passwordVisible, + keyboardType: TextInputType.visiblePassword, + focusNode: _passwordFocusNode, + onChanged: (_) { + setState(() {}); + }, + ), + ), + const Padding( + padding: EdgeInsets.symmetric(vertical: 18), + child: Divider( + thickness: 1, + ), + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/lib/ui/settings/security_section_widget.dart b/lib/ui/settings/security_section_widget.dart index 272c46467..970cd3c80 100644 --- a/lib/ui/settings/security_section_widget.dart +++ b/lib/ui/settings/security_section_widget.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import "dart:typed_data"; import 'package:flutter/material.dart'; import 'package:photos/core/configuration.dart'; @@ -6,10 +7,12 @@ import 'package:photos/core/event_bus.dart'; import 'package:photos/ente_theme_data.dart'; import 'package:photos/events/two_factor_status_change_event.dart'; import "package:photos/generated/l10n.dart"; +import "package:photos/models/user_details.dart"; import 'package:photos/services/local_authentication_service.dart'; import 'package:photos/services/user_service.dart'; import 'package:photos/theme/ente_theme.dart'; import "package:photos/ui/account/recovery_key_page.dart"; +import "package:photos/ui/account/request_pwd_verification_page.dart"; import 'package:photos/ui/account/sessions_page.dart'; import 'package:photos/ui/components/captioned_text_widget.dart'; import 'package:photos/ui/components/expandable_menu_item_widget.dart'; @@ -61,7 +64,6 @@ class _SecuritySectionWidgetState extends State { } Widget _getSectionOptions(BuildContext context) { - final bool canDisableMFA = UserService.instance.getCachedUserDetails()?.profileData?.canDisableEmailMFA ?? false; final Completer completer = Completer(); final List children = []; if (_config.hasConfiguredAccount()) { @@ -133,31 +135,28 @@ class _SecuritySectionWidgetState extends State { }, ), ), - if (canDisableMFA) sectionOptionSpacing, - if (canDisableMFA) - MenuItemWidget( - captionedTextWidget: CaptionedTextWidget( - title: S.of(context).emailVerificationToggle, - ), - trailingWidget: ToggleSwitchWidget( - value: () => UserService.instance.hasEmailMFAEnabled(), - onChanged: () async { - final hasAuthenticated = await LocalAuthenticationService.instance - .requestLocalAuthentication( - context, - S.of(context).authToChangeEmailVerificationSetting, - ); - final isEmailMFAEnabled = - UserService.instance.hasEmailMFAEnabled(); - if (hasAuthenticated) { - await updateEmailMFA(!isEmailMFAEnabled); - /*if (mounted) { - setState(() {}); - }*/ - } - }, - ), + sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: CaptionedTextWidget( + title: S.of(context).emailVerificationToggle, + ), + trailingWidget: ToggleSwitchWidget( + value: () => UserService.instance.hasEmailMFAEnabled(), + onChanged: () async { + final hasAuthenticated = await LocalAuthenticationService + .instance + .requestLocalAuthentication( + context, + S.of(context).authToChangeEmailVerificationSetting, + ); + final isEmailMFAEnabled = + UserService.instance.hasEmailMFAEnabled(); + if (hasAuthenticated) { + await updateEmailMFA(!isEmailMFAEnabled); + } + }, ), + ), sectionOptionSpacing, ], ); @@ -263,6 +262,13 @@ class _SecuritySectionWidgetState extends State { } Future updateEmailMFA(bool isEnabled) async { try { + final UserDetails details = await UserService.instance.getUserDetailsV2(memoryCount: false); + if((details.profileData?.canDisableEmailMFA ?? false) == false) { + await routeToPage(context, RequestPasswordVerificationPage(onPasswordVerified: (Uint8List keyEncryptionKey) async { + final Uint8List loginKey = await CryptoUtil.deriveLoginKey(keyEncryptionKey); + await UserService.instance.registerOrUpdateSrp(loginKey); + },),); + } await UserService.instance.updateEmailMFA(isEnabled); } catch (e) { showToast(context, S.of(context).somethingWentWrong); From 5eb8da59d98e7752f58f2eeb198b1068c0caa31d Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:26:59 +0530 Subject: [PATCH 4/4] Dispose elements --- lib/ui/account/request_pwd_verification_page.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/ui/account/request_pwd_verification_page.dart b/lib/ui/account/request_pwd_verification_page.dart index 2bc9c5a3d..0c6a6cec6 100644 --- a/lib/ui/account/request_pwd_verification_page.dart +++ b/lib/ui/account/request_pwd_verification_page.dart @@ -45,6 +45,13 @@ class _RequestPasswordVerificationPageState }); } + @override + void dispose() { + _passwordController.dispose(); + _passwordFocusNode.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final isKeypadOpen = MediaQuery.of(context).viewInsets.bottom > 100;