Compare commits

..

28 Commits

Author SHA1 Message Date
mahee96
0b072e358a updated em_proxy submodule 2026-04-01 15:56:41 -07:00
mahee96
cc74be4b34 cleanup: removed Jailbreak stuff, PatchAppOperation etc. since no longer relevant 2026-04-01 15:44:34 -07:00
mahee96
eabf9dbaaa SendAppOperation: added missing import 2026-04-01 14:24:19 -07:00
mahee96
bd75d62c7b Merge branch 'develop' into merges
# Conflicts:
#	AltStore.xcodeproj/project.pbxproj
#	AltStore/Operations/InstallAppOperation.swift
#	AltStore/Operations/SendAppOperation.swift
#	Dependencies/minimuxer
#	SideStore/MinimuxerWrapper.swift
2026-04-01 14:21:38 -07:00
Huge_Black
75edfad132 Fix AltBackup.ipa is not included
Added a symlink in AltSotore/Resources/AltBackup.ipa that points to build/AltBackup.ipa

It seems Xcode reads all contents in AltSotore/Resources before ipa-altbackup runs, so AltBackup.ipa is missing in the first build. Adding a symlink will cause Xcode to always include that file
2026-03-21 15:30:49 +08:00
Huge_Black
84c5bf40ca Merge pull request #1218 from LiveContainer/develop-lc
Fix widget not working & Only run turn off data shortcut when minimuxer is not ready and below 26.4
2026-03-21 12:08:32 +08:00
Huge_Black
01e73328f8 Only run turn off data shortcut when minimuxer is not ready and below 26.4 2026-03-21 12:01:16 +08:00
Huge_Black
a1f71a8149 Fix widget not working 2026-03-21 11:58:20 +08:00
suprstarrd
8624a8e919 feat: add Mona to Trusted Sources (#1210)
* feat: add Mona to Trusted Sources

Signed-off-by: suprstarrd <business@suprstarrd.com>
2026-03-17 12:28:56 -04:00
mahee96
dfdac41a70 vpn-configuration: fix - properly report active status 2026-03-03 13:24:48 +05:30
mahee96
62ad755920 vpn-configuration: fix typo in sentence 2026-03-03 12:29:22 +05:30
mahee96
baf1aa7fff vpn-configuration: updated to reflect actual implementation 2026-03-03 12:27:12 +05:30
mahee96
395d2bb657 minimuxer: gutted discovery mechanism for finding the fake deviceIP from uTun routes coz it is impossible to walk subnet and kernel route table doesn't tell active associations but just possible routes attempted 2026-03-03 12:20:47 +05:30
mahee96
e32f4fbeae vpn-configuration: removed UI updating state despite bindTunnelConfig() driving it just behind 2026-03-03 10:57:12 +05:30
mahee96
b643f6ae01 minimuxer: fix some stale state issues during VPN up/down cycles or changing config 2026-03-03 10:49:36 +05:30
mahee96
2f0fb3cb71 minimuxer: added back file headers info about authors 2026-03-03 09:59:48 +05:30
mahee96
0f90f9bf2d DeviceEndpoint: fix all minimuxer woes by properly handling usbmuxd signals for listdevices and listen 2026-03-03 09:20:39 +05:30
mahee96
1c8541fdd4 MinimuxerWrapper: remove spam logs 2026-03-03 04:33:07 +05:30
mahee96
4e6882423d Heartbeat: improved logging intent 2026-03-03 04:32:46 +05:30
mahee96
7c3add0e70 IfaceScanner: fix some state update issues 2026-03-03 04:02:07 +05:30
mahee96
c4139473fa IfaceScanner: used the user specified IP to directly test if device is available there instead of assuming it to be under the subnet of tunnel coz it is fake endpoint interceptable by the tunnel's included routes 2026-03-03 03:23:00 +05:30
mahee96
0837f82a69 minimuxer: added binding for the cached tunnel config values so that application layer can provide and listen to updates. 2026-03-03 02:57:39 +05:30
mahee96
c04ebd3ec6 vpn-configuration: added new swiftUI view to settings to view discovered vpn settings and provide an override for deviceIP (if required) by user. 2026-03-03 02:54:58 +05:30
mahee96
0e81515af9 minimuxer: fix usbmuxd socket error handling - restart on first error and dont wait for 5 lol 2026-03-02 17:05:38 +05:30
mahee96
dd4c0be75d minimuxer: match API name 2026-03-02 16:57:56 +05:30
mahee96
7500dd5b17 minimuxer: usbmuxer was not handling socket kill or death properly when app was backgrounded and came into foreground 2026-03-02 16:57:37 +05:30
mahee96
dba84ed015 minimuxer: IfaceScanner - updated to skim thru kernel routing tables and find the included routes of our uTun 2026-03-02 14:59:08 +05:30
ny
6e9e0aee0a fix: revert 26.4 fix partially to fix everywhere 2026-02-28 18:03:35 -05:00
27 changed files with 316 additions and 1525 deletions

4
.gitmodules vendored
View File

@@ -54,10 +54,6 @@
path = Dependencies/em_proxy
url = https://github.com/SideStore/em_proxy
branch = master
[submodule "Dependencies/libfragmentzip"]
path = Dependencies/libfragmentzip
url = https://github.com/SideStore/libfragmentzip
branch = master
[submodule "Dependencies/apps-v2.json"]
path = Dependencies/apps-v2.json
url = https://github.com/SideStore/apps-v2.json

View File

@@ -93,11 +93,9 @@
A8B646012D70C23E00125819 /* MarkdownKit in Frameworks */ = {isa = PBXBuildFile; productRef = A8B646002D70C23E00125819 /* MarkdownKit */; };
A8C2260E2EC9039A00047C0D /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = A8C2260D2EC9039A00047C0D /* Nuke */; };
A8EB89C22F5448B20094BC01 /* em_proxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BD2F652F543FD40045335F /* em_proxy.swift */; };
A8EB89CA2F54519C0094BC01 /* libfragmentzip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A8EB89C92F54519C0094BC01 /* libfragmentzip.a */; };
A8EB89CC2F5451AF0094BC01 /* Minimuxer in Frameworks */ = {isa = PBXBuildFile; productRef = A8EB89CB2F5451AF0094BC01 /* Minimuxer */; };
A8EB89CE2F5451B50094BC01 /* SemanticVersion in Frameworks */ = {isa = PBXBuildFile; productRef = A8EB89CD2F5451B50094BC01 /* SemanticVersion */; };
A8EB89D02F5451C20094BC01 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = A8EB89CF2F5451C20094BC01 /* KeychainAccess */; };
A8EB89D12F5451E90094BC01 /* libcurl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A8BD2F6D2F543FFF0045335F /* libcurl.a */; };
A8EB955C2F5455B30094BC01 /* debug.c in Sources */ = {isa = PBXBuildFile; fileRef = A8BD30312F5440300045335F /* debug.c */; };
A8EB95C92F5455FE0094BC01 /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = A8BD30302F5440300045335F /* debug.h */; };
A8EB96042F54561E0094BC01 /* afc.c in Sources */ = {isa = PBXBuildFile; fileRef = A8BD30932F5440300045335F /* afc.c */; };
@@ -231,41 +229,6 @@
remoteGlobalIDString = CA60C44C93D7916DE57E6EBD;
remoteInfo = "em_proxy-staticlib";
};
A8EB8CC32F5453CD0094BC01 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A8BD2FFB2F5440300045335F /* libfragmentzip.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 87B8C3401E0E9C37002F817D;
remoteInfo = "fragmentzip-cli-macOS";
};
A8EB8CC52F5453CD0094BC01 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A8BD2FFB2F5440300045335F /* libfragmentzip.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = B315FDB02866CCF8002E243C;
remoteInfo = "fragmentzip-cli-iOS";
};
A8EB8CC72F5453CD0094BC01 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A8BD2FFB2F5440300045335F /* libfragmentzip.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = B315FDB52866CD91002E243C;
remoteInfo = "fragmentzip-macOS";
};
A8EB8CC92F5453CD0094BC01 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A8BD2FFB2F5440300045335F /* libfragmentzip.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = B315FDCE2866CDD3002E243C;
remoteInfo = "fragmentzip-iOS";
};
A8EB8CCE2F5453CD0094BC01 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A8BD2FD72F5440300045335F /* libgeneral.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 87977F6F227C4B71004F31DA;
remoteInfo = libgeneral;
};
BF66EE832501AE50007EE018 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFD247622284B9A500981D42 /* Project object */;
@@ -361,6 +324,10 @@
A8036E7F2F54606400097AF1 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
A8036EA72F54642D00097AF1 /* libimobiledevice.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libimobiledevice.a; sourceTree = BUILT_PRODUCTS_DIR; };
A8037A0D2F54664300097AF1 /* libem_proxy_swift.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libem_proxy_swift.a; sourceTree = BUILT_PRODUCTS_DIR; };
A84596F12F7DC4C90000B8CD /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; };
A84596F22F7DC4C90000B8CD /* .gitmodules */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitmodules; sourceTree = "<group>"; };
A84596F32F7DC4C90000B8CD /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
A84596F42F7DC4C90000B8CD /* trustedapps.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = trustedapps.json; sourceTree = "<group>"; };
A8635D052F4CF16D00E66784 /* OpenSSL.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:67RAULRX93:Marcin Krzyzanowski"; lastKnownFileType = wrapper.xcframework; name = OpenSSL.xcframework; path = Dependencies/AltSign/Dependencies/OpenSSL.xcframework; sourceTree = "<group>"; };
A8945AA52D059B6100D86CBE /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A8BD20292F543FD40045335F /* client_privatekey */ = {isa = PBXFileReference; lastKnownFileType = text; path = client_privatekey; sourceTree = "<group>"; };
@@ -381,26 +348,12 @@
A8BD2F692F543FD40045335F /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
A8BD2F6A2F543FD40045335F /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
A8BD2F6B2F543FD40045335F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
A8BD2F6D2F543FFF0045335F /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libcurl.a; sourceTree = "<group>"; };
A8BD2FA62F54401E0045335F /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; };
A8BD2FA72F54401E0045335F /* NSAttributedString+Markdown.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+Markdown.h"; sourceTree = "<group>"; };
A8BD2FA82F54401E0045335F /* NSAttributedString+Markdown.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+Markdown.m"; sourceTree = "<group>"; };
A8BD2FA92F54401E0045335F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
A8BD2FBD2F5440300045335F /* em_proxy.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = em_proxy.xcodeproj; sourceTree = "<group>"; };
A8BD2FBE2F5440300045335F /* fetch-prebuilt.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "fetch-prebuilt.sh"; sourceTree = "<group>"; };
A8BD2FD72F5440300045335F /* libgeneral.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libgeneral.xcodeproj; sourceTree = "<group>"; };
A8BD2FDB2F5440300045335F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
A8BD2FE02F5440300045335F /* curl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = curl.h; sourceTree = "<group>"; };
A8BD2FE12F5440300045335F /* curlbuild.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = curlbuild.h; sourceTree = "<group>"; };
A8BD2FE42F5440300045335F /* curlrules.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = curlrules.h; sourceTree = "<group>"; };
A8BD2FE52F5440300045335F /* curlver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = curlver.h; sourceTree = "<group>"; };
A8BD2FE62F5440300045335F /* easy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = easy.h; sourceTree = "<group>"; };
A8BD2FE82F5440300045335F /* mprintf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mprintf.h; sourceTree = "<group>"; };
A8BD2FE92F5440300045335F /* multi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = multi.h; sourceTree = "<group>"; };
A8BD2FEA2F5440300045335F /* stdcheaders.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stdcheaders.h; sourceTree = "<group>"; };
A8BD2FEB2F5440300045335F /* typecheck-gcc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "typecheck-gcc.h"; sourceTree = "<group>"; };
A8BD2FFB2F5440300045335F /* libfragmentzip.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = libfragmentzip.xcodeproj; sourceTree = "<group>"; };
A8BD30012F5440300045335F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
A8BD30062F5440300045335F /* add_scalar.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = add_scalar.c; sourceTree = "<group>"; };
A8BD30072F5440300045335F /* ed25519.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ed25519.h; sourceTree = "<group>"; };
A8BD30082F5440300045335F /* fe.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fe.h; sourceTree = "<group>"; };
@@ -568,8 +521,6 @@
A8BD325F2F5440300045335F /* minimuxer */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = minimuxer; sourceTree = "<group>"; };
A8BD32D02F5440300045335F /* Roxas.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = Roxas.xcodeproj; sourceTree = "<group>"; };
A8BD32FA2F54444D0045335F /* AltSign */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = AltSign; sourceTree = "<group>"; };
A8EB89C72F5451970094BC01 /* libfragmentzip.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libfragmentzip.a; sourceTree = BUILT_PRODUCTS_DIR; };
A8EB89C92F54519C0094BC01 /* libfragmentzip.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libfragmentzip.a; sourceTree = BUILT_PRODUCTS_DIR; };
B3C39606284F4C8400DA9E2F /* CodeSigning.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = CodeSigning.xcconfig; sourceTree = "<group>"; };
B3C39607284F4C8400DA9E2F /* Build.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Build.xcconfig; sourceTree = "<group>"; };
B3C39608284F4C8400DA9E2F /* CodeSigning.xcconfig.sample */ = {isa = PBXFileReference; lastKnownFileType = text; path = CodeSigning.xcconfig.sample; sourceTree = "<group>"; };
@@ -644,7 +595,6 @@
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
"Operations/Patch App/ALTAppPatcher.m",
Resources/ReleaseEntitlements.plist,
);
target = BFD247692284B9A500981D42 /* SideStore */;
@@ -686,14 +636,6 @@
);
target = BF989166250AABF3002ACF50 /* AltWidgetExtension */;
};
A8FAC1FE2F4B52F40061A851 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
"Operations/Patch App/ALTAppPatcher.h",
"Operations/Patch App/ALTAppPatcher.m",
);
target = BF66EE7D2501AE50007EE018 /* AltStoreCore */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */
@@ -713,7 +655,7 @@
A8EEC3B92F4B0EFC00F2436D /* AltWidget */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8EEC3CA2F4B0EFC00F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = AltWidget; sourceTree = "<group>"; };
A8EEC3D92F4B0FC800F2436D /* AltBackup */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8EEC3E22F4B0FC800F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = AltBackup; sourceTree = "<group>"; };
A8EEC71D2F4B10D900F2436D /* xcconfigs */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = xcconfigs; sourceTree = "<group>"; };
A8EEC8412F4B146A00F2436D /* AltStore */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8EEC8CB2F4B146B00F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, A8EEC8CC2F4B146B00F2436D /* PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet */, A8FAC1FE2F4B52F40061A851 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, A8EEC8CD2F4B146B00F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = AltStore; sourceTree = "<group>"; };
A8EEC8412F4B146A00F2436D /* AltStore */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8EEC8CB2F4B146B00F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, A8EEC8CC2F4B146B00F2436D /* PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet */, A8EEC8CD2F4B146B00F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = AltStore; sourceTree = "<group>"; };
A8EECF2A2F4B195000F2436D /* SideStore */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (A8EECF492F4B195000F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, A8EECF4A2F4B195000F2436D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = SideStore; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */
@@ -769,9 +711,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A8EB89D12F5451E90094BC01 /* libcurl.a in Frameworks */,
A8EB89CC2F5451AF0094BC01 /* Minimuxer in Frameworks */,
A8EB89CA2F54519C0094BC01 /* libfragmentzip.a in Frameworks */,
A8037A012F54661200097AF1 /* libimobiledevice.a in Frameworks */,
A8B646012D70C23E00125819 /* MarkdownKit in Frameworks */,
A8037A0E2F54664300097AF1 /* libem_proxy_swift.a in Frameworks */,
@@ -848,8 +788,6 @@
A8BD32FA2F54444D0045335F /* AltSign */,
A8BD325F2F5440300045335F /* minimuxer */,
A8BD20242F543FAD0045335F /* apps-v2.json */,
A8BD2F6E2F543FFF0045335F /* libcurl */,
A8BD30022F5440300045335F /* libfragmentzip */,
A8BD325E2F5440300045335F /* libusbmuxd */,
A8BD30F02F5440300045335F /* libimobiledevice */,
A8036E802F54606400097AF1 /* libimobiledevice-glue */,
@@ -904,14 +842,6 @@
path = em_proxy;
sourceTree = "<group>";
};
A8BD2F6E2F543FFF0045335F /* libcurl */ = {
isa = PBXGroup;
children = (
A8BD2F6D2F543FFF0045335F /* libcurl.a */,
);
path = libcurl;
sourceTree = "<group>";
};
A8BD2FAA2F54401E0045335F /* MarkdownAttributedString */ = {
isa = PBXGroup;
children = (
@@ -923,58 +853,6 @@
path = MarkdownAttributedString;
sourceTree = "<group>";
};
A8BD2FDC2F5440300045335F /* libgeneral */ = {
isa = PBXGroup;
children = (
A8BD2FD72F5440300045335F /* libgeneral.xcodeproj */,
A8BD2FDB2F5440300045335F /* README.md */,
);
path = libgeneral;
sourceTree = "<group>";
};
A8BD2FDD2F5440300045335F /* dependencies */ = {
isa = PBXGroup;
children = (
A8BD2FDC2F5440300045335F /* libgeneral */,
);
path = dependencies;
sourceTree = "<group>";
};
A8BD2FEC2F5440300045335F /* curl */ = {
isa = PBXGroup;
children = (
A8BD2FE02F5440300045335F /* curl.h */,
A8BD2FE12F5440300045335F /* curlbuild.h */,
A8BD2FE42F5440300045335F /* curlrules.h */,
A8BD2FE52F5440300045335F /* curlver.h */,
A8BD2FE62F5440300045335F /* easy.h */,
A8BD2FE82F5440300045335F /* mprintf.h */,
A8BD2FE92F5440300045335F /* multi.h */,
A8BD2FEA2F5440300045335F /* stdcheaders.h */,
A8BD2FEB2F5440300045335F /* typecheck-gcc.h */,
);
path = curl;
sourceTree = "<group>";
};
A8BD2FF02F5440300045335F /* include */ = {
isa = PBXGroup;
children = (
A8BD2FEC2F5440300045335F /* curl */,
);
path = include;
sourceTree = "<group>";
};
A8BD30022F5440300045335F /* libfragmentzip */ = {
isa = PBXGroup;
children = (
A8BD2FDD2F5440300045335F /* dependencies */,
A8BD2FF02F5440300045335F /* include */,
A8BD2FFB2F5440300045335F /* libfragmentzip.xcodeproj */,
A8BD30012F5440300045335F /* README.md */,
);
path = libfragmentzip;
sourceTree = "<group>";
};
A8BD301A2F5440300045335F /* ed25519 */ = {
isa = PBXGroup;
children = (
@@ -1290,25 +1168,6 @@
name = Products;
sourceTree = "<group>";
};
A8EB8CBD2F5453CD0094BC01 /* Products */ = {
isa = PBXGroup;
children = (
A8EB8CC42F5453CD0094BC01 /* libfragmentzip */,
A8EB8CC62F5453CD0094BC01 /* libfragmentzip */,
A8EB8CC82F5453CD0094BC01 /* libfragmentzip.a */,
A8EB8CCA2F5453CD0094BC01 /* libfragmentzip.a */,
);
name = Products;
sourceTree = "<group>";
};
A8EB8CCB2F5453CD0094BC01 /* Products */ = {
isa = PBXGroup;
children = (
A8EB8CCF2F5453CD0094BC01 /* libgeneral */,
);
name = Products;
sourceTree = "<group>";
};
BFD247612284B9A500981D42 = {
isa = PBXGroup;
children = (
@@ -1325,6 +1184,10 @@
B3C39607284F4C8400DA9E2F /* Build.xcconfig */,
B3C39606284F4C8400DA9E2F /* CodeSigning.xcconfig */,
B3C39608284F4C8400DA9E2F /* CodeSigning.xcconfig.sample */,
A84596F12F7DC4C90000B8CD /* .gitignore */,
A84596F22F7DC4C90000B8CD /* .gitmodules */,
A84596F32F7DC4C90000B8CD /* README.md */,
A84596F42F7DC4C90000B8CD /* trustedapps.json */,
);
sourceTree = "<group>";
};
@@ -1344,8 +1207,6 @@
BFD247852284BB3300981D42 /* Frameworks */ = {
isa = PBXGroup;
children = (
A8EB89C92F54519C0094BC01 /* libfragmentzip.a */,
A8EB89C72F5451970094BC01 /* libfragmentzip.a */,
A8635D052F4CF16D00E66784 /* OpenSSL.xcframework */,
BF580497246A3D19008AE704 /* UIKit.framework */,
BFD247862284BB3B00981D42 /* Roxas.framework */,
@@ -1624,14 +1485,6 @@
ProductGroup = A8EB8CB82F5453CD0094BC01 /* Products */;
ProjectRef = A8BD2FBD2F5440300045335F /* em_proxy.xcodeproj */;
},
{
ProductGroup = A8EB8CBD2F5453CD0094BC01 /* Products */;
ProjectRef = A8BD2FFB2F5440300045335F /* libfragmentzip.xcodeproj */;
},
{
ProductGroup = A8EB8CCB2F5453CD0094BC01 /* Products */;
ProjectRef = A8BD2FD72F5440300045335F /* libgeneral.xcodeproj */;
},
{
ProductGroup = A8EB8CAD2F5453CD0094BC01 /* Products */;
ProjectRef = A8BD32D02F5440300045335F /* Roxas.xcodeproj */;
@@ -1678,41 +1531,6 @@
remoteRef = A8EB8CBB2F5453CD0094BC01 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
A8EB8CC42F5453CD0094BC01 /* libfragmentzip */ = {
isa = PBXReferenceProxy;
fileType = "compiled.mach-o.executable";
path = libfragmentzip;
remoteRef = A8EB8CC32F5453CD0094BC01 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
A8EB8CC62F5453CD0094BC01 /* libfragmentzip */ = {
isa = PBXReferenceProxy;
fileType = "compiled.mach-o.executable";
path = libfragmentzip;
remoteRef = A8EB8CC52F5453CD0094BC01 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
A8EB8CC82F5453CD0094BC01 /* libfragmentzip.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libfragmentzip.a;
remoteRef = A8EB8CC72F5453CD0094BC01 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
A8EB8CCA2F5453CD0094BC01 /* libfragmentzip.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libfragmentzip.a;
remoteRef = A8EB8CC92F5453CD0094BC01 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
A8EB8CCF2F5453CD0094BC01 /* libgeneral */ = {
isa = PBXReferenceProxy;
fileType = "compiled.mach-o.executable";
path = libgeneral;
remoteRef = A8EB8CCE2F5453CD0094BC01 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
@@ -2453,8 +2271,6 @@
LD_WARN_UNUSED_DYLIBS = YES;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Dependencies/libfragmentzip",
"$(PROJECT_DIR)/Dependencies/libcurl",
"$(PROJECT_DIR)/Dependencies/minimuxer/Sources/RustBridge/lib",
);
LLVM_LTO = YES_THIN;
@@ -2502,8 +2318,6 @@
LD_WARN_UNUSED_DYLIBS = YES;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Dependencies/libfragmentzip",
"$(PROJECT_DIR)/Dependencies/libcurl",
"$(PROJECT_DIR)/Dependencies/minimuxer/Sources/RustBridge/lib",
);
LLVM_LTO = YES_THIN;

View File

@@ -3,6 +3,3 @@
//
#import "NSAttributedString+Markdown.h"
#import "ALTAppPatcher.h"
#include "fragmentzip.h"

View File

@@ -87,7 +87,7 @@ final class LaunchViewController: UIViewController, UIDocumentPickerDelegate {
}
func start_minimuxer_threads(_ pairing_file: String) {
targetMinimuxerAddress()
retargetUsbmuxdAddr()
let documentsDirectory = FileManager.default.documentsDirectory.absoluteString
do {
let loggingEnabled = UserDefaults.standard.isMinimuxerConsoleLoggingEnabled

View File

@@ -942,70 +942,6 @@ extension AppManager
self.run([enableJITOperation], context: context, requiresSerialQueue: true)
}
func patch(resignedApp: ALTApplication, presentingViewController: UIViewController, context authContext: AuthenticatedOperationContext, completionHandler: @escaping (Result<InstalledApp, Error>) -> Void) -> PatchAppOperation
{
final class Context: InstallAppOperationContext, PatchAppContext
{
}
guard let originalBundleID = resignedApp.bundle.infoDictionary?[Bundle.Info.altBundleID] as? String else {
let context = Context(bundleIdentifier: resignedApp.bundleIdentifier, authenticatedContext: authContext)
completionHandler(.failure(OperationError.invalidApp))
return PatchAppOperation(context: context)
}
let context = Context(bundleIdentifier: originalBundleID, authenticatedContext: authContext)
context.resignedApp = resignedApp
let patchAppOperation = PatchAppOperation(context: context)
let sendAppOperation = SendAppOperation(context: context)
let installOperation = InstallAppOperation(context: context)
let installationProgress = Progress.discreteProgress(totalUnitCount: 100)
installationProgress.addChild(sendAppOperation.progress, withPendingUnitCount: 40)
installationProgress.addChild(installOperation.progress, withPendingUnitCount: 60)
/* Patch */
patchAppOperation.resultHandler = { [weak patchAppOperation] (result) in
switch result
{
case .failure(let error):
context.error = error
case .success:
// Kinda hacky that we're calling patchAppOperation's progressHandler manually, but YOLO.
patchAppOperation?.progressHandler?(installationProgress, NSLocalizedString("Patching placeholder app...", comment: ""))
}
}
/* Send */
sendAppOperation.resultHandler = { (result) in
switch result
{
case .failure(let error):
context.error = error
completionHandler(.failure(error))
case .success(_): print("App sent over AFC")
}
}
sendAppOperation.addDependency(patchAppOperation)
/* Install */
installOperation.resultHandler = { (result) in
switch result
{
case .failure(let error): completionHandler(.failure(error))
case .success(let installedApp): completionHandler(.success(installedApp))
}
//UIApplication.shared.open(shortcutURLon, options: [:], completionHandler: nil)
}
installOperation.addDependency(sendAppOperation)
self.run([patchAppOperation, sendAppOperation, installOperation], context: context.authenticatedContext)
return patchAppOperation
}
func installationProgress(for app: AppProtocol) -> Progress?
{
os_unfair_lock_lock(self.progressLock)
@@ -1393,80 +1329,6 @@ private extension AppManager
}
deactivateAppsOperation.addDependency(fetchProvisioningProfilesOperation)
/* Patch App */
let patchAppOperation = RSTAsyncBlockOperation { operation in
do
{
// Only attempt to patch app if we're installing a new app, not refreshing existing app.
// Post reboot, we install the correct jailbreak app by refreshing the patched app,
// so this check avoids infinite recursion.
guard case .install = appOperation else {
operation.finish()
return
}
guard let presentingViewController = context.presentingViewController else { return operation.finish() }
if let error = context.error
{
throw error
}
guard let app = context.app else {
throw OperationError.invalidParameters("AppManager._install.patchAppOperation: context.app is nil")
}
guard let isUntetherRequired = app.bundle.infoDictionary?[Bundle.Info.untetherRequired] as? Bool,
let minimumiOSVersionString = app.bundle.infoDictionary?[Bundle.Info.untetherMinimumiOSVersion] as? String,
let maximumiOSVersionString = app.bundle.infoDictionary?[Bundle.Info.untetherMaximumiOSVersion] as? String,
case let minimumiOSVersion = OperatingSystemVersion(string: minimumiOSVersionString),
case let maximumiOSVersion = OperatingSystemVersion(string: maximumiOSVersionString)
else { return operation.finish() }
let iOSVersion = ProcessInfo.processInfo.operatingSystemVersion
let iOSVersionSupported = ProcessInfo.processInfo.isOperatingSystemAtLeast(minimumiOSVersion) &&
(!ProcessInfo.processInfo.isOperatingSystemAtLeast(maximumiOSVersion) || maximumiOSVersion == iOSVersion)
guard isUntetherRequired, iOSVersionSupported, UIDevice.current.supportsFugu14 else { return operation.finish() }
guard let patchAppLink = app.bundle.infoDictionary?[Bundle.Info.untetherURL] as? String,
let patchAppURL = URL(string: patchAppLink)
else { throw OperationError.invalidApp }
let patchApp = AnyApp(name: app.name, bundleIdentifier: context.bundleIdentifier, url: patchAppURL, storeApp: nil)
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "PatchApp", bundle: nil)
let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController
let patchViewController = navigationController.topViewController as! PatchViewController
patchViewController.patchApp = patchApp
patchViewController.completionHandler = { [weak presentingViewController] (result) in
switch result
{
case .failure(OperationError.cancelled): break // Ignore
case .failure(let error): group.context.error = error
case .success: group.context.error = OperationError.cancelled
}
operation.finish()
DispatchQueue.main.async {
presentingViewController?.dismiss(animated: true, completion: nil)
}
}
presentingViewController.present(navigationController, animated: true, completion: nil)
}
}
catch
{
group.context.error = error
operation.finish()
}
}
patchAppOperation.addDependency(deactivateAppsOperation)
let modifyAppExBundleIdOperation = RSTAsyncBlockOperation { operation in
if !context.useMainProfile {
operation.finish()
@@ -1498,7 +1360,7 @@ private extension AppManager
self.exportResginedAppsToDocsDir(resignedApp)
}
}
resignAppOperation.addDependency(patchAppOperation)
resignAppOperation.addDependency(deactivateAppsOperation)
resignAppOperation.addDependency(modifyAppExBundleIdOperation)
progress.addChild(resignAppOperation.progress, withPendingUnitCount: 20)
@@ -1549,7 +1411,6 @@ private extension AppManager
verifyOperation,
removeAppExtensionsOperation,
deactivateAppsOperation,
patchAppOperation,
refreshAnisetteDataOperation,
fetchProvisioningProfilesOperation,
modifyAppExBundleIdOperation,

View File

@@ -101,7 +101,7 @@ final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result<Inst
if UserDefaults.standard.enableEMPforWireguard {
startEMProxy(bind_addr: AppConstants.Proxy.serverURL)
}
targetMinimuxerAddress()
retargetUsbmuxdAddr()
let documentsDirectory = FileManager.default.documentsDirectory.absoluteString
do {
// enable minimuxer console logging only if enabled in settings

View File

@@ -214,13 +214,11 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
alert.addAction(UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default, handler: { _ in
print("Going home")
// Cell Shortcut
DispatchQueue.main.async{
// UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in
// print("Cell OFF Shortcut finished execution.")
// }
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
if self.context.shouldTurnOffData {
UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in
print("Cell OFF Shortcut finished execution.")}
}
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
}))
DispatchQueue.main.async {
@@ -236,14 +234,11 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
}
}
}
DispatchQueue.main.async {
// Cell Shortcut
// UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in
// print("Cell OFF Shortcut finished execution.")
// }
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
// Cell Shortcut
if self.context.shouldTurnOffData {
UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in print("Cell OFF Shortcut finished execution.")}
}
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
}
}

