@arcis/node 1.4.4 → 1.5.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.
- package/LICENSE +21 -0
- package/README.md +36 -6
- package/dist/astro/index.js +6141 -0
- package/dist/astro/index.js.map +1 -0
- package/dist/astro/index.mjs +6136 -0
- package/dist/astro/index.mjs.map +1 -0
- package/dist/bun/index.js +6195 -0
- package/dist/bun/index.js.map +1 -0
- package/dist/bun/index.mjs +6189 -0
- package/dist/bun/index.mjs.map +1 -0
- package/dist/core/constants.d.ts +3 -2
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/index.js +4 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +4 -3
- package/dist/core/index.mjs.map +1 -1
- package/dist/core/types.d.ts +32 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/fastify/index.js +6160 -0
- package/dist/fastify/index.js.map +1 -0
- package/dist/fastify/index.mjs +6155 -0
- package/dist/fastify/index.mjs.map +1 -0
- package/dist/guards.d.ts +156 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/hono/index.js +6159 -0
- package/dist/hono/index.js.map +1 -0
- package/dist/hono/index.mjs +6154 -0
- package/dist/hono/index.mjs.map +1 -0
- package/dist/index.d.ts +23 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7126 -178
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7088 -179
- package/dist/index.mjs.map +1 -1
- package/dist/koa/index.js +6158 -0
- package/dist/koa/index.js.map +1 -0
- package/dist/koa/index.mjs +6153 -0
- package/dist/koa/index.mjs.map +1 -0
- package/dist/logging/index.js.map +1 -1
- package/dist/logging/index.mjs.map +1 -1
- package/dist/logging/redactor.d.ts.map +1 -1
- package/dist/middleware/astro.d.ts +64 -0
- package/dist/middleware/astro.d.ts.map +1 -0
- package/dist/middleware/bot-detection.d.ts.map +1 -1
- package/dist/middleware/bun.d.ts +75 -0
- package/dist/middleware/bun.d.ts.map +1 -0
- package/dist/middleware/csrf.d.ts.map +1 -1
- package/dist/middleware/error-handler.d.ts.map +1 -1
- package/dist/middleware/fastify.d.ts +89 -0
- package/dist/middleware/fastify.d.ts.map +1 -0
- package/dist/middleware/graphql.d.ts +35 -0
- package/dist/middleware/graphql.d.ts.map +1 -0
- package/dist/middleware/hono.d.ts +63 -0
- package/dist/middleware/hono.d.ts.map +1 -0
- package/dist/middleware/index.d.ts +12 -0
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +6469 -119
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/index.mjs +6459 -120
- package/dist/middleware/index.mjs.map +1 -1
- package/dist/middleware/koa.d.ts +84 -0
- package/dist/middleware/koa.d.ts.map +1 -0
- package/dist/middleware/main.d.ts +0 -30
- package/dist/middleware/main.d.ts.map +1 -1
- package/dist/middleware/mass-assign.d.ts +81 -0
- package/dist/middleware/mass-assign.d.ts.map +1 -0
- package/dist/middleware/method-allowlist.d.ts +66 -0
- package/dist/middleware/method-allowlist.d.ts.map +1 -0
- package/dist/middleware/nestjs.d.ts +62 -0
- package/dist/middleware/nestjs.d.ts.map +1 -0
- package/dist/middleware/nextjs.d.ts +102 -0
- package/dist/middleware/nextjs.d.ts.map +1 -0
- package/dist/middleware/nuxt.d.ts +61 -0
- package/dist/middleware/nuxt.d.ts.map +1 -0
- package/dist/middleware/overload.d.ts +92 -0
- package/dist/middleware/overload.d.ts.map +1 -0
- package/dist/middleware/protect.d.ts +91 -0
- package/dist/middleware/protect.d.ts.map +1 -0
- package/dist/middleware/rate-limit-sliding.d.ts.map +1 -1
- package/dist/middleware/rate-limit-token.d.ts.map +1 -1
- package/dist/middleware/rate-limit.d.ts.map +1 -1
- package/dist/middleware/response-splitting.d.ts +83 -0
- package/dist/middleware/response-splitting.d.ts.map +1 -0
- package/dist/middleware/sveltekit.d.ts +68 -0
- package/dist/middleware/sveltekit.d.ts.map +1 -0
- package/dist/middleware/token-budget.d.ts +75 -0
- package/dist/middleware/token-budget.d.ts.map +1 -0
- package/dist/nestjs/index.js +1724 -0
- package/dist/nestjs/index.js.map +1 -0
- package/dist/nestjs/index.mjs +1717 -0
- package/dist/nestjs/index.mjs.map +1 -0
- package/dist/nextjs/index.js +6184 -0
- package/dist/nextjs/index.js.map +1 -0
- package/dist/nextjs/index.mjs +6178 -0
- package/dist/nextjs/index.mjs.map +1 -0
- package/dist/nuxt/index.js +6141 -0
- package/dist/nuxt/index.js.map +1 -0
- package/dist/nuxt/index.mjs +6136 -0
- package/dist/nuxt/index.mjs.map +1 -0
- package/dist/sanitizers/encode.d.ts.map +1 -1
- package/dist/sanitizers/graphql.d.ts +72 -0
- package/dist/sanitizers/graphql.d.ts.map +1 -0
- package/dist/sanitizers/headers.d.ts +18 -0
- package/dist/sanitizers/headers.d.ts.map +1 -1
- package/dist/sanitizers/index.d.ts +4 -1
- package/dist/sanitizers/index.d.ts.map +1 -1
- package/dist/sanitizers/index.js +140 -66
- package/dist/sanitizers/index.js.map +1 -1
- package/dist/sanitizers/index.mjs +135 -67
- package/dist/sanitizers/index.mjs.map +1 -1
- package/dist/sanitizers/prompt-injection.d.ts +62 -0
- package/dist/sanitizers/prompt-injection.d.ts.map +1 -0
- package/dist/sanitizers/sanitize.d.ts +1 -1
- package/dist/sanitizers/sanitize.d.ts.map +1 -1
- package/dist/sanitizers/xpath.d.ts +37 -0
- package/dist/sanitizers/xpath.d.ts.map +1 -0
- package/dist/stores/index.js +4 -4
- package/dist/stores/index.js.map +1 -1
- package/dist/stores/index.mjs +4 -4
- package/dist/stores/index.mjs.map +1 -1
- package/dist/stores/redis.d.ts +7 -1
- package/dist/stores/redis.d.ts.map +1 -1
- package/dist/sveltekit/index.js +6142 -0
- package/dist/sveltekit/index.js.map +1 -0
- package/dist/sveltekit/index.mjs +6137 -0
- package/dist/sveltekit/index.mjs.map +1 -0
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/index.js +137 -12
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/index.mjs +116 -13
- package/dist/validation/index.mjs.map +1 -1
- package/dist/validation/redirect.d.ts.map +1 -1
- package/dist/validation/schema.d.ts.map +1 -1
- package/dist/validation/url-async.d.ts +137 -0
- package/dist/validation/url-async.d.ts.map +1 -0
- package/package.json +52 -7
- package/scripts/postinstall.cjs +26 -0
- package/dist/cli/arcis.d.ts +0 -23
- package/dist/cli/arcis.d.ts.map +0 -1
- package/dist/cli/arcis.js +0 -312
- package/dist/cli/arcis.js.map +0 -1
- package/dist/cli/arcis.mjs +0 -309
- package/dist/cli/arcis.mjs.map +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as dns from 'dns';
|
|
1
2
|
import { promises } from 'dns';
|
|
2
3
|
|
|
3
4
|
// src/core/constants.ts
|
|
@@ -31,8 +32,8 @@ var XSS_REMOVE_PATTERNS = [
|
|
|
31
32
|
/** javascript: and vbscript: protocols (allow optional spaces before colon) */
|
|
32
33
|
/javascript\s*:/gi,
|
|
33
34
|
/vbscript\s*:/gi,
|
|
34
|
-
/** data: URIs with HTML
|
|
35
|
-
/data\s*:\s*text\/html[^>\s]*/gi,
|
|
35
|
+
/** data: URIs with HTML or SVG content (SVG can run JS via inline event handlers) */
|
|
36
|
+
/data\s*:\s*(?:text\/html|image\/svg)[^>\s]*/gi,
|
|
36
37
|
/** form tag injection — phishing via action= redirection */
|
|
37
38
|
/<form[\s>][^>]*/gi,
|
|
38
39
|
/** meta tag injection — http-equiv refresh or CSP bypass */
|
|
@@ -116,10 +117,11 @@ var VALIDATION = {
|
|
|
116
117
|
EMAIL: /^[^\s@.][^\s@]*(?:\.[^\s@.][^\s@]*)*@[^\s@]+\.[^\s@]+$/,
|
|
117
118
|
/**
|
|
118
119
|
* URL regex pattern.
|
|
119
|
-
* Only allows http:// and https://
|
|
120
|
-
* data:, vbscript:, and
|
|
120
|
+
* Only allows http:// and https:// (case-insensitive scheme per
|
|
121
|
+
* RFC 3986); explicitly rejects javascript:, data:, vbscript:, and
|
|
122
|
+
* other dangerous URI schemes.
|
|
121
123
|
*/
|
|
122
|
-
URL: /^https?:\/\/[^\s/$.?#][^\s]
|
|
124
|
+
URL: /^https?:\/\/[^\s/$.?#][^\s]*$/i,
|
|
123
125
|
/** UUID regex pattern (v4) */
|
|
124
126
|
UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
125
127
|
};
|
|
@@ -400,7 +402,12 @@ function validate(schema, source = "body") {
|
|
|
400
402
|
res.status(400).json({ errors });
|
|
401
403
|
return;
|
|
402
404
|
}
|
|
403
|
-
req
|
|
405
|
+
Object.defineProperty(req, source, {
|
|
406
|
+
value: validated,
|
|
407
|
+
writable: true,
|
|
408
|
+
configurable: true,
|
|
409
|
+
enumerable: true
|
|
410
|
+
});
|
|
404
411
|
next();
|
|
405
412
|
};
|
|
406
413
|
}
|
|
@@ -897,6 +904,99 @@ function checkOctalIp(hostname, allowLocalhost, allowPrivate) {
|
|
|
897
904
|
}
|
|
898
905
|
return null;
|
|
899
906
|
}
|
|
907
|
+
var defaultLookup = (hostname) => new Promise((resolve, reject) => {
|
|
908
|
+
dns.lookup(hostname, { all: true }, (err, addresses) => {
|
|
909
|
+
if (err) reject(err);
|
|
910
|
+
else resolve(addresses);
|
|
911
|
+
});
|
|
912
|
+
});
|
|
913
|
+
function checkResolvedIp(ip, options) {
|
|
914
|
+
const isIpv6 = ip.includes(":");
|
|
915
|
+
const host = isIpv6 ? `[${ip}]` : ip;
|
|
916
|
+
const { allowedProtocols, allowLocalhost, allowPrivate } = options;
|
|
917
|
+
return validateUrl(`http://${host}/`, {
|
|
918
|
+
allowedProtocols,
|
|
919
|
+
allowLocalhost,
|
|
920
|
+
allowPrivate
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
async function validateUrlAsync(url, options = {}) {
|
|
924
|
+
const sync = validateUrl(url, options);
|
|
925
|
+
if (!sync.safe) return sync;
|
|
926
|
+
let parsed;
|
|
927
|
+
try {
|
|
928
|
+
parsed = new URL(url);
|
|
929
|
+
} catch {
|
|
930
|
+
return { safe: false, reason: "invalid URL: failed to parse" };
|
|
931
|
+
}
|
|
932
|
+
const host = parsed.hostname.replace(/^\[|\]$/g, "");
|
|
933
|
+
if (isLiteralIp(host)) return { safe: true };
|
|
934
|
+
if (options.allowedHosts?.some((h) => host.toLowerCase() === h.toLowerCase())) {
|
|
935
|
+
return { safe: true };
|
|
936
|
+
}
|
|
937
|
+
const lookup2 = options.lookup ?? defaultLookup;
|
|
938
|
+
let addresses;
|
|
939
|
+
try {
|
|
940
|
+
addresses = await lookup2(host);
|
|
941
|
+
} catch (err) {
|
|
942
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
943
|
+
return { safe: false, reason: `DNS lookup failed: ${msg}` };
|
|
944
|
+
}
|
|
945
|
+
if (addresses.length === 0) {
|
|
946
|
+
return { safe: false, reason: "DNS returned no addresses" };
|
|
947
|
+
}
|
|
948
|
+
const ips = addresses.map((a) => a.address);
|
|
949
|
+
const acceptFirstPublic = options.acceptFirstPublic === true;
|
|
950
|
+
let firstPublic;
|
|
951
|
+
for (const ip of ips) {
|
|
952
|
+
const ipResult = checkResolvedIp(ip, options);
|
|
953
|
+
if (ipResult.safe) {
|
|
954
|
+
if (firstPublic === void 0) firstPublic = ip;
|
|
955
|
+
} else if (!acceptFirstPublic) {
|
|
956
|
+
return {
|
|
957
|
+
safe: false,
|
|
958
|
+
reason: `resolved IP ${ip} is unsafe: ${ipResult.reason}`,
|
|
959
|
+
resolvedIps: ips
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
if (firstPublic === void 0) {
|
|
964
|
+
return {
|
|
965
|
+
safe: false,
|
|
966
|
+
reason: "all resolved IPs are private/loopback",
|
|
967
|
+
resolvedIps: ips
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
return { safe: true, resolvedIp: firstPublic, resolvedIps: ips };
|
|
971
|
+
}
|
|
972
|
+
function pinnedDnsLookup(ip) {
|
|
973
|
+
if (typeof ip !== "string" || ip.trim() === "") {
|
|
974
|
+
throw new TypeError("pinnedDnsLookup: ip must be a non-empty string");
|
|
975
|
+
}
|
|
976
|
+
const family = ip.includes(":") ? 6 : 4;
|
|
977
|
+
return (_hostname, _options, callback) => {
|
|
978
|
+
callback(null, ip, family);
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
async function safeFollowRedirect(prev, location, options = {}) {
|
|
982
|
+
if (typeof location !== "string" || location.trim() === "") {
|
|
983
|
+
return { safe: false, reason: "redirect Location is empty" };
|
|
984
|
+
}
|
|
985
|
+
let absolute;
|
|
986
|
+
try {
|
|
987
|
+
absolute = new URL(location, prev);
|
|
988
|
+
} catch {
|
|
989
|
+
return { safe: false, reason: "invalid redirect URL" };
|
|
990
|
+
}
|
|
991
|
+
return validateUrlAsync(absolute.toString(), options);
|
|
992
|
+
}
|
|
993
|
+
function isLiteralIp(host) {
|
|
994
|
+
if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host)) return true;
|
|
995
|
+
if (/^\d+$/.test(host)) return true;
|
|
996
|
+
if (/^0[0-7x]/.test(host) && /^[0-9a-fx.]+$/i.test(host) && host.includes(".")) return true;
|
|
997
|
+
if (host.includes(":") && !/[/\s]/.test(host)) return true;
|
|
998
|
+
return false;
|
|
999
|
+
}
|
|
900
1000
|
|
|
901
1001
|
// src/validation/redirect.ts
|
|
902
1002
|
var DANGEROUS_PROTOCOLS = /^(javascript|data|vbscript|blob):/i;
|
|
@@ -911,8 +1011,8 @@ function validateRedirect(url, options = {}) {
|
|
|
911
1011
|
return { safe: false, reason: "invalid redirect: empty or not a string" };
|
|
912
1012
|
}
|
|
913
1013
|
const cleaned = url.replace(CONTROL_CHARS, "");
|
|
914
|
-
|
|
915
|
-
|
|
1014
|
+
const proto = cleaned.match(DANGEROUS_PROTOCOLS);
|
|
1015
|
+
if (proto) {
|
|
916
1016
|
return { safe: false, reason: `dangerous protocol: ${proto[0]}` };
|
|
917
1017
|
}
|
|
918
1018
|
if (cleaned.startsWith("\\")) {
|
|
@@ -942,11 +1042,12 @@ function validateRedirect(url, options = {}) {
|
|
|
942
1042
|
return { safe: false, reason: `disallowed protocol: ${parsed.protocol}` };
|
|
943
1043
|
}
|
|
944
1044
|
const hostname = parsed.hostname.toLowerCase();
|
|
1045
|
+
const hostWithPort = parsed.port ? `${hostname}:${parsed.port}` : hostname;
|
|
945
1046
|
if (allowedHosts.length === 0) {
|
|
946
1047
|
return { safe: false, reason: "absolute URL not in allowed hosts" };
|
|
947
1048
|
}
|
|
948
|
-
if (!allowedHosts.some((h) =>
|
|
949
|
-
return { safe: false, reason: `host not allowed: ${
|
|
1049
|
+
if (!allowedHosts.some((h) => h.toLowerCase() === hostWithPort)) {
|
|
1050
|
+
return { safe: false, reason: `host not allowed: ${hostWithPort}` };
|
|
950
1051
|
}
|
|
951
1052
|
return { safe: true };
|
|
952
1053
|
}
|
|
@@ -954,8 +1055,10 @@ function isRedirectSafe(url, options = {}) {
|
|
|
954
1055
|
return validateRedirect(url, options).safe;
|
|
955
1056
|
}
|
|
956
1057
|
function extractHost(url) {
|
|
957
|
-
const match = url.match(/^\/\/([
|
|
958
|
-
|
|
1058
|
+
const match = url.match(/^\/\/([^/?#]+)/);
|
|
1059
|
+
if (!match) return null;
|
|
1060
|
+
const authority = match[1].includes("@") ? match[1].slice(match[1].indexOf("@") + 1) : match[1];
|
|
1061
|
+
return authority.toLowerCase();
|
|
959
1062
|
}
|
|
960
1063
|
var MAX_EMAIL_LENGTH = 254;
|
|
961
1064
|
var MAX_LOCAL_LENGTH = 64;
|
|
@@ -1209,6 +1312,6 @@ function isValidEmailSyntax(email) {
|
|
|
1209
1312
|
return EMAIL_SYNTAX.test(normalized);
|
|
1210
1313
|
}
|
|
1211
1314
|
|
|
1212
|
-
export { createValidator, isDangerousExtension, isRedirectSafe, isUrlSafe, isValidEmailSyntax, sanitizeFilename, validate, validateEmail, validateFile, validateRedirect, validateUrl, verifyEmailMx };
|
|
1315
|
+
export { createValidator, isDangerousExtension, isRedirectSafe, isUrlSafe, isValidEmailSyntax, pinnedDnsLookup, safeFollowRedirect, sanitizeFilename, validate, validateEmail, validateFile, validateRedirect, validateUrl, validateUrlAsync, verifyEmailMx };
|
|
1213
1316
|
//# sourceMappingURL=index.mjs.map
|
|
1214
1317
|
//# sourceMappingURL=index.mjs.map
|