@echo off
setlocal
chcp 65001 >nul

title SWAM Agent Installer
color 0A

REM =============================================================
REM SWAM Agent Installer – FINAL STABLE VERSION
REM - Elevates when needed and returns after scheduling the agent
REM - Installs SWAM Root CA (downloaded)
REM - Downloads agent + sha256
REM - Validates: signature chains to pinned ROOT + SHA256 matches
REM - Creates scheduled tasks
REM =============================================================

REM -------------------------------------------------------------
REM 1) Elevate
REM -------------------------------------------------------------
net session >nul 2>&1
if not "%errorlevel%"=="0" (
    echo.
    echo =============================================================
    echo   SWAM Installer requires Administrator privileges
    echo   A UAC prompt will appear. Please approve it.
    echo =============================================================
    echo.
    
    powershell -NoProfile -ExecutionPolicy Bypass -Command ^
      "Start-Process cmd.exe -ArgumentList '/c','\"%~f0\"' -Verb RunAs"
    exit /b
)

REM -------------------------------------------------------------
REM 2) Configuration
REM -------------------------------------------------------------
set "AGENT_URL=https://www.in2tech.com.au/agent/swam-agent.ps1"
set "HASH_URL=https://www.in2tech.com.au/agent/swam-agent.ps1.sha256"
set "ROOT_URL=https://www.in2tech.com.au/agent/SWAM-Root-CodeSigning-CA.cer"

set "AGENT_DIR=C:\ProgramData\swam"
set "AGENT_PATH=%AGENT_DIR%\swam-agent.ps1"
set "HASH_PATH=%AGENT_DIR%\swam-agent.ps1.sha256"
set "LOG=%AGENT_DIR%\SWAM-Agent-Install.log"

REM PIN THE ROOT CA ONLY (THIS IS THE TRUST ANCHOR)
set "TRUSTED_ROOT_THUMB=ACB0BE883E8EBA65BAA236E6CC9F3C858636B58C"

if not exist "%AGENT_DIR%" mkdir "%AGENT_DIR%" >nul
if not exist "%AGENT_DIR%" (
    echo ERROR: Could not create %AGENT_DIR%
    exit /b 1
)

echo ============================================================= > "%LOG%"
echo SWAM Agent Installer started: %date% %time% >> "%LOG%"
echo Running elevated installer >> "%LOG%"

cls
echo.
echo =============================================================
echo          SWAM Agent Installer – ProgramData build
echo =============================================================
echo Log: %LOG%
echo.

REM -------------------------------------------------------------
REM 3) Install SWAM Root Code Signing CA (BULLETPROOF)
REM    IMPORTANT: escape pipe as ^| so CMD does not break the line
REM -------------------------------------------------------------
echo Installing SWAM Root Code Signing CA...

powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"$ErrorActionPreference='Stop'; ^
$thumb='%TRUSTED_ROOT_THUMB%'.ToUpperInvariant(); ^
$have = Get-ChildItem Cert:\LocalMachine\Root ^| Where-Object { $_.Thumbprint.ToUpperInvariant() -eq $thumb }; ^
if(-not $have){ ^
  $tmp = Join-Path $env:TEMP 'SWAM-Root-CodeSigning-CA.cer'; ^
  Invoke-WebRequest -Uri '%ROOT_URL%' -OutFile $tmp -UseBasicParsing; ^
  Import-Certificate -FilePath $tmp -CertStoreLocation Cert:\LocalMachine\Root ^| Out-Null; ^
}; ^
exit 0" >> "%LOG%" 2>&1

if errorlevel 1 (
    echo ERROR: Root CA installation failed
    echo ERROR: Root CA installation failed >> "%LOG%"
    echo ---- Last 60 log lines ----
    powershell -NoProfile -Command "Get-Content '%LOG%' -Tail 60"
    echo --------------------------
    exit /b 1
)

REM -------------------------------------------------------------
REM 4) Download agent + hash
REM -------------------------------------------------------------
echo.
echo [1/4] Downloading SWAM agent...

del "%AGENT_PATH%" >nul 2>&1
del "%HASH_PATH%" >nul 2>&1
del "%AGENT_PATH%.download" >nul 2>&1
del "%HASH_PATH%.download" >nul 2>&1

powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"$ErrorActionPreference='Stop'; ^
$ProgressPreference='SilentlyContinue'; ^
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; ^
function Get-SwamInstallerFile { ^
  param([string]$Uri,[string]$Path,[string]$Label,[int64]$MinBytes); ^
  $tmp = $Path + '.download'; ^
  $last = $null; ^
  for($attempt = 1; $attempt -le 5; $attempt++){ ^
    try { ^
      if(Test-Path $tmp){ Remove-Item -LiteralPath $tmp -Force -ErrorAction SilentlyContinue }; ^
      Write-Host ('Downloading {0} attempt {1}/5...' -f $Label,$attempt); ^
      Add-Content -Path '%LOG%' -Value ('DOWNLOAD {0} attempt {1}/5 from {2}' -f $Label,$attempt,$Uri); ^
      Invoke-WebRequest -Uri $Uri -OutFile $tmp -UseBasicParsing -TimeoutSec 45 -ErrorAction Stop; ^
      $item = Get-Item -LiteralPath $tmp -ErrorAction Stop; ^
      if($item.Length -lt $MinBytes){ throw ('Downloaded file too small: {0} bytes' -f $item.Length) }; ^
      Move-Item -LiteralPath $tmp -Destination $Path -Force; ^
      Add-Content -Path '%LOG%' -Value ('DOWNLOAD {0} complete: {1} bytes' -f $Label,$item.Length); ^
      return; ^
    } catch { ^
      $last = $_.Exception.Message; ^
      Add-Content -Path '%LOG%' -Value ('DOWNLOAD {0} attempt {1} failed: {2}' -f $Label,$attempt,$last); ^
      Start-Sleep -Seconds ([Math]::Min(20, 3 * $attempt)); ^
    } ^
  }; ^
  try { ^
    Add-Content -Path '%LOG%' -Value ('DOWNLOAD {0} trying WebClient fallback' -f $Label); ^
    $client = New-Object System.Net.WebClient; ^
    $downloadTask = $client.DownloadFileTaskAsync([Uri]$Uri, $tmp); ^
    if(-not $downloadTask.Wait(45000)){ ^
      try { $client.CancelAsync() } catch {}; ^
      throw 'WebClient fallback timed out after 45 seconds'; ^
    }; ^
    if($downloadTask.IsFaulted){ throw $downloadTask.Exception.GetBaseException().Message }; ^
    $item = Get-Item -LiteralPath $tmp -ErrorAction Stop; ^
    if($item.Length -lt $MinBytes){ throw ('Fallback downloaded file too small: {0} bytes' -f $item.Length) }; ^
    Move-Item -LiteralPath $tmp -Destination $Path -Force; ^
    Add-Content -Path '%LOG%' -Value ('DOWNLOAD {0} fallback complete: {1} bytes' -f $Label,$item.Length); ^
    return; ^
  } catch { ^
    Add-Content -Path '%LOG%' -Value ('DOWNLOAD {0} failed after fallback: {1}' -f $Label,$_.Exception.Message); ^
    throw ('Could not download {0}. Last error: {1}' -f $Label,$last); ^
  } finally { ^
    if(Test-Path $tmp){ Remove-Item -LiteralPath $tmp -Force -ErrorAction SilentlyContinue }; ^
  } ^
}; ^
Get-SwamInstallerFile -Uri '%AGENT_URL%' -Path '%AGENT_PATH%' -Label 'SWAM agent' -MinBytes 100000; ^
Get-SwamInstallerFile -Uri '%HASH_URL%' -Path '%HASH_PATH%' -Label 'SWAM agent hash' -MinBytes 32; ^
exit 0" >> "%LOG%" 2>&1

if errorlevel 1 (
    echo ERROR: SWAM agent download failed
    echo ERROR: SWAM agent download failed >> "%LOG%"
    echo ---- Last 80 log lines ----
    powershell -NoProfile -Command "Get-Content '%LOG%' -Tail 80"
    echo --------------------------
    exit /b 1
)

if not exist "%AGENT_PATH%" (
    echo ERROR: Agent download failed
    echo ERROR: Agent download failed >> "%LOG%"
    exit /b 1
)