View File

@@ -123,6 +123,8 @@ class InstallAppOperationContext: AppOperationContext
var alternateIconURL: URL?
var shouldTurnOffData: Bool = false
// Non-nil when installing from a source.
@AsyncManaged
var appVersion: AppVersion?

View File

@@ -1,19 +0,0 @@
//
// ALTAppPatcher.h
// AltStore
//
// Created by Riley Testut on 10/18/21.
// Copyright © 2021 Riley Testut. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ALTAppPatcher : NSObject
- (BOOL)patchAppBinaryAtURL:(NSURL *)appFileURL withBinaryAtURL:(NSURL *)patchFileURL error:(NSError *_Nullable *)error;
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,143 +0,0 @@
//
// ALTAppPatcher.m
// AltStore
//
// Created by Riley Testut on 10/18/21.
// Copied with minor modifications from sample code provided by Linus Henze.
//
#import "ALTAppPatcher.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@import Roxas;
#define CPU_SUBTYPE_PAC 0x80000000
#define FAT_MAGIC 0xcafebabe
#define ROUND_TO_PAGE(val) (((val % 0x4000) == 0) ? val : (val + (0x4000 - (val & 0x3FFF))))
typedef struct {
uint32_t magic;
uint32_t cpuType;
uint32_t cpuSubType;
// Incomplete, we don't need anything else
} MachOHeader;
typedef struct {
uint32_t cpuType;
uint32_t cpuSubType;
uint32_t fileOffset;
uint32_t size;
uint32_t alignment;
} FatArch;
typedef struct {
uint32_t magic;
uint32_t archCount;
FatArch archs[0];
} FatHeader;
// Given two MachO files, return a FAT file with the following properties:
// 1. installd will still see the original MachO and validate it's code signature
// 2. The kernel will only see the injected MachO instead
//
// Only arm64e for now
void *injectApp(void *originalApp, size_t originalAppSize, void *appToInject, size_t appToInjectSize, size_t *outputSize) {
*outputSize = 0;
// First validate the App to inject: It must be an arm64e application
if (appToInjectSize < sizeof(MachOHeader)) {
return NULL;
}
MachOHeader *injectedHeader = (MachOHeader*) appToInject;
if (injectedHeader->cpuType != CPU_TYPE_ARM64) {
return NULL;
}
if (injectedHeader->cpuSubType != (CPU_SUBTYPE_ARM64E | CPU_SUBTYPE_PAC)) {
return NULL;
}
// Ok, the App to inject is ok
// Now build a fat header
size_t originalAppSizeRounded = ROUND_TO_PAGE(originalAppSize);
size_t appToInjectSizeRounded = ROUND_TO_PAGE(appToInjectSize);
size_t totalSize = 0x4000 /* Fat Header + Alignment */ + originalAppSizeRounded + appToInjectSizeRounded;
void *fatBuf = malloc(totalSize);
if (fatBuf == NULL) {
return NULL;
}
bzero(fatBuf, totalSize);
FatHeader *fatHeader = (FatHeader*) fatBuf;
fatHeader->magic = htonl(FAT_MAGIC);
fatHeader->archCount = htonl(2);
// Write first arch (original app)
fatHeader->archs[0].cpuType = htonl(CPU_TYPE_ARM64);
fatHeader->archs[0].cpuSubType = htonl(CPU_SUBTYPE_ARM64E); /* Note that this is not a valid cpu subtype */
fatHeader->archs[0].fileOffset = htonl(0x4000);
fatHeader->archs[0].size = htonl(originalAppSize);
fatHeader->archs[0].alignment = htonl(0xE);
// Write second arch (injected app)
fatHeader->archs[1].cpuType = htonl(CPU_TYPE_ARM64);
fatHeader->archs[1].cpuSubType = htonl(CPU_SUBTYPE_ARM64E | CPU_SUBTYPE_PAC);
fatHeader->archs[1].fileOffset = htonl(0x4000 + originalAppSizeRounded);
fatHeader->archs[1].size = htonl(appToInjectSize);
fatHeader->archs[1].alignment = htonl(0xE);
// Ok, now write the MachOs
memcpy(fatBuf + 0x4000, originalApp, originalAppSize);
memcpy(fatBuf + 0x4000 + originalAppSizeRounded, appToInject, appToInjectSize);
// We're done!
*outputSize = totalSize;
return fatBuf;
}
@implementation ALTAppPatcher
- (BOOL)patchAppBinaryAtURL:(NSURL *)appFileURL withBinaryAtURL:(NSURL *)patchFileURL error:(NSError *__autoreleasing *)error
{
NSMutableData *originalApp = [NSMutableData dataWithContentsOfURL:appFileURL options:0 error:error];
if (originalApp == nil)
{
return NO;
}
NSMutableData *injectedApp = [NSMutableData dataWithContentsOfURL:patchFileURL options:0 error:error];
if (injectedApp == nil)
{
return NO;
}
size_t outputSize = 0;
void *output = injectApp(originalApp.mutableBytes, originalApp.length, injectedApp.mutableBytes, injectedApp.length, &outputSize);
if (output == NULL)
{
if (error)
{
// If injectApp fails, it means the patch app is in the wrong format.
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadCorruptFileError userInfo:@{NSURLErrorKey: patchFileURL}];
}
return NO;
}
NSData *outputData = [NSData dataWithBytesNoCopy:output length:outputSize freeWhenDone:YES];
if (![outputData writeToURL:appFileURL options:NSDataWritingAtomic error:error])
{
return NO;
}
return YES;
}
@end

