mirror of
https://gitlab.com/comunic/comunicmobile
synced 2024-11-22 21:09:21 +00:00
150 lines
4.5 KiB
Dart
150 lines
4.5 KiB
Dart
import 'package:comunic/helpers/server_config_helper.dart';
|
|
import 'package:comunic/models/server_config.dart';
|
|
import 'package:comunic/utils/intl_utils.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
/// New password input widget
|
|
///
|
|
/// @author Pierre Hubert
|
|
|
|
class UserInfoForPassword {
|
|
final String? firstName;
|
|
final String? lastName;
|
|
final String? email;
|
|
|
|
const UserInfoForPassword({
|
|
required this.firstName,
|
|
required this.lastName,
|
|
required this.email,
|
|
});
|
|
}
|
|
|
|
class NewPasswordInputWidget extends StatefulWidget {
|
|
final Widget? icon;
|
|
final VoidCallback? onEdited;
|
|
final VoidCallback? onSubmitted;
|
|
final TextInputAction? textInputAction;
|
|
final String label;
|
|
|
|
final UserInfoForPassword user;
|
|
|
|
const NewPasswordInputWidget({
|
|
Key? key,
|
|
this.icon,
|
|
this.onEdited,
|
|
this.onSubmitted,
|
|
this.textInputAction,
|
|
required this.label,
|
|
required this.user,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
NewPasswordInputWidgetState createState() => NewPasswordInputWidgetState();
|
|
}
|
|
|
|
class NewPasswordInputWidgetState extends State<NewPasswordInputWidget> {
|
|
final TextEditingController _controller = TextEditingController();
|
|
|
|
String get value => _controller.text;
|
|
|
|
bool get valid => value.isNotEmpty && (_errorMessage ?? "").isEmpty;
|
|
|
|
PasswordPolicy get _policy => ServerConfigurationHelper.config!.passwordPolicy;
|
|
|
|
@override
|
|
void didUpdateWidget(covariant NewPasswordInputWidget oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
setState(() {});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) => TextField(
|
|
controller: _controller,
|
|
obscureText: true,
|
|
onChanged: (s) => _onChanged(),
|
|
onSubmitted:
|
|
widget.onSubmitted == null ? null : (s) => widget.onSubmitted!(),
|
|
textInputAction: widget.textInputAction,
|
|
decoration: InputDecoration(
|
|
errorText: _errorMessage,
|
|
errorMaxLines: 3,
|
|
icon: widget.icon,
|
|
labelText: widget.label,
|
|
),
|
|
);
|
|
|
|
void _onChanged() {
|
|
setState(() {});
|
|
if (widget.onEdited != null) widget.onEdited!();
|
|
}
|
|
|
|
/// Generate an error message associated with current password
|
|
String? get _errorMessage {
|
|
if (value.isEmpty) return null;
|
|
|
|
// Mandatory checks
|
|
if (!_policy.allowMailInPassword &&
|
|
(widget.user.email ?? "").isNotEmpty &&
|
|
(widget.user.email!.toLowerCase().contains(value.toLowerCase()) ||
|
|
value.toLowerCase().contains(widget.user.email!.toLowerCase()))) {
|
|
return tr("Your password must not contains part of your email address!");
|
|
}
|
|
|
|
if (!_policy.allowNameInPassword &&
|
|
(widget.user.firstName ?? "").isNotEmpty &&
|
|
value.toLowerCase().contains(widget.user.firstName!.toLowerCase())) {
|
|
return tr("Your password must not contains your first name!");
|
|
}
|
|
|
|
if (!_policy.allowNameInPassword &&
|
|
(widget.user.lastName ?? "").isNotEmpty &&
|
|
value.toLowerCase().contains(widget.user.lastName!.toLowerCase())) {
|
|
return tr("Your password must not contains your last name!");
|
|
}
|
|
|
|
if (_policy.minPasswordLength > value.length) {
|
|
return tr(
|
|
"Your password must be composed of at least %num% characters!",
|
|
args: {
|
|
"num": _policy.minPasswordLength.toString(),
|
|
},
|
|
);
|
|
}
|
|
|
|
// Characteristics check
|
|
var count = 0;
|
|
|
|
if (_hasCharacteristic(RegExp(r'[A-Z]'), _policy.minNumberUpperCaseLetters))
|
|
count++;
|
|
|
|
if (_hasCharacteristic(RegExp(r'[a-z]'), _policy.minNumberLowerCaseLetters))
|
|
count++;
|
|
|
|
if (_hasCharacteristic(RegExp(r'[0-9]'), _policy.minNumberDigits)) count++;
|
|
|
|
if (_hasCharacteristic(
|
|
RegExp(r'[^A-Za-z0-9]'), _policy.minNumberSpecialCharacters)) count++;
|
|
|
|
if (count >= _policy.minCategoriesPresence) return null;
|
|
|
|
return tr(
|
|
"Your password must contains characters of at least %num% of the following categories : %upper% upper case letter, %lower% lowercase letter, %digit% digit, %special% special character.",
|
|
args: {
|
|
"num": (_policy.minCategoriesPresence == 4
|
|
? tr("ALL")
|
|
: _policy.minCategoriesPresence.toString()),
|
|
"upper": _policy.minNumberUpperCaseLetters.toString(),
|
|
"lower": _policy.minNumberLowerCaseLetters.toString(),
|
|
"digit": _policy.minNumberDigits.toString(),
|
|
"special": _policy.minNumberSpecialCharacters.toString(),
|
|
},
|
|
);
|
|
}
|
|
|
|
bool _hasCharacteristic(RegExp exp, int requiredCount) {
|
|
if (requiredCount < 1) return true;
|
|
|
|
return exp.allMatches(value).length >= requiredCount;
|
|
}
|
|
}
|