mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-24 16:12:23 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
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;
|
|
}
|