@arcis/node 1.0.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/README.md +222 -0
- package/dist/core/index.d.mts +170 -0
- package/dist/core/index.d.ts +170 -0
- package/dist/core/index.js +327 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/index.mjs +307 -0
- package/dist/core/index.mjs.map +1 -0
- package/dist/headers-BJq2OA0i.d.ts +284 -0
- package/dist/headers-DBQedhrb.d.mts +284 -0
- package/dist/index-BgHPM7LC.d.ts +129 -0
- package/dist/index-BpT7flAQ.d.ts +255 -0
- package/dist/index-JaFOUKyK.d.mts +255 -0
- package/dist/index-nAgXexwD.d.mts +129 -0
- package/dist/index.d.mts +139 -0
- package/dist/index.d.ts +139 -0
- package/dist/index.js +1860 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1797 -0
- package/dist/index.mjs.map +1 -0
- package/dist/logging/index.d.mts +38 -0
- package/dist/logging/index.d.ts +38 -0
- package/dist/logging/index.js +140 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/index.mjs +136 -0
- package/dist/logging/index.mjs.map +1 -0
- package/dist/middleware/index.d.mts +3 -0
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +1173 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/index.mjs +1156 -0
- package/dist/middleware/index.mjs.map +1 -0
- package/dist/sanitizers/index.d.mts +24 -0
- package/dist/sanitizers/index.d.ts +24 -0
- package/dist/sanitizers/index.js +610 -0
- package/dist/sanitizers/index.js.map +1 -0
- package/dist/sanitizers/index.mjs +587 -0
- package/dist/sanitizers/index.mjs.map +1 -0
- package/dist/stores/index.d.mts +106 -0
- package/dist/stores/index.d.ts +106 -0
- package/dist/stores/index.js +149 -0
- package/dist/stores/index.js.map +1 -0
- package/dist/stores/index.mjs +145 -0
- package/dist/stores/index.mjs.map +1 -0
- package/dist/types-BOdL3ZWo.d.mts +264 -0
- package/dist/types-BOdL3ZWo.d.ts +264 -0
- package/dist/validation/index.d.mts +3 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.js +705 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/index.mjs +699 -0
- package/dist/validation/index.mjs.map +1 -0
- package/package.json +109 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/core/constants.ts
|
|
4
|
+
var INPUT = {
|
|
5
|
+
/** Default maximum input size (1MB) */
|
|
6
|
+
DEFAULT_MAX_SIZE: 1e6,
|
|
7
|
+
/** Maximum recursion depth for nested objects */
|
|
8
|
+
MAX_RECURSION_DEPTH: 10
|
|
9
|
+
};
|
|
10
|
+
var RATE_LIMIT = {
|
|
11
|
+
/** Default window size (1 minute) */
|
|
12
|
+
DEFAULT_WINDOW_MS: 6e4,
|
|
13
|
+
/** Default max requests per window */
|
|
14
|
+
DEFAULT_MAX_REQUESTS: 100,
|
|
15
|
+
/** Default HTTP status code for rate limited responses */
|
|
16
|
+
DEFAULT_STATUS_CODE: 429,
|
|
17
|
+
/** Default error message */
|
|
18
|
+
DEFAULT_MESSAGE: "Too many requests, please try again later.",
|
|
19
|
+
/** Minimum window size (1 second) */
|
|
20
|
+
MIN_WINDOW_MS: 1e3,
|
|
21
|
+
/** Maximum window size (24 hours) */
|
|
22
|
+
MAX_WINDOW_MS: 864e5
|
|
23
|
+
};
|
|
24
|
+
var HEADERS = {
|
|
25
|
+
/** Default Content Security Policy */
|
|
26
|
+
DEFAULT_CSP: [
|
|
27
|
+
"default-src 'self'",
|
|
28
|
+
"script-src 'self'",
|
|
29
|
+
"style-src 'self' 'unsafe-inline'",
|
|
30
|
+
"img-src 'self' data: https:",
|
|
31
|
+
"font-src 'self'",
|
|
32
|
+
"object-src 'none'",
|
|
33
|
+
"frame-ancestors 'none'"
|
|
34
|
+
].join("; "),
|
|
35
|
+
/** Default HSTS max age (1 year in seconds) */
|
|
36
|
+
HSTS_MAX_AGE: 31536e3,
|
|
37
|
+
/** Default X-Frame-Options value */
|
|
38
|
+
FRAME_OPTIONS: "DENY",
|
|
39
|
+
/** Default X-Content-Type-Options value */
|
|
40
|
+
CONTENT_TYPE_OPTIONS: "nosniff",
|
|
41
|
+
/** Default Referrer-Policy value */
|
|
42
|
+
REFERRER_POLICY: "strict-origin-when-cross-origin",
|
|
43
|
+
/** Default Permissions-Policy value */
|
|
44
|
+
PERMISSIONS_POLICY: "geolocation=(), microphone=(), camera=()",
|
|
45
|
+
/** Default Cache-Control value for security */
|
|
46
|
+
CACHE_CONTROL: "no-store, no-cache, must-revalidate, proxy-revalidate"
|
|
47
|
+
};
|
|
48
|
+
var XSS_PATTERNS = [
|
|
49
|
+
/** Script tags (ReDoS-safe version) */
|
|
50
|
+
/<script[^>]*>[\s\S]*?<\/script>/gi,
|
|
51
|
+
/** javascript: protocol (allow optional spaces before colon) */
|
|
52
|
+
/javascript\s*:/gi,
|
|
53
|
+
/** vbscript: protocol */
|
|
54
|
+
/vbscript\s*:/gi,
|
|
55
|
+
/** Event handlers (onclick, onerror, etc.) — any separator before attribute */
|
|
56
|
+
/(?:[\s/])on\w+\s*=/gi,
|
|
57
|
+
/** iframe tags */
|
|
58
|
+
/<iframe/gi,
|
|
59
|
+
/** object tags */
|
|
60
|
+
/<object/gi,
|
|
61
|
+
/** embed tags */
|
|
62
|
+
/<embed/gi,
|
|
63
|
+
/** data: URIs (only dangerous ones, avoid false positives) */
|
|
64
|
+
/(?:^|[\s"'=])data:/gi,
|
|
65
|
+
/** URL-encoded script tags */
|
|
66
|
+
/%3Cscript/gi,
|
|
67
|
+
/** SVG with onload */
|
|
68
|
+
/<svg[^>]*onload/gi
|
|
69
|
+
];
|
|
70
|
+
var SQL_PATTERNS = [
|
|
71
|
+
/** SQL keywords */
|
|
72
|
+
/(\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)\b)/gi,
|
|
73
|
+
/** SQL comments: ANSI (--), C-style (slash-star ... star-slash), MySQL (#) */
|
|
74
|
+
/(--|\/\*|\*\/|#)/g,
|
|
75
|
+
/** SQL statement separators */
|
|
76
|
+
/(;|\|\||&&)/g,
|
|
77
|
+
/** Boolean injection: OR 1=1 */
|
|
78
|
+
/\bOR\s+\d+\s*=\s*\d+/gi,
|
|
79
|
+
/** Boolean injection: OR 'a'='a' or OR "a"="a" (including mixed quotes) */
|
|
80
|
+
/\bOR\s+(['"])[^'"]*\1\s*=\s*(['"])[^'"]*\2/gi,
|
|
81
|
+
/\bOR\s+('[^']*'|"[^"]*")\s*=\s*('[^']*'|"[^"]*")/gi,
|
|
82
|
+
/** Boolean injection: AND 1=1 */
|
|
83
|
+
/\bAND\s+\d+\s*=\s*\d+/gi,
|
|
84
|
+
/** Boolean injection: AND 'a'='a' or AND "a"="a" (including mixed quotes) */
|
|
85
|
+
/\bAND\s+(['"])[^'"]*\1\s*=\s*(['"])[^'"]*\2/gi,
|
|
86
|
+
/\bAND\s+('[^']*'|"[^"]*")\s*=\s*('[^']*'|"[^"]*")/gi,
|
|
87
|
+
/** Time-based blind: SLEEP() */
|
|
88
|
+
/\bSLEEP\s*\(\s*\d+\s*\)/gi,
|
|
89
|
+
/** Time-based blind: BENCHMARK() */
|
|
90
|
+
/\bBENCHMARK\s*\(/gi
|
|
91
|
+
];
|
|
92
|
+
var PATH_PATTERNS = [
|
|
93
|
+
/** Unix path traversal */
|
|
94
|
+
/\.\.\//g,
|
|
95
|
+
/** Windows path traversal */
|
|
96
|
+
/\.\.\\/g,
|
|
97
|
+
/** URL-encoded traversal (%2e%2e) */
|
|
98
|
+
/%2e%2e/gi,
|
|
99
|
+
/** Double URL-encoded traversal (%252e) */
|
|
100
|
+
/%252e/gi,
|
|
101
|
+
/** Mixed encoding: ..%2F */
|
|
102
|
+
/\.\.%2F/gi,
|
|
103
|
+
/** Mixed encoding: %2e./ and .%2e/ */
|
|
104
|
+
/%2e\.[\\/]/gi,
|
|
105
|
+
/\.%2e[\\/]/gi,
|
|
106
|
+
/** Fully URL-encoded: %2e%2e%2f */
|
|
107
|
+
/%2e%2e%2f/gi,
|
|
108
|
+
/** Null byte injection in paths */
|
|
109
|
+
/\0/g
|
|
110
|
+
];
|
|
111
|
+
var COMMAND_PATTERNS = [
|
|
112
|
+
/**
|
|
113
|
+
* Shell metacharacters that enable command chaining/substitution.
|
|
114
|
+
* Bare ( and ) are excluded — they appear in common legitimate values
|
|
115
|
+
* (function calls in code fields, math expressions, etc.).
|
|
116
|
+
* Command substitution is caught by the $( combined pattern below.
|
|
117
|
+
* NOTE: ';', '&', '|' may appear in legitimate URL query strings
|
|
118
|
+
* and Markdown; consider disabling command checking (command: false)
|
|
119
|
+
* for fields that intentionally allow those characters.
|
|
120
|
+
*/
|
|
121
|
+
/[;&|`]/g,
|
|
122
|
+
/** Command substitution: $( ... ) — matched as a pair to reduce false positives */
|
|
123
|
+
/\$\(/g
|
|
124
|
+
];
|
|
125
|
+
var DANGEROUS_PROTO_KEYS = /* @__PURE__ */ new Set([
|
|
126
|
+
"__proto__",
|
|
127
|
+
"constructor",
|
|
128
|
+
"prototype",
|
|
129
|
+
"__definegetter__",
|
|
130
|
+
"__definesetter__",
|
|
131
|
+
"__lookupgetter__",
|
|
132
|
+
"__lookupsetter__"
|
|
133
|
+
]);
|
|
134
|
+
var NOSQL_DANGEROUS_KEYS = /* @__PURE__ */ new Set([
|
|
135
|
+
// Comparison
|
|
136
|
+
"$gt",
|
|
137
|
+
"$gte",
|
|
138
|
+
"$lt",
|
|
139
|
+
"$lte",
|
|
140
|
+
"$ne",
|
|
141
|
+
"$eq",
|
|
142
|
+
"$in",
|
|
143
|
+
"$nin",
|
|
144
|
+
// Logical
|
|
145
|
+
"$and",
|
|
146
|
+
"$or",
|
|
147
|
+
"$not",
|
|
148
|
+
"$nor",
|
|
149
|
+
// Element / evaluation
|
|
150
|
+
"$exists",
|
|
151
|
+
"$type",
|
|
152
|
+
"$regex",
|
|
153
|
+
"$where",
|
|
154
|
+
"$expr",
|
|
155
|
+
"$mod",
|
|
156
|
+
"$text",
|
|
157
|
+
// Array
|
|
158
|
+
"$elemMatch",
|
|
159
|
+
"$all",
|
|
160
|
+
"$size",
|
|
161
|
+
// JavaScript execution (critical)
|
|
162
|
+
"$function",
|
|
163
|
+
"$accumulator",
|
|
164
|
+
// Aggregation pipeline operators (injectable via $lookup etc.)
|
|
165
|
+
"$lookup",
|
|
166
|
+
"$match",
|
|
167
|
+
"$project",
|
|
168
|
+
"$group",
|
|
169
|
+
"$sort",
|
|
170
|
+
"$limit",
|
|
171
|
+
"$skip",
|
|
172
|
+
"$unwind",
|
|
173
|
+
"$addFields",
|
|
174
|
+
"$replaceRoot"
|
|
175
|
+
]);
|
|
176
|
+
var REDACTION = {
|
|
177
|
+
/** Replacement text for redacted values */
|
|
178
|
+
REPLACEMENT: "[REDACTED]",
|
|
179
|
+
/** Truncation indicator */
|
|
180
|
+
TRUNCATED: "[TRUNCATED]",
|
|
181
|
+
/** Max depth indicator */
|
|
182
|
+
MAX_DEPTH: "[MAX_DEPTH]",
|
|
183
|
+
/** Default max message length */
|
|
184
|
+
DEFAULT_MAX_LENGTH: 1e4,
|
|
185
|
+
/** Default sensitive keys to redact */
|
|
186
|
+
SENSITIVE_KEYS: /* @__PURE__ */ new Set([
|
|
187
|
+
"password",
|
|
188
|
+
"passwd",
|
|
189
|
+
"pwd",
|
|
190
|
+
"secret",
|
|
191
|
+
"token",
|
|
192
|
+
"apikey",
|
|
193
|
+
"api_key",
|
|
194
|
+
"apiKey",
|
|
195
|
+
"auth",
|
|
196
|
+
"authorization",
|
|
197
|
+
"credit_card",
|
|
198
|
+
"creditcard",
|
|
199
|
+
"cc",
|
|
200
|
+
"ssn",
|
|
201
|
+
"social_security",
|
|
202
|
+
"private_key",
|
|
203
|
+
"privateKey",
|
|
204
|
+
"access_token",
|
|
205
|
+
"accessToken",
|
|
206
|
+
"refresh_token",
|
|
207
|
+
"refreshToken",
|
|
208
|
+
"bearer",
|
|
209
|
+
"jwt",
|
|
210
|
+
"session",
|
|
211
|
+
"cookie",
|
|
212
|
+
"credentials",
|
|
213
|
+
"x-api-key",
|
|
214
|
+
"x-auth-token"
|
|
215
|
+
])
|
|
216
|
+
};
|
|
217
|
+
var VALIDATION = {
|
|
218
|
+
/**
|
|
219
|
+
* Email regex pattern.
|
|
220
|
+
* Rejects consecutive dots in local part (e.g. test..foo@example.com),
|
|
221
|
+
* leading/trailing dots, and other common invalid forms.
|
|
222
|
+
*/
|
|
223
|
+
EMAIL: /^[^\s@.][^\s@]*(?:\.[^\s@.][^\s@]*)*@[^\s@]+\.[^\s@]+$/,
|
|
224
|
+
/**
|
|
225
|
+
* URL regex pattern.
|
|
226
|
+
* Only allows http:// and https:// — explicitly rejects javascript:,
|
|
227
|
+
* data:, vbscript:, and other dangerous URI schemes.
|
|
228
|
+
*/
|
|
229
|
+
URL: /^https?:\/\/[^\s/$.?#][^\s]*$/,
|
|
230
|
+
/** UUID regex pattern (v4) */
|
|
231
|
+
UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
232
|
+
};
|
|
233
|
+
var ERRORS = {
|
|
234
|
+
/** Generic error message (production) */
|
|
235
|
+
INTERNAL_SERVER_ERROR: "Internal Server Error",
|
|
236
|
+
/** Input too large error */
|
|
237
|
+
INPUT_TOO_LARGE: (maxSize) => `Input exceeds maximum size of ${maxSize} bytes`,
|
|
238
|
+
/** Validation error messages */
|
|
239
|
+
VALIDATION: {
|
|
240
|
+
REQUIRED: (field) => `${field} is required`,
|
|
241
|
+
INVALID_TYPE: (field, type) => `${field} must be a ${type}`,
|
|
242
|
+
MIN_LENGTH: (field, min) => `${field} must be at least ${min} characters`,
|
|
243
|
+
MAX_LENGTH: (field, max) => `${field} must be at most ${max} characters`,
|
|
244
|
+
MIN_VALUE: (field, min) => `${field} must be at least ${min}`,
|
|
245
|
+
MAX_VALUE: (field, max) => `${field} must be at most ${max}`,
|
|
246
|
+
INVALID_FORMAT: (field) => `${field} format is invalid`,
|
|
247
|
+
INVALID_EMAIL: (field) => `${field} must be a valid email`,
|
|
248
|
+
INVALID_URL: (field) => `${field} must be a valid URL`,
|
|
249
|
+
INVALID_UUID: (field) => `${field} must be a valid UUID`,
|
|
250
|
+
INVALID_ENUM: (field, values) => `${field} must be one of: ${values.join(", ")}`,
|
|
251
|
+
MIN_ITEMS: (field, min) => `${field} must have at least ${min} items`,
|
|
252
|
+
MAX_ITEMS: (field, max) => `${field} must have at most ${max} items`
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
var BLOCKED = "[BLOCKED]";
|
|
256
|
+
|
|
257
|
+
// src/core/errors.ts
|
|
258
|
+
var ArcisError = class extends Error {
|
|
259
|
+
constructor(message, statusCode = 500, code = "ARCIS_ERROR") {
|
|
260
|
+
super(message);
|
|
261
|
+
this.name = "ArcisError";
|
|
262
|
+
this.statusCode = statusCode;
|
|
263
|
+
this.code = code;
|
|
264
|
+
this.expose = statusCode < 500;
|
|
265
|
+
if (Error.captureStackTrace) {
|
|
266
|
+
Error.captureStackTrace(this, this.constructor);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
var ValidationError = class extends ArcisError {
|
|
271
|
+
constructor(errors) {
|
|
272
|
+
super("Validation failed", 400, "VALIDATION_ERROR");
|
|
273
|
+
this.name = "ValidationError";
|
|
274
|
+
this.errors = errors;
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
var RateLimitError = class extends ArcisError {
|
|
278
|
+
constructor(message, retryAfter) {
|
|
279
|
+
super(message, 429, "RATE_LIMIT_EXCEEDED");
|
|
280
|
+
this.name = "RateLimitError";
|
|
281
|
+
this.retryAfter = retryAfter;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
var InputTooLargeError = class extends ArcisError {
|
|
285
|
+
constructor(maxSize, actualSize) {
|
|
286
|
+
super(`Input exceeds maximum size of ${maxSize} bytes`, 413, "INPUT_TOO_LARGE");
|
|
287
|
+
this.name = "InputTooLargeError";
|
|
288
|
+
this.maxSize = maxSize;
|
|
289
|
+
this.actualSize = actualSize;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
var SecurityThreatError = class extends ArcisError {
|
|
293
|
+
constructor(threatType, pattern) {
|
|
294
|
+
super("Request blocked for security reasons", 400, "SECURITY_THREAT");
|
|
295
|
+
this.name = "SecurityThreatError";
|
|
296
|
+
this.threatType = threatType;
|
|
297
|
+
this.pattern = pattern;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
var SanitizationError = class extends ArcisError {
|
|
301
|
+
constructor(message) {
|
|
302
|
+
super(message, 400, "SANITIZATION_ERROR");
|
|
303
|
+
this.name = "SanitizationError";
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
exports.ArcisError = ArcisError;
|
|
308
|
+
exports.ArcisValidationError = ValidationError;
|
|
309
|
+
exports.BLOCKED = BLOCKED;
|
|
310
|
+
exports.COMMAND_PATTERNS = COMMAND_PATTERNS;
|
|
311
|
+
exports.DANGEROUS_PROTO_KEYS = DANGEROUS_PROTO_KEYS;
|
|
312
|
+
exports.ERRORS = ERRORS;
|
|
313
|
+
exports.HEADERS = HEADERS;
|
|
314
|
+
exports.INPUT = INPUT;
|
|
315
|
+
exports.InputTooLargeError = InputTooLargeError;
|
|
316
|
+
exports.NOSQL_DANGEROUS_KEYS = NOSQL_DANGEROUS_KEYS;
|
|
317
|
+
exports.PATH_PATTERNS = PATH_PATTERNS;
|
|
318
|
+
exports.RATE_LIMIT = RATE_LIMIT;
|
|
319
|
+
exports.REDACTION = REDACTION;
|
|
320
|
+
exports.RateLimitError = RateLimitError;
|
|
321
|
+
exports.SQL_PATTERNS = SQL_PATTERNS;
|
|
322
|
+
exports.SanitizationError = SanitizationError;
|
|
323
|
+
exports.SecurityThreatError = SecurityThreatError;
|
|
324
|
+
exports.VALIDATION = VALIDATION;
|
|
325
|
+
exports.XSS_PATTERNS = XSS_PATTERNS;
|
|
326
|
+
//# sourceMappingURL=index.js.map
|
|
327
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/constants.ts","../../src/core/errors.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * @module @arcis/node/core/constants\r\n * Named constants for Arcis - no magic numbers\r\n */\r\n\r\n// =============================================================================\r\n// INPUT LIMITS\r\n// =============================================================================\r\nexport const INPUT = {\r\n /** Default maximum input size (1MB) */\r\n DEFAULT_MAX_SIZE: 1_000_000,\r\n /** Maximum recursion depth for nested objects */\r\n MAX_RECURSION_DEPTH: 10,\r\n} as const;\r\n\r\n// =============================================================================\r\n// RATE LIMITING\r\n// =============================================================================\r\nexport const RATE_LIMIT = {\r\n /** Default window size (1 minute) */\r\n DEFAULT_WINDOW_MS: 60_000,\r\n /** Default max requests per window */\r\n DEFAULT_MAX_REQUESTS: 100,\r\n /** Default HTTP status code for rate limited responses */\r\n DEFAULT_STATUS_CODE: 429,\r\n /** Default error message */\r\n DEFAULT_MESSAGE: 'Too many requests, please try again later.',\r\n /** Minimum window size (1 second) */\r\n MIN_WINDOW_MS: 1_000,\r\n /** Maximum window size (24 hours) */\r\n MAX_WINDOW_MS: 86_400_000,\r\n} as const;\r\n\r\n// =============================================================================\r\n// SECURITY HEADERS\r\n// =============================================================================\r\nexport const HEADERS = {\r\n /** Default Content Security Policy */\r\n DEFAULT_CSP: [\r\n \"default-src 'self'\",\r\n \"script-src 'self'\",\r\n \"style-src 'self' 'unsafe-inline'\",\r\n \"img-src 'self' data: https:\",\r\n \"font-src 'self'\",\r\n \"object-src 'none'\",\r\n \"frame-ancestors 'none'\",\r\n ].join('; '),\r\n /** Default HSTS max age (1 year in seconds) */\r\n HSTS_MAX_AGE: 31_536_000,\r\n /** Default X-Frame-Options value */\r\n FRAME_OPTIONS: 'DENY' as const,\r\n /** Default X-Content-Type-Options value */\r\n CONTENT_TYPE_OPTIONS: 'nosniff',\r\n /** Default Referrer-Policy value */\r\n REFERRER_POLICY: 'strict-origin-when-cross-origin',\r\n /** Default Permissions-Policy value */\r\n PERMISSIONS_POLICY: 'geolocation=(), microphone=(), camera=()',\r\n /** Default Cache-Control value for security */\r\n CACHE_CONTROL: 'no-store, no-cache, must-revalidate, proxy-revalidate',\r\n} as const;\r\n\r\n// =============================================================================\r\n// XSS PATTERNS (ReDoS-safe)\r\n// =============================================================================\r\n\r\n/**\r\n * Detection patterns — used to flag whether a string contains XSS payloads.\r\n * Must stay in sync with XSS_REMOVE_PATTERNS below.\r\n */\r\nexport const XSS_PATTERNS = [\r\n /** Script tags (ReDoS-safe version) */\r\n /<script[^>]*>[\\s\\S]*?<\\/script>/gi,\r\n /** javascript: protocol (allow optional spaces before colon) */\r\n /javascript\\s*:/gi,\r\n /** vbscript: protocol */\r\n /vbscript\\s*:/gi,\r\n /** Event handlers (onclick, onerror, etc.) — any separator before attribute */\r\n /(?:[\\s/])on\\w+\\s*=/gi,\r\n /** iframe tags */\r\n /<iframe/gi,\r\n /** object tags */\r\n /<object/gi,\r\n /** embed tags */\r\n /<embed/gi,\r\n /** data: URIs (only dangerous ones, avoid false positives) */\r\n /(?:^|[\\s\"'=])data:/gi,\r\n /** URL-encoded script tags */\r\n /%3Cscript/gi,\r\n /** SVG with onload */\r\n /<svg[^>]*onload/gi,\r\n] as const;\r\n\r\n/**\r\n * Removal patterns — used by sanitizeXss() to strip dangerous content.\r\n * More targeted than XSS_PATTERNS: each pattern captures the full dangerous\r\n * substring (tag, attribute + value, protocol) so it can be replaced safely.\r\n * Must stay in sync with XSS_PATTERNS above.\r\n */\r\nexport const XSS_REMOVE_PATTERNS = [\r\n /** Full script blocks (content + tags) */\r\n /<script[^>]*>[\\s\\S]*?<\\/script>/gi,\r\n /** Standalone/unclosed script tags */\r\n /<script[^>]*>/gi,\r\n /** iframe — full block and partial/unclosed */\r\n /<iframe[^>]*>[\\s\\S]*?<\\/iframe>/gi,\r\n /<iframe[^>]*/gi,\r\n /** object — full block and partial/unclosed */\r\n /<object[^>]*>[\\s\\S]*?<\\/object>/gi,\r\n /<object[^>]*/gi,\r\n /** embed tags */\r\n /<embed[^>]*/gi,\r\n /** SVG with inline event handlers */\r\n /<svg[^>]*onload[^>]*>/gi,\r\n /** URL-encoded script tags */\r\n /%3Cscript/gi,\r\n /** Event handlers with quoted values: onclick=\"...\", onerror='...' */\r\n /(?:[\\s/])on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi,\r\n /** Event handlers with unquoted values: onload=value */\r\n /(?:[\\s/])on\\w+\\s*=\\s*[^\\s>]*/gi,\r\n /** javascript: and vbscript: protocols (allow optional spaces before colon) */\r\n /javascript\\s*:/gi,\r\n /vbscript\\s*:/gi,\r\n /** data: URIs with HTML/script content */\r\n /data\\s*:\\s*text\\/html[^>\\s]*/gi,\r\n] as const;\r\n\r\n// =============================================================================\r\n// SQL INJECTION PATTERNS\r\n// =============================================================================\r\nexport const SQL_PATTERNS = [\r\n /** SQL keywords */\r\n /(\\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)\\b)/gi,\r\n /** SQL comments: ANSI (--), C-style (slash-star ... star-slash), MySQL (#) */\r\n /(--|\\/\\*|\\*\\/|#)/g,\r\n /** SQL statement separators */\r\n /(;|\\|\\||&&)/g,\r\n /** Boolean injection: OR 1=1 */\r\n /\\bOR\\s+\\d+\\s*=\\s*\\d+/gi,\r\n /** Boolean injection: OR 'a'='a' or OR \"a\"=\"a\" (including mixed quotes) */\r\n /\\bOR\\s+(['\"])[^'\"]*\\1\\s*=\\s*(['\"])[^'\"]*\\2/gi,\r\n /\\bOR\\s+('[^']*'|\"[^\"]*\")\\s*=\\s*('[^']*'|\"[^\"]*\")/gi,\r\n /** Boolean injection: AND 1=1 */\r\n /\\bAND\\s+\\d+\\s*=\\s*\\d+/gi,\r\n /** Boolean injection: AND 'a'='a' or AND \"a\"=\"a\" (including mixed quotes) */\r\n /\\bAND\\s+(['\"])[^'\"]*\\1\\s*=\\s*(['\"])[^'\"]*\\2/gi,\r\n /\\bAND\\s+('[^']*'|\"[^\"]*\")\\s*=\\s*('[^']*'|\"[^\"]*\")/gi,\r\n /** Time-based blind: SLEEP() */\r\n /\\bSLEEP\\s*\\(\\s*\\d+\\s*\\)/gi,\r\n /** Time-based blind: BENCHMARK() */\r\n /\\bBENCHMARK\\s*\\(/gi,\r\n] as const;\r\n\r\n// =============================================================================\r\n// PATH TRAVERSAL PATTERNS\r\n// =============================================================================\r\nexport const PATH_PATTERNS = [\r\n /** Unix path traversal */\r\n /\\.\\.\\//g,\r\n /** Windows path traversal */\r\n /\\.\\.\\\\/g,\r\n /** URL-encoded traversal (%2e%2e) */\r\n /%2e%2e/gi,\r\n /** Double URL-encoded traversal (%252e) */\r\n /%252e/gi,\r\n /** Mixed encoding: ..%2F */\r\n /\\.\\.%2F/gi,\r\n /** Mixed encoding: %2e./ and .%2e/ */\r\n /%2e\\.[\\\\/]/gi,\r\n /\\.%2e[\\\\/]/gi,\r\n /** Fully URL-encoded: %2e%2e%2f */\r\n /%2e%2e%2f/gi,\r\n /** Null byte injection in paths */\r\n /\\0/g,\r\n] as const;\r\n\r\n// =============================================================================\r\n// COMMAND INJECTION PATTERNS\r\n// =============================================================================\r\nexport const COMMAND_PATTERNS = [\r\n /**\r\n * Shell metacharacters that enable command chaining/substitution.\r\n * Bare ( and ) are excluded — they appear in common legitimate values\r\n * (function calls in code fields, math expressions, etc.).\r\n * Command substitution is caught by the $( combined pattern below.\r\n * NOTE: ';', '&', '|' may appear in legitimate URL query strings\r\n * and Markdown; consider disabling command checking (command: false)\r\n * for fields that intentionally allow those characters.\r\n */\r\n /[;&|`]/g,\r\n /** Command substitution: $( ... ) — matched as a pair to reduce false positives */\r\n /\\$\\(/g,\r\n] as const;\r\n\r\n// =============================================================================\r\n// DANGEROUS KEYS\r\n// =============================================================================\r\n\r\n/**\r\n * Prototype pollution keys to block.\r\n * Stored lowercase — always compare with key.toLowerCase().\r\n *\r\n * Includes:\r\n * - __proto__: direct prototype assignment\r\n * - constructor: access to constructor.prototype chain\r\n * - prototype: direct prototype property\r\n * - __defineGetter__/__defineSetter__: legacy property definition (can override getters/setters)\r\n * - __lookupGetter__/__lookupSetter__: legacy property introspection\r\n */\r\nexport const DANGEROUS_PROTO_KEYS = new Set([\r\n '__proto__',\r\n 'constructor',\r\n 'prototype',\r\n '__definegetter__',\r\n '__definesetter__',\r\n '__lookupgetter__',\r\n '__lookupsetter__',\r\n]);\r\n\r\n/** MongoDB operators to block */\r\nexport const NOSQL_DANGEROUS_KEYS = new Set([\r\n // Comparison\r\n '$gt', '$gte', '$lt', '$lte', '$ne', '$eq', '$in', '$nin',\r\n // Logical\r\n '$and', '$or', '$not', '$nor',\r\n // Element / evaluation\r\n '$exists', '$type', '$regex', '$where', '$expr', '$mod', '$text',\r\n // Array\r\n '$elemMatch', '$all', '$size',\r\n // JavaScript execution (critical)\r\n '$function', '$accumulator',\r\n // Aggregation pipeline operators (injectable via $lookup etc.)\r\n '$lookup', '$match', '$project', '$group', '$sort', '$limit', '$skip',\r\n '$unwind', '$addFields', '$replaceRoot',\r\n]);\r\n\r\n// =============================================================================\r\n// REDACTION\r\n// =============================================================================\r\nexport const REDACTION = {\r\n /** Replacement text for redacted values */\r\n REPLACEMENT: '[REDACTED]',\r\n /** Truncation indicator */\r\n TRUNCATED: '[TRUNCATED]',\r\n /** Max depth indicator */\r\n MAX_DEPTH: '[MAX_DEPTH]',\r\n /** Default max message length */\r\n DEFAULT_MAX_LENGTH: 10_000,\r\n /** Default sensitive keys to redact */\r\n SENSITIVE_KEYS: new Set([\r\n 'password', 'passwd', 'pwd', 'secret', 'token', 'apikey',\r\n 'api_key', 'apiKey', 'auth', 'authorization', 'credit_card',\r\n 'creditcard', 'cc', 'ssn', 'social_security', 'private_key',\r\n 'privateKey', 'access_token', 'accessToken', 'refresh_token',\r\n 'refreshToken', 'bearer', 'jwt', 'session', 'cookie',\r\n 'credentials', 'x-api-key', 'x-auth-token',\r\n ]),\r\n} as const;\r\n\r\n// =============================================================================\r\n// VALIDATION PATTERNS\r\n// =============================================================================\r\nexport const VALIDATION = {\r\n /**\r\n * Email regex pattern.\r\n * Rejects consecutive dots in local part (e.g. test..foo@example.com),\r\n * leading/trailing dots, and other common invalid forms.\r\n */\r\n EMAIL: /^[^\\s@.][^\\s@]*(?:\\.[^\\s@.][^\\s@]*)*@[^\\s@]+\\.[^\\s@]+$/,\r\n /**\r\n * URL regex pattern.\r\n * Only allows http:// and https:// — explicitly rejects javascript:,\r\n * data:, vbscript:, and other dangerous URI schemes.\r\n */\r\n URL: /^https?:\\/\\/[^\\s/$.?#][^\\s]*$/,\r\n /** UUID regex pattern (v4) */\r\n UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\r\n} as const;\r\n\r\n// =============================================================================\r\n// ERROR MESSAGES\r\n// =============================================================================\r\nexport const ERRORS = {\r\n /** Generic error message (production) */\r\n INTERNAL_SERVER_ERROR: 'Internal Server Error',\r\n /** Input too large error */\r\n INPUT_TOO_LARGE: (maxSize: number) => `Input exceeds maximum size of ${maxSize} bytes`,\r\n /** Validation error messages */\r\n VALIDATION: {\r\n REQUIRED: (field: string) => `${field} is required`,\r\n INVALID_TYPE: (field: string, type: string) => `${field} must be a ${type}`,\r\n MIN_LENGTH: (field: string, min: number) => `${field} must be at least ${min} characters`,\r\n MAX_LENGTH: (field: string, max: number) => `${field} must be at most ${max} characters`,\r\n MIN_VALUE: (field: string, min: number) => `${field} must be at least ${min}`,\r\n MAX_VALUE: (field: string, max: number) => `${field} must be at most ${max}`,\r\n INVALID_FORMAT: (field: string) => `${field} format is invalid`,\r\n INVALID_EMAIL: (field: string) => `${field} must be a valid email`,\r\n INVALID_URL: (field: string) => `${field} must be a valid URL`,\r\n INVALID_UUID: (field: string) => `${field} must be a valid UUID`,\r\n INVALID_ENUM: (field: string, values: unknown[]) => `${field} must be one of: ${values.join(', ')}`,\r\n MIN_ITEMS: (field: string, min: number) => `${field} must have at least ${min} items`,\r\n MAX_ITEMS: (field: string, max: number) => `${field} must have at most ${max} items`,\r\n },\r\n} as const;\r\n\r\n// =============================================================================\r\n// BLOCKED TEXT (for sanitizer replacements)\r\n// =============================================================================\r\nexport const BLOCKED = '[BLOCKED]' as const;\r\n","/**\r\n * @module @arcis/node/core/errors\r\n * Custom error classes for Arcis\r\n */\r\n\r\n/**\r\n * Base class for all Arcis errors\r\n */\r\nexport class ArcisError extends Error {\r\n public readonly statusCode: number;\r\n public readonly code: string;\r\n /** Whether the error message is safe to expose to API clients. */\r\n public readonly expose: boolean;\r\n\r\n constructor(message: string, statusCode = 500, code = 'ARCIS_ERROR') {\r\n super(message);\r\n this.name = 'ArcisError';\r\n this.statusCode = statusCode;\r\n this.code = code;\r\n // Client errors (4xx) have controlled messages — safe to expose.\r\n // Server errors (5xx) may contain internal details — hide by default.\r\n this.expose = statusCode < 500;\r\n\r\n // Maintains proper stack trace for where error was thrown (V8 engines)\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, this.constructor);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown when input validation fails\r\n */\r\nexport class ValidationError extends ArcisError {\r\n public readonly errors: string[];\r\n\r\n constructor(errors: string[]) {\r\n super('Validation failed', 400, 'VALIDATION_ERROR');\r\n this.name = 'ValidationError';\r\n this.errors = errors;\r\n }\r\n}\r\n\r\n/** Alias for ValidationError (backwards compatibility) */\r\nexport { ValidationError as ArcisValidationError };\r\n\r\n/**\r\n * Error thrown when rate limit is exceeded\r\n */\r\nexport class RateLimitError extends ArcisError {\r\n public readonly retryAfter: number;\r\n\r\n constructor(message: string, retryAfter: number) {\r\n super(message, 429, 'RATE_LIMIT_EXCEEDED');\r\n this.name = 'RateLimitError';\r\n this.retryAfter = retryAfter;\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown when input is too large\r\n */\r\nexport class InputTooLargeError extends ArcisError {\r\n public readonly maxSize: number;\r\n public readonly actualSize: number;\r\n\r\n constructor(maxSize: number, actualSize: number) {\r\n super(`Input exceeds maximum size of ${maxSize} bytes`, 413, 'INPUT_TOO_LARGE');\r\n this.name = 'InputTooLargeError';\r\n this.maxSize = maxSize;\r\n this.actualSize = actualSize;\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown when security threat is detected\r\n */\r\nexport class SecurityThreatError extends ArcisError {\r\n public readonly threatType: string;\r\n public readonly pattern: string;\r\n\r\n constructor(threatType: string, pattern: string) {\r\n super('Request blocked for security reasons', 400, 'SECURITY_THREAT');\r\n this.name = 'SecurityThreatError';\r\n this.threatType = threatType;\r\n this.pattern = pattern;\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown when sanitization fails\r\n */\r\nexport class SanitizationError extends ArcisError {\r\n constructor(message: string) {\r\n super(message, 400, 'SANITIZATION_ERROR');\r\n this.name = 'SanitizationError';\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
// src/core/constants.ts
|
|
2
|
+
var INPUT = {
|
|
3
|
+
/** Default maximum input size (1MB) */
|
|
4
|
+
DEFAULT_MAX_SIZE: 1e6,
|
|
5
|
+
/** Maximum recursion depth for nested objects */
|
|
6
|
+
MAX_RECURSION_DEPTH: 10
|
|
7
|
+
};
|
|
8
|
+
var RATE_LIMIT = {
|
|
9
|
+
/** Default window size (1 minute) */
|
|
10
|
+
DEFAULT_WINDOW_MS: 6e4,
|
|
11
|
+
/** Default max requests per window */
|
|
12
|
+
DEFAULT_MAX_REQUESTS: 100,
|
|
13
|
+
/** Default HTTP status code for rate limited responses */
|
|
14
|
+
DEFAULT_STATUS_CODE: 429,
|
|
15
|
+
/** Default error message */
|
|
16
|
+
DEFAULT_MESSAGE: "Too many requests, please try again later.",
|
|
17
|
+
/** Minimum window size (1 second) */
|
|
18
|
+
MIN_WINDOW_MS: 1e3,
|
|
19
|
+
/** Maximum window size (24 hours) */
|
|
20
|
+
MAX_WINDOW_MS: 864e5
|
|
21
|
+
};
|
|
22
|
+
var HEADERS = {
|
|
23
|
+
/** Default Content Security Policy */
|
|
24
|
+
DEFAULT_CSP: [
|
|
25
|
+
"default-src 'self'",
|
|
26
|
+
"script-src 'self'",
|
|
27
|
+
"style-src 'self' 'unsafe-inline'",
|
|
28
|
+
"img-src 'self' data: https:",
|
|
29
|
+
"font-src 'self'",
|
|
30
|
+
"object-src 'none'",
|
|
31
|
+
"frame-ancestors 'none'"
|
|
32
|
+
].join("; "),
|
|
33
|
+
/** Default HSTS max age (1 year in seconds) */
|
|
34
|
+
HSTS_MAX_AGE: 31536e3,
|
|
35
|
+
/** Default X-Frame-Options value */
|
|
36
|
+
FRAME_OPTIONS: "DENY",
|
|
37
|
+
/** Default X-Content-Type-Options value */
|
|
38
|
+
CONTENT_TYPE_OPTIONS: "nosniff",
|
|
39
|
+
/** Default Referrer-Policy value */
|
|
40
|
+
REFERRER_POLICY: "strict-origin-when-cross-origin",
|
|
41
|
+
/** Default Permissions-Policy value */
|
|
42
|
+
PERMISSIONS_POLICY: "geolocation=(), microphone=(), camera=()",
|
|
43
|
+
/** Default Cache-Control value for security */
|
|
44
|
+
CACHE_CONTROL: "no-store, no-cache, must-revalidate, proxy-revalidate"
|
|
45
|
+
};
|
|
46
|
+
var XSS_PATTERNS = [
|
|
47
|
+
/** Script tags (ReDoS-safe version) */
|
|
48
|
+
/<script[^>]*>[\s\S]*?<\/script>/gi,
|
|
49
|
+
/** javascript: protocol (allow optional spaces before colon) */
|
|
50
|
+
/javascript\s*:/gi,
|
|
51
|
+
/** vbscript: protocol */
|
|
52
|
+
/vbscript\s*:/gi,
|
|
53
|
+
/** Event handlers (onclick, onerror, etc.) — any separator before attribute */
|
|
54
|
+
/(?:[\s/])on\w+\s*=/gi,
|
|
55
|
+
/** iframe tags */
|
|
56
|
+
/<iframe/gi,
|
|
57
|
+
/** object tags */
|
|
58
|
+
/<object/gi,
|
|
59
|
+
/** embed tags */
|
|
60
|
+
/<embed/gi,
|
|
61
|
+
/** data: URIs (only dangerous ones, avoid false positives) */
|
|
62
|
+
/(?:^|[\s"'=])data:/gi,
|
|
63
|
+
/** URL-encoded script tags */
|
|
64
|
+
/%3Cscript/gi,
|
|
65
|
+
/** SVG with onload */
|
|
66
|
+
/<svg[^>]*onload/gi
|
|
67
|
+
];
|
|
68
|
+
var SQL_PATTERNS = [
|
|
69
|
+
/** SQL keywords */
|
|
70
|
+
/(\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)\b)/gi,
|
|
71
|
+
/** SQL comments: ANSI (--), C-style (slash-star ... star-slash), MySQL (#) */
|
|
72
|
+
/(--|\/\*|\*\/|#)/g,
|
|
73
|
+
/** SQL statement separators */
|
|
74
|
+
/(;|\|\||&&)/g,
|
|
75
|
+
/** Boolean injection: OR 1=1 */
|
|
76
|
+
/\bOR\s+\d+\s*=\s*\d+/gi,
|
|
77
|
+
/** Boolean injection: OR 'a'='a' or OR "a"="a" (including mixed quotes) */
|
|
78
|
+
/\bOR\s+(['"])[^'"]*\1\s*=\s*(['"])[^'"]*\2/gi,
|
|
79
|
+
/\bOR\s+('[^']*'|"[^"]*")\s*=\s*('[^']*'|"[^"]*")/gi,
|
|
80
|
+
/** Boolean injection: AND 1=1 */
|
|
81
|
+
/\bAND\s+\d+\s*=\s*\d+/gi,
|
|
82
|
+
/** Boolean injection: AND 'a'='a' or AND "a"="a" (including mixed quotes) */
|
|
83
|
+
/\bAND\s+(['"])[^'"]*\1\s*=\s*(['"])[^'"]*\2/gi,
|
|
84
|
+
/\bAND\s+('[^']*'|"[^"]*")\s*=\s*('[^']*'|"[^"]*")/gi,
|
|
85
|
+
/** Time-based blind: SLEEP() */
|
|
86
|
+
/\bSLEEP\s*\(\s*\d+\s*\)/gi,
|
|
87
|
+
/** Time-based blind: BENCHMARK() */
|
|
88
|
+
/\bBENCHMARK\s*\(/gi
|
|
89
|
+
];
|
|
90
|
+
var PATH_PATTERNS = [
|
|
91
|
+
/** Unix path traversal */
|
|
92
|
+
/\.\.\//g,
|
|
93
|
+
/** Windows path traversal */
|
|
94
|
+
/\.\.\\/g,
|
|
95
|
+
/** URL-encoded traversal (%2e%2e) */
|
|
96
|
+
/%2e%2e/gi,
|
|
97
|
+
/** Double URL-encoded traversal (%252e) */
|
|
98
|
+
/%252e/gi,
|
|
99
|
+
/** Mixed encoding: ..%2F */
|
|
100
|
+
/\.\.%2F/gi,
|
|
101
|
+
/** Mixed encoding: %2e./ and .%2e/ */
|
|
102
|
+
/%2e\.[\\/]/gi,
|
|
103
|
+
/\.%2e[\\/]/gi,
|
|
104
|
+
/** Fully URL-encoded: %2e%2e%2f */
|
|
105
|
+
/%2e%2e%2f/gi,
|
|
106
|
+
/** Null byte injection in paths */
|
|
107
|
+
/\0/g
|
|
108
|
+
];
|
|
109
|
+
var COMMAND_PATTERNS = [
|
|
110
|
+
/**
|
|
111
|
+
* Shell metacharacters that enable command chaining/substitution.
|
|
112
|
+
* Bare ( and ) are excluded — they appear in common legitimate values
|
|
113
|
+
* (function calls in code fields, math expressions, etc.).
|
|
114
|
+
* Command substitution is caught by the $( combined pattern below.
|
|
115
|
+
* NOTE: ';', '&', '|' may appear in legitimate URL query strings
|
|
116
|
+
* and Markdown; consider disabling command checking (command: false)
|
|
117
|
+
* for fields that intentionally allow those characters.
|
|
118
|
+
*/
|
|
119
|
+
/[;&|`]/g,
|
|
120
|
+
/** Command substitution: $( ... ) — matched as a pair to reduce false positives */
|
|
121
|
+
/\$\(/g
|
|
122
|
+
];
|
|
123
|
+
var DANGEROUS_PROTO_KEYS = /* @__PURE__ */ new Set([
|
|
124
|
+
"__proto__",
|
|
125
|
+
"constructor",
|
|
126
|
+
"prototype",
|
|
127
|
+
"__definegetter__",
|
|
128
|
+
"__definesetter__",
|
|
129
|
+
"__lookupgetter__",
|
|
130
|
+
"__lookupsetter__"
|
|
131
|
+
]);
|
|
132
|
+
var NOSQL_DANGEROUS_KEYS = /* @__PURE__ */ new Set([
|
|
133
|
+
// Comparison
|
|
134
|
+
"$gt",
|
|
135
|
+
"$gte",
|
|
136
|
+
"$lt",
|
|
137
|
+
"$lte",
|
|
138
|
+
"$ne",
|
|
139
|
+
"$eq",
|
|
140
|
+
"$in",
|
|
141
|
+
"$nin",
|
|
142
|
+
// Logical
|
|
143
|
+
"$and",
|
|
144
|
+
"$or",
|
|
145
|
+
"$not",
|
|
146
|
+
"$nor",
|
|
147
|
+
// Element / evaluation
|
|
148
|
+
"$exists",
|
|
149
|
+
"$type",
|
|
150
|
+
"$regex",
|
|
151
|
+
"$where",
|
|
152
|
+
"$expr",
|
|
153
|
+
"$mod",
|
|
154
|
+
"$text",
|
|
155
|
+
// Array
|
|
156
|
+
"$elemMatch",
|
|
157
|
+
"$all",
|
|
158
|
+
"$size",
|
|
159
|
+
// JavaScript execution (critical)
|
|
160
|
+
"$function",
|
|
161
|
+
"$accumulator",
|
|
162
|
+
// Aggregation pipeline operators (injectable via $lookup etc.)
|
|
163
|
+
"$lookup",
|
|
164
|
+
"$match",
|
|
165
|
+
"$project",
|
|
166
|
+
"$group",
|
|
167
|
+
"$sort",
|
|
168
|
+
"$limit",
|
|
169
|
+
"$skip",
|
|
170
|
+
"$unwind",
|
|
171
|
+
"$addFields",
|
|
172
|
+
"$replaceRoot"
|
|
173
|
+
]);
|
|
174
|
+
var REDACTION = {
|
|
175
|
+
/** Replacement text for redacted values */
|
|
176
|
+
REPLACEMENT: "[REDACTED]",
|
|
177
|
+
/** Truncation indicator */
|
|
178
|
+
TRUNCATED: "[TRUNCATED]",
|
|
179
|
+
/** Max depth indicator */
|
|
180
|
+
MAX_DEPTH: "[MAX_DEPTH]",
|
|
181
|
+
/** Default max message length */
|
|
182
|
+
DEFAULT_MAX_LENGTH: 1e4,
|
|
183
|
+
/** Default sensitive keys to redact */
|
|
184
|
+
SENSITIVE_KEYS: /* @__PURE__ */ new Set([
|
|
185
|
+
"password",
|
|
186
|
+
"passwd",
|
|
187
|
+
"pwd",
|
|
188
|
+
"secret",
|
|
189
|
+
"token",
|
|
190
|
+
"apikey",
|
|
191
|
+
"api_key",
|
|
192
|
+
"apiKey",
|
|
193
|
+
"auth",
|
|
194
|
+
"authorization",
|
|
195
|
+
"credit_card",
|
|
196
|
+
"creditcard",
|
|
197
|
+
"cc",
|
|
198
|
+
"ssn",
|
|
199
|
+
"social_security",
|
|
200
|
+
"private_key",
|
|
201
|
+
"privateKey",
|
|
202
|
+
"access_token",
|
|
203
|
+
"accessToken",
|
|
204
|
+
"refresh_token",
|
|
205
|
+
"refreshToken",
|
|
206
|
+
"bearer",
|
|
207
|
+
"jwt",
|
|
208
|
+
"session",
|
|
209
|
+
"cookie",
|
|
210
|
+
"credentials",
|
|
211
|
+
"x-api-key",
|
|
212
|
+
"x-auth-token"
|
|
213
|
+
])
|
|
214
|
+
};
|
|
215
|
+
var VALIDATION = {
|
|
216
|
+
/**
|
|
217
|
+
* Email regex pattern.
|
|
218
|
+
* Rejects consecutive dots in local part (e.g. test..foo@example.com),
|
|
219
|
+
* leading/trailing dots, and other common invalid forms.
|
|
220
|
+
*/
|
|
221
|
+
EMAIL: /^[^\s@.][^\s@]*(?:\.[^\s@.][^\s@]*)*@[^\s@]+\.[^\s@]+$/,
|
|
222
|
+
/**
|
|
223
|
+
* URL regex pattern.
|
|
224
|
+
* Only allows http:// and https:// — explicitly rejects javascript:,
|
|
225
|
+
* data:, vbscript:, and other dangerous URI schemes.
|
|
226
|
+
*/
|
|
227
|
+
URL: /^https?:\/\/[^\s/$.?#][^\s]*$/,
|
|
228
|
+
/** UUID regex pattern (v4) */
|
|
229
|
+
UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
230
|
+
};
|
|
231
|
+
var ERRORS = {
|
|
232
|
+
/** Generic error message (production) */
|
|
233
|
+
INTERNAL_SERVER_ERROR: "Internal Server Error",
|
|
234
|
+
/** Input too large error */
|
|
235
|
+
INPUT_TOO_LARGE: (maxSize) => `Input exceeds maximum size of ${maxSize} bytes`,
|
|
236
|
+
/** Validation error messages */
|
|
237
|
+
VALIDATION: {
|
|
238
|
+
REQUIRED: (field) => `${field} is required`,
|
|
239
|
+
INVALID_TYPE: (field, type) => `${field} must be a ${type}`,
|
|
240
|
+
MIN_LENGTH: (field, min) => `${field} must be at least ${min} characters`,
|
|
241
|
+
MAX_LENGTH: (field, max) => `${field} must be at most ${max} characters`,
|
|
242
|
+
MIN_VALUE: (field, min) => `${field} must be at least ${min}`,
|
|
243
|
+
MAX_VALUE: (field, max) => `${field} must be at most ${max}`,
|
|
244
|
+
INVALID_FORMAT: (field) => `${field} format is invalid`,
|
|
245
|
+
INVALID_EMAIL: (field) => `${field} must be a valid email`,
|
|
246
|
+
INVALID_URL: (field) => `${field} must be a valid URL`,
|
|
247
|
+
INVALID_UUID: (field) => `${field} must be a valid UUID`,
|
|
248
|
+
INVALID_ENUM: (field, values) => `${field} must be one of: ${values.join(", ")}`,
|
|
249
|
+
MIN_ITEMS: (field, min) => `${field} must have at least ${min} items`,
|
|
250
|
+
MAX_ITEMS: (field, max) => `${field} must have at most ${max} items`
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
var BLOCKED = "[BLOCKED]";
|
|
254
|
+
|
|
255
|
+
// src/core/errors.ts
|
|
256
|
+
var ArcisError = class extends Error {
|
|
257
|
+
constructor(message, statusCode = 500, code = "ARCIS_ERROR") {
|
|
258
|
+
super(message);
|
|
259
|
+
this.name = "ArcisError";
|
|
260
|
+
this.statusCode = statusCode;
|
|
261
|
+
this.code = code;
|
|
262
|
+
this.expose = statusCode < 500;
|
|
263
|
+
if (Error.captureStackTrace) {
|
|
264
|
+
Error.captureStackTrace(this, this.constructor);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
var ValidationError = class extends ArcisError {
|
|
269
|
+
constructor(errors) {
|
|
270
|
+
super("Validation failed", 400, "VALIDATION_ERROR");
|
|
271
|
+
this.name = "ValidationError";
|
|
272
|
+
this.errors = errors;
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
var RateLimitError = class extends ArcisError {
|
|
276
|
+
constructor(message, retryAfter) {
|
|
277
|
+
super(message, 429, "RATE_LIMIT_EXCEEDED");
|
|
278
|
+
this.name = "RateLimitError";
|
|
279
|
+
this.retryAfter = retryAfter;
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
var InputTooLargeError = class extends ArcisError {
|
|
283
|
+
constructor(maxSize, actualSize) {
|
|
284
|
+
super(`Input exceeds maximum size of ${maxSize} bytes`, 413, "INPUT_TOO_LARGE");
|
|
285
|
+
this.name = "InputTooLargeError";
|
|
286
|
+
this.maxSize = maxSize;
|
|
287
|
+
this.actualSize = actualSize;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
var SecurityThreatError = class extends ArcisError {
|
|
291
|
+
constructor(threatType, pattern) {
|
|
292
|
+
super("Request blocked for security reasons", 400, "SECURITY_THREAT");
|
|
293
|
+
this.name = "SecurityThreatError";
|
|
294
|
+
this.threatType = threatType;
|
|
295
|
+
this.pattern = pattern;
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
var SanitizationError = class extends ArcisError {
|
|
299
|
+
constructor(message) {
|
|
300
|
+
super(message, 400, "SANITIZATION_ERROR");
|
|
301
|
+
this.name = "SanitizationError";
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
export { ArcisError, ValidationError as ArcisValidationError, BLOCKED, COMMAND_PATTERNS, DANGEROUS_PROTO_KEYS, ERRORS, HEADERS, INPUT, InputTooLargeError, NOSQL_DANGEROUS_KEYS, PATH_PATTERNS, RATE_LIMIT, REDACTION, RateLimitError, SQL_PATTERNS, SanitizationError, SecurityThreatError, VALIDATION, XSS_PATTERNS };
|
|
306
|
+
//# sourceMappingURL=index.mjs.map
|
|
307
|
+
//# sourceMappingURL=index.mjs.map
|