137 lines
5.6 KiB
PowerShell
137 lines
5.6 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[switch]$NoLaunch,
|
|
[switch]$SkipShortcuts,
|
|
[switch]$SkipProcessCheck,
|
|
[string]$InstallRoot = '',
|
|
[string]$RoamingRoot = '',
|
|
[string]$LocalRoot = ''
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
Set-StrictMode -Version Latest
|
|
|
|
function Copy-Tree {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$Source,
|
|
[Parameter(Mandatory = $true)][string]$Destination
|
|
)
|
|
|
|
if (-not (Test-Path -LiteralPath $Source -PathType Container)) {
|
|
throw "Required source directory is missing: $Source"
|
|
}
|
|
New-Item -ItemType Directory -Path $Destination -Force | Out-Null
|
|
& robocopy.exe $Source $Destination /E /COPY:DAT /DCOPY:DAT /R:2 /W:1 /XJ /NFL /NDL /NP
|
|
$code = $LASTEXITCODE
|
|
if ($code -gt 7) {
|
|
throw "Copy failed with robocopy exit code $code ($Source)"
|
|
}
|
|
}
|
|
|
|
function Move-ToBackup {
|
|
param([Parameter(Mandatory = $true)][string]$Path)
|
|
|
|
if (-not (Test-Path -LiteralPath $Path)) {
|
|
return $null
|
|
}
|
|
$parent = Split-Path -Parent $Path
|
|
$leaf = Split-Path -Leaf $Path
|
|
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
|
$suffix = [Guid]::NewGuid().ToString('N').Substring(0, 6)
|
|
$backup = Join-Path $parent ($leaf + '.backup-' + $stamp + '-' + $suffix)
|
|
Move-Item -LiteralPath $Path -Destination $backup
|
|
return $backup
|
|
}
|
|
|
|
$packageRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$sourceApp = Join-Path $packageRoot 'App'
|
|
$sourceRoaming = Join-Path $packageRoot 'Seed\Roaming\BitBrowser'
|
|
$sourceLocal = Join-Path $packageRoot 'Seed\Local\BitBrowser'
|
|
$targetApp = if ($InstallRoot) { [System.IO.Path]::GetFullPath($InstallRoot) } else { Join-Path $env:LOCALAPPDATA 'Programs\BitBrowser' }
|
|
$targetRoaming = if ($RoamingRoot) { [System.IO.Path]::GetFullPath($RoamingRoot) } else { Join-Path $env:APPDATA 'BitBrowser' }
|
|
$targetLocal = if ($LocalRoot) { [System.IO.Path]::GetFullPath($LocalRoot) } else { Join-Path $env:LOCALAPPDATA 'BitBrowser' }
|
|
$targetExe = Join-Path $targetApp ([string][char]0x6BD4 + [char]0x7279 + [char]0x6D4F + [char]0x89C8 + [char]0x5668 + '.exe')
|
|
$expectedExtensionId = 'jiofmdifioeejeilfkpegipdjiopiekl'
|
|
$sourceDb = Join-Path $sourceRoaming 'db.sqlite'
|
|
$sourceExtensionManifest = Join-Path $sourceRoaming "BitExtensions\$expectedExtensionId\manifest.json"
|
|
|
|
if (-not $SkipProcessCheck) {
|
|
$running = @(Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
|
|
$_.Name -eq ([string][char]0x6BD4 + [char]0x7279 + [char]0x6D4F + [char]0x89C8 + [char]0x5668 + '.exe') -or
|
|
($_.ExecutablePath -and $_.ExecutablePath.StartsWith($targetApp, [System.StringComparison]::OrdinalIgnoreCase))
|
|
})
|
|
if ($running.Count -gt 0) {
|
|
throw 'BitBrowser is running. Close it and run this installer again.'
|
|
}
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath $sourceDb -PathType Leaf)) {
|
|
throw 'The clean seed database is missing from this package.'
|
|
}
|
|
if (-not (Test-Path -LiteralPath $sourceExtensionManifest -PathType Leaf)) {
|
|
throw 'The YesCaptcha extension is missing from this package.'
|
|
}
|
|
|
|
Write-Host 'Installing BitBrowser application files...'
|
|
Copy-Tree -Source $sourceApp -Destination $targetApp
|
|
|
|
$backups = @()
|
|
$backup = Move-ToBackup -Path $targetRoaming
|
|
if ($backup) { $backups += $backup }
|
|
$backup = Move-ToBackup -Path $targetLocal
|
|
if ($backup) { $backups += $backup }
|
|
|
|
Write-Host 'Installing clean user data and preserved extensions...'
|
|
Copy-Tree -Source $sourceRoaming -Destination $targetRoaming
|
|
if (Test-Path -LiteralPath $sourceLocal -PathType Container) {
|
|
Copy-Tree -Source $sourceLocal -Destination $targetLocal
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath $targetExe -PathType Leaf)) {
|
|
throw "Installed executable was not found: $targetExe"
|
|
}
|
|
$targetDb = Join-Path $targetRoaming 'db.sqlite'
|
|
$targetExtensionManifest = Join-Path $targetRoaming "BitExtensions\$expectedExtensionId\manifest.json"
|
|
if (-not (Test-Path -LiteralPath $targetExtensionManifest -PathType Leaf)) {
|
|
throw "YesCaptcha was not installed: $targetExtensionManifest"
|
|
}
|
|
if ((Get-FileHash -LiteralPath $sourceDb -Algorithm SHA256).Hash -ne (Get-FileHash -LiteralPath $targetDb -Algorithm SHA256).Hash) {
|
|
throw 'The clean database copy failed verification.'
|
|
}
|
|
if ((Get-FileHash -LiteralPath $sourceExtensionManifest -Algorithm SHA256).Hash -ne (Get-FileHash -LiteralPath $targetExtensionManifest -Algorithm SHA256).Hash) {
|
|
throw 'The YesCaptcha extension copy failed verification.'
|
|
}
|
|
|
|
if (-not $SkipShortcuts) {
|
|
$shell = New-Object -ComObject WScript.Shell
|
|
$desktop = [Environment]::GetFolderPath('Desktop')
|
|
$shortcutPath = Join-Path $desktop 'BitBrowser.lnk'
|
|
$shortcut = $shell.CreateShortcut($shortcutPath)
|
|
$shortcut.TargetPath = $targetExe
|
|
$shortcut.WorkingDirectory = $targetApp
|
|
$shortcut.IconLocation = $targetExe + ',0'
|
|
$shortcut.Save()
|
|
|
|
$startMenu = Join-Path $env:APPDATA 'Microsoft\Windows\Start Menu\Programs'
|
|
$startShortcutPath = Join-Path $startMenu 'BitBrowser.lnk'
|
|
$startShortcut = $shell.CreateShortcut($startShortcutPath)
|
|
$startShortcut.TargetPath = $targetExe
|
|
$startShortcut.WorkingDirectory = $targetApp
|
|
$startShortcut.IconLocation = $targetExe + ',0'
|
|
$startShortcut.Save()
|
|
}
|
|
|
|
Write-Host ''
|
|
Write-Host "Installed application: $targetApp"
|
|
Write-Host "Installed clean data: $targetRoaming"
|
|
Write-Host "Verified extension: YesCaptcha 1.4.7 ($expectedExtensionId)"
|
|
if ($backups.Count -gt 0) {
|
|
Write-Host 'Previous data was preserved at:'
|
|
foreach ($item in $backups) { Write-Host " $item" }
|
|
}
|
|
Write-Host 'No browser profiles, cookies, history, cache, proxy settings, or login token were installed.'
|
|
|
|
if (-not $NoLaunch) {
|
|
Start-Process -FilePath $targetExe -WorkingDirectory $targetApp
|
|
}
|