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.
68 lines
2.4 KiB
JavaScript
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';
|
|
}
|
|
};
|
|
}
|