restore changes dropped from altstore by 1713fcc

This commit is contained in:
Magesh K
2024-11-10 02:54:18 +05:30
parent 117412645b
commit 3682b65a4a
12 changed files with 150 additions and 27 deletions

View 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
}
}

View File

@@ -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>";

View File

@@ -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`

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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")

View File

@@ -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

View File

@@ -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)
}
}
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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