Skip to content

Commit e42edff

Browse files
author
Jon Petersson
committed
List only DAITA enabled entry locations if multihop and DAITA are enabled
1 parent a4c4cbe commit e42edff

13 files changed

+140
-61
lines changed

ios/MullvadVPN.xcodeproj/project.pbxproj

+6
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,8 @@
489489
7A516C3C2B712F0B00BBD33D /* IPOverrideWrapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A516C3B2B712F0B00BBD33D /* IPOverrideWrapperTests.swift */; };
490490
7A52F96A2C1735AE00B133B9 /* RelaySelectorStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FE25EF2AA77664003D1918 /* RelaySelectorStub.swift */; };
491491
7A52F96C2C17450C00B133B9 /* RelaySelectorWrapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A52F96B2C17450C00B133B9 /* RelaySelectorWrapperTests.swift */; };
492+
7A5468AC2C6A55B100590086 /* LocationRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5468AB2C6A55B100590086 /* LocationRelays.swift */; };
493+
7A5468AD2C6B5E4B00590086 /* LocationRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5468AB2C6A55B100590086 /* LocationRelays.swift */; };
492494
7A5869952B32E9C700640D27 /* LinkButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5869942B32E9C700640D27 /* LinkButton.swift */; };
493495
7A5869972B32EA4500640D27 /* AppButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5869962B32EA4500640D27 /* AppButton.swift */; };
494496
7A58699B2B482FE200640D27 /* UITableViewCell+Disable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A58699A2B482FE200640D27 /* UITableViewCell+Disable.swift */; };
@@ -1805,6 +1807,7 @@
18051807
7A516C392B7111A700BBD33D /* IPOverrideWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPOverrideWrapper.swift; sourceTree = "<group>"; };
18061808
7A516C3B2B712F0B00BBD33D /* IPOverrideWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPOverrideWrapperTests.swift; sourceTree = "<group>"; };
18071809
7A52F96B2C17450C00B133B9 /* RelaySelectorWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaySelectorWrapperTests.swift; sourceTree = "<group>"; };
1810+
7A5468AB2C6A55B100590086 /* LocationRelays.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRelays.swift; sourceTree = "<group>"; };
18081811
7A5869942B32E9C700640D27 /* LinkButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkButton.swift; sourceTree = "<group>"; };
18091812
7A5869962B32EA4500640D27 /* AppButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppButton.swift; sourceTree = "<group>"; };
18101813
7A58699A2B482FE200640D27 /* UITableViewCell+Disable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+Disable.swift"; sourceTree = "<group>"; };
@@ -2754,6 +2757,7 @@
27542757
F050AE5D2B739A73003F4EDB /* LocationDataSourceProtocol.swift */,
27552758
7A6652B62BB44B120042D848 /* LocationDiffableDataSourceProtocol.swift */,
27562759
7A6389F72B864CDF008E77E1 /* LocationNode.swift */,
2760+
7A5468AB2C6A55B100590086 /* LocationRelays.swift */,
27572761
F050AE512B70DFC0003F4EDB /* LocationSection.swift */,
27582762
F0BE65362B9F136A005CC385 /* LocationSectionHeaderView.swift */,
27592763
5888AD86227B17950051EB06 /* LocationViewController.swift */,
@@ -5248,6 +5252,7 @@
52485252
A9A5FA422ACB05D90083449F /* DeviceStateAccessorProtocol.swift in Sources */,
52495253
7A5869C32B5820CE00640D27 /* IPOverrideRepositoryTests.swift in Sources */,
52505254
A9A5FA392ACB05910083449F /* UIColor+Palette.swift in Sources */,
5255+
7A5468AD2C6B5E4B00590086 /* LocationRelays.swift in Sources */,
52515256
A9A5FA3A2ACB05910083449F /* UIEdgeInsets+Extensions.swift in Sources */,
52525257
A9A5FA3B2ACB05910083449F /* UIMetrics.swift in Sources */,
52535258
58B07C182AEFDD6C00A09625 /* StoreTransactionLog.swift in Sources */,
@@ -5539,6 +5544,7 @@
55395544
7A9CCCC42A96302800DD6A34 /* TunnelCoordinator.swift in Sources */,
55405545
5827B0A42B0F38FD00CCBBA1 /* EditAccessMethodInteractorProtocol.swift in Sources */,
55415546
586C0D852B03D31E00E7CDD7 /* SocksSectionHandler.swift in Sources */,
5547+
7A5468AC2C6A55B100590086 /* LocationRelays.swift in Sources */,
55425548
58BFA5CC22A7CE1F00A6173D /* ApplicationConfiguration.swift in Sources */,
55435549
5891BF5125E66B1E006D6FB0 /* UIBarButtonItem+KeyboardNavigation.swift in Sources */,
55445550
58E511E628DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */,

