mirror of
				https://gitlab.com/comunic/comunicmobile
				synced 2025-11-04 04:04:18 +00:00 
			
		
		
		
	Can change security settings
This commit is contained in:
		@@ -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();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								lib/models/security_settings.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								lib/models/security_settings.dart
									
									
									
									
									
										Normal 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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user