View File

@@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="WBb-E1-bN8">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Navigation Controller-->
<scene sceneID="dx2-fp-qDX">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="WBb-E1-bN8" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" id="cVa-8m-fW6" customClass="NavigationBar" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<color key="barTintColor" name="SettingsBackground"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="idH-XF-rK8" kind="relationship" relationship="rootViewController" id="hSJ-tL-4nB"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="i7K-pi-SRe" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="137.68115942028987" y="137.94642857142856"/>
</scene>
<!--Patch View Controller-->
<scene sceneID="gJ4-4F-79r">
<objects>
<viewController id="idH-XF-rK8" customClass="PatchViewController" customModule="AltStore" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" id="4bV-S5-z7S">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RHK-C5-7wu" customClass="RSTPlaceholderView">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
</view>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="PjB-Dc-9n3">
<rect key="frame" x="20" y="736.5" width="374" height="117.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" " textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GQF-6P-Fit">
<rect key="frame" x="0.0" y="0.0" width="374" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" name="Text"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SNn-Ad-ICf" customClass="PillButton" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="28.5" width="374" height="51"/>
<color key="backgroundColor" name="SettingsHighlighted"/>
<constraints>
<constraint firstAttribute="height" constant="51" id="s4X-uf-nl9"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="19"/>
<color key="tintColor" name="SettingsHighlighted"/>
<state key="normal" title="Install Untethered Jailbreak">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="performButtonAction" destination="idH-XF-rK8" eventType="primaryActionTriggered" id="FxO-1Y-IML"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="leJ-09-giz">
<rect key="frame" x="0.0" y="87.5" width="374" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" title="Install Without Untethering">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="installRegularJailbreak" destination="idH-XF-rK8" eventType="primaryActionTriggered" id="1XB-11-Kdn"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="H6g-xA-DdL"/>
<color key="backgroundColor" name="SettingsBackground"/>
<constraints>
<constraint firstItem="RHK-C5-7wu" firstAttribute="top" secondItem="4bV-S5-z7S" secondAttribute="top" id="CVK-6E-iA6"/>
<constraint firstAttribute="trailingMargin" secondItem="PjB-Dc-9n3" secondAttribute="trailing" id="GOg-JU-LIP"/>
<constraint firstItem="RHK-C5-7wu" firstAttribute="bottom" secondItem="4bV-S5-z7S" secondAttribute="bottom" id="LPh-J8-IVx"/>
<constraint firstItem="PjB-Dc-9n3" firstAttribute="leading" secondItem="4bV-S5-z7S" secondAttribute="leadingMargin" id="Rlg-PC-5ZN"/>
<constraint firstItem="RHK-C5-7wu" firstAttribute="trailing" secondItem="H6g-xA-DdL" secondAttribute="trailing" id="XdZ-36-6yS"/>
<constraint firstAttribute="bottomMargin" secondItem="PjB-Dc-9n3" secondAttribute="bottom" id="hTS-nX-0xv"/>
<constraint firstItem="RHK-C5-7wu" firstAttribute="leading" secondItem="H6g-xA-DdL" secondAttribute="leading" id="lzV-fG-Xv6"/>
</constraints>
</view>
<navigationItem key="navigationItem" largeTitleDisplayMode="always" id="0J1-80-RD8">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="vtw-PQ-Dk1">
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<action selector="cancel" destination="idH-XF-rK8" id="4Wk-dv-RYG"/>
</connections>
</barButtonItem>
</navigationItem>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<connections>
<outlet property="cancelBarButtonItem" destination="vtw-PQ-Dk1" id="8Mh-GU-KD5"/>
<outlet property="cancelButton" destination="leJ-09-giz" id="BNh-I3-vXc"/>
<outlet property="pillButton" destination="SNn-Ad-ICf" id="iJg-TC-p8q"/>
<outlet property="placeholderView" destination="RHK-C5-7wu" id="5x0-sg-HAH"/>
<outlet property="taskDescriptionLabel" destination="GQF-6P-Fit" id="C4c-xy-kvU"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="8ev-19-qsi" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1001" y="138"/>
</scene>
</scenes>
<resources>
<namedColor name="SettingsBackground">
<color red="0.0039215686274509803" green="0.50196078431372548" blue="0.51764705882352946" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="SettingsHighlighted">
<color red="0.0080000003799796104" green="0.32199999690055847" blue="0.40400001406669617" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="Text">
<color red="1" green="1" blue="1" alpha="0.75" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources>
</document>

