mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat: generate ssh key
This commit is contained in:
@@ -42,6 +42,8 @@ export const AddSSHKey = ({ children }: Props) => {
|
|||||||
const { mutateAsync, isError, error, isLoading } =
|
const { mutateAsync, isError, error, isLoading } =
|
||||||
api.sshKey.create.useMutation();
|
api.sshKey.create.useMutation();
|
||||||
|
|
||||||
|
const generateMutation = api.sshKey.generate.useMutation();
|
||||||
|
|
||||||
const form = useForm<SSHKey>({
|
const form = useForm<SSHKey>({
|
||||||
resolver: zodResolver(sshKeyCreate),
|
resolver: zodResolver(sshKeyCreate),
|
||||||
});
|
});
|
||||||
@@ -71,8 +73,31 @@ export const AddSSHKey = ({ children }: Props) => {
|
|||||||
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-2xl">
|
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-2xl">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>SSH Key</DialogTitle>
|
<DialogTitle>SSH Key</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription className="space-y-4">
|
||||||
In this section you can add an SSH key
|
<div>
|
||||||
|
In this section you can add one of your keys or generate a new
|
||||||
|
one.
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant={"secondary"}
|
||||||
|
isLoading={generateMutation.isLoading}
|
||||||
|
className="max-sm:w-full"
|
||||||
|
onClick={async () => {
|
||||||
|
await generateMutation
|
||||||
|
.mutateAsync()
|
||||||
|
.then(async (data) => {
|
||||||
|
toast.success("SSH Key Generated");
|
||||||
|
form.setValue("privateKey", data.privateKey);
|
||||||
|
form.setValue("publicKey", data.publicKey);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toast.error("Error to generate the SSH Key");
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Generate SSH Key
|
||||||
|
</Button>
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
|
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
apiRemoveSshKey,
|
apiRemoveSshKey,
|
||||||
apiUpdateSshKey,
|
apiUpdateSshKey,
|
||||||
} from "@/server/db/schema";
|
} from "@/server/db/schema";
|
||||||
|
import { generateSSHKey } from "@/server/utils/filesystem/ssh";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import {
|
import {
|
||||||
createSshKey,
|
createSshKey,
|
||||||
@@ -49,6 +50,9 @@ export const sshRouter = createTRPCRouter({
|
|||||||
all: adminProcedure.query(async () => {
|
all: adminProcedure.query(async () => {
|
||||||
return await db.query.sshKeys.findMany({});
|
return await db.query.sshKeys.findMany({});
|
||||||
}),
|
}),
|
||||||
|
generate: protectedProcedure.mutation(async () => {
|
||||||
|
return await generateSSHKey();
|
||||||
|
}),
|
||||||
update: adminProcedure.input(apiUpdateSshKey).mutation(async ({ input }) => {
|
update: adminProcedure.input(apiUpdateSshKey).mutation(async ({ input }) => {
|
||||||
try {
|
try {
|
||||||
return await updateSSHKeyById(input);
|
return await updateSSHKeyById(input);
|
||||||
|
|||||||
@@ -3,6 +3,29 @@ import * as path from "node:path";
|
|||||||
import { SSH_PATH } from "@/server/constants";
|
import { SSH_PATH } from "@/server/constants";
|
||||||
import { spawnAsync } from "../process/spawnAsync";
|
import { spawnAsync } from "../process/spawnAsync";
|
||||||
|
|
||||||
|
const readSSHKey = async (id: string) => {
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(SSH_PATH)) {
|
||||||
|
fs.mkdirSync(SSH_PATH, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
privateKey: fs
|
||||||
|
.readFileSync(path.join(SSH_PATH, `${id}_rsa`), {
|
||||||
|
encoding: "utf-8",
|
||||||
|
})
|
||||||
|
.trim(),
|
||||||
|
publicKey: fs
|
||||||
|
.readFileSync(path.join(SSH_PATH, `${id}_rsa.pub`), {
|
||||||
|
encoding: "utf-8",
|
||||||
|
})
|
||||||
|
.trim(),
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const saveSSHKey = async (
|
export const saveSSHKey = async (
|
||||||
id: string,
|
id: string,
|
||||||
publicKey: string,
|
publicKey: string,
|
||||||
@@ -24,21 +47,23 @@ export const saveSSHKey = async (
|
|||||||
publicKeyStream.end();
|
publicKeyStream.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateSSHKey = async (id: string) => {
|
export const generateSSHKey = async () => {
|
||||||
const applicationDirectory = SSH_PATH;
|
const applicationDirectory = SSH_PATH;
|
||||||
|
|
||||||
if (!fs.existsSync(applicationDirectory)) {
|
if (!fs.existsSync(applicationDirectory)) {
|
||||||
fs.mkdirSync(applicationDirectory, { recursive: true });
|
fs.mkdirSync(applicationDirectory, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyPath = path.join(applicationDirectory, `${id}_rsa`);
|
const keyPath = path.join(applicationDirectory, "temp_rsa");
|
||||||
|
|
||||||
if (fs.existsSync(`${keyPath}`)) {
|
if (fs.existsSync(`${keyPath}`)) {
|
||||||
fs.unlinkSync(`${keyPath}`);
|
fs.unlinkSync(`${keyPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs.existsSync(`${keyPath}.pub`)) {
|
if (fs.existsSync(`${keyPath}.pub`)) {
|
||||||
fs.unlinkSync(`${keyPath}.pub`);
|
fs.unlinkSync(`${keyPath}.pub`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const args = [
|
const args = [
|
||||||
"-t",
|
"-t",
|
||||||
"rsa",
|
"rsa",
|
||||||
@@ -46,25 +71,18 @@ export const generateSSHKey = async (id: string) => {
|
|||||||
"4096",
|
"4096",
|
||||||
"-C",
|
"-C",
|
||||||
"dokploy",
|
"dokploy",
|
||||||
|
"-m",
|
||||||
|
"PEM",
|
||||||
"-f",
|
"-f",
|
||||||
keyPath,
|
keyPath,
|
||||||
"-N",
|
"-N",
|
||||||
"",
|
"",
|
||||||
];
|
];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await spawnAsync("ssh-keygen", args);
|
await spawnAsync("ssh-keygen", args);
|
||||||
return keyPath;
|
const data = await readSSHKey("temp");
|
||||||
} catch (error) {
|
await removeSSHKey("temp");
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export const readSSHPublicKey = async (id: string) => {
|
|
||||||
try {
|
|
||||||
if (!fs.existsSync(SSH_PATH)) {
|
|
||||||
fs.mkdirSync(SSH_PATH, { recursive: true });
|
|
||||||
}
|
|
||||||
const keyPath = path.join(SSH_PATH, `${id}_rsa.pub`);
|
|
||||||
const data = fs.readFileSync(keyPath, { encoding: "utf-8" });
|
|
||||||
return data;
|
return data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
Reference in New Issue
Block a user