132 lines
3.7 KiB
JavaScript
132 lines
3.7 KiB
JavaScript
"use strict";
|
|
|
|
const baseEncodeTables = {
|
|
26: "abcdefghijklmnopqrstuvwxyz",
|
|
32: "123456789abcdefghjkmnpqrstuvwxyz", // no 0lio
|
|
36: "0123456789abcdefghijklmnopqrstuvwxyz",
|
|
49: "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", // no lIO
|
|
52: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
58: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", // no 0lIO
|
|
62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
64: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_",
|
|
};
|
|
|
|
/**
|
|
* @param {Uint32Array} uint32Array Treated as a long base-0x100000000 number, little endian
|
|
* @param {number} divisor The divisor
|
|
* @return {number} Modulo (remainder) of the division
|
|
*/
|
|
function divmod32(uint32Array, divisor) {
|
|
let carry = 0;
|
|
for (let i = uint32Array.length - 1; i >= 0; i--) {
|
|
const value = carry * 0x100000000 + uint32Array[i];
|
|
carry = value % divisor;
|
|
uint32Array[i] = Math.floor(value / divisor);
|
|
}
|
|
return carry;
|
|
}
|
|
|
|
function encodeBufferToBase(buffer, base, length) {
|
|
const encodeTable = baseEncodeTables[base];
|
|
|
|
if (!encodeTable) {
|
|
throw new Error("Unknown encoding base" + base);
|
|
}
|
|
|
|
// Input bits are only enough to generate this many characters
|
|
const limit = Math.ceil((buffer.length * 8) / Math.log2(base));
|
|
length = Math.min(length, limit);
|
|
|
|
// Most of the crypto digests (if not all) has length a multiple of 4 bytes.
|
|
// Fewer numbers in the array means faster math.
|
|
const uint32Array = new Uint32Array(Math.ceil(buffer.length / 4));
|
|
|
|
// Make sure the input buffer data is copied and is not mutated by reference.
|
|
// divmod32() would corrupt the BulkUpdateDecorator cache otherwise.
|
|
buffer.copy(Buffer.from(uint32Array.buffer));
|
|
|
|
let output = "";
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
output = encodeTable[divmod32(uint32Array, base)] + output;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
let crypto = undefined;
|
|
let createXXHash64 = undefined;
|
|
let createMd4 = undefined;
|
|
let BatchedHash = undefined;
|
|
let BulkUpdateDecorator = undefined;
|
|
|
|
function getHashDigest(buffer, algorithm, digestType, maxLength) {
|
|
algorithm = algorithm || "xxhash64";
|
|
maxLength = maxLength || 9999;
|
|
|
|
let hash;
|
|
|
|
if (algorithm === "xxhash64") {
|
|
if (createXXHash64 === undefined) {
|
|
createXXHash64 = require("./hash/xxhash64");
|
|
|
|
if (BatchedHash === undefined) {
|
|
BatchedHash = require("./hash/BatchedHash");
|
|
}
|
|
}
|
|
|
|
hash = new BatchedHash(createXXHash64());
|
|
} else if (algorithm === "md4") {
|
|
if (createMd4 === undefined) {
|
|
createMd4 = require("./hash/md4");
|
|
|
|
if (BatchedHash === undefined) {
|
|
BatchedHash = require("./hash/BatchedHash");
|
|
}
|
|
}
|
|
|
|
hash = new BatchedHash(createMd4());
|
|
} else if (algorithm === "native-md4") {
|
|
if (typeof crypto === "undefined") {
|
|
crypto = require("crypto");
|
|
|
|
if (BulkUpdateDecorator === undefined) {
|
|
BulkUpdateDecorator = require("./hash/BulkUpdateDecorator");
|
|
}
|
|
}
|
|
|
|
hash = new BulkUpdateDecorator(() => crypto.createHash("md4"), "md4");
|
|
} else {
|
|
if (typeof crypto === "undefined") {
|
|
crypto = require("crypto");
|
|
|
|
if (BulkUpdateDecorator === undefined) {
|
|
BulkUpdateDecorator = require("./hash/BulkUpdateDecorator");
|
|
}
|
|
}
|
|
|
|
hash = new BulkUpdateDecorator(
|
|
() => crypto.createHash(algorithm),
|
|
algorithm
|
|
);
|
|
}
|
|
|
|
hash.update(buffer);
|
|
|
|
if (
|
|
digestType === "base26" ||
|
|
digestType === "base32" ||
|
|
digestType === "base36" ||
|
|
digestType === "base49" ||
|
|
digestType === "base52" ||
|
|
digestType === "base58" ||
|
|
digestType === "base62"
|
|
) {
|
|
return encodeBufferToBase(hash.digest(), digestType.substr(4), maxLength);
|
|
} else {
|
|
return hash.digest(digestType || "hex").substr(0, maxLength);
|
|
}
|
|
}
|
|
|
|
module.exports = getHashDigest;
|