// // EnableJITOperation.swift // EnableJITOperation // // Created by Riley Testut on 9/1/21. // Copyright © 2021 Riley Testut. All rights reserved. // import UIKit import Combine import minimuxer import UniformTypeIdentifiers import AltStoreCore enum SideJITServerErrorType: Error { case invalidURL case errorConnecting case deviceNotFound case other(String) } @available(iOS 14, *) protocol EnableJITContext { var installedApp: InstalledApp? { get } var error: Error? { get } } @available(iOS 14, *) final class EnableJITOperation: ResultOperation { let context: Context private var cancellable: AnyCancellable? init(context: Context) { self.context = context } override func main() { super.main() if let error = self.context.error { self.finish(.failure(error)) return } guard let installedApp = self.context.installedApp else { return self.finish(.failure(OperationError.invalidParameters("EnableJITOperation.main: self.context.installedApp is nil"))) } if #available(iOS 17, *) { let sideJITenabled = UserDefaults.standard.sidejitenable let SideJITIP = UserDefaults.standard.textInputSideJITServerurl ?? "" if sideJITenabled { installedApp.managedObjectContext?.perform { EnableJITSideJITServer(serverurl: SideJITIP, installedapp: installedApp) { result in switch result { case .failure(let error): switch error { case .invalidURL, .errorConnecting: self.finish(.failure(OperationError.unableToConnectSideJIT)) case .deviceNotFound: self.finish(.failure(OperationError.unableToRespondSideJITDevice)) case .other(let message): if let startRange = message.range(of: "

"), let endRange = message.range(of: "

", range: startRange.upperBound.. 0){ do { try debug_app(installedApp.resignedBundleIdentifier) self.finish(.success(())) retries = 0 } catch { retries -= 1 if (retries <= 0){ self.finish(.failure(error)) } } } } } } } @available(iOS 17, *) func EnableJITSideJITServer(serverurl: String, installedapp: InstalledApp, completion: @escaping (Result) -> Void) { guard let udid = fetch_udid()?.toString() else { completion(.failure(.other("Unable to get UDID"))) return } var SJSURL = serverurl if (UserDefaults.standard.textInputSideJITServerurl ?? "").isEmpty { SJSURL = "http://sidejitserver._http._tcp.local:8080" } if !SJSURL.hasPrefix("http") { completion(.failure(.invalidURL)) return } let fullurl = SJSURL + "/\(udid)/" + installedapp.resignedBundleIdentifier let url = URL(string: fullurl)! let task = URLSession.shared.dataTask(with: url) {(data, response, error) in if let error = error { completion(.failure(.errorConnecting)) return } guard let data = data, let datastring = String(data: data, encoding: .utf8) else { return } if datastring == "Enabled JIT for '\(installedapp.name)'!" { let content = UNMutableNotificationContent() content.title = "JIT Successfully Enabled" content.subtitle = "JIT Enabled For \(installedapp.name)" content.sound = UNNotificationSound.default let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false) let request = UNNotificationRequest(identifier: "EnabledJIT", content: content, trigger: nil) UNUserNotificationCenter.current().add(request) completion(.success(())) } else { let errorType: SideJITServerErrorType = datastring == "Could not find device!" ? .deviceNotFound : .other(datastring) completion(.failure(errorType)) } } task.resume() }