1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-22 12:59:21 +00:00

Can change security settings

This commit is contained in:
Pierre HUBERT 2020-05-01 09:02:15 +02:00
parent 289bf30a40
commit 20ea964337
3 changed files with 177 additions and 0 deletions

View File

@ -5,6 +5,7 @@ import 'package:comunic/models/account_image_settings.dart';
import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/api_request.dart';
import 'package:comunic/models/general_settings.dart'; import 'package:comunic/models/general_settings.dart';
import 'package:comunic/models/new_emoji.dart'; import 'package:comunic/models/new_emoji.dart';
import 'package:comunic/models/security_settings.dart';
/// Settings helper /// Settings helper
/// ///
@ -161,4 +162,36 @@ class SettingsHelper {
.addString("oldPassword", oldPassword) .addString("oldPassword", oldPassword)
.addString("newPassword", newPassword) .addString("newPassword", newPassword)
.execWithThrow(); .execWithThrow();
/// Retrieve security settings of the user
///
/// This method throws in case of failure
static Future<SecuritySettings> getSecuritySettings(String password) async {
final response =
(await APIRequest(uri: "settings/get_security", needLogin: true)
.addString("password", password)
.execWithThrow())
.getObject();
return SecuritySettings(
securityQuestion1: response["security_question_1"],
securityAnswer1: response["security_answer_1"],
securityQuestion2: response["security_question_2"],
securityAnswer2: response["security_answer_2"],
);
}
/// Apply new security settings to the user
///
/// Throws in case of failure
static Future<void> setSecuritySettings(
String password, SecuritySettings newSettings) async {
await APIRequest(uri: "settings/set_security", needLogin: true)
.addString("password", password)
.addString("security_question_1", newSettings.securityQuestion1)
.addString("security_answer_1", newSettings.securityAnswer1)
.addString("security_question_2", newSettings.securityQuestion2)
.addString("security_answer_2", newSettings.securityAnswer2)
.execWithThrow();
}
} }

View File

@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
/// Security settings of the user
///
/// @author Pierre HUBERT
class SecuritySettings {
final String securityQuestion1;
final String securityAnswer1;
final String securityQuestion2;
final String securityAnswer2;
const SecuritySettings({
@required this.securityQuestion1,
@required this.securityAnswer1,
@required this.securityQuestion2,
@required this.securityAnswer2,
}) : assert(securityQuestion1 != null),
assert(securityAnswer1 != null),
assert(securityQuestion2 != null),
assert(securityAnswer2 != null);
}

View File

@ -1,6 +1,8 @@
import 'package:comunic/helpers/settings_helper.dart'; import 'package:comunic/helpers/settings_helper.dart';
import 'package:comunic/models/security_settings.dart';
import 'package:comunic/ui/dialogs/input_new_password_dialog.dart'; import 'package:comunic/ui/dialogs/input_new_password_dialog.dart';
import 'package:comunic/ui/dialogs/input_user_password_dialog.dart'; import 'package:comunic/ui/dialogs/input_user_password_dialog.dart';
import 'package:comunic/ui/widgets/auto_sized_dialog_content_widget.dart';
import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart'; import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -41,6 +43,12 @@ class __AccountSecuritySettingsScreenBodyState
title: tr("Change password"), title: tr("Change password"),
onTap: _changePassword, onTap: _changePassword,
), ),
SettingsTile(
title: tr("Change your security questions"),
subtitle: tr(
"Your security questions can be used to recover an access to your account when you loose your password..."),
onTap: _changeSecurityQuestions,
),
], ],
) )
], ],
@ -67,4 +75,118 @@ class __AccountSecuritySettingsScreenBodyState
showSimpleSnack(context, tr("Could not update password!")); showSimpleSnack(context, tr("Could not update password!"));
} }
} }
/// Change security questions
void _changeSecurityQuestions() async {
try {
final password = await showUserPasswordDialog(context);
if (password == null) return;
final settings = await SettingsHelper.getSecuritySettings(password);
final newSettings = await showDialog<SecuritySettings>(
context: context,
builder: (c) => _SecurityQuestionsDialog(settings: settings));
if (newSettings == null) return;
await SettingsHelper.setSecuritySettings(password, newSettings);
showSimpleSnack(context,
tr("You security questions have been successfully updated!"));
} catch (e, stack) {
print("Could not update security questions!$e\n$stack");
showSimpleSnack(context, tr("Could not update security questions!"));
}
}
}
class _SecurityQuestionsDialog extends StatefulWidget {
final SecuritySettings settings;
const _SecurityQuestionsDialog({Key key, @required this.settings})
: assert(settings != null),
super(key: key);
@override
__SecurityQuestionsDialogState createState() =>
__SecurityQuestionsDialogState();
}
class __SecurityQuestionsDialogState extends State<_SecurityQuestionsDialog> {
TextEditingController _controllerQuestion1;
TextEditingController _controllerAnswer1;
TextEditingController _controllerQuestion2;
TextEditingController _controllerAnswer2;
SecuritySettings get _newSettings => SecuritySettings(
securityQuestion1: _controllerQuestion1.text,
securityAnswer1: _controllerAnswer1.text,
securityQuestion2: _controllerQuestion2.text,
securityAnswer2: _controllerAnswer2.text,
);
@override
void initState() {
_controllerQuestion1 =
TextEditingController(text: widget.settings.securityQuestion1);
_controllerAnswer1 =
TextEditingController(text: widget.settings.securityAnswer1);
_controllerQuestion2 =
TextEditingController(text: widget.settings.securityQuestion2);
_controllerAnswer2 =
TextEditingController(text: widget.settings.securityAnswer2);
super.initState();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(tr("Update security questions")),
content: AutoSizeDialogContentWidget(child: _buildContent()),
actions: <Widget>[
MaterialButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(tr("Cancel").toUpperCase()),
),
MaterialButton(
onPressed: () => Navigator.of(context).pop(_newSettings),
child: Text(tr("Update").toUpperCase()),
)
],
);
}
Widget _buildContent() {
return Column(
children: <Widget>[
Text(tr(
"Note: Your two questions and answers MUST be completed in order to be able to recover your account using your security questions!")),
_buildTextField(
controller: _controllerQuestion1, label: tr("Question 1")),
_buildTextField(controller: _controllerAnswer1, label: tr("Answer 1")),
_buildTextField(
controller: _controllerQuestion2, label: tr("Question 2")),
_buildTextField(controller: _controllerAnswer2, label: tr("Answer 2")),
],
);
}
Widget _buildTextField({
@required TextEditingController controller,
@required String label,
}) {
return TextField(
controller: controller,
onChanged: (s) => setState(() {}),
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: label,
errorText: controller.text.isNotEmpty && controller.text.length < 5
? tr("Unsafe value!")
: null,
),
);
}
} }