@@ -29,7 +29,16 @@ protocol SystemExtensionAsyncRecorder: Sendable {
2929extension CoderVPNService : SystemExtensionAsyncRecorder {
3030 func recordSystemExtensionState( _ state: SystemExtensionState ) async {
3131 sysExtnState = state
32+ if state == . uninstalled {
33+ installSystemExtension ( )
34+ }
3235 if state == . installed {
36+ do {
37+ try await getTunnelManager ( )
38+ neState = . disabled
39+ } catch {
40+ neState = . unconfigured
41+ }
3342 // system extension was successfully installed, so we don't need the delegate any more
3443 systemExtnDelegate = nil
3544 }
@@ -64,7 +73,21 @@ extension CoderVPNService: SystemExtensionAsyncRecorder {
6473 return extensionBundle
6574 }
6675
67- func installSystemExtension( ) {
76+ func checkSystemExtensionStatus( ) {
77+ logger. info ( " checking SystemExtension status " )
78+ guard let bundleID = extensionBundle. bundleIdentifier else {
79+ logger. error ( " Bundle has no identifier " )
80+ return
81+ }
82+ let request = OSSystemExtensionRequest . propertiesRequest ( forExtensionWithIdentifier: bundleID, queue: . main)
83+ let delegate = SystemExtensionDelegate ( asyncDelegate: self )
84+ request. delegate = delegate
85+ systemExtnDelegate = delegate
86+ OSSystemExtensionManager . shared. submitRequest ( request)
87+ logger. info ( " submitted SystemExtension properties request with bundleID: \( bundleID) " )
88+ }
89+
90+ private func installSystemExtension( ) {
6891 logger. info ( " activating SystemExtension " )
6992 guard let bundleID = extensionBundle. bundleIdentifier else {
7093 logger. error ( " Bundle has no identifier " )
@@ -74,11 +97,9 @@ extension CoderVPNService: SystemExtensionAsyncRecorder {
7497 forExtensionWithIdentifier: bundleID,
7598 queue: . main
7699 )
77- let delegate = SystemExtensionDelegate ( asyncDelegate: self )
78- systemExtnDelegate = delegate
79- request. delegate = delegate
100+ request. delegate = systemExtnDelegate
80101 OSSystemExtensionManager . shared. submitRequest ( request)
81- logger. info ( " submitted SystemExtension request with bundleID: \( bundleID) " )
102+ logger. info ( " submitted SystemExtension activate request with bundleID: \( bundleID) " )
82103 }
83104}
84105
@@ -88,6 +109,8 @@ class SystemExtensionDelegate<AsyncDelegate: SystemExtensionAsyncRecorder>:
88109 NSObject , OSSystemExtensionRequestDelegate
89110{
90111 private var logger = Logger ( subsystem: Bundle . main. bundleIdentifier!, category: " vpn-installer " )
112+ // TODO: Refactor this to use a continuation, so the result of a request can be
113+ // 'await'd for the determined state
91114 private var asyncDelegate : AsyncDelegate
92115
93116 init ( asyncDelegate: AsyncDelegate ) {
@@ -138,4 +161,38 @@ class SystemExtensionDelegate<AsyncDelegate: SystemExtensionAsyncRecorder>:
138161 logger. info ( " Replacing \( request. identifier) v \( existing. bundleShortVersion) with v \( `extension`. bundleShortVersion) " )
139162 return . replace
140163 }
164+
165+ public func request(
166+ _: OSSystemExtensionRequest ,
167+ foundProperties properties: [ OSSystemExtensionProperties ]
168+ ) {
169+ // In debug builds we always replace the SE to test
170+ // changes made without bumping the version
171+ #if DEBUG
172+ Task { [ asyncDelegate] in
173+ await asyncDelegate. recordSystemExtensionState ( . uninstalled)
174+ }
175+ return
176+ #else
177+ let version = Bundle . main. object ( forInfoDictionaryKey: " CFBundleVersion " ) as? String
178+ let shortVersion = Bundle . main. object ( forInfoDictionaryKey: " CFBundleShortVersionString " ) as? String
179+
180+ let versionMatches = properties. contains { sysex in
181+ sysex. isEnabled
182+ && sysex. bundleVersion == version
183+ && sysex. bundleShortVersion == shortVersion
184+ }
185+ if versionMatches {
186+ Task { [ asyncDelegate] in
187+ await asyncDelegate. recordSystemExtensionState ( . installed)
188+ }
189+ return
190+ }
191+
192+ // Either uninstalled or needs replacing
193+ Task { [ asyncDelegate] in
194+ await asyncDelegate. recordSystemExtensionState ( . uninstalled)
195+ }
196+ #endif
197+ }
141198}
0 commit comments