Skip to content

Commit

Permalink
List only DAITA enabled entry locations if multihop and DAITA are ena…
Browse files Browse the repository at this point in the history
…bled
  • Loading branch information
Jon Petersson committed Aug 13, 2024
1 parent c5fe10c commit 2272c98
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 60 deletions.
2 changes: 1 addition & 1 deletion ios/MullvadREST/ApiHandlers/ServerRelaysResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ extension REST {
public let ipv4AddrIn: IPv4Address
public let weight: UInt64
public let includeInCountry: Bool
public var daita: Bool? = nil
public var daita: Bool?

public func override(ipv4AddrIn: IPv4Address?) -> Self {
return BridgeRelay(
Expand Down
6 changes: 6 additions & 0 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,8 @@
7A516C3C2B712F0B00BBD33D /* IPOverrideWrapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A516C3B2B712F0B00BBD33D /* IPOverrideWrapperTests.swift */; };
7A52F96A2C1735AE00B133B9 /* RelaySelectorStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FE25EF2AA77664003D1918 /* RelaySelectorStub.swift */; };
7A52F96C2C17450C00B133B9 /* RelaySelectorWrapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A52F96B2C17450C00B133B9 /* RelaySelectorWrapperTests.swift */; };
7A5468AC2C6A55B100590086 /* LocationRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5468AB2C6A55B100590086 /* LocationRelays.swift */; };
7A5468AD2C6B5E4B00590086 /* LocationRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5468AB2C6A55B100590086 /* LocationRelays.swift */; };
7A5869952B32E9C700640D27 /* LinkButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5869942B32E9C700640D27 /* LinkButton.swift */; };
7A5869972B32EA4500640D27 /* AppButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5869962B32EA4500640D27 /* AppButton.swift */; };
7A58699B2B482FE200640D27 /* UITableViewCell+Disable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A58699A2B482FE200640D27 /* UITableViewCell+Disable.swift */; };
Expand Down Expand Up @@ -1803,6 +1805,7 @@
7A516C392B7111A700BBD33D /* IPOverrideWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPOverrideWrapper.swift; sourceTree = "<group>"; };
7A516C3B2B712F0B00BBD33D /* IPOverrideWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPOverrideWrapperTests.swift; sourceTree = "<group>"; };
7A52F96B2C17450C00B133B9 /* RelaySelectorWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaySelectorWrapperTests.swift; sourceTree = "<group>"; };
7A5468AB2C6A55B100590086 /* LocationRelays.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRelays.swift; sourceTree = "<group>"; };
7A5869942B32E9C700640D27 /* LinkButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkButton.swift; sourceTree = "<group>"; };
7A5869962B32EA4500640D27 /* AppButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppButton.swift; sourceTree = "<group>"; };
7A58699A2B482FE200640D27 /* UITableViewCell+Disable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+Disable.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2749,6 +2752,7 @@
F050AE5D2B739A73003F4EDB /* LocationDataSourceProtocol.swift */,
7A6652B62BB44B120042D848 /* LocationDiffableDataSourceProtocol.swift */,
7A6389F72B864CDF008E77E1 /* LocationNode.swift */,
7A5468AB2C6A55B100590086 /* LocationRelays.swift */,
F050AE512B70DFC0003F4EDB /* LocationSection.swift */,
F0BE65362B9F136A005CC385 /* LocationSectionHeaderView.swift */,
5888AD86227B17950051EB06 /* LocationViewController.swift */,
Expand Down Expand Up @@ -5211,6 +5215,7 @@
A9A5FA422ACB05D90083449F /* DeviceStateAccessorProtocol.swift in Sources */,
7A5869C32B5820CE00640D27 /* IPOverrideRepositoryTests.swift in Sources */,
A9A5FA392ACB05910083449F /* UIColor+Palette.swift in Sources */,
7A5468AD2C6B5E4B00590086 /* LocationRelays.swift in Sources */,
A9A5FA3A2ACB05910083449F /* UIEdgeInsets+Extensions.swift in Sources */,
A9A5FA3B2ACB05910083449F /* UIMetrics.swift in Sources */,
58B07C182AEFDD6C00A09625 /* StoreTransactionLog.swift in Sources */,
Expand Down Expand Up @@ -5498,6 +5503,7 @@
7A9CCCC42A96302800DD6A34 /* TunnelCoordinator.swift in Sources */,
5827B0A42B0F38FD00CCBBA1 /* EditAccessMethodInteractorProtocol.swift in Sources */,
586C0D852B03D31E00E7CDD7 /* SocksSectionHandler.swift in Sources */,
7A5468AC2C6A55B100590086 /* LocationRelays.swift in Sources */,
58BFA5CC22A7CE1F00A6173D /* ApplicationConfiguration.swift in Sources */,
5891BF5125E66B1E006D6FB0 /* UIBarButtonItem+KeyboardNavigation.swift in Sources */,
58E511E628DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */,
Expand Down
29 changes: 23 additions & 6 deletions ios/MullvadVPN/Coordinators/LocationCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
private let tunnelManager: TunnelManager
private let relayCacheTracker: RelayCacheTracker
private let customListRepository: CustomListRepositoryProtocol
private var cachedRelays: CachedRelays?
private var cachedRelays: LocationRelays?

