@umituz/react-native-validation 1.4.3 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -1
- package/src/infrastructure/utils/sanitization.ts +99 -0
- package/README.md +0 -245
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-validation",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.5",
|
|
4
4
|
"description": "Comprehensive validation and sanitization utilities for React Native forms",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -29,7 +29,9 @@
|
|
|
29
29
|
"react-native": ">=0.74.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.0.3",
|
|
32
33
|
"@types/react": "~19.1.10",
|
|
34
|
+
"@types/react-native": "^0.72.8",
|
|
33
35
|
"react": "19.1.0",
|
|
34
36
|
"react-native": "0.81.5",
|
|
35
37
|
"typescript": "~5.9.2"
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitization Utilities
|
|
3
|
+
* Secure input cleaning for user data
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Security constants for input validation
|
|
8
|
+
*/
|
|
9
|
+
export const SECURITY_LIMITS = {
|
|
10
|
+
EMAIL_MAX_LENGTH: 254, // RFC 5321
|
|
11
|
+
PASSWORD_MIN_LENGTH: 6,
|
|
12
|
+
PASSWORD_MAX_LENGTH: 128,
|
|
13
|
+
NAME_MAX_LENGTH: 100,
|
|
14
|
+
GENERAL_TEXT_MAX_LENGTH: 500,
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Trim and normalize whitespace
|
|
19
|
+
*/
|
|
20
|
+
export const sanitizeWhitespace = (input: string): string => {
|
|
21
|
+
return input.trim().replace(/\s+/g, ' ');
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Sanitize email address
|
|
26
|
+
* - Trim whitespace
|
|
27
|
+
* - Convert to lowercase
|
|
28
|
+
* - Limit length
|
|
29
|
+
*/
|
|
30
|
+
export const sanitizeEmail = (email: string): string => {
|
|
31
|
+
const trimmed = email.trim().toLowerCase();
|
|
32
|
+
return trimmed.substring(0, SECURITY_LIMITS.EMAIL_MAX_LENGTH);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Sanitize password
|
|
37
|
+
* - Only trim (preserve case and special chars)
|
|
38
|
+
* - Limit length to prevent DoS
|
|
39
|
+
*/
|
|
40
|
+
export const sanitizePassword = (password: string): string => {
|
|
41
|
+
// Don't trim password to preserve intentional spaces
|
|
42
|
+
// Only limit length
|
|
43
|
+
return password.substring(0, SECURITY_LIMITS.PASSWORD_MAX_LENGTH);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Sanitize display name
|
|
48
|
+
* - Trim whitespace
|
|
49
|
+
* - Normalize multiple spaces
|
|
50
|
+
* - Remove potential XSS characters
|
|
51
|
+
* - Limit length
|
|
52
|
+
*/
|
|
53
|
+
export const sanitizeName = (name: string): string => {
|
|
54
|
+
const trimmed = sanitizeWhitespace(name);
|
|
55
|
+
// Remove HTML tags and script content
|
|
56
|
+
const noTags = trimmed.replace(/<[^>]*>/g, '');
|
|
57
|
+
return noTags.substring(0, SECURITY_LIMITS.NAME_MAX_LENGTH);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Sanitize general text input
|
|
62
|
+
* - Trim whitespace
|
|
63
|
+
* - Remove HTML/script tags
|
|
64
|
+
* - Limit length
|
|
65
|
+
*/
|
|
66
|
+
export const sanitizeText = (text: string): string => {
|
|
67
|
+
const trimmed = sanitizeWhitespace(text);
|
|
68
|
+
const noTags = trimmed.replace(/<[^>]*>/g, '');
|
|
69
|
+
return noTags.substring(0, SECURITY_LIMITS.GENERAL_TEXT_MAX_LENGTH);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Check if string contains potentially dangerous characters
|
|
74
|
+
*/
|
|
75
|
+
export const containsDangerousChars = (input: string): boolean => {
|
|
76
|
+
// Check for common XSS patterns
|
|
77
|
+
const dangerousPatterns = [
|
|
78
|
+
/<script/i,
|
|
79
|
+
/javascript:/i,
|
|
80
|
+
/on\w+\s*=/i, // onclick, onload, etc.
|
|
81
|
+
/<iframe/i,
|
|
82
|
+
/eval\(/i,
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
return dangerousPatterns.some(pattern => pattern.test(input));
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Validate string length is within bounds
|
|
90
|
+
*/
|
|
91
|
+
export const isWithinLengthLimit = (
|
|
92
|
+
input: string,
|
|
93
|
+
maxLength: number,
|
|
94
|
+
minLength = 0
|
|
95
|
+
): boolean => {
|
|
96
|
+
const length = input.trim().length;
|
|
97
|
+
return length >= minLength && length <= maxLength;
|
|
98
|
+
};
|
|
99
|
+
|
package/README.md
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
# @umituz/react-native-validation
|
|
2
|
-
|
|
3
|
-
Comprehensive validation and sanitization utilities for React Native forms. Provides reusable validation and sanitization functions for common input types.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @umituz/react-native-validation
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Peer Dependencies
|
|
12
|
-
|
|
13
|
-
- `react` >= 18.2.0
|
|
14
|
-
- `react-native` >= 0.74.0
|
|
15
|
-
|
|
16
|
-
## Features
|
|
17
|
-
|
|
18
|
-
### Validation
|
|
19
|
-
- ✅ Email validation
|
|
20
|
-
- ✅ Password validation (with strength requirements)
|
|
21
|
-
- ✅ Phone number validation (E.164 format)
|
|
22
|
-
- ✅ Required field validation
|
|
23
|
-
- ✅ Name validation
|
|
24
|
-
- ✅ Number range validation
|
|
25
|
-
- ✅ Min/Max length validation
|
|
26
|
-
- ✅ Pattern (regex) validation
|
|
27
|
-
- ✅ Date of birth validation
|
|
28
|
-
- ✅ Age validation
|
|
29
|
-
- ✅ Batch validation
|
|
30
|
-
|
|
31
|
-
### Sanitization
|
|
32
|
-
- ✅ Email sanitization
|
|
33
|
-
- ✅ Password sanitization
|
|
34
|
-
- ✅ Name sanitization
|
|
35
|
-
- ✅ Text sanitization
|
|
36
|
-
- ✅ XSS protection
|
|
37
|
-
- ✅ Length limit validation
|
|
38
|
-
- ✅ Whitespace normalization
|
|
39
|
-
|
|
40
|
-
### General
|
|
41
|
-
- ✅ TypeScript type safety
|
|
42
|
-
- ✅ Image file validation (prevents zip, exe, etc.)
|
|
43
|
-
- ✅ MIME type validation
|
|
44
|
-
|
|
45
|
-
## Usage
|
|
46
|
-
|
|
47
|
-
### Basic Example
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
import { validateEmail, validatePassword, validateRequired } from '@umituz/react-native-validation';
|
|
51
|
-
|
|
52
|
-
// Validate email
|
|
53
|
-
const emailResult = validateEmail('user@example.com');
|
|
54
|
-
if (!emailResult.isValid) {
|
|
55
|
-
console.error(emailResult.error);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Validate password
|
|
59
|
-
const passwordResult = validatePassword('MySecure123', {
|
|
60
|
-
minLength: 8,
|
|
61
|
-
requireUppercase: true,
|
|
62
|
-
requireLowercase: true,
|
|
63
|
-
requireNumber: true,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Validate required field
|
|
67
|
-
const requiredResult = validateRequired('value', 'Field Name');
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Form Validation Example
|
|
71
|
-
|
|
72
|
-
```typescript
|
|
73
|
-
import {
|
|
74
|
-
validateEmail,
|
|
75
|
-
validatePassword,
|
|
76
|
-
validatePasswordConfirmation,
|
|
77
|
-
validateRequired,
|
|
78
|
-
batchValidate,
|
|
79
|
-
} from '@umituz/react-native-validation';
|
|
80
|
-
|
|
81
|
-
const validateForm = (email: string, password: string, confirmPassword: string) => {
|
|
82
|
-
return batchValidate([
|
|
83
|
-
{ field: 'email', validator: () => validateEmail(email) },
|
|
84
|
-
{ field: 'password', validator: () => validatePassword(password) },
|
|
85
|
-
{
|
|
86
|
-
field: 'confirmPassword',
|
|
87
|
-
validator: () => validatePasswordConfirmation(password, confirmPassword),
|
|
88
|
-
},
|
|
89
|
-
]);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const result = validateForm('user@example.com', 'MySecure123', 'MySecure123');
|
|
93
|
-
if (!result.isValid) {
|
|
94
|
-
console.log('Validation errors:', result.errors);
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Custom Validation
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
import { validatePattern, validateNumberRange } from '@umituz/react-native-validation';
|
|
102
|
-
|
|
103
|
-
// Validate with custom pattern
|
|
104
|
-
const patternResult = validatePattern(
|
|
105
|
-
'ABC123',
|
|
106
|
-
/^[A-Z]{3}\d{3}$/,
|
|
107
|
-
'Code',
|
|
108
|
-
'Code must be 3 uppercase letters followed by 3 numbers'
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
// Validate number range
|
|
112
|
-
const rangeResult = validateNumberRange(50, 0, 100, 'Percentage');
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### Sanitization Example
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
import {
|
|
119
|
-
sanitizeEmail,
|
|
120
|
-
sanitizeName,
|
|
121
|
-
sanitizeText,
|
|
122
|
-
containsDangerousChars,
|
|
123
|
-
SECURITY_LIMITS,
|
|
124
|
-
} from '@umituz/react-native-validation';
|
|
125
|
-
|
|
126
|
-
// Sanitize email
|
|
127
|
-
const cleanEmail = sanitizeEmail(' User@Example.COM ');
|
|
128
|
-
// Result: 'user@example.com'
|
|
129
|
-
|
|
130
|
-
// Sanitize name
|
|
131
|
-
const cleanName = sanitizeName(' John Doe ');
|
|
132
|
-
// Result: 'John Doe'
|
|
133
|
-
|
|
134
|
-
// Sanitize text (removes HTML tags)
|
|
135
|
-
const cleanText = sanitizeText('<script>alert("xss")</script>Hello');
|
|
136
|
-
// Result: 'Hello'
|
|
137
|
-
|
|
138
|
-
// Check for dangerous characters
|
|
139
|
-
const isDangerous = containsDangerousChars('<script>alert("xss")</script>');
|
|
140
|
-
// Result: true
|
|
141
|
-
|
|
142
|
-
// Check length limits
|
|
143
|
-
const isValidLength = isWithinLengthLimit('text', SECURITY_LIMITS.NAME_MAX_LENGTH);
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### Image Validation Example
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
import {
|
|
150
|
-
validateImageUri,
|
|
151
|
-
getImageMimeType,
|
|
152
|
-
validateImageExtension,
|
|
153
|
-
IMAGE_MIME_TYPES,
|
|
154
|
-
} from '@umituz/react-native-validation';
|
|
155
|
-
|
|
156
|
-
// Validate image URI (supports file://, http://, https://, and data: URLs)
|
|
157
|
-
const result = validateImageUri('file:///path/to/image.jpg');
|
|
158
|
-
if (!result.isValid) {
|
|
159
|
-
console.error(result.error);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Get MIME type from URI
|
|
163
|
-
const mimeType = getImageMimeType('file:///path/to/image.png');
|
|
164
|
-
// Result: 'image/png'
|
|
165
|
-
|
|
166
|
-
// Validate file extension
|
|
167
|
-
const extensionResult = validateImageExtension('image.jpg');
|
|
168
|
-
if (!extensionResult.isValid) {
|
|
169
|
-
console.error(extensionResult.error);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Use MIME type constants
|
|
173
|
-
if (mimeType === IMAGE_MIME_TYPES.PNG) {
|
|
174
|
-
console.log('PNG image');
|
|
175
|
-
}
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
## API Reference
|
|
179
|
-
|
|
180
|
-
### Core Validators
|
|
181
|
-
|
|
182
|
-
- `validateEmail(email: string): ValidationResult`
|
|
183
|
-
- `validatePassword(password: string, options?: PasswordOptions): ValidationResult`
|
|
184
|
-
- `validatePasswordConfirmation(password: string, confirmPassword: string): ValidationResult`
|
|
185
|
-
- `validateRequired(value: string, fieldName?: string): ValidationResult`
|
|
186
|
-
- `validateName(name: string, fieldName?: string, minLength?: number): ValidationResult`
|
|
187
|
-
- `validatePhone(phone: string): ValidationResult`
|
|
188
|
-
|
|
189
|
-
### Number Validators
|
|
190
|
-
|
|
191
|
-
- `validateNumberRange(value: number, min: number, max: number, fieldName?: string): ValidationResult`
|
|
192
|
-
- `validatePositiveNumber(value: number, fieldName?: string): ValidationResult`
|
|
193
|
-
|
|
194
|
-
### String Validators
|
|
195
|
-
|
|
196
|
-
- `validateMinLength(value: string, minLength: number, fieldName?: string): ValidationResult`
|
|
197
|
-
- `validateMaxLength(value: string, maxLength: number, fieldName?: string): ValidationResult`
|
|
198
|
-
- `validatePattern(value: string, pattern: RegExp, fieldName?: string, errorMessage?: string): ValidationResult`
|
|
199
|
-
|
|
200
|
-
### Date Validators
|
|
201
|
-
|
|
202
|
-
- `validateDateOfBirth(date: Date): ValidationResult`
|
|
203
|
-
- `validateAge(age: number): ValidationResult` (13-120 years)
|
|
204
|
-
|
|
205
|
-
### Image Validators
|
|
206
|
-
|
|
207
|
-
- `validateImageUri(uri: string, fieldName?: string): ValidationResult` - Validates image URI (supports file://, http://, https://, and data: URLs)
|
|
208
|
-
- `validateImageMimeType(mimeType: string, fieldName?: string): ValidationResult` - Validates MIME type is supported image type
|
|
209
|
-
- `validateImageExtension(uri: string, fieldName?: string): ValidationResult` - Validates file extension is supported image type
|
|
210
|
-
- `validateImageDataUrl(dataUrl: string, fieldName?: string): ValidationResult` - Validates data URL is image type
|
|
211
|
-
- `getImageMimeType(uri: string): string | null` - Get MIME type from URI (supports all URI types)
|
|
212
|
-
|
|
213
|
-
### MIME Type Utilities
|
|
214
|
-
|
|
215
|
-
- `getMimeTypeFromExtension(uri: string): string | null` - Get MIME type from file extension
|
|
216
|
-
- `getMimeTypeFromDataUrl(dataUrl: string): string | null` - Get MIME type from data URL
|
|
217
|
-
- `IMAGE_MIME_TYPES` - Supported image MIME types constants
|
|
218
|
-
- `SUPPORTED_IMAGE_MIME_TYPES` - Array of supported image MIME types
|
|
219
|
-
- `EXTENSION_TO_MIME_TYPE` - File extension to MIME type mapping
|
|
220
|
-
- `MIME_TYPE_TO_EXTENSION` - MIME type to file extension mapping
|
|
221
|
-
|
|
222
|
-
### Batch Validation
|
|
223
|
-
|
|
224
|
-
- `batchValidate(validations: Array<{ field: string; validator: () => ValidationResult }>): { isValid: boolean; errors: Record<string, string> }`
|
|
225
|
-
|
|
226
|
-
## Types
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
interface ValidationResult {
|
|
230
|
-
isValid: boolean;
|
|
231
|
-
error?: string;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
interface PasswordOptions {
|
|
235
|
-
minLength?: number;
|
|
236
|
-
requireUppercase?: boolean;
|
|
237
|
-
requireLowercase?: boolean;
|
|
238
|
-
requireNumber?: boolean;
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
## License
|
|
243
|
-
|
|
244
|
-
MIT
|
|
245
|
-
|