@taujs/server 0.3.3 → 0.3.5
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/dist/{SSRServer-C9yjcgke.d.ts → SSRServer-DPZped7n.d.ts} +7 -3
- package/dist/build.d.ts +1 -1
- package/dist/build.js +79 -88
- package/dist/config.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +79 -88
- package/dist/security/csp.d.ts +1 -1
- package/dist/security/csp.js +10 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ServerResponse } from 'node:http';
|
|
2
|
-
import { FastifyRequest, FastifyReply, HookHandlerDoneFunction, FastifyPluginAsync,
|
|
2
|
+
import { FastifyRequest, FastifyReply, HookHandlerDoneFunction, FastifyPluginAsync, FastifyPluginCallback } from 'fastify';
|
|
3
3
|
import { PluginOption } from 'vite';
|
|
4
4
|
|
|
5
5
|
type CSPDirectives = Record<string, string[]>;
|
|
@@ -69,7 +69,10 @@ type SSRServerOptions = {
|
|
|
69
69
|
generateCSP?: (directives: CSPDirectives, nonce: string) => string;
|
|
70
70
|
};
|
|
71
71
|
};
|
|
72
|
-
registerStaticAssets?: false |
|
|
72
|
+
registerStaticAssets?: false | {
|
|
73
|
+
plugin: FastifyPluginCallback<any> | FastifyPluginAsync<any>;
|
|
74
|
+
options?: Record<string, unknown>;
|
|
75
|
+
};
|
|
73
76
|
isDebug?: boolean;
|
|
74
77
|
};
|
|
75
78
|
type ServiceMethod = (params: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
@@ -103,6 +106,7 @@ type RenderModule = {
|
|
|
103
106
|
renderSSR: RenderSSR;
|
|
104
107
|
renderStream: RenderStream;
|
|
105
108
|
};
|
|
109
|
+
type GenericPlugin = FastifyPluginCallback<Record<string, unknown>> | FastifyPluginAsync<Record<string, unknown>>;
|
|
106
110
|
type BaseMiddleware = {
|
|
107
111
|
auth?: {
|
|
108
112
|
required: boolean;
|
|
@@ -146,4 +150,4 @@ interface InitialRouteParams extends Record<string, unknown> {
|
|
|
146
150
|
type RouteParams = InitialRouteParams & Record<string, unknown>;
|
|
147
151
|
type RoutePathsAndAttributes<Params = {}> = Omit<Route<Params>, 'element'>;
|
|
148
152
|
|
|
149
|
-
export { type BaseMiddleware as B, type Config as C, type DataResult as D, type InitialRouteParams as I, type ManifestEntry as M, type NamedService as N, type ProcessedConfig as P, type Route as R, SSRServer as S, TEMPLATE as T, type RouteParams as a, type RouteAttributes as b, createMaps as c, type SSRServerOptions as d, type ServiceMethod as e, type ServiceRegistry as f, type RenderCallbacks as g, type SSRManifest as h, type Manifest as i, type RenderSSR as j, type RenderStream as k, type RenderModule as l, type ServiceCall as m, type DataHandler as n, type RoutePathsAndAttributes as o, processConfigs as p, type CSPDirectives as q, type CSPOptions as r, defaultGenerateCSP as s, generateNonce as t, createCSPHook as u, getRequestNonce as v, applyCSP as w };
|
|
153
|
+
export { type BaseMiddleware as B, type Config as C, type DataResult as D, type GenericPlugin as G, type InitialRouteParams as I, type ManifestEntry as M, type NamedService as N, type ProcessedConfig as P, type Route as R, SSRServer as S, TEMPLATE as T, type RouteParams as a, type RouteAttributes as b, createMaps as c, type SSRServerOptions as d, type ServiceMethod as e, type ServiceRegistry as f, type RenderCallbacks as g, type SSRManifest as h, type Manifest as i, type RenderSSR as j, type RenderStream as k, type RenderModule as l, type ServiceCall as m, type DataHandler as n, type RoutePathsAndAttributes as o, processConfigs as p, type CSPDirectives as q, type CSPOptions as r, defaultGenerateCSP as s, generateNonce as t, createCSPHook as u, getRequestNonce as v, applyCSP as w };
|
package/dist/build.d.ts
CHANGED
package/dist/build.js
CHANGED
|
@@ -267,64 +267,6 @@ function createAuthHook(routes, isDebug) {
|
|
|
267
267
|
|
|
268
268
|
// src/security/csp.ts
|
|
269
269
|
import crypto from "crypto";
|
|
270
|
-
var defaultGenerateCSP = (directives, nonce) => {
|
|
271
|
-
const merged = { ...directives };
|
|
272
|
-
merged["script-src"] = merged["script-src"] || ["'self'"];
|
|
273
|
-
if (!merged["script-src"].some((v) => v.startsWith("'nonce-"))) merged["script-src"].push(`'nonce-${nonce}'`);
|
|
274
|
-
if (process.env.NODE_ENV !== "production") {
|
|
275
|
-
const connect = merged["connect-src"] || ["'self'"];
|
|
276
|
-
if (!connect.includes("ws:")) connect.push("ws:");
|
|
277
|
-
if (!connect.includes("http:")) connect.push("http:");
|
|
278
|
-
merged["connect-src"] = connect;
|
|
279
|
-
const style = merged["style-src"] || ["'self'"];
|
|
280
|
-
if (!style.includes("'unsafe-inline'")) style.push("'unsafe-inline'");
|
|
281
|
-
merged["style-src"] = style;
|
|
282
|
-
}
|
|
283
|
-
return Object.entries(merged).map(([key, values]) => `${key} ${values.join(" ")}`).join("; ");
|
|
284
|
-
};
|
|
285
|
-
var generateNonce = () => crypto.randomBytes(16).toString("base64");
|
|
286
|
-
var createCSPHook = (options = {}) => (req, reply, done) => {
|
|
287
|
-
const nonce = generateNonce();
|
|
288
|
-
const directives = options.directives ?? DEV_CSP_DIRECTIVES;
|
|
289
|
-
const generate = options.generateCSP ?? defaultGenerateCSP;
|
|
290
|
-
const cspHeader = generate(directives, nonce);
|
|
291
|
-
reply.header("Content-Security-Policy", cspHeader);
|
|
292
|
-
if (typeof options.exposeNonce === "function") {
|
|
293
|
-
options.exposeNonce(req, nonce);
|
|
294
|
-
} else {
|
|
295
|
-
req.nonce = nonce;
|
|
296
|
-
}
|
|
297
|
-
done();
|
|
298
|
-
};
|
|
299
|
-
var applyCSP = (security, reply) => {
|
|
300
|
-
const nonce = generateNonce();
|
|
301
|
-
const directives = security?.csp?.directives ?? DEV_CSP_DIRECTIVES;
|
|
302
|
-
const generate = security?.csp?.generateCSP ?? defaultGenerateCSP;
|
|
303
|
-
const header = generate(directives, nonce);
|
|
304
|
-
reply.header("Content-Security-Policy", header);
|
|
305
|
-
reply.request.nonce = nonce;
|
|
306
|
-
return nonce;
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
// src/security/verifyMiddleware.ts
|
|
310
|
-
var isAuthRequired = (r) => r.attr?.middleware?.auth?.required === true;
|
|
311
|
-
var hasAuthenticate = (app) => typeof app.authenticate === "function";
|
|
312
|
-
var verifyContracts = (app, routes, contracts, isDebug) => {
|
|
313
|
-
const logger = createLogger(Boolean(isDebug));
|
|
314
|
-
for (const contract of contracts) {
|
|
315
|
-
const isUsed = routes.some(contract.required);
|
|
316
|
-
if (!isUsed) {
|
|
317
|
-
debugLog(logger, `Middleware "${contract.key}" not used in any routes`);
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
if (!contract.verify(app)) {
|
|
321
|
-
const error = new Error(`[\u03C4js] ${contract.errorMessage}`);
|
|
322
|
-
logger.error(error.message);
|
|
323
|
-
throw error;
|
|
324
|
-
}
|
|
325
|
-
debugLog(logger, `Middleware "${contract.key}" verified \u2713`);
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
270
|
|
|
329
271
|
// src/utils/Utils.ts
|
|
330
272
|
import { dirname, join } from "path";
|
|
@@ -412,19 +354,17 @@ var isServiceDescriptor = (obj) => {
|
|
|
412
354
|
return typeof maybe.serviceName === "string" && typeof maybe.serviceMethod === "string";
|
|
413
355
|
};
|
|
414
356
|
var fetchInitialData = async (attr, params, serviceRegistry, ctx = { headers: {} }, callServiceMethodImpl = callServiceMethod) => {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
return
|
|
357
|
+
const dataHandler = attr?.data;
|
|
358
|
+
if (!dataHandler || typeof dataHandler !== "function") return Promise.resolve({});
|
|
359
|
+
return dataHandler(params, ctx).then(async (result) => {
|
|
360
|
+
if (isServiceDescriptor(result)) {
|
|
361
|
+
const { serviceName, serviceMethod, args } = result;
|
|
362
|
+
if (serviceRegistry[serviceName]?.[serviceMethod]) return callServiceMethodImpl(serviceRegistry, serviceName, serviceMethod, args ?? {});
|
|
363
|
+
throw new Error(`Invalid service: serviceName=${String(serviceName)}, method=${String(serviceMethod)}`);
|
|
421
364
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return result;
|
|
426
|
-
}
|
|
427
|
-
throw new Error("Invalid result from attr.data");
|
|
365
|
+
if (typeof result === "object" && result !== null) return result;
|
|
366
|
+
throw new Error("Invalid result from attr.data");
|
|
367
|
+
});
|
|
428
368
|
};
|
|
429
369
|
var matchRoute = (url, renderRoutes) => {
|
|
430
370
|
for (const route of renderRoutes) {
|
|
@@ -464,6 +404,66 @@ var ensureNonNull = (value, errorMessage) => {
|
|
|
464
404
|
return value;
|
|
465
405
|
};
|
|
466
406
|
|
|
407
|
+
// src/security/csp.ts
|
|
408
|
+
var defaultGenerateCSP = (directives, nonce) => {
|
|
409
|
+
const merged = { ...directives };
|
|
410
|
+
merged["script-src"] = merged["script-src"] || ["'self'"];
|
|
411
|
+
if (!merged["script-src"].some((v) => v.startsWith("'nonce-"))) merged["script-src"].push(`'nonce-${nonce}'`);
|
|
412
|
+
if (isDevelopment) {
|
|
413
|
+
const connect = merged["connect-src"] || ["'self'"];
|
|
414
|
+
if (!connect.includes("ws:")) connect.push("ws:");
|
|
415
|
+
if (!connect.includes("http:")) connect.push("http:");
|
|
416
|
+
merged["connect-src"] = connect;
|
|
417
|
+
const style = merged["style-src"] || ["'self'"];
|
|
418
|
+
if (!style.includes("'unsafe-inline'")) style.push("'unsafe-inline'");
|
|
419
|
+
merged["style-src"] = style;
|
|
420
|
+
}
|
|
421
|
+
return Object.entries(merged).map(([key, values]) => `${key} ${values.join(" ")}`).join("; ");
|
|
422
|
+
};
|
|
423
|
+
var generateNonce = () => crypto.randomBytes(16).toString("base64");
|
|
424
|
+
var createCSPHook = (options = {}) => (req, reply, done) => {
|
|
425
|
+
const nonce = generateNonce();
|
|
426
|
+
const directives = options.directives ?? DEV_CSP_DIRECTIVES;
|
|
427
|
+
const generate = options.generateCSP ?? defaultGenerateCSP;
|
|
428
|
+
const cspHeader = generate(directives, nonce);
|
|
429
|
+
reply.header("Content-Security-Policy", cspHeader);
|
|
430
|
+
if (typeof options.exposeNonce === "function") {
|
|
431
|
+
options.exposeNonce(req, nonce);
|
|
432
|
+
} else {
|
|
433
|
+
req.nonce = nonce;
|
|
434
|
+
}
|
|
435
|
+
done();
|
|
436
|
+
};
|
|
437
|
+
var applyCSP = (security, reply) => {
|
|
438
|
+
const nonce = generateNonce();
|
|
439
|
+
const directives = security?.csp?.directives ?? DEV_CSP_DIRECTIVES;
|
|
440
|
+
const generate = security?.csp?.generateCSP ?? defaultGenerateCSP;
|
|
441
|
+
const header = generate(directives, nonce);
|
|
442
|
+
reply.header("Content-Security-Policy", header);
|
|
443
|
+
reply.request.nonce = nonce;
|
|
444
|
+
return nonce;
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
// src/security/verifyMiddleware.ts
|
|
448
|
+
var isAuthRequired = (r) => r.attr?.middleware?.auth?.required === true;
|
|
449
|
+
var hasAuthenticate = (app) => typeof app.authenticate === "function";
|
|
450
|
+
var verifyContracts = (app, routes, contracts, isDebug) => {
|
|
451
|
+
const logger = createLogger(Boolean(isDebug));
|
|
452
|
+
for (const contract of contracts) {
|
|
453
|
+
const isUsed = routes.some(contract.required);
|
|
454
|
+
if (!isUsed) {
|
|
455
|
+
debugLog(logger, `Middleware "${contract.key}" not used in any routes`);
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
if (!contract.verify(app)) {
|
|
459
|
+
const error = new Error(`[\u03C4js] ${contract.errorMessage}`);
|
|
460
|
+
logger.error(error.message);
|
|
461
|
+
throw error;
|
|
462
|
+
}
|
|
463
|
+
debugLog(logger, `Middleware "${contract.key}" verified \u2713`);
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
|
|
467
467
|
// src/SSRServer.ts
|
|
468
468
|
var createMaps = () => {
|
|
469
469
|
return {
|
|
@@ -538,24 +538,15 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
538
538
|
],
|
|
539
539
|
opts.isDebug
|
|
540
540
|
);
|
|
541
|
-
if (opts.registerStaticAssets
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
root: baseClientRoot,
|
|
551
|
-
wildcard: false
|
|
552
|
-
});
|
|
553
|
-
} catch (err) {
|
|
554
|
-
throw new Error(
|
|
555
|
-
"Static asset handling requires @fastify/static to be installed. Either install it or provide your own static asset handler using `registerStaticAssets`."
|
|
556
|
-
);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
541
|
+
if (opts.registerStaticAssets && typeof opts.registerStaticAssets === "object") {
|
|
542
|
+
const { plugin, options } = opts.registerStaticAssets;
|
|
543
|
+
await app.register(plugin, {
|
|
544
|
+
root: baseClientRoot,
|
|
545
|
+
prefix: "/",
|
|
546
|
+
index: false,
|
|
547
|
+
wildcard: false,
|
|
548
|
+
...options ?? {}
|
|
549
|
+
});
|
|
559
550
|
}
|
|
560
551
|
app.addHook(
|
|
561
552
|
"onRequest",
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PluginOption } from 'vite';
|
|
2
|
-
import { R as Route, a as RouteParams, b as RouteAttributes } from './SSRServer-
|
|
2
|
+
import { R as Route, a as RouteParams, b as RouteAttributes } from './SSRServer-DPZped7n.js';
|
|
3
3
|
import 'node:http';
|
|
4
4
|
import 'fastify';
|
|
5
5
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FastifyReply } from 'fastify';
|
|
2
|
-
export { B as BaseMiddleware, C as Config, n as DataHandler, D as DataResult, I as InitialRouteParams, i as Manifest, M as ManifestEntry, N as NamedService, P as ProcessedConfig, g as RenderCallbacks, l as RenderModule, j as RenderSSR, k as RenderStream, R as Route, b as RouteAttributes, a as RouteParams, o as RoutePathsAndAttributes, h as SSRManifest, S as SSRServer, d as SSRServerOptions, m as ServiceCall, e as ServiceMethod, f as ServiceRegistry, T as TEMPLATE, c as createMaps, p as processConfigs } from './SSRServer-
|
|
2
|
+
export { B as BaseMiddleware, C as Config, n as DataHandler, D as DataResult, G as GenericPlugin, I as InitialRouteParams, i as Manifest, M as ManifestEntry, N as NamedService, P as ProcessedConfig, g as RenderCallbacks, l as RenderModule, j as RenderSSR, k as RenderStream, R as Route, b as RouteAttributes, a as RouteParams, o as RoutePathsAndAttributes, h as SSRManifest, S as SSRServer, d as SSRServerOptions, m as ServiceCall, e as ServiceMethod, f as ServiceRegistry, T as TEMPLATE, c as createMaps, p as processConfigs } from './SSRServer-DPZped7n.js';
|
|
3
3
|
import 'node:http';
|
|
4
4
|
import 'vite';
|
|
5
5
|
|
package/dist/index.js
CHANGED
|
@@ -265,64 +265,6 @@ function createAuthHook(routes, isDebug) {
|
|
|
265
265
|
|
|
266
266
|
// src/security/csp.ts
|
|
267
267
|
import crypto from "crypto";
|
|
268
|
-
var defaultGenerateCSP = (directives, nonce) => {
|
|
269
|
-
const merged = { ...directives };
|
|
270
|
-
merged["script-src"] = merged["script-src"] || ["'self'"];
|
|
271
|
-
if (!merged["script-src"].some((v) => v.startsWith("'nonce-"))) merged["script-src"].push(`'nonce-${nonce}'`);
|
|
272
|
-
if (process.env.NODE_ENV !== "production") {
|
|
273
|
-
const connect = merged["connect-src"] || ["'self'"];
|
|
274
|
-
if (!connect.includes("ws:")) connect.push("ws:");
|
|
275
|
-
if (!connect.includes("http:")) connect.push("http:");
|
|
276
|
-
merged["connect-src"] = connect;
|
|
277
|
-
const style = merged["style-src"] || ["'self'"];
|
|
278
|
-
if (!style.includes("'unsafe-inline'")) style.push("'unsafe-inline'");
|
|
279
|
-
merged["style-src"] = style;
|
|
280
|
-
}
|
|
281
|
-
return Object.entries(merged).map(([key, values]) => `${key} ${values.join(" ")}`).join("; ");
|
|
282
|
-
};
|
|
283
|
-
var generateNonce = () => crypto.randomBytes(16).toString("base64");
|
|
284
|
-
var createCSPHook = (options = {}) => (req, reply, done) => {
|
|
285
|
-
const nonce = generateNonce();
|
|
286
|
-
const directives = options.directives ?? DEV_CSP_DIRECTIVES;
|
|
287
|
-
const generate = options.generateCSP ?? defaultGenerateCSP;
|
|
288
|
-
const cspHeader = generate(directives, nonce);
|
|
289
|
-
reply.header("Content-Security-Policy", cspHeader);
|
|
290
|
-
if (typeof options.exposeNonce === "function") {
|
|
291
|
-
options.exposeNonce(req, nonce);
|
|
292
|
-
} else {
|
|
293
|
-
req.nonce = nonce;
|
|
294
|
-
}
|
|
295
|
-
done();
|
|
296
|
-
};
|
|
297
|
-
var applyCSP = (security, reply) => {
|
|
298
|
-
const nonce = generateNonce();
|
|
299
|
-
const directives = security?.csp?.directives ?? DEV_CSP_DIRECTIVES;
|
|
300
|
-
const generate = security?.csp?.generateCSP ?? defaultGenerateCSP;
|
|
301
|
-
const header = generate(directives, nonce);
|
|
302
|
-
reply.header("Content-Security-Policy", header);
|
|
303
|
-
reply.request.nonce = nonce;
|
|
304
|
-
return nonce;
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
// src/security/verifyMiddleware.ts
|
|
308
|
-
var isAuthRequired = (r) => r.attr?.middleware?.auth?.required === true;
|
|
309
|
-
var hasAuthenticate = (app) => typeof app.authenticate === "function";
|
|
310
|
-
var verifyContracts = (app, routes, contracts, isDebug) => {
|
|
311
|
-
const logger = createLogger(Boolean(isDebug));
|
|
312
|
-
for (const contract of contracts) {
|
|
313
|
-
const isUsed = routes.some(contract.required);
|
|
314
|
-
if (!isUsed) {
|
|
315
|
-
debugLog(logger, `Middleware "${contract.key}" not used in any routes`);
|
|
316
|
-
continue;
|
|
317
|
-
}
|
|
318
|
-
if (!contract.verify(app)) {
|
|
319
|
-
const error = new Error(`[\u03C4js] ${contract.errorMessage}`);
|
|
320
|
-
logger.error(error.message);
|
|
321
|
-
throw error;
|
|
322
|
-
}
|
|
323
|
-
debugLog(logger, `Middleware "${contract.key}" verified \u2713`);
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
268
|
|
|
327
269
|
// src/utils/Utils.ts
|
|
328
270
|
import { dirname, join } from "path";
|
|
@@ -410,19 +352,17 @@ var isServiceDescriptor = (obj) => {
|
|
|
410
352
|
return typeof maybe.serviceName === "string" && typeof maybe.serviceMethod === "string";
|
|
411
353
|
};
|
|
412
354
|
var fetchInitialData = async (attr, params, serviceRegistry, ctx = { headers: {} }, callServiceMethodImpl = callServiceMethod) => {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
return
|
|
355
|
+
const dataHandler = attr?.data;
|
|
356
|
+
if (!dataHandler || typeof dataHandler !== "function") return Promise.resolve({});
|
|
357
|
+
return dataHandler(params, ctx).then(async (result) => {
|
|
358
|
+
if (isServiceDescriptor(result)) {
|
|
359
|
+
const { serviceName, serviceMethod, args } = result;
|
|
360
|
+
if (serviceRegistry[serviceName]?.[serviceMethod]) return callServiceMethodImpl(serviceRegistry, serviceName, serviceMethod, args ?? {});
|
|
361
|
+
throw new Error(`Invalid service: serviceName=${String(serviceName)}, method=${String(serviceMethod)}`);
|
|
419
362
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
return result;
|
|
424
|
-
}
|
|
425
|
-
throw new Error("Invalid result from attr.data");
|
|
363
|
+
if (typeof result === "object" && result !== null) return result;
|
|
364
|
+
throw new Error("Invalid result from attr.data");
|
|
365
|
+
});
|
|
426
366
|
};
|
|
427
367
|
var matchRoute = (url, renderRoutes) => {
|
|
428
368
|
for (const route of renderRoutes) {
|
|
@@ -462,6 +402,66 @@ var ensureNonNull = (value, errorMessage) => {
|
|
|
462
402
|
return value;
|
|
463
403
|
};
|
|
464
404
|
|
|
405
|
+
// src/security/csp.ts
|
|
406
|
+
var defaultGenerateCSP = (directives, nonce) => {
|
|
407
|
+
const merged = { ...directives };
|
|
408
|
+
merged["script-src"] = merged["script-src"] || ["'self'"];
|
|
409
|
+
if (!merged["script-src"].some((v) => v.startsWith("'nonce-"))) merged["script-src"].push(`'nonce-${nonce}'`);
|
|
410
|
+
if (isDevelopment) {
|
|
411
|
+
const connect = merged["connect-src"] || ["'self'"];
|
|
412
|
+
if (!connect.includes("ws:")) connect.push("ws:");
|
|
413
|
+
if (!connect.includes("http:")) connect.push("http:");
|
|
414
|
+
merged["connect-src"] = connect;
|
|
415
|
+
const style = merged["style-src"] || ["'self'"];
|
|
416
|
+
if (!style.includes("'unsafe-inline'")) style.push("'unsafe-inline'");
|
|
417
|
+
merged["style-src"] = style;
|
|
418
|
+
}
|
|
419
|
+
return Object.entries(merged).map(([key, values]) => `${key} ${values.join(" ")}`).join("; ");
|
|
420
|
+
};
|
|
421
|
+
var generateNonce = () => crypto.randomBytes(16).toString("base64");
|
|
422
|
+
var createCSPHook = (options = {}) => (req, reply, done) => {
|
|
423
|
+
const nonce = generateNonce();
|
|
424
|
+
const directives = options.directives ?? DEV_CSP_DIRECTIVES;
|
|
425
|
+
const generate = options.generateCSP ?? defaultGenerateCSP;
|
|
426
|
+
const cspHeader = generate(directives, nonce);
|
|
427
|
+
reply.header("Content-Security-Policy", cspHeader);
|
|
428
|
+
if (typeof options.exposeNonce === "function") {
|
|
429
|
+
options.exposeNonce(req, nonce);
|
|
430
|
+
} else {
|
|
431
|
+
req.nonce = nonce;
|
|
432
|
+
}
|
|
433
|
+
done();
|
|
434
|
+
};
|
|
435
|
+
var applyCSP = (security, reply) => {
|
|
436
|
+
const nonce = generateNonce();
|
|
437
|
+
const directives = security?.csp?.directives ?? DEV_CSP_DIRECTIVES;
|
|
438
|
+
const generate = security?.csp?.generateCSP ?? defaultGenerateCSP;
|
|
439
|
+
const header = generate(directives, nonce);
|
|
440
|
+
reply.header("Content-Security-Policy", header);
|
|
441
|
+
reply.request.nonce = nonce;
|
|
442
|
+
return nonce;
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
// src/security/verifyMiddleware.ts
|
|
446
|
+
var isAuthRequired = (r) => r.attr?.middleware?.auth?.required === true;
|
|
447
|
+
var hasAuthenticate = (app) => typeof app.authenticate === "function";
|
|
448
|
+
var verifyContracts = (app, routes, contracts, isDebug) => {
|
|
449
|
+
const logger = createLogger(Boolean(isDebug));
|
|
450
|
+
for (const contract of contracts) {
|
|
451
|
+
const isUsed = routes.some(contract.required);
|
|
452
|
+
if (!isUsed) {
|
|
453
|
+
debugLog(logger, `Middleware "${contract.key}" not used in any routes`);
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
if (!contract.verify(app)) {
|
|
457
|
+
const error = new Error(`[\u03C4js] ${contract.errorMessage}`);
|
|
458
|
+
logger.error(error.message);
|
|
459
|
+
throw error;
|
|
460
|
+
}
|
|
461
|
+
debugLog(logger, `Middleware "${contract.key}" verified \u2713`);
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
|
|
465
465
|
// src/SSRServer.ts
|
|
466
466
|
var createMaps = () => {
|
|
467
467
|
return {
|
|
@@ -536,24 +536,15 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
536
536
|
],
|
|
537
537
|
opts.isDebug
|
|
538
538
|
);
|
|
539
|
-
if (opts.registerStaticAssets
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
root: baseClientRoot,
|
|
549
|
-
wildcard: false
|
|
550
|
-
});
|
|
551
|
-
} catch (err) {
|
|
552
|
-
throw new Error(
|
|
553
|
-
"Static asset handling requires @fastify/static to be installed. Either install it or provide your own static asset handler using `registerStaticAssets`."
|
|
554
|
-
);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
539
|
+
if (opts.registerStaticAssets && typeof opts.registerStaticAssets === "object") {
|
|
540
|
+
const { plugin, options } = opts.registerStaticAssets;
|
|
541
|
+
await app.register(plugin, {
|
|
542
|
+
root: baseClientRoot,
|
|
543
|
+
prefix: "/",
|
|
544
|
+
index: false,
|
|
545
|
+
wildcard: false,
|
|
546
|
+
...options ?? {}
|
|
547
|
+
});
|
|
557
548
|
}
|
|
558
549
|
app.addHook(
|
|
559
550
|
"onRequest",
|
package/dist/security/csp.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'fastify';
|
|
2
|
-
export { q as CSPDirectives, r as CSPOptions, w as applyCSP, u as createCSPHook, s as defaultGenerateCSP, t as generateNonce, v as getRequestNonce } from '../SSRServer-
|
|
2
|
+
export { q as CSPDirectives, r as CSPOptions, w as applyCSP, u as createCSPHook, s as defaultGenerateCSP, t as generateNonce, v as getRequestNonce } from '../SSRServer-DPZped7n.js';
|
|
3
3
|
import 'node:http';
|
|
4
4
|
import 'vite';
|
package/dist/security/csp.js
CHANGED
|
@@ -9,12 +9,21 @@ var DEV_CSP_DIRECTIVES = {
|
|
|
9
9
|
"img-src": ["'self'", "data:"]
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/utils/Utils.ts
|
|
13
|
+
import { dirname, join } from "path";
|
|
14
|
+
import "path";
|
|
15
|
+
import { fileURLToPath } from "url";
|
|
16
|
+
import { match } from "path-to-regexp";
|
|
17
|
+
var isDevelopment = process.env.NODE_ENV === "development";
|
|
18
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
var __dirname = join(dirname(__filename), !isDevelopment ? "./" : "..");
|
|
20
|
+
|
|
12
21
|
// src/security/csp.ts
|
|
13
22
|
var defaultGenerateCSP = (directives, nonce) => {
|
|
14
23
|
const merged = { ...directives };
|
|
15
24
|
merged["script-src"] = merged["script-src"] || ["'self'"];
|
|
16
25
|
if (!merged["script-src"].some((v) => v.startsWith("'nonce-"))) merged["script-src"].push(`'nonce-${nonce}'`);
|
|
17
|
-
if (
|
|
26
|
+
if (isDevelopment) {
|
|
18
27
|
const connect = merged["connect-src"] || ["'self'"];
|
|
19
28
|
if (!connect.includes("ws:")) connect.push("ws:");
|
|
20
29
|
if (!connect.includes("http:")) connect.push("http:");
|