UNPKG

webpack-subresource-integrity

Version:
211 lines 9.35 kB
"use strict"; /** * Copyright (c) 2015-present, Waysact Pty Ltd * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SubresourceIntegrityPlugin = void 0; const crypto_1 = require("crypto"); const plugin_1 = require("./plugin"); const reporter_1 = require("./reporter"); const util_1 = require("./util"); const hooks_1 = require("./hooks"); const manifest_1 = require("./manifest"); const globals_1 = require("./globals"); /** * The webpack-subresource-integrity plugin. * * @public */ class SubresourceIntegrityPlugin { /** * Create a new instance. * * @public */ constructor(options = {}) { /** * @internal */ this.setup = (compilation, hwpHooks) => { const reporter = new reporter_1.Reporter(compilation); if (!this.validateOptions(compilation, reporter) || !this.isEnabled(compilation)) { return; } const plugin = new plugin_1.Plugin(compilation, this.options, reporter); if (typeof compilation.outputOptions.chunkLoading === "string" && ["require", "async-node"].includes(compilation.outputOptions.chunkLoading)) { reporter.warnNonWeb(); return; } compilation.hooks.beforeRuntimeRequirements.tap(globals_1.thisPluginName, () => { plugin.beforeRuntimeRequirements(); }); compilation.hooks.processAssets.tap({ name: globals_1.thisPluginName, stage: compilation.compiler.webpack.Compilation .PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE, }, (records) => { return plugin.processAssets(records); }); compilation.hooks.afterProcessAssets.tap(globals_1.thisPluginName, (records) => { for (const chunk of compilation.chunks.values()) { for (const chunkFile of chunk.files) { const record = records[chunkFile]; if (record && record.source().includes(util_1.placeholderPrefix)) { reporter.errorUnresolvedIntegrity(chunkFile); } } } }); compilation.compiler.webpack.optimize.RealContentHashPlugin.getCompilationHooks(compilation).updateHash.tap(globals_1.thisPluginName, (input, oldHash) => { // FIXME: remove type hack pending https://github.com/webpack/webpack/pull/12642#issuecomment-784744910 return plugin.updateHash(input, oldHash); }); if (hwpHooks) { hwpHooks.beforeAssetTagGeneration.tapPromise(globals_1.thisPluginName, (pluginArgs) => __awaiter(this, void 0, void 0, function* () { plugin.handleHwpPluginArgs(pluginArgs); return pluginArgs; })); hwpHooks.alterAssetTagGroups.tapPromise({ name: globals_1.thisPluginName, stage: 10000, }, (data) => __awaiter(this, void 0, void 0, function* () { plugin.handleHwpBodyTags(data); return data; })); } const { mainTemplate } = compilation; mainTemplate.hooks.jsonpScript.tap(globals_1.thisPluginName, (source) => plugin.addAttribute("script", source)); mainTemplate.hooks.linkPreload.tap(globals_1.thisPluginName, (source) => plugin.addAttribute("link", source)); mainTemplate.hooks.localVars.tap(globals_1.thisPluginName, (source, chunk) => { const allChunks = this.options.hashLoading === "lazy" ? plugin.getChildChunksToAddToChunkManifest(chunk) : (0, util_1.findChunks)(chunk); const includedChunks = chunk.getChunkMaps(false).hash; if (Object.keys(includedChunks).length > 0) { return compilation.compiler.webpack.Template.asString([ source, `${util_1.sriHashVariableReference} = ` + JSON.stringify((0, util_1.generateSriHashPlaceholders)(Array.from(allChunks).filter((depChunk) => depChunk.id !== null && includedChunks[depChunk.id.toString()]), this.options.hashFuncNames)) + ";", ]); } return source; }); if (this.options.hashLoading === "lazy") { compilation.hooks.additionalChunkRuntimeRequirements.tap(globals_1.thisPluginName, (chunk) => { var _a; const childChunks = plugin.getChildChunksToAddToChunkManifest(chunk); if (childChunks.size > 0 && !chunk.hasRuntime()) { compilation.addRuntimeModule(chunk, new manifest_1.AddLazySriRuntimeModule((0, util_1.generateSriHashPlaceholders)(childChunks, this.options.hashFuncNames), (_a = chunk.name) !== null && _a !== void 0 ? _a : chunk.id)); } }); } }; /** * @internal */ this.validateOptions = (compilation, reporter) => { if (this.isEnabled(compilation) && !compilation.compiler.options.output.crossOriginLoading) { reporter.warnCrossOriginPolicy(); } return (this.validateHashFuncNames(reporter) && this.validateHashLoading(reporter)); }; /** * @internal */ this.validateHashFuncNames = (reporter) => { if (!Array.isArray(this.options.hashFuncNames)) { reporter.errorHashFuncsNonArray(this.options.hashFuncNames); return false; } else if (this.options.hashFuncNames.length === 0) { reporter.errorHashFuncsEmpty(); return false; } else if (!this.options.hashFuncNames.every(this.validateHashFuncName.bind(this, reporter))) { return false; } else { this.warnStandardHashFunc(reporter); return true; } }; /** * @internal */ this.validateHashLoading = (reporter) => { const supportedHashLoadingOptions = Object.freeze(["eager", "lazy"]); if (supportedHashLoadingOptions.includes(this.options.hashLoading)) { return true; } reporter.errorInvalidHashLoading(this.options.hashLoading, supportedHashLoadingOptions); return false; }; /** * @internal */ this.warnStandardHashFunc = (reporter) => { let foundStandardHashFunc = false; this.options.hashFuncNames.forEach((hashFuncName) => { if (globals_1.standardHashFuncNames.indexOf(hashFuncName) >= 0) { foundStandardHashFunc = true; } }); if (!foundStandardHashFunc) { reporter.warnStandardHashFuncs(); } }; /** * @internal */ this.validateHashFuncName = (reporter, hashFuncName) => { if (typeof hashFuncName !== "string" && !(hashFuncName instanceof String)) { reporter.errorNonStringHashFunc(hashFuncName); return false; } try { (0, crypto_1.createHash)(hashFuncName); } catch (error) { reporter.errorUnusableHashFunc(hashFuncName, error); return false; } return true; }; if (typeof options !== "object") { throw new Error("webpack-subresource-integrity: argument must be an object"); } this.options = Object.assign({ hashFuncNames: ["sha384"], enabled: "auto", hashLoading: "eager" }, options); } /** * @internal */ isEnabled(compilation) { if (this.options.enabled === "auto") { return compilation.options.mode !== "development"; } return this.options.enabled; } apply(compiler) { (0, hooks_1.install)(compiler, this.setup); } } exports.SubresourceIntegrityPlugin = SubresourceIntegrityPlugin; //# sourceMappingURL=index.js.map