mirror of
https://github.com/dortania/OpenCore-Legacy-Patcher.git
synced 2026-04-13 20:28:21 +10:00
506 lines
23 KiB
Python
506 lines
23 KiB
Python
|
|
import wx
|
|
import os
|
|
import sys
|
|
import time
|
|
import logging
|
|
import plistlib
|
|
import traceback
|
|
import threading
|
|
import subprocess
|
|
|
|
from pathlib import Path
|
|
|
|
from resources import (
|
|
constants,
|
|
kdk_handler,
|
|
)
|
|
from resources.sys_patch import (
|
|
sys_patch,
|
|
sys_patch_detect
|
|
)
|
|
from resources.wx_gui import (
|
|
gui_main_menu,
|
|
gui_support,
|
|
gui_download,
|
|
)
|
|
from data import os_data
|
|
|
|
|
|
class SysPatchFrame(wx.Frame):
|
|
"""
|
|
Create a frame for root patching
|
|
Uses a Modal Dialog for smoother transition from other frames
|
|
"""
|
|
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None, patches: dict = {}):
|
|
super(SysPatchFrame, self).__init__(parent, title=title, size=(350, 260), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX))
|
|
|
|
self.title = title
|
|
self.constants: constants.Constants = global_constants
|
|
self.frame_modal: wx.Dialog = None
|
|
self.return_button: wx.Button = None
|
|
self.available_patches: bool = False
|
|
|
|
self.frame_modal = wx.Dialog(self, title=title, size=(360, 200))
|
|
self.SetPosition(screen_location) if screen_location else self.Centre()
|
|
|
|
if patches:
|
|
return
|
|
|
|
self._generate_elements_display_patches(self.frame_modal, patches)
|
|
self.frame_modal.ShowWindowModal()
|
|
|
|
if self.constants.update_stage != gui_support.AutoUpdateStages.INACTIVE:
|
|
if self.available_patches is False:
|
|
gui_support.RestartHost(self).restart(message="No root patch updates needed!\n\nWould you like to reboot to apply the new OpenCore build?")
|
|
|
|
|
|
def _kdk_download(self, frame: wx.Frame = None) -> bool:
|
|
frame = self if not frame else frame
|
|
|
|
logging.info("KDK missing, generating KDK download frame")
|
|
|
|
header = wx.StaticText(frame, label="Downloading Kernel Debug Kit", pos=(-1,5))
|
|
header.SetFont(wx.Font(19, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
|
header.Center(wx.HORIZONTAL)
|
|
|
|
subheader = wx.StaticText(frame, label="Fetching KDK database...", pos=(-1, header.GetPosition()[1] + header.GetSize()[1] + 5))
|
|
subheader.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
subheader.Center(wx.HORIZONTAL)
|
|
|
|
progress_bar = wx.Gauge(frame, range=100, pos=(-1, subheader.GetPosition()[1] + subheader.GetSize()[1] + 5), size=(250, 20))
|
|
progress_bar.Center(wx.HORIZONTAL)
|
|
|
|
progress_bar_animation = gui_support.GaugePulseCallback(self.constants, progress_bar)
|
|
progress_bar_animation.start_pulse()
|
|
|
|
# Set size of frame
|
|
frame.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 35))
|
|
frame.Show()
|
|
|
|
# Generate KDK object
|
|
self.kdk_obj: kdk_handler.KernelDebugKitObject = None
|
|
def _kdk_thread_spawn():
|
|
self.kdk_obj = kdk_handler.KernelDebugKitObject(self.constants, self.constants.detected_os_build, self.constants.detected_os_version)
|
|
|
|
kdk_thread = threading.Thread(target=_kdk_thread_spawn)
|
|
kdk_thread.start()
|
|
|
|
while kdk_thread.is_alive():
|
|
wx.GetApp().Yield()
|
|
|
|
if self.kdk_obj.success is False:
|
|
progress_bar_animation.stop_pulse()
|
|
progress_bar.SetValue(0)
|
|
wx.MessageBox(f"KDK download failed: {self.kdk_obj.error_msg}", "Error", wx.OK | wx.ICON_ERROR)
|
|
return False
|
|
|
|
kdk_download_obj = self.kdk_obj.retrieve_download()
|
|
if not kdk_download_obj:
|
|
# KDK is already downloaded
|
|
return True
|
|
|
|
gui_download.DownloadFrame(
|
|
self,
|
|
title=self.title,
|
|
global_constants=self.constants,
|
|
download_obj=kdk_download_obj,
|
|
item_name=f"KDK Build {self.kdk_obj.kdk_url_build}"
|
|
)
|
|
if kdk_download_obj.download_complete is False:
|
|
return False
|
|
|
|
header.SetLabel(f"Validating KDK: {self.kdk_obj.kdk_url_build}")
|
|
header.Center(wx.HORIZONTAL)
|
|
|
|
subheader.SetLabel("Checking if checksum is valid...")
|
|
subheader.Center(wx.HORIZONTAL)
|
|
wx.GetApp().Yield()
|
|
|
|
progress_bar_animation.stop_pulse()
|
|
|
|
if self.kdk_obj.validate_kdk_checksum() is False:
|
|
progress_bar.SetValue(0)
|
|
logging.error("KDK checksum validation failed")
|
|
logging.error(self.kdk_obj.error_msg)
|
|
msg = wx.MessageDialog(frame, f"KDK checksum validation failed: {self.kdk_obj.error_msg}", "Error", wx.OK | wx.ICON_ERROR)
|
|
msg.ShowModal()
|
|
return False
|
|
|
|
progress_bar.SetValue(100)
|
|
|
|
logging.info("KDK download complete")
|
|
return True
|
|
|
|
|
|
def _generate_elements_display_patches(self, frame: wx.Frame = None, patches: dict = {}) -> None:
|
|
"""
|
|
Generate UI elements for root patching frame
|
|
|
|
Format:
|
|
- Title label: Post-Install Menu
|
|
- Label: Available patches:
|
|
- Labels: {patch name}
|
|
- Button: Start Root Patching
|
|
- Button: Revert Root Patches
|
|
- Button: Return to Main Menu
|
|
"""
|
|
frame = self if not frame else frame
|
|
|
|
title_label = wx.StaticText(frame, label="Post-Install Menu", pos=(-1, 10))
|
|
title_label.SetFont(wx.Font(19, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
|
title_label.Center(wx.HORIZONTAL)
|
|
|
|
# Label: Available patches:
|
|
available_label = wx.StaticText(frame, label="Available patches for your system:", pos=(-1, title_label.GetPosition()[1] + title_label.GetSize()[1] + 10))
|
|
available_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
|
available_label.Center(wx.HORIZONTAL)
|
|
|
|
# Labels: {patch name}
|
|
patches: dict = sys_patch_detect.DetectRootPatch(self.constants.computer.real_model, self.constants).detect_patch_set() if not patches else patches
|
|
can_unpatch: bool = patches["Validation: Unpatching Possible"]
|
|
|
|
if not any(not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True for patch in patches):
|
|
logging.info("- No applicable patches available")
|
|
patches = []
|
|
|
|
# Check if OCLP has already applied the same patches
|
|
no_new_patches = not self._check_if_new_patches_needed(patches) if patches else False
|
|
|
|
if not patches:
|
|
# Prompt user with no patches found
|
|
patch_label = wx.StaticText(frame, label="No patches required", pos=(-1, available_label.GetPosition()[1] + 20))
|
|
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
patch_label.Center(wx.HORIZONTAL)
|
|
|
|
else:
|
|
# Add Label for each patch
|
|
i = 0
|
|
if no_new_patches is True:
|
|
patch_label = wx.StaticText(frame, label="All applicable patches already installed", pos=(-1, available_label.GetPosition()[1] + 20))
|
|
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
patch_label.Center(wx.HORIZONTAL)
|
|
i = i + 20
|
|
else:
|
|
longest_patch = ""
|
|
for patch in patches:
|
|
if (not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True):
|
|
if len(patch) > len(longest_patch):
|
|
longest_patch = patch
|
|
anchor = wx.StaticText(frame, label=longest_patch, pos=(-1, available_label.GetPosition()[1] + 20))
|
|
anchor.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
anchor.Center(wx.HORIZONTAL)
|
|
anchor.Hide()
|
|
|
|
for patch in patches:
|
|
if (not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True):
|
|
i = i + 20
|
|
logging.info(f"- Adding patch: {patch} - {patches[patch]}")
|
|
patch_label = wx.StaticText(frame, label=f"- {patch}", pos=(anchor.GetPosition()[0], available_label.GetPosition()[1] + i))
|
|
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
|
|
if i == 20:
|
|
patch_label.SetLabel(patch_label.GetLabel().replace("-", ""))
|
|
patch_label.Center(wx.HORIZONTAL)
|
|
|
|
if patches["Validation: Patching Possible"] is False:
|
|
# Cannot patch due to the following reasons:
|
|
patch_label = wx.StaticText(frame, label="Cannot patch due to the following reasons:", pos=(-1, patch_label.GetPosition().y + 25))
|
|
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
|
patch_label.Center(wx.HORIZONTAL)
|
|
|
|
for patch in patches:
|
|
if not patch.startswith("Validation"):
|
|
continue
|
|
if patches[patch] is False:
|
|
continue
|
|
if patch == "Validation: Unpatching Possible":
|
|
continue
|
|
|
|
patch_label = wx.StaticText(frame, label=f"- {patch.split('Validation: ')[1]}", pos=(available_label.GetPosition().x - 10, patch_label.GetPosition().y + 20))
|
|
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
else:
|
|
if self.constants.computer.oclp_sys_version and self.constants.computer.oclp_sys_date:
|
|
date = self.constants.computer.oclp_sys_date.split(" @")
|
|
date = date[0] if len(date) == 2 else ""
|
|
|
|
patch_text = f"{self.constants.computer.oclp_sys_version}, {date}"
|
|
|
|
patch_label = wx.StaticText(frame, label="Root Volume last patched:", pos=(-1, patch_label.GetPosition().y + 25))
|
|
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
|
patch_label.Center(wx.HORIZONTAL)
|
|
|
|
patch_label = wx.StaticText(frame, label=patch_text, pos=(available_label.GetPosition().x - 10, patch_label.GetPosition().y + 20))
|
|
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
patch_label.Center(wx.HORIZONTAL)
|
|
|
|
|
|
# Button: Start Root Patching
|
|
start_button = wx.Button(frame, label="Start Root Patching", pos=(10, patch_label.GetPosition().y + 25), size=(170, 30))
|
|
start_button.Bind(wx.EVT_BUTTON, lambda event: self.start_root_patching(frame, patches, no_new_patches))
|
|
start_button.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
start_button.Center(wx.HORIZONTAL)
|
|
|
|
# Button: Revert Root Patches
|
|
revert_button = wx.Button(frame, label="Revert Root Patches", pos=(10, start_button.GetPosition().y + start_button.GetSize().height - 5), size=(170, 30))
|
|
revert_button.Bind(wx.EVT_BUTTON, lambda event: self.revert_root_patching(frame, patches, can_unpatch))
|
|
revert_button.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
revert_button.Center(wx.HORIZONTAL)
|
|
|
|
# Button: Return to Main Menu
|
|
return_button = wx.Button(frame, label="Return to Main Menu", pos=(10, revert_button.GetPosition().y + revert_button.GetSize().height), size=(150, 30))
|
|
return_button.Bind(wx.EVT_BUTTON, self.on_return_to_main_menu)
|
|
return_button.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
return_button.Center(wx.HORIZONTAL)
|
|
self.return_button = return_button
|
|
|
|
# Disable buttons if unsupported
|
|
if not patches:
|
|
start_button.Disable()
|
|
else:
|
|
self.available_patches = True
|
|
if patches["Validation: Patching Possible"] is False:
|
|
start_button.Disable()
|
|
elif no_new_patches is False:
|
|
start_button.SetDefault()
|
|
if can_unpatch is False:
|
|
revert_button.Disable()
|
|
|
|
# Relaunch as root if not root
|
|
uid = os.geteuid()
|
|
if uid != 0:
|
|
start_button.Bind(wx.EVT_BUTTON, gui_support.RelaunchApplicationAsRoot(frame, self.constants).relaunch)
|
|
revert_button.Bind(wx.EVT_BUTTON, gui_support.RelaunchApplicationAsRoot(frame, self.constants).relaunch)
|
|
|
|
# Set frame size
|
|
frame.SetSize((-1, return_button.GetPosition().y + return_button.GetSize().height + 35))
|
|
|
|
|
|
def _generate_modal(self, patches: dict = {}, variant: str = "Root Patching"):
|
|
"""
|
|
Create UI for root patching/unpatching
|
|
"""
|
|
supported_variants = ["Root Patching", "Revert Root Patches"]
|
|
if variant not in supported_variants:
|
|
logging.error(f"Unsupported variant: {variant}")
|
|
return
|
|
|
|
self.frame_modal.Close()
|
|
|
|
dialog = wx.Dialog(self, title=self.title, size=(400, 200))
|
|
|
|
# Title
|
|
title = wx.StaticText(dialog, label=variant, pos=(-1, 10))
|
|
title.SetFont(wx.Font(19, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
|
title.Center(wx.HORIZONTAL)
|
|
|
|
if variant == "Root Patching":
|
|
# Label
|
|
label = wx.StaticText(dialog, label="Root Patching will patch the following:", pos=(-1, title.GetPosition()[1] + 30))
|
|
label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
label.Center(wx.HORIZONTAL)
|
|
|
|
|
|
# Get longest patch label, then create anchor for patch labels
|
|
longest_patch = ""
|
|
for patch in patches:
|
|
if (not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True):
|
|
if len(patch) > len(longest_patch):
|
|
longest_patch = patch
|
|
|
|
anchor = wx.StaticText(dialog, label=longest_patch, pos=(label.GetPosition()[0], label.GetPosition()[1] + 20))
|
|
anchor.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
anchor.Center(wx.HORIZONTAL)
|
|
anchor.Hide()
|
|
|
|
# Labels
|
|
i = 0
|
|
for patch in patches:
|
|
if (not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True):
|
|
logging.info(f"- Adding patch: {patch} - {patches[patch]}")
|
|
patch_label = wx.StaticText(dialog, label=f"- {patch}", pos=(anchor.GetPosition()[0], label.GetPosition()[1] + 20 + i))
|
|
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
|
i = i + 20
|
|
|
|
if i == 20:
|
|
patch_label.SetLabel(patch_label.GetLabel().replace("-", ""))
|
|
patch_label.Center(wx.HORIZONTAL)
|
|
|
|
elif i == 0:
|
|
patch_label = wx.StaticText(dialog, label="No patches to apply", pos=(label.GetPosition()[0], label.GetPosition()[1] + 20))
|
|
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
|
patch_label.Center(wx.HORIZONTAL)
|
|
else:
|
|
patch_label = wx.StaticText(dialog, label="Reverting to last sealed snapshot", pos=(-1, title.GetPosition()[1] + 30))
|
|
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
patch_label.Center(wx.HORIZONTAL)
|
|
|
|
|
|
# Text box
|
|
text_box = wx.TextCtrl(dialog, pos=(10, patch_label.GetPosition()[1] + 30), size=(400, 400), style=wx.TE_READONLY | wx.TE_MULTILINE | wx.TE_RICH2)
|
|
text_box.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
text_box.Center(wx.HORIZONTAL)
|
|
self.text_box = text_box
|
|
|
|
# Button: Return to Main Menu
|
|
return_button = wx.Button(dialog, label="Return to Main Menu", pos=(10, text_box.GetPosition()[1] + text_box.GetSize()[1] + 5), size=(150, 30))
|
|
return_button.Bind(wx.EVT_BUTTON, self.on_return_to_main_menu)
|
|
return_button.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
|
return_button.Center(wx.HORIZONTAL)
|
|
self.return_button = return_button
|
|
|
|
# Set frame size
|
|
dialog.SetSize((-1, return_button.GetPosition().y + return_button.GetSize().height + 33))
|
|
|
|
dialog.ShowWindowModal()
|
|
|
|
|
|
def start_root_patching(self, patches: dict):
|
|
logging.info("Starting root patching")
|
|
|
|
while gui_support.PayloadMount(self.constants, self).is_unpack_finished() is False:
|
|
wx.Yield()
|
|
|
|
if patches["Settings: Kernel Debug Kit missing"] is True:
|
|
if self._kdk_download(self) is False:
|
|
self.on_return_to_main_menu()
|
|
return
|
|
|
|
self._generate_modal(patches, "Root Patching")
|
|
|
|
thread = threading.Thread(target=self._start_root_patching, args=(patches,))
|
|
thread.start()
|
|
|
|
while thread.is_alive():
|
|
wx.GetApp().Yield()
|
|
|
|
self._post_patch()
|
|
self.return_button.Enable()
|
|
|
|
|
|
def _start_root_patching(self, patches: dict):
|
|
logger = logging.getLogger()
|
|
logger.addHandler(gui_support.ThreadHandler(self.text_box))
|
|
try:
|
|
sys_patch.PatchSysVolume(self.constants.computer.real_model, self.constants, patches).start_patch()
|
|
except:
|
|
logging.error("- An internal error occurred while running the Root Patcher:\n")
|
|
logging.error(traceback.format_exc())
|
|
logger.removeHandler(logger.handlers[2])
|
|
|
|
|
|
def revert_root_patching(self, patches: dict):
|
|
logging.info("Reverting root patches")
|
|
self._generate_modal(patches, "Revert Root Patches")
|
|
|
|
thread = threading.Thread(target=self._revert_root_patching, args=(patches,))
|
|
thread.start()
|
|
|
|
while thread.is_alive():
|
|
wx.GetApp().Yield()
|
|
|
|
self._post_patch()
|
|
self.return_button.Enable()
|
|
|
|
|
|
def _revert_root_patching(self, patches: dict):
|
|
logger = logging.getLogger()
|
|
logger.addHandler(gui_support.ThreadHandler(self.text_box))
|
|
try:
|
|
sys_patch.PatchSysVolume(self.constants.computer.real_model, self.constants, patches).start_unpatch()
|
|
except:
|
|
logging.error("- An internal error occurred while running the Root Patcher:\n")
|
|
logging.error(traceback.format_exc())
|
|
logger.removeHandler(logger.handlers[2])
|
|
|
|
|
|
def on_return_to_main_menu(self, event: wx.Event = None):
|
|
self.frame_modal.Hide()
|
|
main_menu_frame = gui_main_menu.MainFrame(
|
|
None,
|
|
title=self.title,
|
|
global_constants=self.constants,
|
|
screen_location=self.GetScreenPosition()
|
|
)
|
|
main_menu_frame.Show()
|
|
self.frame_modal.Destroy()
|
|
self.Destroy()
|
|
|
|
|
|
def _post_patch(self):
|
|
if self.constants.root_patcher_succeeded is False:
|
|
return
|
|
|
|
if self.constants.needs_to_open_preferences is False:
|
|
gui_support.RestartHost(self).restart(message="Root Patcher finished successfully!\n\nWould you like to reboot now?")
|
|
return
|
|
|
|
if self.constants.detected_os >= os_data.os_data.ventura:
|
|
gui_support.RestartHost(self).restart(message="Root Patcher finished successfully!\nIf you were prompted to open System Settings to authorize new kexts, this can be ignored. Your system is ready once restarted.\n\nWould you like to reboot now?")
|
|
return
|
|
|
|
# Create dialog box to open System Preferences -> Security and Privacy
|
|
self.popup = wx.MessageDialog(
|
|
self.frame_modal,
|
|
"We just finished installing the patches to your Root Volume!\n\nHowever, Apple requires users to manually approve the kernel extensions installed before they can be used next reboot.\n\nWould you like to open System Preferences?",
|
|
"Open System Preferences?",
|
|
wx.YES_NO | wx.ICON_INFORMATION
|
|
)
|
|
self.popup.SetYesNoLabels("Open System Preferences", "Ignore")
|
|
answer = self.popup.ShowModal()
|
|
if answer == wx.ID_YES:
|
|
output =subprocess.run(
|
|
[
|
|
"osascript", "-e",
|
|
'tell app "System Preferences" to activate',
|
|
"-e", 'tell app "System Preferences" to reveal anchor "General" of pane id "com.apple.preference.security"',
|
|
],
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE
|
|
)
|
|
if output.returncode != 0:
|
|
# Some form of fallback if unaccelerated state errors out
|
|
subprocess.run(["open", "-a", "System Preferences"])
|
|
time.sleep(5)
|
|
sys.exit(0)
|
|
|
|
|
|
def _check_if_new_patches_needed(self, patches: dict) -> bool:
|
|
"""
|
|
Checks if any new patches are needed for the user to install
|
|
Newer users will assume the root patch menu will present missing patches.
|
|
Thus we'll need to see if the exact same OCLP build was used already
|
|
"""
|
|
|
|
if self.constants.commit_info[0] in ["Running from source", "Built from source"]:
|
|
return True
|
|
|
|
if self.constants.computer.oclp_sys_url != self.constants.commit_info[2]:
|
|
# If commits are different, assume patches are as well
|
|
return True
|
|
|
|
oclp_plist = "/System/Library/CoreServices/OpenCore-Legacy-Patcher.plist"
|
|
if not Path(oclp_plist).exists():
|
|
# If it doesn't exist, no patches were ever installed
|
|
# ie. all patches applicable
|
|
return True
|
|
|
|
oclp_plist_data = plistlib.load(open(oclp_plist, "rb"))
|
|
for patch in patches:
|
|
if (not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True):
|
|
# Patches should share the same name as the plist key
|
|
# See sys_patch_dict.py for more info
|
|
patch_installed = False
|
|
for key in oclp_plist_data:
|
|
if "Display Name" not in oclp_plist_data[key]:
|
|
continue
|
|
if oclp_plist_data[key]["Display Name"] == patch:
|
|
patch_installed = True
|
|
break
|
|
|
|
if patch_installed is False:
|
|
logging.info(f"- Patch {patch} not installed")
|
|
return True
|
|
|
|
logging.info("- No new patches detected for system")
|
|
return False |