import subprocess import os import sys import logging # --- Configuration for Code Signing --- # !!! IMPORTANT: Replace these placeholders with your actual details !!! # Path to your .pfx or .p12 certificate file CERTIFICATE_PATH = r"C:\Path\To\Your\my_certificate.pfx" # Password for your certificate file CERTIFICATE_PASSWORD = "YourSecureCertificatePassword" # Path to signtool.exe (usually in Windows SDK bin folder) # You might need to adjust the version number (e.g., 10.0.19041.0) and architecture (x64/x86) SIGNTOOL_PATH = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe" # Name of your PyInstaller-generated executable (found in the 'dist' folder) EXE_NAME = "JarvisKeyPressUtility.exe" # Timestamp server URL (use one provided by your CA, e.g., DigiCert, Sectigo) TIMESTAMP_SERVER = "http://timestamp.digicert.com" # --- Logging Setup --- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') def run_command(command, cwd=None): """Executes a shell command and captures its output.""" try: logging.info(f"Executing command: {' '.join(command)}") process = subprocess.run(command, capture_output=True, text=True, check=True, cwd=cwd) logging.info("Command completed successfully.") logging.info(f"STDOUT:\n{process.stdout}") if process.stderr: logging.warning(f"STDERR:\n{process.stderr}") return True except subprocess.CalledProcessError as e: logging.error(f"Command failed with exit code {e.returncode}.") logging.error(f"STDOUT:\n{e.stdout}") logging.error(f"STDERR:\n{e.stderr}") return False except FileNotFoundError: logging.error(f"Error: Executable not found. Check the path for: {command[0]}") return False except Exception as e: logging.error(f"An unexpected error occurred: {e}") return False def sign_executable(exe_path, cert_path, cert_password, signtool_path, timestamp_server): """ Signs the given executable using signtool.exe. """ if not os.path.exists(signtool_path): logging.error(f"SignTool not found at: {signtool_path}. Please ensure Windows SDK is installed and path is correct.") return False if not os.path.exists(cert_path): logging.error(f"Certificate file not found at: {cert_path}. Please check the path.") return False logging.info(f"Attempting to sign executable: {exe_path}") # Signtool command components command = [ signtool_path, "sign", "/f", cert_path, # Certificate file "/p", cert_password, # Certificate password "/fd", "sha256", # File digest algorithm "/tr", timestamp_server, # Timestamp server URL "/td", "sha256", # Timestamp digest algorithm exe_path # Executable to sign ] return run_command(command) if __name__ == "__main__": # Ensure this script is run from the same directory where 'dist' folder is or adjust paths. # Typically, you'd run this script after PyInstaller has finished its build. current_script_dir = os.path.dirname(os.path.abspath(__file__)) dist_folder = os.path.join(current_script_dir, "dist") exe_path_in_dist = os.path.join(dist_folder, EXE_NAME) if not os.path.exists(dist_folder): logging.error(f"Error: 'dist' folder not found at '{dist_folder}'. Please run PyInstaller first.") sys.exit(1) if not os.path.exists(exe_path_in_dist): # Handle --onefile vs. no --onefile if not os.path.exists(os.path.join(dist_folder, EXE_NAME.replace(".exe", ""), EXE_NAME)): logging.error(f"Error: Executable '{EXE_NAME}' not found in '{dist_folder}' or its subfolder (for non-onefile builds).") logging.info("If you used PyInstaller without --onefile, the EXE might be in a subfolder like 'dist/JarvisKeyPressUtility/JarvisKeyPressUtility.exe'.") sys.exit(1) else: exe_path_to_sign = os.path.join(dist_folder, EXE_NAME.replace(".exe", ""), EXE_NAME) logging.info(f"Detected non-onefile build. Signing: {exe_path_to_sign}") else: exe_path_to_sign = exe_path_in_dist logging.info(f"Detected onefile build. Signing: {exe_path_to_sign}") logging.info("Starting code signing process.") success = sign_executable(exe_path_to_sign, CERTIFICATE_PATH, CERTIFICATE_PASSWORD, SIGNTOOL_PATH, TIMESTAMP_SERVER) if success: logging.info(f"Successfully signed '{EXE_NAME}'. Your AVG should now be less annoyed, theoretically.") else: logging.error(f"Failed to sign '{EXE_NAME}'. Check the log for details on the signtool error.")