Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
jurajhilje committed Sep 4, 2023
2 parents 7431ee4 + 6c73979 commit 54709ad
Show file tree
Hide file tree
Showing 8 changed files with 590 additions and 328 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to this project will be documented in this file.

## 2.10.1 - 2023-09-04

[NEW] Option to disable LAN traffic when connected to VPN
[IMPROVED] Added "Advanced" section in the Settings

## 2.10.0 - 2023-08-08

[NEW] Post-Quantum Resistant WireGuard Connections
Expand Down
4 changes: 4 additions & 0 deletions IVPNClient.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@
82DEF02A2447288100CCB5CD /* PaymentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DEF0292447288100CCB5CD /* PaymentViewController.swift */; };
82DEFFA62452DE5100ECB482 /* MapConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DEFFA52452DE5100ECB482 /* MapConstants.swift */; };
82E01649230BE683008B0AC0 /* APIAccessManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E01648230BE683008B0AC0 /* APIAccessManagerTests.swift */; };
82E0E9072A90CB110008BD3F /* AdvancedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E0E9062A90CB110008BD3F /* AdvancedViewController.swift */; };
82E3B20B29DDCC6300998F67 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82E3B1EF29DDC91C00998F67 /* WidgetKit.framework */; };
82E3B20C29DDCC6300998F67 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82E3B1F129DDC91C00998F67 /* SwiftUI.framework */; };
82E3B20F29DDCC6400998F67 /* IVPNWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E3B20E29DDCC6400998F67 /* IVPNWidgetBundle.swift */; };
Expand Down Expand Up @@ -656,6 +657,7 @@
82DEF0292447288100CCB5CD /* PaymentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentViewController.swift; sourceTree = "<group>"; };
82DEFFA52452DE5100ECB482 /* MapConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapConstants.swift; sourceTree = "<group>"; };
82E01648230BE683008B0AC0 /* APIAccessManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIAccessManagerTests.swift; sourceTree = "<group>"; };
82E0E9062A90CB110008BD3F /* AdvancedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedViewController.swift; sourceTree = "<group>"; };
82E3B1EF29DDC91C00998F67 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
82E3B1F129DDC91C00998F67 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
82E3B20A29DDCC6300998F67 /* IVPNWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = IVPNWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -1215,6 +1217,7 @@
isa = PBXGroup;
children = (
9C3031361DB4307D00C38B0C /* SettingsViewController.swift */,
82E0E9062A90CB110008BD3F /* AdvancedViewController.swift */,
9C50959520FCF4C60048DBF2 /* ProtocolViewController.swift */,
820203922186EE0E00D756AA /* WireGuardSettingsViewController.swift */,
82D598A221A55210000FABDE /* NetworkProtectionViewController.swift */,
Expand Down Expand Up @@ -2328,6 +2331,7 @@
82E7880C22B0DA0D00A98D76 /* NETunnelProviderProtocol+Ext.swift in Sources */,
82968A35298A98C300077E0A /* KeyChain.swift in Sources */,
82F638C2217DA89000410318 /* AddressType.swift in Sources */,
82E0E9072A90CB110008BD3F /* AdvancedViewController.swift in Sources */,
822920A02480FA3600476FC1 /* ServersSort.swift in Sources */,
826E61482428F8E60064F195 /* AccountViewController.swift in Sources */,
820079F42407D96D00EC2062 /* ConnectionInfoBoxView.swift in Sources */,
Expand Down
518 changes: 310 additions & 208 deletions IVPNClient/Scenes/Base.lproj/Main.storyboard

Large diffs are not rendered by default.

225 changes: 225 additions & 0 deletions IVPNClient/Scenes/ViewControllers/AdvancedViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
//
// AdvancedViewController.swift
// IVPN iOS app
// https://github.com/ivpn/ios-app
//
// Created by Juraj Hilje on 2023-08-19.
// Copyright (c) 2023 IVPN Limited.
//
// This file is part of the IVPN iOS app.
//
// The IVPN iOS app is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any later version.
//
// The IVPN iOS app is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License
// along with the IVPN iOS app. If not, see <https://www.gnu.org/licenses/>.
//

import UIKit
import ActiveLabel

