From 0f9a6fd968aed2c75e0bbd88d786962441f6611c Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 15 May 2026 16:07:14 -0700 Subject: [PATCH] Support private key --- src/app/ssh/SshClient.tsx | 94 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/src/app/ssh/SshClient.tsx b/src/app/ssh/SshClient.tsx index 817bb1f30..a84b1dacc 100644 --- a/src/app/ssh/SshClient.tsx +++ b/src/app/ssh/SshClient.tsx @@ -5,6 +5,7 @@ import { useEffect, useRef, useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; type Target = { ip: string; @@ -15,6 +16,7 @@ type Target = { type FormState = { username: string; password: string; + privateKey: string; }; export default function SshClient({ @@ -26,9 +28,27 @@ export default function SshClient({ }) { const [form, setForm] = useState({ username: "", - password: "" + password: "", + privateKey: "" }); + const fileInputRef = useRef(null); + + function handleKeyFile(e: React.ChangeEvent) { + const file = e.target.files?.[0]; + if (!file) return; + const reader = new FileReader(); + reader.onload = (ev) => { + const text = ev.target?.result; + if (typeof text === "string") { + setForm((prev) => ({ ...prev, privateKey: text })); + } + }; + reader.readAsText(file); + // Reset input so the same file can be re-selected if needed. + e.target.value = ""; + } + const [connected, setConnected] = useState(false); const [connecting, setConnecting] = useState(false); const [connectError, setConnectError] = useState(null); @@ -143,9 +163,15 @@ export default function SshClient({ wsRef.current = ws; ws.onopen = () => { - // Send the password (or empty string) as the first frame so the - // proxy can complete SSH authentication before piping pty data. - ws.send(JSON.stringify({ type: "auth", password: form.password })); + // Send credentials as the first frame so the proxy can complete + // SSH authentication before piping pty data. + ws.send( + JSON.stringify({ + type: "auth", + password: form.password, + privateKey: form.privateKey + }) + ); setConnecting(false); setConnected(true); }; @@ -236,6 +262,60 @@ export default function SshClient({ password: e.target.value }) } + placeholder={ + form.privateKey + ? "Optional with key auth" + : "" + } + /> + + + +