ios/MullvadVPN/Coordinators/LocationCoordinator.swift

+30-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
1616
private let tunnelManager: TunnelManager
1717
private let relayCacheTracker: RelayCacheTracker
1818
private let customListRepository: CustomListRepositoryProtocol
19-
private var cachedRelays: CachedRelays?
19+
private var cachedRelays: LocationRelays?
2020

2121
let navigationController: UINavigationController
2222

@@ -54,10 +54,16 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
5454
}
5555

5656
func start() {
57+
let startContext: LocationViewControllerWrapper.MultihopContext =
58+
if case .noRelaysSatisfyingDaitaConstraints = tunnelManager.tunnelStatus.observedState
59+
.blockedState?.reason { .entry } else { .exit }
60+
5761
let locationViewControllerWrapper = LocationViewControllerWrapper(
5862
customListRepository: customListRepository,
5963
constraints: tunnelManager.settings.relayConstraints,
60-
multihopEnabled: tunnelManager.settings.tunnelMultihopState.isEnabled
64+
multihopEnabled: tunnelManager.settings.tunnelMultihopState.isEnabled,
65+
daitaEnabled: tunnelManager.settings.daita.state.isEnabled,
66+
startContext: startContext
6167
)
6268
locationViewControllerWrapper.delegate = self
6369

@@ -69,8 +75,13 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
6975
relayCacheTracker.addObserver(self)
7076

7177
if let cachedRelays = try? relayCacheTracker.getCachedRelays() {
72-
self.cachedRelays = cachedRelays
73-
locationViewControllerWrapper.setCachedRelays(cachedRelays, filter: relayFilter)
78+
let locationRelays = LocationRelays(
79+
relays: cachedRelays.relays.wireguard.relays,
80+
locations: cachedRelays.relays.locations
81+
)
82+
self.cachedRelays = locationRelays
83+
84+
locationViewControllerWrapper.setCachedRelays(locationRelays, filter: relayFilter)
7485
}
7586

7687
navigationController.pushViewController(locationViewControllerWrapper, animated: false)
@@ -87,7 +98,11 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
8798
)
8899

