@@ -27,7 +27,7 @@ import NetworkExtension
2727fileprivate let log = PIALogger . logger ( for: DefaultVPNProvider . self)
2828
2929@available ( tvOS 17 . 0 , * )
30- open class DefaultVPNProvider : VPNProvider , ConfigurationAccess , DatabaseAccess , PreferencesAccess , ProvidersAccess , WebServicesAccess {
30+ open class DefaultVPNProvider : ConfigurationAccess , DatabaseAccess , PreferencesAccess , ProvidersAccess , WebServicesAccess {
3131
3232 private static let forcedStatuses : [ VPNStatus ] = [
3333 . connected,
@@ -48,27 +48,6 @@ open class DefaultVPNProvider: VPNProvider, ConfigurationAccess, DatabaseAccess,
4848 }
4949 }
5050
51- // MARK: VPNProvider
52-
53- public var availableVPNTypes : [ String ] {
54- return accessedConfiguration. availableVPNTypes ( )
55- }
56-
57- public var currentVPNType : String {
58- return accessedPreferences. vpnType
59- }
60-
61- public var vpnStatus : VPNStatus {
62- return accessedDatabase. transient. vpnStatus
63- }
64-
65- public var profileServer : Server ? {
66- guard let identifier = activeProfile? . serverIdentifier else {
67- return nil
68- }
69- return accessedProviders. serverProvider. find ( withIdentifier: identifier)
70- }
71-
7251 var publicIP : String ? {
7352 return accessedDatabase. plain. publicIP
7453 }
@@ -90,6 +69,96 @@ open class DefaultVPNProvider: VPNProvider, ConfigurationAccess, DatabaseAccess,
9069 }
9170 }
9271
72+ private func isLegacyProfile( ) -> Bool {
73+ return DefaultVPNProvider . legacyProtocols. contains ( accessedPreferences. vpnType)
74+ }
75+
76+ @discardableResult private func activeProfileRemovingInactive( ) -> VPNProfile ? {
77+ let activeVPNType = accessedPreferences. vpnType
78+ let activeProfile : VPNProfile ? = accessedConfiguration. profile ( forVPNType: activeVPNType)
79+
80+ for vpnType in availableVPNTypes {
81+ let profile = accessedConfiguration. profile ( forVPNType: vpnType) !
82+ guard ( vpnType == activeVPNType) else {
83+ if let activeProfile = activeProfile {
84+ if !( ( profile. vpnType == IPSecProfile . vpnType || profile. vpnType == IKEv2Profile . vpnType) &&
85+ ( activeProfile. vpnType == IPSecProfile . vpnType || activeProfile. vpnType == IKEv2Profile . vpnType) ) {
86+ //only remove the profile if is not Ipsec or IKEv2, if are one of them, override instead
87+ profile. disconnect ( nil )
88+ profile. remove ( nil )
89+ }
90+ }
91+ continue
92+ }
93+ }
94+ return activeProfile
95+ }
96+
97+ private func vpnClientConfiguration( for profile: VPNProfile ? = nil ) -> VPNConfiguration ? {
98+ guard let currentUser = accessedProviders. accountProvider. currentUser else {
99+ log. error ( " vpnClientConfiguration: No current user available " )
100+ return nil
101+ }
102+
103+ guard let currentPasswordReference = accessedProviders. accountProvider. currentPasswordReference else {
104+ log. error ( " vpnClientConfiguration: No current password reference available " )
105+ return nil
106+ }
107+
108+ guard let profile = profile ?? activeProfile else {
109+ log. error ( " vpnClientConfiguration: No VPN profile available " )
110+ return nil
111+ }
112+
113+ guard let targetServer = try ? accessedProviders. serverProvider. targetServer else {
114+ log. error ( " vpnClientConfiguration: No target server available " )
115+ return nil
116+ }
117+
118+ let customConfiguration = accessedPreferences. vpnCustomConfiguration ( for: profile. vpnType)
119+
120+ return VPNConfiguration (
121+ name: accessedConfiguration. vpnProfileName,
122+ username: currentUser. credentials. username,
123+ passwordReference: currentPasswordReference,
124+ server: targetServer,
125+ isOnDemand: accessedPreferences. isPersistentConnection,
126+ disconnectsOnSleep: accessedPreferences. vpnDisconnectsOnSleep,
127+ customConfiguration: customConfiguration,
128+ leakProtection: accessedPreferences. leakProtection,
129+ allowLocalDeviceAccess: accessedPreferences. allowLocalDeviceAccess
130+ )
131+ }
132+
133+ // MARK: WebServicesConsumer
134+
135+ var webServices : WebServices {
136+ return customWebServices ?? accessedWebServices
137+ }
138+ }
139+
140+ // MARK: - VPNProvider extension
141+
142+ extension DefaultVPNProvider : VPNProvider {
143+ public var availableVPNTypes : [ String ] {
144+ return accessedConfiguration. availableVPNTypes ( )
145+ }
146+
147+ public var currentVPNType : String {
148+ return accessedPreferences. vpnType
149+ }
150+
151+ public var vpnStatus : VPNStatus {
152+ return accessedDatabase. transient. vpnStatus
153+ }
154+
155+ public var profileServer : Server ? {
156+ guard let identifier = activeProfile? . serverIdentifier else {
157+ return nil
158+ }
159+ return accessedProviders. serverProvider. find ( withIdentifier: identifier)
160+ }
161+
93162 public func prepare( ) throws {
94163
95164 var profile = activeProfileRemovingInactive ( )
@@ -139,42 +208,45 @@ open class DefaultVPNProvider: VPNProvider, ConfigurationAccess, DatabaseAccess,
139208
140209 public func install( force forceInstall: Bool , _ callback: SuccessLibraryCallback ? ) {
141210 guard accessedProviders. accountProvider. isLoggedIn else {
211+ log. error ( " VPN install failed: User is not logged in (unauthorized) " )
142212 callback ? ( ClientError . unauthorized)
143213 return
144214 }
145215
146216 let newVPNType = accessedPreferences. vpnType
147217 guard let profile = accessedConfiguration. profile ( forVPNType: newVPNType) else {
148- callback ? ( ClientError . vpnProfileUnavailable)
218+ log. error ( " VPN install failed: No profile configuration found for VPN type: \( newVPNType) " )
219+ callback ? ( ClientError . unsupportedVPNType)
149220 return
150221 }
151222
152223 var previousProfile : VPNProfile ?
153- if ( newVPNType != activeProfile? . vpnType) {
224+ if newVPNType != activeProfile? . vpnType {
154225 previousProfile = activeProfile
155226 }
156227
157228 let forcedStatuses = DefaultVPNProvider . forcedStatuses. contains ( accessedDatabase. transient. vpnStatus)
158- let installBlock : SuccessLibraryCallback = { ( error) in
229+ let installBlock : SuccessLibraryCallback = { error in
159230 guard let configuration = self . vpnClientConfiguration ( for: profile) else {
160231 callback ? ( ClientError . vpnProfileUnavailable)
161232 return
162233 }
163- profile. save ( withConfiguration: configuration, force: forcedStatuses) { ( error) in
164- if let error = error {
234+ profile. save ( withConfiguration: configuration, force: forcedStatuses) { error in
235+ if let error {
236+ log. error ( " VPN install failed: Profile save failed with error: \( error. localizedDescription) " )
165237 callback ? ( error)
166238 return
167239 }
168240 self . activeProfile = profile
169241
170- if let previousProfile = previousProfile ,
242+ if let previousProfile,
171243 !( ( profile. vpnType == IPSecProfile . vpnType || profile. vpnType == IKEv2Profile . vpnType) &&
172244 ( previousProfile. vpnType == IPSecProfile . vpnType || previousProfile. vpnType == IKEv2Profile . vpnType) ) {
173245 //only remove the profile if is not Ipsec or IKEv2, if are one of them, override instead
174- previousProfile. remove ( { _ in
246+ previousProfile. remove { _ in
175247 Macros . postNotification ( . PIAVPNDidInstall)
176248 callback ? ( nil )
177- } )
249+ }
178250 } else {
179251 if previousProfile != nil { // dont connect after install
180252 self . connect ( nil )
@@ -196,7 +268,19 @@ open class DefaultVPNProvider: VPNProvider, ConfigurationAccess, DatabaseAccess,
196268 }
197269 }
198270 }
199-
271+
272+ public func install( force forceInstall: Bool ) async throws {
273+ return try await withCheckedThrowingContinuation { continuation in
274+ install ( force: forceInstall) { error in
275+ if let error = error {
276+ continuation. resume ( throwing: error)
277+ } else {
278+ continuation. resume ( )
279+ }
280+ }
281+ }
282+ }
283+
200284 public func disable( _ callback: SuccessLibraryCallback ? ) {
201285 guard let activeProfile = activeProfile else {
202286 callback ? ( ClientError . vpnProfileUnavailable)
@@ -359,75 +443,7 @@ open class DefaultVPNProvider: VPNProvider, ConfigurationAccess, DatabaseAccess,
359443 callback ? ( usage, nil )
360444 }
361445 }
362-
363- private func isLegacyProfile( ) -> Bool {
364- return DefaultVPNProvider . legacyProtocols. contains ( accessedPreferences. vpnType)
365- }
366-
367- @discardableResult private func activeProfileRemovingInactive( ) -> VPNProfile ? {
368- let activeVPNType = accessedPreferences. vpnType
369- let activeProfile : VPNProfile ? = accessedConfiguration. profile ( forVPNType: activeVPNType)
370-
371- for vpnType in availableVPNTypes {
372- let profile = accessedConfiguration. profile ( forVPNType: vpnType) !
373- guard ( vpnType == activeVPNType) else {
374- if let activeProfile = activeProfile {
375- if !( ( profile. vpnType == IPSecProfile . vpnType || profile. vpnType == IKEv2Profile . vpnType) &&
376- ( activeProfile. vpnType == IPSecProfile . vpnType || activeProfile. vpnType == IKEv2Profile . vpnType) ) {
377- //only remove the profile if is not Ipsec or IKEv2, if are one of them, override instead
378- profile. disconnect ( nil )
379- profile. remove ( nil )
380- }
381- }
382- continue
383- }
384- }
385- return activeProfile
386- }
387-
388- private func vpnClientConfiguration( for profile: VPNProfile ? = nil ) -> VPNConfiguration ? {
389- guard let currentUser = accessedProviders. accountProvider. currentUser else {
390- log. error ( " vpnClientConfiguration: No current user available " )
391- return nil
392- }
393-
394- guard let currentPasswordReference = accessedProviders. accountProvider. currentPasswordReference else {
395- log. error ( " vpnClientConfiguration: No current password reference available " )
396- return nil
397- }
398-
399- guard let profile = profile ?? activeProfile else {
400- log. error ( " vpnClientConfiguration: No VPN profile available " )
401- return nil
402- }
403-
404- guard let targetServer = try ? accessedProviders. serverProvider. targetServer else {
405- log. error ( " vpnClientConfiguration: No target server available " )
406- return nil
407- }
408-
409- let customConfiguration = accessedPreferences. vpnCustomConfiguration ( for: profile. vpnType)
410446
411- return VPNConfiguration (
412- name: accessedConfiguration. vpnProfileName,
413- username: currentUser. credentials. username,
414- passwordReference: currentPasswordReference,
415- server: targetServer,
416- isOnDemand: accessedPreferences. isPersistentConnection,
417- disconnectsOnSleep: accessedPreferences. vpnDisconnectsOnSleep,
418- customConfiguration: customConfiguration,
419- leakProtection: accessedPreferences. leakProtection,
420- allowLocalDeviceAccess: accessedPreferences. allowLocalDeviceAccess
421- )
422- }
423-
424- // MARK: WebServicesConsumer
425-
426- var webServices : WebServices {
427- return customWebServices ?? accessedWebServices
428- }
429-
430- // MARK: Migration
431447 public func needsMigrationToGEN4( ) -> Bool {
432448 if isVPNConnected {
433449 let manager = NEVPNManager . shared ( )
0 commit comments