Skip to content

Commit 382e316

Browse files
author
Jon Petersson
committed
Fix bug where relay selector evaluates only first location constraint when a custom list is selected
1 parent b74b165 commit 382e316

File tree

3 files changed

+67
-19
lines changed

3 files changed

+67
-19
lines changed

ios/MullvadREST/Relay/RelaySelector.swift

+22-19
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ public enum RelaySelector {
136136
}
137137

138138
/// Produce a list of `RelayWithLocation` items satisfying the given constraints
139-
private static func applyConstraints<T: AnyRelay>(
139+
static func applyConstraints<T: AnyRelay>(
140140
_ constraints: RelayConstraints,
141141
relays: [RelayWithLocation<T>]
142142
) -> [RelayWithLocation<T>] {
@@ -154,24 +154,10 @@ public enum RelaySelector {
154154
case .any:
155155
return true
156156
case let .only(relayConstraint):
157-
for location in relayConstraint.locations {
158-
switch location {
159-
case let .country(countryCode):
160-
return relayWithLocation.serverLocation.countryCode == countryCode &&
161-
relayWithLocation.relay.includeInCountry
162-
163-
case let .city(countryCode, cityCode):
164-
return relayWithLocation.serverLocation.countryCode == countryCode &&
165-
relayWithLocation.serverLocation.cityCode == cityCode
166-
167-
case let .hostname(countryCode, cityCode, hostname):
168-
return relayWithLocation.serverLocation.countryCode == countryCode &&
169-
relayWithLocation.serverLocation.cityCode == cityCode &&
170-
relayWithLocation.relay.hostname == hostname
171-
}
157+
// At least one location must match the relay under test.
158+
return relayConstraint.locations.contains { location in
159+
relayWithLocation.matches(location: location)
172160
}
173-
174-
return false
175161
}
176162
}.filter { relayWithLocation -> Bool in
177163
relayWithLocation.relay.active
@@ -310,9 +296,26 @@ public struct RelaySelectorResult: Codable, Equatable {
310296
public var location: Location
311297
}
312298

313-
private struct RelayWithLocation<T: AnyRelay> {
299+
struct RelayWithLocation<T: AnyRelay> {
314300
let relay: T
315301
let serverLocation: Location
302+
303+
func matches(location: RelayLocation) -> Bool {
304+
switch location {
305+
case let .country(countryCode):
306+
serverLocation.countryCode == countryCode &&
307+
relay.includeInCountry
308+
309+
case let .city(countryCode, cityCode):
310+
serverLocation.countryCode == countryCode &&
311+
serverLocation.cityCode == cityCode
312+
313+
case let .hostname(countryCode, cityCode, hostname):
314+
serverLocation.countryCode == countryCode &&
315+
serverLocation.cityCode == cityCode &&
316+
relay.hostname == hostname
317+
}
318+
}
316319
}
317320

318321
private struct RelayWithDistance<T: AnyRelay> {

ios/MullvadVPNTests/RelaySelectorTests.swift

+39
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,45 @@ class RelaySelectorTests: XCTestCase {
5959
XCTAssertEqual(result.relay.hostname, "se6-wireguard")
6060
}
6161

62+
func testMultipleLocationsConstraint() throws {
63+
let constraints = RelayConstraints(
64+
locations: .only(RelayLocations(locations: [
65+
.city("se", "got"),
66+
.hostname("se", "sto", "se6-wireguard"),
67+
]))
68+
)
69+
70+
let relayWithLocations = sampleRelays.wireguard.relays.map {
71+
let location = sampleRelays.locations[$0.location]!
72+
let locationComponents = $0.location.split(separator: "-")
73+
74+
return RelayWithLocation(
75+
relay: $0,
76+
serverLocation: Location(
77+
country: location.country,
78+
countryCode: String(locationComponents[0]),
79+
city: location.city,
80+
cityCode: String(locationComponents[1]),
81+
latitude: location.latitude,
82+
longitude: location.longitude
83+
)
84+
)
85+
}
86+
87+
let constrainedLocations = RelaySelector.applyConstraints(constraints, relays: relayWithLocations)
88+
89+
XCTAssertTrue(
90+
constrainedLocations.contains(
91+
where: { $0.matches(location: .city("se", "got")) }
92+
)
93+
)
94+
XCTAssertTrue(
95+
constrainedLocations.contains(
96+
where: { $0.matches(location: .hostname("se", "sto", "se6-wireguard")) }
97+
)
98+
)
99+
}
100+
62101
func testSpecificPortConstraint() throws {
63102
let constraints = RelayConstraints(
64103
locations: .only(RelayLocations(locations: [.hostname("se", "sto", "se6-wireguard")])),

ios/MullvadVPNTests/ServerRelaysResponse+Stubs.swift

+6
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ enum ServerRelaysResponseStubs {
6363
latitude: 32.89748,
6464
longitude: -97.040443
6565
),
66+
"us-nyc": REST.ServerLocation(
67+
country: "USA",
68+
city: "New York, NY",
69+
latitude: 40.6963302,
70+
longitude: -74.6034843
71+
),
6672
],
6773
wireguard: REST.ServerWireguardTunnels(
6874
ipv4Gateway: .loopback,

0 commit comments

Comments
 (0)