]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKSCreateCKZoneOperation.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / ckks / CKKSCreateCKZoneOperation.m
1 #if OCTAGON
2
3 #import <CloudKit/CloudKit.h>
4 #import <CloudKit/CloudKit_Private.h>
5
6 #import "keychain/ckks/CKKSCreateCKZoneOperation.h"
7 #import "keychain/ckks/CKKSZoneStateEntry.h"
8 #import "keychain/categories/NSError+UsefulConstructors.h"
9 #import "keychain/ot/ObjCImprovements.h"
10 #import "keychain/ot/OTDefines.h"
11
12 @implementation CKKSCreateCKZoneOperation
13 @synthesize nextState = _nextState;
14 @synthesize intendedState = _intendedState;
15
16 - (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
17 intendedState:(OctagonState*)intendedState
18 errorState:(OctagonState*)errorState
19 {
20 if(self = [super init]) {
21 _deps = dependencies;
22
23 _intendedState = intendedState;
24 _nextState = errorState;
25 }
26 return self;
27 }
28
29 - (void)groupStart
30 {
31 __block CKKSZoneStateEntry* ckseOriginal = nil;
32 [self.deps.databaseProvider dispatchSyncWithReadOnlySQLTransaction:^{
33 ckseOriginal = [CKKSZoneStateEntry state:self.deps.zoneID.zoneName];
34 }];
35
36 if(ckseOriginal.ckzonecreated && ckseOriginal.ckzonesubscribed) {
37 ckksinfo("ckkskey", self.deps.zoneID, "Zone is already created and subscribed");
38 self.nextState = self.intendedState;
39 return;
40 }
41
42 ckksnotice("ckkszone", self.deps.zoneID, "Asking to create and subscribe to CloudKit zone '%@'", self.deps.zoneID.zoneName);
43 CKRecordZone* zone = [[CKRecordZone alloc] initWithZoneID:self.deps.zoneID];
44 CKKSZoneModifyOperations* zoneOps = [self.deps.zoneModifier createZone:zone];
45
46 WEAKIFY(self);
47
48 CKKSResultOperation* handleModificationsOperation = [CKKSResultOperation named:@"handle-modification" withBlock:^{
49 STRONGIFY(self);
50 BOOL zoneCreated = NO;
51 BOOL zoneSubscribed = NO;
52 if([zoneOps.savedRecordZones containsObject:zone]) {
53 ckksinfo("ckkszone", self.deps.zoneID, "Successfully created '%@'", self.deps.zoneID);
54 zoneCreated = YES;
55 } else {
56 ckkserror("ckkszone", self.deps.zoneID, "Failed to create '%@'", self.deps.zoneID);
57 }
58
59 bool createdSubscription = false;
60 for(CKSubscription* subscription in zoneOps.savedSubscriptions) {
61 if([subscription.subscriptionID isEqual:[@"zone:" stringByAppendingString: self.deps.zoneID.zoneName]]) {
62 zoneSubscribed = true;
63 break;
64 }
65 }
66
67 if(createdSubscription) {
68 ckksinfo("ckkszone", self.deps.zoneID, "Successfully subscribed '%@'", self.deps.zoneID);
69 zoneSubscribed = YES;
70 } else {
71 ckkserror("ckkszone", self.deps.zoneID, "Failed to subscribe to '%@'", self.deps.zoneID);
72 }
73
74 [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
75 ckksnotice("ckkszone", self.deps.zoneID, "Zone setup progress: created:%d %@ subscribed:%d %@",
76 zoneCreated,
77 zoneOps.zoneModificationOperation.error,
78 zoneSubscribed,
79 zoneOps.zoneSubscriptionOperation.error);
80
81 NSError* error = nil;
82 CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.deps.zoneID.zoneName];
83 ckse.ckzonecreated = zoneCreated;
84 ckse.ckzonesubscribed = zoneSubscribed;
85
86 // Although, if the zone subscribed error says there's no zone, mark down that there's no zone
87 if(zoneOps.zoneSubscriptionOperation.error &&
88 [zoneOps.zoneSubscriptionOperation.error.domain isEqualToString:CKErrorDomain] && zoneOps.zoneSubscriptionOperation.error.code == CKErrorPartialFailure) {
89 NSError* subscriptionError = zoneOps.zoneSubscriptionOperation.error.userInfo[CKPartialErrorsByItemIDKey][self.deps.zoneID];
90 if(subscriptionError && [subscriptionError.domain isEqualToString:CKErrorDomain] && subscriptionError.code == CKErrorZoneNotFound) {
91
92 ckkserror("ckks", self.deps.zoneID, "zone subscription error appears to say the zone doesn't exist, fixing status: %@", zoneOps.zoneSubscriptionOperation.error);
93 ckse.ckzonecreated = false;
94 }
95 }
96
97 [ckse saveToDatabase:&error];
98 if(error) {
99 ckkserror("ckks", self.deps.zoneID, "couldn't save zone creation status for %@: %@", self.deps.zoneID, error);
100 }
101
102 if(!zoneCreated || !zoneSubscribed) {
103 // Go into 'zonecreationfailed'
104 self.nextState = SecCKKSZoneKeyStateZoneCreationFailed;
105 self.error = zoneOps.zoneModificationOperation.error ?: zoneOps.zoneSubscriptionOperation.error;
106 } else {
107 self.nextState = self.intendedState;
108 }
109
110 return CKKSDatabaseTransactionCommit;
111 }];
112 }];
113
114 [handleModificationsOperation addNullableDependency:zoneOps.zoneModificationOperation];
115 [handleModificationsOperation addNullableDependency:zoneOps.zoneSubscriptionOperation];
116 [self runBeforeGroupFinished:handleModificationsOperation];
117 }
118
119 @end
120
121 #endif // OCTAGON