mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-17 10:43:30 +01:00
restore changes dropped from altstore by 1713fcc
This commit is contained in:
48
AltServer/ErrorDetailsViewController.swift
Normal file
48
AltServer/ErrorDetailsViewController.swift
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// ErrorDetailsViewController.swift
|
||||||
|
// AltServer
|
||||||
|
//
|
||||||
|
// Created by Riley Testut on 10/4/22.
|
||||||
|
// Copyright © 2022 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppKit
|
||||||
|
|
||||||
|
class ErrorDetailsViewController: NSViewController
|
||||||
|
{
|
||||||
|
var error: NSError? {
|
||||||
|
didSet {
|
||||||
|
self.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBOutlet private var errorCodeLabel: NSTextField!
|
||||||
|
@IBOutlet private var detailedDescriptionLabel: NSTextField!
|
||||||
|
|
||||||
|
override func viewDidLoad()
|
||||||
|
{
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
self.detailedDescriptionLabel.preferredMaxLayoutWidth = 800
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension ErrorDetailsViewController
|
||||||
|
{
|
||||||
|
func update()
|
||||||
|
{
|
||||||
|
if !self.isViewLoaded
|
||||||
|
{
|
||||||
|
self.loadView()
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let error = self.error else { return }
|
||||||
|
|
||||||
|
self.errorCodeLabel.stringValue = error.localizedErrorCode
|
||||||
|
|
||||||
|
let font = self.detailedDescriptionLabel.font ?? NSFont.systemFont(ofSize: 12)
|
||||||
|
let detailedDescription = error.formattedDetailedDescription(with: font)
|
||||||
|
self.detailedDescriptionLabel.attributedStringValue = detailedDescription
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -847,6 +847,7 @@
|
|||||||
D533E8B82727B61400A9B5DD /* fragmentzip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fragmentzip.h; sourceTree = "<group>"; };
|
D533E8B82727B61400A9B5DD /* fragmentzip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fragmentzip.h; sourceTree = "<group>"; };
|
||||||
D533E8BB2727BBEE00A9B5DD /* libfragmentzip.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfragmentzip.a; path = Dependencies/fragmentzip/libfragmentzip.a; sourceTree = SOURCE_ROOT; };
|
D533E8BB2727BBEE00A9B5DD /* libfragmentzip.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfragmentzip.a; path = Dependencies/fragmentzip/libfragmentzip.a; sourceTree = SOURCE_ROOT; };
|
||||||
D533E8BD2727BBF800A9B5DD /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcurl.a; path = Dependencies/libcurl/libcurl.a; sourceTree = SOURCE_ROOT; };
|
D533E8BD2727BBF800A9B5DD /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcurl.a; path = Dependencies/libcurl/libcurl.a; sourceTree = SOURCE_ROOT; };
|
||||||
|
D540E93728EE1BDE000F1B0F /* ErrorDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorDetailsViewController.swift; sourceTree = "<group>"; };
|
||||||
D54DED1328CBC44B008B27A0 /* ErrorLogTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogTableViewCell.swift; sourceTree = "<group>"; };
|
D54DED1328CBC44B008B27A0 /* ErrorLogTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D55E163528776CB000A627A1 /* ComplicationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationView.swift; sourceTree = "<group>"; };
|
D55E163528776CB000A627A1 /* ComplicationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationView.swift; sourceTree = "<group>"; };
|
||||||
D57DF637271E32F000677701 /* PatchApp.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = PatchApp.storyboard; sourceTree = "<group>"; };
|
D57DF637271E32F000677701 /* PatchApp.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = PatchApp.storyboard; sourceTree = "<group>"; };
|
||||||
@@ -1021,6 +1022,7 @@
|
|||||||
B33FFB8F295F8CF2002259E6 /* Recovered References */ = {
|
B33FFB8F295F8CF2002259E6 /* Recovered References */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D540E93728EE1BDE000F1B0F /* ErrorDetailsViewController.swift */,
|
||||||
);
|
);
|
||||||
name = "Recovered References";
|
name = "Recovered References";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|||||||
@@ -1957,7 +1957,43 @@ private extension AppManager
|
|||||||
UNUserNotificationCenter.current().add(request)
|
UNUserNotificationCenter.current().add(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func log(_ error: Error, for operation: AppOperation)
|
||||||
|
{
|
||||||
|
// Sanitize NSError on same thread before performing background task.
|
||||||
|
let sanitizedError = (error as NSError).sanitizedForSerialization()
|
||||||
|
|
||||||
|
let loggedErrorOperation: LoggedError.Operation = {
|
||||||
|
switch operation
|
||||||
|
{
|
||||||
|
case .install: return .install
|
||||||
|
case .update: return .update
|
||||||
|
case .refresh: return .refresh
|
||||||
|
case .activate: return .activate
|
||||||
|
case .deactivate: return .deactivate
|
||||||
|
case .backup: return .backup
|
||||||
|
case .restore: return .restore
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
DatabaseManager.shared.persistentContainer.performBackgroundTask { context in
|
||||||
|
var app = operation.app
|
||||||
|
if let managedApp = app as? NSManagedObject, let tempApp = context.object(with: managedApp.objectID) as? AppProtocol
|
||||||
|
{
|
||||||
|
app = tempApp
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
_ = LoggedError(error: sanitizedError, app: app, operation: loggedErrorOperation, context: context)
|
||||||
|
try context.save()
|
||||||
|
}
|
||||||
|
catch let saveError
|
||||||
|
{
|
||||||
|
print("[ALTLog] Failed to log error \(sanitizedError.domain) code \(sanitizedError.code) for \(app.bundleIdentifier):", saveError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func run(_ operations: [Foundation.Operation], context: OperationContext?, requiresSerialQueue: Bool = false)
|
func run(_ operations: [Foundation.Operation], context: OperationContext?, requiresSerialQueue: Bool = false)
|
||||||
{
|
{
|
||||||
// Find "Install AltStore" operation if it already exists in `context`
|
// Find "Install AltStore" operation if it already exists in `context`
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ final class DownloadAppOperation: ResultOperation<ALTApplication>
|
|||||||
|
|
||||||
private let appName: String
|
private let appName: String
|
||||||
private let bundleIdentifier: String
|
private let bundleIdentifier: String
|
||||||
|
private var sourceURL: URL?
|
||||||
private let destinationURL: URL
|
private let destinationURL: URL
|
||||||
|
|
||||||
private let session = URLSession(configuration: .default)
|
private let session = URLSession(configuration: .default)
|
||||||
@@ -32,6 +33,7 @@ final class DownloadAppOperation: ResultOperation<ALTApplication>
|
|||||||
|
|
||||||
self.appName = app.name
|
self.appName = app.name
|
||||||
self.bundleIdentifier = app.bundleIdentifier
|
self.bundleIdentifier = app.bundleIdentifier
|
||||||
|
self.sourceURL = app.url
|
||||||
self.destinationURL = destinationURL
|
self.destinationURL = destinationURL
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
@@ -111,7 +113,7 @@ private extension DownloadAppOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func download(@Managed _ app: AppProtocol) {
|
func download(@Managed _ app: AppProtocol) {
|
||||||
guard let sourceURL = $app.url else { return self.finish(.failure(OperationError.appNotFound(name: self.appName))) }
|
guard let sourceURL = self.sourceURL else { return self.finish(.failure(OperationError.appNotFound(name: self.appName))) }
|
||||||
|
|
||||||
self.downloadIPA(from: sourceURL) { result in
|
self.downloadIPA(from: sourceURL) { result in
|
||||||
do
|
do
|
||||||
|
|||||||
@@ -263,6 +263,10 @@ extension FetchProvisioningProfilesOperation
|
|||||||
{
|
{
|
||||||
throw OperationError.maximumAppIDLimitReached(appName: application.name, requiredAppIDs: requiredAppIDs, availableAppIDs: availableAppIDs, expirationDate: expirationDate)
|
throw OperationError.maximumAppIDLimitReached(appName: application.name, requiredAppIDs: requiredAppIDs, availableAppIDs: availableAppIDs, expirationDate: expirationDate)
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw ALTAppleAPIError(.maximumAppIDLimitReached)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//App ID name must be ascii. If the name is not ascii, using bundleID instead
|
//App ID name must be ascii. If the name is not ascii, using bundleID instead
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ extension OperationError
|
|||||||
static func openAppFailed(name: String?) -> OperationError {
|
static func openAppFailed(name: String?) -> OperationError {
|
||||||
OperationError(code: .openAppFailed, appName: name)
|
OperationError(code: .openAppFailed, appName: name)
|
||||||
}
|
}
|
||||||
|
static let domain = OperationError(code: .unknown)._domain
|
||||||
|
|
||||||
static func SideJITIssue(error: String?) -> OperationError {
|
static func SideJITIssue(error: String?) -> OperationError {
|
||||||
var o = OperationError(code: .SideJITIssue)
|
var o = OperationError(code: .SideJITIssue)
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ final class VerifyAppOperation: ResultOperation<Void>
|
|||||||
{
|
{
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
let appName = self.context.app?.name ?? NSLocalizedString("The app", comment: "")
|
||||||
|
self.localizedFailure = String(format: NSLocalizedString("%@ could not be installed.", comment: ""), appName)
|
||||||
|
|
||||||
guard let app = self.context.app else {
|
guard let app = self.context.app else {
|
||||||
throw OperationError.invalidParameters("VerifyAppOperation.main: self.context.app is nil")
|
throw OperationError.invalidParameters("VerifyAppOperation.main: self.context.app is nil")
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ private extension ErrorLogViewController
|
|||||||
self?.searchFAQ(for: loggedError)
|
self?.searchFAQ(for: loggedError)
|
||||||
},
|
},
|
||||||
UIAction(title: NSLocalizedString("View More Details", comment: ""), image: UIImage(systemName: "ellipsis.circle")) { [weak self] _ in
|
UIAction(title: NSLocalizedString("View More Details", comment: ""), image: UIImage(systemName: "ellipsis.circle")) { [weak self] _ in
|
||||||
|
self?.viewMoreDetails(for: loggedError)
|
||||||
}
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
cell.menuButton.menu = menu
|
cell.menuButton.menu = menu
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ extension PatreonViewController: UICollectionViewDelegateFlowLayout
|
|||||||
switch section
|
switch section
|
||||||
{
|
{
|
||||||
case .about: return .zero
|
case .about: return .zero
|
||||||
case .patrons: return CGSize(width: 0, height: 0)
|
case .patrons: return CGSize(width: 320, height: 44)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,6 +169,31 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
|
|||||||
return self._versions.array as! [AppVersion]
|
return self._versions.array as! [AppVersion]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@nonobjc public var size: Int64? {
|
||||||
|
guard let version = self.latestSupportedVersion else { return nil }
|
||||||
|
return version.size
|
||||||
|
}
|
||||||
|
|
||||||
|
@nonobjc public var version: String? {
|
||||||
|
guard let version = self.latestSupportedVersion else { return nil }
|
||||||
|
return version.version
|
||||||
|
}
|
||||||
|
|
||||||
|
@nonobjc public var versionDescription: String? {
|
||||||
|
guard let version = self.latestSupportedVersion else { return nil }
|
||||||
|
return version.localizedDescription
|
||||||
|
}
|
||||||
|
|
||||||
|
@nonobjc public var versionDate: Date? {
|
||||||
|
guard let version = self.latestSupportedVersion else { return nil }
|
||||||
|
return version.date
|
||||||
|
}
|
||||||
|
|
||||||
|
@nonobjc public var downloadURL: URL? {
|
||||||
|
guard let version = self.latestSupportedVersion else { return nil }
|
||||||
|
return version.downloadURL
|
||||||
|
}
|
||||||
|
|
||||||
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)
|
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)
|
||||||
{
|
{
|
||||||
super.init(entity: entity, insertInto: context)
|
super.init(entity: entity, insertInto: context)
|
||||||
|
|||||||
@@ -15,24 +15,25 @@ private let clientSecret = "Zow0ggt9YgwIyd4DVLoO9Z02KuuIXW44xhx4lfL27x2u-_u4FE4r
|
|||||||
|
|
||||||
private let campaignID = "12794837"
|
private let campaignID = "12794837"
|
||||||
|
|
||||||
extension PatreonAPI
|
typealias PatreonAPIError = PatreonAPIErrorCode.Error
|
||||||
|
enum PatreonAPIErrorCode: Int, ALTErrorEnum, CaseIterable
|
||||||
{
|
{
|
||||||
enum Error: LocalizedError
|
case unknown
|
||||||
{
|
case notAuthenticated
|
||||||
case unknown
|
case invalidAccessToken
|
||||||
case notAuthenticated
|
|
||||||
case invalidAccessToken
|
var errorFailureReason: String {
|
||||||
|
switch self
|
||||||
var errorDescription: String? {
|
{
|
||||||
switch self
|
case .unknown: return NSLocalizedString("An unknown error occurred.", comment: "")
|
||||||
{
|
case .notAuthenticated: return NSLocalizedString("No connected Patreon account.", comment: "")
|
||||||
case .unknown: return NSLocalizedString("An unknown error occurred.", comment: "")
|
case .invalidAccessToken: return NSLocalizedString("Invalid access token.", comment: "")
|
||||||
case .notAuthenticated: return NSLocalizedString("No connected Patreon account.", comment: "")
|
|
||||||
case .invalidAccessToken: return NSLocalizedString("Invalid access token.", comment: "")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PatreonAPI
|
||||||
|
{
|
||||||
enum AuthorizationType
|
enum AuthorizationType
|
||||||
{
|
{
|
||||||
case none
|
case none
|
||||||
@@ -110,7 +111,7 @@ public extension PatreonAPI
|
|||||||
let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false),
|
let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false),
|
||||||
let codeQueryItem = components.queryItems?.first(where: { $0.name == "code" }),
|
let codeQueryItem = components.queryItems?.first(where: { $0.name == "code" }),
|
||||||
let code = codeQueryItem.value
|
let code = codeQueryItem.value
|
||||||
else { throw Error.unknown }
|
else { throw PatreonAPIError(.unknown) }
|
||||||
|
|
||||||
self.fetchAccessToken(oauthCode: code) { (result) in
|
self.fetchAccessToken(oauthCode: code) { (result) in
|
||||||
switch result
|
switch result
|
||||||
@@ -151,9 +152,9 @@ public extension PatreonAPI
|
|||||||
self.send(request, authorizationType: .user) { (result: Result<AccountResponse, Swift.Error>) in
|
self.send(request, authorizationType: .user) { (result: Result<AccountResponse, Swift.Error>) in
|
||||||
switch result
|
switch result
|
||||||
{
|
{
|
||||||
case .failure(Error.notAuthenticated):
|
case .failure(~PatreonAPIErrorCode.notAuthenticated):
|
||||||
self.signOut() { (result) in
|
self.signOut() { (result) in
|
||||||
completion(.failure(Error.notAuthenticated))
|
completion(.failure(PatreonAPIError(.notAuthenticated)))
|
||||||
}
|
}
|
||||||
|
|
||||||
case .failure(let error): completion(.failure(error))
|
case .failure(let error): completion(.failure(error))
|
||||||
@@ -357,11 +358,11 @@ private extension PatreonAPI
|
|||||||
{
|
{
|
||||||
case .none: break
|
case .none: break
|
||||||
case .creator:
|
case .creator:
|
||||||
guard let creatorAccessToken = Keychain.shared.patreonCreatorAccessToken else { return completion(.failure(Error.invalidAccessToken)) }
|
guard let creatorAccessToken = Keychain.shared.patreonCreatorAccessToken else { return completion(.failure(PatreonAPIError(.invalidAccessToken))) }
|
||||||
request.setValue("Bearer " + creatorAccessToken, forHTTPHeaderField: "Authorization")
|
request.setValue("Bearer " + creatorAccessToken, forHTTPHeaderField: "Authorization")
|
||||||
|
|
||||||
case .user:
|
case .user:
|
||||||
guard let accessToken = Keychain.shared.patreonAccessToken else { return completion(.failure(Error.notAuthenticated)) }
|
guard let accessToken = Keychain.shared.patreonAccessToken else { return completion(.failure(PatreonAPIError(.notAuthenticated))) }
|
||||||
request.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")
|
request.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,8 +375,8 @@ private extension PatreonAPI
|
|||||||
{
|
{
|
||||||
switch authorizationType
|
switch authorizationType
|
||||||
{
|
{
|
||||||
case .creator: completion(.failure(Error.invalidAccessToken))
|
case .creator: completion(.failure(PatreonAPIError(.invalidAccessToken)))
|
||||||
case .none: completion(.failure(Error.notAuthenticated))
|
case .none: completion(.failure(PatreonAPIError(.notAuthenticated)))
|
||||||
case .user:
|
case .user:
|
||||||
self.refreshAccessToken() { (result) in
|
self.refreshAccessToken() { (result) in
|
||||||
switch result
|
switch result
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ public extension NSError
|
|||||||
{
|
{
|
||||||
var userInfo = self.userInfo
|
var userInfo = self.userInfo
|
||||||
userInfo[NSLocalizedDescriptionKey] = self.localizedDescription
|
userInfo[NSLocalizedDescriptionKey] = self.localizedDescription
|
||||||
|
userInfo[NSLocalizedFailureErrorKey] = self.localizedFailure
|
||||||
userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedFailureReason
|
userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedFailureReason
|
||||||
userInfo[NSLocalizedRecoverySuggestionErrorKey] = self.localizedRecoverySuggestion
|
userInfo[NSLocalizedRecoverySuggestionErrorKey] = self.localizedRecoverySuggestion
|
||||||
userInfo[NSDebugDescriptionErrorKey] = self.localizedDebugDescription
|
userInfo[NSDebugDescriptionErrorKey] = self.localizedDebugDescription
|
||||||
@@ -124,6 +125,7 @@ public extension NSError
|
|||||||
|
|
||||||
var userInfo = self.userInfo
|
var userInfo = self.userInfo
|
||||||
userInfo[NSDebugDescriptionErrorKey] = self.localizedDebugDescription
|
userInfo[NSDebugDescriptionErrorKey] = self.localizedDebugDescription
|
||||||
|
userInfo[NSLocalizedDescriptionKey] = self.localizedDescription
|
||||||
userInfo[NSLocalizedFailureErrorKey] = self.localizedFailure
|
userInfo[NSLocalizedFailureErrorKey] = self.localizedFailure
|
||||||
userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedFailureReason
|
userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedFailureReason
|
||||||
userInfo[NSLocalizedRecoverySuggestionErrorKey] = self.localizedRecoverySuggestion
|
userInfo[NSLocalizedRecoverySuggestionErrorKey] = self.localizedRecoverySuggestion
|
||||||
|
|||||||
Reference in New Issue
Block a user