@nexusts/shield 0.7.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 +41 -0
- package/dist/index.js +288 -0
- package/dist/index.js.map +14 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @nexusts/shield
|
|
2
|
+
|
|
3
|
+
> **NexusTS** — Bun-native fullstack framework
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
CSRF / HSTS / CSP security middleware.
|
|
8
|
+
|
|
9
|
+
Security headers (HSTS, CSP, X-Frame-Options, Referrer-Policy) + CSRF token middleware (HMAC-signed). Apply with `app.use('*', shield())`.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
This module is part of the NexusTS monorepo. Each module is published as its own npm package under the `@nexusts/` scope.
|
|
14
|
+
|
|
15
|
+
Most apps start with just the core:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun add @nexusts/core reflect-metadata zod hono
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then add this module only if you need it:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bun add @nexusts/shield
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Peer dependencies
|
|
28
|
+
|
|
29
|
+
None. This module is fully self-contained.
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { /* public API */ } from "@nexusts/shield";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
See the [user guide](../../docs/user-guide/shield.md) and the [example app](../../examples/) for a working demo.
|
|
38
|
+
|
|
39
|
+
## License
|
|
40
|
+
|
|
41
|
+
MIT — see the root [LICENSE](../../LICENSE).
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __legacyDecorateClassTS = function(decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
5
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
6
|
+
else
|
|
7
|
+
for (var i = decorators.length - 1;i >= 0; i--)
|
|
8
|
+
if (d = decorators[i])
|
|
9
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
10
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
11
|
+
};
|
|
12
|
+
var __legacyDecorateParamTS = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
13
|
+
var __legacyMetadataTS = (k, v) => {
|
|
14
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
|
|
15
|
+
return Reflect.metadata(k, v);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// packages/shield/src/types.ts
|
|
19
|
+
import"reflect-metadata";
|
|
20
|
+
import { randomBytes } from "crypto";
|
|
21
|
+
import { EncryptionService } from "@nexusts/crypto/encryption.js";
|
|
22
|
+
function randomToken(bytes = 24) {
|
|
23
|
+
return randomBytes(bytes).toString("base64url");
|
|
24
|
+
}
|
|
25
|
+
function sign(value, secret) {
|
|
26
|
+
const sig = new EncryptionService(secret).signRaw(value, "csrf");
|
|
27
|
+
return `${value}.${sig}`;
|
|
28
|
+
}
|
|
29
|
+
function verify(signed, secret) {
|
|
30
|
+
const lastDot = signed.lastIndexOf(".");
|
|
31
|
+
if (lastDot < 1)
|
|
32
|
+
return null;
|
|
33
|
+
const value = signed.slice(0, lastDot);
|
|
34
|
+
const sig = signed.slice(lastDot + 1);
|
|
35
|
+
if (!new EncryptionService(secret).verifyRaw(value, sig, "csrf"))
|
|
36
|
+
return null;
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
var ShieldInternals = {
|
|
40
|
+
sign,
|
|
41
|
+
verify,
|
|
42
|
+
randomToken
|
|
43
|
+
};
|
|
44
|
+
// packages/shield/src/guards/csrf.ts
|
|
45
|
+
class CsrfGuard {
|
|
46
|
+
config;
|
|
47
|
+
secret;
|
|
48
|
+
constructor(config, secret) {
|
|
49
|
+
this.config = {
|
|
50
|
+
enabled: config.enabled,
|
|
51
|
+
cookieName: config.cookieName ?? "nexus-csrf",
|
|
52
|
+
headerName: config.headerName ?? "x-csrf-token",
|
|
53
|
+
fieldName: config.fieldName ?? "_csrf",
|
|
54
|
+
protectGet: config.protectGet ?? false,
|
|
55
|
+
cookie: {
|
|
56
|
+
sameSite: config.cookie?.sameSite ?? "Lax",
|
|
57
|
+
secure: config.cookie?.secure ?? true,
|
|
58
|
+
httpOnly: config.cookie?.httpOnly ?? false,
|
|
59
|
+
path: config.cookie?.path ?? "/"
|
|
60
|
+
},
|
|
61
|
+
ignoreMethods: config.ignoreMethods ?? ["GET", "HEAD", "OPTIONS"]
|
|
62
|
+
};
|
|
63
|
+
this.secret = secret;
|
|
64
|
+
}
|
|
65
|
+
issue(res) {
|
|
66
|
+
const raw = ShieldInternals.randomToken();
|
|
67
|
+
const signed = ShieldInternals.sign(raw, this.secret);
|
|
68
|
+
const cookieParts = [
|
|
69
|
+
`${this.config.cookieName}=${raw}`,
|
|
70
|
+
`Path=${this.config.cookie.path}`,
|
|
71
|
+
`SameSite=${this.config.cookie.sameSite}`
|
|
72
|
+
];
|
|
73
|
+
if (this.config.cookie.secure)
|
|
74
|
+
cookieParts.push("Secure");
|
|
75
|
+
if (this.config.cookie.httpOnly)
|
|
76
|
+
cookieParts.push("HttpOnly");
|
|
77
|
+
res.append("Set-Cookie", cookieParts.join("; "));
|
|
78
|
+
return {
|
|
79
|
+
token: signed,
|
|
80
|
+
html: `<meta name="csrf-token" content="${signed}">`
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
verify(req) {
|
|
84
|
+
const method = req.method.toUpperCase();
|
|
85
|
+
if (this.config.ignoreMethods.map((m) => m.toUpperCase()).includes(method)) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
if (this.config.protectGet) {}
|
|
89
|
+
const cookieHeader = req.headers.get("cookie") ?? "";
|
|
90
|
+
const cookieToken = this.extractCookie(cookieHeader, this.config.cookieName);
|
|
91
|
+
if (!cookieToken)
|
|
92
|
+
return false;
|
|
93
|
+
const headerToken = req.headers.get(this.config.headerName);
|
|
94
|
+
if (headerToken && ShieldInternals.verify(headerToken, this.secret) === cookieToken) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
const fieldToken = req.headers.get("x-csrf-field");
|
|
98
|
+
if (fieldToken && ShieldInternals.verify(fieldToken, this.secret) === cookieToken) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
middleware() {
|
|
104
|
+
return async (c, next) => {
|
|
105
|
+
const method = c.req.method.toUpperCase();
|
|
106
|
+
if (this.config.ignoreMethods.map((m) => m.toUpperCase()).includes(method)) {
|
|
107
|
+
const cookieHeader = c.req.header("cookie") ?? "";
|
|
108
|
+
if (!this.extractCookie(cookieHeader, this.config.cookieName)) {
|
|
109
|
+
this.issue(c.res.headers);
|
|
110
|
+
}
|
|
111
|
+
return next();
|
|
112
|
+
}
|
|
113
|
+
if (!this.verify(c.req.raw)) {
|
|
114
|
+
return c.text("Invalid CSRF token", 403);
|
|
115
|
+
}
|
|
116
|
+
return next();
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
extractCookie(cookieHeader, name) {
|
|
120
|
+
for (const part of cookieHeader.split(";")) {
|
|
121
|
+
const [k, ...rest] = part.trim().split("=");
|
|
122
|
+
if (k === name)
|
|
123
|
+
return rest.join("=");
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// packages/shield/src/guards/headers.ts
|
|
129
|
+
class HeadersGuard {
|
|
130
|
+
hsts;
|
|
131
|
+
csp;
|
|
132
|
+
xFrameOptions;
|
|
133
|
+
xContentTypeOptions;
|
|
134
|
+
referrerPolicy;
|
|
135
|
+
constructor(hsts, csp, xFrameOptions, xContentTypeOptions, referrerPolicy) {
|
|
136
|
+
this.hsts = hsts;
|
|
137
|
+
this.csp = csp;
|
|
138
|
+
this.xFrameOptions = xFrameOptions;
|
|
139
|
+
this.xContentTypeOptions = xContentTypeOptions;
|
|
140
|
+
this.referrerPolicy = referrerPolicy;
|
|
141
|
+
}
|
|
142
|
+
apply(headers) {
|
|
143
|
+
if (this.hsts) {
|
|
144
|
+
const h = this.buildHstsHeader(this.hsts);
|
|
145
|
+
if (h)
|
|
146
|
+
headers.set("Strict-Transport-Security", h);
|
|
147
|
+
}
|
|
148
|
+
if (this.csp) {
|
|
149
|
+
const header = this.buildCspHeader(this.csp);
|
|
150
|
+
const name = this.csp.reportOnly ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy";
|
|
151
|
+
headers.set(name, header);
|
|
152
|
+
}
|
|
153
|
+
if (this.xFrameOptions) {
|
|
154
|
+
headers.set("X-Frame-Options", this.xFrameOptions);
|
|
155
|
+
}
|
|
156
|
+
if (this.xContentTypeOptions) {
|
|
157
|
+
headers.set("X-Content-Type-Options", "nosniff");
|
|
158
|
+
}
|
|
159
|
+
if (this.referrerPolicy) {
|
|
160
|
+
headers.set("Referrer-Policy", this.referrerPolicy);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
middleware() {
|
|
164
|
+
return async (_c, next) => {
|
|
165
|
+
this.apply(_c.res.headers);
|
|
166
|
+
return next();
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
buildHstsHeader(cfg) {
|
|
170
|
+
let v = `max-age=${cfg.maxAge}`;
|
|
171
|
+
if (cfg.includeSubDomains)
|
|
172
|
+
v += "; includeSubDomains";
|
|
173
|
+
if (cfg.preload)
|
|
174
|
+
v += "; preload";
|
|
175
|
+
return v;
|
|
176
|
+
}
|
|
177
|
+
buildCspHeader(cfg) {
|
|
178
|
+
const parts = [];
|
|
179
|
+
for (const [name, values] of Object.entries(cfg.directives)) {
|
|
180
|
+
if (!values || values.length === 0)
|
|
181
|
+
continue;
|
|
182
|
+
parts.push(`${camelToKebab(name)} ${values.join(" ")}`);
|
|
183
|
+
}
|
|
184
|
+
if (cfg.reportUri)
|
|
185
|
+
parts.push(`report-uri ${cfg.reportUri}`);
|
|
186
|
+
return parts.join("; ");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function camelToKebab(s) {
|
|
190
|
+
return s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
191
|
+
}
|
|
192
|
+
// packages/shield/src/shield.service.ts
|
|
193
|
+
import { Inject, Injectable } from "@nexusts/core/decorators/index.js";
|
|
194
|
+
class ShieldService {
|
|
195
|
+
static TOKEN = Symbol.for("nexus:ShieldService");
|
|
196
|
+
csrf;
|
|
197
|
+
headers;
|
|
198
|
+
constructor(config = {}) {
|
|
199
|
+
if (config.csrf) {
|
|
200
|
+
const secret = config.secret ?? process.env["NEXUS_SHIELD_SECRET"] ?? "change-me-in-production-please";
|
|
201
|
+
this.csrf = new CsrfGuard(config.csrf, secret);
|
|
202
|
+
}
|
|
203
|
+
this.headers = new HeadersGuard(config.hsts ?? false, config.csp ?? false, config.xFrameOptions ?? "SAMEORIGIN", config.xContentTypeOptions ?? true, config.referrerPolicy);
|
|
204
|
+
}
|
|
205
|
+
middleware() {
|
|
206
|
+
return async (c, next) => {
|
|
207
|
+
if (this.csrf) {
|
|
208
|
+
const method = c.req.method.toUpperCase();
|
|
209
|
+
const ignoreMethods = this.csrf.config.ignoreMethods;
|
|
210
|
+
if (ignoreMethods.map((m) => m.toUpperCase()).includes(method)) {
|
|
211
|
+
const cookieHeader = c.req.header("cookie") ?? "";
|
|
212
|
+
const cookieName = this.csrf.config.cookieName;
|
|
213
|
+
if (!this.extractCookie(cookieHeader, cookieName)) {
|
|
214
|
+
this.csrf.issue(c.res.headers);
|
|
215
|
+
}
|
|
216
|
+
} else if (!this.csrf.verify(c.req.raw)) {
|
|
217
|
+
const resp = c.text("Invalid CSRF token", 403);
|
|
218
|
+
this.headers.apply(resp.headers);
|
|
219
|
+
return resp;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
this.headers.apply(c.res.headers);
|
|
223
|
+
return next();
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
issueToken(headers) {
|
|
227
|
+
if (!this.csrf)
|
|
228
|
+
throw new Error("CSRF guard is not enabled");
|
|
229
|
+
return this.csrf.issue(headers);
|
|
230
|
+
}
|
|
231
|
+
extractCookie(cookieHeader, name) {
|
|
232
|
+
for (const part of cookieHeader.split(";")) {
|
|
233
|
+
const [k, ...rest] = part.trim().split("=");
|
|
234
|
+
if (k === name)
|
|
235
|
+
return rest.join("=");
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
ShieldService = __legacyDecorateClassTS([
|
|
241
|
+
Injectable(),
|
|
242
|
+
__legacyDecorateParamTS(0, Inject("SHIELD_CONFIG")),
|
|
243
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
244
|
+
typeof ShieldConfig === "undefined" ? Object : ShieldConfig
|
|
245
|
+
])
|
|
246
|
+
], ShieldService);
|
|
247
|
+
// packages/shield/src/shield.module.ts
|
|
248
|
+
import"reflect-metadata";
|
|
249
|
+
import { Module } from "@nexusts/core/decorators/module.js";
|
|
250
|
+
class ShieldModule {
|
|
251
|
+
static forRoot(config = {}) {
|
|
252
|
+
class ConfiguredShieldModule {
|
|
253
|
+
}
|
|
254
|
+
ConfiguredShieldModule = __legacyDecorateClassTS([
|
|
255
|
+
Module({
|
|
256
|
+
providers: [
|
|
257
|
+
ShieldService,
|
|
258
|
+
{ provide: ShieldService.TOKEN, useExisting: ShieldService },
|
|
259
|
+
{ provide: "SHIELD_CONFIG", useValue: config }
|
|
260
|
+
],
|
|
261
|
+
exports: [ShieldService, ShieldService.TOKEN]
|
|
262
|
+
})
|
|
263
|
+
], ConfiguredShieldModule);
|
|
264
|
+
Object.defineProperty(ConfiguredShieldModule, "name", {
|
|
265
|
+
value: "ConfiguredShieldModule"
|
|
266
|
+
});
|
|
267
|
+
return ConfiguredShieldModule;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
ShieldModule = __legacyDecorateClassTS([
|
|
271
|
+
Module({
|
|
272
|
+
providers: [
|
|
273
|
+
ShieldService,
|
|
274
|
+
{ provide: ShieldService.TOKEN, useExisting: ShieldService }
|
|
275
|
+
],
|
|
276
|
+
exports: [ShieldService, ShieldService.TOKEN]
|
|
277
|
+
})
|
|
278
|
+
], ShieldModule);
|
|
279
|
+
export {
|
|
280
|
+
ShieldService,
|
|
281
|
+
ShieldModule,
|
|
282
|
+
ShieldInternals,
|
|
283
|
+
HeadersGuard,
|
|
284
|
+
CsrfGuard
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
//# debugId=EC20B67E8295EF5064756E2164756E21
|
|
288
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/types.ts", "../src/guards/csrf.ts", "../src/guards/headers.ts", "../src/shield.service.ts", "../src/shield.module.ts"],
|
|
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/encryption.js\";\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",
|
|
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
|
+
"/**\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/decorators/index.js\";\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",
|
|
9
|
+
"/**\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/decorators/module.js\";\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
|
+
"mappings": "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",
|
|
12
|
+
"debugId": "EC20B67E8295EF5064756E2164756E21",
|
|
13
|
+
"names": []
|
|
14
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nexusts/shield",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "CSRF / HSTS / CSP security middleware",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "bun run ../../build.ts"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"nexusts",
|
|
24
|
+
"framework",
|
|
25
|
+
"bun"
|
|
26
|
+
],
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@nexusts/core": "^0.7.0"
|
|
30
|
+
}
|
|
31
|
+
}
|