quicklify 1.0.4 → 1.1.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/README.md +42 -5
- package/README.tr.md +42 -5
- package/SECURITY.md +42 -9
- package/bin/quicklify-mcp +5 -0
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +30 -10
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +2 -1
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/destroy.js +2 -2
- package/dist/commands/destroy.js.map +1 -1
- package/dist/commands/domain.d.ts.map +1 -1
- package/dist/commands/domain.js +17 -4
- package/dist/commands/domain.js.map +1 -1
- package/dist/commands/firewall.d.ts.map +1 -1
- package/dist/commands/firewall.js +21 -5
- package/dist/commands/firewall.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +50 -18
- package/dist/commands/init.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 +6 -11
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/maintain.d.ts.map +1 -1
- package/dist/commands/maintain.js +18 -5
- 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 +7 -48
- package/dist/commands/monitor.js.map +1 -1
- package/dist/commands/restart.d.ts.map +1 -1
- package/dist/commands/restart.js +5 -1
- package/dist/commands/restart.js.map +1 -1
- package/dist/commands/restore.d.ts.map +1 -1
- package/dist/commands/restore.js +25 -6
- package/dist/commands/restore.js.map +1 -1
- package/dist/commands/secure.d.ts.map +1 -1
- package/dist/commands/secure.js +17 -4
- package/dist/commands/secure.js.map +1 -1
- package/dist/commands/snapshot.d.ts.map +1 -1
- package/dist/commands/snapshot.js +19 -8
- 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 +34 -76
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/transfer.d.ts.map +1 -1
- package/dist/commands/transfer.js +9 -2
- package/dist/commands/transfer.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +9 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/core/backup.d.ts +43 -0
- package/dist/core/backup.d.ts.map +1 -0
- package/dist/core/backup.js +259 -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 +174 -0
- package/dist/core/domain.js.map +1 -0
- package/dist/core/firewall.d.ts +25 -0
- package/dist/core/firewall.d.ts.map +1 -0
- package/dist/core/firewall.js +146 -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 +180 -0
- package/dist/core/maintain.js.map +1 -0
- package/dist/core/manage.d.ts +34 -0
- package/dist/core/manage.d.ts.map +1 -0
- package/dist/core/manage.js +203 -0
- package/dist/core/manage.js.map +1 -0
- package/dist/core/provision.d.ts +18 -0
- package/dist/core/provision.d.ts.map +1 -0
- package/dist/core/provision.js +197 -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 +198 -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 +43 -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/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 +105 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/serverBackup.d.ts +29 -0
- package/dist/mcp/tools/serverBackup.d.ts.map +1 -0
- package/dist/mcp/tools/serverBackup.js +376 -0
- package/dist/mcp/tools/serverBackup.js.map +1 -0
- package/dist/mcp/tools/serverInfo.d.ts +20 -0
- package/dist/mcp/tools/serverInfo.d.ts.map +1 -0
- package/dist/mcp/tools/serverInfo.js +219 -0
- package/dist/mcp/tools/serverInfo.js.map +1 -0
- package/dist/mcp/tools/serverLogs.d.ts +30 -0
- package/dist/mcp/tools/serverLogs.d.ts.map +1 -0
- package/dist/mcp/tools/serverLogs.js +145 -0
- package/dist/mcp/tools/serverLogs.js.map +1 -0
- package/dist/mcp/tools/serverMaintain.d.ts +22 -0
- package/dist/mcp/tools/serverMaintain.d.ts.map +1 -0
- package/dist/mcp/tools/serverMaintain.js +217 -0
- package/dist/mcp/tools/serverMaintain.js.map +1 -0
- package/dist/mcp/tools/serverManage.d.ts +33 -0
- package/dist/mcp/tools/serverManage.d.ts.map +1 -0
- package/dist/mcp/tools/serverManage.js +207 -0
- package/dist/mcp/tools/serverManage.js.map +1 -0
- package/dist/mcp/tools/serverProvision.d.ts +31 -0
- package/dist/mcp/tools/serverProvision.d.ts.map +1 -0
- package/dist/mcp/tools/serverProvision.js +125 -0
- package/dist/mcp/tools/serverProvision.js.map +1 -0
- package/dist/mcp/tools/serverSecure.d.ts +40 -0
- package/dist/mcp/tools/serverSecure.d.ts.map +1 -0
- package/dist/mcp/tools/serverSecure.js +396 -0
- package/dist/mcp/tools/serverSecure.js.map +1 -0
- package/dist/providers/vultr.d.ts.map +1 -1
- package/dist/providers/vultr.js +7 -1
- package/dist/providers/vultr.js.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/errorMapper.d.ts +4 -0
- package/dist/utils/errorMapper.d.ts.map +1 -1
- package/dist/utils/errorMapper.js +93 -0
- package/dist/utils/errorMapper.js.map +1 -1
- package/dist/utils/openBrowser.d.ts.map +1 -1
- package/dist/utils/openBrowser.js +6 -1
- package/dist/utils/openBrowser.js.map +1 -1
- package/dist/utils/ssh.d.ts +1 -0
- package/dist/utils/ssh.d.ts.map +1 -1
- package/dist/utils/ssh.js +6 -2
- package/dist/utils/ssh.js.map +1 -1
- package/package.json +6 -3
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { isValidProvider, validateServerName } from "./manage.js";
|
|
2
|
+
import { getProviderToken } from "./tokens.js";
|
|
3
|
+
import { createProviderWithToken } from "../utils/providerFactory.js";
|
|
4
|
+
import { getCoolifyCloudInit } from "../utils/cloudInit.js";
|
|
5
|
+
import { findLocalSshKey, generateSshKey, getSshKeyName } from "../utils/sshKey.js";
|
|
6
|
+
import { saveServer } from "../utils/config.js";
|
|
7
|
+
import { getTemplateDefaults } from "../utils/templates.js";
|
|
8
|
+
import { getErrorMessage, mapProviderError } from "../utils/errorMapper.js";
|
|
9
|
+
import { assertValidIp } from "../utils/ssh.js";
|
|
10
|
+
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
11
|
+
// TODO: v1.2.0'da init.ts ile birleştirilecek — ortak modüle taşı
|
|
12
|
+
const IP_WAIT = {
|
|
13
|
+
hetzner: { attempts: 10, interval: 3000 }, // 30s
|
|
14
|
+
digitalocean: { attempts: 20, interval: 3000 }, // 60s
|
|
15
|
+
vultr: { attempts: 40, interval: 5000 }, // 200s
|
|
16
|
+
linode: { attempts: 30, interval: 5000 }, // 150s
|
|
17
|
+
};
|
|
18
|
+
const BOOT_MAX_ATTEMPTS = 30;
|
|
19
|
+
const BOOT_INTERVAL = 1000;
|
|
20
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
21
|
+
function sleep(ms) {
|
|
22
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
23
|
+
}
|
|
24
|
+
function isPendingIp(ip) {
|
|
25
|
+
return !ip || ip === "pending" || ip === "0.0.0.0";
|
|
26
|
+
}
|
|
27
|
+
export async function uploadSshKeyBestEffort(provider) {
|
|
28
|
+
let publicKey = findLocalSshKey();
|
|
29
|
+
if (!publicKey) {
|
|
30
|
+
process.stderr.write("[provision] No local SSH key found. Generating one...\n");
|
|
31
|
+
publicKey = generateSshKey();
|
|
32
|
+
if (!publicKey) {
|
|
33
|
+
process.stderr.write("[provision] SSH key generation failed. Continuing without SSH key.\n");
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
process.stderr.write("[provision] SSH key generated (~/.ssh/id_ed25519)\n");
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const keyId = await provider.uploadSshKey(getSshKeyName(), publicKey);
|
|
40
|
+
return [keyId];
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
process.stderr.write(`[provision] SSH key upload failed: ${getErrorMessage(error)}. Continuing without SSH key.\n`);
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
48
|
+
export async function provisionServer(config) {
|
|
49
|
+
// 1. Validate provider
|
|
50
|
+
if (!isValidProvider(config.provider)) {
|
|
51
|
+
return {
|
|
52
|
+
success: false,
|
|
53
|
+
error: `Invalid provider: ${config.provider}. Valid: hetzner, digitalocean, vultr, linode`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// 2. Validate name
|
|
57
|
+
const nameError = validateServerName(config.name);
|
|
58
|
+
if (nameError) {
|
|
59
|
+
return { success: false, error: nameError };
|
|
60
|
+
}
|
|
61
|
+
// 3. Resolve region/size — explicit params override template defaults
|
|
62
|
+
const template = config.template || "starter";
|
|
63
|
+
const defaults = getTemplateDefaults(template, config.provider);
|
|
64
|
+
const region = config.region || defaults?.region;
|
|
65
|
+
const size = config.size || defaults?.size;
|
|
66
|
+
if (!region || !size) {
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
error: `Could not resolve region/size for provider "${config.provider}" with template "${template}"`,
|
|
70
|
+
hint: "Provide explicit region and size parameters, or use a valid template",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// 4. Resolve token
|
|
74
|
+
const token = getProviderToken(config.provider);
|
|
75
|
+
if (!token) {
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
error: `No API token found for ${config.provider}`,
|
|
79
|
+
hint: `Set ${config.provider.toUpperCase()}_TOKEN environment variable`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
// 5. Create provider instance
|
|
83
|
+
const provider = createProviderWithToken(config.provider, token);
|
|
84
|
+
// 6. Validate token
|
|
85
|
+
try {
|
|
86
|
+
const valid = await provider.validateToken(token);
|
|
87
|
+
if (!valid) {
|
|
88
|
+
return { success: false, error: `Invalid API token for ${config.provider}` };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
error: `Token validation failed: ${getErrorMessage(error)}`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// 7. Upload SSH key (best-effort)
|
|
98
|
+
const sshKeyIds = await uploadSshKeyBestEffort(provider);
|
|
99
|
+
// 8. Generate cloud-init
|
|
100
|
+
const cloudInit = getCoolifyCloudInit(config.name);
|
|
101
|
+
// 9. Create server
|
|
102
|
+
let serverId;
|
|
103
|
+
let serverIp;
|
|
104
|
+
try {
|
|
105
|
+
const result = await provider.createServer({
|
|
106
|
+
name: config.name,
|
|
107
|
+
region,
|
|
108
|
+
size,
|
|
109
|
+
cloudInit,
|
|
110
|
+
sshKeyIds,
|
|
111
|
+
});
|
|
112
|
+
serverId = result.id;
|
|
113
|
+
serverIp = result.ip;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
const message = getErrorMessage(error);
|
|
117
|
+
const hint = mapProviderError(error, config.provider);
|
|
118
|
+
return {
|
|
119
|
+
success: false,
|
|
120
|
+
error: `Server creation failed: ${message}`,
|
|
121
|
+
...(hint ? { hint } : {}),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// 10. Wait for running status
|
|
125
|
+
for (let i = 0; i < BOOT_MAX_ATTEMPTS; i++) {
|
|
126
|
+
try {
|
|
127
|
+
const status = await provider.getServerStatus(serverId);
|
|
128
|
+
if (status === "running")
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Ignore polling errors, retry
|
|
133
|
+
}
|
|
134
|
+
if (i === BOOT_MAX_ATTEMPTS - 1) {
|
|
135
|
+
return {
|
|
136
|
+
success: false,
|
|
137
|
+
error: `Server did not reach running state within ${BOOT_MAX_ATTEMPTS}s`,
|
|
138
|
+
hint: "The server may still be booting. Check status manually.",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
await sleep(BOOT_INTERVAL);
|
|
142
|
+
}
|
|
143
|
+
// 11. Wait for IP assignment (provider-specific timing)
|
|
144
|
+
if (isPendingIp(serverIp)) {
|
|
145
|
+
const ipConfig = IP_WAIT[config.provider] || { attempts: 20, interval: 3000 };
|
|
146
|
+
for (let i = 0; i < ipConfig.attempts; i++) {
|
|
147
|
+
await sleep(ipConfig.interval);
|
|
148
|
+
try {
|
|
149
|
+
const details = await provider.getServerDetails(serverId);
|
|
150
|
+
if (!isPendingIp(details.ip)) {
|
|
151
|
+
try {
|
|
152
|
+
assertValidIp(details.ip);
|
|
153
|
+
serverIp = details.ip;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Invalid IP format, keep polling
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Ignore polling errors, retry
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// Validate the IP we already have
|
|
168
|
+
try {
|
|
169
|
+
assertValidIp(serverIp);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
process.stderr.write(`[provision] IP validation failed for ${serverIp}, marking as pending\n`);
|
|
173
|
+
serverIp = "pending";
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// 12. Save to config
|
|
177
|
+
const record = {
|
|
178
|
+
id: serverId,
|
|
179
|
+
name: config.name,
|
|
180
|
+
provider: config.provider,
|
|
181
|
+
ip: serverIp,
|
|
182
|
+
region,
|
|
183
|
+
size,
|
|
184
|
+
createdAt: new Date().toISOString(),
|
|
185
|
+
};
|
|
186
|
+
saveServer(record);
|
|
187
|
+
// 13. Return result
|
|
188
|
+
if (isPendingIp(serverIp)) {
|
|
189
|
+
return {
|
|
190
|
+
success: true,
|
|
191
|
+
server: record,
|
|
192
|
+
hint: `IP address not yet assigned. Check status with: server_info { action: 'status', server: '${config.name}' }`,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return { success: true, server: record };
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=provision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provision.js","sourceRoot":"","sources":["../../src/core/provision.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SshdSetting, SecureAuditResult } from "../types/index.js";
|
|
2
|
+
export declare function parseSshdConfig(content: string): SshdSetting[];
|
|
3
|
+
export declare function parseAuditResult(stdout: string): SecureAuditResult;
|
|
4
|
+
export declare function buildHardeningCommand(options?: {
|
|
5
|
+
port?: number;
|
|
6
|
+
}): string;
|
|
7
|
+
export declare function buildFail2banCommand(): string;
|
|
8
|
+
export declare function buildAuditCommand(): string;
|
|
9
|
+
export declare function buildKeyCheckCommand(): string;
|
|
10
|
+
export interface SecureSetupResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
sshHardening: boolean;
|
|
13
|
+
fail2ban: boolean;
|
|
14
|
+
sshKeyCount: number;
|
|
15
|
+
error?: string;
|
|
16
|
+
hint?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SecureAuditFullResult {
|
|
19
|
+
audit: SecureAuditResult;
|
|
20
|
+
score: number;
|
|
21
|
+
error?: string;
|
|
22
|
+
hint?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function applySecureSetup(ip: string, options?: {
|
|
25
|
+
port?: number;
|
|
26
|
+
}): Promise<SecureSetupResult>;
|
|
27
|
+
export declare function calculateSecurityScore(audit: SecureAuditResult): number;
|
|
28
|
+
export declare function runSecureAudit(ip: string): Promise<SecureAuditFullResult>;
|
|
29
|
+
//# sourceMappingURL=secure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secure.d.ts","sourceRoot":"","sources":["../../src/core/secure.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAIxE,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CA8B9D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CA8BlE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAezE;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAkB7C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAID,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,iBAAiB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CAwD5B;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAOvE;AAED,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAmC/E"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { sshExec, assertValidIp } from "../utils/ssh.js";
|
|
2
|
+
import { getErrorMessage, mapSshError } from "../utils/errorMapper.js";
|
|
3
|
+
// ─── Pure Functions ─────────────────────────────────────────────────────────
|
|
4
|
+
export function parseSshdConfig(content) {
|
|
5
|
+
const settings = [];
|
|
6
|
+
const checks = [
|
|
7
|
+
{ key: "PasswordAuthentication", secureValue: "no" },
|
|
8
|
+
{ key: "PermitRootLogin", secureValue: "prohibit-password" },
|
|
9
|
+
{ key: "PubkeyAuthentication", secureValue: "yes" },
|
|
10
|
+
{ key: "MaxAuthTries", secureValue: "3" },
|
|
11
|
+
];
|
|
12
|
+
for (const check of checks) {
|
|
13
|
+
const regex = new RegExp(`^\\s*${check.key}\\s+(.+)`, "m");
|
|
14
|
+
const match = content.match(regex);
|
|
15
|
+
if (match) {
|
|
16
|
+
const value = match[1].trim();
|
|
17
|
+
settings.push({
|
|
18
|
+
key: check.key,
|
|
19
|
+
value,
|
|
20
|
+
status: value.toLowerCase() === check.secureValue.toLowerCase() ? "secure" : "insecure",
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
settings.push({
|
|
25
|
+
key: check.key,
|
|
26
|
+
value: "",
|
|
27
|
+
status: "missing",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return settings;
|
|
32
|
+
}
|
|
33
|
+
export function parseAuditResult(stdout) {
|
|
34
|
+
const sections = stdout.split("---SEPARATOR---");
|
|
35
|
+
const sshdContent = sections[0] || "";
|
|
36
|
+
const fail2banStatus = sections[1] || "";
|
|
37
|
+
const sshdSettings = parseSshdConfig(sshdContent);
|
|
38
|
+
const passwordAuth = sshdSettings.find((s) => s.key === "PasswordAuthentication") || {
|
|
39
|
+
key: "PasswordAuthentication",
|
|
40
|
+
value: "",
|
|
41
|
+
status: "missing",
|
|
42
|
+
};
|
|
43
|
+
const rootLogin = sshdSettings.find((s) => s.key === "PermitRootLogin") || {
|
|
44
|
+
key: "PermitRootLogin",
|
|
45
|
+
value: "",
|
|
46
|
+
status: "missing",
|
|
47
|
+
};
|
|
48
|
+
const fail2banInstalled = fail2banStatus.includes("active") || fail2banStatus.includes("inactive");
|
|
49
|
+
const fail2banActive = fail2banStatus.includes("active (running)");
|
|
50
|
+
const portMatch = sshdContent.match(/^\s*Port\s+(\d+)/m);
|
|
51
|
+
const sshPort = portMatch ? parseInt(portMatch[1], 10) : 22;
|
|
52
|
+
return {
|
|
53
|
+
passwordAuth,
|
|
54
|
+
rootLogin,
|
|
55
|
+
fail2ban: { installed: fail2banInstalled, active: fail2banActive },
|
|
56
|
+
sshPort,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function buildHardeningCommand(options) {
|
|
60
|
+
const commands = [
|
|
61
|
+
"cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak",
|
|
62
|
+
`sed -i 's/^#\\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config`,
|
|
63
|
+
`sed -i 's/^#\\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config`,
|
|
64
|
+
`sed -i 's/^#\\?PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config`,
|
|
65
|
+
`sed -i 's/^#\\?MaxAuthTries.*/MaxAuthTries 3/' /etc/ssh/sshd_config`,
|
|
66
|
+
];
|
|
67
|
+
if (options?.port && options.port !== 22) {
|
|
68
|
+
commands.push(`sed -i 's/^#\\?Port.*/Port ${options.port}/' /etc/ssh/sshd_config`);
|
|
69
|
+
}
|
|
70
|
+
commands.push("systemctl restart sshd 2>/dev/null || systemctl restart ssh");
|
|
71
|
+
return commands.join(" && ");
|
|
72
|
+
}
|
|
73
|
+
export function buildFail2banCommand() {
|
|
74
|
+
const jailContent = [
|
|
75
|
+
"[sshd]",
|
|
76
|
+
"enabled = true",
|
|
77
|
+
"port = ssh",
|
|
78
|
+
"filter = sshd",
|
|
79
|
+
"backend = systemd",
|
|
80
|
+
"maxretry = 5",
|
|
81
|
+
"bantime = 3600",
|
|
82
|
+
"findtime = 600",
|
|
83
|
+
].join("\\n");
|
|
84
|
+
return [
|
|
85
|
+
"apt-get install -y fail2ban python3-systemd",
|
|
86
|
+
`printf '${jailContent}\\n' > /etc/fail2ban/jail.local`,
|
|
87
|
+
"systemctl enable fail2ban",
|
|
88
|
+
"systemctl restart fail2ban",
|
|
89
|
+
].join(" && ");
|
|
90
|
+
}
|
|
91
|
+
export function buildAuditCommand() {
|
|
92
|
+
return `cat /etc/ssh/sshd_config && echo '---SEPARATOR---' && systemctl status fail2ban 2>&1 || true`;
|
|
93
|
+
}
|
|
94
|
+
export function buildKeyCheckCommand() {
|
|
95
|
+
return "test -f /root/.ssh/authorized_keys && wc -l < /root/.ssh/authorized_keys || echo 0";
|
|
96
|
+
}
|
|
97
|
+
// ─── Async Wrappers ─────────────────────────────────────────────────────────
|
|
98
|
+
export async function applySecureSetup(ip, options) {
|
|
99
|
+
assertValidIp(ip);
|
|
100
|
+
// Step 1: Check SSH keys
|
|
101
|
+
try {
|
|
102
|
+
const keyResult = await sshExec(ip, buildKeyCheckCommand());
|
|
103
|
+
const keyCount = parseInt(keyResult.stdout.trim(), 10);
|
|
104
|
+
if (isNaN(keyCount) || keyCount === 0) {
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
sshHardening: false,
|
|
108
|
+
fail2ban: false,
|
|
109
|
+
sshKeyCount: 0,
|
|
110
|
+
error: "No SSH keys found in /root/.ssh/authorized_keys. Cannot disable password authentication without SSH keys — this would permanently lock you out.",
|
|
111
|
+
hint: `Add an SSH key first: ssh-copy-id root@${ip}`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
// Step 2: Apply SSH hardening
|
|
115
|
+
const hardenResult = await sshExec(ip, buildHardeningCommand(options));
|
|
116
|
+
if (hardenResult.code !== 0) {
|
|
117
|
+
return {
|
|
118
|
+
success: false,
|
|
119
|
+
sshHardening: false,
|
|
120
|
+
fail2ban: false,
|
|
121
|
+
sshKeyCount: keyCount,
|
|
122
|
+
error: `SSH hardening failed (exit code ${hardenResult.code})`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Step 3: Install fail2ban (non-fatal)
|
|
126
|
+
let fail2banOk = true;
|
|
127
|
+
const f2bResult = await sshExec(ip, buildFail2banCommand());
|
|
128
|
+
if (f2bResult.code !== 0) {
|
|
129
|
+
fail2banOk = false;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
success: true,
|
|
133
|
+
sshHardening: true,
|
|
134
|
+
fail2ban: fail2banOk,
|
|
135
|
+
sshKeyCount: keyCount,
|
|
136
|
+
...(!fail2banOk ? { hint: "Fail2ban installation failed. Retry with secure-setup." } : {}),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
const hint = mapSshError(error, ip);
|
|
141
|
+
return {
|
|
142
|
+
success: false,
|
|
143
|
+
sshHardening: false,
|
|
144
|
+
fail2ban: false,
|
|
145
|
+
sshKeyCount: -1,
|
|
146
|
+
error: getErrorMessage(error),
|
|
147
|
+
...(hint ? { hint } : {}),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export function calculateSecurityScore(audit) {
|
|
152
|
+
let score = 0;
|
|
153
|
+
if (audit.passwordAuth.status === "secure")
|
|
154
|
+
score += 25;
|
|
155
|
+
if (audit.rootLogin.status === "secure")
|
|
156
|
+
score += 25;
|
|
157
|
+
if (audit.fail2ban.active)
|
|
158
|
+
score += 25;
|
|
159
|
+
if (audit.sshPort !== 22)
|
|
160
|
+
score += 25;
|
|
161
|
+
return score;
|
|
162
|
+
}
|
|
163
|
+
export async function runSecureAudit(ip) {
|
|
164
|
+
assertValidIp(ip);
|
|
165
|
+
try {
|
|
166
|
+
const result = await sshExec(ip, buildAuditCommand());
|
|
167
|
+
if (result.code !== 0 && !result.stdout) {
|
|
168
|
+
return {
|
|
169
|
+
audit: {
|
|
170
|
+
passwordAuth: { key: "PasswordAuthentication", value: "", status: "missing" },
|
|
171
|
+
rootLogin: { key: "PermitRootLogin", value: "", status: "missing" },
|
|
172
|
+
fail2ban: { installed: false, active: false },
|
|
173
|
+
sshPort: 22,
|
|
174
|
+
},
|
|
175
|
+
score: 0,
|
|
176
|
+
error: `Audit command failed (exit code ${result.code})`,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const audit = parseAuditResult(result.stdout);
|
|
180
|
+
const score = calculateSecurityScore(audit);
|
|
181
|
+
return { audit, score };
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
const hint = mapSshError(error, ip);
|
|
185
|
+
return {
|
|
186
|
+
audit: {
|
|
187
|
+
passwordAuth: { key: "PasswordAuthentication", value: "", status: "missing" },
|
|
188
|
+
rootLogin: { key: "PermitRootLogin", value: "", status: "missing" },
|
|
189
|
+
fail2ban: { installed: false, active: false },
|
|
190
|
+
sshPort: 22,
|
|
191
|
+
},
|
|
192
|
+
score: 0,
|
|
193
|
+
error: getErrorMessage(error),
|
|
194
|
+
...(hint ? { hint } : {}),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=secure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secure.js","sourceRoot":"","sources":["../../src/core/secure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGvE,+EAA+E;AAE/E,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,MAAM,MAAM,GAA2C;QACrD,EAAE,GAAG,EAAE,wBAAwB,EAAE,WAAW,EAAE,IAAI,EAAE;QACpD,EAAE,GAAG,EAAE,iBAAiB,EAAE,WAAW,EAAE,mBAAmB,EAAE;QAC5D,EAAE,GAAG,EAAE,sBAAsB,EAAE,WAAW,EAAE,KAAK,EAAE;QACnD,EAAE,GAAG,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,EAAE;KAC1C,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,GAAG,UAAU,EAAE,GAAG,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAEnC,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9B,QAAQ,CAAC,IAAI,CAAC;gBACZ,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,KAAK;gBACL,MAAM,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU;aACxF,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC;gBACZ,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,KAAK,EAAE,EAAE;gBACT,MAAM,EAAE,SAAS;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACtC,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,MAAM,YAAY,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAElD,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,wBAAwB,CAAC,IAAI;QACnF,GAAG,EAAE,wBAAwB;QAC7B,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,SAAkB;KAC3B,CAAC;IACF,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,iBAAiB,CAAC,IAAI;QACzE,GAAG,EAAE,iBAAiB;QACtB,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,SAAkB;KAC3B,CAAC;IAEF,MAAM,iBAAiB,GACrB,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC3E,MAAM,cAAc,GAAG,cAAc,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAEnE,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5D,OAAO;QACL,YAAY;QACZ,SAAS;QACT,QAAQ,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,cAAc,EAAE;QAClE,OAAO;KACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAA2B;IAC/D,MAAM,QAAQ,GAAG;QACf,kDAAkD;QAClD,0FAA0F;QAC1F,2FAA2F;QAC3F,uFAAuF;QACvF,qEAAqE;KACtE,CAAC;IAEF,IAAI,OAAO,EAAE,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QACzC,QAAQ,CAAC,IAAI,CAAC,8BAA8B,OAAO,CAAC,IAAI,yBAAyB,CAAC,CAAC;IACrF,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;IAC7E,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,MAAM,WAAW,GAAG;QAClB,QAAQ;QACR,gBAAgB;QAChB,YAAY;QACZ,eAAe;QACf,mBAAmB;QACnB,cAAc;QACd,gBAAgB;QAChB,gBAAgB;KACjB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAEd,OAAO;QACL,6CAA6C;QAC7C,WAAW,WAAW,iCAAiC;QACvD,2BAA2B;QAC3B,4BAA4B;KAC7B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,8FAA8F,CAAC;AACxG,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,oFAAoF,CAAC;AAC9F,CAAC;AAoBD,+EAA+E;AAE/E,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,EAAU,EACV,OAA2B;IAE3B,aAAa,CAAC,EAAE,CAAC,CAAC;IAElB,yBAAyB;IACzB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,oBAAoB,EAAE,CAAC,CAAC;QAC5D,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAEvD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YACtC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,YAAY,EAAE,KAAK;gBACnB,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,CAAC;gBACd,KAAK,EAAE,iJAAiJ;gBACxJ,IAAI,EAAE,0CAA0C,EAAE,EAAE;aACrD,CAAC;QACJ,CAAC;QAED,8BAA8B;QAC9B,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;QACvE,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,YAAY,EAAE,KAAK;gBACnB,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,QAAQ;gBACrB,KAAK,EAAE,mCAAmC,YAAY,CAAC,IAAI,GAAG;aAC/D,CAAC;QACJ,CAAC;QAED,uCAAuC;QACvC,IAAI,UAAU,GAAG,IAAI,CAAC;QACtB,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,oBAAoB,EAAE,CAAC,CAAC;QAC5D,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACzB,UAAU,GAAG,KAAK,CAAC;QACrB,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI;YACb,YAAY,EAAE,IAAI;YAClB,QAAQ,EAAE,UAAU;YACpB,WAAW,EAAE,QAAQ;YACrB,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,wDAAwD,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3F,CAAC;IACJ,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,YAAY,EAAE,KAAK;YACnB,QAAQ,EAAE,KAAK;YACf,WAAW,EAAE,CAAC,CAAC;YACf,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,UAAU,sBAAsB,CAAC,KAAwB;IAC7D,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,KAAK,QAAQ;QAAE,KAAK,IAAI,EAAE,CAAC;IACxD,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,QAAQ;QAAE,KAAK,IAAI,EAAE,CAAC;IACrD,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM;QAAE,KAAK,IAAI,EAAE,CAAC;IACvC,IAAI,KAAK,CAAC,OAAO,KAAK,EAAE;QAAE,KAAK,IAAI,EAAE,CAAC;IACtC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EAAU;IAC7C,aAAa,CAAC,EAAE,CAAC,CAAC;IAElB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC;QACtD,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACxC,OAAO;gBACL,KAAK,EAAE;oBACL,YAAY,EAAE,EAAE,GAAG,EAAE,wBAAwB,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE;oBAC7E,SAAS,EAAE,EAAE,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE;oBACnE,QAAQ,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE;oBAC7C,OAAO,EAAE,EAAE;iBACZ;gBACD,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE,mCAAmC,MAAM,CAAC,IAAI,GAAG;aACzD,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC5C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC1B,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO;YACL,KAAK,EAAE;gBACL,YAAY,EAAE,EAAE,GAAG,EAAE,wBAAwB,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE;gBAC7E,SAAS,EAAE,EAAE,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE;gBACnE,QAAQ,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE;gBAC7C,OAAO,EAAE,EAAE;aACZ;YACD,KAAK,EAAE,CAAC;YACR,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,22 @@
|
|
|
1
|
+
import type { ServerRecord, SnapshotInfo } from "../types/index.js";
|
|
2
|
+
export interface SnapshotCreateResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
snapshot?: SnapshotInfo;
|
|
5
|
+
costEstimate?: string;
|
|
6
|
+
error?: string;
|
|
7
|
+
hint?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SnapshotListResult {
|
|
10
|
+
snapshots: SnapshotInfo[];
|
|
11
|
+
error?: string;
|
|
12
|
+
hint?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SnapshotDeleteResult {
|
|
15
|
+
success: boolean;
|
|
16
|
+
error?: string;
|
|
17
|
+
hint?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function createSnapshot(server: ServerRecord, apiToken: string): Promise<SnapshotCreateResult>;
|
|
20
|
+
export declare function listSnapshots(server: ServerRecord, apiToken: string): Promise<SnapshotListResult>;
|
|
21
|
+
export declare function deleteSnapshot(server: ServerRecord, apiToken: string, snapshotId: string): Promise<SnapshotDeleteResult>;
|
|
22
|
+
//# sourceMappingURL=snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/core/snapshot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIpE,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,wBAAsB,cAAc,CAClC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC,CAwB/B;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC,CAa7B;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAa/B"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { createProviderWithToken } from "../utils/providerFactory.js";
|
|
2
|
+
import { getErrorMessage, mapProviderError } from "../utils/errorMapper.js";
|
|
3
|
+
// ─── Async Wrappers ──────────────────────────────────────────────────────────
|
|
4
|
+
export async function createSnapshot(server, apiToken) {
|
|
5
|
+
try {
|
|
6
|
+
const provider = createProviderWithToken(server.provider, apiToken);
|
|
7
|
+
// Best-effort cost estimate
|
|
8
|
+
let costEstimate;
|
|
9
|
+
try {
|
|
10
|
+
costEstimate = await provider.getSnapshotCostEstimate(server.id);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
costEstimate = "unknown";
|
|
14
|
+
}
|
|
15
|
+
const snapshotName = `quicklify-${Date.now()}`;
|
|
16
|
+
const snapshot = await provider.createSnapshot(server.id, snapshotName);
|
|
17
|
+
return { success: true, snapshot, costEstimate };
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
const hint = mapProviderError(error, server.provider);
|
|
21
|
+
return {
|
|
22
|
+
success: false,
|
|
23
|
+
error: getErrorMessage(error),
|
|
24
|
+
...(hint ? { hint } : {}),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function listSnapshots(server, apiToken) {
|
|
29
|
+
try {
|
|
30
|
+
const provider = createProviderWithToken(server.provider, apiToken);
|
|
31
|
+
const snapshots = await provider.listSnapshots(server.id);
|
|
32
|
+
return { snapshots };
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
const hint = mapProviderError(error, server.provider);
|
|
36
|
+
return {
|
|
37
|
+
snapshots: [],
|
|
38
|
+
error: getErrorMessage(error),
|
|
39
|
+
...(hint ? { hint } : {}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export async function deleteSnapshot(server, apiToken, snapshotId) {
|
|
44
|
+
try {
|
|
45
|
+
const provider = createProviderWithToken(server.provider, apiToken);
|
|
46
|
+
await provider.deleteSnapshot(snapshotId);
|
|
47
|
+
return { success: true };
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
const hint = mapProviderError(error, server.provider);
|
|
51
|
+
return {
|
|
52
|
+
success: false,
|
|
53
|
+
error: getErrorMessage(error),
|
|
54
|
+
...(hint ? { hint } : {}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/core/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAyB5E,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAoB,EACpB,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,uBAAuB,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAEpE,4BAA4B;QAC5B,IAAI,YAAgC,CAAC;QACrC,IAAI,CAAC;YACH,YAAY,GAAG,MAAM,QAAQ,CAAC,uBAAuB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnE,CAAC;QAAC,MAAM,CAAC;YACP,YAAY,GAAG,SAAS,CAAC;QAC3B,CAAC;QAED,MAAM,YAAY,GAAG,aAAa,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;QAExE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IACnD,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACtD,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,MAAoB,EACpB,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,uBAAuB,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACpE,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1D,OAAO,EAAE,SAAS,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACtD,OAAO;YACL,SAAS,EAAE,EAAE;YACb,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,cAAc,CAClC,MAAoB,EACpB,QAAgB,EAChB,UAAkB;IAElB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,uBAAuB,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACpE,MAAM,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACtD,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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ServerRecord } from "../types/index.js";
|
|
2
|
+
export interface StatusResult {
|
|
3
|
+
server: ServerRecord;
|
|
4
|
+
serverStatus: string;
|
|
5
|
+
coolifyStatus: string;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function checkCoolifyHealth(ip: string): Promise<"running" | "not reachable">;
|
|
9
|
+
export declare function getCloudServerStatus(server: ServerRecord, apiToken: string): Promise<string>;
|
|
10
|
+
export declare function checkServerStatus(server: ServerRecord, apiToken: string): Promise<StatusResult>;
|
|
11
|
+
export declare function checkAllServersStatus(servers: ServerRecord[], tokenMap: Map<string, string>): Promise<StatusResult[]>;
|
|
12
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/core/status.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,eAAe,CAAC,CAWzF;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,CAavB;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,YAAY,EAAE,EACvB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,OAAO,CAAC,YAAY,EAAE,CAAC,CAIzB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { createProviderWithToken } from "../utils/providerFactory.js";
|
|
3
|
+
import { getErrorMessage } from "../utils/errorMapper.js";
|
|
4
|
+
import { assertValidIp } from "../utils/ssh.js";
|
|
5
|
+
export async function checkCoolifyHealth(ip) {
|
|
6
|
+
assertValidIp(ip);
|
|
7
|
+
try {
|
|
8
|
+
await axios.get(`http://${ip}:8000`, {
|
|
9
|
+
timeout: 5000,
|
|
10
|
+
validateStatus: () => true,
|
|
11
|
+
});
|
|
12
|
+
return "running";
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return "not reachable";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function getCloudServerStatus(server, apiToken) {
|
|
19
|
+
if (server.id.startsWith("manual-")) {
|
|
20
|
+
return "unknown (manual)";
|
|
21
|
+
}
|
|
22
|
+
const provider = createProviderWithToken(server.provider, apiToken);
|
|
23
|
+
return provider.getServerStatus(server.id);
|
|
24
|
+
}
|
|
25
|
+
export async function checkServerStatus(server, apiToken) {
|
|
26
|
+
try {
|
|
27
|
+
const serverStatus = await getCloudServerStatus(server, apiToken);
|
|
28
|
+
const coolifyStatus = await checkCoolifyHealth(server.ip);
|
|
29
|
+
return { server, serverStatus, coolifyStatus };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return {
|
|
33
|
+
server,
|
|
34
|
+
serverStatus: "error",
|
|
35
|
+
coolifyStatus: "unknown",
|
|
36
|
+
error: getErrorMessage(error),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export async function checkAllServersStatus(servers, tokenMap) {
|
|
41
|
+
return Promise.all(servers.map((s) => checkServerStatus(s, tokenMap.get(s.provider) ?? "")));
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/core/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAUhD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EAAU;IACjD,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE;YACnC,OAAO,EAAE,IAAI;YACb,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI;SAC3B,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAoB,EACpB,QAAgB;IAEhB,IAAI,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IACD,MAAM,QAAQ,GAAG,uBAAuB,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACpE,OAAO,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAoB,EACpB,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAClE,MAAM,aAAa,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1D,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;IACjD,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO;YACL,MAAM;YACN,YAAY,EAAE,OAAO;YACrB,aAAa,EAAE,SAAS;YACxB,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC;SAC9B,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAuB,EACvB,QAA6B;IAE7B,OAAO,OAAO,CAAC,GAAG,CAChB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CACzE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ServerRecord } from "../types/index.js";
|
|
2
|
+
export declare function getProviderToken(provider: string): string | undefined;
|
|
3
|
+
export declare function collectProviderTokensFromEnv(servers: ServerRecord[]): Map<string, string>;
|
|
4
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/core/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAStD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGrE;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,YAAY,EAAE,GACtB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAYrB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const ENV_KEYS = {
|
|
2
|
+
hetzner: "HETZNER_TOKEN",
|
|
3
|
+
digitalocean: "DIGITALOCEAN_TOKEN",
|
|
4
|
+
vultr: "VULTR_TOKEN",
|
|
5
|
+
linode: "LINODE_TOKEN",
|
|
6
|
+
};
|
|
7
|
+
export function getProviderToken(provider) {
|
|
8
|
+
const envKey = ENV_KEYS[provider];
|
|
9
|
+
return envKey ? process.env[envKey] : undefined;
|
|
10
|
+
}
|
|
11
|
+
export function collectProviderTokensFromEnv(servers) {
|
|
12
|
+
const tokenMap = new Map();
|
|
13
|
+
const providers = [
|
|
14
|
+
...new Set(servers.filter((s) => !s.id.startsWith("manual-")).map((s) => s.provider)),
|
|
15
|
+
];
|
|
16
|
+
for (const provider of providers) {
|
|
17
|
+
const token = getProviderToken(provider);
|
|
18
|
+
if (token)
|
|
19
|
+
tokenMap.set(provider, token);
|
|
20
|
+
}
|
|
21
|
+
return tokenMap;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/core/tokens.ts"],"names":[],"mappings":"AAEA,MAAM,QAAQ,GAA2B;IACvC,OAAO,EAAE,eAAe;IACxB,YAAY,EAAE,oBAAoB;IAClC,KAAK,EAAE,aAAa;IACpB,MAAM,EAAE,cAAc;CACvB,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,OAAuB;IAEvB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,MAAM,SAAS,GAAG;QAChB,GAAG,IAAI,GAAG,CACR,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAC1E;KACF,CAAC;IACF,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,KAAK;YAAE,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|