Last active
October 18, 2025 00:51
-
-
Save Ciarands/be182eb4f58ae1338715e03f91010c4d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| import sys | |
| import shutil | |
| import zipfile | |
| import platform | |
| import tempfile | |
| MAX_BACKUPS = 5 | |
| PATCHES = { | |
| "chrome/devtools/modules/devtools/server/actors/thread.js": { | |
| "find": """ // But just in case, avoid any possible duplicate call to attach. | |
| if (this.alreadyAttached) { | |
| return; | |
| }""", | |
| "replace": """ // But just in case, avoid any possible duplicate call to attach. | |
| if (this.alreadyAttached || true) { | |
| return; | |
| }""" | |
| }, | |
| "chrome/devtools/modules/devtools/server/actors/webconsole/listeners/console-api.js": { | |
| "find": """ onConsoleAPILogEvent(message) { | |
| if (!this.handler) { | |
| return; | |
| }""", | |
| "replace": """ onConsoleAPILogEvent(message) { | |
| if (!this.handler || true) { | |
| return; | |
| }""" | |
| } | |
| } | |
| def is_elevated(): | |
| system = platform.system() | |
| if system == "Windows": | |
| try: | |
| import ctypes | |
| return ctypes.windll.shell32.IsUserAnAdmin() | |
| except Exception: | |
| return False | |
| else: | |
| return hasattr(os, 'geteuid') and os.geteuid() == 0 | |
| def get_possible_paths(): | |
| system = platform.system() | |
| paths = [] | |
| if system == "Windows": | |
| base_dirs = [ | |
| os.getenv("PROGRAMFILES"), | |
| os.getenv("PROGRAMFILES(X86)"), | |
| os.path.expanduser("~\\AppData\\Local"), | |
| ] | |
| for base in base_dirs: | |
| if base: | |
| paths.append(os.path.join(base, "LibreWolf", "browser")) | |
| paths.append(os.path.join(base, "LibreWolf")) | |
| elif system == "Darwin": # macOS | |
| paths = [ | |
| "/Applications/LibreWolf.app/Contents/Resources/browser", | |
| "/Applications/LibreWolf.app/Contents/Resources", | |
| ] | |
| elif system == "Linux": | |
| paths = [ | |
| "/opt/librewolf/browser", | |
| "/usr/lib/librewolf/browser", | |
| "/usr/share/librewolf/browser", | |
| "/usr/local/lib/librewolf/browser", | |
| os.path.expanduser("~/.librewolf/browser"), | |
| ] | |
| omni_candidates = [] | |
| for path in paths: | |
| if os.path.isdir(path): | |
| omni_path = os.path.join(path, "omni.ja") | |
| omni_candidates.append(omni_path) | |
| return omni_candidates | |
| def create_backup(path): | |
| backup_dir = os.path.dirname(path) | |
| base_name = os.path.basename(path) | |
| existing_backups = sorted([f for f in os.listdir(backup_dir) if f.startswith(f"{base_name}.") and f.endswith(".bak")]) | |
| if len(existing_backups) >= MAX_BACKUPS: | |
| oldest_backup = os.path.join(backup_dir, existing_backups[0]) | |
| print(f"Reached maximum number of backups ({MAX_BACKUPS}). Oldest backup: {oldest_backup}") | |
| print("Please remove a backup file manually and re-run the patcher. Exiting.") | |
| sys.exit(1) | |
| for i in range(MAX_BACKUPS): | |
| backup_path = f"{path}.{i}.bak" | |
| if not os.path.exists(backup_path): | |
| print(f"Backing up {path} to: {backup_path}") | |
| try: | |
| shutil.copy2(path, backup_path) | |
| print(f"Backup created successfully.") | |
| return True | |
| except Exception as e: | |
| print(f"Failed to create backup: {e}") | |
| return False | |
| print("Could not find an available backup slot. This should not happen.") | |
| return False | |
| def patch_file(path): | |
| if not create_backup(path): | |
| print("Aborting patch due to backup failure.") | |
| return | |
| temp_dir = tempfile.gettempdir() | |
| temp_omni_path = os.path.join(temp_dir, "omni.ja.patched") | |
| patches_applied_count = 0 | |
| patches_needed_count = len(PATCHES) | |
| try: | |
| with zipfile.ZipFile(path, 'r') as zip_in: | |
| with zipfile.ZipFile(temp_omni_path, 'w', zipfile.ZIP_DEFLATED) as zip_out: | |
| print(f"\nProcessing files in {os.path.basename(path)}...") | |
| for item in zip_in.infolist(): | |
| content = zip_in.read(item.filename) | |
| if item.filename in PATCHES: | |
| print(f" - Found target file: {item.filename}") | |
| patch_data = PATCHES[item.filename] | |
| original_content_str = content.decode('utf-8-sig') | |
| if patch_data["find"] in original_content_str: | |
| patched_content_str = original_content_str.replace( | |
| patch_data["find"], patch_data["replace"] | |
| ) | |
| content = patched_content_str.encode('utf-8') | |
| print(" ... Patch applied successfully.") | |
| patches_applied_count += 1 | |
| else: | |
| print(f" ... WARNING: Patch pattern not found for {item.filename}.") | |
| print(" The file may already be patched or has changed.") | |
| print(" Skipping patch for this file.") | |
| if patch_data["replace"] in original_content_str: | |
| print(" Confirmation: Replacement code already exists. File is already patched.") | |
| patches_applied_count += 1 | |
| else: | |
| print(" ERROR: Could not confirm if already patched. The file might be from an incompatible version.") | |
| zip_out.writestr(item, content) | |
| print(f"\nProcessed all files. {patches_applied_count}/{patches_needed_count} patches were applied or already present.") | |
| if patches_applied_count < patches_needed_count: | |
| print("\nNot all patches could be applied. This could be due to an incompatible") | |
| print("browser version or an unexpected file modification.") | |
| print("Aborting replacement to ensure browser integrity. Original file is untouched.") | |
| return | |
| print(f"Replacing original file with patched version...") | |
| shutil.move(temp_omni_path, path) | |
| print("\nPatching complete! The original file has been replaced.") | |
| except zipfile.BadZipFile: | |
| print(f"ERROR: {path} is not a valid zip archive.") | |
| except Exception as e: | |
| print(f"An unexpected error occurred during patching: {e}") | |
| finally: | |
| if os.path.exists(temp_omni_path): | |
| os.remove(temp_omni_path) | |
| def main(): | |
| if not is_elevated(): | |
| print("This patcher must be run with elevated (admin/root) privileges.") | |
| print("\tOn Linux/macOS: use `sudo python3 your_script_name.py`") | |
| print("\tOn Windows: run in an Administrator Command Prompt or PowerShell") | |
| sys.exit(1) | |
| print("Please ensure Librewolf is fully closed before patching...") | |
| candidates = get_possible_paths() | |
| found_path = None | |
| for path in candidates: | |
| if os.path.isfile(path): | |
| print(f"Found omni.ja at: {path}") | |
| found_path = path | |
| break | |
| if found_path: | |
| if input("Would you like to patch this file? (y/n): ").lower().strip() == "y": | |
| patch_file(found_path) | |
| else: | |
| print("Patching aborted by user.") | |
| else: | |
| print("Could not find omni.ja in any of the common locations.") | |
| print("You may need to locate the file manually and adapt the script.") | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment