Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add quantum resistance settings to preferences view if DEBUG is set #5806

Merged
merged 1 commit into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading