UNPKG

webpack-subresource-integrity

Version:
225 lines 8.1 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. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.hasOwnProperty = exports.usesAnyHash = exports.replaceInSource = exports.tryGetSource = exports.updateAsset = exports.allChunksInPrimaryChunkIterable = exports.allChunksInChunkIterable = exports.allChunksInGroupIterable = exports.flatMap = exports.map = exports.unionSet = exports.intersectSets = exports.intersect = exports.generateSriHashPlaceholders = exports.notNil = exports.findChunks = exports.addIfNotExist = exports.makePlaceholder = exports.computeIntegrity = exports.placeholderRegex = exports.placeholderPrefix = exports.normalizePath = exports.getTagSrc = exports.assert = exports.sriHashVariableReference = void 0; const crypto_1 = require("crypto"); const path_1 = require("path"); exports.sriHashVariableReference = "__webpack_require__.sriHashes"; function assert(value, message) { if (!value) { throw new Error(message); } } exports.assert = assert; function getTagSrc(tag) { if (!["script", "link"].includes(tag.tagName) || !tag.attributes) { return undefined; } if (typeof tag.attributes["href"] === "string") { return tag.attributes["href"]; } if (typeof tag.attributes["src"] === "string") { return tag.attributes["src"]; } return undefined; } exports.getTagSrc = getTagSrc; const normalizePath = (p) => p.replace(/\?.*$/, "").split(path_1.sep).join("/"); exports.normalizePath = normalizePath; exports.placeholderPrefix = "*-*-*-CHUNK-SRI-HASH-"; exports.placeholderRegex = new RegExp(`${exports.placeholderPrefix.replace(/[-*/\\]/g, "\\$&")}[a-zA-Z0-9=/+]+(\\ssha\\d{3}-[a-zA-Z0-9=/+]+)*`, "g"); const computeIntegrity = (hashFuncNames, source) => { const result = hashFuncNames .map((hashFuncName) => hashFuncName + "-" + (0, crypto_1.createHash)(hashFuncName) .update(typeof source === "string" ? Buffer.from(source, "utf-8") : source) .digest("base64")) .join(" "); return result; }; exports.computeIntegrity = computeIntegrity; const placeholderCache = {}; const makePlaceholder = (hashFuncNames, id) => { const cacheKey = hashFuncNames.join() + id; const cachedPlaceholder = placeholderCache[cacheKey]; if (cachedPlaceholder) return cachedPlaceholder; const placeholderSource = `${exports.placeholderPrefix}${id}`; const filler = (0, exports.computeIntegrity)(hashFuncNames, placeholderSource); const placeholder = exports.placeholderPrefix + filler.substring(exports.placeholderPrefix.length); placeholderCache[cacheKey] = placeholder; return placeholder; }; exports.makePlaceholder = makePlaceholder; function addIfNotExist(set, item) { if (set.has(item)) return true; set.add(item); return false; } exports.addIfNotExist = addIfNotExist; function findChunks(chunk) { const allChunks = new Set(); const groupsVisited = new Set(); (function recurseChunk(childChunk) { function recurseGroup(group) { if (addIfNotExist(groupsVisited, group.id)) return; group.chunks.forEach(recurseChunk); group.childrenIterable.forEach(recurseGroup); } if (addIfNotExist(allChunks, childChunk)) return; Array.from(childChunk.groupsIterable).forEach(recurseGroup); })(chunk); return allChunks; } exports.findChunks = findChunks; function notNil(value) { return value !== null && value !== undefined; } exports.notNil = notNil; function generateSriHashPlaceholders(chunks, hashFuncNames) { return Array.from(chunks).reduce((sriHashes, depChunk) => { if (depChunk.id) { sriHashes[depChunk.id] = (0, exports.makePlaceholder)(hashFuncNames, depChunk.id); } return sriHashes; }, {}); } exports.generateSriHashPlaceholders = generateSriHashPlaceholders; function allSetsHave(sets, item) { for (const set of sets) { if (!set.has(item)) { return false; } } return true; } function* intersect(sets) { const { value: initialSet } = sets[Symbol.iterator]().next(); if (!initialSet) { return; } initialSetLoop: for (const item of initialSet) { if (!allSetsHave(sets, item)) { continue initialSetLoop; } yield item; } } exports.intersect = intersect; function intersectSets(setsToIntersect) { return new Set(intersect(setsToIntersect)); } exports.intersectSets = intersectSets; function unionSet(...sets) { const result = new Set(); for (const set of sets) { for (const item of set) { result.add(item); } } return result; } exports.unionSet = unionSet; function* map(items, fn) { for (const item of items) { yield fn(item); } } exports.map = map; function* flatMap(collections, fn) { for (const item of collections) { for (const result of fn(item)) { yield result; } } } exports.flatMap = flatMap; function* allChunksInGroupIterable(chunkGroup) { for (const childGroup of chunkGroup.childrenIterable) { for (const childChunk of childGroup.chunks) { yield childChunk; } } } exports.allChunksInGroupIterable = allChunksInGroupIterable; function* allChunksInChunkIterable(chunk) { for (const group of chunk.groupsIterable) { for (const childChunk of allChunksInGroupIterable(group)) { yield childChunk; } } } exports.allChunksInChunkIterable = allChunksInChunkIterable; function* allChunksInPrimaryChunkIterable(chunk) { for (const chunkGroup of chunk.groupsIterable) { if (chunkGroup.chunks[chunkGroup.chunks.length - 1] !== chunk) { // Only add sri hashes for one chunk per chunk group, // where the last chunk in the group is the primary chunk continue; } for (const childChunk of allChunksInGroupIterable(chunkGroup)) { yield childChunk; } } } exports.allChunksInPrimaryChunkIterable = allChunksInPrimaryChunkIterable; function updateAsset(compilation, assetPath, source, integrity, onUpdate) { compilation.updateAsset(assetPath, source, (assetInfo) => { if (!assetInfo) { return undefined; } onUpdate(assetInfo); return Object.assign(Object.assign({}, assetInfo), { contenthash: Array.isArray(assetInfo.contenthash) ? [...new Set([...assetInfo.contenthash, integrity])] : assetInfo.contenthash ? [assetInfo.contenthash, integrity] : integrity }); }); } exports.updateAsset = updateAsset; function tryGetSource(source) { try { return source.source(); } catch (_) { return undefined; } } exports.tryGetSource = tryGetSource; function replaceInSource(compiler, source, path, replacements) { const oldSource = source.source(); if (typeof oldSource !== "string") { return source; } const newAsset = new compiler.webpack.sources.ReplaceSource(source, path); for (const match of oldSource.matchAll(exports.placeholderRegex)) { const placeholder = match[0]; const position = match.index; if (placeholder && position !== undefined) { newAsset.replace(position, position + placeholder.length - 1, replacements.get(placeholder) || placeholder); } } return newAsset; } exports.replaceInSource = replaceInSource; function usesAnyHash(assetInfo) { return !!(assetInfo.fullhash || assetInfo.chunkhash || assetInfo.modulehash || assetInfo.contenthash); } exports.usesAnyHash = usesAnyHash; function hasOwnProperty(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } exports.hasOwnProperty = hasOwnProperty; //# sourceMappingURL=util.js.map