11import * as path from 'path' ;
22import merge from "webpack-merge" ;
3+ import { RawSource } from 'webpack-sources' ;
34import * as SentryPlugin from '@sentry/webpack-plugin' ;
45
56import { InjectManifest } from 'workbox-webpack-plugin' ;
67import * as ssri from "ssri" ;
7-
88import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' ;
9+ import CspHtmlWebpackPlugin from 'csp-html-webpack-plugin' ;
910
1011import common from "./webpack.common" ;
1112
@@ -16,6 +17,14 @@ console.log(shouldPublishSentryRelease
1617 : "Sentry source map upload disabled - no token set"
1718) ;
1819
20+ const CSP_REPORT_URL = process . env . REPORT_URI && process . env . UI_VERSION
21+ ? `${ process . env . REPORT_URI } &sentry_release=${ process . env . UI_VERSION } `
22+ : false ;
23+ console . log ( CSP_REPORT_URL
24+ ? "CSP reporting enabled"
25+ : `CSP reporting skipped (uri: ${ process . env . REPORT_URI } . version: ${ process . env . UI_VERSION } )`
26+ ) ;
27+
1928export default merge ( common , {
2029 mode : "production" ,
2130
@@ -68,7 +77,13 @@ export default merge(common, {
6877 'services' ,
6978 'ui-update-worker.ts'
7079 ) ,
71- exclude : [ 'google-fonts' , / ^ a p i \/ / , 'ui-update-worker.js' , / .m a p $ / ] ,
80+ exclude : [
81+ 'google-fonts' ,
82+ / ^ a p i \/ / ,
83+ 'ui-update-worker.js' ,
84+ / \. m a p $ / ,
85+ / \. c a d d y f i l e $ /
86+ ] ,
7287 maximumFileSizeToCacheInBytes : 100 * 1024 * 1024 ,
7388 manifestTransforms : [
7489 ( originalManifest : any , compilation : any ) => {
@@ -111,6 +126,52 @@ export default merge(common, {
111126 analyzerMode : 'static' ,
112127 openAnalyzer : false ,
113128 excludeAssets : / a p i \/ .* \. j s o n /
114- } )
129+ } ) ,
130+ ...( CSP_REPORT_URL
131+ ? [
132+ new CspHtmlWebpackPlugin ( {
133+ 'base-uri' : "'self'" ,
134+ 'default-src' : "'none'" ,
135+ 'object-src' : "'none'" ,
136+ 'frame-ancestors' : "'none'" ,
137+ 'img-src' : [ "'self'" , 'https://httptoolkit.com' , 'data:' ] ,
138+ 'font-src' : [ "'self'" ] ,
139+ 'style-src' : [ "'report-sample'" , "'self'" , "'unsafe-inline'" ] ,
140+ 'script-src' : [
141+ "'report-sample'" ,
142+ "'unsafe-eval'" , // For both wasm & real eval() uses
143+ "'self'" , 'https://cdn.auth0.com/' , 'https://cdn.eu.auth0.com/'
144+ ] ,
145+ 'connect-src' : [
146+ "'self'" , 'http://127.0.0.1:45456' , 'http://127.0.0.1:45457' , 'ws://127.0.0.1:45456' , 'https://*.httptoolkit.tech' , 'https://sentry.io' , 'data:'
147+ ] ,
148+ 'report-uri' : CSP_REPORT_URL ,
149+ 'report-to' : 'csp-endpoint'
150+ } , {
151+ enabled : true ,
152+ hashEnabled : {
153+ 'script-src' : true ,
154+ 'style-src' : false
155+ } ,
156+ nonceEnabled : {
157+ 'script-src' : false ,
158+ 'style-src' : false
159+ } ,
160+ // Output CSP into a Caddy config file, that's imported by Caddyfile
161+ processFn : (
162+ builtPolicy : any ,
163+ _htmlPluginData : any ,
164+ _obj : any ,
165+ compilation : any
166+ ) => {
167+ const header = `
168+ header Content-Security-Policy-Report-Only "${ builtPolicy } "
169+ header Reporting-Endpoints \`csp-endpoint="${ CSP_REPORT_URL } "\`
170+ ` ;
171+ compilation . emitAsset ( 'csp.caddyfile' , new RawSource ( header ) ) ;
172+ }
173+ } as any )
174+ ]
175+ : [ ] )
115176 ]
116- } ) ;
177+ } ) ;
0 commit comments