View File

@@ -1,256 +0,0 @@
//
// PatchAppOperation.swift
// AltStore
//
// Created by Riley Testut on 10/13/21.
// Copyright © 2021 Riley Testut. All rights reserved.
//
import UIKit
import Combine
import AppleArchive
import System
import AltStoreCore
import AltSign
import Roxas
protocol PatchAppContext
{
var bundleIdentifier: String { get }
var temporaryDirectory: URL { get }
var resignedApp: ALTApplication? { get }
var error: Error? { get }
}
extension PatchAppError
{
enum Code: Int, ALTErrorCode, CaseIterable {
typealias Error = PatchAppError
case unsupportedOperatingSystemVersion
}
static func unsupportedOperatingSystemVersion(_ osVersion: OperatingSystemVersion) -> PatchAppError {
PatchAppError(code: .unsupportedOperatingSystemVersion, osVersion: osVersion)
}
}
struct PatchAppError: ALTLocalizedError {
let code: Code
var errorTitle: String?
var errorFailure: String?
var osVersion: OperatingSystemVersion?
var errorFailureReason: String {
switch self.code {
case .unsupportedOperatingSystemVersion:
let osVersionString: String
if let osVersion = self.osVersion?.stringValue {
osVersionString = NSLocalizedString("iOS", comment: "") + " " + osVersion
} else {
osVersionString = NSLocalizedString("your device's iOS version", comment: "")
}
return String(format: NSLocalizedString("The OTA download URL for %@ could not be determined.", comment: ""), osVersionString)
}
}
}
private struct OTAUpdate
{
var url: URL
var archivePath: String
}
@available(iOS 14, *)
final class PatchAppOperation: ResultOperation<Void>
{
let context: PatchAppContext
var progressHandler: ((Progress, String) -> Void)?
private let appPatcher = ALTAppPatcher()
private lazy var patchDirectory: URL = self.context.temporaryDirectory.appendingPathComponent("Patch", isDirectory: true)
private var cancellable: AnyCancellable?
init(context: PatchAppContext)
{
self.context = context
super.init()
self.progress.totalUnitCount = 100
}
override func main()
{
super.main()
if let error = self.context.error
{
self.finish(.failure(error))
return
}
guard let resignedApp = self.context.resignedApp else {
return self.finish(.failure(OperationError.invalidParameters("PatchAppOperation.main: self.context.resignedApp is nil")))
}
self.progressHandler?(self.progress, NSLocalizedString("Downloading iOS firmware...", comment: ""))
self.cancellable = self.fetchOTAUpdate()
.flatMap { self.downloadArchive(from: $0) }
.flatMap { self.extractSpotlightFromArchive(at: $0) }
.flatMap { self.patch(resignedApp, withBinaryAt: $0) }
.tryMap { try FileManager.default.zipAppBundle(at: $0) }
.tryMap { (fileURL) in
let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL, storeApp: nil)
let destinationURL = InstalledApp.refreshedIPAURL(for: app)
try FileManager.default.copyItem(at: fileURL, to: destinationURL, shouldReplace: true)
}
.receive(on: RunLoop.main)
.sink { completion in
switch completion
{
case .failure(let error): self.finish(.failure(error))
case .finished: self.finish(.success(()))
}
} receiveValue: { _ in }
}
override func cancel()
{
super.cancel()
self.cancellable?.cancel()
self.cancellable = nil
}
}
private let ALTFragmentZipCallback: @convention(c) (UInt32) -> Void = { (percentageComplete) in
guard let progress = Progress.current() else { return }
if percentageComplete == 100 && progress.completedUnitCount == 0
{
// Ignore first percentageComplete, which is always 100.
return
}
progress.completedUnitCount = Int64(percentageComplete)
}
private extension PatchAppOperation
{
func fetchOTAUpdate() -> AnyPublisher<OTAUpdate, Error>
{
Just(()).tryMap {
let osVersion = ProcessInfo.processInfo.operatingSystemVersion
switch (osVersion.majorVersion, osVersion.minorVersion)
{
case (14, 3):
return OTAUpdate(url: URL(string: "https://updates.cdn-apple.com/2020WinterFCS/patches/001-87330/99E29969-F6B6-422A-B946-70DE2E2D73BE/com_apple_MobileAsset_SoftwareUpdate/67f9e42f5e57a20e0a87eaf81b69dd2a61311d3f.zip")!,
archivePath: "AssetData/payloadv2/payload.042")
case (14, 4):
return OTAUpdate(url: URL(string: "https://updates.cdn-apple.com/2021WinterFCS/patches/001-98606/43AF99A1-F286-43B1-A101-F9F856EA395A/com_apple_MobileAsset_SoftwareUpdate/c4985c32c344beb7b49c61919b4e39d1fd336c90.zip")!,
archivePath: "AssetData/payloadv2/payload.042")
case (14, 5):
return OTAUpdate(url: URL(string: "https://updates.cdn-apple.com/2021SpringFCS/patches/061-84483/AB525139-066E-46F8-8E85-DCE802C03BA8/com_apple_MobileAsset_SoftwareUpdate/788573ae93113881db04269acedeecabbaa643e3.zip")!,
archivePath: "AssetData/payloadv2/payload.043")
default: throw PatchAppError.unsupportedOperatingSystemVersion(osVersion)
}
}
.eraseToAnyPublisher()
}
func downloadArchive(from update: OTAUpdate) -> AnyPublisher<URL, Error>
{
Just(()).tryMap {
#if targetEnvironment(simulator)
throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion)
#else
try FileManager.default.createDirectory(at: self.patchDirectory, withIntermediateDirectories: true, attributes: nil)
let archiveURL = self.patchDirectory.appendingPathComponent("ota.archive")
try archiveURL.withUnsafeFileSystemRepresentation { archivePath in
guard let fz = fragmentzip_open((update.url.absoluteString as NSString).utf8String!) else {
throw URLError(.cannotConnectToHost, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("The connection failed because a connection cannot be made to the host.", comment: ""),
NSURLErrorKey: update.url])
}
defer { fragmentzip_close(fz) }
self.progress.becomeCurrent(withPendingUnitCount: 100)
defer { self.progress.resignCurrent() }
guard fragmentzip_download_file(fz, update.archivePath, archivePath!, ALTFragmentZipCallback) == 0 else {
throw URLError(.networkConnectionLost, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("The connection failed because the network connection was lost.", comment: ""),
NSURLErrorKey: update.url])
}
}
Logger.fugu14.notice("Downloaded iOS OTA archive.")
return archiveURL
#endif
}
.mapError { ($0 as NSError).withLocalizedFailure(NSLocalizedString("Could not download OTA archive.", comment: "")) }
.eraseToAnyPublisher()
}
func extractSpotlightFromArchive(at archiveURL: URL) -> AnyPublisher<URL, Error>
{
Just(()).tryMap {
#if targetEnvironment(simulator)
throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion)
#else
let spotlightPath = "Applications/Spotlight.app/Spotlight"
let spotlightFileURL = self.patchDirectory.appendingPathComponent(spotlightPath)
guard let readFileStream = ArchiveByteStream.fileStream(path: FilePath(archiveURL.path), mode: .readOnly, options: [], permissions: FilePermissions(rawValue: 0o644)),
let decompressStream = ArchiveByteStream.decompressionStream(readingFrom: readFileStream),
let decodeStream = ArchiveStream.decodeStream(readingFrom: decompressStream),
let readStream = ArchiveStream.extractStream(extractingTo: FilePath(self.patchDirectory.path))
else { throw CocoaError(.fileReadCorruptFile, userInfo: [NSURLErrorKey: archiveURL]) }
_ = try ArchiveStream.process(readingFrom: decodeStream, writingTo: readStream) { message, filePath, data in
guard filePath == FilePath(spotlightPath) else { return .skip }
return .ok
}
Logger.fugu14.notice("Extracted Spotlight from OTA archive.")
return spotlightFileURL
#endif
}
.mapError { ($0 as NSError).withLocalizedFailure(NSLocalizedString("Could not extract Spotlight from OTA archive.", comment: "")) }
.eraseToAnyPublisher()
}
func patch(_ app: ALTApplication, withBinaryAt patchFileURL: URL) -> AnyPublisher<URL, Error>
{
Just(()).tryMap {
// executableURL may be nil, so use infoDictionary instead to determine executable name.
// guard let appName = app.bundle.executableURL?.lastPathComponent else { throw OperationError.invalidApp }
guard let appName = app.bundle.infoDictionary?[kCFBundleExecutableKey as String] as? String else { throw OperationError.invalidApp }
let temporaryAppURL = self.patchDirectory.appendingPathComponent("Patched.app", isDirectory: true)
try FileManager.default.copyItem(at: app.fileURL, to: temporaryAppURL)
let appBinaryURL = temporaryAppURL.appendingPathComponent(appName, isDirectory: false)
try self.appPatcher.patchAppBinary(at: appBinaryURL, withBinaryAt: patchFileURL)
Logger.fugu14.notice("Patched \(app.name, privacy: .public)!")
return temporaryAppURL
}
.mapError { ($0 as NSError).withLocalizedFailure(String(format: NSLocalizedString("Could not patch %@ placeholder.", comment: ""), app.name)) }
.eraseToAnyPublisher()
}
}

