diff --git a/apps/pdc-frontend/src/middleware.ts b/apps/pdc-frontend/src/middleware.ts index 7072d62c..dbccfcfa 100644 --- a/apps/pdc-frontend/src/middleware.ts +++ b/apps/pdc-frontend/src/middleware.ts @@ -1,9 +1,7 @@ import acceptLanguage from 'accept-language'; -import { BLOB, DATA, EVAL, getCSP, INLINE, nonce, NONE, SELF, STRICT_DYNAMIC } from 'csp-header'; import { NextRequest, NextResponse } from 'next/server'; -import { createOpenFormsApiUrl } from '@/util/openFormsSettings'; +import { cspDevelopmentHeader, cspProductionHeader } from '@/util/cspConfig'; import { fallbackLng, languages } from './app/i18n/settings'; - acceptLanguage.languages(languages); export const config = { @@ -12,74 +10,6 @@ export const config = { const cookieName = 'i18next'; -const getOpenFormsHost = () => { - return createOpenFormsApiUrl()?.host || ''; -}; - -// Using "//*" in JavaScript, especially with VSCode, can disrupt syntax highlighting and code analysis, causing confusion and hindering development. -const formatURL = (url: string): string => `https://${url}`; - -const cspBase = { - 'default-src': [SELF], - 'object-src': [NONE], - 'base-uri': [SELF], - 'form-action': [SELF], - 'frame-ancestors': [NONE], - 'worker-src': [BLOB], - 'connect-src': [ - SELF, - getOpenFormsHost(), - 'wss://virtuele-gemeente-assistent.nl', - 'https://virtuele-gemeente-assistent.nl', - DATA, - BLOB, - ], - 'img-src': [ - SELF, - getOpenFormsHost(), - BLOB, - DATA, - 'https://service.pdok.nl', - formatURL('*.siteimproveanalytics.io'), - 'https://virtuele-gemeente-assistent.nl', - 'https://mijn.virtuele-gemeente-assistent.nl', - ], - 'font-src': [SELF, getOpenFormsHost()], - 'frame-src': ['https://www.youtube.com/embed/', 'https://www.youtube-nocookie.com/embed/'], - 'block-all-mixed-content': true, -}; -const cspDevelopmentHeader = () => { - return getCSP({ - directives: { - 'script-src': [ - SELF, - INLINE, - EVAL, - getOpenFormsHost(), - 'siteimproveanalytics.com', - 'https://virtuele-gemeente-assistent.nl', - ], - 'style-src': [SELF, INLINE, 'localhost:8000'], - ...cspBase, - }, - }); -}; - -const cspProductionHeader = (nonceValue: string) => { - return getCSP({ - directives: { - 'script-src': [SELF, nonce(nonceValue), STRICT_DYNAMIC, BLOB], - 'style-src': [ - SELF, - nonce(nonceValue), - 'https://virtuele-gemeente-assistent.nl', - 'https://mijn.virtuele-gemeente-assistent.nl', - ], - ...cspBase, - }, - }); -}; - export function middleware(req: NextRequest) { const nonceValue = Buffer.from(crypto.randomUUID()).toString('base64'); diff --git a/apps/pdc-frontend/src/util/cspConfig.ts b/apps/pdc-frontend/src/util/cspConfig.ts new file mode 100644 index 00000000..45bdd1cf --- /dev/null +++ b/apps/pdc-frontend/src/util/cspConfig.ts @@ -0,0 +1,83 @@ +import { BLOB, DATA, EVAL, getCSP, INLINE, nonce, NONE, SELF, STRICT_DYNAMIC } from 'csp-header'; +import { createOpenFormsApiUrl } from '@/util/openFormsSettings'; +// Using "//*" in JavaScript, especially with VSCode, can disrupt syntax highlighting and code analysis, causing confusion and hindering development. +const formatURL = (url: string): string => `https://${url}`; +const getOpenFormsHost = () => { + return createOpenFormsApiUrl()?.host || ''; +}; + +const chatWidget = { + 'connect-src': ['wss://virtuele-gemeente-assistent.nl', 'https://virtuele-gemeente-assistent.nl'], + 'img-src': ['https://virtuele-gemeente-assistent.nl', 'https://mijn.virtuele-gemeente-assistent.nl'], + 'script-src': ['https://virtuele-gemeente-assistent.nl'], + 'style-src': ['https://virtuele-gemeente-assistent.nl', 'https://mijn.virtuele-gemeente-assistent.nl'], +}; +const map = { + 'img-src': ['https://service.pdok.nl'], +}; + +const youtube = { + 'frame-src': ['https://www.youtube.com/embed/', 'https://www.youtube-nocookie.com/embed/'], +}; + +const siteimproveanalytics = { + 'script-src': [formatURL('siteimproveanalytics.com')], + 'img-src': [formatURL('*.siteimproveanalytics.io')], +}; + +const openForms = { + 'connect-src': [getOpenFormsHost()], + 'img-src': [getOpenFormsHost()], + 'script-src': [getOpenFormsHost()], + 'font-src': [getOpenFormsHost()], + 'style-src': [getOpenFormsHost()], +}; + +export const cspBase = { + 'default-src': [SELF], + 'object-src': [NONE], + 'base-uri': [SELF], + 'form-action': [SELF], + 'frame-ancestors': [NONE], + 'worker-src': [BLOB], + 'connect-src': [SELF, ...openForms['connect-src'], ...chatWidget['connect-src'], DATA, BLOB], + 'img-src': [ + SELF, + ...openForms['img-src'], + BLOB, + DATA, + ...map['img-src'], + ...siteimproveanalytics['img-src'], + ...chatWidget['img-src'], + ], + 'font-src': [SELF, ...openForms['font-src']], + 'frame-src': [...youtube['frame-src']], + 'block-all-mixed-content': true, +}; + +export const cspDevelopmentHeader = () => { + return getCSP({ + directives: { + 'script-src': [ + SELF, + INLINE, + EVAL, + ...openForms['script-src'], + ...siteimproveanalytics['script-src'], + ...chatWidget['script-src'], + ], + 'style-src': [SELF, INLINE, ...openForms['style-src']], + ...cspBase, + }, + }); +}; + +export const cspProductionHeader = (nonceValue: string) => { + return getCSP({ + directives: { + 'script-src': [SELF, nonce(nonceValue), STRICT_DYNAMIC, BLOB], + 'style-src': [SELF, nonce(nonceValue), ...chatWidget['style-src']], + ...cspBase, + }, + }); +}; diff --git a/apps/pdc-frontend/src/util/index.ts b/apps/pdc-frontend/src/util/index.ts index edbc6d43..4228e8d5 100644 --- a/apps/pdc-frontend/src/util/index.ts +++ b/apps/pdc-frontend/src/util/index.ts @@ -3,6 +3,7 @@ export * from './apiSettings'; export * from './buildAlternateLinks'; export * from './create-url'; export * from './createStrapiURL'; +export * from './cspConfig'; export * from './fetchData'; export * from './getAlphabeticallyProductsByLetter'; export * from './getImageBaseUrl';