Skip to content

Commit

Permalink
Merge branch 'add-quantum-resistant-option-to-settings-ios-459'
Browse files Browse the repository at this point in the history
  • Loading branch information
buggmagnet committed Feb 13, 2024
2 parents e79f77a + 0014c3c commit 3a7fdd4
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 4 deletions.
5 changes: 5 additions & 0 deletions ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ public enum AccessibilityIdentifier: String {
case dnsServer
case dnsServerInfo

// Quantum resistance
case quantumResistanceAutomatic
case quantumResistanceOff
case quantumResistanceOn

// Error
case unknown
}
Expand Down
10 changes: 10 additions & 0 deletions ios/MullvadVPN/TunnelManager/TunnelManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,16 @@ final class TunnelManager: StorePaymentObserver {
)
}

func setQuantumResistance(_ newSetting: TunnelQuantumResistance) {
scheduleSettingsUpdate(
taskName: "Set quantum resistance",
modificationBlock: { settings in
settings.tunnelQuantumResistance = newSetting
},
completionHandler: nil
)
}

func refreshRelayCacheTracker() throws {
try relayCacheTracker.refreshCachedRelays()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,43 @@ final class PreferencesCellFactory: CellFactoryProtocol {
)
cell.accessibilityIdentifier = "\(item.accessibilityIdentifier.rawValue) (\(portString))"
cell.applySubCellStyling()

#if DEBUG
case .quantumResistanceAutomatic:
guard let cell = cell as? SelectableSettingsCell else { return }

cell.titleLabel.text = NSLocalizedString(
"QUANTUM_RESISTANCE_AUTOMATIC_LABEL",
tableName: "Preferences",
value: "Automatic",
comment: ""
)
cell.accessibilityIdentifier = item.accessibilityIdentifier
cell.applySubCellStyling()

case .quantumResistanceOn:
guard let cell = cell as? SelectableSettingsCell else { return }

cell.titleLabel.text = NSLocalizedString(
"QUANTUM_RESISTANCE_ON_LABEL",
tableName: "Preferences",
value: "On",
comment: ""
)
cell.accessibilityIdentifier = item.accessibilityIdentifier
cell.applySubCellStyling()
case .quantumResistanceOff:
guard let cell = cell as? SelectableSettingsCell else { return }

cell.titleLabel.text = NSLocalizedString(
"QUANTUM_RESISTANCE_OFF_LABEL",
tableName: "Preferences",
value: "Off",
comment: ""
)
cell.accessibilityIdentifier = item.accessibilityIdentifier
cell.applySubCellStyling()
#endif
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
case wireGuardCustomPort
case wireGuardObfuscation
case wireGuardObfuscationPort
case quantumResistance
var reusableViewClass: AnyClass {
switch self {
case .dnsSettings:
Expand All @@ -33,6 +34,8 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
return SelectableSettingsCell.self
case .wireGuardObfuscationPort:
return SelectableSettingsCell.self
case .quantumResistance:
return SelectableSettingsCell.self
}
}
}
Expand All @@ -50,6 +53,9 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
case wireGuardPorts
case wireGuardObfuscation
case wireGuardObfuscationPort
#if DEBUG
case quantumResistance
#endif
}

enum Item: Hashable {
Expand All @@ -60,6 +66,11 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
case wireGuardObfuscationOn
case wireGuardObfuscationOff
case wireGuardObfuscationPort(_ port: UInt16)
#if DEBUG
case quantumResistanceAutomatic
case quantumResistanceOn
case quantumResistanceOff
#endif

static var wireGuardPorts: [Item] {
let defaultPorts = PreferencesViewModel.defaultWireGuardPorts.map {
Expand All @@ -76,6 +87,12 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
[.wireGuardObfuscationPort(0), wireGuardObfuscationPort(80), wireGuardObfuscationPort(5001)]
}

#if DEBUG
static var quantumResistance: [Item] {
[.quantumResistanceAutomatic, .quantumResistanceOn, .quantumResistanceOff]
}
#endif

var accessibilityIdentifier: AccessibilityIdentifier {
switch self {
case .dnsSettings:
Expand All @@ -92,6 +109,14 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
return .wireGuardObfuscationOff
case .wireGuardObfuscationPort:
return .wireGuardObfuscationAutomatic
#if DEBUG
case .quantumResistanceAutomatic:
return .quantumResistanceAutomatic
case .quantumResistanceOn:
return .quantumResistanceOn
case .quantumResistanceOff:
return .quantumResistanceOff
#endif
}
}

Expand All @@ -107,6 +132,10 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
return .wireGuardObfuscation
case .wireGuardObfuscationPort:
return .wireGuardObfuscationPort
#if DEBUG
case .quantumResistanceAutomatic, .quantumResistanceOn, .quantumResistanceOff:
return .quantumResistance
#endif
}
}
}
Expand All @@ -129,14 +158,30 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
case .off: .wireGuardObfuscationOff
case .on: .wireGuardObfuscationOn
}
#if DEBUG
let quantumResistanceItem: Item = switch viewModel.quantumResistance {
case .automatic: .quantumResistanceAutomatic
case .off: .quantumResistanceOff
case .on: .quantumResistanceOn
}
#endif

let obfuscationPortItem: Item = .wireGuardObfuscationPort(viewModel.obfuscationPort.portValue)

