<# .SYNOPSIS Patch wszystkich paczek aktualizacji: dodanie urlencode() na update_key w URL. .DESCRIPTION Po wczesniejszym patchu http->https, klucz licencji nadal wysylany jako raw string. Klucze zawierajace # @ : $ etc. lamia URL. Fix: urlencode($settings['update_key']). Wzorce zamiany (oba warianty pliku class.S.php legacy oraz Helpers.php nowy): 1. ?key=' . $settings['update_key']) -> ?key=' . urlencode($settings['update_key'])) 2. ?key=' . $settings['update_key'] ) -> ?key=' . urlencode( $settings['update_key'] ) ) Idempotentny: pomija pliki ktore juz maja urlencode(). #> [CmdletBinding()] param( [string]$UpdatesDir = "C:\visual studio code\projekty\cmsPRO\updates", [string]$LogPath = "C:\visual studio code\projekty\cmsPRO\.paul\phases\04h-hotfix-https-updates\patch-urlencode-log.md" ) $ErrorActionPreference = "Stop" Add-Type -AssemblyName System.IO.Compression.FileSystem $SuspectFiles = @( 'autoload/class.S.php', 'autoload/Shared/Helpers/Helpers.php', 'autoload/admin/factory/class.Update.php' ) # Zwraca $true jesli content zawiera buggy pattern (raw $settings['update_key'] w URL) function Test-NeedsUrlencode { param([string]$Content) # already has urlencode wrapping update_key? if ($Content -match "urlencode\s*\(\s*\`$settings\[\s*'update_key'\s*\]\s*\)") { # check if there's still any RAW occurrence # Strategy: count raw vs encoded occurrences $raw = ([regex]::Matches($Content, "\`$settings\[\s*'update_key'\s*\]")).Count $enc = ([regex]::Matches($Content, "urlencode\s*\(\s*\`$settings\[\s*'update_key'\s*\]\s*\)")).Count return ($raw -gt $enc) # any raw not yet wrapped } return ($Content -match "key=['""]?\s*\.\s*\`$settings\[\s*'update_key'\s*\]") } function Apply-UrlencodePatch { param([string]$Content) # Two flavors of whitespace: with and without spaces inside brackets # Replacement strategy: find $settings['update_key'] preceded by something containing ?key= and . and replace with urlencode wrap # Safest: match the full "?key=' . $settings['update_key']" with optional spaces/quotes/closing ). # Variant A: ?key=' . $settings['update_key'] (no trailing space, may have ) or ; after) $newContent = [regex]::Replace($Content, "(\?key=['""]?\s*\.\s*)(\`$settings\[\s*'update_key'\s*\])", '$1urlencode($2)' ) return $newContent } function Patch-Zip { param([string]$ZipPath) $log = [PSCustomObject]@{ Package = (Resolve-Path $ZipPath).Path.Substring($UpdatesDir.Length).TrimStart('\','/') Sha256Before = $null Sha256After = $null PatchedFiles = @() ManifestUpd = $false Skipped = $false Error = $null } # backup (separate from previous .bak) $bak = "$ZipPath.preurlencode.bak" if (-not (Test-Path $bak)) { Copy-Item -LiteralPath $ZipPath -Destination $bak -Force } $log.Sha256Before = (Get-FileHash -Algorithm SHA256 -Path $ZipPath).Hash.ToLower() # Find entries needing patch $entriesToPatch = @() try { $zip = [System.IO.Compression.ZipFile]::OpenRead($ZipPath) foreach ($entry in $zip.Entries) { $name = $entry.FullName.Replace('\','/') if ($SuspectFiles -contains $name) { $reader = New-Object System.IO.StreamReader($entry.Open()) $content = $reader.ReadToEnd() $reader.Close() if (Test-NeedsUrlencode -Content $content) { $entriesToPatch += $name } } } $zip.Dispose() } catch { $log.Error = "OpenRead: $($_.Exception.Message)" return $log } if (-not $entriesToPatch) { $log.Skipped = $true $log.Sha256After = $log.Sha256Before return $log } # Patch in-place try { $zipUpd = [System.IO.Compression.ZipFile]::Open($ZipPath, [System.IO.Compression.ZipArchiveMode]::Update) foreach ($name in $entriesToPatch) { $entry = $zipUpd.Entries | Where-Object { $_.FullName.Replace('\','/') -eq $name } | Select-Object -First 1 if (-not $entry) { continue } $stream = $entry.Open() $reader = New-Object System.IO.StreamReader($stream) $content = $reader.ReadToEnd() $reader.Close() $stream.Close() $newContent = Apply-UrlencodePatch -Content $content if ($newContent -eq $content) { continue } $writeStream = $entry.Open() $writeStream.SetLength(0) $writer = New-Object System.IO.StreamWriter($writeStream, (New-Object System.Text.UTF8Encoding $false)) $writer.Write($newContent) $writer.Flush() $writer.Close() $writeStream.Close() $log.PatchedFiles += $name } $zipUpd.Dispose() } catch { $log.Error = "Patch: $($_.Exception.Message)" return $log } $log.Sha256After = (Get-FileHash -Algorithm SHA256 -Path $ZipPath).Hash.ToLower() # Update manifest $verBase = [System.IO.Path]::GetFileNameWithoutExtension($ZipPath) $manifestPath = Join-Path (Split-Path $ZipPath -Parent) "${verBase}_manifest.json" if (Test-Path $manifestPath) { try { $jsonRaw = [System.IO.File]::ReadAllText($manifestPath) if ($jsonRaw.Length -gt 0 -and $jsonRaw[0] -eq [char]0xFEFF) { $jsonRaw = $jsonRaw.Substring(1) } $manifest = $jsonRaw | ConvertFrom-Json if ($manifest.PSObject.Properties.Name -contains 'checksum_zip') { $manifest.checksum_zip = "sha256:$($log.Sha256After)" $newJson = $manifest | ConvertTo-Json -Depth 20 $utf8 = New-Object System.Text.UTF8Encoding $false [System.IO.File]::WriteAllText($manifestPath, $newJson, $utf8) $log.ManifestUpd = $true } } catch { $log.Error = "Manifest: $($_.Exception.Message)" } } return $log } # --- Main --- Write-Host "Skanuje $UpdatesDir ..." -ForegroundColor Cyan $zips = @() $baseInstall = Join-Path $UpdatesDir 'cmsPro.zip' if (Test-Path $baseInstall) { $zips += $baseInstall } $zips += Get-ChildItem -Path $UpdatesDir -Filter 'ver_*.zip' -Recurse | Sort-Object FullName | ForEach-Object { $_.FullName } Write-Host "Paczek do sprawdzenia: $($zips.Count)" -ForegroundColor Cyan $results = @() $i = 0 foreach ($zip in $zips) { $i++ Write-Progress -Activity "Patch urlencode" -Status "$i / $($zips.Count)" -PercentComplete (($i / $zips.Count) * 100) $results += Patch-Zip -ZipPath $zip } Write-Progress -Activity "Patch urlencode" -Completed $patched = $results | Where-Object { $_.PatchedFiles.Count -gt 0 -and -not $_.Error } $skipped = $results | Where-Object { $_.Skipped } $errored = $results | Where-Object { $_.Error } $manifUpd = $results | Where-Object { $_.ManifestUpd } # Log $lines = @() $lines += '# Patch Log: urlencode($settings[update_key])' $lines += '' $lines += "**Data:** $(Get-Date -Format 'yyyy-MM-dd HH:mm')" $lines += '' $lines += "Spatchowanych: $($patched.Count)" $lines += "Pominietych: $($skipped.Count)" $lines += "Manifestow zaktualizowanych: $($manifUpd.Count)" $lines += "Bledow: $($errored.Count)" $lines += '' $lines += '## Spatchowane' if ($patched) { $lines += '| # | Paczka | Pliki | SHA256 (po) |' $lines += '|---|--------|-------|-------------|' $idx = 0 foreach ($r in $patched) { $idx++ $files = ($r.PatchedFiles -join '
') $sha = if ($r.Sha256After.Length -ge 16) { $r.Sha256After.Substring(0,16) } else { $r.Sha256After } $lines += "| $idx | ``$($r.Package)`` | $files | ``$sha`` |" } } $lines += '' if ($errored) { $lines += '## Bledy' foreach ($r in $errored) { $lines += "- ``$($r.Package)`` -- $($r.Error)" } } $utf8 = New-Object System.Text.UTF8Encoding $false [System.IO.File]::WriteAllText($LogPath, ($lines -join "`r`n"), $utf8) Write-Host "" Write-Host "Patch urlencode zakonczony." -ForegroundColor Green Write-Host " Spatchowanych: $($patched.Count)" -ForegroundColor Yellow Write-Host " Manifestow updated: $($manifUpd.Count)" Write-Host " Pominietych: $($skipped.Count)" Write-Host " Bledow: $($errored.Count)" Write-Host "Log: $LogPath" -ForegroundColor Cyan