diff --git a/devicemanagement/device_manager.py b/devicemanagement/device_manager.py
index 067a368..3eb6c29 100644
--- a/devicemanagement/device_manager.py
+++ b/devicemanagement/device_manager.py
@@ -12,7 +12,7 @@ from pymobiledevice3.exceptions import MuxException, PasswordRequiredError
from devicemanagement.constants import Device, Version
from devicemanagement.data_singleton import DataSingleton
-from tweaks.tweaks import tweaks, FeatureFlagTweak, EligibilityTweak, AITweak, BasicPlistTweak, AdvancedPlistTweak, RdarFixTweak
+from tweaks.tweaks import tweaks, FeatureFlagTweak, EligibilityTweak, AITweak, BasicPlistTweak, AdvancedPlistTweak, RdarFixTweak, NullifyFileTweak
from tweaks.custom_gestalt_tweaks import CustomGestaltTweaks
from tweaks.basic_plist_locations import FileLocationsList, RiskyFileLocationsList
from Sparserestore.restore import restore_files, FileToRestore
@@ -208,8 +208,8 @@ class DeviceManager:
QMessageBox.information(None, "Pairing Reset", "Your device's pairing was successfully reset. Refresh the device list before applying.")
- def add_skip_setup(self, files_to_restore: list[FileToRestore]):
- if self.skip_setup and not self.get_current_device_supported():
+ def add_skip_setup(self, files_to_restore: list[FileToRestore], restoring_domains: bool):
+ if self.skip_setup and (not self.get_current_device_supported() or restoring_domains):
# add the 2 skip setup files
cloud_config_plist: dict = {
"SkipSetup": ["WiFi", "Location", "Restore", "SIMSetup", "Android", "AppleID", "IntendedUser", "TOS", "Siri", "ScreenTime", "Diagnostics", "SoftwareUpdate", "Passcode", "Biometric", "Payment", "Zoom", "DisplayTone", "MessagingActivationUsingPhoneNumber", "HomeButtonSensitivity", "CloudStorage", "ScreenSaver", "TapToSetup", "Keyboard", "PreferredLanguage", "SpokenLanguage", "WatchMigration", "OnBoarding", "TVProviderSignIn", "TVHomeScreenSync", "Privacy", "TVRoom", "iMessageAndFaceTime", "AppStore", "Safety", "Multitasking", "ActionButton", "TermsOfAddress", "AccessibilityAppearance", "Welcome", "Appearance", "RestoreCompleted", "UpdateCompleted"],
@@ -241,7 +241,7 @@ class DeviceManager:
def get_domain_for_path(self, path: str) -> str:
# returns Domain: str?, Path: str
- if self.get_current_device_supported():
+ if self.get_current_device_supported() and not path.startswith("/var/mobile/"):
# don't do anything on sparserestore versions
return None, path
fully_patched = self.get_current_device_patched()
@@ -274,20 +274,13 @@ class DeviceManager:
return None, path
def concat_file(self, contents: str, path: str, files_to_restore: list[FileToRestore], owner: int = 501, group: int = 501):
- if self.get_current_device_supported():
- files_to_restore.append(FileToRestore(
- contents=contents,
- restore_path=path,
- owner=owner, group=group
- ))
- else:
- domain, file_path = self.get_domain_for_path(path)
- files_to_restore.append(FileToRestore(
- contents=contents,
- restore_path=file_path,
- domain=domain,
- owner=owner, group=group
- ))
+ domain, file_path = self.get_domain_for_path(path)
+ files_to_restore.append(FileToRestore(
+ contents=contents,
+ restore_path=file_path,
+ domain=domain,
+ owner=owner, group=group
+ ))
## APPLYING OR REMOVING TWEAKS AND RESTORING
def apply_changes(self, resetting: bool = False, update_label=lambda x: None):
@@ -304,6 +297,8 @@ class DeviceManager:
ai_file = None
basic_plists: dict = {}
basic_plists_ownership: dict = {}
+ files_data: dict = {}
+ uses_domains: bool = False
# set the plist keys
if not resetting:
@@ -318,6 +313,10 @@ class DeviceManager:
elif isinstance(tweak, BasicPlistTweak) or isinstance(tweak, RdarFixTweak) or isinstance(tweak, AdvancedPlistTweak):
basic_plists = tweak.apply_tweak(basic_plists, self.allow_risky_tweaks)
basic_plists_ownership[tweak.file_location] = tweak.owner
+ elif isinstance(tweak, NullifyFileTweak):
+ tweak.apply_tweak(files_data)
+ if tweak.enabled and tweak.file_location.value.startswith("/var/mobile/"):
+ uses_domains = True
else:
if gestalt_plist != None:
gestalt_plist = tweak.apply_tweak(gestalt_plist)
@@ -341,7 +340,7 @@ class DeviceManager:
path="/var/preferences/FeatureFlags/Global.plist",
files_to_restore=files_to_restore
)
- self.add_skip_setup(files_to_restore)
+ self.add_skip_setup(files_to_restore, uses_domains)
if gestalt_data != None:
self.concat_file(
contents=gestalt_data,
@@ -375,6 +374,13 @@ class DeviceManager:
files_to_restore=files_to_restore,
owner=ownership, group=ownership
)
+ for location, data in files_data.items():
+ self.concat_file(
+ contents=data,
+ path=location.value,
+ files_to_restore=files_to_restore,
+ owner=ownership, group=ownership
+ )
# reset basic tweaks
if resetting:
empty_data = plistlib.dumps({})
diff --git a/gui/main_window.py b/gui/main_window.py
index ac7f073..e306d31 100644
--- a/gui/main_window.py
+++ b/gui/main_window.py
@@ -135,6 +135,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.ui.usageTrackingAgentChk.toggled.connect(self.on_usageTrackingAgentChk_clicked)
self.ui.gameCenterChk.toggled.connect(self.on_gameCenterChk_clicked)
self.ui.screenTimeChk.toggled.connect(self.on_screenTimeChk_clicked)
+ self.ui.clearScreenTimeAgentChk.toggled.connect(self.on_clearScreenTimeAgentChk_clicked)
self.ui.crashReportsChk.toggled.connect(self.on_crashReportsChk_clicked)
self.ui.atwakeupChk.toggled.connect(self.on_atwakeupChk_clicked)
self.ui.tipsChk.toggled.connect(self.on_tipsChk_clicked)
@@ -760,6 +761,8 @@ class MainWindow(QtWidgets.QMainWindow):
"com.apple.homed",
"com.apple.familycircled"
], value=checked)
+ def on_clearScreenTimeAgentChk_clicked(self, checked: bool):
+ tweaks["ClearScreenTimeAgentPlist"].set_enabled(checked)
def on_crashReportsChk_clicked(self, checked: bool):
tweaks["Daemons"].set_multiple_values([
"com.apple.ReportCrash",
diff --git a/qt/mainwindow.ui b/qt/mainwindow.ui
index fcb1e3f..5a30af8 100644
--- a/qt/mainwindow.ui
+++ b/qt/mainwindow.ui
@@ -3797,6 +3797,18 @@ QComboBox QAbstractItemView::item:hover {
+ -
+
+
+ Deletes the Screen Time Agent preferences file to prevent app lockout set via iCloud.
+
+To work properly, also disable the daemon using the toggle above.
+
+
+ Clear ScreenTimeAgent.plist file
+
+
+
-
diff --git a/qt/mainwindow_ui.py b/qt/mainwindow_ui.py
index 5c68f9c..6fbd52d 100644
--- a/qt/mainwindow_ui.py
+++ b/qt/mainwindow_ui.py
@@ -1993,6 +1993,11 @@ class Ui_Nugget(object):
self.verticalLayout_132.addWidget(self.screenTimeChk)
+ self.clearScreenTimeAgentChk = QCheckBox(self.daemonsPageContent)
+ self.clearScreenTimeAgentChk.setObjectName(u"clearScreenTimeAgentChk")
+
+ self.verticalLayout_132.addWidget(self.clearScreenTimeAgentChk)
+
self.crashReportsChk = QCheckBox(self.daemonsPageContent)
self.crashReportsChk.setObjectName(u"crashReportsChk")
@@ -3319,6 +3324,12 @@ class Ui_Nugget(object):
self.screenTimeChk.setToolTip(QCoreApplication.translate("Nugget", u"Disables Screen Time monitoring features.", None))
#endif // QT_CONFIG(tooltip)
self.screenTimeChk.setText(QCoreApplication.translate("Nugget", u"Disable Screen Time Agent", None))
+#if QT_CONFIG(tooltip)
+ self.clearScreenTimeAgentChk.setToolTip(QCoreApplication.translate("Nugget", u"Deletes the Screen Time Agent preferences file to prevent app lockout set via iCloud.\n"
+"\n"
+"To work properly, also disable the daemon using the toggle above.", None))
+#endif // QT_CONFIG(tooltip)
+ self.clearScreenTimeAgentChk.setText(QCoreApplication.translate("Nugget", u"Clear ScreenTimeAgent.plist file", None))
#if QT_CONFIG(tooltip)
self.crashReportsChk.setToolTip(QCoreApplication.translate("Nugget", u"Stops logs, dumps, and crash reports collection.", None))
#endif // QT_CONFIG(tooltip)
diff --git a/qt/ui_mainwindow.py b/qt/ui_mainwindow.py
index a06957d..681d2d7 100644
--- a/qt/ui_mainwindow.py
+++ b/qt/ui_mainwindow.py
@@ -1993,6 +1993,11 @@ class Ui_Nugget(object):
self.verticalLayout_132.addWidget(self.screenTimeChk)
+ self.clearScreenTimeAgentChk = QCheckBox(self.daemonsPageContent)
+ self.clearScreenTimeAgentChk.setObjectName(u"clearScreenTimeAgentChk")
+
+ self.verticalLayout_132.addWidget(self.clearScreenTimeAgentChk)
+
self.crashReportsChk = QCheckBox(self.daemonsPageContent)
self.crashReportsChk.setObjectName(u"crashReportsChk")
@@ -3319,6 +3324,12 @@ class Ui_Nugget(object):
self.screenTimeChk.setToolTip(QCoreApplication.translate("Nugget", u"Disables Screen Time monitoring features.", None))
#endif // QT_CONFIG(tooltip)
self.screenTimeChk.setText(QCoreApplication.translate("Nugget", u"Disable Screen Time Agent", None))
+#if QT_CONFIG(tooltip)
+ self.clearScreenTimeAgentChk.setToolTip(QCoreApplication.translate("Nugget", u"Deletes the Screen Time Agent preferences file to prevent app lockout set via iCloud.\n"
+"\n"
+"To work properly, also disable the daemon using the toggle above.", None))
+#endif // QT_CONFIG(tooltip)
+ self.clearScreenTimeAgentChk.setText(QCoreApplication.translate("Nugget", u"Clear ScreenTimeAgent.plist file", None))
#if QT_CONFIG(tooltip)
self.crashReportsChk.setToolTip(QCoreApplication.translate("Nugget", u"Stops logs, dumps, and crash reports collection.", None))
#endif // QT_CONFIG(tooltip)
diff --git a/tweaks/basic_plist_locations.py b/tweaks/basic_plist_locations.py
index c95c9e0..43aef7b 100644
--- a/tweaks/basic_plist_locations.py
+++ b/tweaks/basic_plist_locations.py
@@ -18,6 +18,7 @@ class FileLocation(Enum):
# Daemons
disabledDaemons = "/var/db/com.apple.xpc.launchd/disabled.plist"
+ screentime = "/var/mobile/Library/Preferences/ScreenTimeAgent.plist"
# Risky Options
ota = "/var/Managed Preferences/mobile/com.apple.MobileAsset.plist"
diff --git a/tweaks/tweak_classes.py b/tweaks/tweak_classes.py
index e5182ff..15b6a61 100644
--- a/tweaks/tweak_classes.py
+++ b/tweaks/tweak_classes.py
@@ -43,6 +43,21 @@ class Tweak:
def apply_tweak(self):
raise NotImplementedError
+class NullifyFileTweak(Tweak):
+ def __init__(
+ self, label: str,
+ file_location: FileLocation,
+ min_version: Version = Version("1.0"),
+ owner: int = 501, group: int = 501,
+ divider_below: bool = False
+ ):
+ super().__init__(label=label, key=None, value=None, min_version=min_version, owner=owner, group=group, divider_below=divider_below)
+ self.file_location = file_location
+
+ def apply_tweak(self, other_tweaks: dict):
+ if self.enabled:
+ other_tweaks[self.file_location] = b""
+
class BasicPlistTweak(Tweak):
def __init__(
diff --git a/tweaks/tweaks.py b/tweaks/tweaks.py
index ee435f8..0a07870 100644
--- a/tweaks/tweaks.py
+++ b/tweaks/tweaks.py
@@ -1,5 +1,5 @@
from devicemanagement.constants import Version
-from .tweak_classes import MobileGestaltTweak, MobileGestaltMultiTweak, MobileGestaltPickerTweak, FeatureFlagTweak, TweakModifyType, BasicPlistTweak, AdvancedPlistTweak, RdarFixTweak
+from .tweak_classes import MobileGestaltTweak, MobileGestaltMultiTweak, MobileGestaltPickerTweak, FeatureFlagTweak, TweakModifyType, BasicPlistTweak, AdvancedPlistTweak, RdarFixTweak, NullifyFileTweak
from .eligibility_tweak import EligibilityTweak, AITweak
from .basic_plist_locations import FileLocation
@@ -283,6 +283,9 @@ tweaks = {
},
owner=0, group=0
),
+ "ClearScreenTimeAgentPlist": NullifyFileTweak(
+ "Clear ScreenTimeAgent Plist", FileLocation.screentime
+ ),
## Risky Options
"DisableOTAFile": AdvancedPlistTweak(