Skip to content

Commit f2d99d8

Browse files
authored
Merge pull request #15289 from webpack/disallow-digest-only-content-hash
use nonNumericOnlyHash function for contentHash
2 parents 4bc6150 + 53fcf41 commit f2d99d8

File tree

5 files changed

+63
-4
lines changed

5 files changed

+63
-4
lines changed

lib/asset/AssetGenerator.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const Generator = require("../Generator");
1212
const RuntimeGlobals = require("../RuntimeGlobals");
1313
const createHash = require("../util/createHash");
1414
const { makePathsRelative } = require("../util/identifier");
15+
const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
1516

1617
/** @typedef {import("webpack-sources").Source} Source */
1718
/** @typedef {import("../../declarations/WebpackOptions").AssetGeneratorOptions} AssetGeneratorOptions */
@@ -232,8 +233,8 @@ class AssetGenerator extends Generator {
232233
const fullHash = /** @type {string} */ (
233234
hash.digest(runtimeTemplate.outputOptions.hashDigest)
234235
);
235-
const contentHash = fullHash.slice(
236-
0,
236+
const contentHash = nonNumericOnlyHash(
237+
fullHash,
237238
runtimeTemplate.outputOptions.hashDigestLength
238239
);
239240
module.buildInfo.fullContentHash = fullHash;

lib/css/CssModulesPlugin.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const { compareModulesByIdentifier } = require("../util/comparators");
1919
const createSchemaValidation = require("../util/create-schema-validation");
2020
const createHash = require("../util/createHash");
2121
const memoize = require("../util/memoize");
22+
const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
2223
const CssExportsGenerator = require("./CssExportsGenerator");
2324
const CssGenerator = require("./CssGenerator");
2425
const CssParser = require("./CssParser");
@@ -201,7 +202,7 @@ class CssModulesPlugin {
201202
hash.update(chunkGraph.getModuleHash(module, chunk.runtime));
202203
}
203204
const digest = /** @type {string} */ (hash.digest(hashDigest));
204-
chunk.contentHash.css = digest.substr(0, hashDigestLength);
205+
chunk.contentHash.css = nonNumericOnlyHash(digest, hashDigestLength);
205206
});
206207
compilation.hooks.renderManifest.tap(plugin, (result, options) => {
207208
const { chunkGraph } = compilation;

lib/javascript/JavascriptModulesPlugin.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const { last, someInIterable } = require("../util/IterableHelpers");
2424
const StringXor = require("../util/StringXor");
2525
const { compareModulesByIdentifier } = require("../util/comparators");
2626
const createHash = require("../util/createHash");
27+
const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
2728
const { intersectRuntime } = require("../util/runtime");
2829
const JavascriptGenerator = require("./JavascriptGenerator");
2930
const JavascriptParser = require("./JavascriptParser");
@@ -398,7 +399,10 @@ class JavascriptModulesPlugin {
398399
xor.updateHash(hash);
399400
}
400401
const digest = /** @type {string} */ (hash.digest(hashDigest));
401-
chunk.contentHash.javascript = digest.substr(0, hashDigestLength);
402+
chunk.contentHash.javascript = nonNumericOnlyHash(
403+
digest,
404+
hashDigestLength
405+
);
402406
});
403407
compilation.hooks.additionalTreeRuntimeRequirements.tap(
404408
"JavascriptModulesPlugin",

lib/util/nonNumericOnlyHash.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Ivan Kopeykin @vankop
4+
*/
5+
6+
"use strict";
7+
8+
const A_CODE = "a".charCodeAt(0);
9+
10+
/**
11+
* @param {string} hash hash
12+
* @param {number} hashLength hash length
13+
* @returns {string} returns hash that has at least one non numeric char
14+
*/
15+
module.exports = (hash, hashLength) => {
16+
if (hashLength < 1) return "";
17+
const slice = hash.slice(0, hashLength);
18+
if (slice.match(/[^\d]/)) return slice;
19+
return `${String.fromCharCode(
20+
A_CODE + (parseInt(hash[0], 10) % 6)
21+
)}${slice.slice(1)}`;
22+
};

test/nonNumericOnlyHash.unittest.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"use strict";
2+
3+
const nonNumericOnlyHash = require("../lib/util/nonNumericOnlyHash");
4+
5+
it("hashLength=0", () => {
6+
expect(nonNumericOnlyHash("111", 0)).toBe("");
7+
});
8+
9+
it("abc", () => {
10+
expect(nonNumericOnlyHash("abc", 10)).toBe("abc");
11+
});
12+
13+
it("abc1", () => {
14+
expect(nonNumericOnlyHash("abc1", 3)).toBe("abc");
15+
});
16+
17+
it("ab11", () => {
18+
expect(nonNumericOnlyHash("ab11", 3)).toBe("ab1");
19+
});
20+
21+
it("0111", () => {
22+
expect(nonNumericOnlyHash("0111", 3)).toBe("a11");
23+
});
24+
25+
it("911a", () => {
26+
expect(nonNumericOnlyHash("911a", 3)).toBe("d11");
27+
});
28+
29+
it("511a", () => {
30+
expect(nonNumericOnlyHash("511a", 3)).toBe("f11");
31+
});

0 commit comments

Comments
 (0)