'use client' import { useState, useEffect } from 'react' import { ShieldCheckIcon, KeyIcon, LockClosedIcon, ServerIcon, EyeIcon, EyeSlashIcon, DocumentDuplicateIcon, CheckCircleIcon, XCircleIcon, ExclamationTriangleIcon } from '@heroicons/react/24/outline' interface SecuritySetupProps { systemInfo: any configData: any onComplete: (data: any) => void onBack?: () => void isCompleted: boolean } interface SecurityConfig { sshKeyType: 'generate' | 'existing' | 'manual' sshPublicKey: string sshPrivateKey: string sshUsername: string sshPassword: string sshPort: number enableTLS: boolean tlsCertType: 'self-signed' | 'letsencrypt' | 'existing' tlsCertPath: string tlsKeyPath: string authMethod: 'token' | 'certificate' | 'hybrid' clusterSecret: string accessPolicy: 'open' | 'restricted' | 'invite-only' enableFirewall: boolean allowedPorts: string[] trustedIPs: string[] } export default function SecuritySetup({ systemInfo, configData, onComplete, onBack, isCompleted }: SecuritySetupProps) { console.log('SecuritySetup: Component rendered with configData:', configData) const [config, setConfig] = useState({ sshKeyType: 'generate', sshPublicKey: '', sshPrivateKey: '', sshUsername: 'ubuntu', sshPassword: '', sshPort: 22, enableTLS: true, tlsCertType: 'self-signed', tlsCertPath: '', tlsKeyPath: '', authMethod: 'token', clusterSecret: '', accessPolicy: 'restricted', enableFirewall: true, allowedPorts: ['22', '8080', '8090', '9100', '3000'], trustedIPs: [], ...configData?.security // Load saved security config if exists }) const [showPrivateKey, setShowPrivateKey] = useState(false) const [showClusterSecret, setShowClusterSecret] = useState(false) const [showSSHPassword, setShowSSHPassword] = useState(false) const [generating, setGenerating] = useState(false) const [validation, setValidation] = useState<{[key: string]: boolean}>({}) const [portsInitialized, setPortsInitialized] = useState(false) // Generate cluster secret on mount if not exists useEffect(() => { if (!config.clusterSecret) { generateClusterSecret() } }, []) // Update firewall ports based on network configuration from previous step useEffect(() => { console.log('SecuritySetup: configData changed', { hasNetwork: !!configData?.network, portsInitialized, hasSavedSecurity: !!configData?.security?.allowedPorts, networkConfig: configData?.network }) // If we have network config and haven't initialized ports yet, AND we don't have saved security config if (configData?.network && !portsInitialized && !configData?.security?.allowedPorts) { const networkConfig = configData.network const networkPorts = [ networkConfig.bzzzPort?.toString(), networkConfig.mcpPort?.toString(), networkConfig.webUIPort?.toString(), networkConfig.p2pPort?.toString() ].filter(port => port && port !== 'undefined') console.log('SecuritySetup: Auto-populating ports', { networkPorts, networkConfig }) // Include standard ports plus network configuration ports const standardPorts = ['22', '8090'] // SSH and setup interface const allPorts = [...new Set([...standardPorts, ...networkPorts])] console.log('SecuritySetup: Setting allowed ports to', allPorts) setConfig(prev => ({ ...prev, allowedPorts: allPorts })) setPortsInitialized(true) } }, [configData, portsInitialized]) const generateClusterSecret = () => { const secret = Array.from(crypto.getRandomValues(new Uint8Array(32))) .map(b => b.toString(16).padStart(2, '0')) .join('') setConfig(prev => ({ ...prev, clusterSecret: secret })) } const generateSSHKeys = async () => { setGenerating(true) try { // In a real implementation, this would call the backend to generate SSH keys // For now, simulate the process await new Promise(resolve => setTimeout(resolve, 2000)) // Mock generated keys (in real implementation, these would come from backend) const mockPublicKey = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC... chorus@${systemInfo?.network?.hostname || 'localhost'}` const mockPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAFwwAAAAd... -----END OPENSSH PRIVATE KEY-----` setConfig(prev => ({ ...prev, sshPublicKey: mockPublicKey, sshPrivateKey: mockPrivateKey })) setValidation(prev => ({ ...prev, sshKeys: true })) } catch (error) { console.error('Failed to generate SSH keys:', error) setValidation(prev => ({ ...prev, sshKeys: false })) } finally { setGenerating(false) } } const copyToClipboard = async (text: string) => { try { await navigator.clipboard.writeText(text) } catch (error) { console.error('Failed to copy to clipboard:', error) } } const handleSubmit = (e: React.FormEvent) => { e.preventDefault() // Validate required fields const newValidation: {[key: string]: boolean} = {} if (config.sshKeyType === 'generate' && !config.sshPublicKey) { newValidation.sshKeys = false } else if (config.sshKeyType === 'existing' && !config.sshPublicKey) { newValidation.sshKeys = false } else { newValidation.sshKeys = true } if (config.enableTLS && config.tlsCertType === 'existing' && (!config.tlsCertPath || !config.tlsKeyPath)) { newValidation.tlsCert = false } else { newValidation.tlsCert = true } if (!config.clusterSecret) { newValidation.clusterSecret = false } else { newValidation.clusterSecret = true } if (config.sshKeyType === 'manual' && (!config.sshUsername || !config.sshPassword)) { newValidation.sshCredentials = false } else { newValidation.sshCredentials = true } setValidation(newValidation) // Check if all validations pass const isValid = Object.values(newValidation).every(v => v) if (isValid) { onComplete({ security: config }) } } return (
{/* SSH Key Configuration */}

SSH Key Management

{validation.sshKeys === true && } {validation.sshKeys === false && }
{config.sshKeyType === 'generate' && (
{!config.sshPublicKey ? ( ) : (