diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index af4beda84..6d0d008be 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -218,13 +218,10 @@ jobs: - name: Build shell: bash run: | - if [[ "$RUNNER_OS" != "Windows" && "${{matrix.target.like}}" != "arch" ]]; then + if [[ "${{matrix.target.like}}" != "arch" ]]; then cmake --build build --config Release -j8 --target package else - cmake --build build -j8 - fi - - if [ ${{ matrix.target.like }} == "arch" ];then + cmake --build build --config Release -j8 useradd -m build sudo chown -R build build cd build @@ -241,16 +238,6 @@ jobs: with: job: ${{ matrix.target.name }} - - name: Package - if: ${{ runner.os == 'Windows' }} - shell: bash - run: | - python ./scripts/package.py --package-version ${{env.DESKFLOW_PACKAGE_VERSION}} - mv dist/deskflow* build/ - env: - WINDOWS_PFX_CERTIFICATE: ${{ secrets.WINDOWS_PFX }} - WINDOWS_PFX_PASSWORD: ${{ secrets.WINDOWS_PFX_PASS }} - - name: Upload uses: actions/upload-artifact@v4 with: diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index b8eff8694..74909ae9b 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -69,45 +69,3 @@ macro(configure_linux_package_name) set(OS_STRING "${DISTRO_NAME}-${CN_STRING}${CMAKE_SYSTEM_PROCESSOR}") endmacro() - -# -# Same as the `configure_file` command but for directories recursively. -# -macro(configure_files srcDir destDir) - - message(VERBOSE "Configuring directory ${destDir}") - make_directory(${destDir}) - - file( - GLOB_RECURSE sourceFiles - RELATIVE ${srcDir} - ${srcDir}/*) - file( - GLOB_RECURSE templateFiles - LIST_DIRECTORIES false - RELATIVE ${srcDir} - ${srcDir}/*.in) - list(REMOVE_ITEM sourceFiles ${templateFiles}) - - foreach(sourceFile ${sourceFiles}) - set(sourceFilePath ${srcDir}/${sourceFile}) - if(IS_DIRECTORY ${sourceFilePath}) - message(VERBOSE "Copying directory ${sourceFile}") - make_directory(${destDir}/${sourceFile}) - else() - message(VERBOSE "Copying file ${sourceFile}") - configure_file(${sourceFilePath} ${destDir}/${sourceFile} COPYONLY) - endif() - - endforeach(sourceFile) - - foreach(templateFile ${templateFiles}) - - set(sourceTemplateFilePath ${srcDir}/${templateFile}) - string(REGEX REPLACE "\.in$" "" templateFile ${templateFile}) - message(VERBOSE "Configuring file ${templateFile}") - configure_file(${sourceTemplateFilePath} ${destDir}/${templateFile} @ONLY) - - endforeach(templateFile) - -endmacro(configure_files) diff --git a/deploy/CMakeLists.txt b/deploy/CMakeLists.txt index 800bf9867..e50ebeee4 100644 --- a/deploy/CMakeLists.txt +++ b/deploy/CMakeLists.txt @@ -76,15 +76,6 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") set(CPACK_WIX_UPGRADE_GUID "027D1C8A-E7A5-4754-BB93-B2D45BFDBDC8") - # TODO RM with legacy WIX Builder - cmake_path(SET QT_PATH NORMALIZE "${Qt6_DIR}../../") - - # TODO RM with legacy WIX Builder - configure_files( - ${PROJECT_SOURCE_DIR}/deploy/dist/wix - ${PROJECT_BINARY_DIR}/installer - ) - set(CPACK_WIX_UI_BANNER "${CMAKE_CURRENT_SOURCE_DIR}/wix-banner.png") set(CPACK_WIX_UI_DIALOG "${CMAKE_CURRENT_SOURCE_DIR}/wix-dialog.png") set(CPACK_WIX_MSM_FILE "${CMAKE_CURRENT_SOURCE_DIR}/Microsoft_VC142_CRT_x64.msm") diff --git a/deploy/dist/wix/AppBrowseDlg.wxs b/deploy/dist/wix/AppBrowseDlg.wxs deleted file mode 100644 index 9497816e6..000000000 --- a/deploy/dist/wix/AppBrowseDlg.wxs +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - 1 - 1 - - - 1 - 1 - - - - - - - 1 - - - 1 - - - - - - - - - - diff --git a/deploy/dist/wix/AppDlgSequence.wxs b/deploy/dist/wix/AppDlgSequence.wxs deleted file mode 100644 index 2acb0099d..000000000 --- a/deploy/dist/wix/AppDlgSequence.wxs +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 1 - "1"]]> - - 1 - NOT Installed - - 1 - Installed AND PATCH - - 1 - NOT WIXUI_DONTVALIDATEPATH - "1"]]> - WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1" - 1 - 1 - 1 - - NOT Installed - Installed AND NOT PATCH - Installed AND PATCH - - 1 - - 1 - 1 - 1 - - - - - - - diff --git a/deploy/dist/wix/AppInstallDirDlg.wxs b/deploy/dist/wix/AppInstallDirDlg.wxs deleted file mode 100644 index 6f1afefd0..000000000 --- a/deploy/dist/wix/AppInstallDirDlg.wxs +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/deploy/dist/wix/AppMaintenanceTypeDlg.wxs b/deploy/dist/wix/AppMaintenanceTypeDlg.wxs deleted file mode 100644 index d93473d0f..000000000 --- a/deploy/dist/wix/AppMaintenanceTypeDlg.wxs +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - 1 - ARPNOMODIFY - - - ARPNOMODIFY - - - - 1 - ARPNOREPAIR - - - ARPNOREPAIR - - - - 1 - ARPNOREMOVE - - - ARPNOREMOVE - - - - - - 1 - - - - - - - diff --git a/deploy/dist/wix/AppVerifyReadyDlg.wxs b/deploy/dist/wix/AppVerifyReadyDlg.wxs deleted file mode 100644 index 950246d99..000000000 --- a/deploy/dist/wix/AppVerifyReadyDlg.wxs +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - WixUI_InstallMode = "Remove" - - - - - - - diff --git a/deploy/dist/wix/AppWelcome.wxs b/deploy/dist/wix/AppWelcome.wxs deleted file mode 100644 index 6e63f352a..000000000 --- a/deploy/dist/wix/AppWelcome.wxs +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - welcome_background - - - - - Installed AND PATCH - - - 1 - - - - - - - - NOT Installed OR PATCH - - - - diff --git a/deploy/dist/wix/DeskflowDlgSequence.wxs b/deploy/dist/wix/DeskflowDlgSequence.wxs deleted file mode 100644 index 7ec9e57a7..000000000 --- a/deploy/dist/wix/DeskflowDlgSequence.wxs +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 1 - "1"]]> - - 1 - NOT Installed - - 1 - Installed AND PATCH - - 1 - NOT WIXUI_DONTVALIDATEPATH - "1"]]> - WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1" - 1 - 1 - 1 - - NOT Installed - Installed AND NOT PATCH - Installed AND PATCH - - 1 - - 1 - 1 - 1 - - - - - - - diff --git a/deploy/dist/wix/Include.wxi.in b/deploy/dist/wix/Include.wxi.in deleted file mode 100644 index d70249e44..000000000 --- a/deploy/dist/wix/Include.wxi.in +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/deploy/dist/wix/Installer.sln b/deploy/dist/wix/Installer.sln deleted file mode 100644 index e58a2f5f6..000000000 --- a/deploy/dist/wix/Installer.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29411.108 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Installer", "Installer.wixproj", "{D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Debug|x64.ActiveCfg = Debug|x64 - {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Debug|x64.Build.0 = Debug|x64 - {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Release|x64.ActiveCfg = Release|x64 - {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {2E0AA1C9-0F14-4FE4-8F18-430484EFBACE} - EndGlobalSection -EndGlobal diff --git a/deploy/dist/wix/Installer.wixproj b/deploy/dist/wix/Installer.wixproj deleted file mode 100644 index 9a2f339fa..000000000 --- a/deploy/dist/wix/Installer.wixproj +++ /dev/null @@ -1,41 +0,0 @@ - - - - 3.11 - {d4ba9f39-6a35-4c8f-9cb2-67fcbe5cab17} - 2.0 - Installer - Package - bin\$(Configuration)\ - wix\obj\$(Configuration)\ - - - - - - - - - - - - - - - C:\Program Files (x86)\WiX Toolset v3.11\bin\WixUtilExtension.dll - WixUtilExtension - - - C:\Program Files (x86)\WiX Toolset v3.11\bin\WixUIExtension.dll - WixUIExtension - - - C:\Program Files (x86)\WiX Toolset v3.11\bin\WixFirewallExtension.dll - WixFirewallExtension - - - - - \ No newline at end of file diff --git a/deploy/dist/wix/Product.wxs b/deploy/dist/wix/Product.wxs deleted file mode 100644 index 16d6be793..000000000 --- a/deploy/dist/wix/Product.wxs +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - = 602)]]> - - - - CommonBackground - - - - - - - - - - - - NOT LEGACY_UNINSTALL_EXISTS - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/deploy/dist/wix/images/common_background.png b/deploy/dist/wix/images/common_background.png deleted file mode 100644 index 78dd8045d..000000000 Binary files a/deploy/dist/wix/images/common_background.png and /dev/null differ diff --git a/deploy/dist/wix/images/welcome_background.png b/deploy/dist/wix/images/welcome_background.png deleted file mode 100644 index ef39002cb..000000000 Binary files a/deploy/dist/wix/images/welcome_background.png and /dev/null differ diff --git a/scripts/lib/certificate.py b/scripts/lib/certificate.py deleted file mode 100644 index 927cbacb2..000000000 --- a/scripts/lib/certificate.py +++ /dev/null @@ -1,55 +0,0 @@ -import os, base64 - -# Deskflow -- mouse and keyboard sharing utility -# Copyright (C) 2024 Symless Ltd. -# -# This package is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# found in the file LICENSE that should have accompanied this file. -# -# This package is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -temp_path = "tmp/certificate" - - -class Certificate: - """ - Installs a certificate from a base64 string, and returns the path to the certificate. - Once the context is exited, the certificate is removed from the filesystem. - - Example usage: - with Certificate(base64) as cert_path: - print(f"Certificate path: {cert_path}") - """ - - def __init__(self, base64, file_ext): - self.base64 = base64 - self.temp_filename = f"{temp_path}.{file_ext}" - - def __enter__(self): - print(f"Decoding certificate to temporary path: {self.temp_filename}") - try: - cert_bytes = base64.b64decode(self.base64) - except Exception as e: - raise ValueError("Failed to decode certificate base64") from e - - os.makedirs(os.path.dirname(self.temp_filename), exist_ok=True) - with open(self.temp_filename, "wb") as cert_file: - cert_file.write(cert_bytes) - - return self.temp_filename - - def __exit__(self, _exc_type, _exc_value, _traceback): - # not strictly necessary for ci, but when run on a dev machine, it reduces the risk - # that private keys are left on the filesystem - print(f"Removing temporary certificate file: {self.temp_filename}") - os.remove(self.temp_filename) - - # propagate exceptions - return False diff --git a/scripts/lib/windows.py b/scripts/lib/windows.py index 1ca6ea2a9..b717451f2 100644 --- a/scripts/lib/windows.py +++ b/scripts/lib/windows.py @@ -14,18 +14,13 @@ # along with this program. If not, see . import ctypes, sys, os, shutil, time, subprocess -import xml.etree.ElementTree as ET import lib.cmd_utils as cmd_utils import lib.env as env import psutil # type: ignore -from lib.certificate import Certificate import lib.colors as colors import lib.file_utils as file_utils LOCK_FILE = "tmp/elevated.lock" -MSBUILD_CMD = "msbuild" -SIGNTOOL_CMD = "signtool" -CERTUTIL_CMD = "certutil" RUNNER_TEMP_ENV = "RUNNER_TEMP" SERVICE_NOT_RUNNING_ERROR = 2 ERROR_ACCESS_VIOLATION = 0xC0000005 @@ -100,24 +95,6 @@ def set_env_var(name, value): print(f"Setting environment variable: {name}={value}") cmd_utils.run(["setx", name, new_value], check=True, shell=True, print_cmd=True) - -def package(filename_base, build_dir, dist_dir): - cert_env_key = "WINDOWS_PFX_CERTIFICATE" - cert_base64 = env.get_env(cert_env_key, required=False) - packager = WindowsPackager(filename_base, build_dir, dist_dir) - - if cert_base64: - cert_password = env.get_env("WINDOWS_PFX_PASSWORD") - packager.sign_binaries(cert_base64, cert_password) - - packager.build_msi() - - if cert_base64: - packager.sign_msi(cert_base64, cert_password) - else: - print(f"Skipped code signing, env var not set: {cert_env_key}") - - def assert_vs_cmd(cmd): has_cmd = cmd_utils.has_command(cmd) if not has_cmd: @@ -126,76 +103,6 @@ def assert_vs_cmd(cmd): "re-run from 'Developer Command Prompt for VS'" ) - -def run_codesign(path, cert_base64, cert_password): - time_server = "http://timestamp.digicert.com" - hashing_algorithm = "SHA256" - - with Certificate(cert_base64, "pfx") as cert_path: - print("Signing MSI installer...") - assert_vs_cmd(SIGNTOOL_CMD) - - # WARNING: contains private key password, never print this command - cmd_utils.run( - [ - SIGNTOOL_CMD, - "sign", - "/f", - cert_path, - "/p", - cert_password, - "/t", - time_server, - "/fd", - hashing_algorithm, - path, - ] - ) - - -class WindowsPackager: - - def __init__(self, filename_base, build_dir, dist_dir): - self.filename_base = filename_base - self.build_dir = build_dir - self.dist_dir = dist_dir - self.wix_file = f"{build_dir}/installer/Installer.sln" - self.msi_file = f"{build_dir}/installer/bin/Release/Installer.msi" - - def build_msi(self): - print("Building MSI installer...") - configuration = "Release" - platform = "x64" - - assert_vs_cmd(MSBUILD_CMD) - cmd_utils.run( - [ - MSBUILD_CMD, - self.wix_file, - f"/p:Configuration={configuration}", - f"/p:Platform={platform}", - ], - shell=True, - print_cmd=True, - ) - - path = self.get_package_path() - print(f"Copying MSI installer to {self.dist_dir}") - os.makedirs(self.dist_dir, exist_ok=True) - shutil.copy(self.msi_file, path) - - def get_package_path(self): - return f"{self.dist_dir}/{self.filename_base}.msi" - - def sign_binaries(self, cert_base64, cert_password): - exe_pattern = f"{self.build_dir}/bin/*.exe" - run_codesign(exe_pattern, cert_base64, cert_password) - - def sign_msi(self, cert_base64, cert_password): - path = self.get_package_path() - run_codesign(path, cert_base64, cert_password) - - class WindowsService: def __init__(self, script, args): self.script = script diff --git a/scripts/package.py b/scripts/package.py deleted file mode 100755 index bcb91a5d4..000000000 --- a/scripts/package.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python3 - -# Deskflow -- mouse and keyboard sharing utility -# Copyright (C) 2024 Symless Ltd. -# -# This package is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# found in the file LICENSE that should have accompanied this file. -# -# This package is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import lib.env as env - -env.ensure_in_venv(__file__) - -import argparse -import platform -from dotenv import load_dotenv # type: ignore - -ENV_FILE = ".env" -DEFAULT_FILENAME_BASE = "deskflow" -DEFAULT_PROJECT_BUILD_DIR = "build" -DEFAULT_DIST_DIR = "dist" -DEFAULT_PACKAGE_NAME = "deskflow" - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - "--package-version", - help="Set the Package Version", - required=True) - parser.add_argument( - "--leave-test-installed", - action="store_true", - help="Leave test package installed", - ) - args = parser.parse_args() - - load_dotenv(dotenv_path=ENV_FILE) - - package( - DEFAULT_FILENAME_BASE, - DEFAULT_PROJECT_BUILD_DIR, - DEFAULT_DIST_DIR, - version=args.package_version, - ) - -def package( - filename_prefix, - project_build_dir, - dist_dir, - version, -): - filename_base = get_filename_base(version, filename_prefix) - print(f"Package filename base: {filename_base}") - - if env.is_windows(): - windows_package(filename_base, project_build_dir, dist_dir) - else: - raise RuntimeError(f"Unsupported platform: {env.get_os()}") - - -def get_filename_base(version, prefix): - os = env.get_os() - machine = platform.machine().lower() - os_part = os - - if os == "windows": - # Some Windows users get confused by 'amd64' and think it's 'arm64', - # so we'll use Intel's 'x64' branding (even though it's wrong). - # Also replace 'x86_64' with 'x64' for consistency. - os_part= "win" - if machine == "amd64" or machine == "x86_64": - machine = "x64" - return f"{prefix}-{version}-{os_part}-{machine}" - - - -def windows_package(filename_base, project_build_dir, dist_dir): - import lib.windows as windows - - windows.package(filename_base, project_build_dir, dist_dir) - -if __name__ == "__main__": - main()