OTUpdateTPHOperation.m [plain text]
#if OCTAGON
#import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
#import "keychain/ot/categories/OTAccountMetadataClassC+KeychainSupport.h"
#import <CloudKit/CloudKit_Private.h>
#import "keychain/ckks/CloudKitCategories.h"
#import "keychain/ot/ObjCImprovements.h"
#import "keychain/ot/OTCuttlefishAccountStateHolder.h"
#import "keychain/ot/OTOperationDependencies.h"
#import "keychain/ot/OTStates.h"
#import "keychain/ot/OTUpdateTPHOperation.h"
@interface OTUpdateTPHOperation ()
@property OTOperationDependencies* deps;
@property OctagonState* peerUnknownState;
@property NSOperation* finishedOp;
@property (nullable) OctagonFlag* retryFlag;
@end
@implementation OTUpdateTPHOperation
@synthesize nextState = _nextState;
@synthesize intendedState = _intendedState;
- (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
intendedState:(OctagonState*)intendedState
peerUnknownState:(OctagonState*)peerUnknownState
errorState:(OctagonState*)errorState
retryFlag:(OctagonFlag* _Nullable)retryFlag
{
if((self = [super init])) {
_deps = dependencies;
_intendedState = intendedState;
_nextState = errorState;
_peerUnknownState = peerUnknownState;
_retryFlag = retryFlag;
}
return self;
}
- (void)groupStart
{
WEAKIFY(self);
self.finishedOp = [NSBlockOperation blockOperationWithBlock:^{
// If we errored in some unknown way, ask to try again!
STRONGIFY(self);
if(self.error) {
if(self.retryFlag == nil) {
secerror("octagon: Received an error updating TPH, but no retry flag present.");
return;
}
// Is this a very scary error?
bool fatal = true;
OctagonPendingFlag* pendingFlag = nil;
if([self.deps.lockStateTracker isLockedError:self.error]) {
secnotice("octagon", "Updating trust state failed because locked, retry once unlocked: self.nextState = OctagonStateWaitForUnlock;
pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag
conditions:OctagonPendingConditionsDeviceUnlocked];
fatal = false;
} else {
// more CloudKit errors should trigger a retry here
secnotice("octagon", "Error is currently unknown, aborting: }
if(!fatal) {
if(!pendingFlag) {
NSTimeInterval delay = [self.error overallCuttlefishRetry];
pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag
delayInSeconds:delay];
}
secnotice("octagon", "Updating trust state no fatal: requesting retry: pendingFlag);
[self.deps.flagHandler handlePendingFlag:pendingFlag];
}
}
}];
[self dependOnBeforeGroupFinished:self.finishedOp];
[self.deps.cuttlefishXPCWrapper updateWithContainer:self.deps.containerName
context:self.deps.contextID
deviceName:self.deps.deviceInformationAdapter.deviceName
serialNumber:self.deps.deviceInformationAdapter.serialNumber
osVersion:self.deps.deviceInformationAdapter.osVersion
policyVersion:nil
policySecrets:nil
syncUserControllableViews:nil
reply:^(TrustedPeersHelperPeerState* peerState, TPSyncingPolicy* syncingPolicy, NSError* error) {
STRONGIFY(self);
if(error || !peerState) {
secerror("octagon: update errored: self.error = error;
if ([error isCuttlefishError:CuttlefishErrorUpdateTrustPeerNotFound]) {
secnotice("octagon-ckks", "Cuttlefish reports we no longer exist.");
self.nextState = self.peerUnknownState;
} else {
// On an error, for now, go back to the intended state
// <rdar://problem/50190005> Octagon: handle lock state errors in update()
self.nextState = self.intendedState;
}
[self runBeforeGroupFinished:self.finishedOp];
return;
}
secnotice("octagon", "update complete:
NSError* localError = nil;
BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) {
[metadata setTPSyncingPolicy:syncingPolicy];
return metadata;
} error:&localError];
if(!persisted || localError) {
secerror("octagon: Unable to save new syncing state:
} else {
// After an update(), we're sure that we have a fresh policy
BOOL viewSetChanged = [self.deps.viewManager setCurrentSyncingPolicy:syncingPolicy policyIsFresh:YES];
if(viewSetChanged) {
[self.deps.flagHandler handleFlag:OctagonFlagCKKSViewSetChanged];
}
}
if(peerState.identityIsPreapproved) {
secnotice("octagon-sos", "Self peer is now preapproved!");
[self.deps.flagHandler handleFlag:OctagonFlagEgoPeerPreapproved];
}
if (peerState.memberChanges) {
secnotice("octagon", "Member list changed");
[self.deps.octagonAdapter sendTrustedPeerSetChangedUpdate];
}
if (peerState.unknownMachineIDsPresent) {
secnotice("octagon-authkit", "Unknown machine IDs are present; requesting fetch");
[self.deps.flagHandler handleFlag:OctagonFlagFetchAuthKitMachineIDList];
}
if (peerState.peerStatus & TPPeerStatusExcluded) {
secnotice("octagon", "Self peer ( self.nextState = OctagonStateBecomeUntrusted;
} else if(peerState.peerStatus & TPPeerStatusUnknown) {
if (peerState.identityIsPreapproved) {
secnotice("octagon", "Self peer ( self.nextState = OctagonStateAttemptSOSUpgrade;
} else {
secnotice("octagon", "Self peer ( self.nextState = self.peerUnknownState;
}
} else {
self.nextState = self.intendedState;
}
[self runBeforeGroupFinished:self.finishedOp];
}];
}
@end
#endif // OCTAGON