Kargi-Sitesi/node_modules/webpack-subresource-integrity/util.js

326 lines
No EOL
13 KiB
JavaScript

"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.getChunkToManifestMap = exports.buildTopologicallySortedChunkGraph = exports.generateSriHashPlaceholders = exports.notNil = exports.findChunks = exports.makePlaceholder = exports.computeIntegrity = 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-";
const computeIntegrity = (hashFuncNames, source) => {
const result = hashFuncNames
.map((hashFuncName) => hashFuncName +
"-" +
crypto_1.createHash(hashFuncName)
.update(typeof source === "string" ? Buffer.from(source, "utf-8") : source)
.digest("base64"))
.join(" ");
return result;
};
exports.computeIntegrity = computeIntegrity;
const makePlaceholder = (hashFuncNames, id) => {
const placeholder = `${exports.placeholderPrefix}${id}`;
const filler = exports.computeIntegrity(hashFuncNames, placeholder);
return exports.placeholderPrefix + filler.substring(exports.placeholderPrefix.length);
};
exports.makePlaceholder = makePlaceholder;
function findChunks(chunk) {
const allChunks = new Set();
const groupsVisited = new Set();
function addIfNotExist(set, item) {
if (set.has(item))
return true;
set.add(item);
return false;
}
(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] = exports.makePlaceholder(hashFuncNames, depChunk.id);
}
return sriHashes;
}, {});
}
exports.generateSriHashPlaceholders = generateSriHashPlaceholders;
function* intersect(sets) {
const { value: initialSet } = sets[Symbol.iterator]().next();
if (!initialSet) {
return;
}
initialSetLoop: for (const item of initialSet) {
for (const set of sets) {
if (!set.has(item)) {
continue initialSetLoop;
}
}
yield item;
}
}
function* map(items, fn) {
for (const item of items) {
yield fn(item);
}
}
function* flatMap(collections, fn) {
for (const item of collections) {
for (const result of fn(item)) {
yield result;
}
}
}
/**
* Tarjan's strongly connected components algorithm
* https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
*/
function createDAGfromGraph({ vertices, edges, }) {
var _a;
let index = 0;
const stack = [];
const vertexMetadata = new Map(map(vertices, (vertex) => [vertex, {}]));
const stronglyConnectedComponents = new Set();
function strongConnect(vertex) {
var _a, _b;
// Set the depth index for v to the smallest unused index
const vertexData = vertexMetadata.get(vertex);
assert(vertexData, "Vertex metadata missing");
vertexData.index = index;
vertexData.lowlink = index;
index++;
stack.push(vertex);
vertexData.onstack = true;
for (const child of (_a = edges.get(vertex)) !== null && _a !== void 0 ? _a : []) {
const childData = vertexMetadata.get(child);
assert(childData, "Child vertex metadata missing");
if (childData.index === undefined) {
// Child has not yet been visited; recurse on it
strongConnect(child);
vertexData.lowlink = Math.min(vertexData.lowlink, (_b = childData.lowlink) !== null && _b !== void 0 ? _b : Infinity);
}
else if (childData.onstack) {
// Child is in stack and hence in the current SCC
// If child is not on stack, then (vertex, child) is an edge pointing to an SCC already found and must be ignored
// Note: The next line may look odd - but is correct.
// It says childData.index not childData.lowlink; that is deliberate and from the original paper
vertexData.lowlink = Math.min(vertexData.lowlink, childData.index);
}
}
// If vertex is a root node, pop the stack and generate an SCC
if (vertexData.index === vertexData.lowlink) {
const newStronglyConnectedComponent = { nodes: new Set() };
let currentNode;
do {
currentNode = stack.pop();
assert(currentNode, "Working stack was empty");
const metadata = vertexMetadata.get(currentNode);
assert(metadata, "All nodes on stack should have metadata");
metadata.onstack = false;
newStronglyConnectedComponent.nodes.add(currentNode);
} while (currentNode !== vertex);
stronglyConnectedComponents.add(newStronglyConnectedComponent);
}
}
for (const vertex of vertices) {
const data = vertexMetadata.get(vertex);
assert(data, "Vertex metadata not found");
if (data.index === undefined) {
strongConnect(vertex);
}
}
// Now that all SCCs have been identified, rebuild the graph
const vertexToSCCMap = new Map();
const sccEdges = new Map();
for (const scc of stronglyConnectedComponents) {
for (const vertex of scc.nodes) {
vertexToSCCMap.set(vertex, scc);
}
}
for (const scc of stronglyConnectedComponents) {
const childSCCNodes = new Set();
for (const vertex of scc.nodes) {
for (const childVertex of (_a = edges.get(vertex)) !== null && _a !== void 0 ? _a : []) {
const childScc = vertexToSCCMap.get(childVertex);
if (childScc && childScc !== scc) {
childSCCNodes.add(childScc);
}
}
}
sccEdges.set(scc, childSCCNodes);
}
return { vertices: stronglyConnectedComponents, edges: sccEdges };
}
// This implementation assumes a directed acyclic graph (such as one produced by createDAGfromGraph),
// and does not attempt to detect cycles
function topologicalSort({ vertices, edges }) {
const sortedItems = [];
const seenNodes = new Set();
function visit(node) {
var _a;
if (seenNodes.has(node)) {
return;
}
seenNodes.add(node);
for (const child of (_a = edges.get(node)) !== null && _a !== void 0 ? _a : []) {
visit(child);
}
sortedItems.push(node);
}
for (const vertex of vertices) {
visit(vertex);
}
return sortedItems;
}
function buildTopologicallySortedChunkGraph(chunks) {
var _a;
const vertices = new Set();
const edges = new Map();
// Chunks should have *all* chunks, not simply entry chunks
for (const vertex of chunks) {
if (vertices.has(vertex)) {
continue;
}
vertices.add(vertex);
edges.set(vertex, new Set());
for (const vertexGroup of vertex.groupsIterable) {
for (const childGroup of vertexGroup.childrenIterable) {
for (const childChunk of childGroup.chunks) {
(_a = edges.get(vertex)) === null || _a === void 0 ? void 0 : _a.add(childChunk);
}
}
}
}
const dag = createDAGfromGraph({ vertices, edges });
const sortedVertices = topologicalSort(dag);
const chunkToSccMap = new Map(flatMap(dag.vertices, (scc) => map(scc.nodes, (chunk) => [chunk, scc])));
return [sortedVertices, dag, chunkToSccMap];
}
exports.buildTopologicallySortedChunkGraph = buildTopologicallySortedChunkGraph;
function getChunkToManifestMap(chunks) {
var _a;
const [sortedVertices, , chunkToSccMap] = buildTopologicallySortedChunkGraph(chunks);
// This map tracks which hashes a chunk group has in its manifest and the intersection
// of all its parents (and intersection of all their parents, etc.)
// This is meant as a guarantee that the hash for a given chunk is handled by a chunk group
// or its parents regardless of the tree traversal used from the roots
const hashesByChunkGroupAndParents = new Map();
// A map of what child chunks a given chunk should contain hashes for
const chunkManifest = new Map();
function intersectSets(setsToIntersect) {
return new Set(intersect(setsToIntersect));
}
function findIntersectionOfParentSets(chunk) {
var _a;
const setsToIntersect = [];
for (const group of chunk.groupsIterable) {
for (const parent of group.parentsIterable) {
setsToIntersect.push((_a = hashesByChunkGroupAndParents.get(parent)) !== null && _a !== void 0 ? _a : new Set());
}
}
return intersectSets(setsToIntersect);
}
function getChildChunksToAddToChunkManifest(chunk) {
var _a;
const childChunks = new Set();
const chunkSCC = chunkToSccMap.get(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 childGroup of chunkGroup.childrenIterable) {
for (const childChunk of childGroup.chunks) {
const childChunkSCC = chunkToSccMap.get(childChunk);
if (childChunkSCC === chunkSCC) {
// Don't include your own SCC.
// Your parent will have the hashes for your SCC siblings
continue;
}
for (const childChunkSccNode of (_a = childChunkSCC === null || childChunkSCC === void 0 ? void 0 : childChunkSCC.nodes) !== null && _a !== void 0 ? _a : []) {
childChunks.add(childChunkSccNode);
}
}
}
}
const parentManifest = findIntersectionOfParentSets(chunk);
for (const manifestEntry of parentManifest) {
childChunks.delete(manifestEntry);
}
return childChunks;
}
// We want to walk from the root nodes down to the leaves
for (let i = sortedVertices.length - 1; i >= 0; i--) {
const scc = sortedVertices[i];
for (const chunk of scc.nodes) {
const manifest = getChildChunksToAddToChunkManifest(chunk);
const combinedParentManifest = findIntersectionOfParentSets(chunk);
for (const chunk of manifest) {
if (combinedParentManifest.has(chunk)) {
manifest.delete(chunk);
}
else {
combinedParentManifest.add(chunk);
}
}
chunkManifest.set(chunk, manifest);
for (const group of chunk.groupsIterable) {
// Get intersection of all parent manifests
const groupCombinedManifest = intersectSets(map(group.parentsIterable, (parent) => { var _a; return (_a = hashesByChunkGroupAndParents.get(parent)) !== null && _a !== void 0 ? _a : new Set(); }));
// Add this chunk's manifest
for (const chunk of manifest) {
groupCombinedManifest.add(chunk);
}
// Add any existing manifests part of the group
for (const chunk of (_a = hashesByChunkGroupAndParents.get(group)) !== null && _a !== void 0 ? _a : new Set()) {
groupCombinedManifest.add(chunk);
}
hashesByChunkGroupAndParents.set(group, groupCombinedManifest);
}
}
}
return [sortedVertices, chunkManifest];
}
exports.getChunkToManifestMap = getChunkToManifestMap;
//# sourceMappingURL=util.js.map