Published source
Download source ZIP
CH-J Server Manager
Browse directories and files for a specific application release.
Source is provided under the CH-J Proprietary Software License 1.14. Its availability does not change the license terms or grant additional rights.
1
"use strict";2
const { spawn } = require("node:child_process");3
function biometricError(code, message = code) { return Object.assign(new Error(message), { code }); }4
class NativeRunner {5
constructor({ executable, args = [], timeoutMs = 65000, spawnImpl = spawn } = {}) { Object.assign(this, { executable, args, timeoutMs, spawnImpl }); }6
run(request, { signal } = {}) {7
if (signal?.aborted) return Promise.reject(biometricError("BIOMETRIC_CANCELLED"));8
return new Promise((resolve, reject) => {9
let child, output = Buffer.alloc(0), settled = false, timer;10
const finish = (error, result) => {11
if (settled) { if (result?.key) result.key = null; return; }12
settled = true; clearTimeout(timer); signal?.removeEventListener("abort", abort);13
output.fill(0); output = Buffer.alloc(0);14
if (error) { try { child?.kill(); } catch {} reject(error); } else resolve(result);15
};16
const abort = () => finish(biometricError("BIOMETRIC_CANCELLED"));17
try { child = this.spawnImpl(this.executable, this.args, { shell: false, windowsHide: true, stdio: ["pipe", "pipe", "pipe"] }); }18
catch { finish(biometricError("BIOMETRIC_UNAVAILABLE")); return; }19
signal?.addEventListener("abort", abort, { once: true });20
timer = setTimeout(() => finish(biometricError("BIOMETRIC_TIMEOUT")), request.op === "status" ? Math.min(8000, this.timeoutMs) : this.timeoutMs);21
child.on("error", () => finish(biometricError("BIOMETRIC_UNAVAILABLE")));22
child.stdin.on("error", () => finish(biometricError("BIOMETRIC_UNAVAILABLE")));23
// Never forward helper stderr, stdin or raw responses to logs or the renderer.24
child.stderr.on("data", () => {});25
child.stdout.on("data", chunk => {26
if (settled) return;27
if (output.length + chunk.length > 16384) { finish(biometricError("BIOMETRIC_FAILED")); return; }28
const previous = output; output = Buffer.concat([output, chunk]); previous.fill(0);29
});30
child.once("close", code => {31
if (settled) return;32
try {33
const value = JSON.parse(output.toString("utf8"));34
if (code !== 0 || value.ok !== true) throw biometricError(/^BIOMETRIC_[A-Z_]+$/.test(value.code) ? value.code : "BIOMETRIC_FAILED");35
finish(null, value);36
} catch (error) { finish(error.code?.startsWith("BIOMETRIC_") ? error : biometricError("BIOMETRIC_FAILED")); }37
});38
const input = Buffer.from(JSON.stringify(request) + "\n");39
child.stdin.end(input, () => input.fill(0));40
});41
}42
}43
module.exports = { NativeRunner, biometricError };SHA-256: 9be476532a518be0a6b27290ecf0a15ead61e35b3ffa4040731fd168f2ca325d
Archive SHA-256: 5ac91caf4fa32a6fdb114f2430deed486fbe7489d5eea343d1f034169fafb5e0