import { FormField, FormItem, FormLabel, FormControl, } from "@/components/ui/form.tsx"; import { PasswordInput } from "@/components/ui/password-input.tsx"; import { Button } from "@/components/ui/button.tsx"; import { Tabs, TabsContent, TabsList, TabsTrigger, } from "@/components/ui/tabs.tsx"; import { Controller } from "react-hook-form"; import CodeMirror from "@uiw/react-codemirror"; import { EditorView } from "@codemirror/view"; import React from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; import { generateKeyPair, generatePublicKeyFromPrivate, } from "@/ui/main-axios.ts"; import type { CredentialAuthenticationTabProps } from "./shared/tab-types"; export function CredentialAuthenticationTab({ form, authTab, setAuthTab, detectedKeyType, detectedPublicKeyType, keyDetectionLoading, publicKeyDetectionLoading, editorTheme, debouncedKeyDetection, debouncedPublicKeyDetection, getFriendlyKeyTypeName, }: CredentialAuthenticationTabProps) { const { t } = useTranslation(); return ( <> {t("credentials.authentication")} { const newAuthType = value as "password" | "key"; setAuthTab(newAuthType); form.setValue("authType", newAuthType); form.setValue("password", ""); form.setValue("key", null); form.setValue("keyPassword", ""); form.setValue("keyType", "auto"); }} className="flex-1 flex flex-col h-full min-h-0" > {t("credentials.password")} {t("credentials.key")} ( {t("credentials.password")} )} /> {t("credentials.generateKeyPair")} {t("credentials.generateKeyPairDescription")} { try { const currentKeyPassword = form.watch("keyPassword"); const result = await generateKeyPair( "ssh-ed25519", undefined, currentKeyPassword, ); if (result.success) { form.setValue("key", result.privateKey); form.setValue("publicKey", result.publicKey); debouncedKeyDetection( result.privateKey, currentKeyPassword, ); debouncedPublicKeyDetection(result.publicKey); toast.success( t("credentials.keyPairGeneratedSuccessfully", { keyType: "Ed25519", }), ); } else { toast.error( result.error || t("credentials.failedToGenerateKeyPair"), ); } } catch (error) { console.error( "Failed to generate Ed25519 key pair:", error, ); toast.error(t("credentials.failedToGenerateKeyPair")); } }} > {t("credentials.generateEd25519")} { try { const currentKeyPassword = form.watch("keyPassword"); const result = await generateKeyPair( "ecdsa-sha2-nistp256", undefined, currentKeyPassword, ); if (result.success) { form.setValue("key", result.privateKey); form.setValue("publicKey", result.publicKey); debouncedKeyDetection( result.privateKey, currentKeyPassword, ); debouncedPublicKeyDetection(result.publicKey); toast.success( t("credentials.keyPairGeneratedSuccessfully", { keyType: "ECDSA", }), ); } else { toast.error( result.error || t("credentials.failedToGenerateKeyPair"), ); } } catch (error) { console.error( "Failed to generate ECDSA key pair:", error, ); toast.error(t("credentials.failedToGenerateKeyPair")); } }} > {t("credentials.generateECDSA")} { try { const currentKeyPassword = form.watch("keyPassword"); const result = await generateKeyPair( "ssh-rsa", 2048, currentKeyPassword, ); if (result.success) { form.setValue("key", result.privateKey); form.setValue("publicKey", result.publicKey); debouncedKeyDetection( result.privateKey, currentKeyPassword, ); debouncedPublicKeyDetection(result.publicKey); toast.success( t("credentials.keyPairGeneratedSuccessfully", { keyType: "RSA", }), ); } else { toast.error( result.error || t("credentials.failedToGenerateKeyPair"), ); } } catch (error) { console.error("Failed to generate RSA key pair:", error); toast.error(t("credentials.failedToGenerateKeyPair")); } }} > {t("credentials.generateRSA")} ( {t("credentials.sshPrivateKey")} { const file = e.target.files?.[0]; if (file) { try { const fileContent = await file.text(); field.onChange(fileContent); debouncedKeyDetection( fileContent, form.watch("keyPassword"), ); } catch (error) { console.error( "Failed to read uploaded file:", error, ); } } }} className="absolute inset-0 w-full h-full opacity-0 cursor-pointer" /> {t("credentials.uploadPrivateKeyFile")} { field.onChange(value); debouncedKeyDetection( value, form.watch("keyPassword"), ); }} placeholder={t("placeholders.pastePrivateKey")} theme={editorTheme} className="border border-input rounded-md overflow-hidden" minHeight="120px" basicSetup={{ lineNumbers: true, foldGutter: false, dropCursor: false, allowMultipleSelections: false, highlightSelectionMatches: false, searchKeymap: false, scrollPastEnd: false, }} extensions={[ EditorView.theme({ ".cm-scroller": { overflow: "auto", scrollbarWidth: "thin", scrollbarColor: "var(--scrollbar-thumb) var(--scrollbar-track)", }, }), ]} /> {detectedKeyType && ( {t("credentials.detectedKeyType")}:{" "} {getFriendlyKeyTypeName(detectedKeyType)} {keyDetectionLoading && ( ({t("credentials.detectingKeyType")}) )} )} )} /> ( {t("credentials.sshPublicKey")} { const file = e.target.files?.[0]; if (file) { try { const fileContent = await file.text(); field.onChange(fileContent); debouncedPublicKeyDetection(fileContent); } catch (error) { console.error( "Failed to read uploaded public key file:", error, ); } } }} className="absolute inset-0 w-full h-full opacity-0 cursor-pointer" /> {t("credentials.uploadPublicKeyFile")} { const privateKey = form.watch("key"); if ( !privateKey || typeof privateKey !== "string" || !privateKey.trim() ) { toast.error( t("credentials.privateKeyRequiredForGeneration"), ); return; } try { const keyPassword = form.watch("keyPassword"); const result = await generatePublicKeyFromPrivate( privateKey, keyPassword, ); if (result.success && result.publicKey) { field.onChange(result.publicKey); debouncedPublicKeyDetection(result.publicKey); toast.success( t("credentials.publicKeyGeneratedSuccessfully"), ); } else { toast.error( result.error || t("credentials.failedToGeneratePublicKey"), ); } } catch (error) { console.error( "Failed to generate public key:", error, ); toast.error( t("credentials.failedToGeneratePublicKey"), ); } }} > {t("credentials.generatePublicKey")} { field.onChange(value); debouncedPublicKeyDetection(value); }} placeholder={t("placeholders.pastePublicKey")} theme={editorTheme} className="border border-input rounded-md overflow-hidden" minHeight="120px" basicSetup={{ lineNumbers: true, foldGutter: false, dropCursor: false, allowMultipleSelections: false, highlightSelectionMatches: false, searchKeymap: false, scrollPastEnd: false, }} extensions={[ EditorView.theme({ ".cm-scroller": { overflow: "auto", scrollbarWidth: "thin", scrollbarColor: "var(--scrollbar-thumb) var(--scrollbar-track)", }, }), ]} /> {detectedPublicKeyType && field.value && ( {t("credentials.detectedKeyType")}:{" "} {getFriendlyKeyTypeName(detectedPublicKeyType)} {publicKeyDetectionLoading && ( ({t("credentials.detectingKeyType")}) )} )} )} /> ( {t("credentials.keyPassword")} )} /> > ); }