@blueid/access-capacitor 0.79.0 → 0.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ios/CBlueIDAccess.xcframework/Info.plist +8 -8
- package/ios/CBlueIDAccess.xcframework/ios-arm64/libCBlueIDAccess.a +0 -0
- package/ios/CBlueIDAccess.xcframework/ios-arm64_x86_64-simulator/libCBlueIDAccess.a +0 -0
- package/ios/CBlueIDAccess.xcframework/macos-arm64_x86_64/libCBlueIDAccess.a +0 -0
- package/ios/Plugin/BlueIDAccessSDK/BlueAccess.swift +3 -3
- package/ios/Plugin/BlueIDAccessSDK/BlueAccessSync.swift +3 -11
- package/ios/Plugin/BlueIDAccessSDK/BlueAccessSyncScheduler.swift +145 -0
- package/ios/Plugin/BlueIDAccessSDK/BlueApp.swift +0 -15
- package/ios/Plugin/BlueIDAccessSDK/BlueAppDelegate.swift +4 -4
- package/ios/Plugin/BlueIDAccessSDK/BlueTerminal.swift +15 -2
- package/package.json +1 -1
- package/ios/Plugin/BlueIDAccessSDK/BlueTokenSyncScheduler.swift +0 -265
|
@@ -10,15 +10,18 @@
|
|
|
10
10
|
<key>HeadersPath</key>
|
|
11
11
|
<string>Headers</string>
|
|
12
12
|
<key>LibraryIdentifier</key>
|
|
13
|
-
<string>ios-
|
|
13
|
+
<string>ios-arm64_x86_64-simulator</string>
|
|
14
14
|
<key>LibraryPath</key>
|
|
15
15
|
<string>libCBlueIDAccess.a</string>
|
|
16
16
|
<key>SupportedArchitectures</key>
|
|
17
17
|
<array>
|
|
18
18
|
<string>arm64</string>
|
|
19
|
+
<string>x86_64</string>
|
|
19
20
|
</array>
|
|
20
21
|
<key>SupportedPlatform</key>
|
|
21
22
|
<string>ios</string>
|
|
23
|
+
<key>SupportedPlatformVariant</key>
|
|
24
|
+
<string>simulator</string>
|
|
22
25
|
</dict>
|
|
23
26
|
<dict>
|
|
24
27
|
<key>BinaryPath</key>
|
|
@@ -26,16 +29,15 @@
|
|
|
26
29
|
<key>HeadersPath</key>
|
|
27
30
|
<string>Headers</string>
|
|
28
31
|
<key>LibraryIdentifier</key>
|
|
29
|
-
<string>
|
|
32
|
+
<string>ios-arm64</string>
|
|
30
33
|
<key>LibraryPath</key>
|
|
31
34
|
<string>libCBlueIDAccess.a</string>
|
|
32
35
|
<key>SupportedArchitectures</key>
|
|
33
36
|
<array>
|
|
34
37
|
<string>arm64</string>
|
|
35
|
-
<string>x86_64</string>
|
|
36
38
|
</array>
|
|
37
39
|
<key>SupportedPlatform</key>
|
|
38
|
-
<string>
|
|
40
|
+
<string>ios</string>
|
|
39
41
|
</dict>
|
|
40
42
|
<dict>
|
|
41
43
|
<key>BinaryPath</key>
|
|
@@ -43,7 +45,7 @@
|
|
|
43
45
|
<key>HeadersPath</key>
|
|
44
46
|
<string>Headers</string>
|
|
45
47
|
<key>LibraryIdentifier</key>
|
|
46
|
-
<string>
|
|
48
|
+
<string>macos-arm64_x86_64</string>
|
|
47
49
|
<key>LibraryPath</key>
|
|
48
50
|
<string>libCBlueIDAccess.a</string>
|
|
49
51
|
<key>SupportedArchitectures</key>
|
|
@@ -52,9 +54,7 @@
|
|
|
52
54
|
<string>x86_64</string>
|
|
53
55
|
</array>
|
|
54
56
|
<key>SupportedPlatform</key>
|
|
55
|
-
<string>
|
|
56
|
-
<key>SupportedPlatformVariant</key>
|
|
57
|
-
<string>simulator</string>
|
|
57
|
+
<string>macos</string>
|
|
58
58
|
</dict>
|
|
59
59
|
</array>
|
|
60
60
|
<key>CFBundlePackageType</key>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -500,9 +500,9 @@ public struct BlueTryAccessDeviceCommand: BlueAsyncCommand {
|
|
|
500
500
|
/// A modal view (sheet) is shown in iOS to represent the progress of the command execution.
|
|
501
501
|
///
|
|
502
502
|
/// - parameter deviceID: The Device ID.
|
|
503
|
-
/// - throws: Throws an error of type `BlueError(.
|
|
504
|
-
/// - throws: Throws an error of type `BlueError(.
|
|
505
|
-
/// - throws: Throws an error of type `BlueError(.
|
|
503
|
+
/// - throws: Throws an error of type `BlueError(.sdkDeviceNotFound)` if the device could not be found.
|
|
504
|
+
/// - throws: Throws an error of type `BlueError(.sdkSpTokenNotFound)` if neither an OssSo nor an OssSid token is found.
|
|
505
|
+
/// - throws: Throws an error of type `BlueError(.sdkUnsupportedPlatform)` If the macOS version is earlier than 10.15.
|
|
506
506
|
public func runAsync(deviceID: String) async throws -> BlueOssAccessResult {
|
|
507
507
|
guard let device = blueGetDevice(deviceID) else {
|
|
508
508
|
throw BlueError(.sdkDeviceNotFound)
|
|
@@ -150,22 +150,16 @@ internal class BlueSynchronizeMobileAccessCommand: BlueAbstractSynchronizeAccess
|
|
|
150
150
|
override func purge(_ credential: BlueAccessCredential) throws {
|
|
151
151
|
_ = try? blueAccessCredentialsKeyChain.deleteEntry(id: credential.credentialID.id)
|
|
152
152
|
_ = try? blueAccessAuthenticationTokensKeyChain.deleteEntry(id: credential.credentialID.id)
|
|
153
|
+
_ = try? blueDeleteSpTokens(credential: credential)
|
|
153
154
|
|
|
154
155
|
guard let deviceList = try? BlueGetAccessDevicesCommand().run(credentialID: credential.credentialID.id) else {
|
|
155
156
|
return
|
|
156
157
|
}
|
|
157
|
-
|
|
158
|
-
purgeSpTokens(credential, deviceList.devices)
|
|
158
|
+
|
|
159
159
|
purgeTerminalPublicKeys(deviceList.devices)
|
|
160
160
|
purgeDevicesStorage(credential)
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
private func purgeSpTokens(_ credential: BlueAccessCredential, _ devices: [BlueAccessDevice]) {
|
|
164
|
-
devices.forEach { device in
|
|
165
|
-
_ = try? blueDeleteSpTokens(credential: credential, deviceID: device.deviceID)
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
163
|
/// Deletes terminal public keys for a given device list.
|
|
170
164
|
/// The terminal public keys are only removed if there are no BlueSPTokens in use by the device.
|
|
171
165
|
/// We may have more than one credential that grants access to the same device.
|
|
@@ -197,7 +191,6 @@ public class BlueSynchronizeAccessCredentialsCommand: BlueAPIAsyncCommand {
|
|
|
197
191
|
}
|
|
198
192
|
|
|
199
193
|
/// Synchronizes all stored credentials.
|
|
200
|
-
/// Note: Master credentials are not synced in case of any, as they can only be synced once during the claiming process.
|
|
201
194
|
///
|
|
202
195
|
/// - throws: Throws an error of type `BlueError(.sdkUnsupportedPlatform)` If the macOS version is earlier than 10.15.
|
|
203
196
|
/// - returns: The exit status (BlueReturnCode) of each credential, and its error description, if any.
|
|
@@ -206,8 +199,7 @@ public class BlueSynchronizeAccessCredentialsCommand: BlueAPIAsyncCommand {
|
|
|
206
199
|
throw BlueError(.sdkUnsupportedPlatform)
|
|
207
200
|
}
|
|
208
201
|
|
|
209
|
-
|
|
210
|
-
.filter { $0.credentialType != .master }
|
|
202
|
+
var credentials = try await BlueGetAccessCredentialsCommand().runAsync().credentials
|
|
211
203
|
|
|
212
204
|
if (credentials.isEmpty) {
|
|
213
205
|
return BlueSynchronizeAccessCredentials()
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
private class ForegroundScheduler {
|
|
4
|
+
private var timer: Timer?
|
|
5
|
+
private var scheduler: BlueAccessSyncScheduler?
|
|
6
|
+
|
|
7
|
+
func setup(_ scheduler: BlueAccessSyncScheduler) {
|
|
8
|
+
self.scheduler = scheduler
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
func suspend() {
|
|
12
|
+
timer?.invalidate()
|
|
13
|
+
timer = nil
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
func schedule(_ now: Bool? = false) {
|
|
17
|
+
guard #available(macOS 10.15, *) else {
|
|
18
|
+
blueLogWarn("Unsupported platform")
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
suspend()
|
|
23
|
+
|
|
24
|
+
if now == true {
|
|
25
|
+
self.handleTask()
|
|
26
|
+
} else {
|
|
27
|
+
blueRunInMainThread {
|
|
28
|
+
self.timer = Timer.scheduledTimer(
|
|
29
|
+
timeInterval: self.scheduler!.timeInterval,
|
|
30
|
+
target: self,
|
|
31
|
+
selector: #selector(self.handleTask),
|
|
32
|
+
userInfo: nil,
|
|
33
|
+
repeats: false
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@available(macOS 10.15, *)
|
|
40
|
+
@objc private func handleTask() {
|
|
41
|
+
DispatchQueue.global(qos: .background).async {
|
|
42
|
+
Task {
|
|
43
|
+
do {
|
|
44
|
+
try await self.scheduler!.synchronizeAccessCredentials()
|
|
45
|
+
} catch {
|
|
46
|
+
blueLogError(error.localizedDescription)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (self.scheduler!.autoSchedule) {
|
|
50
|
+
self.schedule()
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
internal class BlueAccessSyncScheduler: BlueEventListener {
|
|
58
|
+
public static let shared = BlueAccessSyncScheduler()
|
|
59
|
+
|
|
60
|
+
let timeInterval: TimeInterval
|
|
61
|
+
let autoSchedule: Bool
|
|
62
|
+
|
|
63
|
+
private let foregroundScheduler = ForegroundScheduler()
|
|
64
|
+
|
|
65
|
+
private let command: BlueSynchronizeAccessCredentialsCommand
|
|
66
|
+
|
|
67
|
+
private var syncing = false
|
|
68
|
+
|
|
69
|
+
init(
|
|
70
|
+
timeInterval: TimeInterval? = 60 * 60 * 6, // every 6h by default
|
|
71
|
+
autoSchedule: Bool? = true,
|
|
72
|
+
command: BlueSynchronizeAccessCredentialsCommand? = nil
|
|
73
|
+
) {
|
|
74
|
+
self.command = command ?? blueCommands.synchronizeAccessCredentials
|
|
75
|
+
self.timeInterval = timeInterval ?? 60
|
|
76
|
+
self.autoSchedule = autoSchedule ?? true
|
|
77
|
+
|
|
78
|
+
foregroundScheduler.setup(self)
|
|
79
|
+
|
|
80
|
+
blueAddEventListener(listener: self)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
deinit {
|
|
84
|
+
blueRemoveEventListener(listener: self)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
func willResignActive() {
|
|
88
|
+
suspend()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
func willTerminate() {
|
|
92
|
+
suspend()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
func didBecomeActive() {
|
|
96
|
+
schedule(true)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func didFinishLaunching() {
|
|
100
|
+
schedule(true)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
func blueEvent(event: BlueEventType, data: Any?) {
|
|
104
|
+
if (event == .accessCredentialAdded) {
|
|
105
|
+
schedule()
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
func schedule(_ now: Bool? = false) {
|
|
110
|
+
do {
|
|
111
|
+
guard try blueAccessCredentialsKeyChain.getNumberOfEntries() > 0 else {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
blueLogError(error.localizedDescription)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
blueRemoveEventListener(listener: self)
|
|
119
|
+
|
|
120
|
+
foregroundScheduler.schedule(now)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
func suspend() {
|
|
124
|
+
foregroundScheduler.suspend()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
func synchronizeAccessCredentials() async throws -> Void {
|
|
128
|
+
if (syncing) {
|
|
129
|
+
blueLogInfo("There is already a synchronization in progress")
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
syncing = true
|
|
134
|
+
|
|
135
|
+
blueFireListeners(fireEvent: BlueEventType.tokenSyncStarted, data: nil)
|
|
136
|
+
|
|
137
|
+
defer {
|
|
138
|
+
syncing = false
|
|
139
|
+
|
|
140
|
+
blueFireListeners(fireEvent: BlueEventType.tokenSyncFinished, data: nil)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
_ = try await command.runAsync()
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -40,18 +40,3 @@ public struct BlueOpenAppSettingsCommand: BlueAsyncCommand {
|
|
|
40
40
|
completionHandler(false)
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
internal func blueAppHasLaunchedBefore() -> Bool {
|
|
45
|
-
if let hasLaunchedBefore = hasLaunchedBefore {
|
|
46
|
-
return hasLaunchedBefore
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
let result = blueAppStorage.getBool(id: "hasLaunchedBefore")
|
|
50
|
-
if (!result) {
|
|
51
|
-
blueAppStorage.storeBool(id: "hasLaunchedBefore", bool: true)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
hasLaunchedBefore = true
|
|
55
|
-
|
|
56
|
-
return result
|
|
57
|
-
}
|
|
@@ -18,7 +18,7 @@ public final class BlueAppDelegate: NSObject {
|
|
|
18
18
|
}
|
|
19
19
|
#endif
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
BlueAccessSyncScheduler.shared.didFinishLaunching()
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
#if os(iOS) || os(watchOS)
|
|
@@ -38,7 +38,7 @@ public final class BlueAppDelegate: NSObject {
|
|
|
38
38
|
#endif
|
|
39
39
|
|
|
40
40
|
@objc public static func willResignActive() {
|
|
41
|
-
|
|
41
|
+
BlueAccessSyncScheduler.shared.willResignActive()
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
@objc public static func didBecomeActive() {
|
|
@@ -46,7 +46,7 @@ public final class BlueAppDelegate: NSObject {
|
|
|
46
46
|
blueNearbyAppBecameActive()
|
|
47
47
|
#endif
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
BlueAccessSyncScheduler.shared.didBecomeActive()
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
@objc public static func didEnterBackground() {
|
|
@@ -62,6 +62,6 @@ public final class BlueAppDelegate: NSObject {
|
|
|
62
62
|
fatalError(error.localizedDescription)
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
BlueAccessSyncScheduler.shared.willTerminate()
|
|
66
66
|
}
|
|
67
67
|
}
|
|
@@ -66,10 +66,22 @@ internal func blueStoreSpToken(credential: BlueAccessCredential, deviceID: Strin
|
|
|
66
66
|
)
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
/// Deletes all SP Tokens for a given credential.
|
|
70
|
+
///
|
|
71
|
+
/// - parameter credential: The credential.
|
|
72
|
+
/// - throws: An error is thrown if any error occurs during the retrieval of the entry IDs from the KeyChain.
|
|
73
|
+
internal func blueDeleteSpTokens(credential: BlueAccessCredential) throws {
|
|
74
|
+
try blueTerminalRequestDataKeychain.getEntryIds().forEach { entryID in
|
|
75
|
+
|
|
71
76
|
if let storedEntry = try? blueGetSpTokenEntry(entryID) {
|
|
77
|
+
|
|
72
78
|
if var spTokenEntries = storedEntry as? [BlueSPTokenEntry] {
|
|
79
|
+
|
|
80
|
+
let matchCredential = spTokenEntries.contains(where: { $0.credentialID == credential.credentialID.id })
|
|
81
|
+
guard matchCredential else {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
73
85
|
spTokenEntries.removeAll( where: { $0.credentialID == credential.credentialID.id } )
|
|
74
86
|
|
|
75
87
|
if (spTokenEntries.isEmpty) {
|
|
@@ -81,6 +93,7 @@ internal func blueDeleteSpTokens(credential: BlueAccessCredential, deviceID: Str
|
|
|
81
93
|
)
|
|
82
94
|
}
|
|
83
95
|
}
|
|
96
|
+
|
|
84
97
|
else if var _ = storedEntry as? Data {
|
|
85
98
|
_ = try? blueTerminalRequestDataKeychain.deleteEntry(id: entryID)
|
|
86
99
|
}
|
package/package.json
CHANGED
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// BlueTokenSyncScheduler.swift
|
|
3
|
-
//
|
|
4
|
-
// Description: Synchronize all tokens from all available credentials at specific intervals.
|
|
5
|
-
//
|
|
6
|
-
// If you would like to test the background task during development, execute the following code in the console:
|
|
7
|
-
// ```
|
|
8
|
-
// e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.blue-id.BlueTokenSyncScheduler"]
|
|
9
|
-
// ```
|
|
10
|
-
//
|
|
11
|
-
// Reference: https://developer.apple.com/documentation/backgroundtasks/starting-and-terminating-tasks-during-development#Launch-a-Task
|
|
12
|
-
//
|
|
13
|
-
// Copyright © 2023 BlueID. All rights reserved.
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
import Foundation
|
|
17
|
-
|
|
18
|
-
private let bgTaskIdentifier = "com.blue-id.BlueTokenSyncScheduler"
|
|
19
|
-
|
|
20
|
-
private class ForegroundScheduler {
|
|
21
|
-
private var timer: Timer?
|
|
22
|
-
private var scheduler: BlueTokenSyncScheduler?
|
|
23
|
-
|
|
24
|
-
func setup(_ scheduler: BlueTokenSyncScheduler) {
|
|
25
|
-
self.scheduler = scheduler
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
func suspend() {
|
|
29
|
-
timer?.invalidate()
|
|
30
|
-
timer = nil
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
func schedule(_ now: Bool? = false) {
|
|
34
|
-
guard #available(macOS 10.15, *) else {
|
|
35
|
-
blueLogWarn("Unsupported platform")
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
suspend()
|
|
40
|
-
|
|
41
|
-
if now == true {
|
|
42
|
-
self.handleTask()
|
|
43
|
-
} else {
|
|
44
|
-
blueRunInMainThread {
|
|
45
|
-
self.timer = Timer.scheduledTimer(
|
|
46
|
-
timeInterval: self.scheduler!.timeInterval,
|
|
47
|
-
target: self,
|
|
48
|
-
selector: #selector(self.handleTask),
|
|
49
|
-
userInfo: nil,
|
|
50
|
-
repeats: false
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
@available(macOS 10.15, *)
|
|
57
|
-
@objc private func handleTask() {
|
|
58
|
-
DispatchQueue.global(qos: .background).async {
|
|
59
|
-
Task {
|
|
60
|
-
do {
|
|
61
|
-
try await self.scheduler!.syncTokens()
|
|
62
|
-
} catch {
|
|
63
|
-
blueLogError("Tokens could not be synchronized")
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (self.scheduler!.autoSchedule) {
|
|
67
|
-
self.schedule()
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
#if os(iOS) || os(watchOS)
|
|
76
|
-
import BackgroundTasks
|
|
77
|
-
|
|
78
|
-
private class BackgroundScheduler {
|
|
79
|
-
private var scheduler: BlueTokenSyncScheduler?
|
|
80
|
-
|
|
81
|
-
func setup(_ scheduler: BlueTokenSyncScheduler) {
|
|
82
|
-
self.scheduler = scheduler
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
func registerIdentifiers() {
|
|
86
|
-
let registered = BGTaskScheduler.shared.register(forTaskWithIdentifier: bgTaskIdentifier, using: DispatchQueue.global()) { task in
|
|
87
|
-
self.handleTask(task: task as! BGProcessingTask)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (!registered) {
|
|
91
|
-
blueLogWarn("Could not register background task identifier: \(bgTaskIdentifier)")
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
blueLogDebug("Background task identifier has been successfully registered: \(bgTaskIdentifier)")
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
func suspend() {
|
|
99
|
-
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: bgTaskIdentifier)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
func schedule() {
|
|
103
|
-
do {
|
|
104
|
-
let request = BGProcessingTaskRequest(identifier: bgTaskIdentifier)
|
|
105
|
-
request.earliestBeginDate = Date(timeIntervalSinceNow: scheduler!.timeInterval)
|
|
106
|
-
request.requiresNetworkConnectivity = true
|
|
107
|
-
|
|
108
|
-
try BGTaskScheduler.shared.submit(request)
|
|
109
|
-
|
|
110
|
-
blueLogDebug("Background task has been successfully scheduled")
|
|
111
|
-
} catch {
|
|
112
|
-
blueLogError("Background task could not be scheduled: \(error)")
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private func handleTask(task: BGProcessingTask) -> Void {
|
|
117
|
-
task.expirationHandler = {
|
|
118
|
-
task.setTaskCompleted(success: false)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
Task {
|
|
122
|
-
do {
|
|
123
|
-
try await scheduler!.syncTokens()
|
|
124
|
-
|
|
125
|
-
task.setTaskCompleted(success: true)
|
|
126
|
-
} catch {
|
|
127
|
-
task.setTaskCompleted(success: false)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (scheduler!.autoSchedule) {
|
|
131
|
-
schedule()
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
#endif
|
|
137
|
-
|
|
138
|
-
internal class BlueTokenSyncScheduler: BlueEventListener {
|
|
139
|
-
public static let shared = BlueTokenSyncScheduler()
|
|
140
|
-
|
|
141
|
-
let timeInterval: TimeInterval
|
|
142
|
-
let autoSchedule: Bool
|
|
143
|
-
|
|
144
|
-
#if os(iOS) || os(watchOS)
|
|
145
|
-
private let backgroundScheduler = BackgroundScheduler()
|
|
146
|
-
#endif
|
|
147
|
-
|
|
148
|
-
private let foregroundScheduler = ForegroundScheduler()
|
|
149
|
-
|
|
150
|
-
private let command: BlueSynchronizeAccessCredentialCommand
|
|
151
|
-
|
|
152
|
-
init(
|
|
153
|
-
timeInterval: TimeInterval? = 60,
|
|
154
|
-
autoSchedule: Bool? = true,
|
|
155
|
-
command: BlueSynchronizeAccessCredentialCommand? = nil
|
|
156
|
-
) {
|
|
157
|
-
self.command = command ?? blueCommands.synchronizeAccessCredential
|
|
158
|
-
self.timeInterval = timeInterval ?? 60
|
|
159
|
-
self.autoSchedule = autoSchedule ?? true
|
|
160
|
-
|
|
161
|
-
foregroundScheduler.setup(self)
|
|
162
|
-
|
|
163
|
-
#if os(iOS) || os(watchOS)
|
|
164
|
-
backgroundScheduler.setup(self)
|
|
165
|
-
#endif
|
|
166
|
-
|
|
167
|
-
blueAddEventListener(listener: self)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
deinit {
|
|
171
|
-
blueRemoveEventListener(listener: self)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
func willResignActive() {
|
|
175
|
-
foregroundScheduler.suspend()
|
|
176
|
-
|
|
177
|
-
#if os(iOS) || os(watchOS)
|
|
178
|
-
backgroundScheduler.schedule()
|
|
179
|
-
#endif
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
func didBecomeActive() {
|
|
183
|
-
#if os(iOS) || os(watchOS)
|
|
184
|
-
backgroundScheduler.suspend()
|
|
185
|
-
#endif
|
|
186
|
-
|
|
187
|
-
foregroundScheduler.schedule()
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
func didFinishLaunching() {
|
|
191
|
-
setup()
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
func willTerminate() {
|
|
195
|
-
suspend()
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
func blueEvent(event: BlueEventType, data: Any?) {
|
|
199
|
-
if (event == .accessCredentialAdded) {
|
|
200
|
-
schedule()
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
func setup() {
|
|
205
|
-
#if os(iOS)
|
|
206
|
-
backgroundScheduler.registerIdentifiers()
|
|
207
|
-
#endif
|
|
208
|
-
|
|
209
|
-
schedule(true)
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
func schedule(_ now: Bool? = false) {
|
|
213
|
-
do {
|
|
214
|
-
guard try blueAccessCredentialsKeyChain.getNumberOfEntries() > 0 else {
|
|
215
|
-
return
|
|
216
|
-
}
|
|
217
|
-
} catch {
|
|
218
|
-
blueLogError(error.localizedDescription)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
blueRemoveEventListener(listener: self)
|
|
222
|
-
|
|
223
|
-
foregroundScheduler.schedule(now)
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
func suspend() {
|
|
227
|
-
foregroundScheduler.suspend()
|
|
228
|
-
|
|
229
|
-
#if os(iOS) || os(watchOS)
|
|
230
|
-
backgroundScheduler.suspend()
|
|
231
|
-
#endif
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
@available(macOS 10.15, *)
|
|
235
|
-
func syncTokens() async throws -> Void {
|
|
236
|
-
blueFireListeners(fireEvent: BlueEventType.tokenSyncStarted, data: nil)
|
|
237
|
-
|
|
238
|
-
defer {
|
|
239
|
-
blueFireListeners(fireEvent: BlueEventType.tokenSyncFinished, data: nil)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
let accessCredentialList = try await blueCommands.getAccessCredentials.runAsync()
|
|
243
|
-
|
|
244
|
-
await withThrowingTaskGroup(of: Void.self) { group in
|
|
245
|
-
// After deleting the app, since we store credentials in KeyChain Access, they reappear upon app reinstallation.
|
|
246
|
-
// But, as the device list is not saved there, it is lost.
|
|
247
|
-
// So, when searching for nearby devices, nothing is shown due to the absence of the device list.
|
|
248
|
-
// Although this issue would be solved in this synchronization, the synchronization may not return the device list as it depends on the refresh rate and can take up to 30 days, which is not ideal.
|
|
249
|
-
// Therefore, we force a refresh in case the app has never been launched before.
|
|
250
|
-
let forceRefresh = !blueAppHasLaunchedBefore()
|
|
251
|
-
|
|
252
|
-
for credential in accessCredentialList.credentials {
|
|
253
|
-
group.addTask {
|
|
254
|
-
do {
|
|
255
|
-
try await self.command.runAsync(credentialID: credential.credentialID.id, forceRefresh: forceRefresh)
|
|
256
|
-
|
|
257
|
-
blueLogDebug("Access credential has been successfully synchronized: \(credential.credentialID.id)")
|
|
258
|
-
} catch {
|
|
259
|
-
blueLogError("Access credential could not be synchronized: \(credential.credentialID.id) - \(error.localizedDescription)")
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|