mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-31 06:42:03 +00:00
- Added rate limiting to the authentication middleware to prevent brute-force attacks. - Introduced a secure comparison function to mitigate timing attacks during API key validation. - Created a new rate limiter class to track failed authentication attempts and block requests after exceeding the maximum allowed failures. - Updated the authentication middleware to handle rate limiting and secure key comparison. - Enhanced error handling for rate-limited requests, providing appropriate responses to clients.
174 lines
5.0 KiB
TypeScript
174 lines
5.0 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { useAppStore } from '@/store/app-store';
|
|
import { getElectronAPI } from '@/lib/electron';
|
|
import type { ProviderConfigParams } from '@/config/api-providers';
|
|
|
|
interface TestResult {
|
|
success: boolean;
|
|
message: string;
|
|
}
|
|
|
|
interface ApiKeyStatus {
|
|
hasAnthropicKey: boolean;
|
|
hasGoogleKey: boolean;
|
|
}
|
|
|
|
/**
|
|
* Custom hook for managing API key state and operations
|
|
* Handles input values, visibility toggles, connection testing, and saving
|
|
*/
|
|
export function useApiKeyManagement() {
|
|
const { apiKeys, setApiKeys } = useAppStore();
|
|
|
|
// API key values
|
|
const [anthropicKey, setAnthropicKey] = useState(apiKeys.anthropic);
|
|
const [googleKey, setGoogleKey] = useState(apiKeys.google);
|
|
|
|
// Visibility toggles
|
|
const [showAnthropicKey, setShowAnthropicKey] = useState(false);
|
|
const [showGoogleKey, setShowGoogleKey] = useState(false);
|
|
|
|
// Test connection states
|
|
const [testingConnection, setTestingConnection] = useState(false);
|
|
const [testResult, setTestResult] = useState<TestResult | null>(null);
|
|
const [testingGeminiConnection, setTestingGeminiConnection] = useState(false);
|
|
const [geminiTestResult, setGeminiTestResult] = useState<TestResult | null>(null);
|
|
|
|
// API key status from environment
|
|
const [apiKeyStatus, setApiKeyStatus] = useState<ApiKeyStatus | null>(null);
|
|
|
|
// Save state
|
|
const [saved, setSaved] = useState(false);
|
|
|
|
// Sync local state with store
|
|
useEffect(() => {
|
|
setAnthropicKey(apiKeys.anthropic);
|
|
setGoogleKey(apiKeys.google);
|
|
}, [apiKeys]);
|
|
|
|
// Check API key status from environment on mount
|
|
useEffect(() => {
|
|
const checkApiKeyStatus = async () => {
|
|
const api = getElectronAPI();
|
|
if (api?.setup?.getApiKeys) {
|
|
try {
|
|
const status = await api.setup.getApiKeys();
|
|
if (status.success) {
|
|
setApiKeyStatus({
|
|
hasAnthropicKey: status.hasAnthropicKey,
|
|
hasGoogleKey: status.hasGoogleKey,
|
|
});
|
|
}
|
|
} catch {
|
|
// Silently handle API key status check failures to avoid exposing
|
|
// sensitive error details in the console
|
|
}
|
|
}
|
|
};
|
|
checkApiKeyStatus();
|
|
}, []);
|
|
|
|
// Test Anthropic/Claude connection
|
|
const handleTestAnthropicConnection = async () => {
|
|
setTestingConnection(true);
|
|
setTestResult(null);
|
|
|
|
try {
|
|
const api = getElectronAPI();
|
|
const data = await api.setup.verifyClaudeAuth('api_key');
|
|
|
|
if (data.success && data.authenticated) {
|
|
setTestResult({
|
|
success: true,
|
|
message: 'Connection successful! Claude responded.',
|
|
});
|
|
} else {
|
|
setTestResult({
|
|
success: false,
|
|
message: data.error || 'Failed to connect to Claude API.',
|
|
});
|
|
}
|
|
} catch {
|
|
setTestResult({
|
|
success: false,
|
|
message: 'Network error. Please check your connection.',
|
|
});
|
|
} finally {
|
|
setTestingConnection(false);
|
|
}
|
|
};
|
|
|
|
// Test Google/Gemini connection
|
|
// NOTE: Full API key validation requires a backend call to verify the key
|
|
// against Google's API. The current client-side validation only checks
|
|
// basic format requirements and cannot confirm the key is actually valid.
|
|
const handleTestGeminiConnection = async () => {
|
|
setTestingGeminiConnection(true);
|
|
setGeminiTestResult(null);
|
|
|
|
// Basic client-side format validation only
|
|
// This does NOT verify the key is valid with Google's API
|
|
if (!googleKey || googleKey.trim().length < 10) {
|
|
setGeminiTestResult({
|
|
success: false,
|
|
message: 'Please enter an API key with at least 10 characters.',
|
|
});
|
|
setTestingGeminiConnection(false);
|
|
return;
|
|
}
|
|
|
|
// Client-side validation cannot confirm key validity.
|
|
// The key will be verified when first used with the Gemini API.
|
|
setGeminiTestResult({
|
|
success: true,
|
|
message: 'API key format accepted. Key will be validated on first use with Gemini API.',
|
|
});
|
|
setTestingGeminiConnection(false);
|
|
};
|
|
|
|
// Save API keys
|
|
const handleSave = () => {
|
|
setApiKeys({
|
|
anthropic: anthropicKey,
|
|
google: googleKey,
|
|
});
|
|
setSaved(true);
|
|
setTimeout(() => setSaved(false), 2000);
|
|
};
|
|
|
|
// Build provider config params for buildProviderConfigs
|
|
const providerConfigParams: ProviderConfigParams = {
|
|
apiKeys,
|
|
anthropic: {
|
|
value: anthropicKey,
|
|
setValue: setAnthropicKey,
|
|
show: showAnthropicKey,
|
|
setShow: setShowAnthropicKey,
|
|
testing: testingConnection,
|
|
onTest: handleTestAnthropicConnection,
|
|
result: testResult,
|
|
},
|
|
google: {
|
|
value: googleKey,
|
|
setValue: setGoogleKey,
|
|
show: showGoogleKey,
|
|
setShow: setShowGoogleKey,
|
|
testing: testingGeminiConnection,
|
|
onTest: handleTestGeminiConnection,
|
|
result: geminiTestResult,
|
|
},
|
|
};
|
|
|
|
return {
|
|
// Provider config params for buildProviderConfigs
|
|
providerConfigParams,
|
|
|
|
// API key status from environment
|
|
apiKeyStatus,
|
|
|
|
// Save handler and state
|
|
handleSave,
|
|
saved,
|
|
};
|
|
}
|