merge AltStore 1.6.3, add dynamic anisette lists, merge SideJITServer integration

* Change error from Swift.Error to NSError

* Adds ResultOperation.localizedFailure

* Finish Riley's monster commit

3b38d725d7
May the Gods have mercy on my soul.

* Fix format strings I broke

* Include "Enable JIT" errors in Error Log

* Fix minimuxer status checking

* [skip ci] Update the no wifi message to include VPN

* Opens Error Log when tapping ToastView

* Fixes Error Log context menu covering cell content

* Fixes Error Log context menu appearing while scrolling

* Fixes incorrect Search FAQ URL

* Fix Error Log showing UIAlertController on iOS 14+

* Fix Error Log not showing UIAlertController on iOS <=13

* Fix wrong color in AuthenticationViewController

* Fix typo

* Fixes logging non-AltServerErrors as AltServerError.underlyingError

* Limits quitting other AltStore/SideStore processes to database migrations

* Skips logging cancelled errors

* Replaces StoreApp.latestVersion with latestSupportedVersion + latestAvailableVersion

We now store the latest supported version as a relationship on StoreApp, rather than the latest available version. This allows us to reference the latest supported version in predicates and sort descriptors.

However, we kept the underlying Core Data property name the same to avoid extra migration.

* Conforms OperatingSystemVersion to Comparable

* Parses AppVersion.minOSVersion/maxOSVersion from source JSON

* Supports non-NSManagedObjects for @Managed properties

This allows us to use @Managed with properties that may or may not be NSManagedObjects at runtime (e.g. protocols). If they are, Managed will keep strong reference to context like before.

* Supports optional @Managed properties

* Conforms AppVersion to AppProtocol

* Verifies min/max OS version before downloading app + asks user to download older app version if necessary

* Improves error message when file does not exist at AppVersion.downloadURL

* Removes unnecessary StoreApp convenience properties

* Removes unnecessary StoreApp convenience properties as well as fix other issues

* Remove Settings bundle, add SwiftUI view instead

Fix refresh all shortcut intent

* Update AuthenticationOperation.swift

Signed-off-by: June Park <rjp2030@outlook.com>

* Fix build issues given by develop

* Add availability check to fix CI build(?)

* If it's gonna be that way...

---------

Signed-off-by: June Park <rjp2030@outlook.com>
Co-authored-by: nythepegasus <nythepegasus84@gmail.com>
Co-authored-by: Riley Testut <riley@rileytestut.com>
Co-authored-by: ny <me@nythepegas.us>
This commit is contained in:
June Park
2024-08-06 10:43:52 +09:00
committed by GitHub
parent 83ece72ae1
commit 1713fccfc4
60 changed files with 2170 additions and 1067 deletions

View File

