mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-08 22:33:26 +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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -1021,6 +1022,7 @@
|
||||
B33FFB8F295F8CF2002259E6 /* Recovered References */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D540E93728EE1BDE000F1B0F /* ErrorDetailsViewController.swift */,
|
||||
);
|
||||
name = "Recovered References";
|
||||
sourceTree = "<group>";
|
||||
|
||||
@@ -1957,7 +1957,43 @@ private extension AppManager
|
||||
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)
|
||||
{
|
||||
// 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 bundleIdentifier: String
|
||||
private var sourceURL: URL?
|
||||
private let destinationURL: URL
|
||||
|
||||
private let session = URLSession(configuration: .default)
|
||||
@@ -32,6 +33,7 @@ final class DownloadAppOperation: ResultOperation<ALTApplication>
|
||||
|
||||
self.appName = app.name
|
||||
self.bundleIdentifier = app.bundleIdentifier
|
||||
self.sourceURL = app.url
|
||||
self.destinationURL = destinationURL
|
||||
|
||||
super.init()
|
||||
@@ -111,7 +113,7 @@ private extension DownloadAppOperation {
|
||||
}
|
||||
|
||||
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
|
||||
do
|
||||
|
||||
@@ -263,6 +263,10 @@ extension FetchProvisioningProfilesOperation
|
||||
{
|
||||
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
|
||||
|
||||
@@ -78,6 +78,7 @@ extension OperationError
|
||||
static func openAppFailed(name: String?) -> OperationError {
|
||||
OperationError(code: .openAppFailed, appName: name)
|
||||
}
|
||||
static let domain = OperationError(code: .unknown)._domain
|
||||
|
||||
static func SideJITIssue(error: String?) -> OperationError {
|
||||
var o = OperationError(code: .SideJITIssue)
|
||||
|
||||
@@ -116,6 +116,8 @@ final class VerifyAppOperation: ResultOperation<Void>
|
||||
{
|
||||
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 {
|
||||
throw OperationError.invalidParameters("VerifyAppOperation.main: self.context.app is nil")
|
||||
|
||||
@@ -105,8 +105,8 @@ private extension ErrorLogViewController
|
||||
self?.searchFAQ(for: loggedError)
|
||||
},
|
||||
UIAction(title: NSLocalizedString("View More Details", comment: ""), image: UIImage(systemName: "ellipsis.circle")) { [weak self] _ in
|
||||
|
||||
}
|
||||
self?.viewMoreDetails(for: loggedError)
|
||||
},
|
||||
])
|
||||
|
||||
cell.menuButton.menu = menu
|
||||
|
||||
@@ -348,7 +348,7 @@ extension PatreonViewController: UICollectionViewDelegateFlowLayout
|
||||
switch section
|
||||
{
|
||||
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]
|
||||
}
|
||||
|
||||
@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?)
|
||||
{
|
||||
super.init(entity: entity, insertInto: context)
|
||||
|
||||
@@ -15,24 +15,25 @@ private let clientSecret = "Zow0ggt9YgwIyd4DVLoO9Z02KuuIXW44xhx4lfL27x2u-_u4FE4r
|
||||
|
||||
private let campaignID = "12794837"
|
||||
|
||||
extension PatreonAPI
|
||||
typealias PatreonAPIError = PatreonAPIErrorCode.Error
|
||||
enum PatreonAPIErrorCode: Int, ALTErrorEnum, CaseIterable
|
||||
{
|
||||
enum Error: LocalizedError
|
||||
{
|
||||
case unknown
|
||||
case notAuthenticated
|
||||
case invalidAccessToken
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self
|
||||
{
|
||||
case .unknown: return NSLocalizedString("An unknown error occurred.", comment: "")
|
||||
case .notAuthenticated: return NSLocalizedString("No connected Patreon account.", comment: "")
|
||||
case .invalidAccessToken: return NSLocalizedString("Invalid access token.", comment: "")
|
||||
}
|
||||
case unknown
|
||||
case notAuthenticated
|
||||
case invalidAccessToken
|
||||
|
||||
var errorFailureReason: String {
|
||||
switch self
|
||||
{
|
||||
case .unknown: return NSLocalizedString("An unknown error occurred.", comment: "")
|
||||
case .notAuthenticated: return NSLocalizedString("No connected Patreon account.", comment: "")
|
||||
case .invalidAccessToken: return NSLocalizedString("Invalid access token.", comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension PatreonAPI
|
||||
{
|
||||
enum AuthorizationType
|
||||
{
|
||||
case none
|
||||
@@ -110,7 +111,7 @@ public extension PatreonAPI
|
||||
let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false),
|
||||
let codeQueryItem = components.queryItems?.first(where: { $0.name == "code" }),
|
||||
let code = codeQueryItem.value
|
||||
else { throw Error.unknown }
|
||||
else { throw PatreonAPIError(.unknown) }
|
||||
|
||||
self.fetchAccessToken(oauthCode: code) { (result) in
|
||||
switch result
|
||||
@@ -151,9 +152,9 @@ public extension PatreonAPI
|
||||
self.send(request, authorizationType: .user) { (result: Result<AccountResponse, Swift.Error>) in
|
||||
switch result
|
||||
{
|
||||
case .failure(Error.notAuthenticated):
|
||||
case .failure(~PatreonAPIErrorCode.notAuthenticated):
|
||||
self.signOut() { (result) in
|
||||
completion(.failure(Error.notAuthenticated))
|
||||
completion(.failure(PatreonAPIError(.notAuthenticated)))
|
||||
}
|
||||
|
||||
case .failure(let error): completion(.failure(error))
|
||||
@@ -357,11 +358,11 @@ private extension PatreonAPI
|
||||
{
|
||||
case .none: break
|
||||
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")
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -374,8 +375,8 @@ private extension PatreonAPI
|
||||
{
|
||||
switch authorizationType
|
||||
{
|
||||
case .creator: completion(.failure(Error.invalidAccessToken))
|
||||
case .none: completion(.failure(Error.notAuthenticated))
|
||||
case .creator: completion(.failure(PatreonAPIError(.invalidAccessToken)))
|
||||
case .none: completion(.failure(PatreonAPIError(.notAuthenticated)))
|
||||
case .user:
|
||||
self.refreshAccessToken() { (result) in
|
||||
switch result
|
||||
|
||||
@@ -73,6 +73,7 @@ public extension NSError
|
||||
{
|
||||
var userInfo = self.userInfo
|
||||
userInfo[NSLocalizedDescriptionKey] = self.localizedDescription
|
||||
userInfo[NSLocalizedFailureErrorKey] = self.localizedFailure
|
||||
userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedFailureReason
|
||||
userInfo[NSLocalizedRecoverySuggestionErrorKey] = self.localizedRecoverySuggestion
|
||||
userInfo[NSDebugDescriptionErrorKey] = self.localizedDebugDescription
|
||||
@@ -124,6 +125,7 @@ public extension NSError
|
||||
|
||||
var userInfo = self.userInfo
|
||||
userInfo[NSDebugDescriptionErrorKey] = self.localizedDebugDescription
|
||||
userInfo[NSLocalizedDescriptionKey] = self.localizedDescription
|
||||
userInfo[NSLocalizedFailureErrorKey] = self.localizedFailure
|
||||
userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedFailureReason
|
||||
userInfo[NSLocalizedRecoverySuggestionErrorKey] = self.localizedRecoverySuggestion
|
||||
|
||||
Reference in New Issue
Block a user