Skip to content

Commit cbf9d1d

Browse files
feat: added md4 (wasm version) and md4-native (crypto module version) algorithms
1 parent 58bb233 commit cbf9d1d

8 files changed

+338
-234
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,12 @@ The following tokens are replaced in the `name` parameter:
7575
- `[query]` the queryof the resource, i.e. `?foo=bar`
7676
- `[contenthash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the `xxhash64` hash)
7777
- `[<hashType>:contenthash:<digestType>:<length>]` optionally one can configure
78-
- other `hashType`s, i. e. `xxhash64`, `sha1`, `md4`, `md5`, `sha256`, `sha512`
78+
- other `hashType`s, i. e. `xxhash64`, `sha1`, `md4` (wasm version), `native-md4` (`crypto` module version), `md5`, `sha256`, `sha512`
7979
- other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
8080
- and `length` the length in chars
8181
- `[hash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the `xxhash64` hash)
8282
- `[<hashType>:hash:<digestType>:<length>]` optionally one can configure
83-
- other `hashType`s, i. e. `xxhash64`, `sha1`, `md4`, `md5`, `sha256`, `sha512`
83+
- other `hashType`s, i. e. `xxhash64`, `sha1`, `md4` (wasm version), `native-md4` (`crypto` module version), `md5`, `sha256`, `sha512`
8484
- other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
8585
- and `length` the length in chars
8686
- `[N]` the N-th match obtained from matching the current file name against `options.regExp`

lib/getHashDigest.js

+29-180
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,5 @@
11
"use strict";
22

