mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Merge pull request #276 from lorenzomigliorero/feat/shared-ssh
feat: shared ssh
This commit is contained in:
@@ -3,57 +3,90 @@ import * as path from "node:path";
|
||||
import { SSH_PATH } from "@/server/constants";
|
||||
import { spawnAsync } from "../process/spawnAsync";
|
||||
|
||||
export const generateSSHKey = async (appName: string) => {
|
||||
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",
|
||||
}),
|
||||
publicKey: fs.readFileSync(path.join(SSH_PATH, `${id}_rsa.pub`), {
|
||||
encoding: "utf-8",
|
||||
}),
|
||||
};
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const saveSSHKey = async (
|
||||
id: string,
|
||||
publicKey: string,
|
||||
privateKey: string,
|
||||
) => {
|
||||
const applicationDirectory = SSH_PATH;
|
||||
|
||||
const privateKeyPath = path.join(applicationDirectory, `${id}_rsa`);
|
||||
const publicKeyPath = path.join(applicationDirectory, `${id}_rsa.pub`);
|
||||
|
||||
const privateKeyStream = fs.createWriteStream(privateKeyPath, {
|
||||
mode: 0o600,
|
||||
});
|
||||
privateKeyStream.write(privateKey);
|
||||
privateKeyStream.end();
|
||||
|
||||
fs.writeFileSync(publicKeyPath, publicKey);
|
||||
};
|
||||
|
||||
export const generateSSHKey = async (type: "rsa" | "ed25519" = "rsa") => {
|
||||
const applicationDirectory = SSH_PATH;
|
||||
|
||||
if (!fs.existsSync(applicationDirectory)) {
|
||||
fs.mkdirSync(applicationDirectory, { recursive: true });
|
||||
}
|
||||
|
||||
const keyPath = path.join(applicationDirectory, `${appName}_rsa`);
|
||||
const keyPath = path.join(applicationDirectory, "temp_rsa");
|
||||
|
||||
if (fs.existsSync(`${keyPath}`)) {
|
||||
fs.unlinkSync(`${keyPath}`);
|
||||
}
|
||||
|
||||
if (fs.existsSync(`${keyPath}.pub`)) {
|
||||
fs.unlinkSync(`${keyPath}.pub`);
|
||||
}
|
||||
|
||||
const args = [
|
||||
"-t",
|
||||
"rsa",
|
||||
type,
|
||||
"-b",
|
||||
"4096",
|
||||
"-C",
|
||||
"dokploy",
|
||||
"-m",
|
||||
"PEM",
|
||||
"-f",
|
||||
keyPath,
|
||||
"-N",
|
||||
"",
|
||||
];
|
||||
|
||||
try {
|
||||
await spawnAsync("ssh-keygen", args);
|
||||
return keyPath;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
export const readRSAFile = async (appName: string) => {
|
||||
try {
|
||||
if (!fs.existsSync(SSH_PATH)) {
|
||||
fs.mkdirSync(SSH_PATH, { recursive: true });
|
||||
}
|
||||
const keyPath = path.join(SSH_PATH, `${appName}_rsa.pub`);
|
||||
const data = fs.readFileSync(keyPath, { encoding: "utf-8" });
|
||||
const data = await readSSHKey("temp");
|
||||
await removeSSHKey("temp");
|
||||
return data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const removeRSAFiles = async (appName: string) => {
|
||||
export const removeSSHKey = async (id: string) => {
|
||||
try {
|
||||
const publicKeyPath = path.join(SSH_PATH, `${appName}_rsa.pub`);
|
||||
const privateKeyPath = path.join(SSH_PATH, `${appName}_rsa`);
|
||||
const publicKeyPath = path.join(SSH_PATH, `${id}_rsa.pub`);
|
||||
const privateKeyPath = path.join(SSH_PATH, `${id}_rsa`);
|
||||
await fs.promises.unlink(publicKeyPath);
|
||||
await fs.promises.unlink(privateKeyPath);
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createWriteStream } from "node:fs";
|
||||
import path, { join } from "node:path";
|
||||
import { updateSSHKeyById } from "@/server/api/services/ssh-key";
|
||||
import { APPLICATIONS_PATH, COMPOSE_PATH, SSH_PATH } from "@/server/constants";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { recreateDirectory } from "../filesystem/directory";
|
||||
@@ -11,12 +12,12 @@ export const cloneGitRepository = async (
|
||||
appName: string;
|
||||
customGitUrl?: string | null;
|
||||
customGitBranch?: string | null;
|
||||
customGitSSHKey?: string | null;
|
||||
customGitSSHKeyId?: string | null;
|
||||
},
|
||||
logPath: string,
|
||||
isCompose = false,
|
||||
) => {
|
||||
const { appName, customGitUrl, customGitBranch, customGitSSHKey } = entity;
|
||||
const { appName, customGitUrl, customGitBranch, customGitSSHKeyId } = entity;
|
||||
|
||||
if (!customGitUrl || !customGitBranch) {
|
||||
throw new TRPCError({
|
||||
@@ -26,7 +27,7 @@ export const cloneGitRepository = async (
|
||||
}
|
||||
|
||||
const writeStream = createWriteStream(logPath, { flags: "a" });
|
||||
const keyPath = path.join(SSH_PATH, `${appName}_rsa`);
|
||||
const keyPath = path.join(SSH_PATH, `${customGitSSHKeyId}_rsa`);
|
||||
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
|
||||
const outputPath = join(basePath, appName, "code");
|
||||
const knownHostsPath = path.join(SSH_PATH, "known_hosts");
|
||||
@@ -40,6 +41,13 @@ export const cloneGitRepository = async (
|
||||
`\nCloning Repo Custom ${customGitUrl} to ${outputPath}: ✅\n`,
|
||||
);
|
||||
|
||||
if (customGitSSHKeyId) {
|
||||
await updateSSHKeyById({
|
||||
sshKeyId: customGitSSHKeyId,
|
||||
lastUsedAt: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
await spawnAsync(
|
||||
"git",
|
||||
[
|
||||
@@ -60,12 +68,13 @@ export const cloneGitRepository = async (
|
||||
{
|
||||
env: {
|
||||
...process.env,
|
||||
...(customGitSSHKey && {
|
||||
...(customGitSSHKeyId && {
|
||||
GIT_SSH_COMMAND: `ssh -i ${keyPath} -o UserKnownHostsFile=${knownHostsPath}`,
|
||||
}),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
writeStream.write(`\nCloned Custom Git ${customGitUrl}: ✅\n`);
|
||||
} catch (error) {
|
||||
writeStream.write(`\nERROR Cloning Custom Git: ${error}: ❌\n`);
|
||||
|
||||
Reference in New Issue
Block a user