@arcis/node 1.4.3 → 1.4.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 +11 -3
- package/dist/cli/arcis.d.ts +23 -0
- package/dist/cli/arcis.d.ts.map +1 -0
- package/dist/cli/arcis.js +312 -0
- package/dist/cli/arcis.js.map +1 -0
- package/dist/cli/arcis.mjs +309 -0
- package/dist/cli/arcis.mjs.map +1 -0
- package/dist/core/constants.d.ts +1 -1
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/index.js +4 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +4 -1
- package/dist/core/index.mjs.map +1 -1
- package/dist/core/types.d.ts +11 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.js +253 -141
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +253 -141
- package/dist/index.mjs.map +1 -1
- package/dist/logging/index.js.map +1 -1
- package/dist/logging/index.mjs.map +1 -1
- package/dist/middleware/bot-detection.d.ts.map +1 -1
- package/dist/middleware/csrf.d.ts.map +1 -1
- package/dist/middleware/index.js +224 -3
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/index.mjs +224 -3
- package/dist/middleware/index.mjs.map +1 -1
- package/dist/middleware/main.d.ts.map +1 -1
- package/dist/sanitizers/index.d.ts +2 -1
- package/dist/sanitizers/index.d.ts.map +1 -1
- package/dist/sanitizers/index.js +213 -145
- package/dist/sanitizers/index.js.map +1 -1
- package/dist/sanitizers/index.mjs +213 -146
- package/dist/sanitizers/index.mjs.map +1 -1
- package/dist/sanitizers/sanitize.d.ts +13 -0
- package/dist/sanitizers/sanitize.d.ts.map +1 -1
- package/dist/stores/index.js.map +1 -1
- package/dist/stores/index.mjs.map +1 -1
- package/dist/telemetry/client.d.ts +3 -0
- package/dist/telemetry/client.d.ts.map +1 -1
- package/dist/telemetry/types.d.ts +12 -0
- package/dist/telemetry/types.d.ts.map +1 -1
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/index.mjs.map +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'child_process';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import { dirname, resolve } from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
var USE_COLOR = !process.env.NO_COLOR && process.stdout.isTTY === true;
|
|
8
|
+
function c(text, ...codes) {
|
|
9
|
+
if (!USE_COLOR) return text;
|
|
10
|
+
return codes.join("") + text + "\x1B[0m";
|
|
11
|
+
}
|
|
12
|
+
var BOLD = "\x1B[1m";
|
|
13
|
+
var DIM = "\x1B[2m";
|
|
14
|
+
var GREEN = "\x1B[32m";
|
|
15
|
+
var YELLOW = "\x1B[33m";
|
|
16
|
+
var CYAN = "\x1B[36m";
|
|
17
|
+
var RED = "\x1B[31m";
|
|
18
|
+
function getInstalledVersion() {
|
|
19
|
+
try {
|
|
20
|
+
const here = fileURLToPath(import.meta.url);
|
|
21
|
+
let dir = dirname(here);
|
|
22
|
+
for (let i = 0; i < 6; i++) {
|
|
23
|
+
try {
|
|
24
|
+
const raw = readFileSync(resolve(dir, "package.json"), "utf-8");
|
|
25
|
+
const pkg = JSON.parse(raw);
|
|
26
|
+
if (pkg.name === "@arcis/node" && pkg.version) {
|
|
27
|
+
return pkg.version;
|
|
28
|
+
}
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
const parent = resolve(dir, "..");
|
|
32
|
+
if (parent === dir) break;
|
|
33
|
+
dir = parent;
|
|
34
|
+
}
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
return "?";
|
|
38
|
+
}
|
|
39
|
+
async function fetchLatestVersion() {
|
|
40
|
+
try {
|
|
41
|
+
const controller = new AbortController();
|
|
42
|
+
const timer = setTimeout(() => controller.abort(), 5e3);
|
|
43
|
+
try {
|
|
44
|
+
const resp = await fetch("https://registry.npmjs.org/@arcis/node", {
|
|
45
|
+
headers: { Accept: "application/json" },
|
|
46
|
+
signal: controller.signal
|
|
47
|
+
});
|
|
48
|
+
if (!resp.ok) return null;
|
|
49
|
+
const data = await resp.json();
|
|
50
|
+
return data["dist-tags"]?.latest ?? null;
|
|
51
|
+
} finally {
|
|
52
|
+
clearTimeout(timer);
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function parseVersion(v) {
|
|
59
|
+
const parts = v.split(".");
|
|
60
|
+
const out = [];
|
|
61
|
+
for (const p of parts) {
|
|
62
|
+
if (!/^\d+$/.test(p)) return null;
|
|
63
|
+
out.push(Number(p));
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
function versionCompare(a, b) {
|
|
68
|
+
const len = Math.max(a.length, b.length);
|
|
69
|
+
for (let i = 0; i < len; i++) {
|
|
70
|
+
const x = a[i] ?? 0;
|
|
71
|
+
const y = b[i] ?? 0;
|
|
72
|
+
if (x < y) return -1;
|
|
73
|
+
if (x > y) return 1;
|
|
74
|
+
}
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
function hasPythonArcis() {
|
|
78
|
+
const probes = [
|
|
79
|
+
{ cmd: "arcis", args: ["--version"] },
|
|
80
|
+
{ cmd: "python", args: ["-m", "arcis.cli", "--version"] },
|
|
81
|
+
{ cmd: "python3", args: ["-m", "arcis.cli", "--version"] }
|
|
82
|
+
];
|
|
83
|
+
for (const p of probes) {
|
|
84
|
+
try {
|
|
85
|
+
const result = spawnSync(p.cmd, p.args, {
|
|
86
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
87
|
+
timeout: 3e3,
|
|
88
|
+
shell: process.platform === "win32"
|
|
89
|
+
});
|
|
90
|
+
if (result.status === 0) return true;
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
function forwardToPython(args) {
|
|
97
|
+
const candidates = [
|
|
98
|
+
{ cmd: "arcis", args },
|
|
99
|
+
{ cmd: "python", args: ["-m", "arcis.cli", ...args] },
|
|
100
|
+
{ cmd: "python3", args: ["-m", "arcis.cli", ...args] }
|
|
101
|
+
];
|
|
102
|
+
for (const cand of candidates) {
|
|
103
|
+
const result = spawnSync(cand.cmd, cand.args, {
|
|
104
|
+
stdio: "inherit",
|
|
105
|
+
shell: process.platform === "win32"
|
|
106
|
+
});
|
|
107
|
+
if (result.error) continue;
|
|
108
|
+
process.exit(result.status ?? 0);
|
|
109
|
+
}
|
|
110
|
+
console.error(
|
|
111
|
+
c("arcis: could not invoke the Python CLI. Install with:", RED, BOLD)
|
|
112
|
+
);
|
|
113
|
+
console.error(" pip install arcis");
|
|
114
|
+
process.exit(127);
|
|
115
|
+
}
|
|
116
|
+
function printCatalog(verbose) {
|
|
117
|
+
const ver = getInstalledVersion();
|
|
118
|
+
console.log();
|
|
119
|
+
console.log(` ${c("Arcis", BOLD, CYAN)} ${c(`v${ver}`, DIM)} ${c("(node)", DIM)}`);
|
|
120
|
+
console.log(c(" Zero-dep security middleware + scanners.", DIM));
|
|
121
|
+
console.log();
|
|
122
|
+
console.log(c(" Commands", BOLD));
|
|
123
|
+
const rows = [
|
|
124
|
+
[
|
|
125
|
+
"scan",
|
|
126
|
+
"Send live attack payloads to a running app.",
|
|
127
|
+
"arcis scan http://localhost:8000 --route POST:/echo --field q"
|
|
128
|
+
],
|
|
129
|
+
[
|
|
130
|
+
"audit",
|
|
131
|
+
"Static-analyse Python / JS / TS source for unsafe patterns.",
|
|
132
|
+
"arcis audit ."
|
|
133
|
+
],
|
|
134
|
+
[
|
|
135
|
+
"sca",
|
|
136
|
+
"Match installed dependencies against the supply-chain threat DB.",
|
|
137
|
+
"arcis sca ."
|
|
138
|
+
],
|
|
139
|
+
["update", "Check npm for a newer @arcis/node release.", "arcis update --apply"]
|
|
140
|
+
];
|
|
141
|
+
for (const [name, desc, example] of rows) {
|
|
142
|
+
console.log(` ${c(name.padEnd(8), BOLD, GREEN)} ${desc}`);
|
|
143
|
+
if (verbose) {
|
|
144
|
+
console.log(` ${c(example, DIM)}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
console.log();
|
|
148
|
+
console.log(c(" Discovery", BOLD));
|
|
149
|
+
console.log(` ${c("--list", BOLD, CYAN).padEnd(24)} Show this catalog (verbose).`);
|
|
150
|
+
console.log(
|
|
151
|
+
` ${c("<cmd> --help", BOLD, CYAN).padEnd(24)} Show full flags for that command.`
|
|
152
|
+
);
|
|
153
|
+
console.log();
|
|
154
|
+
console.log(c(" Note", BOLD));
|
|
155
|
+
console.log(
|
|
156
|
+
` scan/audit/sca delegate to the Python CLI (canonical impl).`
|
|
157
|
+
);
|
|
158
|
+
console.log(` Install once with: ${c("pip install arcis", GREEN)}`);
|
|
159
|
+
console.log();
|
|
160
|
+
}
|
|
161
|
+
async function updateCommand(args) {
|
|
162
|
+
const apply = args.includes("--apply");
|
|
163
|
+
const check = args.includes("--check");
|
|
164
|
+
const yes = args.includes("--yes") || args.includes("-y");
|
|
165
|
+
const current = getInstalledVersion();
|
|
166
|
+
const latest = await fetchLatestVersion();
|
|
167
|
+
if (check) {
|
|
168
|
+
if (latest === null) {
|
|
169
|
+
console.error("arcis: could not reach npm to check for updates");
|
|
170
|
+
process.exitCode = 2;
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const cur2 = parseVersion(current);
|
|
174
|
+
const lat2 = parseVersion(latest);
|
|
175
|
+
if (!cur2 || !lat2 || versionCompare(cur2, lat2) >= 0) {
|
|
176
|
+
console.log(`@arcis/node ${current} is up-to-date`);
|
|
177
|
+
process.exitCode = 0;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
console.error(`@arcis/node ${current} is outdated; latest is ${latest}`);
|
|
181
|
+
process.exitCode = 1;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
console.log();
|
|
185
|
+
console.log(c(" @arcis/node update check", BOLD, CYAN));
|
|
186
|
+
console.log(c(" Source: https://registry.npmjs.org/@arcis/node", DIM));
|
|
187
|
+
console.log();
|
|
188
|
+
if (latest === null) {
|
|
189
|
+
console.log(` Installed @arcis/node ${current}`);
|
|
190
|
+
console.log(
|
|
191
|
+
` Latest ${c("? unreachable", YELLOW)} ${c("(network error or npm down)", DIM)}`
|
|
192
|
+
);
|
|
193
|
+
console.log();
|
|
194
|
+
console.log(c(" Try again later, or run 'npm view @arcis/node version' directly.", DIM));
|
|
195
|
+
console.log();
|
|
196
|
+
process.exitCode = 2;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const cur = parseVersion(current);
|
|
200
|
+
const lat = parseVersion(latest);
|
|
201
|
+
if (!cur || !lat) {
|
|
202
|
+
console.log(
|
|
203
|
+
` Installed @arcis/node ${current} ${c("(pre-release or unparseable)", DIM)}`
|
|
204
|
+
);
|
|
205
|
+
console.log(` Latest @arcis/node ${latest}`);
|
|
206
|
+
console.log();
|
|
207
|
+
console.log(c(" Skipping comparison \u2014 manually decide.", DIM));
|
|
208
|
+
console.log();
|
|
209
|
+
process.exitCode = 0;
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (versionCompare(cur, lat) >= 0) {
|
|
213
|
+
console.log(` Installed @arcis/node ${current}`);
|
|
214
|
+
console.log(` Latest @arcis/node ${latest}`);
|
|
215
|
+
console.log();
|
|
216
|
+
console.log(c(" You are on the latest version.", BOLD, GREEN));
|
|
217
|
+
console.log();
|
|
218
|
+
process.exitCode = 0;
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
console.log(` Installed @arcis/node ${current}`);
|
|
222
|
+
console.log(
|
|
223
|
+
` Latest ${c(`@arcis/node ${latest}`, BOLD)} ${c("(update available)", YELLOW)}`
|
|
224
|
+
);
|
|
225
|
+
console.log();
|
|
226
|
+
console.log(c(" Run to upgrade", BOLD));
|
|
227
|
+
console.log(` ${c("npm install @arcis/node@latest", GREEN)}`);
|
|
228
|
+
console.log();
|
|
229
|
+
if (!apply) {
|
|
230
|
+
console.log(c(" Or rerun: 'arcis update --apply' to upgrade in place.", DIM));
|
|
231
|
+
console.log();
|
|
232
|
+
process.exitCode = 1;
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (!yes && process.stdin.isTTY) {
|
|
236
|
+
process.stdout.write("Upgrade now? [y/N] ");
|
|
237
|
+
const response = await new Promise((res) => {
|
|
238
|
+
process.stdin.once("data", (chunk) => res(chunk.toString().trim().toLowerCase()));
|
|
239
|
+
});
|
|
240
|
+
if (!response.startsWith("y")) {
|
|
241
|
+
process.exitCode = 1;
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
246
|
+
console.log(` $ ${npmCmd} install @arcis/node@latest`);
|
|
247
|
+
const result = spawnSync(npmCmd, ["install", "@arcis/node@latest"], {
|
|
248
|
+
stdio: "inherit"
|
|
249
|
+
});
|
|
250
|
+
process.exitCode = result.status ?? 1;
|
|
251
|
+
}
|
|
252
|
+
async function main() {
|
|
253
|
+
const args = process.argv.slice(2);
|
|
254
|
+
if (args.length === 0) {
|
|
255
|
+
printCatalog(false);
|
|
256
|
+
process.exit(0);
|
|
257
|
+
}
|
|
258
|
+
const arg0 = args[0];
|
|
259
|
+
if (arg0 === "--list" || arg0 === "-l") {
|
|
260
|
+
printCatalog(true);
|
|
261
|
+
process.exit(0);
|
|
262
|
+
}
|
|
263
|
+
if (arg0 === "-h" || arg0 === "--help") {
|
|
264
|
+
printCatalog(false);
|
|
265
|
+
console.log(c(" Run 'arcis <command> --help' for full flags.", DIM));
|
|
266
|
+
console.log();
|
|
267
|
+
process.exit(0);
|
|
268
|
+
}
|
|
269
|
+
if (arg0 === "-V" || arg0 === "--version") {
|
|
270
|
+
console.log(getInstalledVersion());
|
|
271
|
+
process.exit(0);
|
|
272
|
+
}
|
|
273
|
+
if (arg0 === "update") {
|
|
274
|
+
await updateCommand(args.slice(1));
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (arg0 === "scan" || arg0 === "audit" || arg0 === "sca") {
|
|
278
|
+
if (!hasPythonArcis()) {
|
|
279
|
+
console.error(
|
|
280
|
+
c(
|
|
281
|
+
`arcis: '${arg0}' is implemented by the Python CLI. Install with:`,
|
|
282
|
+
YELLOW,
|
|
283
|
+
BOLD
|
|
284
|
+
)
|
|
285
|
+
);
|
|
286
|
+
console.error(" pip install arcis");
|
|
287
|
+
console.error();
|
|
288
|
+
console.error(c("Why: scan/audit/sca rely on Python's threat-DB and rule data.", DIM));
|
|
289
|
+
console.error(
|
|
290
|
+
c(
|
|
291
|
+
"@arcis/node implements the middleware + dashboard upload \u2014 see the docs.",
|
|
292
|
+
DIM
|
|
293
|
+
)
|
|
294
|
+
);
|
|
295
|
+
process.exit(127);
|
|
296
|
+
}
|
|
297
|
+
forwardToPython(args);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
console.error(`arcis: unknown command '${arg0}'`);
|
|
301
|
+
console.error("Run 'arcis --list' for available commands.");
|
|
302
|
+
process.exit(1);
|
|
303
|
+
}
|
|
304
|
+
main().catch((err) => {
|
|
305
|
+
console.error(c(`arcis: unexpected error: ${err}`, RED));
|
|
306
|
+
process.exit(1);
|
|
307
|
+
});
|
|
308
|
+
//# sourceMappingURL=arcis.mjs.map
|
|
309
|
+
//# sourceMappingURL=arcis.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/arcis.ts"],"names":["cur","lat"],"mappings":"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","file":"arcis.mjs","sourcesContent":["#!/usr/bin/env node\n/**\n * @arcis/node — `arcis` CLI dispatcher.\n *\n * Surface (mirrors the Python CLI's discovery layer):\n *\n * arcis → catalog\n * arcis --list → catalog with examples\n * arcis --help / -h → catalog + run-cmd hint\n * arcis --version / -V\n * arcis update [--apply] [--check]\n * arcis scan / audit / sca → forward to Python `arcis` if on PATH,\n * else print install hint\n *\n * Why we delegate scan/audit/sca to Python rather than re-implementing:\n * the threat database, audit rules, and attack-payload catalog are\n * Python-side data files. Maintaining two copies means drift; one\n * canonical CLI + a thin Node forwarder is simpler. The Node binary\n * exists primarily so users who installed `@arcis/node` from npm get\n * the same `arcis update` / discovery UX as Python users.\n */\n\nimport { spawnSync } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// ── ANSI helpers ─────────────────────────────────────────────────────\n\nconst USE_COLOR =\n !process.env.NO_COLOR && process.stdout.isTTY === true;\n\nfunction c(text: string, ...codes: string[]): string {\n if (!USE_COLOR) return text;\n return codes.join(\"\") + text + \"\\x1b[0m\";\n}\n\nconst BOLD = \"\\x1b[1m\";\nconst DIM = \"\\x1b[2m\";\nconst GREEN = \"\\x1b[32m\";\nconst YELLOW = \"\\x1b[33m\";\nconst CYAN = \"\\x1b[36m\";\nconst RED = \"\\x1b[31m\";\n\n// ── Version + npm registry helpers ───────────────────────────────────\n\nfunction getInstalledVersion(): string {\n // Read the package.json that ships with this build so we report the\n // actual installed version, not whatever was hardcoded.\n try {\n const here = fileURLToPath(import.meta.url);\n // Walk up to find the package root (contains package.json).\n let dir = dirname(here);\n for (let i = 0; i < 6; i++) {\n try {\n const raw = readFileSync(resolve(dir, \"package.json\"), \"utf-8\");\n const pkg = JSON.parse(raw) as { name?: string; version?: string };\n if (pkg.name === \"@arcis/node\" && pkg.version) {\n return pkg.version;\n }\n } catch {\n // climb\n }\n const parent = resolve(dir, \"..\");\n if (parent === dir) break;\n dir = parent;\n }\n } catch {\n // ignore\n }\n return \"?\";\n}\n\ninterface NpmRegistryResponse {\n \"dist-tags\"?: { latest?: string };\n}\n\nasync function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 5_000);\n try {\n const resp = await fetch(\"https://registry.npmjs.org/@arcis/node\", {\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n });\n if (!resp.ok) return null;\n const data = (await resp.json()) as NpmRegistryResponse;\n return data[\"dist-tags\"]?.latest ?? null;\n } finally {\n clearTimeout(timer);\n }\n } catch {\n return null;\n }\n}\n\nfunction parseVersion(v: string): number[] | null {\n const parts = v.split(\".\");\n const out: number[] = [];\n for (const p of parts) {\n if (!/^\\d+$/.test(p)) return null;\n out.push(Number(p));\n }\n return out;\n}\n\nfunction versionCompare(a: number[], b: number[]): number {\n const len = Math.max(a.length, b.length);\n for (let i = 0; i < len; i++) {\n const x = a[i] ?? 0;\n const y = b[i] ?? 0;\n if (x < y) return -1;\n if (x > y) return 1;\n }\n return 0;\n}\n\n// ── Python forwarder ─────────────────────────────────────────────────\n\nfunction hasPythonArcis(): boolean {\n // Check both `arcis` (Windows: arcis.exe) and `python -m arcis.cli` so\n // users who have the Python package installed but not on PATH still work.\n const probes: Array<{ cmd: string; args: string[] }> = [\n { cmd: \"arcis\", args: [\"--version\"] },\n { cmd: \"python\", args: [\"-m\", \"arcis.cli\", \"--version\"] },\n { cmd: \"python3\", args: [\"-m\", \"arcis.cli\", \"--version\"] },\n ];\n for (const p of probes) {\n try {\n const result = spawnSync(p.cmd, p.args, {\n stdio: [\"ignore\", \"ignore\", \"ignore\"],\n timeout: 3000,\n shell: process.platform === \"win32\",\n });\n if (result.status === 0) return true;\n } catch {\n // try next\n }\n }\n return false;\n}\n\nfunction forwardToPython(args: string[]): never {\n // Try `arcis` first, fall back to `python -m arcis.cli`. Mirror exit\n // code so CI scripts using the Node CLI get the same behavior they'd\n // get from the Python CLI.\n const candidates: Array<{ cmd: string; args: string[] }> = [\n { cmd: \"arcis\", args },\n { cmd: \"python\", args: [\"-m\", \"arcis.cli\", ...args] },\n { cmd: \"python3\", args: [\"-m\", \"arcis.cli\", ...args] },\n ];\n for (const cand of candidates) {\n const result = spawnSync(cand.cmd, cand.args, {\n stdio: \"inherit\",\n shell: process.platform === \"win32\",\n });\n if (result.error) continue;\n process.exit(result.status ?? 0);\n }\n console.error(\n c(\"arcis: could not invoke the Python CLI. Install with:\", RED, BOLD),\n );\n console.error(\" pip install arcis\");\n process.exit(127);\n}\n\n// ── Catalog ──────────────────────────────────────────────────────────\n\nfunction printCatalog(verbose: boolean): void {\n const ver = getInstalledVersion();\n console.log();\n console.log(` ${c(\"Arcis\", BOLD, CYAN)} ${c(`v${ver}`, DIM)} ${c(\"(node)\", DIM)}`);\n console.log(c(\" Zero-dep security middleware + scanners.\", DIM));\n console.log();\n console.log(c(\" Commands\", BOLD));\n const rows: Array<[string, string, string]> = [\n [\n \"scan\",\n \"Send live attack payloads to a running app.\",\n \"arcis scan http://localhost:8000 --route POST:/echo --field q\",\n ],\n [\n \"audit\",\n \"Static-analyse Python / JS / TS source for unsafe patterns.\",\n \"arcis audit .\",\n ],\n [\n \"sca\",\n \"Match installed dependencies against the supply-chain threat DB.\",\n \"arcis sca .\",\n ],\n [\"update\", \"Check npm for a newer @arcis/node release.\", \"arcis update --apply\"],\n ];\n for (const [name, desc, example] of rows) {\n console.log(` ${c(name.padEnd(8), BOLD, GREEN)} ${desc}`);\n if (verbose) {\n console.log(` ${c(example, DIM)}`);\n }\n }\n console.log();\n console.log(c(\" Discovery\", BOLD));\n console.log(` ${c(\"--list\", BOLD, CYAN).padEnd(24)} Show this catalog (verbose).`);\n console.log(\n ` ${c(\"<cmd> --help\", BOLD, CYAN).padEnd(24)} Show full flags for that command.`,\n );\n console.log();\n console.log(c(\" Note\", BOLD));\n console.log(\n ` scan/audit/sca delegate to the Python CLI (canonical impl).`,\n );\n console.log(` Install once with: ${c(\"pip install arcis\", GREEN)}`);\n console.log();\n}\n\n// ── Update command ───────────────────────────────────────────────────\n\nasync function updateCommand(args: string[]): Promise<void> {\n // Note: this function uses `process.exitCode = N; return;` rather than\n // `process.exit(N)` because the fetch() call leaves an internal undici\n // handle open momentarily on Windows, and process.exit() during that\n // window throws a libuv assertion on stderr. exitCode + return lets\n // Node drain handles cleanly before exit.\n const apply = args.includes(\"--apply\");\n const check = args.includes(\"--check\");\n const yes = args.includes(\"--yes\") || args.includes(\"-y\");\n\n const current = getInstalledVersion();\n const latest = await fetchLatestVersion();\n\n if (check) {\n if (latest === null) {\n console.error(\"arcis: could not reach npm to check for updates\");\n process.exitCode = 2;\n return;\n }\n const cur = parseVersion(current);\n const lat = parseVersion(latest);\n if (!cur || !lat || versionCompare(cur, lat) >= 0) {\n console.log(`@arcis/node ${current} is up-to-date`);\n process.exitCode = 0;\n return;\n }\n console.error(`@arcis/node ${current} is outdated; latest is ${latest}`);\n process.exitCode = 1;\n return;\n }\n\n console.log();\n console.log(c(\" @arcis/node update check\", BOLD, CYAN));\n console.log(c(\" Source: https://registry.npmjs.org/@arcis/node\", DIM));\n console.log();\n\n if (latest === null) {\n console.log(` Installed @arcis/node ${current}`);\n console.log(\n ` Latest ${c(\"? unreachable\", YELLOW)} ${c(\"(network error or npm down)\", DIM)}`,\n );\n console.log();\n console.log(c(\" Try again later, or run 'npm view @arcis/node version' directly.\", DIM));\n console.log();\n process.exitCode = 2;\n return;\n }\n\n const cur = parseVersion(current);\n const lat = parseVersion(latest);\n if (!cur || !lat) {\n console.log(\n ` Installed @arcis/node ${current} ${c(\"(pre-release or unparseable)\", DIM)}`,\n );\n console.log(` Latest @arcis/node ${latest}`);\n console.log();\n console.log(c(\" Skipping comparison — manually decide.\", DIM));\n console.log();\n process.exitCode = 0;\n return;\n }\n\n if (versionCompare(cur, lat) >= 0) {\n console.log(` Installed @arcis/node ${current}`);\n console.log(` Latest @arcis/node ${latest}`);\n console.log();\n console.log(c(\" You are on the latest version.\", BOLD, GREEN));\n console.log();\n process.exitCode = 0;\n return;\n }\n\n console.log(` Installed @arcis/node ${current}`);\n console.log(\n ` Latest ${c(`@arcis/node ${latest}`, BOLD)} ${c(\"(update available)\", YELLOW)}`,\n );\n console.log();\n console.log(c(\" Run to upgrade\", BOLD));\n console.log(` ${c(\"npm install @arcis/node@latest\", GREEN)}`);\n console.log();\n\n if (!apply) {\n console.log(c(\" Or rerun: 'arcis update --apply' to upgrade in place.\", DIM));\n console.log();\n process.exitCode = 1;\n return;\n }\n\n if (!yes && process.stdin.isTTY) {\n process.stdout.write(\"Upgrade now? [y/N] \");\n const response = await new Promise<string>((res) => {\n process.stdin.once(\"data\", (chunk: Buffer) => res(chunk.toString().trim().toLowerCase()));\n });\n if (!response.startsWith(\"y\")) {\n process.exitCode = 1;\n return;\n }\n }\n\n const npmCmd = process.platform === \"win32\" ? \"npm.cmd\" : \"npm\";\n console.log(` $ ${npmCmd} install @arcis/node@latest`);\n const result = spawnSync(npmCmd, [\"install\", \"@arcis/node@latest\"], {\n stdio: \"inherit\",\n });\n process.exitCode = result.status ?? 1;\n}\n\n// ── Main ─────────────────────────────────────────────────────────────\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n\n if (args.length === 0) {\n printCatalog(false);\n process.exit(0);\n }\n\n const arg0 = args[0];\n\n if (arg0 === \"--list\" || arg0 === \"-l\") {\n printCatalog(true);\n process.exit(0);\n }\n\n if (arg0 === \"-h\" || arg0 === \"--help\") {\n printCatalog(false);\n console.log(c(\" Run 'arcis <command> --help' for full flags.\", DIM));\n console.log();\n process.exit(0);\n }\n\n if (arg0 === \"-V\" || arg0 === \"--version\") {\n console.log(getInstalledVersion());\n process.exit(0);\n }\n\n if (arg0 === \"update\") {\n await updateCommand(args.slice(1));\n return;\n }\n\n if (arg0 === \"scan\" || arg0 === \"audit\" || arg0 === \"sca\") {\n if (!hasPythonArcis()) {\n console.error(\n c(\n `arcis: '${arg0}' is implemented by the Python CLI. Install with:`,\n YELLOW,\n BOLD,\n ),\n );\n console.error(\" pip install arcis\");\n console.error();\n console.error(c(\"Why: scan/audit/sca rely on Python's threat-DB and rule data.\", DIM));\n console.error(\n c(\n \"@arcis/node implements the middleware + dashboard upload — see the docs.\",\n DIM,\n ),\n );\n process.exit(127);\n }\n forwardToPython(args);\n return;\n }\n\n console.error(`arcis: unknown command '${arg0}'`);\n console.error(\"Run 'arcis --list' for available commands.\");\n process.exit(1);\n}\n\nmain().catch((err) => {\n console.error(c(`arcis: unexpected error: ${err}`, RED));\n process.exit(1);\n});\n"]}
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export declare const HEADERS: {
|
|
|
42
42
|
* Detection patterns — used to flag whether a string contains XSS payloads.
|
|
43
43
|
* Must stay in sync with XSS_REMOVE_PATTERNS below.
|
|
44
44
|
*/
|
|
45
|
-
export declare const XSS_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp];
|
|
45
|
+
export declare const XSS_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp];
|
|
46
46
|
/**
|
|
47
47
|
* Removal patterns — used by sanitizeXss() to strip dangerous content.
|
|
48
48
|
* More targeted than XSS_PATTERNS: each pattern captures the full dangerous
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,eAAO,MAAM,KAAK;IAChB,uCAAuC;;IAEvC,iDAAiD;;CAEzC,CAAC;AAKX,eAAO,MAAM,UAAU;IACrB,qCAAqC;;IAErC,sCAAsC;;IAEtC,0DAA0D;;IAE1D,4BAA4B;;IAE5B,qCAAqC;;IAErC,qCAAqC;;CAE7B,CAAC;AAKX,eAAO,MAAM,OAAO;IAClB,sCAAsC;;IAUtC,+CAA+C;;IAE/C,oCAAoC;;IAEpC,2CAA2C;;IAE3C,oCAAoC;;IAEpC,uCAAuC;;IAEvC,+CAA+C;;CAEvC,CAAC;AAMX;;;GAGG;AACH,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,eAAO,MAAM,KAAK;IAChB,uCAAuC;;IAEvC,iDAAiD;;CAEzC,CAAC;AAKX,eAAO,MAAM,UAAU;IACrB,qCAAqC;;IAErC,sCAAsC;;IAEtC,0DAA0D;;IAE1D,4BAA4B;;IAE5B,qCAAqC;;IAErC,qCAAqC;;CAE7B,CAAC;AAKX,eAAO,MAAM,OAAO;IAClB,sCAAsC;;IAUtC,+CAA+C;;IAE/C,oCAAoC;;IAEpC,2CAA2C;;IAE3C,oCAAoC;;IAEpC,uCAAuC;;IAEvC,+CAA+C;;CAEvC,CAAC;AAMX;;;GAGG;AACH,eAAO,MAAM,YAAY,mIAgCf,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,2KAqCtB,CAAC;AAKX,eAAO,MAAM,YAAY,mHAyBf,CAAC;AAKX,eAAO,MAAM,aAAa,mGAsBhB,CAAC;AAKX,eAAO,MAAM,gBAAgB,mCAenB,CAAC;AAMX;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,aAQ/B,CAAC;AAEH,iCAAiC;AACjC,eAAO,MAAM,oBAAoB,aAc/B,CAAC;AAKH,eAAO,MAAM,SAAS;IACpB,2CAA2C;;IAE3C,2BAA2B;;IAE3B,0BAA0B;;IAE1B,iCAAiC;;IAEjC,uCAAuC;;CAS/B,CAAC;AAKX,eAAO,MAAM,UAAU;IACrB;;;;OAIG;;IAEH;;;;OAIG;;IAEH,8BAA8B;;CAEtB,CAAC;AAKX,eAAO,MAAM,MAAM;IACjB,yCAAyC;;IAEzC,4BAA4B;wCACD,MAAM;IACjC,gCAAgC;;mCAEZ,MAAM;uCACF,MAAM,QAAQ,MAAM;qCACtB,MAAM,OAAO,MAAM;qCACnB,MAAM,OAAO,MAAM;oCACpB,MAAM,OAAO,MAAM;oCACnB,MAAM,OAAO,MAAM;yCACd,MAAM;wCACP,MAAM;sCACR,MAAM;uCACL,MAAM;uCACN,MAAM,UAAU,OAAO,EAAE;oCAC5B,MAAM,OAAO,MAAM;oCACnB,MAAM,OAAO,MAAM;;CAEhC,CAAC;AAKX,eAAO,MAAM,OAAO,EAAG,WAAoB,CAAC"}
|
package/dist/core/index.js
CHANGED
|
@@ -73,7 +73,10 @@ var XSS_PATTERNS = [
|
|
|
73
73
|
/** base href hijacking — redirects all relative URLs to attacker domain */
|
|
74
74
|
/<base[\s>]/gi,
|
|
75
75
|
/** link tag injection — stylesheet or preload CSRF attacks */
|
|
76
|
-
/<link[\s>]/gi
|
|
76
|
+
/<link[\s>]/gi,
|
|
77
|
+
/** style tag — CSS expression() / behavior: / IE-era attacks. Mirrors
|
|
78
|
+
* Python's xss-style-tag from packages/core/patterns.json. */
|
|
79
|
+
/<style[\s>]/gi
|
|
77
80
|
];
|
|
78
81
|
var SQL_PATTERNS = [
|
|
79
82
|
/** SQL keywords */
|
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/constants.ts","../../src/core/errors.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module @arcis/node/core/constants\n * Named constants for Arcis - no magic numbers\n */\n\n// =============================================================================\n// INPUT LIMITS\n// =============================================================================\nexport const INPUT = {\n /** Default maximum input size (1MB) */\n DEFAULT_MAX_SIZE: 1_000_000,\n /** Maximum recursion depth for nested objects */\n MAX_RECURSION_DEPTH: 10,\n} as const;\n\n// =============================================================================\n// RATE LIMITING\n// =============================================================================\nexport const RATE_LIMIT = {\n /** Default window size (1 minute) */\n DEFAULT_WINDOW_MS: 60_000,\n /** Default max requests per window */\n DEFAULT_MAX_REQUESTS: 100,\n /** Default HTTP status code for rate limited responses */\n DEFAULT_STATUS_CODE: 429,\n /** Default error message */\n DEFAULT_MESSAGE: 'Too many requests, please try again later.',\n /** Minimum window size (1 second) */\n MIN_WINDOW_MS: 1_000,\n /** Maximum window size (24 hours) */\n MAX_WINDOW_MS: 86_400_000,\n} as const;\n\n// =============================================================================\n// SECURITY HEADERS\n// =============================================================================\nexport const HEADERS = {\n /** Default Content Security Policy */\n DEFAULT_CSP: [\n \"default-src 'self'\",\n \"script-src 'self'\",\n \"style-src 'self' 'unsafe-inline'\",\n \"img-src 'self' data: https:\",\n \"font-src 'self'\",\n \"object-src 'none'\",\n \"frame-ancestors 'none'\",\n ].join('; '),\n /** Default HSTS max age (1 year in seconds) */\n HSTS_MAX_AGE: 31_536_000,\n /** Default X-Frame-Options value */\n FRAME_OPTIONS: 'DENY' as const,\n /** Default X-Content-Type-Options value */\n CONTENT_TYPE_OPTIONS: 'nosniff',\n /** Default Referrer-Policy value */\n REFERRER_POLICY: 'strict-origin-when-cross-origin',\n /** Default Permissions-Policy value */\n PERMISSIONS_POLICY: 'geolocation=(), microphone=(), camera=()',\n /** Default Cache-Control value for security */\n CACHE_CONTROL: 'no-store, no-cache, must-revalidate, proxy-revalidate',\n} as const;\n\n// =============================================================================\n// XSS PATTERNS (ReDoS-safe)\n// =============================================================================\n\n/**\n * Detection patterns — used to flag whether a string contains XSS payloads.\n * Must stay in sync with XSS_REMOVE_PATTERNS below.\n */\nexport const XSS_PATTERNS = [\n /** Script tags (ReDoS-safe version) */\n /<script[^>]*>[\\s\\S]*?<\\/script>/gi,\n /** javascript: protocol (allow optional spaces before colon) */\n /javascript\\s*:/gi,\n /** vbscript: protocol */\n /vbscript\\s*:/gi,\n /** Event handlers (onclick, onerror, etc.) — any separator before attribute */\n /(?:[\\s/])on\\w+\\s*=/gi,\n /** iframe tags */\n /<iframe/gi,\n /** object tags */\n /<object/gi,\n /** embed tags */\n /<embed/gi,\n /** data: URIs (only dangerous ones, avoid false positives) */\n /(?:^|[\\s\"'=])data:/gi,\n /** URL-encoded script tags */\n /%3Cscript/gi,\n /** SVG with onload */\n /<svg[^>]*onload/gi,\n /** form tags — phishing/credential harvesting via action= redirection */\n /<form[\\s>]/gi,\n /** meta tags — http-equiv refresh redirects or CSP bypass */\n /<meta[\\s>]/gi,\n /** base href hijacking — redirects all relative URLs to attacker domain */\n /<base[\\s>]/gi,\n /** link tag injection — stylesheet or preload CSRF attacks */\n /<link[\\s>]/gi,\n] as const;\n\n/**\n * Removal patterns — used by sanitizeXss() to strip dangerous content.\n * More targeted than XSS_PATTERNS: each pattern captures the full dangerous\n * substring (tag, attribute + value, protocol) so it can be replaced safely.\n * Must stay in sync with XSS_PATTERNS above.\n */\nexport const XSS_REMOVE_PATTERNS = [\n /** Full script blocks (content + tags) */\n /<script[^>]*>[\\s\\S]*?<\\/script>/gi,\n /** Standalone/unclosed script tags */\n /<script[^>]*>/gi,\n /** style — CSS expression() and behavior: attacks (IE-era but still relevant) */\n /<style[^>]*>[\\s\\S]*?<\\/style>/gi,\n /<style[^>]*/gi,\n /** iframe — full block and partial/unclosed */\n /<iframe[^>]*>[\\s\\S]*?<\\/iframe>/gi,\n /<iframe[^>]*/gi,\n /** object — full block and partial/unclosed */\n /<object[^>]*>[\\s\\S]*?<\\/object>/gi,\n /<object[^>]*/gi,\n /** embed tags */\n /<embed[^>]*/gi,\n /** SVG with inline event handlers */\n /<svg[^>]*onload[^>]*>/gi,\n /** URL-encoded script tags */\n /%3Cscript/gi,\n /** Event handlers with quoted values: onclick=\"...\", onerror='...' */\n /(?:[\\s/])on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi,\n /** Event handlers with unquoted values: onload=value */\n /(?:[\\s/])on\\w+\\s*=\\s*[^\\s>]*/gi,\n /** javascript: and vbscript: protocols (allow optional spaces before colon) */\n /javascript\\s*:/gi,\n /vbscript\\s*:/gi,\n /** data: URIs with HTML/script content */\n /data\\s*:\\s*text\\/html[^>\\s]*/gi,\n /** form tag injection — phishing via action= redirection */\n /<form[\\s>][^>]*/gi,\n /** meta tag injection — http-equiv refresh or CSP bypass */\n /<meta[\\s>][^>]*/gi,\n /** base href hijacking */\n /<base[\\s>][^>]*/gi,\n /** link tag injection — stylesheet or preload attacks */\n /<link[\\s>][^>]*/gi,\n] as const;\n\n// =============================================================================\n// SQL INJECTION PATTERNS\n// =============================================================================\nexport const SQL_PATTERNS = [\n /** SQL keywords */\n /(\\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)\\b)/gi,\n /** SQL comments: ANSI (--), C-style (slash-star ... star-slash), MySQL (#) */\n /(--|\\/\\*|\\*\\/|#)/g,\n /** SQL statement separators */\n /(;|\\|\\||&&)/g,\n /** Boolean injection: OR 1=1 */\n /\\bOR\\s+\\d+\\s*=\\s*\\d+/gi,\n /** Boolean injection: OR 'a'='a' or OR \"a\"=\"a\" (including mixed quotes) */\n /\\bOR\\s+(['\"])[^'\"]*\\1\\s*=\\s*(['\"])[^'\"]*\\2/gi,\n /\\bOR\\s+('[^']*'|\"[^\"]*\")\\s*=\\s*('[^']*'|\"[^\"]*\")/gi,\n /** Boolean injection: AND 1=1 */\n /\\bAND\\s+\\d+\\s*=\\s*\\d+/gi,\n /** Boolean injection: AND 'a'='a' or AND \"a\"=\"a\" (including mixed quotes) */\n /\\bAND\\s+(['\"])[^'\"]*\\1\\s*=\\s*(['\"])[^'\"]*\\2/gi,\n /\\bAND\\s+('[^']*'|\"[^\"]*\")\\s*=\\s*('[^']*'|\"[^\"]*\")/gi,\n /** Time-based blind: SLEEP() */\n /\\bSLEEP\\s*\\(\\s*\\d+\\s*\\)/gi,\n /** Time-based blind: BENCHMARK() */\n /\\bBENCHMARK\\s*\\(/gi,\n /** Time-based blind: PostgreSQL pg_sleep() */\n /\\bpg_sleep\\s*\\(/gi,\n /** Time-based blind: MSSQL WAITFOR DELAY */\n /\\bWAITFOR\\s+DELAY\\b/gi,\n] as const;\n\n// =============================================================================\n// PATH TRAVERSAL PATTERNS\n// =============================================================================\nexport const PATH_PATTERNS = [\n /** Unix path traversal */\n /\\.\\.\\//g,\n /** Windows path traversal */\n /\\.\\.\\\\/g,\n /** URL-encoded traversal (%2e%2e) */\n /%2e%2e/gi,\n /** Double URL-encoded traversal (%252e) */\n /%252e/gi,\n /** Mixed encoding: ..%2F */\n /\\.\\.%2F/gi,\n /** Mixed encoding: %2e./ and .%2e/ */\n /%2e\\.[\\\\/]/gi,\n /\\.%2e[\\\\/]/gi,\n /** Fully URL-encoded: %2e%2e%2f */\n /%2e%2e%2f/gi,\n /** Double URL-encoded forward slash: %252f */\n /%252f/gi,\n /** Dotdotslash bypass: ....// or ....\\\\ */\n /\\.{2,}[/\\\\]{2,}/g,\n /** Null byte injection in paths */\n /\\0/g,\n] as const;\n\n// =============================================================================\n// COMMAND INJECTION PATTERNS\n// =============================================================================\nexport const COMMAND_PATTERNS = [\n /**\n * Shell metacharacters that enable command chaining/substitution.\n * Bare ( and ) are excluded — they appear in common legitimate values\n * (function calls in code fields, math expressions, etc.).\n * Command substitution is caught by the $( combined pattern below.\n * NOTE: ';', '&', '|' may appear in legitimate URL query strings\n * and Markdown; consider disabling command checking (command: false)\n * for fields that intentionally allow those characters.\n */\n /[;&|`]/g,\n /** Command substitution: $( ... ) — matched as a pair to reduce false positives */\n /\\$\\(/g,\n /** URL-encoded control characters (%00-%0F): null, tab, vtab, formfeed, LF, CR */\n /%0[0-9a-f]/gi,\n] as const;\n\n// =============================================================================\n// DANGEROUS KEYS\n// =============================================================================\n\n/**\n * Prototype pollution keys to block.\n * Stored lowercase — always compare with key.toLowerCase().\n *\n * Includes:\n * - __proto__: direct prototype assignment\n * - constructor: access to constructor.prototype chain\n * - prototype: direct prototype property\n * - __defineGetter__/__defineSetter__: legacy property definition (can override getters/setters)\n * - __lookupGetter__/__lookupSetter__: legacy property introspection\n */\nexport const DANGEROUS_PROTO_KEYS = new Set([\n '__proto__',\n 'constructor',\n 'prototype',\n '__definegetter__',\n '__definesetter__',\n '__lookupgetter__',\n '__lookupsetter__',\n]);\n\n/** MongoDB operators to block */\nexport const NOSQL_DANGEROUS_KEYS = new Set([\n // Comparison\n '$gt', '$gte', '$lt', '$lte', '$ne', '$eq', '$in', '$nin',\n // Logical\n '$and', '$or', '$not', '$nor',\n // Element / evaluation\n '$exists', '$type', '$regex', '$where', '$expr', '$mod', '$text', '$jsonSchema',\n // Array\n '$elemMatch', '$all', '$size',\n // JavaScript execution (critical)\n '$function', '$accumulator',\n // Aggregation pipeline operators (injectable via $lookup etc.)\n '$lookup', '$match', '$project', '$group', '$sort', '$limit', '$skip',\n '$unwind', '$addFields', '$replaceRoot',\n]);\n\n// =============================================================================\n// REDACTION\n// =============================================================================\nexport const REDACTION = {\n /** Replacement text for redacted values */\n REPLACEMENT: '[REDACTED]',\n /** Truncation indicator */\n TRUNCATED: '[TRUNCATED]',\n /** Max depth indicator */\n MAX_DEPTH: '[MAX_DEPTH]',\n /** Default max message length */\n DEFAULT_MAX_LENGTH: 10_000,\n /** Default sensitive keys to redact */\n SENSITIVE_KEYS: new Set([\n 'password', 'passwd', 'pwd', 'secret', 'token', 'apikey',\n 'api_key', 'apiKey', 'auth', 'authorization', 'credit_card',\n 'creditcard', 'cc', 'ssn', 'social_security', 'private_key',\n 'privateKey', 'access_token', 'accessToken', 'refresh_token',\n 'refreshToken', 'bearer', 'jwt', 'session', 'cookie',\n 'credentials', 'x-api-key', 'x-auth-token',\n ]),\n} as const;\n\n// =============================================================================\n// VALIDATION PATTERNS\n// =============================================================================\nexport const VALIDATION = {\n /**\n * Email regex pattern.\n * Rejects consecutive dots in local part (e.g. test..foo@example.com),\n * leading/trailing dots, and other common invalid forms.\n */\n EMAIL: /^[^\\s@.][^\\s@]*(?:\\.[^\\s@.][^\\s@]*)*@[^\\s@]+\\.[^\\s@]+$/,\n /**\n * URL regex pattern.\n * Only allows http:// and https:// — explicitly rejects javascript:,\n * data:, vbscript:, and other dangerous URI schemes.\n */\n URL: /^https?:\\/\\/[^\\s/$.?#][^\\s]*$/,\n /** UUID regex pattern (v4) */\n UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n} as const;\n\n// =============================================================================\n// ERROR MESSAGES\n// =============================================================================\nexport const ERRORS = {\n /** Generic error message (production) */\n INTERNAL_SERVER_ERROR: 'Internal Server Error',\n /** Input too large error */\n INPUT_TOO_LARGE: (maxSize: number) => `Input exceeds maximum size of ${maxSize} bytes`,\n /** Validation error messages */\n VALIDATION: {\n REQUIRED: (field: string) => `${field} is required`,\n INVALID_TYPE: (field: string, type: string) => `${field} must be a ${type}`,\n MIN_LENGTH: (field: string, min: number) => `${field} must be at least ${min} characters`,\n MAX_LENGTH: (field: string, max: number) => `${field} must be at most ${max} characters`,\n MIN_VALUE: (field: string, min: number) => `${field} must be at least ${min}`,\n MAX_VALUE: (field: string, max: number) => `${field} must be at most ${max}`,\n INVALID_FORMAT: (field: string) => `${field} format is invalid`,\n INVALID_EMAIL: (field: string) => `${field} must be a valid email`,\n INVALID_URL: (field: string) => `${field} must be a valid URL`,\n INVALID_UUID: (field: string) => `${field} must be a valid UUID`,\n INVALID_ENUM: (field: string, values: unknown[]) => `${field} must be one of: ${values.join(', ')}`,\n MIN_ITEMS: (field: string, min: number) => `${field} must have at least ${min} items`,\n MAX_ITEMS: (field: string, max: number) => `${field} must have at most ${max} items`,\n },\n} as const;\n\n// =============================================================================\n// BLOCKED TEXT (for sanitizer replacements)\n// =============================================================================\nexport const BLOCKED = '[BLOCKED]' as const;\n","/**\n * @module @arcis/node/core/errors\n * Custom error classes for Arcis\n */\n\n/**\n * Base class for all Arcis errors\n */\nexport class ArcisError extends Error {\n public readonly statusCode: number;\n public readonly code: string;\n /** Whether the error message is safe to expose to API clients. */\n public readonly expose: boolean;\n\n constructor(message: string, statusCode = 500, code = 'ARCIS_ERROR') {\n super(message);\n this.name = 'ArcisError';\n this.statusCode = statusCode;\n this.code = code;\n // Client errors (4xx) have controlled messages — safe to expose.\n // Server errors (5xx) may contain internal details — hide by default.\n this.expose = statusCode < 500;\n\n // Maintains proper stack trace for where error was thrown (V8 engines)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error thrown when input validation fails\n */\nexport class ValidationError extends ArcisError {\n public readonly errors: string[];\n\n constructor(errors: string[]) {\n super('Validation failed', 400, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n this.errors = errors;\n }\n}\n\n/** Alias for ValidationError (backwards compatibility) */\nexport { ValidationError as ArcisValidationError };\n\n/**\n * Error thrown when rate limit is exceeded\n */\nexport class RateLimitError extends ArcisError {\n public readonly retryAfter: number;\n\n constructor(message: string, retryAfter: number) {\n super(message, 429, 'RATE_LIMIT_EXCEEDED');\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\n/**\n * Error thrown when input is too large\n */\nexport class InputTooLargeError extends ArcisError {\n public readonly maxSize: number;\n public readonly actualSize: number;\n\n constructor(maxSize: number, actualSize: number) {\n super(`Input exceeds maximum size of ${maxSize} bytes`, 413, 'INPUT_TOO_LARGE');\n this.name = 'InputTooLargeError';\n this.maxSize = maxSize;\n this.actualSize = actualSize;\n }\n}\n\n/**\n * Error thrown when security threat is detected\n */\nexport class SecurityThreatError extends ArcisError {\n public readonly threatType: string;\n public readonly pattern: string;\n\n constructor(threatType: string, pattern: string) {\n super('Request blocked for security reasons', 400, 'SECURITY_THREAT');\n this.name = 'SecurityThreatError';\n this.threatType = threatType;\n this.pattern = pattern;\n }\n}\n\n/**\n * Error thrown when sanitization fails\n */\nexport class SanitizationError extends ArcisError {\n constructor(message: string) {\n super(message, 400, 'SANITIZATION_ERROR');\n this.name = 'SanitizationError';\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/constants.ts","../../src/core/errors.ts"],"names":[],"mappings":";;;AAQO,IAAM,KAAA,GAAQ;AAAA;AAAA,EAEnB,gBAAA,EAAkB,GAAA;AAAA;AAAA,EAElB,mBAAA,EAAqB;AACvB;AAKO,IAAM,UAAA,GAAa;AAAA;AAAA,EAExB,iBAAA,EAAmB,GAAA;AAAA;AAAA,EAEnB,oBAAA,EAAsB,GAAA;AAAA;AAAA,EAEtB,mBAAA,EAAqB,GAAA;AAAA;AAAA,EAErB,eAAA,EAAiB,4CAAA;AAAA;AAAA,EAEjB,aAAA,EAAe,GAAA;AAAA;AAAA,EAEf,aAAA,EAAe;AACjB;AAKO,IAAM,OAAA,GAAU;AAAA;AAAA,EAErB,WAAA,EAAa;AAAA,IACX,oBAAA;AAAA,IACA,mBAAA;AAAA,IACA,kCAAA;AAAA,IACA,6BAAA;AAAA,IACA,iBAAA;AAAA,IACA,mBAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,IAAI,CAAA;AAAA;AAAA,EAEX,YAAA,EAAc,OAAA;AAAA;AAAA,EAEd,aAAA,EAAe,MAAA;AAAA;AAAA,EAEf,oBAAA,EAAsB,SAAA;AAAA;AAAA,EAEtB,eAAA,EAAiB,iCAAA;AAAA;AAAA,EAEjB,kBAAA,EAAoB,0CAAA;AAAA;AAAA,EAEpB,aAAA,EAAe;AACjB;AAUO,IAAM,YAAA,GAAe;AAAA;AAAA,EAE1B,mCAAA;AAAA;AAAA,EAEA,kBAAA;AAAA;AAAA,EAEA,gBAAA;AAAA;AAAA,EAEA,sBAAA;AAAA;AAAA,EAEA,WAAA;AAAA;AAAA,EAEA,WAAA;AAAA;AAAA,EAEA,UAAA;AAAA;AAAA,EAEA,sBAAA;AAAA;AAAA,EAEA,aAAA;AAAA;AAAA,EAEA,mBAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA;AAAA,EAGA;AACF;AAkDO,IAAM,YAAA,GAAe;AAAA;AAAA,EAE1B,qFAAA;AAAA;AAAA,EAEA,mBAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA,EAEA,wBAAA;AAAA;AAAA,EAEA,8CAAA;AAAA,EACA,oDAAA;AAAA;AAAA,EAEA,yBAAA;AAAA;AAAA,EAEA,+CAAA;AAAA,EACA,qDAAA;AAAA;AAAA,EAEA,2BAAA;AAAA;AAAA,EAEA,oBAAA;AAAA;AAAA,EAEA,mBAAA;AAAA;AAAA,EAEA;AACF;AAKO,IAAM,aAAA,GAAgB;AAAA;AAAA,EAE3B,SAAA;AAAA;AAAA,EAEA,SAAA;AAAA;AAAA,EAEA,UAAA;AAAA;AAAA,EAEA,SAAA;AAAA;AAAA,EAEA,WAAA;AAAA;AAAA,EAEA,cAAA;AAAA,EACA,cAAA;AAAA;AAAA,EAEA,aAAA;AAAA;AAAA,EAEA,SAAA;AAAA;AAAA,EAEA,kBAAA;AAAA;AAAA,EAEA;AACF;AAKO,IAAM,gBAAA,GAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU9B,SAAA;AAAA;AAAA,EAEA,OAAA;AAAA;AAAA,EAEA;AACF;AAiBO,IAAM,oBAAA,uBAA2B,GAAA,CAAI;AAAA,EAC1C,WAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACF,CAAC;AAGM,IAAM,oBAAA,uBAA2B,GAAA,CAAI;AAAA;AAAA,EAE1C,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,MAAA;AAAA;AAAA,EAEnD,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,MAAA;AAAA;AAAA,EAEvB,SAAA;AAAA,EAAW,OAAA;AAAA,EAAS,QAAA;AAAA,EAAU,QAAA;AAAA,EAAU,OAAA;AAAA,EAAS,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,aAAA;AAAA;AAAA,EAElE,YAAA;AAAA,EAAc,MAAA;AAAA,EAAQ,OAAA;AAAA;AAAA,EAEtB,WAAA;AAAA,EAAa,cAAA;AAAA;AAAA,EAEb,SAAA;AAAA,EAAW,QAAA;AAAA,EAAU,UAAA;AAAA,EAAY,QAAA;AAAA,EAAU,OAAA;AAAA,EAAS,QAAA;AAAA,EAAU,OAAA;AAAA,EAC9D,SAAA;AAAA,EAAW,YAAA;AAAA,EAAc;AAC3B,CAAC;AAKM,IAAM,SAAA,GAAY;AAAA;AAAA,EAEvB,WAAA,EAAa,YAAA;AAAA;AAAA,EAEb,SAAA,EAAW,aAAA;AAAA;AAAA,EAEX,SAAA,EAAW,aAAA;AAAA;AAAA,EAEX,kBAAA,EAAoB,GAAA;AAAA;AAAA,EAEpB,cAAA,sBAAoB,GAAA,CAAI;AAAA,IACtB,UAAA;AAAA,IAAY,QAAA;AAAA,IAAU,KAAA;AAAA,IAAO,QAAA;AAAA,IAAU,OAAA;AAAA,IAAS,QAAA;AAAA,IAChD,SAAA;AAAA,IAAW,QAAA;AAAA,IAAU,MAAA;AAAA,IAAQ,eAAA;AAAA,IAAiB,aAAA;AAAA,IAC9C,YAAA;AAAA,IAAc,IAAA;AAAA,IAAM,KAAA;AAAA,IAAO,iBAAA;AAAA,IAAmB,aAAA;AAAA,IAC9C,YAAA;AAAA,IAAc,cAAA;AAAA,IAAgB,aAAA;AAAA,IAAe,eAAA;AAAA,IAC7C,cAAA;AAAA,IAAgB,QAAA;AAAA,IAAU,KAAA;AAAA,IAAO,SAAA;AAAA,IAAW,QAAA;AAAA,IAC5C,aAAA;AAAA,IAAe,WAAA;AAAA,IAAa;AAAA,GAC7B;AACH;AAKO,IAAM,UAAA,GAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMxB,KAAA,EAAO,wDAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMP,GAAA,EAAK,+BAAA;AAAA;AAAA,EAEL,IAAA,EAAM;AACR;AAKO,IAAM,MAAA,GAAS;AAAA;AAAA,EAEpB,qBAAA,EAAuB,uBAAA;AAAA;AAAA,EAEvB,eAAA,EAAiB,CAAC,OAAA,KAAoB,CAAA,8BAAA,EAAiC,OAAO,CAAA,MAAA,CAAA;AAAA;AAAA,EAE9E,UAAA,EAAY;AAAA,IACV,QAAA,EAAU,CAAC,KAAA,KAAkB,CAAA,EAAG,KAAK,CAAA,YAAA,CAAA;AAAA,IACrC,cAAc,CAAC,KAAA,EAAe,SAAiB,CAAA,EAAG,KAAK,cAAc,IAAI,CAAA,CAAA;AAAA,IACzE,YAAY,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,qBAAqB,GAAG,CAAA,WAAA,CAAA;AAAA,IAC5E,YAAY,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,oBAAoB,GAAG,CAAA,WAAA,CAAA;AAAA,IAC3E,WAAW,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,qBAAqB,GAAG,CAAA,CAAA;AAAA,IAC3E,WAAW,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,oBAAoB,GAAG,CAAA,CAAA;AAAA,IAC1E,cAAA,EAAgB,CAAC,KAAA,KAAkB,CAAA,EAAG,KAAK,CAAA,kBAAA,CAAA;AAAA,IAC3C,aAAA,EAAe,CAAC,KAAA,KAAkB,CAAA,EAAG,KAAK,CAAA,sBAAA,CAAA;AAAA,IAC1C,WAAA,EAAa,CAAC,KAAA,KAAkB,CAAA,EAAG,KAAK,CAAA,oBAAA,CAAA;AAAA,IACxC,YAAA,EAAc,CAAC,KAAA,KAAkB,CAAA,EAAG,KAAK,CAAA,qBAAA,CAAA;AAAA,IACzC,YAAA,EAAc,CAAC,KAAA,EAAe,MAAA,KAAsB,CAAA,EAAG,KAAK,CAAA,iBAAA,EAAoB,MAAA,CAAO,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,IACjG,WAAW,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,uBAAuB,GAAG,CAAA,MAAA,CAAA;AAAA,IAC7E,WAAW,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,sBAAsB,GAAG,CAAA,MAAA;AAAA;AAEhF;AAKO,IAAM,OAAA,GAAU;;;AC3UhB,IAAM,UAAA,GAAN,cAAyB,KAAA,CAAM;AAAA,EAMpC,WAAA,CAAY,OAAA,EAAiB,UAAA,GAAa,GAAA,EAAK,OAAO,aAAA,EAAe;AACnE,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,YAAA;AACZ,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAClB,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAGZ,IAAA,IAAA,CAAK,SAAS,UAAA,GAAa,GAAA;AAG3B,IAAA,IAAI,MAAM,iBAAA,EAAmB;AAC3B,MAAA,KAAA,CAAM,iBAAA,CAAkB,IAAA,EAAM,IAAA,CAAK,WAAW,CAAA;AAAA,IAChD;AAAA,EACF;AACF;AAKO,IAAM,eAAA,GAAN,cAA8B,UAAA,CAAW;AAAA,EAG9C,YAAY,MAAA,EAAkB;AAC5B,IAAA,KAAA,CAAM,mBAAA,EAAqB,KAAK,kBAAkB,CAAA;AAClD,IAAA,IAAA,CAAK,IAAA,GAAO,iBAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AACF;AAQO,IAAM,cAAA,GAAN,cAA6B,UAAA,CAAW;AAAA,EAG7C,WAAA,CAAY,SAAiB,UAAA,EAAoB;AAC/C,IAAA,KAAA,CAAM,OAAA,EAAS,KAAK,qBAAqB,CAAA;AACzC,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AACZ,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAAA,EACpB;AACF;AAKO,IAAM,kBAAA,GAAN,cAAiC,UAAA,CAAW;AAAA,EAIjD,WAAA,CAAY,SAAiB,UAAA,EAAoB;AAC/C,IAAA,KAAA,CAAM,CAAA,8BAAA,EAAiC,OAAO,CAAA,MAAA,CAAA,EAAU,GAAA,EAAK,iBAAiB,CAAA;AAC9E,IAAA,IAAA,CAAK,IAAA,GAAO,oBAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAAA,EACpB;AACF;AAKO,IAAM,mBAAA,GAAN,cAAkC,UAAA,CAAW;AAAA,EAIlD,WAAA,CAAY,YAAoB,OAAA,EAAiB;AAC/C,IAAA,KAAA,CAAM,sCAAA,EAAwC,KAAK,iBAAiB,CAAA;AACpE,IAAA,IAAA,CAAK,IAAA,GAAO,qBAAA;AACZ,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAClB,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AACF;AAKO,IAAM,iBAAA,GAAN,cAAgC,UAAA,CAAW;AAAA,EAChD,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAA,EAAS,KAAK,oBAAoB,CAAA;AACxC,IAAA,IAAA,CAAK,IAAA,GAAO,mBAAA;AAAA,EACd;AACF","file":"index.js","sourcesContent":["/**\n * @module @arcis/node/core/constants\n * Named constants for Arcis - no magic numbers\n */\n\n// =============================================================================\n// INPUT LIMITS\n// =============================================================================\nexport const INPUT = {\n /** Default maximum input size (1MB) */\n DEFAULT_MAX_SIZE: 1_000_000,\n /** Maximum recursion depth for nested objects */\n MAX_RECURSION_DEPTH: 10,\n} as const;\n\n// =============================================================================\n// RATE LIMITING\n// =============================================================================\nexport const RATE_LIMIT = {\n /** Default window size (1 minute) */\n DEFAULT_WINDOW_MS: 60_000,\n /** Default max requests per window */\n DEFAULT_MAX_REQUESTS: 100,\n /** Default HTTP status code for rate limited responses */\n DEFAULT_STATUS_CODE: 429,\n /** Default error message */\n DEFAULT_MESSAGE: 'Too many requests, please try again later.',\n /** Minimum window size (1 second) */\n MIN_WINDOW_MS: 1_000,\n /** Maximum window size (24 hours) */\n MAX_WINDOW_MS: 86_400_000,\n} as const;\n\n// =============================================================================\n// SECURITY HEADERS\n// =============================================================================\nexport const HEADERS = {\n /** Default Content Security Policy */\n DEFAULT_CSP: [\n \"default-src 'self'\",\n \"script-src 'self'\",\n \"style-src 'self' 'unsafe-inline'\",\n \"img-src 'self' data: https:\",\n \"font-src 'self'\",\n \"object-src 'none'\",\n \"frame-ancestors 'none'\",\n ].join('; '),\n /** Default HSTS max age (1 year in seconds) */\n HSTS_MAX_AGE: 31_536_000,\n /** Default X-Frame-Options value */\n FRAME_OPTIONS: 'DENY' as const,\n /** Default X-Content-Type-Options value */\n CONTENT_TYPE_OPTIONS: 'nosniff',\n /** Default Referrer-Policy value */\n REFERRER_POLICY: 'strict-origin-when-cross-origin',\n /** Default Permissions-Policy value */\n PERMISSIONS_POLICY: 'geolocation=(), microphone=(), camera=()',\n /** Default Cache-Control value for security */\n CACHE_CONTROL: 'no-store, no-cache, must-revalidate, proxy-revalidate',\n} as const;\n\n// =============================================================================\n// XSS PATTERNS (ReDoS-safe)\n// =============================================================================\n\n/**\n * Detection patterns — used to flag whether a string contains XSS payloads.\n * Must stay in sync with XSS_REMOVE_PATTERNS below.\n */\nexport const XSS_PATTERNS = [\n /** Script tags (ReDoS-safe version) */\n /<script[^>]*>[\\s\\S]*?<\\/script>/gi,\n /** javascript: protocol (allow optional spaces before colon) */\n /javascript\\s*:/gi,\n /** vbscript: protocol */\n /vbscript\\s*:/gi,\n /** Event handlers (onclick, onerror, etc.) — any separator before attribute */\n /(?:[\\s/])on\\w+\\s*=/gi,\n /** iframe tags */\n /<iframe/gi,\n /** object tags */\n /<object/gi,\n /** embed tags */\n /<embed/gi,\n /** data: URIs (only dangerous ones, avoid false positives) */\n /(?:^|[\\s\"'=])data:/gi,\n /** URL-encoded script tags */\n /%3Cscript/gi,\n /** SVG with onload */\n /<svg[^>]*onload/gi,\n /** form tags — phishing/credential harvesting via action= redirection */\n /<form[\\s>]/gi,\n /** meta tags — http-equiv refresh redirects or CSP bypass */\n /<meta[\\s>]/gi,\n /** base href hijacking — redirects all relative URLs to attacker domain */\n /<base[\\s>]/gi,\n /** link tag injection — stylesheet or preload CSRF attacks */\n /<link[\\s>]/gi,\n /** style tag — CSS expression() / behavior: / IE-era attacks. Mirrors\n * Python's xss-style-tag from packages/core/patterns.json. */\n /<style[\\s>]/gi,\n] as const;\n\n/**\n * Removal patterns — used by sanitizeXss() to strip dangerous content.\n * More targeted than XSS_PATTERNS: each pattern captures the full dangerous\n * substring (tag, attribute + value, protocol) so it can be replaced safely.\n * Must stay in sync with XSS_PATTERNS above.\n */\nexport const XSS_REMOVE_PATTERNS = [\n /** Full script blocks (content + tags) */\n /<script[^>]*>[\\s\\S]*?<\\/script>/gi,\n /** Standalone/unclosed script tags */\n /<script[^>]*>/gi,\n /** style — CSS expression() and behavior: attacks (IE-era but still relevant) */\n /<style[^>]*>[\\s\\S]*?<\\/style>/gi,\n /<style[^>]*/gi,\n /** iframe — full block and partial/unclosed */\n /<iframe[^>]*>[\\s\\S]*?<\\/iframe>/gi,\n /<iframe[^>]*/gi,\n /** object — full block and partial/unclosed */\n /<object[^>]*>[\\s\\S]*?<\\/object>/gi,\n /<object[^>]*/gi,\n /** embed tags */\n /<embed[^>]*/gi,\n /** SVG with inline event handlers */\n /<svg[^>]*onload[^>]*>/gi,\n /** URL-encoded script tags */\n /%3Cscript/gi,\n /** Event handlers with quoted values: onclick=\"...\", onerror='...' */\n /(?:[\\s/])on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi,\n /** Event handlers with unquoted values: onload=value */\n /(?:[\\s/])on\\w+\\s*=\\s*[^\\s>]*/gi,\n /** javascript: and vbscript: protocols (allow optional spaces before colon) */\n /javascript\\s*:/gi,\n /vbscript\\s*:/gi,\n /** data: URIs with HTML/script content */\n /data\\s*:\\s*text\\/html[^>\\s]*/gi,\n /** form tag injection — phishing via action= redirection */\n /<form[\\s>][^>]*/gi,\n /** meta tag injection — http-equiv refresh or CSP bypass */\n /<meta[\\s>][^>]*/gi,\n /** base href hijacking */\n /<base[\\s>][^>]*/gi,\n /** link tag injection — stylesheet or preload attacks */\n /<link[\\s>][^>]*/gi,\n] as const;\n\n// =============================================================================\n// SQL INJECTION PATTERNS\n// =============================================================================\nexport const SQL_PATTERNS = [\n /** SQL keywords */\n /(\\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)\\b)/gi,\n /** SQL comments: ANSI (--), C-style (slash-star ... star-slash), MySQL (#) */\n /(--|\\/\\*|\\*\\/|#)/g,\n /** SQL statement separators */\n /(;|\\|\\||&&)/g,\n /** Boolean injection: OR 1=1 */\n /\\bOR\\s+\\d+\\s*=\\s*\\d+/gi,\n /** Boolean injection: OR 'a'='a' or OR \"a\"=\"a\" (including mixed quotes) */\n /\\bOR\\s+(['\"])[^'\"]*\\1\\s*=\\s*(['\"])[^'\"]*\\2/gi,\n /\\bOR\\s+('[^']*'|\"[^\"]*\")\\s*=\\s*('[^']*'|\"[^\"]*\")/gi,\n /** Boolean injection: AND 1=1 */\n /\\bAND\\s+\\d+\\s*=\\s*\\d+/gi,\n /** Boolean injection: AND 'a'='a' or AND \"a\"=\"a\" (including mixed quotes) */\n /\\bAND\\s+(['\"])[^'\"]*\\1\\s*=\\s*(['\"])[^'\"]*\\2/gi,\n /\\bAND\\s+('[^']*'|\"[^\"]*\")\\s*=\\s*('[^']*'|\"[^\"]*\")/gi,\n /** Time-based blind: SLEEP() */\n /\\bSLEEP\\s*\\(\\s*\\d+\\s*\\)/gi,\n /** Time-based blind: BENCHMARK() */\n /\\bBENCHMARK\\s*\\(/gi,\n /** Time-based blind: PostgreSQL pg_sleep() */\n /\\bpg_sleep\\s*\\(/gi,\n /** Time-based blind: MSSQL WAITFOR DELAY */\n /\\bWAITFOR\\s+DELAY\\b/gi,\n] as const;\n\n// =============================================================================\n// PATH TRAVERSAL PATTERNS\n// =============================================================================\nexport const PATH_PATTERNS = [\n /** Unix path traversal */\n /\\.\\.\\//g,\n /** Windows path traversal */\n /\\.\\.\\\\/g,\n /** URL-encoded traversal (%2e%2e) */\n /%2e%2e/gi,\n /** Double URL-encoded traversal (%252e) */\n /%252e/gi,\n /** Mixed encoding: ..%2F */\n /\\.\\.%2F/gi,\n /** Mixed encoding: %2e./ and .%2e/ */\n /%2e\\.[\\\\/]/gi,\n /\\.%2e[\\\\/]/gi,\n /** Fully URL-encoded: %2e%2e%2f */\n /%2e%2e%2f/gi,\n /** Double URL-encoded forward slash: %252f */\n /%252f/gi,\n /** Dotdotslash bypass: ....// or ....\\\\ */\n /\\.{2,}[/\\\\]{2,}/g,\n /** Null byte injection in paths */\n /\\0/g,\n] as const;\n\n// =============================================================================\n// COMMAND INJECTION PATTERNS\n// =============================================================================\nexport const COMMAND_PATTERNS = [\n /**\n * Shell metacharacters that enable command chaining/substitution.\n * Bare ( and ) are excluded — they appear in common legitimate values\n * (function calls in code fields, math expressions, etc.).\n * Command substitution is caught by the $( combined pattern below.\n * NOTE: ';', '&', '|' may appear in legitimate URL query strings\n * and Markdown; consider disabling command checking (command: false)\n * for fields that intentionally allow those characters.\n */\n /[;&|`]/g,\n /** Command substitution: $( ... ) — matched as a pair to reduce false positives */\n /\\$\\(/g,\n /** URL-encoded control characters (%00-%0F): null, tab, vtab, formfeed, LF, CR */\n /%0[0-9a-f]/gi,\n] as const;\n\n// =============================================================================\n// DANGEROUS KEYS\n// =============================================================================\n\n/**\n * Prototype pollution keys to block.\n * Stored lowercase — always compare with key.toLowerCase().\n *\n * Includes:\n * - __proto__: direct prototype assignment\n * - constructor: access to constructor.prototype chain\n * - prototype: direct prototype property\n * - __defineGetter__/__defineSetter__: legacy property definition (can override getters/setters)\n * - __lookupGetter__/__lookupSetter__: legacy property introspection\n */\nexport const DANGEROUS_PROTO_KEYS = new Set([\n '__proto__',\n 'constructor',\n 'prototype',\n '__definegetter__',\n '__definesetter__',\n '__lookupgetter__',\n '__lookupsetter__',\n]);\n\n/** MongoDB operators to block */\nexport const NOSQL_DANGEROUS_KEYS = new Set([\n // Comparison\n '$gt', '$gte', '$lt', '$lte', '$ne', '$eq', '$in', '$nin',\n // Logical\n '$and', '$or', '$not', '$nor',\n // Element / evaluation\n '$exists', '$type', '$regex', '$where', '$expr', '$mod', '$text', '$jsonSchema',\n // Array\n '$elemMatch', '$all', '$size',\n // JavaScript execution (critical)\n '$function', '$accumulator',\n // Aggregation pipeline operators (injectable via $lookup etc.)\n '$lookup', '$match', '$project', '$group', '$sort', '$limit', '$skip',\n '$unwind', '$addFields', '$replaceRoot',\n]);\n\n// =============================================================================\n// REDACTION\n// =============================================================================\nexport const REDACTION = {\n /** Replacement text for redacted values */\n REPLACEMENT: '[REDACTED]',\n /** Truncation indicator */\n TRUNCATED: '[TRUNCATED]',\n /** Max depth indicator */\n MAX_DEPTH: '[MAX_DEPTH]',\n /** Default max message length */\n DEFAULT_MAX_LENGTH: 10_000,\n /** Default sensitive keys to redact */\n SENSITIVE_KEYS: new Set([\n 'password', 'passwd', 'pwd', 'secret', 'token', 'apikey',\n 'api_key', 'apiKey', 'auth', 'authorization', 'credit_card',\n 'creditcard', 'cc', 'ssn', 'social_security', 'private_key',\n 'privateKey', 'access_token', 'accessToken', 'refresh_token',\n 'refreshToken', 'bearer', 'jwt', 'session', 'cookie',\n 'credentials', 'x-api-key', 'x-auth-token',\n ]),\n} as const;\n\n// =============================================================================\n// VALIDATION PATTERNS\n// =============================================================================\nexport const VALIDATION = {\n /**\n * Email regex pattern.\n * Rejects consecutive dots in local part (e.g. test..foo@example.com),\n * leading/trailing dots, and other common invalid forms.\n */\n EMAIL: /^[^\\s@.][^\\s@]*(?:\\.[^\\s@.][^\\s@]*)*@[^\\s@]+\\.[^\\s@]+$/,\n /**\n * URL regex pattern.\n * Only allows http:// and https:// — explicitly rejects javascript:,\n * data:, vbscript:, and other dangerous URI schemes.\n */\n URL: /^https?:\\/\\/[^\\s/$.?#][^\\s]*$/,\n /** UUID regex pattern (v4) */\n UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n} as const;\n\n// =============================================================================\n// ERROR MESSAGES\n// =============================================================================\nexport const ERRORS = {\n /** Generic error message (production) */\n INTERNAL_SERVER_ERROR: 'Internal Server Error',\n /** Input too large error */\n INPUT_TOO_LARGE: (maxSize: number) => `Input exceeds maximum size of ${maxSize} bytes`,\n /** Validation error messages */\n VALIDATION: {\n REQUIRED: (field: string) => `${field} is required`,\n INVALID_TYPE: (field: string, type: string) => `${field} must be a ${type}`,\n MIN_LENGTH: (field: string, min: number) => `${field} must be at least ${min} characters`,\n MAX_LENGTH: (field: string, max: number) => `${field} must be at most ${max} characters`,\n MIN_VALUE: (field: string, min: number) => `${field} must be at least ${min}`,\n MAX_VALUE: (field: string, max: number) => `${field} must be at most ${max}`,\n INVALID_FORMAT: (field: string) => `${field} format is invalid`,\n INVALID_EMAIL: (field: string) => `${field} must be a valid email`,\n INVALID_URL: (field: string) => `${field} must be a valid URL`,\n INVALID_UUID: (field: string) => `${field} must be a valid UUID`,\n INVALID_ENUM: (field: string, values: unknown[]) => `${field} must be one of: ${values.join(', ')}`,\n MIN_ITEMS: (field: string, min: number) => `${field} must have at least ${min} items`,\n MAX_ITEMS: (field: string, max: number) => `${field} must have at most ${max} items`,\n },\n} as const;\n\n// =============================================================================\n// BLOCKED TEXT (for sanitizer replacements)\n// =============================================================================\nexport const BLOCKED = '[BLOCKED]' as const;\n","/**\n * @module @arcis/node/core/errors\n * Custom error classes for Arcis\n */\n\n/**\n * Base class for all Arcis errors\n */\nexport class ArcisError extends Error {\n public readonly statusCode: number;\n public readonly code: string;\n /** Whether the error message is safe to expose to API clients. */\n public readonly expose: boolean;\n\n constructor(message: string, statusCode = 500, code = 'ARCIS_ERROR') {\n super(message);\n this.name = 'ArcisError';\n this.statusCode = statusCode;\n this.code = code;\n // Client errors (4xx) have controlled messages — safe to expose.\n // Server errors (5xx) may contain internal details — hide by default.\n this.expose = statusCode < 500;\n\n // Maintains proper stack trace for where error was thrown (V8 engines)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error thrown when input validation fails\n */\nexport class ValidationError extends ArcisError {\n public readonly errors: string[];\n\n constructor(errors: string[]) {\n super('Validation failed', 400, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n this.errors = errors;\n }\n}\n\n/** Alias for ValidationError (backwards compatibility) */\nexport { ValidationError as ArcisValidationError };\n\n/**\n * Error thrown when rate limit is exceeded\n */\nexport class RateLimitError extends ArcisError {\n public readonly retryAfter: number;\n\n constructor(message: string, retryAfter: number) {\n super(message, 429, 'RATE_LIMIT_EXCEEDED');\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\n/**\n * Error thrown when input is too large\n */\nexport class InputTooLargeError extends ArcisError {\n public readonly maxSize: number;\n public readonly actualSize: number;\n\n constructor(maxSize: number, actualSize: number) {\n super(`Input exceeds maximum size of ${maxSize} bytes`, 413, 'INPUT_TOO_LARGE');\n this.name = 'InputTooLargeError';\n this.maxSize = maxSize;\n this.actualSize = actualSize;\n }\n}\n\n/**\n * Error thrown when security threat is detected\n */\nexport class SecurityThreatError extends ArcisError {\n public readonly threatType: string;\n public readonly pattern: string;\n\n constructor(threatType: string, pattern: string) {\n super('Request blocked for security reasons', 400, 'SECURITY_THREAT');\n this.name = 'SecurityThreatError';\n this.threatType = threatType;\n this.pattern = pattern;\n }\n}\n\n/**\n * Error thrown when sanitization fails\n */\nexport class SanitizationError extends ArcisError {\n constructor(message: string) {\n super(message, 400, 'SANITIZATION_ERROR');\n this.name = 'SanitizationError';\n }\n}\n"]}
|
package/dist/core/index.mjs
CHANGED
|
@@ -71,7 +71,10 @@ var XSS_PATTERNS = [
|
|
|
71
71
|
/** base href hijacking — redirects all relative URLs to attacker domain */
|
|
72
72
|
/<base[\s>]/gi,
|
|
73
73
|
/** link tag injection — stylesheet or preload CSRF attacks */
|
|
74
|
-
/<link[\s>]/gi
|
|
74
|
+
/<link[\s>]/gi,
|
|
75
|
+
/** style tag — CSS expression() / behavior: / IE-era attacks. Mirrors
|
|
76
|
+
* Python's xss-style-tag from packages/core/patterns.json. */
|
|
77
|
+
/<style[\s>]/gi
|
|
75
78
|
];
|
|
76
79
|
var SQL_PATTERNS = [
|
|
77
80
|
/** SQL keywords */
|