Skip to content

Instantly share code, notes, and snippets.

@sz-ashik440
Created September 24, 2020 12:07
Show Gist options
  • Save sz-ashik440/8405c5820898fc74c2ea417531807b89 to your computer and use it in GitHub Desktop.
Save sz-ashik440/8405c5820898fc74c2ea417531807b89 to your computer and use it in GitHub Desktop.
class VPNManager {
static var shared = VPNManager()
private init() { }
private var manager: NEVPNManager {
return NEVPNManager.shared()
}
fileprivate func loadPreferances(_ completion: @escaping () -> Void) {
manager.loadFromPreferences { error in
assert(error == nil, "Failed to load preferences: \(error!.localizedDescription)")
completion()
}
}
fileprivate func _save(_ vpn: VPN, completion: VPNConfigureCompletion?) {
#if targetEnvironment(simulator)
assert(false, "I'm afraid you can not connect VPN in simulators.")
#endif
let ipsec = NEVPNProtocolIPSec()
ipsec.useExtendedAuthentication = true
// ipsec.localIdentifier = "VPN"
// ipsec.remoteIdentifier = vpn.serverIP
ipsec.authenticationMethod = .sharedSecret
ipsec.sharedSecretReference = KeychainHelper.getVPNPSK(for: vpn.serverIP)
ipsec.username = vpn.username
ipsec.passwordReference = KeychainHelper.getVPNPassword(for: vpn.serverIP)
ipsec.serverAddress = vpn.serverIP
ipsec.disconnectOnSleep = false
manager.localizedDescription = "VPN"
manager.protocolConfiguration = ipsec
manager.isEnabled = true
manager.onDemandRules = [NEOnDemandRule]()
manager.isOnDemandEnabled = false
manager.saveToPreferences { error in
if let err = error {
print("Failed to save profile: \(err.localizedDescription)")
} else {
completion?()
}
}
}
public func save(_ vpn: VPN, completion: VPNConfigureCompletion?) {
loadPreferances { [weak self] in
self?._save(vpn, completion: completion)
}
}
public func connect() {
do {
try self.manager.connection.startVPNTunnel()
} catch NEVPNError.configurationInvalid {
} catch NEVPNError.configurationDisabled {
} catch let error as NSError {
print(error.localizedDescription)
}
}
public func saveAndConnect(vpn: VPN, complition: @escaping ()->()) {
KeychainHelper.setVPN(password: vpn.password, for: vpn.serverIP)
KeychainHelper.setVPN(psk: vpn.serverPSK, for: vpn.serverIP)
save(vpn) { [weak self] in
self?.connect()
DispatchQueue.main.async {
complition()
}
}
}
public func disconnect(complition: @escaping () -> ()) {
manager.connection.stopVPNTunnel()
complition()
}
}
@sz-ashik440
Copy link
Author

KeychainHelper.swift

import KeychainAccess

struct KeychainHelper {
    
    private static var keychain: Keychain {
        return Keychain(service: Bundle.main.bundleIdentifier ?? "BundleIDDummy")
    }
        
    public static func setVPN(password: String, for address: String) {
        _ = try? keychain.remove("\(address)pass")
        keychain["\(address)pass"] = password
    }
    
    public static func getVPNPassword(for address: String) -> Data? {
        return keychain[attributes: "\(address)pass"]?.persistentRef
    }
    
    public static func setVPN(psk: String, for address: String) {
        _ = try? keychain.remove("\(address)psk")
        keychain["\(address)psk"] = psk
    }
    
    public static func getVPNPSK(for address: String) -> Data? {
        return keychain[attributes: "\(address)psk"]?.persistentRef
    }
    
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment