@arcis/node 1.2.0 → 1.4.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.
Files changed (122) hide show
  1. package/dist/core/{index.d.mts → constants.d.ts} +21 -70
  2. package/dist/core/constants.d.ts.map +1 -0
  3. package/dist/core/errors.d.ts +53 -0
  4. package/dist/core/errors.d.ts.map +1 -0
  5. package/dist/core/index.d.ts +6 -168
  6. package/dist/core/index.d.ts.map +1 -0
  7. package/dist/{types-CsOFHoD9.d.mts → core/types.d.ts} +38 -31
  8. package/dist/core/types.d.ts.map +1 -0
  9. package/dist/index.d.ts +71 -166
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +151 -4
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +145 -5
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/logging/index.d.ts +4 -36
  16. package/dist/logging/index.d.ts.map +1 -0
  17. package/dist/logging/{index.d.mts → redactor.d.ts} +5 -9
  18. package/dist/logging/redactor.d.ts.map +1 -0
  19. package/dist/middleware/bot-detection.d.ts +86 -0
  20. package/dist/middleware/bot-detection.d.ts.map +1 -0
  21. package/dist/middleware/cookies.d.ts +48 -0
  22. package/dist/middleware/cookies.d.ts.map +1 -0
  23. package/dist/middleware/cors.d.ts +65 -0
  24. package/dist/middleware/cors.d.ts.map +1 -0
  25. package/dist/middleware/csrf.d.ts +109 -0
  26. package/dist/middleware/csrf.d.ts.map +1 -0
  27. package/dist/middleware/error-handler.d.ts +43 -0
  28. package/dist/middleware/error-handler.d.ts.map +1 -0
  29. package/dist/middleware/headers.d.ts +29 -0
  30. package/dist/middleware/headers.d.ts.map +1 -0
  31. package/dist/middleware/hpp.d.ts +56 -0
  32. package/dist/middleware/hpp.d.ts.map +1 -0
  33. package/dist/middleware/index.d.ts +16 -3
  34. package/dist/middleware/index.d.ts.map +1 -0
  35. package/dist/middleware/index.js +28 -3
  36. package/dist/middleware/index.js.map +1 -1
  37. package/dist/middleware/index.mjs +28 -3
  38. package/dist/middleware/index.mjs.map +1 -1
  39. package/dist/middleware/main.d.ts +40 -0
  40. package/dist/middleware/main.d.ts.map +1 -0
  41. package/dist/middleware/rate-limit-sliding.d.ts +46 -0
  42. package/dist/middleware/rate-limit-sliding.d.ts.map +1 -0
  43. package/dist/middleware/rate-limit-token.d.ts +51 -0
  44. package/dist/middleware/rate-limit-token.d.ts.map +1 -0
  45. package/dist/middleware/rate-limit.d.ts +34 -0
  46. package/dist/middleware/rate-limit.d.ts.map +1 -0
  47. package/dist/sanitizers/command.d.ts +28 -0
  48. package/dist/sanitizers/command.d.ts.map +1 -0
  49. package/dist/sanitizers/encode.d.ts +46 -0
  50. package/dist/sanitizers/encode.d.ts.map +1 -0
  51. package/dist/sanitizers/headers.d.ts +46 -0
  52. package/dist/sanitizers/headers.d.ts.map +1 -0
  53. package/dist/sanitizers/index.d.ts +17 -22
  54. package/dist/sanitizers/index.d.ts.map +1 -0
  55. package/dist/sanitizers/index.js +72 -0
  56. package/dist/sanitizers/index.js.map +1 -1
  57. package/dist/sanitizers/index.mjs +68 -1
  58. package/dist/sanitizers/index.mjs.map +1 -1
  59. package/dist/sanitizers/jsonp.d.ts +34 -0
  60. package/dist/sanitizers/jsonp.d.ts.map +1 -0
  61. package/dist/sanitizers/nosql.d.ts +31 -0
  62. package/dist/sanitizers/nosql.d.ts.map +1 -0
  63. package/dist/sanitizers/path.d.ts +28 -0
  64. package/dist/sanitizers/path.d.ts.map +1 -0
  65. package/dist/sanitizers/pii.d.ts +80 -0
  66. package/dist/sanitizers/pii.d.ts.map +1 -0
  67. package/dist/sanitizers/prototype.d.ts +34 -0
  68. package/dist/sanitizers/prototype.d.ts.map +1 -0
  69. package/dist/sanitizers/sanitize.d.ts +51 -0
  70. package/dist/sanitizers/sanitize.d.ts.map +1 -0
  71. package/dist/sanitizers/sql.d.ts +28 -0
  72. package/dist/sanitizers/sql.d.ts.map +1 -0
  73. package/dist/sanitizers/ssti.d.ts +20 -0
  74. package/dist/sanitizers/ssti.d.ts.map +1 -0
  75. package/dist/sanitizers/utils.d.ts +19 -0
  76. package/dist/sanitizers/utils.d.ts.map +1 -0
  77. package/dist/sanitizers/xss.d.ts +35 -0
  78. package/dist/sanitizers/xss.d.ts.map +1 -0
  79. package/dist/sanitizers/xxe.d.ts +20 -0
  80. package/dist/sanitizers/xxe.d.ts.map +1 -0
  81. package/dist/stores/index.d.ts +6 -104
  82. package/dist/stores/index.d.ts.map +1 -0
  83. package/dist/stores/memory.d.ts +35 -0
  84. package/dist/stores/memory.d.ts.map +1 -0
  85. package/dist/stores/{index.d.mts → redis.d.ts} +6 -45
  86. package/dist/stores/redis.d.ts.map +1 -0
  87. package/dist/utils/duration.d.ts +34 -0
  88. package/dist/utils/duration.d.ts.map +1 -0
  89. package/dist/utils/fingerprint.d.ts +64 -0
  90. package/dist/utils/fingerprint.d.ts.map +1 -0
  91. package/dist/utils/index.d.ts +10 -0
  92. package/dist/utils/index.d.ts.map +1 -0
  93. package/dist/utils/index.js +188 -0
  94. package/dist/utils/index.js.map +1 -0
  95. package/dist/utils/index.mjs +182 -0
  96. package/dist/utils/index.mjs.map +1 -0
  97. package/dist/utils/ip.d.ts +70 -0
  98. package/dist/utils/ip.d.ts.map +1 -0
  99. package/dist/validation/email.d.ts +82 -0
  100. package/dist/validation/email.d.ts.map +1 -0
  101. package/dist/validation/file.d.ts +90 -0
  102. package/dist/validation/file.d.ts.map +1 -0
  103. package/dist/validation/index.d.ts +10 -3
  104. package/dist/validation/index.d.ts.map +1 -0
  105. package/dist/validation/redirect.d.ts +64 -0
  106. package/dist/validation/redirect.d.ts.map +1 -0
  107. package/dist/validation/schema.d.ts +36 -0
  108. package/dist/validation/schema.d.ts.map +1 -0
  109. package/dist/validation/url.d.ts +65 -0
  110. package/dist/validation/url.d.ts.map +1 -0
  111. package/package.json +8 -6
  112. package/dist/index-A-m-pPeW.d.mts +0 -340
  113. package/dist/index-CgK94hY_.d.mts +0 -532
  114. package/dist/index-Co5kPRZz.d.ts +0 -340
  115. package/dist/index-D_bdJcF0.d.ts +0 -532
  116. package/dist/index.d.mts +0 -175
  117. package/dist/middleware/index.d.mts +0 -3
  118. package/dist/pii-CXcHMlnX.d.mts +0 -438
  119. package/dist/pii-DhNpl7M3.d.ts +0 -438
  120. package/dist/sanitizers/index.d.mts +0 -24
  121. package/dist/types-CsOFHoD9.d.ts +0 -269
  122. package/dist/validation/index.d.mts +0 -3
