97 lines
2.4 KiB
Dart
97 lines
2.4 KiB
Dart
/// Validation and normalization logic for MotorSignal rider handles.
|
|
class HandleValidationResult {
|
|
final bool isValid;
|
|
final String? error;
|
|
final String? normalizedHandle;
|
|
|
|
const HandleValidationResult._({
|
|
required this.isValid,
|
|
this.error,
|
|
this.normalizedHandle,
|
|
});
|
|
|
|
factory HandleValidationResult.valid(String normalized) =>
|
|
HandleValidationResult._(isValid: true, normalizedHandle: normalized);
|
|
|
|
factory HandleValidationResult.invalid(String error) =>
|
|
HandleValidationResult._(isValid: false, error: error);
|
|
}
|
|
|
|
class HandleValidator {
|
|
static const int minLength = 3;
|
|
static const int maxLength = 20;
|
|
|
|
static final RegExp _formatRegex = RegExp(r'^[a-z][a-z0-9_]{2,19}$');
|
|
|
|
static const Set<String> reservedHandles = {
|
|
'admin',
|
|
'administrator',
|
|
'motorsignal',
|
|
'motorcloud',
|
|
'support',
|
|
'system',
|
|
'mod',
|
|
'moderator',
|
|
'help',
|
|
'official',
|
|
'root',
|
|
'api',
|
|
'bot',
|
|
'test',
|
|
'dev',
|
|
'developer',
|
|
'staff',
|
|
'security',
|
|
'null',
|
|
'undefined',
|
|
'guest',
|
|
'anonymous',
|
|
'safety',
|
|
'emergency',
|
|
'police',
|
|
'marshal',
|
|
'leader',
|
|
'host',
|
|
};
|
|
|
|
/// Normalizes a handle: trims whitespace and lowercases.
|
|
static String normalize(String handle) => handle.trim().toLowerCase();
|
|
|
|
/// Validates a handle format and checks against reserved names.
|
|
static HandleValidationResult validate(String rawHandle) {
|
|
final normalized = normalize(rawHandle);
|
|
|
|
if (normalized.isEmpty) {
|
|
return HandleValidationResult.invalid('Handle cannot be empty');
|
|
}
|
|
|
|
if (normalized.length < minLength) {
|
|
return HandleValidationResult.invalid(
|
|
'Handle must be at least $minLength characters',
|
|
);
|
|
}
|
|
|
|
if (normalized.length > maxLength) {
|
|
return HandleValidationResult.invalid(
|
|
'Handle cannot exceed $maxLength characters',
|
|
);
|
|
}
|
|
|
|
if (!RegExp(r'^[a-z]').hasMatch(normalized)) {
|
|
return HandleValidationResult.invalid('Handle must start with a letter');
|
|
}
|
|
|
|
if (!_formatRegex.hasMatch(normalized)) {
|
|
return HandleValidationResult.invalid(
|
|
'Handle can only contain lowercase letters, numbers, and underscores',
|
|
);
|
|
}
|
|
|
|
if (reservedHandles.contains(normalized)) {
|
|
return HandleValidationResult.invalid('This handle is reserved');
|
|
}
|
|
|
|
return HandleValidationResult.valid(normalized);
|
|
}
|
|
}
|