import { useCallback, useEffect, useState, type ReactNode } from 'react' import { Loader2, ShieldAlert, ShieldCheck, ShieldMinus } from 'lucide-react' import { CryptoService, diagnoseWebCryptoEnvironment } from '../../lib/crypto' import { t, type Language } from '../../i18n/translations' export type WebCryptoCheckStatus = | 'idle' | 'checking' | 'secure' | 'insecure' | 'unsupported' | 'disabled' // Transport encryption disabled interface WebCryptoEnvironmentCheckProps { language: Language variant?: 'card' | 'compact' onStatusChange?: (status: WebCryptoCheckStatus) => void } export function WebCryptoEnvironmentCheck({ language, variant = 'card', onStatusChange, }: WebCryptoEnvironmentCheckProps) { const [status, setStatus] = useState('idle') const [summary, setSummary] = useState(null) useEffect(() => { onStatusChange?.(status) }, [onStatusChange, status]) const runCheck = useCallback(async () => { setStatus('checking') setSummary(null) try { // First check if transport encryption is enabled on the server const config = await CryptoService.fetchCryptoConfig() if (!config.transport_encryption) { setStatus('disabled') return } const result = diagnoseWebCryptoEnvironment() setSummary( t('environmentCheck.summary', language, { origin: result.origin || 'N/A', protocol: result.protocol || 'unknown', }) ) if (!result.isBrowser || !result.hasSubtleCrypto) { setStatus('unsupported') return } if (!result.isSecureContext) { setStatus('insecure') return } setStatus('secure') } catch { // If we can't fetch config, assume encryption is disabled setStatus('disabled') } }, [language]) useEffect(() => { runCheck() }, [runCheck]) const isCompact = variant === 'compact' const containerClass = isCompact ? 'p-3 rounded border border-[rgba(26,24,19,0.14)] bg-nofx-bg-lighter space-y-3' : 'p-4 rounded border border-[rgba(26,24,19,0.14)] bg-nofx-bg-lighter space-y-4' const descriptionColor = isCompact ? '#8A8478' : '#8A8478' const showInfo = status !== 'idle' const statusRendererMap: Record ReactNode> = { secure: () => (
{t('environmentCheck.secureTitle', language)}
{t('environmentCheck.secureDesc', language)}
), insecure: () => (
{t('environmentCheck.insecureTitle', language)}
{t('environmentCheck.insecureDesc', language)}
{t('environmentCheck.tipsTitle', language)}
  • {t('environmentCheck.tipHTTPS', language)}
  • {t('environmentCheck.tipLocalhost', language)}
  • {t('environmentCheck.tipIframe', language)}
), unsupported: () => (
{t('environmentCheck.unsupportedTitle', language)}
{t('environmentCheck.unsupportedDesc', language)}
), disabled: () => (
{t('environmentCheck.disabledTitle', language)}
{t('environmentCheck.disabledDesc', language)}
), checking: () => (
{t('environmentCheck.checking', language)}
), idle: () => null, } const renderStatus = () => statusRendererMap[status]() return (
{showInfo && (
{summary ?? t('environmentCheck.description', language)}
)}
{showInfo &&
{renderStatus()}
}
) }