import { injectable } from 'inversify'; import { isDev } from '../../core/env'; import type { SessionHelperInterface } from './session-helper-interface'; const defaultCsp: Session.ContentSecurityPolicy = { 'default-src': ["'self'"], 'style-src': ["'unsafe-inline'"], 'object-src': ["'none'"], }; @injectable() export class SessionHelper implements SessionHelperInterface { private static stringifyCspHeader(csp: Session.ContentSecurityPolicy): string { return Object.entries(csp) .map( (directive: [string, Session.CspValue[] | undefined]) => `${directive[0]} ${directive[1] ? directive[1]?.join(' ') : ''}` ) .join('; '); } public setCsp(window: Electron.BrowserWindow, csp: Session.ContentSecurityPolicy): void { const mergedCsp: Session.ContentSecurityPolicy = { ...defaultCsp, ...csp }; if (isDev()) { mergedCsp['default-src'] = ['devtools:'].concat(mergedCsp['default-src'] ?? []); mergedCsp['script-src'] = ["'unsafe-eval'"].concat(mergedCsp['script-src'] ?? []); mergedCsp['script-src-elem'] = ['file:', 'devtools:', "'unsafe-inline'"].concat( mergedCsp['script-src-elem'] ?? [] ); mergedCsp['style-src'] = ['devtools:', "'unsafe-inline'"].concat(mergedCsp['style-src'] ?? []); mergedCsp['img-src'] = ['devtools:'].concat(mergedCsp['img-src'] ?? []); mergedCsp['connect-src'] = ['devtools:', 'data:'].concat(mergedCsp['connect-src'] ?? []); mergedCsp['worker-src'] = ['devtools:'].concat(mergedCsp['worker-src'] ?? []); } window.webContents.session.webRequest.onHeadersReceived((details, callback) => { callback({ responseHeaders: { ...details.responseHeaders, 'Content-Security-Policy': SessionHelper.stringifyCspHeader(mergedCsp), }, }); }); } }