UNPKG

@clduab11/gemini-flow

Version:

Revolutionary AI agent swarm coordination platform with Google Services integration, multimedia processing, and production-ready monitoring. Features 8 Google AI services, quantum computing capabilities, and enterprise-grade security.

320 lines (267 loc) 7.82 kB
/** * Google AI Authentication * * Simple authentication system for Google AI Studio API key * providing Gemini CLI parity with multiple key detection methods */ import * as fs from "fs"; import * as path from "path"; import * as os from "os"; import { Logger } from "../utils/logger.js"; export interface GoogleAIAuthOptions { apiKey?: string; configPath?: string; } export interface AuthStatus { isAuthenticated: boolean; source: "environment" | "config" | "constructor" | "none"; keyFormat: "valid" | "invalid" | "none"; keyPrefix: string | null; } export interface AuthConfig { apiKey?: string; model?: string; temperature?: number; maxTokens?: number; [key: string]: any; } export class GoogleAIAuth { private apiKey: string | null = null; private configPath: string; private logger: Logger; constructor(options: GoogleAIAuthOptions = {}) { this.logger = new Logger("GoogleAIAuth"); // Set config path this.configPath = options.configPath || this.getDefaultConfigPath(); // Initialize API key from various sources (priority order) this.initializeApiKey(options.apiKey); this.logger.debug("GoogleAI authentication initialized", { hasApiKey: !!this.apiKey, configPath: this.configPath, source: this.getAuthStatus().source, }); } /** * Initialize API key from multiple sources with priority order: * 1. Constructor option * 2. Environment variables (GEMINI_API_KEY, GOOGLE_AI_API_KEY, GOOGLE_API_KEY) * 3. Config file */ private initializeApiKey(constructorKey?: string): void { // Priority 1: Constructor option if (constructorKey) { this.apiKey = constructorKey; this.logger.debug("API key loaded from constructor"); return; } // Priority 2: Environment variables const envKey = this.getApiKeyFromEnvironment(); if (envKey) { this.apiKey = envKey; this.logger.debug("API key loaded from environment"); return; } // Priority 3: Config file const configLoaded = this.loadConfig(this.configPath); if (configLoaded) { this.logger.debug("API key loaded from config file"); return; } this.logger.debug("No API key found in any source"); } /** * Get API key from environment variables */ private getApiKeyFromEnvironment(): string | null { // Check multiple environment variable names const envVars = ["GEMINI_API_KEY", "GOOGLE_AI_API_KEY", "GOOGLE_API_KEY"]; for (const envVar of envVars) { const key = process.env[envVar]; if (key && key.trim()) { return key.trim(); } } return null; } /** * Get default config file path */ private getDefaultConfigPath(): string { const homeDir = os.homedir(); return path.join(homeDir, ".gemini-flow", "config.json"); } /** * Check if user is authenticated */ isAuthenticated(): boolean { return !!this.apiKey; } /** * Validate API key format */ isValidApiKey(): boolean { if (!this.apiKey) { return false; } // Google AI API keys typically start with 'AIza' return this.apiKey.startsWith("AIza") && this.apiKey.length >= 35; } /** * Get current API key */ getApiKey(): string | null { return this.apiKey; } /** * Set API key */ setApiKey(apiKey: string | null): boolean { if (!apiKey) { this.apiKey = null; this.logger.debug("API key cleared"); return true; } // Validate format if (!apiKey.startsWith("AIza") || apiKey.length < 35) { this.logger.warn("Invalid API key format provided"); return false; } this.apiKey = apiKey; this.logger.debug("API key set successfully"); return true; } /** * Load configuration from file */ loadConfig(configPath: string): boolean { try { if (!fs.existsSync(configPath)) { return false; } const configContent = fs.readFileSync(configPath, "utf8"); const config: AuthConfig = JSON.parse(configContent); if (config.apiKey) { this.apiKey = config.apiKey; return true; } return false; } catch (error) { this.logger.error("Failed to load config", { configPath, error }); return false; } } /** * Save configuration to file */ async saveConfig(configPath?: string): Promise<void> { const targetPath = configPath || this.configPath; try { // Ensure directory exists const configDir = path.dirname(targetPath); if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); } // Prepare config object const config: AuthConfig = { apiKey: this.apiKey || undefined, model: "gemini-1.5-flash", temperature: 0.7, maxTokens: 1000000, }; // Write config file fs.writeFileSync(targetPath, JSON.stringify(config, null, 2)); this.logger.info("Configuration saved", { configPath: targetPath }); } catch (error) { this.logger.error("Failed to save config", { configPath: targetPath, error, }); throw error; } } /** * Clear authentication */ clearAuth(): void { this.apiKey = null; this.logger.debug("Authentication cleared"); } /** * Get detailed authentication status */ getAuthStatus(): AuthStatus { if (!this.apiKey) { return { isAuthenticated: false, source: "none", keyFormat: "none", keyPrefix: null, }; } // Determine source let source: AuthStatus["source"] = "config"; if (this.getApiKeyFromEnvironment() === this.apiKey) { source = "environment"; } return { isAuthenticated: true, source, keyFormat: this.isValidApiKey() ? "valid" : "invalid", keyPrefix: this.apiKey ? `${this.apiKey.substring(0, 6)}...` : null, }; } /** * Test API key by making a simple API call */ async testApiKey(): Promise<boolean> { if (!this.isAuthenticated() || !this.isValidApiKey()) { return false; } try { const { GoogleGenerativeAI } = await import("@google/generative-ai"); const genAI = new GoogleGenerativeAI(this.apiKey!); const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" }); // Make a simple test request const result = await model.generateContent("Hello"); const response = await result.response; // If we get here without error, the API key works this.logger.debug("API key test successful"); return true; } catch (error) { this.logger.warn("API key test failed", error); if (error instanceof Error) { if (error.message.includes("API_KEY_INVALID")) { this.logger.error("Invalid API key"); } else if (error.message.includes("QUOTA_EXCEEDED")) { this.logger.warn("API quota exceeded, but key is valid"); return true; // Key is valid, just quota exceeded } } return false; } } /** * Get authentication help message */ getAuthHelpMessage(): string { return ` Google AI API Key Authentication Help: 1. Get an API key from Google AI Studio: https://aistudio.google.com/app/apikey 2. Set your API key using one of these methods: Environment Variable (recommended): export GEMINI_API_KEY="your-api-key-here" Alternative environment variables: export GOOGLE_AI_API_KEY="your-api-key-here" export GOOGLE_API_KEY="your-api-key-here" Configuration file: Save to ~/.gemini-flow/config.json: { "apiKey": "your-api-key-here" } 3. Verify your setup: gemini-flow doctor API keys should start with 'AIza' and be at least 35 characters long. `.trim(); } }