if not exist "%HASH_PATH%" (
    echo ERROR: Hash download failed
    echo ERROR: Hash download failed >> "%LOG%"
    exit /b 1
)

echo Download complete

REM -------------------------------------------------------------
REM 5) Validate Authenticode signature (CHAIN ROOT PINNED)
REM -------------------------------------------------------------
echo.
echo [2/4] Validating digital signature...

powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"$ErrorActionPreference='Stop'; ^
$agent='%AGENT_PATH%'; ^
$expectedRoot='%TRUSTED_ROOT_THUMB%'.ToUpperInvariant(); ^
$sig = Get-AuthenticodeSignature -FilePath $agent; ^
if(-not $sig.SignerCertificate){ exit 11 }; ^
if($sig.Status -eq 'HashMismatch'){ exit 12 }; ^
$chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain; ^
[void]$chain.Build($sig.SignerCertificate); ^
if($chain.ChainElements.Count -lt 1){ exit 13 }; ^
$root = $chain.ChainElements[$chain.ChainElements.Count-1].Certificate; ^
$rootThumb = $root.Thumbprint.ToUpperInvariant(); ^
if($rootThumb -ne $expectedRoot){ exit 14 }; ^
exit 0" >> "%LOG%" 2>&1

if errorlevel 1 (
    echo SIGNATURE VALIDATION FAILED
    echo SIGNATURE VALIDATION FAILED >> "%LOG%"
    echo ---- Last 80 log lines ----
    powershell -NoProfile -Command "Get-Content '%LOG%' -Tail 80"
    echo --------------------------
    exit /b 1
)

echo Signature OK

REM -------------------------------------------------------------
REM 6) Validate SHA256 integrity
REM -------------------------------------------------------------
echo.
echo [3/4] Verifying SHA256 integrity...

powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"$ErrorActionPreference='Stop'; ^
$expected=(Get-Content -Path '%HASH_PATH%' -TotalCount 1).Trim(); ^
$actual=(Get-FileHash -Path '%AGENT_PATH%' -Algorithm SHA256).Hash; ^
if($expected -ne $actual){ exit 21 } else { exit 0 }" >> "%LOG%" 2>&1

if errorlevel 1 (
    echo INTEGRITY CHECK FAILED
    echo INTEGRITY CHECK FAILED >> "%LOG%"
    echo ---- Last 80 log lines ----
    powershell -NoProfile -Command "Get-Content '%LOG%' -Tail 80"
    echo --------------------------
    exit /b 1
)

echo SHA256 OK

REM -------------------------------------------------------------
REM 7) Create scheduled tasks
REM -------------------------------------------------------------
echo.
echo [4/4] Creating scheduled tasks...

schtasks /delete /tn "SWAM Agent" /f >nul 2>&1
schtasks /delete /tn "SWAM Agent Hourly" /f >nul 2>&1

set "TASKCMD=powershell -NoProfile -ExecutionPolicy Bypass -File \"%AGENT_PATH%\""

schtasks /create /tn "SWAM Agent" /sc onstart /delay 0000:30 /ru SYSTEM /rl HIGHEST /tr "%TASKCMD%" /f >nul
schtasks /create /tn "SWAM Agent Hourly" /sc minute /mo 5 /ru SYSTEM /rl HIGHEST /tr "%TASKCMD%" /f >nul

REM -------------------------------------------------------------
REM 8) Start the scheduled agent without blocking this installer shell
REM -------------------------------------------------------------
echo Starting SWAM Agent scheduled task...
echo Starting SWAM Agent Hourly scheduled task >> "%LOG%"
schtasks /run /tn "SWAM Agent Hourly" >> "%LOG%" 2>&1
if errorlevel 1 (
    echo Scheduled task start failed; launching agent hidden as fallback >> "%LOG%"
    powershell -NoProfile -ExecutionPolicy Bypass -Command ^
      "Start-Process powershell.exe -WindowStyle Hidden -ArgumentList @('-NoProfile','-ExecutionPolicy','Bypass','-File','%AGENT_PATH%')" >> "%LOG%" 2>&1
)

echo.
echo =============================================================
echo SUCCESS! SWAM Agent installed and running.
echo =============================================================
echo.
exit /b 0
