Vydané zdroje
Stáhnout zdroje ZIP
CH-J Server Manager
Procházejte adresáře a soubory konkrétního vydání aplikace.
Zdroje jsou zveřejněny pod CH-J Proprietary Software License 1.14. Jejich dostupnost nemění licenční podmínky ani neposkytuje další oprávnění.
1
"use strict";3
const crypto = require("node:crypto");4
const fs = require("node:fs");5
const { parentPort, workerData } = require("node:worker_threads");6
const hashWasm = require("hash-wasm");7
const { FileView, cityHash32, cityHash64, cityHash128, digest128, numericDigest } = require("./cityHash");8
const { createPortableHash } = require("./portableHashes");10
const NODE_NAMES = Object.freeze({11
sha224: "sha224", sha256: "sha256", sha384: "sha384", sha512: "sha512",12
"sha512-256": "sha512-256",13
ripemd160: "ripemd160", md5: "md5", sha1: "sha1"14
});15
const RANDOM_ACCESS = new Set(["cityhash32", "cityhash64", "cityhash128", "farmhash32", "farmhash64", "farmhash128"]);17
function isCancelled() { return Atomics.load(workerData.cancelView, 0) === 1; }18
function cancelledError() { const error = new Error("Hash job was cancelled."); error.code = "HASH_CANCELLED"; return error; }19
function checkCancelled() { if (isCancelled()) throw cancelledError(); }20
function statIdentity(stat) { return { dev: String(stat.dev), ino: String(stat.ino), size: String(stat.size), mtimeNs: String(stat.mtimeNs) }; }21
function sameIdentity(left, right) { return left.dev === String(right.dev) && left.ino === String(right.ino) && left.size === String(right.size) && left.mtimeNs === String(right.mtimeNs); }23
async function createContext(request) {24
if (NODE_NAMES[request.id]) {25
const options = request.id.startsWith("shake") ? { outputLength: request.outputBytes } : undefined;26
return crypto.createHash(NODE_NAMES[request.id], options);27
}28
const portable = createPortableHash(request);29
if (portable) return portable;30
const seed = BigInt(request.seed || "0"); const low = Number(seed & 0xffffffffn); const high = Number((seed >> 32n) & 0xffffffffn);31
switch (request.id) {32
case "sha512-224": {33
const { sha512_224 } = await import("@noble/hashes/sha2.js");34
return sha512_224.create();35
}36
case "sha3-224":37
case "sha3-256":38
case "sha3-384":39
case "sha3-512":40
case "shake128":41
case "shake256": {42
const sha3 = await import("@noble/hashes/sha3.js");43
const name = request.id.replace("-", "_");44
return sha3[name].create(request.id.startsWith("shake") ? { dkLen: request.outputBytes } : undefined);45
}46
case "blake2b-512":47
case "blake2s-256": {48
const { blake2b, blake2s } = await import("@noble/hashes/blake2.js");49
return request.id === "blake2b-512" ? blake2b.create({ dkLen: 64 }) : blake2s.create({ dkLen: 32 });50
}51
case "blake3": return hashWasm.createBLAKE3(256);52
case "whirlpool": return hashWasm.createWhirlpool();53
case "xxh32": return hashWasm.createXXHash32(low);54
case "xxh64": return hashWasm.createXXHash64(low, high);55
case "xxh3-64": return hashWasm.createXXHash3(low, high);56
case "xxh3-128": return hashWasm.createXXHash128(low, high);57
case "crc32": return hashWasm.createCRC32(0xedb88320);58
case "crc32c": return hashWasm.createCRC32(0x82f63b78);59
case "adler32": return hashWasm.createAdler32();60
case "kangaroo-twelve": {61
const { kt128 } = await import("@noble/hashes/sha3-addons.js");62
return kt128.create({ dkLen: request.outputBytes });63
}64
case "highwayhash64":65
case "highwayhash128":66
case "highwayhash256": {67
const { WasmHighwayHash } = require("highwayhasher");68
const hash = await WasmHighwayHash.load(Buffer.from(request.keyHex, "hex"));69
return {70
update: (chunk) => hash.append(chunk),71
finalize64: () => hash.finalize64(),72
finalize128: () => hash.finalize128(),73
finalize256: () => hash.finalize256()74
};75
}76
default: throw Object.assign(new Error(`Unsupported algorithm in worker: ${request.id}`), { code: "HASH_UNSUPPORTED_ALGORITHM" });77
}78
}80
function finishContext(request, context) {81
if (request.id.startsWith("highwayhash")) {82
const method = request.id === "highwayhash64" ? "finalize64" : (request.id === "highwayhash128" ? "finalize128" : "finalize256");83
return Buffer.from(context[method]());84
}85
const result = context.digest("binary");86
return Buffer.isBuffer(result) ? result : (typeof result === "string" ? Buffer.from(result, "latin1") : Buffer.from(result));87
}89
async function farmDigests(view, requests) {90
const module = await import("farmhashjs");91
const marker = Object.freeze({ fileView: true });92
const virtual = new Proxy({93
length: view.length,94
readUInt32LE: (offset = 0) => { checkCancelled(); return view.u32(offset); },95
readBigUInt64LE: (offset = 0) => { checkCancelled(); return view.u64(offset); },96
readInt8: (offset = 0) => { checkCancelled(); const value = view.byte(offset); return value > 127 ? value - 256 : value; }97
}, {98
get(target, property) {99
if (property in target) return target[property];100
if (typeof property === "string" && /^\d+$/.test(property)) { checkCancelled(); return view.byte(Number(property)); }101
return undefined;102
}103
});104
const originalFrom = Buffer.from;105
Buffer.from = function patchedFrom(value, ...args) { return value === marker ? virtual : originalFrom(value, ...args); };106
try {107
const results = new Map();108
for (const request of requests) {109
checkCancelled();110
if (request.id === "farmhash32") results.set(request.id, numericDigest(module.fingerprint32(marker), 4));111
if (request.id === "farmhash64") results.set(request.id, numericDigest(module.fingerprint64BigInt(marker), 8));112
}113
return results;114
} finally {115
Buffer.from = originalFrom;116
}117
}119
async function run() {120
const flags = fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0);121
let fd;122
try {123
fd = fs.openSync(workerData.filePath, flags);124
const before = fs.fstatSync(fd, { bigint: true });125
if (!before.isFile()) throw Object.assign(new Error("Only regular files can be hashed."), { code: "HASH_NOT_REGULAR_FILE" });126
if (!sameIdentity(workerData.expected, before)) throw Object.assign(new Error("The selected file changed before hashing started."), { code: "HASH_FILE_CHANGED" });127
const streamRequests = workerData.algorithms.filter((request) => !RANDOM_ACCESS.has(request.id));128
const contexts = new Map();129
for (const request of streamRequests) { checkCancelled(); contexts.set(request.id, await createContext(request)); }130
const buffer = Buffer.allocUnsafe(workerData.chunkSize);131
let position = 0; let lastProgress = 0;132
while (position < Number(before.size)) {133
checkCancelled();134
const bytes = fs.readSync(fd, buffer, 0, Math.min(buffer.length, Number(before.size) - position), position);135
if (!bytes) throw Object.assign(new Error("Selected file ended unexpectedly."), { code: "HASH_FILE_CHANGED" });136
const chunk = buffer.subarray(0, bytes);137
for (const context of contexts.values()) context.update(chunk);138
position += bytes;139
const now = Date.now();140
if (now - lastProgress >= 100 || position === Number(before.size)) { parentPort.postMessage({ type: "progress", bytes: position, total: Number(before.size) }); lastProgress = now; }141
await new Promise((resolve) => setImmediate(resolve));142
}143
const results = new Map();144
for (const request of streamRequests) { checkCancelled(); results.set(request.id, finishContext(request, contexts.get(request.id))); }145
const randomRequests = workerData.algorithms.filter((request) => RANDOM_ACCESS.has(request.id));146
if (randomRequests.length) {147
const view = new FileView(fd, Number(before.size));148
const originalEnsure = view._ensure.bind(view);149
view._ensure = (offset, width) => { checkCancelled(); return originalEnsure(offset, width); };150
if (randomRequests.some((request) => request.id === "cityhash32")) results.set("cityhash32", numericDigest(cityHash32(view), 4));151
if (randomRequests.some((request) => request.id === "cityhash64")) results.set("cityhash64", numericDigest(cityHash64(view), 8));152
let value128 = null;153
if (randomRequests.some((request) => request.id === "cityhash128" || request.id === "farmhash128")) value128 = digest128(cityHash128(view));154
if (randomRequests.some((request) => request.id === "cityhash128")) results.set("cityhash128", value128);155
if (randomRequests.some((request) => request.id === "farmhash128")) results.set("farmhash128", Buffer.from(value128));156
const farms = await farmDigests(view, randomRequests.filter((request) => request.id === "farmhash32" || request.id === "farmhash64"));157
for (const [id, digest] of farms) results.set(id, digest);158
}159
const after = fs.fstatSync(fd, { bigint: true });160
if (!sameIdentity(statIdentity(before), after)) throw Object.assign(new Error("The file changed while it was being hashed."), { code: "HASH_FILE_CHANGED" });161
parentPort.postMessage({ type: "complete", results: workerData.algorithms.map((request) => ({ id: request.id, hex: results.get(request.id).toString("hex") })) });162
} catch (error) {163
parentPort.postMessage({ type: "error", code: error?.code || "HASH_INTERNAL_ERROR", message: error?.message || String(error) });164
} finally {165
if (fd !== undefined) try { fs.closeSync(fd); } catch {}166
}167
}169
void run();SHA-256: e4c4a9be7c306dcd456e5bad6c932e1d108c6b1ca26cfb371c57b2766900878b
SHA-256 archivu: 5ac91caf4fa32a6fdb114f2430deed486fbe7489d5eea343d1f034169fafb5e0