diff --git a/IVPNClient.xcodeproj/project.pbxproj b/IVPNClient.xcodeproj/project.pbxproj index 9f2457b95..1067c8768 100644 --- a/IVPNClient.xcodeproj/project.pbxproj +++ b/IVPNClient.xcodeproj/project.pbxproj @@ -2552,7 +2552,7 @@ CODE_SIGN_ENTITLEMENTS = "wireguard-tunnel-provider/wireguard_tunnel_provider.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -2568,7 +2568,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -2592,7 +2592,7 @@ CODE_SIGN_ENTITLEMENTS = "wireguard-tunnel-provider/wireguard_tunnel_provider.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -2608,7 +2608,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "net.ivpn.clients.ios.wireguard-tunnel-provider"; @@ -2778,7 +2778,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = IVPNClient/IVPNClient.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -2796,7 +2796,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "-D DEBUG"; @@ -2860,7 +2860,7 @@ CODE_SIGN_ENTITLEMENTS = "openvpn-tunnel-provider/openvpn_tunnel_provider.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2879,7 +2879,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "-D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = "net.ivpn.clients.ios.openvpn-tunnel-provider"; @@ -2902,7 +2902,7 @@ CODE_SIGN_ENTITLEMENTS = "wireguard-tunnel-provider/wireguard_tunnel_provider.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -2918,7 +2918,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -2944,7 +2944,7 @@ CODE_SIGN_ENTITLEMENTS = IVPNWidgetExtension.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -2953,7 +2953,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 IVPN. All rights reserved."; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited)"; - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = net.ivpn.clients.ios.IVPNWidget; @@ -2979,7 +2979,7 @@ CODE_SIGN_ENTITLEMENTS = IVPNWidgetExtension.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -2988,7 +2988,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 IVPN. All rights reserved."; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited)"; - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = net.ivpn.clients.ios.IVPNWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -3013,7 +3013,7 @@ CODE_SIGN_ENTITLEMENTS = IVPNWidgetExtension.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -3022,7 +3022,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 IVPN. All rights reserved."; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited)"; - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = net.ivpn.clients.ios.IVPNWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -3055,7 +3055,7 @@ CODE_SIGN_ENTITLEMENTS = "openvpn-tunnel-provider/openvpn_tunnel_provider.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -3074,7 +3074,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "-D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = "net.ivpn.clients.ios.openvpn-tunnel-provider"; @@ -3107,7 +3107,7 @@ CODE_SIGN_ENTITLEMENTS = "openvpn-tunnel-provider/openvpn_tunnel_provider.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -3126,7 +3126,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "-D RELEASE"; PRODUCT_BUNDLE_IDENTIFIER = "net.ivpn.clients.ios.openvpn-tunnel-provider"; @@ -3267,7 +3267,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = IVPNClient/IVPNClient.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -3285,7 +3285,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "-D DEBUG"; @@ -3306,7 +3306,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = IVPNClient/IVPNClient.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 1.1; DEVELOPMENT_TEAM = WQXXM75BYN; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -3324,7 +3324,7 @@ "$(inherited)", "$(PROJECT_DIR)/IVPNClient/liboqs", ); - MARKETING_VERSION = 2.10.1; + MARKETING_VERSION = 2.10.2; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "-D RELEASE"; diff --git a/IVPNClient/Managers/IAPManager.swift b/IVPNClient/Managers/IAPManager.swift index ce9225166..9140fe452 100644 --- a/IVPNClient/Managers/IAPManager.swift +++ b/IVPNClient/Managers/IAPManager.swift @@ -66,144 +66,150 @@ class IAPManager { } func purchaseProduct(identifier: String, completion: @escaping (PurchaseDetails?, String?) -> Void) { - SwiftyStoreKit.purchaseProduct(identifier, quantity: 1, atomically: false) { result in - switch result { - case .success(let purchase): - completion(purchase, nil) - log(.info, message: "Product was successfully purchased.") - case .error(let error): - switch error.code { - case .unknown: completion(nil, "Unknown error. Please contact support") - case .clientInvalid: completion(nil, "Not allowed to make the payment") - case .paymentCancelled: completion(nil, "Payment cancelled") - case .paymentInvalid: completion(nil, "The purchase identifier was invalid") - case .paymentNotAllowed: completion(nil, "The device is not allowed to make the payment") - case .storeProductNotAvailable: completion(nil, "The product is not available in the current storefront") - case .cloudServicePermissionDenied: completion(nil, "Access to cloud service information is not allowed") - case .cloudServiceNetworkConnectionFailed: completion(nil, "Could not connect to the network") - case .cloudServiceRevoked: completion(nil, "User has revoked permission to use this cloud service") - default: completion(nil, (error as NSError).localizedDescription) - } - log(.error, message: "There was an error with purchase.") - } - } + completion(nil, nil) +// SwiftyStoreKit.purchaseProduct(identifier, quantity: 1, atomically: false) { result in +// switch result { +// case .success(let purchase): +// completion(purchase, nil) +// log(.info, message: "Product was successfully purchased.") +// case .error(let error): +// switch error.code { +// case .unknown: completion(nil, "Unknown error. Please contact support") +// case .clientInvalid: completion(nil, "Not allowed to make the payment") +// case .paymentCancelled: completion(nil, "Payment cancelled") +// case .paymentInvalid: completion(nil, "The purchase identifier was invalid") +// case .paymentNotAllowed: completion(nil, "The device is not allowed to make the payment") +// case .storeProductNotAvailable: completion(nil, "The product is not available in the current storefront") +// case .cloudServicePermissionDenied: completion(nil, "Access to cloud service information is not allowed") +// case .cloudServiceNetworkConnectionFailed: completion(nil, "Could not connect to the network") +// case .cloudServiceRevoked: completion(nil, "User has revoked permission to use this cloud service") +// default: completion(nil, (error as NSError).localizedDescription) +// } +// log(.error, message: "There was an error with purchase.") +// } +// } } func finishIncompletePurchases(completion: @escaping (ServiceStatus?, ErrorResult?) -> Void) { - SwiftyStoreKit.completeTransactions(atomically: false) { products in - self.completePurchases(products: products, endpoint: self.apiEndpoint) { serviceStatus, error in - completion(serviceStatus, error) - } - } + completion(nil, nil) +// SwiftyStoreKit.completeTransactions(atomically: false) { products in +// self.completePurchases(products: products, endpoint: self.apiEndpoint) { serviceStatus, error in +// completion(serviceStatus, error) +// } +// } } func restorePurchases(completion: @escaping (Account?, ErrorResult?) -> Void) { - SwiftyStoreKit.restorePurchases(atomically: false) { results in - if results.restoreFailedPurchases.count > 0 { - if let restoreError = results.restoreFailedPurchases.first { - let error = ErrorResult(status: 500, message: restoreError.0.localizedDescription) - completion(nil, error) - log(.error, message: restoreError.0.localizedDescription) - return - } - - let error = ErrorResult(status: 500, message: "Unknown error") - completion(nil, error) - log(.error, message: "Unknown error") - } else if results.restoredPurchases.count > 0 { - var purchases = results.restoredPurchases - purchases.sort { $0.transaction.transactionDate! > $1.transaction.transactionDate! } - self.completeRestoredPurchase(purchase: purchases.first!) { account, error in - completion(account, error) - log(.info, message: "Purchases are restored.") - } - } else { - let error = ErrorResult(status: 500, message: "There are no purchases to restore.") - completion(nil, error) - log(.error, message: "There are no purchases to restore.") - } - } + completion(nil, nil) +// SwiftyStoreKit.restorePurchases(atomically: false) { results in +// if results.restoreFailedPurchases.count > 0 { +// if let restoreError = results.restoreFailedPurchases.first { +// let error = ErrorResult(status: 500, message: restoreError.0.localizedDescription) +// completion(nil, error) +// log(.error, message: restoreError.0.localizedDescription) +// return +// } +// +// let error = ErrorResult(status: 500, message: "Unknown error") +// completion(nil, error) +// log(.error, message: "Unknown error") +// } else if results.restoredPurchases.count > 0 { +// var purchases = results.restoredPurchases +// purchases.sort { $0.transaction.transactionDate! > $1.transaction.transactionDate! } +// self.completeRestoredPurchase(purchase: purchases.first!) { account, error in +// completion(account, error) +// log(.info, message: "Purchases are restored.") +// } +// } else { +// let error = ErrorResult(status: 500, message: "There are no purchases to restore.") +// completion(nil, error) +// log(.error, message: "There are no purchases to restore.") +// } +// } } func completePurchase(purchase: PurchaseDetails, completion: @escaping (ServiceStatus?, ErrorResult?) -> Void) { - let endpoint = apiEndpoint - let params = purchaseParams(purchase: purchase, endpoint: endpoint) - let request = ApiRequestDI(method: .post, endpoint: endpoint, params: params) - - ApiService.shared.requestCustomError(request) { (result: ResultCustomError) in - switch result { - case .success(let sessionStatus): - if purchase.needsFinishTransaction { - SwiftyStoreKit.finishTransaction(purchase.transaction) - } - Application.shared.serviceStatus = sessionStatus.serviceStatus - completion(sessionStatus.serviceStatus, nil) - log(.info, message: "Purchase was successfully finished.") - case .failure(let error): - let defaultErrorResult = ErrorResult(status: 500, message: "Purchase was completed but service cannot be activated. Restart application to retry.") - completion(nil, error ?? defaultErrorResult) - log(.error, message: "There was an error with purchase completion: \(error?.message ?? "")") - } - } + completion(nil, nil) +// let endpoint = apiEndpoint +// let params = purchaseParams(purchase: purchase, endpoint: endpoint) +// let request = ApiRequestDI(method: .post, endpoint: endpoint, params: params) +// +// ApiService.shared.requestCustomError(request) { (result: ResultCustomError) in +// switch result { +// case .success(let sessionStatus): +// if purchase.needsFinishTransaction { +// SwiftyStoreKit.finishTransaction(purchase.transaction) +// } +// Application.shared.serviceStatus = sessionStatus.serviceStatus +// completion(sessionStatus.serviceStatus, nil) +// log(.info, message: "Purchase was successfully finished.") +// case .failure(let error): +// let defaultErrorResult = ErrorResult(status: 500, message: "Purchase was completed but service cannot be activated. Restart application to retry.") +// completion(nil, error ?? defaultErrorResult) +// log(.error, message: "There was an error with purchase completion: \(error?.message ?? "")") +// } +// } } func completePurchases(products: [Purchase], endpoint: String, completion: @escaping (ServiceStatus?, ErrorResult?) -> Void) { - if let product = products.last { - log(.info, message: "Found incomplete purchase. Completing purchase...") - - switch product.transaction.transactionState { - case .purchased, .restored: - if product.needsFinishTransaction { - let params = finishPurchaseParams(product: product, endpoint: endpoint) - let request = ApiRequestDI(method: .post, endpoint: endpoint, params: params) - - ApiService.shared.requestCustomError(request) { (result: ResultCustomError) in - switch result { - case .success(let sessionStatus): - SwiftyStoreKit.finishTransaction(product.transaction) - Application.shared.serviceStatus = sessionStatus.serviceStatus - completion(sessionStatus.serviceStatus, nil) - log(.info, message: "Purchase was successfully finished.") - case .failure(let error): - let defaultErrorResult = ErrorResult(status: 500, message: "Purchase was completed but service cannot be activated. Restart application to retry.") - completion(nil, error ?? defaultErrorResult) - log(.error, message: "There was an error with purchase completion: \(error?.message ?? "")") - } - } - } - case .failed, .purchasing, .deferred: - break - @unknown default: - break - } - } + completion(nil, nil) +// if let product = products.last { +// log(.info, message: "Found incomplete purchase. Completing purchase...") +// +// switch product.transaction.transactionState { +// case .purchased, .restored: +// if product.needsFinishTransaction { +// let params = finishPurchaseParams(product: product, endpoint: endpoint) +// let request = ApiRequestDI(method: .post, endpoint: endpoint, params: params) +// +// ApiService.shared.requestCustomError(request) { (result: ResultCustomError) in +// switch result { +// case .success(let sessionStatus): +// SwiftyStoreKit.finishTransaction(product.transaction) +// Application.shared.serviceStatus = sessionStatus.serviceStatus +// completion(sessionStatus.serviceStatus, nil) +// log(.info, message: "Purchase was successfully finished.") +// case .failure(let error): +// let defaultErrorResult = ErrorResult(status: 500, message: "Purchase was completed but service cannot be activated. Restart application to retry.") +// completion(nil, error ?? defaultErrorResult) +// log(.error, message: "There was an error with purchase completion: \(error?.message ?? "")") +// } +// } +// } +// case .failed, .purchasing, .deferred: +// break +// @unknown default: +// break +// } +// } } func completeRestoredPurchase(purchase: Purchase, completion: @escaping (Account?, ErrorResult?) -> Void) { - let params = restorePurchaseParams() - let request = ApiRequestDI(method: .post, endpoint: Config.apiPaymentRestore, params: params) - - ApiService.shared.requestCustomError(request) { (result: ResultCustomError) in - switch result { - case .success(let account): - if purchase.needsFinishTransaction { - SwiftyStoreKit.finishTransaction(purchase.transaction) - } - KeyChain.username = account.accountId - completion(account, nil) - log(.info, message: "Purchase was successfully finished.") - case .failure(let error): - let defaultErrorResult = ErrorResult(status: 500, message: "Purchase was restored but service cannot be activated. Restart application to retry.") - completion(nil, error ?? defaultErrorResult) - log(.error, message: "There was an error with purchase completion: \(error?.message ?? "")") - } - } + completion(nil, nil) +// let params = restorePurchaseParams() +// let request = ApiRequestDI(method: .post, endpoint: Config.apiPaymentRestore, params: params) +// +// ApiService.shared.requestCustomError(request) { (result: ResultCustomError) in +// switch result { +// case .success(let account): +// if purchase.needsFinishTransaction { +// SwiftyStoreKit.finishTransaction(purchase.transaction) +// } +// KeyChain.username = account.accountId +// completion(account, nil) +// log(.info, message: "Purchase was successfully finished.") +// case .failure(let error): +// let defaultErrorResult = ErrorResult(status: 500, message: "Purchase was restored but service cannot be activated. Restart application to retry.") +// completion(nil, error ?? defaultErrorResult) +// log(.error, message: "There was an error with purchase completion: \(error?.message ?? "")") +// } +// } } func getProduct(identifier: String) -> SKProduct? { - for product in products where product.productIdentifier == identifier { - return product - } +// for product in products where product.productIdentifier == identifier { +// return product +// } return nil } @@ -217,7 +223,7 @@ class IAPManager { } func completeTransactions() { - SwiftyStoreKit.completeTransactions(atomically: true) { _ in } +// SwiftyStoreKit.completeTransactions(atomically: true) { _ in } } // MARK: - Private methods -