mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-08 22:33:26 +01:00
[diagnostics]: Added switches for OperationLogging to use them for debugging/diagnostics on device
This commit is contained in:
@@ -65,6 +65,8 @@
|
||||
A859ED5D2D1EE827003DCC58 /* OpenSSL.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
A868CFE42D31999A002F1201 /* SingletonGenericMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868CFE32D319988002F1201 /* SingletonGenericMap.swift */; };
|
||||
A8696EE42D34512C00E96389 /* RemoveAppExtensionsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */; };
|
||||
A88B8C492D35AD3200F53F9D /* OperationsLoggingContolView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */; };
|
||||
A88B8C552D35F1EC00F53F9D /* OperationsLoggingControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88B8C542D35F1EC00F53F9D /* OperationsLoggingControl.swift */; };
|
||||
A8945AA62D059B6100D86CBE /* Roxas.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8945AA52D059B6100D86CBE /* Roxas.framework */; };
|
||||
A8A543302D04F14400D72399 /* libfragmentzip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A8A5432F2D04F0C100D72399 /* libfragmentzip.a */; };
|
||||
A8A853AF2D3065A300995795 /* ActiveAppsTimelineProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8A853AE2D3065A300995795 /* ActiveAppsTimelineProvider.swift */; };
|
||||
@@ -647,6 +649,8 @@
|
||||
A86202332D1F35640091187B /* AltStoreCore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStoreCore.xcconfig; sourceTree = "<group>"; };
|
||||
A868CFE32D319988002F1201 /* SingletonGenericMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingletonGenericMap.swift; sourceTree = "<group>"; };
|
||||
A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAppExtensionsOperation.swift; sourceTree = "<group>"; };
|
||||
A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationsLoggingContolView.swift; sourceTree = "<group>"; };
|
||||
A88B8C542D35F1EC00F53F9D /* OperationsLoggingControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationsLoggingControl.swift; sourceTree = "<group>"; };
|
||||
A8945AA52D059B6100D86CBE /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A8A853AE2D3065A300995795 /* ActiveAppsTimelineProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveAppsTimelineProvider.swift; sourceTree = "<group>"; };
|
||||
A8AD35582D31BF29003A28B4 /* PageInfoManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageInfoManager.swift; sourceTree = "<group>"; };
|
||||
@@ -1211,6 +1215,14 @@
|
||||
path = xcconfigs;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A88B8C532D35F1E800F53F9D /* operations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A88B8C542D35F1EC00F53F9D /* OperationsLoggingControl.swift */,
|
||||
);
|
||||
path = operations;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A8A543222D04F0C100D72399 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -1249,6 +1261,7 @@
|
||||
A8B516DE2D2666900047047C /* dignostics */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A88B8C532D35F1E800F53F9D /* operations */,
|
||||
A8B516DF2D2666A00047047C /* database */,
|
||||
);
|
||||
path = dignostics;
|
||||
@@ -1995,6 +2008,7 @@
|
||||
BFDB69FB22A9A7A6007EA6D6 /* Settings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */,
|
||||
BFE60737231ADF49002B0E8E /* Settings.storyboard */,
|
||||
BFE60739231ADF82002B0E8E /* SettingsViewController.swift */,
|
||||
0EA426392C2230150026D7FB /* AnisetteServerList.swift */,
|
||||
@@ -2018,30 +2032,30 @@
|
||||
children = (
|
||||
D513F6152A12CE210061EAA1 /* Errors */,
|
||||
BFDB6A0A22AAEDB7007EA6D6 /* Operation.swift */,
|
||||
BF770E5722BC3D0F002A40FE /* RefreshGroup.swift */,
|
||||
BF770E5322BC044E002A40FE /* OperationContexts.swift */,
|
||||
BF770E5722BC3D0F002A40FE /* RefreshGroup.swift */,
|
||||
BFE6326B22A86FF300F30809 /* AuthenticationOperation.swift */,
|
||||
D561AF812B21669400BF59C6 /* VerifyAppPledgeOperation.swift */,
|
||||
BFC1F38C22AEE3A4003AC21A /* DownloadAppOperation.swift */,
|
||||
BFDB6A0722AAED73007EA6D6 /* ResignAppOperation.swift */,
|
||||
BFCCB519245E3401001853EA /* VerifyAppOperation.swift */,
|
||||
A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */,
|
||||
BFA8172A23C5633D001B5953 /* FetchAnisetteDataOperation.swift */,
|
||||
BF3BEFBE2408673400DE7D55 /* FetchProvisioningProfilesOperation.swift */,
|
||||
BF3BEFC024086A1E00DE7D55 /* RefreshAppOperation.swift */,
|
||||
BFDB6A0722AAED73007EA6D6 /* ResignAppOperation.swift */,
|
||||
BFDB6A0E22AB2776007EA6D6 /* SendAppOperation.swift */,
|
||||
BF770E5022BB1CF6002A40FE /* InstallAppOperation.swift */,
|
||||
BFE338DE22F0EADB002E24B9 /* FetchSourceOperation.swift */,
|
||||
BFA8172A23C5633D001B5953 /* FetchAnisetteDataOperation.swift */,
|
||||
BF3BEFC024086A1E00DE7D55 /* RefreshAppOperation.swift */,
|
||||
BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */,
|
||||
BFC57A642416C72400EB891E /* DeactivateAppOperation.swift */,
|
||||
BFCCB519245E3401001853EA /* VerifyAppOperation.swift */,
|
||||
BF44EEFB246B4550002A52F2 /* RemoveAppOperation.swift */,
|
||||
BFE338DE22F0EADB002E24B9 /* FetchSourceOperation.swift */,
|
||||
D5E1E7C028077DE90016FC96 /* UpdateKnownSourcesOperation.swift */,
|
||||
BF3432FA246B894F0052F4A1 /* BackupAppOperation.swift */,
|
||||
BFDBBD7F246CB84F004ED2F3 /* RemoveAppBackupOperation.swift */,
|
||||
BF44EEFB246B4550002A52F2 /* RemoveAppOperation.swift */,
|
||||
BFC57A642416C72400EB891E /* DeactivateAppOperation.swift */,
|
||||
BFF00D312501BDA100746320 /* BackgroundRefreshAppsOperation.swift */,
|
||||
D57F2C9026E0070200B9FA39 /* EnableJITOperation.swift */,
|
||||
D5DAE0952804DF430034D8D4 /* UpdatePatronsOperation.swift */,
|
||||
D5E1E7C028077DE90016FC96 /* UpdateKnownSourcesOperation.swift */,
|
||||
D5ACE84428E3B8450021CAB9 /* ClearAppCacheOperation.swift */,
|
||||
D561AF812B21669400BF59C6 /* VerifyAppPledgeOperation.swift */,
|
||||
A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */,
|
||||
BF7B44062725A4B8005288A4 /* Patch App */,
|
||||
);
|
||||
path = Operations;
|
||||
@@ -3063,6 +3077,7 @@
|
||||
BF770E5822BC3D0F002A40FE /* RefreshGroup.swift in Sources */,
|
||||
19B9B7452845E6DF0076EF69 /* SelectTeamViewController.swift in Sources */,
|
||||
0E13E5862CC8F55900E9C0DF /* ProcessInfo+SideStore.swift in Sources */,
|
||||
A88B8C492D35AD3200F53F9D /* OperationsLoggingContolView.swift in Sources */,
|
||||
D59162AB29BA60A9005CBF47 /* SourceHeaderView.swift in Sources */,
|
||||
BF18B0F122E25DF9005C4CF5 /* ToastView.swift in Sources */,
|
||||
BF3D649F22E7B24C00E9056B /* CollapsingTextView.swift in Sources */,
|
||||
@@ -3072,6 +3087,7 @@
|
||||
BFC84A4D2421A19100853474 /* SourcesViewController.swift in Sources */,
|
||||
BFF0B696232242D3007A79E1 /* LicensesViewController.swift in Sources */,
|
||||
D57FE84428C7DB7100216002 /* ErrorLogViewController.swift in Sources */,
|
||||
A88B8C552D35F1EC00F53F9D /* OperationsLoggingControl.swift in Sources */,
|
||||
D50107EC2ADF2E1A0069F2A1 /* AddSourceTextFieldCell.swift in Sources */,
|
||||
D5151BD92A8FF64300C96F28 /* RefreshAllAppsIntent.swift in Sources */,
|
||||
BFBE0007250AD0E70080826E /* ViewAppIntentHandler.swift in Sources */,
|
||||
|
||||
@@ -14,6 +14,8 @@ import AltStoreCore
|
||||
import AltSign
|
||||
import Roxas
|
||||
|
||||
class ANISETTE_VERBOSITY: Operation {} // dummy tag iface
|
||||
|
||||
@objc(FetchAnisetteDataOperation)
|
||||
final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSocketDelegate
|
||||
{
|
||||
@@ -58,7 +60,7 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
UserDefaults.standard.menuAnisetteURL = urlString
|
||||
let url = URL(string: urlString)
|
||||
self.url = url
|
||||
print("Anisette URL: \(self.url!.absoluteString)")
|
||||
self.printOut("Anisette URL: \(self.url!.absoluteString)")
|
||||
|
||||
if let identifier = Keychain.shared.identifier,
|
||||
let adiPb = Keychain.shared.adiPb {
|
||||
@@ -107,7 +109,7 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
guard let url = URL(string: currentServerUrlString) else {
|
||||
// Invalid URL, skip to next
|
||||
let errmsg = "Skipping invalid URL: \(currentServerUrlString)"
|
||||
print(errmsg)
|
||||
self.printOut(errmsg)
|
||||
showToast(viewContext: viewContext, message: errmsg)
|
||||
tryNextServer(from: serverUrls, viewContext, currentIndex: currentIndex + 1, completion: completion)
|
||||
return
|
||||
@@ -118,7 +120,7 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
if success {
|
||||
// If the server is reachable, return the URL
|
||||
let okmsg = "Found working server: \(url.absoluteString)"
|
||||
print(okmsg)
|
||||
self.printOut(okmsg)
|
||||
if(currentIndex > 0){
|
||||
// notify user if available server is different the user-specified one
|
||||
self.showToast(viewContext: viewContext, message: okmsg)
|
||||
@@ -127,7 +129,7 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
} else {
|
||||
// If not, try the next URL
|
||||
let errmsg = "Failed to reach server: \(url.absoluteString), trying next server."
|
||||
print(errmsg)
|
||||
self.printOut(errmsg)
|
||||
self.showToast(viewContext: viewContext, message: errmsg)
|
||||
self.tryNextServer(from: serverUrls, viewContext, currentIndex: currentIndex + 1, completion: completion)
|
||||
}
|
||||
@@ -170,10 +172,10 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
if v3 {
|
||||
if json["result"] == "GetHeadersError" {
|
||||
let message = json["message"]
|
||||
print("Error getting V3 headers: \(message ?? "no message")")
|
||||
self.printOut("Error getting V3 headers: \(message ?? "no message")")
|
||||
if let message = message,
|
||||
message.contains("-45061") {
|
||||
print("Error message contains -45061 (not provisioned), resetting adi.pb and retrying")
|
||||
self.printOut("Error message contains -45061 (not provisioned), resetting adi.pb and retrying")
|
||||
Keychain.shared.adiPb = nil
|
||||
return provision()
|
||||
} else { throw OperationError.anisetteV3Error(message: message ?? "Unknown error") }
|
||||
@@ -214,16 +216,16 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
|
||||
if let response = response,
|
||||
let version = response.value(forHTTPHeaderField: "Implementation-Version") {
|
||||
print("Implementation-Version: \(version)")
|
||||
} else { print("No Implementation-Version header") }
|
||||
self.printOut("Implementation-Version: \(version)")
|
||||
} else { self.printOut("No Implementation-Version header") }
|
||||
|
||||
print("Anisette used: \(formattedJSON)")
|
||||
print("Original JSON: \(json)")
|
||||
self.printOut("Anisette used: \(formattedJSON)")
|
||||
self.printOut("Original JSON: \(json)")
|
||||
if let anisette = ALTAnisetteData(json: formattedJSON) {
|
||||
print("Anisette is valid!")
|
||||
self.printOut("Anisette is valid!")
|
||||
self.finish(.success(anisette))
|
||||
} else {
|
||||
print("Anisette is invalid!!!!")
|
||||
self.printOut("Anisette is invalid!!!!")
|
||||
if v3 {
|
||||
throw OperationError.anisetteV3Error(message: "Invalid anisette (the returned data may not have all the required fields)")
|
||||
} else {
|
||||
@@ -242,22 +244,22 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
// MARK: - V1
|
||||
|
||||
func handleV1() {
|
||||
print("Server is V1")
|
||||
self.printOut("Server is V1")
|
||||
|
||||
if UserDefaults.shared.trustedServerURL == AnisetteManager.currentURLString {
|
||||
print("Server has already been trusted, fetching anisette")
|
||||
self.printOut("Server has already been trusted, fetching anisette")
|
||||
return self.fetchAnisetteV1()
|
||||
}
|
||||
|
||||
print("Alerting user about outdated server")
|
||||
self.printOut("Alerting user about outdated server")
|
||||
let alert = UIAlertController(title: "WARNING: Outdated anisette server", message: "We've detected you are using an older anisette server. Using this server has a higher likelihood of locking your account and causing other issues. Are you sure you want to continue?", preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: "Continue", style: UIAlertAction.Style.destructive, handler: { action in
|
||||
print("Fetching anisette via V1")
|
||||
self.printOut("Fetching anisette via V1")
|
||||
UserDefaults.shared.trustedServerURL = AnisetteManager.currentURLString
|
||||
self.fetchAnisetteV1()
|
||||
}))
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: { action in
|
||||
print("Cancelled anisette operation")
|
||||
self.printOut("Cancelled anisette operation")
|
||||
self.finish(.failure(OperationError.cancelled))
|
||||
}))
|
||||
|
||||
@@ -273,14 +275,14 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
}
|
||||
|
||||
func fetchAnisetteV1() {
|
||||
print("Fetching anisette V1")
|
||||
self.printOut("Fetching anisette V1")
|
||||
URLSession.shared.dataTask(with: self.url!) { data, response, error in
|
||||
do {
|
||||
guard let data = data, error == nil else { throw OperationError.anisetteV1Error(message: "Unable to fetch data\(error != nil ? " (\(error!.localizedDescription))" : "")") }
|
||||
|
||||
try self.extractAnisetteData(data, response as? HTTPURLResponse, v3: false)
|
||||
} catch let error as NSError {
|
||||
print("Failed to load: \(error.localizedDescription)")
|
||||
self.printOut("Failed to load: \(error.localizedDescription)")
|
||||
self.finish(.failure(error))
|
||||
}
|
||||
}.resume()
|
||||
@@ -290,7 +292,7 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
|
||||
func provision() {
|
||||
fetchClientInfo {
|
||||
print("Getting provisioning URLs")
|
||||
self.printOut("Getting provisioning URLs")
|
||||
var request = self.buildAppleRequest(url: URL(string: "https://gsa.apple.com/grandslam/GsService2/lookup")!)
|
||||
request.httpMethod = "GET"
|
||||
URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
@@ -302,12 +304,12 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
let endProvisioningURL = URL(string: endProvisioningString) {
|
||||
self.startProvisioningURL = startProvisioningURL
|
||||
self.endProvisioningURL = endProvisioningURL
|
||||
print("startProvisioningURL: \(self.startProvisioningURL!.absoluteString)")
|
||||
print("endProvisioningURL: \(self.endProvisioningURL!.absoluteString)")
|
||||
print("Starting a provisioning session")
|
||||
self.printOut("startProvisioningURL: \(self.startProvisioningURL!.absoluteString)")
|
||||
self.printOut("endProvisioningURL: \(self.endProvisioningURL!.absoluteString)")
|
||||
self.printOut("Starting a provisioning session")
|
||||
self.startProvisioningSession()
|
||||
} else {
|
||||
print("Apple didn't give valid URLs! Got response: \(String(data: data ?? Data("nothing".utf8), encoding: .utf8) ?? "not utf8")")
|
||||
self.printOut("Apple didn't give valid URLs! Got response: \(String(data: data ?? Data("nothing".utf8), encoding: .utf8) ?? "not utf8")")
|
||||
self.finish(.failure(OperationError.provisioningError(result: "Apple didn't give valid URLs. Please try again later", message: nil)))
|
||||
}
|
||||
}.resume()
|
||||
@@ -329,19 +331,19 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
do {
|
||||
if let json = try JSONSerialization.jsonObject(with: string.data(using: .utf8)!, options: []) as? [String: Any] {
|
||||
guard let result = json["result"] as? String else {
|
||||
print("The server didn't give us a result")
|
||||
self.printOut("The server didn't give us a result")
|
||||
client.disconnect(closeCode: 0)
|
||||
self.finish(.failure(OperationError.provisioningError(result: "The server didn't give us a result", message: nil)))
|
||||
return
|
||||
}
|
||||
print("Received result: \(result)")
|
||||
self.printOut("Received result: \(result)")
|
||||
switch result {
|
||||
case "GiveIdentifier":
|
||||
print("Giving identifier")
|
||||
self.printOut("Giving identifier")
|
||||
client.json(["identifier": Keychain.shared.identifier!])
|
||||
|
||||
case "GiveStartProvisioningData":
|
||||
print("Getting start provisioning data")
|
||||
self.printOut("Getting start provisioning data")
|
||||
let body = [
|
||||
"Header": [String: Any](),
|
||||
"Request": [String: Any](),
|
||||
@@ -353,19 +355,19 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
if let data = data,
|
||||
let plist = try? PropertyListSerialization.propertyList(from: data, format: nil) as? Dictionary<String, Dictionary<String, Any>>,
|
||||
let spim = plist["Response"]?["spim"] as? String {
|
||||
print("Giving start provisioning data")
|
||||
self.printOut("Giving start provisioning data")
|
||||
client.json(["spim": spim])
|
||||
} else {
|
||||
print("Apple didn't give valid start provisioning data! Got response: \(String(data: data ?? Data("nothing".utf8), encoding: .utf8) ?? "not utf8")")
|
||||
self.printOut("Apple didn't give valid start provisioning data! Got response: \(String(data: data ?? Data("nothing".utf8), encoding: .utf8) ?? "not utf8")")
|
||||
client.disconnect(closeCode: 0)
|
||||
self.finish(.failure(OperationError.provisioningError(result: "Apple didn't give valid start provisioning data. Please try again later", message: nil)))
|
||||
}
|
||||
}.resume()
|
||||
|
||||
case "GiveEndProvisioningData":
|
||||
print("Getting end provisioning data")
|
||||
self.printOut("Getting end provisioning data")
|
||||
guard let cpim = json["cpim"] as? String else {
|
||||
print("The server didn't give us a cpim")
|
||||
self.printOut("The server didn't give us a cpim")
|
||||
client.disconnect(closeCode: 0)
|
||||
self.finish(.failure(OperationError.provisioningError(result: "The server didn't give us a cpim", message: nil)))
|
||||
return
|
||||
@@ -384,20 +386,20 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
let plist = try? PropertyListSerialization.propertyList(from: data, format: nil) as? Dictionary<String, Dictionary<String, Any>>,
|
||||
let ptm = plist["Response"]?["ptm"] as? String,
|
||||
let tk = plist["Response"]?["tk"] as? String {
|
||||
print("Giving end provisioning data")
|
||||
self.printOut("Giving end provisioning data")
|
||||
client.json(["ptm": ptm, "tk": tk])
|
||||
} else {
|
||||
print("Apple didn't give valid end provisioning data! Got response: \(String(data: data ?? Data("nothing".utf8), encoding: .utf8) ?? "not utf8")")
|
||||
self.printOut("Apple didn't give valid end provisioning data! Got response: \(String(data: data ?? Data("nothing".utf8), encoding: .utf8) ?? "not utf8")")
|
||||
client.disconnect(closeCode: 0)
|
||||
self.finish(.failure(OperationError.provisioningError(result: "Apple didn't give valid end provisioning data. Please try again later", message: nil)))
|
||||
}
|
||||
}.resume()
|
||||
|
||||
case "ProvisioningSuccess":
|
||||
print("Provisioning succeeded!")
|
||||
self.printOut("Provisioning succeeded!")
|
||||
client.disconnect(closeCode: 0)
|
||||
guard let adiPb = json["adi_pb"] as? String else {
|
||||
print("The server didn't give us an adi.pb file")
|
||||
self.printOut("The server didn't give us an adi.pb file")
|
||||
self.finish(.failure(OperationError.provisioningError(result: "The server didn't give us an adi.pb file", message: nil)))
|
||||
return
|
||||
}
|
||||
@@ -406,27 +408,27 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
|
||||
default:
|
||||
if result.contains("Error") || result.contains("Invalid") || result == "ClosingPerRequest" || result == "Timeout" || result == "TextOnly" {
|
||||
print("Failing because of \(result)")
|
||||
self.printOut("Failing because of \(result)")
|
||||
self.finish(.failure(OperationError.provisioningError(result: result, message: json["message"] as? String)))
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch let error as NSError {
|
||||
print("Failed to handle text: \(error.localizedDescription)")
|
||||
self.printOut("Failed to handle text: \(error.localizedDescription)")
|
||||
self.finish(.failure(OperationError.provisioningError(result: error.localizedDescription, message: nil)))
|
||||
}
|
||||
|
||||
case .connected:
|
||||
print("Connected")
|
||||
self.printOut("Connected")
|
||||
|
||||
case .disconnected(let string, let code):
|
||||
print("Disconnected: \(code); \(string)")
|
||||
self.printOut("Disconnected: \(code); \(string)")
|
||||
|
||||
case .error(let error):
|
||||
print("Got error: \(String(describing: error))")
|
||||
self.printOut("Got error: \(String(describing: error))")
|
||||
|
||||
default:
|
||||
print("Unknown event: \(event)")
|
||||
self.printOut("Unknown event: \(event)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,10 +462,10 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
self.mdLu != nil &&
|
||||
self.deviceId != nil &&
|
||||
Keychain.shared.identifier != nil {
|
||||
print("Skipping client_info fetch since all the properties we need aren't nil")
|
||||
self.printOut("Skipping client_info fetch since all the properties we need aren't nil")
|
||||
return callback()
|
||||
}
|
||||
print("Trying to get client_info")
|
||||
self.printOut("Trying to get client_info")
|
||||
let clientInfoURL = self.url!.appendingPathComponent("v3").appendingPathComponent("client_info")
|
||||
URLSession.shared.dataTask(with: clientInfoURL) { data, response, error in
|
||||
do {
|
||||
@@ -473,20 +475,20 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
|
||||
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: String] {
|
||||
if let clientInfo = json["client_info"] {
|
||||
print("Server is V3")
|
||||
self.printOut("Server is V3")
|
||||
|
||||
self.clientInfo = clientInfo
|
||||
self.userAgent = json["user_agent"]!
|
||||
print("Client-Info: \(self.clientInfo!)")
|
||||
print("User-Agent: \(self.userAgent!)")
|
||||
self.printOut("Client-Info: \(self.clientInfo!)")
|
||||
self.printOut("User-Agent: \(self.userAgent!)")
|
||||
|
||||
if Keychain.shared.identifier == nil {
|
||||
print("Generating identifier")
|
||||
self.printOut("Generating identifier")
|
||||
var bytes = [Int8](repeating: 0, count: 16)
|
||||
let status = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
|
||||
|
||||
if status != errSecSuccess {
|
||||
print("ERROR GENERATING IDENTIFIER!!! \(status)")
|
||||
self.printOut("ERROR GENERATING IDENTIFIER!!! \(status)")
|
||||
return self.finish(.failure(OperationError.provisioningError(result: "Couldn't generate identifier", message: nil)))
|
||||
}
|
||||
|
||||
@@ -495,16 +497,16 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
|
||||
let decoded = Data(base64Encoded: Keychain.shared.identifier!)!
|
||||
self.mdLu = decoded.sha256().hexEncodedString()
|
||||
print("X-Apple-I-MD-LU: \(self.mdLu!)")
|
||||
self.printOut("X-Apple-I-MD-LU: \(self.mdLu!)")
|
||||
let uuid: UUID = decoded.object()
|
||||
self.deviceId = uuid.uuidString.uppercased()
|
||||
print("X-Mme-Device-Id: \(self.deviceId!)")
|
||||
self.printOut("X-Mme-Device-Id: \(self.deviceId!)")
|
||||
|
||||
callback()
|
||||
} else { self.handleV1() }
|
||||
} else { self.finish(.failure(OperationError.anisetteV3Error(message: "Couldn't fetch client info. The returned data may not be in JSON"))) }
|
||||
} catch let error as NSError {
|
||||
print("Failed to load: \(error.localizedDescription)")
|
||||
self.printOut("Failed to load: \(error.localizedDescription)")
|
||||
self.handleV1()
|
||||
}
|
||||
}.resume()
|
||||
@@ -512,7 +514,7 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
|
||||
func fetchAnisetteV3(_ identifier: String, _ adiPb: String) {
|
||||
fetchClientInfo {
|
||||
print("Fetching anisette V3")
|
||||
self.printOut("Fetching anisette V3")
|
||||
let url = UserDefaults.standard.menuAnisetteURL
|
||||
var request = URLRequest(url: self.url!.appendingPathComponent("v3").appendingPathComponent("get_headers"))
|
||||
request.httpMethod = "POST"
|
||||
@@ -527,12 +529,21 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>, WebSoc
|
||||
|
||||
try self.extractAnisetteData(data, response as? HTTPURLResponse, v3: true)
|
||||
} catch let error as NSError {
|
||||
print("Failed to load: \(error.localizedDescription)")
|
||||
self.printOut("Failed to load: \(error.localizedDescription)")
|
||||
self.finish(.failure(error))
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func printOut(_ text: String?){
|
||||
let isInternalLoggingEnabled = OperationsLoggingControl.getFromDatabase(for: ANISETTE_VERBOSITY.self)
|
||||
if(isInternalLoggingEnabled){
|
||||
// logging enabled, so log it
|
||||
text.map{ _ in print(text!) } ?? print()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension WebSocketClient {
|
||||
|
||||
@@ -39,7 +39,8 @@ class ResultOperation<ResultType>: Operation
|
||||
}
|
||||
|
||||
// Diagnostics: perform verbose logging of the operations only if enabled (so as to not flood console logs)
|
||||
if UserDefaults.standard.isVerboseOperationsLoggingEnabled {
|
||||
let isLoggingEnabledForThisOperation = OperationsLoggingControl.getFromDatabase(for: type(of: self))
|
||||
if UserDefaults.standard.isVerboseOperationsLoggingEnabled && isLoggingEnabledForThisOperation {
|
||||
// diagnostics logging
|
||||
let resultStatus = String(describing: result).prefix("success".count).uppercased()
|
||||
print("\n ====> OPERATION: `\(type(of: self))` completed with: \(resultStatus) <====\n\n" +
|
||||
|
||||
277
AltStore/Settings/OperationsLoggingContolView.swift
Normal file
277
AltStore/Settings/OperationsLoggingContolView.swift
Normal file
@@ -0,0 +1,277 @@
|
||||
//
|
||||
// SettingsView.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Magesh K on 14/01/25.
|
||||
// Copyright © 2025 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
import SwiftUI
|
||||
import AltStoreCore
|
||||
|
||||
|
||||
private final class DummyConformance: EnableJITContext
|
||||
{
|
||||
private init(){} // non instantiatable
|
||||
var installedApp: AltStoreCore.InstalledApp?
|
||||
var error: (any Error)?
|
||||
}
|
||||
|
||||
|
||||
struct OperationsLoggingControlView: View {
|
||||
let TITLE = "Operations Logging"
|
||||
let BACKGROUND_COLOR = Color(.settingsBackground)
|
||||
|
||||
var viewModel = OperationsLoggingControl()
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
ZStack {
|
||||
// BACKGROUND_COLOR.ignoresSafeArea() // Force background to cover the entire screen
|
||||
VStack{
|
||||
Group{}.padding(12)
|
||||
|
||||
CustomList {
|
||||
CustomSection(header: Text("Install Operations"))
|
||||
{
|
||||
CustomToggle("1. Authentication", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: AuthenticationOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: AuthenticationOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("2. VerifyAppPledge", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: VerifyAppPledgeOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: VerifyAppPledgeOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("3. DownloadApp", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: DownloadAppOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: DownloadAppOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("4. VerifyApp", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: VerifyAppOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: VerifyAppOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("5. RemoveAppExtensions", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: RemoveAppExtensionsOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: RemoveAppExtensionsOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("6. FetchAnisetteData", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: FetchAnisetteDataOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: FetchAnisetteDataOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("7. FetchProvisioningProfiles", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: FetchProvisioningProfilesOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: FetchProvisioningProfilesOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("8. ResignApp", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: ResignAppOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: ResignAppOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("9. SendApp", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: SendAppOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: SendAppOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("10. InstallApp", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: InstallAppOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: InstallAppOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
CustomSection(header: Text("Refresh Operations"))
|
||||
{
|
||||
CustomToggle("1. RefreshApp", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: RefreshAppOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: RefreshAppOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
CustomSection(header: Text("AppIDs related Operations"))
|
||||
{
|
||||
CustomToggle("1. FetchAppIDs", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: FetchAppIDsOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: FetchAppIDsOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
CustomSection(header: Text("Sources related Operations"))
|
||||
{
|
||||
CustomToggle("1. FetchSource", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: FetchSourceOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: FetchSourceOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("2. UpdateKnownSources", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: UpdateKnownSourcesOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: UpdateKnownSourcesOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
CustomSection(header: Text("Backup Operations"))
|
||||
{
|
||||
CustomToggle("1. BackupApp", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: BackupAppOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: BackupAppOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
|
||||
CustomToggle("2. RemoveAppBackup", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: RemoveAppBackupOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: RemoveAppBackupOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
CustomSection(header: Text("Activate/Deactive Operations"))
|
||||
{
|
||||
CustomToggle("1. RemoveApp", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: RemoveAppOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: RemoveAppOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
CustomToggle("2. DeactivateApp", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: DeactivateAppOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: DeactivateAppOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
CustomSection(header: Text("Background refresh Operations"))
|
||||
{
|
||||
CustomToggle("1. BackgroundRefreshApps", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: BackgroundRefreshAppsOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: BackgroundRefreshAppsOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
CustomSection(header: Text("Enable JIT Operations"))
|
||||
{
|
||||
CustomToggle("1. EnableJIT", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: EnableJITOperation<DummyConformance>.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: EnableJITOperation<DummyConformance>.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
CustomSection(header: Text("Patrons Operations"))
|
||||
{
|
||||
CustomToggle("1. UpdatePatrons", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: UpdatePatronsOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: UpdatePatronsOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
CustomSection(header: Text("Cache Operations"))
|
||||
{
|
||||
CustomToggle("1. ClearAppCache", isOn: Binding(
|
||||
get: { self.viewModel.getFromDatabase(for: ClearAppCacheOperation.self) },
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: ClearAppCacheOperation.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
CustomSection(header: Text("Misc Logging"))
|
||||
{
|
||||
CustomToggle("1. Anisette Internal Logging", isOn: Binding(
|
||||
// enable anisette internal logging by default since it was already printing before
|
||||
get: { OperationsLoggingControl.getUpdatedFromDatabase(
|
||||
for: ANISETTE_VERBOSITY.self, defaultVal: true
|
||||
)},
|
||||
set: { value in
|
||||
self.viewModel.updateDatabase(for: ANISETTE_VERBOSITY.self, value: value)
|
||||
}
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle(TITLE)
|
||||
}
|
||||
.ignoresSafeArea(edges: .all)
|
||||
}
|
||||
|
||||
private func CustomList<Content: View>(@ViewBuilder content: () -> Content) -> some View {
|
||||
// ScrollView {
|
||||
List {
|
||||
content()
|
||||
}
|
||||
// .listStyle(.plain)
|
||||
// .listStyle(InsetGroupedListStyle()) // Or PlainListStyle for iOS 15
|
||||
// .background(Color.clear)
|
||||
// .background(Color(.settingsBackground))
|
||||
// .onAppear(perform: {
|
||||
// // cache the current background color
|
||||
// UITableView.appearance().backgroundColor = UIColor.red
|
||||
// })
|
||||
// .onDisappear(perform: {
|
||||
// // reset the background color to the cached value
|
||||
// UITableView.appearance().backgroundColor = UIColor.systemBackground
|
||||
// })
|
||||
}
|
||||
|
||||
private func CustomSection<Content: View>(header: Text, @ViewBuilder content: () -> Content) -> some View {
|
||||
Section(header: header) {
|
||||
content()
|
||||
}
|
||||
// .listRowBackground(Color.clear)
|
||||
}
|
||||
|
||||
private func CustomToggle(_ title: String, isOn: Binding<Bool>) -> some View {
|
||||
Toggle(title, isOn: isOn)
|
||||
.padding(3)
|
||||
// .foregroundColor(.white) // Ensures text color is always white
|
||||
// .font(.headline)
|
||||
}
|
||||
}
|
||||
|
||||
struct SettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
OperationsLoggingControlView()
|
||||
}
|
||||
}
|
||||
@@ -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="1760.3333377838135" width="402" height="125"/>
|
||||
<rect key="frame" x="0.0" y="1818.3333377838135" 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">
|
||||
@@ -530,7 +530,7 @@
|
||||
</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="856.33333587646484" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="863.33333587646484" 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"/>
|
||||
@@ -562,7 +562,7 @@
|
||||
<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="947.66666984558105" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="954.66666984558105" 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"/>
|
||||
@@ -606,7 +606,7 @@
|
||||
</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="998.66666984558105" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1005.6666698455811" 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"/>
|
||||
@@ -650,7 +650,7 @@
|
||||
</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="1049.6666698455811" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1056.6666698455811" 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"/>
|
||||
@@ -694,7 +694,7 @@
|
||||
</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="1100.6666698455811" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1071.6666698455811" 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"/>
|
||||
@@ -734,7 +734,7 @@
|
||||
<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="1192.0000038146973" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1163.0000038146973" 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"/>
|
||||
@@ -767,7 +767,7 @@
|
||||
</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="1243.0000038146973" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1214.0000038146973" 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"/>
|
||||
@@ -803,7 +803,7 @@
|
||||
</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="1294.0000038146973" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1265.0000038146973" 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"/>
|
||||
@@ -836,7 +836,7 @@
|
||||
</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="1345.0000038146973" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1316.0000038146973" 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"/>
|
||||
@@ -869,7 +869,7 @@
|
||||
</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="1396.0000038146973" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1367.0000038146973" 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"/>
|
||||
@@ -902,7 +902,7 @@
|
||||
</userDefinedRuntimeAttributes>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="XW5-Zc-nXH" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="1447.0000038146973" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1418.0000038146973" width="402" height="51"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="XW5-Zc-nXH" id="AtM-bL-8pS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="402" height="51"/>
|
||||
@@ -942,7 +942,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="1538.3333377838135" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1509.3333377838135" 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"/>
|
||||
@@ -978,7 +978,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="1589.3333377838135" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1560.3333377838135" 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"/>
|
||||
@@ -1014,7 +1014,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="1640.3333377838135" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1611.3333377838135" 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"/>
|
||||
@@ -1050,7 +1050,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="1691.3333377838135" width="402" height="51"/>
|
||||
<rect key="frame" x="0.0" y="1662.3333377838135" 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"/>
|
||||
@@ -1075,6 +1075,39 @@
|
||||
</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="xtI-eU-LFb" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="1713.3333377838135" 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"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Operations Logging Control" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LW3-gm-lj5">
|
||||
<rect key="frame" x="30" y="15.333333333333334" width="137.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" image="Next" translatesAutoresizingMaskIntoConstraints="NO" id="zl4-ti-HTW">
|
||||
<rect key="frame" x="354" y="16.666666666666668" width="18" height="18.000000000000004"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="zl4-ti-HTW" secondAttribute="trailing" id="2MC-2C-NDd"/>
|
||||
<constraint firstItem="LW3-gm-lj5" firstAttribute="centerY" secondItem="bc9-41-6mE" secondAttribute="centerY" id="4Ft-s9-hPY"/>
|
||||
<constraint firstItem="zl4-ti-HTW" firstAttribute="centerY" secondItem="bc9-41-6mE" secondAttribute="centerY" id="8Gt-oe-nd0"/>
|
||||
<constraint firstItem="LW3-gm-lj5" firstAttribute="leading" secondItem="bc9-41-6mE" secondAttribute="leadingMargin" id="Pg6-I4-3d4"/>
|
||||
</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="3"/>
|
||||
|
||||
@@ -80,6 +80,7 @@ extension SettingsViewController
|
||||
case exportResignedApp
|
||||
case verboseOperationsLogging
|
||||
case exportSqliteDB
|
||||
case operationsLoggingControl
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1091,6 +1092,13 @@ extension SettingsViewController
|
||||
}
|
||||
}
|
||||
|
||||
case .operationsLoggingControl:
|
||||
// Instantiate SwiftUI View inside UIHostingController
|
||||
let operationsLoggingControlView = OperationsLoggingControlView()
|
||||
let operationsLoggingController = UIHostingController(rootView: operationsLoggingControlView)
|
||||
let segue = UIStoryboardSegue(identifier: "operationsLoggingControl", source: self, destination: operationsLoggingController)
|
||||
self.present(segue.destination, animated: true, completion: nil)
|
||||
|
||||
case .responseCaching, .exportResignedApp, .verboseOperationsLogging : break
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// OperationsLoggingControl.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Magesh K on 14/01/25.
|
||||
// Copyright © 2025 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class OperationsLoggingControl {
|
||||
|
||||
func updateDatabase(for operation: Operation.Type, value: Bool) {
|
||||
Self.updateDatabase(for: operation, value: value)
|
||||
}
|
||||
|
||||
private static func updateDatabase(for operation: Operation.Type, value: Bool) {
|
||||
// This method should handle the database update logic based on the operation and value
|
||||
let key = Self.getKey(operation)
|
||||
print("Updating database for key: \(key), value: \(value)")
|
||||
UserDefaults.standard.set(value, forKey: key)
|
||||
}
|
||||
|
||||
private static func stripGenericTypeName(from string: String) -> String {
|
||||
// ex: 1. "EnableJITOperation<DummyConformance>"
|
||||
// ex: 1. "EnableJITOperation<DummyConformance<SomeMoreType>>"
|
||||
// will become EnableJITOperation without the generics type info
|
||||
if let range = string.range(of: "<") {
|
||||
return String(string[..<range.lowerBound])
|
||||
}
|
||||
return string
|
||||
}
|
||||
|
||||
private static func getKey(_ operation: Operation.Type) -> String {
|
||||
let processedOperation = Self.stripGenericTypeName(from: "\(operation)")
|
||||
return "\(processedOperation)LoggingEnabled"
|
||||
}
|
||||
|
||||
func getFromDatabase(for operation: Operation.Type) -> Bool{
|
||||
return Self.getFromDatabase(for: operation)
|
||||
}
|
||||
|
||||
static func getUpdatedFromDatabase(for operation: Operation.Type, defaultVal: Bool) -> Bool{
|
||||
let key = Self.getKey(operation)
|
||||
let valueInDb = UserDefaults.standard.value(forKey: key) as? Bool
|
||||
if valueInDb == nil {
|
||||
// put the value if not already present
|
||||
updateDatabase(for: operation, value: defaultVal)
|
||||
}
|
||||
return valueInDb ?? defaultVal
|
||||
}
|
||||
|
||||
public static func getFromDatabase(for operation: Operation.Type) -> Bool {
|
||||
let key = Self.getKey(operation)
|
||||
return UserDefaults.standard.bool(forKey: key)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user