diff --git a/AltServer/DeveloperDiskManager.swift b/AltServer/DeveloperDiskManager.swift new file mode 100644 index 00000000..8f016619 --- /dev/null +++ b/AltServer/DeveloperDiskManager.swift @@ -0,0 +1,286 @@ +// +// DeveloperDiskManager.swift +// AltServer +// +// Created by Riley Testut on 2/19/21. +// Copyright © 2021 Riley Testut. All rights reserved. +// + +import Foundation + +import AltSign + +enum DeveloperDiskError: LocalizedError +{ + case unknownDownloadURL + case unsupportedOperatingSystem + case downloadedDiskNotFound + + var errorDescription: String? { + switch self + { + case .unknownDownloadURL: return NSLocalizedString("The URL to download the Developer disk image could not be determined.", comment: "") + case .unsupportedOperatingSystem: return NSLocalizedString("The device's operating system does not support installing Developer disk images.", comment: "") + case .downloadedDiskNotFound: return NSLocalizedString("DeveloperDiskImage.dmg and its signature could not be found in the downloaded archive.", comment: "") + } + } +} + +private extension URL +{ + #if STAGING + static let developerDiskDownloadURLs = URL(string: "https://f000.backblazeb2.com/file/altstore-staging/altserver/developerdisks.json")! + #else + static let developerDiskDownloadURLs = URL(string: "https://cdn.altstore.io/file/altstore/altserver/developerdisks.json")! + #endif +} + +private extension DeveloperDiskManager +{ + struct FetchURLsResponse: Decodable + { + struct Disks: Decodable + { + var iOS: [String: DeveloperDiskURL]? + var tvOS: [String: DeveloperDiskURL]? + } + + var version: Int + var disks: Disks + } + + enum DeveloperDiskURL: Decodable + { + case archive(URL) + case separate(diskURL: URL, signatureURL: URL) + + private enum CodingKeys: CodingKey + { + case archive + case disk + case signature + } + + init(from decoder: Decoder) throws + { + let container = try decoder.container(keyedBy: CodingKeys.self) + + if container.contains(.archive) + { + let archiveURL = try container.decode(URL.self, forKey: .archive) + self = .archive(archiveURL) + } + else + { + let diskURL = try container.decode(URL.self, forKey: .disk) + let signatureURL = try container.decode(URL.self, forKey: .signature) + self = .separate(diskURL: diskURL, signatureURL: signatureURL) + } + } + } +} + +class DeveloperDiskManager +{ + func downloadDeveloperDisk(for device: ALTDevice, completionHandler: @escaping (Result<(URL, URL), Error>) -> Void) + { + let osVersion = "\(device.osVersion.majorVersion).\(device.osVersion.minorVersion)" + let osKeyPath: KeyPath + + switch device.type + { + case .iphone, .ipad: osKeyPath = \FetchURLsResponse.Disks.iOS + case .appletv: osKeyPath = \FetchURLsResponse.Disks.tvOS + default: return completionHandler(.failure(DeveloperDiskError.unsupportedOperatingSystem)) + } + + do + { + let developerDiskDirectoryURL = FileManager.default.developerDisksDirectory.appendingPathComponent(osVersion) + try FileManager.default.createDirectory(at: developerDiskDirectoryURL, withIntermediateDirectories: true, attributes: nil) + + let developerDiskURL = developerDiskDirectoryURL.appendingPathComponent("DeveloperDiskImage.dmg") + let developerDiskSignatureURL = developerDiskDirectoryURL.appendingPathComponent("DeveloperDiskImage.dmg.signature") + + guard !FileManager.default.fileExists(atPath: developerDiskURL.path) || !FileManager.default.fileExists(atPath: developerDiskSignatureURL.path) else { + return completionHandler(.success((developerDiskURL, developerDiskSignatureURL))) + } + + func finish(_ result: Result<(URL, URL), Error>) + { + do + { + let (diskFileURL, signatureFileURL) = try result.get() + + let developerDiskDirectoryURL = FileManager.default.developerDisksDirectory.appendingPathComponent(osVersion) + try FileManager.default.createDirectory(at: developerDiskDirectoryURL, withIntermediateDirectories: true, attributes: nil) + + try FileManager.default.copyItem(at: diskFileURL, to: developerDiskURL) + try FileManager.default.copyItem(at: signatureFileURL, to: developerDiskSignatureURL) + + completionHandler(.success((developerDiskURL, developerDiskSignatureURL))) + } + catch + { + completionHandler(.failure(error)) + } + } + + self.fetchDeveloperDiskURLs { (result) in + do + { + let developerDiskURLs = try result.get() + guard let diskURL = developerDiskURLs[keyPath: osKeyPath]?[osVersion] else { throw DeveloperDiskError.unknownDownloadURL } + + switch diskURL + { + case .archive(let archiveURL): self.downloadDiskArchive(from: archiveURL, completionHandler: finish(_:)) + case .separate(let diskURL, let signatureURL): self.downloadDisk(from: diskURL, signatureURL: signatureURL, completionHandler: finish(_:)) + } + } + catch + { + finish(.failure(error)) + } + } + } + catch + { + completionHandler(.failure(error)) + } + } +} + +private extension DeveloperDiskManager +{ + func fetchDeveloperDiskURLs(completionHandler: @escaping (Result) -> Void) + { + let dataTask = URLSession.shared.dataTask(with: .developerDiskDownloadURLs) { (data, response, error) in + do + { + guard let data = data else { throw error! } + + let response = try JSONDecoder().decode(FetchURLsResponse.self, from: data) + completionHandler(.success(response.disks)) + } + catch + { + completionHandler(.failure(error)) + } + } + + dataTask.resume() + } + + func downloadDiskArchive(from url: URL, completionHandler: @escaping (Result<(URL, URL), Error>) -> Void) + { + let downloadTask = URLSession.shared.downloadTask(with: url) { (fileURL, response, error) in + do + { + guard let fileURL = fileURL else { throw error! } + defer { try? FileManager.default.removeItem(at: fileURL) } + + let temporaryDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil) + defer { try? FileManager.default.removeItem(at: temporaryDirectory) } + + try FileManager.default.unzipArchive(at: fileURL, toDirectory: temporaryDirectory) + + guard let enumerator = FileManager.default.enumerator(at: temporaryDirectory, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles, .skipsPackageDescendants]) else { + throw CocoaError(.fileNoSuchFile, userInfo: [NSURLErrorKey: temporaryDirectory]) + } + + var tempDiskFileURL: URL? + var tempSignatureFileURL: URL? + + for case let fileURL as URL in enumerator + { + switch fileURL.pathExtension.lowercased() + { + case "dmg": tempDiskFileURL = fileURL + case "signature": tempSignatureFileURL = fileURL + default: break + } + } + + guard let diskFileURL = tempDiskFileURL, let signatureFileURL = tempSignatureFileURL else { throw DeveloperDiskError.downloadedDiskNotFound } + + completionHandler(.success((diskFileURL, signatureFileURL))) + } + catch + { + completionHandler(.failure(error)) + } + } + + downloadTask.resume() + } + + func downloadDisk(from diskURL: URL, signatureURL: URL, completionHandler: @escaping (Result<(URL, URL), Error>) -> Void) + { + let temporaryDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + + do { try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil) } + catch { return completionHandler(.failure(error)) } + + var diskFileURL: URL? + var signatureFileURL: URL? + + var downloadError: Error? + + let dispatchGroup = DispatchGroup() + dispatchGroup.enter() + dispatchGroup.enter() + + let diskDownloadTask = URLSession.shared.downloadTask(with: diskURL) { (fileURL, response, error) in + do + { + guard let fileURL = fileURL else { throw error! } + + let destinationURL = temporaryDirectory.appendingPathComponent("DeveloperDiskImage.dmg") + try FileManager.default.copyItem(at: fileURL, to: destinationURL) + + diskFileURL = destinationURL + } + catch + { + downloadError = error + } + + dispatchGroup.leave() + } + + let signatureDownloadTask = URLSession.shared.downloadTask(with: signatureURL) { (fileURL, response, error) in + do + { + guard let fileURL = fileURL else { throw error! } + + let destinationURL = temporaryDirectory.appendingPathComponent("DeveloperDiskImage.dmg.signature") + try FileManager.default.copyItem(at: fileURL, to: destinationURL) + + signatureFileURL = destinationURL + } + catch + { + downloadError = error + } + + dispatchGroup.leave() + } + + diskDownloadTask.resume() + signatureDownloadTask.resume() + + dispatchGroup.notify(queue: .global(qos: .userInitiated)) { + defer { + try? FileManager.default.removeItem(at: temporaryDirectory) + } + + guard let diskFileURL = diskFileURL, let signatureFileURL = signatureFileURL else { + return completionHandler(.failure(downloadError ?? DeveloperDiskError.downloadedDiskNotFound)) + } + + completionHandler(.success((diskFileURL, signatureFileURL))) + } + } +} diff --git a/AltServer/Devices/ALTDeviceManager+Installation.swift b/AltServer/Devices/ALTDeviceManager+Installation.swift index 60df23eb..a51145bf 100644 --- a/AltServer/Devices/ALTDeviceManager+Installation.swift +++ b/AltServer/Devices/ALTDeviceManager+Installation.swift @@ -12,6 +12,8 @@ import ObjectiveC private let appGroupsLock = NSLock() +private let developerDiskManager = DeveloperDiskManager() + enum InstallError: LocalizedError { case cancelled @@ -32,7 +34,7 @@ enum InstallError: LocalizedError extension ALTDeviceManager { - func installApplication(at url: URL, to device: ALTDevice, appleID: String, password: String, completion: @escaping (Result) -> Void) + func installApplication(at url: URL, to altDevice: ALTDevice, appleID: String, password: String, completion: @escaping (Result) -> Void) { let destinationDirectoryURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) @@ -60,10 +62,11 @@ extension ALTDeviceManager { let team = try result.get() - self.register(device, team: team, session: session) { (result) in + self.register(altDevice, team: team, session: session) { (result) in do { let device = try result.get() + device.osVersion = altDevice.osVersion self.fetchCertificate(for: team, session: session) { (result) in do @@ -75,55 +78,67 @@ extension ALTDeviceManager // Show alert before downloading remote .ipa. self.showInstallationAlert(appName: NSLocalizedString("AltStore", comment: ""), deviceName: device.name) } - - self.downloadApp(from: url) { (result) in - do + + self.prepare(device) { (result) in + switch result { - let fileURL = try result.get() - - try FileManager.default.createDirectory(at: destinationDirectoryURL, withIntermediateDirectories: true, attributes: nil) - - let appBundleURL = try FileManager.default.unzipAppBundle(at: fileURL, toDirectory: destinationDirectoryURL) - guard let application = ALTApplication(fileURL: appBundleURL) else { throw ALTError(.invalidApp) } - - if url.isFileURL - { - // Show alert after "downloading" local .ipa. - self.showInstallationAlert(appName: application.name, deviceName: device.name) - } - - // Refresh anisette data to prevent session timeouts. - AnisetteDataManager.shared.requestAnisetteData { (result) in + case .failure(let error): + print("Failed to install DeveloperDiskImage.dmg to \(device).", error) + fallthrough // Continue installing app even if we couldn't install Developer disk image. + + case .success: + self.downloadApp(from: url) { (result) in do { - let anisetteData = try result.get() - session.anisetteData = anisetteData + let fileURL = try result.get() - self.prepareAllProvisioningProfiles(for: application, device: device, team: team, session: session) { (result) in + try FileManager.default.createDirectory(at: destinationDirectoryURL, withIntermediateDirectories: true, attributes: nil) + + let appBundleURL = try FileManager.default.unzipAppBundle(at: fileURL, toDirectory: destinationDirectoryURL) + guard let application = ALTApplication(fileURL: appBundleURL) else { throw ALTError(.invalidApp) } + + if url.isFileURL + { + // Show alert after "downloading" local .ipa. + self.showInstallationAlert(appName: application.name, deviceName: device.name) + } + + appName = application.name + + // Refresh anisette data to prevent session timeouts. + AnisetteDataManager.shared.requestAnisetteData { (result) in do { - let profiles = try result.get() + let anisetteData = try result.get() + session.anisetteData = anisetteData - self.install(application, to: device, team: team, certificate: certificate, profiles: profiles) { (result) in - finish(result.map { application }, title: "Failed to Install AltStore") + self.prepareAllProvisioningProfiles(for: application, device: device, team: team, session: session) { (result) in + do + { + let profiles = try result.get() + + self.install(application, to: device, team: team, certificate: certificate, profiles: profiles) { (result) in + finish(result.map { application }, title: "Failed to Install AltStore") + } + } + catch + { + finish(.failure(error), title: "Failed to Fetch Provisioning Profiles") + } } } catch { - finish(.failure(error), title: "Failed to Fetch Provisioning Profiles") + finish(.failure(error), title: "Failed to Refresh Anisette Data") } } } catch { - finish(.failure(error), title: "Failed to Refresh Anisette Data") + finish(.failure(error), title: "Failed to Download AltStore") } } } - catch - { - finish(.failure(error), title: "Failed to Download AltStore") - } } } catch @@ -158,6 +173,35 @@ extension ALTDeviceManager } } +extension ALTDeviceManager +{ + func prepare(_ device: ALTDevice, completionHandler: @escaping (Result) -> Void) + { + ALTDeviceManager.shared.isDeveloperDiskImageMounted(for: device) { (isMounted, error) in + switch (isMounted, error) + { + case (_, let error?): return completionHandler(.failure(error)) + case (true, _): return completionHandler(.success(())) + case (false, _): + developerDiskManager.downloadDeveloperDisk(for: device) { (result) in + switch result + { + case .failure(let error): completionHandler(.failure(error)) + case .success((let diskFileURL, let signatureFileURL)): + ALTDeviceManager.shared.installDeveloperDiskImage(at: diskFileURL, signatureURL: signatureFileURL, to: device) { (success, error) in + switch Result(success, error) + { + case .failure(let error): completionHandler(.failure(error)) + case .success: completionHandler(.success(())) + } + } + } + } + } + } + } +} + private extension ALTDeviceManager { func downloadApp(from url: URL, completionHandler: @escaping (Result) -> Void) @@ -270,13 +314,8 @@ private extension ALTDeviceManager { let certificates = try Result(certificates, error).get() - let applicationSupportDirectoryURL = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0] - let altserverDirectoryURL = applicationSupportDirectoryURL.appendingPathComponent("com.rileytestut.AltServer") - let certificatesDirectoryURL = altserverDirectoryURL.appendingPathComponent("Certificates") - - try FileManager.default.createDirectory(at: certificatesDirectoryURL, withIntermediateDirectories: true, attributes: nil) - - let certificateFileURL = certificatesDirectoryURL.appendingPathComponent(team.identifier + ".p12") + let certificateFileURL = FileManager.default.certificatesDirectory.appendingPathComponent(team.identifier + ".p12") + try FileManager.default.createDirectory(at: FileManager.default.certificatesDirectory, withIntermediateDirectories: true, attributes: nil) var isCancelled = false diff --git a/AltServer/Extensions/FileManager+URLs.swift b/AltServer/Extensions/FileManager+URLs.swift new file mode 100644 index 00000000..81b5a77e --- /dev/null +++ b/AltServer/Extensions/FileManager+URLs.swift @@ -0,0 +1,29 @@ +// +// FileManager+URLs.swift +// AltServer +// +// Created by Riley Testut on 2/23/21. +// Copyright © 2021 Riley Testut. All rights reserved. +// + +import Foundation + +extension FileManager +{ + var altserverDirectory: URL { + let applicationSupportDirectoryURL = self.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0] + + let altserverDirectoryURL = applicationSupportDirectoryURL.appendingPathComponent("com.rileytestut.AltServer") + return altserverDirectoryURL + } + + var certificatesDirectory: URL { + let certificatesDirectoryURL = self.altserverDirectory.appendingPathComponent("Certificates") + return certificatesDirectoryURL + } + + var developerDisksDirectory: URL { + let developerDisksDirectoryURL = self.altserverDirectory.appendingPathComponent("DeveloperDiskImages") + return developerDisksDirectoryURL + } +} diff --git a/AltStore.xcodeproj/project.pbxproj b/AltStore.xcodeproj/project.pbxproj index 7469a9a8..0f224c4a 100644 --- a/AltStore.xcodeproj/project.pbxproj +++ b/AltStore.xcodeproj/project.pbxproj @@ -119,6 +119,7 @@ BF45884B2298D55000BD7491 /* thread.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4588492298D55000BD7491 /* thread.h */; }; BF4588882298DD3F00BD7491 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BF4588872298DD3F00BD7491 /* libxml2.tbd */; }; BF4B78FE24B3D1DB008AB4AC /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF4B78FD24B3D1DB008AB4AC /* SceneDelegate.swift */; }; + BF541C0B25E5A5FA00CD46B2 /* FileManager+URLs.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF541C0A25E5A5FA00CD46B2 /* FileManager+URLs.swift */; }; BF56D2AC23DF8E170006506D /* FetchAppIDsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */; }; BF56D2AF23DF9E310006506D /* AppIDsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2AE23DF9E310006506D /* AppIDsViewController.swift */; }; BF58047E246A28F7008AE704 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF58047D246A28F7008AE704 /* AppDelegate.swift */; }; @@ -211,6 +212,7 @@ BF9ABA4D22DD16DE008935CF /* PillButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4C22DD16DE008935CF /* PillButton.swift */; }; BFA8172923C56042001B5953 /* ServerConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA8172823C56042001B5953 /* ServerConnection.swift */; }; BFA8172B23C5633D001B5953 /* FetchAnisetteDataOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA8172A23C5633D001B5953 /* FetchAnisetteDataOperation.swift */; }; + BFAD67A325E0854500D4C4D1 /* DeveloperDiskManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFAD67A225E0854500D4C4D1 /* DeveloperDiskManager.swift */; }; BFAECC522501B0A400528F27 /* CodableServerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD44605241188C300EAB90A /* CodableServerError.swift */; }; BFAECC532501B0A400528F27 /* ServerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1E3128229F474900370A3C /* ServerProtocol.swift */; }; BFAECC542501B0A400528F27 /* NSError+ALTServerError.m in Sources */ = {isa = PBXBuildFile; fileRef = BF1E314922A060F400370A3C /* NSError+ALTServerError.m */; }; @@ -562,6 +564,7 @@ BF4588492298D55000BD7491 /* thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = thread.h; path = Dependencies/libusbmuxd/common/thread.h; sourceTree = SOURCE_ROOT; }; BF4588872298DD3F00BD7491 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/lib/libxml2.tbd; sourceTree = DEVELOPER_DIR; }; BF4B78FD24B3D1DB008AB4AC /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + BF541C0A25E5A5FA00CD46B2 /* FileManager+URLs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+URLs.swift"; sourceTree = ""; }; BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchAppIDsOperation.swift; sourceTree = ""; }; BF56D2AE23DF9E310006506D /* AppIDsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIDsViewController.swift; sourceTree = ""; }; BF58047B246A28F7008AE704 /* AltBackup.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AltBackup.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -676,6 +679,7 @@ BF9ABA4C22DD16DE008935CF /* PillButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillButton.swift; sourceTree = ""; }; BFA8172823C56042001B5953 /* ServerConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnection.swift; sourceTree = ""; }; BFA8172A23C5633D001B5953 /* FetchAnisetteDataOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchAnisetteDataOperation.swift; sourceTree = ""; }; + BFAD67A225E0854500D4C4D1 /* DeveloperDiskManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperDiskManager.swift; sourceTree = ""; }; BFB1169C22932DB100BB457C /* apps.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = apps.json; sourceTree = ""; }; BFB364592325985F00CD0EB1 /* FindServerOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindServerOperation.swift; sourceTree = ""; }; BFB39B5B252BC10E00D1BE50 /* Managed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Managed.swift; sourceTree = ""; }; @@ -889,6 +893,7 @@ isa = PBXGroup; children = ( BF0241A922F29CCD00129732 /* UserDefaults+AltServer.swift */, + BF541C0A25E5A5FA00CD46B2 /* FileManager+URLs.swift */, ); path = Extensions; sourceTree = ""; @@ -965,6 +970,7 @@ BF458695229872EA00BD7491 /* Main.storyboard */, BFE48974238007CE003239E0 /* AnisetteDataManager.swift */, BFC712BA2512B9CF00AB5EBE /* PluginManager.swift */, + BFAD67A225E0854500D4C4D1 /* DeveloperDiskManager.swift */, BF703195229F36FF006E110F /* Devices */, BFD52BDC22A0A659000B7ED1 /* Connections */, BF055B4A233B528B0086DEA9 /* Extensions */, @@ -2269,6 +2275,7 @@ BFF767C82489A74E0097E58C /* WirelessConnectionHandler.swift in Sources */, BFECAC8024FD950B0077C41F /* ConnectionManager.swift in Sources */, BFECAC8324FD950B0077C41F /* NetworkConnection.swift in Sources */, + BF541C0B25E5A5FA00CD46B2 /* FileManager+URLs.swift in Sources */, BFECAC8724FD950B0077C41F /* Bundle+AltStore.swift in Sources */, BF3F786422CAA41E008FBD20 /* ALTDeviceManager+Installation.swift in Sources */, BF18BFFD2485A1E400DD5981 /* WiredConnectionHandler.swift in Sources */, @@ -2287,6 +2294,7 @@ BF4586C52298CDB800BD7491 /* ALTDeviceManager.mm in Sources */, BF0241AA22F29CCD00129732 /* UserDefaults+AltServer.swift in Sources */, BFECAC9424FD98BA0077C41F /* NSError+ALTServerError.m in Sources */, + BFAD67A325E0854500D4C4D1 /* DeveloperDiskManager.swift in Sources */, BFECAC9324FD98BA0077C41F /* CFNotificationName+AltStore.m in Sources */, BFE48975238007CE003239E0 /* AnisetteDataManager.swift in Sources */, BFE972E3260A8B2700D0BDAC /* NSError+libimobiledevice.mm in Sources */, diff --git a/Dependencies/AltSign b/Dependencies/AltSign index ae857dc3..5dc5d72f 160000 --- a/Dependencies/AltSign +++ b/Dependencies/AltSign @@ -1 +1 @@ -Subproject commit ae857dc3783161b48b02adf69db4a477b99cf39b +Subproject commit 5dc5d72f3954ea86b2cd0b4e570490424d3f83b5