From 9625939aa5510e41742d94968608078fa393fc70 Mon Sep 17 00:00:00 2001 From: Antoine Jeanselme <67123340+ajeanselme@users.noreply.github.com> Date: Sat, 18 Apr 2026 08:52:07 +0200 Subject: [PATCH] Refactor ssh key generation function to a new ssh utils file --- .../components/volume-forms/sftp-form.tsx | 34 +------------------ app/utils/ssh.ts | 32 +++++++++++++++++ 2 files changed, 33 insertions(+), 33 deletions(-) create mode 100644 app/utils/ssh.ts diff --git a/app/client/modules/volumes/components/volume-forms/sftp-form.tsx b/app/client/modules/volumes/components/volume-forms/sftp-form.tsx index 77af19de..3b8de322 100644 --- a/app/client/modules/volumes/components/volume-forms/sftp-form.tsx +++ b/app/client/modules/volumes/components/volume-forms/sftp-form.tsx @@ -14,44 +14,12 @@ import { SecretInput } from "../../../../components/ui/secret-input"; import { Textarea } from "../../../../components/ui/textarea"; import { Switch } from "../../../../components/ui/switch"; import { Button } from "~/client/components/ui/button"; +import { generatePrivateKeyPem } from "~/utils/ssh"; type Props = { form: UseFormReturn; }; -const arrayBufferToBase64 = (buffer: ArrayBuffer) => { - let binary = ""; - const bytes = new Uint8Array(buffer); - const chunkSize = 0x8000; - - for (let i = 0; i < bytes.length; i += chunkSize) { - binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize)); - } - - return btoa(binary); -}; - -const toPem = (base64: string, label: string) => { - const wrapped = base64.match(/.{1,64}/g)?.join("\n") ?? base64; - return `-----BEGIN ${label}-----\n${wrapped}\n-----END ${label}-----`; -}; - -const generatePrivateKeyPem = async () => { - const keyPair = await crypto.subtle.generateKey( - { - name: "RSASSA-PKCS1-v1_5", - modulusLength: 4096, - publicExponent: new Uint8Array([1, 0, 1]), - hash: "SHA-256", - }, - true, - ["sign", "verify"], - ); - - const privateKey = await crypto.subtle.exportKey("pkcs8", keyPair.privateKey); - return toPem(arrayBufferToBase64(privateKey), "OPENSSH PRIVATE KEY"); -}; - export const SFTPForm = ({ form }: Props) => { const skipHostKeyCheck = useWatch({ control: form.control, name: "skipHostKeyCheck" }); const [isGeneratingKey, setIsGeneratingKey] = useState(false); diff --git a/app/utils/ssh.ts b/app/utils/ssh.ts new file mode 100644 index 00000000..444e3b32 --- /dev/null +++ b/app/utils/ssh.ts @@ -0,0 +1,32 @@ +const arrayBufferToBase64 = (buffer: ArrayBuffer) => { + let binary = ""; + const bytes = new Uint8Array(buffer); + const chunkSize = 0x8000; + + for (let i = 0; i < bytes.length; i += chunkSize) { + binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize)); + } + + return btoa(binary); +}; + +const toPem = (base64: string, label: string) => { + const wrapped = base64.match(/.{1,64}/g)?.join("\n") ?? base64; + return `-----BEGIN ${label}-----\n${wrapped}\n-----END ${label}-----`; +}; + +export const generatePrivateKeyPem = async () => { + const keyPair = await crypto.subtle.generateKey( + { + name: "RSASSA-PKCS1-v1_5", + modulusLength: 4096, + publicExponent: new Uint8Array([1, 0, 1]), + hash: "SHA-256", + }, + true, + ["sign", "verify"], + ); + + const privateKey = await crypto.subtle.exportKey("pkcs8", keyPair.privateKey); + return toPem(arrayBufferToBase64(privateKey), "OPENSSH PRIVATE KEY"); +};