import { useEffect, useRef, useState } from "react"; import type { PluginSshPromptRequest } from "@termix/plugin-sdk/backend"; import { useTranslation } from "@termix/plugin-sdk/frontend"; import { Button, Dialog, DialogContent, DialogHeader, DialogTitle, Input, } from "@termix/plugin-sdk/ui"; type Challenge = { id: string; tunnelName?: string; request: PluginSshPromptRequest; }; export function TunnelAuthPrompts() { const [queue, setQueue] = useState([]); const pending = useRef(new Set()); useEffect(() => { const active = pending.current; const api = window.electronAPI; if (!api?.onC2SAuthPrompt) return; const dispose = api.onC2SAuthPrompt((event) => { if (event.closed) { active.delete(event.id); setQueue((items) => items.filter((item) => item.id !== event.id)); } else if (event.request && !active.has(event.id)) { active.add(event.id); setQueue((items) => [...items, { ...event, request: event.request! }]); } }); return () => { dispose(); for (const id of active) void api.answerC2SAuth(id, null); active.clear(); }; }, []); const current = queue[0]; return current ? ( { pending.current.delete(current.id); setQueue((items) => items.filter((item) => item.id !== current.id)); void window.electronAPI.answerC2SAuth(current.id, answer); }} /> ) : null; } function AuthDialog({ challenge, onAnswer, }: { challenge: Challenge; onAnswer: (answer: string | null) => void; }) { const { t } = useTranslation(); const [answer, setAnswer] = useState(""); const request = challenge.request; const browser = request.kind === "browser"; const url = browser && request.url && /^https?:\/\//i.test(request.url) ? request.url : null; return ( { if (!open) onAnswer(null); }} > {t("tunnels.authTitle")}

{challenge.tunnelName}

{ event.preventDefault(); onAnswer(answer); }} className="space-y-3" >

{browser ? request.instructions : request.prompt}

{request.kind === "totp" && request.retry && (

{t("tunnels.authRetry")}

)} {browser ? ( <>

{request.code}

{url && ( {url} )} ) : ( setAnswer(event.target.value)} /> )}
); }