53 lines
2.4 KiB
JavaScript
53 lines
2.4 KiB
JavaScript
"use strict";
|
|
|
|
const fs = require("node:fs");
|
|
const net = require("node:net");
|
|
const { execFile } = require("node:child_process");
|
|
|
|
const SOCKET_PATH = process.env.LAKE_LAMP_ACTION_SOCKET || "/run/guanghu/action-broker.sock";
|
|
const SSH_CONFIG = process.env.LAKE_LAMP_SSH_CONFIG || "/etc/guanghu/action-broker-ssh-config";
|
|
|
|
const ACTIONS = Object.freeze({
|
|
"JD-FD-PRIMARY:inspect-services": () => run("/usr/bin/ssh", [
|
|
"-F", SSH_CONFIG,
|
|
"-o", "BatchMode=yes",
|
|
"-o", "ConnectTimeout=10",
|
|
"enterprise-lighthouse",
|
|
"printf 'HOST='; hostname; printf 'SSH='; systemctl is-active ssh 2>/dev/null || systemctl is-active sshd 2>/dev/null; printf 'LIGHTHOUSE='; systemctl is-active guanghu-enterprise-lighthouse.service 2>/dev/null || true"
|
|
])
|
|
});
|
|
|
|
function run(file, args) {
|
|
return new Promise(resolve => execFile(file, args, { timeout: 30000, maxBuffer: 100000 }, (error, stdout, stderr) => resolve({
|
|
ok: !error,
|
|
exit_code: error ? (Number.isInteger(error.code) ? error.code : 1) : 0,
|
|
stdout: String(stdout || "").slice(0, 100000),
|
|
stderr: String(stderr || "").slice(0, 10000),
|
|
})));
|
|
}
|
|
|
|
function reply(socket, value) { socket.end(`${JSON.stringify(value)}\n`); }
|
|
|
|
if (require.main === module) {
|
|
fs.mkdirSync(require("node:path").dirname(SOCKET_PATH), { recursive: true, mode: 0o755 });
|
|
try { fs.unlinkSync(SOCKET_PATH); } catch (error) { if (error.code !== "ENOENT") throw error; }
|
|
const server = net.createServer({ allowHalfOpen: true }, socket => {
|
|
let input = "";
|
|
socket.setTimeout(5000, () => socket.destroy());
|
|
socket.on("data", chunk => { input += chunk.toString("utf8"); if (input.length > 4096) socket.destroy(); });
|
|
socket.on("end", async () => {
|
|
let request;
|
|
try { request = JSON.parse(input); } catch { return reply(socket, { ok: false, error: "invalid_request" }); }
|
|
if (!request || request.cmd || request.command || request.shell || request.args) return reply(socket, { ok: false, error: "arbitrary_command_forbidden" });
|
|
const action = ACTIONS[`${request.target}:${request.action}`];
|
|
if (!action) return reply(socket, { ok: false, error: "action_not_registered" });
|
|
reply(socket, await action());
|
|
});
|
|
});
|
|
server.listen(SOCKET_PATH, () => {
|
|
fs.chownSync(SOCKET_PATH, 0, Number(process.env.LAKE_LAMP_AUTHZ_GID || 0));
|
|
fs.chmodSync(SOCKET_PATH, 0o660);
|
|
});
|
|
}
|
|
|
|
module.exports = { ACTIONS };
|