Invoke VPNManager methods with a Profile object (#309)
The VPNConfiguration parameter is opaque and tightly coupled to TunnelKit. Connecting to a Profile makes infinitely more sense, beyond simplifying the VPNManager class. Configuration building is fully delegated to the strategy (as it has to be). - VPNManager takes Profile and produces VPNConfigurationParameters - VPNManagerStrategy takes VPNConfigurationParameters (abstract) - TunnelKitVPNManagerStrategy takes VPNConfigurationParameters and produces TunnelKitVPNConfiguration internally
This commit is contained in:
parent
36cad41529
commit
3a59ac7684
|
@ -85,7 +85,7 @@ let package = Package(
|
|||
.target(
|
||||
name: "PassepartoutCore",
|
||||
dependencies: [
|
||||
.product(name: "GenericJSON", package: "generic-json-swift") // FIXME: arch, drop this
|
||||
.product(name: "GenericJSON", package: "generic-json-swift")
|
||||
]),
|
||||
|
||||
// MARK: App extensions
|
||||
|
|
|
@ -52,3 +52,9 @@ extension TimeInterval {
|
|||
return str
|
||||
}
|
||||
}
|
||||
|
||||
extension TimeInterval {
|
||||
public var dispatchTimeInterval: DispatchTimeInterval {
|
||||
.nanoseconds(Int(self * Double(NSEC_PER_SEC)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,4 +43,20 @@ extension Profile {
|
|||
self.configuration = configuration
|
||||
}
|
||||
}
|
||||
|
||||
init(_ id: UUID = UUID(), name: String, configuration: OpenVPN.Configuration) {
|
||||
let header = Header(
|
||||
uuid: id,
|
||||
name: name,
|
||||
providerName: nil
|
||||
)
|
||||
self.init(header, configuration: configuration)
|
||||
}
|
||||
|
||||
public init(_ header: Header, configuration: OpenVPN.Configuration) {
|
||||
self.header = header
|
||||
currentVPNProtocol = .openVPN
|
||||
host = Host()
|
||||
host?.ovpnSettings = OpenVPNSettings(configuration: configuration)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,4 +39,20 @@ extension Profile {
|
|||
self.configuration = configuration
|
||||
}
|
||||
}
|
||||
|
||||
init(_ id: UUID = UUID(), name: String, configuration: WireGuard.Configuration) {
|
||||
let header = Header(
|
||||
uuid: id,
|
||||
name: name,
|
||||
providerName: nil
|
||||
)
|
||||
self.init(header, configuration: configuration)
|
||||
}
|
||||
|
||||
public init(_ header: Header, configuration: WireGuard.Configuration) {
|
||||
self.header = header
|
||||
currentVPNProtocol = .wireGuard
|
||||
host = Host()
|
||||
host?.wgSettings = WireGuardSettings(configuration: configuration)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
import Foundation
|
||||
import PassepartoutCore
|
||||
import TunnelKitOpenVPN
|
||||
import TunnelKitWireGuard
|
||||
|
||||
public protocol ProfileSubtype {
|
||||
var vpnProtocols: [VPNProtocolType] { get }
|
||||
|
@ -59,24 +57,6 @@ public struct Profile: Identifiable, Codable, Equatable {
|
|||
currentVPNProtocol = .openVPN
|
||||
}
|
||||
|
||||
init(_ id: UUID = UUID(), name: String, configuration: OpenVPN.Configuration) {
|
||||
let header = Header(
|
||||
uuid: id,
|
||||
name: name,
|
||||
providerName: nil
|
||||
)
|
||||
self.init(header, configuration: configuration)
|
||||
}
|
||||
|
||||
init(_ id: UUID = UUID(), name: String, configuration: WireGuard.Configuration) {
|
||||
let header = Header(
|
||||
uuid: id,
|
||||
name: name,
|
||||
providerName: nil
|
||||
)
|
||||
self.init(header, configuration: configuration)
|
||||
}
|
||||
|
||||
init(_ id: UUID = UUID(), name: String, provider: Profile.Provider) {
|
||||
let header = Header(
|
||||
uuid: id,
|
||||
|
@ -86,20 +66,6 @@ public struct Profile: Identifiable, Codable, Equatable {
|
|||
self.init(header, provider: provider)
|
||||
}
|
||||
|
||||
public init(_ header: Header, configuration: OpenVPN.Configuration) {
|
||||
self.header = header
|
||||
currentVPNProtocol = .openVPN
|
||||
host = Host()
|
||||
host?.ovpnSettings = OpenVPNSettings(configuration: configuration)
|
||||
}
|
||||
|
||||
public init(_ header: Header, configuration: WireGuard.Configuration) {
|
||||
self.header = header
|
||||
currentVPNProtocol = .wireGuard
|
||||
host = Host()
|
||||
host?.wgSettings = WireGuardSettings(configuration: configuration)
|
||||
}
|
||||
|
||||
public init(_ header: Header, provider: Profile.Provider) {
|
||||
guard let firstVPNProtocol = provider.vpnSettings.keys.first else {
|
||||
fatalError("No VPN protocols defined in provider")
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
//
|
||||
// VPNConfiguration.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 6/22/22.
|
||||
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import TunnelKitManager
|
||||
|
||||
public typealias VPNConfiguration = (neConfiguration: NetworkExtensionConfiguration, neExtra: NetworkExtensionExtra)
|
|
@ -25,11 +25,13 @@
|
|||
|
||||
import Foundation
|
||||
import PassepartoutCore
|
||||
import TunnelKitManager
|
||||
import PassepartoutProviders
|
||||
|
||||
public struct VPNConfigurationParameters {
|
||||
public let profile: Profile
|
||||
|
||||
public let providerManager: ProviderManager
|
||||
|
||||
public var title: String {
|
||||
profile.header.name
|
||||
}
|
||||
|
@ -52,12 +54,14 @@ public struct VPNConfigurationParameters {
|
|||
|
||||
init(
|
||||
_ profile: Profile,
|
||||
providerManager: ProviderManager,
|
||||
preferences: VPNPreferences,
|
||||
passwordReference: Data?,
|
||||
withNetworkSettings: Bool,
|
||||
withCustomRules: Bool
|
||||
) {
|
||||
self.profile = profile
|
||||
self.providerManager = providerManager
|
||||
self.preferences = preferences
|
||||
self.passwordReference = passwordReference
|
||||
self.withNetworkSettings = withNetworkSettings
|
||||
|
|
|
@ -65,10 +65,9 @@ extension VPNManager {
|
|||
if let newPassword {
|
||||
profile.account.password = newPassword
|
||||
}
|
||||
let cfg = try vpnConfiguration(withProfile: profile)
|
||||
|
||||
profileManager.activateProfile(profile)
|
||||
await reconnect(cfg)
|
||||
await reconnect(profile)
|
||||
return profile
|
||||
}
|
||||
|
||||
|
@ -99,14 +98,13 @@ extension VPNManager {
|
|||
|
||||
pp_log.info("Connecting to: \(profile.logDescription) @ \(newServer.logDescription)")
|
||||
profile.setProviderServer(newServer)
|
||||
let cfg = try vpnConfiguration(withProfile: profile)
|
||||
|
||||
profileManager.activateProfile(profile)
|
||||
guard !profileManager.isCurrentProfile(profileId) else {
|
||||
pp_log.debug("Active profile is current, will reconnect via observation")
|
||||
return profile
|
||||
}
|
||||
await reconnect(cfg)
|
||||
await reconnect(profile)
|
||||
return profile
|
||||
}
|
||||
|
||||
|
@ -118,13 +116,12 @@ extension VPNManager {
|
|||
|
||||
pp_log.info("Modifying active profile")
|
||||
block(&profile)
|
||||
let cfg = try vpnConfiguration(withProfile: profile)
|
||||
|
||||
profileManager.activateProfile(profile)
|
||||
guard !profileManager.isCurrentProfile(profile.id) else {
|
||||
pp_log.debug("Active profile is current, will reinstate via observation")
|
||||
return
|
||||
}
|
||||
await reinstate(cfg)
|
||||
await reinstate(profile)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,16 +84,28 @@ public final class VPNManager: ObservableObject {
|
|||
currentState = ObservableVPNState()
|
||||
}
|
||||
|
||||
func reinstate(_ configuration: VPNConfiguration) async {
|
||||
func reinstate(_ profile: Profile) async {
|
||||
pp_log.info("Reinstating VPN")
|
||||
clearLastError()
|
||||
await strategy.reinstate(configuration: configuration)
|
||||
do {
|
||||
let parameters = try vpnConfigurationParameters(withProfile: profile)
|
||||
await strategy.reinstate(parameters)
|
||||
} catch {
|
||||
pp_log.error("Unable to build configuration: \(error)")
|
||||
configurationError.send((profile, error))
|
||||
}
|
||||
}
|
||||
|
||||
func reconnect(_ configuration: VPNConfiguration) async {
|
||||
func reconnect(_ profile: Profile) async {
|
||||
pp_log.info("Reconnecting VPN (with new configuration)")
|
||||
clearLastError()
|
||||
await strategy.connect(configuration: configuration)
|
||||
do {
|
||||
let parameters = try vpnConfigurationParameters(withProfile: profile)
|
||||
await strategy.connect(parameters)
|
||||
} catch {
|
||||
pp_log.error("Unable to build configuration: \(error)")
|
||||
configurationError.send((profile, error))
|
||||
}
|
||||
}
|
||||
|
||||
public func reconnect() async {
|
||||
|
@ -139,7 +151,11 @@ extension VPNManager {
|
|||
}
|
||||
|
||||
private func observeStrategy() {
|
||||
strategy.observe(into: MutableObservableVPNState(currentState))
|
||||
strategy.observe(into: MutableObservableVPNState(currentState)) { profile, error in
|
||||
|
||||
// UI is certainly interested in configuration errors
|
||||
self.configurationError.send((profile, error))
|
||||
}
|
||||
}
|
||||
|
||||
private func observeProfileManager() {
|
||||
|
@ -233,34 +249,22 @@ extension VPNManager {
|
|||
guard isHandled else {
|
||||
return
|
||||
}
|
||||
guard let cfg = vpnConfigurationWithCurrentProfile() else {
|
||||
guard profileManager.isActiveProfile(newProfile.id) else {
|
||||
pp_log.info("Skipping VPN reaction, current profile is not active")
|
||||
return
|
||||
}
|
||||
if shouldReconnect {
|
||||
await reconnect(cfg)
|
||||
await reconnect(newProfile)
|
||||
} else {
|
||||
await reinstate(cfg)
|
||||
await reinstate(newProfile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Configuration
|
||||
|
||||
extension VPNManager {
|
||||
func vpnConfigurationWithCurrentProfile() -> VPNConfiguration? {
|
||||
do {
|
||||
guard profileManager.isCurrentProfileActive() else {
|
||||
pp_log.info("Skipping VPN configuration, current profile is not active")
|
||||
return nil
|
||||
}
|
||||
return try vpnConfiguration(withProfile: profileManager.currentProfile.value)
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func vpnConfiguration(withProfile profile: Profile) throws -> VPNConfiguration {
|
||||
do {
|
||||
private extension VPNManager {
|
||||
func vpnConfigurationParameters(withProfile profile: Profile) throws -> VPNConfigurationParameters {
|
||||
if profile.requiresCredentials {
|
||||
guard !profile.account.isEmpty else {
|
||||
throw PassepartoutError.missingAccount
|
||||
|
@ -282,23 +286,14 @@ extension VPNManager {
|
|||
// IMPORTANT: must commit password to keychain (tunnel needs a password reference)
|
||||
profileManager.savePassword(forProfile: profile, newPassword: newPassword)
|
||||
|
||||
let parameters = VPNConfigurationParameters(
|
||||
return VPNConfigurationParameters(
|
||||
profile,
|
||||
providerManager: providerManager,
|
||||
preferences: vpnPreferences,
|
||||
passwordReference: profileManager.passwordReference(forProfile: profile),
|
||||
withNetworkSettings: isNetworkSettingsSupported(),
|
||||
withCustomRules: isOnDemandRulesSupported()
|
||||
)
|
||||
|
||||
return try strategy.vpnConfiguration(parameters, providerManager: providerManager)
|
||||
} catch {
|
||||
pp_log.error("Unable to build VPNConfiguration: \(error)")
|
||||
|
||||
// UI is certainly interested in configuration errors
|
||||
configurationError.send((profile, error))
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,11 +29,11 @@ import PassepartoutCore
|
|||
import PassepartoutProviders
|
||||
|
||||
public protocol VPNManagerStrategy {
|
||||
func observe(into state: MutableObservableVPNState)
|
||||
func observe(into state: MutableObservableVPNState, onConfigurationError: @escaping (Profile, Error) -> Void)
|
||||
|
||||
func reinstate(configuration: VPNConfiguration) async
|
||||
func reinstate(_ parameters: VPNConfigurationParameters) async
|
||||
|
||||
func connect(configuration: VPNConfiguration) async
|
||||
func connect(_ parameters: VPNConfigurationParameters) async
|
||||
|
||||
func reconnect() async
|
||||
|
||||
|
@ -44,9 +44,4 @@ public protocol VPNManagerStrategy {
|
|||
func serverConfiguration(forProtocol vpnProtocol: VPNProtocolType) -> Any?
|
||||
|
||||
func debugLogURL(forProtocol vpnProtocol: VPNProtocolType) -> URL?
|
||||
|
||||
func vpnConfiguration(
|
||||
_ parameters: VPNConfigurationParameters,
|
||||
providerManager: ProviderManager
|
||||
) throws -> VPNConfiguration
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import TunnelKitManager
|
|||
import TunnelKitOpenVPN
|
||||
|
||||
extension Profile.OpenVPNSettings: TunnelKitConfigurationProviding {
|
||||
func tunnelKitConfiguration(_ appGroup: String, parameters: VPNConfigurationParameters) throws -> VPNConfiguration {
|
||||
func tunnelKitConfiguration(_ appGroup: String, parameters: VPNConfigurationParameters) throws -> TunnelKitVPNConfiguration {
|
||||
var customBuilder = configuration.builder()
|
||||
|
||||
// tolerate widest range of certificates
|
||||
|
|
|
@ -30,7 +30,7 @@ import TunnelKitManager
|
|||
import TunnelKitWireGuard
|
||||
|
||||
extension Profile.WireGuardSettings: TunnelKitConfigurationProviding {
|
||||
func tunnelKitConfiguration(_ appGroup: String, parameters: VPNConfigurationParameters) throws -> VPNConfiguration {
|
||||
func tunnelKitConfiguration(_ appGroup: String, parameters: VPNConfigurationParameters) throws -> TunnelKitVPNConfiguration {
|
||||
var customBuilder = configuration.builder()
|
||||
|
||||
// network settings
|
||||
|
|
|
@ -33,8 +33,10 @@ import TunnelKitCore
|
|||
import TunnelKitManager
|
||||
import TunnelKitOpenVPNCore
|
||||
|
||||
typealias TunnelKitVPNConfiguration = (neConfiguration: NetworkExtensionConfiguration, neExtra: NetworkExtensionExtra)
|
||||
|
||||
protocol TunnelKitConfigurationProviding {
|
||||
func tunnelKitConfiguration(_ appGroup: String, parameters: VPNConfigurationParameters) throws -> VPNConfiguration
|
||||
func tunnelKitConfiguration(_ appGroup: String, parameters: VPNConfigurationParameters) throws -> TunnelKitVPNConfiguration
|
||||
}
|
||||
|
||||
public final class TunnelKitVPNManagerStrategy<VPNType: VPN>: VPNManagerStrategy where VPNType.Configuration == NetworkExtensionConfiguration, VPNType.Extra == NetworkExtensionExtra {
|
||||
|
@ -49,8 +51,6 @@ public final class TunnelKitVPNManagerStrategy<VPNType: VPN>: VPNManagerStrategy
|
|||
}
|
||||
}
|
||||
|
||||
private let reconnectionSeconds = 2
|
||||
|
||||
private let appGroup: String
|
||||
|
||||
private let tunnelBundleIdentifier: (VPNProtocolType) -> String
|
||||
|
@ -59,12 +59,16 @@ public final class TunnelKitVPNManagerStrategy<VPNType: VPN>: VPNManagerStrategy
|
|||
|
||||
private let vpn: VPNType
|
||||
|
||||
private let reconnectionInterval: TimeInterval
|
||||
|
||||
private let dataCountInterval: TimeInterval
|
||||
|
||||
// MARK: State
|
||||
|
||||
private var currentState: MutableObservableVPNState?
|
||||
|
||||
private var onConfigurationError: ((Profile, Error) -> Void)?
|
||||
|
||||
private let vpnState = CurrentValueSubject<AtomicState, Never>(.init())
|
||||
|
||||
private var dataCountTimer: AnyCancellable?
|
||||
|
@ -79,6 +83,7 @@ public final class TunnelKitVPNManagerStrategy<VPNType: VPN>: VPNManagerStrategy
|
|||
appGroup: String,
|
||||
tunnelBundleIdentifier: @escaping (VPNProtocolType) -> String,
|
||||
vpn: VPNType,
|
||||
reconnectionInterval: TimeInterval = 2.0,
|
||||
dataCountInterval: TimeInterval = 3.0
|
||||
) {
|
||||
self.appGroup = appGroup
|
||||
|
@ -88,6 +93,7 @@ public final class TunnelKitVPNManagerStrategy<VPNType: VPN>: VPNManagerStrategy
|
|||
}
|
||||
self.defaults = defaults
|
||||
self.vpn = vpn
|
||||
self.reconnectionInterval = reconnectionInterval
|
||||
self.dataCountInterval = dataCountInterval
|
||||
|
||||
registerNotification(withName: VPNNotification.didReinstall) {
|
||||
|
@ -115,8 +121,9 @@ public final class TunnelKitVPNManagerStrategy<VPNType: VPN>: VPNManagerStrategy
|
|||
// MARK: Actions
|
||||
|
||||
extension TunnelKitVPNManagerStrategy {
|
||||
public func observe(into state: MutableObservableVPNState) {
|
||||
public func observe(into state: MutableObservableVPNState, onConfigurationError: @escaping (Profile, Error) -> Void) {
|
||||
currentState = state
|
||||
self.onConfigurationError = onConfigurationError
|
||||
|
||||
// use this to drop redundant NE notifications
|
||||
vpnState
|
||||
|
@ -128,7 +135,10 @@ extension TunnelKitVPNManagerStrategy {
|
|||
}.store(in: &cancellables)
|
||||
}
|
||||
|
||||
public func reinstate(configuration: VPNConfiguration) async {
|
||||
public func reinstate(_ parameters: VPNConfigurationParameters) async {
|
||||
guard let configuration = try? vpnConfiguration(withParameters: parameters) else {
|
||||
return
|
||||
}
|
||||
guard let vpnType = configuration.neConfiguration as? VPNProtocolProviding else {
|
||||
fatalError("Configuration must implement VPNProtocolProviding")
|
||||
}
|
||||
|
@ -148,7 +158,10 @@ extension TunnelKitVPNManagerStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
public func connect(configuration: VPNConfiguration) async {
|
||||
public func connect(_ parameters: VPNConfigurationParameters) async {
|
||||
guard let configuration = try? vpnConfiguration(withParameters: parameters) else {
|
||||
return
|
||||
}
|
||||
guard let vpnType = configuration.neConfiguration as? VPNProtocolProviding else {
|
||||
fatalError("Configuration must implement VPNProtocolProviding")
|
||||
}
|
||||
|
@ -162,7 +175,7 @@ extension TunnelKitVPNManagerStrategy {
|
|||
bundleIdentifier,
|
||||
configuration: configuration.neConfiguration,
|
||||
extra: configuration.neExtra,
|
||||
after: .seconds(reconnectionSeconds)
|
||||
after: reconnectionInterval.dispatchTimeInterval
|
||||
)
|
||||
} catch {
|
||||
pp_log.error("Unable to connect: \(error)")
|
||||
|
@ -171,7 +184,7 @@ extension TunnelKitVPNManagerStrategy {
|
|||
|
||||
public func reconnect() async {
|
||||
try? await vpn.reconnect(
|
||||
after: .seconds(reconnectionSeconds)
|
||||
after: reconnectionInterval.dispatchTimeInterval
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -192,8 +205,8 @@ extension TunnelKitVPNManagerStrategy {
|
|||
|
||||
// MARK: Notifications
|
||||
|
||||
extension TunnelKitVPNManagerStrategy {
|
||||
private func onVPNReinstall(_ notification: Notification) {
|
||||
private extension TunnelKitVPNManagerStrategy {
|
||||
func onVPNReinstall(_ notification: Notification) {
|
||||
guard isRelevantNotification(notification) else {
|
||||
return
|
||||
}
|
||||
|
@ -204,7 +217,7 @@ extension TunnelKitVPNManagerStrategy {
|
|||
))
|
||||
}
|
||||
|
||||
private func onVPNStatus(_ notification: Notification) {
|
||||
func onVPNStatus(_ notification: Notification) {
|
||||
|
||||
// assume first notified identifier to be the relevant one
|
||||
// in order to restore VPN status on app launch
|
||||
|
@ -239,7 +252,7 @@ extension TunnelKitVPNManagerStrategy {
|
|||
currentState?.lastError = error
|
||||
}
|
||||
|
||||
private func onVPNFail(_ notification: Notification) {
|
||||
func onVPNFail(_ notification: Notification) {
|
||||
vpnState.send(AtomicState(
|
||||
isEnabled: notification.vpnIsEnabled,
|
||||
vpnStatus: vpnState.value.vpnStatus
|
||||
|
@ -247,7 +260,7 @@ extension TunnelKitVPNManagerStrategy {
|
|||
currentState?.lastError = notification.vpnError
|
||||
}
|
||||
|
||||
private func isRelevantNotification(_ notification: Notification) -> Bool {
|
||||
func isRelevantNotification(_ notification: Notification) -> Bool {
|
||||
guard let notificationTunnelIdentifier = notification.vpnBundleIdentifier else {
|
||||
return false
|
||||
}
|
||||
|
@ -260,7 +273,7 @@ extension TunnelKitVPNManagerStrategy {
|
|||
|
||||
// MARK: Data count
|
||||
|
||||
private func onDataCount(_: Date) {
|
||||
func onDataCount(_: Date) {
|
||||
switch vpnState.value.vpnStatus {
|
||||
case .connected:
|
||||
guard let currentDataCount = currentDataCount else {
|
||||
|
@ -273,7 +286,7 @@ extension TunnelKitVPNManagerStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
private func startCountingData() {
|
||||
func startCountingData() {
|
||||
guard dataCountTimer == nil else {
|
||||
return
|
||||
}
|
||||
|
@ -284,7 +297,7 @@ extension TunnelKitVPNManagerStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
private func stopCountingData() {
|
||||
func stopCountingData() {
|
||||
dataCountTimer?.cancel()
|
||||
dataCountTimer = nil
|
||||
|
||||
|
@ -292,6 +305,45 @@ extension TunnelKitVPNManagerStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: Configuration
|
||||
|
||||
private extension TunnelKitVPNManagerStrategy {
|
||||
func vpnConfiguration(withParameters parameters: VPNConfigurationParameters) throws -> TunnelKitVPNConfiguration {
|
||||
let profile = parameters.profile
|
||||
do {
|
||||
switch profile.currentVPNProtocol {
|
||||
case .openVPN:
|
||||
let settings: Profile.OpenVPNSettings
|
||||
if profile.isProvider {
|
||||
settings = try profile.providerOpenVPNSettings(withManager: parameters.providerManager)
|
||||
} else {
|
||||
guard let hostSettings = profile.hostOpenVPNSettings else {
|
||||
fatalError("Profile currentVPNProtocol is OpenVPN, but host has no OpenVPN settings")
|
||||
}
|
||||
settings = hostSettings
|
||||
}
|
||||
return try settings.tunnelKitConfiguration(appGroup, parameters: parameters)
|
||||
|
||||
case .wireGuard:
|
||||
let settings: Profile.WireGuardSettings
|
||||
if profile.isProvider {
|
||||
settings = try profile.providerWireGuardSettings(withManager: parameters.providerManager)
|
||||
} else {
|
||||
guard let hostSettings = profile.hostWireGuardSettings else {
|
||||
fatalError("Profile currentVPNProtocol is WireGuard, but host has no WireGuard settings")
|
||||
}
|
||||
settings = hostSettings
|
||||
}
|
||||
return try settings.tunnelKitConfiguration(appGroup, parameters: parameters)
|
||||
}
|
||||
} catch {
|
||||
pp_log.error("Unable to build TunnelKitVPNConfiguration: \(error)")
|
||||
onConfigurationError?(profile, error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Pulled
|
||||
|
||||
extension TunnelKitVPNManagerStrategy {
|
||||
|
@ -314,10 +366,12 @@ extension TunnelKitVPNManagerStrategy {
|
|||
return defaults.wireGuardURLForDebugLog(appGroup: appGroup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Callbacks
|
||||
|
||||
private func lastError(withBundleIdentifier bundleIdentifier: String?) -> Error? {
|
||||
private extension TunnelKitVPNManagerStrategy {
|
||||
func lastError(withBundleIdentifier bundleIdentifier: String?) -> Error? {
|
||||
switch bundleIdentifier {
|
||||
case tunnelBundleIdentifier(.openVPN):
|
||||
return defaults.openVPNLastError
|
||||
|
@ -330,7 +384,7 @@ extension TunnelKitVPNManagerStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
private var currentDataCount: DataCount? {
|
||||
var currentDataCount: DataCount? {
|
||||
switch currentBundleIdentifier {
|
||||
case tunnelBundleIdentifier(.openVPN):
|
||||
return defaults.openVPNDataCount
|
||||
|
@ -340,36 +394,3 @@ extension TunnelKitVPNManagerStrategy {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Configuration
|
||||
|
||||
extension TunnelKitVPNManagerStrategy {
|
||||
public func vpnConfiguration(_ parameters: VPNConfigurationParameters, providerManager: ProviderManager) throws -> VPNConfiguration {
|
||||
let profile = parameters.profile
|
||||
switch profile.currentVPNProtocol {
|
||||
case .openVPN:
|
||||
let settings: Profile.OpenVPNSettings
|
||||
if profile.isProvider {
|
||||
settings = try profile.providerOpenVPNSettings(withManager: providerManager)
|
||||
} else {
|
||||
guard let hostSettings = profile.hostOpenVPNSettings else {
|
||||
fatalError("Profile currentVPNProtocol is OpenVPN, but host has no OpenVPN settings")
|
||||
}
|
||||
settings = hostSettings
|
||||
}
|
||||
return try settings.tunnelKitConfiguration(appGroup, parameters: parameters)
|
||||
|
||||
case .wireGuard:
|
||||
let settings: Profile.WireGuardSettings
|
||||
if profile.isProvider {
|
||||
settings = try profile.providerWireGuardSettings(withManager: providerManager)
|
||||
} else {
|
||||
guard let hostSettings = profile.hostWireGuardSettings else {
|
||||
fatalError("Profile currentVPNProtocol is WireGuard, but host has no WireGuard settings")
|
||||
}
|
||||
settings = hostSettings
|
||||
}
|
||||
return try settings.tunnelKitConfiguration(appGroup, parameters: parameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ final class ProvidersTests: XCTestCase {
|
|||
private var cancellables: Set<AnyCancellable> = []
|
||||
|
||||
override func setUp() {
|
||||
let model = NSManagedObjectModel.mergedModel(from: [.module])!
|
||||
persistence = ProvidersPersistence(withName: "ProvidersTests", cloudKit: false, author: nil)
|
||||
|
||||
let remoteStrategy = APIRemoteProvidersStrategy(
|
||||
|
|
Loading…
Reference in New Issue