2  * Copyright (c) 2018 Apple Inc. All Rights Reserved.
 
   4  * @APPLE_LICENSE_HEADER_START@
 
   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
 
  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.
 
  21  * @APPLE_LICENSE_HEADER_END@
 
  26 class Client: TrustedPeersHelperProtocol {
 
  28     let endpoint: NSXPCListenerEndpoint?
 
  29     let containerMap: ContainerMap
 
  31     init(endpoint: NSXPCListenerEndpoint?, containerMap: ContainerMap) {
 
  32         self.endpoint = endpoint
 
  33         self.containerMap = containerMap
 
  36     func ping(reply: @escaping (() -> Void)) {
 
  40     func logComplete(function: String, container: ContainerName, error: Error?) {
 
  41         if let error = error {
 
  42             os_log("%@ errored for %@: %@", log: tplogDebug, type: .default, function, container.description, error as CVarArg)
 
  44             os_log("%@ finished for %@", log: tplogDebug, type: .default, function, container.description)
 
  48     internal func getContainer(withContainer container: String, context: String) throws -> Container {
 
  49         let containerName = ContainerName(container: container, context: context)
 
  50         return try self.containerMap.findOrCreate(name: containerName)
 
  53     func dump(withContainer container: String, context: String, reply: @escaping ([AnyHashable: Any]?, Error?) -> Void) {
 
  55             let containerName = ContainerName(container: container, context: context)
 
  56             os_log("Dumping for %@", log: tplogDebug, type: .default, containerName.description)
 
  57             let container = try self.containerMap.findOrCreate(name: containerName)
 
  58             container.dump { result, error in
 
  59                 self.logComplete(function: "Dumping", container: container.name, error: error)
 
  60                 reply(result, CKXPCSuitableError(error))
 
  63             os_log("Dumping failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
  64             reply(nil, CKXPCSuitableError(error))
 
  68     func dumpEgoPeer(withContainer container: String,
 
  70                      reply: @escaping (String?, TPPeerPermanentInfo?, TPPeerStableInfo?, TPPeerDynamicInfo?, Error?) -> Void) {
 
  72             let containerName = ContainerName(container: container, context: context)
 
  73             os_log("Dumping peer for %@", log: tplogDebug, type: .default, containerName.description)
 
  74             let container = try self.containerMap.findOrCreate(name: containerName)
 
  75             container.dumpEgoPeer { peerID, perm, stable, dyn, error in
 
  76                 self.logComplete(function: "Dumping peer", container: container.name, error: error)
 
  77                 reply(peerID, perm, stable, dyn, CKXPCSuitableError(error))
 
  80             os_log("Dumping peer failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
  81             reply(nil, nil, nil, nil, CKXPCSuitableError(error))
 
  85     func trustStatus(withContainer container: String, context: String, reply: @escaping (TrustedPeersHelperEgoPeerStatus, Error?) -> Void) {
 
  87             let containerName = ContainerName(container: container, context: context)
 
  88             let container = try self.containerMap.findOrCreate(name: containerName)
 
  89             container.trustStatus(reply: reply)
 
  91             os_log("Trust status failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
  92             reply(TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: TPPeerStatus.unknown, peerCountsByModelID: [:], isExcluded: false, isLocked: false), CKXPCSuitableError(error))
 
  96     func fetchTrustState(withContainer container: String, context: String, reply: @escaping (TrustedPeersHelperPeerState?, [TrustedPeersHelperPeer]?, Error?) -> Void) {
 
  98             let containerName = ContainerName(container: container, context: context)
 
  99             os_log("Fetch Trust State for %@", log: tplogDebug, type: .default, containerName.description)
 
 100             let container = try self.containerMap.findOrCreate(name: containerName)
 
 101             container.fetchTrustState(reply: reply)
 
 103             os_log("Fetch Trust State failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 104             reply(nil, nil, CKXPCSuitableError(error))
 
 108     func reset(withContainer container: String, context: String, reply: @escaping (Error?) -> Void) {
 
 110             let containerName = ContainerName(container: container, context: context)
 
 111             os_log("Resetting for %@", log: tplogDebug, type: .default, containerName.description)
 
 112             let container = try self.containerMap.findOrCreate(name: containerName)
 
 113             container.reset { error in
 
 114                 self.logComplete(function: "Resetting", container: container.name, error: error)
 
 115                 reply(CKXPCSuitableError(error)) }
 
 117             os_log("Resetting failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 118             reply(CKXPCSuitableError(error))
 
 122     func localReset(withContainer container: String, context: String, reply: @escaping (Error?) -> Void) {
 
 124             let containerName = ContainerName(container: container, context: context)
 
 125             os_log("Performing local reset for %@", log: tplogDebug, type: .default, containerName.description)
 
 126             let container = try self.containerMap.findOrCreate(name: containerName)
 
 127             container.localReset { error in
 
 128                 self.logComplete(function: "Local reset", container: container.name, error: error)
 
 129                 reply(CKXPCSuitableError(error))
 
 132             os_log("Local reset failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 133             reply(CKXPCSuitableError(error))
 
 137     func setAllowedMachineIDsWithContainer(_ container: String,
 
 139                                            allowedMachineIDs: Set<String>,
 
 140                                            reply: @escaping (Bool, Error?) -> Void) {
 
 142             let containerName = ContainerName(container: container, context: context)
 
 143             os_log("Setting allowed machineIDs for %@ to %@", log: tplogDebug, type: .default, containerName.description, allowedMachineIDs)
 
 144             let container = try self.containerMap.findOrCreate(name: containerName)
 
 145             container.setAllowedMachineIDs(allowedMachineIDs) { differences, error in
 
 146                 self.logComplete(function: "Setting allowed machineIDs", container: container.name, error: error)
 
 147                 reply(differences, CKXPCSuitableError(error))
 
 150             os_log("Setting allowed machineIDs failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 151             reply(false, CKXPCSuitableError(error))
 
 155     func addAllowedMachineIDs(withContainer container: String,
 
 157                               machineIDs: [String],
 
 158                               reply: @escaping (Error?) -> Void) {
 
 160             let containerName = ContainerName(container: container, context: context)
 
 161             os_log("Adding allowed machineIDs for %@: %@", log: tplogDebug, type: .default, containerName.description, machineIDs)
 
 162             let container = try self.containerMap.findOrCreate(name: containerName)
 
 163             container.addAllow(machineIDs) { error in
 
 164                 self.logComplete(function: "Adding allowed machineIDs", container: container.name, error: error)
 
 165                 reply(CKXPCSuitableError(error))
 
 168             os_log("Adding allowed machineID failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 169             reply(CKXPCSuitableError(error))
 
 173     func removeAllowedMachineIDs(withContainer container: String,
 
 175                                  machineIDs: [String],
 
 176                                  reply: @escaping (Error?) -> Void) {
 
 178             let containerName = ContainerName(container: container, context: context)
 
 179             os_log("Removing allowed machineIDs for %@: %@", log: tplogDebug, type: .default, containerName.description, machineIDs)
 
 180             let container = try self.containerMap.findOrCreate(name: containerName)
 
 181             container.removeAllow(machineIDs) { error in
 
 182                 self.logComplete(function: "Removing allowed machineIDs", container: container.name, error: error)
 
 183                 reply(CKXPCSuitableError(error))
 
 186             os_log("Removing allowed machineID failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 187             reply(CKXPCSuitableError(error))
 
 191     func fetchEgoEpoch(withContainer container: String, context: String, reply: @escaping (UInt64, Error?) -> Void) {
 
 193             let containerName = ContainerName(container: container, context: context)
 
 194             os_log("retrieving epoch for %@", log: tplogDebug, type: .default, containerName.description)
 
 195             let container = try self.containerMap.findOrCreate(name: containerName)
 
 196             container.getEgoEpoch { epoch, error in
 
 197                 reply(epoch, CKXPCSuitableError(error))
 
 200             os_log("Epoch retrieval failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 201             reply(0, CKXPCSuitableError(error))
 
 205     func prepare(withContainer container: String,
 
 213                  serialNumber: String,
 
 215                  policyVersion: NSNumber?,
 
 216                  policySecrets: [String: Data]?,
 
 217                  signingPrivKeyPersistentRef: Data?,
 
 218                  encPrivKeyPersistentRef: Data?,
 
 219                  reply: @escaping (String?, Data?, Data?, Data?, Data?, Error?) -> Void) {
 
 221             let containerName = ContainerName(container: container, context: context)
 
 222             os_log("Preparing new identity for %@", log: tplogDebug, type: .default, containerName.description)
 
 223             let container = try self.containerMap.findOrCreate(name: containerName)
 
 224             container.prepare(epoch: epoch,
 
 225                               machineID: machineID,
 
 226                               bottleSalt: bottleSalt,
 
 229                               deviceName: deviceName,
 
 230                               serialNumber: serialNumber,
 
 231                               osVersion: osVersion,
 
 232                               policyVersion: policyVersion?.uint64Value,
 
 233                               policySecrets: policySecrets,
 
 234                               signingPrivateKeyPersistentRef: signingPrivKeyPersistentRef,
 
 235                               encryptionPrivateKeyPersistentRef: encPrivKeyPersistentRef) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, error in
 
 236                                 self.logComplete(function: "Prepare", container: container.name, error: error)
 
 237                                 reply(peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, CKXPCSuitableError(error))
 
 240             os_log("Prepare failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 241             reply(nil, nil, nil, nil, nil, CKXPCSuitableError(error))
 
 245     func establish(withContainer container: String,
 
 247                    ckksKeys: [CKKSKeychainBackedKeySet],
 
 248                    tlkShares: [CKKSTLKShare],
 
 249                    preapprovedKeys: [Data]?,
 
 250                    reply: @escaping (String?, [CKRecord]?, Error?) -> Void) {
 
 252             let containerName = ContainerName(container: container, context: context)
 
 253             os_log("Establishing %@", log: tplogDebug, type: .default, containerName.description)
 
 254             let container = try self.containerMap.findOrCreate(name: containerName)
 
 255             container.establish(ckksKeys: ckksKeys,
 
 256                                 tlkShares: tlkShares,
 
 257                                 preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, error in
 
 258                                     self.logComplete(function: "Establishing", container: container.name, error: error)
 
 259                                     reply(peerID, keyHierarchyRecords, CKXPCSuitableError(error)) }
 
 261             os_log("Establishing failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 262             reply(nil, nil, CKXPCSuitableError(error))
 
 266     func vouch(withContainer container: String,
 
 270                permanentInfoSig: Data,
 
 273                ckksKeys: [CKKSKeychainBackedKeySet],
 
 274                reply: @escaping (Data?, Data?, Error?) -> Void) {
 
 276             let containerName = ContainerName(container: container, context: context)
 
 277             os_log("Vouching %@", log: tplogDebug, type: .default, containerName.description)
 
 278             let container = try self.containerMap.findOrCreate(name: containerName)
 
 279             container.vouch(peerID: peerID,
 
 280                             permanentInfo: permanentInfo,
 
 281                             permanentInfoSig: permanentInfoSig,
 
 282                             stableInfo: stableInfo,
 
 283                             stableInfoSig: stableInfoSig,
 
 284                             ckksKeys: ckksKeys) { voucher, voucherSig, error in
 
 285                                 self.logComplete(function: "Vouching", container: container.name, error: error)
 
 286                                 reply(voucher, voucherSig, CKXPCSuitableError(error)) }
 
 288             os_log("Vouching failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 289             reply(nil, nil, CKXPCSuitableError(error))
 
 293     func vouchWithBottle(withContainer container: String,
 
 298                          tlkShares: [CKKSTLKShare],
 
 299                          reply: @escaping (Data?, Data?, Error?) -> Void) {
 
 301             let containerName = ContainerName(container: container, context: context)
 
 302             os_log("Vouching With Bottle %@", log: tplogDebug, type: .default, containerName.description)
 
 303             let container = try self.containerMap.findOrCreate(name: containerName)
 
 304             container.vouchWithBottle(bottleID: bottleID, entropy: entropy, bottleSalt: bottleSalt, tlkShares: tlkShares) { voucher, voucherSig, error in
 
 305                 self.logComplete(function: "Vouching With Bottle", container: container.name, error: error)
 
 306                 reply(voucher, voucherSig, CKXPCSuitableError(error)) }
 
 308             os_log("Vouching with Bottle failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 309             reply(nil, nil, CKXPCSuitableError(error))
 
 313     func vouchWithRecoveryKey(withContainer container: String,
 
 317                               tlkShares: [CKKSTLKShare],
 
 318                               reply: @escaping (Data?, Data?, Error?) -> Void) {
 
 320             let containerName = ContainerName(container: container, context: context)
 
 321             os_log("Vouching With Recovery Key %@", log: tplogDebug, type: .default, containerName.description)
 
 322             let container = try self.containerMap.findOrCreate(name: containerName)
 
 323             container.vouchWithRecoveryKey(recoveryKey: recoveryKey, salt: salt, tlkShares: tlkShares) { voucher, voucherSig, error in
 
 324                 self.logComplete(function: "Vouching With Recovery Key", container: container.name, error: error)
 
 325                 reply(voucher, voucherSig, CKXPCSuitableError(error)) }
 
 327             os_log("Vouching with Recovery Key failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 328             reply(nil, nil, CKXPCSuitableError(error))
 
 332     func join(withContainer container: String,
 
 336               ckksKeys: [CKKSKeychainBackedKeySet],
 
 337               tlkShares: [CKKSTLKShare],
 
 338               preapprovedKeys: [Data],
 
 339               reply: @escaping (String?, [CKRecord]?, Error?) -> Void) {
 
 341             let containerName = ContainerName(container: container, context: context)
 
 342             os_log("Joining %@", log: tplogDebug, type: .default, containerName.description)
 
 343             let container = try self.containerMap.findOrCreate(name: containerName)
 
 344             container.join(voucherData: voucherData,
 
 345                            voucherSig: voucherSig,
 
 347                            tlkShares: tlkShares,
 
 348                            preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, error in reply(peerID, keyHierarchyRecords, CKXPCSuitableError(error)) }
 
 350             reply(nil, nil, CKXPCSuitableError(error))
 
 354     func preflightPreapprovedJoin(withContainer container: String,
 
 356                                   reply: @escaping (Bool, Error?) -> Void) {
 
 358             let containerName = ContainerName(container: container, context: context)
 
 359             os_log("Attempting to preflight a preapproved join for %@", log: tplogDebug, type: .default, containerName.description)
 
 360             let container = try self.containerMap.findOrCreate(name: containerName)
 
 361             container.preflightPreapprovedJoin() { success, error in reply(success, CKXPCSuitableError(error)) }
 
 363             reply(false, CKXPCSuitableError(error))
 
 367     func attemptPreapprovedJoin(withContainer container: String,
 
 369                                 ckksKeys: [CKKSKeychainBackedKeySet],
 
 370                                 tlkShares: [CKKSTLKShare],
 
 371                                 preapprovedKeys: [Data],
 
 372                                 reply: @escaping (String?, [CKRecord]?, Error?) -> Void) {
 
 374             let containerName = ContainerName(container: container, context: context)
 
 375             os_log("Attempting a preapproved join for %@", log: tplogDebug, type: .default, containerName.description)
 
 376             let container = try self.containerMap.findOrCreate(name: containerName)
 
 377             container.preapprovedJoin(ckksKeys: ckksKeys,
 
 378                                       tlkShares: tlkShares,
 
 379                                       preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, error in reply(peerID, keyHierarchyRecords, CKXPCSuitableError(error)) }
 
 381             reply(nil, nil, CKXPCSuitableError(error))
 
 385     func update(withContainer container: String,
 
 388                 serialNumber: String?,
 
 390                 policyVersion: NSNumber?,
 
 391                 policySecrets: [String: Data]?,
 
 392                 reply: @escaping (TrustedPeersHelperPeerState?, Error?) -> Void) {
 
 394             let containerName = ContainerName(container: container, context: context)
 
 395             os_log("Updating %@", log: tplogDebug, type: .default, containerName.description)
 
 396             let container = try self.containerMap.findOrCreate(name: containerName)
 
 397             container.update(deviceName: deviceName,
 
 398                              serialNumber: serialNumber,
 
 399                              osVersion: osVersion,
 
 400                              policyVersion: policyVersion?.uint64Value,
 
 401                              policySecrets: policySecrets) { state, error in reply(state, CKXPCSuitableError(error)) }
 
 403             reply(nil, CKXPCSuitableError(error))
 
 407     func setPreapprovedKeysWithContainer(_ container: String,
 
 409                                preapprovedKeys: [Data],
 
 410                                reply: @escaping (Error?) -> Void) {
 
 412             let containerName = ContainerName(container: container, context: context)
 
 413             os_log("Updating %@", log: tplogDebug, type: .default, containerName.description)
 
 414             let container = try self.containerMap.findOrCreate(name: containerName)
 
 415             container.set(preapprovedKeys: preapprovedKeys) { error in reply(CKXPCSuitableError(error)) }
 
 417             reply(CKXPCSuitableError(error))
 
 421     func updateTLKs(withContainer container: String,
 
 423                     ckksKeys: [CKKSKeychainBackedKeySet],
 
 424                     tlkShares: [CKKSTLKShare],
 
 425                     reply: @escaping ([CKRecord]?, Error?) -> Void) {
 
 427             let containerName = ContainerName(container: container, context: context)
 
 428             os_log("Updating TLKs for %@", log: tplogDebug, type: .default, containerName.description)
 
 429             let container = try self.containerMap.findOrCreate(name: containerName)
 
 430             container.updateTLKs(ckksKeys: ckksKeys,
 
 431                                  tlkShares: tlkShares,
 
 434             reply(nil, CKXPCSuitableError(error))
 
 438     func departByDistrustingSelf(withContainer container: String,
 
 440                                  reply: @escaping (Error?) -> Void) {
 
 442             let containerName = ContainerName(container: container, context: context)
 
 443             os_log("Departing %@", log: tplogDebug, type: .default, containerName.description)
 
 444             let container = try self.containerMap.findOrCreate(name: containerName)
 
 445             container.departByDistrustingSelf { error in
 
 446                 reply(CKXPCSuitableError(error))
 
 449             reply(CKXPCSuitableError(error))
 
 453     func distrustPeerIDs(withContainer container: String,
 
 455                          peerIDs: Set<String>,
 
 456                          reply: @escaping (Error?) -> Void) {
 
 458             let containerName = ContainerName(container: container, context: context)
 
 459             os_log("Distrusting %@ in %@", log: tplogDebug, type: .default, peerIDs, containerName.description)
 
 460             let container = try self.containerMap.findOrCreate(name: containerName)
 
 461             container.distrust(peerIDs: peerIDs) { error in
 
 462                 reply(CKXPCSuitableError(error))
 
 465             reply(CKXPCSuitableError(error))
 
 469     func fetchViableBottles(withContainer container: String, context: String, reply: @escaping ([String]?, [String]?, Error?) -> Void) {
 
 471             let containerName = ContainerName(container: container, context: context)
 
 472             os_log("fetchViableBottles in %@", log: tplogDebug, type: .default, containerName.description)
 
 473             let container = try self.containerMap.findOrCreate(name: containerName)
 
 474             container.fetchViableBottles { sortedBottleIDs, partialBottleIDs, error in
 
 475                 reply(sortedBottleIDs, partialBottleIDs, CKXPCSuitableError(error))
 
 478             reply(nil, nil, CKXPCSuitableError(error))
 
 482     func fetchEscrowContents(withContainer container: String, context: String, reply: @escaping (Data?, String?, Data?, Error?) -> Void) {
 
 484             let containerName = ContainerName(container: container, context: context)
 
 485             os_log("fetchEscrowContents in %@", log: tplogDebug, type: .default, containerName.description)
 
 486             let container = try self.containerMap.findOrCreate(name: containerName)
 
 487             container.fetchEscrowContents { entropy, bottleID, signingPublicKey, error in
 
 488                 reply(entropy, bottleID, signingPublicKey, CKXPCSuitableError(error))
 
 491             reply(nil, nil, nil, CKXPCSuitableError(error))
 
 495     func fetchPolicy(withContainer container: String,
 
 497                      reply: @escaping (TPPolicy?, Error?) -> Void) {
 
 499             let containerName = ContainerName(container: container, context: context)
 
 500             os_log("Fetching policy for %@", log: tplogDebug, type: .default, containerName.description)
 
 501             let container = try self.containerMap.findOrCreate(name: containerName)
 
 502             container.fetchPolicy { policy, error in
 
 503                 reply(policy, CKXPCSuitableError(error))
 
 506             reply(nil, CKXPCSuitableError(error))
 
 510     func fetchPolicyDocuments(withContainer container: String,
 
 512                               keys: [NSNumber: String],
 
 513                               reply: @escaping ([NSNumber: [String]]?, Error?) -> Void) {
 
 515             let containerName = ContainerName(container: container, context: context)
 
 516             os_log("Fetching policy documents %@ with keys: %@", log: tplogDebug, type: .default, containerName.description, keys)
 
 517             let container = try self.containerMap.findOrCreate(name: containerName)
 
 518             container.fetchPolicyDocuments(keys: keys) { entries, error in
 
 519                 reply(entries, CKXPCSuitableError(error))
 
 522             reply(nil, CKXPCSuitableError(error))
 
 526     func validatePeers(withContainer container: String, context: String, reply: @escaping ([AnyHashable: Any]?, Error?) -> Void) {
 
 528             let containerName = ContainerName(container: container, context: context)
 
 529             os_log("ValidatePeers for %@", log: tplogDebug, type: .default, containerName.description)
 
 530             let container = try self.containerMap.findOrCreate(name: containerName)
 
 531             let request = ValidatePeersRequest()
 
 532             container.validatePeers(request: request) { result, error in
 
 533                 self.logComplete(function: "validatePeers", container: container.name, error: error)
 
 534                 reply(result, CKXPCSuitableError(error))
 
 537             os_log("ValidatePeers failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 538             reply(nil, CKXPCSuitableError(error))
 
 542     func setRecoveryKeyWithContainer(_ container: String, context: String, recoveryKey: String, salt: String, ckksKeys: [CKKSKeychainBackedKeySet], reply: @escaping (Error?) -> Void) {
 
 544             let containerName = ContainerName(container: container, context: context)
 
 545             os_log("SetRecoveryKey for %@", log: tplogDebug, type: .default, containerName.description)
 
 546             let container = try self.containerMap.findOrCreate(name: containerName)
 
 547             container.setRecoveryKey(recoveryKey: recoveryKey, salt: salt, ckksKeys: ckksKeys) { error in
 
 548                 self.logComplete(function: "setRecoveryKey", container: container.name, error: error)
 
 549                 reply(CKXPCSuitableError(error))
 
 552             os_log("SetRecoveryKey failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 553             reply(CKXPCSuitableError(error))
 
 557     func reportHealth(withContainer container: String, context: String, stateMachineState: String, trustState: String, reply: @escaping (Error?) -> Void) {
 
 559             let containerName = ContainerName(container: container, context: context)
 
 560             os_log("ReportHealth for %@", log: tplogDebug, type: .default, containerName.description)
 
 561             let container = try self.containerMap.findOrCreate(name: containerName)
 
 562             let request = ReportHealthRequest.with {
 
 563                 $0.stateMachineState = stateMachineState
 
 565             container.reportHealth(request: request) { error in
 
 566                 self.logComplete(function: "reportHealth", container: container.name, error: error)
 
 567                 reply(CKXPCSuitableError(error))
 
 570             os_log("ReportHealth failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 571             reply(CKXPCSuitableError(error))
 
 575     func pushHealthInquiry(withContainer container: String, context: String, reply: @escaping (Error?) -> Void) {
 
 577             let containerName = ContainerName(container: container, context: context)
 
 578             os_log("PushHealthInquiry for %@", log: tplogDebug, type: .default, containerName.description)
 
 579             let container = try self.containerMap.findOrCreate(name: containerName)
 
 580             container.pushHealthInquiry { error in
 
 581                 self.logComplete(function: "pushHealthInquiry", container: container.name, error: error)
 
 582                 reply(CKXPCSuitableError(error))
 
 585             os_log("PushHealthInquiry failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 586             reply(CKXPCSuitableError(error))
 
 590     func getViewsWithContainer(_ container: String, context: String, inViews: [String], reply: @escaping ([String]?, Error?) -> Void) {
 
 592             let containerName = ContainerName(container: container, context: context)
 
 593             os_log("GetViews (%@) for %@", log: tplogDebug, type: .default, inViews, containerName.description)
 
 594             let container = try self.containerMap.findOrCreate(name: containerName)
 
 595             container.getViews(inViews: inViews) { outViews, error in
 
 596                 reply(outViews, CKXPCSuitableError(error))
 
 599             os_log("GetViews failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 600             reply(nil, CKXPCSuitableError(error))
 
 604     func requestHealthCheck(withContainer container: String, context: String, requiresEscrowCheck: Bool, reply: @escaping (Bool, Bool, Bool, Error?) -> Void) {
 
 606             let containerName = ContainerName(container: container, context: context)
 
 607             os_log("Health Check! requiring escrow check? %d for %@", log: tplogDebug, type: .default, requiresEscrowCheck, containerName.description)
 
 608             let container = try self.containerMap.findOrCreate(name: containerName)
 
 609             container.requestHealthCheck(requiresEscrowCheck: requiresEscrowCheck) { postRepair, postEscrow, postReset, error in
 
 610                 reply(postRepair, postEscrow, postReset, CKXPCSuitableError(error))
 
 613             os_log("Health Check! failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg)
 
 614             reply(false, false, false, CKXPCSuitableError(error))