CKKSDeleteCKZoneOperation.m
1 2 3 #if OCTAGON 4 5 #import <CloudKit/CloudKit.h> 6 #import <CloudKit/CloudKit_Private.h> 7 8 #import "keychain/ckks/CKKSDeleteCKZoneOperation.h" 9 #import "keychain/ckks/CKKSZoneStateEntry.h" 10 #import "keychain/categories/NSError+UsefulConstructors.h" 11 #import "keychain/ot/ObjCImprovements.h" 12 #import "keychain/ot/OTDefines.h" 13 14 @implementation CKKSDeleteCKZoneOperation 15 @synthesize nextState = _nextState; 16 @synthesize intendedState = _intendedState; 17 18 - (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies 19 intendedState:(OctagonState*)intendedState 20 errorState:(OctagonState*)errorState 21 { 22 if(self = [super init]) { 23 _deps = dependencies; 24 25 _intendedState = intendedState; 26 _nextState = errorState; 27 } 28 return self; 29 } 30 31 - (void)groupStart 32 { 33 34 ckksnotice("ckkszone", self.deps.zoneID, "Deleting CloudKit zone '%@'", self.deps.zoneID); 35 CKKSZoneModifyOperations* zoneOps = [self.deps.zoneModifier deleteZone:self.deps.zoneID]; 36 37 38 WEAKIFY(self); 39 40 CKKSResultOperation* handleModificationsOperation = [CKKSResultOperation named:@"handle-modification" withBlock:^{ 41 STRONGIFY(self); 42 43 bool fatalError = false; 44 45 NSError* operationError = zoneOps.zoneModificationOperation.error; 46 bool removed = [zoneOps.deletedRecordZoneIDs containsObject:self.deps.zoneID]; 47 48 if(!removed && operationError) { 49 // Okay, but if this error is either 'ZoneNotFound' or 'UserDeletedZone', that's fine by us: the zone is deleted. 50 NSDictionary* partialErrors = operationError.userInfo[CKPartialErrorsByItemIDKey]; 51 if([operationError.domain isEqualToString:CKErrorDomain] && operationError.code == CKErrorPartialFailure && partialErrors) { 52 for(CKRecordZoneID* errorZoneID in partialErrors.allKeys) { 53 NSError* errorZone = partialErrors[errorZoneID]; 54 55 if(errorZone && [errorZone.domain isEqualToString:CKErrorDomain] && 56 (errorZone.code == CKErrorZoneNotFound || errorZone.code == CKErrorUserDeletedZone)) { 57 ckksnotice("ckkszone", self.deps.zoneID, "Attempted to delete zone %@, but it's already missing. This is okay: %@", errorZoneID, errorZone); 58 } else { 59 fatalError = true; 60 } 61 } 62 63 } else { 64 fatalError = true; 65 } 66 67 ckksnotice("ckkszone", self.deps.zoneID, "deletion of record zone %@ completed with error: %@", self.deps.zoneID, operationError); 68 69 if(fatalError) { 70 // Early-exit 71 self.error = operationError; 72 return; 73 } 74 } 75 76 ckksnotice("ckkszone", self.deps.zoneID, "deletion of record zone %@ completed successfully", self.deps.zoneID); 77 78 [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{ 79 NSError* error = nil; 80 CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.deps.zoneID.zoneName]; 81 ckse.ckzonecreated = NO; 82 ckse.ckzonesubscribed = NO; 83 84 [ckse saveToDatabase:&error]; 85 if(error) { 86 ckkserror("ckks", self.deps.zoneID, "couldn't save zone creation status for %@: %@", self.deps.zoneID, error); 87 } 88 89 self.nextState = self.intendedState; 90 return CKKSDatabaseTransactionCommit; 91 }]; 92 }]; 93 94 [handleModificationsOperation addNullableDependency:zoneOps.zoneModificationOperation]; 95 [handleModificationsOperation addNullableDependency:zoneOps.zoneSubscriptionOperation]; 96 [self runBeforeGroupFinished:handleModificationsOperation]; 97 } 98 99 @end 100 101 #endif // OCTAGON