import type { DesktopSshPasswordPromptRequest } from "@t3tools/contracts"; import { useEffect, useId, useRef, useState } from "react"; import { Button } from "../ui/button"; import { Dialog, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPopup, DialogTitle, } from "../ui/dialog"; import { Input } from "../ui/input"; function describeSshTarget(request: DesktopSshPasswordPromptRequest): string { return request.username ? `${request.username}@${request.destination}` : request.destination; } function formatRemainingSeconds(seconds: number): string { return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`; } function getPromptErrorMessage(error: unknown): string { const message = error instanceof Error ? error.message : "SSH password prompt failed."; return message.includes("expired") || message.includes("no longer pending") ? "This SSH password prompt expired. Try connecting again." : message; } export function SshPasswordPromptDialog() { const [queue, setQueue] = useState([]); const currentRequest = queue[0] ?? null; useEffect(() => { const bridge = window.desktopBridge; if (!bridge?.onSshPasswordPrompt) { return; } return bridge.onSshPasswordPrompt((request) => { setQueue((currentQueue) => [...currentQueue, request]); }); }, []); if (!currentRequest) { return null; } return ( { setQueue((currentQueue) => currentQueue[0]?.requestId === requestId ? currentQueue.slice(1) : currentQueue, ); }} /> ); } function ActiveSshPasswordPrompt({ request, onRemove, }: { readonly request: DesktopSshPasswordPromptRequest; readonly onRemove: (requestId: string) => void; }) { const [password, setPassword] = useState(""); const [isResponding, setIsResponding] = useState(false); const [now, setNow] = useState(() => Date.now()); const [responseError, setResponseError] = useState(null); const inputRef = useRef(null); const isRespondingRef = useRef(false); const formId = useId(); useEffect(() => { const frame = window.requestAnimationFrame(() => { inputRef.current?.focus(); inputRef.current?.select(); }); return () => { window.cancelAnimationFrame(frame); }; }, []); useEffect(() => { const interval = window.setInterval(() => { setNow(Date.now()); }, 1_000); return () => { window.clearInterval(interval); }; }, []); const expiresAtMs = Date.parse(request.expiresAt); const remainingMs = Number.isFinite(expiresAtMs) ? Math.max(0, expiresAtMs - now) : null; const isExpired = remainingMs !== null && remainingMs <= 0; const remainingSeconds = remainingMs === null ? null : Math.ceil(remainingMs / 1_000); const remainingLabel = remainingSeconds === null ? null : formatRemainingSeconds(remainingSeconds); const visibleResponseError = isExpired ? "This SSH password prompt expired. Try connecting again." : responseError; const respond = async (nextPassword: string | null) => { if (isRespondingRef.current) { return; } const requestId = request.requestId; if (nextPassword !== null && isExpired) { setResponseError("This SSH password prompt expired. Try connecting again."); return; } isRespondingRef.current = true; setIsResponding(true); setResponseError(null); try { await window.desktopBridge?.resolveSshPasswordPrompt(requestId, nextPassword); onRemove(requestId); } catch (error) { if (nextPassword === null) { onRemove(requestId); } else { setResponseError(getPromptErrorMessage(error)); } } finally { isRespondingRef.current = false; setIsResponding(false); } }; const dismissExpiredPrompt = () => { onRemove(request.requestId); }; const cancelPrompt = () => { if (isExpired) { dismissExpiredPrompt(); return; } void respond(null); }; const target = describeSshTarget(request); return ( { if (!open) { cancelPrompt(); } }} > SSH Password Required T3 needs your SSH password to connect to {target}. The password is passed to the local SSH process for this connection attempt and is not saved by T3 Code.
{ event.preventDefault(); void respond(password); }} >

{request.prompt}

{remainingLabel ? ( {isExpired ? "Expired" : remainingLabel} ) : null}
setPassword(event.target.value)} />
{visibleResponseError ? (

{visibleResponseError}

) : (

Use SSH keys to avoid repeated password prompts on new SSH sessions.

)}
); }