Skip to content

Commit 2a245bf

Browse files
committed
Add new output callback function
1 parent 95d9f8b commit 2a245bf

File tree

3 files changed

+56
-25
lines changed

3 files changed

+56
-25
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ This `CspHtmlWebpackPlugin` accepts 2 params with the following structure:
4141
- `{string}` hashingMethod - accepts 'sha256', 'sha384', 'sha512' - your node version must also accept this hashing method.
4242
- `{object}` hashEnabled - a `<string, boolean>` entry for which policy rules are allowed to include hashes
4343
- `{object}` nonceEnabled - a `<string, boolean>` entry for which policy rules are allowed to include nonces
44+
- `{Function}` output (optional) - optional callback function receiving the computed CSP policy to implement custom logic instead of including meta tag.
4445

4546
The plugin also adds a new config option onto each `HtmlWebpackPlugin` instance:
4647

plugin.jest.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,4 +852,29 @@ describe('CspHtmlWebpackPlugin', () => {
852852
});
853853
});
854854
});
855+
856+
describe.only('Plugin output callback', () => {
857+
it("doesn't modify the html if enabled is the bool false", done => {
858+
// eslint-disable-next-line no-unused-vars
859+
const mockCallback = jest.fn(csp => {});
860+
const config = createWebpackConfig([
861+
new HtmlWebpackPlugin({
862+
filename: path.join(WEBPACK_OUTPUT_DIR, 'index.html')
863+
}),
864+
new CspHtmlWebpackPlugin({}, { output: mockCallback })
865+
]);
866+
867+
webpackCompile(config, csps => {
868+
const expected =
869+
"base-uri 'self';" +
870+
" object-src 'none';" +
871+
" script-src 'unsafe-inline' 'self' 'unsafe-eval' 'nonce-mockedbase64string-1';" +
872+
" style-src 'unsafe-inline' 'self' 'unsafe-eval'";
873+
874+
expect(mockCallback).toBeCalledWith(expected);
875+
expect(csps['index.html']).not.toEqual(expected);
876+
done();
877+
});
878+
});
879+
});
855880
});

plugin.js

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -296,16 +296,6 @@ class CspHtmlWebpackPlugin {
296296
return compileCb(null, htmlPluginData);
297297
}
298298

299-
let metaTag = $('meta[http-equiv="Content-Security-Policy"]');
300-
301-
// Add element if it doesn't exist.
302-
if (!metaTag.length) {
303-
metaTag = cheerio.load('<meta http-equiv="Content-Security-Policy">')(
304-
'meta'
305-
);
306-
metaTag.prependTo($('head'));
307-
}
308-
309299
// get all nonces for script and style tags
310300
const scriptNonce = this.setNonce($, 'script-src', 'script[src]');
311301
const styleNonce = this.setNonce($, 'style-src', 'link[rel="stylesheet"]');
@@ -314,21 +304,36 @@ class CspHtmlWebpackPlugin {
314304
const scriptShas = this.getShas($, 'script-src', 'script:not([src])');
315305
const styleShas = this.getShas($, 'style-src', 'style:not([href])');
316306

317-
// build the policy into the context attr of the csp meta tag
318-
metaTag.attr(
319-
'content',
320-
this.buildPolicy({
321-
...this.policy,
322-
'script-src': flatten([this.policy['script-src']]).concat(
323-
scriptShas,
324-
scriptNonce
325-
),
326-
'style-src': flatten([this.policy['style-src']]).concat(
327-
styleShas,
328-
styleNonce
329-
)
330-
})
331-
);
307+
// build the CSP policy
308+
const policy = this.buildPolicy({
309+
...this.policy,
310+
'script-src': flatten([this.policy['script-src']]).concat(
311+
scriptShas,
312+
scriptNonce
313+
),
314+
'style-src': flatten([this.policy['style-src']]).concat(
315+
styleShas,
316+
styleNonce
317+
)
318+
});
319+
320+
// Execute output callback if is defined
321+
if (isFunction(this.opts.output)) {
322+
this.opts.output(policy);
323+
} else {
324+
let metaTag = $('meta[http-equiv="Content-Security-Policy"]');
325+
326+
// Add element if it doesn't exist.
327+
if (!metaTag.length) {
328+
metaTag = cheerio.load('<meta http-equiv="Content-Security-Policy">')(
329+
'meta'
330+
);
331+
metaTag.prependTo($('head'));
332+
}
333+
334+
// includes the policy into the context attr of the csp meta tag
335+
metaTag.attr('content', policy);
336+
}
332337

333338
// eslint-disable-next-line no-param-reassign
334339
htmlPluginData.html = $.html();

0 commit comments

Comments
 (0)