diff --git a/native/win_install.ps1 b/native/win_install.ps1 index ad9fb57f..3288cde9 100644 --- a/native/win_install.ps1 +++ b/native/win_install.ps1 @@ -1,214 +1,506 @@ Param ( - [switch]$debug = $false + [switch]$Uninstall = $false, + [string]$DebugDirBase = "", + [string]$InstallDirBase = "" ) # -# Constants +# Global constants # -$win_tridactyl_dir_name = ".tridactyl" -$batch_file_name = "native_main.bat" -$manifest_file_name = "tridactyl.json" -$manifest_replace_str = "REPLACE_ME_WITH_SED" -$native_messenger_binary_name = "native_main.py" +$global:InstallDirName = ".tridactyl" +$global:MessengerBinName = "native_main.py" +$global:MessengerBinWrapperFilename = "native_main.bat" +$global:MessengerManifestFilename = "tridactyl.json" +$global:PythonVersionStr = "Python 3" +$global:MessengerManifestReplaceStr = "REPLACE_ME_WITH_SED" -$native_messenger_files_http_base = ` - "https://raw.githubusercontent.com/cmcaine/tridactyl/master/native" +$global:MessengerFilesHttpUriBase = [string]::Format("{0}{1}", + "https://raw.githubusercontent.com", + "/cmcaine/tridactyl/master/native") -$manifest_registry_path = ` +$global:MessengerManifestRegistryPath = ` "HKCU:\Software\Mozilla\NativeMessagingHosts\tridactyl" +$global:Uninstall = $Uninstall +$global:InstallDirBase = $InstallDirBase.Trim() +$global:DebugDirBase = $DebugDirBase.Trim() -function Check-Path() -{ - Param($Path) - if((Test-Path $Path)) - { - Write-Host " - $Path created successfully!" +function Get-PythonVersionStatus() { + try { + $pythonVersion = py -3 -u --version + } catch { + $pythonVersion = "" } - else - { - Write-Host " - $Path creating failed, quitting ..." + + if ($pythonVersion.IndexOf($global:PythonVersionStr) -ge 0) { + return $true + } else { + return $false } } -# -# Prepare `.tridactyl` directory -# -$win_tridactyl_dir_path = "$env:USERPROFILE\$win_tridactyl_dir_name" -Write-Host "[+] Preparing $win_tridactyl_dir_name ..." +function Set-MessengerUninstall() { + Write-Host "[+] Uninstalling Tridactyl native-messenger ..." -if ($debug) -{ - Write-Host " - [debug] Removing $win_tridactyl_dir_path" - Remove-Item ` + $messengerBinPath = Get-MessengerBinPath + $messengerBinWrapperPath = Get-MessengerBinWrapperPath + $messengerManifestPath = Get-MessengerManifestPath + + $result = Remove-TridactylPath $messengerBinPath + $result = Remove-TridactylPath $messengerBinWrapperPath + $result = Remove-TridactylPath $messengerManifestPath + + $result1 = Test-TridactylPath $messengerBinPath + $result2 = Test-TridactylPath $messengerBinWrapperPath + $result3 = Test-TridactylPath $messengerManifestPath + $result4 = Remove-MessengerManifestRegistry + + if (($result1 -eq $false) ` + -and ($result2 -eq $false) ` + -and ($result3 -eq $false) ` + -and ($result4 -eq $true)) { + Write-Host "[+] Uninstallation successful! :-)" + } else { + Write-Host "[+] Uninstallation failed. :-(" + } +} + +function Remove-TridactylPath() { + Param([string]$path) + + if (! (Test-Path $path)) { + return + } + + Write-Host ` + -NoNewline ` + " - Removing $path " + + $result = Remove-Item ` -Force ` -Recurse ` - -Path $win_tridactyl_dir_path + -Path $path + + if ($result -eq 0) { + Write-Host "was successful!" + return $true + } + else { + Write-Host "failed." + return $false + } } -If(!(test-path $win_tridactyl_dir_path)) -{ - New-Item -ItemType Directory ` - -Force ` - -Path $win_tridactyl_dir_path | Out-Null - - Check-Path -Path $win_tridactyl_dir_path -} -else -{ - Write-Host " - $win_tridactyl_dir_path exists, moving on ..." -} - -# -# Prepare `native_main.py` -# -$download_start_time = [long] (Get-Date ` - -Date ((Get-Date).ToUniversalTime()) ` - -UFormat %s) - -$native_messenger_binary_path = [string]::Format("{0}\{1}", - $win_tridactyl_dir_path, - $native_messenger_binary_name) - -$native_messenger_binary_url = [string]::Format("{0}/{1}?{2}", - $native_messenger_files_http_base, - $native_messenger_binary_name, - $download_start_time) - -Write-Host "[+] Downloading $native_messenger_binary_url ..." - -try { - $retval = Invoke-WebRequest ` - -Uri $native_messenger_binary_url ` - -OutFile $native_messenger_binary_path -} catch { - Write-Host ` - "Invoke-WebRequest StatusCode:" ` - $_.Exception.Response.StatusCode.value__ +function Test-TridactylPath() { + Param([string]$path) Write-Host ` - "Invoke-WebRequest StatusDescription:" ` - $_.Exception.Response.StatusDescription + -NoNewline ` + " - Testing $path " - Write-Host "[+] Downloading failed, quitting ..." - exit + if((Test-Path $path)) { + Write-Host "was successful!" + return $true + } + else { + Write-Host "failed." + return $false + } } -Check-Path -Path $native_messenger_binary_path +function Get-MessengerInstallDir() { + if (($InstallDirBase.Length -gt 0) ` + -and (Test-Path $InstallDirBase.Trim())) { + $messengerInstallDir = [string]::Format("{0}\{1}", + $global:InstallDirBase, + $global:InstallDirName + ) + } else { + $messengerInstallDir = [string]::Format("{0}\{1}", + $env:USERPROFILE, + $global:InstallDirName + ) + } -# -# Prepare `win_tridactyl.bat` -# -$batch_file_path = [string]::Format("{0}\{1}", - $win_tridactyl_dir_path, - $batch_file_name) -Write-Host "[+] Preparing $batch_file_path ..." + return $messengerInstallDir.Trim() +} -$batch_file_content = @" +function Set-InstallDir() { + $messengerInstallDir = Get-MessengerInstallDir + Write-Host "[+] Preparing $messengerInstallDir ..." + + If(! (Test-Path $messengerInstallDir)) { + New-Item -ItemType Directory ` + -Force ` + -Path $messengerInstallDir | Out-Null + } else { + Write-Host ` + " - $messengerInstallDir exists, moving on ..." + } + + $result = Test-TridactylPath $messengerInstallDir + if ($result -eq $true) { + Write-Host ` + " - Create $messengerInstallDir successful!" + return $true + } else { + Write-Host ` + " - Create $messengerInstallDir failed, quitting ..." + exit -1 + } +} + +function Get-MessengerBinPath() { + $messengerInstallDir = Get-MessengerInstallDir + + $native_messenger_binary_path = [string]::Format("{0}\{1}", + $messengerInstallDir, + $global:MessengerBinName) + + Return $native_messenger_binary_path.Trim() +} + +function Get-MessengerBinUri() { + $downloadStartTime = (Get-Date ` + -Date ((Get-Date).ToUniversalTime()) ` + -UFormat %s) + + $messengerBinUri = [string]::Format("{0}/{1}?{2}", + $global:MessengerFilesHttpUriBase, + $global:MessengerBinName, + $downloadStartTime) + + Return $messengerBinUri.Trim() +} + +function Set-MessengerBin() { + $messengerBinPath = Get-MessengerBinPath + $messengerBinUri = Get-MessengerBinUri + + if ($global:DebugDirBase.Length -gt 0) { + $srcPath = [string]::Format("{0}\{1}", + $global:DebugDirBase, + $global:MessengerBinName) + + Write-Host "[+] Copying $srcPath ..." + + Copy-Item ` + -Path $srcPath ` + -Destination $messengerBinPath + } else { + Write-Host "[+] Downloading $messengerBinUri ..." + + try { + Invoke-WebRequest ` + -Uri $messengerBinUri ` + -OutFile $messengerBinPath + } catch { + Write-Host ` + "Invoke-WebRequest StatusCode:" ` + $_.Exception.Response.StatusCode.value__ + + Write-Host ` + "Invoke-WebRequest StatusDescription:" ` + $_.Exception.Response.StatusDescription + + Write-Host "[+] Downloading failed, quitting ..." + exit -1 + } + } + + $result = Test-TridactylPath -Path $messengerBinPath + if ($result -eq $true) { + Write-Host ` + " - Create $messengerBinPath was successful!" + return $true + } else { + Write-Host ` + " - Create $messengerBinPath failed, quitting ..." + exit -1 + } +} + +function Get-MessengerBinWrapperPath() { + $messengerInstallDir = Get-MessengerInstallDir + + $messengerBinWrapperPath = [string]::Format("{0}\{1}", + $messengerInstallDir, + $global:MessengerBinWrapperFilename) + + Return $messengerBinWrapperPath.Trim() +} + +function Set-MessengerBinWrapper() { + $messengerBinPath = Get-MessengerBinPath + $messengerBinWrapperPath = Get-MessengerBinWrapperPath + $messengerWrapperContent = @" @echo off - -call python -u $win_tridactyl_dir_path\native_main.py +call py -3 -u $messengerBinPath "@ -$batch_file_content ` - | Out-File ` - -Encoding ascii ` - -FilePath $batch_file_path + Write-Host "[+] Preparing $messengerBinWrapperPath ..." -Check-Path -Path $batch_file_path + $messengerWrapperContent ` + | Out-File ` + -Encoding ascii ` + -FilePath $messengerBinWrapperPath -# -# Prepare `tridactyl.json` -# -$download_start_time = [long] (Get-Date ` - -Date ((Get-Date).ToUniversalTime()) ` - -UFormat %s) - -$manifest_file_path = [string]::Format("{0}\{1}", - $win_tridactyl_dir_path, - $manifest_file_name) - -Write-Host "[+] Preparing $manifest_file_path ..." - -#$manifest_file_content = @" -#{ -# "name": "tridactyl", -# "description": "Tridactyl native command handler", -# "path": "win_tridactyl.bat", -# "type": "stdio", -# "allowed_extensions": [ -# "tridactyl.vim@cmcaine.co.uk", -# "tridactyl.vim.betas@cmcaine.co.uk" -# ] -#} -#"@ -# -#$manifest_file_content ` -# | Out-File ` -# -Encoding ascii ` -# -FilePath $manifest_file_path - -$manifest_file_url = [string]::Format("{0}/{1}?{2}", - $native_messenger_files_http_base, - $manifest_file_name, - $download_start_time) - -Write-Host "[+] Downloading $manifest_file_url ..." - -try { - $retval = Invoke-WebRequest ` - -Uri $manifest_file_url ` - -OutFile $manifest_file_path -} catch { - Write-Host ` - "Invoke-WebRequest StatusCode:" ` - $_.Exception.Response.StatusCode.value__ - - Write-Host ` - "Invoke-WebRequest StatusDescription:" ` - $_.Exception.Response.StatusDescription - - Write-Host "[+] Downloading failed, quitting ..." - exit + $result = Test-TridactylPath -Path $messengerBinWrapperPath + if ($result -eq $true) { + $msg = [string]::Format( + " - Create {0} failed, was successful!", + $messengerBinWrapperPath) + Write-Host $msg + return $true + } else { + $msg = [string]::Format( + " - Create {0} failed, quitting ...", + $messengerBinWrapperPath) + Write-Host $msg + exit -1 + } } -Check-Path -Path $manifest_file_path +function Get-MessengerManifestPath() { + $messengerInstallDir = Get-MessengerInstallDir -(Get-Content ` - $manifest_file_path).replace($manifest_replace_str, $batch_file_name) ` - | Set-Content -Encoding ascii $manifest_file_path + $messengerManifestPath = [string]::Format("{0}\{1}", + $messengerInstallDir, + $global:MessengerManifestFilename) -$found_pattern = (Select-String ` - -Path $manifest_file_path ` - -Pattern $manifest_replace_str ` - -CaseSensitive ` - | select Line) - -if (! $found_pattern) -{ - Write-Host " - $manifest_file_path patched successfully!" + return $messengerManifestPath.Trim() } -# -# Add registry entry -# -Write-Host "[+] Adding registry key $manifest_registry_path ..." -New-Item ` - -Path $manifest_registry_path ` - -Force | Out-Null +function Get-MessengerManifestUri() { + $downloadStartTime = (Get-Date ` + -Date ((Get-Date).ToUniversalTime()) ` + -UFormat %s) -New-ItemProperty ` - -Path $manifest_registry_path ` - -Name "(Default)" ` - -Value $manifest_file_path ` - -Force | Out-Null + $messengerManifestUri = [string]::Format("{0}/{1}?{2}", + $global:MessengerFilesHttpUriBase, + $global:MessengerManifestFilename, + $downloadStartTime) -#Get-ItemProperty ` -# -Path $manifest_registry_path ` -# -Name "(Default)" - -if ((Get-ItemProperty ` - -Path $manifest_registry_path)."(Default)" = $manifest_file_path) -{ - Write-Host " - Registry key looks good!" + return $messengerManifestUri.Trim() } + +function Set-MessengerManifest() { + $messengerManifestPath = Get-MessengerManifestPath + $messengerManifestUri = Get-MessengerManifestUri + $result = $false + + if ($global:DebugDirBase.Length -gt 0) { + $srcPath = [string]::Format("{0}\{1}", + $global:DebugDirBase, + $global:MessengerManifestFilename) + + Write-Host "[+] Copying $srcPath ..." + + Copy-Item ` + -Path $srcPath ` + -Destination $messengerManifestPath + } else { + Write-Host "[+] Downloading $messengerManifestUri ..." + + try { + Invoke-WebRequest ` + -Uri $messengerManifestUri ` + -OutFile $messengerManifestPath + } catch { + Write-Host ` + "Invoke-WebRequest StatusCode:" ` + $_.Exception.Response.StatusCode.value__ + + Write-Host ` + "Invoke-WebRequest StatusDescription:" ` + $_.Exception.Response.StatusDescription + + Write-Host " - Downloading failed, quitting ..." + exit -1 + } + } + + $result = Test-TridactylPath -Path $messengerManifestPath + + if ($result -eq $true) { + $msg = [string]::Format( + " - Create {0} was successful!", + $messengerManifestPath) + Write-Host $msg + } else { + $msg = [string]::Format( + " - Create {0} failed, quitting ...", + $messengerManifestPath) + Write-Host $msg + exit -1 + } + + (Get-Content ` + $messengerManifestPath).replace( ` + $MessengerManifestReplaceStr, ` + $MessengerBinWrapperFilename) ` + | Set-Content -Encoding ascii $messengerManifestPath + + $found_pattern = (Select-String ` + -Path $messengerManifestPath ` + -Pattern $MessengerManifestReplaceStr ` + -CaseSensitive ` + | Select-Object Line) + + if (! $found_pattern) { + Write-Host ` + " - Patching $messengerManifestPath was successful!" + } + + return $result +} + +function Get-MessengerManifestRegistry(){ + $msg = [string]::Format("[+] Getting registry key {0} ...", + $global:MessengerManifestRegistryPath) + + Write-Host $msg + + $registry = Get-Item ` + -Path "$global:MessengerManifestRegistryPath" ` + -ErrorAction SilentlyContinue + + return $registry +} + +function Get-MessengerManifestRegistryValue(){ + $msg = [string]::Format( ` + "[+] Getting (Default) registry value {0} ...", + $global:MessengerManifestRegistryPath) + + Write-Host $msg + + $registryKey = Get-MessengerManifestRegistry + $registryValue = "" + + if ($registryKey) { + $registryValue = $registryKey."(Default)" ` + -eq $messengerManifestPath + } + + return $registryValue +} + +function Remove-MessengerManifestRegistry() { + $messengerManifestPath = Get-MessengerManifestPath + + $msg = [string]::Format("[+] Removing registry key {0} ...", + $global:MessengerManifestRegistryPath) + + Write-Host $msg + + Remove-Item ` + -Path "$global:MessengerManifestRegistryPath" ` + -Force ` + -ErrorAction SilentlyContinue + + $registryExists = Get-MessengerManifestRegistry + + if (! $registryExists) { + Write-Host " - Removing registry was successful!" + return $true + } else { + Write-Host " - Removing registry failed, quitting ..." + exit -1 + } +} +function Set-MessengerManifestRegistry() { + $messengerManifestPath = Get-MessengerManifestPath + + $msg = [string]::Format("[+] Adding registry key {0} ...", + $global:MessengerManifestRegistryPath) + + Write-Host $msg + + New-Item ` + -Path $global:MessengerManifestRegistryPath ` + -Force | Out-Null + + New-ItemProperty ` + -Path $global:MessengerManifestRegistryPath ` + -Name "(Default)" ` + -Value $messengerManifestPath ` + -Force | Out-Null + + if ((Get-ItemProperty ` + -Path $MessengerManifestRegistryPath)."(Default)" ` + -eq $messengerManifestPath) { + Write-Host " - Adding registry was successful!" + return $true + } else { + Write-Host " - Adding registry failed, quitting ..." + exit -1 + } +} + +function Set-MessengerInstall() { + # Check for Python 3 + + Write-Host "[+] Looking for Python 3 ..." + $pythonVersionStatus = Get-PythonVersionStatus + if (! $pythonVersionStatus) { + Write-Host " - Python 3 not found, quitting ..." + exit -1 + } else { + $pythonPath = Get-Command "py" | Select-Object "Source" + Write-Host " - Python 3 found at: $pythonPath" + } + + # Prepare `.tridactyl` directory + $result = Set-InstallDir + + # Prepare `native_main.py` + if ($result -eq $true) { + $result = Set-MessengerBin + } + + # Prepare `win_tridactyl.bat` + if ($result -eq $true) { + $result = Set-MessengerBinWrapper + } + + # Prepare `tridactyl.json` + if ($result -eq $true) { + $result = Set-MessengerManifest + } + + ## Add registry entry + if ($result -eq $true) { + $result = Set-MessengerManifestRegistry + } + + # + # If we are here passing all the checks above, installation is + # highly likely to have gone as expected. Let's do some final + # sanity checks before declaring "victory"! + # + + Write-Host "[+] Cross-checking everything ..." + $result1 = Test-TridactylPath (Get-MessengerManifestPath) + $result2 = Test-TridactylPath (Get-MessengerBinPath) + $result3 = Test-TridactylPath (Get-MessengerBinWrapperPath) + $result4 = Get-MessengerManifestRegistryValue + + if (($result1 -eq $true) ` + -and ($result2 -eq $true) ` + -and ($result3 -eq $true) ` + -and ($result4)) { + Write-Host "[+] Installation successful!" + Write-Host " - Run ':native' in Firefox to cross-check. :-)" + } else { + Write-Host "[+] Installation failed. :-(" + } +} + +## Perform `Uninstall` if requested +if ($global:Uninstall) { + Set-MessengerUninstall + exit 0 +} + +Set-MessengerInstall \ No newline at end of file