Add: Agent v2.1.2, WebSocket Live Shell, WebRTC Remote Desktop (Beta), Announcement Push
- Agent v2.1.2: WebSocket ShellService, ACK nach WS-Ankündigungen, shown_announcements Fix - Backend: shellServer.js mit WebSocket-Server (Shell + Announcement Push + RTC Signaling) - Backend: patch.controller.js Fix (command_id=0 Falsy-Bug beim Auto-Update) - Frontend: Remote Desktop Tab (WebRTC Beta) in AgentDetailPage für super_admin/admin - Frontend: PatchManagementPage auf v2.1.2 aktualisiert - WPF Notification: AllowsTransparency=False + kein DropShadowEffect (Dispatcher-Crash Fix) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
const { getDatabase } = require('../config/database');
|
||||
const { pushAnnouncementToAgent, broadcastAnnouncement, getConnectedAgents } = require('../ws/shellServer');
|
||||
|
||||
// Hilfsfunktion: welche Ankündigungen sind für einen Agenten relevant (nach Gruppe)?
|
||||
function getForAgent(agentId) {
|
||||
@@ -94,7 +95,18 @@ const create = (req, res) => {
|
||||
INSERT INTO announcements (title, message, type, target_groups, target_agent_ids, created_by_user_id, expires_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(title.trim(), message.trim(), type, JSON.stringify(target_groups), JSON.stringify(target_agent_ids), req.user.id, expires_at || null);
|
||||
res.status(201).json(db.prepare('SELECT * FROM announcements WHERE id=?').get(result.lastInsertRowid));
|
||||
const ann = db.prepare('SELECT * FROM announcements WHERE id=?').get(result.lastInsertRowid);
|
||||
|
||||
// WebSocket-Push: sofort an verbundene Agents schicken
|
||||
const wsPayload = { id: ann.id, title: ann.title, message: ann.message, type: ann.type };
|
||||
const agentIds = JSON.parse(ann.target_agent_ids || '[]');
|
||||
if (agentIds.length > 0) {
|
||||
agentIds.forEach(id => pushAnnouncementToAgent(id, [wsPayload]));
|
||||
} else {
|
||||
broadcastAnnouncement(wsPayload);
|
||||
}
|
||||
|
||||
res.status(201).json(ann);
|
||||
};
|
||||
|
||||
const update = (req, res) => {
|
||||
|
||||
@@ -7,7 +7,10 @@ class FidoKeyController {
|
||||
* GET /api/fido-keys
|
||||
*/
|
||||
static getAllKeys = asyncHandler(async (req, res) => {
|
||||
const keys = FidoKeyService.getAllKeys();
|
||||
const { user_id } = req.query;
|
||||
const keys = user_id
|
||||
? FidoKeyService.getKeysByUser(parseInt(user_id))
|
||||
: FidoKeyService.getAllKeys();
|
||||
|
||||
res.json({
|
||||
status: 'success',
|
||||
|
||||
@@ -273,11 +273,14 @@ const reportCommandResult = (req, res) => {
|
||||
if (!agentKey || agentKey !== process.env.AGENT_API_KEY) {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
const { command_id, status, result } = req.body;
|
||||
if (!command_id) return res.status(400).json({ error: 'command_id erforderlich' });
|
||||
const command_id = req.body.command_id ?? req.body.CommandId;
|
||||
const { status, result } = req.body;
|
||||
if (command_id === undefined || command_id === null) return res.status(400).json({ error: 'command_id erforderlich' });
|
||||
const db = getDatabase();
|
||||
db.prepare("UPDATE patch_commands SET status=?, result=?, completed_at=CURRENT_TIMESTAMP WHERE id=?")
|
||||
.run(status || 'done', result || null, command_id);
|
||||
if (command_id !== 0) {
|
||||
db.prepare("UPDATE patch_commands SET status=?, result=?, completed_at=CURRENT_TIMESTAMP WHERE id=?")
|
||||
.run(status || 'done', result || null, command_id);
|
||||
}
|
||||
res.json({ success: true });
|
||||
};
|
||||
|
||||
@@ -293,6 +296,37 @@ const getPendingCommands = (agentId) => {
|
||||
return { pending: cmds, running };
|
||||
};
|
||||
|
||||
// Remote Shell: POST /api/patch/shell/:agentId
|
||||
const triggerShell = (req, res) => {
|
||||
const { agentId } = req.params;
|
||||
const { command } = req.body;
|
||||
if (!command) return res.status(400).json({ error: 'command erforderlich' });
|
||||
const db = getDatabase();
|
||||
const result = db.prepare(
|
||||
"INSERT INTO patch_commands (agent_id, command, params, triggered_by_user_id) VALUES (?,?,?,?)"
|
||||
).run(parseInt(agentId), 'shell_exec', command, req.user.id);
|
||||
res.status(201).json({ id: result.lastInsertRowid });
|
||||
};
|
||||
|
||||
// Remote Shell: GET /api/patch/shell/:agentId/result/:cmdId
|
||||
const getShellResult = (req, res) => {
|
||||
const { cmdId } = req.params;
|
||||
const db = getDatabase();
|
||||
const cmd = db.prepare("SELECT id, status, result, created_at, completed_at FROM patch_commands WHERE id=?").get(parseInt(cmdId));
|
||||
if (!cmd) return res.status(404).json({ error: 'Nicht gefunden' });
|
||||
res.json(cmd);
|
||||
};
|
||||
|
||||
// Remote Shell: GET /api/patch/shell/:agentId/history
|
||||
const getShellHistory = (req, res) => {
|
||||
const { agentId } = req.params;
|
||||
const db = getDatabase();
|
||||
const cmds = db.prepare(
|
||||
"SELECT id, params, status, result, created_at, completed_at FROM patch_commands WHERE agent_id=? AND command='shell_exec' ORDER BY created_at DESC LIMIT 50"
|
||||
).all(parseInt(agentId));
|
||||
res.json(cmds);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getGroups, createGroup, updateGroup, deleteGroup, releaseVersionToGroup, releaseVersionToAll,
|
||||
upsertPolicy, deletePolicy,
|
||||
@@ -300,4 +334,5 @@ module.exports = {
|
||||
getOverview,
|
||||
triggerCommand, triggerGroupCommand, getCommands, reportCommandResult,
|
||||
getPendingCommands,
|
||||
triggerShell, getShellResult, getShellHistory,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user