5 func preflightVouchWithRecoveryKey(recoveryKey: String,
7 reply: @escaping (String?, Set<String>?, TPPolicy?, Error?) -> Void) {
9 let reply: (String?, Set<String>?, TPPolicy?, Error?) -> Void = {
10 os_log("preflightRecoveryKey complete: %{public}@",
11 log: tplogTrace, type: .info, traceError($3))
12 self.semaphore.signal()
16 self.fetchAndPersistChangesIfNeeded { fetchError in
17 guard fetchError == nil else {
18 os_log("preflightRecoveryKey unable to fetch current peers: %{public}@", log: tplogDebug, type: .default, (fetchError as CVarArg?) ?? "")
19 reply(nil, nil, nil, fetchError)
23 // Ensure we have all policy versions claimed by peers, including our sponsor
24 self.fetchPolicyDocumentsWithSemaphore(versions: self.model.allPolicyVersions()) { _, fetchPolicyDocumentsError in
25 guard fetchPolicyDocumentsError == nil else {
26 os_log("preflightRecoveryKey unable to fetch policy documents: %{public}@", log: tplogDebug, type: .default, (fetchPolicyDocumentsError as CVarArg?) ?? "no error")
27 reply(nil, nil, nil, fetchPolicyDocumentsError)
31 self.moc.performAndWait {
32 guard let egoPeerID = self.containerMO.egoPeerID,
33 let egoPermData = self.containerMO.egoPeerPermanentInfo,
34 let egoPermSig = self.containerMO.egoPeerPermanentInfoSig else {
35 os_log("preflightRecoveryKey: no ego peer ID", log: tplogDebug, type: .default)
36 reply(nil, nil, nil, ContainerError.noPreparedIdentity)
40 let keyFactory = TPECPublicKeyFactory()
41 guard let selfPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
42 reply(nil, nil, nil, ContainerError.invalidPermanentInfoOrSig)
46 var recoveryKeys: RecoveryKey
48 recoveryKeys = try RecoveryKey(recoveryKeyString: recoveryKey, recoverySalt: salt)
50 os_log("preflightRecoveryKey: failed to create recovery keys: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
51 reply(nil, nil, nil, ContainerError.failedToCreateRecoveryKey)
55 // Dear model: if i were to use this recovery key, what peers would I end up using?
56 guard self.model.isRecoveryKeyEnrolled() else {
57 os_log("preflightRecoveryKey: recovery Key is not enrolled", log: tplogDebug, type: .default)
58 reply(nil, nil, nil, ContainerError.recoveryKeysNotEnrolled)
62 guard let sponsorPeerID = self.model.peerIDThatTrustsRecoveryKeys(TPRecoveryKeyPair(signingSPKI: recoveryKeys.peerKeys.signingKey.publicKey.keyData,
63 encryptionSPKI: recoveryKeys.peerKeys.encryptionKey.publicKey.keyData)) else {
64 os_log("preflightRecoveryKey Untrusted recovery key set", log: tplogDebug, type: .default)
65 reply(nil, nil, nil, ContainerError.untrustedRecoveryKeys)
69 guard let sponsor = self.model.peer(withID: sponsorPeerID) else {
70 os_log("preflightRecoveryKey Failed to find peer with ID", log: tplogDebug, type: .default)
71 reply(nil, nil, nil, ContainerError.sponsorNotRegistered(sponsorPeerID))
76 let bestPolicy = try self.model.policy(forPeerIDs: sponsor.dynamicInfo?.includedPeerIDs ?? [sponsor.peerID],
77 candidatePeerID: egoPeerID,
78 candidateStableInfo: sponsor.stableInfo)
80 let views = try bestPolicy.views(forModel: selfPermanentInfo.modelID)
81 reply(recoveryKeys.peerKeys.peerID, views, bestPolicy, nil)
83 os_log("preflightRecoveryKey: error fetching policy: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
84 reply(nil, nil, nil, error)