@@ -8,81 +8,186 @@
import Foundation
import AltSign
import AltStoreCore
import minimuxer
enum OperationError: LocalizedError
extension OperationError
{
static let domain = OperationError.unknown._domain
enum Code: Int, ALTErrorCode, CaseIterable {
typealias Error = OperationError
// General
case unknown = 1000
case unknownResult
case cancelled
case timedOut
case unableToConnectSideJIT
case unableToRespondSideJITDevice
case wrongSideJITIP
case SideJITIssue // (error: String)
case refreshsidejit
case notAuthenticated
case appNotFound
case unknownUDID
case invalidApp
case invalidParameters
case maximumAppIDLimitReached//((application: ALTApplication, requiredAppIDs: Int, availableAppIDs: Int, nextExpirationDate: Date)
case noSources
case openAppFailed//(name: String)
case missingAppGroup
// Connection
case noWiFi = 1200
case tooNewError
case anisetteV1Error//(message: String)
case provisioningError//(result: String, message: String?)
case anisetteV3Error//(message: String)
case cacheClearError//(errors: [String])
}
static let unknownResult: OperationError = .init(code: .unknownResult)
static let cancelled: OperationError = .init(code: .cancelled)
static let timedOut: OperationError = .init(code: .timedOut)
static let unableToConnectSideJIT: OperationError = .init(code: .unableToConnectSideJIT)
static let unableToRespondSideJITDevice: OperationError = .init(code: .unableToRespondSideJITDevice)
static let wrongSideJITIP: OperationError = .init(code: .wrongSideJITIP)
static let notAuthenticated: OperationError = .init(code: .notAuthenticated)
static let unknownUDID: OperationError = .init(code: .unknownUDID)
static let invalidApp: OperationError = .init(code: .invalidApp)
static let invalidParameters: OperationError = .init(code: .invalidParameters)
static let noSources: OperationError = .init(code: .noSources)
static let missingAppGroup: OperationError = .init(code: .missingAppGroup)
static let noWiFi: OperationError = .init(code: .noWiFi)
static let tooNewError: OperationError = .init(code: .tooNewError)
static let provisioningError: OperationError = .init(code: .provisioningError)
static let anisetteV1Error: OperationError = .init(code: .anisetteV1Error)
static let anisetteV3Error: OperationError = .init(code: .anisetteV3Error)
static let cacheClearError: OperationError = .init(code: .cacheClearError)
static func unknown(failureReason: String? = nil, file: String = #fileID, line: UInt = #line) -> OperationError {
OperationError(code: .unknown, failureReason: failureReason, sourceFile: file, sourceLine: line)
}
static func appNotFound(name: String?) -> OperationError {
OperationError(code: .appNotFound, appName: name)
}
static func openAppFailed(name: String?) -> OperationError {
OperationError(code: .openAppFailed, appName: name)
}
case unknown
case unabletoconnectSideJIT
case unabletoconSideJITDevice
case wrongIP
case SideJITIssue(error: String)
case refreshsidejit
case unknownResult
case cancelled
case timedOut
static func SideJITIssue(error: String?) -> OperationError {
var o = OperationError(code: .SideJITIssue)
o.errorFailure = error
return o
}
case notAuthenticated
case appNotFound
case unknownUDID
case invalidApp
case invalidParameters
case maximumAppIDLimitReached(application: ALTApplication, requiredAppIDs: Int, availableAppIDs: Int, nextExpirationDate: Date)
case noSources
case openAppFailed(name: String)
case missingAppGroup
case noWiFi
case tooNewError
case anisetteV1Error(message: String)
case provisioningError(result: String, message: String?)
case anisetteV3Error(message: String)
case cacheClearError(errors: [String])
var failureReason: String? {
switch self {
case .unknown: return NSLocalizedString("An unknown error occured.", comment: "")
static func maximumAppIDLimitReached(appName: String, requiredAppIDs: Int, availableAppIDs: Int, expirationDate: Date) -> OperationError {
OperationError(code: .maximumAppIDLimitReached, appName: appName, requiredAppIDs: requiredAppIDs, availableAppIDs: availableAppIDs, expirationDate: expirationDate)
}
static func provisioningError(result: String, message: String?) -> OperationError {
var o = OperationError(code: .provisioningError, failureReason: result)
o.errorTitle = message
return o
}
static func cacheClearError(errors: [String]) -> OperationError {
OperationError(code: .cacheClearError, failureReason: errors.joined(separator: "\n"))
}
static func anisetteV1Error(message: String) -> OperationError {
OperationError(code: .anisetteV1Error, failureReason: message)
}
static func anisetteV3Error(message: String) -> OperationError {
OperationError(code: .anisetteV3Error, failureReason: message)
}
}
struct OperationError: ALTLocalizedError {
let code: Code
var errorTitle: String?
var errorFailure: String?
var appName: String?
var requiredAppIDs: Int?
var availableAppIDs: Int?
var expirationDate: Date?
var sourceFile: String?
var sourceLine: UInt?
private var _failureReason: String?
private init(code: Code, failureReason: String? = nil,
appName: String? = nil, requiredAppIDs: Int? = nil, availableAppIDs: Int? = nil,
expirationDate: Date? = nil, sourceFile: String? = nil, sourceLine: UInt? = nil){
self.code = code
self._failureReason = failureReason
self.appName = appName
self.requiredAppIDs = requiredAppIDs
self.availableAppIDs = availableAppIDs
self.expirationDate = expirationDate
self.sourceFile = sourceFile
self.sourceLine = sourceLine
}
var errorFailureReason: String {
switch self.code {
case .unknown:
var failureReason = self._failureReason ?? NSLocalizedString("An unknown error occurred.", comment: "")
guard let sourceFile, let sourceLine else { return failureReason }
failureReason += " (\(sourceFile) line \(sourceLine)"
return failureReason
case .unknownResult: return NSLocalizedString("The operation returned an unknown result.", comment: "")
case .cancelled: return NSLocalizedString("The operation was cancelled.", comment: "")
case .timedOut: return NSLocalizedString("The operation timed out.", comment: "")
case .notAuthenticated: return NSLocalizedString("You are not signed in.", comment: "")
case .appNotFound: return NSLocalizedString("App not found.", comment: "")
case .unknownUDID: return NSLocalizedString("Unknown device UDID.", comment: "")
case .invalidApp: return NSLocalizedString("The app is invalid.", comment: "")
case .unknownUDID: return NSLocalizedString("SideStore could not determine this device's UDID.", comment: "")
case .invalidApp: return NSLocalizedString("The app is in an invalid format.", comment: "")
case .invalidParameters: return NSLocalizedString("Invalid parameters.", comment: "")
case .maximumAppIDLimitReached: return NSLocalizedString("Cannot register more than 10 App IDs within a 7 day period.", comment: "")
case .noSources: return NSLocalizedString("There are no SideStore sources.", comment: "")
case .openAppFailed(let name): return String(format: NSLocalizedString("SideStore was denied permission to launch %@.", comment: ""), name)
case .missingAppGroup: return NSLocalizedString("SideStore's shared app group could not be found.", comment: "")
case .maximumAppIDLimitReached: return NSLocalizedString("Cannot register more than 10 App IDs.", comment: "")
case .noWiFi: return NSLocalizedString("You do not appear to be connected to WiFi!\nSideStore will never be able to install or refresh applications without WiFi.", comment: "")
case .unabletoconnectSideJIT: return NSLocalizedString("Unable to connect to SideJITServer Please check that you are on the Same Wi-Fi and your Firewall has been set correctly", comment: "")
case .unabletoconSideJITDevice: return NSLocalizedString("SideJITServer is unable to connect to your iDevice Please make sure you have paired your Device by doing 'SideJITServer -y' or try Refreshing SideJITServer from Settings", comment: "")
case .wrongIP: return NSLocalizedString("Incorrect SideJITServer IP Please make sure that you are on the Samw Wifi as SideJITServer", comment: "")
case .missingAppGroup: return NSLocalizedString("SideStore's shared app group could not be accessed.", comment: "")
case .appNotFound:
let appName = self.appName ?? NSLocalizedString("The app", comment: "")
return String(format: NSLocalizedString("%@ could not be found.", comment: ""), appName)
case .openAppFailed:
let appName = self.appName ?? NSLocalizedString("The app", comment: "")
return String(format: NSLocalizedString("SideStore was denied permission to launch %@.", comment: ""), appName)
case .noWiFi: return NSLocalizedString("You do not appear to be connected to WiFi and/or the WireGuard VPN!\nSideStore will never be able to install or refresh applications without WiFi and the WireGuard VPN.", comment: "")
case .tooNewError: return NSLocalizedString("iOS 17 has changed how JIT is enabled therefore SideStore cannot enable it at this time, sorry for any inconvenience.\nWe will let everyone know once we have a solution!", comment: "")
case .unableToConnectSideJIT: return NSLocalizedString("Unable to connect to SideJITServer Please check that you are on the Same Wi-Fi and your Firewall has been set correctly", comment: "")
case .unableToRespondSideJITDevice: return NSLocalizedString("SideJITServer is unable to connect to your iDevice Please make sure you have paired your Device by doing 'SideJITServer -y' or try Refreshing SideJITServer from Settings", comment: "")
case .wrongSideJITIP: return NSLocalizedString("Incorrect SideJITServer IP Please make sure that you are on the Samw Wifi as SideJITServer", comment: "")
case .refreshsidejit: return NSLocalizedString("Unable to find App Please try Refreshing SideJITServer from Settings", comment: "")
case .tooNewError: return NSLocalizedString("iOS 17 has changed how JIT is enabled therefore SideStore cannot enable it without the use of SideJITServer at this time, sorry for any inconvenience.\nWe will let everyone know once we have a solution!", comment: "")
case .anisetteV1Error(let message): return String(format: NSLocalizedString("An error occurred when getting anisette data from a V1 server: %@. Try using another anisette server.", comment: ""), message)
case .provisioningError(let result, let message): return String(format: NSLocalizedString("An error occurred when provisioning: %@%@. Please try again. If the issue persists, report it on GitHub Issues!", comment: ""), result, message != nil ? (" (" + message! + ")") : "")
case .anisetteV3Error(let message): return String(format: NSLocalizedString("An error occurred when getting anisette data from a V3 server: %@. Please try again. If the issue persists, report it on GitHub Issues!", comment: ""), message)
case .cacheClearError(let errors): return String(format: NSLocalizedString("An error occurred while clearing cache: %@", comment: ""), errors.joined(separator: "\n"))
case .SideJITIssue(let errors): return NSLocalizedString("SideJITServer Error: \(errors)", comment: "")
case .anisetteV1Error: return NSLocalizedString("An error occurred when getting anisette data from a V1 server: %@. Try using another anisette server.", comment: "")
case .provisioningError: return NSLocalizedString("An error occurred when provisioning: %@ %@. Please try again. If the issue persists, report it on GitHub Issues!", comment: "")
case .anisetteV3Error: return NSLocalizedString("An error occurred when getting anisette data from a V3 server: %@. Please try again. If the issue persists, report it on GitHub Issues!", comment: "")
case .cacheClearError: return NSLocalizedString("An error occurred while clearing cache: %@", comment: "")
case .SideJITIssue: return NSLocalizedString("An error occurred while using SideJIT: %@", comment: "")
}
}
var recoverySuggestion: String? {
switch self
switch self.code
{
case .maximumAppIDLimitReached(let application, let requiredAppIDs, let availableAppIDs, let date):
case .noWiFi: return NSLocalizedString("Make sure the VPN is toggled on and you are connected to any WiFi network!", comment: "")
case .maximumAppIDLimitReached:
let baseMessage = NSLocalizedString("Delete sideloaded apps to free up App ID slots.", comment: "")
let message: String
guard let appName, let requiredAppIDs, let availableAppIDs, let expirationDate else { return baseMessage }
var message: String
if requiredAppIDs > 1
{
let availableText: String
@@ -94,23 +199,23 @@ enum OperationError: LocalizedError
default: availableText = String(format: NSLocalizedString("only %@ are available", comment: ""), NSNumber(value: availableAppIDs))
}
let prefixMessage = String(format: NSLocalizedString("%@ requires %@ App IDs, but %@.", comment: ""), application.name, NSNumber(value: requiredAppIDs), availableText)
message = prefixMessage + " " + baseMessage
let prefixMessage = String(format: NSLocalizedString("%@ requires %@ App IDs, but %@.", comment: ""), appName, NSNumber(value: requiredAppIDs), availableText)
message = prefixMessage + " " + baseMessage + "\n\n"
}
else
{
let dateComponents = Calendar.current.dateComponents([.day, .hour, .minute], from: Date(), to: date)
let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.maximumUnitCount = 1
dateComponentsFormatter.unitsStyle = .full
let remainingTime = dateComponentsFormatter.string(from: dateComponents)!
let remainingTimeMessage = String(format: NSLocalizedString("You can register another App ID in %@.", comment: ""), remainingTime)
message = baseMessage + " " + remainingTimeMessage
message = baseMessage + " "
}
let dateComponents = Calendar.current.dateComponents([.day, .hour, .minute], from: Date(), to: expirationDate)
let dateFormatter = DateComponentsFormatter()
dateFormatter.maximumUnitCount = 1
dateFormatter.unitsStyle = .full
let remainingTime = dateFormatter.string(from: dateComponents)!
message += String(format: NSLocalizedString("You can register another App ID in %@.", comment: ""), remainingTime)
return message
default: return nil