mirror of
https://github.com/dortania/OpenCore-Legacy-Patcher.git
synced 2026-04-15 21:28:55 +10:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eec8f3e797 | ||
|
|
5011b2c3f1 | ||
|
|
980142c6ad | ||
|
|
1fe710f4a3 | ||
|
|
472c494fd4 | ||
|
|
ccbb5dafe5 | ||
|
|
939d3a36a4 | ||
|
|
4c19f51a04 | ||
|
|
b34eaccd35 | ||
|
|
52211def51 | ||
|
|
62f619da99 | ||
|
|
2496fa9245 |
4
.github/workflows/build-app-wxpython.yml
vendored
4
.github/workflows/build-app-wxpython.yml
vendored
@@ -18,10 +18,12 @@ jobs:
|
||||
commitdate: ${{ github.event.head_commit.timestamp }}${{ github.event.release.published_at }}
|
||||
MAC_NOTARIZATION_USERNAME: ${{ secrets.MAC_NOTARIZATION_USERNAME }}
|
||||
MAC_NOTARIZATION_PASSWORD: ${{ secrets.MAC_NOTARIZATION_PASSWORD }}
|
||||
ANALYTICS_KEY: ${{ secrets.ANALYTICS_KEY }}
|
||||
ANALYTICS_SITE: ${{ secrets.ANALYTICS_SITE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: /Library/Frameworks/Python.framework/Versions/3.10/bin/python3 Build-Binary.command --reset_binaries --branch "${{ env.branch }}" --commit "${{ env.commiturl }}" --commit_date "${{ env.commitdate }}"
|
||||
- run: /Library/Frameworks/Python.framework/Versions/3.10/bin/python3 Build-Binary.command --reset_binaries --branch "${{ env.branch }}" --commit "${{ env.commiturl }}" --commit_date "${{ env.commitdate }}" --key "${{ env.ANALYTICS_KEY }}" --site "${{ env.ANALYTICS_SITE }}"
|
||||
- run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"'
|
||||
- run: cd dist; ditto -c -k --sequesterRsrc --keepParent OpenCore-Patcher.app ../OpenCore-Patcher-wxPython.app.zip
|
||||
- run: xcrun altool --notarize-app --primary-bundle-id "com.dortania.opencore-legacy-patcher" --username "${{ env.MAC_NOTARIZATION_USERNAME }}" --password "${{ env.MAC_NOTARIZATION_PASSWORD }}" --file OpenCore-Patcher-wxPython.app.zip
|
||||
|
||||
@@ -61,6 +61,8 @@ class CreateBinary:
|
||||
parser.add_argument('--commit', type=str, help='Git commit URL')
|
||||
parser.add_argument('--commit_date', type=str, help='Git commit date')
|
||||
parser.add_argument('--reset_binaries', action='store_true', help='Force redownload and imaging of payloads')
|
||||
parser.add_argument('--key', type=str, help='Developer key for signing')
|
||||
parser.add_argument('--site', type=str, help='Path to server')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
@@ -132,17 +134,85 @@ class CreateBinary:
|
||||
print(rm_output.stderr.decode('utf-8'))
|
||||
raise Exception("Remove failed")
|
||||
|
||||
self._embed_key()
|
||||
|
||||
print("- Building GUI binary...")
|
||||
build_args = [self.pyinstaller_path, "./OpenCore-Patcher-GUI.spec", "--noconfirm"]
|
||||
|
||||
build_result = subprocess.run(build_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
self._strip_key()
|
||||
|
||||
if build_result.returncode != 0:
|
||||
print("- Build failed")
|
||||
print(build_result.stderr.decode('utf-8'))
|
||||
raise Exception("Build failed")
|
||||
|
||||
|
||||
|
||||
|
||||
def _embed_key(self):
|
||||
"""
|
||||
Embed developer key into binary
|
||||
"""
|
||||
|
||||
if not self.args.key:
|
||||
print("- No developer key provided, skipping...")
|
||||
return
|
||||
if not self.args.site:
|
||||
print("- No site provided, skipping...")
|
||||
return
|
||||
|
||||
print("- Embedding developer key...")
|
||||
if not Path("./resources/analytics_handler.py").exists():
|
||||
print("- analytics_handler.py not found")
|
||||
return
|
||||
|
||||
lines = []
|
||||
with open("./resources/analytics_handler.py", "r") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
if line.startswith("SITE_KEY: str = "):
|
||||
lines[i] = f"SITE_KEY: str = \"{self.args.key}\"\n"
|
||||
elif line.startswith("ANALYTICS_SERVER: str = "):
|
||||
lines[i] = f"ANALYTICS_SERVER: str = \"{self.args.site}\"\n"
|
||||
|
||||
with open("./resources/analytics_handler.py", "w") as f:
|
||||
f.writelines(lines)
|
||||
|
||||
|
||||
def _strip_key(self):
|
||||
"""
|
||||
Strip developer key from binary
|
||||
"""
|
||||
|
||||
if not self.args.key:
|
||||
print("- No developer key provided, skipping...")
|
||||
return
|
||||
if not self.args.site:
|
||||
print("- No site provided, skipping...")
|
||||
return
|
||||
|
||||
print("- Stripping developer key...")
|
||||
if not Path("./resources/analytics_handler.py").exists():
|
||||
print("- analytics_handler.py not found")
|
||||
return
|
||||
|
||||
lines = []
|
||||
with open("./resources/analytics_handler.py", "r") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
if line.startswith("SITE_KEY: str = "):
|
||||
lines[i] = f"SITE_KEY: str = \"\"\n"
|
||||
elif line.startswith("ANALYTICS_SERVER: str = "):
|
||||
lines[i] = f"ANALYTICS_SERVER: str = \"\"\n"
|
||||
|
||||
with open("./resources/analytics_handler.py", "w") as f:
|
||||
f.writelines(lines)
|
||||
|
||||
|
||||
def _delete_extra_binaries(self):
|
||||
"""
|
||||
Delete extra binaries from payloads directory
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# OpenCore Legacy Patcher changelog
|
||||
|
||||
## 0.6.4
|
||||
- Backend changes:
|
||||
- Implement new analytics_handler.py module
|
||||
- Adds support for anonymous analytics including host info (and crash reports in the future)
|
||||
- Can be disabled via GUI or `defaults write com.dortania.opencore-legacy-patcher DisableCrashAndAnalyticsReporting -bool true`
|
||||
- Resolve Safari rendering error on Ivy Bridge in macOS 13.3+
|
||||
- Increment Binaries:
|
||||
- RestrictEvents 1.1.1 - rolling (495f4d5)
|
||||
|
||||
## 0.6.3
|
||||
- Update non-Metal Binaries:
|
||||
- Resolves Safari 16.4 rendering issue
|
||||
|
||||
25
PRIVACY.md
Normal file
25
PRIVACY.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Privacy Policy
|
||||
|
||||
OpenCore Legacy Patcher may collect pseudo-anonymized data about the host system and the OpenCore Legacy Patcher application. This data is used to improve the project and to help diagnose issues. The data collected is as follows:
|
||||
|
||||
* System's UUID as a SHA1 hash
|
||||
* This is used to identify the system and to prevent duplicate reports
|
||||
* Cannot be used to identify the system without the user providing the UUID
|
||||
* Application name and version
|
||||
* System's OS version
|
||||
* System's model name, GPUs present and firmware vendor
|
||||
* May include more hardware information in the future (ex. CPU, WiFi, etc)
|
||||
* General country code of system's reported region
|
||||
* ex. `US`, `CA`, etc
|
||||
|
||||
Identifiable data such as IP addresses, MAC addresses, serial numbers, etc. are not collected.
|
||||
|
||||
In the future, crash logs may also be collected to help with diagnosing issues.
|
||||
----------
|
||||
|
||||
Users who wish to opt-out can do so either via the application's preferences or via the following command:
|
||||
```
|
||||
defaults write com.dortania.opencore-legacy-patcher DisableCrashAndAnalyticsReporting -bool true
|
||||
```
|
||||
|
||||
To have your data removed, please contact us via our [Discord server](https://discord.gg/rqdPgH8xSN) and provide the UUID of your system.
|
||||
Binary file not shown.
Binary file not shown.
BIN
payloads/Kexts/Acidanthera/RestrictEvents-v1.1.1-DEBUG.zip
Normal file
BIN
payloads/Kexts/Acidanthera/RestrictEvents-v1.1.1-DEBUG.zip
Normal file
Binary file not shown.
BIN
payloads/Kexts/Acidanthera/RestrictEvents-v1.1.1-RELEASE.zip
Normal file
BIN
payloads/Kexts/Acidanthera/RestrictEvents-v1.1.1-RELEASE.zip
Normal file
Binary file not shown.
97
resources/analytics_handler.py
Normal file
97
resources/analytics_handler.py
Normal file
@@ -0,0 +1,97 @@
|
||||
import datetime
|
||||
import plistlib
|
||||
from pathlib import Path
|
||||
import json
|
||||
|
||||
from resources import network_handler, constants, global_settings
|
||||
|
||||
|
||||
DATE_FORMAT: str = "%Y-%m-%d %H-%M-%S"
|
||||
ANALYTICS_SERVER: str = ""
|
||||
SITE_KEY: str = ""
|
||||
|
||||
VALID_ENTRIES: dict = {
|
||||
'KEY': str, # Prevent abuse (embedded at compile time)
|
||||
'UNIQUE_IDENTITY': str, # Host's UUID as SHA1 hash
|
||||
'APPLICATION_NAME': str, # ex. OpenCore Legacy Patcher
|
||||
'APPLICATION_VERSION': str, # ex. 0.2.0
|
||||
'OS_VERSION': str, # ex. 10.15.7
|
||||
'MODEL': str, # ex. MacBookPro11,5
|
||||
'GPUS': list, # ex. ['Intel Iris Pro', 'AMD Radeon R9 M370X']
|
||||
'FIRMWARE': str, # ex. APPLE
|
||||
'LOCATION': str, # ex. 'US' (just broad region, don't need to be specific)
|
||||
'TIMESTAMP': datetime.datetime, # ex. 2021-09-01-12-00-00
|
||||
}
|
||||
|
||||
|
||||
class Analytics:
|
||||
|
||||
def __init__(self, global_constants: constants.Constants) -> None:
|
||||
self.constants: constants.Constants = global_constants
|
||||
|
||||
if global_settings.GlobalEnviromentSettings().read_property("DisableCrashAndAnalyticsReporting") is True:
|
||||
return
|
||||
|
||||
self._generate_base_data()
|
||||
self._post_data()
|
||||
|
||||
|
||||
def _get_country(self) -> str:
|
||||
# Get approximate country from .GlobalPreferences.plist
|
||||
path = "/Library/Preferences/.GlobalPreferences.plist"
|
||||
if not Path(path).exists():
|
||||
return "US"
|
||||
|
||||
try:
|
||||
result = plistlib.load(Path(path).open("rb"))
|
||||
except:
|
||||
return "US"
|
||||
|
||||
if "Country" not in result:
|
||||
return "US"
|
||||
|
||||
return result["Country"]
|
||||
|
||||
|
||||
def _generate_base_data(self) -> None:
|
||||
|
||||
self.unique_identity = str(self.constants.computer.uuid_sha1)
|
||||
self.application = str("OpenCore Legacy Patcher")
|
||||
self.version = str(self.constants.patcher_version)
|
||||
self.os = str( self.constants.detected_os_version)
|
||||
self.model = str(self.constants.computer.real_model)
|
||||
self.gpus = []
|
||||
|
||||
self.firmware = str(self.constants.computer.firmware_vendor)
|
||||
self.location = str(self._get_country())
|
||||
|
||||
for gpu in self.constants.computer.gpus:
|
||||
self.gpus.append(str(gpu.arch))
|
||||
|
||||
self.data = {
|
||||
'KEY': SITE_KEY,
|
||||
'UNIQUE_IDENTITY': self.unique_identity,
|
||||
'APPLICATION_NAME': self.application,
|
||||
'APPLICATION_VERSION': self.version,
|
||||
'OS_VERSION': self.os,
|
||||
'MODEL': self.model,
|
||||
'GPUS': self.gpus,
|
||||
'FIRMWARE': self.firmware,
|
||||
'LOCATION': self.location,
|
||||
'TIMESTAMP': str(datetime.datetime.now().strftime(DATE_FORMAT)),
|
||||
}
|
||||
|
||||
# convert to JSON:
|
||||
self.data = json.dumps(self.data)
|
||||
|
||||
|
||||
def _post_data(self) -> None:
|
||||
# Post data to analytics server
|
||||
if ANALYTICS_SERVER == "":
|
||||
return
|
||||
if SITE_KEY == "":
|
||||
return
|
||||
network_handler.NetworkUtilities().post(ANALYTICS_SERVER, json = self.data)
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from data import os_data
|
||||
class Constants:
|
||||
def __init__(self) -> None:
|
||||
# Patcher Versioning
|
||||
self.patcher_version: str = "0.6.3" # OpenCore-Legacy-Patcher
|
||||
self.patcher_version: str = "0.6.4" # OpenCore-Legacy-Patcher
|
||||
self.patcher_support_pkg_version: str = "0.9.3" # PatcherSupportPkg
|
||||
self.copyright_date: str = "Copyright © 2020-2023 Dortania"
|
||||
|
||||
@@ -38,7 +38,7 @@ class Constants:
|
||||
self.airportbcrmfixup_version: str = "2.1.7" # AirPortBrcmFixup
|
||||
self.nvmefix_version: str = "1.1.0" # NVMeFix
|
||||
self.applealc_version: str = "1.6.3" # AppleALC
|
||||
self.restrictevents_version: str = "1.1.0" # RestrictEvents
|
||||
self.restrictevents_version: str = "1.1.1" # RestrictEvents
|
||||
self.featureunlock_version: str = "1.1.4" # FeatureUnlock
|
||||
self.debugenhancer_version: str = "1.0.7" # DebugEnhancer
|
||||
self.cpufriend_version: str = "1.2.6" # CPUFriend
|
||||
|
||||
@@ -6,6 +6,7 @@ import enum
|
||||
import itertools
|
||||
import subprocess
|
||||
import plistlib
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, ClassVar, Optional, Type, Union
|
||||
@@ -52,7 +53,7 @@ class PCIDevice:
|
||||
if type(ioname) is bytes:
|
||||
ioname = ioname.strip(b"\0").decode()
|
||||
|
||||
if ioname.startswith("pci"):
|
||||
if ioname.startswith("pci") and "," in ioname:
|
||||
vendor_id_unspoofed, device_id_unspoofed = (int(i, 16) for i in ioname[3:].split(","))
|
||||
if anti_spoof:
|
||||
vendor_id = vendor_id_unspoofed
|
||||
@@ -491,6 +492,7 @@ class Computer:
|
||||
reported_model: Optional[str] = None
|
||||
reported_board_id: Optional[str] = None
|
||||
build_model: Optional[str] = None
|
||||
uuid_sha1: Optional[str] = None
|
||||
gpus: list[GPU] = field(default_factory=list)
|
||||
igpu: Optional[GPU] = None # Shortcut for IGPU
|
||||
dgpu: Optional[GPU] = None # Shortcut for GFX0
|
||||
@@ -719,6 +721,8 @@ class Computer:
|
||||
else:
|
||||
board = "board-id"
|
||||
self.reported_board_id = ioreg.corefoundation_to_native(ioreg.IORegistryEntryCreateCFProperty(entry, board, ioreg.kCFAllocatorDefault, ioreg.kNilOptions)).strip(b"\0").decode() # type: ignore
|
||||
self.uuid_sha1 = ioreg.corefoundation_to_native(ioreg.IORegistryEntryCreateCFProperty(entry, "IOPlatformUUID", ioreg.kCFAllocatorDefault, ioreg.kNilOptions)) # type: ignore
|
||||
self.uuid_sha1 = hashlib.sha1(self.uuid_sha1.encode()).hexdigest()
|
||||
ioreg.IOObjectRelease(entry)
|
||||
|
||||
# Real model
|
||||
|
||||
@@ -2980,12 +2980,23 @@ class wx_python_gui:
|
||||
self.delete_unused_kdks_checkbox.GetPosition().y + self.delete_unused_kdks_checkbox.GetSize().height))
|
||||
self.set_ignore_app_updates_checkbox.SetToolTip(wx.ToolTip("This will set whether OpenCore will ignore App Updates on launch.\nEnable this option if you do not want to be prompted for App Updates"))
|
||||
|
||||
# Set Disable Analytics
|
||||
res = global_settings.GlobalEnviromentSettings().read_property("DisableCrashAndAnalyticsReporting")
|
||||
res = False if res is None else res
|
||||
self.set_disable_analytics_checkbox = wx.CheckBox(self.frame_modal, label="Disable Crash/Analytics")
|
||||
self.set_disable_analytics_checkbox.SetValue(res)
|
||||
self.set_disable_analytics_checkbox.Bind(wx.EVT_CHECKBOX, self.set_disable_analytics_click)
|
||||
self.set_disable_analytics_checkbox.SetPosition(wx.Point(
|
||||
self.set_ignore_app_updates_checkbox.GetPosition().x,
|
||||
self.set_ignore_app_updates_checkbox.GetPosition().y + self.set_ignore_app_updates_checkbox.GetSize().height))
|
||||
self.set_disable_analytics_checkbox.SetToolTip(wx.ToolTip("Sets whether anonymized analytics are sent to the Dortania team.\nThis is used to help improve the application and is completely optional."))
|
||||
|
||||
# Button: Developer Debug Info
|
||||
self.debug_button = wx.Button(self.frame_modal, label="Developer Debug Info")
|
||||
self.debug_button.Bind(wx.EVT_BUTTON, self.additional_info_menu)
|
||||
self.debug_button.SetPosition(wx.Point(
|
||||
self.set_ignore_app_updates_checkbox.GetPosition().x,
|
||||
self.set_ignore_app_updates_checkbox.GetPosition().y + self.set_ignore_app_updates_checkbox.GetSize().height + 5))
|
||||
self.set_disable_analytics_checkbox.GetPosition().x,
|
||||
self.set_disable_analytics_checkbox.GetPosition().y + self.set_disable_analytics_checkbox.GetSize().height + 5))
|
||||
self.debug_button.Center(wx.HORIZONTAL)
|
||||
|
||||
# Button: return to main menu
|
||||
@@ -3038,6 +3049,9 @@ class wx_python_gui:
|
||||
else:
|
||||
global_settings.GlobalEnviromentSettings().write_property("IgnoreAppUpdates", False)
|
||||
|
||||
def set_disable_analytics_click(self, event):
|
||||
global_settings.GlobalEnviromentSettings().write_property("DisableCrashAndAnalyticsReporting", self.set_disable_analytics_checkbox.GetValue())
|
||||
|
||||
def firewire_click(self, event=None):
|
||||
if self.firewire_boot_checkbox.GetValue():
|
||||
logging.info("Firewire Enabled")
|
||||
|
||||
@@ -9,6 +9,7 @@ import logging
|
||||
import binascii
|
||||
import threading
|
||||
|
||||
from typing import Union
|
||||
from pathlib import Path
|
||||
|
||||
CHUNK_LENGTH = 4 + 32
|
||||
@@ -43,7 +44,7 @@ class ChunklistVerification:
|
||||
... print(chunk_obj.error_msg)
|
||||
"""
|
||||
|
||||
def __init__(self, file_path: Path, chunklist_path: Path | bytes) -> None:
|
||||
def __init__(self, file_path: Path, chunklist_path: Union[Path, bytes]) -> None:
|
||||
if isinstance(chunklist_path, bytes):
|
||||
self.chunklist_path: bytes = chunklist_path
|
||||
else:
|
||||
@@ -59,7 +60,7 @@ class ChunklistVerification:
|
||||
self.status: ChunklistStatus = ChunklistStatus.IN_PROGRESS
|
||||
|
||||
|
||||
def _generate_chunks(self, chunklist: Path | bytes) -> dict:
|
||||
def _generate_chunks(self, chunklist: Union[Path, bytes]) -> dict:
|
||||
"""
|
||||
Generate a dictionary of the chunklist header and chunks
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@ from resources import (
|
||||
arguments,
|
||||
reroute_payloads,
|
||||
commit_info,
|
||||
logging_handler
|
||||
logging_handler,
|
||||
analytics_handler,
|
||||
)
|
||||
|
||||
|
||||
@@ -89,6 +90,7 @@ class OpenCoreLegacyPatcher:
|
||||
|
||||
# Generate defaults
|
||||
defaults.GenerateDefaults(self.computer.real_model, True, self.constants)
|
||||
threading.Thread(target=analytics_handler.Analytics, args=(self.constants,)).start()
|
||||
|
||||
if utilities.check_cli_args() is None:
|
||||
logging.info(f"- No arguments present, loading {'GUI' if self.constants.wxpython_variant is True else 'TUI'} mode")
|
||||
|
||||
@@ -109,6 +109,35 @@ class NetworkUtilities:
|
||||
|
||||
return result
|
||||
|
||||
def post(self, url: str, **kwargs) -> requests.Response:
|
||||
"""
|
||||
Wrapper for requests's post method
|
||||
Implement additional error handling
|
||||
|
||||
Parameters:
|
||||
url (str): URL to post
|
||||
**kwargs: Additional parameters for requests.post
|
||||
|
||||
Returns:
|
||||
requests.Response: Response object from requests.post
|
||||
"""
|
||||
|
||||
result: requests.Response = None
|
||||
|
||||
try:
|
||||
result = SESSION.post(url, **kwargs)
|
||||
except (
|
||||
requests.exceptions.Timeout,
|
||||
requests.exceptions.TooManyRedirects,
|
||||
requests.exceptions.ConnectionError,
|
||||
requests.exceptions.HTTPError
|
||||
) as error:
|
||||
logging.warn(f"Error calling requests.post: {error}")
|
||||
# Return empty response object
|
||||
return requests.Response()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class DownloadObject:
|
||||
"""
|
||||
|
||||
@@ -5,6 +5,8 @@ import plistlib
|
||||
import os
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
from typing import Union
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
@@ -213,7 +215,7 @@ class SysPatchHelpers:
|
||||
logging.info(f" - Failed to install RSRRepair: {result.stdout.decode()}")
|
||||
|
||||
|
||||
def patch_gpu_compiler_libraries(self, mount_point: str | Path):
|
||||
def patch_gpu_compiler_libraries(self, mount_point: Union[str, Path]):
|
||||
"""
|
||||
Fix GPUCompiler.framework's libraries to resolve linking issues
|
||||
|
||||
|
||||
Reference in New Issue
Block a user