From 465be339fdd2a37b94228aa4353d5e7aee1a0d44 Mon Sep 17 00:00:00 2001 From: Riley Testut Date: Thu, 11 May 2023 18:17:26 -0500 Subject: [PATCH] =?UTF-8?q?Verifies=20source=E2=80=99s=20identifier=20does?= =?UTF-8?q?n=E2=80=99t=20change=20after=20refreshing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AltStore/Managing Apps/AppManager.swift | 2 +- .../Operations/FetchSourceOperation.swift | 44 ++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/AltStore/Managing Apps/AppManager.swift b/AltStore/Managing Apps/AppManager.swift index c998cb7e..c9288020 100644 --- a/AltStore/Managing Apps/AppManager.swift +++ b/AltStore/Managing Apps/AppManager.swift @@ -428,7 +428,7 @@ extension AppManager let operations = sources.map { (source) -> FetchSourceOperation in dispatchGroup.enter() - let fetchSourceOperation = FetchSourceOperation(sourceURL: source.sourceURL, managedObjectContext: managedObjectContext) + let fetchSourceOperation = FetchSourceOperation(source: source, managedObjectContext: managedObjectContext) fetchSourceOperation.resultHandler = { (result) in switch result { diff --git a/AltStore/Operations/FetchSourceOperation.swift b/AltStore/Operations/FetchSourceOperation.swift index db432915..e87eeb81 100644 --- a/AltStore/Operations/FetchSourceOperation.swift +++ b/AltStore/Operations/FetchSourceOperation.swift @@ -21,11 +21,15 @@ extension SourceError case unsupported case duplicateBundleID case duplicateVersion + + case changedID } static func unsupported(_ source: Source) -> SourceError { SourceError(code: .unsupported, source: source) } static func duplicateBundleID(_ bundleID: String, source: Source) -> SourceError { SourceError(code: .duplicateBundleID, source: source, bundleID: bundleID) } static func duplicateVersion(_ version: String, for app: StoreApp, source: Source) -> SourceError { SourceError(code: .duplicateVersion, source: source, app: app, version: version) } + + static func changedID(_ identifier: String, previousID: String, source: Source) -> SourceError { SourceError(code: .changedID, source: source, sourceID: identifier, previousSourceID: previousID) } } struct SourceError: ALTLocalizedError @@ -39,6 +43,10 @@ struct SourceError: ALTLocalizedError var bundleID: String? var version: String? + // Store in userInfo so they can be viewed from Error Log. + @UserInfoValue var sourceID: String? + @UserInfoValue var previousSourceID: String? + var errorFailureReason: String { switch self.code { @@ -67,6 +75,18 @@ struct SourceError: ALTLocalizedError let failureReason = String(format: NSLocalizedString("The source “%@” contains %@ for %@.", comment: ""), self.$source.name, versionFragment, appFragment) return failureReason + + case .changedID: + let failureReason = String(format: NSLocalizedString("The identifier of the source “%@” has changed.", comment: ""), self.$source.name) + return failureReason + } + } + + var recoverySuggestion: String? { + switch self.code + { + case .changedID: return NSLocalizedString("A source cannot change its identifier once added. This source can no longer be updated.", comment: "") + default: return nil } } } @@ -77,6 +97,10 @@ class FetchSourceOperation: ResultOperation let sourceURL: URL let managedObjectContext: NSManagedObjectContext + // Non-nil when updating an existing source. + @Managed + private var source: Source? + private let session: URLSession private lazy var dateFormatter: ISO8601DateFormatter = { @@ -84,10 +108,23 @@ class FetchSourceOperation: ResultOperation return dateFormatter }() - init(sourceURL: URL, managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext()) + // New source + convenience init(sourceURL: URL, managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext()) + { + self.init(sourceURL: sourceURL, source: nil, managedObjectContext: managedObjectContext) + } + + // Existing source + convenience init(source: Source, managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext()) + { + self.init(sourceURL: source.sourceURL, source: source, managedObjectContext: managedObjectContext) + } + + private init(sourceURL: URL, source: Source?, managedObjectContext: NSManagedObjectContext) { self.sourceURL = sourceURL self.managedObjectContext = managedObjectContext + self.source = source let configuration = URLSessionConfiguration.default configuration.requestCachePolicy = .reloadIgnoringLocalCacheData @@ -191,5 +228,10 @@ private extension FetchSourceOperation versions.insert(version.version) } } + + if let previousSourceID = self.$source.identifier + { + guard source.identifier == previousSourceID else { throw SourceError.changedID(source.identifier, previousID: previousSourceID, source: source) } + } } }