wireguard-apple/WireGuard/ViewControllers/TunnelInfoTableViewControll...

195 lines
6.4 KiB
Swift

//
// Copyright © 2018 WireGuard LLC. All rights reserved.
//
import UIKit
import CoreData
import NetworkExtension
import BNRCoreDataStack
import PromiseKit
protocol TunnelInfoTableViewControllerDelegate: class {
func connect(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController)
func disconnect(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController)
func configure(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController)
func showSettings()
func status(for tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) -> NEVPNStatus
}
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
}
override func viewDidLoad() {
super.viewDidLoad()
// Get rid of seperator lines in table.
tableView.tableFooterView = UIView(frame: CGRect.zero)
NotificationCenter.default.addObserver(self,
selector: #selector(VPNStatusDidChange(notification:)),
name: .NEVPNStatusDidChange,
object: nil)
}
override func viewWillAppear(_ animated: Bool) {
super .viewWillAppear(animated)
self.tableView.reloadData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 1:
return tunnel?.peers?.count ?? 0
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)
cell.delegate = self
cell.configure(model: tunnel.interface, status: delegate?.status(for: tunnel, tunnelInfoTableViewController: self) ?? .invalid)
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
}
}
@IBAction func showSettings(_ sender: Any) {
delegate?.showSettings()
}
@IBAction func editTunnelConfiguration(_ sender: Any) {
delegate?.configure(tunnel: self.tunnel, tunnelInfoTableViewController: self)
}
@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)
}
class InterfaceInfoTableViewCell: UITableViewCell {
weak var delegate: InterfaceInfoTableViewCellDelegate?
private var model: Interface! {
didSet {
nameField.text = model.tunnel?.title
addressesField.text = model.addresses
publicKeyField.text = model.publicKey
}
}
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)
}
}
@IBOutlet weak var nameField: UILabel!
@IBOutlet weak var addressesField: UILabel!
@IBOutlet weak var publicKeyField: CopyableLabel!
@IBOutlet weak var tunnelSwitch: UISwitch!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
}
class PeerInfoTableViewCell: UITableViewCell {
var peer: Peer! {
didSet {
publicKeyField.text = peer.publicKey
allowedIpsField.text = peer.allowedIPs
endpointField.text = peer.endpoint
}
}
@IBOutlet weak var publicKeyField: CopyableLabel!
@IBOutlet weak var allowedIpsField: UILabel!
@IBOutlet weak var endpointField: UILabel!
@IBOutlet weak var copiedStatusLabel: UILabel!
}
extension TunnelInfoTableViewController: Identifyable {}
extension InterfaceInfoTableViewCell: Identifyable {}
extension PeerInfoTableViewCell: Identifyable {}