@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { randomBytes } from 'crypto';
|
|
1
|
+
import { randomBytes, timingSafeEqual } from 'crypto';
|
|
2
2
|
|
|
3
3
|
// src/core/constants.ts
|
|
4
4
|
var INPUT = {
|
|
@@ -65,7 +65,15 @@ var XSS_REMOVE_PATTERNS = [
|
|
|
65
65
|
/javascript\s*:/gi,
|
|
66
66
|
/vbscript\s*:/gi,
|
|
67
67
|
/** data: URIs with HTML/script content */
|
|
68
|
-
/data\s*:\s*text\/html[^>\s]*/gi
|
|
68
|
+
/data\s*:\s*text\/html[^>\s]*/gi,
|
|
69
|
+
/** form tag injection — phishing via action= redirection */
|
|
70
|
+
/<form[\s>][^>]*/gi,
|
|
71
|
+
/** meta tag injection — http-equiv refresh or CSP bypass */
|
|
72
|
+
/<meta[\s>][^>]*/gi,
|
|
73
|
+
/** base href hijacking */
|
|
74
|
+
/<base[\s>][^>]*/gi,
|
|
75
|
+
/** link tag injection — stylesheet or preload attacks */
|
|
76
|
+
/<link[\s>][^>]*/gi
|
|
69
77
|
];
|
|
70
78
|
var SQL_PATTERNS = [
|
|
71
79
|
/** SQL keywords */
|
|
@@ -129,8 +137,8 @@ var COMMAND_PATTERNS = [
|
|
|
129
137
|
/[;&|`]/g,
|
|
130
138
|
/** Command substitution: $( ... ) — matched as a pair to reduce false positives */
|
|
131
139
|
/\$\(/g,
|
|
132
|
-
/** URL-encoded
|
|
133
|
-
/%0[
|
|
140
|
+
/** URL-encoded control characters (%00-%0F): null, tab, vtab, formfeed, LF, CR */
|
|
141
|
+
/%0[0-9a-f]/gi
|
|
134
142
|
];
|
|
135
143
|
var DANGEROUS_PROTO_KEYS = /* @__PURE__ */ new Set([
|
|
136
144
|
"__proto__",
|
|
@@ -418,7 +426,24 @@ function createRateLimiter(options = {}) {
|
|
|
418
426
|
}
|
|
419
427
|
next();
|
|
420
428
|
} catch (error) {
|
|
421
|
-
console.error("[arcis] Rate limiter error:", error);
|
|
429
|
+
console.error("[arcis] Rate limiter store error, using in-memory fallback:", error);
|
|
430
|
+
try {
|
|
431
|
+
const key = keyGenerator(req);
|
|
432
|
+
const now = Date.now();
|
|
433
|
+
if (!inMemoryStore[key] || inMemoryStore[key].resetTime < now) {
|
|
434
|
+
inMemoryStore[key] = { count: 1, resetTime: now + windowMs };
|
|
435
|
+
} else {
|
|
436
|
+
inMemoryStore[key].count++;
|
|
437
|
+
}
|
|
438
|
+
const count = inMemoryStore[key].count;
|
|
439
|
+
if (count > max) {
|
|
440
|
+
const resetSeconds = Math.ceil((inMemoryStore[key].resetTime - now) / 1e3);
|
|
441
|
+
res.setHeader("Retry-After", resetSeconds.toString());
|
|
442
|
+
res.status(statusCode).json({ error: message, retryAfter: resetSeconds });
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
} catch {
|
|
446
|
+
}
|
|
422
447
|
next();
|
|
423
448
|
}
|
|
424
449
|
};
|
|
@@ -628,26 +653,31 @@ function sanitizePath(input, collectThreats = false) {
|
|
|
628
653
|
const threats = [];
|
|
629
654
|
let value = input;
|
|
630
655
|
let wasSanitized = false;
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
656
|
+
value = value.normalize("NFKC");
|
|
657
|
+
let prev;
|
|
658
|
+
do {
|
|
659
|
+
prev = value;
|
|
660
|
+
for (const pattern of PATH_PATTERNS) {
|
|
634
661
|
pattern.lastIndex = 0;
|
|
635
|
-
if (
|
|
636
|
-
|
|
637
|
-
if (
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
662
|
+
if (pattern.test(value)) {
|
|
663
|
+
pattern.lastIndex = 0;
|
|
664
|
+
if (collectThreats) {
|
|
665
|
+
const matches = value.match(pattern);
|
|
666
|
+
if (matches) {
|
|
667
|
+
for (const match of matches) {
|
|
668
|
+
threats.push({
|
|
669
|
+
type: "path_traversal",
|
|
670
|
+
pattern: pattern.source,
|
|
671
|
+
original: match
|
|
672
|
+
});
|
|
673
|
+
}
|
|
644
674
|
}
|
|
645
675
|
}
|
|
676
|
+
value = value.replace(pattern, "");
|
|
677
|
+
wasSanitized = true;
|
|
646
678
|
}
|
|
647
|
-
value = value.replace(pattern, "");
|
|
648
|
-
wasSanitized = true;
|
|
649
679
|
}
|
|
650
|
-
}
|
|
680
|
+
} while (value !== prev);
|
|
651
681
|
if (collectThreats) {
|
|
652
682
|
return { value, wasSanitized, threats };
|
|
653
683
|
}
|
|
@@ -705,7 +735,7 @@ function sanitizeString(value, options = {}) {
|
|
|
705
735
|
if (value.length > maxSize) {
|
|
706
736
|
throw new InputTooLargeError(maxSize, value.length);
|
|
707
737
|
}
|
|
708
|
-
const reject = options.mode
|
|
738
|
+
const reject = options.mode === "reject";
|
|
709
739
|
let result = value;
|
|
710
740
|
if (options.sql !== false) {
|
|
711
741
|
if (reject) {
|
|
@@ -1582,11 +1612,9 @@ function generateCsrfToken(length = 32) {
|
|
|
1582
1612
|
function validateCsrfToken(cookieToken, requestToken) {
|
|
1583
1613
|
if (!cookieToken || !requestToken) return false;
|
|
1584
1614
|
if (cookieToken.length !== requestToken.length) return false;
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
}
|
|
1589
|
-
return result === 0;
|
|
1615
|
+
const a = Buffer.from(cookieToken);
|
|
1616
|
+
const b = Buffer.from(requestToken);
|
|
1617
|
+
return timingSafeEqual(a, b);
|
|
1590
1618
|
}
|
|
1591
1619
|
function getRequestToken(req, headerName, fieldName) {
|
|
1592
1620
|
const headerToken = req.headers[headerName.toLowerCase()];
|
|
@@ -1595,19 +1623,17 @@ function getRequestToken(req, headerName, fieldName) {
|
|
|
1595
1623
|
const bodyToken = req.body[fieldName];
|
|
1596
1624
|
if (typeof bodyToken === "string" && bodyToken) return bodyToken;
|
|
1597
1625
|
}
|
|
1598
|
-
if (req.query && fieldName in req.query) {
|
|
1599
|
-
const queryToken = req.query[fieldName];
|
|
1600
|
-
if (typeof queryToken === "string" && queryToken) return queryToken;
|
|
1601
|
-
}
|
|
1602
1626
|
return void 0;
|
|
1603
1627
|
}
|
|
1604
1628
|
function csrfProtection(options = {}) {
|
|
1605
|
-
const
|
|
1629
|
+
const baseCookieName = options.cookieName ?? DEFAULTS.cookieName;
|
|
1630
|
+
const cookieName = options.useHostPrefix ? `__Host-${baseCookieName}` : baseCookieName;
|
|
1606
1631
|
const headerName = options.headerName ?? DEFAULTS.headerName;
|
|
1607
1632
|
const fieldName = options.fieldName ?? DEFAULTS.fieldName;
|
|
1608
1633
|
const tokenLength = options.tokenLength ?? DEFAULTS.tokenLength;
|
|
1609
1634
|
const protectedMethods = options.protectedMethods ?? [...DEFAULTS.protectedMethods];
|
|
1610
1635
|
const excludePaths = options.excludePaths ?? [];
|
|
1636
|
+
const skipCsrf = options.skipCsrf;
|
|
1611
1637
|
const isProduction = process.env.NODE_ENV === "production";
|
|
1612
1638
|
const cookieOpts = {
|
|
1613
1639
|
path: options.cookie?.path ?? "/",
|
|
@@ -1627,6 +1653,9 @@ function csrfProtection(options = {}) {
|
|
|
1627
1653
|
const protectedSet = new Set(protectedMethods.map((m) => m.toUpperCase()));
|
|
1628
1654
|
return (req, res, next) => {
|
|
1629
1655
|
const method = req.method.toUpperCase();
|
|
1656
|
+
if (skipCsrf && skipCsrf(req)) {
|
|
1657
|
+
return next();
|
|
1658
|
+
}
|
|
1630
1659
|
const requestPath = req.path || req.url;
|
|
1631
1660
|
if (excludePaths.some((p) => requestPath === p || requestPath.startsWith(p + "/"))) {
|
|
1632
1661
|
return next();
|
|
@@ -1676,7 +1705,15 @@ function setCsrfCookie(res, name, token, opts) {
|
|
|
1676
1705
|
if (opts.secure) parts.push("Secure");
|
|
1677
1706
|
parts.push(`SameSite=${opts.sameSite}`);
|
|
1678
1707
|
if (opts.domain) parts.push(`Domain=${opts.domain}`);
|
|
1679
|
-
|
|
1708
|
+
const newCookie = parts.join("; ");
|
|
1709
|
+
const existing = res.getHeader("Set-Cookie");
|
|
1710
|
+
if (existing === void 0) {
|
|
1711
|
+
res.setHeader("Set-Cookie", newCookie);
|
|
1712
|
+
} else if (Array.isArray(existing)) {
|
|
1713
|
+
res.setHeader("Set-Cookie", [...existing, newCookie]);
|
|
1714
|
+
} else {
|
|
1715
|
+
res.setHeader("Set-Cookie", [existing, newCookie]);
|
|
1716
|
+
}
|
|
1680
1717
|
}
|
|
1681
1718
|
function escapeRegex(str) {
|
|
1682
1719
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|