Reuse code for macOS demo
This commit is contained in:
parent
ac46108454
commit
eb9eb63658
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue