espilon-source/tools/C3PO/static/js/commander.js
Eun0us 79c2a4d4bf c3po: full server rewrite with modular routes and honeypot dashboard
Replace monolithic CLI and web server with route-based Flask API.
New routes: api_commands, api_build, api_can, api_monitor, api_ota,
api_tunnel. Add honeypot security dashboard with real-time SSE,
MITRE ATT&CK mapping, kill chain analysis.

New TUI with commander/help modules. Add session management,
tunnel proxy core, CAN bus data store. Docker support.
2026-02-28 20:12:27 +01:00

68 lines
2.4 KiB
JavaScript

/* ESPILON C2 — Command send + poll mixin for Alpine.js */
function commander() {
return {
cmdPending: {},
cmdHistory: [],
async sendCommand(deviceIds, command, argv = []) {
const payload = { device_ids: deviceIds, command, argv };
const res = await fetch('/api/commands', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
const data = await res.json();
if (data.error) throw new Error(data.error);
for (const r of (data.results || [])) {
if (r.status === 'ok' && r.request_id) {
this.cmdPending[r.request_id] = {
device_id: r.device_id, command, status: 'pending', output: []
};
this._pollResult(r.request_id);
}
this.cmdHistory.unshift({
...r, command, argv,
time: new Date().toISOString()
});
}
if (this.cmdHistory.length > 200) this.cmdHistory.length = 200;
return data;
},
_pollResult(requestId) {
let attempts = 0;
const poll = async () => {
attempts++;
try {
const res = await fetch('/api/commands/' + encodeURIComponent(requestId));
const data = await res.json();
const entry = this.cmdPending[requestId];
if (entry) {
entry.output = data.output || [];
if (data.status === 'completed' || data.status === 'error' || attempts >= 60) {
entry.status = data.status || 'completed';
clearInterval(iv);
}
}
} catch (e) {
if (attempts >= 60) clearInterval(iv);
}
};
const iv = setInterval(poll, 500);
setTimeout(poll, 200);
},
getPendingOutput(requestId) {
const entry = this.cmdPending[requestId];
return entry ? entry.output : [];
},
isPending(requestId) {
const entry = this.cmdPending[requestId];
return entry && entry.status === 'pending';
}
};
}