Reuse code for macOS demo
This commit is contained in:
parent
ac46108454
commit
eb9eb63658
|
@ -39,79 +39,9 @@ import Cocoa
|
|||
import NetworkExtension
|
||||
import TunnelKit
|
||||
|
||||
private let ca = OpenVPN.CryptoContainer(pem: """
|
||||
-----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-----
|
||||
""")
|
||||
private let appGroup = "DTDYD63ZX9.group.com.algoritmico.macos.demo.BasicTunnel"
|
||||
|
||||
extension ViewController {
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
private let tunnelIdentifier = "com.algoritmico.macos.demo.BasicTunnel.Extension"
|
||||
|
||||
class ViewController: NSViewController {
|
||||
@IBOutlet var textUsername: NSTextField!
|
||||
|
@ -126,18 +56,18 @@ class ViewController: NSViewController {
|
|||
|
||||
@IBOutlet var buttonConnection: NSButton!
|
||||
|
||||
var currentManager: NETunnelProviderManager?
|
||||
|
||||
var status = NEVPNStatus.invalid
|
||||
//
|
||||
|
||||
let vpn = StandardVPNProvider(bundleIdentifier: tunnelIdentifier)
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
textServer.stringValue = "germany"
|
||||
textDomain.stringValue = "privateinternetaccess.com"
|
||||
textPort.stringValue = "1198"
|
||||
textUsername.stringValue = "myusername"
|
||||
textPassword.stringValue = "mypassword"
|
||||
textServer.stringValue = "es"
|
||||
textDomain.stringValue = "lazerpenguin.com"
|
||||
textPort.stringValue = "443"
|
||||
textUsername.stringValue = ""
|
||||
textPassword.stringValue = ""
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
|
@ -146,7 +76,7 @@ class ViewController: NSViewController {
|
|||
object: nil
|
||||
)
|
||||
|
||||
reloadCurrentManager(nil)
|
||||
vpn.prepare(completionHandler: nil)
|
||||
|
||||
//
|
||||
|
||||
|
@ -154,111 +84,43 @@ class ViewController: NSViewController {
|
|||
}
|
||||
|
||||
@IBAction func connectionClicked(_ sender: Any) {
|
||||
let block = {
|
||||
switch (self.status) {
|
||||
case .invalid, .disconnected:
|
||||
self.connect()
|
||||
|
||||
case .connected, .connecting:
|
||||
self.disconnect()
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (status == .invalid) {
|
||||
reloadCurrentManager({ (error) in
|
||||
block()
|
||||
})
|
||||
}
|
||||
else {
|
||||
block()
|
||||
switch vpn.status {
|
||||
case .disconnected:
|
||||
connect()
|
||||
|
||||
case .connected, .connecting, .disconnecting:
|
||||
disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
func connect() {
|
||||
configureVPN({ (manager) in
|
||||
return self.makeProtocol()
|
||||
}, completionHandler: { (error) in
|
||||
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)
|
||||
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 {
|
||||
print("configure error: \(error)")
|
||||
return
|
||||
}
|
||||
let session = self.currentManager?.connection as! NETunnelProviderSession
|
||||
do {
|
||||
try session.startTunnel()
|
||||
} catch let e {
|
||||
print("error starting tunnel: \(e)")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func disconnect() {
|
||||
configureVPN({ (manager) in
|
||||
return nil
|
||||
}, completionHandler: { (error) in
|
||||
self.currentManager?.connection.stopVPNTunnel()
|
||||
})
|
||||
vpn.disconnect(completionHandler: nil)
|
||||
}
|
||||
|
||||
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() {
|
||||
switch status {
|
||||
switch vpn.status {
|
||||
case .connected, .connecting:
|
||||
buttonConnection.title = "Disconnect"
|
||||
|
||||
|
@ -267,22 +129,14 @@ class ViewController: NSViewController {
|
|||
|
||||
case .disconnecting:
|
||||
buttonConnection.title = "Disconnecting"
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func VPNStatusDidChange(notification: NSNotification) {
|
||||
guard let status = currentManager?.connection.status else {
|
||||
print("VPNStatusDidChange")
|
||||
return
|
||||
}
|
||||
print("VPNStatusDidChange: \(status.rawValue)")
|
||||
self.status = status
|
||||
print("VPNStatusDidChange: \(vpn.status)")
|
||||
updateButton()
|
||||
}
|
||||
|
||||
|
||||
private func testFetchRef() {
|
||||
// let keychain = Keychain(group: ViewController.APP_GROUP)
|
||||
// let username = "foo"
|
||||
|
|
Loading…
Reference in New Issue