Files
medreport_mrb2b/lib/create-csp-response.ts
2025-06-08 16:18:30 +03:00

95 lines
2.5 KiB
TypeScript

import type { NoseconeOptions } from '@nosecone/next';
// we need to allow connecting to the Supabase API from the client
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL as string;
// the URL used for Supabase Realtime
const WEBSOCKET_URL = SUPABASE_URL.replace('https://', 'ws://').replace(
'http://',
'ws://',
);
// disabled to allow loading images from Supabase Storage
const CROSS_ORIGIN_EMBEDDER_POLICY = false;
/**
* @name ALLOWED_ORIGINS
* @description List of allowed origins for the "connectSrc" directive in the Content Security Policy.
*/
const ALLOWED_ORIGINS = [
SUPABASE_URL,
WEBSOCKET_URL,
// add here additional allowed origins
] as never[];
/**
* @name IMG_SRC_ORIGINS
*/
const IMG_SRC_ORIGINS = [SUPABASE_URL] as never[];
/**
* @name UPGRADE_INSECURE_REQUESTS
* @description Upgrade insecure requests to HTTPS when in production
*/
const UPGRADE_INSECURE_REQUESTS = process.env.NODE_ENV === 'production';
/**
* @name createCspResponse
* @description Create a middleware with enhanced headers applied (if applied).
*/
export async function createCspResponse() {
const {
createMiddleware,
withVercelToolbar,
defaults: noseconeConfig,
} = await import('@nosecone/next');
/*
* @name allowedOrigins
* @description List of allowed origins for the "connectSrc" directive in the Content Security Policy.
*/
const config: NoseconeOptions = {
...noseconeConfig,
contentSecurityPolicy: {
directives: {
...noseconeConfig.contentSecurityPolicy.directives,
connectSrc: [
...noseconeConfig.contentSecurityPolicy.directives.connectSrc,
...ALLOWED_ORIGINS,
],
imgSrc: [
...noseconeConfig.contentSecurityPolicy.directives.imgSrc,
...IMG_SRC_ORIGINS,
],
upgradeInsecureRequests: UPGRADE_INSECURE_REQUESTS,
},
},
crossOriginEmbedderPolicy: CROSS_ORIGIN_EMBEDDER_POLICY,
};
const middleware = createMiddleware(
process.env.VERCEL_ENV === 'preview' ? withVercelToolbar(config) : config,
);
// create response
const response = await middleware();
if (response) {
const contentSecurityPolicy = response.headers.get(
'Content-Security-Policy',
);
const matches = contentSecurityPolicy?.match(/nonce-([\w-]+)/) || [];
const nonce = matches[1];
// set x-nonce header if nonce is found
// so we can pass it to client-side scripts
if (nonce) {
response.headers.set('x-nonce', nonce);
}
}
return response;
}