Reuse code for macOS demo

This commit is contained in:
Davide De Rosa 2020-06-13 00:54:44 +02:00
parent ac46108454
commit eb9eb63658
1 changed files with 37 additions and 183 deletions

View File

@ -39,79 +39,9 @@ import Cocoa
import NetworkExtension import NetworkExtension
import TunnelKit import TunnelKit
private let ca = OpenVPN.CryptoContainer(pem: """ private let appGroup = "DTDYD63ZX9.group.com.algoritmico.macos.demo.BasicTunnel"
-----BEGIN CERTIFICATE-----
MIIFqzCCBJOgAwIBAgIJAKZ7D5Yv87qDMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNV
BAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIElu
dGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3Mx
IDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkB
FiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzM1
MThaFw0zNDA0MTIxNzM1MThaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
EzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQg
QWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UE
AxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50
ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVy
bmV0YWNjZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXD
L1L9tX6DGf36liA7UBTy5I869z0UVo3lImfOs/GSiFKPtInlesP65577nd7UNzzX
lH/P/CnFPdBWlLp5ze3HRBCc/Avgr5CdMRkEsySL5GHBZsx6w2cayQ2EcRhVTwWp
cdldeNO+pPr9rIgPrtXqT4SWViTQRBeGM8CDxAyTopTsobjSiYZCF9Ta1gunl0G/
8Vfp+SXfYCC+ZzWvP+L1pFhPRqzQQ8k+wMZIovObK1s+nlwPaLyayzw9a8sUnvWB
/5rGPdIYnQWPgoNlLN9HpSmsAcw2z8DXI9pIxbr74cb3/HSfuYGOLkRqrOk6h4RC
OfuWoTrZup1uEOn+fw8CAwEAAaOCAVQwggFQMB0GA1UdDgQWBBQv63nQ/pJAt5tL
y8VJcbHe22ZOsjCCAR8GA1UdIwSCARYwggESgBQv63nQ/pJAt5tLy8VJcbHe22ZO
sqGB7qSB6zCB6DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpM
b3NBbmdlbGVzMSAwHgYDVQQKExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4G
A1UECxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAMTF1ByaXZhdGUg
SW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQpExdQcml2YXRlIEludGVybmV0IEFjY2Vz
czEvMC0GCSqGSIb3DQEJARYgc2VjdXJlQHByaXZhdGVpbnRlcm5ldGFjY2Vzcy5j
b22CCQCmew+WL/O6gzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQAn
a5PgrtxfwTumD4+3/SYvwoD66cB8IcK//h1mCzAduU8KgUXocLx7QgJWo9lnZ8xU
ryXvWab2usg4fqk7FPi00bED4f4qVQFVfGfPZIH9QQ7/48bPM9RyfzImZWUCenK3
7pdw4Bvgoys2rHLHbGen7f28knT2j/cbMxd78tQc20TIObGjo8+ISTRclSTRBtyC
GohseKYpTS9himFERpUgNtefvYHbn70mIOzfOJFTVqfrptf9jXa9N8Mpy3ayfodz
1wiqdteqFXkTYoSDctgKMiZ6GdocK9nMroQipIQtpnwd4yBDWIyC6Bvlkrq5TQUt
YDQ8z9v+DMO6iwyIDRiU
-----END CERTIFICATE-----
""")
extension ViewController { private let tunnelIdentifier = "com.algoritmico.macos.demo.BasicTunnel.Extension"
private static let appGroup = "DTDYD63ZX9.group.com.algoritmico.macos.demo.BasicTunnel"
private static let tunnelIdentifier = "com.algoritmico.macos.demo.BasicTunnel.Extension"
private func makeProtocol() -> NETunnelProviderProtocol {
let server = textServer.stringValue
let domain = textDomain.stringValue
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
let port = UInt16(textPort.stringValue)!
let credentials = OpenVPN.Credentials(textUsername.stringValue, textPassword.stringValue)
var sessionBuilder = OpenVPN.ConfigurationBuilder()
sessionBuilder.ca = ca
sessionBuilder.cipher = .aes128cbc
sessionBuilder.digest = .sha1
sessionBuilder.compressionFraming = .compLZO
sessionBuilder.renegotiatesAfter = nil
sessionBuilder.hostname = hostname
// let socketType: SocketType = isTCP ? .tcp : .udp
let socketType: SocketType = .udp
sessionBuilder.endpointProtocols = [EndpointProtocol(socketType, port)]
sessionBuilder.usesPIAPatches = true
var builder = OpenVPNTunnelProvider.ConfigurationBuilder(sessionConfiguration: sessionBuilder.build())
builder.mtu = 1350
builder.shouldDebug = true
builder.masksPrivateData = false
let configuration = builder.build()
return try! configuration.generatedTunnelProtocol(
withBundleIdentifier: ViewController.tunnelIdentifier,
appGroup: ViewController.appGroup,
credentials: credentials
)
}
}
class ViewController: NSViewController { class ViewController: NSViewController {
@IBOutlet var textUsername: NSTextField! @IBOutlet var textUsername: NSTextField!
@ -126,18 +56,18 @@ class ViewController: NSViewController {
@IBOutlet var buttonConnection: NSButton! @IBOutlet var buttonConnection: NSButton!
var currentManager: NETunnelProviderManager? //
var status = NEVPNStatus.invalid
let vpn = StandardVPNProvider(bundleIdentifier: tunnelIdentifier)
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
textServer.stringValue = "germany" textServer.stringValue = "es"
textDomain.stringValue = "privateinternetaccess.com" textDomain.stringValue = "lazerpenguin.com"
textPort.stringValue = "1198" textPort.stringValue = "443"
textUsername.stringValue = "myusername" textUsername.stringValue = ""
textPassword.stringValue = "mypassword" textPassword.stringValue = ""
NotificationCenter.default.addObserver( NotificationCenter.default.addObserver(
self, self,
@ -146,7 +76,7 @@ class ViewController: NSViewController {
object: nil object: nil
) )
reloadCurrentManager(nil) vpn.prepare(completionHandler: nil)
// //
@ -154,111 +84,43 @@ class ViewController: NSViewController {
} }
@IBAction func connectionClicked(_ sender: Any) { @IBAction func connectionClicked(_ sender: Any) {
let block = { switch vpn.status {
switch (self.status) { case .disconnected:
case .invalid, .disconnected: connect()
self.connect()
case .connected, .connecting, .disconnecting:
case .connected, .connecting: disconnect()
self.disconnect()
default:
break
}
}
if (status == .invalid) {
reloadCurrentManager({ (error) in
block()
})
}
else {
block()
} }
} }
func connect() { func connect() {
configureVPN({ (manager) in let server = textServer.stringValue
return self.makeProtocol() let domain = textDomain.stringValue
}, completionHandler: { (error) in let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
let port = UInt16(textPort.stringValue)!
let credentials = OpenVPN.Credentials(textUsername.stringValue, textPassword.stringValue)
let cfg = Configuration.make(hostname: hostname, port: port, socketType: .udp)
let proto = try! cfg.generatedTunnelProtocol(
withBundleIdentifier: tunnelIdentifier,
appGroup: appGroup,
credentials: credentials
)
let neCfg = NetworkExtensionVPNConfiguration(protocolConfiguration: proto, onDemandRules: [])
vpn.reconnect(configuration: neCfg) { (error) in
if let error = error { if let error = error {
print("configure error: \(error)") print("configure error: \(error)")
return return
} }
let session = self.currentManager?.connection as! NETunnelProviderSession }
do {
try session.startTunnel()
} catch let e {
print("error starting tunnel: \(e)")
}
})
} }
func disconnect() { func disconnect() {
configureVPN({ (manager) in vpn.disconnect(completionHandler: nil)
return nil
}, completionHandler: { (error) in
self.currentManager?.connection.stopVPNTunnel()
})
} }
func configureVPN(_ configure: @escaping (NETunnelProviderManager) -> NETunnelProviderProtocol?, completionHandler: @escaping (Error?) -> Void) {
reloadCurrentManager { (error) in
if let error = error {
print("error reloading preferences: \(error)")
completionHandler(error)
return
}
let manager = self.currentManager!
if let protocolConfiguration = configure(manager) {
manager.protocolConfiguration = protocolConfiguration
}
manager.isEnabled = true
manager.saveToPreferences { (error) in
if let error = error {
print("error saving preferences: \(error)")
completionHandler(error)
return
}
print("saved preferences")
self.reloadCurrentManager(completionHandler)
}
}
}
func reloadCurrentManager(_ completionHandler: ((Error?) -> Void)?) {
NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
if let error = error {
completionHandler?(error)
return
}
var manager: NETunnelProviderManager?
for m in managers! {
if let p = m.protocolConfiguration as? NETunnelProviderProtocol {
if (p.providerBundleIdentifier == ViewController.tunnelIdentifier) {
manager = m
break
}
}
}
if (manager == nil) {
manager = NETunnelProviderManager()
}
self.currentManager = manager
self.status = manager!.connection.status
self.updateButton()
completionHandler?(nil)
}
}
func updateButton() { func updateButton() {
switch status { switch vpn.status {
case .connected, .connecting: case .connected, .connecting:
buttonConnection.title = "Disconnect" buttonConnection.title = "Disconnect"
@ -267,22 +129,14 @@ class ViewController: NSViewController {
case .disconnecting: case .disconnecting:
buttonConnection.title = "Disconnecting" buttonConnection.title = "Disconnecting"
default:
break
} }
} }
@objc private func VPNStatusDidChange(notification: NSNotification) { @objc private func VPNStatusDidChange(notification: NSNotification) {
guard let status = currentManager?.connection.status else { print("VPNStatusDidChange: \(vpn.status)")
print("VPNStatusDidChange")
return
}
print("VPNStatusDidChange: \(status.rawValue)")
self.status = status
updateButton() updateButton()
} }
private func testFetchRef() { private func testFetchRef() {
// let keychain = Keychain(group: ViewController.APP_GROUP) // let keychain = Keychain(group: ViewController.APP_GROUP)
// let username = "foo" // let username = "foo"