2FA reset via SMS
This commit is contained in:
parent
aa486ab314
commit
00b979c731
|
|
@ -77,6 +77,7 @@ class _LoginState extends State<LoginView> {
|
||||||
bool _createAccount = false;
|
bool _createAccount = false;
|
||||||
|
|
||||||
bool _recoverPassword = false;
|
bool _recoverPassword = false;
|
||||||
|
bool _disable2FA = false;
|
||||||
bool _termsChecked = false;
|
bool _termsChecked = false;
|
||||||
bool _privacyChecked = false;
|
bool _privacyChecked = false;
|
||||||
|
|
||||||
|
|
@ -235,6 +236,7 @@ class _LoginState extends State<LoginView> {
|
||||||
_loginError = '';
|
_loginError = '';
|
||||||
if (_recoverPassword) {
|
if (_recoverPassword) {
|
||||||
_recoverPassword = false;
|
_recoverPassword = false;
|
||||||
|
_disable2FA = false;
|
||||||
_buttonController.reset();
|
_buttonController.reset();
|
||||||
showDialog<MessageDialog>(
|
showDialog<MessageDialog>(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
@ -269,6 +271,14 @@ class _LoginState extends State<LoginView> {
|
||||||
url: url,
|
url: url,
|
||||||
secret: _isSelfHosted ? _secretController.text : '',
|
secret: _isSelfHosted ? _secretController.text : '',
|
||||||
);
|
);
|
||||||
|
} else if (_disable2FA) {
|
||||||
|
viewModel.onDisable2FAPressed(
|
||||||
|
context,
|
||||||
|
completer,
|
||||||
|
email: _emailController.text,
|
||||||
|
url: url,
|
||||||
|
secret: _isSelfHosted ? _secretController.text : '',
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
viewModel.onLoginPressed(
|
viewModel.onLoginPressed(
|
||||||
context,
|
context,
|
||||||
|
|
@ -599,24 +609,29 @@ class _LoginState extends State<LoginView> {
|
||||||
),
|
),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
_recoverPassword
|
_disable2FA
|
||||||
? localization.recoverPassword
|
? localization.disable2fa
|
||||||
: _createAccount
|
: _recoverPassword
|
||||||
? (_loginType == LOGIN_TYPE_EMAIL
|
? localization.recoverPassword
|
||||||
? localization.emailSignUp
|
: _createAccount
|
||||||
: _loginType ==
|
? (_loginType ==
|
||||||
LOGIN_TYPE_MICROSOFT
|
LOGIN_TYPE_EMAIL
|
||||||
? localization
|
? localization.emailSignUp
|
||||||
.microsoftSignUp
|
: _loginType ==
|
||||||
: localization.googleSignUp)
|
LOGIN_TYPE_MICROSOFT
|
||||||
: (_loginType == LOGIN_TYPE_EMAIL
|
? localization
|
||||||
? localization.emailSignIn
|
.microsoftSignUp
|
||||||
: _loginType ==
|
: localization
|
||||||
LOGIN_TYPE_MICROSOFT
|
.googleSignUp)
|
||||||
? localization
|
: (_loginType ==
|
||||||
.microsoftSignIn
|
LOGIN_TYPE_EMAIL
|
||||||
: localization
|
? localization.emailSignIn
|
||||||
.googleSignIn),
|
: _loginType ==
|
||||||
|
LOGIN_TYPE_MICROSOFT
|
||||||
|
? localization
|
||||||
|
.microsoftSignIn
|
||||||
|
: localization
|
||||||
|
.googleSignIn),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18, color: Colors.white),
|
fontSize: 18, color: Colors.white),
|
||||||
)
|
)
|
||||||
|
|
@ -662,11 +677,34 @@ class _LoginState extends State<LoginView> {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (!_createAccount)
|
if (_recoverPassword) ...[
|
||||||
|
if (!_disable2FA)
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_disable2FA = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(14),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(Icons.lock, size: 16),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
Text(localization.disable2fa),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_recoverPassword = !_recoverPassword;
|
if (_disable2FA) {
|
||||||
|
_disable2FA = false;
|
||||||
|
} else {
|
||||||
|
_recoverPassword = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|
@ -675,67 +713,88 @@ class _LoginState extends State<LoginView> {
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (!_recoverPassword)
|
Icon(Icons.cancel, size: 16),
|
||||||
Icon(MdiIcons.lock, size: 16),
|
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Text(_recoverPassword
|
Text(localization.cancel),
|
||||||
? localization.cancel
|
|
||||||
: localization.recoverPassword),
|
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!_recoverPassword && !_isSelfHosted)
|
] else ...[
|
||||||
InkWell(
|
if (!_createAccount)
|
||||||
onTap: () {
|
InkWell(
|
||||||
launchUrl(Uri.parse(kStatusCheckUrl));
|
onTap: () {
|
||||||
},
|
setState(() {
|
||||||
child: Padding(
|
_recoverPassword = true;
|
||||||
padding: const EdgeInsets.all(14),
|
});
|
||||||
child: Row(
|
},
|
||||||
mainAxisSize: MainAxisSize.max,
|
child: Padding(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
padding: const EdgeInsets.all(14),
|
||||||
children: [
|
child: Row(
|
||||||
Icon(Icons.security, size: 16),
|
mainAxisSize: MainAxisSize.max,
|
||||||
SizedBox(width: 8),
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
Text(localization.checkStatus)
|
children: <Widget>[
|
||||||
],
|
if (!_recoverPassword)
|
||||||
|
Icon(MdiIcons.lock, size: 16),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
Text(_recoverPassword
|
||||||
|
? localization.cancel
|
||||||
|
: localization.recoverPassword),
|
||||||
|
]),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
if (!_recoverPassword && !_isSelfHosted)
|
||||||
if (!_recoverPassword)
|
|
||||||
if (kIsWeb)
|
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () =>
|
onTap: () {
|
||||||
launchUrl(Uri.parse(getNativeAppUrl(platform))),
|
launchUrl(Uri.parse(kStatusCheckUrl));
|
||||||
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(14),
|
padding: const EdgeInsets.all(14),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(getNativeAppIcon(platform), size: 16),
|
Icon(Icons.security, size: 16),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Text('$platform ${localization.app}')
|
Text(localization.checkStatus)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
else
|
if (!_recoverPassword)
|
||||||
InkWell(
|
if (kIsWeb)
|
||||||
onTap: () => launchUrl(Uri.parse(kDocsUrl)),
|
InkWell(
|
||||||
child: Padding(
|
onTap: () =>
|
||||||
padding: const EdgeInsets.all(14),
|
launchUrl(Uri.parse(getNativeAppUrl(platform))),
|
||||||
child: Row(
|
child: Padding(
|
||||||
mainAxisSize: MainAxisSize.max,
|
padding: const EdgeInsets.all(14),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Row(
|
||||||
children: [
|
mainAxisSize: MainAxisSize.max,
|
||||||
Icon(Icons.book, size: 16),
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
SizedBox(width: 8),
|
children: [
|
||||||
Text(localization.documentation)
|
Icon(getNativeAppIcon(platform), size: 16),
|
||||||
],
|
SizedBox(width: 8),
|
||||||
|
Text('$platform ${localization.app}')
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
)
|
else
|
||||||
|
InkWell(
|
||||||
|
onTap: () => launchUrl(Uri.parse(kDocsUrl)),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(14),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.book, size: 16),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
Text(localization.documentation)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ class LoginVM {
|
||||||
@required this.authState,
|
@required this.authState,
|
||||||
@required this.onLoginPressed,
|
@required this.onLoginPressed,
|
||||||
@required this.onRecoverPressed,
|
@required this.onRecoverPressed,
|
||||||
|
@required this.onDisable2FAPressed,
|
||||||
@required this.onSignUpPressed,
|
@required this.onSignUpPressed,
|
||||||
@required this.onGoogleLoginPressed,
|
@required this.onGoogleLoginPressed,
|
||||||
@required this.onGoogleSignUpPressed,
|
@required this.onGoogleSignUpPressed,
|
||||||
|
|
@ -89,6 +90,14 @@ class LoginVM {
|
||||||
@required String secret,
|
@required String secret,
|
||||||
}) onRecoverPressed;
|
}) onRecoverPressed;
|
||||||
|
|
||||||
|
final Function(
|
||||||
|
BuildContext,
|
||||||
|
Completer<Null> completer, {
|
||||||
|
@required String email,
|
||||||
|
@required String url,
|
||||||
|
@required String secret,
|
||||||
|
}) onDisable2FAPressed;
|
||||||
|
|
||||||
final Function(
|
final Function(
|
||||||
BuildContext,
|
BuildContext,
|
||||||
Completer<Null> completer, {
|
Completer<Null> completer, {
|
||||||
|
|
@ -376,6 +385,24 @@ class LoginVM {
|
||||||
secret: secret.trim(),
|
secret: secret.trim(),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
onDisable2FAPressed: (
|
||||||
|
BuildContext context,
|
||||||
|
Completer<Null> completer, {
|
||||||
|
@required String email,
|
||||||
|
@required String url,
|
||||||
|
@required String secret,
|
||||||
|
}) async {
|
||||||
|
if (store.state.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
store.dispatch(RecoverPasswordRequest(
|
||||||
|
completer: completer,
|
||||||
|
email: email.trim(),
|
||||||
|
url: _formatApiUrl(url),
|
||||||
|
secret: secret.trim(),
|
||||||
|
));
|
||||||
|
},
|
||||||
onLoginPressed: (
|
onLoginPressed: (
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
Completer<Null> completer, {
|
Completer<Null> completer, {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
||||||
static final Map<String, Map<String, String>> _localizedValues = {
|
static final Map<String, Map<String, String>> _localizedValues = {
|
||||||
'en': {
|
'en': {
|
||||||
// STARTER: lang key - do not remove comment
|
// STARTER: lang key - do not remove comment
|
||||||
|
'disable_2fa': 'Disable 2FA',
|
||||||
'change_number': 'Change Number',
|
'change_number': 'Change Number',
|
||||||
'resend_code': 'Resend Code',
|
'resend_code': 'Resend Code',
|
||||||
'base_type': 'Base Type',
|
'base_type': 'Base Type',
|
||||||
|
|
@ -87487,6 +87488,11 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
||||||
_localizedValues[localeCode]['change_number'] ??
|
_localizedValues[localeCode]['change_number'] ??
|
||||||
_localizedValues['en']['change_number'];
|
_localizedValues['en']['change_number'];
|
||||||
|
|
||||||
|
String get disable2fa =>
|
||||||
|
_localizedValues[localeCode]['disable_2fa'] ??
|
||||||
|
_localizedValues['en']['disable_2fa'];
|
||||||
|
|
||||||
|
|
||||||
// STARTER: lang field - do not remove comment
|
// STARTER: lang field - do not remove comment
|
||||||
|
|
||||||
String lookup(String key) {
|
String lookup(String key) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue