mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-21 22:52:19 +03:00
Obrigado por restaurar e endurecer a autenticação por machine-token no CLI empacotado. Validação (worktree combinado a partir de origin/release/v3.8.50, merge limpo, 0 conflitos — 34 arquivos, +1078/-247): - `npm run typecheck:core` — limpo - `node scripts/check/check-complexity.mjs` — OK (2558 violações vs baseline 2774) - `node scripts/check/check-cognitive-complexity.mjs` — OK (1152 violações vs baseline 1223) - `node scripts/check/check-file-size.mjs` — OK - `node scripts/check/check-changelog-integrity.mjs` — OK - Testes focados (8 arquivos: cli-doctor-command, cli-machine-token, lib/machineToken, lib/managementCliToken, agentSkills-generator, api/settings-audit, check-pack-boot, next-config) — 95/95 passando Os dois achados de segurança do maintainer-feedback original (checagem de loopback tipo SSRF, escopo de cookie/CSRF) já estavam corrigidos e cobertos por teste no commit `2b785f0068a862fbd867221294325ad921787782` desta branch.
54 lines
2.0 KiB
JavaScript
54 lines
2.0 KiB
JavaScript
import crypto from "node:crypto";
|
|
|
|
const BUILTIN_DEFAULT_SALT = "omniroute-cli-auth-v1";
|
|
export const CLI_TOKEN_HEADER = "x-omniroute-cli-token";
|
|
|
|
let _cached = null;
|
|
let _cachedSalt = null;
|
|
|
|
/** Mirrors getActiveSalt() in src/lib/machineToken.ts so a rotated
|
|
* OMNIROUTE_CLI_SALT reaches the CLI too (docs/security/CLI_TOKEN.md). */
|
|
function getActiveSalt() {
|
|
return process.env.OMNIROUTE_CLI_SALT || BUILTIN_DEFAULT_SALT;
|
|
}
|
|
|
|
export function deriveCliToken(machineIdModule, salt) {
|
|
try {
|
|
// node-machine-id is CommonJS: under `await import()` its exports land on
|
|
// `.default`, so destructuring `machineIdSync` off the namespace yields
|
|
// undefined and calling it throws — which the catch below turned into an
|
|
// empty token, silently disabling CLI auth for every management request.
|
|
// Same resolution order as src/lib/machineToken.ts.
|
|
const machineIdSync =
|
|
machineIdModule?.machineIdSync || machineIdModule?.default?.machineIdSync;
|
|
if (typeof machineIdSync !== "function") return "";
|
|
// machineIdSync(true) returns the original unhashed hardware ID — mirrors
|
|
// getMachineTokenSync() in src/lib/machineToken.ts (#10148 cliToken hardening).
|
|
const rawId = machineIdSync(true);
|
|
if (!rawId) return "";
|
|
return crypto.createHmac("sha256", rawId).update(salt).digest("hex");
|
|
} catch {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
export async function getCliToken() {
|
|
const salt = getActiveSalt();
|
|
if (_cached !== null && _cachedSalt === salt) return _cached;
|
|
try {
|
|
const imported = await import("node-machine-id");
|
|
const token = deriveCliToken(imported, salt);
|
|
if (!token) {
|
|
// Swallowing here changes control flow (every management call goes out
|
|
// unauthenticated and 401s), so leave a breadcrumb rather than failing mute.
|
|
console.debug("[CLI_TOKEN] machine-id resolution failed, CLI auth disabled");
|
|
}
|
|
_cached = token;
|
|
} catch (e) {
|
|
console.debug("[CLI_TOKEN] machine-id resolution failed, CLI auth disabled:", e);
|
|
_cached = "";
|
|
}
|
|
_cachedSalt = salt;
|
|
return _cached;
|
|
}
|