Import source: app/backend/src/plugins/security-headers

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:19:47 +03:30
parent 82cb492014
commit ff48a0a3c2
@@ -0,0 +1,36 @@
import fp from 'fastify-plugin';
import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import { randomBytes } from 'node:crypto';
declare module 'fastify' {
interface FastifyReply {
cspNonce: string;
}
}
function generateNonce(): string {
return randomBytes(16).toString('base64');
}
export default fp(async function securityHeadersPlugin(app: FastifyInstance) {
app.decorateReply('cspNonce', '');
app.addHook('onRequest', async (req: FastifyRequest, reply: FastifyReply) => {
const nonce = generateNonce();
reply.cspNonce = nonce;
reply.header('X-Content-Type-Options', 'nosniff');
reply.header('X-Frame-Options', 'SAMEORIGIN');
reply.header('Referrer-Policy', 'strict-origin-when-cross-origin');
reply.header('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
if (req.url.startsWith('/embed') || req.url === '/embed.html') {
reply.header('Content-Security-Policy', `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; frame-ancestors *; report-uri /api/v1/csp-report`);
} else {
reply.header('Content-Security-Policy', `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self'; connect-src 'self'; frame-ancestors 'self'; form-action 'self'; report-uri /api/v1/csp-report`);
}
if (process.env.NODE_ENV === 'production') {
reply.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
}
});
});