summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2023-06-22 15:22:37 +0200
committerAndrej Mihajlov <and@mullvad.net>2023-06-26 16:09:29 +0200
commit3948b611a5ad42bebe99ac52a176c280291e48b7 (patch)
treef25fca404cee0ef2addfcc28eb0ee0f417309f13
parentd66e83dba82597945d74ab80279925c82969b7e5 (diff)
downloadmullvadvpn-3948b611a5ad42bebe99ac52a176c280291e48b7.tar.xz
mullvadvpn-3948b611a5ad42bebe99ac52a176c280291e48b7.zip
TunnelManager: fetch device on pubkey-in-use error
-rw-r--r--ios/MullvadVPN/TunnelManager/SetAccountOperation.swift52
1 files changed, 44 insertions, 8 deletions
diff --git a/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift b/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift
index 4c6ddace88..349487014a 100644
--- a/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift
+++ b/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift
@@ -12,6 +12,7 @@ import MullvadREST
import MullvadTypes
import Operations
import class WireGuardKitTypes.PrivateKey
+import class WireGuardKitTypes.PublicKey
enum SetAccountAction {
/// Set new account.
@@ -348,21 +349,56 @@ class SetAccountOperation: ResultOperation<StoredAccountData?> {
let task = devicesProxy
.createDevice(accountNumber: accountNumber, request: request, retryStrategy: .default) { [self] result in
dispatchQueue.async { [self] in
- let result = result
- .map { device in
- return NewDevice(privateKey: privateKey, device: device)
+ // Due to retry strategy, it's possible for server to register the new key without being
+ // able to return the acknowledgment back to client.
+ // In that case the subsequent retry attempt will error with `.publicKeyInUse`. Fetch the device
+ // from API when that happens.
+ if let error = result.error as? REST.Error, error.compareErrorCode(.publicKeyInUse) {
+ self.findDevice(accountNumber: accountNumber, publicKey: privateKey.publicKey) { result in
+ let result = result.flatMap { device in
+ if let device {
+ return .success(NewDevice(privateKey: privateKey, device: device))
+ } else {
+ return .failure(error)
+ }
+ }
+ completion(result)
}
- .inspectError { error in
- logger.error(error: error, message: "Failed to create device.")
- }
-
- completion(result)
+ } else {
+ completion(result.map { NewDevice(privateKey: privateKey, device: $0) })
+ }
}
}
tasks.append(task)
}
+ /// Find device by public key in the list of devices registered on server. The result passed to `completion` handler
+ /// may contain `nil` if such device is not found for some reason.
+ private func findDevice(
+ accountNumber: String,
+ publicKey: PublicKey,
+ completion: @escaping (Result<Device?, Error>) -> Void
+ ) {
+ let task = devicesProxy.getDevices(accountNumber: accountNumber, retryStrategy: .default) { [self] result in
+ dispatchQueue.async { [self] in
+ let result = result
+ .flatMap { devices in
+ return .success(devices.first { device in
+ return device.pubkey == publicKey
+ })
+ }
+ .inspectError { error in
+ logger.error(error: error, message: "Failed to get devices.")
+ }
+
+ completion(result)
+ }
+ }
+
+ tasks.append(task)
+ }
+
/// Struct that holds a private key that was used for creating a new device on the API along with the successful
/// response from the API.
private struct NewDevice {