@arcis/node 1.3.0 → 1.4.2
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 +1 -1
- package/dist/core/{index.d.mts → constants.d.ts} +21 -70
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/errors.d.ts +53 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/index.d.ts +6 -168
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +11 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +11 -3
- package/dist/core/index.mjs.map +1 -1
- package/dist/{types-BOkx5YJc.d.mts → core/types.d.ts} +27 -30
- package/dist/core/types.d.ts.map +1 -0
- package/dist/index.d.ts +71 -166
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +182 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +182 -50
- package/dist/index.mjs.map +1 -1
- package/dist/logging/index.d.ts +4 -36
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js.map +1 -1
- package/dist/logging/index.mjs.map +1 -1
- package/dist/logging/{index.d.mts → redactor.d.ts} +5 -9
- package/dist/logging/redactor.d.ts.map +1 -0
- package/dist/middleware/bot-detection.d.ts +86 -0
- package/dist/middleware/bot-detection.d.ts.map +1 -0
- package/dist/middleware/cookies.d.ts +48 -0
- package/dist/middleware/cookies.d.ts.map +1 -0
- package/dist/middleware/cors.d.ts +65 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/csrf.d.ts +109 -0
- package/dist/middleware/csrf.d.ts.map +1 -0
- package/dist/middleware/error-handler.d.ts +43 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/headers.d.ts +29 -0
- package/dist/middleware/headers.d.ts.map +1 -0
- package/dist/middleware/hpp.d.ts +56 -0
- package/dist/middleware/hpp.d.ts.map +1 -0
- package/dist/middleware/index.d.ts +16 -3
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +68 -31
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/index.mjs +69 -32
- package/dist/middleware/index.mjs.map +1 -1
- package/dist/middleware/main.d.ts +40 -0
- package/dist/middleware/main.d.ts.map +1 -0
- package/dist/middleware/rate-limit-sliding.d.ts +46 -0
- package/dist/middleware/rate-limit-sliding.d.ts.map +1 -0
- package/dist/middleware/rate-limit-token.d.ts +51 -0
- package/dist/middleware/rate-limit-token.d.ts.map +1 -0
- package/dist/middleware/rate-limit.d.ts +34 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/sanitizers/command.d.ts +28 -0
- package/dist/sanitizers/command.d.ts.map +1 -0
- package/dist/sanitizers/encode.d.ts +46 -0
- package/dist/sanitizers/encode.d.ts.map +1 -0
- package/dist/sanitizers/headers.d.ts +46 -0
- package/dist/sanitizers/headers.d.ts.map +1 -0
- package/dist/sanitizers/index.d.ts +18 -22
- package/dist/sanitizers/index.d.ts.map +1 -0
- package/dist/sanitizers/index.js +90 -32
- package/dist/sanitizers/index.js.map +1 -1
- package/dist/sanitizers/index.mjs +88 -33
- package/dist/sanitizers/index.mjs.map +1 -1
- package/dist/sanitizers/jsonp.d.ts +34 -0
- package/dist/sanitizers/jsonp.d.ts.map +1 -0
- package/dist/sanitizers/ldap.d.ts +42 -0
- package/dist/sanitizers/ldap.d.ts.map +1 -0
- package/dist/sanitizers/nosql.d.ts +31 -0
- package/dist/sanitizers/nosql.d.ts.map +1 -0
- package/dist/sanitizers/path.d.ts +28 -0
- package/dist/sanitizers/path.d.ts.map +1 -0
- package/dist/sanitizers/pii.d.ts +80 -0
- package/dist/sanitizers/pii.d.ts.map +1 -0
- package/dist/sanitizers/prototype.d.ts +34 -0
- package/dist/sanitizers/prototype.d.ts.map +1 -0
- package/dist/sanitizers/sanitize.d.ts +51 -0
- package/dist/sanitizers/sanitize.d.ts.map +1 -0
- package/dist/sanitizers/sql.d.ts +28 -0
- package/dist/sanitizers/sql.d.ts.map +1 -0
- package/dist/sanitizers/ssti.d.ts +20 -0
- package/dist/sanitizers/ssti.d.ts.map +1 -0
- package/dist/sanitizers/utils.d.ts +19 -0
- package/dist/sanitizers/utils.d.ts.map +1 -0
- package/dist/sanitizers/xss.d.ts +35 -0
- package/dist/sanitizers/xss.d.ts.map +1 -0
- package/dist/sanitizers/xxe.d.ts +20 -0
- package/dist/sanitizers/xxe.d.ts.map +1 -0
- package/dist/stores/index.d.ts +6 -104
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/index.js +21 -1
- package/dist/stores/index.js.map +1 -1
- package/dist/stores/index.mjs +21 -1
- package/dist/stores/index.mjs.map +1 -1
- package/dist/stores/memory.d.ts +29 -0
- package/dist/stores/memory.d.ts.map +1 -0
- package/dist/stores/{index.d.mts → redis.d.ts} +6 -45
- package/dist/stores/redis.d.ts.map +1 -0
- package/dist/utils/duration.d.ts +34 -0
- package/dist/utils/duration.d.ts.map +1 -0
- package/dist/utils/fingerprint.d.ts +64 -0
- package/dist/utils/fingerprint.d.ts.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +188 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/index.mjs +182 -0
- package/dist/utils/index.mjs.map +1 -0
- package/dist/utils/ip.d.ts +70 -0
- package/dist/utils/ip.d.ts.map +1 -0
- package/dist/validation/email.d.ts +82 -0
- package/dist/validation/email.d.ts.map +1 -0
- package/dist/validation/file.d.ts +90 -0
- package/dist/validation/file.d.ts.map +1 -0
- package/dist/validation/index.d.ts +10 -3
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +38 -21
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/index.mjs +38 -21
- package/dist/validation/index.mjs.map +1 -1
- package/dist/validation/redirect.d.ts +64 -0
- package/dist/validation/redirect.d.ts.map +1 -0
- package/dist/validation/schema.d.ts +36 -0
- package/dist/validation/schema.d.ts.map +1 -0
- package/dist/validation/url.d.ts +65 -0
- package/dist/validation/url.d.ts.map +1 -0
- package/package.json +8 -6
- package/dist/encode-CrQCGlBq.d.mts +0 -484
- package/dist/encode-jl9sOwmA.d.ts +0 -484
- package/dist/index-BAhgn9V2.d.ts +0 -532
- package/dist/index-BGNKspqH.d.ts +0 -340
- package/dist/index-Cd02z-0j.d.mts +0 -340
- package/dist/index-DgJtWMSj.d.mts +0 -532
- package/dist/index.d.mts +0 -175
- package/dist/middleware/index.d.mts +0 -3
- package/dist/sanitizers/index.d.mts +0 -24
- package/dist/types-BOkx5YJc.d.ts +0 -279
- package/dist/validation/index.d.mts +0 -3
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @arcis/node/validation/file
|
|
3
|
+
* File upload validation and filename sanitization
|
|
4
|
+
*/
|
|
5
|
+
/** File upload validation options */
|
|
6
|
+
export interface ValidateFileOptions {
|
|
7
|
+
/** Maximum file size in bytes. Default: 5MB */
|
|
8
|
+
maxSize?: number;
|
|
9
|
+
/** Allowed MIME types (e.g., ['image/jpeg', 'image/png']) */
|
|
10
|
+
allowedTypes?: string[];
|
|
11
|
+
/** Allowed file extensions (e.g., ['.jpg', '.png']). Includes dot. */
|
|
12
|
+
allowedExtensions?: string[];
|
|
13
|
+
/** Block dangerous/executable extensions. Default: true */
|
|
14
|
+
blockExecutables?: boolean;
|
|
15
|
+
/** Validate magic bytes match the claimed MIME type. Default: true */
|
|
16
|
+
validateMagicBytes?: boolean;
|
|
17
|
+
/** Block files with no extension. Default: true */
|
|
18
|
+
blockNoExtension?: boolean;
|
|
19
|
+
/** Block double extensions (e.g., file.php.jpg). Default: true */
|
|
20
|
+
blockDoubleExtensions?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** File metadata for validation */
|
|
23
|
+
export interface FileInput {
|
|
24
|
+
/** Original filename */
|
|
25
|
+
filename: string;
|
|
26
|
+
/** MIME type (as claimed by client) */
|
|
27
|
+
mimetype: string;
|
|
28
|
+
/** File size in bytes */
|
|
29
|
+
size: number;
|
|
30
|
+
/** File content buffer (for magic byte validation) */
|
|
31
|
+
buffer?: Buffer;
|
|
32
|
+
}
|
|
33
|
+
/** File validation result */
|
|
34
|
+
export interface ValidateFileResult {
|
|
35
|
+
/** Whether the file passed validation */
|
|
36
|
+
valid: boolean;
|
|
37
|
+
/** Validation errors (empty if valid) */
|
|
38
|
+
errors: string[];
|
|
39
|
+
/** Sanitized filename (safe for storage) */
|
|
40
|
+
sanitizedFilename: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Sanitize a filename for safe storage.
|
|
44
|
+
*
|
|
45
|
+
* Strips path traversal, null bytes, control characters, and special characters.
|
|
46
|
+
* Preserves the extension and converts to a filesystem-safe name.
|
|
47
|
+
*
|
|
48
|
+
* @param filename - The original filename
|
|
49
|
+
* @returns A sanitized filename safe for storage
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* sanitizeFilename('../../etc/passwd') // 'etc_passwd'
|
|
53
|
+
* sanitizeFilename('file<name>.jpg') // 'filename.jpg'
|
|
54
|
+
* sanitizeFilename('photo (1).jpg') // 'photo_1.jpg'
|
|
55
|
+
* sanitizeFilename('.htaccess') // 'htaccess'
|
|
56
|
+
*/
|
|
57
|
+
export declare function sanitizeFilename(filename: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Validate a file upload for security.
|
|
60
|
+
*
|
|
61
|
+
* Checks file size, MIME type, extension, magic bytes, and dangerous patterns.
|
|
62
|
+
* Returns a result with validation errors and a sanitized filename.
|
|
63
|
+
*
|
|
64
|
+
* @param file - File metadata and optional content
|
|
65
|
+
* @param options - Validation options
|
|
66
|
+
* @returns Validation result
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* const result = validateFile(
|
|
70
|
+
* { filename: 'photo.jpg', mimetype: 'image/jpeg', size: 1024, buffer },
|
|
71
|
+
* { allowedTypes: ['image/jpeg', 'image/png'], maxSize: 2 * 1024 * 1024 }
|
|
72
|
+
* );
|
|
73
|
+
* if (!result.valid) {
|
|
74
|
+
* return res.status(400).json({ errors: result.errors });
|
|
75
|
+
* }
|
|
76
|
+
* // Use result.sanitizedFilename for storage
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* // Block executables only (no whitelist)
|
|
80
|
+
* const result = validateFile(file, { blockExecutables: true });
|
|
81
|
+
*/
|
|
82
|
+
export declare function validateFile(file: FileInput, options?: ValidateFileOptions): ValidateFileResult;
|
|
83
|
+
/**
|
|
84
|
+
* Check if a file extension is considered dangerous/executable.
|
|
85
|
+
*
|
|
86
|
+
* @param filename - Filename or extension to check
|
|
87
|
+
* @returns true if the extension is dangerous
|
|
88
|
+
*/
|
|
89
|
+
export declare function isDangerousExtension(filename: string): boolean;
|
|
90
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/validation/file.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuDH,qCAAqC;AACrC,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,kEAAkE;IAClE,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,mCAAmC;AACnC,MAAM,WAAW,SAAS;IACxB,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,6BAA6B;AAC7B,MAAM,WAAW,kBAAkB;IACjC,yCAAyC;IACzC,KAAK,EAAE,OAAO,CAAC;IACf,yCAAyC;IACzC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,4CAA4C;IAC5C,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAYD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAqCzD;AAmDD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,EACf,OAAO,GAAE,mBAAwB,GAChC,kBAAkB,CA6DpB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG9D"}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module @arcis/node/validation
|
|
3
|
+
* Request validation for Arcis
|
|
4
|
+
*/
|
|
5
|
+
export { validate, createValidator } from './schema';
|
|
6
|
+
export { validateFile, sanitizeFilename, isDangerousExtension } from './file';
|
|
7
|
+
export { validateUrl, isUrlSafe } from './url';
|
|
8
|
+
export { validateRedirect, isRedirectSafe } from './redirect';
|
|
9
|
+
export { validateEmail, verifyEmailMx, isValidEmailSyntax } from './email';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/validation/index.js
CHANGED
|
@@ -31,7 +31,15 @@ var XSS_REMOVE_PATTERNS = [
|
|
|
31
31
|
/javascript\s*:/gi,
|
|
32
32
|
/vbscript\s*:/gi,
|
|
33
33
|
/** data: URIs with HTML/script content */
|
|
34
|
-
/data\s*:\s*text\/html[^>\s]*/gi
|
|
34
|
+
/data\s*:\s*text\/html[^>\s]*/gi,
|
|
35
|
+
/** form tag injection — phishing via action= redirection */
|
|
36
|
+
/<form[\s>][^>]*/gi,
|
|
37
|
+
/** meta tag injection — http-equiv refresh or CSP bypass */
|
|
38
|
+
/<meta[\s>][^>]*/gi,
|
|
39
|
+
/** base href hijacking */
|
|
40
|
+
/<base[\s>][^>]*/gi,
|
|
41
|
+
/** link tag injection — stylesheet or preload attacks */
|
|
42
|
+
/<link[\s>][^>]*/gi
|
|
35
43
|
];
|
|
36
44
|
var SQL_PATTERNS = [
|
|
37
45
|
/** SQL keywords */
|
|
@@ -95,8 +103,8 @@ var COMMAND_PATTERNS = [
|
|
|
95
103
|
/[;&|`]/g,
|
|
96
104
|
/** Command substitution: $( ... ) — matched as a pair to reduce false positives */
|
|
97
105
|
/\$\(/g,
|
|
98
|
-
/** URL-encoded
|
|
99
|
-
/%0[
|
|
106
|
+
/** URL-encoded control characters (%00-%0F): null, tab, vtab, formfeed, LF, CR */
|
|
107
|
+
/%0[0-9a-f]/gi
|
|
100
108
|
];
|
|
101
109
|
var VALIDATION = {
|
|
102
110
|
/**
|
|
@@ -261,26 +269,31 @@ function sanitizePath(input, collectThreats = false) {
|
|
|
261
269
|
const threats = [];
|
|
262
270
|
let value = input;
|
|
263
271
|
let wasSanitized = false;
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
272
|
+
value = value.normalize("NFKC");
|
|
273
|
+
let prev;
|
|
274
|
+
do {
|
|
275
|
+
prev = value;
|
|
276
|
+
for (const pattern of PATH_PATTERNS) {
|
|
267
277
|
pattern.lastIndex = 0;
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
278
|
+
if (pattern.test(value)) {
|
|
279
|
+
pattern.lastIndex = 0;
|
|
280
|
+
if (collectThreats) {
|
|
281
|
+
const matches = value.match(pattern);
|
|
282
|
+
if (matches) {
|
|
283
|
+
for (const match of matches) {
|
|
284
|
+
threats.push({
|
|
285
|
+
type: "path_traversal",
|
|
286
|
+
pattern: pattern.source,
|
|
287
|
+
original: match
|
|
288
|
+
});
|
|
289
|
+
}
|
|
277
290
|
}
|
|
278
291
|
}
|
|
292
|
+
value = value.replace(pattern, "");
|
|
293
|
+
wasSanitized = true;
|
|
279
294
|
}
|
|
280
|
-
value = value.replace(pattern, "");
|
|
281
|
-
wasSanitized = true;
|
|
282
295
|
}
|
|
283
|
-
}
|
|
296
|
+
} while (value !== prev);
|
|
284
297
|
if (collectThreats) {
|
|
285
298
|
return { value, wasSanitized, threats };
|
|
286
299
|
}
|
|
@@ -338,7 +351,7 @@ function sanitizeString(value, options = {}) {
|
|
|
338
351
|
if (value.length > maxSize) {
|
|
339
352
|
throw new InputTooLargeError(maxSize, value.length);
|
|
340
353
|
}
|
|
341
|
-
const reject = options.mode
|
|
354
|
+
const reject = options.mode === "reject";
|
|
342
355
|
let result = value;
|
|
343
356
|
if (options.sql !== false) {
|
|
344
357
|
if (reject) {
|
|
@@ -793,8 +806,12 @@ function checkPrivateIp(hostname) {
|
|
|
793
806
|
if (hostname === "metadata.google.internal" || hostname === "metadata.internal" || hostname === "metadata.azure.internal") {
|
|
794
807
|
return "cloud metadata endpoint";
|
|
795
808
|
}
|
|
796
|
-
|
|
797
|
-
|
|
809
|
+
let ipv6 = hostname.replace(/^\[|\]$/g, "");
|
|
810
|
+
const zoneIdx = ipv6.indexOf("%");
|
|
811
|
+
if (zoneIdx !== -1) {
|
|
812
|
+
ipv6 = ipv6.slice(0, zoneIdx);
|
|
813
|
+
}
|
|
814
|
+
if (ipv6 === "::1" || ipv6 === "::" || /^fc[0-9a-f]{2}:/i.test(ipv6) || /^fd[0-9a-f]{2}:/i.test(ipv6) || /^fe80:/i.test(ipv6) || /^ff[0-9a-f]{2}:/i.test(ipv6)) {
|
|
798
815
|
return "private IPv6 address";
|
|
799
816
|
}
|
|
800
817
|
const mappedDotted = ipv6.match(/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i);
|