deskflow/scripts/lib/windows.py

237 lines
7.9 KiB
Python
Raw Normal View History

# Deskflow -- mouse and keyboard sharing utility
Use `vcpkg` to manage `openssl` dep instead of `choco` (#7471) * Brighter red * Move openssl to vcpkg.exe * Revert "Move openssl to vcpkg.exe" This reverts commit 36f39d916f3cc2c8ce779442bd964bd6af7edd69. * Add missing copyright * Fix copyright dates * Remove openssl from choco * Install openssl using vcpkg * Add deps for vcpkg * Add missing vcpkg manifest * Revert "Add deps for vcpkg" This reverts commit c266d29c2cec4474a181b89c2f759b62ed67db10. * Make vcpkg Windows only * Improve comment about vcpkg * Remove unused var * Add caching for vcpkg * Reorg launch.json * Remove static env var for openssl on Windows * Add openssl dep to vcpkg * Update ChangeLog * Add OpenSSL include dir * Remove pointless choco cache * Remove vcpkg downloads * Remove wixtoolset for CI already installed on GitHub runners * Use `Remove-Item` instead of `rmdir` * Move cmake and ninja out of choco * Revert "Move cmake and ninja out of choco (winget not supported on GitHub runner)" This reverts commit a65c02d275e58705b8cd86fac72629284191d737. * Move cmake and ninja to winget and don't use choco on CI * Remove winget action * Use scoop on CI and winget locally * Use `seanmiddleditch/gha-setup-ninja` for Ninja * Improve comments * Install Ninja before deps * Use system vcpkg if installed * Revert "Use system vcpkg if installed" This reverts commit 4ddee1c66e8cace458c047285a70d2f98cf9d82c. * Add comment about why we're using local vcpkg * Fixed comment about VC++ * Improve config comments * Delete dead code * Improve comment about vcpkg/buildtrees
2024-09-04 15:52:37 +00:00
# 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 <http://www.gnu.org/licenses/>.
import ctypes, sys, os, shutil, time, subprocess
import lib.cmd_utils as cmd_utils
import lib.env as env
import psutil # type: ignore
import lib.colors as colors
import lib.file_utils as file_utils
Use `vcpkg` to manage `openssl` dep instead of `choco` (#7471) * Brighter red * Move openssl to vcpkg.exe * Revert "Move openssl to vcpkg.exe" This reverts commit 36f39d916f3cc2c8ce779442bd964bd6af7edd69. * Add missing copyright * Fix copyright dates * Remove openssl from choco * Install openssl using vcpkg * Add deps for vcpkg * Add missing vcpkg manifest * Revert "Add deps for vcpkg" This reverts commit c266d29c2cec4474a181b89c2f759b62ed67db10. * Make vcpkg Windows only * Improve comment about vcpkg * Remove unused var * Add caching for vcpkg * Reorg launch.json * Remove static env var for openssl on Windows * Add openssl dep to vcpkg * Update ChangeLog * Add OpenSSL include dir * Remove pointless choco cache * Remove vcpkg downloads * Remove wixtoolset for CI already installed on GitHub runners * Use `Remove-Item` instead of `rmdir` * Move cmake and ninja out of choco * Revert "Move cmake and ninja out of choco (winget not supported on GitHub runner)" This reverts commit a65c02d275e58705b8cd86fac72629284191d737. * Move cmake and ninja to winget and don't use choco on CI * Remove winget action * Use scoop on CI and winget locally * Use `seanmiddleditch/gha-setup-ninja` for Ninja * Improve comments * Install Ninja before deps * Use system vcpkg if installed * Revert "Use system vcpkg if installed" This reverts commit 4ddee1c66e8cace458c047285a70d2f98cf9d82c. * Add comment about why we're using local vcpkg * Fixed comment about VC++ * Improve config comments * Delete dead code * Improve comment about vcpkg/buildtrees
2024-09-04 15:52:37 +00:00
LOCK_FILE = "tmp/elevated.lock"
RUNNER_TEMP_ENV = "RUNNER_TEMP"
SERVICE_NOT_RUNNING_ERROR = 2
ERROR_ACCESS_VIOLATION = 0xC0000005
Use `vcpkg` to manage `openssl` dep instead of `choco` (#7471) * Brighter red * Move openssl to vcpkg.exe * Revert "Move openssl to vcpkg.exe" This reverts commit 36f39d916f3cc2c8ce779442bd964bd6af7edd69. * Add missing copyright * Fix copyright dates * Remove openssl from choco * Install openssl using vcpkg * Add deps for vcpkg * Add missing vcpkg manifest * Revert "Add deps for vcpkg" This reverts commit c266d29c2cec4474a181b89c2f759b62ed67db10. * Make vcpkg Windows only * Improve comment about vcpkg * Remove unused var * Add caching for vcpkg * Reorg launch.json * Remove static env var for openssl on Windows * Add openssl dep to vcpkg * Update ChangeLog * Add OpenSSL include dir * Remove pointless choco cache * Remove vcpkg downloads * Remove wixtoolset for CI already installed on GitHub runners * Use `Remove-Item` instead of `rmdir` * Move cmake and ninja out of choco * Revert "Move cmake and ninja out of choco (winget not supported on GitHub runner)" This reverts commit a65c02d275e58705b8cd86fac72629284191d737. * Move cmake and ninja to winget and don't use choco on CI * Remove winget action * Use scoop on CI and winget locally * Use `seanmiddleditch/gha-setup-ninja` for Ninja * Improve comments * Install Ninja before deps * Use system vcpkg if installed * Revert "Use system vcpkg if installed" This reverts commit 4ddee1c66e8cace458c047285a70d2f98cf9d82c. * Add comment about why we're using local vcpkg * Fixed comment about VC++ * Improve config comments * Delete dead code * Improve comment about vcpkg/buildtrees
2024-09-04 15:52:37 +00:00
def run_elevated(script, args=None, use_sys_argv=True, wait_for_exit=False):
Use `vcpkg` to manage `openssl` dep instead of `choco` (#7471) * Brighter red * Move openssl to vcpkg.exe * Revert "Move openssl to vcpkg.exe" This reverts commit 36f39d916f3cc2c8ce779442bd964bd6af7edd69. * Add missing copyright * Fix copyright dates * Remove openssl from choco * Install openssl using vcpkg * Add deps for vcpkg * Add missing vcpkg manifest * Revert "Add deps for vcpkg" This reverts commit c266d29c2cec4474a181b89c2f759b62ed67db10. * Make vcpkg Windows only * Improve comment about vcpkg * Remove unused var * Add caching for vcpkg * Reorg launch.json * Remove static env var for openssl on Windows * Add openssl dep to vcpkg * Update ChangeLog * Add OpenSSL include dir * Remove pointless choco cache * Remove vcpkg downloads * Remove wixtoolset for CI already installed on GitHub runners * Use `Remove-Item` instead of `rmdir` * Move cmake and ninja out of choco * Revert "Move cmake and ninja out of choco (winget not supported on GitHub runner)" This reverts commit a65c02d275e58705b8cd86fac72629284191d737. * Move cmake and ninja to winget and don't use choco on CI * Remove winget action * Use scoop on CI and winget locally * Use `seanmiddleditch/gha-setup-ninja` for Ninja * Improve comments * Install Ninja before deps * Use system vcpkg if installed * Revert "Use system vcpkg if installed" This reverts commit 4ddee1c66e8cace458c047285a70d2f98cf9d82c. * Add comment about why we're using local vcpkg * Fixed comment about VC++ * Improve config comments * Delete dead code * Improve comment about vcpkg/buildtrees
2024-09-04 15:52:37 +00:00
if not args and use_sys_argv:
args = " ".join(sys.argv[1:])
if wait_for_exit:
args += f" --lock-file {LOCK_FILE}"
env.persist_lock_file(LOCK_FILE)
command = f"{script} {args} --pause-on-exit"
Use `vcpkg` to manage `openssl` dep instead of `choco` (#7471) * Brighter red * Move openssl to vcpkg.exe * Revert "Move openssl to vcpkg.exe" This reverts commit 36f39d916f3cc2c8ce779442bd964bd6af7edd69. * Add missing copyright * Fix copyright dates * Remove openssl from choco * Install openssl using vcpkg * Add deps for vcpkg * Add missing vcpkg manifest * Revert "Add deps for vcpkg" This reverts commit c266d29c2cec4474a181b89c2f759b62ed67db10. * Make vcpkg Windows only * Improve comment about vcpkg * Remove unused var * Add caching for vcpkg * Reorg launch.json * Remove static env var for openssl on Windows * Add openssl dep to vcpkg * Update ChangeLog * Add OpenSSL include dir * Remove pointless choco cache * Remove vcpkg downloads * Remove wixtoolset for CI already installed on GitHub runners * Use `Remove-Item` instead of `rmdir` * Move cmake and ninja out of choco * Revert "Move cmake and ninja out of choco (winget not supported on GitHub runner)" This reverts commit a65c02d275e58705b8cd86fac72629284191d737. * Move cmake and ninja to winget and don't use choco on CI * Remove winget action * Use scoop on CI and winget locally * Use `seanmiddleditch/gha-setup-ninja` for Ninja * Improve comments * Install Ninja before deps * Use system vcpkg if installed * Revert "Use system vcpkg if installed" This reverts commit 4ddee1c66e8cace458c047285a70d2f98cf9d82c. * Add comment about why we're using local vcpkg * Fixed comment about VC++ * Improve config comments * Delete dead code * Improve comment about vcpkg/buildtrees
2024-09-04 15:52:37 +00:00
print(f"Running script with elevated privileges: {command}")
WINDOW_HANDLE = None
OPERATION = "runas"
DIRECTORY = None
SHOW_CMD = 1
instance = ctypes.windll.shell32.ShellExecuteW(
WINDOW_HANDLE, OPERATION, sys.executable, command, DIRECTORY, SHOW_CMD
)
Use `vcpkg` to manage `openssl` dep instead of `choco` (#7471) * Brighter red * Move openssl to vcpkg.exe * Revert "Move openssl to vcpkg.exe" This reverts commit 36f39d916f3cc2c8ce779442bd964bd6af7edd69. * Add missing copyright * Fix copyright dates * Remove openssl from choco * Install openssl using vcpkg * Add deps for vcpkg * Add missing vcpkg manifest * Revert "Add deps for vcpkg" This reverts commit c266d29c2cec4474a181b89c2f759b62ed67db10. * Make vcpkg Windows only * Improve comment about vcpkg * Remove unused var * Add caching for vcpkg * Reorg launch.json * Remove static env var for openssl on Windows * Add openssl dep to vcpkg * Update ChangeLog * Add OpenSSL include dir * Remove pointless choco cache * Remove vcpkg downloads * Remove wixtoolset for CI already installed on GitHub runners * Use `Remove-Item` instead of `rmdir` * Move cmake and ninja out of choco * Revert "Move cmake and ninja out of choco (winget not supported on GitHub runner)" This reverts commit a65c02d275e58705b8cd86fac72629284191d737. * Move cmake and ninja to winget and don't use choco on CI * Remove winget action * Use scoop on CI and winget locally * Use `seanmiddleditch/gha-setup-ninja` for Ninja * Improve comments * Install Ninja before deps * Use system vcpkg if installed * Revert "Use system vcpkg if installed" This reverts commit 4ddee1c66e8cace458c047285a70d2f98cf9d82c. * Add comment about why we're using local vcpkg * Fixed comment about VC++ * Improve config comments * Delete dead code * Improve comment about vcpkg/buildtrees
2024-09-04 15:52:37 +00:00
ERROR_ACCESS_DENIED = 5
if instance == ERROR_ACCESS_DENIED:
raise RuntimeError(
f"Failed to run script with elevated privileges, access denied (code {instance})"
)
Use `vcpkg` to manage `openssl` dep instead of `choco` (#7471) * Brighter red * Move openssl to vcpkg.exe * Revert "Move openssl to vcpkg.exe" This reverts commit 36f39d916f3cc2c8ce779442bd964bd6af7edd69. * Add missing copyright * Fix copyright dates * Remove openssl from choco * Install openssl using vcpkg * Add deps for vcpkg * Add missing vcpkg manifest * Revert "Add deps for vcpkg" This reverts commit c266d29c2cec4474a181b89c2f759b62ed67db10. * Make vcpkg Windows only * Improve comment about vcpkg * Remove unused var * Add caching for vcpkg * Reorg launch.json * Remove static env var for openssl on Windows * Add openssl dep to vcpkg * Update ChangeLog * Add OpenSSL include dir * Remove pointless choco cache * Remove vcpkg downloads * Remove wixtoolset for CI already installed on GitHub runners * Use `Remove-Item` instead of `rmdir` * Move cmake and ninja out of choco * Revert "Move cmake and ninja out of choco (winget not supported on GitHub runner)" This reverts commit a65c02d275e58705b8cd86fac72629284191d737. * Move cmake and ninja to winget and don't use choco on CI * Remove winget action * Use scoop on CI and winget locally * Use `seanmiddleditch/gha-setup-ninja` for Ninja * Improve comments * Install Ninja before deps * Use system vcpkg if installed * Revert "Use system vcpkg if installed" This reverts commit 4ddee1c66e8cace458c047285a70d2f98cf9d82c. * Add comment about why we're using local vcpkg * Fixed comment about VC++ * Improve config comments * Delete dead code * Improve comment about vcpkg/buildtrees
2024-09-04 15:52:37 +00:00
ERROR_MAX = 32
if instance <= ERROR_MAX:
raise RuntimeError(
f"Failed to run script with elevated privileges, error code: {instance}"
)
print("Script is running with elevated privileges")
if wait_for_exit:
with open(LOCK_FILE, "r") as f:
pid = f.read()
Use `vcpkg` to manage `openssl` dep instead of `choco` (#7471) * Brighter red * Move openssl to vcpkg.exe * Revert "Move openssl to vcpkg.exe" This reverts commit 36f39d916f3cc2c8ce779442bd964bd6af7edd69. * Add missing copyright * Fix copyright dates * Remove openssl from choco * Install openssl using vcpkg * Add deps for vcpkg * Add missing vcpkg manifest * Revert "Add deps for vcpkg" This reverts commit c266d29c2cec4474a181b89c2f759b62ed67db10. * Make vcpkg Windows only * Improve comment about vcpkg * Remove unused var * Add caching for vcpkg * Reorg launch.json * Remove static env var for openssl on Windows * Add openssl dep to vcpkg * Update ChangeLog * Add OpenSSL include dir * Remove pointless choco cache * Remove vcpkg downloads * Remove wixtoolset for CI already installed on GitHub runners * Use `Remove-Item` instead of `rmdir` * Move cmake and ninja out of choco * Revert "Move cmake and ninja out of choco (winget not supported on GitHub runner)" This reverts commit a65c02d275e58705b8cd86fac72629284191d737. * Move cmake and ninja to winget and don't use choco on CI * Remove winget action * Use scoop on CI and winget locally * Use `seanmiddleditch/gha-setup-ninja` for Ninja * Improve comments * Install Ninja before deps * Use system vcpkg if installed * Revert "Use system vcpkg if installed" This reverts commit 4ddee1c66e8cace458c047285a70d2f98cf9d82c. * Add comment about why we're using local vcpkg * Fixed comment about VC++ * Improve config comments * Delete dead code * Improve comment about vcpkg/buildtrees
2024-09-04 15:52:37 +00:00
print(f"Waiting for elevated process to exit: {pid}")
while os.path.exists(LOCK_FILE):
# Intentionally wait forever, since this code should not run where a developer
# has no control, such as in a CI environment.
pass
def is_admin():
"""Returns True if the current process has admin privileges."""
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except ctypes.WinError:
return False
Re-implement packaging for GitHub workflows (macOS) (#7353) * Restore Azure macOS dist scripts * Move steps to workflow for testing * Always upload to GitHub * Add codesign ID * Echo codesign ID * Add cert import code * Stub file for Mac * Self-install pyyaml and choco * Auto add env var on Windows * Auto add CMAKE_PREFIX_PATH to .zshrc * Shorter var names * Append env var instead of replace * Only set env var if not CI * Improve function names and print output * Simplify Linux package command * Support continuation sequence * Add note about Windows * Remove dead doc file * Tidy up version file and move to .env format * Use Python venv for deps * Only use venv on Mac * Rename package script for all OS * Add package and dist steps, and use common upload * Remove version source * Fixed vars not available * Fixed python paths * Use RuntimeError which is sufficient * Remove dead code * Add extras command for Linux * Always install deps on Linux * Move Python deps to CI * More env bootstrapping, ugh * Forgot to return! * Simplify code * Use shell * Simplify command * Skip sudo if no sudo * Update package managers * Fixed Fedora package name * Tidy up commands * Use newer upload artifact * Strip don't trim! * Check for version file and reduce log verbosity * Remove CentOS 7.6 * Print more info about return code and log more to stderr * Install certificate on macOS * Better errors for no env var * Implement Mac signing and notary * Move dmgbuild load * Simplify notary * Rename dist files to same as dest * Fixed paths for dist * Move checked-in dist files to res (dist is meant to be a temp dir) * Fixed Mac path in CMake * Fixed dmg path * Format Python * Ignore import warnings and move function * Fixed cmake paths * Add missing env var secrets * Remove extensions from GH upload * Make deps.yml general purpose config * Add cspell config * Pass codesign ID * Use new general config file * Sign bundle on Mac * Move imports to functions * Escape chars in docs * Fixed config key accessor * Change module import order * Move file to tmp dir in workflow dir * Persist temp dir * Add tmp dir to ignore * Flush stdio before running process * Trying quotes around env values * Add codesigning certificate validation for Mac signing * Revert "Trying quotes around env values" This reverts commit 0dd741e8cd6fde21e69d4fb871e835a5f4fa1a23. * Extract codesign verify * Fixed version number * Ignore .cache dir * Fix macro name * Package name with version number and arch * Improve package function readability * Change order of vars * Testing upload to GDrive * Add missing return code * Use positional args and declare error * Use machine instead of arch and remove build from filename * Remove redundant build jobs * Replace massively over-complicated `build_version.py` script * Move version info to env module * Use version info script * Fixed: too many values to unpack * Chmod version script * Use shebang * Don't check return code on Linux * Fixed function name * Convert to GitHub specific script * Env vars must be after configure * Fixed Windows env var command * Remove && from deps command so it's not conditional * Fixed position of set env * Change order of env script * Only upload when not draft * Test * Tweak config * Fixed if condition * Don't package in draft (Windows and Linux)
2024-06-24 09:36:30 +00:00
def set_env_var(name, value):
"""
Sets or updates an environment variable. Appends the value if it doesn't already exist.
Args:
name (str): The name of the environment variable.
value (str): The value of the environment variable.
"""
current_value = os.getenv(name, "")
if value not in current_value:
new_value = f"{current_value}{os.pathsep}{value}" if current_value else value
os.environ[name] = new_value
print(f"Setting environment variable: {name}={value}")
cmd_utils.run(["setx", name, new_value], check=True, shell=True, print_cmd=True)
def assert_vs_cmd(cmd):
has_cmd = cmd_utils.has_command(cmd)
if not has_cmd:
raise RuntimeError(
f"The '{cmd}' command was not found, "
"re-run from 'Developer Command Prompt for VS'"
)
class WindowsService:
def __init__(self, script, args):
self.script = script
self.verbose = args.verbose
self.bin_name = args.bin_name
self.source_dir = os.path.abspath(args.source_dir)
self.target_dir = os.path.abspath(args.target_dir)
self.service_id = args.service_id
self.ignore_processes = args.ignore_processes
def print_verbose(self, message):
if self.verbose:
print(message)
def ensure_admin(self):
if not is_admin():
run_elevated(self.script)
sys.exit()
def restart(self):
"""Stops the daemon service, copies files, and restarts the daemon service."""
self.ensure_admin()
self.stop()
self.copy_files()
self.start()
def reinstall(self):
"""Stops and uninstalls daemon service, copies files, and reinstalls the daemon service."""
self.ensure_admin()
self.stop()
source_bin_path = f"{os.path.join(self.source_dir, self.bin_name)}.exe"
self.copy_files()
print("Removing old daemon service")
try:
subprocess.run([source_bin_path, "/uninstall"], shell=True, check=True)
except subprocess.CalledProcessError as e:
self.check_access_violation(e.returncode, source_bin_path)
if e.returncode != 0:
print(
f"{colors.WARNING_TEXT} Uninstall failed, return code: {e.returncode}",
file=sys.stderr,
)
target_bin_path = os.path.join(self.target_dir, self.bin_name + ".exe")
try:
print("Installing daemon service")
subprocess.run([target_bin_path, "/install"], shell=True, check=True)
except subprocess.CalledProcessError as e:
self.check_access_violation(e.returncode, target_bin_path)
if e.returncode != 0:
print(
f"{colors.WARNING_TEXT} Install failed, return code: {e.returncode}"
)
def copy_files(self):
options = file_utils.CopyOptions(ignore_errors=True, verbose=False)
print(f"Copying files from {self.source_dir} to {self.target_dir}")
file_utils.copy(f"{self.source_dir}/*", self.target_dir, options)
def stop(self):
self.ensure_admin()
print("Stopping daemon service")
try:
subprocess.run(["net", "stop", self.service_id], shell=True, check=True)
except subprocess.CalledProcessError as e:
if e.returncode == SERVICE_NOT_RUNNING_ERROR:
self.print_verbose("Daemon service not running")
else:
raise e
# Wait for Windows to release the file handles after process termination.
self.wait_for_stop()
def start(self):
self.ensure_admin()
print("Starting daemon service")
subprocess.run(["net", "start", self.service_id], shell=True, check=True)
def wait_for_stop(self):
if self.is_any_process_running(self.target_dir):
print("Waiting for file handles to release...", end="", flush=True)
while self.is_any_process_running(self.target_dir):
if not self.verbose:
print(".", end="", flush=True)
time.sleep(1)
if not self.verbose:
print()
def check_access_violation(self, return_code, bin_path):
if return_code == ERROR_ACCESS_VIOLATION:
print(
f"{colors.WARNING_TEXT} Process crashed with memory access violation: {bin_path}",
file=sys.stderr,
)
def is_ignored_process(self, exe):
for ignore_process in self.ignore_processes:
if exe.endswith(ignore_process):
return True
return False
def is_any_process_running(self, dir):
"""Check if there is any running process that contains the given directory."""
self.print_verbose(f"Checking if any process is running in: {dir}")
for proc in psutil.process_iter(attrs=["name", "exe"]):
exe = proc.info["exe"]
if not exe:
self.print_verbose(f"Skipping process with no exe: {proc}")
continue
if self.is_ignored_process(exe):
self.print_verbose(f"Ignoring process: {exe}")
continue
try:
if dir.lower() in exe.lower():
self.print_verbose(f"Process found: {exe}")
return True
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
return False