quicklify 1.0.5 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +86 -25
- package/README.tr.md +86 -25
- package/SECURITY.md +79 -17
- package/bin/quicklify-mcp +5 -0
- package/dist/commands/add.d.ts +1 -0
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +41 -65
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/backup.d.ts +2 -11
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +113 -57
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/destroy.d.ts.map +1 -1
- package/dist/commands/destroy.js +58 -37
- package/dist/commands/destroy.js.map +1 -1
- package/dist/commands/domain.d.ts +2 -9
- package/dist/commands/domain.d.ts.map +1 -1
- package/dist/commands/domain.js +47 -56
- package/dist/commands/domain.js.map +1 -1
- package/dist/commands/firewall.d.ts +3 -10
- package/dist/commands/firewall.d.ts.map +1 -1
- package/dist/commands/firewall.js +28 -51
- package/dist/commands/firewall.js.map +1 -1
- package/dist/commands/health.d.ts +2 -2
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +77 -19
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +142 -24
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/interactive.d.ts +2 -0
- package/dist/commands/interactive.d.ts.map +1 -0
- package/dist/commands/interactive.js +357 -0
- package/dist/commands/interactive.js.map +1 -0
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +4 -2
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/logs.d.ts +3 -2
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +15 -12
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/maintain.d.ts.map +1 -1
- package/dist/commands/maintain.js +28 -47
- package/dist/commands/maintain.js.map +1 -1
- package/dist/commands/monitor.d.ts +3 -9
- package/dist/commands/monitor.d.ts.map +1 -1
- package/dist/commands/monitor.js +3 -48
- package/dist/commands/monitor.js.map +1 -1
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/remove.js +25 -0
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/restart.d.ts.map +1 -1
- package/dist/commands/restart.js +39 -39
- package/dist/commands/restart.js.map +1 -1
- package/dist/commands/restore.d.ts +2 -13
- package/dist/commands/restore.d.ts.map +1 -1
- package/dist/commands/restore.js +42 -54
- package/dist/commands/restore.js.map +1 -1
- package/dist/commands/secure.d.ts +2 -9
- package/dist/commands/secure.d.ts.map +1 -1
- package/dist/commands/secure.js +2 -97
- package/dist/commands/secure.js.map +1 -1
- package/dist/commands/snapshot.d.ts.map +1 -1
- package/dist/commands/snapshot.js +55 -67
- package/dist/commands/snapshot.js.map +1 -1
- package/dist/commands/ssh.d.ts.map +1 -1
- package/dist/commands/ssh.js +4 -1
- package/dist/commands/ssh.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +53 -85
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +23 -16
- package/dist/commands/update.js.map +1 -1
- package/dist/constants.d.ts +14 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +23 -0
- package/dist/constants.js.map +1 -0
- package/dist/core/backup.d.ts +59 -0
- package/dist/core/backup.d.ts.map +1 -0
- package/dist/core/backup.js +417 -0
- package/dist/core/backup.js.map +1 -0
- package/dist/core/domain.d.ts +30 -0
- package/dist/core/domain.d.ts.map +1 -0
- package/dist/core/domain.js +170 -0
- package/dist/core/domain.js.map +1 -0
- package/dist/core/firewall.d.ts +27 -0
- package/dist/core/firewall.d.ts.map +1 -0
- package/dist/core/firewall.js +158 -0
- package/dist/core/firewall.js.map +1 -0
- package/dist/core/logs.d.ts +28 -0
- package/dist/core/logs.d.ts.map +1 -0
- package/dist/core/logs.js +129 -0
- package/dist/core/logs.js.map +1 -0
- package/dist/core/maintain.d.ts +41 -0
- package/dist/core/maintain.d.ts.map +1 -0
- package/dist/core/maintain.js +179 -0
- package/dist/core/maintain.js.map +1 -0
- package/dist/core/manage.d.ts +43 -0
- package/dist/core/manage.d.ts.map +1 -0
- package/dist/core/manage.js +241 -0
- package/dist/core/manage.js.map +1 -0
- package/dist/core/provision.d.ts +19 -0
- package/dist/core/provision.d.ts.map +1 -0
- package/dist/core/provision.js +192 -0
- package/dist/core/provision.js.map +1 -0
- package/dist/core/secure.d.ts +29 -0
- package/dist/core/secure.d.ts.map +1 -0
- package/dist/core/secure.js +204 -0
- package/dist/core/secure.js.map +1 -0
- package/dist/core/snapshot.d.ts +22 -0
- package/dist/core/snapshot.d.ts.map +1 -0
- package/dist/core/snapshot.js +58 -0
- package/dist/core/snapshot.js.map +1 -0
- package/dist/core/status.d.ts +12 -0
- package/dist/core/status.d.ts.map +1 -0
- package/dist/core/status.js +44 -0
- package/dist/core/status.js.map +1 -0
- package/dist/core/tokens.d.ts +4 -0
- package/dist/core/tokens.d.ts.map +1 -0
- package/dist/core/tokens.js +23 -0
- package/dist/core/tokens.js.map +1 -0
- package/dist/index.js +17 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +16 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +111 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/serverBackup.d.ts +24 -0
- package/dist/mcp/tools/serverBackup.d.ts.map +1 -0
- package/dist/mcp/tools/serverBackup.js +262 -0
- package/dist/mcp/tools/serverBackup.js.map +1 -0
- package/dist/mcp/tools/serverInfo.d.ts +36 -0
- package/dist/mcp/tools/serverInfo.d.ts.map +1 -0
- package/dist/mcp/tools/serverInfo.js +283 -0
- package/dist/mcp/tools/serverInfo.js.map +1 -0
- package/dist/mcp/tools/serverLogs.d.ts +25 -0
- package/dist/mcp/tools/serverLogs.d.ts.map +1 -0
- package/dist/mcp/tools/serverLogs.js +124 -0
- package/dist/mcp/tools/serverLogs.js.map +1 -0
- package/dist/mcp/tools/serverMaintain.d.ts +17 -0
- package/dist/mcp/tools/serverMaintain.d.ts.map +1 -0
- package/dist/mcp/tools/serverMaintain.js +156 -0
- package/dist/mcp/tools/serverMaintain.js.map +1 -0
- package/dist/mcp/tools/serverManage.d.ts +38 -0
- package/dist/mcp/tools/serverManage.d.ts.map +1 -0
- package/dist/mcp/tools/serverManage.js +190 -0
- package/dist/mcp/tools/serverManage.js.map +1 -0
- package/dist/mcp/tools/serverProvision.d.ts +36 -0
- package/dist/mcp/tools/serverProvision.d.ts.map +1 -0
- package/dist/mcp/tools/serverProvision.js +116 -0
- package/dist/mcp/tools/serverProvision.js.map +1 -0
- package/dist/mcp/tools/serverSecure.d.ts +35 -0
- package/dist/mcp/tools/serverSecure.d.ts.map +1 -0
- package/dist/mcp/tools/serverSecure.js +335 -0
- package/dist/mcp/tools/serverSecure.js.map +1 -0
- package/dist/mcp/utils.d.ts +42 -0
- package/dist/mcp/utils.d.ts.map +1 -0
- package/dist/mcp/utils.js +61 -0
- package/dist/mcp/utils.js.map +1 -0
- package/dist/providers/base.d.ts +2 -2
- package/dist/providers/base.d.ts.map +1 -1
- package/dist/providers/digitalocean.d.ts +2 -2
- package/dist/providers/digitalocean.d.ts.map +1 -1
- package/dist/providers/digitalocean.js +3 -3
- package/dist/providers/digitalocean.js.map +1 -1
- package/dist/providers/hetzner.d.ts +2 -2
- package/dist/providers/hetzner.d.ts.map +1 -1
- package/dist/providers/hetzner.js +7 -4
- package/dist/providers/hetzner.js.map +1 -1
- package/dist/providers/linode.d.ts +2 -2
- package/dist/providers/linode.d.ts.map +1 -1
- package/dist/providers/linode.js +2 -2
- package/dist/providers/linode.js.map +1 -1
- package/dist/providers/vultr.d.ts +2 -2
- package/dist/providers/vultr.d.ts.map +1 -1
- package/dist/providers/vultr.js +9 -3
- package/dist/providers/vultr.js.map +1 -1
- package/dist/types/index.d.ts +11 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/cloudInit.d.ts +1 -0
- package/dist/utils/cloudInit.d.ts.map +1 -1
- package/dist/utils/cloudInit.js +62 -0
- package/dist/utils/cloudInit.js.map +1 -1
- package/dist/utils/config.js +1 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/errorMapper.d.ts +1 -0
- package/dist/utils/errorMapper.d.ts.map +1 -1
- package/dist/utils/errorMapper.js +25 -1
- package/dist/utils/errorMapper.js.map +1 -1
- package/dist/utils/modeGuard.d.ts +5 -0
- package/dist/utils/modeGuard.d.ts.map +1 -0
- package/dist/utils/modeGuard.js +13 -0
- package/dist/utils/modeGuard.js.map +1 -0
- package/dist/utils/openBrowser.d.ts.map +1 -1
- package/dist/utils/openBrowser.js +9 -2
- package/dist/utils/openBrowser.js.map +1 -1
- package/dist/utils/prompts.d.ts +2 -2
- package/dist/utils/prompts.d.ts.map +1 -1
- package/dist/utils/prompts.js +3 -3
- package/dist/utils/prompts.js.map +1 -1
- package/dist/utils/ssh.d.ts +10 -0
- package/dist/utils/ssh.d.ts.map +1 -1
- package/dist/utils/ssh.js +181 -17
- package/dist/utils/ssh.js.map +1 -1
- package/dist/utils/sshKey.d.ts.map +1 -1
- package/dist/utils/sshKey.js +3 -0
- package/dist/utils/sshKey.js.map +1 -1
- package/package.json +7 -4
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import { mkdirSync, existsSync, writeFileSync, readFileSync, readdirSync, rmSync } from "fs";
|
|
2
|
+
import { join, resolve } from "path";
|
|
3
|
+
import { spawn } from "child_process";
|
|
4
|
+
import { sshExec, assertValidIp, sanitizedEnv } from "../utils/ssh.js";
|
|
5
|
+
import { BACKUPS_DIR } from "../utils/config.js";
|
|
6
|
+
import { getErrorMessage, mapSshError, sanitizeStderr } from "../utils/errorMapper.js";
|
|
7
|
+
// ─── Pure Functions (Backup) ─────────────────────────────────────────────────
|
|
8
|
+
export function formatTimestamp(date) {
|
|
9
|
+
return date.toISOString().replace(/[:.]/g, "-").replace("T", "_").replace("Z", "");
|
|
10
|
+
}
|
|
11
|
+
export function getBackupDir(serverName) {
|
|
12
|
+
return join(BACKUPS_DIR, serverName);
|
|
13
|
+
}
|
|
14
|
+
export function buildPgDumpCommand() {
|
|
15
|
+
return "docker exec coolify-db pg_dump -U coolify -d coolify | gzip > /tmp/coolify-backup.sql.gz";
|
|
16
|
+
}
|
|
17
|
+
export function buildConfigTarCommand() {
|
|
18
|
+
return "tar czf /tmp/coolify-config.tar.gz -C /data/coolify/source .env docker-compose.yml docker-compose.prod.yml 2>/dev/null || tar czf /tmp/coolify-config.tar.gz -C /data/coolify/source .env docker-compose.yml";
|
|
19
|
+
}
|
|
20
|
+
export function buildCleanupCommand() {
|
|
21
|
+
return "rm -f /tmp/coolify-backup.sql.gz /tmp/coolify-config.tar.gz";
|
|
22
|
+
}
|
|
23
|
+
export function buildCoolifyVersionCommand() {
|
|
24
|
+
return "docker inspect coolify --format '{{.Config.Image}}' 2>/dev/null | sed 's/.*://' || echo unknown";
|
|
25
|
+
}
|
|
26
|
+
// ─── Pure Functions (Restore) ────────────────────────────────────────────────
|
|
27
|
+
export function buildStopCoolifyCommand() {
|
|
28
|
+
return "cd /data/coolify/source && docker compose -f docker-compose.yml -f docker-compose.prod.yml stop";
|
|
29
|
+
}
|
|
30
|
+
export function buildStartCoolifyCommand() {
|
|
31
|
+
return "cd /data/coolify/source && docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d";
|
|
32
|
+
}
|
|
33
|
+
export function buildStartDbCommand() {
|
|
34
|
+
return "cd /data/coolify/source && docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d postgres && sleep 3";
|
|
35
|
+
}
|
|
36
|
+
export function buildRestoreDbCommand() {
|
|
37
|
+
return "gunzip -c /tmp/coolify-backup.sql.gz | docker exec -i coolify-db psql -U coolify -d coolify";
|
|
38
|
+
}
|
|
39
|
+
export function buildRestoreConfigCommand() {
|
|
40
|
+
return "tar xzf /tmp/coolify-config.tar.gz -C /data/coolify/source";
|
|
41
|
+
}
|
|
42
|
+
// ─── Semi-Pure Functions (FS Read) ───────────────────────────────────────────
|
|
43
|
+
export function listBackups(serverName) {
|
|
44
|
+
const dir = getBackupDir(serverName);
|
|
45
|
+
if (!existsSync(dir))
|
|
46
|
+
return [];
|
|
47
|
+
try {
|
|
48
|
+
return readdirSync(dir)
|
|
49
|
+
.filter((name) => existsSync(join(dir, name, "manifest.json")))
|
|
50
|
+
.sort()
|
|
51
|
+
.reverse();
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function loadManifest(backupPath) {
|
|
58
|
+
const manifestPath = join(backupPath, "manifest.json");
|
|
59
|
+
if (!existsSync(manifestPath))
|
|
60
|
+
return undefined;
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function listOrphanBackups(activeServerNames) {
|
|
69
|
+
if (!existsSync(BACKUPS_DIR))
|
|
70
|
+
return [];
|
|
71
|
+
try {
|
|
72
|
+
return readdirSync(BACKUPS_DIR)
|
|
73
|
+
.filter((name) => {
|
|
74
|
+
const fullPath = join(BACKUPS_DIR, name);
|
|
75
|
+
// Only directories that are not in active server list
|
|
76
|
+
return existsSync(fullPath) && !activeServerNames.includes(name);
|
|
77
|
+
})
|
|
78
|
+
.sort();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export function cleanupServerBackups(serverName) {
|
|
85
|
+
const dir = getBackupDir(serverName);
|
|
86
|
+
if (!existsSync(dir))
|
|
87
|
+
return { removed: false, path: dir };
|
|
88
|
+
try {
|
|
89
|
+
rmSync(dir, { recursive: true, force: true });
|
|
90
|
+
return { removed: true, path: dir };
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return { removed: false, path: dir };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// ─── Path Validation ─────────────────────────────────────────────────────────
|
|
97
|
+
/**
|
|
98
|
+
* Asserts that a remote SCP path does not contain shell metacharacters.
|
|
99
|
+
* Prevents command injection via crafted remotePath values.
|
|
100
|
+
* Allowed: alphanumeric, hyphens, underscores, dots, forward slashes.
|
|
101
|
+
*/
|
|
102
|
+
export function assertSafePath(remotePath) {
|
|
103
|
+
// Reject any path containing shell metacharacters: ; | & $ ` ( ) < > \n \r \t space
|
|
104
|
+
if (/[;|&$`()<>\n\r\t ]/.test(remotePath)) {
|
|
105
|
+
throw new Error(`Unsafe remote path rejected: contains shell metacharacters`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// ─── SCP Functions ───────────────────────────────────────────────────────────
|
|
109
|
+
export function scpDownload(ip, remotePath, localPath) {
|
|
110
|
+
assertValidIp(ip);
|
|
111
|
+
assertSafePath(remotePath);
|
|
112
|
+
return new Promise((resolve) => {
|
|
113
|
+
const child = spawn("scp", ["-o", "StrictHostKeyChecking=accept-new", `root@${ip}:${remotePath}`, localPath], { stdio: ["inherit", "pipe", "pipe"], env: sanitizedEnv() });
|
|
114
|
+
let stderr = "";
|
|
115
|
+
child.stderr?.on("data", (data) => {
|
|
116
|
+
stderr += data.toString();
|
|
117
|
+
});
|
|
118
|
+
child.on("close", (code) => resolve({ code: code ?? 1, stderr }));
|
|
119
|
+
child.on("error", (err) => resolve({ code: 1, stderr: err.message }));
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
export function scpUpload(ip, localPath, remotePath) {
|
|
123
|
+
assertValidIp(ip);
|
|
124
|
+
assertSafePath(remotePath);
|
|
125
|
+
return new Promise((resolve) => {
|
|
126
|
+
const child = spawn("scp", ["-o", "StrictHostKeyChecking=accept-new", localPath, `root@${ip}:${remotePath}`], { stdio: ["inherit", "pipe", "pipe"], env: sanitizedEnv() });
|
|
127
|
+
let stderr = "";
|
|
128
|
+
child.stderr?.on("data", (data) => {
|
|
129
|
+
stderr += data.toString();
|
|
130
|
+
});
|
|
131
|
+
child.on("close", (code) => resolve({ code: code ?? 1, stderr }));
|
|
132
|
+
child.on("error", (err) => resolve({ code: 1, stderr: err.message }));
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
// ─── Pure Functions (Bare Backup) ────────────────────────────────────────────
|
|
136
|
+
export function buildBareConfigTarCommand() {
|
|
137
|
+
return ("tar czf /tmp/bare-config.tar.gz --ignore-failed-read " +
|
|
138
|
+
"-C / " +
|
|
139
|
+
"etc/nginx " +
|
|
140
|
+
"etc/ssh/sshd_config " +
|
|
141
|
+
"etc/ufw " +
|
|
142
|
+
"etc/fail2ban " +
|
|
143
|
+
"etc/crontab " +
|
|
144
|
+
"etc/apt/apt.conf.d/50unattended-upgrades " +
|
|
145
|
+
"2>/dev/null || tar czf /tmp/bare-config.tar.gz --ignore-failed-read -C / etc/ssh/sshd_config");
|
|
146
|
+
}
|
|
147
|
+
export function buildBareRestoreConfigCommand() {
|
|
148
|
+
return "tar xzf /tmp/bare-config.tar.gz -C /";
|
|
149
|
+
}
|
|
150
|
+
export function buildBareCleanupCommand() {
|
|
151
|
+
return "rm -f /tmp/bare-config.tar.gz";
|
|
152
|
+
}
|
|
153
|
+
// ─── Async Wrappers (Bare) ────────────────────────────────────────────────────
|
|
154
|
+
export async function createBareBackup(ip, serverName, provider) {
|
|
155
|
+
assertValidIp(ip);
|
|
156
|
+
try {
|
|
157
|
+
// Step 1: Create config archive on server
|
|
158
|
+
const configResult = await sshExec(ip, buildBareConfigTarCommand());
|
|
159
|
+
if (configResult.code !== 0) {
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
error: "Config backup failed",
|
|
163
|
+
hint: sanitizeStderr(configResult.stderr) || undefined,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// Step 2: Download
|
|
167
|
+
const timestamp = formatTimestamp(new Date());
|
|
168
|
+
const backupPath = join(getBackupDir(serverName), timestamp);
|
|
169
|
+
mkdirSync(backupPath, { recursive: true, mode: 0o700 });
|
|
170
|
+
const dl = await scpDownload(ip, "/tmp/bare-config.tar.gz", join(backupPath, "bare-config.tar.gz"));
|
|
171
|
+
if (dl.code !== 0) {
|
|
172
|
+
return {
|
|
173
|
+
success: false,
|
|
174
|
+
error: "Failed to download config backup",
|
|
175
|
+
hint: sanitizeStderr(dl.stderr) || undefined,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
// Step 3: Write manifest
|
|
179
|
+
const manifest = {
|
|
180
|
+
serverName,
|
|
181
|
+
provider,
|
|
182
|
+
timestamp,
|
|
183
|
+
coolifyVersion: "n/a",
|
|
184
|
+
files: ["bare-config.tar.gz"],
|
|
185
|
+
mode: "bare",
|
|
186
|
+
};
|
|
187
|
+
writeFileSync(join(backupPath, "manifest.json"), JSON.stringify(manifest, null, 2), { mode: 0o600 });
|
|
188
|
+
// Step 4: Cleanup remote
|
|
189
|
+
await sshExec(ip, buildBareCleanupCommand()).catch(() => { });
|
|
190
|
+
return { success: true, backupPath, manifest };
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
const hint = mapSshError(error, ip);
|
|
194
|
+
return {
|
|
195
|
+
success: false,
|
|
196
|
+
error: getErrorMessage(error),
|
|
197
|
+
...(hint ? { hint } : {}),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
export async function restoreBareBackup(ip, serverName, backupId) {
|
|
202
|
+
assertValidIp(ip);
|
|
203
|
+
const baseDir = getBackupDir(serverName);
|
|
204
|
+
const backupPath = join(baseDir, backupId);
|
|
205
|
+
// Path traversal guard
|
|
206
|
+
if (!resolve(backupPath).startsWith(resolve(baseDir))) {
|
|
207
|
+
return { success: false, steps: [], error: "Invalid backupId: path traversal detected" };
|
|
208
|
+
}
|
|
209
|
+
const steps = [];
|
|
210
|
+
const manifest = loadManifest(backupPath);
|
|
211
|
+
if (!manifest) {
|
|
212
|
+
return { success: false, steps, error: `Backup not found or corrupt: ${backupId}` };
|
|
213
|
+
}
|
|
214
|
+
// Verify backup file exists
|
|
215
|
+
const configFile = join(backupPath, "bare-config.tar.gz");
|
|
216
|
+
if (!existsSync(configFile)) {
|
|
217
|
+
return { success: false, steps, error: "Missing backup file: bare-config.tar.gz" };
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
// Upload config archive
|
|
221
|
+
const upload = await scpUpload(ip, configFile, "/tmp/bare-config.tar.gz");
|
|
222
|
+
if (upload.code !== 0) {
|
|
223
|
+
return {
|
|
224
|
+
success: false,
|
|
225
|
+
steps: [{ name: "Upload config", status: "failure", error: sanitizeStderr(upload.stderr) }],
|
|
226
|
+
error: "Upload failed",
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
steps.push({ name: "Upload config", status: "success" });
|
|
230
|
+
// Extract config
|
|
231
|
+
const restoreResult = await sshExec(ip, buildBareRestoreConfigCommand());
|
|
232
|
+
if (restoreResult.code !== 0) {
|
|
233
|
+
steps.push({ name: "Restore config", status: "failure", error: sanitizeStderr(restoreResult.stderr) });
|
|
234
|
+
return { success: false, steps, error: "Config restore failed" };
|
|
235
|
+
}
|
|
236
|
+
steps.push({ name: "Restore config", status: "success" });
|
|
237
|
+
// Cleanup
|
|
238
|
+
await sshExec(ip, buildBareCleanupCommand()).catch(() => { });
|
|
239
|
+
return { success: true, steps };
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
const hint = mapSshError(error, ip);
|
|
243
|
+
return {
|
|
244
|
+
success: false,
|
|
245
|
+
steps,
|
|
246
|
+
error: getErrorMessage(error),
|
|
247
|
+
...(hint ? { hint } : {}),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// ─── Best-Effort Rollback ────────────────────────────────────────────────────
|
|
252
|
+
export async function tryRestartCoolify(ip) {
|
|
253
|
+
try {
|
|
254
|
+
await sshExec(ip, buildStartCoolifyCommand());
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
// Best-effort — swallow errors
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// ─── Async Wrappers ─────────────────────────────────────────────────────────
|
|
261
|
+
export async function createBackup(ip, serverName, provider) {
|
|
262
|
+
assertValidIp(ip);
|
|
263
|
+
try {
|
|
264
|
+
// Step 1: Get Coolify version (best-effort)
|
|
265
|
+
const versionResult = await sshExec(ip, buildCoolifyVersionCommand());
|
|
266
|
+
const coolifyVersion = versionResult.code === 0 ? versionResult.stdout.trim() : "unknown";
|
|
267
|
+
// Step 2: Database backup
|
|
268
|
+
const dbResult = await sshExec(ip, buildPgDumpCommand());
|
|
269
|
+
if (dbResult.code !== 0) {
|
|
270
|
+
return {
|
|
271
|
+
success: false,
|
|
272
|
+
error: "Database backup failed",
|
|
273
|
+
hint: sanitizeStderr(dbResult.stderr) || undefined,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
// Step 3: Config backup
|
|
277
|
+
const configResult = await sshExec(ip, buildConfigTarCommand());
|
|
278
|
+
if (configResult.code !== 0) {
|
|
279
|
+
return {
|
|
280
|
+
success: false,
|
|
281
|
+
error: "Config backup failed",
|
|
282
|
+
hint: sanitizeStderr(configResult.stderr) || undefined,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
// Step 4: Create local directory and download
|
|
286
|
+
const timestamp = formatTimestamp(new Date());
|
|
287
|
+
const backupPath = join(getBackupDir(serverName), timestamp);
|
|
288
|
+
mkdirSync(backupPath, { recursive: true, mode: 0o700 });
|
|
289
|
+
const dbDl = await scpDownload(ip, "/tmp/coolify-backup.sql.gz", join(backupPath, "coolify-backup.sql.gz"));
|
|
290
|
+
if (dbDl.code !== 0) {
|
|
291
|
+
return { success: false, error: "Failed to download database backup", hint: sanitizeStderr(dbDl.stderr) || undefined };
|
|
292
|
+
}
|
|
293
|
+
const configDl = await scpDownload(ip, "/tmp/coolify-config.tar.gz", join(backupPath, "coolify-config.tar.gz"));
|
|
294
|
+
if (configDl.code !== 0) {
|
|
295
|
+
return { success: false, error: "Failed to download config backup", hint: sanitizeStderr(configDl.stderr) || undefined };
|
|
296
|
+
}
|
|
297
|
+
// Step 5: Write manifest
|
|
298
|
+
const manifest = {
|
|
299
|
+
serverName,
|
|
300
|
+
provider,
|
|
301
|
+
timestamp,
|
|
302
|
+
coolifyVersion,
|
|
303
|
+
files: ["coolify-backup.sql.gz", "coolify-config.tar.gz"],
|
|
304
|
+
};
|
|
305
|
+
writeFileSync(join(backupPath, "manifest.json"), JSON.stringify(manifest, null, 2), { mode: 0o600 });
|
|
306
|
+
// Step 6: Cleanup remote (best-effort)
|
|
307
|
+
await sshExec(ip, buildCleanupCommand()).catch(() => { });
|
|
308
|
+
return { success: true, backupPath, manifest };
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
const hint = mapSshError(error, ip);
|
|
312
|
+
return {
|
|
313
|
+
success: false,
|
|
314
|
+
error: getErrorMessage(error),
|
|
315
|
+
...(hint ? { hint } : {}),
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
export async function restoreBackup(ip, serverName, backupId) {
|
|
320
|
+
assertValidIp(ip);
|
|
321
|
+
const baseDir = getBackupDir(serverName);
|
|
322
|
+
const backupPath = join(baseDir, backupId);
|
|
323
|
+
// Path traversal guard
|
|
324
|
+
if (!resolve(backupPath).startsWith(resolve(baseDir))) {
|
|
325
|
+
return { success: false, steps: [], error: "Invalid backupId: path traversal detected" };
|
|
326
|
+
}
|
|
327
|
+
const steps = [];
|
|
328
|
+
// Validate manifest
|
|
329
|
+
const manifest = loadManifest(backupPath);
|
|
330
|
+
if (!manifest) {
|
|
331
|
+
return {
|
|
332
|
+
success: false,
|
|
333
|
+
steps,
|
|
334
|
+
error: `Backup not found or corrupt: ${backupId}`,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
// Verify backup files exist
|
|
338
|
+
for (const file of manifest.files) {
|
|
339
|
+
if (!existsSync(join(backupPath, file))) {
|
|
340
|
+
return {
|
|
341
|
+
success: false,
|
|
342
|
+
steps,
|
|
343
|
+
error: `Missing backup file: ${file}`,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
// Upload backup files (before stopping Coolify — safe to fail here)
|
|
349
|
+
const dbUpload = await scpUpload(ip, join(backupPath, "coolify-backup.sql.gz"), "/tmp/coolify-backup.sql.gz");
|
|
350
|
+
if (dbUpload.code !== 0) {
|
|
351
|
+
return {
|
|
352
|
+
success: false,
|
|
353
|
+
steps: [{ name: "Upload database backup", status: "failure", error: sanitizeStderr(dbUpload.stderr) }],
|
|
354
|
+
error: "Failed to upload database backup",
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
const configUpload = await scpUpload(ip, join(backupPath, "coolify-config.tar.gz"), "/tmp/coolify-config.tar.gz");
|
|
358
|
+
if (configUpload.code !== 0) {
|
|
359
|
+
return {
|
|
360
|
+
success: false,
|
|
361
|
+
steps: [{ name: "Upload config backup", status: "failure", error: sanitizeStderr(configUpload.stderr) }],
|
|
362
|
+
error: "Failed to upload config backup",
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
// Step 1: Stop Coolify
|
|
366
|
+
const stopResult = await sshExec(ip, buildStopCoolifyCommand());
|
|
367
|
+
if (stopResult.code !== 0) {
|
|
368
|
+
steps.push({ name: "Stop Coolify", status: "failure", error: sanitizeStderr(stopResult.stderr) });
|
|
369
|
+
return { success: false, steps, error: "Failed to stop Coolify" };
|
|
370
|
+
}
|
|
371
|
+
steps.push({ name: "Stop Coolify", status: "success" });
|
|
372
|
+
// Step 2: Start DB only
|
|
373
|
+
const dbStartResult = await sshExec(ip, buildStartDbCommand());
|
|
374
|
+
if (dbStartResult.code !== 0) {
|
|
375
|
+
steps.push({ name: "Start database", status: "failure", error: sanitizeStderr(dbStartResult.stderr) });
|
|
376
|
+
await tryRestartCoolify(ip);
|
|
377
|
+
return { success: false, steps, error: "Failed to start database" };
|
|
378
|
+
}
|
|
379
|
+
steps.push({ name: "Start database", status: "success" });
|
|
380
|
+
// Step 3: Restore database
|
|
381
|
+
const restoreDbResult = await sshExec(ip, buildRestoreDbCommand());
|
|
382
|
+
if (restoreDbResult.code !== 0) {
|
|
383
|
+
steps.push({ name: "Restore database", status: "failure", error: sanitizeStderr(restoreDbResult.stderr) });
|
|
384
|
+
await tryRestartCoolify(ip);
|
|
385
|
+
return { success: false, steps, error: "Database restore failed" };
|
|
386
|
+
}
|
|
387
|
+
steps.push({ name: "Restore database", status: "success" });
|
|
388
|
+
// Step 4: Restore config
|
|
389
|
+
const restoreConfigResult = await sshExec(ip, buildRestoreConfigCommand());
|
|
390
|
+
if (restoreConfigResult.code !== 0) {
|
|
391
|
+
steps.push({ name: "Restore config", status: "failure", error: sanitizeStderr(restoreConfigResult.stderr) });
|
|
392
|
+
await tryRestartCoolify(ip);
|
|
393
|
+
return { success: false, steps, error: "Config restore failed" };
|
|
394
|
+
}
|
|
395
|
+
steps.push({ name: "Restore config", status: "success" });
|
|
396
|
+
// Step 5: Start Coolify
|
|
397
|
+
const startResult = await sshExec(ip, buildStartCoolifyCommand());
|
|
398
|
+
if (startResult.code !== 0) {
|
|
399
|
+
steps.push({ name: "Start Coolify", status: "failure", error: sanitizeStderr(startResult.stderr) });
|
|
400
|
+
return { success: false, steps, error: "Failed to start Coolify" };
|
|
401
|
+
}
|
|
402
|
+
steps.push({ name: "Start Coolify", status: "success" });
|
|
403
|
+
// Cleanup remote (best-effort)
|
|
404
|
+
await sshExec(ip, buildCleanupCommand()).catch(() => { });
|
|
405
|
+
return { success: true, steps };
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
const hint = mapSshError(error, ip);
|
|
409
|
+
return {
|
|
410
|
+
success: false,
|
|
411
|
+
steps,
|
|
412
|
+
error: getErrorMessage(error),
|
|
413
|
+
...(hint ? { hint } : {}),
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
//# sourceMappingURL=backup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup.js","sourceRoot":"","sources":["../../src/core/backup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC7F,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGvF,gFAAgF;AAEhF,MAAM,UAAU,eAAe,CAAC,IAAU;IACxC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,OAAO,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,0FAA0F,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,8MAA8M,CAAC;AACxN,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,6DAA6D,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO,iGAAiG,CAAC;AAC3G,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,uBAAuB;IACrC,OAAO,iGAAiG,CAAC;AAC3G,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,OAAO,kGAAkG,CAAC;AAC5G,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,sHAAsH,CAAC;AAChI,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,6FAA6F,CAAC;AACvG,CAAC;AAED,MAAM,UAAU,yBAAyB;IACvC,OAAO,4DAA4D,CAAC;AACtE,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,WAAW,CAAC,UAAkB;IAC5C,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,GAAG,CAAC;aACpB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC;aAC9D,IAAI,EAAE;aACN,OAAO,EAAE,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;IACvD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,SAAS,CAAC;IAChD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,iBAA2B;IAC3D,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,WAAW,CAAC;aAC5B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YACf,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACzC,sDAAsD;YACtD,OAAO,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACnE,CAAC,CAAC;aACD,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,UAAkB;IACrD,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IACvC,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,oFAAoF;IACpF,IAAI,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,WAAW,CACzB,EAAU,EACV,UAAkB,EAClB,SAAiB;IAEjB,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,cAAc,CAAC,UAAU,CAAC,CAAC;IAC3B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,KAAK,CACjB,KAAK,EACL,CAAC,IAAI,EAAE,kCAAkC,EAAE,QAAQ,EAAE,IAAI,UAAU,EAAE,EAAE,SAAS,CAAC,EACjF,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,CAC5D,CAAC;QACF,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACxC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAClE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,EAAU,EACV,SAAiB,EACjB,UAAkB;IAElB,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,cAAc,CAAC,UAAU,CAAC,CAAC;IAC3B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,KAAK,CACjB,KAAK,EACL,CAAC,IAAI,EAAE,kCAAkC,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,UAAU,EAAE,CAAC,EACjF,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,CAC5D,CAAC;QACF,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACxC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAClE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,yBAAyB;IACvC,OAAO,CACL,uDAAuD;QACvD,OAAO;QACP,YAAY;QACZ,sBAAsB;QACtB,UAAU;QACV,eAAe;QACf,cAAc;QACd,2CAA2C;QAC3C,8FAA8F,CAC/F,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,6BAA6B;IAC3C,OAAO,sCAAsC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,OAAO,+BAA+B,CAAC;AACzC,CAAC;AAED,iFAAiF;AAEjF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,EAAU,EACV,UAAkB,EAClB,QAAgB;IAEhB,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,IAAI,CAAC;QACH,0CAA0C;QAC1C,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,yBAAyB,EAAE,CAAC,CAAC;QACpE,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,sBAAsB;gBAC7B,IAAI,EAAE,cAAc,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS;aACvD,CAAC;QACJ,CAAC;QAED,mBAAmB;QACnB,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,CAAC;QAC7D,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAExD,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,yBAAyB,EAAE,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACpG,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,kCAAkC;gBACzC,IAAI,EAAE,cAAc,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,SAAS;aAC7C,CAAC;QACJ,CAAC;QAED,yBAAyB;QACzB,MAAM,QAAQ,GAAmB;YAC/B,UAAU;YACV,QAAQ;YACR,SAAS;YACT,cAAc,EAAE,KAAK;YACrB,KAAK,EAAE,CAAC,oBAAoB,CAAC;YAC7B,IAAI,EAAE,MAAM;SACb,CAAC;QACF,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAErG,yBAAyB;QACzB,MAAM,OAAO,CAAC,EAAE,EAAE,uBAAuB,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAE7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IACjD,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC;YAC7B,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1B,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,EAAU,EACV,UAAkB,EAClB,QAAgB;IAEhB,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAE3C,uBAAuB;IACvB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QACtD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,2CAA2C,EAAE,CAAC;IAC3F,CAAC;IAED,MAAM,KAAK,GAA2E,EAAE,CAAC;IAEzF,MAAM,QAAQ,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,gCAAgC,QAAQ,EAAE,EAAE,CAAC;IACtF,CAAC;IAED,4BAA4B;IAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC;IACrF,CAAC;IAED,IAAI,CAAC;QACH,wBAAwB;QACxB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,yBAAyB,CAAC,CAAC;QAC1E,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3F,KAAK,EAAE,eAAe;aACvB,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAEzD,iBAAiB;QACjB,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,6BAA6B,EAAE,CAAC,CAAC;QACzE,IAAI,aAAa,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACvG,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;QACnE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAE1D,UAAU;QACV,MAAM,OAAO,CAAC,EAAE,EAAE,uBAAuB,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAE7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK;YACL,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC;YAC7B,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1B,CAAC;IACJ,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EAAU;IAChD,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,EAAE,EAAE,wBAAwB,EAAE,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,+BAA+B;IACjC,CAAC;AACH,CAAC;AAmBD,+EAA+E;AAE/E,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,EAAU,EACV,UAAkB,EAClB,QAAgB;IAEhB,aAAa,CAAC,EAAE,CAAC,CAAC;IAElB,IAAI,CAAC;QACH,4CAA4C;QAC5C,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACtE,MAAM,cAAc,GAAG,aAAa,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAE1F,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,kBAAkB,EAAE,CAAC,CAAC;QACzD,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,wBAAwB;gBAC/B,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,SAAS;aACnD,CAAC;QACJ,CAAC;QAED,wBAAwB;QACxB,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAChE,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,sBAAsB;gBAC7B,IAAI,EAAE,cAAc,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS;aACvD,CAAC;QACJ,CAAC;QAED,8CAA8C;QAC9C,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,CAAC;QAC7D,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAExD,MAAM,IAAI,GAAG,MAAM,WAAW,CAC5B,EAAE,EACF,4BAA4B,EAC5B,IAAI,CAAC,UAAU,EAAE,uBAAuB,CAAC,CAC1C,CAAC;QACF,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,oCAAoC,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QACzH,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,WAAW,CAChC,EAAE,EACF,4BAA4B,EAC5B,IAAI,CAAC,UAAU,EAAE,uBAAuB,CAAC,CAC1C,CAAC;QACF,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,EAAE,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC3H,CAAC;QAED,yBAAyB;QACzB,MAAM,QAAQ,GAAmB;YAC/B,UAAU;YACV,QAAQ;YACR,SAAS;YACT,cAAc;YACd,KAAK,EAAE,CAAC,uBAAuB,EAAE,uBAAuB,CAAC;SAC1D,CAAC;QACF,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAErG,uCAAuC;QACvC,MAAM,OAAO,CAAC,EAAE,EAAE,mBAAmB,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEzD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IACjD,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC;YAC7B,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1B,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,EAAU,EACV,UAAkB,EAClB,QAAgB;IAEhB,aAAa,CAAC,EAAE,CAAC,CAAC;IAElB,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAE3C,uBAAuB;IACvB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QACtD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,2CAA2C,EAAE,CAAC;IAC3F,CAAC;IAED,MAAM,KAAK,GAA2E,EAAE,CAAC;IAEzF,oBAAoB;IACpB,MAAM,QAAQ,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK;YACL,KAAK,EAAE,gCAAgC,QAAQ,EAAE;SAClD,CAAC;IACJ,CAAC;IAED,4BAA4B;IAC5B,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;YACxC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK;gBACL,KAAK,EAAE,wBAAwB,IAAI,EAAE;aACtC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,oEAAoE;QACpE,MAAM,QAAQ,GAAG,MAAM,SAAS,CAC9B,EAAE,EACF,IAAI,CAAC,UAAU,EAAE,uBAAuB,CAAC,EACzC,4BAA4B,CAC7B,CAAC;QACF,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,wBAAwB,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtG,KAAK,EAAE,kCAAkC;aAC1C,CAAC;QACJ,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,SAAS,CAClC,EAAE,EACF,IAAI,CAAC,UAAU,EAAE,uBAAuB,CAAC,EACzC,4BAA4B,CAC7B,CAAC;QACF,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;gBACxG,KAAK,EAAE,gCAAgC;aACxC,CAAC;QACJ,CAAC;QAED,uBAAuB;QACvB,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAChE,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAClG,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC;QACpE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAExD,wBAAwB;QACxB,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAC/D,IAAI,aAAa,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACvG,MAAM,iBAAiB,CAAC,EAAE,CAAC,CAAC;YAC5B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC;QACtE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAE1D,2BAA2B;QAC3B,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,qBAAqB,EAAE,CAAC,CAAC;QACnE,IAAI,eAAe,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC3G,MAAM,iBAAiB,CAAC,EAAE,CAAC,CAAC;YAC5B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;QACrE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAE5D,yBAAyB;QACzB,MAAM,mBAAmB,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,yBAAyB,EAAE,CAAC,CAAC;QAC3E,IAAI,mBAAmB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC7G,MAAM,iBAAiB,CAAC,EAAE,CAAC,CAAC;YAC5B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;QACnE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAE1D,wBAAwB;QACxB,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,wBAAwB,EAAE,CAAC,CAAC;QAClE,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACpG,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;QACrE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAEzD,+BAA+B;QAC/B,MAAM,OAAO,CAAC,EAAE,EAAE,mBAAmB,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEzD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK;YACL,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC;YAC7B,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1B,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare function isValidDomain(domain: string): boolean;
|
|
2
|
+
export declare function sanitizeDomain(input: string): string;
|
|
3
|
+
export declare function escapePsqlString(input: string): string;
|
|
4
|
+
export declare function buildSetFqdnCommand(domain: string, ssl: boolean): string;
|
|
5
|
+
export declare function buildGetFqdnCommand(): string;
|
|
6
|
+
export declare function buildCoolifyCheckCommand(): string;
|
|
7
|
+
export declare function buildDnsCheckCommand(domain: string): string;
|
|
8
|
+
export declare function parseDnsResult(stdout: string): string | null;
|
|
9
|
+
export declare function parseFqdn(stdout: string): string | null;
|
|
10
|
+
export interface DomainResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
hint?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface DomainInfoResult {
|
|
16
|
+
fqdn: string | null;
|
|
17
|
+
error?: string;
|
|
18
|
+
hint?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface DnsCheckResult {
|
|
21
|
+
resolvedIp: string | null;
|
|
22
|
+
match: boolean;
|
|
23
|
+
error?: string;
|
|
24
|
+
hint?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function setDomain(ip: string, domain: string, ssl?: boolean): Promise<DomainResult>;
|
|
27
|
+
export declare function removeDomain(ip: string): Promise<DomainResult>;
|
|
28
|
+
export declare function getDomain(ip: string): Promise<DomainInfoResult>;
|
|
29
|
+
export declare function checkDns(ip: string, domain: string): Promise<DnsCheckResult>;
|
|
30
|
+
//# sourceMappingURL=domain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../src/core/domain.ts"],"names":[],"mappings":"AAWA,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAUxE;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG5D;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIvD;AAID,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,wBAAsB,SAAS,CAC7B,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,GAAG,GAAE,OAAc,GAClB,OAAO,CAAC,YAAY,CAAC,CAoCvB;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA+BpE;AAED,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqBrE;AAED,wBAAsB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAoClF"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { sshExec, assertValidIp } from "../utils/ssh.js";
|
|
2
|
+
import { getErrorMessage, mapSshError } from "../utils/errorMapper.js";
|
|
3
|
+
import { COOLIFY_SOURCE_DIR, COOLIFY_DB_CONTAINER, COOLIFY_DB_USER, COOLIFY_DB_NAME, } from "../constants.js";
|
|
4
|
+
// ─── Pure Functions ─────────────────────────────────────────────────────────
|
|
5
|
+
export function isValidDomain(domain) {
|
|
6
|
+
const pattern = /^(?!-)[a-zA-Z0-9-]{1,63}(?<!-)(\.[a-zA-Z0-9-]{1,63})*\.[a-zA-Z]{2,}$/;
|
|
7
|
+
return pattern.test(domain);
|
|
8
|
+
}
|
|
9
|
+
export function sanitizeDomain(input) {
|
|
10
|
+
let domain = input.trim();
|
|
11
|
+
domain = domain.replace(/^https?:\/\//, "");
|
|
12
|
+
domain = domain.replace(/\/+$/, "");
|
|
13
|
+
domain = domain.replace(/:\d+$/, "");
|
|
14
|
+
return domain;
|
|
15
|
+
}
|
|
16
|
+
export function escapePsqlString(input) {
|
|
17
|
+
return input.replace(/'/g, "''");
|
|
18
|
+
}
|
|
19
|
+
export function buildSetFqdnCommand(domain, ssl) {
|
|
20
|
+
if (/[^a-zA-Z0-9.:_-]/.test(domain)) {
|
|
21
|
+
throw new Error(`Invalid domain for FQDN command: ${domain}`);
|
|
22
|
+
}
|
|
23
|
+
const protocol = ssl ? "https" : "http";
|
|
24
|
+
const url = escapePsqlString(`${protocol}://${domain}`);
|
|
25
|
+
return [
|
|
26
|
+
`docker exec ${COOLIFY_DB_CONTAINER} psql -U ${COOLIFY_DB_USER} -d ${COOLIFY_DB_NAME} -c "UPDATE instance_settings SET fqdn='${url}' WHERE id=0;"`,
|
|
27
|
+
`cd ${COOLIFY_SOURCE_DIR} && docker compose -f docker-compose.yml -f docker-compose.prod.yml restart coolify`,
|
|
28
|
+
].join(" && ");
|
|
29
|
+
}
|
|
30
|
+
export function buildGetFqdnCommand() {
|
|
31
|
+
return `docker exec ${COOLIFY_DB_CONTAINER} psql -U ${COOLIFY_DB_USER} -d ${COOLIFY_DB_NAME} -t -c "SELECT fqdn FROM instance_settings WHERE id=0;"`;
|
|
32
|
+
}
|
|
33
|
+
export function buildCoolifyCheckCommand() {
|
|
34
|
+
return `docker ps --filter name=${COOLIFY_DB_CONTAINER} --format '{{.Names}}' 2>/dev/null`;
|
|
35
|
+
}
|
|
36
|
+
export function buildDnsCheckCommand(domain) {
|
|
37
|
+
const safeDomain = domain.replace(/[^a-zA-Z0-9.-]/g, "");
|
|
38
|
+
return `dig +short A ${safeDomain} 2>/dev/null || getent ahosts ${safeDomain} 2>/dev/null | head -1 | awk '{print $1}'`;
|
|
39
|
+
}
|
|
40
|
+
export function parseDnsResult(stdout) {
|
|
41
|
+
const ipMatch = stdout.match(/\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b/);
|
|
42
|
+
return ipMatch ? ipMatch[1] : null;
|
|
43
|
+
}
|
|
44
|
+
export function parseFqdn(stdout) {
|
|
45
|
+
const trimmed = stdout.trim();
|
|
46
|
+
if (!trimmed)
|
|
47
|
+
return null;
|
|
48
|
+
return trimmed;
|
|
49
|
+
}
|
|
50
|
+
// ─── Async Wrappers ─────────────────────────────────────────────────────────
|
|
51
|
+
export async function setDomain(ip, domain, ssl = true) {
|
|
52
|
+
assertValidIp(ip);
|
|
53
|
+
const cleanDomain = sanitizeDomain(domain);
|
|
54
|
+
if (!isValidDomain(cleanDomain)) {
|
|
55
|
+
return { success: false, error: `Invalid domain: ${cleanDomain}` };
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
// Check if coolify-db container is running
|
|
59
|
+
const checkResult = await sshExec(ip, buildCoolifyCheckCommand());
|
|
60
|
+
if (!checkResult.stdout.includes(COOLIFY_DB_CONTAINER)) {
|
|
61
|
+
return {
|
|
62
|
+
success: false,
|
|
63
|
+
error: "Coolify database container not found. Is Coolify installed and running?",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const command = buildSetFqdnCommand(cleanDomain, ssl);
|
|
67
|
+
const result = await sshExec(ip, command);
|
|
68
|
+
if (result.code !== 0) {
|
|
69
|
+
return {
|
|
70
|
+
success: false,
|
|
71
|
+
error: `Failed to set domain (exit code ${result.code})`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { success: true };
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const hint = mapSshError(error, ip);
|
|
78
|
+
return {
|
|
79
|
+
success: false,
|
|
80
|
+
error: getErrorMessage(error),
|
|
81
|
+
...(hint ? { hint } : {}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export async function removeDomain(ip) {
|
|
86
|
+
assertValidIp(ip);
|
|
87
|
+
try {
|
|
88
|
+
// Check if coolify-db container is running
|
|
89
|
+
const checkResult = await sshExec(ip, buildCoolifyCheckCommand());
|
|
90
|
+
if (!checkResult.stdout.includes(COOLIFY_DB_CONTAINER)) {
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
error: "Coolify database container not found. Is Coolify installed and running?",
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const command = buildSetFqdnCommand(`${ip}:8000`, false);
|
|
97
|
+
const result = await sshExec(ip, command);
|
|
98
|
+
if (result.code !== 0) {
|
|
99
|
+
return {
|
|
100
|
+
success: false,
|
|
101
|
+
error: `Failed to remove domain (exit code ${result.code})`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return { success: true };
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
const hint = mapSshError(error, ip);
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
error: getErrorMessage(error),
|
|
111
|
+
...(hint ? { hint } : {}),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export async function getDomain(ip) {
|
|
116
|
+
assertValidIp(ip);
|
|
117
|
+
try {
|
|
118
|
+
const result = await sshExec(ip, buildGetFqdnCommand());
|
|
119
|
+
if (result.code !== 0) {
|
|
120
|
+
return {
|
|
121
|
+
fqdn: null,
|
|
122
|
+
error: `Failed to get domain (exit code ${result.code})`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return { fqdn: parseFqdn(result.stdout) };
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
const hint = mapSshError(error, ip);
|
|
129
|
+
return {
|
|
130
|
+
fqdn: null,
|
|
131
|
+
error: getErrorMessage(error),
|
|
132
|
+
...(hint ? { hint } : {}),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export async function checkDns(ip, domain) {
|
|
137
|
+
assertValidIp(ip);
|
|
138
|
+
const cleanDomain = sanitizeDomain(domain);
|
|
139
|
+
if (!isValidDomain(cleanDomain)) {
|
|
140
|
+
return { resolvedIp: null, match: false, error: `Invalid domain: ${cleanDomain}` };
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const result = await sshExec(ip, buildDnsCheckCommand(cleanDomain));
|
|
144
|
+
const resolvedIp = parseDnsResult(result.stdout);
|
|
145
|
+
if (!resolvedIp) {
|
|
146
|
+
return {
|
|
147
|
+
resolvedIp: null,
|
|
148
|
+
match: false,
|
|
149
|
+
hint: `No A record found for ${cleanDomain}. Add an A record pointing to ${ip}`,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
resolvedIp,
|
|
154
|
+
match: resolvedIp === ip,
|
|
155
|
+
...(resolvedIp !== ip
|
|
156
|
+
? { hint: `DNS mismatch: ${cleanDomain} → ${resolvedIp} (expected ${ip}). Update your A record.` }
|
|
157
|
+
: {}),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
const hint = mapSshError(error, ip);
|
|
162
|
+
return {
|
|
163
|
+
resolvedIp: null,
|
|
164
|
+
match: false,
|
|
165
|
+
error: getErrorMessage(error),
|
|
166
|
+
...(hint ? { hint } : {}),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=domain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain.js","sourceRoot":"","sources":["../../src/core/domain.ts"],"names":[],"mappings":"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"}
|