# Richtfunkplaner Local Handler PoC - PowerShell 5.1, keine Adminrechte erforderlich. # Als Text veröffentlicht. Nur nach Freigabe durch die eigene Organisation in .ps1 umbenennen. & { $ErrorActionPreference = 'Stop' $listener = New-Object System.Net.HttpListener $listener.Prefixes.Add('http://127.0.0.1:17777/') $allowedOrigin = 'https://richtfunkplaner.app' $tokenBytes = New-Object byte[] 24 [Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($tokenBytes) $token = [Convert]::ToBase64String($tokenBytes) $state = [hashtable]::Synchronized(@{ Stopping = $false }) $cancelHandler = [ConsoleCancelEventHandler]{ param($sender, $eventArgs) $eventArgs.Cancel = $true $state.Stopping = $true } function Send-Json($context, [int]$status, $body) { $json = $body | ConvertTo-Json -Compress -Depth 5 $bytes = [Text.Encoding]::UTF8.GetBytes($json) $context.Response.StatusCode = $status $context.Response.ContentType = 'application/json; charset=utf-8' $context.Response.ContentLength64 = $bytes.Length $context.Response.OutputStream.Write($bytes, 0, $bytes.Length) $context.Response.Close() } try { [Console]::add_CancelKeyPress($cancelHandler) $listener.Start() Write-Host 'Richtfunkplaner Local Handler läuft auf http://127.0.0.1:17777/' -ForegroundColor Green Write-Host ('Einmal-Token für die PWA: ' + $token) -ForegroundColor Cyan Write-Host 'Beenden mit Strg+C.' while (-not $state.Stopping) { $pending = $listener.GetContextAsync() while (-not $pending.Wait(250)) { if ($state.Stopping) { break } } if ($state.Stopping) { break } $context = $pending.Result $origin = $context.Request.Headers['Origin'] if ($origin -ne $allowedOrigin) { Send-Json $context 403 @{ error = 'Origin nicht erlaubt.' }; continue } $context.Response.Headers['Access-Control-Allow-Origin'] = $allowedOrigin $context.Response.Headers['Vary'] = 'Origin' if ($context.Request.HttpMethod -eq 'OPTIONS') { $context.Response.Headers['Access-Control-Allow-Methods'] = 'GET, OPTIONS' $context.Response.Headers['Access-Control-Allow-Headers'] = 'X-Richtfunkplaner-Token' $context.Response.Headers['Access-Control-Allow-Private-Network'] = 'true' $context.Response.StatusCode = 204 $context.Response.Close() continue } if ($context.Request.Headers['X-Richtfunkplaner-Token'] -cne $token) { Send-Json $context 401 @{ error = 'Token ungültig.' }; continue } if ($context.Request.HttpMethod -ne 'GET') { Send-Json $context 405 @{ error = 'Methode nicht erlaubt.' }; continue } switch ($context.Request.Url.AbsolutePath) { '/health' { Send-Json $context 200 @{ status = 'ok'; version = '0.1-poc'; listener = '127.0.0.1'; utc = [DateTime]::UtcNow.ToString('o') } } '/lancom/status' { Send-Json $context 501 @{ status = 'prepared'; message = 'Read-only LANCOM-Zugriff ist noch nicht auf realer Hardware freigegeben.' } } '/sensor/status' { Send-Json $context 501 @{ status = 'prepared'; deviceClass = 'WT55-prefix'; message = 'UDP-Discovery ist vorbereitet, aber noch nicht aktiviert.' } } default { Send-Json $context 404 @{ error = 'Route nicht vorhanden.' } } } } } finally { if ($listener.IsListening) { $listener.Stop() } $listener.Close() [Console]::remove_CancelKeyPress($cancelHandler) Write-Host 'Richtfunkplaner Local Handler beendet.' } }