2018-09-15 19:24:52 +00:00
|
|
|
//
|
|
|
|
// Copyright © 2018 WireGuard LLC. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
import CoreData
|
2018-09-29 20:29:34 +00:00
|
|
|
import NetworkExtension
|
|
|
|
|
2018-09-15 19:24:52 +00:00
|
|
|
import BNRCoreDataStack
|
|
|
|
import PromiseKit
|
|
|
|
|
|
|
|
protocol TunnelInfoTableViewControllerDelegate: class {
|
2018-09-29 20:29:34 +00:00
|
|
|
func connect(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController)
|
|
|
|
func disconnect(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController)
|
2018-09-15 19:24:52 +00:00
|
|
|
func configure(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController)
|
2018-09-18 19:47:43 +00:00
|
|
|
func showSettings()
|
2018-09-29 20:29:34 +00:00
|
|
|
func status(for tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) -> NEVPNStatus
|
2018-09-15 19:24:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class TunnelInfoTableViewController: UITableViewController {
|
|
|
|
|
|
|
|
@IBOutlet weak var editButton: UIBarButtonItem!
|
|
|
|
|
|
|
|
private var viewContext: NSManagedObjectContext!
|
|
|
|
private weak var delegate: TunnelInfoTableViewControllerDelegate?
|
|
|
|
private var tunnel: Tunnel!
|
|
|
|
|
|
|
|
func configure(context: NSManagedObjectContext, delegate: TunnelInfoTableViewControllerDelegate? = nil, tunnel: Tunnel) {
|
|
|
|
viewContext = context
|
|
|
|
self.delegate = delegate
|
|
|
|
self.tunnel = tunnel
|
|
|
|
}
|
|
|
|
|
2018-09-19 22:43:57 +00:00
|
|
|
override func viewDidLoad() {
|
|
|
|
super.viewDidLoad()
|
|
|
|
|
|
|
|
// Get rid of seperator lines in table.
|
|
|
|
tableView.tableFooterView = UIView(frame: CGRect.zero)
|
2018-09-29 20:29:34 +00:00
|
|
|
|
|
|
|
NotificationCenter.default.addObserver(self,
|
|
|
|
selector: #selector(VPNStatusDidChange(notification:)),
|
|
|
|
name: .NEVPNStatusDidChange,
|
|
|
|
object: nil)
|
2018-09-19 22:43:57 +00:00
|
|
|
}
|
|
|
|
|
2018-09-15 19:24:52 +00:00
|
|
|
override func viewWillAppear(_ animated: Bool) {
|
|
|
|
super .viewWillAppear(animated)
|
|
|
|
|
|
|
|
self.tableView.reloadData()
|
|
|
|
}
|
|
|
|
|
|
|
|
override func numberOfSections(in tableView: UITableView) -> Int {
|
2018-09-19 22:44:24 +00:00
|
|
|
return 2
|
2018-09-15 19:24:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
|
|
switch section {
|
|
|
|
case 1:
|
2018-09-19 22:44:24 +00:00
|
|
|
return tunnel?.peers?.count ?? 0
|
2018-09-15 19:24:52 +00:00
|
|
|
default:
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
|
|
switch indexPath.section {
|
|
|
|
case 0:
|
|
|
|
let cell = tableView.dequeueReusableCell(type: InterfaceInfoTableViewCell.self, for: indexPath)
|
2018-09-29 20:29:34 +00:00
|
|
|
cell.delegate = self
|
|
|
|
cell.configure(model: tunnel.interface, status: delegate?.status(for: tunnel, tunnelInfoTableViewController: self) ?? .invalid)
|
2018-09-15 19:24:52 +00:00
|
|
|
return cell
|
|
|
|
default:
|
|
|
|
let cell = tableView.dequeueReusableCell(type: PeerInfoTableViewCell.self, for: indexPath)
|
|
|
|
if let peer = tunnel.peers?.object(at: indexPath.row) as? Peer {
|
|
|
|
cell.peer = peer
|
|
|
|
} else {
|
|
|
|
let peer = Peer(context: tunnel.managedObjectContext!)
|
|
|
|
tunnel.addToPeers(peer)
|
|
|
|
cell.peer = peer
|
|
|
|
}
|
|
|
|
return cell
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-18 19:47:43 +00:00
|
|
|
@IBAction func showSettings(_ sender: Any) {
|
|
|
|
delegate?.showSettings()
|
|
|
|
}
|
|
|
|
|
2018-09-15 19:24:52 +00:00
|
|
|
@IBAction func editTunnelConfiguration(_ sender: Any) {
|
|
|
|
delegate?.configure(tunnel: self.tunnel, tunnelInfoTableViewController: self)
|
|
|
|
}
|
2018-09-29 20:29:34 +00:00
|
|
|
|
|
|
|
@objc private func VPNStatusDidChange(notification: NSNotification) {
|
|
|
|
guard let session = notification.object as? NETunnelProviderSession else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
guard let prot = session.manager.protocolConfiguration as? NETunnelProviderProtocol else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
guard let changedTunnelIdentifier = prot.providerConfiguration?[PCKeys.tunnelIdentifier.rawValue] as? String else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
guard tunnel.tunnelIdentifier == changedTunnelIdentifier else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
self.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .none)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension TunnelInfoTableViewController: InterfaceInfoTableViewCellDelegate {
|
|
|
|
func connect(tunnelIdentifier: String) {
|
|
|
|
delegate?.connect(tunnel: tunnel, tunnelInfoTableViewController: self)
|
|
|
|
}
|
|
|
|
|
|
|
|
func disconnect(tunnelIdentifier: String) {
|
|
|
|
delegate?.disconnect(tunnel: tunnel, tunnelInfoTableViewController: self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protocol InterfaceInfoTableViewCellDelegate: class {
|
|
|
|
func connect(tunnelIdentifier: String)
|
|
|
|
func disconnect(tunnelIdentifier: String)
|
2018-09-15 19:24:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class InterfaceInfoTableViewCell: UITableViewCell {
|
2018-09-29 20:29:34 +00:00
|
|
|
weak var delegate: InterfaceInfoTableViewCellDelegate?
|
|
|
|
private var model: Interface! {
|
2018-09-15 19:24:52 +00:00
|
|
|
didSet {
|
|
|
|
nameField.text = model.tunnel?.title
|
|
|
|
addressesField.text = model.addresses
|
2018-09-16 20:38:32 +00:00
|
|
|
publicKeyField.text = model.publicKey
|
2018-09-15 19:24:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-29 20:29:34 +00:00
|
|
|
func configure(model: Interface!, status: NEVPNStatus) {
|
|
|
|
self.model = model
|
|
|
|
|
|
|
|
if status == .connecting || status == .disconnecting || status == .reasserting {
|
|
|
|
activityIndicator.startAnimating()
|
|
|
|
tunnelSwitch.isHidden = true
|
|
|
|
} else {
|
|
|
|
activityIndicator.stopAnimating()
|
|
|
|
tunnelSwitch.isHidden = false
|
|
|
|
}
|
|
|
|
|
|
|
|
tunnelSwitch.isOn = status == .connected
|
|
|
|
tunnelSwitch.onTintColor = status == .invalid || status == .reasserting ? .gray : .green
|
|
|
|
tunnelSwitch.isEnabled = true
|
|
|
|
}
|
|
|
|
|
|
|
|
@IBAction func tunnelSwitchChanged(_ sender: Any) {
|
|
|
|
tunnelSwitch.isEnabled = false
|
|
|
|
|
|
|
|
guard let tunnelIdentifier = model.tunnel?.tunnelIdentifier else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if tunnelSwitch.isOn {
|
|
|
|
delegate?.connect(tunnelIdentifier: tunnelIdentifier)
|
|
|
|
} else {
|
|
|
|
delegate?.disconnect(tunnelIdentifier: tunnelIdentifier)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-15 19:24:52 +00:00
|
|
|
@IBOutlet weak var nameField: UILabel!
|
|
|
|
@IBOutlet weak var addressesField: UILabel!
|
2018-09-16 20:38:32 +00:00
|
|
|
@IBOutlet weak var publicKeyField: UILabel!
|
2018-09-29 20:29:34 +00:00
|
|
|
@IBOutlet weak var tunnelSwitch: UISwitch!
|
|
|
|
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
|
2018-09-16 20:38:32 +00:00
|
|
|
|
|
|
|
@IBAction func copyPublicKey(_ sender: Any) {
|
|
|
|
if let publicKey = model.publicKey {
|
|
|
|
UIPasteboard.general.string = publicKey
|
|
|
|
}
|
|
|
|
}
|
2018-09-15 19:24:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class PeerInfoTableViewCell: UITableViewCell {
|
|
|
|
var peer: Peer! {
|
|
|
|
didSet {
|
|
|
|
publicKeyField.text = peer.publicKey
|
|
|
|
allowedIpsField.text = peer.allowedIPs
|
|
|
|
endpointField.text = peer.endpoint
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@IBOutlet weak var publicKeyField: UILabel!
|
|
|
|
@IBOutlet weak var allowedIpsField: UILabel!
|
|
|
|
@IBOutlet weak var endpointField: UILabel!
|
2018-09-16 20:38:32 +00:00
|
|
|
|
|
|
|
@IBAction func copyPublicKey(_ sender: Any) {
|
|
|
|
if let publicKey = peer.publicKey {
|
|
|
|
UIPasteboard.general.string = publicKey
|
|
|
|
}
|
|
|
|
}
|
2018-09-15 19:24:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
extension TunnelInfoTableViewController: Identifyable {}
|
|
|
|
extension InterfaceInfoTableViewCell: Identifyable {}
|
|
|
|
extension PeerInfoTableViewCell: Identifyable {}
|