class AdvancedViewController: UITableViewController {

@IBOutlet weak var disableLanAccessSwitch: UISwitch!
@IBOutlet weak var askToReconnectSwitch: UISwitch!
@IBOutlet weak var preventSameCountryMultiHopSwitch: UISwitch!
@IBOutlet weak var preventSameISPMultiHopSwitch: UISwitch!
@IBOutlet weak var loggingSwitch: UISwitch!
@IBOutlet weak var loggingCell: UITableViewCell!
@IBOutlet weak var sendLogsLabel: UILabel!

// MARK: - @IBActions -

@IBAction func toggleDisableLanAccess(_ sender: UISwitch) {
if sender.isOn && Application.shared.settings.connectionProtocol.tunnelType() == .ipsec {
showAlert(title: "IKEv2 not supported", message: "Disable LAN traffic is supported only for OpenVPN and WireGuard protocols.") { _ in
sender.setOn(false, animated: true)
}
return
}

UserDefaults.shared.set(sender.isOn, forKey: UserDefaults.Key.disableLanAccess)
evaluateReconnect(sender: sender as UIView)
}

@IBAction func toggleAskToReconnect(_ sender: UISwitch) {
UserDefaults.shared.set(!sender.isOn, forKey: UserDefaults.Key.notAskToReconnect)
}

@IBAction func togglePreventSameCountryMultiHop(_ sender: UISwitch) {
UserDefaults.standard.set(sender.isOn, forKey: UserDefaults.Key.preventSameCountryMultiHop)
}

@IBAction func togglePreventSameISPMultiHop(_ sender: UISwitch) {
UserDefaults.standard.set(sender.isOn, forKey: UserDefaults.Key.preventSameISPMultiHop)
}

@IBAction func toggleLogging(_ sender: UISwitch) {
UserDefaults.shared.set(sender.isOn, forKey: UserDefaults.Key.isLogging)
FileSystemManager.clearSession()
setupLoggingView()
}

// MARK: - View Lifecycle -

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

// MARK: - Methods -

private func setupView() {
tableView.backgroundColor = UIColor.init(named: Theme.ivpnBackgroundQuaternary)
disableLanAccessSwitch.setOn(UserDefaults.shared.disableLanAccess, animated: false)
askToReconnectSwitch.setOn(!UserDefaults.shared.notAskToReconnect, animated: false)
preventSameCountryMultiHopSwitch.setOn(UserDefaults.standard.preventSameCountryMultiHop, animated: false)
preventSameISPMultiHopSwitch.setOn(UserDefaults.standard.preventSameISPMultiHop, animated: false)
loggingSwitch.setOn(UserDefaults.shared.isLogging, animated: false)
setupLoggingView()
}

private func setupLoggingView() {
loggingCell.isUserInteractionEnabled = UserDefaults.shared.isLogging ? true : false
sendLogsLabel.alpha = UserDefaults.shared.isLogging ? 1 : 0.65
sendLogsLabel.textColor = UserDefaults.shared.isLogging ? UIColor.init(named: Theme.ivpnBlue) : UIColor.init(named: Theme.ivpnLabel5)
}

private func sendLogs() {
guard evaluateIsLoggedIn() else {
return
}

guard let appLogPath = FileManager.logTextFileURL?.path else {
return
}

guard let wireguardLogPath = FileManager.wgLogTextFileURL?.path else {
return
}

guard logger.app?.writeLog(to: appLogPath) ?? false else {
return
}

guard logger.wireguard?.writeLog(to: wireguardLogPath) ?? false else {
return
}

var logFiles = [URL]()
var openvpnLogAttached = false
var presentMailComposer = true

// App logs
var appLog = ""
if let file = NSData(contentsOfFile: appLogPath) {
appLog = String(data: file as Data, encoding: .utf8) ?? ""
}

FileSystemManager.updateLogFile(newestLog: appLog, name: Config.appLogFile, isLoggedIn: Application.shared.authentication.isLoggedIn)

let logFile = FileSystemManager.sharedFilePath(name: Config.appLogFile).path
if let fileData = NSData(contentsOfFile: logFile) {
appLog = String(data: fileData as Data, encoding: .utf8) ?? ""
logFiles.append(FileSystemManager.tempFile(text: appLog, fileName: "app-\(Date.logFileName())"))
}

// WireGuard tunnel logs
var wireguardLog = ""
if let file = NSData(contentsOfFile: wireguardLogPath) {
wireguardLog = String(data: file as Data, encoding: .utf8) ?? ""
}

FileSystemManager.updateLogFile(newestLog: wireguardLog, name: Config.wireGuardLogFile, isLoggedIn: Application.shared.authentication.isLoggedIn)

let wireguardLogFile = FileSystemManager.sharedFilePath(name: Config.wireGuardLogFile).path
if let fileData = NSData(contentsOfFile: wireguardLogFile) {
wireguardLog = String(data: fileData as Data, encoding: .utf8) ?? ""
logFiles.append(FileSystemManager.tempFile(text: wireguardLog, fileName: "wireguard-\(Date.logFileName())"))
}

// OpenVPN tunnel logs
Application.shared.connectionManager.getOpenVPNLog { openVPNLog in
if UserDefaults.shared.isLogging {
FileSystemManager.updateLogFile(newestLog: openVPNLog, name: Config.openVPNLogFile, isLoggedIn: Application.shared.authentication.isLoggedIn)

let logFile = FileSystemManager.sharedFilePath(name: Config.openVPNLogFile).path
var openvpnLog = ""
if let file = NSData(contentsOfFile: logFile), !openvpnLogAttached {
openvpnLog = String(data: file as Data, encoding: .utf8) ?? ""
logFiles.append(FileSystemManager.tempFile(text: openvpnLog, fileName: "openvpn-\(Date.logFileName())"))
openvpnLogAttached = true
}
}

if presentMailComposer {
let activityView = UIActivityViewController(activityItems: logFiles, applicationActivities: nil)
activityView.popoverPresentationController?.sourceView = self.view
self.present(activityView, animated: true, completion: nil)
if let popOver = activityView.popoverPresentationController {
popOver.sourceView = self.sendLogsLabel
}
presentMailComposer = false
}
}
}

}

