Merge pull request #194 from passepartoutvpn/refactor-provider-configuration
Refactor internal provider configuration
This commit is contained in:
commit
1bf6c9084a
|
@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Changed
|
||||
|
||||
- Encoding of internal provider configuration.
|
||||
|
||||
## 3.1.0 (2020-12-28)
|
||||
|
||||
### Added
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
PODS:
|
||||
- OpenSSL-Apple (1.1.1h.8)
|
||||
- OpenSSL-Apple (1.1.1h.10)
|
||||
- SwiftyBeaver (1.9.3)
|
||||
- TunnelKit (3.1.0):
|
||||
- TunnelKit/Protocols/OpenVPN (= 3.1.0)
|
||||
- TunnelKit/AppExtension (3.1.0):
|
||||
- TunnelKit (3.2.0):
|
||||
- TunnelKit/Protocols/OpenVPN (= 3.2.0)
|
||||
- TunnelKit/AppExtension (3.2.0):
|
||||
- SwiftyBeaver
|
||||
- TunnelKit/Core
|
||||
- TunnelKit/Core (3.1.0):
|
||||
- TunnelKit/Core (3.2.0):
|
||||
- SwiftyBeaver
|
||||
- TunnelKit/Manager (3.1.0):
|
||||
- TunnelKit/Manager (3.2.0):
|
||||
- SwiftyBeaver
|
||||
- TunnelKit/Protocols/OpenVPN (3.1.0):
|
||||
- OpenSSL-Apple (~> 1.1.1h.8)
|
||||
- TunnelKit/Protocols/OpenVPN (3.2.0):
|
||||
- OpenSSL-Apple (~> 1.1.1h.10)
|
||||
- TunnelKit/AppExtension
|
||||
- TunnelKit/Core
|
||||
- TunnelKit/Manager
|
||||
|
@ -30,9 +30,9 @@ EXTERNAL SOURCES:
|
|||
:path: ".."
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
OpenSSL-Apple: 70990157548ecf94885310231aff52db698e1077
|
||||
OpenSSL-Apple: 8a8fcb06fb66f9c2f7aed45ce363668493b8e5f6
|
||||
SwiftyBeaver: 2e8acd6fc90c6d0a27055867a290794926d57c02
|
||||
TunnelKit: 4db9180956f8aaf4ab152fd0d38c6c9c63a46cf8
|
||||
TunnelKit: b9ea352cbcce641f98687109c2e7d8cb1fa40e19
|
||||
|
||||
PODFILE CHECKSUM: 518aaea9a529c96ba3024918bc0850dd6e92ac61
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# TunnelKit
|
||||
|
||||
![iOS 12+](https://img.shields.io/badge/ios-12+-green.svg)
|
||||
![macOS 10.15+](https://img.shields.io/badge/macos-10.15+-green.svg)
|
||||
[![OpenSSL 1.1.1h](https://img.shields.io/badge/openssl-1.1.1h-d69c68.svg)](https://www.openssl.org/news/openssl-1.1.1-notes.html)
|
||||
[![License GPLv3](https://img.shields.io/badge/license-GPLv3-lightgray.svg)](LICENSE)
|
||||
[![Travis-CI](https://api.travis-ci.org/passepartoutvpn/tunnelkit.svg?branch=master)](https://travis-ci.org/passepartoutvpn/tunnelkit)
|
||||
|
@ -52,8 +53,8 @@ Unsupported:
|
|||
|
||||
Ignored:
|
||||
|
||||
- MTU overrides
|
||||
- `--*-mtu` and variants
|
||||
- Some MTU overrides
|
||||
- `--link-mtu` and variants
|
||||
- `--mssfix`
|
||||
- Multiple `--remote` with different `host` values (first wins)
|
||||
- Static client-side routes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = "TunnelKit"
|
||||
s.version = "3.1.0"
|
||||
s.version = "3.2.0"
|
||||
s.summary = "Non-official OpenVPN client for Apple platforms."
|
||||
|
||||
s.homepage = "https://github.com/passepartoutvpn/tunnelkit"
|
||||
|
|
|
@ -750,12 +750,12 @@
|
|||
0E23B3F722982AF800304C30 /* AppExtension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0E23B3F822982AF800304C30 /* OpenVPNTunnelProvider+Interaction.swift */,
|
||||
0E23B3F922982AF800304C30 /* NEUDPLink.swift */,
|
||||
0E23B3FA22982AF800304C30 /* ConnectionStrategy.swift */,
|
||||
0E23B3FB22982AF800304C30 /* OpenVPNTunnelProvider+Configuration.swift */,
|
||||
0E23B3FC22982AF800304C30 /* NETCPLink.swift */,
|
||||
0E23B3F922982AF800304C30 /* NEUDPLink.swift */,
|
||||
0E23B3FD22982AF800304C30 /* OpenVPNTunnelProvider.swift */,
|
||||
0E23B3FB22982AF800304C30 /* OpenVPNTunnelProvider+Configuration.swift */,
|
||||
0E23B3F822982AF800304C30 /* OpenVPNTunnelProvider+Interaction.swift */,
|
||||
);
|
||||
path = AppExtension;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1781,7 +1781,7 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 766;
|
||||
CURRENT_PROJECT_VERSION = 825;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
|
@ -1846,7 +1846,7 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 766;
|
||||
CURRENT_PROJECT_VERSION = 825;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
|
@ -1879,7 +1879,7 @@
|
|||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 766;
|
||||
DYLIB_CURRENT_VERSION = 825;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = "$(SRCROOT)/TunnelKit-iOS/Info.plist";
|
||||
|
@ -1904,7 +1904,7 @@
|
|||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 766;
|
||||
DYLIB_CURRENT_VERSION = 825;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = "$(SRCROOT)/TunnelKit-iOS/Info.plist";
|
||||
|
@ -1929,7 +1929,7 @@
|
|||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 766;
|
||||
DYLIB_CURRENT_VERSION = 825;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_VERSION = A;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/TunnelKit-macOS/Info.plist";
|
||||
|
@ -1953,7 +1953,7 @@
|
|||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 766;
|
||||
DYLIB_CURRENT_VERSION = 825;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_VERSION = A;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/TunnelKit-macOS/Info.plist";
|
||||
|
|
|
@ -42,3 +42,20 @@ public extension DispatchQueue {
|
|||
asyncAfter(deadline: .now() + after, execute: block)
|
||||
}
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
func fromDictionary<T: Decodable>(_ type: T.Type, _ dictionary: [String: Any]) throws -> T {
|
||||
let data = try JSONSerialization.data(withJSONObject: dictionary, options: .fragmentsAllowed)
|
||||
return try JSONDecoder().decode(T.self, from: data)
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
public extension Encodable {
|
||||
func asDictionary() throws -> [String: Any] {
|
||||
let data = try JSONEncoder().encode(self)
|
||||
guard let dictionary = try JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed) as? [String: Any] else {
|
||||
fatalError("JSONSerialization failed to encode")
|
||||
}
|
||||
return dictionary
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ import SwiftyBeaver
|
|||
private let log = SwiftyBeaver.self
|
||||
|
||||
extension OpenVPNTunnelProvider {
|
||||
private struct ExtraKeys {
|
||||
static let appGroup = "appGroup"
|
||||
}
|
||||
|
||||
// MARK: Configuration
|
||||
|
||||
|
@ -100,24 +103,6 @@ extension OpenVPNTunnelProvider {
|
|||
versionIdentifier = ConfigurationBuilder.defaults.versionIdentifier
|
||||
}
|
||||
|
||||
fileprivate init(providerConfiguration: [String: Any]) throws {
|
||||
let S = Configuration.Keys.self
|
||||
|
||||
sessionConfiguration = try OpenVPN.Configuration.with(providerConfiguration: providerConfiguration)
|
||||
prefersResolvedAddresses = providerConfiguration[S.prefersResolvedAddresses] as? Bool ?? ConfigurationBuilder.defaults.prefersResolvedAddresses
|
||||
resolvedAddresses = providerConfiguration[S.resolvedAddresses] as? [String]
|
||||
shouldDebug = providerConfiguration[S.debug] as? Bool ?? ConfigurationBuilder.defaults.shouldDebug
|
||||
if shouldDebug {
|
||||
debugLogFormat = providerConfiguration[S.debugLogFormat] as? String
|
||||
}
|
||||
masksPrivateData = providerConfiguration[S.masksPrivateData] as? Bool ?? ConfigurationBuilder.defaults.masksPrivateData
|
||||
versionIdentifier = providerConfiguration[S.versionIdentifier] as? String ?? ConfigurationBuilder.defaults.versionIdentifier
|
||||
|
||||
guard !prefersResolvedAddresses || !(resolvedAddresses?.isEmpty ?? true) else {
|
||||
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(S.prefersResolvedAddresses)] is true but no [\(S.resolvedAddresses)]")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Builds a `OpenVPNTunnelProvider.Configuration` object that will connect to the provided endpoint.
|
||||
|
||||
|
@ -138,79 +123,6 @@ extension OpenVPNTunnelProvider {
|
|||
|
||||
/// Offers a bridge between the abstract `OpenVPNTunnelProvider.ConfigurationBuilder` and a concrete `NETunnelProviderProtocol` profile.
|
||||
public struct Configuration: Codable {
|
||||
struct Keys {
|
||||
static let appGroup = "AppGroup"
|
||||
|
||||
static let versionIdentifier = "VersionIdentifier"
|
||||
|
||||
// MARK: SessionConfiguration
|
||||
|
||||
static let cipherAlgorithm = "CipherAlgorithm"
|
||||
|
||||
static let digestAlgorithm = "DigestAlgorithm"
|
||||
|
||||
static let compressionFraming = "CompressionFraming"
|
||||
|
||||
static let compressionAlgorithm = "CompressionAlgorithm"
|
||||
|
||||
static let ca = "CA"
|
||||
|
||||
static let clientCertificate = "ClientCertificate"
|
||||
|
||||
static let clientKey = "ClientKey"
|
||||
|
||||
static let tlsWrap = "TLSWrap"
|
||||
|
||||
static let tlsSecurityLevel = "TLSSecurityLevel"
|
||||
|
||||
static let keepAlive = "KeepAlive"
|
||||
|
||||
static let keepAliveTimeout = "KeepAliveTimeout"
|
||||
|
||||
static let endpointProtocols = "EndpointProtocols"
|
||||
|
||||
static let renegotiatesAfter = "RenegotiatesAfter"
|
||||
|
||||
static let checksEKU = "ChecksEKU"
|
||||
|
||||
static let checksSANHost = "checksSANHost"
|
||||
|
||||
static let sanHost = "sanHost"
|
||||
|
||||
static let randomizeEndpoint = "RandomizeEndpoint"
|
||||
|
||||
static let usesPIAPatches = "UsesPIAPatches"
|
||||
|
||||
static let mtu = "MTU"
|
||||
|
||||
static let dnsServers = "DNSServers"
|
||||
|
||||
static let searchDomains = "SearchDomains"
|
||||
|
||||
static let httpProxy = "HTTPProxy"
|
||||
|
||||
static let httpsProxy = "HTTPSProxy"
|
||||
|
||||
static let proxyAutoConfigurationURL = "ProxyAutoConfigurationURL"
|
||||
|
||||
static let proxyBypassDomains = "ProxyBypassDomains"
|
||||
|
||||
static let routingPolicies = "RoutingPolicies"
|
||||
|
||||
// MARK: Customization
|
||||
|
||||
static let prefersResolvedAddresses = "PrefersResolvedAddresses"
|
||||
|
||||
static let resolvedAddresses = "ResolvedAddresses"
|
||||
|
||||
// MARK: Debugging
|
||||
|
||||
static let debug = "Debug"
|
||||
|
||||
static let debugLogFormat = "DebugLogFormat"
|
||||
|
||||
static let masksPrivateData = "MasksPrivateData"
|
||||
}
|
||||
|
||||
/// - Seealso: `OpenVPNTunnelProvider.ConfigurationBuilder.sessionConfiguration`
|
||||
public let sessionConfiguration: OpenVPN.Configuration
|
||||
|
@ -318,8 +230,8 @@ extension OpenVPNTunnelProvider {
|
|||
- Throws: `ProviderError.configuration` if `providerConfiguration` does not contain an app group.
|
||||
*/
|
||||
public static func appGroup(from providerConfiguration: [String: Any]) throws -> String {
|
||||
guard let appGroup = providerConfiguration[Keys.appGroup] as? String else {
|
||||
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(Keys.appGroup)]")
|
||||
guard let appGroup = providerConfiguration[ExtraKeys.appGroup] as? String else {
|
||||
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[\(ExtraKeys.appGroup)]")
|
||||
}
|
||||
return appGroup
|
||||
}
|
||||
|
@ -332,10 +244,13 @@ extension OpenVPNTunnelProvider {
|
|||
- Throws: `ProviderError.configuration` if `providerConfiguration` is incomplete.
|
||||
*/
|
||||
public static func parsed(from providerConfiguration: [String: Any]) throws -> Configuration {
|
||||
let builder = try ConfigurationBuilder(providerConfiguration: providerConfiguration)
|
||||
return builder.build()
|
||||
let cfg = try fromDictionary(OpenVPNTunnelProvider.Configuration.self, providerConfiguration)
|
||||
guard !cfg.prefersResolvedAddresses || !(cfg.resolvedAddresses?.isEmpty ?? true) else {
|
||||
throw ProviderConfigurationError.parameter(name: "protocolConfiguration.providerConfiguration[prefersResolvedAddresses] is true but no [resolvedAddresses]")
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns a dictionary representation of this configuration for use with `NETunnelProviderProtocol.providerConfiguration`.
|
||||
|
||||
|
@ -343,36 +258,14 @@ extension OpenVPNTunnelProvider {
|
|||
- Returns: The dictionary representation of `self`.
|
||||
*/
|
||||
public func generatedProviderConfiguration(appGroup: String) -> [String: Any] {
|
||||
let S = Keys.self
|
||||
|
||||
guard let ca = sessionConfiguration.ca else {
|
||||
fatalError("No sessionConfiguration.ca set")
|
||||
do {
|
||||
var dict = try asDictionary()
|
||||
dict[ExtraKeys.appGroup] = appGroup
|
||||
return dict
|
||||
} catch let e {
|
||||
log.error("Unable to encode OpenVPN.Configuration: \(e)")
|
||||
}
|
||||
guard let endpointProtocols = sessionConfiguration.endpointProtocols else {
|
||||
fatalError("No sessionConfiguration.endpointProtocols set")
|
||||
}
|
||||
|
||||
var dict: [String: Any] = [
|
||||
S.appGroup: appGroup,
|
||||
S.prefersResolvedAddresses: prefersResolvedAddresses,
|
||||
S.ca: ca.pem,
|
||||
S.endpointProtocols: endpointProtocols.map { $0.rawValue },
|
||||
S.debug: shouldDebug
|
||||
]
|
||||
sessionConfiguration.store(to: &dict)
|
||||
if let resolvedAddresses = resolvedAddresses {
|
||||
dict[S.resolvedAddresses] = resolvedAddresses
|
||||
}
|
||||
if let debugLogFormat = debugLogFormat {
|
||||
dict[S.debugLogFormat] = debugLogFormat
|
||||
}
|
||||
if let masksPrivateData = masksPrivateData {
|
||||
dict[S.masksPrivateData] = masksPrivateData
|
||||
}
|
||||
if let versionIdentifier = versionIdentifier {
|
||||
dict[S.versionIdentifier] = versionIdentifier
|
||||
}
|
||||
return dict
|
||||
return [:]
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -451,284 +344,3 @@ public extension UserDefaults {
|
|||
removeObject(forKey: OpenVPNTunnelProvider.Configuration.dataCountKey)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: OpenVPN configuration
|
||||
|
||||
private extension OpenVPN.Configuration {
|
||||
static func with(providerConfiguration: [String: Any]) throws -> OpenVPN.Configuration {
|
||||
let S = OpenVPNTunnelProvider.Configuration.Keys.self
|
||||
let E = OpenVPNTunnelProvider.ProviderConfigurationError.self
|
||||
|
||||
guard let caPEM = providerConfiguration[S.ca] as? String else {
|
||||
throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.ca)]")
|
||||
}
|
||||
guard let endpointProtocolsStrings = providerConfiguration[S.endpointProtocols] as? [String], !endpointProtocolsStrings.isEmpty else {
|
||||
throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.endpointProtocols)] is nil or empty")
|
||||
}
|
||||
|
||||
var builder = OpenVPNTunnelProvider.ConfigurationBuilder.defaults.sessionConfiguration.builder()
|
||||
|
||||
builder.ca = OpenVPN.CryptoContainer(pem: caPEM)
|
||||
builder.endpointProtocols = try endpointProtocolsStrings.map {
|
||||
guard let ep = EndpointProtocol(rawValue: $0) else {
|
||||
throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.endpointProtocols)] has a badly formed element")
|
||||
}
|
||||
return ep
|
||||
}
|
||||
|
||||
if let cipherAlgorithm = providerConfiguration[S.cipherAlgorithm] as? String {
|
||||
builder.cipher = OpenVPN.Cipher(rawValue: cipherAlgorithm)
|
||||
}
|
||||
if let digestAlgorithm = providerConfiguration[S.digestAlgorithm] as? String {
|
||||
builder.digest = OpenVPN.Digest(rawValue: digestAlgorithm)
|
||||
}
|
||||
if let compressionFramingValue = providerConfiguration[S.compressionFraming] as? Int, let compressionFraming = OpenVPN.CompressionFraming(rawValue: compressionFramingValue) {
|
||||
builder.compressionFraming = compressionFraming
|
||||
}
|
||||
if let compressionAlgorithmValue = providerConfiguration[S.compressionAlgorithm] as? Int, let compressionAlgorithm = OpenVPN.CompressionAlgorithm(rawValue: compressionAlgorithmValue) {
|
||||
builder.compressionAlgorithm = compressionAlgorithm
|
||||
}
|
||||
if let clientPEM = providerConfiguration[S.clientCertificate] as? String {
|
||||
guard let keyPEM = providerConfiguration[S.clientKey] as? String else {
|
||||
throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.clientKey)]")
|
||||
}
|
||||
builder.clientCertificate = OpenVPN.CryptoContainer(pem: clientPEM)
|
||||
builder.clientKey = OpenVPN.CryptoContainer(pem: keyPEM)
|
||||
}
|
||||
if let tlsWrapData = providerConfiguration[S.tlsWrap] as? Data {
|
||||
do {
|
||||
builder.tlsWrap = try OpenVPN.TLSWrap.deserialized(tlsWrapData)
|
||||
} catch {
|
||||
throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.tlsWrap)]")
|
||||
}
|
||||
}
|
||||
if let tlsSecurityLevel = providerConfiguration[S.tlsSecurityLevel] as? Int {
|
||||
builder.tlsSecurityLevel = tlsSecurityLevel
|
||||
}
|
||||
if let keepAliveInterval = providerConfiguration[S.keepAlive] as? TimeInterval {
|
||||
builder.keepAliveInterval = keepAliveInterval
|
||||
}
|
||||
if let keepAliveTimeout = providerConfiguration[S.keepAliveTimeout] as? TimeInterval {
|
||||
builder.keepAliveTimeout = keepAliveTimeout
|
||||
}
|
||||
if let renegotiatesAfter = providerConfiguration[S.renegotiatesAfter] as? TimeInterval {
|
||||
builder.renegotiatesAfter = renegotiatesAfter
|
||||
}
|
||||
if let checksEKU = providerConfiguration[S.checksEKU] as? Bool {
|
||||
builder.checksEKU = checksEKU
|
||||
}
|
||||
if let checksSANHost = providerConfiguration[S.checksSANHost] as? Bool {
|
||||
builder.checksSANHost = checksSANHost
|
||||
}
|
||||
if let sanHost = providerConfiguration[S.sanHost] as? String {
|
||||
builder.sanHost = sanHost
|
||||
}
|
||||
if let randomizeEndpoint = providerConfiguration[S.randomizeEndpoint] as? Bool {
|
||||
builder.randomizeEndpoint = randomizeEndpoint
|
||||
}
|
||||
if let usesPIAPatches = providerConfiguration[S.usesPIAPatches] as? Bool {
|
||||
builder.usesPIAPatches = usesPIAPatches
|
||||
}
|
||||
if let mtu = providerConfiguration[S.mtu] as? Int {
|
||||
builder.mtu = mtu
|
||||
}
|
||||
if let dnsServers = providerConfiguration[S.dnsServers] as? [String] {
|
||||
builder.dnsServers = dnsServers
|
||||
}
|
||||
if let searchDomains = providerConfiguration[S.searchDomains] as? [String] {
|
||||
builder.searchDomains = searchDomains
|
||||
}
|
||||
if let proxyString = providerConfiguration[S.httpProxy] as? String {
|
||||
guard let proxy = Proxy(rawValue: proxyString) else {
|
||||
throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.httpProxy)] has a badly formed element")
|
||||
}
|
||||
builder.httpProxy = proxy
|
||||
}
|
||||
if let proxyString = providerConfiguration[S.httpsProxy] as? String {
|
||||
guard let proxy = Proxy(rawValue: proxyString) else {
|
||||
throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.httpsProxy)] has a badly formed element")
|
||||
}
|
||||
builder.httpsProxy = proxy
|
||||
}
|
||||
if let proxyAutoConfigurationURLString = providerConfiguration[S.proxyAutoConfigurationURL] as? String, let proxyAutoConfigurationURL = URL(string: proxyAutoConfigurationURLString) {
|
||||
builder.proxyAutoConfigurationURL = proxyAutoConfigurationURL
|
||||
}
|
||||
if let proxyBypassDomains = providerConfiguration[S.proxyBypassDomains] as? [String] {
|
||||
builder.proxyBypassDomains = proxyBypassDomains
|
||||
}
|
||||
if let routingPoliciesStrings = providerConfiguration[S.routingPolicies] as? [String] {
|
||||
builder.routingPolicies = try routingPoliciesStrings.map {
|
||||
guard let policy = OpenVPN.RoutingPolicy(rawValue: $0) else {
|
||||
throw E.parameter(name: "protocolConfiguration.providerConfiguration[\(S.routingPolicies)] has a badly formed element")
|
||||
}
|
||||
return policy
|
||||
}
|
||||
}
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
func store(to dict: inout [String: Any]) {
|
||||
let S = OpenVPNTunnelProvider.Configuration.Keys.self
|
||||
|
||||
if let cipher = cipher {
|
||||
dict[S.cipherAlgorithm] = cipher.rawValue
|
||||
}
|
||||
if let digest = digest {
|
||||
dict[S.digestAlgorithm] = digest.rawValue
|
||||
}
|
||||
if let compressionFraming = compressionFraming {
|
||||
dict[S.compressionFraming] = compressionFraming.rawValue
|
||||
}
|
||||
if let compressionAlgorithm = compressionAlgorithm {
|
||||
dict[S.compressionAlgorithm] = compressionAlgorithm.rawValue
|
||||
}
|
||||
if let clientCertificate = clientCertificate {
|
||||
dict[S.clientCertificate] = clientCertificate.pem
|
||||
}
|
||||
if let clientKey = clientKey {
|
||||
dict[S.clientKey] = clientKey.pem
|
||||
}
|
||||
if let tlsWrapData = tlsWrap?.serialized() {
|
||||
dict[S.tlsWrap] = tlsWrapData
|
||||
}
|
||||
if let tlsSecurityLevel = tlsSecurityLevel {
|
||||
dict[S.tlsSecurityLevel] = tlsSecurityLevel
|
||||
}
|
||||
if let keepAliveSeconds = keepAliveInterval {
|
||||
dict[S.keepAlive] = keepAliveSeconds
|
||||
}
|
||||
if let keepAliveTimeoutSeconds = keepAliveTimeout {
|
||||
dict[S.keepAliveTimeout] = keepAliveTimeoutSeconds
|
||||
}
|
||||
if let renegotiatesAfterSeconds = renegotiatesAfter {
|
||||
dict[S.renegotiatesAfter] = renegotiatesAfterSeconds
|
||||
}
|
||||
if let checksEKU = checksEKU {
|
||||
dict[S.checksEKU] = checksEKU
|
||||
}
|
||||
if let checksSANHost = checksSANHost {
|
||||
dict[S.checksSANHost] = checksSANHost
|
||||
}
|
||||
if let sanHost = sanHost {
|
||||
dict[S.sanHost] = sanHost
|
||||
}
|
||||
if let randomizeEndpoint = randomizeEndpoint {
|
||||
dict[S.randomizeEndpoint] = randomizeEndpoint
|
||||
}
|
||||
if let usesPIAPatches = usesPIAPatches {
|
||||
dict[S.usesPIAPatches] = usesPIAPatches
|
||||
}
|
||||
if let mtu = mtu {
|
||||
dict[S.mtu] = mtu
|
||||
}
|
||||
if let dnsServers = dnsServers {
|
||||
dict[S.dnsServers] = dnsServers
|
||||
}
|
||||
if let searchDomains = searchDomains {
|
||||
dict[S.searchDomains] = searchDomains
|
||||
}
|
||||
if let httpProxy = httpProxy {
|
||||
dict[S.httpProxy] = httpProxy.rawValue
|
||||
}
|
||||
if let httpsProxy = httpsProxy {
|
||||
dict[S.httpsProxy] = httpsProxy.rawValue
|
||||
}
|
||||
if let proxyAutoConfigurationURL = proxyAutoConfigurationURL {
|
||||
dict[S.proxyAutoConfigurationURL] = proxyAutoConfigurationURL.absoluteString
|
||||
}
|
||||
if let proxyBypassDomains = proxyBypassDomains {
|
||||
dict[S.proxyBypassDomains] = proxyBypassDomains
|
||||
}
|
||||
if let routingPolicies = routingPolicies {
|
||||
dict[S.routingPolicies] = routingPolicies.map { $0.rawValue }
|
||||
}
|
||||
}
|
||||
|
||||
func print() {
|
||||
guard let endpointProtocols = endpointProtocols else {
|
||||
fatalError("No sessionConfiguration.endpointProtocols set")
|
||||
}
|
||||
log.info("\tProtocols: \(endpointProtocols)")
|
||||
log.info("\tCipher: \(fallbackCipher)")
|
||||
log.info("\tDigest: \(fallbackDigest)")
|
||||
log.info("\tCompression framing: \(fallbackCompressionFraming)")
|
||||
if let compressionAlgorithm = compressionAlgorithm, compressionAlgorithm != .disabled {
|
||||
log.info("\tCompression algorithm: \(compressionAlgorithm)")
|
||||
} else {
|
||||
log.info("\tCompression algorithm: disabled")
|
||||
}
|
||||
if let _ = clientCertificate {
|
||||
log.info("\tClient verification: enabled")
|
||||
} else {
|
||||
log.info("\tClient verification: disabled")
|
||||
}
|
||||
if let tlsWrap = tlsWrap {
|
||||
log.info("\tTLS wrapping: \(tlsWrap.strategy)")
|
||||
} else {
|
||||
log.info("\tTLS wrapping: disabled")
|
||||
}
|
||||
if let tlsSecurityLevel = tlsSecurityLevel {
|
||||
log.info("\tTLS security level: \(tlsSecurityLevel)")
|
||||
} else {
|
||||
log.info("\tTLS security level: default")
|
||||
}
|
||||
if let keepAliveSeconds = keepAliveInterval, keepAliveSeconds > 0 {
|
||||
log.info("\tKeep-alive interval: \(keepAliveSeconds) seconds")
|
||||
} else {
|
||||
log.info("\tKeep-alive interval: never")
|
||||
}
|
||||
if let keepAliveTimeoutSeconds = keepAliveTimeout, keepAliveTimeoutSeconds > 0 {
|
||||
log.info("\tKeep-alive timeout: \(keepAliveTimeoutSeconds) seconds")
|
||||
} else {
|
||||
log.info("\tKeep-alive timeout: never")
|
||||
}
|
||||
if let renegotiatesAfterSeconds = renegotiatesAfter, renegotiatesAfterSeconds > 0 {
|
||||
log.info("\tRenegotiation: \(renegotiatesAfterSeconds) seconds")
|
||||
} else {
|
||||
log.info("\tRenegotiation: never")
|
||||
}
|
||||
if checksEKU ?? false {
|
||||
log.info("\tServer EKU verification: enabled")
|
||||
} else {
|
||||
log.info("\tServer EKU verification: disabled")
|
||||
}
|
||||
if checksSANHost ?? false {
|
||||
log.info("\tHost SAN verification: enabled (\(sanHost ?? "-"))")
|
||||
} else {
|
||||
log.info("\tHost SAN verification: disabled")
|
||||
}
|
||||
if randomizeEndpoint ?? false {
|
||||
log.info("\tRandomize endpoint: true")
|
||||
}
|
||||
if let routingPolicies = routingPolicies {
|
||||
log.info("\tGateway: \(routingPolicies.map { $0.rawValue })")
|
||||
} else {
|
||||
log.info("\tGateway: not configured")
|
||||
}
|
||||
if let dnsServers = dnsServers, !dnsServers.isEmpty {
|
||||
log.info("\tDNS: \(dnsServers.maskedDescription)")
|
||||
} else {
|
||||
log.info("\tDNS: not configured")
|
||||
}
|
||||
if let searchDomains = searchDomains, !searchDomains.isEmpty {
|
||||
log.info("\tSearch domains: \(searchDomains.maskedDescription)")
|
||||
}
|
||||
if let httpProxy = httpProxy {
|
||||
log.info("\tHTTP proxy: \(httpProxy.maskedDescription)")
|
||||
}
|
||||
if let httpsProxy = httpsProxy {
|
||||
log.info("\tHTTPS proxy: \(httpsProxy.maskedDescription)")
|
||||
}
|
||||
if let proxyAutoConfigurationURL = proxyAutoConfigurationURL {
|
||||
log.info("\tPAC: \(proxyAutoConfigurationURL)")
|
||||
}
|
||||
if let proxyBypassDomains = proxyBypassDomains {
|
||||
log.info("\tProxy bypass domains: \(proxyBypassDomains.maskedDescription)")
|
||||
}
|
||||
if let mtu = mtu {
|
||||
log.info("\tMTU: \(mtu)")
|
||||
} else {
|
||||
log.info("\tMTU: default")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftyBeaver
|
||||
|
||||
private let log = SwiftyBeaver.self
|
||||
|
||||
extension OpenVPN {
|
||||
|
||||
|
@ -506,3 +509,95 @@ extension OpenVPN.Configuration {
|
|||
return builder
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Encoding
|
||||
|
||||
extension OpenVPN.Configuration {
|
||||
func print() {
|
||||
guard let endpointProtocols = endpointProtocols else {
|
||||
fatalError("No sessionConfiguration.endpointProtocols set")
|
||||
}
|
||||
log.info("\tProtocols: \(endpointProtocols)")
|
||||
log.info("\tCipher: \(fallbackCipher)")
|
||||
log.info("\tDigest: \(fallbackDigest)")
|
||||
log.info("\tCompression framing: \(fallbackCompressionFraming)")
|
||||
if let compressionAlgorithm = compressionAlgorithm, compressionAlgorithm != .disabled {
|
||||
log.info("\tCompression algorithm: \(compressionAlgorithm)")
|
||||
} else {
|
||||
log.info("\tCompression algorithm: disabled")
|
||||
}
|
||||
if let _ = clientCertificate {
|
||||
log.info("\tClient verification: enabled")
|
||||
} else {
|
||||
log.info("\tClient verification: disabled")
|
||||
}
|
||||
if let tlsWrap = tlsWrap {
|
||||
log.info("\tTLS wrapping: \(tlsWrap.strategy)")
|
||||
} else {
|
||||
log.info("\tTLS wrapping: disabled")
|
||||
}
|
||||
if let tlsSecurityLevel = tlsSecurityLevel {
|
||||
log.info("\tTLS security level: \(tlsSecurityLevel)")
|
||||
} else {
|
||||
log.info("\tTLS security level: default")
|
||||
}
|
||||
if let keepAliveSeconds = keepAliveInterval, keepAliveSeconds > 0 {
|
||||
log.info("\tKeep-alive interval: \(keepAliveSeconds) seconds")
|
||||
} else {
|
||||
log.info("\tKeep-alive interval: never")
|
||||
}
|
||||
if let keepAliveTimeoutSeconds = keepAliveTimeout, keepAliveTimeoutSeconds > 0 {
|
||||
log.info("\tKeep-alive timeout: \(keepAliveTimeoutSeconds) seconds")
|
||||
} else {
|
||||
log.info("\tKeep-alive timeout: never")
|
||||
}
|
||||
if let renegotiatesAfterSeconds = renegotiatesAfter, renegotiatesAfterSeconds > 0 {
|
||||
log.info("\tRenegotiation: \(renegotiatesAfterSeconds) seconds")
|
||||
} else {
|
||||
log.info("\tRenegotiation: never")
|
||||
}
|
||||
if checksEKU ?? false {
|
||||
log.info("\tServer EKU verification: enabled")
|
||||
} else {
|
||||
log.info("\tServer EKU verification: disabled")
|
||||
}
|
||||
if checksSANHost ?? false {
|
||||
log.info("\tHost SAN verification: enabled (\(sanHost ?? "-"))")
|
||||
} else {
|
||||
log.info("\tHost SAN verification: disabled")
|
||||
}
|
||||
if randomizeEndpoint ?? false {
|
||||
log.info("\tRandomize endpoint: true")
|
||||
}
|
||||
if let routingPolicies = routingPolicies {
|
||||
log.info("\tGateway: \(routingPolicies.map { $0.rawValue })")
|
||||
} else {
|
||||
log.info("\tGateway: not configured")
|
||||
}
|
||||
if let dnsServers = dnsServers, !dnsServers.isEmpty {
|
||||
log.info("\tDNS: \(dnsServers.maskedDescription)")
|
||||
} else {
|
||||
log.info("\tDNS: not configured")
|
||||
}
|
||||
if let searchDomains = searchDomains, !searchDomains.isEmpty {
|
||||
log.info("\tSearch domains: \(searchDomains.maskedDescription)")
|
||||
}
|
||||
if let httpProxy = httpProxy {
|
||||
log.info("\tHTTP proxy: \(httpProxy.maskedDescription)")
|
||||
}
|
||||
if let httpsProxy = httpsProxy {
|
||||
log.info("\tHTTPS proxy: \(httpsProxy.maskedDescription)")
|
||||
}
|
||||
if let proxyAutoConfigurationURL = proxyAutoConfigurationURL {
|
||||
log.info("\tPAC: \(proxyAutoConfigurationURL)")
|
||||
}
|
||||
if let proxyBypassDomains = proxyBypassDomains {
|
||||
log.info("\tProxy bypass domains: \(proxyBypassDomains.maskedDescription)")
|
||||
}
|
||||
if let mtu = mtu {
|
||||
log.info("\tMTU: \(mtu)")
|
||||
} else {
|
||||
log.info("\tMTU: default")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.1.0</string>
|
||||
<string>3.2.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.1.0</string>
|
||||
<string>3.2.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.1.0</string>
|
||||
<string>3.2.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
|
|
|
@ -79,18 +79,19 @@ class AppExtensionTests: XCTestCase {
|
|||
XCTAssertEqual(proto?.username, credentials.username)
|
||||
XCTAssertEqual(proto?.passwordReference, try? Keychain(group: appGroup).passwordReference(for: credentials.username))
|
||||
|
||||
if let pc = proto?.providerConfiguration {
|
||||
print("\(pc)")
|
||||
guard let pc = proto?.providerConfiguration else {
|
||||
return
|
||||
}
|
||||
|
||||
let K = OpenVPNTunnelProvider.Configuration.Keys.self
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.appGroup] as? String, appGroup)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.cipherAlgorithm] as? String, cfg.sessionConfiguration.cipher?.rawValue)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.digestAlgorithm] as? String, cfg.sessionConfiguration.digest?.rawValue)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.ca] as? String, cfg.sessionConfiguration.ca?.pem)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.mtu] as? Int, cfg.sessionConfiguration.mtu)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.renegotiatesAfter] as? TimeInterval, cfg.sessionConfiguration.renegotiatesAfter)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.debug] as? Bool, cfg.shouldDebug)
|
||||
print("\(pc)")
|
||||
|
||||
let pcSession = pc["sessionConfiguration"] as? [String: Any]
|
||||
XCTAssertEqual(pc["appGroup"] as? String, appGroup)
|
||||
XCTAssertEqual(pc["shouldDebug"] as? Bool, cfg.shouldDebug)
|
||||
XCTAssertEqual(pcSession?["cipher"] as? String, cfg.sessionConfiguration.cipher?.rawValue)
|
||||
XCTAssertEqual(pcSession?["digest"] as? String, cfg.sessionConfiguration.digest?.rawValue)
|
||||
XCTAssertEqual(pcSession?["ca"] as? String, cfg.sessionConfiguration.ca?.pem)
|
||||
XCTAssertEqual(pcSession?["mtu"] as? Int, cfg.sessionConfiguration.mtu)
|
||||
XCTAssertEqual(pcSession?["renegotiatesAfter"] as? TimeInterval, cfg.sessionConfiguration.renegotiatesAfter)
|
||||
}
|
||||
|
||||
func testDNSResolver() {
|
||||
|
|
Loading…
Reference in New Issue