Spaces:
Sleeping
Sleeping
| import crypto from "crypto"; | |
| const API_KEY_SECRET = process.env.API_KEY_SECRET || "endpoint-proxy-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; | |
| } | |