4 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
5 #import "keychain/ot/categories/OTAccountMetadataClassC+KeychainSupport.h"
7 #import <CloudKit/CloudKit_Private.h>
9 #import "keychain/ckks/CloudKitCategories.h"
11 #import "keychain/ot/ObjCImprovements.h"
13 #import "keychain/ot/OTCuttlefishAccountStateHolder.h"
14 #import "keychain/ot/OTOperationDependencies.h"
15 #import "keychain/ot/OTStates.h"
16 #import "keychain/ot/OTUpdateTPHOperation.h"
18 @interface OTUpdateTPHOperation ()
19 @property OTOperationDependencies* deps;
21 @property NSOperation* finishedOp;
23 @property (nullable) OctagonFlag* retryFlag;
26 @implementation OTUpdateTPHOperation
27 @synthesize nextState = _nextState;
28 @synthesize intendedState = _intendedState;
30 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
31 intendedState:(OctagonState*)intendedState
32 errorState:(OctagonState*)errorState
33 retryFlag:(OctagonFlag* _Nullable)retryFlag
35 if((self = [super init])) {
38 _intendedState = intendedState;
39 _nextState = errorState;
41 _retryFlag = retryFlag;
49 self.finishedOp = [NSBlockOperation blockOperationWithBlock:^{
50 // If we errored in some unknown way, ask to try again!
54 if(self.retryFlag == nil) {
55 secerror("octagon: Received an error updating TPH, but no retry flag present.");
59 // Is this a very scary error?
62 OctagonPendingFlag* pendingFlag = nil;
64 if([self.deps.lockStateTracker isLockedError:self.error]) {
65 secnotice("octagon", "Updating trust state failed because locked, retry once unlocked: %@", self.error);
66 self.nextState = OctagonStateWaitForUnlock;
67 pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag
68 conditions:OctagonPendingConditionsDeviceUnlocked];
71 // more CloudKit errors should trigger a retry here
72 secnotice("octagon", "Error is currently unknown, aborting: %@", self.error);
77 NSTimeInterval baseDelay = SecCKKSTestsEnabled() ? 2 : 30;
78 NSTimeInterval ckDelay = CKRetryAfterSecondsForError(self.error);
79 NSTimeInterval cuttlefishDelay = [self.error cuttlefishRetryAfter];
80 NSTimeInterval delay = MAX(ckDelay, cuttlefishDelay);
85 pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag
86 delayInSeconds:delay];
88 secnotice("octagon", "Updating trust state no fatal: requesting retry: %@",
90 [self.deps.flagHandler handlePendingFlag:pendingFlag];
94 [self dependOnBeforeGroupFinished:self.finishedOp];
97 [self.deps.cuttlefishXPCWrapper updateWithContainer:self.deps.containerName
98 context:self.deps.contextID
99 deviceName:self.deps.deviceInformationAdapter.deviceName
100 serialNumber:self.deps.deviceInformationAdapter.serialNumber
101 osVersion:self.deps.deviceInformationAdapter.osVersion
104 reply:^(TrustedPeersHelperPeerState* peerState, NSError* error) {
106 if(error || !peerState) {
107 secerror("octagon: update errored: %@", error);
110 // On an error, for now, go back to the intended state
111 // <rdar://problem/50190005> Octagon: handle lock state errors in update()
112 self.nextState = self.intendedState;
113 [self runBeforeGroupFinished:self.finishedOp];
117 secnotice("octagon", "update complete: %@", peerState);
119 if(peerState.identityIsPreapproved) {
120 secnotice("octagon-sos", "Self peer is now preapproved!");
121 [self.deps.flagHandler handleFlag:OctagonFlagEgoPeerPreapproved];
123 if (peerState.memberChanges) {
124 secnotice("octagon", "Member list changed");
125 [self.deps.octagonAdapter sendTrustedPeerSetChangedUpdate];
128 if (peerState.unknownMachineIDsPresent) {
129 secnotice("octagon-authkit", "Unknown machine IDs are present; requesting fetch");
130 [self.deps.flagHandler handleFlag:OctagonFlagFetchAuthKitMachineIDList];
133 if(peerState.peerStatus & TPPeerStatusExcluded) {
134 secnotice("octagon", "Self peer (%@) is excluded; moving to untrusted", peerState.peerID);
135 self.nextState = OctagonStateBecomeUntrusted;
137 } else if(peerState.peerStatus & TPPeerStatusUnknown) {
138 secnotice("octagon", "Self peer (%@) is unknown; moving to untrusted", peerState.peerID);
139 self.nextState = OctagonStateBecomeUntrusted;
142 self.nextState = self.intendedState;
145 [self runBeforeGroupFinished:self.finishedOp];