Skip to content

Commit

Permalink
Show number of available relays in filter view
Browse files Browse the repository at this point in the history
  • Loading branch information
mojganii committed Feb 27, 2025
1 parent cefb461 commit 68821ed
Show file tree
Hide file tree
Showing 22 changed files with 479 additions and 335 deletions.
23 changes: 18 additions & 5 deletions ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,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: (UInt) throws -> SelectedRelays
var candidatesResult: (() throws -> RelaysCandidates)?

init(selectedRelaysResult: @escaping (UInt) throws -> SelectedRelays) {
init(
selectedRelaysResult: @escaping (UInt) throws -> SelectedRelays,
candidatesResult: (() throws -> RelaysCandidates)? = nil
) {
self.selectedRelaysResult = selectedRelaysResult
self.candidatesResult = candidatesResult
}

public func selectRelays(
Expand All @@ -25,14 +30,20 @@ public final class RelaySelectorStub: RelaySelectorProtocol {
) throws -> SelectedRelays {
return try selectedRelaysResult(connectionAttemptCount)
}

public func findCandidates(
tunnelSettings: LatestTunnelSettings
) throws -> RelaysCandidates {
return try candidatesResult?() ?? RelaysCandidates(entryRelays: [], exitRelays: [])
}
}

extension RelaySelectorStub {
/// Returns a relay selector that never fails.
public static func nonFallible() -> RelaySelectorStub {
let publicKey = PrivateKey().publicKey.rawValue

return RelaySelectorStub { _ in
return RelaySelectorStub(selectedRelaysResult: { _ in
let cityRelay = SelectedRelay(
endpoint: MullvadEndpoint(
ipv4Relay: IPv4Endpoint(ip: .loopback, port: 1300),
Expand All @@ -56,13 +67,15 @@ extension RelaySelectorStub {
exit: cityRelay,
retryAttempt: 0
)
}
}, candidatesResult: nil)
}

/// Returns a relay selector that cannot satisfy constraints .
public static func unsatisfied() -> RelaySelectorStub {
return RelaySelectorStub { _ in
return RelaySelectorStub(selectedRelaysResult: { _ in
throw NoRelaysSatisfyingConstraintsError(.relayConstraintNotMatching)
}, candidatesResult: {
throw NoRelaysSatisfyingConstraintsError(.relayConstraintNotMatching)
}
})
}
}
11 changes: 11 additions & 0 deletions ios/MullvadREST/Relay/RelayPicking/RelayPicking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@
import MullvadSettings
import MullvadTypes
import Network
public struct RelaysCandidates {
public let entryRelays: [RelayWithLocation<REST.ServerRelay>]?
public let exitRelays: [RelayWithLocation<REST.ServerRelay>]
public init(
entryRelays: [RelayWithLocation<REST.ServerRelay>]?,
exitRelays: [RelayWithLocation<REST.ServerRelay>]
) {
self.entryRelays = entryRelays
self.exitRelays = exitRelays
}
}

protocol RelayPicking {
var obfuscation: ObfuscatorPortSelection { get }
Expand Down
2 changes: 1 addition & 1 deletion ios/MullvadREST/Relay/RelaySelector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public enum RelaySelector {
// MARK: - public

/// Determines whether a `REST.ServerRelay` satisfies the given relay filter.
public static func relayMatchesFilter(_ relay: AnyRelay, filter: RelayFilter) -> Bool {
static func relayMatchesFilter(_ relay: AnyRelay, filter: RelayFilter) -> Bool {
if case let .only(providers) = filter.providers, providers.contains(relay.provider) == false {
return false
}
Expand Down
4 changes: 4 additions & 0 deletions ios/MullvadREST/Relay/RelaySelectorProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ public protocol RelaySelectorProtocol {
tunnelSettings: LatestTunnelSettings,
connectionAttemptCount: UInt
) throws -> SelectedRelays

func findCandidates(
tunnelSettings: LatestTunnelSettings
) throws -> RelaysCandidates
}

/// Struct describing the selected relay.
Expand Down
46 changes: 39 additions & 7 deletions ios/MullvadREST/Relay/RelaySelectorWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import MullvadSettings
import MullvadTypes

public final class RelaySelectorWrapper: RelaySelectorProtocol, Sendable {
let relayCache: RelayCacheProtocol
public let relayCache: RelayCacheProtocol

public init(relayCache: RelayCacheProtocol) {
self.relayCache = relayCache
Expand All @@ -20,12 +20,7 @@ public final class RelaySelectorWrapper: RelaySelectorProtocol, Sendable {
tunnelSettings: LatestTunnelSettings,
connectionAttemptCount: UInt
) throws -> SelectedRelays {
let obfuscation = try ObfuscatorPortSelector(
relays: try relayCache.read().relays
).obfuscate(
tunnelSettings: tunnelSettings,
connectionAttemptCount: connectionAttemptCount
)
let obfuscation = try prepareObfuscation(for: tunnelSettings, connectionAttemptCount: connectionAttemptCount)

return switch tunnelSettings.tunnelMultihopState {
case .off:
Expand All @@ -44,4 +39,41 @@ public final class RelaySelectorWrapper: RelaySelectorProtocol, Sendable {
).pick()
}
}

public func findCandidates(tunnelSettings: LatestTunnelSettings) throws -> RelaysCandidates {
let obfuscation = try prepareObfuscation(for: tunnelSettings, connectionAttemptCount: 0)

let findCandidates: (REST.ServerRelaysResponse, Bool) throws
-> [RelayWithLocation<REST.ServerRelay>] = { relays, daitaEnabled in
try RelaySelector.WireGuard.findCandidates(
by: .any,
in: relays,
filterConstraint: tunnelSettings.relayConstraints.filter,
daitaEnabled: daitaEnabled
)
}

if tunnelSettings.daita.isAutomaticRouting {
let entryCandidates = try findCandidates(
obfuscation.entryRelays,
tunnelSettings.daita.daitaState.isEnabled
)
let exitCandidates = try findCandidates(obfuscation.exitRelays, false)
return RelaysCandidates(entryRelays: entryCandidates, exitRelays: exitCandidates)
} else {
let exitCandidates = try findCandidates(obfuscation.exitRelays, tunnelSettings.daita.daitaState.isEnabled)
return RelaysCandidates(entryRelays: nil, exitRelays: exitCandidates)
}
}

private func prepareObfuscation(
for tunnelSettings: LatestTunnelSettings,
connectionAttemptCount: UInt
) throws -> ObfuscatorPortSelection {
let relays = try relayCache.read().relays
return try ObfuscatorPortSelector(relays: relays).obfuscate(
tunnelSettings: tunnelSettings,
connectionAttemptCount: connectionAttemptCount
)
}
}
2 changes: 1 addition & 1 deletion ios/MullvadREST/Relay/RelayWithLocation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
import MullvadTypes

public struct RelayWithLocation<T: AnyRelay> {
let relay: T
public let relay: T
public let serverLocation: Location

public func matches(location: RelayLocation) -> Bool {
Expand Down
12 changes: 8 additions & 4 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1033,11 +1033,12 @@
F0B495762D02025200CFEC2A /* ChipContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B495752D02025200CFEC2A /* ChipContainerView.swift */; };
F0B495782D02038B00CFEC2A /* ChipViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B495772D02038B00CFEC2A /* ChipViewModelProtocol.swift */; };
F0B4957A2D02F49200CFEC2A /* ChipFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B495792D02F41F00CFEC2A /* ChipFeature.swift */; };
F0B583D42D6DCE12007F5AE4 /* FilterDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B583D32D6DCE0D007F5AE4 /* FilterDescriptor.swift */; };
F0B894EF2BF751C500817A42 /* RelayWithLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B894EE2BF751C500817A42 /* RelayWithLocation.swift */; };
F0B894F12BF751E300817A42 /* RelayWithDistance.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B894F02BF751E300817A42 /* RelayWithDistance.swift */; };
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 */; };
F0BE65372B9F136A005CC385 /* LocationSectionHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0BE65362B9F136A005CC385 /* LocationSectionHeaderFooterView.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 */; };
Expand Down Expand Up @@ -2420,11 +2421,12 @@
F0B495752D02025200CFEC2A /* ChipContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChipContainerView.swift; sourceTree = "<group>"; };
F0B495772D02038B00CFEC2A /* ChipViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChipViewModelProtocol.swift; sourceTree = "<group>"; };
F0B495792D02F41F00CFEC2A /* ChipFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChipFeature.swift; sourceTree = "<group>"; };
F0B583D32D6DCE0D007F5AE4 /* FilterDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterDescriptor.swift; sourceTree = "<group>"; };
F0B894EE2BF751C500817A42 /* RelayWithLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayWithLocation.swift; sourceTree = "<group>"; };
F0B894F02BF751E300817A42 /* RelayWithDistance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayWithDistance.swift; sourceTree = "<group>"; };
F0B894F22BF7526700817A42 /* RelaySelector+Wireguard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RelaySelector+Wireguard.swift"; sourceTree = "<group>"; };
F0B894F42BF7528700817A42 /* RelaySelector+Shadowsocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RelaySelector+Shadowsocks.swift"; sourceTree = "<group>"; };
F0BE65362B9F136A005CC385 /* LocationSectionHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationSectionHeaderView.swift; sourceTree = "<group>"; };
F0BE65362B9F136A005CC385 /* LocationSectionHeaderFooterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationSectionHeaderFooterView.swift; sourceTree = "<group>"; };
F0C13FE32C64F7CB00BD087D /* DAITASettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAITASettings.swift; sourceTree = "<group>"; };
F0C13FE52C64FB3400BD087D /* TunnelSettingsV6.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsV6.swift; sourceTree = "<group>"; };
F0C2AEFC2A0BB5CC00986207 /* NotificationProviderIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationProviderIdentifier.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3115,7 +3117,7 @@
7A6389F72B864CDF008E77E1 /* LocationNode.swift */,
7A5468AB2C6A55B100590086 /* LocationRelays.swift */,
F050AE512B70DFC0003F4EDB /* LocationSection.swift */,
F0BE65362B9F136A005CC385 /* LocationSectionHeaderView.swift */,
F0BE65362B9F136A005CC385 /* LocationSectionHeaderFooterView.swift */,
5888AD86227B17950051EB06 /* LocationViewController.swift */,
7AB3BEB42BD7A6CB00E34384 /* LocationViewControllerWrapper.swift */,
F01DAE322C2B032A00521E46 /* RelaySelection.swift */,
Expand Down Expand Up @@ -4299,6 +4301,7 @@
F0ADC3712CD3AD1600A1AD97 /* ChipCollectionView.swift */,
F0ADC3732CD3C47400A1AD97 /* ChipFlowLayout.swift */,
7AF9BE962A41C71F00DBFEDB /* ChipViewCell.swift */,
F0B583D32D6DCE0D007F5AE4 /* FilterDescriptor.swift */,
7A1A26482A29D48A00B978AA /* RelayFilterCellFactory.swift */,
7A1A26462A29CF0800B978AA /* RelayFilterDataSource.swift */,
7AF9BE942A40461100DBFEDB /* RelayFilterView.swift */,
Expand Down Expand Up @@ -6183,7 +6186,7 @@
7ABE318D2A1CDD4500DF4963 /* UIFont+Weight.swift in Sources */,
58C774BE29A7A249003A1A56 /* CustomNavigationController.swift in Sources */,
E1FD0DF528AA7CE400299DB4 /* StatusActivityView.swift in Sources */,
F0BE65372B9F136A005CC385 /* LocationSectionHeaderView.swift in Sources */,
F0BE65372B9F136A005CC385 /* LocationSectionHeaderFooterView.swift in Sources */,
7A2960FD2A964BB700389B82 /* AlertPresentation.swift in Sources */,
0697D6E728F01513007A9E99 /* TransportMonitor.swift in Sources */,
58968FAE28743E2000B799DC /* TunnelInteractor.swift in Sources */,
Expand Down Expand Up @@ -6418,6 +6421,7 @@
584592612639B4A200EF967F /* TermsOfServiceContentView.swift in Sources */,
5875960A26F371FC00BF6711 /* Tunnel+Messaging.swift in Sources */,
586C0D912B03D8A400E7CDD7 /* AccessMethodHeaderFooterReuseIdentifier.swift in Sources */,
F0B583D42D6DCE12007F5AE4 /* FilterDescriptor.swift in Sources */,
7A2960F62A963F7500389B82 /* AlertCoordinator.swift in Sources */,
F050AE522B70DFC0003F4EDB /* LocationSection.swift in Sources */,
063687BA28EB234F00BE7161 /* PacketTunnelTransport.swift in Sources */,
Expand Down
3 changes: 2 additions & 1 deletion ios/MullvadVPN/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
private(set) var shadowsocksLoader: ShadowsocksLoaderProtocol!
private(set) var configuredTransportProvider: ProxyConfigurationTransportProvider!
private(set) var ipOverrideRepository = IPOverrideRepository()
private(set) var relaySelector: RelaySelectorWrapper!
private var launchArguments = LaunchArguments()
private var encryptedDNSTransport: EncryptedDNSTransport!

Expand Down Expand Up @@ -104,7 +105,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD

tunnelStore = TunnelStore(application: backgroundTaskProvider)

let relaySelector = RelaySelectorWrapper(
relaySelector = RelaySelectorWrapper(
relayCache: ipOverrideWrapper
)
tunnelManager = createTunnelManager(
Expand Down
7 changes: 5 additions & 2 deletions ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
private var accessMethodRepository: AccessMethodRepositoryProtocol
private let configuredTransportProvider: ProxyConfigurationTransportProvider
private let ipOverrideRepository: IPOverrideRepository
private let relaySelectorWrapper: RelaySelectorWrapper

private var outOfTimeTimer: Timer?

Expand All @@ -72,7 +73,8 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
appPreferences: AppPreferencesDataSource,
accessMethodRepository: AccessMethodRepositoryProtocol,
transportProvider: ProxyConfigurationTransportProvider,
ipOverrideRepository: IPOverrideRepository
ipOverrideRepository: IPOverrideRepository,
relaySelectorWrapper: RelaySelectorWrapper

) {
self.tunnelManager = tunnelManager
Expand All @@ -86,6 +88,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
self.accessMethodRepository = accessMethodRepository
self.configuredTransportProvider = transportProvider
self.ipOverrideRepository = ipOverrideRepository
self.relaySelectorWrapper = relaySelectorWrapper

super.init()

Expand Down Expand Up @@ -509,7 +512,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
let locationCoordinator = LocationCoordinator(
navigationController: navigationController,
tunnelManager: tunnelManager,
relayCacheTracker: relayCacheTracker,
relaySelectorWrapper: relaySelectorWrapper,
customListRepository: CustomListRepository()
)

Expand Down
Loading

0 comments on commit 68821ed

Please sign in to comment.