mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-27 11:16:45 +00:00
Fix username validation and exception handling
1. Refactor string validation classes 2. Rename string validation assets for length 3. Improve exception handling when server is not able to create requested server
This commit is contained in:
parent
265cc15ea5
commit
4c99579f13
|
@ -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."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": "Этот ключ уже добавлен."
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class ApiResponse<D> {
|
|||
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<ApiResponse<User>> 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<dynamic> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,6 @@ class BackblazeFormCubit extends FormCubit {
|
|||
initalValue: '',
|
||||
validations: [
|
||||
RequiredStringValidation('validations.required'.tr()),
|
||||
//ValidationModel<String>(
|
||||
//(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<String>(
|
||||
//(s) => regExp.hasMatch(s), 'invalid key format'),
|
||||
//LegnthStringValidationWithLenghShowing(64, 'length is [] shoud be 64')
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
@ -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<String>(
|
||||
(s) => regExp.hasMatch(s), 'validations.key_format'.tr()),
|
||||
LengthStringValidationWithLengthShowing(
|
||||
40,
|
||||
'validations.length'.tr(
|
||||
args: ["40"],
|
||||
),
|
||||
)
|
||||
LengthStringNotEqualValidation(40)
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
@ -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<String>(
|
||||
(s) => regExp.hasMatch(s), 'validations.key_format'.tr()),
|
||||
LengthStringValidationWithLengthShowing(
|
||||
64, 'validations.length'.tr(args: ["64"]))
|
||||
LengthStringNotEqualValidation(64)
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
@ -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<String>(
|
||||
(s) => userRegExp.hasMatch(s), 'validations.invalid_format'.tr()),
|
||||
LengthStringLongerValidation(userMaxLength),
|
||||
ValidationModel<String>((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<String>((s) => passwordRegExp.hasMatch(s),
|
||||
ValidationModel<String>((s) => passwordForbiddenRegExp.hasMatch(s),
|
||||
'validations.invalid_format'.tr()),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -1,13 +1,28 @@
|
|||
import 'package:cubit_form/cubit_form.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
class LengthStringValidationWithLengthShowing extends ValidationModel<String> {
|
||||
LengthStringValidationWithLengthShowing(int length, String errorText)
|
||||
: super((n) => n.length != length, errorText);
|
||||
abstract class LengthStringValidation extends ValidationModel<String> {
|
||||
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()]));
|
||||
}
|
||||
|
|
|
@ -160,7 +160,12 @@ class UsersCubit extends AppConfigDependendCubit<UsersState> {
|
|||
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<User>.from(state.users);
|
||||
loadedUsers.add(result.data);
|
||||
await box.clear();
|
||||
|
|
Loading…
Reference in a new issue