From 881091595c3b347eb7cac1a7860571c7f67da742 Mon Sep 17 00:00:00 2001 From: Riley Testut Date: Wed, 23 Nov 2022 19:14:20 -0600 Subject: [PATCH] =?UTF-8?q?Verifies=20Sources=20don=E2=80=99t=20contain=20?= =?UTF-8?q?duplicate=20app=20versions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Operations/FetchSourceOperation.swift | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/AltStore/Operations/FetchSourceOperation.swift b/AltStore/Operations/FetchSourceOperation.swift index 49611ac1..f9a3107e 100644 --- a/AltStore/Operations/FetchSourceOperation.swift +++ b/AltStore/Operations/FetchSourceOperation.swift @@ -20,29 +20,53 @@ extension SourceError case unsupported case duplicateBundleID + case duplicateVersion } static func unsupported(_ source: Source) -> SourceError { SourceError(code: .unsupported, source: source) } - static func duplicateBundleID(_ bundleID: String, source: Source) -> SourceError { SourceError(code: .duplicateBundleID, source: source, duplicateBundleID: bundleID) } + 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) } } struct SourceError: ALTLocalizedError { - var code: Code + let code: Code var errorTitle: String? var errorFailure: String? @Managed var source: Source - var duplicateBundleID: String? + @Managed var app: StoreApp? + var bundleID: String? + var version: String? var errorFailureReason: String { switch self.code { case .unsupported: return String(format: NSLocalizedString("The source “%@” is not supported by this version of AltStore.", comment: ""), self.$source.name) case .duplicateBundleID: - let bundleIDFragment = self.duplicateBundleID.map { String(format: NSLocalizedString("the bundle identifier %@", comment: ""), $0) } ?? NSLocalizedString("the same bundle identifier", comment: "") + let bundleIDFragment = self.bundleID.map { String(format: NSLocalizedString("the bundle identifier %@", comment: ""), $0) } ?? NSLocalizedString("the same bundle identifier", comment: "") let failureReason = String(format: NSLocalizedString("The source “%@” contains multiple apps with %@.", comment: ""), self.$source.name, bundleIDFragment) return failureReason + + case .duplicateVersion: + var versionFragment = NSLocalizedString("duplicate versions", comment: "") + if let version + { + versionFragment += " (\(version))" + } + + let appFragment: String + if let name = self.$app.name, let bundleID = self.$app.bundleIdentifier + { + appFragment = name + " (\(bundleID))" + } + else + { + appFragment = NSLocalizedString("one or more apps", comment: "") + } + + let failureReason = String(format: NSLocalizedString("The source “%@” contains %@ for %@.", comment: ""), self.$source.name, versionFragment, appFragment) + return failureReason } } } @@ -159,6 +183,13 @@ private extension FetchSourceOperation { guard !bundleIDs.contains(app.bundleIdentifier) else { throw SourceError.duplicateBundleID(app.bundleIdentifier, source: source) } bundleIDs.insert(app.bundleIdentifier) + + var versions = Set() + for version in app.versions + { + guard !versions.contains(version.version) else { throw SourceError.duplicateVersion(version.version, for: app, source: source) } + versions.insert(version.version) + } } } }