]> git.saurik.com Git - apple/security.git/blob - keychain/TrustedPeersHelper/Client.swift
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / TrustedPeersHelper / Client.swift
1 /*
2 * Copyright (c) 2018 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 import Foundation
25
26 extension Error {
27 func sanitizeForClientXPC() -> Error {
28 let nserror = self as NSError
29
30 // CoreData errors might have extra things in them that need removal.
31 if nserror.domain == NSCocoaErrorDomain {
32 return nserror.cleanAllButDescription()
33 }
34
35 // The docs for CKXPCSuitableError say it only returns nil if you pass it nil, but swift can't read those.
36 guard let ckCleanedError = CKXPCSuitableError(self) else {
37 return ContainerError.unknownCloudKitError
38 }
39 return ckCleanedError
40 }
41 }
42
43 extension NSError {
44 func cleanAllButDescription() -> NSError {
45 let userInfo: [String: AnyHashable]?
46 if let description = self.userInfo[NSLocalizedDescriptionKey] as? AnyHashable {
47 userInfo = [NSLocalizedDescriptionKey: description]
48 } else {
49 userInfo = nil
50 }
51
52 return NSError(domain: self.domain,
53 code: self.code,
54 userInfo: userInfo)
55 }
56 }
57
58 class Client: TrustedPeersHelperProtocol {
59
60 let endpoint: NSXPCListenerEndpoint?
61 let containerMap: ContainerMap
62
63 init(endpoint: NSXPCListenerEndpoint?, containerMap: ContainerMap) {
64 self.endpoint = endpoint
65 self.containerMap = containerMap
66 }
67
68 func ping(reply: @escaping (() -> Void)) {
69 reply()
70 }
71
72 func logComplete(function: String, container: ContainerName, error: Error?) {
73 if let error = error {
74 os_log("%{public}@ errored for %{public}@: %{public}@", log: tplogDebug, type: .default, function, container.description, error as CVarArg)
75 } else {
76 os_log("%{public}@ finished for %{public}@", log: tplogDebug, type: .default, function, container.description)
77 }
78 }
79
80 internal func getContainer(withContainer container: String, context: String) throws -> Container {
81 let containerName = ContainerName(container: container, context: context)
82 return try self.containerMap.findOrCreate(name: containerName)
83 }
84
85 func dump(withContainer container: String, context: String, reply: @escaping ([AnyHashable: Any]?, Error?) -> Void) {
86 do {
87 let containerName = ContainerName(container: container, context: context)
88 os_log("Dumping for %{public}@", log: tplogDebug, type: .default, containerName.description)
89 let container = try self.containerMap.findOrCreate(name: containerName)
90 container.dump { result, error in
91 self.logComplete(function: "Dumping", container: container.name, error: error)
92 reply(result, error?.sanitizeForClientXPC())
93 }
94 } catch {
95 os_log("Dumping failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
96 reply(nil, error.sanitizeForClientXPC())
97 }
98 }
99
100 func dumpEgoPeer(withContainer container: String,
101 context: String,
102 reply: @escaping (String?, TPPeerPermanentInfo?, TPPeerStableInfo?, TPPeerDynamicInfo?, Error?) -> Void) {
103 do {
104 let containerName = ContainerName(container: container, context: context)
105 os_log("Dumping peer for %{public}@", log: tplogDebug, type: .default, containerName.description)
106 let container = try self.containerMap.findOrCreate(name: containerName)
107 container.dumpEgoPeer { peerID, perm, stable, dyn, error in
108 self.logComplete(function: "Dumping peer", container: container.name, error: error)
109 reply(peerID, perm, stable, dyn, error?.sanitizeForClientXPC())
110 }
111 } catch {
112 os_log("Dumping peer failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
113 reply(nil, nil, nil, nil, error.sanitizeForClientXPC())
114 }
115 }
116
117 func trustStatus(withContainer container: String, context: String, reply: @escaping (TrustedPeersHelperEgoPeerStatus, Error?) -> Void) {
118 do {
119 let containerName = ContainerName(container: container, context: context)
120 let container = try self.containerMap.findOrCreate(name: containerName)
121 container.trustStatus { egoPeerStatus, error in
122 reply(egoPeerStatus, error?.sanitizeForClientXPC())
123 }
124 } catch {
125 os_log("Trust status failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
126 reply(TrustedPeersHelperEgoPeerStatus(egoPeerID: nil,
127 status: TPPeerStatus.unknown,
128 viablePeerCountsByModelID: [:],
129 peerCountsByMachineID: [:],
130 isExcluded: false,
131 isLocked: false),
132 error.sanitizeForClientXPC())
133 }
134 }
135
136 func fetchTrustState(withContainer container: String, context: String, reply: @escaping (TrustedPeersHelperPeerState?, [TrustedPeersHelperPeer]?, Error?) -> Void) {
137 do {
138 let containerName = ContainerName(container: container, context: context)
139 os_log("Fetch Trust State for %{public}@", log: tplogDebug, type: .default, containerName.description)
140 let container = try self.containerMap.findOrCreate(name: containerName)
141 container.fetchTrustState { peerState, peerList, error in
142 reply(peerState, peerList, error?.sanitizeForClientXPC())
143 }
144 } catch {
145 os_log("Fetch Trust State failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
146 reply(nil, nil, error.sanitizeForClientXPC())
147 }
148 }
149
150 func reset(withContainer container: String, context: String, resetReason: CuttlefishResetReason, reply: @escaping (Error?) -> Void) {
151 do {
152 let containerName = ContainerName(container: container, context: context)
153 os_log("Resetting for %{public}@", log: tplogDebug, type: .default, containerName.description)
154 let container = try self.containerMap.findOrCreate(name: containerName)
155 container.reset(resetReason: resetReason) { error in
156 self.logComplete(function: "Resetting", container: container.name, error: error)
157 reply(error?.sanitizeForClientXPC()) }
158 } catch {
159 os_log("Resetting failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
160 reply(error.sanitizeForClientXPC())
161 }
162 }
163
164 func localReset(withContainer container: String, context: String, reply: @escaping (Error?) -> Void) {
165 do {
166 let containerName = ContainerName(container: container, context: context)
167 os_log("Performing local reset for %{public}@", log: tplogDebug, type: .default, containerName.description)
168 let container = try self.containerMap.findOrCreate(name: containerName)
169 container.localReset { error in
170 self.logComplete(function: "Local reset", container: container.name, error: error)
171 reply(error?.sanitizeForClientXPC())
172 }
173 } catch {
174 os_log("Local reset failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
175 reply(error.sanitizeForClientXPC())
176 }
177 }
178
179 func setAllowedMachineIDsWithContainer(_ container: String,
180 context: String,
181 allowedMachineIDs: Set<String>,
182 honorIDMSListChanges: Bool,
183 reply: @escaping (Bool, Error?) -> Void) {
184 do {
185 let containerName = ContainerName(container: container, context: context)
186 os_log("Setting allowed machineIDs for %{public}@ to %{public}@", log: tplogDebug, type: .default, containerName.description, allowedMachineIDs)
187 let container = try self.containerMap.findOrCreate(name: containerName)
188 container.setAllowedMachineIDs(allowedMachineIDs, honorIDMSListChanges: honorIDMSListChanges) { differences, error in
189 self.logComplete(function: "Setting allowed machineIDs", container: container.name, error: error)
190 reply(differences, error?.sanitizeForClientXPC())
191 }
192 } catch {
193 os_log("Setting allowed machineIDs failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
194 reply(false, error.sanitizeForClientXPC())
195 }
196 }
197
198 func addAllowedMachineIDs(withContainer container: String,
199 context: String,
200 machineIDs: [String],
201 reply: @escaping (Error?) -> Void) {
202 do {
203 let containerName = ContainerName(container: container, context: context)
204 os_log("Adding allowed machineIDs for %{public}@: %{public}@", log: tplogDebug, type: .default, containerName.description, machineIDs)
205 let container = try self.containerMap.findOrCreate(name: containerName)
206 container.addAllow(machineIDs) { error in
207 self.logComplete(function: "Adding allowed machineIDs", container: container.name, error: error)
208 reply(error?.sanitizeForClientXPC())
209 }
210 } catch {
211 os_log("Adding allowed machineID failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
212 reply(error.sanitizeForClientXPC())
213 }
214 }
215
216 func removeAllowedMachineIDs(withContainer container: String,
217 context: String,
218 machineIDs: [String],
219 reply: @escaping (Error?) -> Void) {
220 do {
221 let containerName = ContainerName(container: container, context: context)
222 os_log("Removing allowed machineIDs for %{public}@: %{public}@", log: tplogDebug, type: .default, containerName.description, machineIDs)
223 let container = try self.containerMap.findOrCreate(name: containerName)
224 container.removeAllow(machineIDs) { error in
225 self.logComplete(function: "Removing allowed machineIDs", container: container.name, error: error)
226 reply(error?.sanitizeForClientXPC())
227 }
228 } catch {
229 os_log("Removing allowed machineID failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
230 reply(error.sanitizeForClientXPC())
231 }
232 }
233
234 func fetchAllowedMachineIDs(withContainer container: String, context: String, reply: @escaping (Set<String>?, Error?) -> Void) {
235 do {
236 let containerName = ContainerName(container: container, context: context)
237 os_log("Fetching allowed machineIDs for %{public}@", log: tplogDebug, type: .default, containerName.description)
238 let container = try self.containerMap.findOrCreate(name: containerName)
239 container.fetchAllowedMachineIDs { mids, error in
240 self.logComplete(function: "Fetched allowed machineIDs", container: container.name, error: error)
241 reply(mids, error?.sanitizeForClientXPC())
242 }
243 } catch {
244 os_log("Fetching allowed machineIDs failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
245 reply(nil, error.sanitizeForClientXPC())
246 }
247 }
248
249 func fetchEgoEpoch(withContainer container: String, context: String, reply: @escaping (UInt64, Error?) -> Void) {
250 do {
251 let containerName = ContainerName(container: container, context: context)
252 os_log("retrieving epoch for %{public}@", log: tplogDebug, type: .default, containerName.description)
253 let container = try self.containerMap.findOrCreate(name: containerName)
254 container.getEgoEpoch { epoch, error in
255 reply(epoch, error?.sanitizeForClientXPC())
256 }
257 } catch {
258 os_log("Epoch retrieval failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
259 reply(0, error.sanitizeForClientXPC())
260 }
261 }
262
263 func prepare(withContainer container: String,
264 context: String,
265 epoch: UInt64,
266 machineID: String,
267 bottleSalt: String,
268 bottleID: String,
269 modelID: String,
270 deviceName: String?,
271 serialNumber: String?,
272 osVersion: String,
273 policyVersion: TPPolicyVersion?,
274 policySecrets: [String: Data]?,
275 syncUserControllableViews: TPPBPeerStableInfo_UserControllableViewStatus,
276 signingPrivKeyPersistentRef: Data?,
277 encPrivKeyPersistentRef: Data?,
278 reply: @escaping (String?, Data?, Data?, Data?, Data?, TPSyncingPolicy?, Error?) -> Void) {
279 do {
280 let containerName = ContainerName(container: container, context: context)
281 os_log("Preparing new identity for %{public}@", log: tplogDebug, type: .default, containerName.description)
282 let container = try self.containerMap.findOrCreate(name: containerName)
283 container.prepare(epoch: epoch,
284 machineID: machineID,
285 bottleSalt: bottleSalt,
286 bottleID: bottleID,
287 modelID: modelID,
288 deviceName: deviceName,
289 serialNumber: serialNumber,
290 osVersion: osVersion,
291 policyVersion: policyVersion,
292 policySecrets: policySecrets,
293 syncUserControllableViews: syncUserControllableViews,
294 signingPrivateKeyPersistentRef: signingPrivKeyPersistentRef,
295 encryptionPrivateKeyPersistentRef: encPrivKeyPersistentRef) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, policy, error in
296 self.logComplete(function: "Prepare", container: container.name, error: error)
297 reply(peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, policy, error?.sanitizeForClientXPC())
298 }
299 } catch {
300 os_log("Prepare failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
301 reply(nil, nil, nil, nil, nil, nil, error.sanitizeForClientXPC())
302 }
303 }
304
305 func establish(withContainer container: String,
306 context: String,
307 ckksKeys: [CKKSKeychainBackedKeySet],
308 tlkShares: [CKKSTLKShare],
309 preapprovedKeys: [Data]?,
310 reply: @escaping (String?, [CKRecord]?, TPSyncingPolicy?, Error?) -> Void) {
311 do {
312 let containerName = ContainerName(container: container, context: context)
313 os_log("Establishing %{public}@", log: tplogDebug, type: .default, containerName.description)
314 let container = try self.containerMap.findOrCreate(name: containerName)
315 container.establish(ckksKeys: ckksKeys,
316 tlkShares: tlkShares,
317 preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, policy, error in
318 self.logComplete(function: "Establishing", container: container.name, error: error)
319 reply(peerID, keyHierarchyRecords, policy, error?.sanitizeForClientXPC()) }
320 } catch {
321 os_log("Establishing failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
322 reply(nil, nil, nil, error.sanitizeForClientXPC())
323 }
324 }
325
326 func vouch(withContainer container: String,
327 context: String,
328 peerID: String,
329 permanentInfo: Data,
330 permanentInfoSig: Data,
331 stableInfo: Data,
332 stableInfoSig: Data,
333 ckksKeys: [CKKSKeychainBackedKeySet],
334 reply: @escaping (Data?, Data?, Error?) -> Void) {
335 do {
336 let containerName = ContainerName(container: container, context: context)
337 os_log("Vouching %{public}@", log: tplogDebug, type: .default, containerName.description)
338 let container = try self.containerMap.findOrCreate(name: containerName)
339 container.vouch(peerID: peerID,
340 permanentInfo: permanentInfo,
341 permanentInfoSig: permanentInfoSig,
342 stableInfo: stableInfo,
343 stableInfoSig: stableInfoSig,
344 ckksKeys: ckksKeys) { voucher, voucherSig, error in
345 self.logComplete(function: "Vouching", container: container.name, error: error)
346 reply(voucher, voucherSig, error?.sanitizeForClientXPC()) }
347 } catch {
348 os_log("Vouching failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
349 reply(nil, nil, error.sanitizeForClientXPC())
350 }
351 }
352
353 func preflightVouchWithBottle(withContainer container: String,
354 context: String,
355 bottleID: String,
356 reply: @escaping (String?, TPSyncingPolicy?, Bool, Error?) -> Void) {
357 do {
358 let containerName = ContainerName(container: container, context: context)
359 os_log("Preflight Vouch With Bottle %{public}@", log: tplogDebug, type: .default, containerName.description)
360 let container = try self.containerMap.findOrCreate(name: containerName)
361 container.preflightVouchWithBottle(bottleID: bottleID) { peerID, policy, refetched, error in
362 self.logComplete(function: "Preflight Vouch With Bottle", container: container.name, error: error)
363 reply(peerID, policy, refetched, error?.sanitizeForClientXPC()) }
364 } catch {
365 os_log("Preflighting Vouch With Bottle failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
366 reply(nil, nil, false, error.sanitizeForClientXPC())
367 }
368 }
369
370 func vouchWithBottle(withContainer container: String,
371 context: String,
372 bottleID: String,
373 entropy: Data,
374 bottleSalt: String,
375 tlkShares: [CKKSTLKShare],
376 reply: @escaping (Data?, Data?, Int64, Int64, Error?) -> Void) {
377 do {
378 let containerName = ContainerName(container: container, context: context)
379 os_log("Vouching With Bottle %{public}@", log: tplogDebug, type: .default, containerName.description)
380 let container = try self.containerMap.findOrCreate(name: containerName)
381 container.vouchWithBottle(bottleID: bottleID, entropy: entropy, bottleSalt: bottleSalt, tlkShares: tlkShares) { voucher, voucherSig, uniqueTLKsRecovered, totalTLKSharesRecovered, error in
382 self.logComplete(function: "Vouching With Bottle", container: container.name, error: error)
383 reply(voucher, voucherSig, uniqueTLKsRecovered, totalTLKSharesRecovered, error?.sanitizeForClientXPC()) }
384 } catch {
385 os_log("Vouching with Bottle failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
386 reply(nil, nil, 0, 0, error.sanitizeForClientXPC())
387 }
388 }
389
390 func preflightVouchWithRecoveryKey(withContainer container: String,
391 context: String,
392 recoveryKey: String,
393 salt: String,
394 reply: @escaping (String?, TPSyncingPolicy?, Error?) -> Void) {
395 do {
396 let containerName = ContainerName(container: container, context: context)
397 os_log("Preflight Vouch With RecoveryKey %{public}@", log: tplogDebug, type: .default, containerName.description)
398 let container = try self.containerMap.findOrCreate(name: containerName)
399 container.preflightVouchWithRecoveryKey(recoveryKey: recoveryKey, salt: salt) { rkID, policy, error in
400 self.logComplete(function: "Preflight Vouch With RecoveryKey", container: container.name, error: error)
401 reply(rkID, policy, error?.sanitizeForClientXPC()) }
402 } catch {
403 os_log("Preflighting Vouch With RecoveryKey failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
404 reply(nil, nil, error.sanitizeForClientXPC())
405 }
406 }
407
408 func vouchWithRecoveryKey(withContainer container: String,
409 context: String,
410 recoveryKey: String,
411 salt: String,
412 tlkShares: [CKKSTLKShare],
413 reply: @escaping (Data?, Data?, Error?) -> Void) {
414 do {
415 let containerName = ContainerName(container: container, context: context)
416 os_log("Vouching With Recovery Key %{public}@", log: tplogDebug, type: .default, containerName.description)
417 let container = try self.containerMap.findOrCreate(name: containerName)
418 container.vouchWithRecoveryKey(recoveryKey: recoveryKey, salt: salt, tlkShares: tlkShares) { voucher, voucherSig, error in
419 self.logComplete(function: "Vouching With Recovery Key", container: container.name, error: error)
420 reply(voucher, voucherSig, error?.sanitizeForClientXPC()) }
421 } catch {
422 os_log("Vouching with Recovery Key failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
423 reply(nil, nil, error.sanitizeForClientXPC())
424 }
425 }
426
427 func join(withContainer container: String,
428 context: String,
429 voucherData: Data,
430 voucherSig: Data,
431 ckksKeys: [CKKSKeychainBackedKeySet],
432 tlkShares: [CKKSTLKShare],
433 preapprovedKeys: [Data]?,
434 reply: @escaping (String?, [CKRecord]?, TPSyncingPolicy?, Error?) -> Void) {
435 do {
436 let containerName = ContainerName(container: container, context: context)
437 os_log("Joining %{public}@", log: tplogDebug, type: .default, containerName.description)
438 let container = try self.containerMap.findOrCreate(name: containerName)
439 container.join(voucherData: voucherData,
440 voucherSig: voucherSig,
441 ckksKeys: ckksKeys,
442 tlkShares: tlkShares,
443 preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, policy, error in
444 reply(peerID, keyHierarchyRecords, policy, error?.sanitizeForClientXPC())
445 }
446 } catch {
447 os_log("Joining failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
448 reply(nil, nil, nil, error.sanitizeForClientXPC())
449 }
450 }
451
452 func preflightPreapprovedJoin(withContainer container: String,
453 context: String,
454 preapprovedKeys: [Data]?,
455 reply: @escaping (Bool, Error?) -> Void) {
456 do {
457 let containerName = ContainerName(container: container, context: context)
458 os_log("Attempting to preflight a preapproved join for %{public}@", log: tplogDebug, type: .default, containerName.description)
459 let container = try self.containerMap.findOrCreate(name: containerName)
460 container.preflightPreapprovedJoin(preapprovedKeys: preapprovedKeys) { success, error in reply(success, error?.sanitizeForClientXPC()) }
461 } catch {
462 os_log("preflightPreapprovedJoin failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
463 reply(false, error.sanitizeForClientXPC())
464 }
465 }
466
467 func attemptPreapprovedJoin(withContainer container: String,
468 context: String,
469 ckksKeys: [CKKSKeychainBackedKeySet],
470 tlkShares: [CKKSTLKShare],
471 preapprovedKeys: [Data]?,
472 reply: @escaping (String?, [CKRecord]?, TPSyncingPolicy?, Error?) -> Void) {
473 do {
474 let containerName = ContainerName(container: container, context: context)
475 os_log("Attempting a preapproved join for %{public}@", log: tplogDebug, type: .default, containerName.description)
476 let container = try self.containerMap.findOrCreate(name: containerName)
477 container.preapprovedJoin(ckksKeys: ckksKeys,
478 tlkShares: tlkShares,
479 preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, policy, error in
480 reply(peerID, keyHierarchyRecords, policy, error?.sanitizeForClientXPC()) }
481 } catch {
482 os_log("attemptPreapprovedJoin failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
483 reply(nil, nil, nil, error.sanitizeForClientXPC())
484 }
485 }
486
487 func update(withContainer container: String,
488 context: String,
489 deviceName: String?,
490 serialNumber: String?,
491 osVersion: String?,
492 policyVersion: NSNumber?,
493 policySecrets: [String: Data]?,
494 syncUserControllableViews: NSNumber?,
495 reply: @escaping (TrustedPeersHelperPeerState?, TPSyncingPolicy?, Error?) -> Void) {
496 do {
497 let containerName = ContainerName(container: container, context: context)
498 os_log("Updating %{public}@", log: tplogDebug, type: .default, containerName.description)
499 let container = try self.containerMap.findOrCreate(name: containerName)
500
501 let syncUserControllableSetting: TPPBPeerStableInfo_UserControllableViewStatus?
502 if let value = syncUserControllableViews?.int32Value {
503 switch value {
504 case TPPBPeerStableInfo_UserControllableViewStatus.ENABLED.rawValue:
505 syncUserControllableSetting = .ENABLED
506 case TPPBPeerStableInfo_UserControllableViewStatus.DISABLED.rawValue:
507 syncUserControllableSetting = .DISABLED
508 case TPPBPeerStableInfo_UserControllableViewStatus.FOLLOWING.rawValue:
509 syncUserControllableSetting = .FOLLOWING
510 default:
511 throw ContainerError.unknownSyncUserControllableViewsValue(value: value)
512 }
513 } else {
514 syncUserControllableSetting = nil
515 }
516
517 container.update(deviceName: deviceName,
518 serialNumber: serialNumber,
519 osVersion: osVersion,
520 policyVersion: policyVersion?.uint64Value,
521 policySecrets: policySecrets,
522 syncUserControllableViews: syncUserControllableSetting) { state, policy, error in reply(state, policy, error?.sanitizeForClientXPC()) }
523 } catch {
524 os_log("update failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
525 reply(nil, nil, error.sanitizeForClientXPC())
526 }
527 }
528
529 func setPreapprovedKeysWithContainer(_ container: String,
530 context: String,
531 preapprovedKeys: [Data],
532 reply: @escaping (TrustedPeersHelperPeerState?, Error?) -> Void) {
533 do {
534 let containerName = ContainerName(container: container, context: context)
535 os_log("setPreapprovedKeysWithContainer %{public}@", log: tplogDebug, type: .default, containerName.description)
536 let container = try self.containerMap.findOrCreate(name: containerName)
537 container.set(preapprovedKeys: preapprovedKeys) { state, error in reply(state, error?.sanitizeForClientXPC()) }
538 } catch {
539 os_log("setPreapprovedKeysWithContainer failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
540 reply(nil, error.sanitizeForClientXPC())
541 }
542 }
543
544 func updateTLKs(withContainer container: String,
545 context: String,
546 ckksKeys: [CKKSKeychainBackedKeySet],
547 tlkShares: [CKKSTLKShare],
548 reply: @escaping ([CKRecord]?, Error?) -> Void) {
549 do {
550 let containerName = ContainerName(container: container, context: context)
551 os_log("Updating TLKs for %{public}@", log: tplogDebug, type: .default, containerName.description)
552 let container = try self.containerMap.findOrCreate(name: containerName)
553 container.updateTLKs(ckksKeys: ckksKeys,
554 tlkShares: tlkShares) { records, error in
555 reply(records, error?.sanitizeForClientXPC())
556 }
557 } catch {
558 os_log("updateTLKs failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
559 reply(nil, error.sanitizeForClientXPC())
560 }
561 }
562
563 func departByDistrustingSelf(withContainer container: String,
564 context: String,
565 reply: @escaping (Error?) -> Void) {
566 do {
567 let containerName = ContainerName(container: container, context: context)
568 os_log("Departing %{public}@", log: tplogDebug, type: .default, containerName.description)
569 let container = try self.containerMap.findOrCreate(name: containerName)
570 container.departByDistrustingSelf { error in
571 reply(error?.sanitizeForClientXPC())
572 }
573 } catch {
574 os_log("departByDistrustingSelf failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
575 reply(error.sanitizeForClientXPC())
576 }
577 }
578
579 func distrustPeerIDs(withContainer container: String,
580 context: String,
581 peerIDs: Set<String>,
582 reply: @escaping (Error?) -> Void) {
583 do {
584 let containerName = ContainerName(container: container, context: context)
585 os_log("Distrusting %{public}@ in %{public}@", log: tplogDebug, type: .default, peerIDs, containerName.description)
586 let container = try self.containerMap.findOrCreate(name: containerName)
587 container.distrust(peerIDs: peerIDs) { error in
588 reply(error?.sanitizeForClientXPC())
589 }
590 } catch {
591 os_log("distrustPeerIDs failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
592 reply(error.sanitizeForClientXPC())
593 }
594 }
595
596 func fetchViableBottles(withContainer container: String, context: String, reply: @escaping ([String]?, [String]?, Error?) -> Void) {
597 do {
598 let containerName = ContainerName(container: container, context: context)
599 os_log("fetchViableBottles in %{public}@", log: tplogDebug, type: .default, containerName.description)
600 let container = try self.containerMap.findOrCreate(name: containerName)
601 container.fetchViableBottles { sortedBottleIDs, partialBottleIDs, error in
602 reply(sortedBottleIDs, partialBottleIDs, error?.sanitizeForClientXPC())
603 }
604 } catch {
605 os_log("fetchViableBottles failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
606 reply(nil, nil, error.sanitizeForClientXPC())
607 }
608 }
609
610 func fetchViableEscrowRecords(withContainer container: String, context: String, forceFetch: Bool, reply: @escaping ([Data]?, Error?) -> Void) {
611 do {
612 let containerName = ContainerName(container: container, context: context)
613 os_log("fetchViableEscrowRecords in %@", log: tplogDebug, type: .default, containerName.description)
614 let container = try self.containerMap.findOrCreate(name: containerName)
615 container.fetchEscrowRecords(forceFetch: forceFetch) { recordDatas, error in
616 reply(recordDatas, error?.sanitizeForClientXPC())
617 }
618 } catch {
619 reply(nil, error.sanitizeForClientXPC())
620 }
621 }
622
623 func fetchEscrowContents(withContainer container: String, context: String, reply: @escaping (Data?, String?, Data?, Error?) -> Void) {
624 do {
625 let containerName = ContainerName(container: container, context: context)
626 os_log("fetchEscrowContents in %{public}@", log: tplogDebug, type: .default, containerName.description)
627 let container = try self.containerMap.findOrCreate(name: containerName)
628 container.fetchEscrowContents { entropy, bottleID, signingPublicKey, error in
629 reply(entropy, bottleID, signingPublicKey, error?.sanitizeForClientXPC())
630 }
631 } catch {
632 os_log("fetchEscrowContents failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
633 reply(nil, nil, nil, error.sanitizeForClientXPC())
634 }
635 }
636
637 func fetchCurrentPolicy(withContainer container: String,
638 context: String,
639 modelIDOverride: String?,
640 reply: @escaping (TPSyncingPolicy?, TPPBPeerStableInfo_UserControllableViewStatus, Error?) -> Void) {
641 do {
642 let containerName = ContainerName(container: container, context: context)
643 os_log("Fetching policy+views for %{public}@", log: tplogDebug, type: .default, containerName.description)
644 let container = try self.containerMap.findOrCreate(name: containerName)
645 container.fetchCurrentPolicy(modelIDOverride: modelIDOverride) { policy, peersOpinion, error in
646 reply(policy, peersOpinion, error?.sanitizeForClientXPC())
647 }
648 } catch {
649 os_log("fetchCurrentPolicy failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
650 reply(nil, .UNKNOWN, error.sanitizeForClientXPC())
651 }
652 }
653
654 func fetchPolicyDocuments(withContainer container: String,
655 context: String,
656 versions: Set<TPPolicyVersion>,
657 reply: @escaping ([TPPolicyVersion: Data]?, Error?) -> Void) {
658 do {
659 let containerName = ContainerName(container: container, context: context)
660 os_log("Fetching policy documents %{public}@ with versions: %{public}@", log: tplogDebug, type: .default, containerName.description, versions)
661 let container = try self.containerMap.findOrCreate(name: containerName)
662 container.fetchPolicyDocuments(versions: versions) { entries, error in
663 reply(entries, error?.sanitizeForClientXPC())
664 }
665 } catch {
666 os_log("fetchPolicyDocuments failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
667 reply(nil, error.sanitizeForClientXPC())
668 }
669 }
670
671 func validatePeers(withContainer container: String, context: String, reply: @escaping ([AnyHashable: Any]?, Error?) -> Void) {
672 do {
673 let containerName = ContainerName(container: container, context: context)
674 os_log("ValidatePeers for %{public}@", log: tplogDebug, type: .default, containerName.description)
675 let container = try self.containerMap.findOrCreate(name: containerName)
676 let request = ValidatePeersRequest()
677 container.validatePeers(request: request) { result, error in
678 self.logComplete(function: "validatePeers", container: container.name, error: error)
679 reply(result, error?.sanitizeForClientXPC())
680 }
681 } catch {
682 os_log("ValidatePeers failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
683 reply(nil, error.sanitizeForClientXPC())
684 }
685 }
686
687 func setRecoveryKeyWithContainer(_ container: String,
688 context: String,
689 recoveryKey: String,
690 salt: String,
691 ckksKeys: [CKKSKeychainBackedKeySet],
692 reply: @escaping ([CKRecord]?, Error?) -> Void) {
693 do {
694 let containerName = ContainerName(container: container, context: context)
695 os_log("SetRecoveryKey for %{public}@", log: tplogDebug, type: .default, containerName.description)
696 let container = try self.containerMap.findOrCreate(name: containerName)
697 container.setRecoveryKey(recoveryKey: recoveryKey, salt: salt, ckksKeys: ckksKeys) { records, error in
698 self.logComplete(function: "setRecoveryKey", container: container.name, error: error)
699 reply(records, error?.sanitizeForClientXPC())
700 }
701 } catch {
702 os_log("SetRecoveryKey failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
703 reply(nil, error.sanitizeForClientXPC())
704 }
705 }
706
707 func reportHealth(withContainer container: String, context: String, stateMachineState: String, trustState: String, reply: @escaping (Error?) -> Void) {
708 do {
709 let containerName = ContainerName(container: container, context: context)
710 os_log("ReportHealth for %{public}@", log: tplogDebug, type: .default, containerName.description)
711 let container = try self.containerMap.findOrCreate(name: containerName)
712 let request = ReportHealthRequest.with {
713 $0.stateMachineState = stateMachineState
714 }
715 container.reportHealth(request: request) { error in
716 self.logComplete(function: "reportHealth", container: container.name, error: error)
717 reply(error?.sanitizeForClientXPC())
718 }
719 } catch {
720 os_log("ReportHealth failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
721 reply(error.sanitizeForClientXPC())
722 }
723 }
724
725 func pushHealthInquiry(withContainer container: String, context: String, reply: @escaping (Error?) -> Void) {
726 do {
727 let containerName = ContainerName(container: container, context: context)
728 os_log("PushHealthInquiry for %{public}@", log: tplogDebug, type: .default, containerName.description)
729 let container = try self.containerMap.findOrCreate(name: containerName)
730 container.pushHealthInquiry { error in
731 self.logComplete(function: "pushHealthInquiry", container: container.name, error: error)
732 reply(error?.sanitizeForClientXPC())
733 }
734 } catch {
735 os_log("PushHealthInquiry failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
736 reply(error.sanitizeForClientXPC())
737 }
738 }
739
740 func requestHealthCheck(withContainer container: String, context: String, requiresEscrowCheck: Bool, reply: @escaping (Bool, Bool, Bool, Bool, Error?) -> Void) {
741 do {
742 let containerName = ContainerName(container: container, context: context)
743 os_log("Health Check! requiring escrow check? %d for %{public}@", log: tplogDebug, type: .default, requiresEscrowCheck, containerName.description)
744 let container = try self.containerMap.findOrCreate(name: containerName)
745 container.requestHealthCheck(requiresEscrowCheck: requiresEscrowCheck) { postRepair, postEscrow, postReset, leaveTrust, error in
746 reply(postRepair, postEscrow, postReset, leaveTrust, error?.sanitizeForClientXPC())
747 }
748 } catch {
749 os_log("Health Check! failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
750 reply(false, false, false, false, error.sanitizeForClientXPC())
751 }
752 }
753
754 func getSupportAppInfo(withContainer container: String, context: String, reply: @escaping (Data?, Error?) -> Void) {
755 do {
756 let containerName = ContainerName(container: container, context: context)
757 os_log("getSupportAppInfo for %{public}@", log: tplogDebug, type: .default, containerName.description)
758 let container = try self.containerMap.findOrCreate(name: containerName)
759 container.getSupportAppInfo { info, error in
760 reply(info, error?.sanitizeForClientXPC())
761 }
762 } catch {
763 os_log("getSupportInfo failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
764 reply(nil, error.sanitizeForClientXPC())
765 }
766 }
767 func removeEscrowCache(withContainer container: String, context: String, reply: @escaping (Error?) -> Void) {
768 do {
769 let containerName = ContainerName(container: container, context: context)
770 os_log("removeEscrowCache for %{public}@", log: tplogDebug, type: .default, containerName.description)
771 let container = try self.containerMap.findOrCreate(name: containerName)
772 container.removeEscrowCache { error in
773 reply(error?.sanitizeForClientXPC())
774 }
775 } catch {
776 os_log("removeEscrowCache failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
777 reply(error.sanitizeForClientXPC())
778 }
779 }
780 }