summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ios/MullvadREST/Transport/EncryptedDNS/EncryptedDNSTransport.swift36
-rw-r--r--ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift2
-rw-r--r--ios/MullvadREST/Transport/TransportProvider.swift5
-rw-r--r--ios/MullvadREST/Transport/TransportStrategy.swift17
-rw-r--r--ios/MullvadRESTTests/TransportStrategyTests.swift20
-rw-r--r--ios/MullvadSettings/AccessMethodKind.swift7
-rw-r--r--ios/MullvadSettings/AccessMethodRepository.swift28
-rw-r--r--ios/MullvadSettings/AccessMethodRepositoryProtocol.swift2
-rw-r--r--ios/MullvadSettings/PersistentAccessMethod.swift3
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj18
-rw-r--r--ios/MullvadVPN/AppDelegate.swift2
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsDataSourceConfiguration.swift4
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsItemIdentifier.swift2
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodKind.swift11
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel+Persistent.swift2
-rw-r--r--ios/MullvadVPNTests/MullvadSettings/APIAccessMethodsTests.swift12
16 files changed, 147 insertions, 24 deletions
diff --git a/ios/MullvadREST/Transport/EncryptedDNS/EncryptedDNSTransport.swift b/ios/MullvadREST/Transport/EncryptedDNS/EncryptedDNSTransport.swift
new file mode 100644
index 0000000000..e0b983d853
--- /dev/null
+++ b/ios/MullvadREST/Transport/EncryptedDNS/EncryptedDNSTransport.swift
@@ -0,0 +1,36 @@
+//
+// EncryptedDNSTransport.swift
+// MullvadVPN
+//
+// Created by Mojgan on 2024-09-19.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+import Foundation
+import MullvadRustRuntime
+import MullvadTypes
+
+public final class EncryptedDNSTransport: RESTTransport {
+ public var name: String {
+ "encrypted-dns-url-session"
+ }
+
+ /// The `URLSession` used to send requests via `encryptedDNSProxy`
+ public let urlSession: URLSession
+
+ public init(
+ urlSession: URLSession,
+ addressCache: REST.AddressCache
+ ) {
+ self.urlSession = urlSession
+ }
+
+ public func sendRequest(
+ _ request: URLRequest,
+ completion: @escaping (Data?, URLResponse?, (any Error)?) -> Void
+ ) -> any Cancellable {
+ // TODO: Start proxy once the backend is integrated into the Swift code.
+ let dataTask = urlSession.dataTask(with: request, completionHandler: completion)
+ dataTask.resume()
+ return dataTask
+ }
+}
diff --git a/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift b/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift
index 356b9c1b19..b65edfa52a 100644
--- a/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift
+++ b/ios/MullvadREST/Transport/ProxyConfigurationTransportProvider.swift
@@ -32,6 +32,8 @@ public class ProxyConfigurationTransportProvider {
configuration: shadowsocksConfiguration,
addressCache: addressCache
)
+ case .encryptedDNS:
+ return EncryptedDNSTransport(urlSession: urlSession, addressCache: addressCache)
case let .shadowsocks(shadowSocksConfiguration):
return ShadowsocksTransport(
urlSession: urlSession,
diff --git a/ios/MullvadREST/Transport/TransportProvider.swift b/ios/MullvadREST/Transport/TransportProvider.swift
index 06aaf6395c..a102f61cd8 100644
--- a/ios/MullvadREST/Transport/TransportProvider.swift
+++ b/ios/MullvadREST/Transport/TransportProvider.swift
@@ -81,6 +81,11 @@ public final class TransportProvider: RESTTransportProvider {
configuration: configuration,
addressCache: addressCache
)
+ case .encryptedDNS:
+ currentTransport = EncryptedDNSTransport(
+ urlSession: urlSessionTransport.urlSession,
+ addressCache: addressCache
+ )
case .none:
currentTransport = nil
}
diff --git a/ios/MullvadREST/Transport/TransportStrategy.swift b/ios/MullvadREST/Transport/TransportStrategy.swift
index a1d029b2b6..394e7cac40 100644
--- a/ios/MullvadREST/Transport/TransportStrategy.swift
+++ b/ios/MullvadREST/Transport/TransportStrategy.swift
@@ -23,19 +23,24 @@ public struct TransportStrategy: Equatable {
/// Connecting via socks proxy
case socks5(configuration: Socks5Configuration)
- /// Failing to retrive transport
+ /// Connecting via encrypted DNS proxy
+ case encryptedDNS
+
+ /// Failing to retrieve transport
case none
public static func == (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case(.direct, .direct), (.none, .none):
- return true
+ true
case let (.shadowsocks(lhsConfiguration), .shadowsocks(rhsConfiguration)):
- return lhsConfiguration == rhsConfiguration
+ lhsConfiguration == rhsConfiguration
case let (.socks5(lhsConfiguration), .socks5(rhsConfiguration)):
- return lhsConfiguration == rhsConfiguration
+ lhsConfiguration == rhsConfiguration
+ case (.encryptedDNS, .encryptedDNS):
+ true
default:
- return false
+ false
}
}
}
@@ -70,6 +75,8 @@ public struct TransportStrategy: Equatable {
switch configuration.proxyConfiguration {
case .direct:
return .direct
+ case .encryptedDNS:
+ return .encryptedDNS
case .bridges:
do {
let configuration = try shadowsocksLoader.load()
diff --git a/ios/MullvadRESTTests/TransportStrategyTests.swift b/ios/MullvadRESTTests/TransportStrategyTests.swift
index b1875c87e5..4aa26c8606 100644
--- a/ios/MullvadRESTTests/TransportStrategyTests.swift
+++ b/ios/MullvadRESTTests/TransportStrategyTests.swift
@@ -15,6 +15,7 @@ import XCTest
class TransportStrategyTests: XCTestCase {
private var directAccess: PersistentAccessMethod!
private var bridgeAccess: PersistentAccessMethod!
+ private var encryptedDNS: PersistentAccessMethod!
private var shadowsocksLoader: ShadowsocksLoaderStub!
@@ -41,15 +42,24 @@ class TransportStrategyTests: XCTestCase {
isEnabled: true,
proxyConfiguration: .bridges
)
+
+ encryptedDNS = PersistentAccessMethod(
+ id: UUID(uuidString: "831CB1F8-1829-42DD-B9DC-82902F298EC0")!,
+ name: "Encrypted DNS proxy",
+ isEnabled: true,
+ proxyConfiguration: .encryptedDNS
+ )
}
func testDefaultStrategyIsDirectWhenAllMethodsAreDisabled() throws {
directAccess.isEnabled = false
bridgeAccess.isEnabled = false
+ encryptedDNS.isEnabled = false
let transportStrategy = TransportStrategy(
datasource: AccessMethodRepositoryStub(accessMethods: [
directAccess,
bridgeAccess,
+ encryptedDNS,
]),
shadowsocksLoader: shadowsocksLoader
)
@@ -61,10 +71,12 @@ class TransportStrategyTests: XCTestCase {
func testReuseSameStrategyWhenEverythingElseIsDisabled() throws {
directAccess.isEnabled = false
+ encryptedDNS.isEnabled = false
let transportStrategy = TransportStrategy(
datasource: AccessMethodRepositoryStub(accessMethods: [
directAccess,
bridgeAccess,
+ encryptedDNS,
]),
shadowsocksLoader: shadowsocksLoader
)
@@ -84,6 +96,7 @@ class TransportStrategyTests: XCTestCase {
datasource: AccessMethodRepositoryStub(accessMethods: [
directAccess,
bridgeAccess,
+ encryptedDNS,
PersistentAccessMethod(
id: UUID(uuidString: "8586E75A-CA7B-4432-B70D-EE65F3F95090")!,
name: "",
@@ -98,7 +111,7 @@ class TransportStrategyTests: XCTestCase {
]),
shadowsocksLoader: shadowsocksLoader
)
- let accessMethodsCount = 3
+ let accessMethodsCount = 4
for i in 0 ..< (accessMethodsCount * 2) {
let previousOne = transportStrategy.connectionTransport()
transportStrategy.didFail()
@@ -113,10 +126,12 @@ class TransportStrategyTests: XCTestCase {
func testUsesNextWhenItIsNotReachable() {
bridgeAccess.isEnabled = false
+ encryptedDNS.isEnabled = false
let transportStrategy = TransportStrategy(
datasource: AccessMethodRepositoryStub(accessMethods: [
directAccess,
bridgeAccess,
+ encryptedDNS,
PersistentAccessMethod(
id: UUID(uuidString: "8586E75A-CA7B-4432-B70D-EE65F3F95090")!,
name: "",
@@ -150,12 +165,13 @@ class TransportStrategyTests: XCTestCase {
datasource: AccessMethodRepositoryStub(accessMethods: [
directAccess,
bridgeAccess,
+ encryptedDNS,
]),
shadowsocksLoader: shadowsocksLoader
)
transportStrategy.didFail()
- XCTAssertEqual(transportStrategy.connectionTransport(), .direct)
+ XCTAssertEqual(transportStrategy.connectionTransport(), .encryptedDNS)
}
func testNoLoopOnFailureAtLoadingConfigurationWhenBridgeIsOnlyEnabled() {
diff --git a/ios/MullvadSettings/AccessMethodKind.swift b/ios/MullvadSettings/AccessMethodKind.swift
index 7f8ab380dc..7f59ab00c3 100644
--- a/ios/MullvadSettings/AccessMethodKind.swift
+++ b/ios/MullvadSettings/AccessMethodKind.swift
@@ -16,6 +16,9 @@ public enum AccessMethodKind: Equatable, Hashable, CaseIterable {
/// Communication over bridges.
case bridges
+ /// Communication over proxy address from a DNS.
+ case encryptedDNS
+
/// Communication over shadowsocks.
case shadowsocks
@@ -27,7 +30,7 @@ public extension AccessMethodKind {
/// Returns `true` if the method is permanent and cannot be deleted.
var isPermanent: Bool {
switch self {
- case .direct, .bridges:
+ case .direct, .bridges, .encryptedDNS:
true
case .shadowsocks, .socks5:
false
@@ -48,6 +51,8 @@ extension PersistentAccessMethod {
.direct
case .bridges:
.bridges
+ case .encryptedDNS:
+ .encryptedDNS
case .shadowsocks:
.shadowsocks
case .socks5:
diff --git a/ios/MullvadSettings/AccessMethodRepository.swift b/ios/MullvadSettings/AccessMethodRepository.swift
index a1193f917b..1ffa3c68e1 100644
--- a/ios/MullvadSettings/AccessMethodRepository.swift
+++ b/ios/MullvadSettings/AccessMethodRepository.swift
@@ -28,6 +28,13 @@ public class AccessMethodRepository: AccessMethodRepositoryProtocol {
proxyConfiguration: .bridges
)
+ private let encryptedDNS = PersistentAccessMethod(
+ id: UUID(uuidString: "831CB1F8-1829-42DD-B9DC-82902F298EC0")!,
+ name: "Encrypted DNS proxy",
+ isEnabled: true,
+ proxyConfiguration: .encryptedDNS
+ )
+
private let accessMethodsSubject: CurrentValueSubject<[PersistentAccessMethod], Never>
public var accessMethodsPublisher: AnyPublisher<[PersistentAccessMethod], Never> {
accessMethodsSubject.eraseToAnyPublisher()
@@ -46,7 +53,7 @@ public class AccessMethodRepository: AccessMethodRepositoryProtocol {
accessMethodsSubject = CurrentValueSubject([])
lastReachableAccessMethodSubject = CurrentValueSubject(direct)
- add([direct, bridge])
+ addDefaultsMethods()
accessMethodsSubject.send(fetchAll())
lastReachableAccessMethodSubject.send(fetchLastReachable())
@@ -107,15 +114,30 @@ public class AccessMethodRepository: AccessMethodRepositoryProtocol {
}
public func fetchAll() -> [PersistentAccessMethod] {
+ #if DEBUG
readApiAccessMethodStore().accessMethods
+ #else
+ readApiAccessMethodStore().accessMethods.filter { $0.id != encryptedDNS.id }
+ #endif
}
public func fetchLastReachable() -> PersistentAccessMethod {
readApiAccessMethodStore().lastReachableAccessMethod
}
- public func reloadWithDefaultsAfterDataRemoval() {
- add([direct, bridge])
+ public func addDefaultsMethods() {
+ #if DEBUG
+ add([
+ direct,
+ bridge,
+ encryptedDNS,
+ ])
+ #else
+ add([
+ direct,
+ bridge,
+ ])
+ #endif
}
private func add(_ methods: [PersistentAccessMethod]) {
diff --git a/ios/MullvadSettings/AccessMethodRepositoryProtocol.swift b/ios/MullvadSettings/AccessMethodRepositoryProtocol.swift
index 02e0fa71f9..0239919f4c 100644
--- a/ios/MullvadSettings/AccessMethodRepositoryProtocol.swift
+++ b/ios/MullvadSettings/AccessMethodRepositoryProtocol.swift
@@ -44,5 +44,5 @@ public protocol AccessMethodRepositoryProtocol: AccessMethodRepositoryDataSource
func fetch(by id: UUID) -> PersistentAccessMethod?
/// Refreshes the storage with default values.
- func reloadWithDefaultsAfterDataRemoval()
+ func addDefaultsMethods()
}
diff --git a/ios/MullvadSettings/PersistentAccessMethod.swift b/ios/MullvadSettings/PersistentAccessMethod.swift
index 2194167a8e..49c9f9c668 100644
--- a/ios/MullvadSettings/PersistentAccessMethod.swift
+++ b/ios/MullvadSettings/PersistentAccessMethod.swift
@@ -66,6 +66,9 @@ public enum PersistentProxyConfiguration: Codable {
/// Communication over bridges.
case bridges
+ /// Communication over proxy address from a DNS.
+ case encryptedDNS
+
/// Communication over shadowsocks.
case shadowsocks(ShadowsocksConfiguration)
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index f939a41780..f8f9d646bd 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -970,6 +970,7 @@
F0DDE42B2B220A15006B57A7 /* RelaySelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0DDE4282B220A15006B57A7 /* RelaySelector.swift */; };
F0DDE42C2B220A15006B57A7 /* Midpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0DDE4292B220A15006B57A7 /* Midpoint.swift */; };
F0E3618B2A4ADD2F00AEEF2B /* WelcomeContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0E3618A2A4ADD2F00AEEF2B /* WelcomeContentView.swift */; };
+ F0E5B2F82C9C68CF0007F78C /* EncryptedDNSTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0E5B2F72C9C68CD0007F78C /* EncryptedDNSTransport.swift */; };
F0E61CAA2BF2911D000C4A95 /* TunnelSettingsV5.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0E61CA82BF2911D000C4A95 /* TunnelSettingsV5.swift */; };
F0E61CAB2BF2911D000C4A95 /* MultihopSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0E61CA92BF2911D000C4A95 /* MultihopSettings.swift */; };
F0E8CC032A4C753B007ED3B4 /* WelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0E8CC022A4C753B007ED3B4 /* WelcomeViewController.swift */; };
@@ -2155,6 +2156,7 @@
F0DDE4282B220A15006B57A7 /* RelaySelector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelaySelector.swift; sourceTree = "<group>"; };
F0DDE4292B220A15006B57A7 /* Midpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Midpoint.swift; sourceTree = "<group>"; };
F0E3618A2A4ADD2F00AEEF2B /* WelcomeContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeContentView.swift; sourceTree = "<group>"; };
+ F0E5B2F72C9C68CD0007F78C /* EncryptedDNSTransport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedDNSTransport.swift; sourceTree = "<group>"; };
F0E61CA82BF2911D000C4A95 /* TunnelSettingsV5.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelSettingsV5.swift; sourceTree = "<group>"; };
F0E61CA92BF2911D000C4A95 /* MultihopSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultihopSettings.swift; sourceTree = "<group>"; };
F0E8CC022A4C753B007ED3B4 /* WelcomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewController.swift; sourceTree = "<group>"; };
@@ -4176,8 +4178,9 @@
isa = PBXGroup;
children = (
F0164ED02B4F2DCB0020268D /* AccessMethodIterator.swift */,
- A932D9EE2B5ADD0700999395 /* ProxyConfigurationTransportProvider.swift */,
F0DC77A32B2315800087F09D /* Direct */,
+ F0E5B2F62C9C689C0007F78C /* EncryptedDNS */,
+ A932D9EE2B5ADD0700999395 /* ProxyConfigurationTransportProvider.swift */,
06FAE67D28F83CA50033DD93 /* RESTTransport.swift */,
58E7BA182A975DF70068EC3A /* RESTTransportProvider.swift */,
F0DC77A22B2314EF0087F09D /* Shadowsocks */,
@@ -4228,6 +4231,14 @@
path = Welcome;
sourceTree = "<group>";
};
+ F0E5B2F62C9C689C0007F78C /* EncryptedDNS */ = {
+ isa = PBXGroup;
+ children = (
+ F0E5B2F72C9C68CD0007F78C /* EncryptedDNSTransport.swift */,
+ );
+ path = EncryptedDNS;
+ sourceTree = "<group>";
+ };
F0E8CC082A4EE0DC007ED3B4 /* Completed */ = {
isa = PBXGroup;
children = (
@@ -5200,6 +5211,7 @@
06799ADB28F98E4800ACD94E /* RESTProxyFactory.swift in Sources */,
F0DDE4182B220458006B57A7 /* ShadowsocksConfiguration.swift in Sources */,
7AA7046A2C8EFE2B0045699D /* StoredRelays.swift in Sources */,
+ F0E5B2F82C9C68CF0007F78C /* EncryptedDNSTransport.swift in Sources */,
06799AF228F98E4800ACD94E /* RESTAccessTokenManager.swift in Sources */,
A90763B12B2857D50045ADF0 /* Socks5Endpoint.swift in Sources */,
06799AF328F98E4800ACD94E /* RESTAuthenticationProxy.swift in Sources */,
@@ -7183,6 +7195,7 @@
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PATH = "${PATH}:/opt/homebrew/opt/go@1.19/bin";
@@ -7195,6 +7208,7 @@
baseConfigurationReference = 5808273928487E3E006B77A4 /* Base.xcconfig */;
buildSettings = {
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PATH = "${PATH}:/opt/homebrew/opt/go@1.19/bin";
@@ -7551,6 +7565,7 @@
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PATH = "${PATH}:/opt/homebrew/opt/go@1.19/bin";
@@ -8388,6 +8403,7 @@
baseConfigurationReference = 5808273928487E3E006B77A4 /* Base.xcconfig */;
buildSettings = {
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PATH = "${PATH}:/opt/homebrew/opt/go@1.19/bin";
diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift
index 48314ee2af..55d6153fee 100644
--- a/ios/MullvadVPN/AppDelegate.swift
+++ b/ios/MullvadVPN/AppDelegate.swift
@@ -537,7 +537,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
try? SettingsManager.writeSettings(LatestTunnelSettings())
// Default access methods need to be repopulated again after settings wipe.
- self.accessMethodRepository.reloadWithDefaultsAfterDataRemoval()
+ self.accessMethodRepository.addDefaultsMethods()
// At app startup, the relay cache tracker will get populated with a list of overriden IPs.
// The overriden IPs will get wiped, therefore, the cache needs to be pruned as well.
try? self.relayCacheTracker.refreshCachedRelays()
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsDataSourceConfiguration.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsDataSourceConfiguration.swift
index c0f1e750d0..7e88cfc1c5 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsDataSourceConfiguration.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsDataSourceConfiguration.swift
@@ -49,7 +49,7 @@ class MethodSettingsDataSourceConfiguration {
}
switch newValue.method {
- case .direct, .bridges:
+ case .direct, .bridges, .encryptedDNS:
break
case .shadowsocks:
@@ -106,7 +106,7 @@ class MethodSettingsDataSourceConfiguration {
}
let itemsToReload: [MethodSettingsItemIdentifier] = switch viewModel.method {
- case .direct, .bridges:
+ case .direct, .bridges, .encryptedDNS:
[]
case .shadowsocks:
MethodSettingsItemIdentifier.allShadowsocksItems
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsItemIdentifier.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsItemIdentifier.swift
index b24b94ad32..87e0e2e45d 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsItemIdentifier.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsItemIdentifier.swift
@@ -87,7 +87,7 @@ enum MethodSettingsItemIdentifier: Hashable {
selectedMethod: AccessMethodKind
) -> [MethodSettingsItemIdentifier] {
switch selectedMethod {
- case .direct, .bridges:
+ case .direct, .bridges, .encryptedDNS:
[]
case .shadowsocks:
errors.compactMap { error in
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodKind.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodKind.swift
index 35fe1fd43c..559b3fce04 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodKind.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodKind.swift
@@ -20,13 +20,16 @@ enum AccessMethodKind: Equatable, Hashable, CaseIterable {
/// Communication over shadowsocks.
case shadowsocks
+ /// Communication over proxy address from a DNS.
+ case encryptedDNS
+
/// Communication over socks v5 proxy.
case socks5
/// Returns `true` if the method is permanent and cannot be deleted.
var isPermanent: Bool {
switch self {
- case .direct, .bridges:
+ case .direct, .bridges, .encryptedDNS:
true
case .shadowsocks, .socks5:
false
@@ -41,7 +44,7 @@ enum AccessMethodKind: Equatable, Hashable, CaseIterable {
/// Returns localized description describing the access method.
var localizedDescription: String {
switch self {
- case .direct, .bridges:
+ case .direct, .bridges, .encryptedDNS:
""
case .shadowsocks:
NSLocalizedString("SHADOWSOCKS", tableName: "APIAccess", value: "Shadowsocks", comment: "")
@@ -54,7 +57,7 @@ enum AccessMethodKind: Equatable, Hashable, CaseIterable {
/// Methods that aren't configurable do not offer any additional configuration.
var hasProxyConfiguration: Bool {
switch self {
- case .direct, .bridges:
+ case .direct, .bridges, .encryptedDNS:
false
case .shadowsocks, .socks5:
true
@@ -68,6 +71,8 @@ extension PersistentAccessMethod {
switch proxyConfiguration {
case .direct:
.direct
+ case .encryptedDNS:
+ .encryptedDNS
case .bridges:
.bridges
case .shadowsocks:
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel+Persistent.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel+Persistent.swift
index 0d8182b5af..4ad1cea25b 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel+Persistent.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel+Persistent.swift
@@ -58,6 +58,8 @@ extension AccessMethodViewModel {
.direct
case .bridges:
.bridges
+ case .encryptedDNS:
+ .encryptedDNS
case .socks5:
try socks.intoPersistentProxyConfiguration()
case .shadowsocks:
diff --git a/ios/MullvadVPNTests/MullvadSettings/APIAccessMethodsTests.swift b/ios/MullvadVPNTests/MullvadSettings/APIAccessMethodsTests.swift
index 4ed3bdc1a3..048c5c2719 100644
--- a/ios/MullvadVPNTests/MullvadSettings/APIAccessMethodsTests.swift
+++ b/ios/MullvadVPNTests/MullvadSettings/APIAccessMethodsTests.swift
@@ -40,8 +40,12 @@ final class APIAccessMethodsTests: XCTestCase {
method.kind == .bridges
}
- XCTAssertEqual(storedMethods.count, 2)
- XCTAssertTrue(hasDirectMethod && hasBridgesMethod)
+ let hasEncryptedDNS = storedMethods.contains { method in
+ method.kind == .encryptedDNS
+ }
+
+ XCTAssertEqual(storedMethods.count, 3)
+ XCTAssertTrue(hasDirectMethod && hasBridgesMethod && hasEncryptedDNS)
}
func testAddingSocks5AccessMethod() throws {
@@ -78,8 +82,8 @@ final class APIAccessMethodsTests: XCTestCase {
let storedMethods = repository.fetchAll()
- // Account for .direct and .bridges that are always added by default.
- XCTAssertEqual(storedMethods.count, 3)
+ // Account for .direct, .bridges and .encryptedDNS that are always added by default.
+ XCTAssertEqual(storedMethods.count, 4)
}
func testUpdatingAccessMethod() throws {