mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-20 20:23:25 +01:00
Logs sideloading-related events with OSLog
This commit is contained in:
@@ -354,6 +354,7 @@
|
|||||||
D51AD27E29356B7B00967AAA /* ALTWrappedError.h in Headers */ = {isa = PBXBuildFile; fileRef = D51AD27C29356B7B00967AAA /* ALTWrappedError.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D51AD27E29356B7B00967AAA /* ALTWrappedError.h in Headers */ = {isa = PBXBuildFile; fileRef = D51AD27C29356B7B00967AAA /* ALTWrappedError.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
D51AD27F29356B7B00967AAA /* ALTWrappedError.m in Sources */ = {isa = PBXBuildFile; fileRef = D51AD27D29356B7B00967AAA /* ALTWrappedError.m */; };
|
D51AD27F29356B7B00967AAA /* ALTWrappedError.m in Sources */ = {isa = PBXBuildFile; fileRef = D51AD27D29356B7B00967AAA /* ALTWrappedError.m */; };
|
||||||
D51AD28029356B8000967AAA /* ALTWrappedError.m in Sources */ = {isa = PBXBuildFile; fileRef = D51AD27D29356B7B00967AAA /* ALTWrappedError.m */; };
|
D51AD28029356B8000967AAA /* ALTWrappedError.m in Sources */ = {isa = PBXBuildFile; fileRef = D51AD27D29356B7B00967AAA /* ALTWrappedError.m */; };
|
||||||
|
D52A2F972ACB40F700BDF8E3 /* Logger+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52A2F962ACB40F700BDF8E3 /* Logger+AltStore.swift */; };
|
||||||
D52C08EE28AEC37A006C4AE5 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */; };
|
D52C08EE28AEC37A006C4AE5 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */; };
|
||||||
D52DD35E2AAA89A600A7F2B6 /* AltSign-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = D52DD35D2AAA89A600A7F2B6 /* AltSign-Dynamic */; };
|
D52DD35E2AAA89A600A7F2B6 /* AltSign-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = D52DD35D2AAA89A600A7F2B6 /* AltSign-Dynamic */; };
|
||||||
D52EF2BE2A0594550096C377 /* AppDetailCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52EF2BD2A0594550096C377 /* AppDetailCollectionViewController.swift */; };
|
D52EF2BE2A0594550096C377 /* AppDetailCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52EF2BD2A0594550096C377 /* AppDetailCollectionViewController.swift */; };
|
||||||
@@ -1011,6 +1012,7 @@
|
|||||||
D5189C002A01BC6800F44625 /* UserInfoValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoValue.swift; sourceTree = "<group>"; };
|
D5189C002A01BC6800F44625 /* UserInfoValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoValue.swift; sourceTree = "<group>"; };
|
||||||
D51AD27C29356B7B00967AAA /* ALTWrappedError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTWrappedError.h; sourceTree = "<group>"; };
|
D51AD27C29356B7B00967AAA /* ALTWrappedError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTWrappedError.h; sourceTree = "<group>"; };
|
||||||
D51AD27D29356B7B00967AAA /* ALTWrappedError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTWrappedError.m; sourceTree = "<group>"; };
|
D51AD27D29356B7B00967AAA /* ALTWrappedError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTWrappedError.m; sourceTree = "<group>"; };
|
||||||
|
D52A2F962ACB40F700BDF8E3 /* Logger+AltStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+AltStore.swift"; sourceTree = "<group>"; };
|
||||||
D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = "<group>"; };
|
D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = "<group>"; };
|
||||||
D52E988928D002D30032BE6B /* AltStore 11.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 11.xcdatamodel"; sourceTree = "<group>"; };
|
D52E988928D002D30032BE6B /* AltStore 11.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 11.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
D52EF2BD2A0594550096C377 /* AppDetailCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDetailCollectionViewController.swift; sourceTree = "<group>"; };
|
D52EF2BD2A0594550096C377 /* AppDetailCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDetailCollectionViewController.swift; sourceTree = "<group>"; };
|
||||||
@@ -1723,6 +1725,7 @@
|
|||||||
0E05025B2BEC947000879B5C /* String+SideStore.swift */,
|
0E05025B2BEC947000879B5C /* String+SideStore.swift */,
|
||||||
D5F48B4729CCF21B002B52A4 /* AltStore+Async.swift */,
|
D5F48B4729CCF21B002B52A4 /* AltStore+Async.swift */,
|
||||||
D5893F7E2A14183200E767CD /* NSManagedObjectContext+Conveniences.swift */,
|
D5893F7E2A14183200E767CD /* NSManagedObjectContext+Conveniences.swift */,
|
||||||
|
D52A2F962ACB40F700BDF8E3 /* Logger+AltStore.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -3031,6 +3034,7 @@
|
|||||||
BFAECC572501B0A400528F27 /* ConnectionManager.swift in Sources */,
|
BFAECC572501B0A400528F27 /* ConnectionManager.swift in Sources */,
|
||||||
BF66EE9D2501AEC1007EE018 /* AppProtocol.swift in Sources */,
|
BF66EE9D2501AEC1007EE018 /* AppProtocol.swift in Sources */,
|
||||||
D519AD46292D665B004B12F9 /* Managed.swift in Sources */,
|
D519AD46292D665B004B12F9 /* Managed.swift in Sources */,
|
||||||
|
D52A2F972ACB40F700BDF8E3 /* Logger+AltStore.swift in Sources */,
|
||||||
BFC712C42512D5F100AB5EBE /* XPCConnection.swift in Sources */,
|
BFC712C42512D5F100AB5EBE /* XPCConnection.swift in Sources */,
|
||||||
D5CA0C4B280E141900469595 /* ManagedPatron.swift in Sources */,
|
D5CA0C4B280E141900469595 /* ManagedPatron.swift in Sources */,
|
||||||
0E05025A2BEC83C500879B5C /* OperatingSystemVersion+Comparable.swift in Sources */,
|
0E05025A2BEC83C500879B5C /* OperatingSystemVersion+Comparable.swift in Sources */,
|
||||||
|
|||||||
@@ -205,7 +205,11 @@ final class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, A
|
|||||||
{
|
{
|
||||||
guard !self.isFinished else { return }
|
guard !self.isFinished else { return }
|
||||||
|
|
||||||
print("Finished authenticating with result:", result.error?.localizedDescription ?? "success")
|
switch result
|
||||||
|
{
|
||||||
|
case .failure(let error): Logger.sideload.error("Failed to authenticate account. \(error.localizedDescription, privacy: .public)")
|
||||||
|
case .success((let team, _, _)): Logger.sideload.notice("Authenticated account for team \(team.identifier, privacy: .public).")
|
||||||
|
}
|
||||||
|
|
||||||
let context = DatabaseManager.shared.persistentContainer.newBackgroundContext()
|
let context = DatabaseManager.shared.persistentContainer.newBackgroundContext()
|
||||||
context.perform {
|
context.perform {
|
||||||
@@ -348,6 +352,8 @@ private extension AuthenticationOperation
|
|||||||
|
|
||||||
if let appleID = Keychain.shared.appleIDEmailAddress, let password = Keychain.shared.appleIDPassword
|
if let appleID = Keychain.shared.appleIDEmailAddress, let password = Keychain.shared.appleIDPassword
|
||||||
{
|
{
|
||||||
|
Logger.sideload.notice("Authenticating Apple ID...")
|
||||||
|
|
||||||
self.authenticate(appleID: appleID, password: password) { (result) in
|
self.authenticate(appleID: appleID, password: password) { (result) in
|
||||||
switch result
|
switch result
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result<Inst
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.managedObjectContext.perform {
|
self.managedObjectContext.perform {
|
||||||
print("Apps to refresh:", self.installedApps.map(\.bundleIdentifier))
|
Logger.sideload.notice("Refreshing apps in background: \(self.installedApps.map(\.bundleIdentifier), privacy: .public)")
|
||||||
|
|
||||||
self.startListeningForRunningApps()
|
self.startListeningForRunningApps()
|
||||||
|
|
||||||
@@ -125,7 +125,10 @@ final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result<Inst
|
|||||||
self.managedObjectContext.perform {
|
self.managedObjectContext.perform {
|
||||||
|
|
||||||
let filteredApps = self.installedApps.filter { !self.runningApplications.contains($0.bundleIdentifier) }
|
let filteredApps = self.installedApps.filter { !self.runningApplications.contains($0.bundleIdentifier) }
|
||||||
print("Filtered Apps to Refresh:", filteredApps.map { $0.bundleIdentifier })
|
if !self.runningApplications.isEmpty
|
||||||
|
{
|
||||||
|
Logger.sideload.notice("Skipping refreshing running apps: \(self.runningApplications, privacy: .public)")
|
||||||
|
}
|
||||||
|
|
||||||
let group = AppManager.shared.refresh(filteredApps, presentingViewController: nil)
|
let group = AppManager.shared.refresh(filteredApps, presentingViewController: nil)
|
||||||
group.beginInstallationHandler = { (installedApp) in
|
group.beginInstallationHandler = { (installedApp) in
|
||||||
@@ -235,6 +238,8 @@ private extension BackgroundRefreshAppsOperation
|
|||||||
{
|
{
|
||||||
print("Failed to refresh apps in background.", error)
|
print("Failed to refresh apps in background.", error)
|
||||||
|
|
||||||
|
Logger.sideload.error("Failed to refresh apps in background. \(error.localizedDescription, privacy: .public)")
|
||||||
|
|
||||||
content.title = NSLocalizedString("Failed to Refresh Apps", comment: "")
|
content.title = NSLocalizedString("Failed to Refresh Apps", comment: "")
|
||||||
content.body = error.localizedDescription
|
content.body = error.localizedDescription
|
||||||
}
|
}
|
||||||
@@ -275,7 +280,7 @@ private extension BackgroundRefreshAppsOperation
|
|||||||
_ = RefreshAttempt(identifier: self.refreshIdentifier, result: result, context: context)
|
_ = RefreshAttempt(identifier: self.refreshIdentifier, result: result, context: context)
|
||||||
|
|
||||||
do { try context.save() }
|
do { try context.save() }
|
||||||
catch { print("Failed to save refresh attempt.", error) }
|
catch { Logger.sideload.error("Failed to save refresh attempt. \(error.localizedDescription, privacy: .public)") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class BackupAppOperation: ResultOperation<Void>
|
|||||||
// Failed too quickly for human to respond to alert, possibly still finalizing installation.
|
// Failed too quickly for human to respond to alert, possibly still finalizing installation.
|
||||||
// Try again in a couple seconds.
|
// Try again in a couple seconds.
|
||||||
|
|
||||||
print("Failed too quickly, retrying after a few seconds...")
|
Logger.sideload.error("Failed to open app too quickly, retrying after a few seconds...")
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
|
||||||
UIApplication.shared.open(openURL, options: [:]) { (success) in
|
UIApplication.shared.open(openURL, options: [:]) { (success) in
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ final class DownloadAppOperation: ResultOperation<ALTApplication>
|
|||||||
|
|
||||||
print("Downloading App:", self.bundleIdentifier)
|
print("Downloading App:", self.bundleIdentifier)
|
||||||
|
|
||||||
|
|
||||||
|
Logger.sideload.notice("Downloading app \(self.bundleIdentifier, privacy: .public)...")
|
||||||
|
|
||||||
|
// Set _after_ checking self.context.error to prevent overwriting localized failure for previous errors.
|
||||||
self.localizedFailure = String(format: NSLocalizedString("%@ could not be downloaded.", comment: ""), self.appName)
|
self.localizedFailure = String(format: NSLocalizedString("%@ could not be downloaded.", comment: ""), self.appName)
|
||||||
|
|
||||||
guard let storeApp = self.app as? StoreApp else {
|
guard let storeApp = self.app as? StoreApp else {
|
||||||
@@ -100,6 +104,7 @@ final class DownloadAppOperation: ResultOperation<ALTApplication>
|
|||||||
try FileManager.default.removeItem(at: self.temporaryDirectory)
|
try FileManager.default.removeItem(at: self.temporaryDirectory)
|
||||||
} catch {
|
} catch {
|
||||||
print("Failed to remove DownloadAppOperation temporary directory: \(self.temporaryDirectory).", error)
|
print("Failed to remove DownloadAppOperation temporary directory: \(self.temporaryDirectory).", error)
|
||||||
|
Logger.sideload.error("Failed to remove DownloadAppOperation temporary directory: \(self.temporaryDirectory, privacy: .public). \(error.localizedDescription, privacy: .public)")
|
||||||
}
|
}
|
||||||
super.finish(result)
|
super.finish(result)
|
||||||
}
|
}
|
||||||
@@ -156,6 +161,9 @@ private extension DownloadAppOperation {
|
|||||||
try FileManager.default.copyItem(at: application.fileURL, to: self.destinationURL, shouldReplace: true)
|
try FileManager.default.copyItem(at: application.fileURL, to: self.destinationURL, shouldReplace: true)
|
||||||
|
|
||||||
guard let copiedApplication = ALTApplication(fileURL: self.destinationURL) else { throw OperationError.invalidApp }
|
guard let copiedApplication = ALTApplication(fileURL: self.destinationURL) else { throw OperationError.invalidApp }
|
||||||
|
|
||||||
|
Logger.sideload.notice("Downloaded app \(copiedApplication.bundleIdentifier, privacy: .public) from \(sourceURL, privacy: .public)")
|
||||||
|
|
||||||
self.finish(.success(copiedApplication))
|
self.finish(.success(copiedApplication))
|
||||||
|
|
||||||
self.progress.completedUnitCount += 1
|
self.progress.completedUnitCount += 1
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ final class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProv
|
|||||||
|
|
||||||
guard let app = self.context.app else { return self.finish(.failure(OperationError.appNotFound(name: nil))) }
|
guard let app = self.context.app else { return self.finish(.failure(OperationError.appNotFound(name: nil))) }
|
||||||
|
|
||||||
|
Logger.sideload.notice("Fetching provisioning profiles for app \(self.context.bundleIdentifier, privacy: .public)...")
|
||||||
|
|
||||||
self.progress.totalUnitCount = Int64(1 + app.appExtensions.count)
|
self.progress.totalUnitCount = Int64(1 + app.appExtensions.count)
|
||||||
|
|
||||||
self.prepareProvisioningProfile(for: app, parentApp: nil, team: team, session: session) { (result) in
|
self.prepareProvisioningProfile(for: app, parentApp: nil, team: team, session: session) { (result) in
|
||||||
@@ -246,6 +248,8 @@ extension FetchProvisioningProfilesOperation
|
|||||||
|
|
||||||
if let appID = appIDs.first(where: { $0.bundleIdentifier.lowercased() == bundleIdentifier.lowercased() })
|
if let appID = appIDs.first(where: { $0.bundleIdentifier.lowercased() == bundleIdentifier.lowercased() })
|
||||||
{
|
{
|
||||||
|
Logger.sideload.notice("Using existing App ID \(appID.bundleIdentifier, privacy: .public)")
|
||||||
|
|
||||||
completionHandler(.success(appID))
|
completionHandler(.success(appID))
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -285,6 +289,9 @@ extension FetchProvisioningProfilesOperation
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
let appID = try Result(appID, error).get()
|
let appID = try Result(appID, error).get()
|
||||||
|
|
||||||
|
Logger.sideload.notice("Registered new App ID \(appID.bundleIdentifier, privacy: .public)")
|
||||||
|
|
||||||
completionHandler(.success(appID))
|
completionHandler(.success(appID))
|
||||||
}
|
}
|
||||||
catch ALTAppleAPIError.maximumAppIDLimitReached
|
catch ALTAppleAPIError.maximumAppIDLimitReached
|
||||||
@@ -383,8 +390,15 @@ extension FetchProvisioningProfilesOperation
|
|||||||
let appID = appID.copy() as! ALTAppID
|
let appID = appID.copy() as! ALTAppID
|
||||||
appID.features = features
|
appID.features = features
|
||||||
|
|
||||||
ALTAppleAPI.shared.update(appID, team: team, session: session) { (appID, error) in
|
ALTAppleAPI.shared.update(appID, team: team, session: session) { (updatedAppID, error) in
|
||||||
completionHandler(Result(appID, error))
|
let result = Result(updatedAppID, error)
|
||||||
|
switch result
|
||||||
|
{
|
||||||
|
case .success(let appID): Logger.sideload.notice("Updated features for App ID \(appID.bundleIdentifier, privacy: .public).")
|
||||||
|
case .failure(let error): Logger.sideload.error("Failed to update features for App ID \(appID.bundleIdentifier, privacy: .public). \(error.localizedDescription, privacy: .public)")
|
||||||
|
}
|
||||||
|
|
||||||
|
completionHandler(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -402,6 +416,7 @@ extension FetchProvisioningProfilesOperation
|
|||||||
}
|
}
|
||||||
|
|
||||||
guard var applicationGroups = entitlements[.appGroups] as? [String], !applicationGroups.isEmpty else {
|
guard var applicationGroups = entitlements[.appGroups] as? [String], !applicationGroups.isEmpty else {
|
||||||
|
Logger.sideload.notice("App ID \(appID.bundleIdentifier, privacy: .public) has no app groups, skipping assignment.")
|
||||||
// Assigning an App ID to an empty app group array fails,
|
// Assigning an App ID to an empty app group array fails,
|
||||||
// so just do nothing if there are no app groups.
|
// so just do nothing if there are no app groups.
|
||||||
return completionHandler(.success(appID))
|
return completionHandler(.success(appID))
|
||||||
@@ -459,7 +474,10 @@ extension FetchProvisioningProfilesOperation
|
|||||||
ALTAppleAPI.shared.fetchAppGroups(for: team, session: session) { (groups, error) in
|
ALTAppleAPI.shared.fetchAppGroups(for: team, session: session) { (groups, error) in
|
||||||
switch Result(groups, error)
|
switch Result(groups, error)
|
||||||
{
|
{
|
||||||
case .failure(let error): finish(.failure(error))
|
case .failure(let error):
|
||||||
|
Logger.sideload.error("Failed to fetch app groups for team \(team.identifier, privacy: .public). \(error.localizedDescription, privacy: .public)")
|
||||||
|
finish(.failure(error))
|
||||||
|
|
||||||
case .success(let fetchedGroups):
|
case .success(let fetchedGroups):
|
||||||
let dispatchGroup = DispatchGroup()
|
let dispatchGroup = DispatchGroup()
|
||||||
|
|
||||||
@@ -484,8 +502,13 @@ extension FetchProvisioningProfilesOperation
|
|||||||
ALTAppleAPI.shared.addAppGroup(withName: name, groupIdentifier: adjustedGroupIdentifier, team: team, session: session) { (group, error) in
|
ALTAppleAPI.shared.addAppGroup(withName: name, groupIdentifier: adjustedGroupIdentifier, team: team, session: session) { (group, error) in
|
||||||
switch Result(group, error)
|
switch Result(group, error)
|
||||||
{
|
{
|
||||||
case .success(let group): groups.append(group)
|
case .success(let group):
|
||||||
case .failure(let error): errors.append(error)
|
Logger.sideload.notice("Created new App Group \(group.groupIdentifier, privacy: .public).")
|
||||||
|
groups.append(group)
|
||||||
|
|
||||||
|
case .failure(let error):
|
||||||
|
Logger.sideload.notice("Failed to create new App Group \(adjustedGroupIdentifier, privacy: .public). \(error.localizedDescription, privacy: .public)")
|
||||||
|
errors.append(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchGroup.leave()
|
dispatchGroup.leave()
|
||||||
@@ -501,8 +524,17 @@ extension FetchProvisioningProfilesOperation
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
ALTAppleAPI.shared.assign(appID, to: Array(groups), team: team, session: session) { (success, error) in
|
ALTAppleAPI.shared.assign(appID, to: Array(groups), team: team, session: session) { (success, error) in
|
||||||
let result = Result(success, error)
|
let groupIDs = groups.map { $0.groupIdentifier }
|
||||||
finish(result.map { _ in appID })
|
switch Result(success, error)
|
||||||
|
{
|
||||||
|
case .success:
|
||||||
|
Logger.sideload.notice("Assigned App ID \(appID.bundleIdentifier, privacy: .public) to App Groups \(groupIDs.description, privacy: .public).")
|
||||||
|
finish(.success(appID))
|
||||||
|
|
||||||
|
case .failure(let error):
|
||||||
|
Logger.sideload.error("Failed to assign App ID \(appID.bundleIdentifier, privacy: .public) to App Groups \(groupIDs.description, privacy: .public). \(error.localizedDescription, privacy: .public)")
|
||||||
|
finish(.failure(error))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -529,6 +561,8 @@ extension FetchProvisioningProfilesOperation
|
|||||||
completionHandler(.success(profile))
|
completionHandler(.success(profile))
|
||||||
|
|
||||||
case .success:
|
case .success:
|
||||||
|
Logger.sideload.notice("Generating new free provisioning profile for App ID \(appID.bundleIdentifier, privacy: .public).")
|
||||||
|
|
||||||
// Fetch new provisioning profile
|
// Fetch new provisioning profile
|
||||||
ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in
|
ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in
|
||||||
completionHandler(Result(profile, error))
|
completionHandler(Result(profile, error))
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
|
|||||||
return self.finish(.failure(OperationError.invalidParameters("InstallAppOperation.main: self.context.certificate or self.context.resignedApp or self.context.provisioningProfiles is nil")))
|
return self.finish(.failure(OperationError.invalidParameters("InstallAppOperation.main: self.context.certificate or self.context.resignedApp or self.context.provisioningProfiles is nil")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.sideload.notice("Installing resigned app \(resignedApp.bundleIdentifier, privacy: .public)...")
|
||||||
|
|
||||||
@Managed var appVersion = self.context.appVersion
|
@Managed var appVersion = self.context.appVersion
|
||||||
let storeBuildVersion = $appVersion.buildVersion
|
let storeBuildVersion = $appVersion.buildVersion
|
||||||
|
|
||||||
@@ -255,6 +257,7 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
|
|||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
print("Failed to remove refreshed .ipa: \(error)")
|
print("Failed to remove refreshed .ipa: \(error)")
|
||||||
|
Logger.sideload.error("Failed to remove refreshed .ipa: \(error.localizedDescription, privacy: .public)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +267,43 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
|
|||||||
|
|
||||||
private extension InstallAppOperation
|
private extension InstallAppOperation
|
||||||
{
|
{
|
||||||
|
func receive(from connection: ServerConnection, completionHandler: @escaping (Result<Void, Error>) -> Void)
|
||||||
|
{
|
||||||
|
connection.receiveResponse() { (result) in
|
||||||
|
do
|
||||||
|
{
|
||||||
|
let response = try result.get()
|
||||||
|
|
||||||
|
switch response
|
||||||
|
{
|
||||||
|
case .installationProgress(let response):
|
||||||
|
Logger.sideload.debug("Installing \(self.context.resignedApp?.bundleIdentifier ?? self.context.bundleIdentifier, privacy: .public)... \((response.progress * 100).rounded())%")
|
||||||
|
|
||||||
|
if response.progress == 1.0
|
||||||
|
{
|
||||||
|
self.progress.completedUnitCount = self.progress.totalUnitCount
|
||||||
|
completionHandler(.success(()))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.progress.completedUnitCount = Int64(response.progress * 100)
|
||||||
|
self.receive(from: connection, completionHandler: completionHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
case .error(let response):
|
||||||
|
completionHandler(.failure(response.error))
|
||||||
|
|
||||||
|
default:
|
||||||
|
completionHandler(.failure(ALTServerError(.unknownRequest)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
completionHandler(.failure(ALTServerError(error)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func cleanUp()
|
func cleanUp()
|
||||||
{
|
{
|
||||||
guard !self.didCleanUp else { return }
|
guard !self.didCleanUp else { return }
|
||||||
@@ -275,7 +315,7 @@ private extension InstallAppOperation
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
print("Failed to remove temporary directory.", error)
|
Logger.sideload.error("Failed to remove temporary directory: \(error.localizedDescription, privacy: .public)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import AltStoreCore
|
||||||
|
|
||||||
@objc(RemoveAppBackupOperation)
|
@objc(RemoveAppBackupOperation)
|
||||||
final class RemoveAppBackupOperation: ResultOperation<Void>
|
final class RemoveAppBackupOperation: ResultOperation<Void>
|
||||||
{
|
{
|
||||||
@@ -63,14 +65,14 @@ final class RemoveAppBackupOperation: ResultOperation<Void>
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
print("Failed to remove app backup directory:", error)
|
Logger.sideload.error("Failed to remove app backup directory \(backupDirectoryURL.lastPathComponent, privacy: .public). \(error.localizedDescription, privacy: .public)")
|
||||||
self.finish(.failure(error))
|
self.finish(.failure(error))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
print("Failed to remove app backup directory:", error)
|
Logger.sideload.error("Failed to remove app backup directory \(backupDirectoryURL.lastPathComponent, privacy: .public). \(error.localizedDescription, privacy: .public)")
|
||||||
self.finish(.failure(error))
|
self.finish(.failure(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ final class RemoveAppOperation: ResultOperation<InstalledApp>
|
|||||||
return self.finish(.failure(OperationError.invalidParameters("RemoveAppOperation.main: self.context.installedApp is nil")))
|
return self.finish(.failure(OperationError.invalidParameters("RemoveAppOperation.main: self.context.installedApp is nil")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.sideload.notice("Removing app \(self.context.bundleIdentifier, privacy: .public)...")
|
||||||
|
|
||||||
installedApp.managedObjectContext?.perform {
|
installedApp.managedObjectContext?.perform {
|
||||||
let resignedBundleIdentifier = installedApp.resignedBundleIdentifier
|
let resignedBundleIdentifier = installedApp.resignedBundleIdentifier
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ final class ResignAppOperation: ResultOperation<ALTApplication>
|
|||||||
"self.context.certificate is nil")))
|
"self.context.certificate is nil")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.sideload.notice("Resigning app \(self.context.bundleIdentifier, privacy: .public)...")
|
||||||
|
|
||||||
// Prepare app bundle
|
// Prepare app bundle
|
||||||
let prepareAppProgress = Progress.discreteProgress(totalUnitCount: 2)
|
let prepareAppProgress = Progress.discreteProgress(totalUnitCount: 2)
|
||||||
self.progress.addChild(prepareAppProgress, withPendingUnitCount: 3)
|
self.progress.addChild(prepareAppProgress, withPendingUnitCount: 3)
|
||||||
@@ -56,8 +58,6 @@ final class ResignAppOperation: ResultOperation<ALTApplication>
|
|||||||
let prepareAppBundleProgress = self.prepareAppBundle(for: app, profiles: profiles) { (result) in
|
let prepareAppBundleProgress = self.prepareAppBundle(for: app, profiles: profiles) { (result) in
|
||||||
guard let appBundleURL = self.process(result) else { return }
|
guard let appBundleURL = self.process(result) else { return }
|
||||||
|
|
||||||
print("Resigning App:", self.context.bundleIdentifier)
|
|
||||||
|
|
||||||
// Resign app bundle
|
// Resign app bundle
|
||||||
let resignProgress = self.resignAppBundle(at: appBundleURL, team: team, certificate: certificate, profiles: Array(profiles.values)) { (result) in
|
let resignProgress = self.resignAppBundle(at: appBundleURL, team: team, certificate: certificate, profiles: Array(profiles.values)) { (result) in
|
||||||
guard let resignedURL = self.process(result) else { return }
|
guard let resignedURL = self.process(result) else { return }
|
||||||
@@ -71,6 +71,9 @@ final class ResignAppOperation: ResultOperation<ALTApplication>
|
|||||||
|
|
||||||
// Use appBundleURL since we need an app bundle, not .ipa.
|
// Use appBundleURL since we need an app bundle, not .ipa.
|
||||||
guard let resignedApplication = ALTApplication(fileURL: appBundleURL) else { throw OperationError.invalidApp }
|
guard let resignedApplication = ALTApplication(fileURL: appBundleURL) else { throw OperationError.invalidApp }
|
||||||
|
|
||||||
|
Logger.sideload.notice("Resigned app \(self.context.bundleIdentifier, privacy: .public) to \(resignedApplication.bundleIdentifier, privacy: .public).")
|
||||||
|
|
||||||
self.finish(.success(resignedApplication))
|
self.finish(.success(resignedApplication))
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ final class SendAppOperation: ResultOperation<()>
|
|||||||
return self.finish(.failure(OperationError.invalidParameters("SendAppOperation.main: self.resignedApp is nil")))
|
return self.finish(.failure(OperationError.invalidParameters("SendAppOperation.main: self.resignedApp is nil")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.sideload.notice("Sending app \(self.context.bundleIdentifier, privacy: .public) to AltServer \(server.localizedName ?? "nil", privacy: .public)...")
|
||||||
|
|
||||||
// self.context.resignedApp.fileURL points to the app bundle, but we want the .ipa.
|
// self.context.resignedApp.fileURL points to the app bundle, but we want the .ipa.
|
||||||
let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL)
|
let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL)
|
||||||
let fileURL = InstalledApp.refreshedIPAURL(for: app)
|
let fileURL = InstalledApp.refreshedIPAURL(for: app)
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ private extension VerifyAppOperation
|
|||||||
let sha256Hash = SHA256.hash(data: data)
|
let sha256Hash = SHA256.hash(data: data)
|
||||||
let hashString = sha256Hash.compactMap { String(format: "%02x", $0) }.joined()
|
let hashString = sha256Hash.compactMap { String(format: "%02x", $0) }.joined()
|
||||||
|
|
||||||
print("[ALTLog] Comparing app hash (\(hashString)) against expected hash (\(expectedHash))...")
|
Logger.sideload.debug("Comparing app hash (\(hashString, privacy: .public)) against expected hash (\(expectedHash, privacy: .public))...")
|
||||||
|
|
||||||
guard hashString == expectedHash else { throw VerificationError.mismatchedHash(hashString, expectedHash: expectedHash, app: app) }
|
guard hashString == expectedHash else { throw VerificationError.mismatchedHash(hashString, expectedHash: expectedHash, app: app) }
|
||||||
}
|
}
|
||||||
|
|||||||
33
AltStoreCore/Extensions/Logger+AltStore.swift
Normal file
33
AltStoreCore/Extensions/Logger+AltStore.swift
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// Logger+AltStore.swift
|
||||||
|
// AltStoreCore
|
||||||
|
//
|
||||||
|
// Created by Riley Testut on 10/2/23.
|
||||||
|
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
@_exported import OSLog
|
||||||
|
|
||||||
|
public extension Logger
|
||||||
|
{
|
||||||
|
static let altstoreSubsystem = Bundle.main.bundleIdentifier!
|
||||||
|
|
||||||
|
static let sideload = Logger(subsystem: altstoreSubsystem, category: "Sideload")
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 15, *)
|
||||||
|
public extension OSLogEntryLog.Level
|
||||||
|
{
|
||||||
|
var localizedName: String {
|
||||||
|
switch self
|
||||||
|
{
|
||||||
|
case .undefined: return NSLocalizedString("Undefined", comment: "")
|
||||||
|
case .debug: return NSLocalizedString("Debug", comment: "")
|
||||||
|
case .info: return NSLocalizedString("Info", comment: "")
|
||||||
|
case .notice: return NSLocalizedString("Notice", comment: "")
|
||||||
|
case .error: return NSLocalizedString("Error", comment: "")
|
||||||
|
case .fault: return NSLocalizedString("Fault", comment: "")
|
||||||
|
@unknown default: return NSLocalizedString("Unknown", comment: "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user