package/dist/index.d.ts CHANGED
@@ -1,175 +1,80 @@
1
- export { B as BotCategory, a as BotDetectionResult, b as BotProtectionOptions, C as CorsOptions, c as CsrfOptions, S as SecureCookieOptions, d as SlidingWindowMiddleware, e as SlidingWindowOptions, T as TokenBucketMiddleware, f as TokenBucketOptions, g as arcis, h as arcisFunction, i as botProtection, j as createCors, k as createCsrf, l as createErrorHandler, m as createHeaders, n as createRateLimiter, o as createSecureCookies, p as createSlidingWindowLimiter, q as createTokenBucketLimiter, r as csrfProtection, h as default, s as detectBot, t as enforceSecureCookie, u as errorHandler, v as generateCsrfToken, w as rateLimit, x as safeCors, y as secureCookieDefaults, z as securityHeaders, A as validateCsrfToken } from './index-D_bdJcF0.js';
2
- export { P as PiiMatch, F as PiiRedactOptions, G as PiiScanOptions, H as PiiType, c as createSanitizer, d as detectCommandInjection, a as detectHeaderInjection, b as detectJsonpInjection, e as detectNoSqlInjection, f as detectPathTraversal, g as detectPii, h as detectPrototypePollution, i as detectSql, j as detectSsti, k as detectXss, l as detectXxe, o as isDangerousNoSqlKey, p as isDangerousProtoKey, r as redactObjectPii, q as redactPii, s as sanitizeCommand, t as sanitizeHeaderValue, u as sanitizeHeaders, v as sanitizeJsonpCallback, w as sanitizeObject, x as sanitizePath, y as sanitizeSql, z as sanitizeSsti, A as sanitizeString, B as sanitizeXss, C as sanitizeXxe, D as scanObjectPii, E as scanPii } from './pii-DhNpl7M3.js';
3
- export { E as EmailValidationOptions, a as EmailValidationResult, F as FileInput, V as ValidateFileOptions, b as ValidateFileResult, c as ValidateRedirectOptions, d as ValidateRedirectResult, e as ValidateUrlOptions, f as ValidateUrlResult, g as createValidator, i as isDangerousExtension, h as isRedirectSafe, j as isUrlSafe, k as isValidEmailSyntax, s as sanitizeFilename, v as validate, l as validateEmail, m as validateFile, n as validateRedirect, o as validateUrl, p as verifyEmailMx } from './index-Co5kPRZz.js';
4
- import { IncomingMessage } from 'http';
5
- export { createRedactor, createSafeLogger, safeLog } from './logging/index.js';
6
- export { MemoryStore, RedisClientLike, RedisStore, RedisStoreOptions, createRedisStore } from './stores/index.js';
7
- export { A as ArcisFunction, a as ArcisMiddleware, b as ArcisOptions, E as ErrorHandlerOptions, F as FieldValidator, H as HeaderOptions, c as HstsOptions, d as HttpError, L as LogOptions, R as RateLimitEntry, e as RateLimitOptions, f as RateLimitResult, g as RateLimitStore, h as RateLimiterMiddleware, S as SafeLogger, i as SanitizeOptions, j as SanitizeResult, T as ThreatInfo, k as ThreatType, V as ValidationConfig, l as ValidationError, m as ValidationResult, n as ValidationSchema } from './types-CsOFHoD9.js';
8
- export { ArcisError, ArcisValidationError, BLOCKED, ERRORS, HEADERS, INPUT, InputTooLargeError, RATE_LIMIT, REDACTION, RateLimitError, SanitizationError, SecurityThreatError, VALIDATION } from './core/index.js';
9
- import 'express';
10
-
11
1
  /**
12
- * @module @arcis/node/utils/duration
13
- * Parse human-readable duration strings into milliseconds.
2
+ * Arcis - One-line security for Node.js apps
3
+ * A cross-platform security library
14
4
  *
15
- * Supports: ms, s, m, h, d
5
+ * @module @arcis/node
6
+ * @version 1.0.0
16
7
  *
17
8
  * @example
18
- * parseDuration('5m') // 300000
19
- * parseDuration('2h') // 7200000
20
- * parseDuration(60000) // 60000 (passthrough)
21
- * parseDuration('500ms') // 500
22
- */
23
- /**
24
- * Parse a duration string or number into milliseconds.
25
- *
26
- * @param value - Duration string (e.g. "5m", "2h", "30s") or number (ms)
27
- * @returns Duration in milliseconds
28
- * @throws {Error} If the value is not a valid duration
29
- *
30
- * @example
31
- * parseDuration('15m') // 900000
32
- * parseDuration('1d') // 86400000
33
- * parseDuration('500ms') // 500
34
- * parseDuration(60000) // 60000
35
- */
36
- declare function parseDuration(value: string | number): number;
37
- /**
38
- * Format milliseconds into a human-readable duration string.
39
- *
40
- * @param ms - Duration in milliseconds
41
- * @returns Human-readable string (e.g. "5m", "2h 30m")
42
- */
43
- declare function formatDuration(ms: number): string;
44
-
45
- /**
46
- * @module @arcis/node/utils/ip
47
- * Platform-aware client IP detection.
48
- *
49
- * Prevents IP spoofing by reading platform-specific headers
50
- * instead of blindly trusting X-Forwarded-For.
51
- *
52
- * @example
53
- * // Auto-detect platform from environment
54
- * const ip = detectClientIp(req);
55
- *
56
- * // Explicit platform
57
- * const ip = detectClientIp(req, { platform: 'cloudflare' });
58
- */
59
-
60
- type Platform = 'auto' | 'cloudflare' | 'vercel' | 'flyio' | 'render' | 'firebase' | 'aws-alb' | 'generic';
61
- interface DetectIpOptions {
62
- /** Platform to use for header selection. Default: 'auto' */
63
- platform?: Platform;
64
- /** Number of trusted proxies (for X-Forwarded-For parsing). Default: 1 */
65
- trustedProxyCount?: number;
66
- }
67
- interface RequestLike$1 {
68
- headers: Record<string, string | string[] | undefined>;
69
- socket?: {
70
- remoteAddress?: string;
71
- };
72
- connection?: {
73
- remoteAddress?: string;
74
- };
75
- ip?: string;
76
- }
77
- /**
78
- * Detect the real client IP address from a request.
79
- *
80
- * Uses platform-specific headers when available to prevent IP spoofing.
81
- * Falls back to X-Forwarded-For (parsed from the right) and then
82
- * the socket remote address.
83
- *
84
- * @param req - HTTP request object (Express, raw http, etc.)
85
- * @param options - Detection options
86
- * @returns Client IP address, or 'unknown' if unresolvable
87
- *
88
- * @example
89
- * // Auto-detect platform
90
- * app.use((req, res, next) => {
91
- * const clientIp = detectClientIp(req);
92
- * console.log('Client IP:', clientIp);
93
- * next();
94
- * });
95
- *
96
- * @example
97
- * // Behind Cloudflare
98
- * const ip = detectClientIp(req, { platform: 'cloudflare' });
99
- *
100
- * @example
101
- * // Behind 2 proxies (e.g. CDN + load balancer)
102
- * const ip = detectClientIp(req, { trustedProxyCount: 2 });
103
- */
104
- declare function detectClientIp(req: RequestLike$1 | IncomingMessage, options?: DetectIpOptions): string;
105
- /**
106
- * Check if an IP address is a private/internal address.
107
- *
108
- * Detects: loopback, private ranges (RFC 1918), link-local, IPv6 equivalents.
109
- */
110
- declare function isPrivateIp(ip: string): boolean;
111
-
112
- /**
113
- * @module @arcis/node/utils/fingerprint
114
- * Deterministic request fingerprinting via SHA-256.
115
- *
116
- * Generates a stable hash from request characteristics for
117
- * rate limiting keys, abuse detection, and analytics.
118
- *
119
- * @example
120
- * const fp = await fingerprint(req);
121
- * // "a3f2b8c1d4e5..."
122
- */
123
-
124
- interface FingerprintOptions {
125
- /** Include IP address in fingerprint. Default: true */
126
- ip?: boolean;
127
- /** Include User-Agent header. Default: true */
128
- userAgent?: boolean;
129
- /** Include Accept header. Default: true */
130
- accept?: boolean;
131
- /** Include Accept-Language header. Default: true */
132
- acceptLanguage?: boolean;
133
- /** Include Accept-Encoding header. Default: true */
134
- acceptEncoding?: boolean;
135
- /** Additional custom components to include */
136
- custom?: string[];
137
- /** IP detection options */
138
- ipOptions?: DetectIpOptions;
139
- }
140
- interface RequestLike {
141
- headers: Record<string, string | string[] | undefined>;
142
- socket?: {
143
- remoteAddress?: string;
144
- };
145
- connection?: {
146
- remoteAddress?: string;
147
- };
148
- ip?: string;
149
- }
150
- /**
151
- * Generate a deterministic fingerprint for a request.
152
- *
153
- * Creates a SHA-256 hash from configurable request components.
154
- * The fingerprint is stable across requests from the same client
155
- * (same IP, browser, language settings).
156
- *
157
- * @param req - HTTP request object
158
- * @param options - Fingerprint configuration
159
- * @returns Hex-encoded SHA-256 hash (64 characters)
160
- *
161
- * @example
162
- * // Default fingerprint (IP + UA + Accept headers)
163
- * const fp = fingerprint(req);
9
+ * // Full protection (recommended)
10
+ * import { arcis } from '@arcis/node';
11
+ * app.use(arcis());
164
12
  *
165
13
  * @example
166
- * // IP-only fingerprint (for simple rate limiting)
167
- * const fp = fingerprint(req, { userAgent: false, accept: false, acceptLanguage: false, acceptEncoding: false });
14
+ * // Granular control
15
+ * app.use(arcis.headers());
16
+ * app.use(arcis.rateLimit({ max: 100, windowMs: 60000 }));
17
+ * app.use(arcis.sanitize());
168
18
  *
169
19
  * @example
170
- * // With custom components
171
- * const fp = fingerprint(req, { custom: [req.body?.userId] });
20
+ * // With validation
21
+ * app.post('/users', arcis.validate({
22
+ * email: { type: 'email', required: true },
23
+ * age: { type: 'number', min: 0, max: 150 }
24
+ * }), handler);
172
25
  */
