Add RDP user consent popup before screen sharing
When rdp_start arrives, agent first spawns a WPF consent dialog in the user session (via schtasks). User has 30s to accept or deny. On deny, agent sends rdp_denied to browser which shows "Zugriff abgelehnt". On accept, screen capture starts as before. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -67,8 +67,8 @@ public class RtcService
|
||||
{
|
||||
var screenIdx = obj["screen"]?.ToObject<int>() ?? 0;
|
||||
captureCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
||||
_ = CapturePipeLoopAsync(ws, screenIdx, captureCts.Token);
|
||||
AgentWorker.Log($"RDP: Screen-Capture gestartet (screen={screenIdx})");
|
||||
_ = ConsentAndCaptureAsync(ws, screenIdx, captureCts.Token);
|
||||
AgentWorker.Log($"RDP: Consent angefordert (screen={screenIdx})");
|
||||
}
|
||||
else if (type == "rdp_stop" && captureCts != null)
|
||||
{
|
||||
@@ -82,6 +82,100 @@ public class RtcService
|
||||
AgentWorker.Log("RDP: Getrennt");
|
||||
}
|
||||
|
||||
private async Task ConsentAndCaptureAsync(ClientWebSocket ws, int screenIdx, CancellationToken ct)
|
||||
{
|
||||
var exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule!.FileName;
|
||||
|
||||
var consentListener = new TcpListener(IPAddress.Loopback, 0);
|
||||
consentListener.Start();
|
||||
var consentPort = ((IPEndPoint)consentListener.LocalEndpoint).Port;
|
||||
|
||||
if (!SpawnConsentHelper(exePath, consentPort.ToString()))
|
||||
{
|
||||
consentListener.Stop();
|
||||
AgentWorker.Log("RDP: Consent-Helper fehlgeschlagen, starte ohne Consent");
|
||||
await CapturePipeLoopAsync(ws, screenIdx, ct);
|
||||
return;
|
||||
}
|
||||
|
||||
bool accepted = false;
|
||||
try
|
||||
{
|
||||
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(35));
|
||||
using var linked = CancellationTokenSource.CreateLinkedTokenSource(ct, timeoutCts.Token);
|
||||
using var tcp = await consentListener.AcceptTcpClientAsync(linked.Token);
|
||||
var b = tcp.GetStream().ReadByte();
|
||||
accepted = b == 1;
|
||||
}
|
||||
catch { accepted = false; }
|
||||
finally { consentListener.Stop(); }
|
||||
|
||||
if (!accepted)
|
||||
{
|
||||
AgentWorker.Log("RDP: User hat Zugriff abgelehnt");
|
||||
var denied = Encoding.UTF8.GetBytes("{\"type\":\"rdp_denied\"}");
|
||||
if (ws.State == WebSocketState.Open)
|
||||
await ws.SendAsync(new ArraySegment<byte>(denied), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
|
||||
AgentWorker.Log("RDP: User hat Zugriff erlaubt, starte Capture");
|
||||
await CapturePipeLoopAsync(ws, screenIdx, ct);
|
||||
}
|
||||
|
||||
private static bool SpawnConsentHelper(string exePath, string portStr)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fullUser = NotificationService.GetLoggedOnUser();
|
||||
if (string.IsNullOrEmpty(fullUser))
|
||||
{
|
||||
AgentWorker.Log("RDP: Kein eingeloggter User für Consent");
|
||||
return false;
|
||||
}
|
||||
|
||||
var taskName = $"ITNexus-RDPConsent-{portStr}";
|
||||
Process.Start(new ProcessStartInfo("schtasks.exe", $"/delete /tn \"{taskName}\" /f")
|
||||
{ CreateNoWindow = true })?.WaitForExit();
|
||||
|
||||
var triggerTime = DateTime.Now.AddMinutes(60).ToString("HH:mm:ss");
|
||||
var ruArg = fullUser.StartsWith("AzureAD\\", StringComparison.OrdinalIgnoreCase)
|
||||
? "/ru \"INTERACTIVE\""
|
||||
: $"/ru \"{fullUser}\"";
|
||||
|
||||
var args = $"/create /tn \"{taskName}\" /tr \"\\\"{exePath}\\\" --rdp-consent {portStr}\" " +
|
||||
$"/sc ONCE /st {triggerTime} {ruArg} /it /f";
|
||||
|
||||
var p = Process.Start(new ProcessStartInfo("schtasks.exe", args)
|
||||
{ CreateNoWindow = true, RedirectStandardError = true, UseShellExecute = false });
|
||||
p?.WaitForExit();
|
||||
|
||||
if (p?.ExitCode != 0)
|
||||
{
|
||||
AgentWorker.Log($"RDP: schtasks consent fehlgeschlagen (ExitCode={p?.ExitCode})");
|
||||
return false;
|
||||
}
|
||||
|
||||
Process.Start(new ProcessStartInfo("schtasks.exe", $"/run /tn \"{taskName}\"")
|
||||
{ CreateNoWindow = true })?.WaitForExit();
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(40000);
|
||||
Process.Start(new ProcessStartInfo("schtasks.exe", $"/delete /tn \"{taskName}\" /f")
|
||||
{ CreateNoWindow = true })?.WaitForExit();
|
||||
});
|
||||
|
||||
AgentWorker.Log($"RDP: Consent-Helper gestartet als '{fullUser}'");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AgentWorker.Log($"RDP: SpawnConsentHelper Fehler: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CapturePipeLoopAsync(ClientWebSocket ws, int screenIdx, CancellationToken ct)
|
||||
{
|
||||
var exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule!.FileName;
|
||||
|
||||
Reference in New Issue
Block a user