View File

@@ -1,494 +0,0 @@
//
// PatchViewController.swift
// AltStore
//
// Created by Riley Testut on 10/20/21.
// Copyright © 2021 Riley Testut. All rights reserved.
//
import UIKit
import Combine
import AltStoreCore
import AltSign
import Roxas
extension PatchViewController
{
enum Step
{
case confirm
case install
case openApp
case patchApp
case reboot
case refresh
case finish
}
}
@available(iOS 14.0, *)
final class PatchViewController: UIViewController
{
var patchApp: AnyApp?
var installedApp: InstalledApp?
var completionHandler: ((Result<Void, Error>) -> Void)?
private let context = AuthenticatedOperationContext()
private var currentStep: Step = .confirm {
didSet {
DispatchQueue.main.async {
self.update()
}
}
}
private var buttonHandler: (() -> Void)?
private var resignedApp: ALTApplication?
private lazy var temporaryDirectory: URL = FileManager.default.uniqueTemporaryURL()
private var didEnterBackgroundObservation: NSObjectProtocol?
private weak var cancellableProgress: Progress?
@IBOutlet private var placeholderView: RSTPlaceholderView!
@IBOutlet private var taskDescriptionLabel: UILabel!
@IBOutlet private var pillButton: PillButton!
@IBOutlet private var cancelBarButtonItem: UIBarButtonItem!
@IBOutlet private var cancelButton: UIButton!
override func viewDidLoad()
{
super.viewDidLoad()
self.isModalInPresentation = true
self.placeholderView.stackView.spacing = 20
self.placeholderView.textLabel.textColor = .white
self.placeholderView.detailTextLabel.textAlignment = .left
self.placeholderView.detailTextLabel.textColor = UIColor.white.withAlphaComponent(0.6)
self.buttonHandler = { [weak self] in
self?.startProcess()
}
do
{
try FileManager.default.createDirectory(at: self.temporaryDirectory, withIntermediateDirectories: true, attributes: nil)
}
catch
{
Logger.fugu14.error("Failed to create temporary directory \(self.temporaryDirectory.lastPathComponent, privacy: .public). \(error.localizedDescription, privacy: .public)")
}
self.update()
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
if self.installedApp != nil
{
self.refreshApp()
}
}
}
private extension PatchViewController
{
func update()
{
self.cancelButton.alpha = 0.0
switch self.currentStep
{
case .confirm:
guard let app = self.patchApp else { break }
if UIDevice.current.isUntetheredJailbreakRequired
{
self.placeholderView.textLabel.text = NSLocalizedString("Jailbreak Requires Untethering", comment: "")
self.placeholderView.detailTextLabel.text = String(format: NSLocalizedString("This jailbreak is untethered, which means %@ will never expire — even after 7 days or rebooting the device.\n\nInstalling an untethered jailbreak requires a few extra steps, but SideStore will walk you through the process.\n\nWould you like to continue? ", comment: ""), app.name)
}
else
{
self.placeholderView.textLabel.text = NSLocalizedString("Jailbreak Supports Untethering", comment: "")
self.placeholderView.detailTextLabel.text = String(format: NSLocalizedString("This jailbreak has an untethered version, which means %@ will never expire — even after 7 days or rebooting the device.\n\nInstalling an untethered jailbreak requires a few extra steps, but SideStore will walk you through the process.\n\nWould you like to continue? ", comment: ""), app.name)
}
self.pillButton.setTitle(NSLocalizedString("Install Untethered Jailbreak", comment: ""), for: .normal)
self.cancelButton.alpha = 1.0
case .install:
guard let app = self.patchApp else { break }
self.placeholderView.textLabel.text = String(format: NSLocalizedString("Installing %@ placeholder…", comment: ""), app.name)
self.placeholderView.detailTextLabel.text = NSLocalizedString("A placeholder app needs to be installed in order to prepare your device for untethering.\n\nThis may take a few moments.", comment: "")
case .openApp:
self.placeholderView.textLabel.text = NSLocalizedString("Continue in App", comment: "")
self.placeholderView.detailTextLabel.text = NSLocalizedString("Please open the placeholder app and follow the instructions to continue jailbreaking your device.", comment: "")
self.pillButton.setTitle(NSLocalizedString("Open Placeholder", comment: ""), for: .normal)
case .patchApp:
guard let app = self.patchApp else { break }
self.placeholderView.textLabel.text = String(format: NSLocalizedString("Patching %@ placeholder…", comment: ""), app.name)
self.placeholderView.detailTextLabel.text = NSLocalizedString("This will take a few moments. Please do not turn off the screen or leave the app until patching is complete.", comment: "")
self.pillButton.setTitle(NSLocalizedString("Patch Placeholder", comment: ""), for: .normal)
case .reboot:
self.placeholderView.textLabel.text = NSLocalizedString("Continue in App", comment: "")
self.placeholderView.detailTextLabel.text = NSLocalizedString("Please open the placeholder app and follow the instructions to continue jailbreaking your device.", comment: "")
self.pillButton.setTitle(NSLocalizedString("Open Placeholder", comment: ""), for: .normal)
case .refresh:
guard let installedApp = self.installedApp else { break }
self.placeholderView.textLabel.text = String(format: NSLocalizedString("Finish installing %@?", comment: ""), installedApp.name)
self.placeholderView.detailTextLabel.text = String(format: NSLocalizedString("In order to finish jailbreaking this device, you need to install %@ then follow the instructions in the app.", comment: ""), installedApp.name)
self.pillButton.setTitle(String(format: NSLocalizedString("Install %@", comment: ""), installedApp.name), for: .normal)
case .finish:
guard let installedApp = self.installedApp else { break }
self.placeholderView.textLabel.text = String(format: NSLocalizedString("Finish in %@", comment: ""), installedApp.name)
self.placeholderView.detailTextLabel.text = String(format: NSLocalizedString("Follow the instructions in %@ to finish jailbreaking this device.", comment: ""), installedApp.name)
self.pillButton.setTitle(String(format: NSLocalizedString("Open %@", comment: ""), installedApp.name), for: .normal)
}
}
func present(_ error: Error, title: String)
{
DispatchQueue.main.async {
let nsError = error as NSError
let alertController = UIAlertController(title: nsError.localizedFailure ?? title, message: error.localizedDescription, preferredStyle: .alert)
alertController.addAction(.ok)
self.present(alertController, animated: true, completion: nil)
self.setProgress(nil, description: nil)
}
}
func setProgress(_ progress: Progress?, description: String?)
{
DispatchQueue.main.async {
self.pillButton.progress = progress
self.taskDescriptionLabel.text = description ?? " " // Use non-empty string to prevent label resizing itself.
}
}
func finish(with result: Result<Void, Error>)
{
do
{
try FileManager.default.removeItem(at: self.temporaryDirectory)
}
catch
{
Logger.fugu14.error("Failed to remove temporary directory \(self.temporaryDirectory.lastPathComponent, privacy: .public). \(error.localizedDescription, privacy: .public)")
}
if let observation = self.didEnterBackgroundObservation
{
NotificationCenter.default.removeObserver(observation)
}
self.completionHandler?(result)
self.completionHandler = nil
}
}
private extension PatchViewController
{
@IBAction func performButtonAction()
{
self.buttonHandler?()
}
@IBAction func cancel()
{
self.finish(with: .success(()))
self.cancellableProgress?.cancel()
}
@IBAction func installRegularJailbreak()
{
guard let app = self.patchApp else { return }
let title: String
let message: String
if UIDevice.current.isUntetheredJailbreakRequired
{
title = NSLocalizedString("Untethering Required", comment: "")
message = String(format: NSLocalizedString("%@ can not jailbreak this device unless you untether it first. Are you sure you want to install without untethering?", comment: ""), app.name)
}
else
{
title = NSLocalizedString("Untethering Recommended", comment: "")
message = String(format: NSLocalizedString("Untethering this jailbreak will prevent %@ from expiring, even after 7 days or rebooting the device. Are you sure you want to install without untethering?", comment: ""), app.name)
}
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Install Without Untethering", comment: ""), style: .default) { _ in
self.finish(with: .failure(OperationError.cancelled))
})
alertController.addAction(.cancel)
self.present(alertController, animated: true, completion: nil)
}
}
private extension PatchViewController
{
func startProcess()
{
guard let patchApp = self.patchApp else { return }
self.currentStep = .install
if let progress = AppManager.shared.installationProgress(for: patchApp)
{
// Cancel pending jailbreak app installation so we can start a new one.
progress.cancel()
}
let appURL = InstalledApp.fileURL(for: patchApp)
let cachedAppURL = self.temporaryDirectory.appendingPathComponent("Cached.app")
do
{
// Make copy of original app, so we can replace the cached patch app with it later.
try FileManager.default.copyItem(at: appURL, to: cachedAppURL, shouldReplace: true)
}
catch
{
self.present(error, title: NSLocalizedString("Could not back up jailbreak app.", comment: ""))
return
}
var unzippingError: Error?
let refreshGroup = AppManager.shared.install(patchApp, presentingViewController: self, context: self.context) { result in
do
{
_ = try result.get()
if let unzippingError = unzippingError
{
throw unzippingError
}
// Replace cached patch app with original app so we can resume installing it post-reboot.
try FileManager.default.copyItem(at: cachedAppURL, to: appURL, shouldReplace: true)
self.openApp()
}
catch
{
self.present(error, title: String(format: NSLocalizedString("Could not install %@ placeholder.", comment: ""), patchApp.name))
}
}
refreshGroup.beginInstallationHandler = { (installedApp) in
do
{
// Replace patch app name with correct name.
installedApp.name = patchApp.name
let ipaURL = installedApp.refreshedIPAURL
let resignedAppURL = try FileManager.default.unzipAppBundle(at: ipaURL, toDirectory: self.temporaryDirectory)
self.resignedApp = ALTApplication(fileURL: resignedAppURL)
}
catch
{
Logger.fugu14.error("Error unzipping app bundle: \(error.localizedDescription, privacy: .public)")
unzippingError = error
}
}
self.setProgress(refreshGroup.progress, description: nil)
self.cancellableProgress = refreshGroup.progress
}
func openApp()
{
guard let patchApp = self.patchApp else { return }
self.setProgress(nil, description: nil)
self.currentStep = .openApp
// This observation is willEnterForeground because patching starts immediately upon return.
self.didEnterBackgroundObservation = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { (notification) in
self.didEnterBackgroundObservation.map { NotificationCenter.default.removeObserver($0) }
self.patchApplication()
}
self.buttonHandler = { [weak self] in
guard let self = self else { return }
#if !targetEnvironment(simulator)
let openURL = InstalledApp.openAppURL(for: patchApp)
UIApplication.shared.open(openURL) { success in
guard !success else { return }
self.present(OperationError.openAppFailed(name: patchApp.name), title: String(format: NSLocalizedString("Could not open %@ placeholder.", comment: ""), patchApp.name))
}
#endif
}
}
func patchApplication()
{
guard let resignedApp = self.resignedApp else { return }
self.currentStep = .patchApp
self.buttonHandler = { [weak self] in
self?.patchApplication()
}
let patchAppOperation = AppManager.shared.patch(resignedApp: resignedApp, presentingViewController: self, context: self.context) { result in
switch result
{
case .failure(let error): self.present(error, title: String(format: NSLocalizedString("Could not patch %@ placeholder.", comment: ""), resignedApp.name))
case .success: self.rebootDevice()
}
}
patchAppOperation.progressHandler = { (progress, description) in
self.setProgress(progress, description: description)
}
self.cancellableProgress = patchAppOperation.progress
}
func rebootDevice()
{
guard let patchApp = self.patchApp else { return }
self.setProgress(nil, description: nil)
self.currentStep = .reboot
self.didEnterBackgroundObservation = NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { (notification) in
self.didEnterBackgroundObservation.map { NotificationCenter.default.removeObserver($0) }
var patchedApps = UserDefaults.standard.patchedApps ?? []
if !patchedApps.contains(patchApp.bundleIdentifier)
{
patchedApps.append(patchApp.bundleIdentifier)
UserDefaults.standard.patchedApps = patchedApps
}
self.finish(with: .success(()))
}
self.buttonHandler = { [weak self] in
guard let self = self else { return }
#if !targetEnvironment(simulator)
let openURL = InstalledApp.openAppURL(for: patchApp)
UIApplication.shared.open(openURL) { success in
guard !success else { return }
self.present(OperationError.openAppFailed(name: patchApp.name), title: String(format: NSLocalizedString("Could not open %@ placeholder.", comment: ""), patchApp.name))
}
#endif
}
}
func refreshApp()
{
guard let installedApp = self.installedApp else { return }
self.currentStep = .refresh
self.buttonHandler = { [weak self] in
guard let self = self else { return }
DatabaseManager.shared.persistentContainer.performBackgroundTask { context in
let tempApp = context.object(with: installedApp.objectID) as! InstalledApp
tempApp.needsResign = true
let errorTitle = String(format: NSLocalizedString("Could not install %@.", comment: ""), tempApp.name)
do
{
try context.save()
installedApp.managedObjectContext?.perform {
// Refreshing ensures we don't attempt to patch the app again,
// since that is only checked when installing a new app.
let refreshGroup = AppManager.shared.refresh([installedApp], presentingViewController: self, group: nil)
refreshGroup.completionHandler = { [weak refreshGroup, weak self] (results) in
guard let self = self else { return }
do
{
guard let (bundleIdentifier, result) = results.first else { throw refreshGroup?.context.error ?? OperationError.unknown() }
_ = try result.get()
if var patchedApps = UserDefaults.standard.patchedApps, let index = patchedApps.firstIndex(of: bundleIdentifier)
{
patchedApps.remove(at: index)
UserDefaults.standard.patchedApps = patchedApps
}
self.finish()
}
catch
{
self.present(error, title: errorTitle)
}
}
self.setProgress(refreshGroup.progress, description: String(format: NSLocalizedString("Installing %@...", comment: ""), installedApp.name))
}
}
catch
{
self.present(error, title: errorTitle)
}
}
}
}
func finish()
{
guard let installedApp = self.installedApp else { return }
self.setProgress(nil, description: nil)
self.currentStep = .finish
self.didEnterBackgroundObservation = NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { (notification) in
self.didEnterBackgroundObservation.map { NotificationCenter.default.removeObserver($0) }
self.finish(with: .success(()))
}
installedApp.managedObjectContext?.perform {
let appName = installedApp.name
let openURL = installedApp.openAppURL
self.buttonHandler = { [weak self] in
guard let self = self else { return }
#if !targetEnvironment(simulator)
UIApplication.shared.open(openURL) { success in
guard !success else { return }
self.present(OperationError.openAppFailed(name: appName), title: String(format: NSLocalizedString("Could not open %@.", comment: ""), appName))
}
#endif
}
}
}
}

