diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2021-09-14 13:16:12 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2021-09-15 11:03:47 +0200 |
| commit | d2987ab97492787acf84f8aff589101cd8219e0f (patch) | |
| tree | efa5b7f16229eebbb501df8b063235ec92b2b5f3 | |
| parent | 28d5e14abed7cab6dabfe2ec1e6d0c2a04ff5f3e (diff) | |
| download | mullvadvpn-d2987ab97492787acf84f8aff589101cd8219e0f.tar.xz mullvadvpn-d2987ab97492787acf84f8aff589101cd8219e0f.zip | |
AppStoreReceipt: refactor
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 4 | ||||
| -rw-r--r-- | ios/MullvadVPN/AppStoreReceipt.swift | 92 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/ReceiptRefreshOperation.swift | 46 |
3 files changed, 80 insertions, 62 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 15263a1696..12f9d22b1e 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -54,6 +54,7 @@ 5845F843236CBDAB00B2D93C /* PacketTunnelIpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5845F841236CBACD00B2D93C /* PacketTunnelIpc.swift */; }; 5846226726E0DF960035F7C2 /* Promise+OperationQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846226626E0DF960035F7C2 /* Promise+OperationQueue.swift */; }; 5846226826E0DF960035F7C2 /* Promise+OperationQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846226626E0DF960035F7C2 /* Promise+OperationQueue.swift */; }; + 5846226A26E0E6FA0035F7C2 /* ReceiptRefreshOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846226926E0E6FA0035F7C2 /* ReceiptRefreshOperation.swift */; }; 584789B8264D4A2A000E45FB /* old_le_root_cert.cer in Resources */ = {isa = PBXBuildFile; fileRef = 584789B4264D4A2A000E45FB /* old_le_root_cert.cer */; }; 584789B9264D4A2A000E45FB /* old_le_root_cert.cer in Resources */ = {isa = PBXBuildFile; fileRef = 584789B4264D4A2A000E45FB /* old_le_root_cert.cer */; }; 584789BE264D4A2A000E45FB /* new_le_root_cert.cer in Resources */ = {isa = PBXBuildFile; fileRef = 584789B7264D4A2A000E45FB /* new_le_root_cert.cer */; }; @@ -339,6 +340,7 @@ 584592602639B4A200EF967F /* ConsentContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentContentView.swift; sourceTree = "<group>"; }; 5845F841236CBACD00B2D93C /* PacketTunnelIpc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelIpc.swift; sourceTree = "<group>"; }; 5846226626E0DF960035F7C2 /* Promise+OperationQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+OperationQueue.swift"; sourceTree = "<group>"; }; + 5846226926E0E6FA0035F7C2 /* ReceiptRefreshOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptRefreshOperation.swift; sourceTree = "<group>"; }; 584789B4264D4A2A000E45FB /* old_le_root_cert.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = old_le_root_cert.cer; sourceTree = "<group>"; }; 584789B7264D4A2A000E45FB /* new_le_root_cert.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = new_le_root_cert.cer; sourceTree = "<group>"; }; 584789DF26529D72000E45FB /* SSLPinningURLSessionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSLPinningURLSessionDelegate.swift; sourceTree = "<group>"; }; @@ -530,6 +532,7 @@ 580EE22324B3243100F9D8A1 /* AsyncBlockOperation.swift */, 58E973DD24850EB600096F90 /* AsyncOperation.swift */, 580EE20524B3222200F9D8A1 /* ExclusivityController.swift */, + 5846226926E0E6FA0035F7C2 /* ReceiptRefreshOperation.swift */, ); path = Operations; sourceTree = "<group>"; @@ -1135,6 +1138,7 @@ 58FEEB58260B662E00A621A8 /* AutomaticKeyboardResponder.swift in Sources */, 58FAEDEF245069C700CB0F5B /* KeychainAttributes.swift in Sources */, 58CB0EE024B86751001EF0D8 /* MullvadRest.swift in Sources */, + 5846226A26E0E6FA0035F7C2 /* ReceiptRefreshOperation.swift in Sources */, 58E1337526D2BEC400CC316B /* Promise+Optional.swift in Sources */, 58293FB125124117005D0BB5 /* CustomTextField.swift in Sources */, 582AE3102440A6CA00E6733A /* AccountTokenInput.swift in Sources */, diff --git a/ios/MullvadVPN/AppStoreReceipt.swift b/ios/MullvadVPN/AppStoreReceipt.swift index 9ced1bad7d..200d6ba1df 100644 --- a/ios/MullvadVPN/AppStoreReceipt.swift +++ b/ios/MullvadVPN/AppStoreReceipt.swift @@ -40,8 +40,26 @@ enum AppStoreReceipt { return queue }() + /// Read AppStore receipt from disk or refresh it from AppStore if it's missing. + /// This call may trigger a sign in with AppStore prompt to appear. + static func fetch(forceRefresh: Bool = false, receiptProperties: [String: Any]? = nil) -> Result<Data, Error>.Promise { + if forceRefresh { + return refreshReceipt(receiptProperties: receiptProperties) + } else { + return self.readFromDisk() + .asPromise() + .flatMapErrorThen { error in + if case .doesNotExist = error { + return refreshReceipt(receiptProperties: receiptProperties) + } else { + return .failure(error) + } + } + } + } + /// Read AppStore receipt from disk - static func readFromDisk() -> Result<Data, Error> { + private static func readFromDisk() -> Result<Data, Error> { guard let appStoreReceiptURL = Bundle.main.appStoreReceiptURL else { return .failure(.doesNotExist) } @@ -56,70 +74,20 @@ enum AppStoreReceipt { } } - /// Read AppStore receipt from disk or refresh it from the AppStore if it's missing - /// This call may trigger a sign in with AppStore prompt to appear - static func fetch(forceRefresh: Bool = false, receiptProperties: [String: Any]? = nil, - completionHandler: @escaping (Result<Data, Error>) -> Void) - { - if forceRefresh { - refreshReceipt(receiptProperties: receiptProperties, - completionHandler: completionHandler) - } else { - switch self.readFromDisk() { - case .success(let data): - completionHandler(.success(data)) - - case .failure(let error): - // Refresh the receipt from AppStore if it's not on disk - if case .doesNotExist = error { - refreshReceipt(receiptProperties: receiptProperties, - completionHandler: completionHandler) - } else { - completionHandler(.failure(error)) - } + /// Refresh receipt from AppStore + private static func refreshReceipt(receiptProperties: [String: Any]?) -> Result<Data, Error>.Promise { + return Result<(), Swift.Error>.Promise { resolver in + let operation = ReceiptRefreshOperation(receiptProperties: receiptProperties) { result in + resolver.resolve(value: result) } + self.operationQueue.addOperation(operation) } - } - - private static func refreshReceipt(receiptProperties: [String: Any]?, completionHandler: @escaping (Result<Data, Error>) -> Void) { - let refreshOperation = ReceiptRefreshOperation(receiptProperties: receiptProperties) - refreshOperation.addDidFinishBlockObserver { (operation, result) in - let result = result - .mapError { Error.refresh($0) } - .flatMap { Self.readFromDisk() } - completionHandler(result) + .mapError { error in + return .refresh(error) + } + .flatMap { + return Self.readFromDisk() } - - operationQueue.addOperation(refreshOperation) } } - -private class ReceiptRefreshOperation: AsyncOperation, OutputOperation, SKRequestDelegate { - typealias Output = Result<(), Error> - - private let request: SKReceiptRefreshRequest - - init(receiptProperties: [String: Any]?) { - request = SKReceiptRefreshRequest(receiptProperties: receiptProperties) - } - - override func main() { - request.delegate = self - request.start() - } - - override func operationDidCancel() { - request.cancel() - } - - // - MARK: SKRequestDelegate - - func requestDidFinish(_ request: SKRequest) { - finish(with: .success(())) - } - - func request(_ request: SKRequest, didFailWithError error: Error) { - finish(with: .failure(error)) - } -} diff --git a/ios/MullvadVPN/Operations/ReceiptRefreshOperation.swift b/ios/MullvadVPN/Operations/ReceiptRefreshOperation.swift new file mode 100644 index 0000000000..c386fc1cb1 --- /dev/null +++ b/ios/MullvadVPN/Operations/ReceiptRefreshOperation.swift @@ -0,0 +1,46 @@ +// +// ReceiptRefreshOperation.swift +// ReceiptRefreshOperation +// +// Created by pronebird on 02/09/2021. +// Copyright © 2021 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import StoreKit + +class ReceiptRefreshOperation: AsyncOperation, SKRequestDelegate { + private let request: SKReceiptRefreshRequest + private let completionHandler: (Result<(), Error>) -> Void + + init(receiptProperties: [String: Any]?, completionHandler: @escaping (Result<(), Error>) -> Void) { + request = SKReceiptRefreshRequest(receiptProperties: receiptProperties) + self.completionHandler = completionHandler + + super.init() + + request.delegate = self + } + + override func main() { + request.start() + } + + override func cancel() { + super.cancel() + + request.cancel() + } + + // - MARK: SKRequestDelegate + + func requestDidFinish(_ request: SKRequest) { + completionHandler(.success(())) + finish() + } + + func request(_ request: SKRequest, didFailWithError error: Error) { + completionHandler(.failure(error)) + finish() + } +} |
