From bdfd39740fdbf9c5462967c23a03e29aeece41d2 Mon Sep 17 00:00:00 2001 From: mojganii Date: Wed, 14 Aug 2024 14:03:23 +0200 Subject: [PATCH] Add DAITA into TunnelSettings --- .../MullvadREST/RelaySelectorStub.swift | 15 ++--- .../Relay/RelaySelectorProtocol.swift | 3 +- .../Relay/RelaySelectorWrapper.swift | 26 ++++---- .../Shadowsocks/ShadowsocksLoader.swift | 51 +++++++------- .../ShadowsocksRelaySelector.swift | 20 ++---- ios/MullvadSettings/DAITASettings.swift | 27 ++++++++ ios/MullvadSettings/MultihopSettings.swift | 56 ---------------- ios/MullvadSettings/TunnelSettings.swift | 11 +++- .../TunnelSettingsPropagator.swift | 65 ++++++++++++++++++ .../TunnelSettingsStrategy.swift | 29 ++++++++ .../TunnelSettingsUpdate.swift | 4 ++ ios/MullvadSettings/TunnelSettingsV5.swift | 9 ++- ios/MullvadSettings/TunnelSettingsV6.swift | 50 ++++++++++++++ ios/MullvadTypes/RelayConstraints.swift | 12 ---- ios/MullvadVPN.xcodeproj/project.pbxproj | 30 ++++++--- ios/MullvadVPN/AppDelegate.swift | 18 ++--- .../SimulatorTunnelProviderHost.swift | 7 +- .../TunnelManager/Tunnel+Settings.swift | 26 -------- .../TunnelManager/TunnelManager.swift | 5 +- .../Relay/RelaySelectorWrapperTests.swift | 20 +++--- .../Shadowsocks/ShadowsocksLoaderTests.swift | 19 +++--- .../MigrationManagerTests.swift | 22 +++++++ .../MultihopUpdaterTests.swift | 46 ------------- .../SettingsUpdaterTests.swift | 48 ++++++++++++++ .../TunnelSettingsUpdateTests.swift | 13 ++++ .../PacketTunnelActorReducerTests.swift | 4 +- .../TunnelManager/TunnelManagerTests.swift | 14 ++-- .../PacketTunnelProvider.swift | 15 ++--- .../PacketTunnelProvider/SettingsReader.swift | 22 +------ .../Actor/PacketTunnelActor.swift | 5 +- .../Protocols/SettingsReaderProtocol.swift | 66 +++++++++++++------ .../Mocks/SettingsReaderStub.swift | 26 +++++--- .../PacketTunnelActorTests.swift | 6 +- .../ProtocolObfuscatorTests.swift | 8 +-- 34 files changed, 449 insertions(+), 349 deletions(-) create mode 100644 ios/MullvadSettings/DAITASettings.swift create mode 100644 ios/MullvadSettings/TunnelSettingsPropagator.swift create mode 100644 ios/MullvadSettings/TunnelSettingsStrategy.swift create mode 100644 ios/MullvadSettings/TunnelSettingsV6.swift delete mode 100644 ios/MullvadVPN/TunnelManager/Tunnel+Settings.swift delete mode 100644 ios/MullvadVPNTests/MullvadSettings/MultihopUpdaterTests.swift create mode 100644 ios/MullvadVPNTests/MullvadSettings/SettingsUpdaterTests.swift diff --git a/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift b/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift index 4445aa8cc8c4..7dd95ae97621 100644 --- a/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift +++ b/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift @@ -12,17 +12,14 @@ import WireGuardKitTypes /// Relay selector stub that accepts a block that can be used to provide custom implementation. public final class RelaySelectorStub: RelaySelectorProtocol { - var selectedRelaysResult: (RelayConstraints, UInt) throws -> SelectedRelays + var selectedRelaysResult: (UInt) throws -> SelectedRelays - init(selectedRelaysResult: @escaping (RelayConstraints, UInt) throws -> SelectedRelays) { + init(selectedRelaysResult: @escaping (UInt) throws -> SelectedRelays) { self.selectedRelaysResult = selectedRelaysResult } - public func selectRelays( - with constraints: RelayConstraints, - connectionAttemptCount: UInt - ) throws -> SelectedRelays { - return try selectedRelaysResult(constraints, connectionAttemptCount) + public func selectRelays(connectionAttemptCount: UInt) throws -> SelectedRelays { + return try selectedRelaysResult(connectionAttemptCount) } } @@ -31,7 +28,7 @@ extension RelaySelectorStub { public static func nonFallible() -> RelaySelectorStub { let publicKey = PrivateKey().publicKey.rawValue - return RelaySelectorStub { _, _ in + return RelaySelectorStub { _ in let cityRelay = SelectedRelay( endpoint: MullvadEndpoint( ipv4Relay: IPv4Endpoint(ip: .loopback, port: 1300), @@ -60,7 +57,7 @@ extension RelaySelectorStub { /// Returns a relay selector that cannot satisfy constraints . public static func unsatisfied() -> RelaySelectorStub { - return RelaySelectorStub { _, _ in + return RelaySelectorStub { _ in throw NoRelaysSatisfyingConstraintsError() } } diff --git a/ios/MullvadREST/Relay/RelaySelectorProtocol.swift b/ios/MullvadREST/Relay/RelaySelectorProtocol.swift index c1de0951aa56..44a01f8dc804 100644 --- a/ios/MullvadREST/Relay/RelaySelectorProtocol.swift +++ b/ios/MullvadREST/Relay/RelaySelectorProtocol.swift @@ -7,11 +7,12 @@ // import Foundation +import MullvadSettings import MullvadTypes /// Protocol describing a type that can select a relay. public protocol RelaySelectorProtocol { - func selectRelays(with constraints: RelayConstraints, connectionAttemptCount: UInt) throws -> SelectedRelays + func selectRelays(connectionAttemptCount: UInt) throws -> SelectedRelays } /// Struct describing the selected relay. diff --git a/ios/MullvadREST/Relay/RelaySelectorWrapper.swift b/ios/MullvadREST/Relay/RelaySelectorWrapper.swift index 3ee447d0ab59..839b19f84ae4 100644 --- a/ios/MullvadREST/Relay/RelaySelectorWrapper.swift +++ b/ios/MullvadREST/Relay/RelaySelectorWrapper.swift @@ -11,40 +11,40 @@ import MullvadTypes public final class RelaySelectorWrapper: RelaySelectorProtocol { let relayCache: RelayCacheProtocol - let multihopUpdater: MultihopUpdater - private var multihopState: MultihopState = .off - private var observer: MultihopObserverBlock! + + let tunnelSettingsUpdater: SettingsUpdater + private var tunnelSettings = LatestTunnelSettings() + private var observer: SettingsObserverBlock! deinit { - self.multihopUpdater.removeObserver(observer) + self.tunnelSettingsUpdater.removeObserver(observer) } public init( relayCache: RelayCacheProtocol, - multihopUpdater: MultihopUpdater + tunnelSettingsUpdater: SettingsUpdater ) { self.relayCache = relayCache - self.multihopUpdater = multihopUpdater + self.tunnelSettingsUpdater = tunnelSettingsUpdater self.addObserver() } public func selectRelays( - with constraints: RelayConstraints, connectionAttemptCount: UInt ) throws -> SelectedRelays { let relays = try relayCache.read().relays - switch multihopState { + switch tunnelSettings.tunnelMultihopState { case .off: return try SinglehopPicker( - constraints: constraints, + constraints: tunnelSettings.relayConstraints, relays: relays, connectionAttemptCount: connectionAttemptCount ).pick() case .on: return try MultihopPicker( - constraints: constraints, + constraints: tunnelSettings.relayConstraints, relays: relays, connectionAttemptCount: connectionAttemptCount ).pick() @@ -52,10 +52,10 @@ public final class RelaySelectorWrapper: RelaySelectorProtocol { } private func addObserver() { - self.observer = MultihopObserverBlock(didUpdateMultihop: { [weak self] _, multihopState in - self?.multihopState = multihopState + self.observer = SettingsObserverBlock(didUpdateSettings: { [weak self] latestTunnelSettings in + self?.tunnelSettings = latestTunnelSettings }) - multihopUpdater.addObserver(observer) + tunnelSettingsUpdater.addObserver(observer) } } diff --git a/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksLoader.swift b/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksLoader.swift index 2b46571bc820..c35b0692b5cc 100644 --- a/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksLoader.swift +++ b/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksLoader.swift @@ -18,47 +18,42 @@ public protocol ShadowsocksLoaderProtocol { public class ShadowsocksLoader: ShadowsocksLoaderProtocol { let cache: ShadowsocksConfigurationCacheProtocol let relaySelector: ShadowsocksRelaySelectorProtocol - let constraintsUpdater: RelayConstraintsUpdater - let multihopUpdater: MultihopUpdater - private var multihopState: MultihopState = .off - private var observer: MultihopObserverBlock! + let settingsUpdater: SettingsUpdater + + private var observer: SettingsObserverBlock! + private var tunnelSettings = LatestTunnelSettings() + private let settingsStrategy = TunnelSettingsStrategy() deinit { - self.multihopUpdater.removeObserver(observer) + self.settingsUpdater.removeObserver(observer) } - private var relayConstraints = RelayConstraints() - public init( cache: ShadowsocksConfigurationCacheProtocol, relaySelector: ShadowsocksRelaySelectorProtocol, - constraintsUpdater: RelayConstraintsUpdater, - multihopUpdater: MultihopUpdater + settingsUpdater: SettingsUpdater ) { self.cache = cache self.relaySelector = relaySelector - self.constraintsUpdater = constraintsUpdater - self.multihopUpdater = multihopUpdater + self.settingsUpdater = settingsUpdater self.addObservers() } private func addObservers() { - // The constraints gets updated a lot when observing the tunnel, clear the cache if the constraints have changed. - constraintsUpdater.onNewConstraints = { [weak self] newConstraints in - if self?.relayConstraints != newConstraints { - self?.relayConstraints = newConstraints - try? self?.clear() - } - } - - // The multihop state gets updated a lot when observing the tunnel, clear the cache if the multihop settings have changed. - self.observer = MultihopObserverBlock(didUpdateMultihop: { [weak self] _, newMultihopState in - if self?.multihopState != newMultihopState { - self?.multihopState = newMultihopState - try? self?.clear() - } - }) - multihopUpdater.addObserver(self.observer) + observer = + SettingsObserverBlock( + didUpdateSettings: { [weak self] latestTunnelSettings in + guard let self else { return } + if settingsStrategy.shouldReconnectToNewRelay( + oldSettings: tunnelSettings, + newSettings: latestTunnelSettings + ) { + try? clear() + } + tunnelSettings = latestTunnelSettings + } + ) + settingsUpdater.addObserver(self.observer) } public func clear() throws { @@ -81,7 +76,7 @@ public class ShadowsocksLoader: ShadowsocksLoaderProtocol { /// Returns a randomly selected shadowsocks configuration. private func create() throws -> ShadowsocksConfiguration { let bridgeConfiguration = try relaySelector.getBridges() - let closestRelay = try relaySelector.selectRelay(with: relayConstraints, multihopState: multihopState) + let closestRelay = try relaySelector.selectRelay(with: tunnelSettings) guard let bridgeAddress = closestRelay?.ipv4AddrIn, let bridgeConfiguration else { throw POSIXError(.ENOENT) } diff --git a/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksRelaySelector.swift b/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksRelaySelector.swift index 2519c4065a31..c0d83bc701fb 100644 --- a/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksRelaySelector.swift +++ b/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksRelaySelector.swift @@ -11,10 +11,7 @@ import MullvadSettings import MullvadTypes public protocol ShadowsocksRelaySelectorProtocol { - func selectRelay( - with constraints: RelayConstraints, - multihopState: MultihopState - ) throws -> REST.BridgeRelay? + func selectRelay(with settings: LatestTunnelSettings) throws -> REST.BridgeRelay? func getBridges() throws -> REST.ServerShadowsocks? } @@ -28,21 +25,18 @@ final public class ShadowsocksRelaySelector: ShadowsocksRelaySelectorProtocol { self.relayCache = relayCache } - public func selectRelay( - with constraints: RelayConstraints, - multihopState: MultihopState - ) throws -> REST.BridgeRelay? { + public func selectRelay(with settings: LatestTunnelSettings) throws -> REST.BridgeRelay? { let cachedRelays = try relayCache.read().relays - let locationConstraint = switch multihopState { - case .on: constraints.entryLocations - case .off: constraints.exitLocations + let locationConstraint = switch settings.tunnelMultihopState { + case .on: settings.relayConstraints.entryLocations + case .off: settings.relayConstraints.exitLocations } return RelaySelector.Shadowsocks.closestRelay( location: locationConstraint, - port: constraints.port, - filter: constraints.filter, + port: settings.relayConstraints.port, + filter: settings.relayConstraints.filter, in: cachedRelays ) } diff --git a/ios/MullvadSettings/DAITASettings.swift b/ios/MullvadSettings/DAITASettings.swift new file mode 100644 index 000000000000..fe87cbb95e0e --- /dev/null +++ b/ios/MullvadSettings/DAITASettings.swift @@ -0,0 +1,27 @@ +// +// DAITASettings.swift +// MullvadSettings +// +// Created by Mojgan on 2024-08-08. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +/// Whether DAITA is enabled +public enum DAITAState: Codable { + case on + case off + + public var isEnabled: Bool { + self == .on + } +} + +public struct DAITASettings: Codable, Equatable { + public let state: DAITAState + + public init(state: DAITAState = .off) { + self.state = state + } +} diff --git a/ios/MullvadSettings/MultihopSettings.swift b/ios/MullvadSettings/MultihopSettings.swift index ba64c12e485f..a6abe4c7bcb4 100644 --- a/ios/MullvadSettings/MultihopSettings.swift +++ b/ios/MullvadSettings/MultihopSettings.swift @@ -9,62 +9,6 @@ import Foundation import MullvadTypes -public protocol MultihopPropagation { - typealias MultihopHandler = (MultihopState) -> Void - var onNewMultihop: MultihopHandler? { get set } -} - -public protocol MultihopObserver: AnyObject { - func multihop(_ object: MultihopPropagation, didUpdateMultihop state: MultihopState) -} - -public class MultihopObserverBlock: MultihopObserver { - public typealias DidUpdateMultihopHandler = (MultihopPropagation, MultihopState) -> Void - public var onNewState: DidUpdateMultihopHandler - - public init(didUpdateMultihop: @escaping DidUpdateMultihopHandler) { - self.onNewState = didUpdateMultihop - } - - public func multihop(_ object: MultihopPropagation, didUpdateMultihop state: MultihopState) { - self.onNewState(object, state) - } -} - -public final class MultihopStateListener: MultihopPropagation { - public var onNewMultihop: MultihopHandler? - - public init(onNewMultihop: MultihopHandler? = nil) { - self.onNewMultihop = onNewMultihop - } -} - -public class MultihopUpdater { - /// Observers. - private let observerList = ObserverList() - private var listener: MultihopPropagation - - public init(listener: MultihopPropagation) { - self.listener = listener - self.listener.onNewMultihop = { [weak self] state in - guard let self else { return } - self.observerList.notify { - $0.multihop(listener, didUpdateMultihop: state) - } - } - } - - // MARK: - Multihop observations - - public func addObserver(_ observer: MultihopObserver) { - observerList.append(observer) - } - - public func removeObserver(_ observer: MultihopObserver) { - observerList.remove(observer) - } -} - /// Whether Multi-hop is enabled public enum MultihopState: Codable { case on diff --git a/ios/MullvadSettings/TunnelSettings.swift b/ios/MullvadSettings/TunnelSettings.swift index 853e3dc70ee3..3298e84356e7 100644 --- a/ios/MullvadSettings/TunnelSettings.swift +++ b/ios/MullvadSettings/TunnelSettings.swift @@ -9,7 +9,7 @@ import Foundation /// Alias to the latest version of the `TunnelSettings`. -public typealias LatestTunnelSettings = TunnelSettingsV5 +public typealias LatestTunnelSettings = TunnelSettingsV6 /// Protocol all TunnelSettings must adhere to, for upgrade purposes. public protocol TunnelSettings: Codable { @@ -33,6 +33,9 @@ public enum SchemaVersion: Int, Equatable { /// V4 format with multi-hop options, stored as `TunnelSettingsV5`. case v5 = 5 + /// V5 format with DAITA settings, stored as `TunnelSettingsV6`. + case v6 = 6 + var settingsType: any TunnelSettings.Type { switch self { case .v1: return TunnelSettingsV1.self @@ -40,6 +43,7 @@ public enum SchemaVersion: Int, Equatable { case .v3: return TunnelSettingsV3.self case .v4: return TunnelSettingsV4.self case .v5: return TunnelSettingsV5.self + case .v6: return TunnelSettingsV6.self } } @@ -49,10 +53,11 @@ public enum SchemaVersion: Int, Equatable { case .v2: return .v3 case .v3: return .v4 case .v4: return .v5 - case .v5: return .v5 + case .v5: return .v6 + case .v6: return .v6 } } /// Current schema version. - public static let current = SchemaVersion.v5 + public static let current = SchemaVersion.v6 } diff --git a/ios/MullvadSettings/TunnelSettingsPropagator.swift b/ios/MullvadSettings/TunnelSettingsPropagator.swift new file mode 100644 index 000000000000..3f0a3395adbd --- /dev/null +++ b/ios/MullvadSettings/TunnelSettingsPropagator.swift @@ -0,0 +1,65 @@ +// +// TunnelSettingsPropagator.swift +// MullvadSettings +// +// Created by Mojgan on 2024-08-09. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import MullvadTypes + +public protocol SettingsPropagation { + typealias SettingsHandler = (LatestTunnelSettings) -> Void + var onNewSettings: SettingsHandler? { get set } +} + +public protocol SettingsObserver: AnyObject { + func didUpdateSettings(_ settings: LatestTunnelSettings) +} + +public class SettingsObserverBlock: SettingsObserver { + public typealias DidUpdateSettingsHandler = (LatestTunnelSettings) -> Void + public var onNewSettings: DidUpdateSettingsHandler + + public init(didUpdateSettings: @escaping DidUpdateSettingsHandler) { + self.onNewSettings = didUpdateSettings + } + + public func didUpdateSettings(_ settings: LatestTunnelSettings) { + self.onNewSettings(settings) + } +} + +public final class TunnelSettingsListener: SettingsPropagation { + public var onNewSettings: SettingsHandler? + + public init(onNewSettings: SettingsHandler? = nil) { + self.onNewSettings = onNewSettings + } +} + +public class SettingsUpdater { + /// Observers. + private let observerList = ObserverList() + private var listener: SettingsPropagation + + public init(listener: SettingsPropagation) { + self.listener = listener + self.listener.onNewSettings = { [weak self] settings in + guard let self else { return } + self.observerList.notify { + $0.didUpdateSettings(settings) + } + } + } + + // MARK: - Multihop observations + + public func addObserver(_ observer: SettingsObserver) { + observerList.append(observer) + } + + public func removeObserver(_ observer: SettingsObserver) { + observerList.remove(observer) + } +} diff --git a/ios/MullvadSettings/TunnelSettingsStrategy.swift b/ios/MullvadSettings/TunnelSettingsStrategy.swift new file mode 100644 index 000000000000..1c8a08f2127b --- /dev/null +++ b/ios/MullvadSettings/TunnelSettingsStrategy.swift @@ -0,0 +1,29 @@ +// +// TunnelSettingsStrategy.swift +// MullvadSettings +// +// Created by Mojgan on 2024-08-09. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +public protocol TunnelSettingsStrategyProtocol { + func shouldReconnectToNewRelay(oldSettings: LatestTunnelSettings, newSettings: LatestTunnelSettings) -> Bool +} + +public struct TunnelSettingsStrategy: TunnelSettingsStrategyProtocol { + public init() {} + public func shouldReconnectToNewRelay( + oldSettings: LatestTunnelSettings, + newSettings: LatestTunnelSettings + ) -> Bool { + switch (oldSettings, newSettings) { + case let (old, new) where old.relayConstraints != new.relayConstraints, + let (old, new) where old.tunnelMultihopState != new.tunnelMultihopState, + let (old, new) where old.daita != new.daita: + true + default: + false + } + } +} diff --git a/ios/MullvadSettings/TunnelSettingsUpdate.swift b/ios/MullvadSettings/TunnelSettingsUpdate.swift index 5ab46b84132d..6fd333d003d5 100644 --- a/ios/MullvadSettings/TunnelSettingsUpdate.swift +++ b/ios/MullvadSettings/TunnelSettingsUpdate.swift @@ -15,6 +15,7 @@ public enum TunnelSettingsUpdate { case relayConstraints(RelayConstraints) case quantumResistance(TunnelQuantumResistance) case multihop(MultihopState) + case daita(DAITASettings) } extension TunnelSettingsUpdate { @@ -30,6 +31,8 @@ extension TunnelSettingsUpdate { settings.tunnelQuantumResistance = newQuantumResistance case let .multihop(newState): settings.tunnelMultihopState = newState + case let .daita(newDAITASettings): + settings.daita = newDAITASettings } } @@ -40,6 +43,7 @@ extension TunnelSettingsUpdate { case .relayConstraints: "relay constraints" case .quantumResistance: "quantum resistance" case .multihop: "multihop" + case .daita: "daita" } } } diff --git a/ios/MullvadSettings/TunnelSettingsV5.swift b/ios/MullvadSettings/TunnelSettingsV5.swift index e8035d0b6629..14f7ef7276e0 100644 --- a/ios/MullvadSettings/TunnelSettingsV5.swift +++ b/ios/MullvadSettings/TunnelSettingsV5.swift @@ -41,6 +41,13 @@ public struct TunnelSettingsV5: Codable, Equatable, TunnelSettings { } public func upgradeToNextVersion() -> any TunnelSettings { - self + TunnelSettingsV6( + relayConstraints: relayConstraints, + dnsSettings: dnsSettings, + wireGuardObfuscation: wireGuardObfuscation, + tunnelQuantumResistance: tunnelQuantumResistance, + tunnelMultihopState: tunnelMultihopState, + daita: DAITASettings() + ) } } diff --git a/ios/MullvadSettings/TunnelSettingsV6.swift b/ios/MullvadSettings/TunnelSettingsV6.swift new file mode 100644 index 000000000000..3d10b8be0c66 --- /dev/null +++ b/ios/MullvadSettings/TunnelSettingsV6.swift @@ -0,0 +1,50 @@ +// +// TunnelSettingsV6.swift +// MullvadSettings +// +// Created by Mojgan on 2024-08-08. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadTypes + +public struct TunnelSettingsV6: Codable, Equatable, TunnelSettings { + /// Relay constraints. + public var relayConstraints: RelayConstraints + + /// DNS settings. + public var dnsSettings: DNSSettings + + /// WireGuard obfuscation settings + public var wireGuardObfuscation: WireGuardObfuscationSettings + + /// Whether Post Quantum exchanges are enabled. + public var tunnelQuantumResistance: TunnelQuantumResistance + + /// Whether Multi-hop is enabled. + public var tunnelMultihopState: MultihopState + + /// DAITA settings. + public var daita: DAITASettings + + public init( + relayConstraints: RelayConstraints = RelayConstraints(), + dnsSettings: DNSSettings = DNSSettings(), + wireGuardObfuscation: WireGuardObfuscationSettings = WireGuardObfuscationSettings(), + tunnelQuantumResistance: TunnelQuantumResistance = .automatic, + tunnelMultihopState: MultihopState = .off, + daita: DAITASettings = DAITASettings() + ) { + self.relayConstraints = relayConstraints + self.dnsSettings = dnsSettings + self.wireGuardObfuscation = wireGuardObfuscation + self.tunnelQuantumResistance = tunnelQuantumResistance + self.tunnelMultihopState = tunnelMultihopState + self.daita = daita + } + + public func upgradeToNextVersion() -> any TunnelSettings { + self + } +} diff --git a/ios/MullvadTypes/RelayConstraints.swift b/ios/MullvadTypes/RelayConstraints.swift index 125d81b1c162..b6396767d8a3 100644 --- a/ios/MullvadTypes/RelayConstraints.swift +++ b/ios/MullvadTypes/RelayConstraints.swift @@ -8,18 +8,6 @@ import Foundation -public protocol ConstraintsPropagation { - var onNewConstraints: ((RelayConstraints) -> Void)? { get set } -} - -public class RelayConstraintsUpdater: ConstraintsPropagation { - public var onNewConstraints: ((RelayConstraints) -> Void)? - - public init(onNewConstraints: ((RelayConstraints) -> Void)? = nil) { - self.onNewConstraints = onNewConstraints - } -} - public struct RelayConstraints: Codable, Equatable, CustomDebugStringConvertible { @available(*, deprecated, renamed: "locations") private var location: RelayConstraint = .only(.country("se")) diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 73e239060ac6..48a9b6f0ae14 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -874,6 +874,8 @@ F0570CD12C4FB8E1007BDF2D /* PostQuantumKeyExchangingPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919762C453FAF00C301F3 /* PostQuantumKeyExchangingPipeline.swift */; }; F0570CD22C4FB8E1007BDF2D /* SingleHopPostQuantumKeyExchanging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919782C45402E00C301F3 /* SingleHopPostQuantumKeyExchanging.swift */; }; F0570CD42C4FB8E1007BDF2D /* MultiHopPostQuantumKeyExchanging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F059197C2C454C9200C301F3 /* MultiHopPostQuantumKeyExchanging.swift */; }; + F05769B92C6656E400D9778B /* TunnelSettingsPropagator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05769B82C6656E400D9778B /* TunnelSettingsPropagator.swift */; }; + F05769BB2C6661EE00D9778B /* TunnelSettingsStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05769BA2C6661EE00D9778B /* TunnelSettingsStrategy.swift */; }; F05919752C45194B00C301F3 /* PostQuantumKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919742C45194B00C301F3 /* PostQuantumKey.swift */; }; F05919802C45515200C301F3 /* PostQuantumKeyExchangeActor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A948809A2BC9308D0090A44C /* PostQuantumKeyExchangeActor.swift */; }; F05F39942B21C6C6006E60A7 /* relays.json in Resources */ = {isa = PBXBuildFile; fileRef = 58F3C0A524A50155003E76BE /* relays.json */; }; @@ -883,7 +885,7 @@ F06045EA2B23217E00B2D37A /* ShadowsocksTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06045E92B23217E00B2D37A /* ShadowsocksTransport.swift */; }; F06045EC2B2322A500B2D37A /* Jittered.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06045EB2B2322A500B2D37A /* Jittered.swift */; }; F062B94D2C16E09700B6D47A /* TunnelSettingsManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F062B94C2C16E09700B6D47A /* TunnelSettingsManagerTests.swift */; }; - F072D3CF2C07122400906F64 /* MultihopUpdaterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F072D3CE2C07122400906F64 /* MultihopUpdaterTests.swift */; }; + F072D3CF2C07122400906F64 /* SettingsUpdaterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F072D3CE2C07122400906F64 /* SettingsUpdaterTests.swift */; }; F072D3D22C071AD100906F64 /* ShadowsocksLoaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F072D3D12C071AD100906F64 /* ShadowsocksLoaderTests.swift */; }; F073FCB32C6617D70062EA1D /* TunnelStore+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = F073FCB22C6617D70062EA1D /* TunnelStore+Stubs.swift */; }; F07751552C50F149006E6A12 /* PostQuantumKeyExchangeActorStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C4C9BF2C495E7500A79006 /* PostQuantumKeyExchangeActorStub.swift */; }; @@ -916,9 +918,7 @@ F09D04BD2AEBB7C5003D4F89 /* OutgoingConnectionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F09D04BC2AEBB7C5003D4F89 /* OutgoingConnectionService.swift */; }; F09D04C02AF39D63003D4F89 /* OutgoingConnectionServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F09D04BF2AF39D63003D4F89 /* OutgoingConnectionServiceTests.swift */; }; F09D04C12AF39EA2003D4F89 /* OutgoingConnectionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F09D04BC2AEBB7C5003D4F89 /* OutgoingConnectionService.swift */; }; - F0A0868E2C22D60100BF83E7 /* Tunnel+Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0A0868D2C22D60100BF83E7 /* Tunnel+Settings.swift */; }; F0A086902C22D6A700BF83E7 /* TunnelSettingsStrategyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0A0868F2C22D6A700BF83E7 /* TunnelSettingsStrategyTests.swift */; }; - F0A086922C22E0F100BF83E7 /* Tunnel+Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0A0868D2C22D60100BF83E7 /* Tunnel+Settings.swift */; }; F0A1638A2C47B77300592300 /* ServerRelaysResponse+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0ACE3342BE51745006D5333 /* ServerRelaysResponse+Stubs.swift */; }; F0ACE30D2BE4E478006D5333 /* MullvadMockData.h in Headers */ = {isa = PBXBuildFile; fileRef = F0ACE30A2BE4E478006D5333 /* MullvadMockData.h */; settings = {ATTRIBUTES = (Public, ); }; }; F0ACE3102BE4E478006D5333 /* MullvadMockData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0ACE3082BE4E478006D5333 /* MullvadMockData.framework */; }; @@ -942,6 +942,8 @@ F0B894F32BF7526700817A42 /* RelaySelector+Wireguard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B894F22BF7526700817A42 /* RelaySelector+Wireguard.swift */; }; F0B894F52BF7528700817A42 /* RelaySelector+Shadowsocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B894F42BF7528700817A42 /* RelaySelector+Shadowsocks.swift */; }; F0BE65372B9F136A005CC385 /* LocationSectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0BE65362B9F136A005CC385 /* LocationSectionHeaderView.swift */; }; + F0C13FE42C64F7CB00BD087D /* DAITASettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C13FE32C64F7CB00BD087D /* DAITASettings.swift */; }; + F0C13FE62C64FB3400BD087D /* TunnelSettingsV6.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C13FE52C64FB3400BD087D /* TunnelSettingsV6.swift */; }; F0C2AEFD2A0BB5CC00986207 /* NotificationProviderIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C2AEFC2A0BB5CC00986207 /* NotificationProviderIdentifier.swift */; }; F0C3333C2B31A29C00D1A478 /* MullvadSettings.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 58B2FDD32AA71D2A003EB5C6 /* MullvadSettings.framework */; }; F0C6A8432AB08E54000777A8 /* RedeemVoucherViewConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C6A8422AB08E54000777A8 /* RedeemVoucherViewConfiguration.swift */; }; @@ -2081,6 +2083,8 @@ F050AE5F2B73A41E003F4EDB /* AllLocationDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllLocationDataSource.swift; sourceTree = ""; }; F050AE612B74DBAC003F4EDB /* CustomListsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomListsDataSource.swift; sourceTree = ""; }; F053F4B92C4A94D300FBD937 /* PostQuantumKeyExchangingPipelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyExchangingPipelineTests.swift; sourceTree = ""; }; + F05769B82C6656E400D9778B /* TunnelSettingsPropagator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsPropagator.swift; sourceTree = ""; }; + F05769BA2C6661EE00D9778B /* TunnelSettingsStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsStrategy.swift; sourceTree = ""; }; F05919742C45194B00C301F3 /* PostQuantumKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKey.swift; sourceTree = ""; }; F05919762C453FAF00C301F3 /* PostQuantumKeyExchangingPipeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyExchangingPipeline.swift; sourceTree = ""; }; F05919782C45402E00C301F3 /* SingleHopPostQuantumKeyExchanging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleHopPostQuantumKeyExchanging.swift; sourceTree = ""; }; @@ -2090,7 +2094,7 @@ F06045E92B23217E00B2D37A /* ShadowsocksTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShadowsocksTransport.swift; sourceTree = ""; }; F06045EB2B2322A500B2D37A /* Jittered.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Jittered.swift; sourceTree = ""; }; F062B94C2C16E09700B6D47A /* TunnelSettingsManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsManagerTests.swift; sourceTree = ""; }; - F072D3CE2C07122400906F64 /* MultihopUpdaterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultihopUpdaterTests.swift; sourceTree = ""; }; + F072D3CE2C07122400906F64 /* SettingsUpdaterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsUpdaterTests.swift; sourceTree = ""; }; F072D3D12C071AD100906F64 /* ShadowsocksLoaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowsocksLoaderTests.swift; sourceTree = ""; }; F073FCB22C6617D70062EA1D /* TunnelStore+Stubs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TunnelStore+Stubs.swift"; sourceTree = ""; }; F07B53562C53B5270024F547 /* LocalNetworkIPs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNetworkIPs.swift; sourceTree = ""; }; @@ -2107,7 +2111,6 @@ F09D04BA2AE95396003D4F89 /* URLSessionStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionStub.swift; sourceTree = ""; }; F09D04BC2AEBB7C5003D4F89 /* OutgoingConnectionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingConnectionService.swift; sourceTree = ""; }; F09D04BF2AF39D63003D4F89 /* OutgoingConnectionServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingConnectionServiceTests.swift; sourceTree = ""; }; - F0A0868D2C22D60100BF83E7 /* Tunnel+Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tunnel+Settings.swift"; sourceTree = ""; }; F0A0868F2C22D6A700BF83E7 /* TunnelSettingsStrategyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsStrategyTests.swift; sourceTree = ""; }; F0A163882C47B46300592300 /* SingleHopPostQuantumKeyExchangingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleHopPostQuantumKeyExchangingTests.swift; sourceTree = ""; }; F0ACE3082BE4E478006D5333 /* MullvadMockData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MullvadMockData.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2120,6 +2123,8 @@ F0B894F22BF7526700817A42 /* RelaySelector+Wireguard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RelaySelector+Wireguard.swift"; sourceTree = ""; }; F0B894F42BF7528700817A42 /* RelaySelector+Shadowsocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RelaySelector+Shadowsocks.swift"; sourceTree = ""; }; F0BE65362B9F136A005CC385 /* LocationSectionHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationSectionHeaderView.swift; sourceTree = ""; }; + F0C13FE32C64F7CB00BD087D /* DAITASettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAITASettings.swift; sourceTree = ""; }; + F0C13FE52C64FB3400BD087D /* TunnelSettingsV6.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsV6.swift; sourceTree = ""; }; F0C2AEFC2A0BB5CC00986207 /* NotificationProviderIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationProviderIdentifier.swift; sourceTree = ""; }; F0C4C9BD2C49477B00A79006 /* MultiHopPostQuantumKeyExchangingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiHopPostQuantumKeyExchangingTests.swift; sourceTree = ""; }; F0C4C9BF2C495E7500A79006 /* PostQuantumKeyExchangeActorStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyExchangeActorStub.swift; sourceTree = ""; }; @@ -2548,7 +2553,7 @@ 7AB4CCB82B69097E006037F5 /* IPOverrideTests.swift */, 7A516C3B2B712F0B00BBD33D /* IPOverrideWrapperTests.swift */, A9B6AC172ADE8F4300F7802A /* MigrationManagerTests.swift */, - F072D3CE2C07122400906F64 /* MultihopUpdaterTests.swift */, + F072D3CE2C07122400906F64 /* SettingsUpdaterTests.swift */, 449872E32B7CB96300094DDC /* TunnelSettingsUpdateTests.swift */, ); path = MullvadSettings; @@ -2634,7 +2639,6 @@ 58F2E145276A2C9900A79513 /* StopTunnelOperation.swift */, 58E0A98727C8F46300FE6BDD /* Tunnel.swift */, 5875960926F371FC00BF6711 /* Tunnel+Messaging.swift */, - F0A0868D2C22D60100BF83E7 /* Tunnel+Settings.swift */, 5878A27229091D6D0096FC88 /* TunnelBlockObserver.swift */, 5803B4AF2940A47300C23744 /* TunnelConfiguration.swift */, 58968FAD28743E2000B799DC /* TunnelInteractor.swift */, @@ -3267,6 +3271,7 @@ F050AE592B7376F4003F4EDB /* CustomList.swift */, F050AE562B7376C6003F4EDB /* CustomListRepository.swift */, F050AE552B7376C5003F4EDB /* CustomListRepositoryProtocol.swift */, + F0C13FE32C64F7CB00BD087D /* DAITASettings.swift */, A92ECC2B2A7803A50052F1B1 /* DeviceState.swift */, 580F8B8528197958002E0998 /* DNSSettings.swift */, 7A5869B22B5697AC00640D27 /* IPOverride.swift */, @@ -3286,12 +3291,15 @@ A92ECC272A7802AB0052F1B1 /* StoredDeviceData.swift */, A97D30162AE6B5E90045C0E4 /* StoredWgKeyData.swift */, A92ECC202A77FFAF0052F1B1 /* TunnelSettings.swift */, + F05769B82C6656E400D9778B /* TunnelSettingsPropagator.swift */, + F05769BA2C6661EE00D9778B /* TunnelSettingsStrategy.swift */, 449872E02B7BBC5400094DDC /* TunnelSettingsUpdate.swift */, 587AD7C523421D7000E93A53 /* TunnelSettingsV1.swift */, 580F8B8228197881002E0998 /* TunnelSettingsV2.swift */, A988DF282ADE880300D807EF /* TunnelSettingsV3.swift */, A93181A02B727ED700E341D2 /* TunnelSettingsV4.swift */, F0E61CA82BF2911D000C4A95 /* TunnelSettingsV5.swift */, + F0C13FE52C64FB3400BD087D /* TunnelSettingsV6.swift */, A988DF252ADE86ED00D807EF /* WireGuardObfuscationSettings.swift */, ); path = MullvadSettings; @@ -5280,7 +5288,6 @@ A9A5F9F62ACB05160083449F /* TunnelStatusNotificationProvider.swift in Sources */, A9A5F9F72ACB05160083449F /* NotificationProviderProtocol.swift in Sources */, A9A5F9F82ACB05160083449F /* NotificationProviderIdentifier.swift in Sources */, - F0A086922C22E0F100BF83E7 /* Tunnel+Settings.swift in Sources */, A9A5F9F92ACB05160083449F /* NotificationProvider.swift in Sources */, A9A5F9FA2ACB05160083449F /* InAppNotificationDescriptor.swift in Sources */, A9A5F9FB2ACB05160083449F /* InAppNotificationProvider.swift in Sources */, @@ -5316,7 +5323,7 @@ A9A5FA142ACB05160083449F /* MapConnectionStatusOperation.swift in Sources */, A9A5FA152ACB05160083449F /* RedeemVoucherOperation.swift in Sources */, A9A5FA162ACB05160083449F /* RotateKeyOperation.swift in Sources */, - F072D3CF2C07122400906F64 /* MultihopUpdaterTests.swift in Sources */, + F072D3CF2C07122400906F64 /* SettingsUpdaterTests.swift in Sources */, 7ACE19132C1C352100260BB6 /* RelayPickingTests.swift in Sources */, F09D04B52AE93CB6003D4F89 /* OutgoingConnectionProxy+Stub.swift in Sources */, 58BE4B9D2B18A85B007EA1D3 /* NSAttributedString+Extensions.swift in Sources */, @@ -5385,6 +5392,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F05769B92C6656E400D9778B /* TunnelSettingsPropagator.swift in Sources */, + F0C13FE62C64FB3400BD087D /* TunnelSettingsV6.swift in Sources */, + F0C13FE42C64F7CB00BD087D /* DAITASettings.swift in Sources */, F050AE582B7376C6003F4EDB /* CustomListRepository.swift in Sources */, F0E61CAA2BF2911D000C4A95 /* TunnelSettingsV5.swift in Sources */, 7A5869BD2B56EF7300640D27 /* IPOverride.swift in Sources */, @@ -5405,6 +5415,7 @@ 58B2FDEF2AA720C4003EB5C6 /* ApplicationTarget.swift in Sources */, A988DF272ADE86ED00D807EF /* WireGuardObfuscationSettings.swift in Sources */, 58B2FDDE2AA71D5C003EB5C6 /* Migration.swift in Sources */, + F05769BB2C6661EE00D9778B /* TunnelSettingsStrategy.swift in Sources */, F0D7FF8F2B31DF5900E0FDE5 /* AccessMethodRepository.swift in Sources */, 58B2FDE12AA71D5C003EB5C6 /* TunnelSettingsV1.swift in Sources */, 449872E12B7BBC5400094DDC /* TunnelSettingsUpdate.swift in Sources */, @@ -5532,7 +5543,6 @@ 5891BF5125E66B1E006D6FB0 /* UIBarButtonItem+KeyboardNavigation.swift in Sources */, 58E511E628DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */, 58C76A0B2A338E4300100D75 /* BackgroundTask.swift in Sources */, - F0A0868E2C22D60100BF83E7 /* Tunnel+Settings.swift in Sources */, 7A9CCCC32A96302800DD6A34 /* ApplicationCoordinator.swift in Sources */, 5864AF0729C78843005B0CD9 /* SettingsCellFactory.swift in Sources */, 587B75412668FD7800DEF7E9 /* AccountExpirySystemNotificationProvider.swift in Sources */, diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift index 124ec5751739..68b55ee9c95c 100644 --- a/ios/MullvadVPN/AppDelegate.swift +++ b/ios/MullvadVPN/AppDelegate.swift @@ -79,9 +79,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD ipOverrideRepository: ipOverrideRepository ) - let constraintsUpdater = RelayConstraintsUpdater() - let multihopListener = MultihopStateListener() - let multihopUpdater = MultihopUpdater(listener: multihopListener) + let tunnelSettingsListener = TunnelSettingsListener() + let tunnelSettingsUpdater = SettingsUpdater(listener: tunnelSettingsListener) relayCacheTracker = RelayCacheTracker( relayCache: ipOverrideWrapper, @@ -95,16 +94,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD let relaySelector = RelaySelectorWrapper( relayCache: ipOverrideWrapper, - multihopUpdater: multihopUpdater + tunnelSettingsUpdater: tunnelSettingsUpdater ) tunnelManager = createTunnelManager(application: application, relaySelector: relaySelector) - settingsObserver = TunnelBlockObserver(didLoadConfiguration: { tunnelManager in - multihopListener.onNewMultihop?(tunnelManager.settings.tunnelMultihopState) - constraintsUpdater.onNewConstraints?(tunnelManager.settings.relayConstraints) - }, didUpdateTunnelSettings: { _, settings in - multihopListener.onNewMultihop?(settings.tunnelMultihopState) - constraintsUpdater.onNewConstraints?(settings.relayConstraints) + settingsObserver = TunnelBlockObserver(didUpdateTunnelSettings: { _, settings in + tunnelSettingsListener.onNewSettings?(settings) }) tunnelManager.addObserver(settingsObserver) @@ -124,8 +119,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD shadowsocksLoader = ShadowsocksLoader( cache: shadowsocksCache, relaySelector: shadowsocksRelaySelector, - constraintsUpdater: constraintsUpdater, - multihopUpdater: multihopUpdater + settingsUpdater: tunnelSettingsUpdater ) configuredTransportProvider = ProxyConfigurationTransportProvider( diff --git a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift index 2bd8898e847f..04ea6c13751b 100644 --- a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift +++ b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift @@ -160,12 +160,7 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { } private func pickRelays() throws -> SelectedRelays { - let tunnelSettings = try SettingsManager.readSettings() - - return try relaySelector.selectRelays( - with: tunnelSettings.relayConstraints, - connectionAttemptCount: 0 - ) + return try relaySelector.selectRelays(connectionAttemptCount: 0) } private func setInternalStateConnected(with selectedRelays: SelectedRelays?) { diff --git a/ios/MullvadVPN/TunnelManager/Tunnel+Settings.swift b/ios/MullvadVPN/TunnelManager/Tunnel+Settings.swift deleted file mode 100644 index 80c91b761892..000000000000 --- a/ios/MullvadVPN/TunnelManager/Tunnel+Settings.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// Tunnel+Settings.swift -// MullvadVPN -// -// Created by Mojgan on 2024-06-19. -// Copyright © 2024 Mullvad VPN AB. All rights reserved. -// - -import MullvadLogging -import MullvadSettings - -protocol TunnelSettingsStrategyProtocol { - func shouldReconnectToNewRelay(oldSettings: LatestTunnelSettings, newSettings: LatestTunnelSettings) -> Bool -} - -struct TunnelSettingsStrategy: TunnelSettingsStrategyProtocol { - func shouldReconnectToNewRelay(oldSettings: LatestTunnelSettings, newSettings: LatestTunnelSettings) -> Bool { - switch (oldSettings, newSettings) { - case let (old, new) where old.relayConstraints != new.relayConstraints, - let (old, new) where old.tunnelMultihopState != new.tunnelMultihopState: - true - default: - false - } - } -} diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift index fb03fa2f18ca..2d663a048fb0 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift @@ -785,10 +785,7 @@ final class TunnelManager: StorePaymentObserver { fileprivate func selectRelays() throws -> SelectedRelays { let retryAttempts = tunnelStatus.observedState.connectionState?.connectionAttemptCount ?? 0 - return try relaySelector.selectRelays( - with: settings.relayConstraints, - connectionAttemptCount: retryAttempts - ) + return try relaySelector.selectRelays(connectionAttemptCount: retryAttempts) } fileprivate func prepareForVPNConfigurationDeletion() { diff --git a/ios/MullvadVPNTests/MullvadREST/Relay/RelaySelectorWrapperTests.swift b/ios/MullvadVPNTests/MullvadREST/Relay/RelaySelectorWrapperTests.swift index a1ecb02fdfc2..6131b23d08bf 100644 --- a/ios/MullvadVPNTests/MullvadREST/Relay/RelaySelectorWrapperTests.swift +++ b/ios/MullvadVPNTests/MullvadREST/Relay/RelaySelectorWrapperTests.swift @@ -20,36 +20,36 @@ class RelaySelectorWrapperTests: XCTestCase { ) var relayCache: RelayCache! - var multihopUpdater: MultihopUpdater! - var multihopStateListener: MultihopStateListener! + var settingsUpdater: SettingsUpdater! + var settingsListener: TunnelSettingsListener! override func setUp() { relayCache = RelayCache(fileCache: fileCache) - multihopStateListener = MultihopStateListener() - multihopUpdater = MultihopUpdater(listener: multihopStateListener) + settingsListener = TunnelSettingsListener() + settingsUpdater = SettingsUpdater(listener: settingsListener) } func testSelectRelayWithMultihopOff() throws { let wrapper = RelaySelectorWrapper( relayCache: relayCache, - multihopUpdater: multihopUpdater + tunnelSettingsUpdater: settingsUpdater ) - multihopStateListener.onNewMultihop?(.off) + settingsListener.onNewSettings?(LatestTunnelSettings(tunnelMultihopState: .off)) - let selectedRelays = try wrapper.selectRelays(with: RelayConstraints(), connectionAttemptCount: 0) + let selectedRelays = try wrapper.selectRelays(connectionAttemptCount: 0) XCTAssertNil(selectedRelays.entry) } func testSelectRelayWithMultihopOn() throws { let wrapper = RelaySelectorWrapper( relayCache: relayCache, - multihopUpdater: multihopUpdater + tunnelSettingsUpdater: settingsUpdater ) - multihopStateListener.onNewMultihop?(.on) + settingsListener.onNewSettings?(LatestTunnelSettings(tunnelMultihopState: .on)) - let selectedRelays = try wrapper.selectRelays(with: RelayConstraints(), connectionAttemptCount: 0) + let selectedRelays = try wrapper.selectRelays(connectionAttemptCount: 0) XCTAssertNotNil(selectedRelays.entry) } } diff --git a/ios/MullvadVPNTests/MullvadREST/Shadowsocks/ShadowsocksLoaderTests.swift b/ios/MullvadVPNTests/MullvadREST/Shadowsocks/ShadowsocksLoaderTests.swift index 253e9545129f..c8cfc4308f68 100644 --- a/ios/MullvadVPNTests/MullvadREST/Shadowsocks/ShadowsocksLoaderTests.swift +++ b/ios/MullvadVPNTests/MullvadREST/Shadowsocks/ShadowsocksLoaderTests.swift @@ -15,15 +15,13 @@ import XCTest class ShadowsocksLoaderTests: XCTestCase { private let sampleRelays = ServerRelaysResponseStubs.sampleRelays - private var relayConstraintsUpdater: RelayConstraintsUpdater! private var shadowsocksConfigurationCache: ShadowsocksConfigurationCacheStub! private var relaySelector: ShadowsocksRelaySelectorStub! private var shadowsocksLoader: ShadowsocksLoader! private var relayConstraints = RelayConstraints() - private var multihopStateListener = MultihopStateListener() + private var settingsListener = TunnelSettingsListener() override func setUpWithError() throws { - relayConstraintsUpdater = RelayConstraintsUpdater() shadowsocksConfigurationCache = ShadowsocksConfigurationCacheStub() relaySelector = ShadowsocksRelaySelectorStub(relays: sampleRelays) @@ -44,20 +42,19 @@ class ShadowsocksLoaderTests: XCTestCase { shadowsocksLoader = ShadowsocksLoader( cache: shadowsocksConfigurationCache, relaySelector: relaySelector, - constraintsUpdater: relayConstraintsUpdater, - multihopUpdater: MultihopUpdater(listener: multihopStateListener) + settingsUpdater: SettingsUpdater(listener: settingsListener) ) } func testLoadConfigWithMultihopDisabled() throws { - multihopStateListener.onNewMultihop?(.off) + settingsListener.onNewSettings?(LatestTunnelSettings(tunnelMultihopState: .off)) relaySelector.entryBridgeResult = .failure(ShadowsocksRelaySelectorStubError()) let configuration = try XCTUnwrap(shadowsocksLoader.load()) XCTAssertEqual(configuration, try XCTUnwrap(shadowsocksConfigurationCache.read())) } func testLoadConfigWithMultihopEnabled() throws { - multihopStateListener.onNewMultihop?(.on) + settingsListener.onNewSettings?(LatestTunnelSettings(tunnelMultihopState: .on)) relaySelector.exitBridgeResult = .failure(ShadowsocksRelaySelectorStubError()) let configuration = try XCTUnwrap(shadowsocksLoader.load()) XCTAssertEqual(configuration, try XCTUnwrap(shadowsocksConfigurationCache.read())) @@ -69,13 +66,13 @@ class ShadowsocksLoaderTests: XCTestCase { exitLocations: .only(UserSelectedRelays(locations: [.country("ae")])) ) - relayConstraintsUpdater.onNewConstraints?(relayConstraints) + settingsListener.onNewSettings?(LatestTunnelSettings(relayConstraints: relayConstraints)) XCTAssertNil(shadowsocksConfigurationCache.cachedConfiguration) } func testMultihopUpdateClearsCache() throws { - multihopStateListener.onNewMultihop?(.off) + settingsListener.onNewSettings?(LatestTunnelSettings(tunnelMultihopState: .off)) XCTAssertNil(shadowsocksConfigurationCache.cachedConfiguration) } @@ -103,8 +100,8 @@ class ShadowsocksRelaySelectorStub: ShadowsocksRelaySelectorProtocol { self.relays = relays } - func selectRelay(with constraints: RelayConstraints, multihopState: MultihopState) throws -> REST.BridgeRelay? { - switch multihopState { + func selectRelay(with settings: LatestTunnelSettings) throws -> REST.BridgeRelay? { + switch settings.tunnelMultihopState { case .on: try entryBridgeResult.get() case .off: diff --git a/ios/MullvadVPNTests/MullvadSettings/MigrationManagerTests.swift b/ios/MullvadVPNTests/MullvadSettings/MigrationManagerTests.swift index 9b3739f9d06f..628906115ac0 100644 --- a/ios/MullvadVPNTests/MullvadSettings/MigrationManagerTests.swift +++ b/ios/MullvadVPNTests/MullvadSettings/MigrationManagerTests.swift @@ -120,6 +120,28 @@ final class MigrationManagerTests: XCTestCase { wait(for: [failedMigrationExpectation], timeout: .UnitTest.timeout) } + func testSuccessfulMigrationFromV5ToLatest() throws { + var settingsV5 = TunnelSettingsV5() + let relayConstraints = RelayConstraints( + exitLocations: .only(UserSelectedRelays(locations: [.city("jp", "osa")])) + ) + + settingsV5.relayConstraints = relayConstraints + settingsV5.tunnelQuantumResistance = .off + settingsV5.wireGuardObfuscation = WireGuardObfuscationSettings(state: .off, port: .automatic) + settingsV5.tunnelMultihopState = .off + + try migrateToLatest(settingsV5, version: .v5) + + // Once the migration is done, settings should have been updated to the latest available version + // Verify that the old settings are still valid + let latestSettings = try SettingsManager.readSettings() + XCTAssertEqual(settingsV5.relayConstraints, latestSettings.relayConstraints) + XCTAssertEqual(settingsV5.tunnelQuantumResistance, latestSettings.tunnelQuantumResistance) + XCTAssertEqual(settingsV5.wireGuardObfuscation, latestSettings.wireGuardObfuscation) + XCTAssertEqual(settingsV5.tunnelMultihopState, latestSettings.tunnelMultihopState) + } + func testSuccessfulMigrationFromV4ToLatest() throws { var settingsV4 = TunnelSettingsV4() let relayConstraints = RelayConstraints( diff --git a/ios/MullvadVPNTests/MullvadSettings/MultihopUpdaterTests.swift b/ios/MullvadVPNTests/MullvadSettings/MultihopUpdaterTests.swift deleted file mode 100644 index ba6ab3625d67..000000000000 --- a/ios/MullvadVPNTests/MullvadSettings/MultihopUpdaterTests.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// MultihopUpdaterTests.swift -// MullvadVPNTests -// -// Created by Mojgan on 2024-05-29. -// Copyright © 2024 Mullvad VPN AB. All rights reserved. -// - -@testable import MullvadSettings -import XCTest - -class MultihopUpdaterTests: XCTestCase { - private var multihopStateListener: MultihopStateListener! - private var multihopUpdater: MultihopUpdater! - private var observers: [MultihopObserver]! - - override func setUp() { - multihopStateListener = MultihopStateListener() - multihopUpdater = MultihopUpdater(listener: multihopStateListener) - observers = [] - } - - override func tearDown() { - self.observers.forEach { - multihopUpdater.removeObserver($0) - } - } - - func testMultipleListener() { - var count = 0 - - observers.append(MultihopObserverBlock(didUpdateMultihop: { _, _ in - count += 1 - })) - - observers.append(MultihopObserverBlock(didUpdateMultihop: { _, _ in - count += 1 - })) - - observers.forEach { multihopUpdater.addObserver($0) } - - multihopStateListener.onNewMultihop?(.on) - - XCTAssertEqual(count, 2) - } -} diff --git a/ios/MullvadVPNTests/MullvadSettings/SettingsUpdaterTests.swift b/ios/MullvadVPNTests/MullvadSettings/SettingsUpdaterTests.swift new file mode 100644 index 000000000000..af089acaa4ec --- /dev/null +++ b/ios/MullvadVPNTests/MullvadSettings/SettingsUpdaterTests.swift @@ -0,0 +1,48 @@ +// +// SettingsUpdaterTests.swift +// MullvadVPNTests +// +// Created by Mojgan on 2024-05-29. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// +@testable import MullvadSettings +@testable import MullvadTypes +import XCTest + +class SettingsUpdaterTests: XCTestCase { + private var settingsListener: TunnelSettingsListener! + private var settingsUpdater: SettingsUpdater! + private var observers: [SettingsObserver]! + + override func setUp() { + settingsListener = TunnelSettingsListener() + settingsUpdater = SettingsUpdater(listener: settingsListener) + observers = [] + } + + override func tearDown() { + self.observers.forEach { + settingsUpdater.removeObserver($0) + } + } + + func testSettingsListener() { + var count = 0 + + let latestSettings = LatestTunnelSettings() + + observers.append(SettingsObserverBlock(didUpdateSettings: { _ in + count += 1 + })) + + observers.append(SettingsObserverBlock(didUpdateSettings: { _ in + count += 1 + })) + + observers.forEach { settingsUpdater.addObserver($0) } + + settingsListener.onNewSettings?(latestSettings) + + XCTAssertEqual(count, 2) + } +} diff --git a/ios/MullvadVPNTests/MullvadSettings/TunnelSettingsUpdateTests.swift b/ios/MullvadVPNTests/MullvadSettings/TunnelSettingsUpdateTests.swift index 9ebcee9d4097..824546e9e695 100644 --- a/ios/MullvadVPNTests/MullvadSettings/TunnelSettingsUpdateTests.swift +++ b/ios/MullvadVPNTests/MullvadSettings/TunnelSettingsUpdateTests.swift @@ -82,4 +82,17 @@ final class TunnelSettingsUpdateTests: XCTestCase { // Then: XCTAssertEqual(settings.tunnelMultihopState, .on) } + + func testApplyDAITA() { + // Given: + let daitaSettings = DAITASettings(state: .on) + var settings = LatestTunnelSettings() + + // When: + let update = TunnelSettingsUpdate.daita(daitaSettings) + update.apply(to: &settings) + + // Then: + XCTAssertEqual(settings.daita, daitaSettings) + } } diff --git a/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift b/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift index 1eefa09816bf..936548afd581 100644 --- a/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift +++ b/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift @@ -14,9 +14,7 @@ import XCTest final class PacketTunnelActorReducerTests: XCTestCase { // swiftlint:disable:next force_try - let selectedRelays = try! RelaySelectorStub - .nonFallible() - .selectRelays(with: RelayConstraints(), connectionAttemptCount: 0) + let selectedRelays = try! RelaySelectorStub.nonFallible().selectRelays(connectionAttemptCount: 0) func makeConnectionData(keyPolicy: State.KeyPolicy = .useCurrent) -> State.ConnectionData { State.ConnectionData( diff --git a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift index d8626783451b..28b119fe44b4 100644 --- a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift +++ b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/TunnelManagerTests.swift @@ -59,8 +59,7 @@ class TunnelManagerTests: XCTestCase { shadowsocksLoader: ShadowsocksLoader( cache: ShadowsocksConfigurationCacheStub(), relaySelector: ShadowsocksRelaySelectorStub(relays: .mock()), - constraintsUpdater: RelayConstraintsUpdater(), - multihopUpdater: MultihopUpdater(listener: MultihopStateListener()) + settingsUpdater: SettingsUpdater(listener: TunnelSettingsListener()) ) ) ) @@ -122,8 +121,8 @@ class TunnelManagerTests: XCTestCase { accountProxy.createAccountResult = .success(REST.NewAccountData.mockValue()) - let relaySelector = RelaySelectorStub { _, _ in - try RelaySelectorStub.unsatisfied().selectRelays(with: RelayConstraints(), connectionAttemptCount: 0) + let relaySelector = RelaySelectorStub { _ in + try RelaySelectorStub.unsatisfied().selectRelays(connectionAttemptCount: 0) } let tunnelManager = TunnelManager( @@ -148,11 +147,8 @@ class TunnelManagerTests: XCTestCase { switch tunnelStatus.state { case let .error(blockedStateReason) where blockedStateReason == .noRelaysSatisfyingConstraints: blockedExpectation.fulfill() - relaySelector.selectedRelaysResult = { relayConstraints, connectionAttemptCount in - try RelaySelectorStub.nonFallible().selectRelays( - with: relayConstraints, - connectionAttemptCount: connectionAttemptCount - ) + relaySelector.selectedRelaysResult = { connectionAttemptCount in + try RelaySelectorStub.nonFallible().selectRelays(connectionAttemptCount: connectionAttemptCount) } tunnelManager.reconnectTunnel(selectNewRelay: true) diff --git a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift index c6b7a7e8cd24..f40d00d4f23d 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift @@ -27,10 +27,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider { private var adapter: WgAdapter! private var relaySelector: RelaySelectorWrapper! private var postQuantumKeyExchangingPipeline: PostQuantumKeyExchangingPipeline! + private let tunnelSettingsUpdater: SettingsUpdater! - private let multihopStateListener = MultihopStateListener() - private let multihopUpdater: MultihopUpdater - private let constraintsUpdater = RelayConstraintsUpdater() + private let tunnelSettingsListener = TunnelSettingsListener() private lazy var postQuantumReceiver = { PostQuantumKeyReceiver(tunnelProvider: self) }() @@ -48,7 +47,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { relayCache: RelayCache(cacheDirectory: containerURL), ipOverrideRepository: IPOverrideRepository() ) - multihopUpdater = MultihopUpdater(listener: multihopStateListener) + tunnelSettingsUpdater = SettingsUpdater(listener: tunnelSettingsListener) super.init() @@ -77,7 +76,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { deviceChecker = DeviceChecker(accountsProxy: accountsProxy, devicesProxy: devicesProxy) relaySelector = RelaySelectorWrapper( relayCache: ipOverrideWrapper, - multihopUpdater: multihopUpdater + tunnelSettingsUpdater: tunnelSettingsUpdater ) actor = PacketTunnelActor( @@ -89,8 +88,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { relaySelector: relaySelector, settingsReader: TunnelSettingsManager(settingsReader: SettingsReader()) { [weak self] settings in guard let self = self else { return } - multihopStateListener.onNewMultihop?(settings.multihopState) - constraintsUpdater.onNewConstraints?(settings.relayConstraints) + tunnelSettingsListener.onNewSettings?(settings.tunnelSettings) }, protocolObfuscator: ProtocolObfuscator() ) @@ -186,8 +184,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { shadowsocksLoader: ShadowsocksLoader( cache: shadowsocksCache, relaySelector: shadowsocksRelaySelector, - constraintsUpdater: constraintsUpdater, - multihopUpdater: multihopUpdater + settingsUpdater: tunnelSettingsUpdater ) ) diff --git a/ios/PacketTunnel/PacketTunnelProvider/SettingsReader.swift b/ios/PacketTunnel/PacketTunnelProvider/SettingsReader.swift index 2de052e1bd69..1c96fa3e9316 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/SettingsReader.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/SettingsReader.swift @@ -19,11 +19,7 @@ struct SettingsReader: SettingsReaderProtocol { return Settings( privateKey: deviceData.wgKeyData.privateKey, interfaceAddresses: [deviceData.ipv4Address, deviceData.ipv6Address], - relayConstraints: settings.relayConstraints, - dnsServers: settings.dnsSettings.selectedDNSServers, - obfuscation: settings.wireGuardObfuscation, - quantumResistance: settings.tunnelQuantumResistance, - multihopState: settings.tunnelMultihopState + tunnelSettings: settings ) } } @@ -47,22 +43,6 @@ private extension DeviceState { } } -private extension DNSSettings { - /** - Converts `DNSSettings` to `SelectedDNSServers` structure. - */ - var selectedDNSServers: SelectedDNSServers { - if effectiveEnableCustomDNS { - let addresses = Array(customDNSDomains.prefix(DNSSettings.maxAllowedCustomDNSDomains)) - return .custom(addresses) - } else if let serverAddress = blockingOptions.serverAddress { - return .blocking(serverAddress) - } else { - return .gateway - } - } -} - /// Error returned when device state is either revoked or logged out. public enum ReadDeviceDataError: LocalizedError { case loggedOut, revoked diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift index 86d6baae72bd..10cd928cf8a8 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift @@ -500,10 +500,7 @@ extension PacketTunnelActor { } case .random: - return try relaySelector.selectRelays( - with: relayConstraints, - connectionAttemptCount: connectionAttemptCount - ) + return try relaySelector.selectRelays(connectionAttemptCount: connectionAttemptCount) case let .preSelected(selectedRelays): return selectedRelays diff --git a/ios/PacketTunnelCore/Actor/Protocols/SettingsReaderProtocol.swift b/ios/PacketTunnelCore/Actor/Protocols/SettingsReaderProtocol.swift index 8df91bd31bfd..a1107efc2a19 100644 --- a/ios/PacketTunnelCore/Actor/Protocols/SettingsReaderProtocol.swift +++ b/ios/PacketTunnelCore/Actor/Protocols/SettingsReaderProtocol.swift @@ -31,36 +31,60 @@ public struct Settings: Equatable { /// IP addresses assigned for tunnel interface. public var interfaceAddresses: [IPAddressRange] + public var tunnelSettings: LatestTunnelSettings + + public init( + privateKey: PrivateKey, + interfaceAddresses: [IPAddressRange], + tunnelSettings: LatestTunnelSettings + ) { + self.privateKey = privateKey + self.interfaceAddresses = interfaceAddresses + self.tunnelSettings = tunnelSettings + } +} + +extension Settings { /// Relay constraints. - public var relayConstraints: RelayConstraints + public var relayConstraints: RelayConstraints { + tunnelSettings.relayConstraints + } /// DNS servers selected by user. - public var dnsServers: SelectedDNSServers + public var dnsServers: SelectedDNSServers { + /** + Converts `DNSSettings` to `SelectedDNSServers` structure. + */ + if tunnelSettings.dnsSettings.effectiveEnableCustomDNS { + let addresses = Array( + tunnelSettings.dnsSettings.customDNSDomains + .prefix(DNSSettings.maxAllowedCustomDNSDomains) + ) + return .custom(addresses) + } else if let serverAddress = tunnelSettings.dnsSettings.blockingOptions.serverAddress { + return .blocking(serverAddress) + } else { + return .gateway + } + } /// Obfuscation settings - public var obfuscation: WireGuardObfuscationSettings + public var obfuscation: WireGuardObfuscationSettings { + tunnelSettings.wireGuardObfuscation + } - public var quantumResistance: TunnelQuantumResistance + public var quantumResistance: TunnelQuantumResistance { + tunnelSettings.tunnelQuantumResistance + } /// Whether multi-hop is enabled. - public var multihopState: MultihopState + public var multihopState: MultihopState { + tunnelSettings.tunnelMultihopState + } - public init( - privateKey: PrivateKey, - interfaceAddresses: [IPAddressRange], - relayConstraints: RelayConstraints, - dnsServers: SelectedDNSServers, - obfuscation: WireGuardObfuscationSettings, - quantumResistance: TunnelQuantumResistance, - multihopState: MultihopState - ) { - self.privateKey = privateKey - self.interfaceAddresses = interfaceAddresses - self.relayConstraints = relayConstraints - self.dnsServers = dnsServers - self.obfuscation = obfuscation - self.quantumResistance = quantumResistance - self.multihopState = multihopState + /// DAITA settings. + public var daita: DAITASettings { + tunnelSettings.daita } } diff --git a/ios/PacketTunnelCoreTests/Mocks/SettingsReaderStub.swift b/ios/PacketTunnelCoreTests/Mocks/SettingsReaderStub.swift index e202ad04e319..d3caaf70d1c9 100644 --- a/ios/PacketTunnelCoreTests/Mocks/SettingsReaderStub.swift +++ b/ios/PacketTunnelCoreTests/Mocks/SettingsReaderStub.swift @@ -27,11 +27,14 @@ extension SettingsReaderStub { let staticSettings = Settings( privateKey: PrivateKey(), interfaceAddresses: [IPAddressRange(from: "127.0.0.1/32")!], - relayConstraints: RelayConstraints(), - dnsServers: .gateway, - obfuscation: WireGuardObfuscationSettings(state: .off, port: .automatic), - quantumResistance: .automatic, - multihopState: .off + tunnelSettings: LatestTunnelSettings( + relayConstraints: RelayConstraints(), + dnsSettings: DNSSettings(), + wireGuardObfuscation: WireGuardObfuscationSettings(state: .off, port: .automatic), + tunnelQuantumResistance: .automatic, + tunnelMultihopState: .off, + daita: DAITASettings() + ) ) return SettingsReaderStub { @@ -43,11 +46,14 @@ extension SettingsReaderStub { let staticSettings = Settings( privateKey: PrivateKey(), interfaceAddresses: [IPAddressRange(from: "127.0.0.1/32")!], - relayConstraints: RelayConstraints(), - dnsServers: .gateway, - obfuscation: WireGuardObfuscationSettings(state: .off, port: .automatic), - quantumResistance: .on, - multihopState: .off + tunnelSettings: LatestTunnelSettings( + relayConstraints: RelayConstraints(), + dnsSettings: DNSSettings(), + wireGuardObfuscation: WireGuardObfuscationSettings(state: .off, port: .automatic), + tunnelQuantumResistance: .on, + tunnelMultihopState: .off, + daita: DAITASettings() + ) ) return SettingsReaderStub { return staticSettings diff --git a/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift b/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift index b656230c70ab..1d649b59a397 100644 --- a/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift +++ b/ios/PacketTunnelCoreTests/PacketTunnelActorTests.swift @@ -239,11 +239,7 @@ final class PacketTunnelActorTests: XCTestCase { return Settings( privateKey: privateKey, interfaceAddresses: [IPAddressRange(from: "127.0.0.1/32")!], - relayConstraints: RelayConstraints(), - dnsServers: .gateway, - obfuscation: WireGuardObfuscationSettings(state: .off, port: .automatic), - quantumResistance: .automatic, - multihopState: .off + tunnelSettings: LatestTunnelSettings() ) } } diff --git a/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift b/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift index e81ae10bf606..3e2c8b52ec90 100644 --- a/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift +++ b/ios/PacketTunnelCoreTests/ProtocolObfuscatorTests.swift @@ -106,14 +106,10 @@ final class ProtocolObfuscatorTests: XCTestCase { Settings( privateKey: PrivateKey(), interfaceAddresses: [IPAddressRange(from: "127.0.0.1/32")!], - relayConstraints: RelayConstraints(), - dnsServers: .gateway, - obfuscation: WireGuardObfuscationSettings( + tunnelSettings: LatestTunnelSettings(wireGuardObfuscation: WireGuardObfuscationSettings( state: obfuscationState, port: obfuscationPort - ), - quantumResistance: quantumResistance, - multihopState: .off + )) ) } }