CH-J Server ManagerSerververwaltung über SSH
Menü
Veröffentlichte Quellen

CH-J Server Manager

Durchsuchen Sie Verzeichnisse und Dateien einer bestimmten Anwendungsausgabe.

Quellen als ZIP herunterladen
CH-J Proprietary Software License 1.14

Die Quellen werden unter der CH-J Proprietary Software License 1.14 bereitgestellt. Ihre Verfügbarkeit ändert die Lizenzbedingungen nicht und gewährt keine zusätzlichen Rechte.

9,0 KB · 169 ZeilenDatei herunterladen
1"use strict";
3const crypto = require("node:crypto");
4const fs = require("node:fs");
5const { parentPort, workerData } = require("node:worker_threads");
6const hashWasm = require("hash-wasm");
7const { FileView, cityHash32, cityHash64, cityHash128, digest128, numericDigest } = require("./cityHash");
8const { createPortableHash } = require("./portableHashes");
10const 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});
15const RANDOM_ACCESS = new Set(["cityhash32", "cityhash64", "cityhash128", "farmhash32", "farmhash64", "farmhash128"]);
17function isCancelled() { return Atomics.load(workerData.cancelView, 0) === 1; }
18function cancelledError() { const error = new Error("Hash job was cancelled."); error.code = "HASH_CANCELLED"; return error; }
19function checkCancelled() { if (isCancelled()) throw cancelledError(); }
20function statIdentity(stat) { return { dev: String(stat.dev), ino: String(stat.ino), size: String(stat.size), mtimeNs: String(stat.mtimeNs) }; }
21function sameIdentity(left, right) { return left.dev === String(right.dev) && left.ino === String(right.ino) && left.size === String(right.size) && left.mtimeNs === String(right.mtimeNs); }
23async 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 }
80function 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));
89async 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 }
119async 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 }
169void run();

SHA-256: e4c4a9be7c306dcd456e5bad6c932e1d108c6b1ca26cfb371c57b2766900878b

SHA-256 des Archivs: 5ac91caf4fa32a6fdb114f2430deed486fbe7489d5eea343d1f034169fafb5e0