diff options
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 26 | ||||
| -rw-r--r-- | ios/MullvadVPN/AnyEncodable.swift | 28 | ||||
| -rw-r--r-- | ios/MullvadVPN/DisplayChainedError.swift | 45 | ||||
| -rw-r--r-- | ios/MullvadVPN/JsonRpc.swift | 87 | ||||
| -rw-r--r-- | ios/MullvadVPN/MullvadRpc.swift | 347 | ||||
| -rw-r--r-- | ios/MullvadVPN/RelayList.swift | 91 |
6 files changed, 44 insertions, 580 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 9d2adfa428..e259a3aef0 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -39,6 +39,8 @@ 580EE22824B3289300F9D8A1 /* AssociatedValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 580EE22724B3289300F9D8A1 /* AssociatedValue.swift */; }; 580EE22924B3289300F9D8A1 /* AssociatedValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 580EE22724B3289300F9D8A1 /* AssociatedValue.swift */; }; 5811DE50239014550011EB53 /* NEVPNStatus+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5811DE4F239014550011EB53 /* NEVPNStatus+Debug.swift */; }; + 581C9BF524C7096E0059F0C6 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581C9BF424C7096E0059F0C6 /* AnyEncodable.swift */; }; + 581C9BF624C7096E0059F0C6 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581C9BF424C7096E0059F0C6 /* AnyEncodable.swift */; }; 581CBCE62296B97300727D7F /* ViewControllerIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581CBCE52296B97300727D7F /* ViewControllerIdentifier.swift */; }; 581CBCEC2298041B00727D7F /* SettingsAppVersionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581CBCEB2298041B00727D7F /* SettingsAppVersionCell.swift */; }; 581CBCEE229826FD00727D7F /* StaticTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581CBCED229826FD00727D7F /* StaticTableViewDataSource.swift */; }; @@ -88,7 +90,6 @@ 5888AD7F2279B6BF0051EB06 /* RelayStatusIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD7E2279B6BF0051EB06 /* RelayStatusIndicatorView.swift */; }; 5888AD83227B11080051EB06 /* SelectLocationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD82227B11080051EB06 /* SelectLocationCell.swift */; }; 5888AD87227B17950051EB06 /* SelectLocationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD86227B17950051EB06 /* SelectLocationController.swift */; }; - 5888AD89227B18C40051EB06 /* RelayList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD88227B18C40051EB06 /* RelayList.swift */; }; 588D2FE3248AC27F00E313F7 /* AsyncOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E973DD24850EB600096F90 /* AsyncOperation.swift */; }; 58906DE02445C7A5002F0673 /* NEProviderStopReason+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58906DDF2445C7A5002F0673 /* NEProviderStopReason+Debug.swift */; }; 5896AE7E246ACE65005B36CB /* KeychainAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FAEDEB245059F000CB0F5B /* KeychainAttributes.swift */; }; @@ -103,8 +104,6 @@ 58A1AA8C23F5584C009F7EA6 /* ConnectionPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A1AA8B23F5584B009F7EA6 /* ConnectionPanelView.swift */; }; 58A8BE81239FBE62006B74AC /* IPEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58561C98239A5D1500BD6B5E /* IPEndpoint.swift */; }; 58A99ED3240014A0006599E9 /* ConsentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A99ED2240014A0006599E9 /* ConsentViewController.swift */; }; - 58ADDB3C227B1BD200FAFEA7 /* JsonRpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58ADDB3B227B1BD200FAFEA7 /* JsonRpc.swift */; }; - 58ADDB3E227B1CD900FAFEA7 /* MullvadRpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58ADDB3D227B1CD900FAFEA7 /* MullvadRpc.swift */; }; 58AEEF652344A36000C9BBD5 /* KeychainError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AEEF642344A36000C9BBD5 /* KeychainError.swift */; }; 58AEEF662344A37400C9BBD5 /* KeychainError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AEEF642344A36000C9BBD5 /* KeychainError.swift */; }; 58AEEF6B2344A46200C9BBD5 /* TunnelSettingsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AEEF6A2344A46200C9BBD5 /* TunnelSettingsManager.swift */; }; @@ -112,7 +111,6 @@ 58B0A2A8238EE68200BC001D /* RelaySelectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 584B26F3237434D00073B10E /* RelaySelectorTests.swift */; }; 58B0A2A9238EE6A100BC001D /* RelayConstraints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58781CC822AE7CA8009B9D8E /* RelayConstraints.swift */; }; 58B0A2AA238EE6A900BC001D /* RelaySelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58781CD422AFBA39009B9D8E /* RelaySelector.swift */; }; - 58B0A2AB238EE6BF00BC001D /* RelayList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD88227B18C40051EB06 /* RelayList.swift */; }; 58B0A2AC238EE6D500BC001D /* IpAddress+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250022B1124600E4CFEC /* IpAddress+Codable.swift */; }; 58B0A2AD238EE6EC00BC001D /* MullvadEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */; }; 58B8743222B25A7600015324 /* WireguardAssociatedAddresses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B8743122B25A7600015324 /* WireguardAssociatedAddresses.swift */; }; @@ -123,9 +121,6 @@ 58BA692F23E99F5B009DC256 /* Locking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BA692D23E99EFF009DC256 /* Locking.swift */; }; 58BA693123EADA6A009DC256 /* SimulatorTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BA693023EADA6A009DC256 /* SimulatorTunnelProvider.swift */; }; 58BA693223EAE1AE009DC256 /* SimulatorTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BA693023EADA6A009DC256 /* SimulatorTunnelProvider.swift */; }; - 58BFA5C022A7C8A900A6173D /* MullvadRpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58ADDB3D227B1CD900FAFEA7 /* MullvadRpc.swift */; }; - 58BFA5C222A7C92900A6173D /* JsonRpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58ADDB3B227B1BD200FAFEA7 /* JsonRpc.swift */; }; - 58BFA5C322A7C93400A6173D /* RelayList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5888AD88227B18C40051EB06 /* RelayList.swift */; }; 58BFA5C622A7C97F00A6173D /* RelayCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BFA5C522A7C97F00A6173D /* RelayCache.swift */; }; 58BFA5C722A7C97F00A6173D /* RelayCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BFA5C522A7C97F00A6173D /* RelayCache.swift */; }; 58BFA5CC22A7CE1F00A6173D /* ApplicationConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BFA5CB22A7CE1F00A6173D /* ApplicationConfiguration.swift */; }; @@ -249,6 +244,7 @@ 580EE22324B3243100F9D8A1 /* AsyncBlockOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncBlockOperation.swift; sourceTree = "<group>"; }; 580EE22724B3289300F9D8A1 /* AssociatedValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssociatedValue.swift; sourceTree = "<group>"; }; 5811DE4F239014550011EB53 /* NEVPNStatus+Debug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEVPNStatus+Debug.swift"; sourceTree = "<group>"; }; + 581C9BF424C7096E0059F0C6 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = "<group>"; }; 581CBCE52296B97300727D7F /* ViewControllerIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerIdentifier.swift; sourceTree = "<group>"; }; 581CBCEB2298041B00727D7F /* SettingsAppVersionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsAppVersionCell.swift; sourceTree = "<group>"; }; 581CBCED229826FD00727D7F /* StaticTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticTableViewDataSource.swift; sourceTree = "<group>"; }; @@ -288,7 +284,6 @@ 5888AD7E2279B6BF0051EB06 /* RelayStatusIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayStatusIndicatorView.swift; sourceTree = "<group>"; }; 5888AD82227B11080051EB06 /* SelectLocationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationCell.swift; sourceTree = "<group>"; }; 5888AD86227B17950051EB06 /* SelectLocationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationController.swift; sourceTree = "<group>"; }; - 5888AD88227B18C40051EB06 /* RelayList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayList.swift; sourceTree = "<group>"; }; 58906DDF2445C7A5002F0673 /* NEProviderStopReason+Debug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEProviderStopReason+Debug.swift"; sourceTree = "<group>"; }; 5894E725236B2801008A2793 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; 5896AE83246D5889005B36CB /* CustomDateComponentsFormatting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDateComponentsFormatting.swift; sourceTree = "<group>"; }; @@ -297,8 +292,6 @@ 58A1AA8623F43901009F7EA6 /* Location.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Location.swift; sourceTree = "<group>"; }; 58A1AA8B23F5584B009F7EA6 /* ConnectionPanelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionPanelView.swift; sourceTree = "<group>"; }; 58A99ED2240014A0006599E9 /* ConsentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentViewController.swift; sourceTree = "<group>"; }; - 58ADDB3B227B1BD200FAFEA7 /* JsonRpc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JsonRpc.swift; sourceTree = "<group>"; }; - 58ADDB3D227B1CD900FAFEA7 /* MullvadRpc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MullvadRpc.swift; sourceTree = "<group>"; }; 58AEEF642344A36000C9BBD5 /* KeychainError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainError.swift; sourceTree = "<group>"; }; 58AEEF6A2344A46200C9BBD5 /* TunnelSettingsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsManager.swift; sourceTree = "<group>"; }; 58B0A2A0238EE67E00BC001D /* MullvadVPNTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MullvadVPNTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -508,7 +501,6 @@ 5840250022B1124600E4CFEC /* IpAddress+Codable.swift */, 58C6B34E22BB7AC0003C19AD /* IPAddressRange.swift */, 58561C98239A5D1500BD6B5E /* IPEndpoint.swift */, - 58ADDB3B227B1BD200FAFEA7 /* JsonRpc.swift */, 58FAEDF6245088E100CB0F5B /* Keychain.swift */, 58FAEDEB245059F000CB0F5B /* KeychainAttributes.swift */, 58FAEE0024533A9C00CB0F5B /* KeychainClass.swift */, @@ -523,7 +515,6 @@ 58CE5E67224146200008646E /* Main.storyboard */, 5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */, 58CB0EDF24B86751001EF0D8 /* MullvadRest.swift */, - 58ADDB3D227B1CD900FAFEA7 /* MullvadRpc.swift */, 58FBDAAA22A52DC500EB69A3 /* MullvadVPN-Bridging-Header.h */, 5866F39B2243B82D00168AE5 /* MullvadVPN.entitlements */, 58906DDF2445C7A5002F0673 /* NEProviderStopReason+Debug.swift */, @@ -533,7 +524,6 @@ 5845F841236CBACD00B2D93C /* PacketTunnelIpc.swift */, 58BFA5C522A7C97F00A6173D /* RelayCache.swift */, 58781CC822AE7CA8009B9D8E /* RelayConstraints.swift */, - 5888AD88227B18C40051EB06 /* RelayList.swift */, 58781CD422AFBA39009B9D8E /* RelaySelector.swift */, 5888AD7E2279B6BF0051EB06 /* RelayStatusIndicatorView.swift */, 587425C02299833500CA2045 /* RootContainerViewController.swift */, @@ -566,6 +556,7 @@ 58C6B35322BB87C4003C19AD /* WireguardPrivateKey.swift */, 58F3C098249B978C003E76BE /* x25519.c */, 58F3C097249B978C003E76BE /* x25519.h */, + 581C9BF424C7096E0059F0C6 /* AnyEncodable.swift */, ); path = MullvadVPN; sourceTree = "<group>"; @@ -871,7 +862,6 @@ 58B0A2A8238EE68200BC001D /* RelaySelectorTests.swift in Sources */, 584E96BE240FD4DB00D3334F /* Location.swift in Sources */, 58B0A2AC238EE6D500BC001D /* IpAddress+Codable.swift in Sources */, - 58B0A2AB238EE6BF00BC001D /* RelayList.swift in Sources */, 58B0A2AD238EE6EC00BC001D /* MullvadEndpoint.swift in Sources */, 58FAEDF4245088B300CB0F5B /* KeychainError.swift in Sources */, 5896AE88246D7FAF005B36CB /* CustomDateComponentsFormatting.swift in Sources */, @@ -931,7 +921,6 @@ 5845F842236CBACD00B2D93C /* PacketTunnelIpc.swift in Sources */, 58781CC922AE7CA8009B9D8E /* RelayConstraints.swift in Sources */, 584E96BC240FD4DA00D3334F /* Location.swift in Sources */, - 58ADDB3E227B1CD900FAFEA7 /* MullvadRpc.swift in Sources */, 580EE20F24B322E700F9D8A1 /* TransformOperation.swift in Sources */, 58B8743222B25A7600015324 /* WireguardAssociatedAddresses.swift in Sources */, 58C6B34F22BB7AC0003C19AD /* IPAddressRange.swift in Sources */, @@ -952,7 +941,6 @@ 5877152E23981C5B001F8237 /* SettingsBasicCell.swift in Sources */, 58FD5BE724192A2C00112C88 /* AppStoreReceipt.swift in Sources */, 5835B7CC233B76CB0096D79F /* TunnelManager.swift in Sources */, - 58ADDB3C227B1BD200FAFEA7 /* JsonRpc.swift in Sources */, 581CBCEE229826FD00727D7F /* StaticTableViewDataSource.swift in Sources */, 58CE5E64224146200008646E /* AppDelegate.swift in Sources */, 58C6B35E22BBBFE3003C19AD /* Data+HexCoding.swift in Sources */, @@ -971,7 +959,6 @@ 587425C12299833500CA2045 /* RootContainerViewController.swift in Sources */, 580EE20124B321D500F9D8A1 /* OperationProtocol.swift in Sources */, 5896AE84246D5889005B36CB /* CustomDateComponentsFormatting.swift in Sources */, - 5888AD89227B18C40051EB06 /* RelayList.swift in Sources */, 580EE21824B3235100F9D8A1 /* AnyOperationObserver.swift in Sources */, 587AD7C623421D7000E93A53 /* TunnelSettings.swift in Sources */, 58FD5BF024238EB300112C88 /* SKProduct+Formatting.swift in Sources */, @@ -981,6 +968,7 @@ 58C3A4B222456F1B00340BDB /* AccountInputGroupView.swift in Sources */, 58F840B22464491D0044E708 /* ChainedError.swift in Sources */, 58FAEDFF24533A7000CB0F5B /* KeychainReturn.swift in Sources */, + 581C9BF524C7096E0059F0C6 /* AnyEncodable.swift in Sources */, 580EE20C24B3225F00F9D8A1 /* DelayOperation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -995,16 +983,15 @@ 580EE21F24B3237F00F9D8A1 /* OutputOperation.swift in Sources */, 580EE20224B321DB00F9D8A1 /* OperationProtocol.swift in Sources */, 58FAEE0224533ABB00CB0F5B /* KeychainMatchLimit.swift in Sources */, + 581C9BF624C7096E0059F0C6 /* AnyEncodable.swift in Sources */, 58FAEE0324533ABE00CB0F5B /* KeychainReturn.swift in Sources */, 58BFA5CD22A7CE1F00A6173D /* ApplicationConfiguration.swift in Sources */, - 58BFA5C222A7C92900A6173D /* JsonRpc.swift in Sources */, 580EE20724B3222400F9D8A1 /* ExclusivityController.swift in Sources */, 58F840B02464382C0044E708 /* KeychainItemRevision.swift in Sources */, 58C6B35122BB7CFD003C19AD /* IPAddressRange.swift in Sources */, 587AD7C723421D8600E93A53 /* TunnelSettings.swift in Sources */, 58F3C0962492617E003E76BE /* AsyncOperation.swift in Sources */, 580EE22924B3289300F9D8A1 /* AssociatedValue.swift in Sources */, - 58BFA5C322A7C93400A6173D /* RelayList.swift in Sources */, 58AEEF662344A37400C9BBD5 /* KeychainError.swift in Sources */, 5840250222B1124600E4CFEC /* IpAddress+Codable.swift in Sources */, 58BA693223EAE1AE009DC256 /* SimulatorTunnelProvider.swift in Sources */, @@ -1027,7 +1014,6 @@ 58C6B35F22BBBFE3003C19AD /* Data+HexCoding.swift in Sources */, 5840250522B11AB700E4CFEC /* MullvadEndpoint.swift in Sources */, 58BFA5C722A7C97F00A6173D /* RelayCache.swift in Sources */, - 58BFA5C022A7C8A900A6173D /* MullvadRpc.swift in Sources */, 580EE21024B322E700F9D8A1 /* TransformOperation.swift in Sources */, 58906DE02445C7A5002F0673 /* NEProviderStopReason+Debug.swift in Sources */, 584E96BD240FD4DA00D3334F /* Location.swift in Sources */, diff --git a/ios/MullvadVPN/AnyEncodable.swift b/ios/MullvadVPN/AnyEncodable.swift new file mode 100644 index 0000000000..b4b27a1507 --- /dev/null +++ b/ios/MullvadVPN/AnyEncodable.swift @@ -0,0 +1,28 @@ +// +// AnyEncodable.swift +// MullvadVPN +// +// Created by pronebird on 21/07/2020. +// Copyright © 2020 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +extension Encodable { + fileprivate func encode(to container: inout SingleValueEncodingContainer) throws { + try container.encode(self) + } +} + +struct AnyEncodable: Encodable { + let value: Encodable + + init(_ value: Encodable) { + self.value = value + } + + func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try value.encode(to: &container) + } +} diff --git a/ios/MullvadVPN/DisplayChainedError.swift b/ios/MullvadVPN/DisplayChainedError.swift index cae6437af2..4fa2883e6b 100644 --- a/ios/MullvadVPN/DisplayChainedError.swift +++ b/ios/MullvadVPN/DisplayChainedError.swift @@ -36,31 +36,6 @@ extension RestError: DisplayChainedError { } } -extension MullvadRpc.Error: DisplayChainedError { - var errorChainDescription: String? { - switch self { - case .network(let urlError): - return urlError.localizedDescription - - case .server(let serverError): - if let knownErrorDescription = serverError.errorDescription { - return knownErrorDescription - } else { - return String( - format: NSLocalizedString("Server error: %@", comment: ""), - serverError.message - ) - } - - case .encoding: - return NSLocalizedString("Server request encoding error", comment: "") - - case .decoding: - return NSLocalizedString("Server response decoding error", comment: "") - } - } -} - extension TunnelManager.Error: DisplayChainedError { var errorChainDescription: String? { switch self { @@ -97,22 +72,22 @@ extension TunnelManager.Error: DisplayChainedError { case .removeTunnelSettings(_): return NSLocalizedString("Failed to remove tunnel settings", comment: "") - case .pushWireguardKey(let rpcError): - let reason = rpcError.errorChainDescription ?? "" + case .pushWireguardKey(let restError): + let reason = restError.errorChainDescription ?? "" var message = String(format: NSLocalizedString("Failed to send the WireGuard key to server: %@", comment: ""), reason) - if case .server(let serverError) = rpcError, serverError.code == .tooManyWireguardKeys { + if case .server(.keyLimitReached) = restError { message.append("\n\n") message.append(NSLocalizedString("Remove unused WireGuard keys and try again", comment: "")) } return message - case .replaceWireguardKey(let rpcError): - let reason = rpcError.errorChainDescription ?? "" + case .replaceWireguardKey(let restError): + let reason = restError.errorChainDescription ?? "" var message = String(format: NSLocalizedString("Failed to replace the WireGuard key on server: %@", comment: ""), reason) - if case .server(let serverError) = rpcError, serverError.code == .tooManyWireguardKeys { + if case .server(.keyLimitReached) = restError { message.append("\n\n") message.append(NSLocalizedString("Remove unused WireGuard keys and try again", comment: "")) } @@ -123,8 +98,8 @@ extension TunnelManager.Error: DisplayChainedError { // This error is never displayed anywhere return nil - case .verifyWireguardKey(let rpcError): - let reason = rpcError.errorChainDescription ?? "" + case .verifyWireguardKey(let restError): + let reason = restError.errorChainDescription ?? "" return String(format: NSLocalizedString("Failed to verify the WireGuard key on server: %@", comment: ""), reason) @@ -157,8 +132,8 @@ extension AppStorePaymentManager.Error: DisplayChainedError { case .readReceipt(let readReceiptError): return String(format: NSLocalizedString("Cannot read the receipt: %@", comment: ""), readReceiptError.errorChainDescription ?? "") - case .sendReceipt(let rpcError): - let reason = rpcError.errorChainDescription ?? "" + case .sendReceipt(let restError): + let reason = restError.errorChainDescription ?? "" return String(format: NSLocalizedString(#"Failed to send the receipt to server: %@\n\nPlease retry by using the "Restore purchases" button."#, comment: ""), reason) diff --git a/ios/MullvadVPN/JsonRpc.swift b/ios/MullvadVPN/JsonRpc.swift deleted file mode 100644 index a41678fa1e..0000000000 --- a/ios/MullvadVPN/JsonRpc.swift +++ /dev/null @@ -1,87 +0,0 @@ -// -// JsonRpc.swift -// MullvadVPN -// -// Created by pronebird on 02/05/2019. -// Copyright © 2019 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -extension Encodable { - fileprivate func encode(to container: inout SingleValueEncodingContainer) throws { - try container.encode(self) - } -} - -struct AnyEncodable: Encodable { - let value: Encodable - - init(_ value: Encodable) { - self.value = value - } - - func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try value.encode(to: &container) - } -} - -struct JsonRpcRequest: Encodable { - let version = "2.0" - let id = UUID().uuidString - let method: String - let params: [AnyEncodable] - - fileprivate enum CodingKeys: String, CodingKey { - case version = "jsonrpc", id, method, params - } -} - -class JsonRpcResponseError<ResponseCode>: Error, Decodable - where ResponseCode: Decodable -{ - let code: ResponseCode - let message: String - - var localizedDescription: String { - return message - } - - private enum CodingKeys: String, CodingKey { - case code, message - } - - required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - code = try container.decode(ResponseCode.self, forKey: .code) - message = try container.decode(String.self, forKey: .message) - } -} - -struct JsonRpcResponse<T, ResponseCode>: Decodable - where - T: Decodable, ResponseCode: Decodable -{ - let version: String - let id: String - let result: Result<T, JsonRpcResponseError<ResponseCode>> - - private enum CodingKeys: String, CodingKey { - case version = "jsonrpc", id, result, error - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.version = try container.decode(String.self, forKey: .version) - self.id = try container.decode(String.self, forKey: .id) - - if container.contains(.result) { - self.result = .success(try container.decode(T.self, forKey: .result)) - } else { - self.result = .failure(try container.decode(JsonRpcResponseError<ResponseCode>.self, forKey: .error)) - } - } -} diff --git a/ios/MullvadVPN/MullvadRpc.swift b/ios/MullvadVPN/MullvadRpc.swift deleted file mode 100644 index 59c53348fe..0000000000 --- a/ios/MullvadVPN/MullvadRpc.swift +++ /dev/null @@ -1,347 +0,0 @@ -// -// MullvadRpc.swift -// MullvadVPN -// -// Created by pronebird on 02/05/2019. -// Copyright © 2019 Mullvad VPN AB. All rights reserved. -// - -import Foundation -import Network - -/// API server URL -private let kMullvadAPIURL = URL(string: "https://api.mullvad.net/rpc/")! - -/// Network request timeout in seconds -private let kNetworkTimeout: TimeInterval = 10 - -/// A response received when sending the AppStore receipt to the backend -struct SendAppStoreReceiptResponse: Codable { - let timeAdded: TimeInterval - let newExpiry: Date - - /// Returns a formatted string for the `timeAdded` interval, i.e "30 days" - var formattedTimeAdded: String? { - let formatter = DateComponentsFormatter() - formatter.allowedUnits = [.day, .hour] - formatter.unitsStyle = .full - - return formatter.string(from: timeAdded) - } -} - -class MullvadRpc { - private let session: URLSession - - /// A enum mapping the integer codes returned by Mullvad API with the corresponding enum - /// variants - private enum RawResponseCode: Int { - case accountDoesNotExist = -200 - case tooManyWireguardKeys = -703 - } - - /// A enum describing the Mullvad API response code - enum ResponseCode: RawRepresentable, Codable { - var rawValue: Int { - switch self { - case .accountDoesNotExist: - return RawResponseCode.accountDoesNotExist.rawValue - - case .tooManyWireguardKeys: - return RawResponseCode.tooManyWireguardKeys.rawValue - - case .other(let value): - return value - } - } - - init?(rawValue: Int) { - switch RawResponseCode(rawValue: rawValue) { - case .accountDoesNotExist: - self = .accountDoesNotExist - case .tooManyWireguardKeys: - self = .tooManyWireguardKeys - case .none: - self = ResponseCode.other(rawValue) - } - } - - case accountDoesNotExist - case tooManyWireguardKeys - case other(Int) - } - - /// An error type emitted by `MullvadRpc` - enum Error: ChainedError { - /// A network communication error - case network(URLError) - - /// A server error - case server(JsonRpcResponseError<ResponseCode>) - - /// An error occured when decoding the JSON response - case decoding(Swift.Error) - - /// An error occured when encoding the JSON request - case encoding(Swift.Error) - - var errorDescription: String? { - switch self { - case .network: - return "Network error" - - case .server: - return "Server error" - - case .encoding: - return "Encoding error" - - case .decoding: - return "Decoding error" - } - } - } - - /// Returns an instance of `MullvadRpc` configured with ephemeral `URLSession` configuration - class func withEphemeralURLSession() -> MullvadRpc { - return MullvadRpc(session: URLSession(configuration: .ephemeral)) - } - - class func makeJSONEncoder() -> JSONEncoder { - let encoder = JSONEncoder() - encoder.keyEncodingStrategy = .convertToSnakeCase - encoder.dateEncodingStrategy = .iso8601 - encoder.dataEncodingStrategy = .base64 - return encoder - } - - class func makeJSONDecoder() -> JSONDecoder { - let decoder = JSONDecoder() - decoder.keyDecodingStrategy = .convertFromSnakeCase - decoder.dateDecodingStrategy = .iso8601 - decoder.dataDecodingStrategy = .base64 - return decoder - } - - init(session: URLSession) { - self.session = session - } - - func createAccount() -> MullvadRpc.Request<String> { - let request = JsonRpcRequest(method: "create_account", params: []) - - return MullvadRpc.Request(session: session, request: request) - } - - func getRelayList() -> MullvadRpc.Request<RelayList> { - let request = JsonRpcRequest(method: "relay_list_v3", params: []) - - return MullvadRpc.Request(session: session, request: request) - } - - func getAccountExpiry(accountToken: String) -> MullvadRpc.Request<Date> { - let request = JsonRpcRequest(method: "get_expiry", params: [AnyEncodable(accountToken)]) - - return MullvadRpc.Request(session: session, request: request) - } - - func getAccountExpiry(request: MullvadRpc.Request<Date>? = nil) -> MullvadRpc.Operation<Date> { - return MullvadRpc.Operation(request: request) - } - - func pushWireguardKey(accountToken: String, publicKey: Data) -> MullvadRpc.Request<WireguardAssociatedAddresses> { - let request = JsonRpcRequest(method: "push_wg_key", params: [ - AnyEncodable(accountToken), - AnyEncodable(publicKey) - ]) - - return MullvadRpc.Request(session: session, request: request) - } - - func replaceWireguardKey(accountToken: String, oldPublicKey: Data, newPublicKey: Data) -> MullvadRpc.Request<WireguardAssociatedAddresses> { - let request = JsonRpcRequest(method: "replace_wg_key", params: [ - AnyEncodable(accountToken), - AnyEncodable(oldPublicKey), - AnyEncodable(newPublicKey) - ]) - - return MullvadRpc.Request(session: session, request: request) - } - - func checkWireguardKey(accountToken: String, publicKey: Data) -> MullvadRpc.Request<Bool> { - let request = JsonRpcRequest(method: "check_wg_key", params: [ - AnyEncodable(accountToken), - AnyEncodable(publicKey) - ]) - - return MullvadRpc.Request(session: session, request: request) - } - - func checkWireguardKey(request: MullvadRpc.Request<Bool>? = nil) -> MullvadRpc.Operation<Bool> { - return MullvadRpc.Operation(request: request) - } - - func removeWireguardKey(accountToken: String, publicKey: Data) -> MullvadRpc.Request<Bool> { - let request = JsonRpcRequest(method: "remove_wg_key", params: [ - AnyEncodable(accountToken), - AnyEncodable(publicKey) - ]) - - return MullvadRpc.Request(session: session, request: request) - } - - func sendAppStoreReceipt(accountToken: String, receiptData: Data) -> MullvadRpc.Request<SendAppStoreReceiptResponse> { - let request = JsonRpcRequest(method: "apple_payment", params: [ - AnyEncodable(accountToken), - AnyEncodable(receiptData) - ]) - - return MullvadRpc.Request(session: session, request: request) - } -} - - -extension JsonRpcResponseError: LocalizedError - where - ResponseCode == MullvadRpc.ResponseCode -{ - var errorDescription: String? { - switch code { - case .accountDoesNotExist: - return NSLocalizedString("Invalid account", comment: "") - - case .tooManyWireguardKeys: - return NSLocalizedString("Too many public WireGuard keys", comment: "") - - case .other: - return nil - } - } - - var recoverySuggestion: String? { - switch code { - case .tooManyWireguardKeys: - return NSLocalizedString("Remove unused WireGuard keys", comment: "") - - default: - return nil - } - } -} - - -extension MullvadRpc { - - class Request<Response: Decodable> { - typealias RequestCompletionHandler = (Result<Response, MullvadRpc.Error>) -> Void - - private let session: URLSession - private let request: JsonRpcRequest - - private let lock = NSLock() - private var urlSessionTask: URLSessionTask? - - fileprivate init(session: URLSession, request: JsonRpcRequest) { - self.session = session - self.request = request - } - - func start(completionHandler: @escaping RequestCompletionHandler) { - lock.withCriticalBlock { - assert(self.urlSessionTask == nil) - - switch makeURLRequest() { - case .success(let urlRequest): - let task = session.dataTask(with: urlRequest) { (responseData, urlResponse, error) in - switch (responseData, error) { - case (.some(let data), .none): - completionHandler(Self.decodeResponse(data)) - - case (.none, .some(let urlError as URLError)): - completionHandler(.failure(.network(urlError))) - - default: - fatalError() - } - } - self.urlSessionTask = task - task.resume() - - case .failure(let error): - completionHandler(.failure(error)) - } - } - } - - func cancel() { - lock.withCriticalBlock { - self.urlSessionTask?.cancel() - } - } - - func operation() -> MullvadRpc.Operation<Response> { - return MullvadRpc.Operation(request: self) - } - - private func makeURLRequest() -> Result<URLRequest, MullvadRpc.Error> { - do { - let data = try MullvadRpc.makeJSONEncoder().encode(request) - - return .success(Self.makeURLRequest(httpBody: data)) - } catch { - return .failure(.encoding(error)) - } - } - - private static func decodeResponse(_ responseData: Data) -> Result<Response, MullvadRpc.Error> { - do { - let serverResponse = try MullvadRpc.makeJSONDecoder() - .decode(JsonRpcResponse<Response, MullvadRpc.ResponseCode>.self, from: responseData) - - // unwrap JsonRpcResponse.result - return serverResponse.result - .mapError { .server($0) } - } catch { - return .failure(.decoding(error)) - } - } - - private static func makeURLRequest(httpBody: Data) -> URLRequest { - var request = URLRequest( - url: kMullvadAPIURL, - cachePolicy: .useProtocolCachePolicy, - timeoutInterval: kNetworkTimeout - ) - request.addValue("application/json", forHTTPHeaderField: "Content-Type") - request.httpMethod = "POST" - request.httpBody = httpBody - - return request - } - } - - class Operation<Response>: AsyncOperation, InputOperation, OutputOperation where Response: Decodable { - typealias Input = Request<Response> - typealias Output = Result<Response, MullvadRpc.Error> - - init(request: Input? = nil) { - super.init() - self.input = request - } - - override func main() { - guard let request = self.input else { - self.finish() - return - } - - request.start { [weak self] (result) in - self?.finish(with: result) - } - } - - override func operationDidCancel() { - input?.cancel() - } - } -} diff --git a/ios/MullvadVPN/RelayList.swift b/ios/MullvadVPN/RelayList.swift deleted file mode 100644 index d4384696d7..0000000000 --- a/ios/MullvadVPN/RelayList.swift +++ /dev/null @@ -1,91 +0,0 @@ - -// -// RelayList.swift -// MullvadVPN -// -// Created by pronebird on 02/05/2019. -// Copyright © 2019 Mullvad VPN AB. All rights reserved. -// - -import Foundation -import Network - -struct RelayList: Codable { - struct Country: Codable { - var name: String - var code: String - var cities: [City] - } - - struct City: Codable { - var name: String - var code: String - var latitude: Double - var longitude: Double - var relays: [Relay] - } - - struct Relay: Codable { - var hostname: String - var provider: String - var ipv4AddrIn: IPv4Address - var includeInCountry: Bool - var active: Bool - var owned: Bool - var weight: Int32 - var tunnels: Tunnels? - } - - struct Tunnels: Codable { - var wireguard: [WireguardTunnel]? - } - - struct WireguardTunnel: Codable { - var ipv4Gateway: IPv4Address - var ipv6Gateway: IPv6Address - var publicKey: Data - var portRanges: [ClosedRange<UInt16>] - } - - var countries: [Country] -} - -extension RelayList { - - /// Returns the total number of relays - var numRelays: Int { - return countries.reduce(0) { (accum, country) -> Int in - return country.cities.reduce(accum, { (accum, city) -> Int in - return accum + city.relays.count - }) - } - } - - /// Returns an alphabetically sorted `RelayList` - func sorted() -> Self { - let lexicalComparator = { (a: String, b: String) -> Bool in - return a.localizedCaseInsensitiveCompare(b) == .orderedAscending - } - - let fileComparator = { (a: String, b: String) -> Bool in - return a.localizedStandardCompare(b) == .orderedAscending - } - - let sortedCountries = countries - .sorted { lexicalComparator($0.name, $1.name) } - .map { (country) -> RelayList.Country in - var sortedCountry = country - sortedCountry.cities = country.cities.sorted { lexicalComparator($0.name, $1.name) } - .map({ (city) -> RelayList.City in - var sortedCity = city - sortedCity.relays = city.relays - .sorted { fileComparator($0.hostname, $1.hostname) } - return sortedCity - }) - return sortedCountry - } - - return RelayList(countries: sortedCountries) - } - -} |
