diff --git a/assets/translations/en.json b/assets/translations/en.json index 45faa3e8..73c3575e 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -320,12 +320,13 @@ "delete_ssh_key": "Delete SSH key for {}" }, "validations": { - "required": "Required", - "invalid_format": "Invalid format", - "root_name": "User name cannot be 'root'", - "key_format": "Invalid key format", - "length": "Length is [] should be {}", - "user_already_exist": "Already exists", - "key_already_exists": "This key already exists" + "required": "Required.", + "invalid_format": "Invalid format.", + "root_name": "User name cannot be 'root'.", + "key_format": "Invalid key format.", + "length_not_equal": "Length is []. Should be {}.", + "length_longer": "Length is []. Should be shorter than or equal to {}.", + "user_already_exist": "This user already exists.", + "key_already_exists": "This key already exists." } } diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 619096a7..ee085ed4 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -323,9 +323,10 @@ "validations": { "required": "Обязательное поле.", "invalid_format": "Неверный формат.", - "root_name": "Имя пользователя не может быть'root'.", + "root_name": "Имя пользователя не может быть 'root'.", "key_format": "Неверный формат.", - "length": "Длина строки [] должна быть {}.", + "length_not_equal": "Длина строки []. Должно быть равно {}.", + "length_longer": "Длина строки []. Должно быть меньше либо равно {}.", "user_already_exist": "Имя уже используется.", "key_already_exists": "Этот ключ уже добавлен." } diff --git a/lib/logic/api_maps/server.dart b/lib/logic/api_maps/server.dart index 0e8930e5..1d2c3bce 100644 --- a/lib/logic/api_maps/server.dart +++ b/lib/logic/api_maps/server.dart @@ -18,7 +18,7 @@ class ApiResponse { final String? errorMessage; final D data; - get isSuccess => statusCode >= 200 && statusCode < 300; + bool get isSuccess => statusCode >= 200 && statusCode < 300; ApiResponse({ required this.statusCode, @@ -65,27 +65,48 @@ class ServerApi extends ApiMap { } Future> createUser(User user) async { - Response response; - var client = await getClient(); // POST request with JSON body containing username and password - response = await client.post( - '/users', - data: { - 'username': user.login, - 'password': user.password, - }, - options: Options( - contentType: 'application/json', - ), - ); - - close(client); - - if (response.statusCode == HttpStatus.created) { + var makeErrorApiReponse = (int status) { return ApiResponse( - statusCode: response.statusCode ?? HttpStatus.internalServerError, + statusCode: status, + data: User( + login: user.login, + password: user.password, + isFoundOnServer: false, + ), + ); + }; + + late Response response; + + try { + response = await client.post( + '/users', + data: { + 'username': user.login, + 'password': user.password, + }, + options: Options( + contentType: 'application/json', + receiveDataWhenStatusError: true, + followRedirects: false, + validateStatus: (status) { + return (status != null) && + (status < HttpStatus.internalServerError); + }), + ); + } catch (e) { + return makeErrorApiReponse(HttpStatus.internalServerError); + } finally { + close(client); + } + + if ((response.statusCode != null) && + (response.statusCode == HttpStatus.created)) { + return ApiResponse( + statusCode: response.statusCode!, data: User( login: user.login, password: user.password, @@ -93,18 +114,11 @@ class ServerApi extends ApiMap { ), ); } else { - return ApiResponse( - statusCode: response.statusCode ?? HttpStatus.internalServerError, - data: User( - login: user.login, - password: user.password, - isFoundOnServer: false, - note: response.data['message'] ?? null, - ), - errorMessage: response.data?.containsKey('error') ?? false - ? response.data['error'] - : null, - ); + print(response.statusCode.toString() + + ": " + + (response.statusMessage ?? "")); + return makeErrorApiReponse( + response.statusCode ?? HttpStatus.internalServerError); } } diff --git a/lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart b/lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart index eda06939..d8777fa8 100644 --- a/lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart +++ b/lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart @@ -12,9 +12,6 @@ class BackblazeFormCubit extends FormCubit { initalValue: '', validations: [ RequiredStringValidation('validations.required'.tr()), - //ValidationModel( - //(s) => regExp.hasMatch(s), 'invalid key format'), - //LegnthStringValidationWithLenghShowing(64, 'length is [] shoud be 64') ], ); @@ -22,9 +19,6 @@ class BackblazeFormCubit extends FormCubit { initalValue: '', validations: [ RequiredStringValidation('required'), - //ValidationModel( - //(s) => regExp.hasMatch(s), 'invalid key format'), - //LegnthStringValidationWithLenghShowing(64, 'length is [] shoud be 64') ], ); diff --git a/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart b/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart index 7ee8c8fa..d811843b 100644 --- a/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart +++ b/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart @@ -4,8 +4,7 @@ import 'package:cubit_form/cubit_form.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:selfprivacy/logic/api_maps/cloudflare.dart'; import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart'; - -import '../validations/validations.dart'; +import 'package:selfprivacy/logic/cubit/forms/validations/validations.dart'; class CloudFlareFormCubit extends FormCubit { CloudFlareFormCubit(this.initializingCubit) { @@ -16,12 +15,7 @@ class CloudFlareFormCubit extends FormCubit { RequiredStringValidation('validations.required'.tr()), ValidationModel( (s) => regExp.hasMatch(s), 'validations.key_format'.tr()), - LengthStringValidationWithLengthShowing( - 40, - 'validations.length'.tr( - args: ["40"], - ), - ) + LengthStringNotEqualValidation(40) ], ); diff --git a/lib/logic/cubit/forms/initializing/hetzner_form_cubit.dart b/lib/logic/cubit/forms/initializing/hetzner_form_cubit.dart index 55af50d9..ce3e5aa9 100644 --- a/lib/logic/cubit/forms/initializing/hetzner_form_cubit.dart +++ b/lib/logic/cubit/forms/initializing/hetzner_form_cubit.dart @@ -4,8 +4,7 @@ import 'package:cubit_form/cubit_form.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:selfprivacy/logic/api_maps/hetzner.dart'; import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart'; - -import '../validations/validations.dart'; +import 'package:selfprivacy/logic/cubit/forms/validations/validations.dart'; class HetznerFormCubit extends FormCubit { HetznerFormCubit(this.initializingCubit) { @@ -16,8 +15,7 @@ class HetznerFormCubit extends FormCubit { RequiredStringValidation('validations.required'.tr()), ValidationModel( (s) => regExp.hasMatch(s), 'validations.key_format'.tr()), - LengthStringValidationWithLengthShowing( - 64, 'validations.length'.tr(args: ["64"])) + LengthStringNotEqualValidation(64) ], ); diff --git a/lib/logic/cubit/forms/user/user_form_cubit.dart b/lib/logic/cubit/forms/user/user_form_cubit.dart index 24f67437..4f0e6488 100644 --- a/lib/logic/cubit/forms/user/user_form_cubit.dart +++ b/lib/logic/cubit/forms/user/user_form_cubit.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:cubit_form/cubit_form.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:selfprivacy/logic/cubit/forms/validations/validations.dart'; import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart'; import 'package:selfprivacy/logic/models/job.dart'; import 'package:selfprivacy/logic/models/user.dart'; @@ -15,8 +16,10 @@ class UserFormCubit extends FormCubit { }) { var isEdit = user != null; - var userRegExp = RegExp(r"\W"); - var passwordRegExp = RegExp(r"[\n\r\s]+"); + var userAllowedRegExp = RegExp(r"^[a-z_][a-z0-9_]+$"); + const userMaxLength = 31; + + var passwordForbiddenRegExp = RegExp(r"[\n\r\s]+"); login = FieldCubit( initalValue: isEdit ? user!.login : '', @@ -28,8 +31,9 @@ class UserFormCubit extends FormCubit { 'validations.user_already_exist'.tr(), ), RequiredStringValidation('validations.required'.tr()), - ValidationModel( - (s) => userRegExp.hasMatch(s), 'validations.invalid_format'.tr()), + LengthStringLongerValidation(userMaxLength), + ValidationModel((s) => !userAllowedRegExp.hasMatch(s), + 'validations.invalid_format'.tr()), ], ); @@ -38,7 +42,7 @@ class UserFormCubit extends FormCubit { isEdit ? (user?.password ?? '') : StringGenerators.userPassword(), validations: [ RequiredStringValidation('validations.required'.tr()), - ValidationModel((s) => passwordRegExp.hasMatch(s), + ValidationModel((s) => passwordForbiddenRegExp.hasMatch(s), 'validations.invalid_format'.tr()), ], ); diff --git a/lib/logic/cubit/forms/validations/validations.dart b/lib/logic/cubit/forms/validations/validations.dart index aff4ec92..34338559 100644 --- a/lib/logic/cubit/forms/validations/validations.dart +++ b/lib/logic/cubit/forms/validations/validations.dart @@ -1,13 +1,28 @@ import 'package:cubit_form/cubit_form.dart'; +import 'package:easy_localization/easy_localization.dart'; -class LengthStringValidationWithLengthShowing extends ValidationModel { - LengthStringValidationWithLengthShowing(int length, String errorText) - : super((n) => n.length != length, errorText); +abstract class LengthStringValidation extends ValidationModel { + LengthStringValidation(bool Function(String) predicate, String errorMessage) + : super(predicate, errorMessage); @override - String? check(String val) { - var length = val.length; - var errorMassage = this.errorMassage.replaceAll("[]", length.toString()); - return test(val) ? errorMassage : null; + String? check(String value) { + var length = value.length; + var errorMessage = this.errorMassage.replaceAll("[]", length.toString()); + return test(value) ? errorMessage : null; } } + +// String must be equal to [length] +class LengthStringNotEqualValidation extends LengthStringValidation { + LengthStringNotEqualValidation(int length) + : super((n) => n.length != length, + 'validations.length_not_equal'.tr(args: [length.toString()])); +} + +// String must be shorter than or equal to [length] +class LengthStringLongerValidation extends LengthStringValidation { + LengthStringLongerValidation(int length) + : super((n) => n.length > length, + 'validations.length_longer'.tr(args: [length.toString()])); +} diff --git a/lib/logic/cubit/users/users_cubit.dart b/lib/logic/cubit/users/users_cubit.dart index 65967a9a..0fd27064 100644 --- a/lib/logic/cubit/users/users_cubit.dart +++ b/lib/logic/cubit/users/users_cubit.dart @@ -160,7 +160,12 @@ class UsersCubit extends AppConfigDependendCubit { if (user.login == 'root' || user.login == state.primaryUser.login) { return; } + // If API returned error, do nothing final result = await api.createUser(user); + if (!result.isSuccess) { + return; + } + var loadedUsers = List.from(state.users); loadedUsers.add(result.data); await box.clear();