]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
Added swiftlint and fixed all errors (and a bunch, but not all, warnings)
authorEric Kuck <eric@bluelinelabs.com>
Wed, 12 Dec 2018 17:40:57 +0000 (11:40 -0600)
committerEric Kuck <eric@bluelinelabs.com>
Wed, 12 Dec 2018 17:40:57 +0000 (11:40 -0600)
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
25 files changed:
.swiftlint.yml [deleted file]
README.md
WireGuard/.swiftlint.yml [new file with mode: 0644]
WireGuard/Shared/FileManager+Extension.swift
WireGuard/Shared/Model/Configuration.swift
WireGuard/Shared/Model/DNSServer.swift
WireGuard/Shared/Model/Endpoint.swift
WireGuard/Shared/Model/IPAddressRange.swift
WireGuard/WireGuard.xcodeproj/project.pbxproj
WireGuard/WireGuard/UI/TunnelViewModel.swift
WireGuard/WireGuard/UI/iOS/MainViewController.swift
WireGuard/WireGuard/UI/iOS/QRScanViewController.swift
WireGuard/WireGuard/UI/iOS/ScrollableLabel.swift
WireGuard/WireGuard/UI/iOS/SettingsTableViewController.swift
WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift
WireGuard/WireGuard/UI/iOS/TunnelEditTableViewController.swift
WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift
WireGuard/WireGuard/VPN/TunnelsManager.swift
WireGuard/WireGuard/WireGuardResult.swift
WireGuard/WireGuard/ZipArchive/ZipExporter.swift
WireGuard/WireGuard/ZipArchive/ZipImporter.swift
WireGuard/WireGuardNetworkExtension/DNSResolver.swift
WireGuard/WireGuardNetworkExtension/ErrorNotifier.swift
WireGuard/WireGuardNetworkExtension/PacketTunnelProvider.swift
WireGuard/WireGuardNetworkExtension/PacketTunnelSettingsGenerator.swift

diff --git a/.swiftlint.yml b/.swiftlint.yml
deleted file mode 100644 (file)
index df5ce7d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-disabled_rules:
- - line_length
- - trailing_comma
-excluded:
- - Pods
-file_length:
-  warning: 500
-type_name:
-  min_length: 2 # only warning
-  max_length: # warning and error
-    warning: 50
-    error: 60
index 924b9916203e4e8ef694ab2a787c0bbfba8575d0..921c37c6d2b39a8a9c849b15952988898002d9e5 100644 (file)
--- a/README.md
+++ b/README.md
@@ -23,6 +23,12 @@ $ cp WireGuard/WireGuard/Config/Developer.xcconfig.template WireGuard/WireGuard/
 $ vim WireGuard/WireGuard/Config/Developer.xcconfig
 ```
 
+- Install swiftlint:
+
+```
+$ brew install swiftlint
+```
+
 - Open project in XCode:
 
 ```
