Skip to content

Commit

Permalink
VPN-5466 - Bring back LAN Bypass setting on iOS (#9070)
Browse files Browse the repository at this point in the history
* Bring back LAN Bypass setting on iOS

* Fix stuff

* Remove unnecessary binding

* Fix stuf

* Fix build

* Use toggle, address comments

* Get stuff to work

* typographic quotes
  • Loading branch information
brizental authored Mar 18, 2024
1 parent 2feb637 commit 8f68e3d
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 31 deletions.
1 change: 1 addition & 0 deletions src/platforms/ios/ioscontroller.mm
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
serverPublicKey:config.m_serverPublicKey.toNSString()
serverIpv4AddrIn:config.m_serverIpv4AddrIn.toNSString()
serverPort:config.m_serverPort
excludeLocalNetworks:settingsHolder->localNetworkAccess()
allowedIPAddressRanges:allowedIPAddressRangesNS
reason:reason
gleanDebugTag:settingsHolder->gleanDebugTagActive()
Expand Down
16 changes: 8 additions & 8 deletions src/platforms/ios/ioscontroller.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public class IOSControllerImpl : NSObject {
}
}

@objc func connect(dnsServer: String, serverIpv6Gateway: String, serverPublicKey: String, serverIpv4AddrIn: String, serverPort: Int, allowedIPAddressRanges: Array<VPNIPAddressRange>, reason: Int, gleanDebugTag: String, isSuperDooperFeatureActive: Bool, installationId: String, disconnectOnErrorCallback: @escaping () -> Void, onboardingCompletedCallback: @escaping () -> Void, vpnConfigPermissionResponseCallback: @escaping (Bool) -> Void) {
@objc func connect(dnsServer: String, serverIpv6Gateway: String, serverPublicKey: String, serverIpv4AddrIn: String, serverPort: Int, excludeLocalNetworks: Bool, allowedIPAddressRanges: Array<VPNIPAddressRange>, reason: Int, gleanDebugTag: String, isSuperDooperFeatureActive: Bool, installationId: String, disconnectOnErrorCallback: @escaping () -> Void, onboardingCompletedCallback: @escaping () -> Void, vpnConfigPermissionResponseCallback: @escaping (Bool) -> Void) {
IOSControllerImpl.logger.debug(message: "Connecting")

TunnelManager.withTunnel { tunnel in
Expand All @@ -142,7 +142,7 @@ public class IOSControllerImpl : NSObject {
var peerConfigurations: [PeerConfiguration] = []
peerConfigurations.append(peerConfiguration)

var interface = InterfaceConfiguration(privateKey: privateKey!)
var interface = InterfaceConfiguration(privateKey: self.privateKey!)

if let ipv4Address = IPAddressRange(from: deviceIpv4Address!),
let ipv6Address = IPAddressRange(from: deviceIpv6Address!) {
Expand All @@ -152,11 +152,11 @@ public class IOSControllerImpl : NSObject {

let config = TunnelConfiguration(name: VPN_NAME, interface: interface, peers: peerConfigurations)

return self.configureTunnel(config: config, reason: reason, serverName: serverIpv4AddrIn + ":\(serverPort )", gleanDebugTag: gleanDebugTag, isSuperDooperFeatureActive: isSuperDooperFeatureActive, installationId: installationId, disconnectOnErrorCallback: disconnectOnErrorCallback, onboardingCompletedCallback: onboardingCompletedCallback, vpnConfigPermissionResponseCallback: vpnConfigPermissionResponseCallback)
return self.configureTunnel(config: config, reason: reason, serverName: serverIpv4AddrIn + ":\(serverPort )", excludeLocalNetworks: excludeLocalNetworks, gleanDebugTag: gleanDebugTag, isSuperDooperFeatureActive: isSuperDooperFeatureActive, installationId: installationId, disconnectOnErrorCallback: disconnectOnErrorCallback, onboardingCompletedCallback: onboardingCompletedCallback, vpnConfigPermissionResponseCallback: vpnConfigPermissionResponseCallback)
}
}

func configureTunnel(config: TunnelConfiguration, reason: Int, serverName: String, gleanDebugTag: String, isSuperDooperFeatureActive: Bool, installationId: String, disconnectOnErrorCallback: @escaping () -> Void, onboardingCompletedCallback: @escaping () -> Void, vpnConfigPermissionResponseCallback: @escaping (Bool) -> Void) {
func configureTunnel(config: TunnelConfiguration, reason: Int, serverName: String, excludeLocalNetworks: Bool, gleanDebugTag: String, isSuperDooperFeatureActive: Bool, installationId: String, disconnectOnErrorCallback: @escaping () -> Void, onboardingCompletedCallback: @escaping () -> Void, vpnConfigPermissionResponseCallback: @escaping (Bool) -> Void) {
TunnelManager.withTunnel { tunnel in
let proto = NETunnelProviderProtocol(tunnelConfiguration: config)
proto!.providerBundleIdentifier = TunnelManager.vpnBundleId
Expand All @@ -166,7 +166,7 @@ public class IOSControllerImpl : NSObject {
if #available(iOS 15.1, *) {
IOSControllerImpl.logger.debug(message: "Activating includeAllNetworks")
proto!.includeAllNetworks = true
proto!.excludeLocalNetworks = true
proto!.excludeLocalNetworks = excludeLocalNetworks

if #available(iOS 16.4, *) {
// By default, APNs is excluded from the VPN tunnel on 16.4 and later. We want to include it.
Expand All @@ -189,7 +189,7 @@ public class IOSControllerImpl : NSObject {
// the vpn configuration to be created, so it is safe to run activation retries via Controller::startHandshakeTimer()
// without the possibility or re-prompting (flickering) the modal while it is currently being displayed
vpnConfigPermissionResponseCallback(saveError == nil)

if let error = saveError {
IOSControllerImpl.logger.error(message: "Connect Tunnel Save Error: \(error)")
disconnectOnErrorCallback()
Expand Down Expand Up @@ -246,7 +246,7 @@ public class IOSControllerImpl : NSObject {

@objc func checkStatus(callback: @escaping (String, String, String) -> Void) {
IOSControllerImpl.logger.info(message: "Check status")

TunnelManager.withTunnel { tunnel in
let proto = tunnel.protocolConfiguration as? NETunnelProviderProtocol
if proto == nil {
Expand Down Expand Up @@ -296,7 +296,7 @@ public class IOSControllerImpl : NSObject {
IOSControllerImpl.logger.error(message: "Failed to retrieve data from session. \(error)")
callback("", "", "")
}

return
}
}
Expand Down
13 changes: 12 additions & 1 deletion src/settingslist.h
Original file line number Diff line number Diff line change
Expand Up @@ -705,10 +705,21 @@ SETTING_STRINGLIST(subscriptionTransactions, // getter
removeSubscriptionTransactions, // remover
hasSubscriptionTransactions, // has
"subscriptionTransactions", // key
QStringList(), // efault value
QStringList(), // default value
false, // remove when reset
true // sensitive (do not log)
)

SETTING_BOOL(localNetworkAccess, // getter
setLocalNetworkAccess, // setter
removeLocalNetworkAccess, // remover
hasLocalNetworkAccess, // has
"localNetworkAccess", // key
false, // default value
true, // remove when reset
false // sensitive (do not log)
)

#endif

SETTING_BOOL(gleanDebugTagActive, // getter
Expand Down
24 changes: 14 additions & 10 deletions src/translations/strings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,11 @@ settings:
value: Clear all
comment: Button label to clear all apps from the exclusions list

localNetworkAccess:
label: Local network access
subLabel: Access Apple CarPlay, AirDrop, AirPlay and local network devices like printers.
vpnMustBeOff: VPN must be off to edit “Local network access”

dnsOverwriteDialog:
titleDNS: Override DNS settings?
titlePrivacy: Override privacy features?
Expand Down Expand Up @@ -724,7 +729,6 @@ inAppAuth:
value: Continue to sign in
comment: Button a user clicks after updating their Mozilla account settings so that they can re-attempt sign-in


postAuthentication:
headline: Quick access
subtitle: You can quickly access Mozilla VPN from your status bar.
Expand Down Expand Up @@ -953,11 +957,11 @@ devices:
value: My devices
comment: Title for the menu bar when viewing the devices or device limit pages

helpSheets:
helpSheets:
dnsTitle:
value: Custom DNS settings
comment: Title label for the custom dns help sheet
dnsHeader:
dnsHeader:
value: What is a custom DNS?
comment: Header label for the custom dns help sheet
dnsBody1:
Expand All @@ -982,7 +986,7 @@ helpSheets:
value: Excluded apps
comment: Title label for the excluded apps help sheet
excludedAppsHeader:
value: What are excluded apps?
value: What are excluded apps?
comment: Header label for the excluded apps help sheet
excludedAppsBody1:
value: Excluded apps let you turn off VPN protection for specific apps, without turning off VPN protection for your entire device.
Expand All @@ -1002,7 +1006,7 @@ helpSheets:
devicesHeader:
value: Adding and removing devices
comment: Header label for the devices help sheet
devicesBody1:
devicesBody1:
value: "Adding a new device to your subscription is easy: just download and log in to Mozilla VPN on that device."
comment: Body label for the devices help sheet
devicesBody2:
Expand All @@ -1021,7 +1025,7 @@ helpSheets:
value: If you want to add more privacy, switch to “Multi-hop” and add an additional server location. Multi-hop VPN routes your traffic through two server locations instead of one for extra security and privacy. This may also slow down your connection a bit.
comment: Body label for the location selection help sheet

resetSettings:
resetSettings:
resetLabel:
value: Reset VPN
comment: Label for button that takes the user to the factory reset flow
Expand All @@ -1030,16 +1034,16 @@ resetSettings:
comment: Title of the screen where users go to reset the VPN to factory settings
body1:
value: "This will reset all VPN settings, including:"
comment: Body content of the screen where users go to reset the VPN to factory settings
comment: Body content of the screen where users go to reset the VPN to factory settings
listItemPreferences:
value: Preferences
comment: Item in a bulleted list denoting what will be deleted if the user opts to factory reset the client
body2:
value: Resetting the VPN will sign you out, but your account will not be deleted.
comment: Body content of the screen where users go to reset the VPN to factory settings
comment: Body content of the screen where users go to reset the VPN to factory settings
resetButtonLabel:
value: Reset VPN
comment: Label for button that initiates a restore to factory settings
comment: Label for button that initiates a restore to factory settings
confirmResetModalTitle:
value: Confirm reset
comment: Title of the modal where users can confirm they want to restore back to factory settings
Expand All @@ -1048,7 +1052,7 @@ resetSettings:
comment: Body of the modal where users can confirm they want to restore back to factory settings
confirmResetModalResetButtonLabel:
value: Reset and quit
comment: Label for button that finalizes a restore to factory settings
comment: Label for button that finalizes a restore to factory settings

global:
expand:
Expand Down
65 changes: 53 additions & 12 deletions src/ui/screens/settings/ViewPreferences.qml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import QtQuick.Layouts 1.14
import Mozilla.Shared 1.0
import Mozilla.VPN 1.0
import components 0.1
import components.forms 0.1

MZViewBase {
id: vpnFlickable
Expand All @@ -17,22 +18,25 @@ MZViewBase {
property string _languageTitle: ""
readonly property string telemetryScreenId : "app_preferences"

property bool vpnIsOff: VPNController.state === VPNController.StateOff
property bool isIOS: Qt.platform.os === "ios"

objectName: "settingsPreferencesView"

Component.onCompleted: Glean.impression.appPreferencesScreen.record({screen:telemetryScreenId})

_viewContentData: Column {
spacing: MZTheme.theme.windowMargin
Layout.fillWidth: true
_viewContentData: ColumnLayout {
Layout.preferredWidth: parent.width
Layout.alignment: Qt.AlignHCenter

spacing: MZTheme.theme.windowMargin

MZToggleRow {
objectName: "startAtBootToogle"

anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: MZTheme.theme.windowMargin
anchors.rightMargin: MZTheme.theme.windowMargin
Layout.fillWidth: true
Layout.rightMargin: MZTheme.theme.windowMargin
Layout.leftMargin: MZTheme.theme.windowMargin

labelText: _startAtBootTitle
subLabelText: MZI18n.SettingsStartAtBootSubtitle
Expand All @@ -55,10 +59,10 @@ MZViewBase {
MZToggleRow {
objectName: "dataCollectionToggle"

anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: MZTheme.theme.windowMargin
anchors.rightMargin: MZTheme.theme.windowMargin
Layout.fillWidth: true
Layout.rightMargin: MZTheme.theme.windowMargin
Layout.leftMargin: MZTheme.theme.windowMargin
showDivider: isIOS

labelText: MZI18n.TelemetryPolicyViewDataCollectionAndUse
subLabelText: MZI18n.SettingsDataCollectionDescription
Expand All @@ -67,7 +71,44 @@ MZViewBase {
onClicked: MZSettings.gleanEnabled = !MZSettings.gleanEnabled
}

Column {
MZToggleRow {
id: localNetwork
objectName: "settingLocalNetworkAccess"
visible: isIOS

Layout.fillWidth: true
Layout.rightMargin: MZTheme.theme.windowMargin
Layout.leftMargin: MZTheme.theme.windowMargin
showDivider: false

labelText: MZI18n.LocalNetworkAccessLabel
subLabelText: MZI18n.LocalNetworkAccessSubLabel
checked: MZSettings.localNetworkAccess
enabled: isIOS && vpnIsOff
dividerTopMargin: MZTheme.theme.toggleRowDividerSpacing
onClicked: {
if (VPNController.StateOff) {
MZSettings.localNetworkAccess = !MZSettings.localNetworkAccess
}
}
}

MZContextualAlerts {
Layout.topMargin: MZTheme.theme.listSpacing
Layout.rightMargin: MZTheme.theme.windowMargin
Layout.leftMargin: MZTheme.theme.windowMargin

visible: isIOS && !vpnIsOff

messages: [
{
type: "warning",
message: MZI18n.LocalNetworkAccessVpnMustBeOff,
}
]
}

ColumnLayout {
spacing: MZTheme.theme.windowMargin / 2
width: parent.width
MZSettingsItem {
Expand Down

0 comments on commit 8f68e3d

Please sign in to comment.