173
- declare function fingerprint(req: RequestLike, options?: FingerprintOptions): string;
174
-
175
- export { type DetectIpOptions, type FingerprintOptions, type Platform, detectClientIp, fingerprint, formatDuration, isPrivateIp, parseDuration };
26
+ export { arcis, arcisFunction } from './middleware/main';
27
+ export { default } from './middleware/main';
28
+ export { createRateLimiter, rateLimit } from './middleware/rate-limit';
29
+ export { createSlidingWindowLimiter } from './middleware/rate-limit-sliding';
30
+ export { createTokenBucketLimiter } from './middleware/rate-limit-token';
31
+ export { createHeaders, securityHeaders } from './middleware/headers';
32
+ export { errorHandler, createErrorHandler } from './middleware/error-handler';
33
+ export { safeCors, createCors } from './middleware/cors';
34
+ export { secureCookieDefaults, createSecureCookies, enforceSecureCookie } from './middleware/cookies';
35
+ export { botProtection, detectBot } from './middleware/bot-detection';
36
+ export { csrfProtection, createCsrf, generateCsrfToken, validateCsrfToken } from './middleware/csrf';
37
+ export { hpp, createHpp } from './middleware/hpp';
38
+ export { sanitizeString, sanitizeObject, createSanitizer, } from './sanitizers/sanitize';
39
+ export { sanitizeXss, detectXss } from './sanitizers/xss';
40
+ export { sanitizeSql, detectSql } from './sanitizers/sql';
41
+ export { sanitizePath, detectPathTraversal } from './sanitizers/path';
42
+ export { sanitizeCommand, detectCommandInjection } from './sanitizers/command';
43
+ export { sanitizeSsti, detectSsti } from './sanitizers/ssti';
44
+ export { sanitizeXxe, detectXxe } from './sanitizers/xxe';
45
+ export { sanitizeJsonpCallback, detectJsonpInjection } from './sanitizers/jsonp';
46
+ export { isDangerousNoSqlKey, detectNoSqlInjection } from './sanitizers/nosql';
47
+ export { isDangerousProtoKey, detectPrototypePollution } from './sanitizers/prototype';
48
+ export { sanitizeHeaderValue, sanitizeHeaders, detectHeaderInjection } from './sanitizers/headers';
49
+ export { scanPii, detectPii, redactPii, scanObjectPii, redactObjectPii } from './sanitizers/pii';
50
+ export { encodeForHtml, encodeForAttribute, encodeForJs, encodeForUrl, encodeForCss } from './sanitizers/encode';
51
+ export { validate, createValidator } from './validation/schema';
52
+ export { validateUrl, isUrlSafe } from './validation/url';
53
+ export { validateRedirect, isRedirectSafe } from './validation/redirect';
54
+ export { validateFile, sanitizeFilename, isDangerousExtension } from './validation/file';
55
+ export { validateEmail, verifyEmailMx, isValidEmailSyntax } from './validation/email';
56
+ export { parseDuration, formatDuration } from './utils/duration';
57
+ export { detectClientIp, isPrivateIp } from './utils/ip';
58
+ export { fingerprint } from './utils/fingerprint';
59
+ export { createSafeLogger, createRedactor, safeLog } from './logging/redactor';
60
+ export { MemoryStore } from './stores/memory';
61
+ export { RedisStore, createRedisStore } from './stores/redis';
62
+ export type { ArcisOptions, ArcisFunction, ArcisMiddleware, SanitizeOptions, SanitizeResult, ThreatInfo, ThreatType, RateLimitOptions, RateLimitStore, RateLimitEntry, RateLimitResult, RateLimiterMiddleware, HeaderOptions, HstsOptions, ValidationConfig, ValidationSchema, FieldValidator, ValidationResult, ValidationError, LogOptions, SafeLogger, ErrorHandlerOptions, HttpError, } from './core/types';
63
+ export type { ValidateUrlOptions, ValidateUrlResult } from './validation/url';
64
+ export type { CorsOptions } from './middleware/cors';
65
+ export type { SecureCookieOptions } from './middleware/cookies';
66
+ export type { ValidateFileOptions, FileInput, ValidateFileResult } from './validation/file';
67
+ export type { ValidateRedirectOptions, ValidateRedirectResult } from './validation/redirect';
68
+ export type { RedisClientLike, RedisStoreOptions } from './stores/redis';
69
+ export type { Platform, DetectIpOptions } from './utils/ip';
70
+ export type { FingerprintOptions } from './utils/fingerprint';
71
+ export type { EmailValidationOptions, EmailValidationResult } from './validation/email';
72
+ export type { SlidingWindowOptions, SlidingWindowMiddleware } from './middleware/rate-limit-sliding';
73
+ export type { TokenBucketOptions, TokenBucketMiddleware } from './middleware/rate-limit-token';
74
+ export type { BotCategory, BotDetectionResult, BotProtectionOptions } from './middleware/bot-detection';
75
+ export type { CsrfOptions } from './middleware/csrf';
76
+ export type { HppOptions } from './middleware/hpp';
77
+ export type { PiiType, PiiMatch, PiiScanOptions, PiiRedactOptions } from './sanitizers/pii';
78
+ export { ArcisError, ArcisValidationError, RateLimitError, InputTooLargeError, SecurityThreatError, SanitizationError, } from './core/errors';
79
+ export { INPUT, RATE_LIMIT, HEADERS, REDACTION, VALIDATION, ERRORS, BLOCKED, } from './core/constants';
80
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -307,7 +307,12 @@ function createHeaders(options = {}) {
307
307
  hsts = true,
308
308
  referrerPolicy = HEADERS.REFERRER_POLICY,
309
309
  permissionsPolicy = HEADERS.PERMISSIONS_POLICY,
310
- cacheControl = true
310
+ cacheControl = true,
311
+ crossOriginOpenerPolicy = "same-origin",
312
+ crossOriginResourcePolicy = "same-origin",
313
+ crossOriginEmbedderPolicy = "require-corp",
314
+ originAgentCluster = true,
315
+ dnsPrefetchControl = true
311
316
  } = options;
