import * as crypto from 'crypto'; import * as fs from 'fs'; import * as http from 'http'; import * as https from 'https'; import * as path from 'path'; import * as readline from 'readline'; import { AGENTGUARD_SPEND_VERSION } from '../index'; import { licenseKeyFingerprint, readConfiguredLicenseKey, writeConfiguredLicenseKey } from '../license'; import { agentguardHome, banner, dim, green, statusBar, yellow } from './colors'; const OPENROUTER_AUTH_URL = 'https://openrouter.ai/api/v1/auth/key'; export function openRouterKeyPath(): string { return path.join(agentguardHome(), 'openrouter-key'); } export function keyFingerprint(key: string): string { return crypto.createHash('sha256').update(key).digest('hex').slice(0, 16); } export async function validateOpenRouterKey(key: string, endpoint = process.env.AGENTGUARD_OPENROUTER_AUTH_URL || OPENROUTER_AUTH_URL): Promise { if (!key.trim()) return false; if (endpoint.startsWith('mock://')) { const expected = new URL(endpoint).searchParams.get('key'); return expected === key.trim(); } try { const status = await requestStatus(endpoint, key.trim()); return status >= 200 && status < 300; } catch { return false; } } export function readOpenRouterKey(): string | null { if (process.env.OPENROUTER_API_KEY) return process.env.OPENROUTER_API_KEY; try { const value = fs.readFileSync(openRouterKeyPath(), 'utf8').trim(); return value.length > 0 ? value : null; } catch { return null; } } export function writeOpenRouterKey(key: string): void { const filePath = openRouterKeyPath(); fs.mkdirSync(path.dirname(filePath), { recursive: true }); fs.writeFileSync(filePath, key.trim() + '\n', { mode: 0o600 }); try { fs.chmodSync(filePath, 0o600); } catch { return; } } export async function runAuth(argv: string[]): Promise { if (argv.includes('--help') || argv.includes('-h')) { console.log('agentguard auth openrouter | license-key | status | clear openrouter'); return 0; } const sub = argv[0] ?? 'status'; if (sub === 'status') return authStatus(); if (sub === 'license-key') return configureLicenseKey(argv[1]); if (sub === 'clear' && argv[1] === 'openrouter') return clearOpenRouter(); if (sub === 'openrouter') return configureOpenRouter(argv); console.error(`agentguard auth: unknown command '${argv.join(' ')}'`); return 2; } async function configureOpenRouter(argv: string[]): Promise { const flagKey = valueAfter(argv, '--key'); const key = flagKey ?? await promptForKey(); if (!key) { console.error('No key provided.'); return 2; } const ok = await validateOpenRouterKey(key); if (!ok) { console.error('OpenRouter key validation failed.'); return 1; } writeOpenRouterKey(key); console.log(''); console.log(' ' + banner(AGENTGUARD_SPEND_VERSION)); console.log(''); console.log(` ${green('configured')} openrouter fingerprint ${keyFingerprint(key)}`); console.log(` ${dim('saved')} ${openRouterKeyPath()}`); console.log(''); return 0; } function authStatus(): number { const key = readOpenRouterKey(); console.log(''); console.log(' ' + banner(AGENTGUARD_SPEND_VERSION)); console.log(''); if (key) { console.log(` ${green('openrouter')} configured fingerprint ${keyFingerprint(key)}`); } else { console.log(` ${yellow('openrouter')} not configured`); } const licenseKey = readConfiguredLicenseKey(); if (licenseKey) { console.log(` ${green('license')} configured fingerprint ${licenseKeyFingerprint(licenseKey)}`); } else { console.log(` ${yellow('license')} free tier`); } console.log(''); console.log(' ' + statusBar()); console.log(''); return 0; } function configureLicenseKey(key?: string): number { if (!key?.trim()) { console.error('Usage: agentguard auth license-key '); return 2; } writeConfiguredLicenseKey(key); console.log(`License key saved. fingerprint ${licenseKeyFingerprint(key)}`); return 0; } function clearOpenRouter(): number { try { fs.unlinkSync(openRouterKeyPath()); } catch { return 0; } console.log('OpenRouter key removed.'); return 0; } async function promptForKey(): Promise { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); return new Promise((resolve) => { rl.question('OpenRouter API key: ', (answer) => { rl.close(); resolve(answer.trim()); }); }); } function requestStatus(endpoint: string, key: string): Promise { return new Promise((resolve, reject) => { const url = new URL(endpoint); const client = url.protocol === 'http:' ? http : https; const req = client.request( { method: 'GET', hostname: url.hostname, port: url.port, path: url.pathname + url.search, headers: { authorization: `Bearer ${key}`, accept: 'application/json' }, timeout: 5000, }, (res) => { res.resume(); res.on('end', () => resolve(res.statusCode ?? 0)); }, ); req.on('error', reject); req.on('timeout', () => req.destroy(new Error('OpenRouter auth validation timed out'))); req.end(); }); } function valueAfter(argv: string[], flag: string): string | undefined { const index = argv.indexOf(flag); return index >= 0 ? argv[index + 1] : undefined; }