Files
OmniRoute/src/shared/utils/apiKey.ts
diegosouzapw 71d14209a4 feat: OmniRoute v1.0.0 — Intelligent AI Gateway & Universal LLM Proxy
OmniRoute is an intelligent API gateway that unifies 20+ AI providers behind a single
OpenAI-compatible endpoint. Features include intelligent routing with 6 strategies,
multi-format translation (OpenAI/Claude/Gemini/Responses API), circuit breakers,
semantic caching, combo fallback chains, real-time health monitoring, and a full
dashboard with provider management, analytics, and CLI tool integration.

Key highlights:
- 20+ providers (Claude Code, Codex, Gemini CLI, GitHub Copilot, iFlow, Qwen, Kiro, etc.)
- 6 routing strategies (Fill First, Round Robin, P2C, Random, Least Used, Cost Optimized)
- Export/Import database backup with full archive support
- Translator Playground with 4 modes (Playground, Chat Tester, Test Bench, Live Monitor)
- 100% TypeScript across src/ and open-sse/
- Docker support with multi-stage builds
- Comprehensive documentation and 9 dashboard screenshots
2026-02-18 00:02:15 -03:00

102 lines
2.6 KiB
TypeScript

import crypto from "crypto";
// FASE-01: No hardcoded fallback — enforced by secretsValidator at startup
if (!process.env.API_KEY_SECRET) {
console.error("[SECURITY] API_KEY_SECRET is not set. API key CRC will be insecure.");
}
const API_KEY_SECRET = process.env.API_KEY_SECRET;
/**
* Generate 6-char random keyId
*/
function generateKeyId() {
const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
for (let i = 0; i < 6; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
/**
* Generate CRC (8-char HMAC)
*/
function generateCrc(machineId, keyId) {
return crypto
.createHmac("sha256", API_KEY_SECRET)
.update(machineId + keyId)
.digest("hex")
.slice(0, 8);
}
/**
* Generate API key with machineId embedded
* Format: sk-{machineId}-{keyId}-{crc8}
* @param {string} machineId - 16-char machine ID
* @returns {{ key: string, keyId: string }}
*/
export function generateApiKeyWithMachine(machineId) {
const keyId = generateKeyId();
const crc = generateCrc(machineId, keyId);
const key = `sk-${machineId}-${keyId}-${crc}`;
return { key, keyId };
}
/**
* Parse API key and extract machineId + keyId
* Supports both formats:
* - New: sk-{machineId}-{keyId}-{crc8}
* - Old: sk-{random8}
* @param {string} apiKey
* @returns {{ machineId: string, keyId: string, isNewFormat: boolean } | null}
*/
export function parseApiKey(apiKey) {
if (!apiKey || !apiKey.startsWith("sk-")) return null;
const parts = apiKey.split("-");
// New format: sk-{machineId}-{keyId}-{crc8} = 4 parts
if (parts.length === 4) {
const [, machineId, keyId, crc] = parts;
// Validate CRC
const expectedCrc = generateCrc(machineId, keyId);
if (crc !== expectedCrc) return null;
return { machineId, keyId, isNewFormat: true };
}
// Old format: sk-{random8} = 2 parts
if (parts.length === 2) {
return { machineId: null, keyId: parts[1], isNewFormat: false };
}
return null;
}
/**
* Verify API key CRC (only for new format)
* @param {string} apiKey
* @returns {boolean}
*/
export function verifyApiKeyCrc(apiKey) {
const parsed = parseApiKey(apiKey);
if (!parsed) return false;
// Old format doesn't have CRC, always valid if parsed
if (!parsed.isNewFormat) return true;
// New format already verified in parseApiKey
return true;
}
/**
* Check if API key is new format (contains machineId)
* @param {string} apiKey
* @returns {boolean}
*/
export function isNewFormatKey(apiKey) {
const parsed = parseApiKey(apiKey);
return parsed?.isNewFormat === true;
}