312
317
  return (req, res, next) => {
313
318
  if (contentSecurityPolicy) {
@@ -315,7 +320,7 @@ function createHeaders(options = {}) {
315
320
  res.setHeader("Content-Security-Policy", csp);
316
321
  }
317
322
  if (xssFilter) {
318
- res.setHeader("X-XSS-Protection", "1; mode=block");
323
+ res.setHeader("X-XSS-Protection", "0");
319
324
  }
320
325
  if (noSniff) {
321
326
  res.setHeader("X-Content-Type-Options", HEADERS.CONTENT_TYPE_OPTIONS);
@@ -342,6 +347,21 @@ function createHeaders(options = {}) {
342
347
  if (permissionsPolicy) {
343
348
  res.setHeader("Permissions-Policy", permissionsPolicy);
344
349
  }
350
+ if (crossOriginOpenerPolicy) {
351
+ res.setHeader("Cross-Origin-Opener-Policy", crossOriginOpenerPolicy);
352
+ }
353
+ if (crossOriginResourcePolicy) {
354
+ res.setHeader("Cross-Origin-Resource-Policy", crossOriginResourcePolicy);
355
+ }
356
+ if (crossOriginEmbedderPolicy) {
357
+ res.setHeader("Cross-Origin-Embedder-Policy", crossOriginEmbedderPolicy);
358
+ }
359
+ if (originAgentCluster) {
360
+ res.setHeader("Origin-Agent-Cluster", "?1");
361
+ }
362
+ if (dnsPrefetchControl) {
363
+ res.setHeader("X-DNS-Prefetch-Control", "off");
364
+ }
345
365
  res.setHeader("X-Permitted-Cross-Domain-Policies", "none");
346
366
  if (cacheControl) {
347
367
  const cacheControlValue = typeof cacheControl === "string" ? cacheControl : HEADERS.CACHE_CONTROL;
@@ -1249,6 +1269,73 @@ function redactObjectPii(obj, options = {}) {
1249
1269
  return result;
1250
1270
  }
1251
1271
 
1272
+ // src/sanitizers/encode.ts
1273
+ var HTML_ENTITIES = {
1274
+ "&": "&amp;",
1275
+ "<": "&lt;",
1276
+ ">": "&gt;",
1277
+ '"': "&quot;",
1278
+ "'": "&#x27;"
1279
+ };
1280
+ var HTML_ENCODE_RE = /[&<>"']/g;
1281
+ function encodeForHtml(value) {
1282
+ if (!value) return "";
1283
+ return value.replace(HTML_ENCODE_RE, (ch) => HTML_ENTITIES[ch]);
1284
+ }
1285
+ function encodeForAttribute(value) {
1286
+ if (!value) return "";
1287
+ let result = "";
1288
+ for (let i = 0; i < value.length; i++) {
1289
+ const ch = value.charCodeAt(i);
1290
+ if (ch >= 48 && ch <= 57 || // 0-9
1291
+ ch >= 65 && ch <= 90 || // A-Z
1292
+ ch >= 97 && ch <= 122) {
1293
+ result += value[i];
1294
+ } else {
1295
+ result += `&#x${ch.toString(16).toUpperCase()};`;
1296
+ }
1297
+ }
1298
+ return result;
1299
+ }
1300
+ function encodeForJs(value) {
1301
+ if (!value) return "";
1302
+ let result = "";
1303
+ for (let i = 0; i < value.length; i++) {
1304
+ const ch = value.charCodeAt(i);
1305
+ if (ch >= 48 && ch <= 57 || // 0-9
1306
+ ch >= 65 && ch <= 90 || // A-Z
1307
+ ch >= 97 && ch <= 122) {
1308
+ result += value[i];
1309
+ } else if (ch < 256) {
1310
+ result += `\\x${ch.toString(16).toUpperCase().padStart(2, "0")}`;
1311
+ } else {
1312
+ result += `\\u${ch.toString(16).toUpperCase().padStart(4, "0")}`;
1313
+ }
1314
+ }
1315
+ return result;
1316
+ }
1317
+ function encodeForUrl(value) {
1318
+ if (!value) return "";
1319
+ return encodeURIComponent(value).replace(/[!'()*]/g, (ch) => {
1320
+ return `%${ch.charCodeAt(0).toString(16).toUpperCase()}`;
1321
+ });
1322
+ }
1323
+ function encodeForCss(value) {
1324
+ if (!value) return "";
1325
+ let result = "";
1326
+ for (let i = 0; i < value.length; i++) {
1327
+ const ch = value.charCodeAt(i);
1328
+ if (ch >= 48 && ch <= 57 || // 0-9
1329
+ ch >= 65 && ch <= 90 || // A-Z
1330
+ ch >= 97 && ch <= 122) {
1331
+ result += value[i];
1332
+ } else {
1333
+ result += `\\${ch.toString(16).toUpperCase()} `;
1334
+ }
1335
+ }
1336
+ return result;
1337
+ }
1338
+
1252
1339
  // src/validation/schema.ts
1253
1340
  function validate(schema, source = "body") {
1254
1341
  return (req, res, next) => {
@@ -2755,12 +2842,14 @@ function getRequestToken(req, headerName, fieldName) {
2755
2842
  return void 0;
2756
2843
  }
2757
2844
  function csrfProtection(options = {}) {
2758
- const cookieName = options.cookieName ?? DEFAULTS.cookieName;
2845
+ const baseCookieName = options.cookieName ?? DEFAULTS.cookieName;
2846
+ const cookieName = options.useHostPrefix ? `__Host-${baseCookieName}` : baseCookieName;
2759
2847
  const headerName = options.headerName ?? DEFAULTS.headerName;
2760
2848
  const fieldName = options.fieldName ?? DEFAULTS.fieldName;
2761
2849
  const tokenLength = options.tokenLength ?? DEFAULTS.tokenLength;
2762
2850
  const protectedMethods = options.protectedMethods ?? [...DEFAULTS.protectedMethods];
2763
2851
  const excludePaths = options.excludePaths ?? [];
2852
+ const skipCsrf = options.skipCsrf;
2764
2853
  const isProduction = process.env.NODE_ENV === "production";
2765
2854
  const cookieOpts = {
2766
2855
  path: options.cookie?.path ?? "/",
@@ -2780,6 +2869,9 @@ function csrfProtection(options = {}) {
2780
2869
  const protectedSet = new Set(protectedMethods.map((m) => m.toUpperCase()));
2781
2870
  return (req, res, next) => {
2782
2871
  const method = req.method.toUpperCase();
2872
+ if (skipCsrf && skipCsrf(req)) {
2873
+ return next();
2874
+ }
2783
2875
  const requestPath = req.path || req.url;
2784
2876
  if (excludePaths.some((p) => requestPath === p || requestPath.startsWith(p + "/"))) {
2785
2877
  return next();
@@ -2836,6 +2928,54 @@ function escapeRegex(str) {
2836
2928
  }
2837
2929
  var createCsrf = csrfProtection;
2838
2930
 
2931
+ // src/middleware/hpp.ts
2932
+ function hpp(options = {}) {
2933
+ const whitelist = new Set(options.whitelist ?? []);
2934
+ const checkQuery = options.checkQuery ?? true;
2935
+ const checkBody = options.checkBody ?? true;
2936
+ return (req, _res, next) => {
2937
+ if (checkQuery && req.query && typeof req.query === "object") {
2938
+ const polluted = {};
2939
+ const clean = {};
2940
+ for (const [key, value] of Object.entries(req.query)) {
2941
+ if (Array.isArray(value)) {
2942
+ const strings = value.filter((v) => typeof v === "string");
2943
+ if (whitelist.has(key)) {
2944
+ clean[key] = strings;
2945
+ } else {
2946
+ polluted[key] = strings;
2947
+ clean[key] = strings[strings.length - 1] ?? "";
2948
+ }
2949
+ } else {
2950
+ clean[key] = value;
2951
+ }
2952
+ }
2953
+ req.queryPolluted = polluted;
2954
+ Object.defineProperty(req, "query", { value: clean, writable: true, configurable: true });
2955
+ }
2956
+ if (checkBody && req.body && typeof req.body === "object" && !Array.isArray(req.body)) {
2957
+ const polluted = {};
2958
+ const clean = {};
2959
+ for (const [key, value] of Object.entries(req.body)) {
2960
+ if (Array.isArray(value)) {
2961
+ if (whitelist.has(key)) {
2962
+ clean[key] = value;
2963
+ } else {
2964
+ polluted[key] = value;
2965
+ clean[key] = value[value.length - 1];
2966
+ }
2967
+ } else {
2968
+ clean[key] = value;
2969
+ }
2970
+ }
2971
+ req.bodyPolluted = polluted;
2972
+ Object.defineProperty(req, "body", { value: clean, writable: true, configurable: true });
2973
+ }
2974
+ next();
2975
+ };
2976
+ }
2977
+ var createHpp = hpp;
2978
+
2839
2979
  // src/utils/ip.ts
2840
2980
  var PLATFORM_HEADERS = {
2841
2981
  cloudflare: "cf-connecting-ip",
@@ -2956,7 +3096,7 @@ function fingerprint(req, options = {}) {
2956
3096
  components.push(`enc:${getHeader2(req, "accept-encoding")}`);
2957
3097
  }
2958
3098
  for (const c of custom) {
2959
- if (c != null) components.push(`custom:${c}`);
3099
+ if (c !== null && c !== void 0) components.push(`custom:${c}`);
2960
3100
  }
2961
3101
  components.sort();
2962
3102
  const hash = crypto.createHash("sha256");
@@ -3121,6 +3261,7 @@ exports.createCors = createCors;
3121
3261
  exports.createCsrf = createCsrf;
3122
3262
  exports.createErrorHandler = createErrorHandler;
3123
3263
  exports.createHeaders = createHeaders;
3264
+ exports.createHpp = createHpp;
3124
3265
  exports.createRateLimiter = createRateLimiter;
3125
3266
  exports.createRedactor = createRedactor;
3126
3267
  exports.createRedisStore = createRedisStore;
@@ -3145,11 +3286,17 @@ exports.detectSql = detectSql;
3145
3286
  exports.detectSsti = detectSsti;
3146
3287
  exports.detectXss = detectXss;
3147
3288
  exports.detectXxe = detectXxe;
3289
+ exports.encodeForAttribute = encodeForAttribute;
3290
+ exports.encodeForCss = encodeForCss;
3291
+ exports.encodeForHtml = encodeForHtml;
3292
+ exports.encodeForJs = encodeForJs;
3293
+ exports.encodeForUrl = encodeForUrl;
3148
3294
  exports.enforceSecureCookie = enforceSecureCookie;
3149
3295
  exports.errorHandler = errorHandler;
3150
3296
  exports.fingerprint = fingerprint;
3151
3297
  exports.formatDuration = formatDuration;
3152
3298
  exports.generateCsrfToken = generateCsrfToken;
3299
+ exports.hpp = hpp;
3153
3300
  exports.isDangerousExtension = isDangerousExtension;
3154
3301
  exports.isDangerousNoSqlKey = isDangerousNoSqlKey;
3155
3302
  exports.isDangerousProtoKey = isDangerousProtoKey;