mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-01 21:02:12 +03:00
- management.ts: replace === with timingSafeEqual for CLI token comparison - machineToken.ts: salt upgraded to omniroute-cli-auth-v1; OMNIROUTE_CLI_SALT env var honoured for rotation; full 64-char SHA-256 hex token - tray.ps1: accept .png via GDI+ Bitmap->Icon handle; Windows tray works without .ico - tray.ts: getIconPath() tries icon.ico then icon.png on Windows - compression/types.ts: DEFAULT_CAVEMAN_CONFIG.preservePatterns filled with six defaults (fenced code, inline code, URLs, paths, error lines, stack traces) - CLAUDE.md: Hard Rule #15 — spawn-capable routes must use isLocalOnlyPath() - .env.example + docs/reference/ENVIRONMENT.md: document OMNIROUTE_CLI_SALT - docs/security/CLI_TOKEN.md: new (was referenced in changelog but missing) - docs/security/ROUTE_GUARD_TIERS.md: new (was referenced in changelog but missing) - tests/unit/lib/machineToken.test.ts: updated for 64-char token; added OMNIROUTE_CLI_SALT env-var rotation test
65 lines
3.3 KiB
Markdown
65 lines
3.3 KiB
Markdown
# CLI Machine-ID Token
|
|
|
|
## Overview
|
|
|
|
OmniRoute CLI commands authenticate against the local management API using a
|
|
`HMAC-SHA256(machine-id, salt)` token sent via the `x-omniroute-cli-token`
|
|
request header.
|
|
|
|
This allows CLI subcommands (`omniroute status`, `omniroute providers`, etc.)
|
|
to call management endpoints without requiring the user to supply a JWT or
|
|
password on every invocation.
|
|
|
|
## How it works
|
|
|
|
1. `getMachineTokenSync()` reads the hardware machine ID via `node-machine-id`
|
|
(falls back to an empty string on failure, disabling CLI auth).
|
|
2. It computes `HMAC-SHA256(machine_id, salt)` and returns the full 64-char
|
|
hex digest — a deterministic, non-reversible token tied to this machine.
|
|
3. The CLI sends the token as `x-omniroute-cli-token` on every request to
|
|
`http://localhost:<port>/api/...`.
|
|
4. The server (`src/server/authz/policies/management.ts`) recomputes the
|
|
expected token with the same salt and compares via `timingSafeEqual` to
|
|
prevent timing-based extraction.
|
|
|
|
## Security properties
|
|
|
|
| Property | Detail |
|
|
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
| **Loopback-only** | Accepted only when `Host` is `localhost`, `127.0.0.1`, or `::1`. |
|
|
| **Constant-time compare** | `crypto.timingSafeEqual` prevents timing attacks. |
|
|
| **Non-reversible** | HMAC output cannot recover the machine-id. |
|
|
| **No `always`-protected bypass** | `isAlwaysProtectedPath()` is evaluated before the CLI token check. `/api/shutdown` and `/api/settings/database` always require JWT. |
|
|
| **Non-exportable** | Token is never written to disk or logged. |
|
|
|
|
## Salt rotation
|
|
|
|
Set `OMNIROUTE_CLI_SALT` to rotate the derived token without code changes.
|
|
After rotation, all CLI processes on this machine will use the new token
|
|
automatically. Useful after a process-list leak that may have exposed the
|
|
previous derived value.
|
|
|
|
```bash
|
|
# Persistent rotation (add to shell profile)
|
|
export OMNIROUTE_CLI_SALT="my-secret-salt-2026"
|
|
|
|
# Verify new token is in use
|
|
omniroute status
|
|
```
|
|
|
|
Default salt: `omniroute-cli-auth-v1`
|
|
|
|
## Files
|
|
|
|
| File | Purpose |
|
|
| ----------------------------------------- | ---------------------------------------- |
|
|
| `src/lib/machineToken.ts` | Token derivation (`getMachineTokenSync`) |
|
|
| `src/server/authz/headers.ts` | `CLI_TOKEN_HEADER` constant |
|
|
| `src/server/authz/policies/management.ts` | Server-side verification |
|
|
| `src/server/authz/routeGuard.ts` | Loopback host check (`isLoopbackHost`) |
|
|
|
|
## See also
|
|
|
|
- `docs/security/ROUTE_GUARD_TIERS.md` — route protection tiers
|
|
- `docs/architecture/AUTHZ_GUIDE.md` — full authorization pipeline
|