From 11bd86804f93f5151d2a3dfc11ec694b4e7d00ae Mon Sep 17 00:00:00 2001 From: Jon Petersson Date: Wed, 25 Sep 2024 13:43:59 +0200 Subject: [PATCH] Add smart routing to daita settings data --- ios/MullvadREST/Relay/RelayPicking.swift | 4 +-- ios/MullvadSettings/DAITASettings.swift | 34 ++++++++++++++++--- .../Coordinators/LocationCoordinator.swift | 2 +- .../SimulatorTunnelProviderHost.swift | 2 +- .../TunnelManager/StartTunnelOperation.swift | 2 +- .../VPNSettings/VPNSettingsCellFactory.swift | 4 +-- .../VPNSettings/VPNSettingsInteractor.swift | 2 +- .../Relay/MultihopDecisionFlowTests.swift | 2 +- .../MullvadREST/Relay/RelayPickingTests.swift | 6 ++-- .../Relay/RelaySelectorWrapperTests.swift | 12 +++---- .../TunnelSettingsUpdateTests.swift | 2 +- .../Actor/PacketTunnelActor+PostQuantum.swift | 2 +- .../Actor/PacketTunnelActor.swift | 8 ++--- 13 files changed, 54 insertions(+), 28 deletions(-) diff --git a/ios/MullvadREST/Relay/RelayPicking.swift b/ios/MullvadREST/Relay/RelayPicking.swift index 15ae2ee90ce5..4d752d37079d 100644 --- a/ios/MullvadREST/Relay/RelayPicking.swift +++ b/ios/MullvadREST/Relay/RelayPicking.swift @@ -49,7 +49,7 @@ struct SinglehopPicker: RelayPicking { by: constraints.exitLocations, in: relays, filterConstraint: constraints.filter, - daitaEnabled: daitaSettings.state.isEnabled + daitaEnabled: daitaSettings.daitaState.isEnabled ) } catch let error as NoRelaysSatisfyingConstraintsError where error.reason == .noDaitaRelaysFound { #if DEBUG @@ -83,7 +83,7 @@ struct MultihopPicker: RelayPicking { by: constraints.entryLocations, in: relays, filterConstraint: constraints.filter, - daitaEnabled: daitaSettings.state.isEnabled + daitaEnabled: daitaSettings.daitaState.isEnabled ) let exitCandidates = try RelaySelector.WireGuard.findCandidates( diff --git a/ios/MullvadSettings/DAITASettings.swift b/ios/MullvadSettings/DAITASettings.swift index ca946b68911b..9e0a0f1fb778 100644 --- a/ios/MullvadSettings/DAITASettings.swift +++ b/ios/MullvadSettings/DAITASettings.swift @@ -18,15 +18,41 @@ public enum DAITAState: Codable { } } -/// Selected relay is incompatible with Daita, either through singlehop or multihop. +/// Whether smart routing is enabled +public enum SmartRoutingState: Codable { + case on + case off + + public var isEnabled: Bool { + self == .on + } +} + +/// Selected relay is incompatible with DAITA, either through singlehop or multihop. public enum DAITASettingsCompatibilityError { case singlehop, multihop } public struct DAITASettings: Codable, Equatable { - public let state: DAITAState + @available(*, deprecated, renamed: "daitaState") + public let state: DAITAState = .off + + public let daitaState: DAITAState + public let smartRoutingState: SmartRoutingState + + public init(daitaState: DAITAState = .off, smartRoutingState: SmartRoutingState = .off) { + self.daitaState = daitaState + self.smartRoutingState = smartRoutingState + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + daitaState = try container.decodeIfPresent(DAITAState.self, forKey: .daitaState) + ?? container.decodeIfPresent(DAITAState.self, forKey: .state) + ?? .off - public init(state: DAITAState = .off) { - self.state = state + smartRoutingState = try container.decodeIfPresent(SmartRoutingState.self, forKey: .smartRoutingState) + ?? .off } } diff --git a/ios/MullvadVPN/Coordinators/LocationCoordinator.swift b/ios/MullvadVPN/Coordinators/LocationCoordinator.swift index 222a20db1b79..36c6f52cdf78 100644 --- a/ios/MullvadVPN/Coordinators/LocationCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/LocationCoordinator.swift @@ -62,7 +62,7 @@ class LocationCoordinator: Coordinator, Presentable, Presenting { customListRepository: customListRepository, constraints: tunnelManager.settings.relayConstraints, multihopEnabled: tunnelManager.settings.tunnelMultihopState.isEnabled, - daitaEnabled: tunnelManager.settings.daita.state.isEnabled, + daitaEnabled: tunnelManager.settings.daita.daitaState.isEnabled, startContext: startContext ) locationViewControllerWrapper.delegate = self diff --git a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift index 561039f1a098..3dd21b1351a7 100644 --- a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift +++ b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift @@ -182,7 +182,7 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { remotePort: selectedRelays.entry?.endpoint.ipv4Relay.port ?? selectedRelays.exit.endpoint.ipv4Relay .port, isPostQuantum: settings.tunnelQuantumResistance.isEnabled, - isDaitaEnabled: settings.daita.state.isEnabled + isDaitaEnabled: settings.daita.daitaState.isEnabled ) ) } catch { diff --git a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift index eb2ece3a13e1..c6b712061ccc 100644 --- a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift +++ b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift @@ -93,7 +93,7 @@ class StartTunnelOperation: ResultOperation { tunnelStatus.state = .connecting( selectedRelays, isPostQuantum: interactor.settings.tunnelQuantumResistance.isEnabled, - isDaita: interactor.settings.daita.state.isEnabled + isDaita: interactor.settings.daita.daitaState.isEnabled ) } diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift index 42f1c29afcc9..996e340dc4dd 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift @@ -216,7 +216,7 @@ final class VPNSettingsCellFactory: CellFactoryProtocol { comment: "" ) cell.accessibilityIdentifier = item.accessibilityIdentifier - cell.setOn(viewModel.daitaSettings.state.isEnabled, animated: false) + cell.setOn(viewModel.daitaSettings.daitaState.isEnabled, animated: false) cell.infoButtonHandler = { [weak self] in self?.delegate?.showInfo(for: .daita) @@ -224,7 +224,7 @@ final class VPNSettingsCellFactory: CellFactoryProtocol { cell.action = { [weak self] isEnabled in let state: DAITAState = isEnabled ? .on : .off - self?.delegate?.switchDaitaState(DAITASettings(state: state)) + self?.delegate?.switchDaitaState(DAITASettings(daitaState: state)) } case .multihopSwitch: diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInteractor.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInteractor.swift index c7a5749ce24f..8857c46493e8 100644 --- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInteractor.swift +++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInteractor.swift @@ -53,7 +53,7 @@ final class VPNSettingsInteractor { } func evaluateDaitaSettingsCompatibility(_ settings: DAITASettings) -> DAITASettingsCompatibilityError? { - guard settings.state.isEnabled else { return nil } + guard settings.daitaState.isEnabled else { return nil } var tunnelSettings = tunnelSettings tunnelSettings.daita = settings diff --git a/ios/MullvadVPNTests/MullvadREST/Relay/MultihopDecisionFlowTests.swift b/ios/MullvadVPNTests/MullvadREST/Relay/MultihopDecisionFlowTests.swift index 190593778fed..7f004ad5a91e 100644 --- a/ios/MullvadVPNTests/MullvadREST/Relay/MultihopDecisionFlowTests.swift +++ b/ios/MullvadVPNTests/MullvadREST/Relay/MultihopDecisionFlowTests.swift @@ -120,7 +120,7 @@ extension MultihopDecisionFlowTests { return MultihopPicker( constraints: constraints, - daitaSettings: DAITASettings(state: .off), + daitaSettings: DAITASettings(daitaState: .off), relays: sampleRelays, connectionAttemptCount: 0 ) diff --git a/ios/MullvadVPNTests/MullvadREST/Relay/RelayPickingTests.swift b/ios/MullvadVPNTests/MullvadREST/Relay/RelayPickingTests.swift index 9229d4ab8f31..73d538ab1b09 100644 --- a/ios/MullvadVPNTests/MullvadREST/Relay/RelayPickingTests.swift +++ b/ios/MullvadVPNTests/MullvadREST/Relay/RelayPickingTests.swift @@ -24,7 +24,7 @@ class RelayPickingTests: XCTestCase { let picker = SinglehopPicker( constraints: constraints, - daitaSettings: DAITASettings(state: .off), + daitaSettings: DAITASettings(daitaState: .off), relays: sampleRelays, connectionAttemptCount: 0 ) @@ -43,7 +43,7 @@ class RelayPickingTests: XCTestCase { let picker = MultihopPicker( constraints: constraints, - daitaSettings: DAITASettings(state: .off), + daitaSettings: DAITASettings(daitaState: .off), relays: sampleRelays, connectionAttemptCount: 0 ) @@ -62,7 +62,7 @@ class RelayPickingTests: XCTestCase { let picker = MultihopPicker( constraints: constraints, - daitaSettings: DAITASettings(state: .off), + daitaSettings: DAITASettings(daitaState: .off), relays: sampleRelays, connectionAttemptCount: 0 ) diff --git a/ios/MullvadVPNTests/MullvadREST/Relay/RelaySelectorWrapperTests.swift b/ios/MullvadVPNTests/MullvadREST/Relay/RelaySelectorWrapperTests.swift index beca599c5ffc..2bc33ca86eea 100644 --- a/ios/MullvadVPNTests/MullvadREST/Relay/RelaySelectorWrapperTests.swift +++ b/ios/MullvadVPNTests/MullvadREST/Relay/RelaySelectorWrapperTests.swift @@ -48,7 +48,7 @@ class RelaySelectorWrapperTests: XCTestCase { let settings = LatestTunnelSettings( relayConstraints: singlehopWithoutDaitaConstraints, tunnelMultihopState: .off, - daita: DAITASettings(state: .off) + daita: DAITASettings(daitaState: .off) ) let selectedRelays = try wrapper.selectRelays(tunnelSettings: settings, connectionAttemptCount: 0) @@ -61,7 +61,7 @@ class RelaySelectorWrapperTests: XCTestCase { let settings = LatestTunnelSettings( relayConstraints: multihopWithDaitaConstraints, tunnelMultihopState: .on, - daita: DAITASettings(state: .off) + daita: DAITASettings(daitaState: .off) ) let selectedRelays = try wrapper.selectRelays(tunnelSettings: settings, connectionAttemptCount: 0) @@ -74,7 +74,7 @@ class RelaySelectorWrapperTests: XCTestCase { let settings = LatestTunnelSettings( relayConstraints: multihopWithDaitaConstraints, tunnelMultihopState: .on, - daita: DAITASettings(state: .on) + daita: DAITASettings(daitaState: .on) ) XCTAssertNoThrow(try wrapper.selectRelays(tunnelSettings: settings, connectionAttemptCount: 0)) @@ -86,7 +86,7 @@ class RelaySelectorWrapperTests: XCTestCase { let settings = LatestTunnelSettings( relayConstraints: multihopWithoutDaitaConstraints, tunnelMultihopState: .on, - daita: DAITASettings(state: .on) + daita: DAITASettings(daitaState: .on) ) XCTAssertThrowsError(try wrapper.selectRelays(tunnelSettings: settings, connectionAttemptCount: 0)) @@ -98,7 +98,7 @@ class RelaySelectorWrapperTests: XCTestCase { let settings = LatestTunnelSettings( relayConstraints: singlehopWithDaitaConstraints, tunnelMultihopState: .off, - daita: DAITASettings(state: .on) + daita: DAITASettings(daitaState: .on) ) let selectedRelays = try wrapper.selectRelays(tunnelSettings: settings, connectionAttemptCount: 0) @@ -113,7 +113,7 @@ class RelaySelectorWrapperTests: XCTestCase { let settings = LatestTunnelSettings( relayConstraints: singlehopWithoutDaitaConstraints, tunnelMultihopState: .off, - daita: DAITASettings(state: .on) + daita: DAITASettings(daitaState: .on) ) let selectedRelays = try wrapper.selectRelays(tunnelSettings: settings, connectionAttemptCount: 0) diff --git a/ios/MullvadVPNTests/MullvadSettings/TunnelSettingsUpdateTests.swift b/ios/MullvadVPNTests/MullvadSettings/TunnelSettingsUpdateTests.swift index 824546e9e695..881372d2be0e 100644 --- a/ios/MullvadVPNTests/MullvadSettings/TunnelSettingsUpdateTests.swift +++ b/ios/MullvadVPNTests/MullvadSettings/TunnelSettingsUpdateTests.swift @@ -85,7 +85,7 @@ final class TunnelSettingsUpdateTests: XCTestCase { func testApplyDAITA() { // Given: - let daitaSettings = DAITASettings(state: .on) + let daitaSettings = DAITASettings(daitaState: .on) var settings = LatestTunnelSettings() // When: diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift index 3b3c5ad560ed..f35677c84622 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift @@ -65,7 +65,7 @@ extension PacketTunnelActor { } var daitaConfiguration: DaitaConfiguration? - if settings.daita.state.isEnabled { + if settings.daita.daitaState.isEnabled { let maybeNot = Maybenot() daitaConfiguration = DaitaConfiguration( machines: maybeNot.machines, diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift index 98dbeea262b7..6f6b0a02cd25 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift @@ -259,7 +259,7 @@ extension PacketTunnelActor { ) async throws { let settings: Settings = try settingsReader.read() - if settings.quantumResistance.isEnabled || settings.daita.state.isEnabled { + if settings.quantumResistance.isEnabled || settings.daita.daitaState.isEnabled { try await tryStartEphemeralPeerNegotiation(withSettings: settings, nextRelays: nextRelays, reason: reason) } else { try await tryStartConnection(withSettings: settings, nextRelays: nextRelays, reason: reason) @@ -307,7 +307,7 @@ extension PacketTunnelActor { } var daitaConfiguration: DaitaConfiguration? - if settings.daita.state.isEnabled { + if settings.daita.daitaState.isEnabled { let maybeNot = Maybenot() daitaConfiguration = DaitaConfiguration( machines: maybeNot.machines, @@ -417,7 +417,7 @@ extension PacketTunnelActor { transportLayer: .udp, remotePort: connectedRelay.endpoint.ipv4Relay.port, isPostQuantum: settings.quantumResistance.isEnabled, - isDaitaEnabled: settings.daita.state.isEnabled + isDaitaEnabled: settings.daita.daitaState.isEnabled ) case .disconnecting, .disconnected: return nil @@ -460,7 +460,7 @@ extension PacketTunnelActor { transportLayer: transportLayer, remotePort: protocolObfuscator.remotePort, isPostQuantum: settings.quantumResistance.isEnabled, - isDaitaEnabled: settings.daita.state.isEnabled + isDaitaEnabled: settings.daita.daitaState.isEnabled ) }