Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Fix #7255: VPN Protocol (Tunnel) Option #7334

Merged
merged 6 commits into from
Apr 28, 2023
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
37 changes: 31 additions & 6 deletions Sources/BraveStrings/BraveStrings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2587,18 +2587,18 @@ extension Strings {
public static let settingsServerLocation =
NSLocalizedString("vpn.settingsServerLocation", tableName: "BraveShared", bundle: .module,
value: "Location",
comment: "Table cell title for vpn's server location")
comment: "Table cell title for vpn's server location and which open opens location select")

public static let settingsResetConfiguration =
NSLocalizedString("vpn.settingsResetConfiguration", tableName: "BraveShared", bundle: .module,
value: "Reset Configuration",
comment: "Button to reset VPN configuration")

public static let settingsChangeLocation =
NSLocalizedString("vpn.settingsChangeLocation", tableName: "BraveShared", bundle: .module,
value: "Change Location",
comment: "Button to change VPN server location")

public static let settingsTransportProtocol =
NSLocalizedString("vpn.settingsTransportProtocol", tableName: "BraveShared", bundle: .module,
value: "Transport Protocol",
comment: "Table cell title for vpn's transport protocol and which open opens protocol select")
public static let settingsContactSupport =
NSLocalizedString("vpn.settingsContactSupport", tableName: "BraveShared", bundle: .module,
value: "Contact Technical Support",
Expand Down Expand Up @@ -2869,10 +2869,35 @@ extension Strings {
value: "Failed to switch servers, please try again later.",
comment: "Message for error when we fail to switch vpn server for the user")

public static let protocolPickerTitle =
NSLocalizedString("vpn.protocolPickerTitle", tableName: "BraveShared", bundle: .module,
value: "Transport Protocol",
comment: "Title for vpn tunnel protocol screen")

public static let protocolPickerDescription =
NSLocalizedString("vpn.protocolPickerDescription", tableName: "BraveShared", bundle: .module,
value: "Please select your preferred transport protocol. Once switched your existing VPN credentials will be cleared and you will be reconnected if a VPN connection is currently established.",
comment: "Description of vpn tunnel protocol")

public static let regionSwitchSuccessPopupText =
NSLocalizedString("vpn.regionSwitchSuccessPopupText", tableName: "BraveShared", bundle: .module,
value: "VPN region changed.",
comment: "Message that we show after successfully changing vpn region.")

public static let protocolPickerErrorTitle =
NSLocalizedString("vpn.protocolPickerErrorTitle", tableName: "BraveShared", bundle: .module,
value: "Server Error",
comment: "Title for error when we fail to switch tunnel protocol for the user")

public static let protocolPickerErrorMessage =
NSLocalizedString("vpn.protocolPickerErrorMessage", tableName: "BraveShared", bundle: .module,
value: "Failed to switch tunnel protocol, please try again later.",
comment: "Message for error when we fail to switch tunnel protocol for the user")

public static let protocolSwitchSuccessPopupText =
NSLocalizedString("vpn.protocolSwitchSuccessPopupText", tableName: "BraveShared", bundle: .module,
value: "VPN Tunnel Protocol changed.",
comment: "Message that we show after successfully changing tunnel protocol.")

public static let settingsFailedToFetchServerList =
NSLocalizedString("vpn.settingsFailedToFetchServerList", tableName: "BraveShared", bundle: .module,
Expand Down
38 changes: 36 additions & 2 deletions Sources/BraveVPN/BraveVPN.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class BraveVPN {
private static let housekeepingApi = GRDHousekeepingAPI()
private static let helper = GRDVPNHelper.sharedInstance()
private static let serverManager = GRDServerManager()
private static let tunnelManager = GRDTunnelManager()

public static let iapObserver = IAPObserver()

Expand Down Expand Up @@ -278,11 +279,14 @@ public class BraveVPN {
completion?(status == .success)
}
} else {
// Setting preferred protocol in order to determine which tunnel to be activated while region selection
// Setting User preferred Transport Protocol to WireGuard
// In order to easily fetch and change in settings later
GRDTransportProtocol.setUserPreferred(.wireGuard)

// New user or no credentials and have to remake them.
helper.configureFirstTimeUser(for: .wireGuard, postCredential: nil) { success, error in
helper.configureFirstTimeUser(
for: GRDTransportProtocol.getUserPreferredTransportProtocol(),
postCredential: nil) { success, error in
if let error = error {
logAndStoreError("configureFirstTimeUserPostCredential \(error)")
} else {
Expand All @@ -308,6 +312,36 @@ public class BraveVPN {
completion?(status)
}
}

public static func changePreferredTransportProtocol(with transportProtocol: TransportProtocol, completion: ((Bool) -> Void)? = nil) {
helper.forceDisconnectVPNIfNecessary()
GRDVPNHelper.clearVpnConfiguration()

GRDTransportProtocol.setUserPreferred(transportProtocol)

// New user or no credentials and have to remake them.
helper.configureFirstTimeUser(for: transportProtocol, postCredential: nil) { success, error in
if let error = error {
logAndStoreError("Change Preferred transport FirstTimeUserPostCredential \(error)")
} else {
removeConfigurationFromPreferences(for: transportProtocol)
}

reconnectPending = false
completion?(success)
}

func removeConfigurationFromPreferences(for transportProtocol: TransportProtocol) {
switch transportProtocol {
case .wireGuard:
helper.ikev2VPNManager.removeFromPreferences()
case .ikEv2:
tunnelManager.removeTunnel()
default:
return
}
}
}

public static func clearCredentials() {
GRDKeychain.removeGuardianKeychainItems()
Expand Down
28 changes: 26 additions & 2 deletions Sources/BraveVPN/BraveVPNContactFormViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import UIKit
import BraveUI
import os.log
import BraveStrings
import GuardianConnect

class BraveVPNContactFormViewController: TableViewController {

Expand All @@ -24,6 +25,7 @@ class BraveVPNContactFormViewController: TableViewController {

private struct ContactForm {
var hostname: String?
var tunnelProtocol: String?
var subscriptionType: String?
var receipt: String?
var appVersion: String?
Expand Down Expand Up @@ -75,6 +77,23 @@ class BraveVPNContactFormViewController: TableViewController {
}
})))

// MARK: TunnelProtocol
let userPreferredTunnelProtocol = GRDTransportProtocol.getUserPreferredTransportProtocol()
let transportProtocol = GRDTransportProtocol.prettyTransportProtocolString(for: userPreferredTunnelProtocol)
let tunnelProtocolRow =
Row(
text: Strings.VPN.protocolPickerTitle, detailText: transportProtocol,
accessory: .view(
SwitchAccessoryView(
initialValue: false,
valueChange: { [weak self] isOn in
if isOn {
self?.contactForm.tunnelProtocol = transportProtocol
} else {
self?.contactForm.tunnelProtocol = nil
}
})), cellClass: MultilineSubtitleCell.self)

// MARK: SubscriptionType
let subscriptionType = BraveVPN.subscriptionName
let subscriptionTypeRow =
Expand Down Expand Up @@ -189,8 +208,8 @@ class BraveVPNContactFormViewController: TableViewController {
})), cellClass: MultilineSubtitleCell.self)

var section = Section(rows: [
hostnameRow, subscriptionTypeRow, receiptRow, appVersionRow,
timezoneRow, networkTypeRow, carrierRow, errorLogs,
hostnameRow, tunnelProtocolRow, subscriptionTypeRow, receiptRow,
appVersionRow, timezoneRow, networkTypeRow, carrierRow, errorLogs
])

// MARK: Issue
Expand Down Expand Up @@ -280,6 +299,11 @@ class BraveVPNContactFormViewController: TableViewController {
body.append(Strings.VPN.contactFormHostname)
body.append("\n\(hostname)\n\n")
}

if let tunnelProtocol = contactForm.tunnelProtocol {
body.append(Strings.VPN.protocolPickerTitle)
body.append("\n\(tunnelProtocol)\n\n")
}

if let subcriptionType = contactForm.subscriptionType {
body.append(Strings.VPN.contactFormSubscriptionType)
Expand Down
116 changes: 116 additions & 0 deletions Sources/BraveVPN/BraveVPNPickerViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright 2020 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

import UIKit
import Shared
import BraveUI
import Lottie
import NetworkExtension
import GuardianConnect

class BraveVPNPickerViewController: UIViewController {

private var overlayView: UIView?
let tableView: UITableView = .init(frame: .zero, style: .insetGrouped)

deinit {
NotificationCenter.default.removeObserver(self)
}

var isLoading: Bool = false {
didSet {
overlayView?.removeFromSuperview()

navigationItem.hidesBackButton = isLoading

// Prevent dismissing the modal by swipe when the VPN is being configured
navigationController?.isModalInPresentation = isLoading

if !isLoading { return }

let overlay = UIView().then {
$0.backgroundColor = UIColor.black.withAlphaComponent(0.5)
let activityIndicator = UIActivityIndicatorView().then { indicator in
indicator.startAnimating()
indicator.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}

$0.addSubview(activityIndicator)
}

view.addSubview(overlay)
overlay.snp.makeConstraints {
$0.edges.equalToSuperview()
}

overlayView = overlay
}
}

init() {
super.init(nibName: nil, bundle: nil)
}

@available(*, unavailable)
required init?(coder: NSCoder) { fatalError() }

override func viewDidLoad() {
tableView.register(VPNRegionCell.self)

NotificationCenter.default.addObserver(self, selector: #selector(vpnConfigChanged(notification:)),
name: .NEVPNStatusDidChange, object: nil)

view.addSubview(tableView)
tableView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}

@objc func vpnConfigChanged(notification: NSNotification) { }

func showSuccessAlert(text: String) {
let animation = AnimationView(name: "vpncheckmark", bundle: .module).then {
$0.bounds = CGRect(x: 0, y: 0, width: 300, height: 200)
$0.contentMode = .scaleAspectFill
$0.play()
}

let popup = AlertPopupView(imageView: animation,
title: text, message: "",
titleWeight: .semibold, titleSize: 18,
dismissHandler: { true })

popup.showWithType(showType: .flyUp, autoDismissTime: 1.5)
}

func showErrorAlert(title: String, message: String?) {
DispatchQueue.main.async {
let alert = AlertController(title: Strings.VPN.regionPickerErrorTitle,
message: Strings.VPN.regionPickerErrorMessage,
preferredStyle: .alert)
let okAction = UIAlertAction(title: Strings.OKString, style: .default) { _ in
self.dismiss(animated: true)
}
alert.addAction(okAction)

self.present(alert, animated: true)
}
}
}

class VPNRegionCell: UITableViewCell, TableViewReusable {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: .value1, reuseIdentifier: reuseIdentifier)
}
@available(*, unavailable)
required init(coder: NSCoder) {
fatalError()
}
}
Loading