@scallywag/validation 1.0.0 → 1.0.4
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/README.md +1372 -0
- package/dist/env.d.ts +56 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +262 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +85 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +407 -0
- package/dist/middleware.js.map +1 -0
- package/dist/sanitization.d.ts +41 -0
- package/dist/sanitization.d.ts.map +1 -0
- package/dist/sanitization.js +111 -0
- package/dist/sanitization.js.map +1 -0
- package/dist/schemas.d.ts +231 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +245 -0
- package/dist/schemas.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types.d.ts +136 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/validators.d.ts +111 -0
- package/dist/validators.d.ts.map +1 -0
- package/dist/validators.js +324 -0
- package/dist/validators.js.map +1 -0
- package/dist/wrappers.d.ts +117 -0
- package/dist/wrappers.d.ts.map +1 -0
- package/dist/wrappers.js +184 -0
- package/dist/wrappers.js.map +1 -0
- package/dist/zod-schema-converter.d.ts +80 -0
- package/dist/zod-schema-converter.d.ts.map +1 -0
- package/dist/zod-schema-converter.js +97 -0
- package/dist/zod-schema-converter.js.map +1 -0
- package/package.json +40 -1
- package/index.js +0 -1
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Middleware
|
|
3
|
+
*
|
|
4
|
+
* Next.js API route validation middleware using Zod
|
|
5
|
+
*/
|
|
6
|
+
import { NextResponse } from 'next/server';
|
|
7
|
+
import { SecurityLevel, } from './types';
|
|
8
|
+
import { formatValidationErrors, validateData } from './validators';
|
|
9
|
+
import { MemoryRateLimitStore } from '@scallywag/gateway/middleware/security/RateLimiter';
|
|
10
|
+
import { logger } from '@scallywag/security/logger';
|
|
11
|
+
/**
|
|
12
|
+
* Helper function to extract request body safely
|
|
13
|
+
*/
|
|
14
|
+
async function extractRequestBody(request) {
|
|
15
|
+
return await request.json().catch(() => ({}));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Helper function to safely extract validated data from result
|
|
19
|
+
* Extracted for better testability
|
|
20
|
+
*/
|
|
21
|
+
export function safeExtractValidatedData(result) {
|
|
22
|
+
return typeof result === 'object' &&
|
|
23
|
+
result !== null &&
|
|
24
|
+
'validatedData' in result
|
|
25
|
+
? result['validatedData']
|
|
26
|
+
: {};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Helper function to validate request body
|
|
30
|
+
*/
|
|
31
|
+
async function validateRequestBody(config, request, errors, validatedData) {
|
|
32
|
+
if (!config || request.method === 'GET')
|
|
33
|
+
return;
|
|
34
|
+
const body = await extractRequestBody(request);
|
|
35
|
+
const bodyResult = await validateData(config, body);
|
|
36
|
+
if (!bodyResult.success) {
|
|
37
|
+
errors.push(...bodyResult.errors);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
validatedData['body'] = bodyResult.data;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Helper function to validate query parameters
|
|
45
|
+
*/
|
|
46
|
+
async function validateRequestQuery(config, request, errors, validatedData) {
|
|
47
|
+
if (!config)
|
|
48
|
+
return;
|
|
49
|
+
const url = new URL(request.url);
|
|
50
|
+
const queryParams = Object.fromEntries(url.searchParams.entries());
|
|
51
|
+
const queryResult = await validateData(config, queryParams);
|
|
52
|
+
if (!queryResult.success) {
|
|
53
|
+
errors.push(...queryResult.errors);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
validatedData['query'] = queryResult.data;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Helper function to validate headers
|
|
61
|
+
*/
|
|
62
|
+
async function validateRequestHeaders(config, request, errors, validatedData) {
|
|
63
|
+
if (!config)
|
|
64
|
+
return;
|
|
65
|
+
// Convert Headers to plain object (safely iterate over header entries)
|
|
66
|
+
const headers = {};
|
|
67
|
+
request.headers.forEach((value, key) => {
|
|
68
|
+
// Safe to use bracket notation here since we're creating a new object
|
|
69
|
+
// and headers from NextRequest are guaranteed to be strings
|
|
70
|
+
Object.defineProperty(headers, key, {
|
|
71
|
+
value,
|
|
72
|
+
enumerable: true,
|
|
73
|
+
writable: true,
|
|
74
|
+
configurable: true,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
const headersResult = await validateData(config, headers);
|
|
78
|
+
if (!headersResult.success) {
|
|
79
|
+
errors.push(...headersResult.errors);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
validatedData['headers'] = headersResult.data;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Helper function to validate unified input
|
|
87
|
+
* Merges body, query params, and URL params into a single object
|
|
88
|
+
* and validates against the input schema.
|
|
89
|
+
*/
|
|
90
|
+
async function validateUnifiedInput(config, request, params, errors, validatedData) {
|
|
91
|
+
if (!config)
|
|
92
|
+
return false;
|
|
93
|
+
// Extract URL query parameters
|
|
94
|
+
const url = new URL(request.url);
|
|
95
|
+
const queryParams = Object.fromEntries(url.searchParams.entries());
|
|
96
|
+
// Extract request body (if not GET)
|
|
97
|
+
const body = request.method !== 'GET' ? await extractRequestBody(request) : {};
|
|
98
|
+
// Merge all inputs: query params + URL params + body
|
|
99
|
+
// Later values override earlier ones (body takes precedence)
|
|
100
|
+
const mergedInput = {
|
|
101
|
+
...queryParams,
|
|
102
|
+
...params,
|
|
103
|
+
...(typeof body === 'object' && body !== null ? body : {}),
|
|
104
|
+
};
|
|
105
|
+
const inputResult = await validateData(config, mergedInput);
|
|
106
|
+
if (!inputResult.success) {
|
|
107
|
+
errors.push(...inputResult.errors);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// Store validated data at top level for easy access
|
|
111
|
+
validatedData['input'] = inputResult.data;
|
|
112
|
+
// Also store in legacy locations for backwards compatibility
|
|
113
|
+
validatedData['body'] = inputResult.data;
|
|
114
|
+
validatedData['query'] = queryParams;
|
|
115
|
+
}
|
|
116
|
+
return true; // Indicates unified validation was performed
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Create validation middleware for API routes
|
|
120
|
+
*
|
|
121
|
+
* Supports two validation modes:
|
|
122
|
+
* 1. Unified input validation (config.input): Merges body, query, and params
|
|
123
|
+
* into a single validated object. Preferred for new endpoints.
|
|
124
|
+
* 2. Legacy validation (config.body/query/headers): Validates each part
|
|
125
|
+
* separately. Maintained for backwards compatibility.
|
|
126
|
+
*/
|
|
127
|
+
export function createValidationMiddleware(config) {
|
|
128
|
+
return async function validationMiddleware(request, _context, params) {
|
|
129
|
+
const errors = [];
|
|
130
|
+
const validatedData = {};
|
|
131
|
+
const routeParams = params !== null && params !== void 0 ? params : {};
|
|
132
|
+
try {
|
|
133
|
+
// Check for unified input validation first (preferred mode)
|
|
134
|
+
const usedUnifiedValidation = await validateUnifiedInput(config.input, request, routeParams, errors, validatedData);
|
|
135
|
+
// If unified validation was used, skip legacy body/query validation
|
|
136
|
+
// but still validate headers if configured
|
|
137
|
+
if (usedUnifiedValidation) {
|
|
138
|
+
await validateRequestHeaders(config.headers, request, errors, validatedData);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Fall back to legacy validation for separate body/query/headers
|
|
142
|
+
await validateRequestBody(config.body, request, errors, validatedData);
|
|
143
|
+
await validateRequestQuery(config.query, request, errors, validatedData);
|
|
144
|
+
await validateRequestHeaders(config.headers, request, errors, validatedData);
|
|
145
|
+
}
|
|
146
|
+
if (errors.length > 0) {
|
|
147
|
+
return NextResponse.json({
|
|
148
|
+
success: false,
|
|
149
|
+
error: 'Validation failed',
|
|
150
|
+
details: formatValidationErrors(errors),
|
|
151
|
+
timestamp: new Date().toISOString(),
|
|
152
|
+
}, { status: 400 });
|
|
153
|
+
}
|
|
154
|
+
return { validatedData };
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
logger.error('Validation middleware error', {
|
|
158
|
+
error: error instanceof Error ? error.message : String(error),
|
|
159
|
+
});
|
|
160
|
+
return NextResponse.json({
|
|
161
|
+
success: false,
|
|
162
|
+
error: 'Validation error',
|
|
163
|
+
details: { server: ['Internal validation error'] },
|
|
164
|
+
timestamp: new Date().toISOString(),
|
|
165
|
+
}, { status: 500 });
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Validation decorator for API route handlers
|
|
171
|
+
*
|
|
172
|
+
* Supports unified input validation when config.input is provided.
|
|
173
|
+
* Extracts route params from the context argument automatically.
|
|
174
|
+
*/
|
|
175
|
+
export function validateRoute(config) {
|
|
176
|
+
return function (_target, _propertyKey, descriptor) {
|
|
177
|
+
const originalMethod = descriptor.value;
|
|
178
|
+
descriptor.value = async function (request, ...args) {
|
|
179
|
+
const middleware = createValidationMiddleware(config);
|
|
180
|
+
// Extract params from context (first arg after request in Next.js)
|
|
181
|
+
const context = args[0];
|
|
182
|
+
const params = extractParamsFromContext(context);
|
|
183
|
+
const result = await middleware(request, undefined, params);
|
|
184
|
+
// Check if result is an error response
|
|
185
|
+
if ('status' in result && result.status !== 200) {
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
// Add validated data to the request context
|
|
189
|
+
const validatedData = safeExtractValidatedData(result);
|
|
190
|
+
return originalMethod.call(this, request, validatedData, ...args);
|
|
191
|
+
};
|
|
192
|
+
return descriptor;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Extract route params from Next.js context
|
|
197
|
+
*/
|
|
198
|
+
function extractParamsFromContext(context) {
|
|
199
|
+
if (typeof context !== 'object' || context === null)
|
|
200
|
+
return undefined;
|
|
201
|
+
const ctx = context;
|
|
202
|
+
if (typeof ctx['params'] !== 'object' || ctx['params'] === null) {
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
// Next.js params can be strings or arrays - normalize to strings
|
|
206
|
+
const params = ctx['params'];
|
|
207
|
+
const normalized = {};
|
|
208
|
+
// Use Object.entries to avoid object injection sink warnings
|
|
209
|
+
for (const [key, value] of Object.entries(params)) {
|
|
210
|
+
if (typeof value === 'string') {
|
|
211
|
+
Object.defineProperty(normalized, key, {
|
|
212
|
+
value,
|
|
213
|
+
enumerable: true,
|
|
214
|
+
writable: true,
|
|
215
|
+
configurable: true,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
else if (Array.isArray(value) && value.length > 0) {
|
|
219
|
+
// For catch-all routes, join array segments
|
|
220
|
+
Object.defineProperty(normalized, key, {
|
|
221
|
+
value: value.join('/'),
|
|
222
|
+
enumerable: true,
|
|
223
|
+
writable: true,
|
|
224
|
+
configurable: true,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return normalized;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Higher-order function to wrap API route with validation
|
|
232
|
+
*
|
|
233
|
+
* Supports unified input validation when config.input is provided.
|
|
234
|
+
* Extracts route params from Next.js context automatically.
|
|
235
|
+
*/
|
|
236
|
+
export function withValidation(config, handler) {
|
|
237
|
+
return async function (request, context) {
|
|
238
|
+
const middleware = createValidationMiddleware(config);
|
|
239
|
+
const params = extractParamsFromContext(context);
|
|
240
|
+
const result = await middleware(request, undefined, params);
|
|
241
|
+
// Check if result is an error response
|
|
242
|
+
if ('status' in result && result.status !== 200) {
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
const validatedData = safeExtractValidatedData(result);
|
|
246
|
+
return handler(request, validatedData, context);
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Check if user agent indicates a bot
|
|
251
|
+
*/
|
|
252
|
+
function isBotUserAgent(userAgent) {
|
|
253
|
+
return /bot|crawler|spider/i.test(userAgent);
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Check if user agent indicates automated tools
|
|
257
|
+
*/
|
|
258
|
+
function isAutomatedToolUserAgent(userAgent) {
|
|
259
|
+
return /bot|crawler|spider|curl|wget/i.test(userAgent);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Check if user agent indicates scripting languages
|
|
263
|
+
*/
|
|
264
|
+
function isScriptingUserAgent(userAgent) {
|
|
265
|
+
return /bot|crawler|spider|curl|wget|python|ruby|php/i.test(userAgent);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Perform security checks based on level
|
|
269
|
+
*/
|
|
270
|
+
function performSecurityCheck(securityLevel, userAgent, origin, hasAuthorization) {
|
|
271
|
+
switch (securityLevel) {
|
|
272
|
+
case SecurityLevel.LOW:
|
|
273
|
+
return true;
|
|
274
|
+
case SecurityLevel.MEDIUM:
|
|
275
|
+
return !isBotUserAgent(userAgent);
|
|
276
|
+
case SecurityLevel.HIGH:
|
|
277
|
+
return !isAutomatedToolUserAgent(userAgent) && origin.length > 0;
|
|
278
|
+
case SecurityLevel.CRITICAL:
|
|
279
|
+
return (!isScriptingUserAgent(userAgent) &&
|
|
280
|
+
origin.length > 0 &&
|
|
281
|
+
hasAuthorization);
|
|
282
|
+
default:
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Security-focused validation middleware
|
|
288
|
+
*/
|
|
289
|
+
export function createSecurityMiddleware(securityLevel = SecurityLevel.MEDIUM) {
|
|
290
|
+
return function (request) {
|
|
291
|
+
var _a, _b;
|
|
292
|
+
const userAgent = (_a = request.headers.get('user-agent')) !== null && _a !== void 0 ? _a : '';
|
|
293
|
+
const origin = (_b = request.headers.get('origin')) !== null && _b !== void 0 ? _b : '';
|
|
294
|
+
const hasAuthorization = request.headers.has('authorization');
|
|
295
|
+
const passes = performSecurityCheck(securityLevel, userAgent, origin, hasAuthorization);
|
|
296
|
+
if (!passes) {
|
|
297
|
+
return NextResponse.json({
|
|
298
|
+
success: false,
|
|
299
|
+
error: 'Security check failed',
|
|
300
|
+
timestamp: new Date().toISOString(),
|
|
301
|
+
}, { status: 403 });
|
|
302
|
+
}
|
|
303
|
+
return null; // Pass security check
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Rate limiting middleware
|
|
308
|
+
*
|
|
309
|
+
* Uses standardized gateway MemoryRateLimitStore for consistent rate limiting across the application.
|
|
310
|
+
* This maintains backward compatibility with the existing Next.js API route middleware pattern
|
|
311
|
+
* while using the standardized gateway rate limiting infrastructure.
|
|
312
|
+
*/
|
|
313
|
+
export function createRateLimitMiddleware(requests = 100, windowMs = 60000 // 1 minute
|
|
314
|
+
) {
|
|
315
|
+
// Use the same store implementation as the gateway for consistency
|
|
316
|
+
const store = new MemoryRateLimitStore();
|
|
317
|
+
/**
|
|
318
|
+
* Extract client IP from request headers
|
|
319
|
+
*/
|
|
320
|
+
function extractClientIP(request) {
|
|
321
|
+
var _a, _b;
|
|
322
|
+
return (((_b = (_a = request.headers.get('x-forwarded-for')) === null || _a === void 0 ? void 0 : _a.split(',')[0]) === null || _b === void 0 ? void 0 : _b.trim()) ||
|
|
323
|
+
request.headers.get('x-real-ip') ||
|
|
324
|
+
'127.0.0.1');
|
|
325
|
+
}
|
|
326
|
+
return function (request) {
|
|
327
|
+
const ip = extractClientIP(request);
|
|
328
|
+
const key = `rate-limit:ip:${ip}`;
|
|
329
|
+
const now = Date.now();
|
|
330
|
+
// Get current rate limit info
|
|
331
|
+
const info = store.get(key);
|
|
332
|
+
// Check if rate limit exceeded
|
|
333
|
+
if (info && info.count >= requests) {
|
|
334
|
+
const retryAfter = Math.max(0, Math.ceil((info.resetTime - now) / 1000));
|
|
335
|
+
return NextResponse.json({
|
|
336
|
+
success: false,
|
|
337
|
+
error: 'Rate limit exceeded',
|
|
338
|
+
retryAfter,
|
|
339
|
+
timestamp: new Date().toISOString(),
|
|
340
|
+
}, {
|
|
341
|
+
status: 429,
|
|
342
|
+
headers: {
|
|
343
|
+
'X-RateLimit-Limit': requests.toString(),
|
|
344
|
+
'X-RateLimit-Remaining': '0',
|
|
345
|
+
'X-RateLimit-Reset': new Date(info.resetTime).toISOString(),
|
|
346
|
+
'Retry-After': retryAfter.toString(),
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
// Increment the counter (this will create entry if it doesn't exist)
|
|
351
|
+
store.increment(key, windowMs);
|
|
352
|
+
// Return null to allow the request (rate limit passed)
|
|
353
|
+
return null;
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Combine multiple middleware functions
|
|
358
|
+
*/
|
|
359
|
+
export function combineMiddleware(...middlewares) {
|
|
360
|
+
return function (request) {
|
|
361
|
+
for (const middleware of middlewares) {
|
|
362
|
+
const result = middleware(request);
|
|
363
|
+
if (result) {
|
|
364
|
+
return result; // Return error response from first failing middleware
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return null; // All middleware passed
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Create comprehensive API middleware
|
|
372
|
+
*
|
|
373
|
+
* Supports unified input validation when options.validation.input is provided.
|
|
374
|
+
* Accepts optional context for extracting route params.
|
|
375
|
+
*/
|
|
376
|
+
export function createApiMiddleware(options) {
|
|
377
|
+
const middlewares = [];
|
|
378
|
+
// Add security middleware
|
|
379
|
+
if (options.security) {
|
|
380
|
+
middlewares.push(createSecurityMiddleware(options.security));
|
|
381
|
+
}
|
|
382
|
+
// Add rate limiting
|
|
383
|
+
if (options.rateLimit) {
|
|
384
|
+
middlewares.push(createRateLimitMiddleware(options.rateLimit.requests, options.rateLimit.windowMs));
|
|
385
|
+
}
|
|
386
|
+
const combinedMiddleware = combineMiddleware(...middlewares);
|
|
387
|
+
return async function (request, handler, context) {
|
|
388
|
+
// Run security and rate limiting checks
|
|
389
|
+
const middlewareResult = combinedMiddleware(request);
|
|
390
|
+
if (middlewareResult) {
|
|
391
|
+
return middlewareResult;
|
|
392
|
+
}
|
|
393
|
+
// Run validation if configured
|
|
394
|
+
if (options.validation) {
|
|
395
|
+
const validationMiddleware = createValidationMiddleware(options.validation);
|
|
396
|
+
const params = extractParamsFromContext(context);
|
|
397
|
+
const validationResult = await validationMiddleware(request, undefined, params);
|
|
398
|
+
if ('status' in validationResult && validationResult.status !== 200) {
|
|
399
|
+
return validationResult;
|
|
400
|
+
}
|
|
401
|
+
const validatedData = safeExtractValidatedData(validationResult);
|
|
402
|
+
return handler(request, validatedData);
|
|
403
|
+
}
|
|
404
|
+
return handler(request);
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String Sanitization Utilities
|
|
3
|
+
*
|
|
4
|
+
* Centralized XSS/SQL injection protection and string sanitization.
|
|
5
|
+
* This is the single source of truth for sanitization patterns.
|
|
6
|
+
*/
|
|
7
|
+
import type { SanitizationOptions } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* XSS detection patterns
|
|
10
|
+
*/
|
|
11
|
+
export declare const XSS_PATTERNS: {
|
|
12
|
+
readonly scriptTags: RegExp;
|
|
13
|
+
readonly iframeTags: RegExp;
|
|
14
|
+
readonly javascriptProtocol: RegExp;
|
|
15
|
+
readonly vbscriptProtocol: RegExp;
|
|
16
|
+
readonly eventHandlers: RegExp;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* SQL injection patterns
|
|
20
|
+
*/
|
|
21
|
+
export declare const SQL_PATTERNS: {
|
|
22
|
+
readonly specialChars: RegExp;
|
|
23
|
+
readonly keywords: RegExp;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* HTML entity mapping for encoding
|
|
27
|
+
*/
|
|
28
|
+
export declare const HTML_ENTITIES: Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* Check if a string contains XSS patterns (for validation without modification)
|
|
31
|
+
*/
|
|
32
|
+
export declare function containsXssPatterns(value: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Sanitize string input by removing/encoding dangerous patterns
|
|
35
|
+
*/
|
|
36
|
+
export declare function sanitizeString(input: string, options?: SanitizationOptions): string;
|
|
37
|
+
/**
|
|
38
|
+
* Recursively sanitize string fields in an object
|
|
39
|
+
*/
|
|
40
|
+
export declare function sanitizeObjectStrings(obj: unknown): unknown;
|
|
41
|
+
//# sourceMappingURL=sanitization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitization.d.ts","sourceRoot":"","sources":["../sanitization.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMhD,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAK1D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,mBAAwB,GAChC,MAAM,CA0CR;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CA8B3D"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String Sanitization Utilities
|
|
3
|
+
*
|
|
4
|
+
* Centralized XSS/SQL injection protection and string sanitization.
|
|
5
|
+
* This is the single source of truth for sanitization patterns.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* XSS detection patterns
|
|
9
|
+
*/
|
|
10
|
+
export const XSS_PATTERNS = {
|
|
11
|
+
scriptTags: /<script[^>]*>.*?<\/script>/gi,
|
|
12
|
+
iframeTags: /<iframe[^>]*>.*?<\/iframe>/gi,
|
|
13
|
+
javascriptProtocol: /javascript:/gi,
|
|
14
|
+
vbscriptProtocol: /vbscript:/gi,
|
|
15
|
+
eventHandlers: /on\w+=/gi,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* SQL injection patterns
|
|
19
|
+
*/
|
|
20
|
+
export const SQL_PATTERNS = {
|
|
21
|
+
specialChars: /['";\\]/g,
|
|
22
|
+
keywords: /\b(union|select|insert|update|delete|drop|exec|execute)\b/gi,
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* HTML entity mapping for encoding
|
|
26
|
+
*/
|
|
27
|
+
export const HTML_ENTITIES = {
|
|
28
|
+
'&': '&',
|
|
29
|
+
'<': '<',
|
|
30
|
+
'>': '>',
|
|
31
|
+
'"': '"',
|
|
32
|
+
"'": ''',
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Check if a string contains XSS patterns (for validation without modification)
|
|
36
|
+
*/
|
|
37
|
+
export function containsXssPatterns(value) {
|
|
38
|
+
const hasScriptTag = /<script/i.test(value);
|
|
39
|
+
const hasEventHandler = /on\w+=/i.test(value);
|
|
40
|
+
const hasJavascriptProtocol = /javascript:/i.test(value);
|
|
41
|
+
return hasScriptTag || hasEventHandler || hasJavascriptProtocol;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Sanitize string input by removing/encoding dangerous patterns
|
|
45
|
+
*/
|
|
46
|
+
export function sanitizeString(input, options = {}) {
|
|
47
|
+
let sanitized = input;
|
|
48
|
+
// Trim whitespace
|
|
49
|
+
if (options.trim !== false) {
|
|
50
|
+
sanitized = sanitized.trim();
|
|
51
|
+
}
|
|
52
|
+
// XSS protection
|
|
53
|
+
if (options.xss !== false) {
|
|
54
|
+
sanitized = sanitized
|
|
55
|
+
.replace(XSS_PATTERNS.scriptTags, '')
|
|
56
|
+
.replace(XSS_PATTERNS.iframeTags, '')
|
|
57
|
+
.replace(XSS_PATTERNS.javascriptProtocol, '')
|
|
58
|
+
.replace(XSS_PATTERNS.vbscriptProtocol, '')
|
|
59
|
+
.replace(XSS_PATTERNS.eventHandlers, '');
|
|
60
|
+
}
|
|
61
|
+
// SQL injection protection
|
|
62
|
+
if (options.sql !== false) {
|
|
63
|
+
sanitized = sanitized
|
|
64
|
+
.replace(SQL_PATTERNS.specialChars, '')
|
|
65
|
+
.replace(SQL_PATTERNS.keywords, '');
|
|
66
|
+
}
|
|
67
|
+
// HTML encoding
|
|
68
|
+
if (options.html) {
|
|
69
|
+
sanitized = sanitized.replace(/[&<>"']/g,
|
|
70
|
+
// eslint-disable-next-line security/detect-object-injection -- char is from known regex match set
|
|
71
|
+
(char) => { var _a; return (_a = HTML_ENTITIES[char]) !== null && _a !== void 0 ? _a : char; });
|
|
72
|
+
}
|
|
73
|
+
// Case transformations
|
|
74
|
+
if (options.lowercase) {
|
|
75
|
+
sanitized = sanitized.toLowerCase();
|
|
76
|
+
}
|
|
77
|
+
else if (options.uppercase) {
|
|
78
|
+
sanitized = sanitized.toUpperCase();
|
|
79
|
+
}
|
|
80
|
+
return sanitized;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Recursively sanitize string fields in an object
|
|
84
|
+
*/
|
|
85
|
+
export function sanitizeObjectStrings(obj) {
|
|
86
|
+
if (typeof obj === 'string') {
|
|
87
|
+
return sanitizeString(obj, { xss: true, sql: true, trim: true });
|
|
88
|
+
}
|
|
89
|
+
if (Array.isArray(obj)) {
|
|
90
|
+
return obj.map(sanitizeObjectStrings);
|
|
91
|
+
}
|
|
92
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
93
|
+
const sanitized = {};
|
|
94
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
95
|
+
// Type-safe property assignment for security
|
|
96
|
+
if (typeof key === 'string' &&
|
|
97
|
+
Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
98
|
+
// Use Object.defineProperty to safely assign dynamic keys
|
|
99
|
+
Object.defineProperty(sanitized, key, {
|
|
100
|
+
value: sanitizeObjectStrings(value),
|
|
101
|
+
writable: true,
|
|
102
|
+
enumerable: true,
|
|
103
|
+
configurable: true,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return sanitized;
|
|
108
|
+
}
|
|
109
|
+
return obj;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=sanitization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitization.js","sourceRoot":"","sources":["../sanitization.ts"],"names":[],"mappings":"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"}
|