summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ChipView/ChipFeature.swift
blob: 5fd444815735d30eec27cabd76f134f122976955 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//
//  ChipFeature.swift
//  MullvadVPN
//
//  Created by Mojgan on 2024-12-06.
//  Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
import MullvadSettings
import PacketTunnelCore
import SwiftUI

protocol ChipFeature: Identifiable {
    var id: FeatureType { get }
    var isEnabled: Bool { get }
    var name: String { get }
}

enum FeatureType {
    case daita
    case multihop
    case quantumResistance
    case obfuscation
    case dns
    case ipOverrides
}

struct DaitaFeature: ChipFeature {
    let id: FeatureType = .daita
    let state: TunnelState
    let settings: LatestTunnelSettings

    var isEnabled: Bool {
        state.isDaita ?? false
    }

    var name: String {
        // When multihop is enabled via DAITA without being explicitly enabled
        // by the user, display combined indicator instead.
        state.isMultihop && !settings.tunnelMultihopState.isEnabled
            ? "\(NSLocalizedString("DAITA", comment: "")): \(NSLocalizedString("Multihop", comment: ""))"
            : NSLocalizedString("DAITA", comment: "")
    }
}

struct QuantumResistanceFeature: ChipFeature {
    let id: FeatureType = .quantumResistance
    let state: TunnelState

    var isEnabled: Bool {
        state.isPostQuantum ?? false
    }

    var name: String {
        NSLocalizedString("Quantum resistance", comment: "")
    }
}

struct MultihopFeature: ChipFeature {
    let id: FeatureType = .multihop
    let state: TunnelState
    let settings: LatestTunnelSettings

    var isEnabled: Bool {
        // Multihop indicator should only be visible when user has explicitly turned on
        // multihop, not when using multihop via DAITA.
        state.isMultihop && settings.tunnelMultihopState.isEnabled
    }

    var name: String {
        NSLocalizedString("Multihop", comment: "")
    }
}

struct ObfuscationFeature: ChipFeature {
    let id: FeatureType = .obfuscation
    let settings: LatestTunnelSettings
    let state: ObservedState

    var actualObfuscationMethod: WireGuardObfuscationState {
        state.connectionState.map { $0.obfuscationMethod } ?? .off
    }

    var isEnabled: Bool {
        actualObfuscationMethod != .off
    }

    var isAutomatic: Bool {
        settings.wireGuardObfuscation.state == .automatic
    }

    var name: String {
        // This just currently says "Obfuscation".
        // To add an automaticity indicator (a trailing " (automatic)"
        // or a colour/border style or whatever), use the `isAutomatic` field.
        // To say what type of obfuscation it is,
        // we can look at `actualObfuscationMethod`
        NSLocalizedString("Obfuscation", comment: "")
    }
}

struct DNSFeature: ChipFeature {
    let id: FeatureType = .dns
    let settings: LatestTunnelSettings

    var isEnabled: Bool {
        settings.dnsSettings.enableCustomDNS || !settings.dnsSettings.blockingOptions.isEmpty
    }

    var name: String {
        if !settings.dnsSettings.blockingOptions.isEmpty {
            NSLocalizedString("DNS content blockers", comment: "")
        } else {
            NSLocalizedString("Custom DNS", comment: "")
        }
    }
}

struct IPOverrideFeature: ChipFeature {
    let id: FeatureType = .ipOverrides
    let state: TunnelState
    let overrides: [IPOverride]

    var isEnabled: Bool {
        guard
            let endpoint = state.relays?.ingress.endpoint
        else { return false }
        return overrides.contains { override in
            (override.ipv4Address.map { $0 == endpoint.ipv4Relay.ip } ?? false)
                || (override.ipv6Address.map { $0 == endpoint.ipv6Relay?.ip } ?? false)
        }
    }

    var name: String {
        NSLocalizedString("Server IP override", comment: "")
    }
}