import { useCallback, useEffect, useState } from 'react' import { Alert, Box, Button, Chip, CircularProgress, Container, Dialog, DialogActions, DialogContent, DialogTitle, FormControl, IconButton, InputLabel, MenuItem, Paper, Select, type SelectChangeEvent, Snackbar, Table, TableBody, TableCell, TableHead, TableRow, TextField, Toolbar, Tooltip, Typography, } from '@mui/material' import { ContentCopy as CopyIcon, Download as DownloadIcon, Refresh as RefreshIcon, Security as SecurityIcon, } from '@mui/icons-material' import { certsApi } from '../api/client' import { useAuthStore } from '../store/authStore' import type { Certificate, CertStatus, IssuedCert } from '../types' // ── Helpers ─────────────────────────────────────────────────────────────────── function downloadBlob(blob: Blob, filename: string): void { const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = filename a.click() URL.revokeObjectURL(url) } function fmtDate(iso: string): string { return new Date(iso).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric', }) } function isExpiringSoon(iso: string): boolean { return new Date(iso).getTime() - Date.now() < 30 * 24 * 60 * 60 * 1000 } function statusChip(status: CertStatus) { const map: Record = { active: { label: 'Active', color: 'success' }, revoked: { label: 'Revoked', color: 'error' }, expired: { label: 'Expired', color: 'warning' }, } const { label, color } = map[status] return } // ── Issue Dialog ────────────────────────────────────────────────────────────── interface IssueDialogProps { open: boolean onClose: () => void onIssued: (cert: IssuedCert) => void } function IssueDialog({ open, onClose, onIssued }: IssueDialogProps) { const [hostId, setHostId] = useState('') const [hostname, setHostname] = useState('') const [saving, setSaving] = useState(false) const [err, setErr] = useState(null) useEffect(() => { if (open) { setHostId(''); setHostname(''); setErr(null) } }, [open]) const handleSubmit = async () => { if (!hostId.trim()) { setErr('Host ID is required'); return } if (!hostname.trim()) { setErr('Hostname is required'); return } setSaving(true); setErr(null) try { const res = await certsApi.issue(hostId.trim(), hostname.trim()) onIssued(res.data) onClose() } catch (e: unknown) { const msg = (e as { response?: { data?: { error?: { message?: string } } } }) ?.response?.data?.error?.message ?? 'Failed to issue certificate' setErr(msg) } finally { setSaving(false) } } return ( Issue Client Certificate {err && {err}} setHostId(e.target.value)} required fullWidth placeholder="e.g. 3fa85f64-5717-4562-b3fc-2c963f66afa6" /> setHostname(e.target.value)} required fullWidth placeholder="e.g. web-01.example.com" /> ) } // ── One-Time Key Display Dialog ─────────────────────────────────────────────── interface KeyDisplayDialogProps { open: boolean cert: IssuedCert | null onClose: () => void } function KeyDisplayDialog({ open, cert, onClose }: KeyDisplayDialogProps) { const [copied, setCopied] = useState(false) const handleCopy = async () => { if (!cert?.key_pem) return await navigator.clipboard.writeText(cert.key_pem) setCopied(true) setTimeout(() => setCopied(false), 2000) } return ( Certificate Issued — Save Your Private Key This private key will NOT be shown again. Copy and store it securely before closing this dialog. {cert && ( Serial: {cert.serial_number}  |  Expires: {fmtDate(cert.expires_at)} {cert.key_pem} )} ) } // ── Main Page ───────────────────────────────────────────────────────────────── export default function CertificatesPage() { const user = useAuthStore((s) => s.user) const isAdmin = user?.role === 'admin' const [certs, setCerts] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) // Filters const [statusFilter, setStatusFilter] = useState('all') const [hostFilter, setHostFilter] = useState('') // Dialogs const [issueOpen, setIssueOpen] = useState(false) const [issuedCert, setIssuedCert] = useState(null) const [keyDialogOpen, setKeyDialogOpen] = useState(false) // Snackbar const [snackbar, setSnackbar] = useState<{ open: boolean; message: string; severity: 'success' | 'error' }>({ open: false, message: '', severity: 'success', }) const showSnack = (message: string, severity: 'success' | 'error') => setSnackbar({ open: true, message, severity }) // ── Load certs ────────────────────────────────────────────────────────────── const load = useCallback(async () => { setLoading(true) setError(null) try { const params: { status?: string; host_id?: string } = {} if (statusFilter !== 'all') params.status = statusFilter if (hostFilter.trim()) params.host_id = hostFilter.trim() const res = await certsApi.list(params) setCerts(res.data) } catch { setError('Failed to load certificates') } finally { setLoading(false) } }, [statusFilter, hostFilter]) useEffect(() => { load() }, [load]) // ── Download Root CA ──────────────────────────────────────────────────────── const handleDownloadRootCa = async () => { try { const res = await certsApi.downloadRootCa() downloadBlob(res.data as Blob, 'ca.crt') } catch { showSnack('Failed to download Root CA certificate', 'error') } } // ── Issue cert ────────────────────────────────────────────────────────────── const handleIssued = (cert: IssuedCert) => { setIssuedCert(cert) setKeyDialogOpen(true) void load() } // ── Renew cert ────────────────────────────────────────────────────────────── const handleRenew = async (certId: string) => { try { const res = await certsApi.renew(certId) setIssuedCert(res.data) setKeyDialogOpen(true) void load() } catch { showSnack('Failed to renew certificate', 'error') } } // ── Revoke cert ───────────────────────────────────────────────────────────── const handleRevoke = async (certId: string) => { if (!window.confirm('Revoke this certificate? This cannot be undone.')) return try { await certsApi.revoke(certId) showSnack('Certificate revoked', 'success') void load() } catch { showSnack('Failed to revoke certificate', 'error') } } // ── Render ────────────────────────────────────────────────────────────────── return ( {/* Header */} Certificate Management {isAdmin && ( )} {loading ? : } {/* Error */} {error && ( {error} )} {/* Filters */} Status setHostFilter(e.target.value)} placeholder="UUID or partial…" sx={{ minWidth: 260 }} /> {/* Table */} {loading ? ( ) : certs.length === 0 ? ( No certificates found. ) : ( Common Name Serial Number Status Issued At Expires At Host Actions {certs.map((cert) => { const expiring = cert.status === 'active' && isExpiringSoon(cert.expires_at) return ( {cert.common_name} {cert.serial_number} {statusChip(cert.status)} {fmtDate(cert.issued_at)} {fmtDate(cert.expires_at)} {expiring && ' ⚠️'} {cert.host_id ?? Root CA} {isAdmin && ( <> {cert.status === 'active' && ( )} )} ) })}
)}
{/* Issue Dialog */} setIssueOpen(false)} onIssued={handleIssued} /> {/* One-time key display dialog */} setKeyDialogOpen(false)} /> {/* Snackbar */} setSnackbar((p) => ({ ...p, open: false }))} anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }} > setSnackbar((p) => ({ ...p, open: false }))} > {snackbar.message}
) }