mirror of
https://github.com/grafana/grafana.git
synced 2025-08-03 03:13:49 +08:00
Feature: Introduce subresource integrity checks (SRI) for frontend assets (#100983)
* feat(featuremgmt): introduce feature toggle for enabling sri checks * feat(frontend): use assetSriChecks feature toggle to inject integrity hash into script tags * chore(webpack): align sri algorithms across dev and prod builds * docs(featuremgmt): update assetSriChecks to pass CI * docs(featuremgmt): fix more spelling complaints with assetSriChecks * Add crossorigin attribute * chore(webpack): add subresource-integrity plugin * build(webpack): wrap webpack jsonp loader integrity checks in feature flag checks * revert(index.html): remove crossorigin attribute if assertSriChecks is disabled --------- Co-authored-by: Kristian Bremberg <kristian.bremberg@grafana.com>
This commit is contained in:
66
scripts/webpack/plugins/FeatureFlaggedSriPlugin.js
Normal file
66
scripts/webpack/plugins/FeatureFlaggedSriPlugin.js
Normal file
@ -0,0 +1,66 @@
|
||||
// @ts-check
|
||||
const webpack = require('webpack');
|
||||
|
||||
/** @typedef {import('webpack/lib/Compiler.js')} Compiler */
|
||||
|
||||
const PLUGIN_NAME = 'FeatureFlaggedSRIPlugin';
|
||||
const FEATURE_TOGGLE_WRAP = [
|
||||
'if (window.grafanaBootData && window.grafanaBootData.settings && window.grafanaBootData.settings.featureToggles && window.grafanaBootData.settings.featureToggles.assetSriChecks) {',
|
||||
'}',
|
||||
];
|
||||
|
||||
/**
|
||||
* Webpack plugin that wraps Webpack runtime integrity checks in a feature flag
|
||||
* This allows us to disable SRI checks in both the initial chunks but also in the
|
||||
* dynamically loaded chunks.
|
||||
*/
|
||||
class FeatureFlaggedSRIPlugin {
|
||||
/**
|
||||
* @param {Compiler} compiler The webpack compiler instance
|
||||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.afterPlugins.tap(PLUGIN_NAME, (compiler) => {
|
||||
const logger = compiler.getInfrastructureLogger(PLUGIN_NAME);
|
||||
compiler.hooks.thisCompilation.tap(
|
||||
{
|
||||
name: PLUGIN_NAME,
|
||||
},
|
||||
(compilation) => {
|
||||
const { mainTemplate } = compilation;
|
||||
mainTemplate.hooks.jsonpScript.tap(
|
||||
PLUGIN_NAME,
|
||||
/**
|
||||
* @param {string} source
|
||||
*/
|
||||
(source) => {
|
||||
if (source.includes('script.integrity =')) {
|
||||
logger.log('FeatureFlaggedSRIPlugin: Wrapping SRI checks in feature flag');
|
||||
return createFeatureFlaggedSRITemplate(source);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a template string wrapping the integrity and crossorigin attributes in a feature flag
|
||||
* @param {string} source The original webpack template source
|
||||
* @returns {string} The modified template source
|
||||
*/
|
||||
function createFeatureFlaggedSRITemplate(source) {
|
||||
const lines = source.split('\n');
|
||||
const integrityAttributeLineNumber = lines.findIndex((line) => line.includes('script.integrity ='));
|
||||
const [prefix, suffix] = FEATURE_TOGGLE_WRAP;
|
||||
return webpack.Template.asString([
|
||||
...lines.slice(0, integrityAttributeLineNumber),
|
||||
prefix,
|
||||
webpack.Template.indent(lines.slice(integrityAttributeLineNumber)),
|
||||
suffix,
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = FeatureFlaggedSRIPlugin;
|
Reference in New Issue
Block a user