summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ios/MullvadREST/RESTAccessTokenManager.swift50
-rw-r--r--ios/MullvadVPN/AddressCacheTracker/AddressCacheTracker.swift8
-rw-r--r--ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift15
-rw-r--r--ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift9
-rw-r--r--ios/MullvadVPN/TunnelManager/SetAccountOperation.swift169
-rw-r--r--ios/MullvadVPN/TunnelManager/TunnelManager.swift43
-rw-r--r--ios/PacketTunnel/PacketTunnelProvider.swift48
7 files changed, 142 insertions, 200 deletions
diff --git a/ios/MullvadREST/RESTAccessTokenManager.swift b/ios/MullvadREST/RESTAccessTokenManager.swift
index d8d7ef5521..a0fe79ba75 100644
--- a/ios/MullvadREST/RESTAccessTokenManager.swift
+++ b/ios/MullvadREST/RESTAccessTokenManager.swift
@@ -27,41 +27,35 @@ extension REST {
accountNumber: String,
completionHandler: @escaping (Result<REST.AccessTokenData, Swift.Error>) -> Void
) -> Cancellable {
- let operation = ResultBlockOperation<REST.AccessTokenData>(dispatchQueue: dispatchQueue)
+ let operation = ResultBlockOperation<REST.AccessTokenData>(
+ dispatchQueue: dispatchQueue,
+ cancellableTask: { operation -> Cancellable in
+ if let tokenData = self.tokens[accountNumber], tokenData.expiry > Date() {
+ operation.finish(result: .success(tokenData))
+ return AnyCancellable {}
+ }
- operation.setExecutionBlock { operation in
- if let tokenData = self.tokens[accountNumber], tokenData.expiry > Date() {
- operation.finish(result: .success(tokenData))
- return
- }
+ return self.proxy.getAccessToken(accountNumber: accountNumber, retryStrategy: .noRetry) { result in
+ self.dispatchQueue.async {
+ switch result {
+ case let .success(tokenData):
+ self.tokens[accountNumber] = tokenData
- let task = self.proxy.getAccessToken(
- accountNumber: accountNumber,
- retryStrategy: .noRetry
- ) { result in
- self.dispatchQueue.async {
- switch result {
- case let .success(tokenData):
- self.tokens[accountNumber] = tokenData
+ case let .failure(error) where !error.isOperationCancellationError:
+ self.logger.error(
+ error: error,
+ message: "Failed to fetch access token."
+ )
- case let .failure(error) where !error.isOperationCancellationError:
- self.logger.error(
- error: error,
- message: "Failed to fetch access token."
- )
+ default:
+ break
+ }
- default:
- break
+ operation.finish(result: result)
}
-
- operation.finish(result: result)
}
}
-
- operation.addCancellationBlock {
- task.cancel()
- }
- }
+ )
operation.completionQueue = .main
operation.completionHandler = completionHandler
diff --git a/ios/MullvadVPN/AddressCacheTracker/AddressCacheTracker.swift b/ios/MullvadVPN/AddressCacheTracker/AddressCacheTracker.swift
index 8c3100f92b..99c666e193 100644
--- a/ios/MullvadVPN/AddressCacheTracker/AddressCacheTracker.swift
+++ b/ios/MullvadVPN/AddressCacheTracker/AddressCacheTracker.swift
@@ -88,18 +88,14 @@ final class AddressCacheTracker {
let operation = ResultBlockOperation<Bool> { operation in
guard self.nextScheduleDate() <= Date() else {
operation.finish(result: .success(false))
- return
+ return AnyCancellable {}
}
- let task = self.apiProxy.getAddressList(retryStrategy: .default) { result in
+ return self.apiProxy.getAddressList(retryStrategy: .default) { result in
self.setEndpoints(from: result)
operation.finish(result: result.map { _ in true })
}
-
- operation.addCancellationBlock {
- task.cancel()
- }
}
operation.completionQueue = .main
diff --git a/ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift b/ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift
index 75b73b2119..afc761ebf5 100644
--- a/ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift
+++ b/ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift
@@ -97,25 +97,18 @@ final class RelayCacheTracker {
func updateRelays(completionHandler: ((Result<RelaysFetchResult, Error>) -> Void)? = nil)
-> Cancellable
{
- let operation = ResultBlockOperation<RelaysFetchResult>(dispatchQueue: nil) { operation in
+ let operation = ResultBlockOperation<RelaysFetchResult>(cancellableTask: { operation in
let cachedRelays = try? self.getCachedRelays()
if self.getNextUpdateDate() > Date() {
operation.finish(result: .success(.throttled))
- return
+ return AnyCancellable {}
}
- let task = self.apiProxy.getRelays(
- etag: cachedRelays?.etag,
- retryStrategy: .noRetry
- ) { result in
+ return self.apiProxy.getRelays(etag: cachedRelays?.etag, retryStrategy: .noRetry) { result in
operation.finish(result: self.handleResponse(result: result))
}
-
- operation.addCancellationBlock {
- task.cancel()
- }
- }
+ })
operation.addObserver(
BackgroundObserver(
diff --git a/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift b/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift
index 40e1b6b7e3..7e8545bea5 100644
--- a/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift
+++ b/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift
@@ -182,16 +182,9 @@ final class StorePaymentManager: NSObject, SKPaymentTransactionObserver {
completionHandler: @escaping (StorePaymentManagerError?) -> Void
) {
let accountOperation = ResultBlockOperation<REST.AccountData>(dispatchQueue: .main) { op in
- let task = self.accountsProxy.getAccountData(
- accountNumber: accountNumber,
- retryStrategy: .default
- ) { result in
+ return self.accountsProxy.getAccountData(accountNumber: accountNumber, retryStrategy: .default) { result in
op.finish(result: result)
}
-
- op.addCancellationBlock {
- task.cancel()
- }
}
accountOperation.addObserver(BackgroundObserver(
diff --git a/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift b/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift
index 4f99c86bdc..aa08234af3 100644
--- a/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift
+++ b/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift
@@ -9,6 +9,7 @@
import Foundation
import MullvadLogging
import MullvadREST
+import MullvadTypes
import Operations
import class WireGuardKitTypes.PrivateKey
import class WireGuardKitTypes.PublicKey
@@ -183,12 +184,10 @@ class SetAccountOperation: ResultOperation<StoredAccountData?> {
}
private func getCreateAccountOperation() -> ResultBlockOperation<StoredAccountData> {
- let operation = ResultBlockOperation<StoredAccountData>(dispatchQueue: dispatchQueue)
-
- operation.setExecutionBlock { operation in
+ let operation = ResultBlockOperation<StoredAccountData>(dispatchQueue: dispatchQueue) { operation in
self.logger.debug("Create new account...")
- let task = self.accountsProxy.createAccount(retryStrategy: .default) { result in
+ return self.accountsProxy.createAccount(retryStrategy: .default) { result in
let result = result.inspectError { error in
guard !error.isOperationCancellationError else { return }
@@ -208,53 +207,40 @@ class SetAccountOperation: ResultOperation<StoredAccountData?> {
operation.finish(result: result)
}
-
- operation.addCancellationBlock {
- task.cancel()
- }
}
return operation
}
- private func getExistingAccountOperation(accountNumber: String)
- -> ResultOperation<StoredAccountData>
- {
- let operation = ResultBlockOperation<StoredAccountData>(dispatchQueue: dispatchQueue)
-
- operation.setExecutionBlock { operation in
- self.logger.debug("Request account data...")
-
- let task = self.accountsProxy.getAccountData(
- accountNumber: accountNumber,
- retryStrategy: .default
- ) { result in
- let result = result.inspectError { error in
- guard !error.isOperationCancellationError else { return }
+ private func getExistingAccountOperation(accountNumber: String) -> ResultOperation<StoredAccountData> {
+ return ResultBlockOperation<StoredAccountData>(
+ dispatchQueue: dispatchQueue,
+ cancellableTask: { operation -> Cancellable in
+ self.logger.debug("Request account data...")
- self.logger.error(
- error: error,
- message: "Failed to receive account data."
- )
- }.map { accountData -> StoredAccountData in
- self.logger.debug("Received account data.")
+ return self.accountsProxy
+ .getAccountData(accountNumber: accountNumber, retryStrategy: .default) { result in
+ let result = result.inspectError { error in
+ guard !error.isOperationCancellationError else { return }
- return StoredAccountData(
- identifier: accountData.id,
- number: accountNumber,
- expiry: accountData.expiry
- )
- }
+ self.logger.error(
+ error: error,
+ message: "Failed to receive account data."
+ )
+ }.map { accountData -> StoredAccountData in
+ self.logger.debug("Received account data.")
- operation.finish(result: result)
- }
+ return StoredAccountData(
+ identifier: accountData.id,
+ number: accountNumber,
+ expiry: accountData.expiry
+ )
+ }
- operation.addCancellationBlock {
- task.cancel()
+ operation.finish(result: result)
+ }
}
- }
-
- return operation
+ )
}
private func getDeleteDeviceOperation() -> AsyncBlockOperation? {
@@ -262,12 +248,10 @@ class SetAccountOperation: ResultOperation<StoredAccountData?> {
return nil
}
- let operation = AsyncBlockOperation(dispatchQueue: dispatchQueue)
-
- operation.setExecutionBlock { operation in
+ let operation = AsyncBlockOperation(dispatchQueue: dispatchQueue, cancellableTask: { operation -> Cancellable in
self.logger.debug("Delete current device...")
- let task = self.devicesProxy.deleteDevice(
+ return self.devicesProxy.deleteDevice(
accountNumber: accountData.number,
identifier: deviceData.identifier,
retryStrategy: .default
@@ -288,11 +272,7 @@ class SetAccountOperation: ResultOperation<StoredAccountData?> {
operation.finish(error: result.error)
}
-
- operation.addCancellationBlock {
- task.cancel()
- }
- }
+ })
return operation
}
@@ -334,68 +314,53 @@ class SetAccountOperation: ResultOperation<StoredAccountData?> {
}
}
- private func getCreateDeviceOperation()
- -> TransformOperation<StoredAccountData, (PrivateKey, REST.Device)>
- {
- let createDeviceOperation = TransformOperation<
- StoredAccountData,
- (PrivateKey, REST.Device)
- >(dispatchQueue: dispatchQueue)
-
- createDeviceOperation.setExecutionBlock { storedAccountData, operation in
- self.logger.debug("Store last used account.")
-
- do {
- try SettingsManager.setLastUsedAccount(storedAccountData.number)
- } catch {
- self.logger.error(
- error: error,
- message: "Failed to store last used account number."
- )
- }
+ private func getCreateDeviceOperation() -> TransformOperation<StoredAccountData, (PrivateKey, REST.Device)> {
+ let createDeviceOperation = TransformOperation<StoredAccountData, (PrivateKey, REST.Device)>(
+ dispatchQueue: dispatchQueue,
+ cancellableTask: { storedAccountData, operation -> Cancellable in
+ self.logger.debug("Store last used account.")
- self.logger.debug("Create device...")
+ do {
+ try SettingsManager.setLastUsedAccount(storedAccountData.number)
+ } catch {
+ self.logger.error(
+ error: error,
+ message: "Failed to store last used account number."
+ )
+ }
- let privateKey = PrivateKey()
+ self.logger.debug("Create device...")
- let request = REST.CreateDeviceRequest(
- publicKey: privateKey.publicKey,
- hijackDNS: false
- )
+ let privateKey = PrivateKey()
- let task = self.devicesProxy.createDevice(
- accountNumber: storedAccountData.number,
- request: request,
- retryStrategy: .default
- ) { result in
- let result = result
- .map { device in
- return (privateKey, device)
- }
- .inspectError { error in
- self.logger.error(error: error, message: "Failed to create device.")
- }
+ let request = REST.CreateDeviceRequest(
+ publicKey: privateKey.publicKey,
+ hijackDNS: false
+ )
- operation.finish(result: result)
- }
+ return self.devicesProxy.createDevice(
+ accountNumber: storedAccountData.number,
+ request: request,
+ retryStrategy: .default
+ ) { result in
+ let result = result
+ .map { device in
+ return (privateKey, device)
+ }
+ .inspectError { error in
+ self.logger.error(error: error, message: "Failed to create device.")
+ }
- operation.addCancellationBlock {
- task.cancel()
+ operation.finish(result: result)
+ }
}
- }
+ )
return createDeviceOperation
}
- private func getSaveSettingsOperation()
- -> TransformOperation<SetAccountResult, StoredAccountData>
- {
- let saveSettingsOperation = TransformOperation<
- SetAccountResult,
- StoredAccountData
- >(dispatchQueue: dispatchQueue)
-
- saveSettingsOperation.setExecutionBlock { input in
+ private func getSaveSettingsOperation() -> TransformOperation<SetAccountResult, StoredAccountData> {
+ return TransformOperation<SetAccountResult, StoredAccountData>(dispatchQueue: dispatchQueue) { input in
self.logger.debug("Saving settings...")
let device = input.device
@@ -421,7 +386,5 @@ class SetAccountOperation: ResultOperation<StoredAccountData?> {
return input.accountData
}
-
- return saveSettingsOperation
}
}
diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift
index 9c9190200b..47f7196ea4 100644
--- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift
+++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift
@@ -268,26 +268,24 @@ final class TunnelManager: StorePaymentObserver {
}
func reconnectTunnel(selectNewRelay: Bool, completionHandler: ((Error?) -> Void)? = nil) {
- let operation = AsyncBlockOperation(dispatchQueue: internalQueue) { operation in
+ let operation = AsyncBlockOperation(dispatchQueue: internalQueue, cancellableTask: { operation -> Cancellable in
guard let tunnel = self.tunnel else {
operation.finish(error: UnsetTunnelError())
- return
+ return AnyCancellable {}
}
do {
let selectorResult = selectNewRelay ? try self.selectRelay() : nil
- let task = tunnel.reconnectTunnel(relaySelectorResult: selectorResult) { result in
+ return tunnel.reconnectTunnel(relaySelectorResult: selectorResult) { result in
operation.finish(error: result.error)
}
-
- operation.addCancellationBlock {
- task.cancel()
- }
} catch {
operation.finish(error: error)
+
+ return AnyCancellable {}
}
- }
+ })
operation.completionBlock = {
DispatchQueue.main.async {
@@ -740,9 +738,10 @@ final class TunnelManager: StorePaymentObserver {
@objc private func applicationDidBecomeActive(_ notification: Notification) {
#if DEBUG
- logger.debug("Refresh tunnel status due to application becoming active.")
+ logger.debug("Refresh device state and tunnel status due to application becoming active.")
#endif
refreshTunnelStatus()
+ refreshDeviceState()
}
fileprivate func selectRelay() throws -> RelaySelectorResult {
@@ -819,6 +818,32 @@ final class TunnelManager: StorePaymentObserver {
}
}
+ private func refreshDeviceState() {
+ let operation = AsyncBlockOperation(dispatchQueue: internalQueue) {
+ do {
+ let newDeviceState = try SettingsManager.readDeviceState()
+
+ self.setDeviceState(newDeviceState, persist: false)
+ } catch {
+ if let error = error as? KeychainError, error == .itemNotFound {
+ return
+ }
+
+ self.logger.error(error: error, message: "Failed to refresh device state")
+ }
+ }
+
+ operation.addCondition(MutuallyExclusive(category: OperationCategory.deviceStateUpdate.category))
+ operation
+ .addObserver(BackgroundObserver(
+ application: application,
+ name: "Refresh device state",
+ cancelUponExpiration: true
+ ))
+
+ operationQueue.addOperation(operation)
+ }
+
/// Update `TunnelStatus` from `NEVPNStatus`.
/// Collects the `PacketTunnelStatus` from the tunnel via IPC if needed before assigning
/// the `tunnelStatus`.
diff --git a/ios/PacketTunnel/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider.swift
index 380293695b..614626b2e8 100644
--- a/ios/PacketTunnel/PacketTunnelProvider.swift
+++ b/ios/PacketTunnel/PacketTunnelProvider.swift
@@ -585,7 +585,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate {
// Ignore all requests to reconnect once tunnel is preparing to stop.
guard !isStopping else { return }
- let blockOperation = AsyncBlockOperation(dispatchQueue: dispatchQueue) { operation in
+ let blockOperation = AsyncBlockOperation(dispatchQueue: dispatchQueue, block: { operation in
if shouldStopTunnelMonitor {
self.tunnelMonitor.stop()
}
@@ -594,7 +594,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate {
completionHandler?(error)
operation.finish()
}
- }
+ })
if let reconnectTunnelTask = reconnectTunnelTask {
blockOperation.addDependency(reconnectTunnelTask)
@@ -779,49 +779,27 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate {
operationQueue.addOperation(groupOperation)
}
- private func createGetAccountDataOperation(accountNumber: String)
- -> ResultOperation<REST.AccountData>
- {
- let operation = ResultBlockOperation<REST.AccountData>(
- dispatchQueue: dispatchQueue
- )
-
- operation.setExecutionBlock { operation in
- let task = self.accountsProxy.getAccountData(
- accountNumber: accountNumber,
- retryStrategy: .noRetry
- ) { result in
+ private func createGetAccountDataOperation(accountNumber: String) -> ResultOperation<REST.AccountData> {
+ return ResultBlockOperation<REST.AccountData>(dispatchQueue: dispatchQueue, cancellableTask: { operation in
+ return self.accountsProxy.getAccountData(accountNumber: accountNumber, retryStrategy: .noRetry) { result in
operation.finish(result: result)
}
-
- operation.addCancellationBlock {
- task.cancel()
- }
- }
-
- return operation
+ })
}
- private func createGetDeviceDataOperation(accountNumber: String, identifier: String)
- -> ResultOperation<REST.Device>
- {
- let operation = ResultBlockOperation<REST.Device>(dispatchQueue: dispatchQueue)
-
- operation.setExecutionBlock { operation in
- let task = self.devicesProxy.getDevice(
+ private func createGetDeviceDataOperation(
+ accountNumber: String,
+ identifier: String
+ ) -> ResultOperation<REST.Device> {
+ return ResultBlockOperation<REST.Device>(dispatchQueue: dispatchQueue, cancellableTask: { operation in
+ return self.devicesProxy.getDevice(
accountNumber: accountNumber,
identifier: identifier,
retryStrategy: .noRetry
) { result in
operation.finish(result: result)
}
-
- operation.addCancellationBlock {
- task.cancel()
- }
- }
-
- return operation
+ })
}
}