@nexusts/shield 0.7.9 → 0.8.1

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.
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CORS guard — handles preflight and sets Access-Control-* headers
3
+ * on every response according to the configured policy.
4
+ */
5
+ import type { CorsConfig } from "../types.js";
6
+ export declare class CorsGuard {
7
+ private config;
8
+ constructor(config: CorsConfig);
9
+ /**
10
+ * Resolve the `Access-Control-Allow-Origin` value for a given
11
+ * request origin. Returns `null` when the origin is not allowed.
12
+ */
13
+ resolveOrigin(requestOrigin: string): string | null;
14
+ /** Apply CORS response headers (non-preflight). */
15
+ applyHeaders(headers: Headers, requestOrigin: string): void;
16
+ /** Apply preflight response headers. Returns false if origin is not allowed. */
17
+ applyPreflightHeaders(headers: Headers, requestOrigin: string): boolean;
18
+ /** Hono middleware — handles preflight (OPTIONS) and annotates responses. */
19
+ middleware(): (c: any, next: () => Promise<any>) => Promise<any>;
20
+ }
@@ -3,3 +3,4 @@
3
3
  */
4
4
  export { CsrfGuard } from "./csrf.js";
5
5
  export { HeadersGuard } from "./headers.js";
6
+ export { CorsGuard } from "./cors.js";
package/dist/index.d.ts CHANGED
@@ -2,6 +2,6 @@
2
2
  * Public entry point for `nexusjs/shield`.
3
3
  */
4
4
  export * from "./types.js";
5
- export { CsrfGuard, HeadersGuard } from "./guards/index.js";
5
+ export { CorsGuard, CsrfGuard, HeadersGuard } from "./guards/index.js";
6
6
  export { ShieldService } from "./shield.service.js";
7
7
  export { ShieldModule } from "./shield.module.js";
package/dist/index.js CHANGED
@@ -189,13 +189,91 @@ class HeadersGuard {
189
189
  function camelToKebab(s) {
190
190
  return s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
191
191
  }
192
+ // packages/shield/src/guards/cors.ts
193
+ class CorsGuard {
194
+ config;
195
+ constructor(config) {
196
+ this.config = config;
197
+ }
198
+ resolveOrigin(requestOrigin) {
199
+ const { origin = "*" } = this.config;
200
+ if (origin === "*")
201
+ return "*";
202
+ if (typeof origin === "string")
203
+ return requestOrigin === origin ? origin : null;
204
+ if (Array.isArray(origin))
205
+ return origin.includes(requestOrigin) ? requestOrigin : null;
206
+ if (typeof origin === "function") {
207
+ const result = origin(requestOrigin);
208
+ if (result === true)
209
+ return requestOrigin;
210
+ if (typeof result === "string")
211
+ return result;
212
+ return null;
213
+ }
214
+ return null;
215
+ }
216
+ applyHeaders(headers, requestOrigin) {
217
+ const resolved = this.resolveOrigin(requestOrigin);
218
+ if (!resolved)
219
+ return;
220
+ headers.set("Access-Control-Allow-Origin", resolved);
221
+ if (this.config.credentials) {
222
+ headers.set("Access-Control-Allow-Credentials", "true");
223
+ }
224
+ if (this.config.exposedHeaders?.length) {
225
+ headers.set("Access-Control-Expose-Headers", this.config.exposedHeaders.join(", "));
226
+ }
227
+ if (resolved !== "*") {
228
+ headers.append("Vary", "Origin");
229
+ }
230
+ }
231
+ applyPreflightHeaders(headers, requestOrigin) {
232
+ const resolved = this.resolveOrigin(requestOrigin);
233
+ if (!resolved)
234
+ return false;
235
+ headers.set("Access-Control-Allow-Origin", resolved);
236
+ const methods = (this.config.methods ?? ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]).join(", ");
237
+ headers.set("Access-Control-Allow-Methods", methods);
238
+ if (this.config.allowedHeaders?.length) {
239
+ headers.set("Access-Control-Allow-Headers", this.config.allowedHeaders.join(", "));
240
+ }
241
+ if (this.config.credentials) {
242
+ headers.set("Access-Control-Allow-Credentials", "true");
243
+ }
244
+ if (this.config.maxAge !== undefined) {
245
+ headers.set("Access-Control-Max-Age", String(this.config.maxAge));
246
+ }
247
+ if (resolved !== "*") {
248
+ headers.append("Vary", "Origin");
249
+ }
250
+ return true;
251
+ }
252
+ middleware() {
253
+ return async (c, next) => {
254
+ const requestOrigin = c.req.header("origin") ?? "";
255
+ const method = c.req.method.toUpperCase();
256
+ if (method === "OPTIONS" && c.req.header("access-control-request-method")) {
257
+ const headers = new Headers;
258
+ const allowed = this.applyPreflightHeaders(headers, requestOrigin);
259
+ return new Response(null, { status: allowed ? 204 : 403, headers });
260
+ }
261
+ this.applyHeaders(c.res.headers, requestOrigin);
262
+ return next();
263
+ };
264
+ }
265
+ }
192
266
  // packages/shield/src/shield.service.ts
193
267
  import { Inject, Injectable } from "@nexusts/core";