// MARK: - UITableViewDelegate -

extension AdvancedViewController {

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 2 && indexPath.row == 0 {
return 60
}

return UITableView.automaticDimension
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 2 && indexPath.row == 1 {
tableView.deselectRow(at: indexPath, animated: true)
sendLogs()
}
}

override func tableView(_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) {
let footer = view as! UITableViewHeaderFooterView
footer.textLabel?.textColor = UIColor.init(named: Theme.ivpnLabel6)

let urlString = "https://www.ivpn.net/knowledgebase/ios/known-issues-with-native-ios-kill-switch/"
let label = ActiveLabel(frame: .zero)
let customType = ActiveType.custom(pattern: "Learn more")
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 13)
label.enabledTypes = [customType]
label.text = footer.textLabel?.text
label.textColor = UIColor.init(named: Theme.ivpnLabel6)
label.customColor[customType] = UIColor.init(named: Theme.ivpnBlue)
label.handleCustomTap(for: customType) { _ in
self.openWebPage(urlString)
}
footer.addSubview(label)
footer.textLabel?.text = ""
label.bindFrameToSuperviewBounds(leading: 16, trailing: -16)
}

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
if let header = view as? UITableViewHeaderFooterView {
header.textLabel?.textColor = UIColor.init(named: Theme.ivpnLabel6)
}
}

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = UIColor.init(named: Theme.ivpnBackgroundPrimary)
}

}
25 changes: 25 additions & 0 deletions IVPNClient/Scenes/ViewControllers/ProtocolViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ class ProtocolViewController: UITableViewController {
return true
}

func validateDisableLanTraffic(connectionProtocol: ConnectionSettings) -> Bool {
if UserDefaults.shared.disableLanAccess && connectionProtocol == .ipsec {
return false
}

return true
}

func reloadTable(connectionProtocol: ConnectionSettings, indexPath: IndexPath) {
Application.shared.settings.connectionProtocol = connectionProtocol
Application.shared.serverList = VPNServerList()
Expand Down Expand Up @@ -369,6 +377,23 @@ extension ProtocolViewController {
return
}

guard validateDisableLanTraffic(connectionProtocol: connectionProtocol) else {
if let cell = tableView.cellForRow(at: indexPath) {
showActionSheet(title: "To use IKEv2 protocol you must turn Disable LAN traffic off", actions: ["Turn off"], sourceView: cell as UIView) { index in
switch index {
case 0:
UserDefaults.shared.set(false, forKey: UserDefaults.Key.disableLanAccess)
tableView.reloadData()
default:
break
}
}
tableView.deselectRow(at: indexPath, animated: true)
}

return
}

if connectionProtocol.tunnelType() != Application.shared.settings.connectionProtocol.tunnelType() && connectionProtocol.tunnelType() == .wireguard {
if KeyChain.wgPublicKey == nil || AppKeyManager.needToRegenerate() {
keyManager.setNewKey { _, _, _ in }
Expand Down
Loading

0 comments on commit 54709ad

Please sign in to comment.