]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKSAnalytics.m
Security-59306.11.20.tar.gz
[apple/security.git] / keychain / ckks / CKKSAnalytics.m
1 /*
2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #if OCTAGON
25
26 #import <CloudKit/CloudKit.h>
27 #import <CloudKit/CloudKit_Private.h>
28 #import <os/log.h>
29
30 #import "keychain/ckks/CKKSAnalytics.h"
31 #import "keychain/ot/OTDefines.h"
32 #import "keychain/ckks/CKKS.h"
33 #import "keychain/ckks/CKKSViewManager.h"
34 #import "keychain/ckks/CKKSKeychainView.h"
35 #include <utilities/SecFileLocations.h>
36 #include <sys/stat.h>
37
38 NSString* const CKKSAnalyticsInCircle = @"inCircle";
39 NSString* const CKKSAnalyticsHasTLKs = @"TLKs";
40 NSString* const CKKSAnalyticsSyncedClassARecently = @"inSyncA";
41 NSString* const CKKSAnalyticsSyncedClassCRecently = @"inSyncC";
42 NSString* const CKKSAnalyticsIncomingQueueIsErrorFree = @"IQNOE";
43 NSString* const CKKSAnalyticsOutgoingQueueIsErrorFree = @"OQNOE";
44 NSString* const CKKSAnalyticsInSync = @"inSync";
45 NSString* const CKKSAnalyticsValidCredentials = @"validCredentials";
46 NSString* const CKKSAnalyticsLastUnlock = @"lastUnlock";
47 NSString* const CKKSAnalyticsLastKeystateReady = @"lastKSR";
48 NSString* const CKKSAnalyticsLastInCircle = @"lastInCircle";
49
50 NSString* const OctagonAnalyticsStateMachineState = @"OASMState";
51 NSString* const OctagonAnalyticIcloudAccountState = @"OAiC";
52 NSString* const OctagonAnalyticsTrustState = @"OATrust";
53 NSString* const OctagonAnalyticsLastHealthCheck = @"OAHealthCheck";
54 NSString* const OctagonAnalyticsSOSStatus = @"OASOSStatus";
55 NSString* const OctagonAnalyticsDateOfLastPreflightPreapprovedJoin = @"OALastPPJ";
56 NSString* const OctagonAnalyticsLastKeystateReady = @"OALastKSR";
57 NSString* const OctagonAnalyticsLastCoreFollowup = @"OALastCFU";
58 NSString* const OctagonAnalyticsCoreFollowupStatus = @"OACFUStatus";
59 NSString* const OctagonAnalyticsCoreFollowupFailureCount = @"OACFUTFailureCount";
60 NSString* const OctagonAnalyticsCoreFollowupLastFailureTime = @"OACFULastFailureTime";
61 NSString* const OctagonAnalyticsPrerecordPending = @"OAPrerecordPending";
62 NSString* const OctagonAnalyticsCDPStateRun = @"OACDPStateRun";
63
64 NSString* const OctagonAnalyticsKVSProvisioned = @"OADCKVSProvisioned";
65 NSString* const OctagonAnalyticsKVSEnabled = @"OADCKVSEnabled";
66 NSString* const OctagonAnalyticsKeychainSyncProvisioned = @"OADCKCSProvisioned";
67 NSString* const OctagonAnalyticsKeychainSyncEnabled = @"OADCKCSEnabled";
68 NSString* const OctagonAnalyticsCloudKitProvisioned = @"OADCCKProvisioned";
69 NSString* const OctagonAnalyticsCloudKitEnabled = @"OADCCKEnabled";
70
71 static NSString* const CKKSAnalyticsAttributeRecoverableError = @"recoverableError";
72 static NSString* const CKKSAnalyticsAttributeZoneName = @"zone";
73 static NSString* const CKKSAnalyticsAttributeErrorDomain = @"errorDomain";
74 static NSString* const CKKSAnalyticsAttributeErrorCode = @"errorCode";
75 static NSString* const CKKSAnalyticsAttributeErrorChain = @"errorChain";
76
77 CKKSAnalyticsFailableEvent* const CKKSEventProcessIncomingQueueClassA = (CKKSAnalyticsFailableEvent*)@"CKKSEventProcessIncomingQueueClassA";
78 CKKSAnalyticsFailableEvent* const CKKSEventProcessIncomingQueueClassC = (CKKSAnalyticsFailableEvent*)@"CKKSEventProcessIncomingQueueClassC";
79 CKKSAnalyticsFailableEvent* const CKKSEventProcessOutgoingQueue = (CKKSAnalyticsFailableEvent*)@"CKKSEventProcessOutgoingQueue";
80 CKKSAnalyticsFailableEvent* const CKKSEventUploadChanges = (CKKSAnalyticsFailableEvent*)@"CKKSEventUploadChanges";
81 CKKSAnalyticsFailableEvent* const CKKSEventStateError = (CKKSAnalyticsFailableEvent*)@"CKKSEventStateError";
82 CKKSAnalyticsFailableEvent* const CKKSEventProcessHealKeyHierarchy = (CKKSAnalyticsFailableEvent *)@"CKKSEventProcessHealKeyHierarchy";
83 CKKSAnalyticsFailableEvent* const CKKSEventProcessReencryption = (CKKSAnalyticsFailableEvent *)@"CKKSEventProcessReencryption";
84
85 NSString* const OctagonEventFailureReason = @"FailureReason";
86
87 CKKSAnalyticsFailableEvent* const OctagonEventPreflightBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventPreflightBottle";
88 CKKSAnalyticsFailableEvent* const OctagonEventLaunchBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventLaunchBottle";
89 CKKSAnalyticsFailableEvent* const OctagonEventRestoreBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventRestoreBottle";
90 CKKSAnalyticsFailableEvent* const OctagonEventScrubBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventScrubBottle";
91 CKKSAnalyticsFailableEvent* const OctagonEventSignIn = (CKKSAnalyticsFailableEvent *)@"OctagonEventSignIn";
92 CKKSAnalyticsFailableEvent* const OctagonEventSignOut = (CKKSAnalyticsFailableEvent *)@"OctagonEventSignIn";
93 CKKSAnalyticsFailableEvent* const OctagonEventRamp = (CKKSAnalyticsFailableEvent *)@"OctagonEventRamp";
94 CKKSAnalyticsFailableEvent* const OctagonEventBottleCheck = (CKKSAnalyticsFailableEvent *)@"OctagonEventBottleCheck";
95 CKKSAnalyticsFailableEvent* const OctagonEventCoreFollowUp = (CKKSAnalyticsFailableEvent *)@"OctagonEventCoreFollowUp";
96 CKKSAnalyticsFailableEvent* const OctagonEventUpdateBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpdateBottle";
97
98 CKKSAnalyticsFailableEvent* const OctagonEventCheckTrustState = (CKKSAnalyticsFailableEvent *)@"OctagonEventCheckTrustState";
99
100 CKKSAnalyticsFailableEvent* const OctagonEventBottledPeerRestore = (CKKSAnalyticsFailableEvent*)@"OctagonEventBottledPeerRestore";
101 CKKSAnalyticsFailableEvent* const OctagonEventRecoveryKey = (CKKSAnalyticsFailableEvent*)@"OctagonEventRecoveryKey";
102
103 CKKSAnalyticsFailableEvent* const OctagonEventFetchAllBottles = (CKKSAnalyticsFailableEvent*)@"OctagonEventFetchAllBottles";
104 CKKSAnalyticsFailableEvent* const OctagonEventFetchEscrowContents = (CKKSAnalyticsFailableEvent*)@"OctagonEventFetchEscrowContents";
105 CKKSAnalyticsFailableEvent* const OctagonEventResetAndEstablish = (CKKSAnalyticsFailableEvent*)@"OctagonEventResetAndEstablish";
106 CKKSAnalyticsFailableEvent* const OctagonEventEstablish = (CKKSAnalyticsFailableEvent*)@"OctagonEventEstablish";
107 CKKSAnalyticsFailableEvent* const OctagonEventLeaveClique = (CKKSAnalyticsFailableEvent*)@"OctagonEventLeaveClique";
108 CKKSAnalyticsFailableEvent* const OctagonEventRemoveFriendsInClique = (CKKSAnalyticsFailableEvent*)@"OctagonEventRemoveFriendsInClique";
109
110 CKKSAnalyticsFailableEvent* const OctagonEventUpgradeFetchDeviceIDs = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradeFetchDeviceIDs";
111 CKKSAnalyticsFailableEvent* const OctagonEventUpgradeSetAllowList = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradeSetAllowList";
112 CKKSAnalyticsFailableEvent* const OctagonEventUpgradeSilentEscrow = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradeSilentEscrow";
113 CKKSAnalyticsFailableEvent* const OctagonEventUpgradePreapprovedJoin = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradePreapprovedJoin";
114 CKKSAnalyticsFailableEvent* const OctagonEventUpgradePreflightPreapprovedJoin = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradePreflightPreapprovedJoin";
115 CKKSAnalyticsFailableEvent* const OctagonEventUpgradePreapprovedJoinAfterPairing = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradePreapprovedJoinAfterPairing";
116 CKKSAnalyticsFailableEvent* const OctagonEventUpgradePrepare = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradePrepare";
117
118 CKKSAnalyticsFailableEvent* const OctagonEventJoinWithVoucher = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinWithVoucher";
119
120 CKKSAnalyticsFailableEvent* const OctagonEventVoucherWithBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventVoucherWithBottle";
121
122 CKKSAnalyticsFailableEvent* const OctagonEventVoucherWithRecoveryKey = (CKKSAnalyticsFailableEvent*)@"OctagonEventVoucherWithRecoveryKey";
123
124 CKKSAnalyticsFailableEvent* const OctagonEventSetRecoveryKey = (CKKSAnalyticsFailableEvent*)@"OctagonEventSetRecoveryKey";
125
126 CKKSAnalyticsFailableEvent* const OctagonEventSetRecoveryKeyValidationFailed = (CKKSAnalyticsFailableEvent*)@"OctagonEventSetRecoveryKeyValidationFailed";
127 CKKSAnalyticsFailableEvent* const OctagonEventJoinRecoveryKeyValidationFailed = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinRecoveryKeyValidationFailed";
128 CKKSAnalyticsFailableEvent* const OctagonEventJoinRecoveryKeyCircleReset = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinRecoveryKeyCircleReset";
129 CKKSAnalyticsFailableEvent* const OctagonEventJoinRecoveryKeyCircleResetFailed = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinRecoveryKeyCircleResetFailed";
130 CKKSAnalyticsFailableEvent* const OctagonEventJoinRecoveryKeyEnrollFailed = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinRecoveryKeyEnrollFailed";
131 CKKSAnalyticsFailableEvent* const OctagonEventJoinRecoveryKeyFailed = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinRecoveryKeyFailed";
132
133 CKKSAnalyticsFailableEvent* const OctagonEventReset = (CKKSAnalyticsFailableEvent*)@"OctagonEventReset";
134
135 CKKSAnalyticsFailableEvent* const OctagonEventPrepareIdentity = (CKKSAnalyticsFailableEvent*)@"OctagonEventPrepareIdentity";
136
137 CKKSAnalyticsFailableEvent* const OctagonEventEstablishIdentity = (CKKSAnalyticsFailableEvent*)@"OctagonEventEstablishIdentity";
138 CKKSAnalyticsFailableEvent* const OctagonEventFetchViews = (CKKSAnalyticsFailableEvent*)@"OctagonEventFetchViews";
139
140 CKKSAnalyticsFailableEvent* const OctagonEventStateTransition = (CKKSAnalyticsFailableEvent*)@"OctagonEventStateTransition";
141
142 CKKSAnalyticsFailableEvent* const OctagonEventCompanionPairing = (CKKSAnalyticsFailableEvent*)@"OctagonEventCompanionPairing";
143
144 CKKSAnalyticsFailableEvent* const OctagonEventCheckTrustForCFU = (CKKSAnalyticsFailableEvent*)@"OctagonEventCheckTrustForCFU";
145
146 CKKSAnalyticsSignpostEvent* const CKKSEventPushNotificationReceived = (CKKSAnalyticsSignpostEvent*)@"CKKSEventPushNotificationReceived";
147 CKKSAnalyticsSignpostEvent* const CKKSEventItemAddedToOutgoingQueue = (CKKSAnalyticsSignpostEvent*)@"CKKSEventItemAddedToOutgoingQueue";
148 CKKSAnalyticsSignpostEvent* const CKKSEventMissingLocalItemsFound = (CKKSAnalyticsSignpostEvent*)@"CKKSEventMissingLocalItemsFound";
149 CKKSAnalyticsSignpostEvent* const CKKSEventReachabilityTimerExpired = (CKKSAnalyticsSignpostEvent *)@"CKKSEventReachabilityTimerExpired";
150
151 CKKSAnalyticsFailableEvent* const OctagonEventTPHHealthCheckStatus = (CKKSAnalyticsFailableEvent*)@"OctagonEventTPHHealthCheckStatus";
152
153 CKKSAnalyticsActivity* const CKKSActivityOTFetchRampState = (CKKSAnalyticsActivity *)@"CKKSActivityOTFetchRampState";
154 CKKSAnalyticsActivity* const CKKSActivityOctagonPreflightBottle = (CKKSAnalyticsActivity *)@"CKKSActivityOctagonPreflightBottle";
155 CKKSAnalyticsActivity* const CKKSActivityOctagonLaunchBottle = (CKKSAnalyticsActivity *)@"CKKSActivityOctagonLaunchBottle";
156 CKKSAnalyticsActivity* const CKKSActivityOctagonRestore = (CKKSAnalyticsActivity *)@"CKKSActivityOctagonRestore";
157 CKKSAnalyticsActivity* const CKKSActivityScrubBottle = (CKKSAnalyticsActivity *)@"CKKSActivityScrubBottle";
158 CKKSAnalyticsActivity* const CKKSActivityBottleCheck = (CKKSAnalyticsActivity *)@"CKKSActivityBottleCheck";
159 CKKSAnalyticsActivity* const CKKSActivityOctagonUpdateBottle = (CKKSAnalyticsActivity *)@"CKKSActivityOctagonUpdateBottle";
160
161 CKKSAnalyticsActivity* const OctagonActivityAccountAvailable = (CKKSAnalyticsActivity *)@"OctagonActivityAccountAvailable";
162 CKKSAnalyticsActivity* const OctagonActivityAccountNotAvailable = (CKKSAnalyticsActivity *)@"OctagonActivityAccountNotAvailable";
163 CKKSAnalyticsActivity* const OctagonActivityResetAndEstablish = (CKKSAnalyticsActivity *)@"OctagonActivityResetAndEstablish";
164 CKKSAnalyticsActivity* const OctagonActivityEstablish = (CKKSAnalyticsActivity *)@"OctagonActivityEstablish";
165 CKKSAnalyticsActivity* const OctagonSOSAdapterUpdateKeys = (CKKSAnalyticsActivity*)@"OctagonSOSAdapterUpdateKeys";
166
167 CKKSAnalyticsActivity* const OctagonActivityFetchAllViableBottles = (CKKSAnalyticsActivity *)@"OctagonActivityFetchAllViableBottles";
168 CKKSAnalyticsActivity* const OctagonActivityFetchEscrowContents = (CKKSAnalyticsActivity *)@"OctagonActivityFetchEscrowContents";
169 CKKSAnalyticsActivity* const OctagonActivityBottledPeerRestore = (CKKSAnalyticsActivity *)@"OctagonActivityBottledPeerRestore";
170 CKKSAnalyticsActivity* const OctagonActivitySetRecoveryKey = (CKKSAnalyticsActivity *)@"OctagonActivitySetRecoveryKey";
171 CKKSAnalyticsActivity* const OctagonActivityJoinWithRecoveryKey = (CKKSAnalyticsActivity *)@"OctagonActivityJoinWithRecoveryKey";
172
173 CKKSAnalyticsActivity* const OctagonActivityLeaveClique = (CKKSAnalyticsActivity *)@"OctagonActivityLeaveClique";
174 CKKSAnalyticsActivity* const OctagonActivityRemoveFriendsInClique = (CKKSAnalyticsActivity *)@"OctagonActivityRemoveFriendsInClique";
175
176
177
178 @implementation CKKSAnalytics
179
180 + (NSString*)databasePath
181 {
182 // This block exists because we moved database locations in 11.3 for easier sandboxing of securityuploadd, so we're cleaning up.
183 static dispatch_once_t onceToken;
184 dispatch_once(&onceToken, ^{
185 WithPathInKeychainDirectory(CFSTR("ckks_analytics_v2.db"), ^(const char *filename) {
186 remove(filename);
187 });
188 WithPathInKeychainDirectory(CFSTR("ckks_analytics_v2.db-wal"), ^(const char *filename) {
189 remove(filename);
190 });
191 WithPathInKeychainDirectory(CFSTR("ckks_analytics_v2.db-shm"), ^(const char *filename) {
192 remove(filename);
193 });
194 });
195 return [CKKSAnalytics defaultAnalyticsDatabasePath:@"ckks_analytics"];
196 }
197
198 + (instancetype)logger
199 {
200 // just here because I want it in the header for discoverability
201 return [super logger];
202 }
203
204 - (void)logSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view
205 {
206 [self logSuccessForEventNamed:[NSString stringWithFormat:@"%@-%@", view.zoneName, event]];
207 [self setDateProperty:[NSDate date] forKey:[NSString stringWithFormat:@"last_success_%@-%@", view.zoneName, event]];
208 }
209
210 - (bool)isCKPartialError:(NSError *)error
211 {
212 return [error.domain isEqualToString:CKErrorDomain] && error.code == CKErrorPartialFailure;
213 }
214
215 - (void)addCKPartialError:(NSMutableDictionary *)errorDictionary error:(NSError *)error depth:(NSUInteger)depth
216 {
217 // capture one random underlaying error
218 if ([self isCKPartialError:error]) {
219 NSDictionary<NSString *,NSError *> *partialErrors = error.userInfo[CKPartialErrorsByItemIDKey];
220 if ([partialErrors isKindOfClass:[NSDictionary class]]) {
221 for (NSString *key in partialErrors) {
222 NSError* ckError = partialErrors[key];
223 if (![ckError isKindOfClass:[NSError class]])
224 continue;
225 if ([ckError.domain isEqualToString:CKErrorDomain] && ckError.code == CKErrorBatchRequestFailed) {
226 continue;
227 }
228 NSDictionary *res = [self errorChain:ckError depth:(depth + 1)];
229 if (res) {
230 errorDictionary[@"oneCloudKitPartialFailure"] = res;
231 break;
232 }
233 }
234 }
235 }
236 }
237
238 // if we have underlying errors, capture the chain below the top-most error
239 - (NSDictionary *)errorChain:(NSError *)error depth:(NSUInteger)depth
240 {
241 NSMutableDictionary *errorDictionary = nil;
242
243 if (depth > 5 || ![error isKindOfClass:[NSError class]])
244 return nil;
245
246 errorDictionary = [@{
247 @"domain" : error.domain,
248 @"code" : @(error.code),
249 } mutableCopy];
250
251 errorDictionary[@"child"] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:(depth + 1)];
252 [self addCKPartialError:errorDictionary error:error depth:(depth + 1)];
253
254 return errorDictionary;
255 }
256
257 - (NSDictionary *)createErrorAttributes:(NSError *)error
258 depth:(NSUInteger)depth
259 attributes:(NSDictionary *)attributes
260 {
261 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
262
263 /* Don't allow caller to overwrite our attributes, lets merge them first */
264 if (attributes) {
265 [eventAttributes setValuesForKeysWithDictionary:attributes];
266 }
267
268 [eventAttributes setValuesForKeysWithDictionary:@{
269 CKKSAnalyticsAttributeRecoverableError : @(YES),
270 CKKSAnalyticsAttributeErrorDomain : error.domain,
271 CKKSAnalyticsAttributeErrorCode : @(error.code)
272 }];
273
274 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
275 [self addCKPartialError:eventAttributes error:error depth:0];
276
277 return eventAttributes;
278 }
279
280 - (void)logRecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event zoneName:(NSString*)zoneName withAttributes:(NSDictionary *)attributes
281 {
282 if (error == nil){
283 return;
284 }
285 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
286
287 /* Don't allow caller to overwrite our attributes, lets merge them first */
288 if (attributes) {
289 [eventAttributes setValuesForKeysWithDictionary:attributes];
290 }
291
292 [eventAttributes setValuesForKeysWithDictionary:@{
293 CKKSAnalyticsAttributeRecoverableError : @(YES),
294 CKKSAnalyticsAttributeZoneName : zoneName,
295 CKKSAnalyticsAttributeErrorDomain : error.domain,
296 CKKSAnalyticsAttributeErrorCode : @(error.code)
297 }];
298
299 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
300 [self addCKPartialError:eventAttributes error:error depth:0];
301
302 [super logSoftFailureForEventNamed:event withAttributes:eventAttributes];
303 }
304
305 - (void)logRecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event withAttributes:(NSDictionary *)attributes
306 {
307 if (error == nil){
308 return;
309 }
310 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
311
312 /* Don't allow caller to overwrite our attributes, lets merge them first */
313 if (attributes) {
314 [eventAttributes setValuesForKeysWithDictionary:attributes];
315 }
316
317 [eventAttributes setValuesForKeysWithDictionary:@{
318 CKKSAnalyticsAttributeRecoverableError : @(YES),
319 CKKSAnalyticsAttributeErrorDomain : error.domain,
320 CKKSAnalyticsAttributeErrorCode : @(error.code)
321 }];
322
323 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
324 [self addCKPartialError:eventAttributes error:error depth:0];
325
326 [super logSoftFailureForEventNamed:event withAttributes:eventAttributes];
327 }
328
329 - (void)logRecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view withAttributes:(NSDictionary *)attributes
330 {
331 if (error == nil){
332 return;
333 }
334 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
335
336 /* Don't allow caller to overwrite our attributes, lets merge them first */
337 if (attributes) {
338 [eventAttributes setValuesForKeysWithDictionary:attributes];
339 }
340
341 [eventAttributes setValuesForKeysWithDictionary:@{
342 CKKSAnalyticsAttributeRecoverableError : @(YES),
343 CKKSAnalyticsAttributeZoneName : view.zoneName,
344 CKKSAnalyticsAttributeErrorDomain : error.domain,
345 CKKSAnalyticsAttributeErrorCode : @(error.code)
346 }];
347
348 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
349 [self addCKPartialError:eventAttributes error:error depth:0];
350
351 [super logSoftFailureForEventNamed:event withAttributes:eventAttributes];
352 }
353
354 - (void)logUnrecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view withAttributes:(NSDictionary *)attributes
355 {
356 if (error == nil){
357 return;
358 }
359 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
360 if (attributes) {
361 [eventAttributes setValuesForKeysWithDictionary:attributes];
362 }
363
364 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
365 [self addCKPartialError:eventAttributes error:error depth:0];
366
367 [eventAttributes setValuesForKeysWithDictionary:@{
368 CKKSAnalyticsAttributeRecoverableError : @(NO),
369 CKKSAnalyticsAttributeZoneName : view.zoneName,
370 CKKSAnalyticsAttributeErrorDomain : error.domain,
371 CKKSAnalyticsAttributeErrorCode : @(error.code)
372 }];
373
374 [self logHardFailureForEventNamed:event withAttributes:eventAttributes];
375 }
376
377 - (void)logUnrecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event withAttributes:(NSDictionary *)attributes
378 {
379 if (error == nil){
380 return;
381 }
382 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
383
384 /* Don't allow caller to overwrite our attributes, lets merge them first */
385 if (attributes) {
386 [eventAttributes setValuesForKeysWithDictionary:attributes];
387 }
388
389 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
390 [self addCKPartialError:eventAttributes error:error depth:0];
391
392 [eventAttributes setValuesForKeysWithDictionary:@{
393 CKKSAnalyticsAttributeRecoverableError : @(NO),
394 CKKSAnalyticsAttributeZoneName : OctagonEventAttributeZoneName,
395 CKKSAnalyticsAttributeErrorDomain : error.domain,
396 CKKSAnalyticsAttributeErrorCode : @(error.code)
397 }];
398
399 [self logHardFailureForEventNamed:event withAttributes:eventAttributes];
400 }
401
402 - (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event
403 {
404 [self noteEventNamed:event];
405 }
406 - (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event inView:(CKKSKeychainView*)view
407 {
408 [self noteEventNamed:[NSString stringWithFormat:@"%@-%@", view.zoneName, event]];
409 }
410
411 - (NSDate*)dateOfLastSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view
412 {
413 return [self datePropertyForKey:[NSString stringWithFormat:@"last_success_%@-%@", view.zoneName, event]];
414 }
415
416 - (void)setDateProperty:(NSDate*)date forKey:(NSString*)key inView:(CKKSKeychainView *)view
417 {
418 [self setDateProperty:date forKey:[NSString stringWithFormat:@"%@-%@", key, view.zoneName]];
419 }
420 - (NSDate *)datePropertyForKey:(NSString *)key inView:(CKKSKeychainView *)view
421 {
422 return [self datePropertyForKey:[NSString stringWithFormat:@"%@-%@", key, view.zoneName]];
423 }
424
425 @end
426
427 #endif // OCTAGON