diff --git a/Passepartout.xcodeproj/project.pbxproj b/Passepartout.xcodeproj/project.pbxproj index a2553a79..3ba88709 100644 --- a/Passepartout.xcodeproj/project.pbxproj +++ b/Passepartout.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 0EDE56EA2CABE40D0082D21C /* Intents.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0EDE56E62CABE40D0082D21C /* Intents.plist */; }; 0EDE56FA2CABE42E0082D21C /* PassepartoutIntents.appex in Embed ExtensionKit Extensions */ = {isa = PBXBuildFile; fileRef = 0EDE56F02CABE42E0082D21C /* PassepartoutIntents.appex */; platformFilters = (ios, macos, ); settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 0EDE57002CABE4B50082D21C /* IntentsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE56E72CABE40D0082D21C /* IntentsExtension.swift */; }; + 0EE254912CE67946007A96F2 /* LegacyV2 in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE254902CE67946007A96F2 /* LegacyV2 */; }; 0EE8D7E12CD112C200F6600C /* App+tvOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE8D7E02CD112C200F6600C /* App+tvOS.swift */; }; 0EF5FE4D2CE53B1C00EC2CD4 /* PassepartoutImplementations in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF5FE4C2CE53B1C00EC2CD4 /* PassepartoutImplementations */; }; 0EF5FE4F2CE53BCE00EC2CD4 /* LegacyV2 in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF5FE4E2CE53BCE00EC2CD4 /* LegacyV2 */; }; @@ -149,6 +150,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0EE254912CE67946007A96F2 /* LegacyV2 in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -442,7 +444,6 @@ }; 0E3FF4AD2CE3AF6F00BFF640 = { CreatedOnToolsVersion = 15.4; - TestTargetID = 0E06D18E2B87629100176E1D; }; 0E757F0F2CD0CFFC006E13E1 = { CreatedOnToolsVersion = 15.4; @@ -884,26 +885,24 @@ 0E3FF4B52CE3AF6F00BFF640 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; + ALLOW_TARGET_PLATFORM_SPECIALIZATION = NO; ENABLE_USER_SCRIPT_SANDBOXING = YES; PRODUCT_BUNDLE_IDENTIFIER = com.algoritmico.ios.PassepartoutTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Passepartout.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Passepartout"; }; name = Debug; }; 0E3FF4B62CE3AF6F00BFF640 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; + ALLOW_TARGET_PLATFORM_SPECIALIZATION = NO; ENABLE_USER_SCRIPT_SANDBOXING = YES; PRODUCT_BUNDLE_IDENTIFIER = com.algoritmico.ios.PassepartoutTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Passepartout.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Passepartout"; }; name = Release; }; @@ -1148,6 +1147,10 @@ isa = XCSwiftPackageProductDependency; productName = TunnelLibrary; }; + 0EE254902CE67946007A96F2 /* LegacyV2 */ = { + isa = XCSwiftPackageProductDependency; + productName = LegacyV2; + }; 0EF5FE4C2CE53B1C00EC2CD4 /* PassepartoutImplementations */ = { isa = XCSwiftPackageProductDependency; productName = PassepartoutImplementations; diff --git a/Passepartout/Library/Sources/CommonUtils/Extensions/Bundle+Extensions.swift b/Passepartout/Library/Sources/CommonUtils/Extensions/Bundle+Extensions.swift new file mode 100644 index 00000000..071c14a8 --- /dev/null +++ b/Passepartout/Library/Sources/CommonUtils/Extensions/Bundle+Extensions.swift @@ -0,0 +1,34 @@ +// +// Bundle+Extensions.swift +// Passepartout +// +// Created by Davide De Rosa on 11/14/24. +// Copyright (c) 2024 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation + +extension Bundle { + public var appStoreProductionReceiptURL: URL? { + appStoreReceiptURL? + .deletingLastPathComponent() + .appendingPathComponent("receipt") // could be "sandboxReceipt" + } +} diff --git a/Passepartout/Library/Sources/UILibrary/Business/AppContext.swift b/Passepartout/Library/Sources/UILibrary/Business/AppContext.swift index b0e307c9..dab28ec1 100644 --- a/Passepartout/Library/Sources/UILibrary/Business/AppContext.swift +++ b/Passepartout/Library/Sources/UILibrary/Business/AppContext.swift @@ -115,6 +115,18 @@ private extension AppContext { } .store(in: &subscriptions) + // copy release receipt to tunnel for TestFlight eligibility (once is enough, it won't change) + if let appReceiptURL = Bundle.main.appStoreProductionReceiptURL { + let tunnelReceiptURL = BundleConfiguration.urlForAppGroupReceipt + do { + pp_log(.App.iap, .info, "Copy release receipt to tunnel...") + try? FileManager.default.removeItem(at: tunnelReceiptURL) + try FileManager.default.copyItem(at: appReceiptURL, to: tunnelReceiptURL) + } catch { + pp_log(.App.iap, .error, "Unable to copy release receipt to tunnel: \(error)") + } + } + do { pp_log(.app, .notice, "Fetch providers index...") try await providerManager.fetchIndex(from: API.shared) @@ -137,6 +149,7 @@ private extension AppContext { } catch { pp_log(.App.profiles, .error, "Unable to re-observe local profiles: \(error)") } + await iapManager.reloadReceipt() } await pendingTask?.value diff --git a/Passepartout/Shared/Shared+App.swift b/Passepartout/Shared/Shared+App.swift index 1c39ad02..31c5328b 100644 --- a/Passepartout/Shared/Shared+App.swift +++ b/Passepartout/Shared/Shared+App.swift @@ -50,17 +50,6 @@ extension IAPManager { willConnect: { iap, profile in var builder = profile.builder() - // copy app receipt URL to tunnel for beta eligibility - if let appReceiptURL = Bundle.main.appStoreReceiptURL { - let tunnelReceiptURL = BundleConfiguration.urlForAppGroupReceipt - do { - try FileManager.default.removeItem(at: tunnelReceiptURL) - try FileManager.default.copyItem(at: appReceiptURL, to: tunnelReceiptURL) - } catch { - pp_log(.App.iap, .error, "Unable to copy receipt URL to tunnel: \(error)") - } - } - // ineligible, suppress on-demand rules if !iap.isEligible(for: .onDemand) { pp_log(.App.iap, .notice, "Ineligible, suppress on-demand rules")