3-
// Copied from `webpack`
4-
//#region wasm code: xxhash64 (../../../assembly/hash/xxhash64.asm.ts) --initialMemory 1
5-
const xxhash64 = new WebAssembly.Module(
6-
Buffer.from(
7-
// 1180 bytes
8-
"AGFzbQEAAAABCAJgAX8AYAAAAwQDAQAABQMBAAEGGgV+AUIAC34BQgALfgFCAAt+AUIAC34BQgALByIEBGluaXQAAAZ1cGRhdGUAAQVmaW5hbAACBm1lbW9yeQIACrwIAzAAQtbrgu7q/Yn14AAkAELP1tO+0ser2UIkAUIAJAJC+erQ0OfJoeThACQDQgAkBAvUAQIBfwR+IABFBEAPCyMEIACtfCQEIwAhAiMBIQMjAiEEIwMhBQNAIAIgASkDAELP1tO+0ser2UJ+fEIfiUKHla+vmLbem55/fiECIAMgASkDCELP1tO+0ser2UJ+fEIfiUKHla+vmLbem55/fiEDIAQgASkDEELP1tO+0ser2UJ+fEIfiUKHla+vmLbem55/fiEEIAUgASkDGELP1tO+0ser2UJ+fEIfiUKHla+vmLbem55/fiEFIAAgAUEgaiIBSw0ACyACJAAgAyQBIAQkAiAFJAMLsgYCAX8EfiMEQgBSBH4jACICQgGJIwEiA0IHiXwjAiIEQgyJfCMDIgVCEol8IAJCz9bTvtLHq9lCfkIfiUKHla+vmLbem55/foVCh5Wvr5i23puef35CnaO16oOxjYr6AH0gA0LP1tO+0ser2UJ+Qh+JQoeVr6+Ytt6bnn9+hUKHla+vmLbem55/fkKdo7Xqg7GNivoAfSAEQs/W077Sx6vZQn5CH4lCh5Wvr5i23puef36FQoeVr6+Ytt6bnn9+Qp2jteqDsY2K+gB9IAVCz9bTvtLHq9lCfkIfiUKHla+vmLbem55/foVCh5Wvr5i23puef35CnaO16oOxjYr6AH0FQsXP2bLx5brqJwsjBCAArXx8IQIDQCABQQhqIABNBEAgAiABKQMAQs/W077Sx6vZQn5CH4lCh5Wvr5i23puef36FQhuJQoeVr6+Ytt6bnn9+Qp2jteqDsY2K+gB9IQIgAUEIaiEBDAELCyABQQRqIABNBEACfyACIAE1AgBCh5Wvr5i23puef36FQheJQs/W077Sx6vZQn5C+fPd8Zn2masWfCECIAFBBGoLIQELA0AgACABRwRAIAIgATEAAELFz9my8eW66id+hUILiUKHla+vmLbem55/fiECIAFBAWohAQwBCwtBACACIAJCIYiFQs/W077Sx6vZQn4iAiACQh2IhUL5893xmfaZqxZ+IgIgAkIgiIUiAjcDAEEAIAJCIIgiA0L//wODQiCGIANCgID8/w+DQhCIhCIDQv+BgIDwH4NCEIYgA0KA/oOAgOA/g0IIiIQiA0KPgLyA8IHAB4NCCIYgA0LwgcCHgJ6A+ACDQgSIhCIDQoaMmLDgwIGDBnxCBIhCgYKEiJCgwIABg0InfiADQrDgwIGDhoyYMIR8NwMAQQggAkL/////D4MiAkL//wODQiCGIAJCgID8/w+DQhCIhCICQv+BgIDwH4NCEIYgAkKA/oOAgOA/g0IIiIQiAkKPgLyA8IHAB4NCCIYgAkLwgcCHgJ6A+ACDQgSIhCICQoaMmLDgwIGDBnxCBIhCgYKEiJCgwIABg0InfiACQrDgwIGDhoyYMIR8NwMACw==",
9-
"base64"
10-
)
11-
);
12-
//#endregion
13-
14-
class XxHash64 {
15-
/**
16-
* @param {WebAssembly.Instance} instance wasm instance
17-
*/
18-
constructor(instance) {
19-
const exports = /** @type {any} */ (instance.exports);
20-
21-
exports.init();
22-
23-
this.exports = exports;
24-
this.mem = Buffer.from(exports.memory.buffer, 0, 65536);
25-
this.buffered = 0;
26-
}
27-
28-
reset() {
29-
this.buffered = 0;
30-
this.exports.init();
31-
}
32-
33-
/**
34-
* @param {Buffer | string} data data
35-
* @param {BufferEncoding=} encoding encoding
36-
* @returns {this} itself
37-
*/
38-
update(data, encoding) {
39-
if (typeof data === "string") {
40-
if (data.length < 21845) {
41-
this._updateWithShortString(data, encoding);
42-
43-
return this;
44-
} else {
45-
data = Buffer.from(data, encoding);
46-
}
47-
}
48-
49-
this._updateWithBuffer(data);
50-
51-
return this;
52-
}
53-
54-
/**
55-
* @param {string} data data
56-
* @param {BufferEncoding=} encoding encoding
57-
* @returns {void}
58-
*/
59-
_updateWithShortString(data, encoding) {
60-
const { exports, buffered, mem } = this;
61-
62-
let endPos;
63-
64-
if (data.length < 70) {
65-
if (!encoding || encoding === "utf-8" || encoding === "utf8") {
66-
endPos = buffered;
67-
68-
for (let i = 0; i < data.length; i++) {
69-
const cc = data.charCodeAt(i);
70-
71-
if (cc < 0x80) {
72-
mem[endPos++] = cc;
73-
} else if (cc < 0x800) {
74-
mem[endPos] = (cc >> 6) | 0xc0;
75-
mem[endPos + 1] = (cc & 0x3f) | 0x80;
76-
endPos += 2;
77-
} else {
78-
// bail-out for weird chars
79-
endPos += mem.write(data.slice(endPos), endPos, encoding);
80-
break;
81-
}
82-
}
83-
} else if (encoding === "latin1") {
84-
endPos = buffered;
85-
86-
for (let i = 0; i < data.length; i++) {
87-
const cc = data.charCodeAt(i);
88-
89-
mem[endPos++] = cc;
90-
}
91-
} else {
92-
endPos = buffered + mem.write(data, buffered, encoding);
93-
}
94-
} else {
95-
endPos = buffered + mem.write(data, buffered, encoding);
96-
}
97-
98-
if (endPos < 32) {
99-
this.buffered = endPos;
100-
} else {
101-
const l = (endPos >> 5) << 5;
102-
103-
exports.update(l);
104-
105-
const newBuffered = endPos - l;
106-
107-
this.buffered = newBuffered;
108-
109-
if (newBuffered > 0) {
110-
mem.copyWithin(0, l, endPos);
111-
}
112-
}
113-
}
114-
115-
/**
116-
* @param {Buffer} data data
117-
* @returns {void}
118-
*/
119-
_updateWithBuffer(data) {
120-
const { exports, buffered, mem } = this;
121-
const length = data.length;
122-
if (buffered + length < 32) {
123-
data.copy(mem, buffered, 0, length);
124-
this.buffered += length;
125-
} else {
126-
const l = ((buffered + length) >> 5) << 5;
127-
if (l > 65536) {
128-
let i = 65536 - buffered;
129-
data.copy(mem, buffered, 0, i);
130-
exports.update(65536);
131-
const stop = l - buffered - 65536;
132-
while (i < stop) {
133-
data.copy(mem, 0, i, i + 65536);
134-
exports.update(65536);
135-
i += 65536;
136-
}
137-
data.copy(mem, 0, i, l - buffered);
138-
exports.update(l - buffered - i);
139-
} else {
140-
data.copy(mem, buffered, 0, l - buffered);
141-
exports.update(l);
142-
}
143-
144-
const newBuffered = length + buffered - l;
145-
146-
this.buffered = newBuffered;
147-
148-
if (newBuffered > 0) {
149-
data.copy(mem, 0, length - newBuffered, length);
150-
}
151-
}
152-
}
153-
154-
digest() {
155-
const { exports, buffered, mem } = this;
156-
157-
exports.final(buffered);
158-
instancesPool.push(this);
159-
160-
return mem.toString("latin1", 0, 16);
161-
}
162-
}
163-
164-
const instancesPool = [];
165-
1663
const baseEncodeTables = {
1674
26: "abcdefghijklmnopqrstuvwxyz",
1685
32: "123456789abcdefghjkmnpqrstuvwxyz", // no 0lio
@@ -205,17 +42,9 @@ function encodeBufferToBase(buffer, base) {
20542
return output;
20643
}
20744

208-
const create = () => {
209-
if (instancesPool.length > 0) {
210-
const old = instancesPool.pop();
211-
212-
old.reset();
213-
214-
return old;
215-
} else {
216-
return new XxHash64(new WebAssembly.Instance(xxhash64));
217-
}
218-
};
45+
let crypto = undefined;
46+
let createXXHash64 = undefined;
47+
let createMd4 = undefined;
21948

22049
function getHashDigest(buffer, hashType, digestType, maxLength) {
22150
hashType = hashType || "xxhash64";
@@ -224,9 +53,29 @@ function getHashDigest(buffer, hashType, digestType, maxLength) {
22453
let hash;
22554

22655
if (hashType === "xxhash64") {
227-
hash = create(maxLength);
56+
if (createXXHash64 === undefined) {
57+
createXXHash64 = require("./hash/xxhash64");
58+
}
59+
60+
hash = createXXHash64();
61+
} else if (hashType === "md4") {
62+
if (createMd4 === undefined) {
63+
createMd4 = require("./hash/md4");
64+
}
65+
66+
hash = createMd4();
67+
} else if (hashType === "native-md4") {
68+
if (typeof crypto === "undefined") {
69+
crypto = require("crypto");
70+
}
71+
72+
hash = crypto.createHash("md4");
22873
} else {
229-
hash = require("crypto").createHash(hashType);
74+
if (typeof crypto === "undefined") {
75+
crypto = require("crypto");
76+
}
77+
78+
hash = crypto.createHash(hashType);
23079
}
23180

23281
hash.update(buffer);
@@ -241,10 +90,10 @@ function getHashDigest(buffer, hashType, digestType, maxLength) {
24190
digestType === "base62" ||
24291
digestType === "base64"
24392
) {
244-
return encodeBufferToBase(
245-
hashType === "xxhash64" ? Buffer.from(hash.digest()) : hash.digest(),
246-
digestType.substr(4)
247-
).substr(0, maxLength);
93+
return encodeBufferToBase(hash.digest(), digestType.substr(4)).substr(
94+
0,
95+
maxLength
96+
);
24897
} else {
24998
return hash.digest(digestType || "hex").substr(0, maxLength);
25099
}

lib/hash/md4.js

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)