2026-05-03 19:51:57 -05:00
|
|
|
'use strict';
|
|
|
|
|
|
refactor(server): migrate middleware, workers, and db layer to TypeScript (.cts)
- middleware/ (5): requireAuth, securityHeaders, errorFormatter, csrf,
rateLimiter — fully typed against the shared http Req/Res/Next types.
- workers/dailyWorker — fully typed.
- db/ (4): database, subscriptionCatalogSeed, migrations/versionedMigrations,
migrations/legacyReconcileMigrations — large dynamic schema/migration infra,
converted with @ts-nocheck (typing deferred). All requires updated to .cts.
Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:34:08 -05:00
|
|
|
import type { Req, Res, Next } from '../types/http';
|
|
|
|
|
|
2026-05-09 13:03:36 -05:00
|
|
|
const crypto = require('crypto');
|
|
|
|
|
|
refactor(server): migrate middleware, workers, and db layer to TypeScript (.cts)
- middleware/ (5): requireAuth, securityHeaders, errorFormatter, csrf,
rateLimiter — fully typed against the shared http Req/Res/Next types.
- workers/dailyWorker — fully typed.
- db/ (4): database, subscriptionCatalogSeed, migrations/versionedMigrations,
migrations/legacyReconcileMigrations — large dynamic schema/migration infra,
converted with @ts-nocheck (typing deferred). All requires updated to .cts.
Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:34:08 -05:00
|
|
|
/** Generates a secure nonce for CSP policy. Call once per request. */
|
|
|
|
|
function getCspNonce(req: Req): string {
|
2026-05-09 13:03:36 -05:00
|
|
|
if (!req.cspNonce) {
|
|
|
|
|
req.cspNonce = crypto.randomBytes(16).toString('base64');
|
|
|
|
|
}
|
|
|
|
|
return req.cspNonce;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-03 19:51:57 -05:00
|
|
|
/**
|
|
|
|
|
* Applies baseline security response headers on every request.
|
refactor(server): migrate middleware, workers, and db layer to TypeScript (.cts)
- middleware/ (5): requireAuth, securityHeaders, errorFormatter, csrf,
rateLimiter — fully typed against the shared http Req/Res/Next types.
- workers/dailyWorker — fully typed.
- db/ (4): database, subscriptionCatalogSeed, migrations/versionedMigrations,
migrations/legacyReconcileMigrations — large dynamic schema/migration infra,
converted with @ts-nocheck (typing deferred). All requires updated to .cts.
Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:34:08 -05:00
|
|
|
* (See original notes on why CSP uses no nonce — index.html is static.)
|
2026-05-03 19:51:57 -05:00
|
|
|
*/
|
refactor(server): migrate middleware, workers, and db layer to TypeScript (.cts)
- middleware/ (5): requireAuth, securityHeaders, errorFormatter, csrf,
rateLimiter — fully typed against the shared http Req/Res/Next types.
- workers/dailyWorker — fully typed.
- db/ (4): database, subscriptionCatalogSeed, migrations/versionedMigrations,
migrations/legacyReconcileMigrations — large dynamic schema/migration infra,
converted with @ts-nocheck (typing deferred). All requires updated to .cts.
Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:34:08 -05:00
|
|
|
function securityHeaders(req: Req, res: Res, next: Next): void {
|
2026-06-10 19:28:54 -05:00
|
|
|
const cspPolicy =
|
2026-05-09 13:03:36 -05:00
|
|
|
`default-src 'self'; ` +
|
2026-06-10 19:28:54 -05:00
|
|
|
`script-src 'self'; ` +
|
|
|
|
|
`style-src 'self' 'unsafe-inline'; ` +
|
2026-05-09 13:03:36 -05:00
|
|
|
`img-src 'self' data:; ` +
|
|
|
|
|
`font-src 'self'; ` +
|
|
|
|
|
`connect-src 'self'; ` +
|
|
|
|
|
`frame-ancestors 'self'; ` +
|
|
|
|
|
`form-action 'self'; ` +
|
|
|
|
|
`base-uri 'self'; ` +
|
|
|
|
|
`object-src 'none';`;
|
|
|
|
|
|
refactor(server): migrate middleware, workers, and db layer to TypeScript (.cts)
- middleware/ (5): requireAuth, securityHeaders, errorFormatter, csrf,
rateLimiter — fully typed against the shared http Req/Res/Next types.
- workers/dailyWorker — fully typed.
- db/ (4): database, subscriptionCatalogSeed, migrations/versionedMigrations,
migrations/legacyReconcileMigrations — large dynamic schema/migration infra,
converted with @ts-nocheck (typing deferred). All requires updated to .cts.
Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:34:08 -05:00
|
|
|
res.setHeader('Content-Security-Policy', cspPolicy);
|
2026-05-03 19:51:57 -05:00
|
|
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
|
|
|
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
|
|
|
|
|
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
|
|
|
res.setHeader('X-Permitted-Cross-Domain-Policies', 'none');
|
|
|
|
|
res.removeHeader('X-Powered-By');
|
|
|
|
|
|
refactor(server): migrate middleware, workers, and db layer to TypeScript (.cts)
- middleware/ (5): requireAuth, securityHeaders, errorFormatter, csrf,
rateLimiter — fully typed against the shared http Req/Res/Next types.
- workers/dailyWorker — fully typed.
- db/ (4): database, subscriptionCatalogSeed, migrations/versionedMigrations,
migrations/legacyReconcileMigrations — large dynamic schema/migration infra,
converted with @ts-nocheck (typing deferred). All requires updated to .cts.
Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:34:08 -05:00
|
|
|
// HSTS — only when explicitly configured to run over HTTPS.
|
2026-05-03 19:51:57 -05:00
|
|
|
if (process.env.HTTPS === 'true') {
|
|
|
|
|
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next();
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-09 13:03:36 -05:00
|
|
|
module.exports = { securityHeaders, getCspNonce };
|