diff --git a/agent-cs/Services/RtcService.cs b/agent-cs/Services/RtcService.cs index c10e85a..76d5808 100644 --- a/agent-cs/Services/RtcService.cs +++ b/agent-cs/Services/RtcService.cs @@ -98,6 +98,11 @@ public class RtcService return; } + // Browser informieren dass auf User-Zustimmung gewartet wird + var pending = Encoding.UTF8.GetBytes("{\"type\":\"rdp_consent_pending\"}"); + if (ws.State == WebSocketState.Open) + await ws.SendAsync(new ArraySegment(pending), WebSocketMessageType.Text, true, CancellationToken.None); + bool accepted = false; try { diff --git a/frontend/src/components/common/RemoteDesktopPanel.jsx b/frontend/src/components/common/RemoteDesktopPanel.jsx index 2958553..e19acfc 100644 --- a/frontend/src/components/common/RemoteDesktopPanel.jsx +++ b/frontend/src/components/common/RemoteDesktopPanel.jsx @@ -9,7 +9,7 @@ const SCREEN_OPTIONS = [ ]; export default function RemoteDesktopPanel({ agentId, agentHostname, autoConnect = false, fullscreen = false }) { - const [status, setStatus] = useState('idle'); + const [status, setStatus] = useState('idle'); // idle | connecting | waiting | connected | error const [error, setError] = useState(''); const [fps, setFps] = useState(0); const [resolution, setResolution] = useState(''); @@ -17,6 +17,7 @@ export default function RemoteDesktopPanel({ agentId, agentHostname, autoConnect const canvasRef = useRef(null); const wsRef = useRef(null); const fpsRef = useRef({ count: 0, last: Date.now() }); + const connectedRef = useRef(false); const getWsUrl = () => { const token = localStorage.getItem('token'); @@ -30,15 +31,18 @@ export default function RemoteDesktopPanel({ agentId, agentHostname, autoConnect const ws = new WebSocket(getWsUrl()); wsRef.current = ws; + connectedRef.current = false; ws.onopen = () => { ws.send(JSON.stringify({ type: 'rdp_start', screen })); - setStatus('connected'); }; ws.onmessage = (e) => { try { const msg = JSON.parse(e.data); - if (msg.type === 'rdp_frame') { + if (msg.type === 'rdp_consent_pending') { + setStatus('waiting'); + } else if (msg.type === 'rdp_frame') { + if (!connectedRef.current) { connectedRef.current = true; setStatus('connected'); } const img = new window.Image(); img.onload = () => { const canvas = canvasRef.current; @@ -67,7 +71,7 @@ export default function RemoteDesktopPanel({ agentId, agentHostname, autoConnect }; ws.onerror = () => { setStatus('error'); setError('WebSocket-Fehler'); }; - ws.onclose = () => setStatus(s => s === 'connected' ? 'idle' : s); + ws.onclose = () => setStatus(s => (s === 'connected' || s === 'waiting' || s === 'connecting') ? 'idle' : s); }; const disconnect = () => { @@ -88,8 +92,8 @@ export default function RemoteDesktopPanel({ agentId, agentHostname, autoConnect return () => { wsRef.current?.close(); }; }, []); - const statusColor = { connected: '#34d399', connecting: '#f59e0b', error: '#ef4444', idle: '#6b7280' }[status]; - const statusLabel = { connected: 'Verbunden', connecting: 'Verbinde…', error: 'Fehler', idle: 'Getrennt' }[status]; + const statusColor = { connected: '#34d399', connecting: '#f59e0b', waiting: '#f59e0b', error: '#ef4444', idle: '#6b7280' }[status] ?? '#6b7280'; + const statusLabel = { connected: 'Verbunden', connecting: 'Verbinde…', waiting: 'Warte auf Zustimmung…', error: 'Fehler', idle: 'Getrennt' }[status] ?? ''; const containerStyle = fullscreen ? { display: 'flex', flexDirection: 'column', height: '100vh', background: '#0d1117' } @@ -116,7 +120,7 @@ export default function RemoteDesktopPanel({ agentId, agentHostname, autoConnect