View File

@@ -1,18 +0,0 @@
//
// fragmentzip.h
// AltStore
//
// Created by Riley Testut on 10/25/21.
// Copyright © 2021 Riley Testut. All rights reserved.
//
#ifndef fragmentzip_h
#define fragmentzip_h
typedef void fragmentzip_t;
typedef void (*fragmentzip_process_callback_t)(unsigned int progress);
fragmentzip_t *fragmentzip_open(const char *url);
int fragmentzip_download_file(fragmentzip_t *info, const char *remotepath, const char *savepath, fragmentzip_process_callback_t callback);
void fragmentzip_close(fragmentzip_t *info);
#endif /* fragmentzip_h */

View File

@@ -10,7 +10,6 @@ import Network
import AltStoreCore
import Minimuxer
@objc(SendAppOperation)
final class SendAppOperation: ResultOperation<()>
{
@@ -44,15 +43,28 @@ final class SendAppOperation: ResultOperation<()>
let fileURL = InstalledApp.refreshedIPAURL(for: app)
print("AFC App `fileURL`: \(fileURL.absoluteString)")
// Wait for Shortcut to Finish Before Proceeding
DispatchQueue.main.async {
// UIApplication.shared.open(shortcutURLoff, options: [:]) { _ in
// print("Shortcut finished execution. Proceeding with file transfer.")
// only when minimuxer is not ready and below 26.4 should we turn off data
if #available(iOS 26.4, *) {
context.shouldTurnOffData = false
} else if !isMinimuxerReady {
context.shouldTurnOffData = true
} else {
context.shouldTurnOffData = false
}
if context.shouldTurnOffData {
// Wait for Shortcut to Finish Before Proceeding
UIApplication.shared.open(shortcutURLoff, options: [:]) { _ in
print("Shortcut finished execution. Proceeding with file transfer.")
DispatchQueue.global().async {
self.processFile(at: fileURL, for: app.bundleIdentifier)
}
// }
}
} else {
DispatchQueue.global().async {
self.processFile(at: fileURL, for: app.bundleIdentifier)
}
}
}

View File

@@ -0,0 +1 @@
../../build/AltBackup.ipa

View File

