Move ProductManager to Core
This commit is contained in:
parent
a6f59f72bb
commit
1213212332
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// AppConstants+Flags.swift
|
// AppConstants+App.swift
|
||||||
// Passepartout-iOS
|
// Passepartout-iOS
|
||||||
//
|
//
|
||||||
// Created by Davide De Rosa on 11/2/19.
|
// Created by Davide De Rosa on 11/2/19.
|
||||||
|
@ -31,24 +31,16 @@ extension AppConstants {
|
||||||
static let eventCount = 3
|
static let eventCount = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Flags {
|
struct InApp {
|
||||||
static var isBeta: Bool {
|
|
||||||
#if targetEnvironment(simulator)
|
|
||||||
return true
|
|
||||||
#else
|
|
||||||
return Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static var isBetaFullVersion: Bool {
|
static var isBetaFullVersion: Bool {
|
||||||
guard !ProcessInfo.processInfo.arguments.contains("FULL_VERSION") else {
|
guard !ProcessInfo.processInfo.arguments.contains("FULL_VERSION") else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
struct InApp {
|
static let lastFullVersionBuild = 2016
|
||||||
public static let limitedNumberOfHosts = 2
|
|
||||||
|
static let limitedNumberOfHosts = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,6 +24,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import PassepartoutCore
|
||||||
|
|
||||||
extension UIView {
|
extension UIView {
|
||||||
static func get<T: UIView>() -> T {
|
static func get<T: UIView>() -> T {
|
||||||
|
|
|
@ -1,148 +0,0 @@
|
||||||
//
|
|
||||||
// Product.swift
|
|
||||||
// Passepartout-iOS
|
|
||||||
//
|
|
||||||
// Created by Davide De Rosa on 10/11/19.
|
|
||||||
// Copyright (c) 2020 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 <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import StoreKit
|
|
||||||
import PassepartoutCore
|
|
||||||
|
|
||||||
struct Product: RawRepresentable, Equatable, Hashable {
|
|
||||||
private static let bundle = "com.algoritmico.ios.Passepartout"
|
|
||||||
|
|
||||||
private static let donationsBundle = "\(bundle).donations"
|
|
||||||
|
|
||||||
private static let featuresBundle = "\(bundle).features"
|
|
||||||
|
|
||||||
private static let providersBundle = "\(bundle).providers"
|
|
||||||
|
|
||||||
// MARK: Donations
|
|
||||||
|
|
||||||
static let tinyDonation = Product(donationDescription: "Tiny")
|
|
||||||
|
|
||||||
static let smallDonation = Product(donationDescription: "Small")
|
|
||||||
|
|
||||||
static let mediumDonation = Product(donationDescription: "Medium")
|
|
||||||
|
|
||||||
static let bigDonation = Product(donationDescription: "Big")
|
|
||||||
|
|
||||||
static let hugeDonation = Product(donationDescription: "Huge")
|
|
||||||
|
|
||||||
static let maxiDonation = Product(donationDescription: "Maxi")
|
|
||||||
|
|
||||||
static let allDonations: [Product] = [
|
|
||||||
.tinyDonation,
|
|
||||||
.smallDonation,
|
|
||||||
.mediumDonation,
|
|
||||||
.bigDonation,
|
|
||||||
.hugeDonation,
|
|
||||||
.maxiDonation
|
|
||||||
]
|
|
||||||
|
|
||||||
private init(donationDescription: String) {
|
|
||||||
self.init(rawValue: "\(Product.donationsBundle).\(donationDescription)")!
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Features
|
|
||||||
|
|
||||||
static let unlimitedHosts = Product(featureId: "unlimited_hosts")
|
|
||||||
|
|
||||||
static let trustedNetworks = Product(featureId: "trusted_networks")
|
|
||||||
|
|
||||||
static let siriShortcuts = Product(featureId: "siri")
|
|
||||||
|
|
||||||
static let fullVersion = Product(featureId: "full_version")
|
|
||||||
|
|
||||||
static let allFeatures: [Product] = [
|
|
||||||
.unlimitedHosts,
|
|
||||||
.trustedNetworks,
|
|
||||||
.siriShortcuts,
|
|
||||||
.fullVersion
|
|
||||||
]
|
|
||||||
|
|
||||||
private init(featureId: String) {
|
|
||||||
self.init(rawValue: "\(Product.featuresBundle).\(featureId)")!
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Providers
|
|
||||||
|
|
||||||
static var allProviders: [Product] {
|
|
||||||
return InfrastructureFactory.shared.allMetadata.map {
|
|
||||||
return Product(providerMetadata: $0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate init(providerMetadata: Infrastructure.Metadata) {
|
|
||||||
self.init(rawValue: "\(Product.providersBundle).\(providerMetadata.inApp ?? providerMetadata.name)")!
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: All
|
|
||||||
|
|
||||||
static var all: [Product] {
|
|
||||||
return allDonations + allFeatures + allProviders
|
|
||||||
}
|
|
||||||
|
|
||||||
var isDonation: Bool {
|
|
||||||
return rawValue.hasPrefix(Product.donationsBundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
var isFeature: Bool {
|
|
||||||
return rawValue.hasPrefix(Product.featuresBundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
var isProvider: Bool {
|
|
||||||
return rawValue.hasPrefix(Product.providersBundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: RawRepresentable
|
|
||||||
|
|
||||||
let rawValue: String
|
|
||||||
|
|
||||||
init?(rawValue: String) {
|
|
||||||
self.rawValue = rawValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Equatable
|
|
||||||
|
|
||||||
static func ==(lhs: Product, rhs: Product) -> Bool {
|
|
||||||
return lhs.rawValue == rhs.rawValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Hashable
|
|
||||||
|
|
||||||
func hash(into hasher: inout Hasher) {
|
|
||||||
rawValue.hash(into: &hasher)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Infrastructure.Metadata {
|
|
||||||
var product: Product {
|
|
||||||
return Product(providerMetadata: self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Product {
|
|
||||||
func matchesStoreKitProduct(_ skProduct: SKProduct) -> Bool {
|
|
||||||
return skProduct.productIdentifier == rawValue
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
//
|
||||||
|
// ProductManager+App.swift
|
||||||
|
// Passepartout-iOS
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 4/6/19.
|
||||||
|
// Copyright (c) 2020 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 <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import PassepartoutCore
|
||||||
|
import TunnelKit
|
||||||
|
import SwiftyBeaver
|
||||||
|
|
||||||
|
private let log = SwiftyBeaver.self
|
||||||
|
|
||||||
|
extension ProductManager {
|
||||||
|
static let shared = ProductManager(
|
||||||
|
Configuration(
|
||||||
|
isBetaFullVersion: AppConstants.InApp.isBetaFullVersion,
|
||||||
|
lastFullVersionBuild: AppConstants.InApp.lastFullVersionBuild
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
public func reviewPurchases() {
|
||||||
|
let service = TransientStore.shared.service
|
||||||
|
reloadReceipt(andNotify: false)
|
||||||
|
var anyRefund = false
|
||||||
|
|
||||||
|
// review features and potentially revert them if they were used (Siri is handled in AppDelegate)
|
||||||
|
|
||||||
|
log.debug("Checking 'Trusted networks'")
|
||||||
|
if !isEligible(forFeature: .trustedNetworks) {
|
||||||
|
|
||||||
|
// reset trusted networks for ALL profiles (must load first)
|
||||||
|
for key in service.allProfileKeys() {
|
||||||
|
guard let profile = service.profile(withKey: key) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
#if os(iOS)
|
||||||
|
if profile.trustedNetworks.includesMobile || !profile.trustedNetworks.includedWiFis.isEmpty {
|
||||||
|
profile.trustedNetworks.includesMobile = false
|
||||||
|
profile.trustedNetworks.includedWiFis.removeAll()
|
||||||
|
anyRefund = true
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if !profile.trustedNetworks.includedWiFis.isEmpty {
|
||||||
|
profile.trustedNetworks.includedWiFis.removeAll()
|
||||||
|
anyRefund = true
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if anyRefund {
|
||||||
|
log.debug("\tRefunded")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Checking 'Unlimited hosts'")
|
||||||
|
if !isEligible(forFeature: .unlimitedHosts) {
|
||||||
|
let ids = service.hostIds()
|
||||||
|
if ids.count > AppConstants.InApp.limitedNumberOfHosts {
|
||||||
|
for id in ids {
|
||||||
|
service.removeProfile(ProfileKey(.host, id))
|
||||||
|
}
|
||||||
|
log.debug("\tRefunded")
|
||||||
|
anyRefund = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Checking providers")
|
||||||
|
for name in service.providerNames() {
|
||||||
|
guard let metadata = InfrastructureFactory.shared.metadata(forName: name) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !isEligible(forProvider: metadata) {
|
||||||
|
service.removeProfile(ProfileKey(name))
|
||||||
|
log.debug("\tRefunded provider: \(name)")
|
||||||
|
anyRefund = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
guard anyRefund else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
// save reverts and remove fraud VPN profile
|
||||||
|
TransientStore.shared.serialize(withProfiles: true)
|
||||||
|
VPN.shared.uninstall(completionHandler: nil)
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: ProductManager.didReviewPurchases, object: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ConnectionService {
|
||||||
|
var hasReachedMaximumNumberOfHosts: Bool {
|
||||||
|
let numberOfHosts = hostIds().count
|
||||||
|
return numberOfHosts >= AppConstants.InApp.limitedNumberOfHosts
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,282 +0,0 @@
|
||||||
//
|
|
||||||
// ProductManager.swift
|
|
||||||
// Passepartout-iOS
|
|
||||||
//
|
|
||||||
// Created by Davide De Rosa on 4/6/19.
|
|
||||||
// Copyright (c) 2020 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 <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import StoreKit
|
|
||||||
import Convenience
|
|
||||||
import SwiftyBeaver
|
|
||||||
import Kvitto
|
|
||||||
import PassepartoutCore
|
|
||||||
import TunnelKit
|
|
||||||
|
|
||||||
private let log = SwiftyBeaver.self
|
|
||||||
|
|
||||||
class ProductManager: NSObject {
|
|
||||||
static let didReloadReceipt = Notification.Name("ProductManagerDidReloadReceipt")
|
|
||||||
|
|
||||||
static let didReviewPurchases = Notification.Name("ProductManagerDidReviewPurchases")
|
|
||||||
|
|
||||||
private static let lastFullVersionBuild = 2016 // 1.8.1
|
|
||||||
|
|
||||||
static let shared = ProductManager()
|
|
||||||
|
|
||||||
private let inApp: InApp<Product>
|
|
||||||
|
|
||||||
private var purchasedAppBuild: Int?
|
|
||||||
|
|
||||||
private var purchasedFeatures: Set<Product>
|
|
||||||
|
|
||||||
private var refreshRequest: SKReceiptRefreshRequest?
|
|
||||||
|
|
||||||
private var restoreCompletionHandler: ((Error?) -> Void)?
|
|
||||||
|
|
||||||
private override init() {
|
|
||||||
inApp = InApp()
|
|
||||||
purchasedAppBuild = nil
|
|
||||||
purchasedFeatures = []
|
|
||||||
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
reloadReceipt()
|
|
||||||
SKPaymentQueue.default().add(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
deinit {
|
|
||||||
SKPaymentQueue.default().remove(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listProducts(completionHandler: (([SKProduct]?, Error?) -> Void)?) {
|
|
||||||
let products = Product.all
|
|
||||||
guard !products.isEmpty else {
|
|
||||||
completionHandler?(nil, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
inApp.requestProducts(withIdentifiers: products, completionHandler: { _ in
|
|
||||||
log.debug("In-app products: \(self.inApp.products.map { $0.productIdentifier })")
|
|
||||||
|
|
||||||
completionHandler?(self.inApp.products, nil)
|
|
||||||
}, failureHandler: {
|
|
||||||
completionHandler?(nil, $0)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func product(withIdentifier identifier: Product) -> SKProduct? {
|
|
||||||
return inApp.product(withIdentifier: identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
func featureProducts(includingFullVersion: Bool) -> [SKProduct] {
|
|
||||||
return inApp.products.filter {
|
|
||||||
guard let p = Product(rawValue: $0.productIdentifier) else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
guard includingFullVersion || p != .fullVersion else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
guard p.isFeature else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func purchase(_ product: SKProduct, completionHandler: @escaping (InAppPurchaseResult, Error?) -> Void) {
|
|
||||||
inApp.purchase(product: product) {
|
|
||||||
if $0 == .success {
|
|
||||||
self.reloadReceipt()
|
|
||||||
}
|
|
||||||
completionHandler($0, $1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func restorePurchases(completionHandler: @escaping (Error?) -> Void) {
|
|
||||||
restoreCompletionHandler = completionHandler
|
|
||||||
refreshRequest = SKReceiptRefreshRequest()
|
|
||||||
refreshRequest?.delegate = self
|
|
||||||
refreshRequest?.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: In-app eligibility
|
|
||||||
|
|
||||||
private func reloadReceipt(andNotify: Bool = true) {
|
|
||||||
guard let url = Bundle.main.appStoreReceiptURL else {
|
|
||||||
log.warning("No App Store receipt found!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
guard let receipt = Receipt(contentsOfURL: url) else {
|
|
||||||
log.error("Could not parse App Store receipt!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let originalAppVersion = receipt.originalAppVersion, let buildNumber = Int(originalAppVersion) {
|
|
||||||
purchasedAppBuild = buildNumber
|
|
||||||
}
|
|
||||||
purchasedFeatures.removeAll()
|
|
||||||
|
|
||||||
if let buildNumber = purchasedAppBuild {
|
|
||||||
log.debug("Original purchased build: \(buildNumber)")
|
|
||||||
|
|
||||||
// treat former purchases as full versions
|
|
||||||
if buildNumber <= ProductManager.lastFullVersionBuild {
|
|
||||||
purchasedFeatures.insert(.fullVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let iapReceipts = receipt.inAppPurchaseReceipts {
|
|
||||||
log.debug("In-app receipts:")
|
|
||||||
iapReceipts.forEach {
|
|
||||||
guard let pid = $0.productIdentifier, let product = Product(rawValue: pid) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if let cancellationDate = $0.cancellationDate {
|
|
||||||
log.debug("\t\(pid) [cancelled on: \(cancellationDate)]")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if let purchaseDate = $0.originalPurchaseDate {
|
|
||||||
log.debug("\t\(pid) [purchased on: \(purchaseDate)]")
|
|
||||||
}
|
|
||||||
purchasedFeatures.insert(product)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.info("Purchased features: \(purchasedFeatures)")
|
|
||||||
|
|
||||||
if andNotify {
|
|
||||||
NotificationCenter.default.post(name: ProductManager.didReloadReceipt, object: nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isFullVersion() -> Bool {
|
|
||||||
if AppConstants.Flags.isBeta && AppConstants.Flags.isBetaFullVersion {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return purchasedFeatures.contains(.fullVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isEligible(forFeature feature: Product) -> Bool {
|
|
||||||
return isFullVersion() || purchasedFeatures.contains(feature)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isEligible(forProvider metadata: Infrastructure.Metadata) -> Bool {
|
|
||||||
return isFullVersion() || purchasedFeatures.contains(metadata.product)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isEligibleForFeedback() -> Bool {
|
|
||||||
return AppConstants.Flags.isBeta || !purchasedFeatures.isEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Review
|
|
||||||
|
|
||||||
func reviewPurchases() {
|
|
||||||
let service = TransientStore.shared.service
|
|
||||||
reloadReceipt(andNotify: false)
|
|
||||||
var anyRefund = false
|
|
||||||
|
|
||||||
// review features and potentially revert them if they were used (Siri is handled in AppDelegate)
|
|
||||||
|
|
||||||
log.debug("Checking 'Trusted networks'")
|
|
||||||
if !isEligible(forFeature: .trustedNetworks) {
|
|
||||||
|
|
||||||
// reset trusted networks for ALL profiles (must load first)
|
|
||||||
for key in service.allProfileKeys() {
|
|
||||||
guard let profile = service.profile(withKey: key) else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if profile.trustedNetworks.includesMobile || !profile.trustedNetworks.includedWiFis.isEmpty {
|
|
||||||
profile.trustedNetworks.includesMobile = false
|
|
||||||
profile.trustedNetworks.includedWiFis.removeAll()
|
|
||||||
anyRefund = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if anyRefund {
|
|
||||||
log.debug("\tRefunded")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("Checking 'Unlimited hosts'")
|
|
||||||
if !isEligible(forFeature: .unlimitedHosts) {
|
|
||||||
let ids = service.hostIds()
|
|
||||||
if ids.count > AppConstants.InApp.limitedNumberOfHosts {
|
|
||||||
for id in ids {
|
|
||||||
service.removeProfile(ProfileKey(.host, id))
|
|
||||||
}
|
|
||||||
log.debug("\tRefunded")
|
|
||||||
anyRefund = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("Checking providers")
|
|
||||||
for name in service.providerNames() {
|
|
||||||
guard let metadata = InfrastructureFactory.shared.metadata(forName: name) else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !isEligible(forProvider: metadata) {
|
|
||||||
service.removeProfile(ProfileKey(name))
|
|
||||||
log.debug("\tRefunded provider: \(name)")
|
|
||||||
anyRefund = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
guard anyRefund else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
// save reverts and remove fraud VPN profile
|
|
||||||
TransientStore.shared.serialize(withProfiles: true)
|
|
||||||
VPN.shared.uninstall(completionHandler: nil)
|
|
||||||
|
|
||||||
NotificationCenter.default.post(name: ProductManager.didReviewPurchases, object: nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ConnectionService {
|
|
||||||
var hasReachedMaximumNumberOfHosts: Bool {
|
|
||||||
let numberOfHosts = hostIds().count
|
|
||||||
return numberOfHosts >= AppConstants.InApp.limitedNumberOfHosts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ProductManager: SKPaymentTransactionObserver {
|
|
||||||
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
|
|
||||||
reloadReceipt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ProductManager: SKRequestDelegate {
|
|
||||||
func requestDidFinish(_ request: SKRequest) {
|
|
||||||
reloadReceipt()
|
|
||||||
inApp.restorePurchases { [weak self] (finished, _, error) in
|
|
||||||
guard finished else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self?.restoreCompletionHandler?(error)
|
|
||||||
self?.restoreCompletionHandler = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func request(_ request: SKRequest, didFailWithError error: Error) {
|
|
||||||
restoreCompletionHandler?(error)
|
|
||||||
restoreCompletionHandler = nil
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -86,7 +86,7 @@ class OrganizerViewController: UITableViewController, StrongTableHost {
|
||||||
|
|
||||||
model.set([.openAbout], forSection: .about)
|
model.set([.openAbout], forSection: .about)
|
||||||
model.set([.uninstall], forSection: .destruction)
|
model.set([.uninstall], forSection: .destruction)
|
||||||
if AppConstants.Flags.isBeta {
|
if ProductManager.shared.isBeta {
|
||||||
model.add(.test)
|
model.add(.test)
|
||||||
model.setHeader("Beta", forSection: .test)
|
model.setHeader("Beta", forSection: .test)
|
||||||
model.set([.testInterfaces, .testDisplayLog, .testTermination], forSection: .test)
|
model.set([.testInterfaces, .testDisplayLog, .testTermination], forSection: .test)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import StoreKit
|
import StoreKit
|
||||||
|
import PassepartoutCore
|
||||||
import SwiftyBeaver
|
import SwiftyBeaver
|
||||||
import Convenience
|
import Convenience
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,10 @@
|
||||||
0E1D72B2213BFFCF00BA1586 /* ProviderPresetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1D72B1213BFFCF00BA1586 /* ProviderPresetViewController.swift */; };
|
0E1D72B2213BFFCF00BA1586 /* ProviderPresetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1D72B1213BFFCF00BA1586 /* ProviderPresetViewController.swift */; };
|
||||||
0E1D72B4213C118500BA1586 /* ConfigurationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1D72B3213C118500BA1586 /* ConfigurationViewController.swift */; };
|
0E1D72B4213C118500BA1586 /* ConfigurationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1D72B3213C118500BA1586 /* ConfigurationViewController.swift */; };
|
||||||
0E24273A225950450064A1A3 /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E24273C225950450064A1A3 /* About.storyboard */; };
|
0E24273A225950450064A1A3 /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E24273C225950450064A1A3 /* About.storyboard */; };
|
||||||
0E242740225951B00064A1A3 /* ProductManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E24273F225951B00064A1A3 /* ProductManager.swift */; };
|
|
||||||
0E242742225956AC0064A1A3 /* DonationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E242741225956AC0064A1A3 /* DonationViewController.swift */; };
|
0E242742225956AC0064A1A3 /* DonationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E242741225956AC0064A1A3 /* DonationViewController.swift */; };
|
||||||
0E2AC24522EC3AC10037B4B0 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 0E2AC24422EC3AC10037B4B0 /* Settings.bundle */; };
|
0E2AC24522EC3AC10037B4B0 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 0E2AC24422EC3AC10037B4B0 /* Settings.bundle */; };
|
||||||
0E2B494020FCFF990094784C /* Theme+Titles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2B493F20FCFF990094784C /* Theme+Titles.swift */; };
|
0E2B494020FCFF990094784C /* Theme+Titles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2B493F20FCFF990094784C /* Theme+Titles.swift */; };
|
||||||
0E2EB063236D8E1E0079DB53 /* AppConstants+Flags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2EB062236D8E1E0079DB53 /* AppConstants+Flags.swift */; };
|
0E2EB063236D8E1E0079DB53 /* AppConstants+App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2EB062236D8E1E0079DB53 /* AppConstants+App.swift */; };
|
||||||
0E3152AD223F9EF500F61841 /* PassepartoutCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E31529D223F9EF500F61841 /* PassepartoutCore.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
0E3152AD223F9EF500F61841 /* PassepartoutCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E31529D223F9EF500F61841 /* PassepartoutCore.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
0E3152B0223F9EF500F61841 /* PassepartoutCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E31529B223F9EF400F61841 /* PassepartoutCore.framework */; };
|
0E3152B0223F9EF500F61841 /* PassepartoutCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E31529B223F9EF400F61841 /* PassepartoutCore.framework */; };
|
||||||
0E3152B1223F9EF500F61841 /* PassepartoutCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0E31529B223F9EF400F61841 /* PassepartoutCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
0E3152B1223F9EF500F61841 /* PassepartoutCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0E31529B223F9EF400F61841 /* PassepartoutCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
|
@ -52,7 +51,6 @@
|
||||||
0E3152DB223FA05800F61841 /* ProfileKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79D14021919F5600BB5FB2 /* ProfileKey.swift */; };
|
0E3152DB223FA05800F61841 /* ProfileKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79D14021919F5600BB5FB2 /* ProfileKey.swift */; };
|
||||||
0E3152DC223FA05800F61841 /* ProviderConnectionProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE3AA4213DC1B000BFA2F5 /* ProviderConnectionProfile.swift */; };
|
0E3152DC223FA05800F61841 /* ProviderConnectionProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE3AA4213DC1B000BFA2F5 /* ProviderConnectionProfile.swift */; };
|
||||||
0E3262D9235EE8DA00B5E470 /* HostImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3262D8235EE8DA00B5E470 /* HostImporter.swift */; };
|
0E3262D9235EE8DA00B5E470 /* HostImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3262D8235EE8DA00B5E470 /* HostImporter.swift */; };
|
||||||
0E3419AD2350815E00419E18 /* Product.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3419AC2350815E00419E18 /* Product.swift */; };
|
|
||||||
0E3586FE225BD34800509A4D /* ActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3586FD225BD34800509A4D /* ActivityTableViewCell.swift */; };
|
0E3586FE225BD34800509A4D /* ActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3586FD225BD34800509A4D /* ActivityTableViewCell.swift */; };
|
||||||
0E36D24D2240234B006AF062 /* ShortcutsAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E36D24C2240234B006AF062 /* ShortcutsAddViewController.swift */; };
|
0E36D24D2240234B006AF062 /* ShortcutsAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E36D24C2240234B006AF062 /* ShortcutsAddViewController.swift */; };
|
||||||
0E36D25822403469006AF062 /* Shortcuts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E36D25A22403469006AF062 /* Shortcuts.storyboard */; };
|
0E36D25822403469006AF062 /* Shortcuts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E36D25A22403469006AF062 /* Shortcuts.storyboard */; };
|
||||||
|
@ -90,6 +88,9 @@
|
||||||
0EB67D6B2184581E00BA6200 /* ImportedHostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */; };
|
0EB67D6B2184581E00BA6200 /* ImportedHostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */; };
|
||||||
0EB9EB7323867E7F009C0A1C /* TrustedNetworksUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB9EB7223867E7F009C0A1C /* TrustedNetworksUI.swift */; };
|
0EB9EB7323867E7F009C0A1C /* TrustedNetworksUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB9EB7223867E7F009C0A1C /* TrustedNetworksUI.swift */; };
|
||||||
0EBE3A79213C4E5500BFA2F5 /* OrganizerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE3A78213C4E5400BFA2F5 /* OrganizerViewController.swift */; };
|
0EBE3A79213C4E5500BFA2F5 /* OrganizerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE3A78213C4E5400BFA2F5 /* OrganizerViewController.swift */; };
|
||||||
|
0ECA7E2225967BB90095F369 /* ProductManager+App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA7E2125967BB90095F369 /* ProductManager+App.swift */; };
|
||||||
|
0ECA7E2D25967BF40095F369 /* Product.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA7E2525967BDB0095F369 /* Product.swift */; };
|
||||||
|
0ECA7E3025967BFB0095F369 /* ProductManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA7E2625967BDB0095F369 /* ProductManager.swift */; };
|
||||||
0ECC60DE2256B68A0020BEAC /* SwiftGen+Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECC60DD2256B6890020BEAC /* SwiftGen+Assets.swift */; };
|
0ECC60DE2256B68A0020BEAC /* SwiftGen+Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECC60DD2256B6890020BEAC /* SwiftGen+Assets.swift */; };
|
||||||
0ECEB10A224FECEA00E9E551 /* DataUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECEB109224FECEA00E9E551 /* DataUnit.swift */; };
|
0ECEB10A224FECEA00E9E551 /* DataUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECEB109224FECEA00E9E551 /* DataUnit.swift */; };
|
||||||
0ECEE45020E1182E00A6BB43 /* Theme+Cells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECEE44F20E1182E00A6BB43 /* Theme+Cells.swift */; };
|
0ECEE45020E1182E00A6BB43 /* Theme+Cells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECEE44F20E1182E00A6BB43 /* Theme+Cells.swift */; };
|
||||||
|
@ -174,7 +175,6 @@
|
||||||
0E1D72B3213C118500BA1586 /* ConfigurationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationViewController.swift; sourceTree = "<group>"; };
|
0E1D72B3213C118500BA1586 /* ConfigurationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationViewController.swift; sourceTree = "<group>"; };
|
||||||
0E23B4A12298559800304C30 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
0E23B4A12298559800304C30 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
||||||
0E24273B225950450064A1A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/About.storyboard; sourceTree = "<group>"; };
|
0E24273B225950450064A1A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/About.storyboard; sourceTree = "<group>"; };
|
||||||
0E24273F225951B00064A1A3 /* ProductManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductManager.swift; sourceTree = "<group>"; };
|
|
||||||
0E242741225956AC0064A1A3 /* DonationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DonationViewController.swift; sourceTree = "<group>"; };
|
0E242741225956AC0064A1A3 /* DonationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DonationViewController.swift; sourceTree = "<group>"; };
|
||||||
0E2AC24422EC3AC10037B4B0 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
|
0E2AC24422EC3AC10037B4B0 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
|
||||||
0E2B493F20FCFF990094784C /* Theme+Titles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+Titles.swift"; sourceTree = "<group>"; };
|
0E2B493F20FCFF990094784C /* Theme+Titles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+Titles.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -183,12 +183,11 @@
|
||||||
0E2C54C4230056EF00F59453 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Core.strings"; sourceTree = "<group>"; };
|
0E2C54C4230056EF00F59453 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Core.strings"; sourceTree = "<group>"; };
|
||||||
0E2C54C52300570200F59453 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/App.strings"; sourceTree = "<group>"; };
|
0E2C54C52300570200F59453 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/App.strings"; sourceTree = "<group>"; };
|
||||||
0E2D11B9217DBEDE0096822C /* ConnectionService+Configurations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConnectionService+Configurations.swift"; sourceTree = "<group>"; };
|
0E2D11B9217DBEDE0096822C /* ConnectionService+Configurations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConnectionService+Configurations.swift"; sourceTree = "<group>"; };
|
||||||
0E2EB062236D8E1E0079DB53 /* AppConstants+Flags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppConstants+Flags.swift"; sourceTree = "<group>"; };
|
0E2EB062236D8E1E0079DB53 /* AppConstants+App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppConstants+App.swift"; sourceTree = "<group>"; };
|
||||||
0E31529B223F9EF400F61841 /* PassepartoutCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PassepartoutCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
0E31529B223F9EF400F61841 /* PassepartoutCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PassepartoutCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
0E31529D223F9EF500F61841 /* PassepartoutCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PassepartoutCore.h; sourceTree = "<group>"; };
|
0E31529D223F9EF500F61841 /* PassepartoutCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PassepartoutCore.h; sourceTree = "<group>"; };
|
||||||
0E31529E223F9EF500F61841 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
0E31529E223F9EF500F61841 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
0E3262D8235EE8DA00B5E470 /* HostImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostImporter.swift; sourceTree = "<group>"; };
|
0E3262D8235EE8DA00B5E470 /* HostImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostImporter.swift; sourceTree = "<group>"; };
|
||||||
0E3419AC2350815E00419E18 /* Product.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Product.swift; sourceTree = "<group>"; };
|
|
||||||
0E3586FD225BD34800509A4D /* ActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityTableViewCell.swift; sourceTree = "<group>"; };
|
0E3586FD225BD34800509A4D /* ActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
0E36D24C2240234B006AF062 /* ShortcutsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsAddViewController.swift; sourceTree = "<group>"; };
|
0E36D24C2240234B006AF062 /* ShortcutsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsAddViewController.swift; sourceTree = "<group>"; };
|
||||||
0E36D25B224034AD006AF062 /* ShortcutsConnectToViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsConnectToViewController.swift; sourceTree = "<group>"; };
|
0E36D25B224034AD006AF062 /* ShortcutsConnectToViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsConnectToViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -277,6 +276,9 @@
|
||||||
0EBE3AA3213DC1B000BFA2F5 /* HostConnectionProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HostConnectionProfile.swift; sourceTree = "<group>"; };
|
0EBE3AA3213DC1B000BFA2F5 /* HostConnectionProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HostConnectionProfile.swift; sourceTree = "<group>"; };
|
||||||
0EBE3AA4213DC1B000BFA2F5 /* ProviderConnectionProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProviderConnectionProfile.swift; sourceTree = "<group>"; };
|
0EBE3AA4213DC1B000BFA2F5 /* ProviderConnectionProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProviderConnectionProfile.swift; sourceTree = "<group>"; };
|
||||||
0EC7F20420E24308004EA58E /* DebugLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugLog.swift; sourceTree = "<group>"; };
|
0EC7F20420E24308004EA58E /* DebugLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugLog.swift; sourceTree = "<group>"; };
|
||||||
|
0ECA7E2125967BB90095F369 /* ProductManager+App.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ProductManager+App.swift"; sourceTree = "<group>"; };
|
||||||
|
0ECA7E2525967BDB0095F369 /* Product.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Product.swift; path = Submodules/Core/Passepartout/Sources/Model/Product.swift; sourceTree = SOURCE_ROOT; };
|
||||||
|
0ECA7E2625967BDB0095F369 /* ProductManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProductManager.swift; path = Submodules/Core/Passepartout/Sources/Model/ProductManager.swift; sourceTree = SOURCE_ROOT; };
|
||||||
0ECC60DD2256B6890020BEAC /* SwiftGen+Assets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SwiftGen+Assets.swift"; sourceTree = "<group>"; };
|
0ECC60DD2256B6890020BEAC /* SwiftGen+Assets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SwiftGen+Assets.swift"; sourceTree = "<group>"; };
|
||||||
0ECEB105224FE51400E9E551 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
0ECEB105224FE51400E9E551 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
0ECEB106224FE51400E9E551 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Organizer.storyboard; sourceTree = "<group>"; };
|
0ECEB106224FE51400E9E551 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Organizer.storyboard; sourceTree = "<group>"; };
|
||||||
|
@ -515,6 +517,8 @@
|
||||||
0EAC572E249426E200D0FCE0 /* GracefulVPN.swift */,
|
0EAC572E249426E200D0FCE0 /* GracefulVPN.swift */,
|
||||||
0E45E70F22BE108100F19312 /* OpenVPNOptions.swift */,
|
0E45E70F22BE108100F19312 /* OpenVPNOptions.swift */,
|
||||||
0E89DFC4213DF7AE00741BA1 /* Preferences.swift */,
|
0E89DFC4213DF7AE00741BA1 /* Preferences.swift */,
|
||||||
|
0ECA7E2525967BDB0095F369 /* Product.swift */,
|
||||||
|
0ECA7E2625967BDB0095F369 /* ProductManager.swift */,
|
||||||
0EFB901722764689006405E4 /* ProfileNetworkSettings.swift */,
|
0EFB901722764689006405E4 /* ProfileNetworkSettings.swift */,
|
||||||
0E89DFC7213E8FC500741BA1 /* SessionProxy+Communication.swift */,
|
0E89DFC7213E8FC500741BA1 /* SessionProxy+Communication.swift */,
|
||||||
0E2B494120FD16540094784C /* TransientStore.swift */,
|
0E2B494120FD16540094784C /* TransientStore.swift */,
|
||||||
|
@ -554,12 +558,11 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
0E45E6E222BD793800F19312 /* App.strings */,
|
0E45E6E222BD793800F19312 /* App.strings */,
|
||||||
0E2EB062236D8E1E0079DB53 /* AppConstants+Flags.swift */,
|
0E2EB062236D8E1E0079DB53 /* AppConstants+App.swift */,
|
||||||
0E3262D8235EE8DA00B5E470 /* HostImporter.swift */,
|
0E3262D8235EE8DA00B5E470 /* HostImporter.swift */,
|
||||||
0EFD943D215BE10800529B64 /* IssueReporter.swift */,
|
0EFD943D215BE10800529B64 /* IssueReporter.swift */,
|
||||||
0E4FD7F020D58618002221FF /* Macros.swift */,
|
0E4FD7F020D58618002221FF /* Macros.swift */,
|
||||||
0E3419AC2350815E00419E18 /* Product.swift */,
|
0ECA7E2125967BB90095F369 /* ProductManager+App.swift */,
|
||||||
0E24273F225951B00064A1A3 /* ProductManager.swift */,
|
|
||||||
0ECC60DD2256B6890020BEAC /* SwiftGen+Assets.swift */,
|
0ECC60DD2256B6890020BEAC /* SwiftGen+Assets.swift */,
|
||||||
0EDE8DE320C89028004C739C /* SwiftGen+Scenes.swift */,
|
0EDE8DE320C89028004C739C /* SwiftGen+Scenes.swift */,
|
||||||
0EF56BBA2185AC8500B0C8AB /* SwiftGen+Segues.swift */,
|
0EF56BBA2185AC8500B0C8AB /* SwiftGen+Segues.swift */,
|
||||||
|
@ -962,6 +965,7 @@
|
||||||
0E3152D9223FA05800F61841 /* HostConnectionProfile.swift in Sources */,
|
0E3152D9223FA05800F61841 /* HostConnectionProfile.swift in Sources */,
|
||||||
0E3152D6223FA05400F61841 /* TransientStore.swift in Sources */,
|
0E3152D6223FA05400F61841 /* TransientStore.swift in Sources */,
|
||||||
0E3152CC223FA04D00F61841 /* WebServices.swift in Sources */,
|
0E3152CC223FA04D00F61841 /* WebServices.swift in Sources */,
|
||||||
|
0ECA7E2D25967BF40095F369 /* Product.swift in Sources */,
|
||||||
0E3152BB223FA03D00F61841 /* AppConstants.swift in Sources */,
|
0E3152BB223FA03D00F61841 /* AppConstants.swift in Sources */,
|
||||||
0E3152CA223FA04D00F61841 /* InfrastructurePreset.swift in Sources */,
|
0E3152CA223FA04D00F61841 /* InfrastructurePreset.swift in Sources */,
|
||||||
0E3152CE223FA05400F61841 /* ConnectionService.swift in Sources */,
|
0E3152CE223FA05400F61841 /* ConnectionService.swift in Sources */,
|
||||||
|
@ -979,6 +983,7 @@
|
||||||
0E3152CB223FA04D00F61841 /* Pool.swift in Sources */,
|
0E3152CB223FA04D00F61841 /* Pool.swift in Sources */,
|
||||||
0EA8451A238C2AB500EFC500 /* Infrastructure+Metadata.swift in Sources */,
|
0EA8451A238C2AB500EFC500 /* Infrastructure+Metadata.swift in Sources */,
|
||||||
0EB9EB7323867E7F009C0A1C /* TrustedNetworksUI.swift in Sources */,
|
0EB9EB7323867E7F009C0A1C /* TrustedNetworksUI.swift in Sources */,
|
||||||
|
0ECA7E3025967BFB0095F369 /* ProductManager.swift in Sources */,
|
||||||
0E3CAFC0229AAE770008E5C8 /* Intents.intentdefinition in Sources */,
|
0E3CAFC0229AAE770008E5C8 /* Intents.intentdefinition in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -1002,20 +1007,18 @@
|
||||||
0ED38AEC2141260D0004D387 /* ConfigurationModificationDelegate.swift in Sources */,
|
0ED38AEC2141260D0004D387 /* ConfigurationModificationDelegate.swift in Sources */,
|
||||||
0E776642229D0DAE0023FA76 /* Intents.intentdefinition in Sources */,
|
0E776642229D0DAE0023FA76 /* Intents.intentdefinition in Sources */,
|
||||||
0ECEE45020E1182E00A6BB43 /* Theme+Cells.swift in Sources */,
|
0ECEE45020E1182E00A6BB43 /* Theme+Cells.swift in Sources */,
|
||||||
0E242740225951B00064A1A3 /* ProductManager.swift in Sources */,
|
|
||||||
0E6268942369AD0600355F75 /* PurchaseTableViewCell.swift in Sources */,
|
0E6268942369AD0600355F75 /* PurchaseTableViewCell.swift in Sources */,
|
||||||
0E1066C920E0F84A004F98B7 /* Cells.swift in Sources */,
|
0E1066C920E0F84A004F98B7 /* Cells.swift in Sources */,
|
||||||
0E4B0D6B2366E3C100C890B4 /* PurchaseViewController.swift in Sources */,
|
0E4B0D6B2366E3C100C890B4 /* PurchaseViewController.swift in Sources */,
|
||||||
0EF56BBB2185AC8500B0C8AB /* SwiftGen+Segues.swift in Sources */,
|
0EF56BBB2185AC8500B0C8AB /* SwiftGen+Segues.swift in Sources */,
|
||||||
0E05C5D620D1645F006EE732 /* SwiftGen+Scenes.swift in Sources */,
|
0E05C5D620D1645F006EE732 /* SwiftGen+Scenes.swift in Sources */,
|
||||||
0E773BF8224BF37600CDDC8E /* ShortcutsViewController.swift in Sources */,
|
0E773BF8224BF37600CDDC8E /* ShortcutsViewController.swift in Sources */,
|
||||||
0E3419AD2350815E00419E18 /* Product.swift in Sources */,
|
|
||||||
0E9CDB6723604AD5006733B4 /* ServerNetworkViewController.swift in Sources */,
|
0E9CDB6723604AD5006733B4 /* ServerNetworkViewController.swift in Sources */,
|
||||||
0E3262D9235EE8DA00B5E470 /* HostImporter.swift in Sources */,
|
0E3262D9235EE8DA00B5E470 /* HostImporter.swift in Sources */,
|
||||||
0ED31C2C20CF2D6F0027975F /* ProviderPoolViewController.swift in Sources */,
|
0ED31C2C20CF2D6F0027975F /* ProviderPoolViewController.swift in Sources */,
|
||||||
0E2B494020FCFF990094784C /* Theme+Titles.swift in Sources */,
|
0E2B494020FCFF990094784C /* Theme+Titles.swift in Sources */,
|
||||||
0E05C5D520D1645F006EE732 /* SettingTableViewCell.swift in Sources */,
|
0E05C5D520D1645F006EE732 /* SettingTableViewCell.swift in Sources */,
|
||||||
0E2EB063236D8E1E0079DB53 /* AppConstants+Flags.swift in Sources */,
|
0E2EB063236D8E1E0079DB53 /* AppConstants+App.swift in Sources */,
|
||||||
0E89DFCE213EEDFA00741BA1 /* WizardProviderViewController.swift in Sources */,
|
0E89DFCE213EEDFA00741BA1 /* WizardProviderViewController.swift in Sources */,
|
||||||
0E1D72B2213BFFCF00BA1586 /* ProviderPresetViewController.swift in Sources */,
|
0E1D72B2213BFFCF00BA1586 /* ProviderPresetViewController.swift in Sources */,
|
||||||
0E6BE13F20CFBAB300A6DD36 /* DebugLogViewController.swift in Sources */,
|
0E6BE13F20CFBAB300A6DD36 /* DebugLogViewController.swift in Sources */,
|
||||||
|
@ -1026,6 +1029,7 @@
|
||||||
0E57F63E20C83FC5008323CF /* ServiceViewController.swift in Sources */,
|
0E57F63E20C83FC5008323CF /* ServiceViewController.swift in Sources */,
|
||||||
0E36D24D2240234B006AF062 /* ShortcutsAddViewController.swift in Sources */,
|
0E36D24D2240234B006AF062 /* ShortcutsAddViewController.swift in Sources */,
|
||||||
0E57F63C20C83FC5008323CF /* AppDelegate.swift in Sources */,
|
0E57F63C20C83FC5008323CF /* AppDelegate.swift in Sources */,
|
||||||
|
0ECA7E2225967BB90095F369 /* ProductManager+App.swift in Sources */,
|
||||||
0ED31C2920CF2A340027975F /* AccountViewController.swift in Sources */,
|
0ED31C2920CF2A340027975F /* AccountViewController.swift in Sources */,
|
||||||
0E158ADA20E11B0B00C85A82 /* EndpointViewController.swift in Sources */,
|
0E158ADA20E11B0B00C85A82 /* EndpointViewController.swift in Sources */,
|
||||||
0E1D72B4213C118500BA1586 /* ConfigurationViewController.swift in Sources */,
|
0E1D72B4213C118500BA1586 /* ConfigurationViewController.swift in Sources */,
|
||||||
|
|
2
Podfile
2
Podfile
|
@ -9,7 +9,7 @@ $tunnelkit_specs = ['Protocols/OpenVPN', 'Extra/LZO']
|
||||||
|
|
||||||
def shared_pods
|
def shared_pods
|
||||||
#pod_version $tunnelkit_name, $tunnelkit_specs, '~> 3.0.1'
|
#pod_version $tunnelkit_name, $tunnelkit_specs, '~> 3.0.1'
|
||||||
pod_git $tunnelkit_name, $tunnelkit_specs, '4e2dca9'
|
pod_git $tunnelkit_name, $tunnelkit_specs, '304d021'
|
||||||
#pod_path $tunnelkit_name, $tunnelkit_specs, '..'
|
#pod_path $tunnelkit_name, $tunnelkit_specs, '..'
|
||||||
pod 'SSZipArchive'
|
pod 'SSZipArchive'
|
||||||
|
|
||||||
|
|
10
Podfile.lock
10
Podfile.lock
|
@ -52,8 +52,8 @@ DEPENDENCIES:
|
||||||
- Kvitto
|
- Kvitto
|
||||||
- MBProgressHUD
|
- MBProgressHUD
|
||||||
- SSZipArchive
|
- SSZipArchive
|
||||||
- TunnelKit/Extra/LZO (from `https://github.com/passepartoutvpn/tunnelkit`, commit `4e2dca9`)
|
- TunnelKit/Extra/LZO (from `https://github.com/passepartoutvpn/tunnelkit`, commit `304d021`)
|
||||||
- TunnelKit/Protocols/OpenVPN (from `https://github.com/passepartoutvpn/tunnelkit`, commit `4e2dca9`)
|
- TunnelKit/Protocols/OpenVPN (from `https://github.com/passepartoutvpn/tunnelkit`, commit `304d021`)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
https://github.com/cocoapods/specs.git:
|
https://github.com/cocoapods/specs.git:
|
||||||
|
@ -69,7 +69,7 @@ EXTERNAL SOURCES:
|
||||||
:commit: 0b09b1e
|
:commit: 0b09b1e
|
||||||
:git: https://github.com/keeshux/convenience
|
:git: https://github.com/keeshux/convenience
|
||||||
TunnelKit:
|
TunnelKit:
|
||||||
:commit: 4e2dca9
|
:commit: 304d021
|
||||||
:git: https://github.com/passepartoutvpn/tunnelkit
|
:git: https://github.com/passepartoutvpn/tunnelkit
|
||||||
|
|
||||||
CHECKOUT OPTIONS:
|
CHECKOUT OPTIONS:
|
||||||
|
@ -77,7 +77,7 @@ CHECKOUT OPTIONS:
|
||||||
:commit: 0b09b1e
|
:commit: 0b09b1e
|
||||||
:git: https://github.com/keeshux/convenience
|
:git: https://github.com/keeshux/convenience
|
||||||
TunnelKit:
|
TunnelKit:
|
||||||
:commit: 4e2dca9
|
:commit: 304d021
|
||||||
:git: https://github.com/passepartoutvpn/tunnelkit
|
:git: https://github.com/passepartoutvpn/tunnelkit
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
|
@ -90,6 +90,6 @@ SPEC CHECKSUMS:
|
||||||
SwiftyBeaver: 2e8acd6fc90c6d0a27055867a290794926d57c02
|
SwiftyBeaver: 2e8acd6fc90c6d0a27055867a290794926d57c02
|
||||||
TunnelKit: 4db9180956f8aaf4ab152fd0d38c6c9c63a46cf8
|
TunnelKit: 4db9180956f8aaf4ab152fd0d38c6c9c63a46cf8
|
||||||
|
|
||||||
PODFILE CHECKSUM: 1fd20c6db48881199527c72f0e28c9a6c3cb85dc
|
PODFILE CHECKSUM: c61d36f819940bcbb0684b98ec889e9bb5df918e
|
||||||
|
|
||||||
COCOAPODS: 1.10.0
|
COCOAPODS: 1.10.0
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 4ec43fd23982c52b45511fc3b394766148492049
|
Subproject commit 51a2835ffe9eeb5005cc4c673ace075eb5a00e3f
|
Loading…
Reference in New Issue