#if DEBUG
return [
wireGuardPortItem,
obfuscationStateItem,
obfuscationPortItem,
quantumResistanceItem,
].compactMap { indexPath(for: $0) }
#else
return [
indexPath(for: wireGuardPortItem),
indexPath(for: obfuscationStateItem),
indexPath(for: obfuscationPortItem),
].compactMap { $0 }
wireGuardPortItem,
obfuscationStateItem,
obfuscationPortItem,
].compactMap { indexPath(for: $0) }
#endif
}

init(tableView: UITableView) {
Expand Down Expand Up @@ -240,6 +285,18 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
case let .wireGuardObfuscationPort(port):
selectObfuscationPort(port)
delegate?.didChangeViewModel(viewModel)

#if DEBUG
case .quantumResistanceAutomatic:
selectQuantumResistance(.automatic)
delegate?.didChangeViewModel(viewModel)
case .quantumResistanceOn:
selectQuantumResistance(.on)
delegate?.didChangeViewModel(viewModel)
case .quantumResistanceOff:
selectQuantumResistance(.off)
delegate?.didChangeViewModel(viewModel)
#endif
default:
break
}
Expand Down Expand Up @@ -277,6 +334,12 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
case .wireGuardObfuscationPort:
configureObfuscationPortHeader(view)
return view
#if DEBUG
case .quantumResistance:
configureQuantumResistanceHeader(view)
return view
#endif

default:
return nil
}
Expand Down Expand Up @@ -459,6 +522,36 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
}
}

#if DEBUG
private func configureQuantumResistanceHeader(_ header: SettingsHeaderView) {
let title = NSLocalizedString(
"QUANTUM_RESISTANCE_HEADER_LABEL",
tableName: "Preferences",
value: "Quantum-resistant tunnel",
comment: ""
)

header.titleLabel.text = title
header.accessibilityCustomActionName = title
header.didCollapseHandler = { [weak self] header in
guard let self else { return }

var snapshot = snapshot()
if header.isExpanded {
snapshot.deleteItems(Item.quantumResistance)
} else {
snapshot.appendItems(Item.quantumResistance, toSection: .quantumResistance)
}
header.isExpanded.toggle()
applySnapshot(snapshot, animated: true)
}

header.infoButtonHandler = { [weak self] in
self.map { $0.delegate?.showInfo(for: .quantumResistance) }
}
}
#endif

private func selectRow(at indexPath: IndexPath?, animated: Bool = false) {
tableView?.selectRow(at: indexPath, animated: animated, scrollPosition: .none)
}
Expand Down Expand Up @@ -505,6 +598,10 @@ extension PreferencesDataSource: PreferencesCellEventHandler {
let selectedPort = WireGuardObfuscationPort(rawValue: port)!
viewModel.setWireGuardObfuscationPort(selectedPort)
}

func selectQuantumResistance(_ state: TunnelQuantumResistance) {
viewModel.setQuantumResistance(state)
}
}

// swiftlint:disable:this file_length
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ enum PreferencesInfoButtonItem {
case wireGuardPorts
case wireGuardObfuscation
case wireGuardObfuscationPort
case quantumResistance
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ final class PreferencesInteractor {

tunnelManager.setRelayConstraints(relayConstraints, completionHandler: completion)
}

func setQuantumResistance(_ newSetting: TunnelQuantumResistance) {
tunnelManager.setQuantumResistance(newSetting)
}
}

extension PreferencesInteractor: RelayCacheTrackerObserver {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class PreferencesViewController: UITableViewController, PreferencesDataSourceDel
state: viewModel.obfuscationState,
port: viewModel.obfuscationPort
))
interactor.setQuantumResistance(viewModel.quantumResistance)
}

func showInfo(for item: PreferencesInfoButtonItem) {
Expand Down Expand Up @@ -152,6 +153,18 @@ class PreferencesViewController: UITableViewController, PreferencesDataSourceDel
comment: ""
)

case .quantumResistance:
message = NSLocalizedString(
"PREFERENCES_QUANTUM_RESISTANCE_GENERAL",
tableName: "QuantumResistance",
value: """
This feature makes the WireGuard tunnel resistant to potential attacks from quantum computers.
It does this by performing an extra key exchange using a quantum safe algorithm and mixing the result into WireGuard’s regular encryption.
This extra step uses approximately 500 kiB of traffic every time a new tunnel is established.
""",
comment: ""
)

default:
assertionFailure("No matching InfoButtonItem")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ struct PreferencesViewModel: Equatable {
private(set) var obfuscationState: WireGuardObfuscationState
private(set) var obfuscationPort: WireGuardObfuscationPort

private(set) var quantumResistance: TunnelQuantumResistance

static let defaultWireGuardPorts: [UInt16] = [51820, 53]

mutating func setBlockAdvertising(_ newValue: Bool) {
Expand Down Expand Up @@ -148,6 +150,10 @@ struct PreferencesViewModel: Equatable {
obfuscationPort = newPort
}

mutating func setQuantumResistance(_ newState: TunnelQuantumResistance) {
quantumResistance = newState
}

/// Precondition for enabling Custom DNS.
var customDNSPrecondition: CustomDNSPrecondition {
if blockAdvertising || blockTracking || blockMalware ||
Expand Down Expand Up @@ -193,6 +199,8 @@ struct PreferencesViewModel: Equatable {

obfuscationState = tunnelSettings.wireGuardObfuscation.state
obfuscationPort = tunnelSettings.wireGuardObfuscation.port

quantumResistance = tunnelSettings.tunnelQuantumResistance
}

/// Produce merged view model keeping entry `identifier` for matching DNS entries.
Expand Down

0 comments on commit 3a7fdd4

Please sign in to comment.