mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-18 21:22:28 +03:00
* fix(cli): derive machine-id token under plain Node and honor salt rotation
`getCliToken()` destructured `machineIdSync` off `await import("node-machine-id")`.
That module is CommonJS, so under plain Node its exports land on `.default` and the
destructured binding is `undefined`. Calling it threw, the bare catch blanked the
token, and every management request went out with no `x-omniroute-cli-token` header
— silently unauthenticated, 401 on every `omniroute combo` / `usage budget` call.
Resolve the binding the same way `src/lib/machineToken.ts` already does, and read
`OMNIROUTE_CLI_SALT` so the rotation documented in docs/security/CLI_TOKEN.md
actually reaches CLI processes (the salt was hardcoded). The catch now logs instead
of failing mute, per the error-handling convention in CONTRIBUTING.md.
The existing test asserted `token === "" || token.length === 32`, so the blanked
token passed. Tightening it in-process is not enough either: the suite runs under
`tsx/esm`, which resolves CJS named exports and hides the bug. The regression test
therefore spawns plain `node` — the loader the CLI actually runs under.
Both new tests fail on the previous code and pass on this one.
* chore(changelog): use the real PR number for the fragment
41 lines
1.5 KiB
JavaScript
41 lines
1.5 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 async function getCliToken() {
|
|
const salt = getActiveSalt();
|
|
if (_cached !== null && _cachedSalt === salt) return _cached;
|
|
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 mod = await import("node-machine-id");
|
|
const machineIdSync = mod.machineIdSync ?? mod.default?.machineIdSync;
|
|
const mid = machineIdSync();
|
|
_cached = crypto
|
|
.createHash("sha256")
|
|
.update(mid + salt)
|
|
.digest("hex")
|
|
.substring(0, 32);
|
|
} catch (e) {
|
|
// 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:", e);
|
|
_cached = "";
|
|
}
|
|
_cachedSalt = salt;
|
|
return _cached;
|
|
}
|