From a34caacab2e252d6da35c0dc06c16cc459fb275b Mon Sep 17 00:00:00 2001 From: Bug Magnet Date: Tue, 9 Jan 2024 11:47:18 +0100 Subject: [PATCH] Enable testing API access with a given configuration --- .../APIAvailabilityTestRequest.swift | 55 ++++++++++++++++++ ios/MullvadREST/ApiHandlers/HTTP.swift | 1 + .../ProxyConfigurationTransportProvider.swift | 58 +++++++++++++++++++ .../Transport/RESTTransportProvider.swift | 1 + ios/MullvadRESTTests/HeadRequestTests.swift | 40 +++++++++++++ .../Mocks/RESTTransportStub.swift | 27 +++++++++ .../RequestExecutorTests.swift | 6 +- ios/MullvadVPN.xcodeproj/project.pbxproj | 16 +++++ .../ProxyConfigurationTester.swift | 35 ++++++----- ios/MullvadVPN/AppDelegate.swift | 19 ++++-- .../Coordinators/ApplicationCoordinator.swift | 11 +++- .../Edit/EditAccessMethodCoordinator.swift | 4 +- .../List/ListAccessMethodCoordinator.swift | 6 +- .../Settings/SettingsCoordinator.swift | 8 ++- ios/MullvadVPN/SceneDelegate.swift | 3 +- 15 files changed, 259 insertions(+), 31 deletions(-) create mode 100644 ios/MullvadREST/ApiHandlers/APIAvailabilityTestRequest.swift create mode 100644 ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift create mode 100644 ios/MullvadRESTTests/HeadRequestTests.swift create mode 100644 ios/MullvadRESTTests/Mocks/RESTTransportStub.swift diff --git a/ios/MullvadREST/ApiHandlers/APIAvailabilityTestRequest.swift b/ios/MullvadREST/ApiHandlers/APIAvailabilityTestRequest.swift new file mode 100644 index 000000000000..03c180c34929 --- /dev/null +++ b/ios/MullvadREST/ApiHandlers/APIAvailabilityTestRequest.swift @@ -0,0 +1,55 @@ +// +// APIAvailabilityTestRequest.swift +// MullvadREST +// +// Created by Marco Nikic on 2024-01-08. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadTypes + +extension REST { + public struct APIAvailabilityTestRequest { + let transport: RESTTransport + + public init(transport: RESTTransport) { + self.transport = transport + } + + /// Executes an HTTP `HEAD` request to the "api-addrs" endpoint. + /// + /// - Parameter completion: Completes with `nil` if the request was successful, and `Error` otherwise. + /// - Returns: A cancellable token to cancel the request inflight. + public func makeRequest(completion: @escaping (Swift.Error?) -> Void) -> Cancellable { + do { + let factory = RequestFactory( + hostname: defaultAPIHostname, + pathPrefix: "/app/v1", + networkTimeout: defaultAPINetworkTimeout, + bodyEncoder: JSONEncoder() + ) + var request = try factory.createRequest( + endpoint: defaultAPIEndpoint, + method: .head, + pathTemplate: "api-addrs" + ) + request.urlRequest.cachePolicy = .reloadIgnoringLocalCacheData + + return transport.sendRequest(request.urlRequest) { _, response, error in + // Any response in the form of `HTTPURLResponse` means that the API was reached successfully + // and implying an HTTP server is running, therefore the test is considered successful. + guard response is HTTPURLResponse else { + completion(error) + return + } + completion(nil) + } + + } catch { + completion(error) + } + return AnyCancellable() + } + } +} diff --git a/ios/MullvadREST/ApiHandlers/HTTP.swift b/ios/MullvadREST/ApiHandlers/HTTP.swift index 93074fdbd35a..8a14e957d11a 100644 --- a/ios/MullvadREST/ApiHandlers/HTTP.swift +++ b/ios/MullvadREST/ApiHandlers/HTTP.swift @@ -14,6 +14,7 @@ struct HTTPMethod: RawRepresentable { static let post = HTTPMethod(rawValue: "POST") static let delete = HTTPMethod(rawValue: "DELETE") static let put = HTTPMethod(rawValue: "PUT") + static let head = HTTPMethod(rawValue: "HEAD") let rawValue: String init(rawValue: String) { diff --git a/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift b/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift new file mode 100644 index 000000000000..356b9c1b1953 --- /dev/null +++ b/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift @@ -0,0 +1,58 @@ +// +// ProxyConfigurationTransportProvider.swift +// MullvadREST +// +// Created by Marco Nikic on 2024-01-19. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadSettings +import MullvadTypes + +/// Allows the creation of `RESTTransport` objects that bypass the network routing logic provided by `TransportProvider`. +public class ProxyConfigurationTransportProvider { + private let shadowsocksLoader: ShadowsocksLoaderProtocol + private let addressCache: REST.AddressCache + + public init(shadowsocksLoader: ShadowsocksLoaderProtocol, addressCache: REST.AddressCache) { + self.shadowsocksLoader = shadowsocksLoader + self.addressCache = addressCache + } + + public func makeTransport(with configuration: PersistentProxyConfiguration) throws -> RESTTransport { + let urlSession = REST.makeURLSession() + switch configuration { + case .direct: + return URLSessionTransport(urlSession: urlSession) + case .bridges: + let shadowsocksConfiguration = try shadowsocksLoader.load() + return ShadowsocksTransport( + urlSession: urlSession, + configuration: shadowsocksConfiguration, + addressCache: addressCache + ) + case let .shadowsocks(shadowSocksConfiguration): + return ShadowsocksTransport( + urlSession: urlSession, + configuration: ShadowsocksConfiguration( + address: shadowSocksConfiguration.server, + port: shadowSocksConfiguration.port, + password: shadowSocksConfiguration.password, + cipher: shadowSocksConfiguration.cipher.rawValue.description + ), + addressCache: addressCache + ) + case let .socks5(socksConfiguration): + return URLSessionSocks5Transport( + urlSession: urlSession, + configuration: Socks5Configuration( + proxyEndpoint: socksConfiguration.toAnyIPEndpoint, + username: socksConfiguration.credential?.username, + password: socksConfiguration.credential?.password + ), + addressCache: addressCache + ) + } + } +} diff --git a/ios/MullvadREST/Transport/RESTTransportProvider.swift b/ios/MullvadREST/Transport/RESTTransportProvider.swift index 5476338ece2a..33e661bc9c33 100644 --- a/ios/MullvadREST/Transport/RESTTransportProvider.swift +++ b/ios/MullvadREST/Transport/RESTTransportProvider.swift @@ -7,6 +7,7 @@ // import Foundation +import MullvadSettings public protocol RESTTransportProvider { func makeTransport() -> RESTTransport? diff --git a/ios/MullvadRESTTests/HeadRequestTests.swift b/ios/MullvadRESTTests/HeadRequestTests.swift new file mode 100644 index 000000000000..e5424538dbfa --- /dev/null +++ b/ios/MullvadRESTTests/HeadRequestTests.swift @@ -0,0 +1,40 @@ +// +// HeadRequestTests.swift +// MullvadRESTTests +// +// Created by Marco Nikic on 2024-01-22. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +@testable import MullvadREST +import XCTest + +class HeadRequestTests: XCTestCase { + func testSuccessfulRequestHasNoError() throws { + let transport = RESTTransportStub(data: Data(), response: HTTPURLResponse()) + let request = REST.APIAvailabilityTestRequest(transport: transport) + + let successfulRequestExpectation = expectation(description: "HEAD request completed") + _ = request.makeRequest { error in + if error == nil { + successfulRequestExpectation.fulfill() + } + } + + wait(for: [successfulRequestExpectation], timeout: 1) + } + + func testRequestWithErrors() throws { + let transport = RESTTransportStub(error: URLError(.timedOut)) + let request = REST.APIAvailabilityTestRequest(transport: transport) + + let failedRequestExpectation = expectation(description: "HEAD request failed") + _ = request.makeRequest { error in + if error != nil { + failedRequestExpectation.fulfill() + } + } + + wait(for: [failedRequestExpectation], timeout: 1) + } +} diff --git a/ios/MullvadRESTTests/Mocks/RESTTransportStub.swift b/ios/MullvadRESTTests/Mocks/RESTTransportStub.swift new file mode 100644 index 000000000000..5e0915554b22 --- /dev/null +++ b/ios/MullvadRESTTests/Mocks/RESTTransportStub.swift @@ -0,0 +1,27 @@ +// +// RESTTransportStub.swift +// MullvadRESTTests +// +// Created by Marco Nikic on 2024-01-22. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +@testable import MullvadREST +@testable import MullvadTypes +import XCTest + +struct RESTTransportStub: RESTTransport { + let name = "transport-stub" + + var data: Data? + var response: URLResponse? + var error: Error? + + func sendRequest( + _ request: URLRequest, + completion: @escaping (Data?, URLResponse?, Error?) -> Void + ) -> Cancellable { + completion(data, response, error) + return AnyCancellable() + } +} diff --git a/ios/MullvadRESTTests/RequestExecutorTests.swift b/ios/MullvadRESTTests/RequestExecutorTests.swift index e4ca6b953778..d257007f8328 100644 --- a/ios/MullvadRESTTests/RequestExecutorTests.swift +++ b/ios/MullvadRESTTests/RequestExecutorTests.swift @@ -7,7 +7,7 @@ // @testable import MullvadREST -import MullvadTypes +@testable import MullvadTypes import XCTest final class RequestExecutorTests: XCTestCase { @@ -18,8 +18,8 @@ final class RequestExecutorTests: XCTestCase { super.setUp() let transportProvider = REST.AnyTransportProvider { - return AnyTransport { - return Response(delay: 1, statusCode: 200, value: TimeResponse(dateTime: Date())) + AnyTransport { + Response(delay: 1, statusCode: 200, value: TimeResponse(dateTime: Date())) } } diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 0e6a5225cb8b..b8ee9d98a5fb 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -611,6 +611,10 @@ A917352129FAAA5200D5DCFD /* TransportStrategyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A917352029FAAA5200D5DCFD /* TransportStrategyTests.swift */; }; A91D78E32B03BDF200FCD5D3 /* TunnelObfuscation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5840231F2A406BF5007B27AC /* TunnelObfuscation.framework */; }; A91D78E42B03C01600FCD5D3 /* MullvadSettings.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 58B2FDD32AA71D2A003EB5C6 /* MullvadSettings.framework */; }; + A932D9EF2B5ADD0700999395 /* ProxyConfigurationTransportProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A932D9EE2B5ADD0700999395 /* ProxyConfigurationTransportProvider.swift */; }; + A932D9F32B5EB61100999395 /* HeadRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A932D9F22B5EB61100999395 /* HeadRequestTests.swift */; }; + A932D9F52B5EBB9D00999395 /* RESTTransportStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = A932D9F42B5EBB9D00999395 /* RESTTransportStub.swift */; }; + A935594C2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935594B2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift */; }; A94D691A2ABAD66700413DD4 /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = 58FE25E22AA72AE9003D1918 /* WireGuardKitTypes */; }; A94D691B2ABAD66700413DD4 /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = 58FE25E72AA7399D003D1918 /* WireGuardKitTypes */; }; A970C89D2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = A970C89C2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift */; }; @@ -1773,6 +1777,10 @@ A92ECC232A7802520052F1B1 /* StoredAccountData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredAccountData.swift; sourceTree = ""; }; A92ECC272A7802AB0052F1B1 /* StoredDeviceData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredDeviceData.swift; sourceTree = ""; }; A92ECC2B2A7803A50052F1B1 /* DeviceState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceState.swift; sourceTree = ""; }; + A932D9EE2B5ADD0700999395 /* ProxyConfigurationTransportProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyConfigurationTransportProvider.swift; sourceTree = ""; }; + A932D9F22B5EB61100999395 /* HeadRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadRequestTests.swift; sourceTree = ""; }; + A932D9F42B5EBB9D00999395 /* RESTTransportStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RESTTransportStub.swift; sourceTree = ""; }; + A935594B2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIAvailabilityTestRequest.swift; sourceTree = ""; }; A935594D2B4E919F00D5D524 /* Api.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Api.xcconfig; sourceTree = ""; }; A9467E7E2A29DEFE000DC21F /* RelayCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayCacheTests.swift; sourceTree = ""; }; A970C89C2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Socks5UsernamePasswordCommand.swift; sourceTree = ""; }; @@ -2834,6 +2842,7 @@ children = ( 58BDEB982A98F4ED00F578F2 /* AnyTransport.swift */, 58BDEB9C2A98F69E00F578F2 /* MemoryCache.swift */, + A932D9F42B5EBB9D00999395 /* RESTTransportStub.swift */, 58BDEB9A2A98F58600F578F2 /* TimeServerProxy.swift */, ); path = Mocks; @@ -3248,6 +3257,7 @@ children = ( F0164EB92B4456D30020268D /* AccessMethodRepositoryStub.swift */, 58FBFBE8291622580020E046 /* ExponentialBackoffTests.swift */, + A932D9F22B5EB61100999395 /* HeadRequestTests.swift */, 58BDEB9E2A98F6B400F578F2 /* Mocks */, 58B4656F2A98C53300467203 /* RequestExecutorTests.swift */, F0164EC22B4C49D30020268D /* ShadowsocksLoaderStub.swift */, @@ -3409,6 +3419,7 @@ isa = PBXGroup; children = ( 06AC114128F8413A0037AF9A /* AddressCache.swift */, + A935594B2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift */, 06FAE67128F83CA40033DD93 /* HTTP.swift */, 06FAE67228F83CA40033DD93 /* RESTAccessTokenManager.swift */, 06FAE66828F83CA30033DD93 /* RESTAccountsProxy.swift */, @@ -3459,6 +3470,7 @@ isa = PBXGroup; children = ( F0164ED02B4F2DCB0020268D /* AccessMethodIterator.swift */, + A932D9EE2B5ADD0700999395 /* ProxyConfigurationTransportProvider.swift */, F0DC77A32B2315800087F09D /* Direct */, F0164EC02B4C03980020268D /* LastReachableApiAccessCache.swift */, 06FAE67D28F83CA50033DD93 /* RESTTransport.swift */, @@ -4391,6 +4403,7 @@ files = ( F05F39982B21C73C006E60A7 /* CachedRelays.swift in Sources */, F05F39972B21C735006E60A7 /* RelayCache.swift in Sources */, + A932D9EF2B5ADD0700999395 /* ProxyConfigurationTransportProvider.swift in Sources */, 06799AE728F98E4800ACD94E /* RESTURLSession.swift in Sources */, A90763B52B2857D50045ADF0 /* Socks5Constants.swift in Sources */, A90763BA2B2857D50045ADF0 /* Socks5Error.swift in Sources */, @@ -4449,6 +4462,7 @@ 06799ADF28F98E4800ACD94E /* RESTDevicesProxy.swift in Sources */, 06799ADA28F98E4800ACD94E /* RESTResponseHandler.swift in Sources */, 062B45BC28FD8C3B00746E77 /* RESTDefaults.swift in Sources */, + A935594C2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift in Sources */, A90763C32B2858630045ADF0 /* Socks5Configuration.swift in Sources */, 06799AE428F98E4800ACD94E /* RESTAccountsProxy.swift in Sources */, 5897F1742913EAF800AF5695 /* ExponentialBackoff.swift in Sources */, @@ -5185,7 +5199,9 @@ F0164EC32B4C49D30020268D /* ShadowsocksLoaderStub.swift in Sources */, 58BDEB9D2A98F69E00F578F2 /* MemoryCache.swift in Sources */, 58BDEB9B2A98F58600F578F2 /* TimeServerProxy.swift in Sources */, + A932D9F52B5EBB9D00999395 /* RESTTransportStub.swift in Sources */, 58BDEB992A98F4ED00F578F2 /* AnyTransport.swift in Sources */, + A932D9F32B5EB61100999395 /* HeadRequestTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ios/MullvadVPN/AccessMethodRepository/ProxyConfigurationTester.swift b/ios/MullvadVPN/AccessMethodRepository/ProxyConfigurationTester.swift index 95f6b302f719..03e108968a9c 100644 --- a/ios/MullvadVPN/AccessMethodRepository/ProxyConfigurationTester.swift +++ b/ios/MullvadVPN/AccessMethodRepository/ProxyConfigurationTester.swift @@ -8,31 +8,38 @@ import Combine import Foundation +import MullvadREST import MullvadSettings +import MullvadTypes /// A concrete implementation of an access method proxy configuration. class ProxyConfigurationTester: ProxyConfigurationTesterProtocol { - private var cancellable: Cancellable? + private var cancellable: MullvadTypes.Cancellable? + private let transportProvider: ProxyConfigurationTransportProvider + private var headRequest: REST.APIAvailabilityTestRequest? - static let shared = ProxyConfigurationTester() - - init() {} + init(transportProvider: ProxyConfigurationTransportProvider) { + self.transportProvider = transportProvider + } func start(configuration: PersistentProxyConfiguration, completion: @escaping (Error?) -> Void) { - let workItem = DispatchWorkItem { - let randomResult = (0 ... 255).randomElement()?.isMultiple(of: 2) ?? true - - completion(randomResult ? nil : URLError(.timedOut)) - } - - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute: workItem) - - cancellable = AnyCancellable { - workItem.cancel() + do { + let transport = try transportProvider.makeTransport(with: configuration) + let request = REST.APIAvailabilityTestRequest(transport: transport) + headRequest = request + cancellable = request.makeRequest { error in + DispatchQueue.main.async { + completion(error) + } + } + } catch { + completion(error) } } func cancel() { + cancellable?.cancel() cancellable = nil + headRequest = nil } } diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift index 8a49c19fef79..fba6e13391fd 100644 --- a/ios/MullvadVPN/AppDelegate.swift +++ b/ios/MullvadVPN/AppDelegate.swift @@ -43,6 +43,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD private let migrationManager = MigrationManager() private(set) var accessMethodRepository = AccessMethodRepository() + private(set) var shadowsocksLoader: ShadowsocksLoaderProtocol! + private(set) var configuredTransportProvider: ProxyConfigurationTransportProvider! // MARK: - Application lifecycle @@ -94,14 +96,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // This init cannot fail as long as the security group identifier is valid let sharedUserDefaults = UserDefaults(suiteName: ApplicationConfiguration.securityGroupIdentifier)! + shadowsocksLoader = ShadowsocksLoader( + shadowsocksCache: shadowsocksCache, + relayCache: relayCache, + constraintsUpdater: constraintsUpdater + ) + + configuredTransportProvider = ProxyConfigurationTransportProvider( + shadowsocksLoader: shadowsocksLoader, + addressCache: addressCache + ) + let transportStrategy = TransportStrategy( sharedUserDefaults, datasource: accessMethodRepository, - shadowsocksLoader: ShadowsocksLoader( - shadowsocksCache: shadowsocksCache, - relayCache: relayCache, - constraintsUpdater: constraintsUpdater - ) + shadowsocksLoader: shadowsocksLoader ) let transportProvider = TransportProvider( diff --git a/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift b/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift index c56c376721a8..719c97066af3 100644 --- a/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift @@ -78,6 +78,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo private var appPreferences: AppPreferencesDataSource private var outgoingConnectionService: OutgoingConnectionServiceHandling private var accessMethodRepository: AccessMethodRepositoryProtocol + private let configuredTransportProvider: ProxyConfigurationTransportProvider private var outOfTimeTimer: Timer? @@ -94,7 +95,8 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo accountsProxy: RESTAccountHandling, outgoingConnectionService: OutgoingConnectionServiceHandling, appPreferences: AppPreferencesDataSource, - accessMethodRepository: AccessMethodRepositoryProtocol + accessMethodRepository: AccessMethodRepositoryProtocol, + transportProvider: ProxyConfigurationTransportProvider ) { self.tunnelManager = tunnelManager self.storePaymentManager = storePaymentManager @@ -105,6 +107,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo self.appPreferences = appPreferences self.outgoingConnectionService = outgoingConnectionService self.accessMethodRepository = accessMethodRepository + self.configuredTransportProvider = transportProvider super.init() @@ -758,10 +761,14 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo ) let navigationController = CustomNavigationController() + + let configurationTester = ProxyConfigurationTester(transportProvider: configuredTransportProvider) + let coordinator = SettingsCoordinator( navigationController: navigationController, interactorFactory: interactorFactory, - accessMethodRepository: accessMethodRepository + accessMethodRepository: accessMethodRepository, + proxyConfigurationTester: configurationTester ) coordinator.didFinish = { [weak self] _ in diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodCoordinator.swift index 237b3f1ea2a1..4e7d5c17b72b 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodCoordinator.swift @@ -15,7 +15,7 @@ class EditAccessMethodCoordinator: Coordinator { let navigationController: UINavigationController let subject: CurrentValueSubject = .init(AccessMethodViewModel()) let accessMethodRepo: AccessMethodRepositoryProtocol - let proxyConfigurationTester: ProxyConfigurationTester + let proxyConfigurationTester: ProxyConfigurationTesterProtocol let methodIdentifier: UUID var onFinish: ((EditAccessMethodCoordinator) -> Void)? @@ -23,7 +23,7 @@ class EditAccessMethodCoordinator: Coordinator { init( navigationController: UINavigationController, accessMethodRepo: AccessMethodRepositoryProtocol, - proxyConfigurationTester: ProxyConfigurationTester, + proxyConfigurationTester: ProxyConfigurationTesterProtocol, methodIdentifier: UUID ) { self.navigationController = navigationController diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodCoordinator.swift index c355343d2c31..0cfa2d508932 100644 --- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodCoordinator.swift @@ -13,7 +13,7 @@ import UIKit class ListAccessMethodCoordinator: Coordinator, Presenting, SettingsChildCoordinator { let navigationController: UINavigationController let accessMethodRepository: AccessMethodRepositoryProtocol - let proxyConfigurationTester: ProxyConfigurationTester = .shared + let proxyConfigurationTester: ProxyConfigurationTesterProtocol var presentationContext: UIViewController { navigationController @@ -21,10 +21,12 @@ class ListAccessMethodCoordinator: Coordinator, Presenting, SettingsChildCoordin init( navigationController: UINavigationController, - accessMethodRepository: AccessMethodRepositoryProtocol + accessMethodRepository: AccessMethodRepositoryProtocol, + proxyConfigurationTester: ProxyConfigurationTesterProtocol ) { self.navigationController = navigationController self.accessMethodRepository = accessMethodRepository + self.proxyConfigurationTester = proxyConfigurationTester } func start(animated: Bool) { diff --git a/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift index 06178b93e99a..b2d7d3dfc6dd 100644 --- a/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift @@ -42,6 +42,7 @@ final class SettingsCoordinator: Coordinator, Presentable, Presenting, SettingsV private var currentRoute: SettingsNavigationRoute? private var modalRoute: SettingsNavigationRoute? private let accessMethodRepository: AccessMethodRepositoryProtocol + private let proxyConfigurationTester: ProxyConfigurationTesterProtocol let navigationController: UINavigationController @@ -66,11 +67,13 @@ final class SettingsCoordinator: Coordinator, Presentable, Presenting, SettingsV init( navigationController: UINavigationController, interactorFactory: SettingsInteractorFactory, - accessMethodRepository: AccessMethodRepositoryProtocol + accessMethodRepository: AccessMethodRepositoryProtocol, + proxyConfigurationTester: ProxyConfigurationTesterProtocol ) { self.navigationController = navigationController self.interactorFactory = interactorFactory self.accessMethodRepository = accessMethodRepository + self.proxyConfigurationTester = proxyConfigurationTester } /// Start the coordinator fllow. @@ -255,7 +258,8 @@ final class SettingsCoordinator: Coordinator, Presentable, Presenting, SettingsV case .apiAccess: return .childCoordinator(ListAccessMethodCoordinator( navigationController: navigationController, - accessMethodRepository: accessMethodRepository + accessMethodRepository: accessMethodRepository, + proxyConfigurationTester: proxyConfigurationTester )) case .ipOverride: diff --git a/ios/MullvadVPN/SceneDelegate.swift b/ios/MullvadVPN/SceneDelegate.swift index cb7347c9e610..c65b09881422 100644 --- a/ios/MullvadVPN/SceneDelegate.swift +++ b/ios/MullvadVPN/SceneDelegate.swift @@ -76,7 +76,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, SettingsMigrationUIHand outgoingConnectionProxy: OutgoingConnectionProxy(urlSession: URLSession(configuration: .ephemeral)) ), appPreferences: AppPreferences(), - accessMethodRepository: accessMethodRepository + accessMethodRepository: accessMethodRepository, + transportProvider: appDelegate.configuredTransportProvider ) appCoordinator?.onShowSettings = { [weak self] in