fix(ui): сохранять контекст экспорта сертификатов IPsec

This commit is contained in:
Denozordec committed 2026-09-29 19:23:34 +07:00
1 parent 86ecf764ff
commit 74e7cd257d
7 files changed
+151 -67

No files matched your search

+41 -41
View File
@@ -173,6 +173,10 @@ export default function IpsecPage() {
const [loading, setLoading] = useState(false)
const [busy, setBusy] = useState(false)
const [certBusy, setCertBusy] = useState(false)
const [certError, setCertError] = useState<string | null>(null)
const certEpoch = useRef(0)
const certPending = useRef(false)
useEffect(() => () => { certEpoch.current += 1 }, [])
const [selectedServerId, setSelectedServerId] = useState(ALL_SERVERS_ID)
const [workspaceTab, setWorkspaceTab] = useState<IpsecWorkspaceTab>("clients")
@@ -393,6 +397,10 @@ export default function IpsecPage() {
setEditing(null)
await loadLive()
if (res.bundle) {
certEpoch.current += 1
certPending.current = false
setCertBusy(false)
setCertError(null)
setCertBundle(res.bundle)
setCertClient(res.client ?? null)
setCertByName(null)
@@ -421,63 +429,51 @@ export default function IpsecPage() {
}
}
const loadCert = async (request: () => Promise<IpsecCertBundle>) => {
if (certPending.current) return
certPending.current = true
const epoch = ++certEpoch.current
setCertBusy(true)
setCertError(null)
try {
const bundle = await request()
if (epoch === certEpoch.current) setCertBundle(bundle)
} catch (error) {
if (epoch === certEpoch.current) setCertError(error instanceof Error ? error.message : "Ошибка экспорта сертификата")
} finally {
if (epoch === certEpoch.current) { certPending.current = false; setCertBusy(false) }
}
}
const openCert = async (client: IpsecClientDto) => {
const byName = client.kind === "cert" && Boolean(client.certName)
certEpoch.current += 1
certPending.current = false
setCertClient(byName ? null : client)
setCertByName(byName ? { serverId: client.serverId, name: client.certName! } : null)
setCertBundle(null)
setCertOpen(true)
setCertBusy(true)
try {
const passphrase = `mm-${Math.random().toString(36).slice(2, 10)}`
const bundle = byName
? await exportIpsecCertByName(backendUrl, client.serverId, client.certName!, passphrase)
: await exportIpsecUserCert(backendUrl, client.serverId, client.rosId, passphrase)
setCertBundle(bundle)
} catch (e) {
toast.error("Ошибка экспорта сертификата", {
description: e instanceof Error ? e.message : String(e),
})
setCertOpen(false)
} finally {
setCertBusy(false)
}
const passphrase = crypto.randomUUID()
await loadCert(() => byName
? exportIpsecCertByName(backendUrl, client.serverId, client.certName!, passphrase)
: exportIpsecUserCert(backendUrl, client.serverId, client.rosId, passphrase))
}
/** Экспорт .p12 существующего клиентского серта по имени (client1/anakondra и т.п.). */
const openCertByName = async (serverId: string, cert: IpsecCertInfoDto) => {
certEpoch.current += 1
certPending.current = false
setCertByName({ serverId, name: cert.name })
setCertClient(null)
setCertBundle(null)
setCertOpen(true)
setCertBusy(true)
try {
const passphrase = `mm-${Math.random().toString(36).slice(2, 10)}`
const bundle = await exportIpsecCertByName(backendUrl, serverId, cert.name, passphrase)
setCertBundle(bundle)
} catch (e) {
toast.error("Ошибка экспорта сертификата", {
description: e instanceof Error ? e.message : String(e),
})
setCertOpen(false)
} finally {
setCertBusy(false)
}
await loadCert(() => exportIpsecCertByName(backendUrl, serverId, cert.name, crypto.randomUUID()))
}
const reexportCert = async (passphrase: string) => {
if (!certClient && !certByName) return
setCertBusy(true)
try {
const bundle = certByName
? await exportIpsecCertByName(backendUrl, certByName.serverId, certByName.name, passphrase)
: await exportIpsecUserCert(backendUrl, certClient!.serverId, certClient!.rosId, passphrase)
setCertBundle(bundle)
} catch (e) {
toast.error("Ошибка экспорта", { description: e instanceof Error ? e.message : String(e) })
} finally {
setCertBusy(false)
}
await loadCert(() => certByName
? exportIpsecCertByName(backendUrl, certByName.serverId, certByName.name, passphrase)
: exportIpsecUserCert(backendUrl, certClient!.serverId, certClient!.rosId, passphrase))
}
const confirmDelete = async () => {
@@ -850,7 +846,11 @@ export default function IpsecPage() {
<IpsecCertSheet
open={certOpen}
onOpenChange={(v) => { setCertOpen(v); if (!v) setCertByName(null) }}
onOpenChange={(v) => {
if (!v) { certEpoch.current += 1; certPending.current = false; setCertBusy(false); setCertBundle(null); setCertClient(null); setCertByName(null) }
setCertOpen(v)
}}
error={certError}
bundle={certBundle}
busy={certBusy}
onReexport={reexportCert}