89100
relayFilterCoordinator.didFinish = { [weak self] coordinator, filter in
90-
if let cachedRelays = self?.cachedRelays, let filter {
101+
if var cachedRelays = self?.cachedRelays, let filter {
102+
cachedRelays.relays = cachedRelays.relays.filter { relay in
103+
RelaySelector.relayMatchesFilter(relay, filter: filter)
104+
}
105+
91106
self?.locationViewControllerWrapper?.setCachedRelays(cachedRelays, filter: filter)
92107
}
93108

@@ -148,9 +163,13 @@ extension LocationCoordinator: RelayCacheTrackerObserver {
148163
_ tracker: RelayCacheTracker,
149164
didUpdateCachedRelays cachedRelays: CachedRelays
150165
) {
151-
self.cachedRelays = cachedRelays
166+
let locationRelays = LocationRelays(
167+
relays: cachedRelays.relays.wireguard.relays,
168+
locations: cachedRelays.relays.locations
169+
)
170+
self.cachedRelays = locationRelays
152171

153-
locationViewControllerWrapper?.setCachedRelays(cachedRelays, filter: relayFilter)
172+
locationViewControllerWrapper?.setCachedRelays(locationRelays, filter: relayFilter)
154173
}
155174
}
156175

@@ -178,6 +197,10 @@ extension LocationCoordinator: LocationViewControllerWrapperDelegate {
178197
relayConstraints.filter = .only(filter)
179198

180199
tunnelManager.updateSettings([.relayConstraints(relayConstraints)])
200+
201+
if let cachedRelays {
202+
locationViewControllerWrapper?.setCachedRelays(cachedRelays, filter: filter)
203+
}
181204
}
182205

183206
func navigateToFilter() {

ios/MullvadVPN/View controllers/RelayFilter/RelayFilterChipView.swift

+10-6
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,23 @@ class RelayFilterChipView: UIView {
1818
return label
1919
}()
2020

21+
let closeButton: IncreasedHitButton = {
22+
let button = IncreasedHitButton()
23+
button.setImage(
24+
UIImage(named: "IconCloseSml")?.withTintColor(.white.withAlphaComponent(0.6)),
25+
for: .normal
26+
)
27+
button.accessibilityIdentifier = .relayFilterChipCloseButton
28+
return button
29+
}()
30+
2131
var didTapButton: (() -> Void)?
2232

2333
init() {
2434
super.init(frame: .zero)
2535

2636
self.accessibilityIdentifier = .relayFilterChipView
2737

28-
let closeButton = IncreasedHitButton()
29-
closeButton.setImage(
30-
UIImage(named: "IconCloseSml")?.withTintColor(.white.withAlphaComponent(0.6)),
31-
for: .normal
32-
)
33-
closeButton.accessibilityIdentifier = .relayFilterChipCloseButton
3438
closeButton.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)
3539

3640
let container = UIStackView(arrangedSubviews: [titleLabel, closeButton])

ios/MullvadVPN/View controllers/RelayFilter/RelayFilterView.swift

+22-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
77
//
88

9+
import MullvadSettings
910
import MullvadTypes
1011
import UIKit
1112

@@ -34,6 +35,7 @@ class RelayFilterView: UIView {
3435

3536
private let ownershipView = RelayFilterChipView()
3637
private let providersView = RelayFilterChipView()
38+
private let daitaView = RelayFilterChipView()
3739
private var filter: RelayFilter?
3840

3941
var didUpdateFilter: ((RelayFilter) -> Void)?
@@ -71,14 +73,24 @@ class RelayFilterView: UIView {
7173
}
7274
}
7375

76+
func setDaita(_ enabled: Bool) {
77+
daitaView.isHidden = !enabled
78+
}
79+
7480
private func setUpViews() {
81+
daitaView.setTitle(localizedDaitaText())
82+
daitaView.isHidden = true
83+
daitaView.closeButton.isHidden = true
84+
85+
ownershipView.isHidden = true
7586
ownershipView.didTapButton = { [weak self] in
7687
guard var filter = self?.filter else { return }
7788

7889
filter.ownership = .any
7990
self?.didUpdateFilter?(filter)
8091
}
8192

93+
providersView.isHidden = true
8294
providersView.didTapButton = { [weak self] in
8395
guard var filter = self?.filter else { return }
8496

@@ -87,7 +99,7 @@ class RelayFilterView: UIView {
8799
}
88100

89101
// Add a dummy view at the end to push content to the left.
90-
let filterContainer = UIStackView(arrangedSubviews: [ownershipView, providersView, UIView()])
102+
let filterContainer = UIStackView(arrangedSubviews: [daitaView, ownershipView, providersView, UIView()])
91103
filterContainer.spacing = UIMetrics.FilterView.interChipViewSpacing
92104

93105
let contentContainer = UIStackView(arrangedSubviews: [titleLabel, filterContainer])
@@ -99,6 +111,15 @@ class RelayFilterView: UIView {
99111
}
100112
}
101113

114+
private func localizedDaitaText() -> String {
115+
return NSLocalizedString(
116+
"RELAY_FILTER_APPLIED_DAITA",
117+
tableName: "RelayFilter",
118+
value: "Setting: DAITA",
119+
comment: ""
120+
)
121+
}
122+
102123
private func localizedOwnershipText(for string: String) -> String {
103124
return NSLocalizedString(
104125
"RELAY_FILTER_APPLIED_OWNERSHIP",

ios/MullvadVPN/View controllers/SelectLocation/AllLocationDataSource.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ class AllLocationDataSource: LocationDataSourceProtocol {
2020
/// Constructs a collection of node trees from relays fetched from the API.
2121
/// ``RelayLocation.city`` is of special import since we use it to get country
2222
/// and city names.
23-
func reload(_ response: REST.ServerRelaysResponse, relays: [REST.ServerRelay]) {
23+
func reload(_ relays: LocationRelays) {
2424
let rootNode = RootLocationNode()
2525

26-
for relay in relays {
26+
for relay in relays.relays {
2727
guard case
2828
let .city(countryCode, cityCode) = RelayLocation(dashSeparatedString: relay.location),
29-
let serverLocation = response.locations[relay.location]
29+
let serverLocation = relays.locations[relay.location]
3030
else { continue }
3131

3232
let relayLocation = RelayLocation.hostname(countryCode, cityCode, relay.hostname)

ios/MullvadVPN/View controllers/SelectLocation/LocationCellViewModel.swift

+9-9
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,17 @@ extension [LocationCellViewModel] {
6262
}
6363

6464
extension LocationCellViewModel {
65-
/* Exclusion of other locations in the same node tree as the currently excluded location
65+
/* Exclusion of other locations in the same node tree (as the currently excluded location)
6666
happens when there are no more hosts in that tree that can be selected.
6767
We check this by doing the following, in order:
6868

69-
1. Count host names in the tree. More than one means that there are other locations than
69+
1. Count hostnames in the tree. More than one means that there are other locations than
7070
the excluded one for the relay selector to choose from. No exlusion.
7171

72-
2. Count host names in the excluded node. More than one means that there are multiple
73-
locations for the relay selector to choose from. No exlusion.
72+
2. Count hostnames in the excluded node. More than one means that there are multiple
73+
locations for the relay selector to choose from. No exclusion.
7474

75-
3. Check existance of a location in the tree that match the currently excluded location.
75+
3. Check existance of a location in the tree that matches the currently excluded location.
7676
No match means no exclusion.
7777
*/
7878
func shouldExcludeLocation(_ excludedLocation: LocationCellViewModel?) -> Bool {
@@ -86,8 +86,8 @@ extension LocationCellViewModel {
8686
if case .hostname = location { true } else { false }
8787
}.count
8888

89-
// If the there are more than one selectable relay in the current node we don't need
90-
// show this in the location tree and can return early.
89+
// If the there's more than one selectable relay in the current node we don't need
90+
// to show this in the location tree and can return early.
9191
guard hostCount == 1 else { return false }
9292

9393
let proxyExcludedNode = RootLocationNode(children: [excludedLocation.node])
@@ -96,8 +96,8 @@ extension LocationCellViewModel {
9696
if case .hostname = location { true } else { false }
9797
}.count
9898

99-
// If the there are more than one selectable relay in the excluded node we don't need
100-
// show this in the location tree and can return early.
99+
// If the there's more than one selectable relay in the excluded node we don't need
100+
// to show this in the location tree and can return early.
101101
guard excludedHostCount == 1 else { return false }
102102

103103
var containsExcludedLocation = false

ios/MullvadVPN/View controllers/SelectLocation/LocationDataSource.swift

+2-12
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,14 @@ final class LocationDataSource:
5454
defaultRowAnimation = .fade
5555
}
5656

57-
func setRelays(_ response: REST.ServerRelaysResponse, selectedRelays: RelaySelection, filter: RelayFilter) {
57+
func setRelays(_ cachedRelays: LocationRelays, selectedRelays: RelaySelection) {
5858
let allLocationsDataSource =
5959
dataSources.first(where: { $0 is AllLocationDataSource }) as? AllLocationDataSource
6060

6161
let customListsDataSource =
6262
dataSources.first(where: { $0 is CustomListsDataSource }) as? CustomListsDataSource
6363

64-
let relays = response.wireguard.relays.filter { relay in
65-
RelaySelector.relayMatchesFilter(relay, filter: filter)
66-
}
67-
68-
allLocationsDataSource?.reload(response, relays: relays)
64+
allLocationsDataSource?.reload(cachedRelays)
6965
customListsDataSource?.reload(allLocationNodes: allLocationsDataSource?.nodes ?? [])
7066

7167
setSelectedRelays(selectedRelays)
@@ -237,12 +233,6 @@ final class LocationDataSource:
237233
)
238234
}
239235

240-
private func nodeMatchesExcludedLocation(_ node: LocationNode) -> Bool {
241-
// Compare nodes on name rather than whole node in order to match all items in both .customLists
242-
// and .allLocations.
243-
node.name == excludedLocation?.node.name
244-
}
245-
246236
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
247237
let cell = super.tableView(tableView, cellForRowAt: indexPath)
248238
guard let cell = cell as? LocationCell, let item = itemIdentifier(for: indexPath) else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// LocationRelays.swift
3+
// MullvadVPN
4+
//
5+
// Created by Jon Petersson on 2024-08-12.
6+
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
7+
//
8+
9+
import MullvadREST
10+
11+
struct LocationRelays {
12+
var relays: [REST.ServerRelay]
13+
var locations: [String: REST.ServerLocation]
14+
}

0 commit comments

Comments
 (0)