38 lines
1.6 KiB
PowerShell
38 lines
1.6 KiB
PowerShell
param([Parameter(Mandatory = $true)][string]$WebRoot)
|
|
Set-StrictMode -Version 3.0
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$root = [IO.Path]::GetFullPath($WebRoot)
|
|
$indexPath = Join-Path $root 'index.html'
|
|
if (-not (Test-Path -LiteralPath $indexPath -PathType Leaf)) {
|
|
throw "Web index not found: $indexPath"
|
|
}
|
|
|
|
$rootPrefix = $root.TrimEnd('\') + '\'
|
|
$html = Get-Content -LiteralPath $indexPath -Raw
|
|
$references = [regex]::Matches($html, '(?i)(?:src|href)\s*=\s*["''](?<path>[^"'']+)["'']')
|
|
$checked = 0
|
|
foreach ($match in $references) {
|
|
$assetReference = $match.Groups['path'].Value.Trim()
|
|
if (-not $assetReference -or $assetReference.StartsWith('//') -or $assetReference -match '^[a-z][a-z0-9+.-]*:') {
|
|
continue
|
|
}
|
|
$assetPath = ($assetReference -split '[?#]', 2)[0]
|
|
if ([IO.Path]::GetExtension($assetPath).ToLowerInvariant() -notin @('.js', '.css')) {
|
|
continue
|
|
}
|
|
$relative = [Uri]::UnescapeDataString($assetPath).TrimStart('/').Replace('/', '\')
|
|
if (-not $relative) { throw "Web index contains an empty local asset path: $assetReference" }
|
|
$resolved = [IO.Path]::GetFullPath((Join-Path $root $relative))
|
|
if (-not $resolved.StartsWith($rootPrefix, [StringComparison]::OrdinalIgnoreCase)) {
|
|
throw "Web index asset escapes the web root: $assetReference"
|
|
}
|
|
if (-not (Test-Path -LiteralPath $resolved -PathType Leaf)) {
|
|
throw "Web index references missing local asset: $assetReference"
|
|
}
|
|
$checked++
|
|
}
|
|
|
|
if ($checked -eq 0) { throw 'Web index does not reference any local JavaScript or CSS assets.' }
|
|
Write-Host "Sense web asset audit passed: $checked local references."
|