let navigationController: UINavigationController

Expand Down Expand Up @@ -69,8 +69,13 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
relayCacheTracker.addObserver(self)

if let cachedRelays = try? relayCacheTracker.getCachedRelays() {
self.cachedRelays = cachedRelays
locationViewControllerWrapper.setCachedRelays(cachedRelays, filter: relayFilter)
let locationRelays = LocationRelays(
relays: cachedRelays.relays.wireguard.relays,
locations: cachedRelays.relays.locations
)
self.cachedRelays = locationRelays

locationViewControllerWrapper.setCachedRelays(locationRelays, filter: relayFilter)
}

navigationController.pushViewController(locationViewControllerWrapper, animated: false)
Expand All @@ -87,7 +92,11 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
)

relayFilterCoordinator.didFinish = { [weak self] coordinator, filter in
if let cachedRelays = self?.cachedRelays, let filter {
if var cachedRelays = self?.cachedRelays, let filter {
cachedRelays.relays = cachedRelays.relays.filter { relay in
RelaySelector.relayMatchesFilter(relay, filter: filter)
}

self?.locationViewControllerWrapper?.setCachedRelays(cachedRelays, filter: filter)
}

Expand Down Expand Up @@ -148,9 +157,13 @@ extension LocationCoordinator: RelayCacheTrackerObserver {
_ tracker: RelayCacheTracker,
didUpdateCachedRelays cachedRelays: CachedRelays
) {
self.cachedRelays = cachedRelays
let locationRelays = LocationRelays(
relays: cachedRelays.relays.wireguard.relays,
locations: cachedRelays.relays.locations
)
self.cachedRelays = locationRelays

locationViewControllerWrapper?.setCachedRelays(cachedRelays, filter: relayFilter)
locationViewControllerWrapper?.setCachedRelays(locationRelays, filter: relayFilter)
}
}

Expand Down Expand Up @@ -178,6 +191,10 @@ extension LocationCoordinator: LocationViewControllerWrapperDelegate {
relayConstraints.filter = .only(filter)

tunnelManager.updateSettings([.relayConstraints(relayConstraints)])

if let cachedRelays {
locationViewControllerWrapper?.setCachedRelays(cachedRelays, filter: filter)
}
}

func navigateToFilter() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,23 @@ class RelayFilterChipView: UIView {
return label
}()

let closeButton: IncreasedHitButton = {
let button = IncreasedHitButton()
button.setImage(
UIImage(named: "IconCloseSml")?.withTintColor(.white.withAlphaComponent(0.6)),
for: .normal
)
button.accessibilityIdentifier = .relayFilterChipCloseButton
return button
}()

var didTapButton: (() -> Void)?

init() {
super.init(frame: .zero)

self.accessibilityIdentifier = .relayFilterChipView

let closeButton = IncreasedHitButton()
closeButton.setImage(
UIImage(named: "IconCloseSml")?.withTintColor(.white.withAlphaComponent(0.6)),
for: .normal
)
closeButton.accessibilityIdentifier = .relayFilterChipCloseButton
closeButton.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)

let container = UIStackView(arrangedSubviews: [titleLabel, closeButton])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import MullvadTypes
import MullvadSettings
import UIKit

class RelayFilterView: UIView {
Expand Down Expand Up @@ -34,7 +35,9 @@ class RelayFilterView: UIView {

private let ownershipView = RelayFilterChipView()
private let providersView = RelayFilterChipView()
private let daitaView = RelayFilterChipView()
private var filter: RelayFilter?
private var daitaState: MultihopState = .off

var didUpdateFilter: ((RelayFilter) -> Void)?

Expand Down Expand Up @@ -71,14 +74,25 @@ class RelayFilterView: UIView {
}
}

func setDaita(_ state: MultihopState) {
daitaState = state
daitaView.isHidden = state == .off
}

private func setUpViews() {
daitaView.setTitle(localizedDaitaText())
daitaView.isHidden = true
daitaView.closeButton.isHidden = true

ownershipView.isHidden = true
ownershipView.didTapButton = { [weak self] in
guard var filter = self?.filter else { return }

filter.ownership = .any
self?.didUpdateFilter?(filter)
}

providersView.isHidden = true
providersView.didTapButton = { [weak self] in
guard var filter = self?.filter else { return }

Expand All @@ -87,7 +101,7 @@ class RelayFilterView: UIView {
}

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

let contentContainer = UIStackView(arrangedSubviews: [titleLabel, filterContainer])
Expand All @@ -99,6 +113,15 @@ class RelayFilterView: UIView {
}
}

private func localizedDaitaText() -> String {
return NSLocalizedString(
"RELAY_FILTER_APPLIED_DAITA",
tableName: "RelayFilter",
value: "Setting: DAITA",
comment: ""
)
}

private func localizedOwnershipText(for string: String) -> String {
return NSLocalizedString(
"RELAY_FILTER_APPLIED_OWNERSHIP",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ class AllLocationDataSource: LocationDataSourceProtocol {
/// Constructs a collection of node trees from relays fetched from the API.
/// ``RelayLocation.city`` is of special import since we use it to get country
/// and city names.
func reload(_ response: REST.ServerRelaysResponse, relays: [REST.ServerRelay]) {
func reload(_ relays: LocationRelays) {
let rootNode = RootLocationNode()

for relay in relays {
for relay in relays.relays {
guard case
let .city(countryCode, cityCode) = RelayLocation(dashSeparatedString: relay.location),
let serverLocation = response.locations[relay.location]
let serverLocation = relays.locations[relay.location]
else { continue }

let relayLocation = RelayLocation.hostname(countryCode, cityCode, relay.hostname)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ extension [LocationCellViewModel] {
}

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

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

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

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

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

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

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

var containsExcludedLocation = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,14 @@ final class LocationDataSource:
defaultRowAnimation = .fade
}

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

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

let relays = response.wireguard.relays.filter { relay in
RelaySelector.relayMatchesFilter(relay, filter: filter)
}

allLocationsDataSource?.reload(response, relays: relays)
allLocationsDataSource?.reload(cachedRelays)
customListsDataSource?.reload(allLocationNodes: allLocationsDataSource?.nodes ?? [])

setSelectedRelays(selectedRelays)
Expand Down Expand Up @@ -237,12 +233,6 @@ final class LocationDataSource:
)
}

private func nodeMatchesExcludedLocation(_ node: LocationNode) -> Bool {
// Compare nodes on name rather than whole node in order to match all items in both .customLists
// and .allLocations.
node.name == excludedLocation?.node.name
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAt: indexPath)
guard let cell = cell as? LocationCell, let item = itemIdentifier(for: indexPath) else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// LocationRelays.swift
// MullvadVPN
//
// Created by Jon Petersson on 2024-08-12.
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
//

import MullvadREST

struct LocationRelays {
var relays: [REST.ServerRelay]
var locations: [String: REST.ServerLocation]
}
Loading

0 comments on commit 2272c98

Please sign in to comment.