diff --git a/AltServer/AltServer-Bridging-Header.h b/AltServer/AltServer-Bridging-Header.h index db577fd9..b3ec0689 100644 --- a/AltServer/AltServer-Bridging-Header.h +++ b/AltServer/AltServer-Bridging-Header.h @@ -9,5 +9,6 @@ // Shared #import "ALTConstants.h" #import "ALTConnection.h" +#import "AltXPCProtocol.h" #import "NSError+ALTServerError.h" #import "CFNotificationName+AltStore.h" diff --git a/AltServer/AnisetteDataManager.swift b/AltServer/AnisetteDataManager.swift index f28a589d..b5c26afb 100644 --- a/AltServer/AnisetteDataManager.swift +++ b/AltServer/AnisetteDataManager.swift @@ -8,6 +8,28 @@ import Foundation +private extension Bundle +{ + struct ID + { + static let mail = "com.apple.mail" + static let altXPC = "com.rileytestut.AltXPC" + } +} + +private extension ALTAnisetteData +{ + func sanitize(byReplacingBundleID bundleID: String) + { + guard let range = self.deviceDescription.lowercased().range(of: "(" + bundleID.lowercased()) else { return } + + var adjustedDescription = self.deviceDescription[..) -> Void] = [:] private var anisetteDataTimers: [String: Timer] = [:] + private lazy var xpcConnection: NSXPCConnection = { + let connection = NSXPCConnection(serviceName: Bundle.ID.altXPC) + connection.remoteObjectInterface = NSXPCInterface(with: AltXPCProtocol.self) + connection.resume() + return connection + }() + private override init() { super.init() @@ -23,6 +52,55 @@ class AnisetteDataManager: NSObject } func requestAnisetteData(_ completion: @escaping (Result) -> Void) + { + self.requestAnisetteDataFromXPCService { (result) in + do + { + let anisetteData = try result.get() + completion(.success(anisetteData)) + } + catch CocoaError.xpcConnectionInterrupted + { + // SIP and/or AMFI are not disabled, so fall back to Mail plug-in. + self.requestAnisetteDataFromPlugin { (result) in + completion(result) + } + } + catch + { + completion(.failure(error)) + } + } + } + + func isXPCAvailable(completion: @escaping (Bool) -> Void) + { + guard let proxy = self.xpcConnection.remoteObjectProxyWithErrorHandler({ (error) in + completion(false) + }) as? AltXPCProtocol else { return } + + proxy.ping { + completion(true) + } + } +} + +private extension AnisetteDataManager +{ + func requestAnisetteDataFromXPCService(completion: @escaping (Result) -> Void) + { + guard let proxy = self.xpcConnection.remoteObjectProxyWithErrorHandler({ (error) in + print("Anisette XPC Error:", error) + completion(.failure(error)) + }) as? AltXPCProtocol else { return } + + proxy.requestAnisetteData { (anisetteData, error) in + anisetteData?.sanitize(byReplacingBundleID: Bundle.ID.altXPC) + completion(Result(anisetteData, error)) + } + } + + func requestAnisetteDataFromPlugin(completion: @escaping (Result) -> Void) { let requestUUID = UUID().uuidString self.anisetteDataCompletionHandlers[requestUUID] = completion @@ -36,10 +114,7 @@ class AnisetteDataManager: NSObject DistributedNotificationCenter.default().postNotificationName(Notification.Name("com.rileytestut.AltServer.FetchAnisetteData"), object: nil, userInfo: ["requestUUID": requestUUID], options: .deliverImmediately) } -} - -private extension AnisetteDataManager -{ + @objc func handleAnisetteDataResponse(_ notification: Notification) { guard let userInfo = notification.userInfo, let requestUUID = userInfo["requestUUID"] as? String else { return } @@ -48,14 +123,7 @@ private extension AnisetteDataManager let archivedAnisetteData = userInfo["anisetteData"] as? Data, let anisetteData = try? NSKeyedUnarchiver.unarchivedObject(ofClass: ALTAnisetteData.self, from: archivedAnisetteData) { - if let range = anisetteData.deviceDescription.lowercased().range(of: "(com.apple.mail") - { - var adjustedDescription = anisetteData.deviceDescription[..