Files
origin_client/js/src/machineId.ts
T
warkanumandClaude Sonnet 5 2590e404f5
CI / rust (push) Successful in 3m6s
CI / go (push) Successful in 33s
CI / js (push) Successful in 34s
feat: initial Go/JS/Rust Origin check-in client SDKs
Standalone clients that resolve a machine unique ID (OS machine ID first,
falling back to a generated UUID persisted to disk), detect hostname/IP/
container/orchestrator, and register+re-ping origin.warky.dev's public
service-checkin endpoint on a daily interval. Ported from icy2's internal
origincheckin package but extended to the full check-in contract and made
dependency-light for external reuse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 15:25:30 +02:00

125 lines
3.9 KiB
TypeScript

import { execFileSync } from "node:child_process";
import { randomUUID } from "node:crypto";
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { homedir, platform, tmpdir } from "node:os";
import { dirname, join } from "node:path";
export interface Logger {
warn(msg: string, err?: unknown): void;
}
const noopLogger: Logger = { warn: () => {} };
function readLinuxMachineId(): string | undefined {
for (const path of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
try {
const id = readFileSync(path, "utf8").trim();
if (id) return id;
} catch {
// try the next candidate path
}
}
return undefined;
}
function readDarwinMachineId(): string | undefined {
try {
const out = execFileSync("ioreg", ["-rd1", "-c", "IOPlatformExpertDevice"], {
encoding: "utf8",
timeout: 2000,
});
return out.match(/"IOPlatformUUID"\s*=\s*"([0-9A-Fa-f-]+)"/)?.[1];
} catch {
return undefined;
}
}
function readWindowsMachineId(): string | undefined {
try {
const out = execFileSync(
"reg",
["query", "HKLM\\SOFTWARE\\Microsoft\\Cryptography", "/v", "MachineGuid"],
{ encoding: "utf8", timeout: 2000 },
);
return out.match(/MachineGuid\s+REG_SZ\s+([0-9A-Fa-f-]+)/)?.[1];
} catch {
return undefined;
}
}
/** detectOsMachineId reads the real OS machine ID, or undefined if unavailable/unsupported. */
export function detectOsMachineId(): string | undefined {
switch (platform()) {
case "linux":
return readLinuxMachineId();
case "darwin":
return readDarwinMachineId();
case "win32":
return readWindowsMachineId();
default:
return undefined;
}
}
/**
* machineIdDetector is a mutable indirection over detectOsMachineId so
* tests can stub OS machine-id lookup without depending on the actual
* host's state. It's a settable-property holder rather than a plain
* exported `let` because ES module namespace bindings can't be reassigned
* from outside the module.
*/
export const machineIdDetector: { current: () => string | undefined } = {
current: detectOsMachineId,
};
/** defaultInstallIdPath returns the fallback-UUID persistence path used when no explicit path is given. */
export function defaultInstallIdPath(): string {
const base = process.env.XDG_CONFIG_HOME || join(homedir() || tmpdir(), ".config");
return join(base, "origin-client", "install-id");
}
/**
* resolveMachineId returns the unique install ID to report to Origin, in
* priority order:
*
* 1. explicit, if non-empty - a caller-supplied override.
* 2. the real OS machine ID (/etc/machine-id on Linux, IOPlatformUUID on
* macOS, MachineGuid on Windows), if readable.
* 3. the ID already persisted at path, if present.
* 4. a newly generated UUID, which resolveMachineId attempts to persist
* to path for future runs.
*
* OS-ID and persistence failures are logged as warnings, not thrown:
* resolveMachineId always returns a usable ID.
*/
export function resolveMachineId(explicit?: string, path?: string, logger: Logger = noopLogger): string {
const trimmedExplicit = explicit?.trim();
if (trimmedExplicit) return trimmedExplicit;
const osId = machineIdDetector.current();
if (osId) {
const trimmed = osId.trim();
if (trimmed) return trimmed;
} else {
logger.warn("machine id: OS machine id unavailable, falling back to a generated id");
}
const resolvedPath = path && path.length > 0 ? path : defaultInstallIdPath();
try {
const existing = readFileSync(resolvedPath, "utf8").trim();
if (existing) return existing;
} catch {
// no persisted id yet
}
const id = randomUUID();
try {
mkdirSync(dirname(resolvedPath), { recursive: true, mode: 0o750 });
writeFileSync(resolvedPath, id + "\n", { mode: 0o600 });
} catch (err) {
logger.warn("machine id: failed to persist generated id, using an ephemeral id for this run", err);
}
return id;
}