diff --git a/WireGuard/.swiftlint.yml b/WireGuard/.swiftlint.yml
new file mode 100644 (file)
index 0000000..b16b6b3
--- /dev/null
@@ -0,0 +1,8 @@
+disabled_rules:
+ - force_cast
+ - line_length
+file_length:
+  warning: 500
+cyclomatic_complexity:
+  warning: 10
+  error: 25
index d4c2547bcd4c17e83a55dc5281db674ba7206b22..535b999611dc16b993df808a74672eba9e4a96e5 100644 (file)
@@ -20,8 +20,8 @@ extension FileManager {
     static func deleteFile(at url: URL) -> Bool {
         do {
             try FileManager.default.removeItem(at: url)
-        } catch(let e) {
-            os_log("Failed to delete file '%{public}@': %{public}@", log: OSLog.default, type: .debug, url.absoluteString, e.localizedDescription)
+        } catch let error {
+            os_log("Failed to delete file '%{public}@': %{public}@", log: OSLog.default, type: .debug, url.absoluteString, error.localizedDescription)
             return false
         }
         return true
index d2680cbef1f90c612aa3eadb379a8fd601e8a29d..09fdd6b86823cc79c7e11af364b0329b23eb1cfc 100644 (file)
@@ -16,7 +16,7 @@ final class TunnelConfiguration: Codable {
 
         let peerPublicKeysArray = peers.map { $0.publicKey }
         let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
-        if (peerPublicKeysArray.count != peerPublicKeysSet.count) {
+        if peerPublicKeysArray.count != peerPublicKeysSet.count {
             fatalError("Two or more peers cannot have the same public key")
         }
     }
@@ -34,8 +34,12 @@ struct InterfaceConfiguration: Codable {
     init(name: String, privateKey: Data) {
         self.name = name
         self.privateKey = privateKey
-        if (name.isEmpty) { fatalError("Empty name") }
-        if (privateKey.count != TunnelConfiguration.keyLength) { fatalError("Invalid private key") }
+        if name.isEmpty {
+            fatalError("Empty name")
+        }
+        if privateKey.count != TunnelConfiguration.keyLength {
+            fatalError("Invalid private key")
+        }
     }
 }
 
@@ -45,7 +49,9 @@ struct PeerConfiguration: Codable {
     var preSharedKey: Data? {
         didSet(value) {
             if let value = value {
-                if (value.count != TunnelConfiguration.keyLength) { fatalError("Invalid preshared key") }
+                if value.count != TunnelConfiguration.keyLength {
+                    fatalError("Invalid preshared key")
+                }
             }
         }
     }
@@ -55,6 +61,8 @@ struct PeerConfiguration: Codable {
 
     init(publicKey: Data) {
         self.publicKey = publicKey
-        if (publicKey.count != TunnelConfiguration.keyLength) { fatalError("Invalid public key") }
+        if publicKey.count != TunnelConfiguration.keyLength {
+            fatalError("Invalid public key")
+        }
     }
 }
index 8be1dddd9d7fd941480a2d226a240eaa0ab7d3de..bb20c025c01623500f65e2949df2399c4282b171 100644 (file)
@@ -40,7 +40,7 @@ extension DNSServer: Codable {
         let container = try decoder.singleValueContainer()
         var data = try container.decode(Data.self)
         let ipAddressFromData: IPAddress? = {
-            switch (data.count) {
+            switch data.count {
             case 4: return IPv4Address(data)
             case 16: return IPv6Address(data)
             default: return nil
index ab357ba219ca81023134d85b5a64a66a84fac9c6..38ffab9a6db51bc54d5d2c1bd3aa46881a80a907 100644 (file)
@@ -35,8 +35,8 @@ extension Endpoint {
             hostString = String(string[string.startIndex ..< endOfHost])
         }
         guard let endpointPort = NWEndpoint.Port(String(string[startOfPort ..< string.endIndex])) else { return nil }
-        let invalidCharacterIndex = hostString.unicodeScalars.firstIndex { (c) -> Bool in
-            return !CharacterSet.urlHostAllowed.contains(c)
+        let invalidCharacterIndex = hostString.unicodeScalars.firstIndex { char in
+            return !CharacterSet.urlHostAllowed.contains(char)
         }
         guard (invalidCharacterIndex == nil) else { return nil }
         host = NWEndpoint.Host(hostString)
@@ -79,11 +79,11 @@ extension Endpoint: Codable {
 extension Endpoint {
     func hasHostAsIPAddress() -> Bool {
         switch (host) {
-        case .name(_, _):
+        case .name:
             return false
-        case .ipv4(_):
+        case .ipv4:
             return true
-        case .ipv6(_):
+        case .ipv6:
             return true
         }
     }
@@ -92,9 +92,9 @@ extension Endpoint {
         switch (host) {
         case .name(let hostname, _):
             return hostname
-        case .ipv4(_):
+        case .ipv4:
             return nil
-        case .ipv6(_):
+        case .ipv6:
             return nil
         }
     }
index 2fb4a16de67bbe6ef783a33c4c4f7379d98e4f30..e3c14414885abb35d9f660f65703ae594ae8a62a 100644 (file)
@@ -27,9 +27,9 @@ extension IPAddressRange {
         }
         let maxNetworkPrefixLength: UInt8 = (address is IPv4Address) ? 32 : 128
         var networkPrefixLength: UInt8
-        if (endOfIPAddress < string.endIndex) { // "/" was located
+        if endOfIPAddress < string.endIndex { // "/" was located
             let indexOfNetworkPrefixLength = string.index(after: endOfIPAddress)
-            guard (indexOfNetworkPrefixLength < string.endIndex) else { return nil }
+            guard indexOfNetworkPrefixLength < string.endIndex else { return nil }
             let networkPrefixLengthSubstring = string[indexOfNetworkPrefixLength ..< string.endIndex]
             guard let npl = UInt8(networkPrefixLengthSubstring) else { return nil }
             networkPrefixLength = min(npl, maxNetworkPrefixLength)
@@ -69,7 +69,7 @@ extension IPAddressRange: Codable {
         var data = try container.decode(Data.self)
         networkPrefixLength = data.removeLast()
         let ipAddressFromData: IPAddress? = {
-            switch (data.count) {
+            switch data.count {
             case 4: return IPv4Address(data)
             case 16: return IPv6Address(data)
             default: return nil
index dc22757d386c97fff354ccbf10801738893f8065..79d606d92a3efb93fd07377847a8bd98a47ea825 100644 (file)
                        isa = PBXNativeTarget;
                        buildConfigurationList = 6F5D0C25218352EF000F85AD /* Build configuration list for PBXNativeTarget "WireGuardNetworkExtension" */;
                        buildPhases = (
+                               5F45417B21C0906F00994C13 /* Swiftlint */,
                                6F61F1EC21BA4D4700483816 /* Extract wireguard-go Version */,
                                6F5D0C16218352EF000F85AD /* Sources */,
                                6F5D0C17218352EF000F85AD /* Frameworks */,
                        isa = PBXNativeTarget;
                        buildConfigurationList = 6FF4AC26211EC472002C96EB /* Build configuration list for PBXNativeTarget "WireGuard" */;
                        buildPhases = (
+                               5F45417A21C0902400994C13 /* Swiftlint */,
                                6B87860E2189532500C099FB /* Extract wireguard-go Version */,
                                6FF4AC10211EC46F002C96EB /* Sources */,
                                6FF4AC11211EC46F002C96EB /* Frameworks */,
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
+               5F45417A21C0902400994C13 /* Swiftlint */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputFileListPaths = (
+                       );
+                       inputPaths = (
+                       );
+                       name = Swiftlint;
+                       outputFileListPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "if which swiftlint >/dev/null; then\n    swiftlint\nelse\n    echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
+               };
+               5F45417B21C0906F00994C13 /* Swiftlint */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputFileListPaths = (
+                       );
+                       inputPaths = (
+                       );
+                       name = Swiftlint;
+                       outputFileListPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "if which swiftlint >/dev/null; then\n    swiftlint\nelse\n    echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
+               };
                6B87860E2189532500C099FB /* Extract wireguard-go Version */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
index 92a1a646654c4adf732527e9b1cc35324d02cd4d..e623eab1d3777f58e3c64776b5f341753260e190 100644 (file)
@@ -379,8 +379,8 @@ class TunnelViewModel {
         var peersData: [PeerData] = []
         if let tunnelConfiguration = tunnelConfiguration {
             interfaceData.validatedConfiguration = tunnelConfiguration.interface
-            for (i, peerConfiguration) in tunnelConfiguration.peers.enumerated() {
-                let peerData = PeerData(index: i)
+            for (index, peerConfiguration) in tunnelConfiguration.peers.enumerated() {
+                let peerData = PeerData(index: index)
                 peerData.validatedConfiguration = peerConfiguration
                 peersData.append(peerData)
             }
@@ -397,22 +397,22 @@ class TunnelViewModel {
     func appendEmptyPeer() {
         let peer = PeerData(index: peersData.count)
         peersData.append(peer)
-        for p in peersData {
-            p.numberOfPeers = peersData.count
-            p.updateExcludePrivateIPsFieldState()
+        for peer in peersData {
+            peer.numberOfPeers = peersData.count
+            peer.updateExcludePrivateIPsFieldState()
         }
     }
 
     func deletePeer(peer: PeerData) {
         let removedPeer = peersData.remove(at: peer.index)
         assert(removedPeer.index == peer.index)
-        for p in peersData[peer.index ..< peersData.count] {
-            assert(p.index > 0)
-            p.index = p.index - 1
+        for peer in peersData[peer.index ..< peersData.count] {
+            assert(peer.index > 0)
+            peer.index -= 1
         }
-        for p in peersData {
-            p.numberOfPeers = peersData.count
-            p.updateExcludePrivateIPsFieldState()
+        for peer in peersData {
+            peer.numberOfPeers = peersData.count
+            peer.updateExcludePrivateIPsFieldState()
         }
     }
 
index 69f40d5170a67e5b89289abe3392d1c5f69f3fdd..c06b5d3fc93b9532eaf06fb8b1aa8a4d4eed7174 100644 (file)
@@ -42,20 +42,21 @@ class MainViewController: UISplitViewController {
 
         // Create the tunnels manager, and when it's ready, inform tunnelsListVC
         TunnelsManager.create { [weak self] result in
+            guard let self = self else { return }
+
             if let error = result.error {
                 ErrorPresenter.showErrorAlert(error: error, from: self)
                 return
             }
             let tunnelsManager: TunnelsManager = result.value!
-            guard let s = self else { return }
 
-            s.tunnelsManager = tunnelsManager
-            s.tunnelsListVC?.setTunnelsManager(tunnelsManager: tunnelsManager)
+            self.tunnelsManager = tunnelsManager
+            self.tunnelsListVC?.setTunnelsManager(tunnelsManager: tunnelsManager)
 
-            tunnelsManager.activationDelegate = s
+            tunnelsManager.activationDelegate = self
 
-            s.onTunnelsManagerReady?(tunnelsManager)
-            s.onTunnelsManagerReady = nil
+            self.onTunnelsManagerReady?(tunnelsManager)
+        self.onTunnelsManagerReady = nil
         }
     }
 }
index 207fc43a53bdb853e26c7feb9ecd4010e9c74da6..3849f70691cb7d922accc36184c69f52dd85eb5b 100644 (file)
@@ -32,7 +32,7 @@ class QRScanViewController: UIViewController {
         NSLayoutConstraint.activate([
             tipLabel.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor),
             tipLabel.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor),
-            tipLabel.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -32),
+            tipLabel.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -32)
             ])
 
         guard let videoCaptureDevice = AVCaptureDevice.default(for: .video),
@@ -118,12 +118,11 @@ class QRScanViewController: UIViewController {
             self?.dismiss(animated: true, completion: nil)
         }))
         alert.addAction(UIAlertAction(title: NSLocalizedString("Save", comment: ""), style: .default, handler: { [weak self] _ in
-            let title = alert.textFields?[0].text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
-            if (title.isEmpty) { return }
+            guard let title = alert.textFields?[0].text?.trimmingCharacters(in: .whitespacesAndNewlines), !title.isEmpty else { return }
             tunnelConfiguration.interface.name = title
-            if let s = self {
-                s.delegate?.addScannedQRCode(tunnelConfiguration: tunnelConfiguration, qrScanViewController: s) {
-                    s.dismiss(animated: true, completion: nil)
+            if let self = self {
+                self.delegate?.addScannedQRCode(tunnelConfiguration: tunnelConfiguration, qrScanViewController: self) {
+                    self.dismiss(animated: true, completion: nil)
                 }
             }
         }))
index 7abd4dea5e016b8562f944663685dc642c34c5d9..c0cc86bc18139d4375c82ca90c2e6fb3037e2222 100644 (file)
@@ -34,7 +34,7 @@ class ScrollableLabel: UIScrollView {
             label.topAnchor.constraint(equalTo: self.contentLayoutGuide.topAnchor),
             label.bottomAnchor.constraint(equalTo: self.contentLayoutGuide.bottomAnchor),
             label.rightAnchor.constraint(equalTo: self.contentLayoutGuide.rightAnchor),
-            label.heightAnchor.constraint(equalTo: self.heightAnchor),
+            label.heightAnchor.constraint(equalTo: self.heightAnchor)
             ])
         // If label has less content, it should expand to fit the scrollView,
         // so that right-alignment works in the label.
index bbe5d2527d2238d5c6096e97fbbe0cf40c17fa15..aade1df3711bf09ca8410099311785df6b30a384 100644 (file)
@@ -57,8 +57,8 @@ class SettingsTableViewController: UITableViewController {
         guard let logo = self.tableView.tableFooterView else { return }
         let bottomPadding = max(self.tableView.layoutMargins.bottom, CGFloat(10))
         let fullHeight = max(self.tableView.contentSize.height, self.tableView.bounds.size.height - self.tableView.layoutMargins.top - bottomPadding)
-        let e = logo.frame
-        logo.frame = CGRect(x: e.minX, y: fullHeight - e.height, width: e.width, height: e.height)
+        let frame = logo.frame
+        logo.frame = CGRect(x: frame.minX, y: fullHeight - frame.height, width: frame.width, height: frame.height)
     }
 
     @objc func doneTapped() {
@@ -116,7 +116,8 @@ class SettingsTableViewController: UITableViewController {
             do {
                 try FileManager.default.copyItem(at: networkExtensionLogFileURL, to: destinationURL)
             } catch {
-                os_log("Failed to copy file: %{public}@ to %{public}@: %{public}@", log: OSLog.default, type: .error, networkExtensionLogFileURL.absoluteString, destinationURL.absoluteString, error.localizedDescription)
+                os_log("Failed to copy file: %{public}@ to %{public}@: %{public}@", log: OSLog.default, type: .error,
+                       networkExtensionLogFileURL.absoluteString, destinationURL.absoluteString, error.localizedDescription)
                 ErrorPresenter.showErrorAlert(title: "Log export failed", message: "The log could not be copied", from: self)
                 return
             }
index be81f7f7e441ac919ee35eb8577b17115c46eccf..b54efd9bc0b5ea947fc6e235796d60e07e18404d 100644 (file)
@@ -21,10 +21,10 @@ class TunnelDetailTableViewController: UITableViewController {
     let tunnel: TunnelContainer
     var tunnelViewModel: TunnelViewModel
 
-    init(tunnelsManager tm: TunnelsManager, tunnel t: TunnelContainer) {
-        tunnelsManager = tm
-        tunnel = t
-        tunnelViewModel = TunnelViewModel(tunnelConfiguration: t.tunnelConfiguration())
+    init(tunnelsManager: TunnelsManager, tunnel: TunnelContainer) {
+        self.tunnelsManager = tunnelsManager
+        self.tunnel = tunnel
+        tunnelViewModel = TunnelViewModel(tunnelConfiguration: tunnel.tunnelConfiguration())
         super.init(style: .grouped)
     }
 
@@ -152,11 +152,11 @@ extension TunnelDetailTableViewController {
             let cell = tableView.dequeueReusableCell(withIdentifier: TunnelDetailTableViewStatusCell.id, for: indexPath) as! TunnelDetailTableViewStatusCell
             cell.tunnel = self.tunnel
             cell.onSwitchToggled = { [weak self] isOn in
-                guard let s = self else { return }
+                guard let self = self else { return }
                 if (isOn) {
-                    s.tunnelsManager.startActivation(of: s.tunnel) { [weak s] error in
+                    self.tunnelsManager.startActivation(of: self.tunnel) { [weak self] error in
                         if let error = error {
-                            ErrorPresenter.showErrorAlert(error: error, from: s, onPresented: {
+                            ErrorPresenter.showErrorAlert(error: error, from: self, onPresented: {
                                 DispatchQueue.main.async {
                                     cell.statusSwitch.isOn = false
                                 }
@@ -164,7 +164,7 @@ extension TunnelDetailTableViewController {
                         }
                     }
                 } else {
-                    s.tunnelsManager.startDeactivation(of: s.tunnel)
+                    self.tunnelsManager.startDeactivation(of: self.tunnel)
                 }
             }
             return cell
@@ -198,16 +198,16 @@ extension TunnelDetailTableViewController {
             cell.buttonText = "Delete tunnel"
             cell.hasDestructiveAction = true
             cell.onTapped = { [weak self] in
-                guard let s = self else { return }
-                s.showConfirmationAlert(message: "Delete this tunnel?", buttonTitle: "Delete", from: cell) { [weak s] in
-                    guard let tunnelsManager = s?.tunnelsManager, let tunnel = s?.tunnel else { return }
+                guard let self = self else { return }
+                self.showConfirmationAlert(message: "Delete this tunnel?", buttonTitle: "Delete", from: cell) { [weak self] in
+                    guard let tunnelsManager = self?.tunnelsManager, let tunnel = self?.tunnel else { return }
                     tunnelsManager.remove(tunnel: tunnel) { (error) in
                         if (error != nil) {
                             print("Error removing tunnel: \(String(describing: error))")
                             return
                         }
                     }
-                    s?.navigationController?.navigationController?.popToRootViewController(animated: true)
+                    self?.navigationController?.navigationController?.popToRootViewController(animated: true)
                 }
             }
             return cell
@@ -374,7 +374,7 @@ class TunnelDetailTableViewKeyValueCell: CopyableLabelTableViewCell {
                 constraints = [
                     contentView.layoutMarginsGuide.bottomAnchor.constraint(equalToSystemSpacingBelow: keyLabel.bottomAnchor, multiplier: 0.5),
                     valueLabel.leftAnchor.constraint(equalToSystemSpacingAfter: keyLabel.rightAnchor, multiplier: 1),
-                    valueLabel.topAnchor.constraint(equalToSystemSpacingBelow: contentView.layoutMarginsGuide.topAnchor, multiplier: 0.5),
+                    valueLabel.topAnchor.constraint(equalToSystemSpacingBelow: contentView.layoutMarginsGuide.topAnchor, multiplier: 0.5)
                 ]
                 isStackedHorizontally = true
                 isStackedVertically = false
index 3565a42f25f7f15a74ace35ca7102fe510345c3d..abe573a785c257342022384489f977b10aa8e547 100644 (file)
@@ -37,19 +37,22 @@ class TunnelEditTableViewController: UITableViewController {
     let tunnelViewModel: TunnelViewModel
     var activateOnDemandSetting: ActivateOnDemandSetting
 
-    init(tunnelsManager tm: TunnelsManager, tunnel t: TunnelContainer) {
+    private var interfaceSectionCount: Int { return interfaceFieldsBySection.count }
+    private var peerSectionCount: Int { return tunnelViewModel.peersData.count }
+
+    init(tunnelsManager: TunnelsManager, tunnel: TunnelContainer) {
         // Use this initializer to edit an existing tunnel.
-        tunnelsManager = tm
-        tunnel = t
-        tunnelViewModel = TunnelViewModel(tunnelConfiguration: t.tunnelConfiguration())
-        activateOnDemandSetting = t.activateOnDemandSetting()
+        self.tunnelsManager = tunnelsManager
+        self.tunnel = tunnel
+        tunnelViewModel = TunnelViewModel(tunnelConfiguration: tunnel.tunnelConfiguration())
+        activateOnDemandSetting = tunnel.activateOnDemandSetting()
         super.init(style: .grouped)
     }
 
-    init(tunnelsManager tm: TunnelsManager, tunnelConfiguration: TunnelConfiguration?) {
+    init(tunnelsManager: TunnelsManager, tunnelConfiguration: TunnelConfiguration?) {
         // Use this initializer to create a new tunnel.
         // If tunnelConfiguration is passed, data will be prepopulated from that configuration.
-        tunnelsManager = tm
+        self.tunnelsManager = tunnelsManager
         tunnel = nil
         tunnelViewModel = TunnelViewModel(tunnelConfiguration: tunnelConfiguration)
         activateOnDemandSetting = ActivateOnDemandSetting.defaultSetting
@@ -62,18 +65,18 @@ class TunnelEditTableViewController: UITableViewController {
 
     override func viewDidLoad() {
         super.viewDidLoad()
-        self.title = (tunnel == nil) ? "New configuration" : "Edit configuration"
+        self.title = tunnel == nil ? "New configuration" : "Edit configuration"
         self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(saveTapped))
         self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelTapped))
 
         self.tableView.estimatedRowHeight = 44
         self.tableView.rowHeight = UITableView.automaticDimension
 
-        self.tableView.register(TunnelEditTableViewKeyValueCell.self, forCellReuseIdentifier: TunnelEditTableViewKeyValueCell.id)
-        self.tableView.register(TunnelEditTableViewReadOnlyKeyValueCell.self, forCellReuseIdentifier: TunnelEditTableViewReadOnlyKeyValueCell.id)
-        self.tableView.register(TunnelEditTableViewButtonCell.self, forCellReuseIdentifier: TunnelEditTableViewButtonCell.id)
-        self.tableView.register(TunnelEditTableViewSwitchCell.self, forCellReuseIdentifier: TunnelEditTableViewSwitchCell.id)
-        self.tableView.register(TunnelEditTableViewSelectionListCell.self, forCellReuseIdentifier: TunnelEditTableViewSelectionListCell.id)
+        self.tableView.register(TunnelEditTableViewKeyValueCell.self, forCellReuseIdentifier: TunnelEditTableViewKeyValueCell.reuseIdentifier)
+        self.tableView.register(TunnelEditTableViewReadOnlyKeyValueCell.self, forCellReuseIdentifier: TunnelEditTableViewReadOnlyKeyValueCell.reuseIdentifier)
+        self.tableView.register(TunnelEditTableViewButtonCell.self, forCellReuseIdentifier: TunnelEditTableViewButtonCell.reuseIdentifier)
+        self.tableView.register(TunnelEditTableViewSwitchCell.self, forCellReuseIdentifier: TunnelEditTableViewSwitchCell.reuseIdentifier)
+        self.tableView.register(TunnelEditTableViewSelectionListCell.self, forCellReuseIdentifier: TunnelEditTableViewSelectionListCell.reuseIdentifier)
     }
 
     @objc func saveTapped() {
@@ -123,26 +126,20 @@ class TunnelEditTableViewController: UITableViewController {
 
 extension TunnelEditTableViewController {
     override func numberOfSections(in tableView: UITableView) -> Int {
-        let numberOfInterfaceSections = interfaceFieldsBySection.count
-        let numberOfPeerSections = tunnelViewModel.peersData.count
-
-        return numberOfInterfaceSections + numberOfPeerSections + 1 /* Add Peer */ + 1 /* On-Demand */
+        return interfaceSectionCount + peerSectionCount + 1 /* Add Peer */ + 1 /* On-Demand */
     }
 
     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
-        let numberOfInterfaceSections = interfaceFieldsBySection.count
-        let numberOfPeerSections = tunnelViewModel.peersData.count
-
-        if (section < numberOfInterfaceSections) {
+        if (section < interfaceSectionCount) {
             // Interface
             return interfaceFieldsBySection[section].count
-        } else if ((numberOfPeerSections > 0) && (section < (numberOfInterfaceSections + numberOfPeerSections))) {
+        } else if ((peerSectionCount > 0) && (section < (interfaceSectionCount + peerSectionCount))) {
             // Peer
-            let peerIndex = (section - numberOfInterfaceSections)
+            let peerIndex = (section - interfaceSectionCount)
             let peerData = tunnelViewModel.peersData[peerIndex]
             let peerFieldsToShow = peerData.shouldAllowExcludePrivateIPsControl ? peerFields : peerFields.filter { $0 != .excludePrivateIPs }
             return peerFieldsToShow.count
-        } else if (section < (numberOfInterfaceSections + numberOfPeerSections + 1)) {
+        } else if (section < (interfaceSectionCount + peerSectionCount + 1)) {
             // Add peer
             return 1
         } else {
@@ -156,284 +153,279 @@ extension TunnelEditTableViewController {
     }
 
     override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
-        let numberOfInterfaceSections = interfaceFieldsBySection.count
-        let numberOfPeerSections = tunnelViewModel.peersData.count
-
-        if (section < numberOfInterfaceSections) {
+        if (section < interfaceSectionCount) {
             // Interface
             return (section == 0) ? "Interface" : nil
-        } else if ((numberOfPeerSections > 0) && (section < (numberOfInterfaceSections + numberOfPeerSections))) {
+        } else if ((peerSectionCount > 0) && (section < (interfaceSectionCount + peerSectionCount))) {
             // Peer
             return "Peer"
-        } else if (section == (numberOfInterfaceSections + numberOfPeerSections)) {
+        } else if (section == (interfaceSectionCount + peerSectionCount)) {
             // Add peer
             return nil
         } else {
-            assert(section == (numberOfInterfaceSections + numberOfPeerSections + 1))
+            assert(section == (interfaceSectionCount + peerSectionCount + 1))
             return "On-Demand Activation"
         }
     }
 
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
-        let numberOfInterfaceSections = interfaceFieldsBySection.count
-        let numberOfPeerSections = tunnelViewModel.peersData.count
-
-        let section = indexPath.section
-        let row = indexPath.row
+        if (indexPath.section < interfaceSectionCount) {
+            return interfaceFieldCell(for: tableView, at: indexPath)
+        } else if ((peerSectionCount > 0) && (indexPath.section < (interfaceSectionCount + peerSectionCount))) {
+            return peerCell(for: tableView, at: indexPath)
+        } else if (indexPath.section == (interfaceSectionCount + peerSectionCount)) {
+            return addPeerCell(for: tableView, at: indexPath)
+        } else {
+            return onDemandCell(for: tableView, at: indexPath)
+        }
+    }
 
-        if (section < numberOfInterfaceSections) {
-            // Interface
-            let interfaceData = tunnelViewModel.interfaceData
-            let field = interfaceFieldsBySection[section][row]
-            if (field == .generateKeyPair) {
-                let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewButtonCell.id, for: indexPath) as! TunnelEditTableViewButtonCell
-                cell.buttonText = field.rawValue
-                cell.onTapped = { [weak self, weak interfaceData] in
-                    if let interfaceData = interfaceData, let s = self {
-                        interfaceData[.privateKey] = Curve25519.generatePrivateKey().base64EncodedString()
-                        if let privateKeyRow = s.interfaceFieldsBySection[section].firstIndex(of: .privateKey),
-                            let publicKeyRow = s.interfaceFieldsBySection[section].firstIndex(of: .publicKey) {
-                            let privateKeyIndex = IndexPath(row: privateKeyRow, section: section)
-                            let publicKeyIndex = IndexPath(row: publicKeyRow, section: section)
-                            s.tableView.reloadRows(at: [privateKeyIndex, publicKeyIndex], with: .automatic)
-                        }
+    private func interfaceFieldCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell {
+        let interfaceData = tunnelViewModel.interfaceData
+        let field = interfaceFieldsBySection[indexPath.section][indexPath.row]
+        if (field == .generateKeyPair) {
+            let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewButtonCell.reuseIdentifier, for: indexPath) as! TunnelEditTableViewButtonCell
+            cell.buttonText = field.rawValue
+            cell.onTapped = { [weak self, weak interfaceData] in
+                if let interfaceData = interfaceData, let self = self {
+                    interfaceData[.privateKey] = Curve25519.generatePrivateKey().base64EncodedString()
+                    if let privateKeyRow = self.interfaceFieldsBySection[indexPath.section].firstIndex(of: .privateKey),
+                        let publicKeyRow = self.interfaceFieldsBySection[indexPath.section].firstIndex(of: .publicKey) {
+                        let privateKeyIndex = IndexPath(row: privateKeyRow, section: indexPath.section)
+                        let publicKeyIndex = IndexPath(row: publicKeyRow, section: indexPath.section)
+                        self.tableView.reloadRows(at: [privateKeyIndex, publicKeyIndex], with: .automatic)
                     }
                 }
-                return cell
-            } else if (field == .publicKey) {
-                let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewReadOnlyKeyValueCell.id, for: indexPath) as! TunnelEditTableViewReadOnlyKeyValueCell
-                cell.key = field.rawValue
-                cell.value = interfaceData[field]
-                return cell
-            } else {
-                let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewKeyValueCell.id, for: indexPath) as! TunnelEditTableViewKeyValueCell
-                // Set key
-                cell.key = field.rawValue
-                // Set placeholder text
-                switch (field) {
-                case .name:
-                    cell.placeholderText = "Required"
-                case .privateKey:
-                    cell.placeholderText = "Required"
-                case .addresses:
-                    cell.placeholderText = "Optional"
-                case .listenPort:
-                    cell.placeholderText = "Automatic"
-                case .mtu:
-                    cell.placeholderText = "Automatic"
-                case .dns:
-                    cell.placeholderText = "Optional"
-                case .publicKey: break
-                case .generateKeyPair: break
-                }
-                // Set keyboardType
-                if (field == .mtu || field == .listenPort) {
-                    cell.keyboardType = .numberPad
-                } else if (field == .addresses || field == .dns) {
-                    cell.keyboardType = .numbersAndPunctuation
+            }
+            return cell
+        } else if field == .publicKey {
+            let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewReadOnlyKeyValueCell.reuseIdentifier, for: indexPath) as! TunnelEditTableViewReadOnlyKeyValueCell
+            cell.key = field.rawValue
+            cell.value = interfaceData[field]
+            return cell
+        } else {
+            let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewKeyValueCell.reuseIdentifier, for: indexPath) as! TunnelEditTableViewKeyValueCell
+            // Set key
+            cell.key = field.rawValue
+            // Set placeholder text
+            switch field {
+            case .name:
+                cell.placeholderText = "Required"
+            case .privateKey:
+                cell.placeholderText = "Required"
+            case .addresses:
+                cell.placeholderText = "Optional"
+            case .listenPort:
+                cell.placeholderText = "Automatic"
+            case .mtu:
+                cell.placeholderText = "Automatic"
+            case .dns:
+                cell.placeholderText = "Optional"
+            case .publicKey: break
+            case .generateKeyPair: break
+            }
+            // Set keyboardType
+            if field == .mtu || field == .listenPort {
+                cell.keyboardType = .numberPad
+            } else if field == .addresses || field == .dns {
+                cell.keyboardType = .numbersAndPunctuation
+            }
+            // Show erroring fields
+            cell.isValueValid = (!interfaceData.fieldsWithError.contains(field))
+            // Bind values to view model
+            cell.value = interfaceData[field]
+            if field == .dns { // While editing DNS, you might directly set exclude private IPs
+                cell.onValueBeingEdited = { [weak interfaceData] value in
+                    interfaceData?[field] = value
                 }
-                // Show erroring fields
-                cell.isValueValid = (!interfaceData.fieldsWithError.contains(field))
-                // Bind values to view model
-                cell.value = interfaceData[field]
-                if (field == .dns) { // While editing DNS, you might directly set exclude private IPs
-                    cell.onValueBeingEdited = { [weak interfaceData] value in
-                        interfaceData?[field] = value
-                    }
-                } else {
-                    cell.onValueChanged = { [weak interfaceData] value in
-                        interfaceData?[field] = value
-                    }
+            } else {
+                cell.onValueChanged = { [weak interfaceData] value in
+                    interfaceData?[field] = value
                 }
-                // Compute public key live
-                if (field == .privateKey) {
-                    cell.onValueBeingEdited = { [weak self, weak interfaceData] value in
-                        if let interfaceData = interfaceData, let s = self {
-                            interfaceData[.privateKey] = value
-                            if let row = s.interfaceFieldsBySection[section].firstIndex(of: .publicKey) {
-                                s.tableView.reloadRows(at: [IndexPath(row: row, section: section)], with: .none)
-                            }
+            }
+            // Compute public key live
+            if field == .privateKey {
+                cell.onValueBeingEdited = { [weak self, weak interfaceData] value in
+                    if let interfaceData = interfaceData, let self = self {
+                        interfaceData[.privateKey] = value
+                        if let row = self.interfaceFieldsBySection[indexPath.section].firstIndex(of: .publicKey) {
+                            self.tableView.reloadRows(at: [IndexPath(row: row, section: indexPath.section)], with: .none)
                         }
                     }
                 }
-                return cell
             }
-        } else if ((numberOfPeerSections > 0) && (section < (numberOfInterfaceSections + numberOfPeerSections))) {
-            // Peer
-            let peerIndex = (section - numberOfInterfaceSections)
-            let peerData = tunnelViewModel.peersData[peerIndex]
-            let peerFieldsToShow = peerData.shouldAllowExcludePrivateIPsControl ? peerFields : peerFields.filter { $0 != .excludePrivateIPs }
-            let field = peerFieldsToShow[row]
-            if (field == .deletePeer) {
-                let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewButtonCell.id, for: indexPath) as! TunnelEditTableViewButtonCell
-                cell.buttonText = field.rawValue
-                cell.hasDestructiveAction = true
-                cell.onTapped = { [weak self, weak peerData] in
-                    guard let peerData = peerData else { return }
-                    guard let s = self else { return }
-                    s.showConfirmationAlert(message: "Delete this peer?",
-                                            buttonTitle: "Delete", from: cell,
-                                            onConfirmed: { [weak s] in
-                                                guard let s = s else { return }
-                                                let removedSectionIndices = s.deletePeer(peer: peerData)
-                                                let shouldShowExcludePrivateIPs = (s.tunnelViewModel.peersData.count == 1 &&
-                                                    s.tunnelViewModel.peersData[0].shouldAllowExcludePrivateIPsControl)
-                                                tableView.performBatchUpdates({
-                                                    s.tableView.deleteSections(removedSectionIndices, with: .automatic)
-                                                    if (shouldShowExcludePrivateIPs) {
-                                                        if let row = s.peerFields.firstIndex(of: .excludePrivateIPs) {
-                                                            let rowIndexPath = IndexPath(row: row, section: numberOfInterfaceSections /* First peer section */)
-                                                            s.tableView.insertRows(at: [rowIndexPath], with: .automatic)
-                                                        }
-
-                                                    }
-                                                })
+            return cell
+        }
+    }
+
+    private func peerCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell {
+        let peerIndex = indexPath.section - interfaceFieldsBySection.count
+        let peerData = tunnelViewModel.peersData[peerIndex]
+        let peerFieldsToShow = peerData.shouldAllowExcludePrivateIPsControl ? peerFields : peerFields.filter { $0 != .excludePrivateIPs }
+        let field = peerFieldsToShow[indexPath.row]
+        if field == .deletePeer {
+            let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewButtonCell.reuseIdentifier, for: indexPath) as! TunnelEditTableViewButtonCell
+            cell.buttonText = field.rawValue
+            cell.hasDestructiveAction = true
+            cell.onTapped = { [weak self, weak peerData] in
+                guard let peerData = peerData else { return }
+                guard let self = self else { return }
+                self.showConfirmationAlert(message: "Delete this peer?", buttonTitle: "Delete", from: cell) { [weak self] in
+                    guard let self = self else { return }
+                    let removedSectionIndices = self.deletePeer(peer: peerData)
+                    let shouldShowExcludePrivateIPs = (self.tunnelViewModel.peersData.count == 1 && self.tunnelViewModel.peersData[0].shouldAllowExcludePrivateIPsControl)
+                    tableView.performBatchUpdates({
+                        self.tableView.deleteSections(removedSectionIndices, with: .automatic)
+                        if shouldShowExcludePrivateIPs {
+                            if let row = self.peerFields.firstIndex(of: .excludePrivateIPs) {
+                                let rowIndexPath = IndexPath(row: row, section: self.interfaceFieldsBySection.count /* First peer section */)
+                                self.tableView.insertRows(at: [rowIndexPath], with: .automatic)
+                            }
+
+                        }
                     })
                 }
-                return cell
-            } else if (field == .excludePrivateIPs) {
-                let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewSwitchCell.id, for: indexPath) as! TunnelEditTableViewSwitchCell
-                cell.message = field.rawValue
-                cell.isEnabled = peerData.shouldAllowExcludePrivateIPsControl
-                cell.isOn = peerData.excludePrivateIPsValue
-                cell.onSwitchToggled = { [weak self] (isOn) in
-                    guard let s = self else { return }
-                    peerData.excludePrivateIPsValueChanged(isOn: isOn, dnsServers: s.tunnelViewModel.interfaceData[.dns])
-                    if let row = s.peerFields.firstIndex(of: .allowedIPs) {
-                        s.tableView.reloadRows(at: [IndexPath(row: row, section: section)], with: .none)
-                    }
-                }
-                return cell
-            } else {
-                let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewKeyValueCell.id, for: indexPath) as! TunnelEditTableViewKeyValueCell
-                // Set key
-                cell.key = field.rawValue
-                // Set placeholder text
-                switch (field) {
-                case .publicKey:
-                    cell.placeholderText = "Required"
-                case .preSharedKey:
-                    cell.placeholderText = "Optional"
-                case .endpoint:
-                    cell.placeholderText = "Optional"
-                case .allowedIPs:
-                    cell.placeholderText = "Optional"
-                case .persistentKeepAlive:
-                    cell.placeholderText = "Off"
-                case .excludePrivateIPs: break
-                case .deletePeer: break
-                }
-                // Set keyboardType
-                if (field == .persistentKeepAlive) {
-                    cell.keyboardType = .numberPad
-                } else if (field == .allowedIPs) {
-                    cell.keyboardType = .numbersAndPunctuation
+            }
+            return cell
+        } else if field == .excludePrivateIPs {
+            let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewSwitchCell.reuseIdentifier, for: indexPath) as! TunnelEditTableViewSwitchCell
+            cell.message = field.rawValue
+            cell.isEnabled = peerData.shouldAllowExcludePrivateIPsControl
+            cell.isOn = peerData.excludePrivateIPsValue
+            cell.onSwitchToggled = { [weak self] (isOn) in
+                guard let self = self else { return }
+                peerData.excludePrivateIPsValueChanged(isOn: isOn, dnsServers: self.tunnelViewModel.interfaceData[.dns])
+                if let row = self.peerFields.firstIndex(of: .allowedIPs) {
+                    self.tableView.reloadRows(at: [IndexPath(row: row, section: indexPath.section)], with: .none)
                 }
-                // Show erroring fields
-                cell.isValueValid = (!peerData.fieldsWithError.contains(field))
-                // Bind values to view model
-                cell.value = peerData[field]
-                if (field != .allowedIPs) {
-                    cell.onValueChanged = { [weak peerData] value in
-                        peerData?[field] = value
-                    }
+            }
+            return cell
+        } else {
+            let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewKeyValueCell.reuseIdentifier, for: indexPath) as! TunnelEditTableViewKeyValueCell
+            // Set key
+            cell.key = field.rawValue
+            // Set placeholder text
+            switch field {
+            case .publicKey:
+                cell.placeholderText = "Required"
+            case .preSharedKey:
+                cell.placeholderText = "Optional"
+            case .endpoint:
+                cell.placeholderText = "Optional"
+            case .allowedIPs:
+                cell.placeholderText = "Optional"
+            case .persistentKeepAlive:
+                cell.placeholderText = "Off"
+            case .excludePrivateIPs: break
+            case .deletePeer: break
+            }
+            // Set keyboardType
+            if field == .persistentKeepAlive {
+                cell.keyboardType = .numberPad
+            } else if field == .allowedIPs {
+                cell.keyboardType = .numbersAndPunctuation
+            }
+            // Show erroring fields
+            cell.isValueValid = (!peerData.fieldsWithError.contains(field))
+            // Bind values to view model
+            cell.value = peerData[field]
+            if field != .allowedIPs {
+                cell.onValueChanged = { [weak peerData] value in
+                    peerData?[field] = value
                 }
-                // Compute state of exclude private IPs live
-                if (field == .allowedIPs) {
-                    cell.onValueBeingEdited = { [weak self, weak peerData] value in
-                        if let peerData = peerData, let s = self {
-                            let oldValue = peerData.shouldAllowExcludePrivateIPsControl
-                            peerData[.allowedIPs] = value
-                            if (oldValue != peerData.shouldAllowExcludePrivateIPsControl) {
-                                if let row = s.peerFields.firstIndex(of: .excludePrivateIPs) {
-                                    if (peerData.shouldAllowExcludePrivateIPsControl) {
-                                        s.tableView.insertRows(at: [IndexPath(row: row, section: section)], with: .automatic)
-                                    } else {
-                                        s.tableView.deleteRows(at: [IndexPath(row: row, section: section)], with: .automatic)
-                                    }
+            }
+            // Compute state of exclude private IPs live
+            if field == .allowedIPs {
+                cell.onValueBeingEdited = { [weak self, weak peerData] value in
+                    if let peerData = peerData, let self = self {
+                        let oldValue = peerData.shouldAllowExcludePrivateIPsControl
+                        peerData[.allowedIPs] = value
+                        if oldValue != peerData.shouldAllowExcludePrivateIPsControl {
+                            if let row = self.peerFields.firstIndex(of: .excludePrivateIPs) {
+                                if peerData.shouldAllowExcludePrivateIPsControl {
+                                    self.tableView.insertRows(at: [IndexPath(row: row, section: indexPath.section)], with: .automatic)
+                                } else {
+                                    self.tableView.deleteRows(at: [IndexPath(row: row, section: indexPath.section)], with: .automatic)
                                 }
                             }
                         }
                     }
                 }
-                return cell
-            }
-        } else if (section == (numberOfInterfaceSections + numberOfPeerSections)) {
-            // Add peer
-            let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewButtonCell.id, for: indexPath) as! TunnelEditTableViewButtonCell
-            cell.buttonText = "Add peer"
-            cell.onTapped = { [weak self] in
-                guard let s = self else { return }
-                let shouldHideExcludePrivateIPs = (s.tunnelViewModel.peersData.count == 1 &&
-                    s.tunnelViewModel.peersData[0].shouldAllowExcludePrivateIPsControl)
-                let addedSectionIndices = s.appendEmptyPeer()
-                tableView.performBatchUpdates({
-                    tableView.insertSections(addedSectionIndices, with: .automatic)
-                    if (shouldHideExcludePrivateIPs) {
-                        if let row = s.peerFields.firstIndex(of: .excludePrivateIPs) {
-                            let rowIndexPath = IndexPath(row: row, section: numberOfInterfaceSections /* First peer section */)
-                            s.tableView.deleteRows(at: [rowIndexPath], with: .automatic)
-                        }
-                    }
-                }, completion: nil)
             }
             return cell
-        } else {
-            assert(section == (numberOfInterfaceSections + numberOfPeerSections + 1))
-            if (row == 0) {
-                let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewSwitchCell.id, for: indexPath) as! TunnelEditTableViewSwitchCell
-                cell.message = "Activate on demand"
-                cell.isOn = activateOnDemandSetting.isActivateOnDemandEnabled
-                cell.onSwitchToggled = { [weak self] (isOn) in
-                    guard let s = self else { return }
-                    let indexPaths: [IndexPath] = (1 ..< 4).map { IndexPath(row: $0, section: section) }
-                    if (isOn) {
-                        s.activateOnDemandSetting.isActivateOnDemandEnabled = true
-                        if (s.activateOnDemandSetting.activateOnDemandOption == .none) {
-                            s.activateOnDemandSetting.activateOnDemandOption = TunnelViewModel.defaultActivateOnDemandOption()
-                        }
-                        s.tableView.insertRows(at: indexPaths, with: .automatic)
-                    } else {
-                        s.activateOnDemandSetting.isActivateOnDemandEnabled = false
-                        s.tableView.deleteRows(at: indexPaths, with: .automatic)
+        }
+    }
+
+    private func addPeerCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell {
+        let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewButtonCell.reuseIdentifier, for: indexPath) as! TunnelEditTableViewButtonCell
+        cell.buttonText = "Add peer"
+        cell.onTapped = { [weak self] in
+            guard let self = self else { return }
+            let shouldHideExcludePrivateIPs = (self.tunnelViewModel.peersData.count == 1 && self.tunnelViewModel.peersData[0].shouldAllowExcludePrivateIPsControl)
+            let addedSectionIndices = self.appendEmptyPeer()
+            tableView.performBatchUpdates({
+                tableView.insertSections(addedSectionIndices, with: .automatic)
+                if shouldHideExcludePrivateIPs {
+                    if let row = self.peerFields.firstIndex(of: .excludePrivateIPs) {
+                        let rowIndexPath = IndexPath(row: row, section: self.interfaceFieldsBySection.count /* First peer section */)
+                        self.tableView.deleteRows(at: [rowIndexPath], with: .automatic)
                     }
                 }
-                return cell
-            } else {
-                assert(row < 4)
-                let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewSelectionListCell.id, for: indexPath) as! TunnelEditTableViewSelectionListCell
-                let rowOption = activateOnDemandOptions[row - 1]
-                let selectedOption = activateOnDemandSetting.activateOnDemandOption
-                assert(selectedOption != .none)
-                cell.message = TunnelViewModel.activateOnDemandOptionText(for: rowOption)
-                cell.isChecked = (selectedOption == rowOption)
-                return cell
+            }, completion: nil)
+        }
+        return cell
+    }
+
+    private func onDemandCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell {
+        assert(indexPath.section == interfaceSectionCount + peerSectionCount + 1)
+        if indexPath.row == 0 {
+            let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewSwitchCell.reuseIdentifier, for: indexPath) as! TunnelEditTableViewSwitchCell
+            cell.message = "Activate on demand"
+            cell.isOn = activateOnDemandSetting.isActivateOnDemandEnabled
+            cell.onSwitchToggled = { [weak self] (isOn) in
+                guard let self = self else { return }
+                let indexPaths: [IndexPath] = (1 ..< 4).map { IndexPath(row: $0, section: indexPath.section) }
+                if isOn {
+                    self.activateOnDemandSetting.isActivateOnDemandEnabled = true
+                    if self.activateOnDemandSetting.activateOnDemandOption == .none {
+                        self.activateOnDemandSetting.activateOnDemandOption = TunnelViewModel.defaultActivateOnDemandOption()
+                    }
+                    self.tableView.insertRows(at: indexPaths, with: .automatic)
+                } else {
+                    self.activateOnDemandSetting.isActivateOnDemandEnabled = false
+                    self.tableView.deleteRows(at: indexPaths, with: .automatic)
+                }
             }
+            return cell
+        } else {
+            assert(indexPath.row < 4)
+            let cell = tableView.dequeueReusableCell(withIdentifier: TunnelEditTableViewSelectionListCell.reuseIdentifier, for: indexPath) as! TunnelEditTableViewSelectionListCell
+            let rowOption = activateOnDemandOptions[indexPath.row - 1]
+            let selectedOption = activateOnDemandSetting.activateOnDemandOption
+            assert(selectedOption != .none)
+            cell.message = TunnelViewModel.activateOnDemandOptionText(for: rowOption)
+            cell.isChecked = (selectedOption == rowOption)
+            return cell
         }
     }
 
     func appendEmptyPeer() -> IndexSet {
-        let numberOfInterfaceSections = interfaceFieldsBySection.count
-
         tunnelViewModel.appendEmptyPeer()
         let addedPeerIndex = tunnelViewModel.peersData.count - 1
 
-        let addedSectionIndices = IndexSet(integer: (numberOfInterfaceSections + addedPeerIndex))
+        let addedSectionIndices = IndexSet(integer: interfaceSectionCount + addedPeerIndex)
         return addedSectionIndices
     }
 
     func deletePeer(peer: TunnelViewModel.PeerData) -> IndexSet {
-        let numberOfInterfaceSections = interfaceFieldsBySection.count
-
         assert(peer.index < tunnelViewModel.peersData.count)
         tunnelViewModel.deletePeer(peer: peer)
 
-        let removedSectionIndices = IndexSet(integer: (numberOfInterfaceSections + peer.index))
+        let removedSectionIndices = IndexSet(integer: (interfaceSectionCount + peer.index))
         return removedSectionIndices
     }
 
-    func showConfirmationAlert(message: String, buttonTitle: String, from sourceView: UIView,
-                               onConfirmed: @escaping (() -> Void)) {
+    func showConfirmationAlert(message: String, buttonTitle: String, from sourceView: UIView, onConfirmed: @escaping (() -> Void)) {
         let destroyAction = UIAlertAction(title: buttonTitle, style: .destructive) { (_) in
             onConfirmed()
         }
@@ -454,27 +446,18 @@ extension TunnelEditTableViewController {
 
 extension TunnelEditTableViewController {
     override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
-        let numberOfInterfaceSections = interfaceFieldsBySection.count
-        let numberOfPeerSections = tunnelViewModel.peersData.count
-
-        let section = indexPath.section
-        let row = indexPath.row
-
-        if (section == (numberOfInterfaceSections + numberOfPeerSections + 1)) {
-            return (row > 0) ? indexPath : nil
+        if indexPath.section == (interfaceSectionCount + peerSectionCount + 1) {
+            return (indexPath.row > 0) ? indexPath : nil
         } else {
             return nil
         }
     }
 
     override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
-        let numberOfInterfaceSections = interfaceFieldsBySection.count
-        let numberOfPeerSections = tunnelViewModel.peersData.count
-
         let section = indexPath.section
         let row = indexPath.row
 
-        assert(section == (numberOfInterfaceSections + numberOfPeerSections + 1))
+        assert(section == (interfaceSectionCount + peerSectionCount + 1))
         assert(row > 0)
 
         let option = activateOnDemandOptions[row - 1]
@@ -487,7 +470,7 @@ extension TunnelEditTableViewController {
 }
 
 class TunnelEditTableViewKeyValueCell: UITableViewCell {
-    static let id: String = "TunnelEditTableViewKeyValueCell"
+    static let reuseIdentifier = "TunnelEditTableViewKeyValueCell"
     var key: String {
         get { return keyLabel.text ?? "" }
         set(value) {keyLabel.text = value }
@@ -502,7 +485,7 @@ class TunnelEditTableViewKeyValueCell: UITableViewCell {
     }
     var isValueValid: Bool = true {
         didSet {
-            if (isValueValid) {
+            if isValueValid {
                 keyLabel.textColor = UIColor.black
             } else {
                 keyLabel.textColor = UIColor.red
@@ -584,7 +567,7 @@ class TunnelEditTableViewKeyValueCell: UITableViewCell {
                 constraints = [
                     contentView.layoutMarginsGuide.bottomAnchor.constraint(equalToSystemSpacingBelow: keyLabel.bottomAnchor, multiplier: 0.5),
                     valueTextField.leftAnchor.constraint(equalToSystemSpacingAfter: keyLabel.rightAnchor, multiplier: 1),
-                    valueTextField.topAnchor.constraint(equalToSystemSpacingBelow: contentView.layoutMarginsGuide.topAnchor, multiplier: 0.5),
+                    valueTextField.topAnchor.constraint(equalToSystemSpacingBelow: contentView.layoutMarginsGuide.topAnchor, multiplier: 0.5)
                 ]
                 isStackedHorizontally = true
                 isStackedVertically = false
@@ -636,7 +619,7 @@ extension TunnelEditTableViewKeyValueCell: UITextFieldDelegate {
 }
 
 class TunnelEditTableViewReadOnlyKeyValueCell: CopyableLabelTableViewCell {
-    static let id: String = "TunnelEditTableViewReadOnlyKeyValueCell"
+    static let reuseIdentifier = "TunnelEditTableViewReadOnlyKeyValueCell"
     var key: String {
         get { return keyLabel.text ?? "" }
         set(value) {keyLabel.text = value }
@@ -684,7 +667,7 @@ class TunnelEditTableViewReadOnlyKeyValueCell: CopyableLabelTableViewCell {
         NSLayoutConstraint.activate([
             valueLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
             valueLabel.leftAnchor.constraint(equalToSystemSpacingAfter: keyLabel.rightAnchor, multiplier: 1),
-            valueLabel.rightAnchor.constraint(equalTo: contentView.layoutMarginsGuide.rightAnchor),
+            valueLabel.rightAnchor.constraint(equalTo: contentView.layoutMarginsGuide.rightAnchor)
             ])
     }
 
@@ -704,7 +687,7 @@ class TunnelEditTableViewReadOnlyKeyValueCell: CopyableLabelTableViewCell {
 }
 
 class TunnelEditTableViewButtonCell: UITableViewCell {
-    static let id: String = "TunnelEditTableViewButtonCell"
+    static let reuseIdentifier = "TunnelEditTableViewButtonCell"
     var buttonText: String {
         get { return button.title(for: .normal) ?? "" }
         set(value) { button.setTitle(value, for: .normal) }
@@ -751,7 +734,7 @@ class TunnelEditTableViewButtonCell: UITableViewCell {
 }
 
 class TunnelEditTableViewSwitchCell: UITableViewCell {
-    static let id: String = "TunnelEditTableViewSwitchCell"
+    static let reuseIdentifier = "TunnelEditTableViewSwitchCell"
     var message: String {
         get { return textLabel?.text ?? "" }
         set(value) { textLabel!.text = value }
@@ -796,7 +779,7 @@ class TunnelEditTableViewSwitchCell: UITableViewCell {
 }
 
 class TunnelEditTableViewSelectionListCell: UITableViewCell {
-    static let id: String = "TunnelEditTableViewSelectionListCell"
+    static let reuseIdentifier = "TunnelEditTableViewSelectionListCell"
     var message: String {
         get { return textLabel?.text ?? "" }
         set(value) { textLabel!.text = value }
index 66c4452743835e314ea0e341698bb9eee94f792e..07fbee41e6ccf7c1eeee9e83a3085a2897769bda 100644 (file)
@@ -116,8 +116,8 @@ class TunnelsListTableViewController: UIViewController {
         alert.addAction(scanQRCodeAction)
 
         let createFromScratchAction = UIAlertAction(title: "Create from scratch", style: .default) { [weak self] (_) in
-            if let s = self, let tunnelsManager = s.tunnelsManager {
-                s.presentViewControllerForTunnelCreation(tunnelsManager: tunnelsManager, tunnelConfiguration: nil)
+            if let self = self, let tunnelsManager = self.tunnelsManager {
+                self.presentViewControllerForTunnelCreation(tunnelsManager: tunnelsManager, tunnelConfiguration: nil)
             }
         }
         alert.addAction(createFromScratchAction)
@@ -246,11 +246,11 @@ extension TunnelsListTableViewController: UITableViewDataSource {
             let tunnel = tunnelsManager.tunnel(at: indexPath.row)
             cell.tunnel = tunnel
             cell.onSwitchToggled = { [weak self] isOn in
-                guard let s = self, let tunnelsManager = s.tunnelsManager else { return }
+                guard let self = self, let tunnelsManager = self.tunnelsManager else { return }
                 if (isOn) {
-                    tunnelsManager.startActivation(of: tunnel) { [weak s] error in
+                    tunnelsManager.startActivation(of: tunnel) { [weak self] error in
                         if let error = error {
-                            ErrorPresenter.showErrorAlert(error: error, from: s, onPresented: {
+                            ErrorPresenter.showErrorAlert(error: error, from: self, onPresented: {
                                 DispatchQueue.main.async {
                                     cell.statusSwitch.isOn = false
                                 }
index 222100d220569a949848b842c0cf6f1fffe729b4..f8819d4761693159ce6a4a58351fefc38ac6ec79 100644 (file)
@@ -118,11 +118,11 @@ class TunnelsManager {
                 completionHandler(.failure(TunnelsManagerError.vpnSystemErrorOnAddTunnel))
                 return
             }
-            if let s = self {
+            if let self = self {
                 let tunnel = TunnelContainer(tunnel: tunnelProviderManager)
-                s.tunnels.append(tunnel)
-                s.tunnels.sort { $0.name < $1.name }
-                s.tunnelsListDelegate?.tunnelAdded(at: s.tunnels.firstIndex(of: tunnel)!)
+                self.tunnels.append(tunnel)
+                self.tunnels.sort { $0.name < $1.name }
+                self.tunnelsListDelegate?.tunnelAdded(at: self.tunnels.firstIndex(of: tunnel)!)
                 completionHandler(.success(tunnel))
             }
         }
@@ -175,14 +175,14 @@ class TunnelsManager {
                 completionHandler(TunnelsManagerError.vpnSystemErrorOnModifyTunnel)
                 return
             }
-            if let s = self {
+            if let self = self {
                 if (isNameChanged) {
-                    let oldIndex = s.tunnels.firstIndex(of: tunnel)!
-                    s.tunnels.sort { $0.name < $1.name }
-                    let newIndex = s.tunnels.firstIndex(of: tunnel)!
-                    s.tunnelsListDelegate?.tunnelMoved(at: oldIndex, to: newIndex)
+                    let oldIndex = self.tunnels.firstIndex(of: tunnel)!
+                    self.tunnels.sort { $0.name < $1.name }
+                    let newIndex = self.tunnels.firstIndex(of: tunnel)!
+                    self.tunnelsListDelegate?.tunnelMoved(at: oldIndex, to: newIndex)
                 }
-                s.tunnelsListDelegate?.tunnelModified(at: s.tunnels.firstIndex(of: tunnel)!)
+                self.tunnelsListDelegate?.tunnelModified(at: self.tunnels.firstIndex(of: tunnel)!)
 
                 if (tunnel.status == .active || tunnel.status == .activating || tunnel.status == .reasserting) {
                     // Turn off the tunnel, and then turn it back on, so the changes are made effective
@@ -219,10 +219,10 @@ class TunnelsManager {
                 completionHandler(TunnelsManagerError.vpnSystemErrorOnRemoveTunnel)
                 return
             }
-            if let s = self {
-                let index = s.tunnels.firstIndex(of: tunnel)!
-                s.tunnels.remove(at: index)
-                s.tunnelsListDelegate?.tunnelRemoved(at: index)
+            if let self = self {
+                let index = self.tunnels.firstIndex(of: tunnel)!
+                self.tunnels.remove(at: index)
+                self.tunnelsListDelegate?.tunnelRemoved(at: index)
             }
             completionHandler(nil)
         }
@@ -264,9 +264,7 @@ class TunnelsManager {
     }
 
     func refreshStatuses() {
-        for t in tunnels {
-            t.refreshStatus()
-        }
+        tunnels.forEach { $0.refreshStatus() }
     }
 
     private func startObservingTunnelStatuses() {
@@ -275,24 +273,24 @@ class TunnelsManager {
             forName: .NEVPNStatusDidChange,
             object: nil,
             queue: OperationQueue.main) { [weak self] (statusChangeNotification) in
+                guard let self = self else { return }
                 guard let session = statusChangeNotification.object as? NETunnelProviderSession else { return }
                 guard let tunnelProvider = session.manager as? NETunnelProviderManager else { return }
-                guard let tunnel = self?.tunnels.first(where: { $0.tunnelProvider == tunnelProvider }) else { return }
-                guard let s = self else { return }
+                guard let tunnel = self.tunnels.first(where: { $0.tunnelProvider == tunnelProvider }) else { return }
 
                 os_log("Tunnel '%{public}@' connection status changed to '%{public}@'",
                        log: OSLog.default, type: .debug, tunnel.name, "\(tunnel.tunnelProvider.connection.status)")
 
                 // In case our attempt to start the tunnel, didn't succeed
-                if (tunnel == s.tunnelBeingActivated) {
+                if (tunnel == self.tunnelBeingActivated) {
                     if (session.status == .disconnected) {
                         if (InternetReachability.currentStatus() == .notReachable) {
                             let error = TunnelsManagerError.tunnelActivationFailedNoInternetConnection
-                            s.activationDelegate?.tunnelActivationFailed(tunnel: tunnel, error: error)
+                            self.activationDelegate?.tunnelActivationFailed(tunnel: tunnel, error: error)
                         }
-                        s.tunnelBeingActivated = nil
+                        self.tunnelBeingActivated = nil
                     } else if (session.status == .connected) {
-                        s.tunnelBeingActivated = nil
+                        self.tunnelBeingActivated = nil
                     }
                 }
 
@@ -300,7 +298,7 @@ class TunnelsManager {
                 if ((tunnel.status == .restarting) && (session.status == .disconnected || session.status == .disconnecting)) {
                     // Don't change tunnel.status when disconnecting for a restart
                     if (session.status == .disconnected) {
-                        s.tunnelBeingActivated = tunnel
+                        self.tunnelBeingActivated = tunnel
                         tunnel.startActivation(completionHandler: { _ in })
                     }
                     return
@@ -387,7 +385,8 @@ class TunnelContainer: NSObject {
                 }
                 os_log("startActivation: Tunnel saved after re-enabling", log: OSLog.default, type: .info)
                 os_log("startActivation: Invoking startActivation", log: OSLog.default, type: .debug)
-                self?.startActivation(recursionCount: recursionCount + 1, lastError: NEVPNError(NEVPNError.configurationUnknown), tunnelConfiguration: tunnelConfiguration, completionHandler: completionHandler)
+                self?.startActivation(recursionCount: recursionCount + 1, lastError: NEVPNError(NEVPNError.configurationUnknown),
+                                      tunnelConfiguration: tunnelConfiguration, completionHandler: completionHandler)
             }
             return
         }
index 93fc4c2ce3fa015886b088015f31d7dff5b9dea5..92f73cd8f664469bff6dfdd06a5a179b09bd8089 100644 (file)
@@ -2,27 +2,27 @@
 // Copyright © 2018 WireGuard LLC. All Rights Reserved.
 
 enum WireGuardResult<T> {
-    case success(T)
-    case failure(WireGuardAppError)
+    case success(_ value: T)
+    case failure(_ error: WireGuardAppError)
 
     var value: T? {
         switch (self) {
-        case .success(let v): return v
-        case .failure(_): return nil
+        case .success(let value): return value
+        case .failure: return nil
         }
     }
 
     var error: WireGuardAppError? {
         switch (self) {
-        case .success(_): return nil
-        case .failure(let e): return e
+        case .success: return nil
+        case .failure(let error): return error
         }
     }
 
     var isSuccess: Bool {
         switch (self) {
-        case .success(_): return true
-        case .failure(_): return false
+        case .success: return true
+        case .failure: return false
         }
     }
 }
index 4f576138fd4e5af697f5dfe93992a3b2794e08f2..f875e1b83e9de184d222a2c8b0b4bd0768b3a3a7 100644 (file)
@@ -16,7 +16,7 @@ enum ZipExporterError: WireGuardAppError {
 
 class ZipExporter {
     static func exportConfigFiles(tunnelConfigurations: [TunnelConfiguration], to url: URL,
-                                  completion: @escaping (WireGuardAppError?) -> Void)  {
+                                  completion: @escaping (WireGuardAppError?) -> Void) {
 
         guard (!tunnelConfigurations.isEmpty) else {
             completion(ZipExporterError.noTunnelsToExport)
index 6c1e3de2eceeeac28d02e13377cb9197a085d4b7..194dc0eca03fd1d5538fb3e69e7192323fe18afc 100644 (file)
@@ -20,13 +20,13 @@ class ZipImporter {
             var unarchivedFiles: [(fileBaseName: String, contents: Data)]
             do {
                 unarchivedFiles = try ZipArchive.unarchive(url: url, requiredFileExtensions: ["conf"])
-                for (i, unarchivedFile) in unarchivedFiles.enumerated().reversed() {
+                for (index, unarchivedFile) in unarchivedFiles.enumerated().reversed() {
                     let fileBaseName = unarchivedFile.fileBaseName
                     let trimmedName = fileBaseName.trimmingCharacters(in: .whitespacesAndNewlines)
                     if (!trimmedName.isEmpty) {
-                        unarchivedFiles[i].fileBaseName = trimmedName
+                        unarchivedFiles[index].fileBaseName = trimmedName
                     } else {
-                        unarchivedFiles.remove(at: i)
+                        unarchivedFiles.remove(at: index)
                     }
                 }
 
@@ -42,8 +42,8 @@ class ZipImporter {
 
             unarchivedFiles.sort { $0.fileBaseName < $1.fileBaseName }
             var configs = Array<TunnelConfiguration?>(repeating: nil, count: unarchivedFiles.count)
-            for (i, file) in unarchivedFiles.enumerated() {
-                if (i > 0 && file == unarchivedFiles[i - 1]) {
+            for (index, file) in unarchivedFiles.enumerated() {
+                if (index > 0 && file == unarchivedFiles[index - 1]) {
                     continue
                 }
                 guard let fileContents = String(data: file.contents, encoding: .utf8) else {
@@ -52,7 +52,7 @@ class ZipImporter {
                 guard let tunnelConfig = try? WgQuickConfigFileParser.parse(fileContents, name: file.fileBaseName) else {
                     continue
                 }
-                configs[i] = tunnelConfig
+                configs[index] = tunnelConfig
             }
             DispatchQueue.main.async { completion(.success(configs)) }
         }
index 0874fd9687bcfdb075f37ff2fe811ba3ec647e75..8a9873f6499928bd5f628468e60d0806638963e9 100644 (file)
@@ -28,13 +28,13 @@ class DNSResolver {
         }
 
         var resolvedEndpoints: [Endpoint?] = Array<Endpoint?>(repeating: nil, count: endpoints.count)
-        for (i, endpoint) in endpoints.enumerated() {
+        for (index, endpoint) in endpoints.enumerated() {
             guard let endpoint = endpoint else { continue }
             if (endpoint.hasHostAsIPAddress()) {
-                resolvedEndpoints[i] = endpoint
+                resolvedEndpoints[index] = endpoint
             } else {
                 let workItem = DispatchWorkItem {
-                    resolvedEndpoints[i] = DNSResolver.resolveSync(endpoint: endpoint)
+                    resolvedEndpoints[index] = DNSResolver.resolveSync(endpoint: endpoint)
                 }
                 DispatchQueue.global(qos: .userInitiated).async(group: dispatchGroup, execute: workItem)
             }
index 4087fe75cf8e91986a69a26a47e026b680f46927..4723e799aaae8cca3139236426a76594909e9406 100644 (file)
@@ -8,7 +8,7 @@ class ErrorNotifier {
         switch (error) {
         case .savedProtocolConfigurationIsInvalid:
             return ("Activation failure", "Could not retrieve tunnel information from the saved configuration")
-        case .dnsResolutionFailure(_):
+        case .dnsResolutionFailure:
             return ("DNS resolution failure", "One or more endpoint domains could not be resolved")
         case .couldNotStartWireGuard:
             return ("Activation failure", "WireGuard backend could not be started")
index f5f0296ac29484cf843275c3b9f1302a6ac9d69b..81a95207c7906057aac97b2034b47254b13a3fb3 100644 (file)
@@ -21,7 +21,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
     // MARK: Properties
 
     private var wgHandle: Int32?
-    
+
     private var networkMonitor: NWPathMonitor?
 
     // MARK: NEPacketTunnelProvider
@@ -29,7 +29,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
     deinit {
         networkMonitor?.cancel()
     }
-    
+
     /// Begin the process of establishing the tunnel.
     override func startTunnel(options: [String: NSObject]?,
                               completionHandler startTunnelCompletionHandler: @escaping (Error?) -> Void) {
@@ -89,9 +89,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
         }
 
         let wireguardSettings = packetTunnelSettingsGenerator.uapiConfiguration()
-        
+
         var handle: Int32 = -1
-        
+
         networkMonitor = NWPathMonitor()
         networkMonitor?.pathUpdateHandler = { path in
             guard handle >= 0 else { return }
@@ -99,18 +99,18 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
                 wg_log(.debug, message: "Network change detected, re-establishing sockets and IPs: \(path.availableInterfaces)")
                 let endpointString = packetTunnelSettingsGenerator.endpointUapiConfiguration(currentListenPort: wgGetListenPort(handle))
                 let err = endpointString.withCString {
-                    wgSetConfig(handle,  gostring_t(p: $0, n: endpointString.utf8.count))
+                    wgSetConfig(handle, gostring_t(p: $0, n: endpointString.utf8.count))
                 }
                 if err == -EADDRINUSE {
                     let endpointString = packetTunnelSettingsGenerator.endpointUapiConfiguration(currentListenPort: 0)
                     _ = endpointString.withCString {
-                        wgSetConfig(handle,  gostring_t(p: $0, n: endpointString.utf8.count))
+                        wgSetConfig(handle, gostring_t(p: $0, n: endpointString.utf8.count))
                     }
                 }
             }
         }
         networkMonitor?.start(queue: DispatchQueue(label: "NetworkMonitor"))
-        
+
         handle = connect(interfaceName: tunnelConfiguration.interface.name, settings: wireguardSettings, fd: fd)
 
         if handle < 0 {
@@ -141,7 +141,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
     override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
         networkMonitor?.cancel()
         networkMonitor = nil
-        
+
         wg_log(.info, staticMessage: "Stopping tunnel")
         if let handle = wgHandle {
             wgTurnOff(handle)
index 61e161eb31dba7dc4a99cdcf7e4300f614082e7c..f6bcdba7787e229b8e2d3ccea36754e15d2116e6 100644 (file)
@@ -18,17 +18,17 @@ class PacketTunnelSettingsGenerator {
     func endpointUapiConfiguration(currentListenPort: UInt16) -> String {
         var wgSettings = "listen_port=\(tunnelConfiguration.interface.listenPort ?? currentListenPort)\n"
 
-        for (i, peer) in tunnelConfiguration.peers.enumerated() {
+        for (index, peer) in tunnelConfiguration.peers.enumerated() {
             wgSettings.append("public_key=\(peer.publicKey.hexEncodedString())\n")
-            if let endpoint = resolvedEndpoints[i] {
+            if let endpoint = resolvedEndpoints[index] {
                 if case .name(_, _) = endpoint.host { assert(false, "Endpoint is not resolved") }
                 wgSettings.append("endpoint=\(endpoint.stringRepresentation())\n")
             }
         }
-        
+
         return wgSettings
     }
-    
+
     func uapiConfiguration() -> String {
         var wgSettings = ""
         let privateKey = tunnelConfiguration.interface.privateKey.hexEncodedString()
@@ -40,12 +40,12 @@ class PacketTunnelSettingsGenerator {
             wgSettings.append("replace_peers=true\n")
         }
         assert(tunnelConfiguration.peers.count == resolvedEndpoints.count)
-        for (i, peer) in tunnelConfiguration.peers.enumerated() {
+        for (index, peer) in tunnelConfiguration.peers.enumerated() {
             wgSettings.append("public_key=\(peer.publicKey.hexEncodedString())\n")
             if let preSharedKey = peer.preSharedKey {
                 wgSettings.append("preshared_key=\(preSharedKey.hexEncodedString())\n")
             }
-            if let endpoint = resolvedEndpoints[i] {
+            if let endpoint = resolvedEndpoints[index] {
                 if case .name(_, _) = endpoint.host { assert(false, "Endpoint is not resolved") }
                 wgSettings.append("endpoint=\(endpoint.stringRepresentation())\n")
             }
@@ -200,10 +200,10 @@ class PacketTunnelSettingsGenerator {
     }
 
     static func ipv4SubnetMaskString(of addressRange: IPAddressRange) -> String {
-        let n: UInt8 = addressRange.networkPrefixLength
-        assert(n <= 32)
+        let length: UInt8 = addressRange.networkPrefixLength
+        assert(length <= 32)
         var octets: [UInt8] = [0, 0, 0, 0]
-        let subnetMask: UInt32 = n > 0 ? ~UInt32(0) << (32 - n) : UInt32(0)
+        let subnetMask: UInt32 = length > 0 ? ~UInt32(0) << (32 - length) : UInt32(0)
         octets[0] = UInt8(truncatingIfNeeded: subnetMask >> 24)
         octets[1] = UInt8(truncatingIfNeeded: subnetMask >> 16)
         octets[2] = UInt8(truncatingIfNeeded: subnetMask >> 8)