@@ -25,10 +25,10 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
25
25
private let authBridgeItemService : AuthenticatorBridgeItemService
26
26
27
27
/// The Tasks listening for Cipher updates (one for each user, indexed by the userId).
28
- private var cipherPublisherTasks = [ String : Task < Void , Error > ? ] ( )
28
+ private var cipherPublisherTasks = [ String : Task < Void , Error > ] ( )
29
29
30
30
/// The service used to manage syncing and updates to the user's ciphers.
31
- private let cipherService : CipherService
31
+ private let cipherDataStore : CipherDataStore
32
32
33
33
/// The service that handles common client functionality such as encryption and decryption.
34
34
private let clientService : ClientService
@@ -51,10 +51,6 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
51
51
/// The service used by the application to manage account state.
52
52
private let stateService : StateService
53
53
54
- /// a Task that subscribes to the sync setting publisher for accounts. This allows us to take action once
55
- /// a user opts-in to Authenticator sync.
56
- private var syncSettingSubscriberTask : Task < Void , Error > ?
57
-
58
54
/// The service used by the application to manage vault access.
59
55
private let vaultTimeoutService : VaultTimeoutService
60
56
@@ -64,7 +60,7 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
64
60
///
65
61
/// - Parameters:
66
62
/// - authBridgeItemService: The service for managing sharing items to/from the Authenticator app.
67
- /// - cipherService : The service used to manage syncing and updates to the user's ciphers.
63
+ /// - cipherDataStore : The service used to manage syncing and updates to the user's ciphers.
68
64
/// - clientService: The service that handles common client functionality such as encryption and decryption.
69
65
/// - configService: The service to get server-specified configuration.
70
66
/// - errorReporter: The service used by the application to report non-fatal errors.\ organizations.
@@ -76,7 +72,7 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
76
72
///
77
73
init (
78
74
authBridgeItemService: AuthenticatorBridgeItemService ,
79
- cipherService : CipherService ,
75
+ cipherDataStore : CipherDataStore ,
80
76
clientService: ClientService ,
81
77
configService: ConfigService ,
82
78
errorReporter: ErrorReporter ,
@@ -86,7 +82,7 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
86
82
vaultTimeoutService: VaultTimeoutService
87
83
) {
88
84
self . authBridgeItemService = authBridgeItemService
89
- self . cipherService = cipherService
85
+ self . cipherDataStore = cipherDataStore
90
86
self . clientService = clientService
91
87
self . configService = configService
92
88
self . errorReporter = errorReporter
@@ -102,9 +98,33 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
102
98
public func start( ) async {
103
99
guard !started else { return }
104
100
started = true
105
- if await configService. getFeatureFlag ( FeatureFlag . enableAuthenticatorSync,
106
- defaultValue: false ) {
107
- subscribeToAppState ( )
101
+
102
+ guard await configService. getFeatureFlag ( FeatureFlag . enableAuthenticatorSync,
103
+ defaultValue: false ) else {
104
+ return
105
+ }
106
+
107
+ Task {
108
+ for await (userId, _) in await self . stateService. syncToAuthenticatorPublisher ( ) . values {
109
+ guard let userId else { continue }
110
+
111
+ do {
112
+ try await determineSyncForUserId ( userId)
113
+ } catch {
114
+ errorReporter. log ( error: error)
115
+ }
116
+ }
117
+ }
118
+ Task {
119
+ for await vaultStatus in await self . vaultTimeoutService. vaultLockStatusPublisher ( ) . values {
120
+ guard let vaultStatus else { continue }
121
+
122
+ do {
123
+ try await determineSyncForUserId ( vaultStatus. userId)
124
+ } catch {
125
+ errorReporter. log ( error: error)
126
+ }
127
+ }
108
128
}
109
129
}
110
130
@@ -138,10 +158,10 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
138
158
&& cipher. login? . totp != nil
139
159
}
140
160
let decryptedCiphers = try await totpCiphers. asyncMap { cipher in
141
- try await self . clientService. vault ( ) . ciphers ( ) . decrypt ( cipher: cipher)
161
+ try await self . clientService. vault ( for : userId ) . ciphers ( ) . decrypt ( cipher: cipher)
142
162
}
143
163
let account = try await stateService. getActiveAccount ( )
144
- let username = account. profile. name ?? account . profile . email
164
+ let username = account. profile. email
145
165
146
166
return decryptedCiphers. map { cipher in
147
167
AuthenticatorBridgeItemDataView (
@@ -154,43 +174,24 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
154
174
}
155
175
}
156
176
157
- /// This function handles the initial syncing with the Authenticator app as well as listening for updates
158
- /// when the user adds new items. This is called when the sync is turned on.
177
+ /// Determine if the given userId has sync turned on and an unlocked vault. This method serves as the
178
+ /// integration point of both the sync settings subscriber and the vault subscriber. When the user has sync turned
179
+ /// on and the vault unlocked, we can proceed with the sync.
159
180
///
160
- /// - Parameter userId: The userId of the user who has turned on sync .
181
+ /// - Parameter userId: The userId of the user whose sync status is being determined .
161
182
///
162
- private func handleSyncOnForUserId( _ userId: String ) async {
163
- guard !vaultTimeoutService. isLocked ( userId: userId) else {
183
+ private func determineSyncForUserId( _ userId: String ) async throws {
184
+ guard try await stateService. getSyncToAuthenticator ( userId: userId) ,
185
+ !vaultTimeoutService. isLocked ( userId: userId) else {
186
+ cipherPublisherTasks [ userId] ? . cancel ( )
187
+ cipherPublisherTasks. removeValue ( forKey: userId)
164
188
return
165
189
}
166
190
167
- do {
168
- try await createAuthenticatorKeyIfNeeded ( )
169
- } catch {
170
- errorReporter. log ( error: error)
171
- }
191
+ try await createAuthenticatorKeyIfNeeded ( )
172
192
subscribeToCipherUpdates ( userId: userId)
173
193
}
174
194
175
- /// This function handles stopping sync and cleaning up all sync-related items when a user has turned sync Off.
176
- ///
177
- /// - Parameter userId: The userId of the user who has turned off sync.
178
- ///
179
- private func handleSyncOffForUserId( _ userId: String ) {
180
- cipherPublisherTasks [ userId] ?? . cancel( )
181
- cipherPublisherTasks [ userId] = nil
182
- }
183
-
184
- /// Subscribe to NotificationCenter updates about if the app is in the foreground vs. background.
185
- ///
186
- private func subscribeToAppState( ) {
187
- Task {
188
- for await _ in notificationCenterService. willEnterForegroundPublisher ( ) {
189
- subscribeToSyncToAuthenticatorSetting ( )
190
- }
191
- }
192
- }
193
-
194
195
/// Create a task for the given userId to listen for Cipher updates and sync to the Authenticator store.
195
196
///
196
197
/// - Parameter userId: The userId of the account to listen for.
@@ -200,7 +201,7 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
200
201
201
202
cipherPublisherTasks [ userId] = Task {
202
203
do {
203
- for try await ciphers in try await self . cipherService . ciphersPublisher ( ) . values {
204
+ for try await ciphers in self . cipherDataStore . cipherPublisher ( userId : userId ) . values {
204
205
try await writeCiphers ( ciphers: ciphers, userId: userId)
205
206
}
206
207
} catch {
@@ -209,31 +210,15 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
209
210
}
210
211
}
211
212
212
- /// Subscribe to the Sync to Authenticator setting to handle when the user grants (or revokes)
213
- /// permission to sync items to the Authenticator app.
214
- ///
215
- private func subscribeToSyncToAuthenticatorSetting( ) {
216
- syncSettingSubscriberTask? . cancel ( )
217
- syncSettingSubscriberTask = Task {
218
- for await (userId, shouldSync) in await self . stateService. syncToAuthenticatorPublisher ( ) . values {
219
- guard let userId else { continue }
220
-
221
- if shouldSync {
222
- await handleSyncOnForUserId ( userId)
223
- } else {
224
- handleSyncOffForUserId ( userId)
225
- }
226
- }
227
- }
228
- }
229
-
230
213
/// Takes in a list of encrypted Ciphers, decrypts them, and writes ones with TOTP codes to the shared store.
231
214
///
232
215
/// - Parameters:
233
216
/// - ciphers: The array of Ciphers belonging to a user to decrypt and store if necessary.
234
217
/// - userId: The userId of the account to which the Ciphers belong.
235
218
///
236
219
private func writeCiphers( ciphers: [ Cipher ] , userId: String ) async throws {
220
+ guard !vaultTimeoutService. isLocked ( userId: userId) else { return }
221
+
237
222
let items = try await decryptTOTPs ( ciphers, userId: userId)
238
223
try await authBridgeItemService. replaceAllItems ( with: items, forUserId: userId)
239
224
}
0 commit comments