File size: 2,227 Bytes
88c4c60 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | import { machineIdSync } from 'node-machine-id';
import fs from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
import { DATA_DIR } from '@/lib/dataDir';
const MACHINE_ID_FILE = path.join(DATA_DIR, 'machine-id');
const AUTH_DIR = path.join(DATA_DIR, 'auth');
const CLI_SECRET_FILE = path.join(AUTH_DIR, 'cli-secret');
const CLI_AUTH_SALT = '9r-cli-auth';
let cachedRawId = null;
let cachedCliSecret = null;
// Persist raw machine ID to file → guarantees CLI/server/middleware see same value
// even when machineIdSync fails or returns inconsistent values across runtimes.
function loadRawMachineId() {
if (cachedRawId) return cachedRawId;
try {
cachedRawId = fs.readFileSync(MACHINE_ID_FILE, 'utf8').trim();
if (cachedRawId) return cachedRawId;
} catch {}
try {
cachedRawId = machineIdSync();
} catch {
cachedRawId = crypto.randomUUID();
}
try {
fs.mkdirSync(DATA_DIR, { recursive: true });
fs.writeFileSync(MACHINE_ID_FILE, cachedRawId, { mode: 0o600 });
} catch {}
return cachedRawId;
}
// Random secret persisted on first run → unpredictable CLI token even when machineId leaks.
function loadCliSecret() {
if (cachedCliSecret) return cachedCliSecret;
try {
cachedCliSecret = fs.readFileSync(CLI_SECRET_FILE, 'utf8').trim();
if (cachedCliSecret) return cachedCliSecret;
} catch {}
cachedCliSecret = crypto.randomBytes(32).toString('hex');
try {
fs.mkdirSync(AUTH_DIR, { recursive: true });
fs.writeFileSync(CLI_SECRET_FILE, cachedCliSecret, { mode: 0o600 });
} catch {}
return cachedCliSecret;
}
export async function getConsistentMachineId(salt = null) {
const saltValue = salt || process.env.MACHINE_ID_SALT || 'endpoint-proxy-salt';
const raw = loadRawMachineId();
const extra = saltValue === CLI_AUTH_SALT ? loadCliSecret() : '';
return crypto.createHash('sha256').update(raw + saltValue + extra).digest('hex').substring(0, 16);
}
export async function getRawMachineId() {
return loadRawMachineId();
}
/**
* Check if we're running in browser or server environment
* @returns {boolean} True if in browser, false if in server
*/
export function isBrowser() {
return typeof window !== 'undefined';
}
|