@@ -29,7 +29,16 @@ protocol SystemExtensionAsyncRecorder: Sendable {
29
29
extension CoderVPNService : SystemExtensionAsyncRecorder {
30
30
func recordSystemExtensionState( _ state: SystemExtensionState ) async {
31
31
sysExtnState = state
32
+ if state == . uninstalled {
33
+ installSystemExtension ( )
34
+ }
32
35
if state == . installed {
36
+ do {
37
+ try await getTunnelManager ( )
38
+ neState = . disabled
39
+ } catch {
40
+ neState = . unconfigured
41
+ }
33
42
// system extension was successfully installed, so we don't need the delegate any more
34
43
systemExtnDelegate = nil
35
44
}
@@ -64,7 +73,21 @@ extension CoderVPNService: SystemExtensionAsyncRecorder {
64
73
return extensionBundle
65
74
}
66
75
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( ) {
68
91
logger. info ( " activating SystemExtension " )
69
92
guard let bundleID = extensionBundle. bundleIdentifier else {
70
93
logger. error ( " Bundle has no identifier " )
@@ -74,11 +97,9 @@ extension CoderVPNService: SystemExtensionAsyncRecorder {
74
97
forExtensionWithIdentifier: bundleID,
75
98
queue: . main
76
99
)
77
- let delegate = SystemExtensionDelegate ( asyncDelegate: self )
78
- systemExtnDelegate = delegate
79
- request. delegate = delegate
100
+ request. delegate = systemExtnDelegate
80
101
OSSystemExtensionManager . shared. submitRequest ( request)
81
- logger. info ( " submitted SystemExtension request with bundleID: \( bundleID) " )
102
+ logger. info ( " submitted SystemExtension activate request with bundleID: \( bundleID) " )
82
103
}
83
104
}
84
105
@@ -88,6 +109,8 @@ class SystemExtensionDelegate<AsyncDelegate: SystemExtensionAsyncRecorder>:
88
109
NSObject , OSSystemExtensionRequestDelegate
89
110
{
90
111
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
91
114
private var asyncDelegate : AsyncDelegate
92
115
93
116
init ( asyncDelegate: AsyncDelegate ) {
@@ -138,4 +161,38 @@ class SystemExtensionDelegate<AsyncDelegate: SystemExtensionAsyncRecorder>:
138
161
logger. info ( " Replacing \( request. identifier) v \( existing. bundleShortVersion) with v \( `extension`. bundleShortVersion) " )
139
162
return . replace
140
163
}
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
+ }
141
198
}
0 commit comments