Update module/Samy.Http.ps1

This commit is contained in:
2025-12-09 23:14:35 -05:00
parent ce301273ed
commit 2c343d9cc2

View File

@@ -1,220 +0,0 @@
# Samy.Http.ps1
# HTTP helpers, listener, and dispatcher
function Send-Text {
param($Context, $Text)
if (-not $Context -or -not $Context.Response) {
return
}
$bytes = [Text.Encoding]::UTF8.GetBytes([string]$Text)
$Context.Response.ContentType = 'text/plain'
$Context.Response.ContentLength64 = $bytes.Length
$Context.Response.OutputStream.Write($bytes,0,$bytes.Length)
$Context.Response.OutputStream.Close()
}
function Send-HTML {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)][object] $Context,
[Parameter(Mandatory = $true)][string] $Html
)
if (-not $Context -or -not $Context.Response) {
return
}
$bytes = [Text.Encoding]::UTF8.GetBytes($Html)
$Context.Response.ContentType = 'text/html'
$Context.Response.ContentLength64 = $bytes.Length
$Context.Response.OutputStream.Write($bytes, 0, $bytes.Length)
$Context.Response.OutputStream.Close()
}
function Send-JSON {
[CmdletBinding()]
param(
$Context,
$Object
)
if (-not $Context -or -not $Context.Response) {
return
}
try {
if ($null -eq $Object) {
Write-LogHybrid "Send-JSON called with `$null object; returning empty JSON array." Warning Printers -LogToEvent
$json = '[]'
}
else {
try {
$json = $Object | ConvertTo-Json -Depth 5 -ErrorAction Stop
}
catch {
Write-LogHybrid "Send-JSON serialization failed: $($_.Exception.Message); returning empty JSON array." Error Printers -LogToEvent
$json = '[]'
}
}
$json = [string]$json
$bytes = [Text.Encoding]::UTF8.GetBytes($json)
$Context.Response.ContentType = 'application/json'
$Context.Response.ContentLength64 = $bytes.Length
$Context.Response.OutputStream.Write($bytes, 0, $bytes.Length)
$Context.Response.OutputStream.Close()
}
catch {
Write-LogHybrid "Send-JSON fatal error: $($_.Exception.Message)" Error Printers -LogToEvent
try {
$fallback = '[]'
$bytes = [Text.Encoding]::UTF8.GetBytes($fallback)
$Context.Response.ContentType = 'application/json'
$Context.Response.ContentLength64 = $bytes.Length
$Context.Response.OutputStream.Write($bytes, 0, $bytes.Length)
$Context.Response.OutputStream.Close()
}
catch {
}
}
}
function Invoke-TasksCompleted {
param($Context)
Write-LogHybrid "All UI-selected tasks processed" Info UI -LogToEvent
Send-Text $Context "Tasks completion acknowledged."
}
function Get-NextFreePort {
param([int]$Start)
for ($p = [Math]::Max(1024,$Start); $p -lt 65535; $p++) {
$l = [System.Net.Sockets.TcpListener]::new([Net.IPAddress]::Loopback, $p)
try {
$l.Start()
$l.Stop()
return $p
}
catch {
}
}
throw "No free TCP port available."
}
function Dispatch-Request {
param($Context)
$path = $Context.Request.Url.AbsolutePath.TrimStart('/')
if ($path -eq 'quit') {
Write-LogHybrid "Shutdown requested" Info Server -LogToEvent
Send-Text $Context "Server shutting down."
$Global:Listener.Stop()
return
}
if ($Context.Request.HttpMethod -eq 'POST' -and $path -eq 'tasksCompleted') {
Invoke-TasksCompleted $Context
return
}
if ($Context.Request.HttpMethod -eq 'POST' -and $path -eq 'getpw') {
Invoke-FetchSites $Context
return
}
if ($Context.Request.HttpMethod -eq 'POST' -and $path -eq 'renameComputer') {
Invoke-RenameComputer $Context
return
}
if ($Context.Request.HttpMethod -eq 'POST' -and $path -eq 'getprinters') {
Invoke-GetPrinters $Context
return
}
if ($Context.Request.HttpMethod -eq 'POST' -and $path -eq 'installprinters') {
Invoke-InstallPrinters $Context
return
}
if ($path -in @('', 'onboard', 'offboard', 'tweaks', 'SVSApps')) {
$page = if ($path -eq '') { 'onboard' } else { $path }
$html = Get-UIHtml -Page $page
Send-HTML $Context $html
return
}
$task = $Global:SamyTasks | Where-Object Name -EQ $path
if ($task) {
& $task.HandlerFn $Context
return
}
$Context.Response.StatusCode = 404
Send-Text $Context '404 - Not Found'
}
function Start-SamyHttpServer {
param(
[Parameter(Mandatory)][int]$Port
)
$Global:Listener = [System.Net.HttpListener]::new()
$primaryPrefix = "http://localhost:$Port/"
$wildcardPrefix = "http://+:$Port/"
try {
$Global:Listener.Prefixes.Add($primaryPrefix)
$Global:Listener.Start()
Write-LogHybrid "Listening on $primaryPrefix" Info Server -LogToEvent
}
catch [System.Net.HttpListenerException] {
if ($_.Exception.ErrorCode -eq 5) {
Write-LogHybrid "Access denied on $primaryPrefix. Attempting URL ACL..." Warning Server -LogToEvent
try {
$user = "$env:USERDOMAIN\$env:USERNAME"
if (-not $user.Trim()) {
$user = $env:USERNAME
}
Start-Process -FilePath "netsh" -ArgumentList "http add urlacl url=$wildcardPrefix user=`"$user`" listen=yes" -Verb RunAs -WindowStyle Hidden -Wait
$Global:Listener = [System.Net.HttpListener]::new()
$Global:Listener.Prefixes.Add($wildcardPrefix)
$Global:Listener.Start()
Write-LogHybrid "Listening on $wildcardPrefix (URL ACL added for $user)" Success Server -LogToEvent
}
catch {
Write-LogHybrid "URL ACL registration failed: $($_.Exception.Message)" Error Server -LogToEvent
return
}
}
elseif ($_.Exception.NativeErrorCode -in 32,183) {
$old = $Port
$Port = Get-NextFreePort -Start ($Port + 1)
$Global:Listener = [System.Net.HttpListener]::new()
$primaryPrefix = "http://localhost:$Port/"
$Global:Listener.Prefixes.Add($primaryPrefix)
$Global:Listener.Start()
Write-LogHybrid "Port $old busy. Listening on $primaryPrefix" Warning Server -LogToEvent
}
else {
Write-LogHybrid "HttpListener start failed: $($_.Exception.Message)" Error Server -LogToEvent
return
}
}
try {
while ($Global:Listener.IsListening) {
$ctx = $Global:Listener.GetContext()
try {
Dispatch-Request $ctx
}
catch {
Write-LogHybrid "Dispatch error: $($_.Exception.Message)" Error Server -LogToEvent
}
}
}
finally {
$Global:Listener.Close()
Write-LogHybrid "Listener closed." Info Server -LogToEvent
}
}