]> git.saurik.com Git - apple/security.git/blob - keychain/TrustedPeersHelper/Container_BottledPeers.swift
Security-59754.60.13.tar.gz
[apple/security.git] / keychain / TrustedPeersHelper / Container_BottledPeers.swift
1 import CoreData
2 import Foundation
3
4 extension Container {
5 func onMOCQueueFindBottle(bottleID: String) throws -> (BottleMO) {
6 guard let containerBottles = self.containerMO.bottles as? Set<BottleMO> else {
7 throw ContainerError.noBottlesPresent
8 }
9
10 let bottles = containerBottles.filter { $0.bottleID == bottleID }
11
12 guard let bottle = bottles.first else {
13 throw ContainerError.noBottlesForEscrowRecordID
14 }
15
16 return bottle
17 }
18
19 func preflightVouchWithBottle(bottleID: String,
20 reply: @escaping (String?, TPSyncingPolicy?, Bool, Error?) -> Void) {
21 self.semaphore.wait()
22 let reply: (String?, TPSyncingPolicy?, Bool, Error?) -> Void = {
23 os_log("preflightVouchWithBottle complete: %{public}@",
24 log: tplogTrace, type: .info, traceError($3))
25 self.semaphore.signal()
26 reply($0, $1, $2, $3)
27 }
28
29 self.moc.performAndWait {
30 do {
31 let (_, peerID, syncingPolicy) = try self.onMOCQueuePerformPreflight(bottleID: bottleID)
32 reply(peerID, syncingPolicy, false, nil)
33 } catch {
34 os_log("preflightVouchWithBottle failed; forcing refetch and retrying: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
35
36 self.fetchAndPersistChanges { fetchError in
37 guard fetchError == nil else {
38 os_log("preflightVouchWithBottle unable to fetch current peers: %{public}@", log: tplogDebug, type: .default, (fetchError as CVarArg?) ?? "")
39 reply(nil, nil, true, fetchError)
40 return
41 }
42
43 // Ensure we have all policy versions claimed by peers, including our sponsor
44 let allPolicyVersions = self.model.allPolicyVersions()
45 self.fetchPolicyDocumentsWithSemaphore(versions: allPolicyVersions) { _, fetchPolicyDocumentsError in
46 guard fetchPolicyDocumentsError == nil else {
47 os_log("preflightVouchWithBottle unable to fetch policy documents: %{public}@", log: tplogDebug, type: .default, (fetchPolicyDocumentsError as CVarArg?) ?? "no error")
48 reply(nil, nil, true, fetchPolicyDocumentsError)
49 return
50 }
51
52 self.fetchViableBottlesWithSemaphore { _, _, fetchBottlesError in
53 guard fetchBottlesError == nil else {
54 os_log("preflightVouchWithBottle unable to fetch viable bottles: %{public}@", log: tplogDebug, type: .default, (fetchPolicyDocumentsError as CVarArg?) ?? "no error")
55 reply(nil, nil, true, fetchBottlesError)
56 return
57 }
58
59 // and try again:
60 self.moc.performAndWait {
61 do {
62 let (_, peerID, syncingPolicy) = try self.onMOCQueuePerformPreflight(bottleID: bottleID)
63 reply(peerID, syncingPolicy, true, nil)
64 } catch {
65 os_log("preflightVouchWithBottle failed after refetches; failing: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
66 reply(nil, nil, true, error)
67 }
68 }
69 }
70 }
71 }
72 }
73 }
74 }
75
76 func onMOCQueuePerformPreflight(bottleID: String) throws -> (BottleMO, String, TPSyncingPolicy) {
77 guard let egoPeerID = self.containerMO.egoPeerID,
78 let egoPermData = self.containerMO.egoPeerPermanentInfo,
79 let egoPermSig = self.containerMO.egoPeerPermanentInfoSig else {
80 os_log("fetchCurrentPolicy failed to find ego peer information", log: tplogDebug, type: .error)
81 throw ContainerError.noPreparedIdentity
82 }
83
84 let keyFactory = TPECPublicKeyFactory()
85 guard let egoPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
86 os_log("fetchCurrentPolicy failed to create TPPeerPermanentInfo", log: tplogDebug, type: .error)
87 throw ContainerError.invalidPermanentInfoOrSig
88 }
89
90 let bottleMO = try self.onMOCQueueFindBottle(bottleID: bottleID)
91
92 guard let sponsorPeer = self.model.peer(withID: bottleMO.peerID ?? "") else {
93 os_log("preflightVouchWithBottle found no peer to match bottle", log: tplogDebug, type: .default)
94 throw ContainerError.sponsorNotRegistered(bottleMO.peerID ?? "no peer ID given")
95 }
96
97 guard let sponsorPeerStableInfo = sponsorPeer.stableInfo else {
98 os_log("preflightVouchWithBottle sponsor peer has no stable info", log: tplogDebug, type: .default)
99 throw ContainerError.sponsorNotRegistered(bottleMO.peerID ?? "no peer ID given")
100 }
101
102 // We need to extract the syncing policy that the remote peer would have used (if they were the type of device that we are)
103 let policy = try self.syncingPolicyFor(modelID: egoPermanentInfo.modelID, stableInfo: sponsorPeerStableInfo)
104 return (bottleMO, sponsorPeer.peerID, policy)
105 }
106 }