194
268
  class ShieldService {
195
269
  static TOKEN = Symbol.for("nexus:ShieldService");
270
+ cors;
196
271
  csrf;
197
272
  headers;
198
273
  constructor(config = {}) {
274
+ if (config.cors) {
275
+ this.cors = new CorsGuard(config.cors);
276
+ }
199
277
  if (config.csrf) {
200
278
  const secret = config.secret ?? process.env["NEXUS_SHIELD_SECRET"] ?? "change-me-in-production-please";
201
279
  this.csrf = new CsrfGuard(config.csrf, secret);
@@ -204,8 +282,17 @@ class ShieldService {
204
282
  }
205
283
  middleware() {
206
284
  return async (c, next) => {
285
+ const requestOrigin = c.req.header("origin") ?? "";
286
+ const method = c.req.method.toUpperCase();
287
+ if (this.cors && method === "OPTIONS" && c.req.header("access-control-request-method")) {
288
+ const headers = new Headers;
289
+ const allowed = this.cors.applyPreflightHeaders(headers, requestOrigin);
290
+ return new Response(null, { status: allowed ? 204 : 403, headers });
291
+ }
292
+ if (this.cors) {
293
+ this.cors.applyHeaders(c.res.headers, requestOrigin);
294
+ }
207
295
  if (this.csrf) {
208
- const method = c.req.method.toUpperCase();
209
296
  const ignoreMethods = this.csrf.config.ignoreMethods;
210
297
  if (ignoreMethods.map((m) => m.toUpperCase()).includes(method)) {
211
298
  const cookieHeader = c.req.header("cookie") ?? "";
@@ -281,8 +368,9 @@ export {
281
368
  ShieldModule,
282
369
  ShieldInternals,
283
370
  HeadersGuard,
284
- CsrfGuard
371
+ CsrfGuard,
372
+ CorsGuard
285
373
  };
286
374
 
287
- //# debugId=23942CA3353F531F64756E2164756E21
375
+ //# debugId=346A697C0ADA68A864756E2164756E21
288
376
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/types.ts", "../src/guards/csrf.ts", "../src/guards/headers.ts", "../src/shield.service.ts", "../src/shield.module.ts"],
3
+ "sources": ["../src/types.ts", "../src/guards/csrf.ts", "../src/guards/headers.ts", "../src/guards/cors.ts", "../src/shield.service.ts", "../src/shield.module.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * `nexusjs/shield` — security middleware suite.\n *\n * Inspired by AdonisJS Shield. Provides:\n * - CSRF protection (synchronizer token pattern)\n * - Security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy)\n * - HSTS (Strict-Transport-Security)\n * - CSP (Content-Security-Policy) — optional\n * - XSS filter (browser-level, for legacy browsers)\n *\n * @Module({\n * imports: [\n * ShieldModule.forRoot({\n * csrf: { enabled: true },\n * hsts: { maxAge: 31_536_000, includeSubDomains: true },\n * csp: { directives: { defaultSrc: [\"'self'\"] } },\n * }),\n * ],\n * })\n * export class AppModule {}\n */\n\nimport \"reflect-metadata\";\nimport { randomBytes } from \"node:crypto\";\nimport { EncryptionService } from \"@nexusts/crypto\";\n\n/** CSRF protection configuration. */\nexport interface CsrfConfig {\n\tenabled: boolean;\n\t/** Cookie name. Default: 'nexus-csrf'. */\n\tcookieName?: string;\n\t/** Header name expected from clients. Default: 'x-csrf-token'. */\n\theaderName?: string;\n\t/** Form field name. Default: '_csrf'. */\n\tfieldName?: string;\n\t/** Whether to require the token on GET. Default: false. */\n\tprotectGet?: boolean;\n\t/** Cookie attributes. */\n\tcookie?: {\n\t\tsameSite?: \"Strict\" | \"Lax\" | \"None\";\n\t\tsecure?: boolean;\n\t\thttpOnly?: boolean;\n\t\tpath?: string;\n\t};\n\t/** Methods that bypass CSRF check. Default: ['GET', 'HEAD', 'OPTIONS']. */\n\tignoreMethods?: string[];\n}\n\n/** HSTS configuration. */\nexport interface HstsConfig {\n\tmaxAge: number;\n\tincludeSubDomains?: boolean;\n\tpreload?: boolean;\n}\n\n/** CSP configuration. */\nexport interface CspConfig {\n\tdirectives: Record<string, string[]>;\n\treportOnly?: boolean;\n\treportUri?: string;\n}\n\n/** Top-level Shield config. */\nexport interface ShieldConfig {\n\tcsrf?: CsrfConfig | false;\n\thsts?: HstsConfig | false;\n\tcsp?: CspConfig | false;\n\txFrameOptions?: \"DENY\" | \"SAMEORIGIN\" | false;\n\txContentTypeOptions?: boolean;\n\treferrerPolicy?: string;\n\t/** Secret used to sign CSRF tokens. */\n\tsecret?: string;\n}\n\n/** CSRF token (synchronizer pattern). */\nexport interface CsrfToken {\n\t/** The token to embed in forms/headers. */\n\ttoken: string;\n\t/** A pre-formed <meta> tag. */\n\thtml: string;\n}\n\n/** Generate a random base64url string. */\nfunction randomToken(bytes = 24): string {\n\treturn randomBytes(bytes).toString(\"base64url\");\n}\n\n/**\n * Sign `value` with `secret` using EncryptionService.\n *\n * Returns the signed value in `<value>.<signature>` format. The\n * HMAC is HKDF-derived from the secret + purpose tag (\"csrf\"), so\n * a CSRF token can't be replayed as another-purpose token.\n */\nfunction sign(value: string, secret: string): string {\n\tconst sig = new EncryptionService(secret).signRaw(value, \"csrf\");\n\treturn `${value}.${sig}`;\n}\n\n/**\n * Verify a signed token. Returns the original value on success,\n * `null` on failure (tampered, wrong purpose, malformed).\n */\nfunction verify(signed: string, secret: string): string | null {\n\tconst lastDot = signed.lastIndexOf(\".\");\n\tif (lastDot < 1) return null;\n\tconst value = signed.slice(0, lastDot);\n\tconst sig = signed.slice(lastDot + 1);\n\tif (!new EncryptionService(secret).verifyRaw(value, sig, \"csrf\")) return null;\n\treturn value;\n}\n\nexport const ShieldInternals = {\n\tsign,\n\tverify,\n\trandomToken,\n};\n",
5
+ "/**\n * `nexusjs/shield` — security middleware suite.\n *\n * Inspired by AdonisJS Shield. Provides:\n * - CSRF protection (synchronizer token pattern)\n * - Security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy)\n * - HSTS (Strict-Transport-Security)\n * - CSP (Content-Security-Policy) — optional\n * - XSS filter (browser-level, for legacy browsers)\n *\n * @Module({\n * imports: [\n * ShieldModule.forRoot({\n * csrf: { enabled: true },\n * hsts: { maxAge: 31_536_000, includeSubDomains: true },\n * csp: { directives: { defaultSrc: [\"'self'\"] } },\n * }),\n * ],\n * })\n * export class AppModule {}\n */\n\nimport \"reflect-metadata\";\nimport { randomBytes } from \"node:crypto\";\nimport { EncryptionService } from \"@nexusts/crypto\";\n\n/** CSRF protection configuration. */\nexport interface CsrfConfig {\n\tenabled: boolean;\n\t/** Cookie name. Default: 'nexus-csrf'. */\n\tcookieName?: string;\n\t/** Header name expected from clients. Default: 'x-csrf-token'. */\n\theaderName?: string;\n\t/** Form field name. Default: '_csrf'. */\n\tfieldName?: string;\n\t/** Whether to require the token on GET. Default: false. */\n\tprotectGet?: boolean;\n\t/** Cookie attributes. */\n\tcookie?: {\n\t\tsameSite?: \"Strict\" | \"Lax\" | \"None\";\n\t\tsecure?: boolean;\n\t\thttpOnly?: boolean;\n\t\tpath?: string;\n\t};\n\t/** Methods that bypass CSRF check. Default: ['GET', 'HEAD', 'OPTIONS']. */\n\tignoreMethods?: string[];\n}\n\n/** HSTS configuration. */\nexport interface HstsConfig {\n\tmaxAge: number;\n\tincludeSubDomains?: boolean;\n\tpreload?: boolean;\n}\n\n/** CSP configuration. */\nexport interface CspConfig {\n\tdirectives: Record<string, string[]>;\n\treportOnly?: boolean;\n\treportUri?: string;\n}\n\n/** CORS configuration. */\nexport interface CorsConfig {\n\t/**\n\t * Allowed origin(s). Default: `\"*\"` (all origins).\n\t * - `\"*\"` — reflect wildcard (credentials not supported)\n\t * - `string` — exact match\n\t * - `string[]` — whitelist\n\t * - `(origin) => boolean | string | null` — custom resolver\n\t */\n\torigin?: string | string[] | ((origin: string) => boolean | string | null);\n\t/** Allowed HTTP methods. Default: GET POST PUT PATCH DELETE HEAD OPTIONS. */\n\tmethods?: string[];\n\t/** Allowed request headers (`Access-Control-Allow-Headers`). */\n\tallowedHeaders?: string[];\n\t/** Headers exposed to the browser (`Access-Control-Expose-Headers`). */\n\texposedHeaders?: string[];\n\t/** Set `Access-Control-Allow-Credentials: true`. Default: false. */\n\tcredentials?: boolean;\n\t/** Preflight cache duration in seconds (`Access-Control-Max-Age`). */\n\tmaxAge?: number;\n}\n\n/** Top-level Shield config. */\nexport interface ShieldConfig {\n\tcors?: CorsConfig | false;\n\tcsrf?: CsrfConfig | false;\n\thsts?: HstsConfig | false;\n\tcsp?: CspConfig | false;\n\txFrameOptions?: \"DENY\" | \"SAMEORIGIN\" | false;\n\txContentTypeOptions?: boolean;\n\treferrerPolicy?: string;\n\t/** Secret used to sign CSRF tokens. */\n\tsecret?: string;\n}\n\n/** CSRF token (synchronizer pattern). */\nexport interface CsrfToken {\n\t/** The token to embed in forms/headers. */\n\ttoken: string;\n\t/** A pre-formed <meta> tag. */\n\thtml: string;\n}\n\n/** Generate a random base64url string. */\nfunction randomToken(bytes = 24): string {\n\treturn randomBytes(bytes).toString(\"base64url\");\n}\n\n/**\n * Sign `value` with `secret` using EncryptionService.\n *\n * Returns the signed value in `<value>.<signature>` format. The\n * HMAC is HKDF-derived from the secret + purpose tag (\"csrf\"), so\n * a CSRF token can't be replayed as another-purpose token.\n */\nfunction sign(value: string, secret: string): string {\n\tconst sig = new EncryptionService(secret).signRaw(value, \"csrf\");\n\treturn `${value}.${sig}`;\n}\n\n/**\n * Verify a signed token. Returns the original value on success,\n * `null` on failure (tampered, wrong purpose, malformed).\n */\nfunction verify(signed: string, secret: string): string | null {\n\tconst lastDot = signed.lastIndexOf(\".\");\n\tif (lastDot < 1) return null;\n\tconst value = signed.slice(0, lastDot);\n\tconst sig = signed.slice(lastDot + 1);\n\tif (!new EncryptionService(secret).verifyRaw(value, sig, \"csrf\")) return null;\n\treturn value;\n}\n\nexport const ShieldInternals = {\n\tsign,\n\tverify,\n\trandomToken,\n};\n",
6
6
  "/**\n * CSRF guard — synchronizer token pattern.\n *\n * On `GET` (or any non-mutating request) we ensure a `nexus-csrf` cookie\n * is set. On `POST`/`PUT`/`DELETE`/`PATCH` we read the cookie, then\n * compare it against the `X-CSRF-Token` header (or `_csrf` form field).\n *\n * Both values must match (constant-time compare) for the request to pass.\n */\nimport type { CsrfConfig, CsrfToken } from \"../types.js\";\nimport { ShieldInternals } from \"../types.js\";\n\nexport class CsrfGuard {\n\tprivate config: Required<CsrfConfig>;\n\tprivate secret: string;\n\n\tconstructor(config: CsrfConfig, secret: string) {\n\t\tthis.config = {\n\t\t\tenabled: config.enabled,\n\t\t\tcookieName: config.cookieName ?? \"nexus-csrf\",\n\t\t\theaderName: config.headerName ?? \"x-csrf-token\",\n\t\t\tfieldName: config.fieldName ?? \"_csrf\",\n\t\t\tprotectGet: config.protectGet ?? false,\n\t\t\tcookie: {\n\t\t\t\tsameSite: config.cookie?.sameSite ?? \"Lax\",\n\t\t\t\tsecure: config.cookie?.secure ?? true,\n\t\t\t\thttpOnly: config.cookie?.httpOnly ?? false,\n\t\t\t\tpath: config.cookie?.path ?? \"/\",\n\t\t\t},\n\t\t\tignoreMethods: config.ignoreMethods ?? [\"GET\", \"HEAD\", \"OPTIONS\"],\n\t\t};\n\t\tthis.secret = secret;\n\t}\n\n\t/**\n\t * Issue a CSRF token. Sets the cookie on the response.\n\t */\n\tissue(res: Headers): CsrfToken {\n\t\tconst raw = ShieldInternals.randomToken();\n\t\tconst signed = ShieldInternals.sign(raw, this.secret);\n\t\t// Set the cookie. The unsigned value is stored.\n\t\tconst cookieParts = [\n\t\t\t`${this.config.cookieName}=${raw}`,\n\t\t\t`Path=${this.config.cookie.path}`,\n\t\t\t`SameSite=${this.config.cookie.sameSite}`,\n\t\t];\n\t\tif (this.config.cookie.secure) cookieParts.push(\"Secure\");\n\t\tif (this.config.cookie.httpOnly) cookieParts.push(\"HttpOnly\");\n\t\tres.append(\"Set-Cookie\", cookieParts.join(\"; \"));\n\t\treturn {\n\t\t\ttoken: signed,\n\t\t\thtml: `<meta name=\"csrf-token\" content=\"${signed}\">`,\n\t\t};\n\t}\n\n\t/**\n\t * Verify a request. Returns `true` if the request is allowed.\n\t */\n\tverify(req: { method: string; headers: Headers }): boolean {\n\t\tconst method = req.method.toUpperCase();\n\t\tif (\n\t\t\tthis.config.ignoreMethods.map((m) => m.toUpperCase()).includes(method)\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\tif (this.config.protectGet) {\n\t\t\t// (no-op; protectGet currently shares ignoreMethods logic)\n\t\t}\n\t\tconst cookieHeader = req.headers.get(\"cookie\") ?? \"\";\n\t\tconst cookieToken = this.extractCookie(\n\t\t\tcookieHeader,\n\t\t\tthis.config.cookieName,\n\t\t);\n\t\tif (!cookieToken) return false;\n\t\t// Header value\n\t\tconst headerToken = req.headers.get(this.config.headerName);\n\t\tif (\n\t\t\theaderToken &&\n\t\t\tShieldInternals.verify(headerToken, this.secret) === cookieToken\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\t// Form field (parsed from x-www-form-urlencoded body or multipart)\n\t\t// For simplicity, we accept a custom header `x-csrf-field` with the value.\n\t\tconst fieldToken = req.headers.get(\"x-csrf-field\");\n\t\tif (\n\t\t\tfieldToken &&\n\t\t\tShieldInternals.verify(fieldToken, this.secret) === cookieToken\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Build a Hono middleware. Sets the cookie on every safe request and\n\t * enforces the check on mutating ones.\n\t */\n\tmiddleware() {\n\t\treturn async (c: any, next: () => Promise<any>) => {\n\t\t\tconst method = (c.req.method as string).toUpperCase();\n\t\t\tif (\n\t\t\t\tthis.config.ignoreMethods.map((m) => m.toUpperCase()).includes(method)\n\t\t\t) {\n\t\t\t\t// Safe method: ensure a cookie is present.\n\t\t\t\tconst cookieHeader = c.req.header(\"cookie\") ?? \"\";\n\t\t\t\tif (!this.extractCookie(cookieHeader, this.config.cookieName)) {\n\t\t\t\t\tthis.issue(c.res.headers);\n\t\t\t\t}\n\t\t\t\treturn next();\n\t\t\t}\n\t\t\tif (!this.verify(c.req.raw)) {\n\t\t\t\treturn c.text(\"Invalid CSRF token\", 403);\n\t\t\t}\n\t\t\treturn next();\n\t\t};\n\t}\n\n\tprivate extractCookie(cookieHeader: string, name: string): string | null {\n\t\tfor (const part of cookieHeader.split(\";\")) {\n\t\t\tconst [k, ...rest] = part.trim().split(\"=\");\n\t\t\tif (k === name) return rest.join(\"=\");\n\t\t}\n\t\treturn null;\n\t}\n}\n",
7
7
  "/**\n * Security headers middleware. Sets HSTS, X-Frame-Options,\n * X-Content-Type-Options, Referrer-Policy, and CSP on every response.\n */\nimport type { CspConfig, HstsConfig } from \"../types.js\";\n\nexport class HeadersGuard {\n\thsts: HstsConfig | false;\n\tcsp: CspConfig | false;\n\txFrameOptions: \"DENY\" | \"SAMEORIGIN\" | false;\n\txContentTypeOptions: boolean;\n\treferrerPolicy: string | undefined;\n\n\tconstructor(\n\t\thsts: HstsConfig | false,\n\t\tcsp: CspConfig | false,\n\t\txFrameOptions: \"DENY\" | \"SAMEORIGIN\" | false,\n\t\txContentTypeOptions: boolean,\n\t\treferrerPolicy: string | undefined,\n\t) {\n\t\tthis.hsts = hsts;\n\t\tthis.csp = csp;\n\t\tthis.xFrameOptions = xFrameOptions;\n\t\tthis.xContentTypeOptions = xContentTypeOptions;\n\t\tthis.referrerPolicy = referrerPolicy;\n\t}\n\n\t/**\n\t * Apply configured headers to the given `Headers` instance in place.\n\t * Useful when you already have a Response and want to enrich it.\n\t */\n\tapply(headers: Headers): void {\n\t\tif (this.hsts) {\n\t\t\tconst h = this.buildHstsHeader(this.hsts);\n\t\t\tif (h) headers.set(\"Strict-Transport-Security\", h);\n\t\t}\n\t\tif (this.csp) {\n\t\t\tconst header = this.buildCspHeader(this.csp);\n\t\t\tconst name = this.csp.reportOnly\n\t\t\t\t? \"Content-Security-Policy-Report-Only\"\n\t\t\t\t: \"Content-Security-Policy\";\n\t\t\theaders.set(name, header);\n\t\t}\n\t\tif (this.xFrameOptions) {\n\t\t\theaders.set(\"X-Frame-Options\", this.xFrameOptions);\n\t\t}\n\t\tif (this.xContentTypeOptions) {\n\t\t\theaders.set(\"X-Content-Type-Options\", \"nosniff\");\n\t\t}\n\t\tif (this.referrerPolicy) {\n\t\t\theaders.set(\"Referrer-Policy\", this.referrerPolicy);\n\t\t}\n\t}\n\n\tmiddleware() {\n\t\treturn async (_c: any, next: () => Promise<any>) => {\n\t\t\t// Apply headers to c.res BEFORE next() so the handler inherits them.\n\t\t\tthis.apply(_c.res.headers as Headers);\n\t\t\treturn next();\n\t\t};\n\t}\n\n\tprivate buildHstsHeader(cfg: HstsConfig): string {\n\t\tlet v = `max-age=${cfg.maxAge}`;\n\t\tif (cfg.includeSubDomains) v += \"; includeSubDomains\";\n\t\tif (cfg.preload) v += \"; preload\";\n\t\treturn v;\n\t}\n\n\tprivate buildCspHeader(cfg: CspConfig): string {\n\t\tconst parts: string[] = [];\n\t\tfor (const [name, values] of Object.entries(cfg.directives)) {\n\t\t\tif (!values || values.length === 0) continue;\n\t\t\tparts.push(`${camelToKebab(name)} ${values.join(\" \")}`);\n\t\t}\n\t\tif (cfg.reportUri) parts.push(`report-uri ${cfg.reportUri}`);\n\t\treturn parts.join(\"; \");\n\t}\n}\n\n/** Convert `defaultSrc` → `default-src`. Already-kebab names pass through. */\nfunction camelToKebab(s: string): string {\n\treturn s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);\n}\n",
8
- "/**\n * `ShieldService`orchestrator. Aggregates the per-feature guards\n * into a single Hono middleware that can be mounted globally.\n */\nimport { Inject, Injectable } from \"@nexusts/core\";\nimport type { CsrfConfig, ShieldConfig } from \"./types.js\";\nimport { CsrfGuard, HeadersGuard } from \"./guards/index.js\";\n\n@Injectable()\nexport class ShieldService {\n\t/** DI token. */\n\tstatic readonly TOKEN = Symbol.for(\"nexus:ShieldService\");\n\n\tcsrf?: CsrfGuard;\n\theaders: HeadersGuard;\n\n\tconstructor(@Inject(\"SHIELD_CONFIG\") config: ShieldConfig = {}) {\n\t\tif (config.csrf) {\n\t\t\tconst secret =\n\t\t\t\tconfig.secret ??\n\t\t\t\tprocess.env[\"NEXUS_SHIELD_SECRET\"] ??\n\t\t\t\t\"change-me-in-production-please\";\n\t\t\tthis.csrf = new CsrfGuard(config.csrf as CsrfConfig, secret);\n\t\t}\n\t\tthis.headers = new HeadersGuard(\n\t\t\tconfig.hsts ?? false,\n\t\t\tconfig.csp ?? false,\n\t\t\tconfig.xFrameOptions ?? \"SAMEORIGIN\",\n\t\t\tconfig.xContentTypeOptions ?? true,\n\t\t\tconfig.referrerPolicy,\n\t\t);\n\t}\n\n\t/**\n\t * Returns a Hono middleware that applies all configured guards.\n\t *\n\t * Order:\n\t * 1. CSRF check on mutating requests (rejects with 403 + security headers)\n\t * 2. Security headers applied to the final response\n\t */\n\tmiddleware() {\n\t\treturn async (c: any, next: () => Promise<any>) => {\n\t\t\t// 1. CSRF check must run before `next()` so we can short-circuit.\n\t\t\tif (this.csrf) {\n\t\t\t\tconst method = (c.req.method as string).toUpperCase();\n\t\t\t\tconst ignoreMethods = (this.csrf as any).config.ignoreMethods as string[];\n\t\t\t\tif (ignoreMethods.map((m) => m.toUpperCase()).includes(method)) {\n\t\t\t\t\t// Safe method: ensure a CSRF cookie is present.\n\t\t\t\t\tconst cookieHeader = c.req.header(\"cookie\") ?? \"\";\n\t\t\t\t\tconst cookieName = (this.csrf as any).config.cookieName as string;\n\t\t\t\t\tif (!this.extractCookie(cookieHeader, cookieName)) {\n\t\t\t\t\t\t(this.csrf as any).issue(c.res.headers);\n\t\t\t\t\t}\n\t\t\t\t} else if (!(this.csrf as any).verify(c.req.raw)) {\n\t\t\t\t\t// 403 apply security headers and return.\n\t\t\t\t\tconst resp = c.text(\"Invalid CSRF token\", 403);\n\t\t\t\t\tthis.headers.apply(resp.headers as Headers);\n\t\t\t\t\treturn resp;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 2. Apply security headers to c.res BEFORE the handler runs.\n\t\t\t// Hono's c.text()/c.json() etc. create a new Response but\n\t\t\t// inherit existing headers from c.res.headers.\n\t\t\tthis.headers.apply(c.res.headers as Headers);\n\n\t\t\t// 3. Continue to next middleware/handler.\n\t\t\treturn next();\n\t\t};\n\t}\n\n\t/** Generate a CSRF token and set the cookie. Useful for forms. */\n\tissueToken(headers: Headers) {\n\t\tif (!this.csrf) throw new Error(\"CSRF guard is not enabled\");\n\t\treturn this.csrf.issue(headers);\n\t}\n\n\tprivate extractCookie(cookieHeader: string, name: string): string | null {\n\t\tfor (const part of cookieHeader.split(\";\")) {\n\t\t\tconst [k, ...rest] = part.trim().split(\"=\");\n\t\t\tif (k === name) return rest.join(\"=\");\n\t\t}\n\t\treturn null;\n\t}\n}\n",
8
+ "/**\n * CORS guard handles preflight and sets Access-Control-* headers\n * on every response according to the configured policy.\n */\nimport type { CorsConfig } from \"../types.js\";\n\nexport class CorsGuard {\n\tconstructor(private config: CorsConfig) {}\n\n\t/**\n\t * Resolve the `Access-Control-Allow-Origin` value for a given\n\t * request origin. Returns `null` when the origin is not allowed.\n\t */\n\tresolveOrigin(requestOrigin: string): string | null {\n\t\tconst { origin = \"*\" } = this.config;\n\t\tif (origin === \"*\") return \"*\";\n\t\tif (typeof origin === \"string\")\n\t\t\treturn requestOrigin === origin ? origin : null;\n\t\tif (Array.isArray(origin))\n\t\t\treturn origin.includes(requestOrigin) ? requestOrigin : null;\n\t\tif (typeof origin === \"function\") {\n\t\t\tconst result = origin(requestOrigin);\n\t\t\tif (result === true) return requestOrigin;\n\t\t\tif (typeof result === \"string\") return result;\n\t\t\treturn null;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/** Apply CORS response headers (non-preflight). */\n\tapplyHeaders(headers: Headers, requestOrigin: string): void {\n\t\tconst resolved = this.resolveOrigin(requestOrigin);\n\t\tif (!resolved) return;\n\t\theaders.set(\"Access-Control-Allow-Origin\", resolved);\n\t\tif (this.config.credentials) {\n\t\t\theaders.set(\"Access-Control-Allow-Credentials\", \"true\");\n\t\t}\n\t\tif (this.config.exposedHeaders?.length) {\n\t\t\theaders.set(\n\t\t\t\t\"Access-Control-Expose-Headers\",\n\t\t\t\tthis.config.exposedHeaders.join(\", \"),\n\t\t\t);\n\t\t}\n\t\tif (resolved !== \"*\") {\n\t\t\t// Vary so caches don't conflate responses for different origins.\n\t\t\theaders.append(\"Vary\", \"Origin\");\n\t\t}\n\t}\n\n\t/** Apply preflight response headers. Returns false if origin is not allowed. */\n\tapplyPreflightHeaders(headers: Headers, requestOrigin: string): boolean {\n\t\tconst resolved = this.resolveOrigin(requestOrigin);\n\t\tif (!resolved) return false;\n\t\theaders.set(\"Access-Control-Allow-Origin\", resolved);\n\t\tconst methods = (\n\t\t\tthis.config.methods ?? [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\", \"OPTIONS\"]\n\t\t).join(\", \");\n\t\theaders.set(\"Access-Control-Allow-Methods\", methods);\n\t\tif (this.config.allowedHeaders?.length) {\n\t\t\theaders.set(\n\t\t\t\t\"Access-Control-Allow-Headers\",\n\t\t\t\tthis.config.allowedHeaders.join(\", \"),\n\t\t\t);\n\t\t}\n\t\tif (this.config.credentials) {\n\t\t\theaders.set(\"Access-Control-Allow-Credentials\", \"true\");\n\t\t}\n\t\tif (this.config.maxAge !== undefined) {\n\t\t\theaders.set(\"Access-Control-Max-Age\", String(this.config.maxAge));\n\t\t}\n\t\tif (resolved !== \"*\") {\n\t\t\theaders.append(\"Vary\", \"Origin\");\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** Hono middleware handles preflight (OPTIONS) and annotates responses. */\n\tmiddleware() {\n\t\treturn async (c: any, next: () => Promise<any>) => {\n\t\t\tconst requestOrigin = (c.req.header(\"origin\") as string) ?? \"\";\n\t\t\tconst method = (c.req.method as string).toUpperCase();\n\n\t\t\t// Preflight: OPTIONS + Access-Control-Request-Method\n\t\t\tif (method === \"OPTIONS\" && c.req.header(\"access-control-request-method\")) {\n\t\t\t\tconst headers = new Headers();\n\t\t\t\tconst allowed = this.applyPreflightHeaders(headers, requestOrigin);\n\t\t\t\treturn new Response(null, { status: allowed ? 204 : 403, headers });\n\t\t\t}\n\n\t\t\t// Regular request: apply CORS headers before the handler.\n\t\t\tthis.applyHeaders(c.res.headers as Headers, requestOrigin);\n\t\t\treturn next();\n\t\t};\n\t}\n}\n",
9
+ "/**\n * `ShieldService` — orchestrator. Aggregates the per-feature guards\n * into a single Hono middleware that can be mounted globally.\n */\nimport { Inject, Injectable } from \"@nexusts/core\";\nimport type { CorsConfig, CsrfConfig, ShieldConfig } from \"./types.js\";\nimport { CorsGuard, CsrfGuard, HeadersGuard } from \"./guards/index.js\";\n\n@Injectable()\nexport class ShieldService {\n\t/** DI token. */\n\tstatic readonly TOKEN = Symbol.for(\"nexus:ShieldService\");\n\n\tcors?: CorsGuard;\n\tcsrf?: CsrfGuard;\n\theaders: HeadersGuard;\n\n\tconstructor(@Inject(\"SHIELD_CONFIG\") config: ShieldConfig = {}) {\n\t\tif (config.cors) {\n\t\t\tthis.cors = new CorsGuard(config.cors as CorsConfig);\n\t\t}\n\t\tif (config.csrf) {\n\t\t\tconst secret =\n\t\t\t\tconfig.secret ??\n\t\t\t\tprocess.env[\"NEXUS_SHIELD_SECRET\"] ??\n\t\t\t\t\"change-me-in-production-please\";\n\t\t\tthis.csrf = new CsrfGuard(config.csrf as CsrfConfig, secret);\n\t\t}\n\t\tthis.headers = new HeadersGuard(\n\t\t\tconfig.hsts ?? false,\n\t\t\tconfig.csp ?? false,\n\t\t\tconfig.xFrameOptions ?? \"SAMEORIGIN\",\n\t\t\tconfig.xContentTypeOptions ?? true,\n\t\t\tconfig.referrerPolicy,\n\t\t);\n\t}\n\n\t/**\n\t * Returns a Hono middleware that applies all configured guards.\n\t *\n\t * Order:\n\t * 1. CSRF check on mutating requests (rejects with 403 + security headers)\n\t * 2. Security headers applied to the final response\n\t */\n\tmiddleware() {\n\t\treturn async (c: any, next: () => Promise<any>) => {\n\t\t\tconst requestOrigin = (c.req.header(\"origin\") as string) ?? \"\";\n\t\t\tconst method = (c.req.method as string).toUpperCase();\n\n\t\t\t// 0. CORS preflight — short-circuit before CSRF so OPTIONS doesn't 403.\n\t\t\tif (this.cors && method === \"OPTIONS\" && c.req.header(\"access-control-request-method\")) {\n\t\t\t\tconst headers = new Headers();\n\t\t\t\tconst allowed = this.cors.applyPreflightHeaders(headers, requestOrigin);\n\t\t\t\treturn new Response(null, { status: allowed ? 204 : 403, headers });\n\t\t\t}\n\n\t\t\t// 0b. Apply CORS headers to regular requests.\n\t\t\tif (this.cors) {\n\t\t\t\tthis.cors.applyHeaders(c.res.headers as Headers, requestOrigin);\n\t\t\t}\n\n\t\t\t// 1. CSRF check — must run before `next()` so we can short-circuit.\n\t\t\tif (this.csrf) {\n\t\t\t\tconst ignoreMethods = (this.csrf as any).config.ignoreMethods as string[];\n\t\t\t\tif (ignoreMethods.map((m) => m.toUpperCase()).includes(method)) {\n\t\t\t\t\t// Safe method: ensure a CSRF cookie is present.\n\t\t\t\t\tconst cookieHeader = c.req.header(\"cookie\") ?? \"\";\n\t\t\t\t\tconst cookieName = (this.csrf as any).config.cookieName as string;\n\t\t\t\t\tif (!this.extractCookie(cookieHeader, cookieName)) {\n\t\t\t\t\t\t(this.csrf as any).issue(c.res.headers);\n\t\t\t\t\t}\n\t\t\t\t} else if (!(this.csrf as any).verify(c.req.raw)) {\n\t\t\t\t\t// 403 — apply security headers and return.\n\t\t\t\t\tconst resp = c.text(\"Invalid CSRF token\", 403);\n\t\t\t\t\tthis.headers.apply(resp.headers as Headers);\n\t\t\t\t\treturn resp;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 2. Apply security headers to c.res BEFORE the handler runs.\n\t\t\t// Hono's c.text()/c.json() etc. create a new Response but\n\t\t\t// inherit existing headers from c.res.headers.\n\t\t\tthis.headers.apply(c.res.headers as Headers);\n\n\t\t\t// 3. Continue to next middleware/handler.\n\t\t\treturn next();\n\t\t};\n\t}\n\n\t/** Generate a CSRF token and set the cookie. Useful for forms. */\n\tissueToken(headers: Headers) {\n\t\tif (!this.csrf) throw new Error(\"CSRF guard is not enabled\");\n\t\treturn this.csrf.issue(headers);\n\t}\n\n\tprivate extractCookie(cookieHeader: string, name: string): string | null {\n\t\tfor (const part of cookieHeader.split(\";\")) {\n\t\t\tconst [k, ...rest] = part.trim().split(\"=\");\n\t\t\tif (k === name) return rest.join(\"=\");\n\t\t}\n\t\treturn null;\n\t}\n}\n",
9
10
  "/**\n * `ShieldModule` — drop-in security middleware suite.\n *\n * @Module({\n * imports: [\n * ShieldModule.forRoot({\n * csrf: { enabled: true },\n * hsts: { maxAge: 31_536_000, includeSubDomains: true },\n * csp: { directives: { defaultSrc: [\"'self'\"] } },\n * xFrameOptions: 'SAMEORIGIN',\n * xContentTypeOptions: true,\n * referrerPolicy: 'strict-origin-when-cross-origin',\n * }),\n * ],\n * })\n * export class AppModule {}\n */\nimport \"reflect-metadata\";\nimport { Module } from \"@nexusts/core\";\nimport { ShieldService } from \"./shield.service.js\";\nimport type { ShieldConfig } from \"./types.js\";\n\n@Module({\n\tproviders: [\n\t\tShieldService,\n\t\t{ provide: ShieldService.TOKEN, useExisting: ShieldService },\n\t],\n\texports: [ShieldService, ShieldService.TOKEN],\n})\nexport class ShieldModule {\n\tstatic forRoot(config: ShieldConfig = {}) {\n\t\t@Module({\n\t\t\tproviders: [\n\t\t\t\tShieldService,\n\t\t\t\t{ provide: ShieldService.TOKEN, useExisting: ShieldService },\n\t\t\t\t{ provide: \"SHIELD_CONFIG\", useValue: config },\n\t\t\t],\n\t\t\texports: [ShieldService, ShieldService.TOKEN],\n\t\t})\n\t\tclass ConfiguredShieldModule {}\n\t\tObject.defineProperty(ConfiguredShieldModule, \"name\", {\n\t\t\tvalue: \"ConfiguredShieldModule\",\n\t\t});\n\t\treturn ConfiguredShieldModule;\n\t}\n}\n"
10
11
  ],
11
- "mappings": "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",
12
- "debugId": "23942CA3353F531F64756E2164756E21",
12
+ "mappings": "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",
13
+ "debugId": "346A697C0ADA68A864756E2164756E21",
13
14
  "names": []
14
15
  }
@@ -1,8 +1,9 @@
1
1
  import type { ShieldConfig } from "./types.js";
2
- import { CsrfGuard, HeadersGuard } from "./guards/index.js";
2
+ import { CorsGuard, CsrfGuard, HeadersGuard } from "./guards/index.js";
3
3
  export declare class ShieldService {
4
4
  /** DI token. */
5
5
  static readonly TOKEN: unique symbol;
6
+ cors?: CorsGuard;
6
7
  csrf?: CsrfGuard;
7
8
  headers: HeadersGuard;
8
9
  constructor(config?: ShieldConfig);
package/dist/types.d.ts CHANGED
@@ -53,8 +53,30 @@ export interface CspConfig {
53
53
  reportOnly?: boolean;
54
54
  reportUri?: string;
55
55
  }
56
+ /** CORS configuration. */
57
+ export interface CorsConfig {
58
+ /**
59
+ * Allowed origin(s). Default: `"*"` (all origins).
60
+ * - `"*"` — reflect wildcard (credentials not supported)
61
+ * - `string` — exact match
62
+ * - `string[]` — whitelist
63
+ * - `(origin) => boolean | string | null` — custom resolver
64
+ */
65
+ origin?: string | string[] | ((origin: string) => boolean | string | null);
66
+ /** Allowed HTTP methods. Default: GET POST PUT PATCH DELETE HEAD OPTIONS. */
67
+ methods?: string[];
68
+ /** Allowed request headers (`Access-Control-Allow-Headers`). */
69
+ allowedHeaders?: string[];
70
+ /** Headers exposed to the browser (`Access-Control-Expose-Headers`). */
71
+ exposedHeaders?: string[];
72
+ /** Set `Access-Control-Allow-Credentials: true`. Default: false. */
73
+ credentials?: boolean;
74
+ /** Preflight cache duration in seconds (`Access-Control-Max-Age`). */
75
+ maxAge?: number;
76
+ }
56
77
  /** Top-level Shield config. */
57
78
  export interface ShieldConfig {
79
+ cors?: CorsConfig | false;
58
80
  csrf?: CsrfConfig | false;
59
81
  hsts?: HstsConfig | false;
60
82
  csp?: CspConfig | false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexusts/shield",
3
- "version": "0.7.9",
3
+ "version": "0.8.1",
4
4
  "description": "CSRF / HSTS / CSP security middleware",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -26,7 +26,7 @@
26
26
  ],
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
- "@nexusts/core": "^0.7.9"
29
+ "@nexusts/core": "^0.8.1"
30
30
  },
31
31
  "repository": {
32
32
  "type": "git",