LoginV2 changes
This commit is contained in:
parent
37ce8a55db
commit
a88cd75a5c
1 changed files with 128 additions and 82 deletions
|
@ -1,12 +1,15 @@
|
|||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:ente_auth/core/configuration.dart';
|
||||
import 'package:ente_auth/core/errors.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/services/user_service.dart';
|
||||
import 'package:ente_auth/ui/account/recovery_page.dart';
|
||||
import 'package:ente_auth/ui/common/dynamic_fab.dart';
|
||||
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
|
||||
import 'package:ente_auth/ui/home_page.dart';
|
||||
import 'package:ente_auth/utils/crypto_util.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/email_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -26,11 +29,20 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
|
|||
String? email;
|
||||
bool _passwordInFocus = false;
|
||||
bool _passwordVisible = false;
|
||||
String? _volatilePassword;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
email = Configuration.instance.getEmail();
|
||||
_volatilePassword = Configuration.instance.getVolatilePassword();
|
||||
if (_volatilePassword != null) {
|
||||
_passwordController.text = _volatilePassword!;
|
||||
Future.delayed(
|
||||
Duration.zero,
|
||||
() => verifyPassword(_volatilePassword!),
|
||||
);
|
||||
}
|
||||
_passwordFocusNode.addListener(() {
|
||||
setState(() {
|
||||
_passwordInFocus = _passwordFocusNode.hasFocus;
|
||||
|
@ -64,68 +76,13 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
|
|||
),
|
||||
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);
|
||||
await dialog.show();
|
||||
try {
|
||||
await Configuration.instance.decryptSecretsAndGetKeyEncKey(
|
||||
_passwordController.text,
|
||||
Configuration.instance.getKeyAttributes()!,
|
||||
);
|
||||
} on KeyDerivationError catch (e, s) {
|
||||
_logger.severe("Password verification failed", e, s);
|
||||
await dialog.hide();
|
||||
final dialogChoice = await showChoiceDialog(
|
||||
context,
|
||||
title: context.l10n.recreatePasswordTitle,
|
||||
body: context.l10n.recreatePasswordBody,
|
||||
firstButtonLabel: context.l10n.useRecoveryKey,
|
||||
);
|
||||
if (dialogChoice!.action == ButtonAction.first) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const RecoveryPage();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
return;
|
||||
} catch (e, s) {
|
||||
_logger.severe("Password verification failed", e, s);
|
||||
await dialog.hide();
|
||||
final dialogChoice = await showChoiceDialog(
|
||||
context,
|
||||
title: context.l10n.incorrectPasswordTitle,
|
||||
body: context.l10n.pleaseTryAgain,
|
||||
firstButtonLabel: context.l10n.contactSupport,
|
||||
secondButtonLabel: context.l10n.ok,
|
||||
);
|
||||
if (dialogChoice!.action == ButtonAction.first) {
|
||||
await sendLogs(
|
||||
context,
|
||||
context.l10n.contactSupport,
|
||||
"support@ente.io",
|
||||
postShare: () {},
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
await dialog.hide();
|
||||
unawaited(
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const HomePage();
|
||||
},
|
||||
),
|
||||
(route) => false,
|
||||
),
|
||||
);
|
||||
await verifyPassword(_passwordController.text);
|
||||
},
|
||||
),
|
||||
floatingActionButtonLocation: fabLocation(),
|
||||
|
@ -133,6 +90,90 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> verifyPassword(String password) async {
|
||||
FocusScope.of(context).unfocus();
|
||||
final dialog =
|
||||
createProgressDialog(context, context.l10n.pleaseWait);
|
||||
await dialog.show();
|
||||
try {
|
||||
final kek = await Configuration.instance.decryptSecretsAndGetKeyEncKey(
|
||||
password,
|
||||
Configuration.instance.getKeyAttributes()!,
|
||||
);
|
||||
_registerSRPForExistingUsers(kek).ignore();
|
||||
} on KeyDerivationError catch (e, s) {
|
||||
_logger.severe("Password verification failed", e, s);
|
||||
await dialog.hide();
|
||||
final dialogChoice = await showChoiceDialog(
|
||||
context,
|
||||
title: context.l10n.recreatePasswordTitle,
|
||||
body: context.l10n.recreatePasswordBody,
|
||||
firstButtonLabel: context.l10n.useRecoveryKey,
|
||||
);
|
||||
if (dialogChoice!.action == ButtonAction.first) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const RecoveryPage();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
return;
|
||||
} catch (e, s) {
|
||||
_logger.severe("Password verification failed", e, s);
|
||||
await dialog.hide();
|
||||
final dialogChoice = await showChoiceDialog(
|
||||
context,
|
||||
title: context.l10n.incorrectPasswordTitle,
|
||||
body: context.l10n.pleaseTryAgain,
|
||||
firstButtonLabel: context.l10n.contactSupport,
|
||||
secondButtonLabel: context.l10n.ok,
|
||||
);
|
||||
if (dialogChoice!.action == ButtonAction.first) {
|
||||
await sendLogs(
|
||||
context,
|
||||
context.l10n.contactSupport,
|
||||
"support@ente.io",
|
||||
postShare: () {},
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
await dialog.hide();
|
||||
Configuration.instance.setVolatilePassword(null);
|
||||
unawaited(
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const HomePage();
|
||||
},
|
||||
),
|
||||
(route) => false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _registerSRPForExistingUsers(Uint8List key) async {
|
||||
bool shouldSetupSRP = false;
|
||||
try {
|
||||
// ignore: unused_local_variable
|
||||
final attr = await UserService.instance.getSrpAttributes(email!);
|
||||
} on SrpSetupNotCompleteError {
|
||||
shouldSetupSRP = true;
|
||||
} catch (e, s) {
|
||||
_logger.severe("error while fetching attr", e, s);
|
||||
}
|
||||
if (shouldSetupSRP) {
|
||||
try {
|
||||
final Uint8List loginKey = await CryptoUtil.deriveLoginKey(key);
|
||||
await UserService.instance.registerOrUpdateSrp(loginKey);
|
||||
} catch (e, s) {
|
||||
_logger.severe("error while setting up srp for existing users", e, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widget _getBody() {
|
||||
return Column(
|
||||
children: [
|
||||
|
@ -142,10 +183,10 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
|
|||
children: [
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
|
||||
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
|
||||
child: Text(
|
||||
context.l10n.welcomeBack,
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
|
@ -165,6 +206,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
|
|||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 24, 20, 0),
|
||||
child: TextFormField(
|
||||
key: const ValueKey("passwordInputField"),
|
||||
autofillHints: const [AutofillHints.password],
|
||||
decoration: InputDecoration(
|
||||
hintText: context.l10n.enterYourPasswordHint,
|
||||
|
@ -176,19 +218,19 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
|
|||
),
|
||||
suffixIcon: _passwordInFocus
|
||||
? IconButton(
|
||||
icon: Icon(
|
||||
_passwordVisible
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
color: Theme.of(context).iconTheme.color,
|
||||
size: 20,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_passwordVisible = !_passwordVisible;
|
||||
});
|
||||
},
|
||||
)
|
||||
icon: Icon(
|
||||
_passwordVisible
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
color: Theme.of(context).iconTheme.color,
|
||||
size: 20,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_passwordVisible = !_passwordVisible;
|
||||
});
|
||||
},
|
||||
)
|
||||
: null,
|
||||
),
|
||||
style: const TextStyle(
|
||||
|
@ -230,11 +272,13 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
|
|||
child: Center(
|
||||
child: Text(
|
||||
context.l10n.forgotPassword,
|
||||
style:
|
||||
Theme.of(context).textTheme.subtitle1!.copyWith(
|
||||
fontSize: 14,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -254,11 +298,13 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
|
|||
child: Center(
|
||||
child: Text(
|
||||
context.l10n.changeEmail,
|
||||
style:
|
||||
Theme.of(context).textTheme.subtitle1!.copyWith(
|
||||
fontSize: 14,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue