mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-04-24 00:00:05 +08:00
Merge branch 'feature/custom-factory' into feature/extended-configuration
* feature/custom-factory: (75 commits) Update configuration tests Update adapter tests Delete templates for enum elements Remove unnecessary link to sstream Update project configuration Call clock_tick method Reconnect vpn client Resume vpn client Pause vpn client Call handleLog only if delegate responds to selector Return core copyright Remove expiration class method and convert platform to class property Return expiration and platform Rename openvpn configuration file Return session token Remove "defined" property Return transport stats and interface stats Fix incorrect header Return connection info Change queue name ... # Conflicts: # OpenVPN Adapter Tests/OpenVPNAdapterTests.swift # OpenVPN Adapter Tests/Resources/free_openvpn_udp_us.ovpn # OpenVPN Adapter/OpenVPNAdapter.mm
This commit is contained in:
@@ -12,18 +12,10 @@ import NetworkExtension
|
||||
|
||||
class OpenVPNAdapterTests: XCTestCase {
|
||||
|
||||
enum ConfigurationType {
|
||||
case withoutCredentials, withCredentials
|
||||
}
|
||||
|
||||
enum ExpectationsType {
|
||||
case connection
|
||||
}
|
||||
|
||||
let configurations: [ConfigurationType : String] = [
|
||||
.withoutCredentials: "free_openvpn_udp_us"
|
||||
]
|
||||
|
||||
var expectations = [ExpectationsType : XCTestExpectation]()
|
||||
|
||||
override func setUp() {
|
||||
@@ -35,45 +27,86 @@ class OpenVPNAdapterTests: XCTestCase {
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
// Test connection without specifying username and password
|
||||
func testConectionWithoutCredentials() {
|
||||
let configuration = getVPNConfiguration(type: .withoutCredentials)
|
||||
|
||||
func testApplyConfiguration() {
|
||||
let adapter = OpenVPNAdapter()
|
||||
|
||||
let configuration = OpenVPNConfiguration()
|
||||
configuration.fileContent = ProfileLoader.getVPNProfile(type: .localVPNServer)
|
||||
configuration.settings = ["auth-user-pass": ""]
|
||||
|
||||
let result: OpenVPNProperties
|
||||
do {
|
||||
try adapter.configure(using: configuration)
|
||||
result = try adapter.apply(configuration: configuration)
|
||||
} catch {
|
||||
XCTFail("Failed to configure OpenVPN adapted due to error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
expectations[.connection] = expectation(description: "me.ss-abramchuk.openvpn-adapter.connection-w/o-credentials")
|
||||
XCTAssert(result.remoteHost == "192.168.1.200")
|
||||
XCTAssert(result.remotePort == 1194)
|
||||
XCTAssert(result.remoteProto == .UDP)
|
||||
XCTAssert(result.autologin == false)
|
||||
}
|
||||
|
||||
func testProvideCredentials() {
|
||||
let adapter = OpenVPNAdapter()
|
||||
|
||||
let credentials = OpenVPNCredentials()
|
||||
credentials.username = "username"
|
||||
credentials.password = "password"
|
||||
|
||||
do {
|
||||
try adapter.provide(credentials: credentials)
|
||||
} catch {
|
||||
XCTFail("Failed to provide credentials. \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Test connection without specifying username and password
|
||||
func testConection() {
|
||||
let adapter = OpenVPNAdapter()
|
||||
|
||||
let configuration = OpenVPNConfiguration()
|
||||
configuration.fileContent = ProfileLoader.getVPNProfile(type: .localVPNServer)
|
||||
configuration.settings = ["auth-user-pass": ""]
|
||||
|
||||
let result: OpenVPNProperties
|
||||
do {
|
||||
result = try adapter.apply(configuration: configuration)
|
||||
} catch {
|
||||
XCTFail("Failed to configure OpenVPN adapted due to error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
guard !result.autologin else {
|
||||
XCTFail()
|
||||
return
|
||||
}
|
||||
|
||||
let credentials = OpenVPNCredentials()
|
||||
credentials.username = "testuser"
|
||||
credentials.password = "nonsecure"
|
||||
|
||||
do {
|
||||
try adapter.provide(credentials: credentials)
|
||||
} catch {
|
||||
XCTFail("Failed to provide credentials. \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
expectations[.connection] = expectation(description: "me.ss-abramchuk.openvpn-adapter.connection")
|
||||
|
||||
adapter.delegate = self
|
||||
adapter.connect()
|
||||
|
||||
waitForExpectations(timeout: 10.0) { (error) in
|
||||
waitForExpectations(timeout: 30.0) { (error) in
|
||||
adapter.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension OpenVPNAdapterTests {
|
||||
|
||||
func getVPNConfiguration(type: ConfigurationType) -> Data {
|
||||
guard
|
||||
let fileName = configurations[type],
|
||||
let path = Bundle.current.url(forResource: fileName, withExtension: "ovpn"),
|
||||
let configuration = try? Data(contentsOf: path)
|
||||
else {
|
||||
fatalError("Failed to retrieve OpenVPN configuration")
|
||||
}
|
||||
|
||||
return configuration
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension OpenVPNAdapterTests: OpenVPNAdapterDelegate {
|
||||
|
||||
func configureTunnel(settings: NEPacketTunnelNetworkSettings, callback: @escaping (OpenVPNAdapterPacketFlow?) -> Void) {
|
||||
@@ -95,7 +128,10 @@ extension OpenVPNAdapterTests: OpenVPNAdapterDelegate {
|
||||
}
|
||||
|
||||
func handle(error: Error) {
|
||||
|
||||
if let connectionExpectation = expectations[.connection] {
|
||||
XCTFail("Failed to establish conection. \(error.localizedDescription)")
|
||||
connectionExpectation.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
func handle(logMessage: String) {
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// OpenVPNConfigurationTests.swift
|
||||
// OpenVPN Adapter
|
||||
//
|
||||
// Created by Sergey Abramchuk on 21.04.17.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import OpenVPNAdapter
|
||||
|
||||
// TODO: Test getting/setting of all properties of OpenVPNConfiguration
|
||||
|
||||
class OpenVPNConfigurationTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testGetSetProfile() {
|
||||
let originalProfile = ProfileLoader.getVPNProfile(type: .localVPNServer)
|
||||
|
||||
let configuration = OpenVPNConfiguration()
|
||||
|
||||
guard configuration.fileContent == nil else {
|
||||
XCTFail("Empty file content should return nil")
|
||||
return
|
||||
}
|
||||
|
||||
configuration.fileContent = originalProfile
|
||||
|
||||
guard let returnedProfile = configuration.fileContent else {
|
||||
XCTFail("Returned file content should not be nil")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssert(originalProfile.elementsEqual(returnedProfile))
|
||||
|
||||
configuration.fileContent = nil
|
||||
XCTAssert(configuration.fileContent == nil, "Empty file content should return nil")
|
||||
|
||||
configuration.fileContent = Data()
|
||||
XCTAssert(configuration.fileContent == nil, "Empty file content should return nil")
|
||||
}
|
||||
|
||||
func testGetSetSettings() {
|
||||
let originalSettings = [
|
||||
"client": "",
|
||||
"dev": "tun",
|
||||
"remote-cert-tls" : "server"
|
||||
]
|
||||
|
||||
let configuration = OpenVPNConfiguration()
|
||||
|
||||
guard configuration.settings == nil else {
|
||||
XCTFail("Empty settings should return nil")
|
||||
return
|
||||
}
|
||||
|
||||
configuration.settings = originalSettings
|
||||
|
||||
guard let returnedSettings = configuration.settings else {
|
||||
XCTFail("Returned settings should not be nil")
|
||||
return
|
||||
}
|
||||
|
||||
let equals = originalSettings.elementsEqual(returnedSettings) { (first, second) -> Bool in
|
||||
first.key == second.key && first.value == second.value
|
||||
}
|
||||
XCTAssert(equals)
|
||||
|
||||
configuration.settings = [:]
|
||||
XCTAssert(configuration.settings == nil, "Empty settings should return nil")
|
||||
|
||||
configuration.settings = nil
|
||||
XCTAssert(configuration.settings == nil, "Empty settings should return nil")
|
||||
}
|
||||
|
||||
func testGetSetProto() {
|
||||
let originalOption: OpenVPNTransportProtocol = .UDP
|
||||
|
||||
let configuration = OpenVPNConfiguration()
|
||||
|
||||
guard configuration.proto == .default else {
|
||||
XCTFail("proto option should return default value")
|
||||
return
|
||||
}
|
||||
|
||||
configuration.proto = originalOption
|
||||
guard configuration.proto == originalOption else {
|
||||
XCTFail("proto option should be equal to original value (enabled)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testGetSetIPv6() {
|
||||
let originalOption: OpenVPNIPv6Preference = .enabled
|
||||
|
||||
let configuration = OpenVPNConfiguration()
|
||||
|
||||
guard configuration.ipv6 == .default else {
|
||||
XCTFail("IPv6 option should return default value")
|
||||
return
|
||||
}
|
||||
|
||||
configuration.ipv6 = originalOption
|
||||
guard configuration.ipv6 == originalOption else {
|
||||
XCTFail("IPv6 option should be equal to original value (enabled)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testGetSetTLSCertProfile() {
|
||||
let originalOption: OpenVPNTLSCertProfile = .preferred
|
||||
|
||||
let configuration = OpenVPNConfiguration()
|
||||
|
||||
guard configuration.tlsCertProfile == .default else {
|
||||
XCTFail("TLS Cert Profile option should return default value")
|
||||
return
|
||||
}
|
||||
|
||||
configuration.tlsCertProfile = originalOption
|
||||
guard configuration.tlsCertProfile == originalOption else {
|
||||
XCTFail("TLS Cert Profile option should be equal to original value (preferred)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// ProfileLoader.swift
|
||||
// OpenVPN Adapter
|
||||
//
|
||||
// Created by Sergey Abramchuk on 22.04.17.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ProfileType: String {
|
||||
case localVPNServer = "local_vpn_server"
|
||||
}
|
||||
|
||||
struct ProfileLoader {
|
||||
|
||||
static func getVPNProfile(type: ProfileType) -> Data {
|
||||
let fileName = type.rawValue
|
||||
|
||||
guard
|
||||
let path = Bundle.current.url(forResource: fileName, withExtension: "ovpn"),
|
||||
let profile = try? Data(contentsOf: path)
|
||||
else {
|
||||
fatalError("Failed to retrieve OpenVPN profile")
|
||||
}
|
||||
|
||||
return profile
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
dev tun
|
||||
proto udp
|
||||
remote 192.168.1.200 1194
|
||||
cipher AES-256-CBC
|
||||
resolv-retry infinite
|
||||
nobind
|
||||
persist-key
|
||||
persist-tun
|
||||
client
|
||||
verb 3
|
||||
<ca>
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDpjCCAo6gAwIBAgIBADANBgkqhkiG9w0BAQsFADBSMRUwEwYDVQQDEww5ZTQ3
|
||||
NThlOTVlZTIxFTATBgNVBAoTDDllNDc1OGU5NWVlMjEVMBMGA1UECxMMOWU0NzU4
|
||||
ZTk1ZWUyMQswCQYDVQQGEwJVUzAeFw0xNzA0MjgxODU3MjhaFw0zNzEyMzExODU3
|
||||
MjhaMFIxFTATBgNVBAMTDDllNDc1OGU5NWVlMjEVMBMGA1UEChMMOWU0NzU4ZTk1
|
||||
ZWUyMRUwEwYDVQQLEww5ZTQ3NThlOTVlZTIxCzAJBgNVBAYTAlVTMIIBIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3ecfScl3JGwRhbmHgIrNx7LItVyTX9V3
|
||||
CSZOjBOZymXIKt7/vNt9w6suebtK64/YCRAyPsUbvqUwYqfZhd6jngua/917LrnO
|
||||
SKHMrGtwDLfnxKY3WTPl1tI5GlrojgF2Z3wCgzRr/+KkFAk8Fq2iffJDRi2Iptqn
|
||||
5PlOosGfpA1fQKYsedKx7DAXbwTvXPbE/tJ0m8WfdiHIUkWWrNxAFOuctWLk+oBi
|
||||
vAmlb3/GSctXEIcVPHdF5AKU/GR5AjY1Qqde4LcMS+54YV+g/rpFYNUFsySNSvLQ
|
||||
Lxg3zZ79HAd9DMwYSt47MP9pih8dT2jdt7df6y+/RXq32B6SoqrYPwIDAQABo4GG
|
||||
MIGDMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgH2MGMGA1UdJQRcMFoGCCsG
|
||||
AQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDBQYI
|
||||
KwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcN
|
||||
AQELBQADggEBAKnWRxFiKPR7mhbH+JKg8uxu1ONe8TpBygMw6B0XM0WXFY0byTnK
|
||||
7IX1X1TzIeJNaeDiBKvrm8o4SJGXy8qC1DM+tFAlcRCwwBl5Yi89TcbLup0SSYnw
|
||||
QEJQ169+u1WNS6H14ED2p0Um8kslRXqSC04yLjImy3Sr4d52h1TQNjkpSGKggBbN
|
||||
L6YR29j8LX+3ls+Jx5e+allaw6v9Dft+jjsPEZE6KznhtQa6Zyw6Afk44yPLWjne
|
||||
ShcnY1Au3meaU98Q/S891i7o1tEFUKNBy+n4Qu3J/BnK77NPw1g7FJOcOD0JZIUq
|
||||
XtjqsiTviTpsUFcwp/Bl3BTXT0b6BwKi978=
|
||||
-----END CERTIFICATE-----
|
||||
</ca>
|
||||
<cert>
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID0DCCArigAwIBAgIBADANBgkqhkiG9w0BAQsFADBnMRwwGgYDVQQDExM2OTg1
|
||||
MzIwMzIwNzkwNTYyMDkzMRwwGgYDVQQKExM2OTg1MzIwMzIwNzkwNTYyMDkzMRww
|
||||
GgYDVQQLExM2OTg1MzIwMzIwNzkwNTYyMDkzMQswCQYDVQQGEwJVUzAeFw0xNzA0
|
||||
MjgxODU3MzFaFw0zNzEyMzExODU3MzFaMGcxHDAaBgNVBAMTEzY5ODUzMjAzMjA3
|
||||
OTA1NjIwOTMxHDAaBgNVBAoTEzY5ODUzMjAzMjA3OTA1NjIwOTMxHDAaBgNVBAsT
|
||||
EzY5ODUzMjAzMjA3OTA1NjIwOTMxCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAx9oRmlK91IFxB3WWjrRJkR8l4csle9EmrH+6r6US
|
||||
Utq/Ik9SctVZz7n8L5IrJc1/hpPvdSyD8uq3lI0U9/h0eDca5pKy0b9Oe4qS75wv
|
||||
JFkebg/5V2grRL9//125ux/2zytOPG3WIQF0p2NT4Y4OSOPG0RCdQRd2pZBS1sIu
|
||||
AMO+jRZGlrLxc+QyokR64wlkTHnv3dWJBUm8iuVaQpr5X22a5urCPk3H79zRPJuO
|
||||
1u74a0AaMRREzAp9F547VghvMWKxd6y38jOVteSQyB6E4c/T7rnO0MWk8GPO3JEj
|
||||
qNQ/9N0OE9kVWNuKVQf6UHV2cknyfHyg9Va0IgWvRoLt7QIDAQABo4GGMIGDMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgH2MGMGA1UdJQRcMFoGCCsGAQUFBwMB
|
||||
BggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDBQYIKwYBBQUH
|
||||
AwYGCCsGAQUFBwMHBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQELBQAD
|
||||
ggEBAFZZJLTP84lo46eZkaRfvXiv0qKO2FHHTSJtrHl7C6mR9ffZzp6nTd0EPB6T
|
||||
AkQZong8LqjcDmTk+3JGTHDSdy+5E6TkDTp1oiOoVApxRd13TIFmxpPslBczyHwt
|
||||
u5MrWNMMk+urGHK4tm/TBCm13AQAv20CQBsI+s+3pW3blcUpD7HbZvahZgNg978h
|
||||
g/y5hFtffBJbCEzJpYV9bvh7tyI0ndhyxB6ew93jfaGukDtIbpTjLTD1qvmnaGvW
|
||||
dEY8VmtmQ7gKuSMvfkW7ClN0XxTfDwkT8jxADF4P9RGHeUW2AUwMKw2dV2LbX933
|
||||
BNZuIgS6Lcaxso+R20VwQnefPvM=
|
||||
-----END CERTIFICATE-----
|
||||
</cert>
|
||||
<key>
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDH2hGaUr3UgXEH
|
||||
dZaOtEmRHyXhyyV70Sasf7qvpRJS2r8iT1Jy1VnPufwvkislzX+Gk+91LIPy6reU
|
||||
jRT3+HR4NxrmkrLRv057ipLvnC8kWR5uD/lXaCtEv3//Xbm7H/bPK048bdYhAXSn
|
||||
Y1Phjg5I48bREJ1BF3alkFLWwi4Aw76NFkaWsvFz5DKiRHrjCWRMee/d1YkFSbyK
|
||||
5VpCmvlfbZrm6sI+Tcfv3NE8m47W7vhrQBoxFETMCn0XnjtWCG8xYrF3rLfyM5W1
|
||||
5JDIHoThz9Puuc7QxaTwY87ckSOo1D/03Q4T2RVY24pVB/pQdXZySfJ8fKD1VrQi
|
||||
Ba9Ggu3tAgMBAAECggEAU6V8FKFo/pam3j5jI5tl5y2oR1cleytRCoXzdyyZ/L+9
|
||||
m/ijQ5j0nDL10FtXX90g8Qzd/qcBGx0OdUiPbDI7XU2DHtprqcpuaNrZIRy3xnje
|
||||
eaaJ8AGTipS0WAe8gwuf25n+huBZ7TqUvrKeGxu/8tYTEtHnX6UYbbd4VJa1dm+5
|
||||
16LfueOIricLu5JJ7TFLls4kFY6R//cFu6wzmlHwYvU7xsTQg8yWReojCifyvPqW
|
||||
yvF/MARb+1XWGCWKfT9B/A64uy8a4vqT52JHoG53t35luAjtHni65r+HDdiEf2Ph
|
||||
+gvpH/g0bOBBDFLQe5j1CdZr1PdzBNv9a1rxVVVgAQKBgQDoyKM9pTbNjmMPSb64
|
||||
3SsbBpF8M4JuIVg2qmu+xs25CoRKT+S6sMnnY/2uLzvYeUQWAQRPCqjL6jYWoLyZ
|
||||
AwDAl3uvAGG6LNuMqscSkDfO5hpr2y+fXRyh1+vTl9Fau3ZCSlCwJy/wBIfKbls9
|
||||
4Y0aLBlaS4AivMh9dSJe7e9MAQKBgQDbyJ+wcS8QcyRtOAZ7MQMRqsLjXRk6E2aY
|
||||
1a/WhLDfcsew56dh6F6VGE75DTvnOVmw19+HHj+bmmqbwU4Ook46E+BIWeonK6yZ
|
||||
8hBq6VFYutNaiid9MzV+90u1VYPT1C7/H28WkQ5F2obzSEdpQUs+z/Kb2wTRbgEx
|
||||
ECYTGe2R7QKBgF3Do21LRR3bQq9/xuDzxU8ngCaFIP53U+8BClFYBrmIMO017S39
|
||||
0/XuYtpskDCL+A7c7f1gj8lDV/IZYJ5JhV4OJnXBM5woQW8RwwoJKVGfgfj72tzY
|
||||
RpYyQP2D44ImjGX7RTEPN9H4ITI67Wmplop6ROQIEV7sp91Q9z1BnegBAoGAHMU3
|
||||
ej5mvc2E0DNMTeYNk8t5tY+jVMHjZVBbs0YtbSK2V0cL1zo232eONvXviIYuYoLv
|
||||
xN1F0FW3bOoyEKJYgSvG6VGz4CrMbl6MnaIrPuU985UwNCh28UboBzXJivo0qLrx
|
||||
rM+SQbyoe8JTbsjYU8Ge7Z4PFGdFCqolgcycF8UCgYBEVR50Ze1j8XK8oyySePqn
|
||||
YN1/CPQHkMv4Z9J511uDOw+rZpo8BtZX19jj4MWpFtcR7EAj4OyCe8gdn7YRv/n9
|
||||
Hw+zm4o54mkL4tgWg0/9jt0eCR3j3Ph03mTlkqwE/PPXaRIb1E8EmEYSwT0hDzjc
|
||||
Wb3dqIAxzkHucnvInG+TEw==
|
||||
-----END PRIVATE KEY-----
|
||||
</key>
|
||||
Reference in New Issue
Block a user