mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-04-28 06:19:46 +00:00
167 lines
4.5 KiB
JavaScript
167 lines
4.5 KiB
JavaScript
import { existsSync, openSync, readSync, closeSync } from "node:fs";
|
|
|
|
export const PUBLISHED_BUILD_PLATFORM = "linux";
|
|
export const PUBLISHED_BUILD_ARCH = "x64";
|
|
|
|
const HEADER_SIZE = 4096;
|
|
const MAX_FAT_ARCH_COUNT = 30;
|
|
|
|
function mapElfMachine(machine) {
|
|
switch (machine) {
|
|
case 62:
|
|
return "x64";
|
|
case 183:
|
|
return "arm64";
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function mapMachCpuType(cpuType) {
|
|
switch (cpuType) {
|
|
case 0x01000007:
|
|
return "x64";
|
|
case 0x0100000c:
|
|
return "arm64";
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function mapPeMachine(machine) {
|
|
switch (machine) {
|
|
case 0x8664:
|
|
return "x64";
|
|
case 0xaa64:
|
|
return "arm64";
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function readUInt16(buffer, offset, littleEndian) {
|
|
return littleEndian ? buffer.readUInt16LE(offset) : buffer.readUInt16BE(offset);
|
|
}
|
|
|
|
function readUInt32(buffer, offset, littleEndian) {
|
|
return littleEndian ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset);
|
|
}
|
|
|
|
const ELF_MAGIC = 0x7f454c46;
|
|
|
|
function detectElfTarget(buffer) {
|
|
if (buffer.length < 20) return null;
|
|
if (buffer.readUInt32BE(0) !== ELF_MAGIC) return null;
|
|
|
|
const littleEndian = buffer[5] !== 2;
|
|
const arch = mapElfMachine(readUInt16(buffer, 18, littleEndian));
|
|
if (!arch) return null;
|
|
|
|
return { platform: "linux", architectures: [arch] };
|
|
}
|
|
|
|
const THIN_MACH_MAGIC = new Map([
|
|
[0xfeedface, false],
|
|
[0xfeedfacf, false],
|
|
[0xcefaedfe, true],
|
|
[0xcffaedfe, true],
|
|
]);
|
|
const FAT_MACH_MAGIC = new Map([
|
|
[0xcafebabe, false],
|
|
[0xcafebabf, false],
|
|
[0xbebafeca, true],
|
|
[0xbfbafeca, true],
|
|
]);
|
|
|
|
function detectMachTarget(buffer) {
|
|
if (buffer.length < 8) return null;
|
|
|
|
const magic = buffer.readUInt32BE(0);
|
|
|
|
if (THIN_MACH_MAGIC.has(magic)) {
|
|
const littleEndian = THIN_MACH_MAGIC.get(magic);
|
|
const arch = mapMachCpuType(readUInt32(buffer, 4, littleEndian));
|
|
if (!arch) return null;
|
|
return { platform: "darwin", architectures: [arch] };
|
|
}
|
|
|
|
if (!FAT_MACH_MAGIC.has(magic)) return null;
|
|
|
|
const littleEndian = FAT_MACH_MAGIC.get(magic);
|
|
const isFat64 = magic === 0xcafebabf || magic === 0xbfbafeca;
|
|
const archCount = readUInt32(buffer, 4, littleEndian);
|
|
if (archCount > MAX_FAT_ARCH_COUNT) return null;
|
|
const entrySize = isFat64 ? 32 : 20;
|
|
const architectures = new Set();
|
|
|
|
for (let index = 0; index < archCount; index += 1) {
|
|
const offset = 8 + index * entrySize;
|
|
if (offset + 4 > buffer.length) break;
|
|
const arch = mapMachCpuType(readUInt32(buffer, offset, littleEndian));
|
|
if (arch) architectures.add(arch);
|
|
}
|
|
|
|
if (architectures.size === 0) return null;
|
|
return { platform: "darwin", architectures: [...architectures] };
|
|
}
|
|
|
|
function detectPeTarget(buffer) {
|
|
if (buffer.length < 0x40) return null;
|
|
if (buffer.readUInt16LE(0) !== 0x5a4d) return null;
|
|
|
|
const peHeaderOffset = buffer.readUInt32LE(0x3c);
|
|
if (peHeaderOffset + 6 > buffer.length) return null;
|
|
if (buffer.readUInt32LE(peHeaderOffset) !== 0x00004550) return null;
|
|
|
|
const arch = mapPeMachine(buffer.readUInt16LE(peHeaderOffset + 4));
|
|
if (!arch) return null;
|
|
return { platform: "win32", architectures: [arch] };
|
|
}
|
|
|
|
export function detectNativeBinaryTarget(buffer) {
|
|
return detectElfTarget(buffer) ?? detectMachTarget(buffer) ?? detectPeTarget(buffer);
|
|
}
|
|
|
|
export function readNativeBinaryTarget(binaryPath) {
|
|
if (!existsSync(binaryPath)) return null;
|
|
|
|
let fd;
|
|
try {
|
|
fd = openSync(binaryPath, "r");
|
|
const buffer = Buffer.alloc(HEADER_SIZE);
|
|
const bytesRead = readSync(fd, buffer, 0, HEADER_SIZE, 0);
|
|
return detectNativeBinaryTarget(buffer.subarray(0, bytesRead));
|
|
} catch (err) {
|
|
console.warn(` ⚠️ Could not read native binary at ${binaryPath}: ${err.message}`);
|
|
return null;
|
|
} finally {
|
|
if (fd !== undefined) closeSync(fd);
|
|
}
|
|
}
|
|
|
|
export function isNativeBinaryCompatible(
|
|
binaryPath,
|
|
{ runtimePlatform = process.platform, runtimeArch = process.arch, dlopen = process.dlopen } = {}
|
|
) {
|
|
const target = readNativeBinaryTarget(binaryPath);
|
|
|
|
if (target) {
|
|
if (
|
|
(target.platform !== runtimePlatform &&
|
|
!(target.platform === "linux" && runtimePlatform === "android")) ||
|
|
!target.architectures.includes(runtimeArch)
|
|
) {
|
|
return false;
|
|
}
|
|
} else if (runtimePlatform !== PUBLISHED_BUILD_PLATFORM || runtimeArch !== PUBLISHED_BUILD_ARCH) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
dlopen({ exports: {} }, binaryPath);
|
|
return true;
|
|
} catch (err) {
|
|
console.warn(` ⚠️ Native binary dlopen failed: ${err.message}`);
|
|
return false;
|
|
}
|
|
}
|