105 lines
4.7 KiB
Python
105 lines
4.7 KiB
Python
|
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.")
|