@@ -22,7 +22,7 @@
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="separatorColor" white="1" alpha="0.25" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<stackView key="tableFooterView" opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalCentering" alignment="center" spacing="15" id="48g-cT-stR">
<rect key="frame" x="0.0" y="2442.6666641235352" width="402" height="125"/>
<rect key="frame" x="0.0" y="2469.3333282470703" width="402" height="125"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="900" text="Follow SideStore for updates" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XFa-MY-7cV">
@@ -494,7 +494,7 @@
<tableViewSection id="1fc-f1-ALD">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="7Ek-Ls-QVO" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="793.66666412353516" width="402" height="51"/>
<rect key="frame" x="0.0" y="794.66666412353516" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="7Ek-Ls-QVO" id="KjD-M3-oNg">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -531,13 +531,13 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="hFh-X1-ZAi" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="844.66666412353516" width="402" height="51"/>
<rect key="frame" x="0.0" y="845.66666412353516" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hFh-X1-ZAi" id="nCs-Ro-A6t">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Clear Cache…" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j4e-Mz-DlL">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Clear Cache…" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j4e-Mz-DlL">
<rect key="frame" x="29.999999999999993" y="15.333333333333334" width="114.33333333333331" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -563,28 +563,28 @@
<tableViewSection headerTitle="" id="J90-vn-u2O">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="i4T-2q-jF3" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="931.33333015441895" width="402" height="51"/>
<rect key="frame" x="0.0" y="932.33333015441895" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="i4T-2q-jF3" id="VTQ-H4-aCM">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Developers" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hRA-OK-Vjw">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Developers" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hRA-OK-Vjw">
<rect key="frame" x="30" y="15.333333333333334" width="86" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="lx9-35-OSk">
<rect key="frame" x="217" y="15.333333333333336" width="155" height="20.333333333333329"/>
<stackView opaque="NO" contentMode="scaleToFill" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="lx9-35-OSk">
<rect key="frame" x="217" y="15.333333333333334" width="155" height="20.333333333333329"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="SideStore Team" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JAA-iZ-VGb">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SideStore Team" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JAA-iZ-VGb">
<rect key="frame" x="0.0" y="0.0" width="125.33333333333333" height="20.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Mmj-3V-fTb">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Mmj-3V-fTb">
<rect key="frame" x="139.33333333333331" y="-1" width="15.666666666666657" height="22.333333333333332"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView>
@@ -608,29 +608,29 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="oHX-oR-nwJ" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="982.33333015441895" width="402" height="51"/>
<rect key="frame" x="0.0" y="983.33333015441895" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="oHX-oR-nwJ" id="hN4-i5-igu">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="UI Designer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oqY-wY-1Vf">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="UI Designer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oqY-wY-1Vf">
<rect key="frame" x="30" y="15.333333333333334" width="89" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="gUq-6Q-t5X">
<rect key="frame" x="227.33333333333337" y="15.333333333333336" width="144.66666666666663" height="20.333333333333329"/>
<stackView opaque="NO" contentMode="scaleToFill" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="gUq-6Q-t5X">
<rect key="frame" x="227.33333333333337" y="15.333333333333334" width="144.66666666666663" height="20.333333333333329"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Fabian (thdev)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ylE-VL-7Fq">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Fabian (thdev)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ylE-VL-7Fq">
<rect key="frame" x="0.0" y="0.0" width="115" height="20.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="e3L-vR-Jae">
<rect key="frame" x="129" y="-1" width="15.666666666666657" height="22.333333333333332"/>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="e3L-vR-Jae">
<rect key="frame" x="128.99999999999997" y="-1" width="15.666666666666657" height="22.333333333333332"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView>
</subviews>
@@ -653,29 +653,29 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="0MT-ht-Sit" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1033.3333301544189" width="402" height="51"/>
<rect key="frame" x="0.0" y="1034.3333301544189" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="0MT-ht-Sit" id="OZp-WM-5H7">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Asset Designer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fGU-Fp-XgM">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Asset Designer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fGU-Fp-XgM">
<rect key="frame" x="29.999999999999993" y="15.333333333333334" width="115.33333333333331" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="R8B-DW-7mY">
<rect key="frame" x="235.33333333333337" y="15.333333333333336" width="136.66666666666663" height="20.333333333333329"/>
<stackView opaque="NO" contentMode="scaleToFill" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="R8B-DW-7mY">
<rect key="frame" x="235.33333333333337" y="15.333333333333334" width="136.66666666666663" height="20.333333333333329"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Chris (LitRitt)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hId-3P-41T">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Chris (LitRitt)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hId-3P-41T">
<rect key="frame" x="0.0" y="0.0" width="107" height="20.333333333333332"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="baq-cE-fMY">
<rect key="frame" x="120.99999999999997" y="-1" width="15.666666666666657" height="22.333333333333332"/>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="baq-cE-fMY">
<rect key="frame" x="120.99999999999999" y="-1" width="15.666666666666671" height="22.333333333333332"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView>
</subviews>
@@ -698,19 +698,19 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="O5R-Al-lGj" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1084.3333301544189" width="402" height="51"/>
<rect key="frame" x="0.0" y="1085.3333301544189" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="O5R-Al-lGj" id="CrG-Mr-xQq">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Licenses" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D6b-cd-pVK">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Licenses" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D6b-cd-pVK">
<rect key="frame" x="30" y="15.333333333333334" width="67.333333333333329" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="s79-GQ-khr">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="s79-GQ-khr">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView>
@@ -739,19 +739,19 @@
<tableViewSection headerTitle="" id="swj-Wc-IR6">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="xGq-wV-SCd" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1170.9999961853027" width="402" height="51"/>
<rect key="frame" x="0.0" y="1171.9999961853027" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xGq-wV-SCd" id="G7G-sK-oO3">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Enable Beta Updates" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1B5-BJ-Rkb">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable Beta Updates" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1B5-BJ-Rkb">
<rect key="frame" x="30" y="15.333333333333334" width="169" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Blb-Dp-9QF">
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Blb-Dp-9QF">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/>
<connections>
<action selector="toggleEnableBetaUpdates:" destination="aMk-Xp-UL8" eventType="valueChanged" id="9Ea-BQ-DAE"/>
@@ -774,19 +774,19 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="eHa-Cd-p4h" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1221.9999961853027" width="402" height="51"/>
<rect key="frame" x="0.0" y="1222.9999961853027" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="eHa-Cd-p4h" id="V9s-7b-vkR">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Beta Updates Track" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nSh-L8-ca0" userLabel="Beta Track Label">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Beta Updates Track" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nSh-L8-ca0" userLabel="Beta Track Label">
<rect key="frame" x="30" y="15.333333333333334" width="159.66666666666666" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" ambiguous="YES" showsMenuAsPrimaryAction="YES" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" changesSelectionAsPrimaryAction="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kYQ-zz-vjQ" userLabel="Beta Track Drop Down Button">
<button opaque="NO" contentMode="scaleToFill" showsMenuAsPrimaryAction="YES" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" changesSelectionAsPrimaryAction="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kYQ-zz-vjQ" userLabel="Beta Track Drop Down Button">
<rect key="frame" x="301.66666666666669" y="8.3333333333333321" width="70.333333333333314" height="34.333333333333343"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="50" id="n1r-LA-2uh"/>
@@ -815,19 +815,19 @@
<tableViewSection headerTitle="" id="OMa-EK-hRI">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="FMZ-as-Ljo" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1308.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1309.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="FMZ-as-Ljo" id="JzL-Of-A3T">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Send Feedback" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pMI-Aj-nQF">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Send Feedback" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pMI-Aj-nQF">
<rect key="frame" x="29.999999999999993" y="15.333333333333334" width="125.33333333333331" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Jyy-x0-Owj">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Jyy-x0-Owj">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView>
@@ -849,19 +849,19 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="Qca-pU-sJh" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1359.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1360.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Qca-pU-sJh" id="QtU-8J-VQN">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="View Refresh Attempts" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sni-07-q0M">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="View Refresh Attempts" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sni-07-q0M">
<rect key="frame" x="30" y="15.333333333333334" width="187.66666666666666" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4d3-me-Hqc">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="4d3-me-Hqc">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView>
@@ -886,19 +886,19 @@
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="VrV-qI-zXF" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1410.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1411.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VrV-qI-zXF" id="w1r-uY-4pD">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="SideJITServer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="46q-DB-5nc">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SideJITServer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="46q-DB-5nc">
<rect key="frame" x="29.999999999999993" y="15.333333333333334" width="115.33333333333331" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wvD-eZ-nQI">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="wvD-eZ-nQI">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView>
@@ -920,19 +920,19 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="VNn-u4-cN8" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1461.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1462.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VNn-u4-cN8" id="4bh-qe-l2N">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Reset Pairing File" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ysS-9s-dXm">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Reset Pairing File" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ysS-9s-dXm">
<rect key="frame" x="30" y="15.333333333333334" width="140" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="r09-mH-pOD">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="r09-mH-pOD">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView>
@@ -954,19 +954,19 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="e7s-hL-kv9" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1512.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1513.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="e7s-hL-kv9" id="yjL-Mu-HTk">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Anisette Servers" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eds-Dj-36y">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Anisette Servers" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eds-Dj-36y">
<rect key="frame" x="30" y="15.333333333333334" width="135.66666666666666" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0dh-yd-7i9">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="0dh-yd-7i9">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView>
@@ -987,20 +987,54 @@
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="LEH-wv-o2q" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1564.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="LEH-wv-o2q" id="AP9-UO-vZk">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="VPN Configuration" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iie-Nj-lki" userLabel="VPN Configuration">
<rect key="frame" x="30" y="15.333333333333334" width="151.66666666666666" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="639-RC-1ii">
<rect key="frame" x="356.33333333333331" y="14.333333333333334" width="15.666666666666686" height="22.333333333333329"/>
<imageReference key="image" image="chevron.right" catalog="system" symbolScale="large"/>
</imageView>
</subviews>
<constraints>
<constraint firstItem="iie-Nj-lki" firstAttribute="centerY" secondItem="AP9-UO-vZk" secondAttribute="centerY" id="Mxs-Yx-TRW"/>
<constraint firstItem="iie-Nj-lki" firstAttribute="leading" secondItem="AP9-UO-vZk" secondAttribute="leadingMargin" id="f7R-Ql-UHL"/>
<constraint firstItem="639-RC-1ii" firstAttribute="centerY" secondItem="AP9-UO-vZk" secondAttribute="centerY" id="tew-j2-B3V"/>
<constraint firstAttribute="trailingMargin" secondItem="639-RC-1ii" secondAttribute="trailing" id="ygE-k7-OKf"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="7rt-MT-kFH" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1563.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1615.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="7rt-MT-kFH" id="mZL-UA-6V0">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Enable EMP for wireguard" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZH7-ZA-Epf" userLabel="Enable EMP for wireguard">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable EMP for wireguard" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZH7-ZA-Epf" userLabel="Enable EMP for wireguard">
<rect key="frame" x="30" y="15.333333333333334" width="209" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8qE-hE-Ujn">
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8qE-hE-Ujn">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/>
<connections>
<action selector="toggleEnableEMPforWireguard:" destination="aMk-Xp-UL8" eventType="valueChanged" id="B0Q-Jb-fox"/>
@@ -1023,19 +1057,19 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="q6e-PG-mTq" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1614.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1666.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="q6e-PG-mTq" id="PRJ-Ed-P86">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Enable AppId Customization" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fq4-2u-Lgd" userLabel="Enable AppId Customization">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable AppId Customization" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fq4-2u-Lgd" userLabel="Enable AppId Customization">
<rect key="frame" x="30" y="15.333333333333334" width="230" height="20.333333333333329"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="fXx-wl-F5H">
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="fXx-wl-F5H">
<rect key="frame" x="311" y="11.666666666666664" width="63" height="28"/>
<connections>
<action selector="toggleEnableAppIdCustomization:" destination="aMk-Xp-UL8" eventType="valueChanged" id="gtP-5M-9Ms"/>
@@ -1062,7 +1096,7 @@
<tableViewSection id="ZhW-yK-wdJ">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="qjD-UK-myl" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1701.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1752.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qjD-UK-myl" id="bcu-KT-Xee">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1090,7 +1124,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="dNh-fp-vBs" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1752.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1803.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="dNh-fp-vBs" id="Meb-tV-6br">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1118,7 +1152,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="Y6h-Bo-yec" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1803.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1854.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Y6h-Bo-yec" id="4Jf-I6-v7z">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1146,7 +1180,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="dLk-d6-X4T" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1854.6666622161865" width="402" height="51"/>
<rect key="frame" x="0.0" y="1905.6666622161865" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="dLk-d6-X4T" id="Okl-3m-rde">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1178,7 +1212,7 @@
<tableViewSection headerTitle="" id="lLQ-K0-XSb">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="daQ-mk-yqC" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1941.3333282470703" width="402" height="51"/>
<rect key="frame" x="0.0" y="1992.3333282470703" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="daQ-mk-yqC" id="ZkW-ZR-twy">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1213,7 +1247,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="hRP-jU-2hd" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="1992.3333282470703" width="402" height="51"/>
<rect key="frame" x="0.0" y="2043.3333282470703" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hRP-jU-2hd" id="JhE-O4-pRg">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1248,7 +1282,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="JoN-Aj-XtZ" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2043.3333282470703" width="402" height="51"/>
<rect key="frame" x="0.0" y="2094.3333282470703" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="JoN-Aj-XtZ" id="v8Q-VQ-Q1h">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1283,7 +1317,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="QOO-bO-4M5" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2094.3333282470703" width="402" height="51"/>
<rect key="frame" x="0.0" y="2145.3333282470703" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QOO-bO-4M5" id="VTT-z5-C89">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1311,7 +1345,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="ToB-H7-2lR" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2145.3333282470703" width="402" height="51"/>
<rect key="frame" x="0.0" y="2196.3333282470703" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ToB-H7-2lR" id="Acf-xV-Isn">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1339,7 +1373,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="xtI-eU-LFb" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2196.3333282470703" width="402" height="51"/>
<rect key="frame" x="0.0" y="2247.3333282470703" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xtI-eU-LFb" id="bc9-41-6mE">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1373,7 +1407,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="pvu-IV-Poa" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2247.3333282470703" width="402" height="51"/>
<rect key="frame" x="0.0" y="2298.3333282470703" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="pvu-IV-Poa" id="zck-an-8cK">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1408,7 +1442,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="9By-QW-Jw9" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2298.3333282470703" width="402" height="51"/>
<rect key="frame" x="0.0" y="2349.3333282470703" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="9By-QW-Jw9" id="Dzq-gE-zyT">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
@@ -1443,7 +1477,7 @@
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="LzP-Qb-bmC" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="2349.3333282470703" width="402" height="51"/>
<rect key="frame" x="0.0" y="2400.3333282470703" width="402" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="LzP-Qb-bmC" id="3rE-h0-8kb">
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>

