source dump of claude code
at main 84 lines 2.7 kB view raw
1import { useCallback, useState } from 'react' 2import { getIsNonInteractiveSession } from '../bootstrap/state.js' 3import { verifyApiKey } from '../services/api/claude.js' 4import { 5 getAnthropicApiKeyWithSource, 6 getApiKeyFromApiKeyHelper, 7 isAnthropicAuthEnabled, 8 isClaudeAISubscriber, 9} from '../utils/auth.js' 10 11export type VerificationStatus = 12 | 'loading' 13 | 'valid' 14 | 'invalid' 15 | 'missing' 16 | 'error' 17 18export type ApiKeyVerificationResult = { 19 status: VerificationStatus 20 reverify: () => Promise<void> 21 error: Error | null 22} 23 24export function useApiKeyVerification(): ApiKeyVerificationResult { 25 const [status, setStatus] = useState<VerificationStatus>(() => { 26 if (!isAnthropicAuthEnabled() || isClaudeAISubscriber()) { 27 return 'valid' 28 } 29 // Use skipRetrievingKeyFromApiKeyHelper to avoid executing apiKeyHelper 30 // before trust dialog is shown (security: prevents RCE via settings.json) 31 const { key, source } = getAnthropicApiKeyWithSource({ 32 skipRetrievingKeyFromApiKeyHelper: true, 33 }) 34 // If apiKeyHelper is configured, we have a key source even though we 35 // haven't executed it yet - return 'loading' to indicate we'll verify later 36 if (key || source === 'apiKeyHelper') { 37 return 'loading' 38 } 39 return 'missing' 40 }) 41 const [error, setError] = useState<Error | null>(null) 42 43 const verify = useCallback(async (): Promise<void> => { 44 if (!isAnthropicAuthEnabled() || isClaudeAISubscriber()) { 45 setStatus('valid') 46 return 47 } 48 // Warm the apiKeyHelper cache (no-op if not configured), then read from 49 // all sources. getAnthropicApiKeyWithSource() reads the now-warm cache. 50 await getApiKeyFromApiKeyHelper(getIsNonInteractiveSession()) 51 const { key: apiKey, source } = getAnthropicApiKeyWithSource() 52 if (!apiKey) { 53 if (source === 'apiKeyHelper') { 54 setStatus('error') 55 setError(new Error('API key helper did not return a valid key')) 56 return 57 } 58 const newStatus = 'missing' 59 setStatus(newStatus) 60 return 61 } 62 63 try { 64 const isValid = await verifyApiKey(apiKey, false) 65 const newStatus = isValid ? 'valid' : 'invalid' 66 setStatus(newStatus) 67 return 68 } catch (error) { 69 // This happens when there an error response from the API but it's not an invalid API key error 70 // In this case, we still mark the API key as invalid - but we also log the error so we can 71 // display it to the user to be more helpful 72 setError(error as Error) 73 const newStatus = 'error' 74 setStatus(newStatus) 75 return 76 } 77 }, []) 78 79 return { 80 status, 81 reverify: verify, 82 error, 83 } 84}