@umituz/web-design-system 1.0.4 → 1.1.0

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.
@@ -0,0 +1,242 @@
1
+ export interface ValidationResult {
2
+ isValid: boolean;
3
+ error?: string;
4
+ }
5
+
6
+ export interface ValidationConfig {
7
+ allowHtml?: boolean;
8
+ stripTags?: boolean;
9
+ allowedTags?: string[];
10
+ allowedAttributes?: string[];
11
+ }
12
+
13
+ /**
14
+ * Input validation with XSS protection
15
+ * Basic sanitization without external dependencies
16
+ */
17
+ export const validateInput = (
18
+ input: string,
19
+ maxLength: number = 1000,
20
+ minLength: number = 0,
21
+ config?: ValidationConfig
22
+ ): ValidationResult => {
23
+ const trimmed = input.trim();
24
+
25
+ // Required field validation
26
+ if (minLength > 0 && !trimmed) {
27
+ return { isValid: false, error: "This field is required" };
28
+ }
29
+
30
+ // Length validation
31
+ if (trimmed.length > maxLength) {
32
+ return { isValid: false, error: `Must be less than ${maxLength} characters` };
33
+ }
34
+
35
+ if (trimmed.length < minLength) {
36
+ return { isValid: false, error: `Must be at least ${minLength} characters` };
37
+ }
38
+
39
+ // HTML tag check for non-HTML content
40
+ if (!config?.allowHtml) {
41
+ if (/<[^>]*>/.test(trimmed)) {
42
+ return { isValid: false, error: "HTML tags are not allowed" };
43
+ }
44
+
45
+ // Check for suspicious patterns
46
+ const suspiciousPatterns = [
47
+ /javascript:/gi,
48
+ /vbscript:/gi,
49
+ /data:text\/html/gi,
50
+ /data:application\/javascript/gi,
51
+ /on\w+\s*=/gi,
52
+ ];
53
+
54
+ for (const pattern of suspiciousPatterns) {
55
+ if (pattern.test(trimmed)) {
56
+ return { isValid: false, error: "Potentially unsafe content detected" };
57
+ }
58
+ }
59
+ }
60
+
61
+ return { isValid: true };
62
+ };
63
+
64
+ /**
65
+ * Email validation with basic security checks
66
+ */
67
+ export const validateEmail = (email: string): ValidationResult => {
68
+ const trimmed = email.trim();
69
+
70
+ if (!trimmed) {
71
+ return { isValid: false, error: "Email is required" };
72
+ }
73
+
74
+ // Check for HTML/script content
75
+ if (/<[^>]*>/.test(trimmed)) {
76
+ return { isValid: false, error: "Invalid characters in email address" };
77
+ }
78
+
79
+ // Email regex
80
+ const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
81
+
82
+ if (!emailRegex.test(trimmed)) {
83
+ return { isValid: false, error: "Please enter a valid email address" };
84
+ }
85
+
86
+ // Check for suspicious patterns
87
+ const suspiciousPatterns = [
88
+ /javascript:/gi,
89
+ /data:/gi,
90
+ /<[^>]*>/gi
91
+ ];
92
+
93
+ for (const pattern of suspiciousPatterns) {
94
+ if (pattern.test(trimmed)) {
95
+ return { isValid: false, error: "Invalid email format" };
96
+ }
97
+ }
98
+
99
+ return { isValid: true };
100
+ };
101
+
102
+ /**
103
+ * URL validation with security checks
104
+ */
105
+ export const validateUrl = (url: string): ValidationResult => {
106
+ const trimmed = url.trim();
107
+
108
+ if (!trimmed) {
109
+ return { isValid: false, error: "URL is required" };
110
+ }
111
+
112
+ // Check for HTML/script content
113
+ if (/<[^>]*>/.test(trimmed)) {
114
+ return { isValid: false, error: "Invalid characters in URL" };
115
+ }
116
+
117
+ try {
118
+ const urlObj = new URL(trimmed);
119
+
120
+ // Only allow safe protocols
121
+ const allowedProtocols = ['http:', 'https:', 'ftp:', 'ftps:'];
122
+ if (!allowedProtocols.includes(urlObj.protocol)) {
123
+ return { isValid: false, error: "Only HTTP, HTTPS, and FTP URLs are allowed" };
124
+ }
125
+
126
+ return { isValid: true };
127
+ } catch {
128
+ return { isValid: false, error: "Please enter a valid URL" };
129
+ }
130
+ };
131
+
132
+ /**
133
+ * Required field validation
134
+ */
135
+ export const validateRequired = (value: string): ValidationResult => {
136
+ const trimmed = value.trim();
137
+
138
+ if (!trimmed) {
139
+ return { isValid: false, error: "This field is required" };
140
+ }
141
+
142
+ return { isValid: true };
143
+ };
144
+
145
+ /**
146
+ * Basic input sanitization
147
+ * Removes potentially dangerous content
148
+ */
149
+ export const sanitizeInput = (
150
+ input: string,
151
+ config?: ValidationConfig
152
+ ): string => {
153
+ if (!input) return '';
154
+
155
+ let sanitized = input.trim();
156
+
157
+ // Remove dangerous content for non-HTML input
158
+ if (!config?.allowHtml) {
159
+ sanitized = sanitized
160
+ .replace(/javascript:/gi, '')
161
+ .replace(/vbscript:/gi, '')
162
+ .replace(/data:text\/html/gi, '')
163
+ .replace(/data:application\/javascript/gi, '')
164
+ .replace(/on\w+\s*=/gi, '')
165
+ .replace(/<[^>]*>/g, '');
166
+ }
167
+
168
+ // Limit length
169
+ return sanitized.slice(0, config?.allowHtml ? 10000 : 1000);
170
+ };
171
+
172
+ /**
173
+ * Validate and sanitize file names
174
+ * Prevents directory traversal and other file-based attacks
175
+ */
176
+ export const validateFileName = (fileName: string): ValidationResult => {
177
+ const trimmed = fileName.trim();
178
+
179
+ if (!trimmed) {
180
+ return { isValid: false, error: "File name is required" };
181
+ }
182
+
183
+ // Check for dangerous patterns
184
+ const dangerousPatterns = [
185
+ /\.\./g, // Directory traversal
186
+ /[<>:"|?*]/g, // Invalid file name characters
187
+ /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i, // Windows reserved names
188
+ /^\./g, // Hidden files starting with dot
189
+ /\.$/, // Files ending with dot
190
+ /\s+$/ // Trailing whitespace
191
+ ];
192
+
193
+ for (const pattern of dangerousPatterns) {
194
+ if (pattern.test(trimmed)) {
195
+ return { isValid: false, error: "Invalid file name format" };
196
+ }
197
+ }
198
+
199
+ // Length check
200
+ if (trimmed.length > 255) {
201
+ return { isValid: false, error: "File name too long (max 255 characters)" };
202
+ }
203
+
204
+ return { isValid: true };
205
+ };
206
+
207
+ /**
208
+ * Content Security Policy helper
209
+ * Validates that content meets basic CSP requirements
210
+ */
211
+ export const validateCSPCompliance = (content: string): ValidationResult => {
212
+ const violations = [];
213
+
214
+ // Check for inline scripts
215
+ if (/<script[^>]*>/.test(content)) {
216
+ violations.push("Inline scripts not allowed");
217
+ }
218
+
219
+ // Check for inline styles
220
+ if (/style\s*=/.test(content)) {
221
+ violations.push("Inline styles not allowed");
222
+ }
223
+
224
+ // Check for javascript: URLs
225
+ if (/javascript:/gi.test(content)) {
226
+ violations.push("JavaScript URLs not allowed");
227
+ }
228
+
229
+ // Check for data: URLs with dangerous content
230
+ if (/data:(?:text\/html|application\/javascript)/gi.test(content)) {
231
+ violations.push("Dangerous data URLs not allowed");
232
+ }
233
+
234
+ if (violations.length > 0) {
235
+ return {
236
+ isValid: false,
237
+ error: `Content Security Policy violations: ${violations.join(', ')}`
238
+ };
239
+ }
240
+
241
+ return { isValid: true };
242
+ };