View File

@@ -77,6 +77,7 @@ extension SettingsViewController
case refreshSideJITServer
case resetPairingFile
case anisetteServers
case vpnConfiguration
case enableEMPForWiregaurd
case customizeAppId
}
@@ -1364,9 +1365,19 @@ extension SettingsViewController
handleRefreshResult(result)
})
let anisetteServersController = UIHostingController(rootView: anisetteServersView)
let vc = UIHostingController(rootView: anisetteServersView)
self.prepare(for: UIStoryboardSegue(identifier: "anisetteServers", source: self, destination: vc), sender: nil)
self.prepare(for: UIStoryboardSegue(identifier: "anisetteServers", source: self, destination: anisetteServersController), sender: nil)
case .vpnConfiguration:
let vpnConfigurationView = VPNConfigurationView()
let vc = UIHostingController(rootView: vpnConfigurationView)
let appearance = UINavigationBarAppearance()
appearance.configureWithDefaultBackground() // gives solid background
vc.navigationItem.scrollEdgeAppearance = appearance
vc.navigationItem.standardAppearance = appearance
navigationController?.pushViewController(vc, animated: true)
case .refreshAttempts, .enableEMPForWiregaurd, .customizeAppId: break
}
case .signing:

View File

@@ -0,0 +1,119 @@
//
// VPNConfiguration.swift
// AltStore
//
// Created by Magesh K on 02/03/26.
// Copyright © 2026 SideStore. All rights reserved.
//
import SwiftUI
import Combine
private typealias SButton = SwiftUI.Button
struct VPNConfigurationView: View {
@Environment(\.presentationMode) var presentationMode
@StateObject private var config = TunnelConfig.shared
var body: some View {
List {
Section(header: Text("Discovered from network")) {
Group {
networkConfigRow(label: "Tunnel IP", text: $config.deviceIP, editable: false)
networkConfigRow(label: "Device IP", text: $config.fakeIP, editable: false)
networkConfigRow(label: "Subnet Mask", text: $config.subnetMask, editable: false)
}
}
Section {
networkConfigRow(
label: "Device IP",
text: Binding<String?>(get: { config.overrideFakeIP }, set: { config.overrideFakeIP = $0 ?? "" }),
editable: true
)
networkConfigRow(
label: "Active",
text: Binding<String?>(get: { config.overrideActive }, set: { _ in }),
editable: false
)
} header: {
Text("User Configuration")
} footer: {
HStack(alignment: .top, spacing: 0) {
Text("Note: ")
Text("'Device IP' is mandatory and should match exactly as in the VPN's configuration")
}
}
}
.navigationTitle("VPN Configuration")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
SButton("Confirm") {
commitChanges()
}
}
}
}
private func commitChanges() {
bindTunnelConfig()
}
private func dismiss() {
presentationMode.wrappedValue.dismiss()
}
private func networkConfigRow(
label: LocalizedStringKey,
text: Binding<String?>,
editable: Bool
) -> some View {
let proxy = Binding<String>(
get: { text.wrappedValue ?? "N/A" },
set: { text.wrappedValue = $0.isEmpty || $0 == "N/A" ? nil : $0 }
)
return HStack {
Text(label)
.foregroundColor(editable ? .primary : .gray)
Spacer()
TextField(label, text: proxy)
.multilineTextAlignment(.trailing)
.foregroundColor(editable ? .secondary : .gray)
.disabled(!editable)
.keyboardType(.numbersAndPunctuation)
.onChange(of: proxy.wrappedValue) { newValue in
guard editable else { return }
proxy.wrappedValue =
newValue.filter { "0123456789.".contains($0) }
}
}
}
}
final class TunnelConfig: ObservableObject {
static let shared = TunnelConfig()
private static let defaultOverrideIP: String = {
if #available(iOS 26.4, *) { return "192.168.1.50" }
return "10.7.0.1"
}()
@Published var deviceIP: String?
@Published var subnetMask: String?
@Published var fakeIP: String?
@Published var overrideFakeIP: String = overrideIPStorage {
didSet { Self.overrideIPStorage = overrideFakeIP }
}
@Published var overrideEffective: Bool = false
private static var overrideIPStorage: String {
get { UserDefaults.standard.string(forKey: "TunnelOverrideFakeIP") ?? defaultOverrideIP }
set { UserDefaults.standard.set(newValue, forKey: "TunnelOverrideFakeIP") }
}
var overrideActive: String { overrideEffective ? "Yes" : "No" }
}

View File

@@ -61,35 +61,6 @@ final class TabBarController: UITabBarController
self.initialSegue = nil
self.performSegue(withIdentifier: identifier, sender: sender)
}
else if let patchedApps = UserDefaults.standard.patchedApps, !patchedApps.isEmpty
{
// Check if we need to finish installing untethered jailbreak.
let activeApps = InstalledApp.fetchActiveApps(in: DatabaseManager.shared.viewContext)
guard let patchedApp = activeApps.first(where: { patchedApps.contains($0.bundleIdentifier) }) else { return }
self.performSegue(withIdentifier: "finishJailbreak", sender: patchedApp)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
guard let identifier = segue.identifier else { return }
switch identifier
{
case "finishJailbreak":
guard let installedApp = sender as? InstalledApp else { return }
let navigationController = segue.destination as! UINavigationController
let patchViewController = navigationController.viewControllers.first as! PatchViewController
patchViewController.installedApp = installedApp
patchViewController.completionHandler = { [weak self] _ in
self?.dismiss(animated: true, completion: nil)
}
default: break
}
}
override func performSegue(withIdentifier identifier: String, sender: Any?)

Binary file not shown.

View File

@@ -374,8 +374,7 @@ ipa-altbackup: checkPaths copy-altbackup
@echo " Copying from $(ALT_APP_SRC) into $(ALT_APP_PAYLOAD_DST)"
@cp -R -f "$(ALT_APP_SRC)/." "$(ALT_APP_PAYLOAD_DST)/$(TARGET_NAME)"
@pushd "$(ALT_APP_DST_ARCHIVE)" && zip -r "../../$(ALT_APP_IPA_DST)" Payload || popd
@cp -f "$(ALT_APP_IPA_DST)" AltStore/Resources
@echo " IPA created: AltStore/Resources/AltBackup.ipa"
@echo " IPA created: build/AltBackup.ipa"
clean-altbackup:
@echo ""

View File

@@ -8,6 +8,30 @@
import Foundation
import Minimuxer
func bindTunnelConfig() {
defer { print("[SideStore] bindTunnelConfig() completed") }
#if targetEnvironment(simulator)
print("[SideStore] bindTunnelConfig() is no-op on simulator")
#else
print("[SideStore] bindTunnelConfig() invoked")
Task { @MainActor in
let config = TunnelConfig.shared
Minimuxer.bindTunnelConfig(
TunnelConfigBinding(
setDeviceIP: { value in Task { @MainActor in config.deviceIP = value } },
setFakeIP: { value in Task { @MainActor in config.fakeIP = value } },
setSubnetMask: { value in Task { @MainActor in config.subnetMask = value } },
getOverrideFakeIP: { config.overrideFakeIP },
setOverrideEffective: { value in Task { @MainActor in config.overrideEffective = value } }
)
)
}
#endif
}
var isMinimuxerReady: Bool {
var result = true
#if targetEnvironment(simulator)
@@ -20,13 +44,13 @@ var isMinimuxerReady: Bool {
}
func targetMinimuxerAddress() {
defer { print("[SideStore] targetMinimuxerAddress() completed") }
func retargetUsbmuxdAddr() {
defer { print("[SideStore] retargetUsbmuxdAddr() completed") }
#if targetEnvironment(simulator)
print("[SideStore] targetMinimuxerAddress() is no-op on simulator")
print("[SideStore] retargetUsbmuxdAddr() is no-op on simulator")
#else
print("[SideStore] targetMinimuxerAddress() invoked")
Minimuxer.updateUsbMuxdAddr()
print("[SideStore] retargetUsbmuxdAddr() invoked")
Minimuxer.retargetUsbmuxdAddr()
#endif
}
@@ -35,6 +59,8 @@ func minimuxerStartWithLogger(_ pairingFile: String, _ logPath: String, _ loggin
#if targetEnvironment(simulator)
print("[SideStore] minimuxerStartWithLogger(pairingFile, logPath, loggingEnabled) is no-op on simulator")
#else
// refresh config if any
bindTunnelConfig()
// observe network route changes (and update device endpoint from vpn(utun))
NetworkObserver.shared.start()

View File

@@ -75,6 +75,10 @@
{
"identifier": "thatstel.la.altsource",
"sourceURL": "https://alt.thatstel.la/"
},
{
"identifier": "com.deliacheminot.mona",
"sourceURL": "https://raw.githubusercontent.com/delia-cheminot/mona-hrt/refs/heads/main/ios_source.json"
}
],
"sources": [
@@ -148,6 +152,10 @@
{
"identifier": "thatstel.la.altsource",
"sourceURL": "https://alt.thatstel.la/"
},
{
"identifier": "com.deliacheminot.mona",
"sourceURL": "https://raw.githubusercontent.com/delia-cheminot/mona-hrt/refs/heads/main/ios_source.json"
}
]
}