]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKSAnalytics.m
Security-59306.101.1.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 OctagonAnalyticCDPBitStatus = @"OACDPStatus";
53
54 NSString* const OctagonAnalyticsTrustState = @"OATrust";
55 NSString* const OctagonAnalyticsAttemptedJoin = @"OAAttemptedJoin";
56 NSString* const OctagonAnalyticsLastHealthCheck = @"OAHealthCheck";
57 NSString* const OctagonAnalyticsSOSStatus = @"OASOSStatus";
58 NSString* const OctagonAnalyticsDateOfLastPreflightPreapprovedJoin = @"OALastPPJ";
59 NSString* const OctagonAnalyticsLastKeystateReady = @"OALastKSR";
60 NSString* const OctagonAnalyticsLastCoreFollowup = @"OALastCFU";
61 //NSString* const OctagonAnalyticsCoreFollowupStatus = @"OACFUStatus";
62 NSString* const OctagonAnalyticsCoreFollowupFailureCount = @"OACFUTFailureCount";
63 NSString* const OctagonAnalyticsCoreFollowupLastFailureTime = @"OACFULastFailureTime";
64 NSString* const OctagonAnalyticsPrerecordPending = @"OAPrerecordPending";
65 NSString* const OctagonAnalyticsCDPStateRun = @"OACDPStateRun";
66
67 NSString* const OctagonAnalyticsBottledUniqueTLKsRecovered = @"OABottledUniqueTLKsRecoveredCount";
68 NSString* const OctagonAnalyticsBottledTotalTLKShares = @"OABottledTotalTLKSharesCount";
69 NSString* const OctagonAnalyticsBottledTotalTLKSharesRecovered = @"OABottledTotalTLKSharesRecoveredCount";
70 NSString* const OctagonAnalyticsBottledUniqueTLKsWithSharesCount = @"OABottledUniqueTLKsWithSharesCount";
71 NSString* const OctagonAnalyticsBottledTLKUniqueViewCount = @"OABottledTLKUniqueViewCount";
72
73 NSString* const OctagonAnalyticsHaveMachineID = @"OAMIDPresent";
74 NSString* const OctagonAnalyticsMIDOnMemoizedList = @"OAMIDOnList";
75 NSString* const OctagonAnalyticsPeersWithMID = @"OAPeersWithMID";
76
77 NSString* const CKKSAnalyticsLastCKKSPush = @"lastCKKSPush";
78 NSString* const CKKSAnalyticsLastOctagonPush = @"lastOctagonPush";
79
80 NSString* const OctagonAnalyticsKVSProvisioned = @"OADCKVSProvisioned";
81 NSString* const OctagonAnalyticsKVSEnabled = @"OADCKVSEnabled";
82 NSString* const OctagonAnalyticsKeychainSyncProvisioned = @"OADCKCSProvisioned";
83 NSString* const OctagonAnalyticsKeychainSyncEnabled = @"OADCKCSEnabled";
84 NSString* const OctagonAnalyticsCloudKitProvisioned = @"OADCCKProvisioned";
85 NSString* const OctagonAnalyticsCloudKitEnabled = @"OADCCKEnabled";
86
87 static NSString* const CKKSAnalyticsAttributeRecoverableError = @"recoverableError";
88 static NSString* const CKKSAnalyticsAttributeZoneName = @"zone";
89 static NSString* const CKKSAnalyticsAttributeErrorDomain = @"errorDomain";
90 static NSString* const CKKSAnalyticsAttributeErrorCode = @"errorCode";
91 static NSString* const CKKSAnalyticsAttributeErrorChain = @"errorChain";
92
93 CKKSAnalyticsFailableEvent* const CKKSEventProcessIncomingQueueClassA = (CKKSAnalyticsFailableEvent*)@"CKKSEventProcessIncomingQueueClassA";
94 CKKSAnalyticsFailableEvent* const CKKSEventProcessIncomingQueueClassC = (CKKSAnalyticsFailableEvent*)@"CKKSEventProcessIncomingQueueClassC";
95 CKKSAnalyticsFailableEvent* const CKKSEventProcessOutgoingQueue = (CKKSAnalyticsFailableEvent*)@"CKKSEventProcessOutgoingQueue";
96 CKKSAnalyticsFailableEvent* const CKKSEventUploadChanges = (CKKSAnalyticsFailableEvent*)@"CKKSEventUploadChanges";
97 CKKSAnalyticsFailableEvent* const CKKSEventStateError = (CKKSAnalyticsFailableEvent*)@"CKKSEventStateError";
98 CKKSAnalyticsFailableEvent* const CKKSEventProcessHealKeyHierarchy = (CKKSAnalyticsFailableEvent *)@"CKKSEventProcessHealKeyHierarchy";
99 CKKSAnalyticsFailableEvent* const CKKSEventProcessReencryption = (CKKSAnalyticsFailableEvent *)@"CKKSEventProcessReencryption";
100
101 NSString* const OctagonEventFailureReason = @"FailureReason";
102
103 CKKSAnalyticsFailableEvent* const OctagonEventPreflightBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventPreflightBottle";
104 CKKSAnalyticsFailableEvent* const OctagonEventLaunchBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventLaunchBottle";
105 CKKSAnalyticsFailableEvent* const OctagonEventRestoreBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventRestoreBottle";
106 CKKSAnalyticsFailableEvent* const OctagonEventScrubBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventScrubBottle";
107 CKKSAnalyticsFailableEvent* const OctagonEventSignIn = (CKKSAnalyticsFailableEvent *)@"OctagonEventSignIn";
108 CKKSAnalyticsFailableEvent* const OctagonEventSignOut = (CKKSAnalyticsFailableEvent *)@"OctagonEventSignIn";
109 CKKSAnalyticsFailableEvent* const OctagonEventRamp = (CKKSAnalyticsFailableEvent *)@"OctagonEventRamp";
110 CKKSAnalyticsFailableEvent* const OctagonEventBottleCheck = (CKKSAnalyticsFailableEvent *)@"OctagonEventBottleCheck";
111 CKKSAnalyticsFailableEvent* const OctagonEventCoreFollowUp = (CKKSAnalyticsFailableEvent *)@"OctagonEventCoreFollowUp";
112 CKKSAnalyticsFailableEvent* const OctagonEventUpdateBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpdateBottle";
113
114 CKKSAnalyticsFailableEvent* const OctagonEventCheckTrustState = (CKKSAnalyticsFailableEvent *)@"OctagonEventCheckTrustState";
115
116 CKKSAnalyticsFailableEvent* const OctagonEventBottledPeerRestore = (CKKSAnalyticsFailableEvent*)@"OctagonEventBottledPeerRestore";
117 CKKSAnalyticsFailableEvent* const OctagonEventRecoveryKey = (CKKSAnalyticsFailableEvent*)@"OctagonEventRecoveryKey";
118
119 CKKSAnalyticsFailableEvent* const OctagonEventFetchAllBottles = (CKKSAnalyticsFailableEvent*)@"OctagonEventFetchAllBottles";
120 CKKSAnalyticsFailableEvent* const OctagonEventFetchEscrowContents = (CKKSAnalyticsFailableEvent*)@"OctagonEventFetchEscrowContents";
121 CKKSAnalyticsFailableEvent* const OctagonEventResetAndEstablish = (CKKSAnalyticsFailableEvent*)@"OctagonEventResetAndEstablish";
122 CKKSAnalyticsFailableEvent* const OctagonEventEstablish = (CKKSAnalyticsFailableEvent*)@"OctagonEventEstablish";
123 CKKSAnalyticsFailableEvent* const OctagonEventLeaveClique = (CKKSAnalyticsFailableEvent*)@"OctagonEventLeaveClique";
124 CKKSAnalyticsFailableEvent* const OctagonEventRemoveFriendsInClique = (CKKSAnalyticsFailableEvent*)@"OctagonEventRemoveFriendsInClique";
125
126 CKKSAnalyticsFailableEvent* const OctagonEventUpgradeFetchDeviceIDs = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradeFetchDeviceIDs";
127 CKKSAnalyticsFailableEvent* const OctagonEventUpgradeSetAllowList = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradeSetAllowList";
128 CKKSAnalyticsFailableEvent* const OctagonEventUpgradeSilentEscrow = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradeSilentEscrow";
129 CKKSAnalyticsFailableEvent* const OctagonEventUpgradePreapprovedJoin = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradePreapprovedJoin";
130 CKKSAnalyticsFailableEvent* const OctagonEventUpgradePreflightPreapprovedJoin = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradePreflightPreapprovedJoin";
131 CKKSAnalyticsFailableEvent* const OctagonEventUpgradePreapprovedJoinAfterPairing = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradePreapprovedJoinAfterPairing";
132 CKKSAnalyticsFailableEvent* const OctagonEventUpgradePrepare = (CKKSAnalyticsFailableEvent*)@"OctagonEventUpgradePrepare";
133
134 CKKSAnalyticsFailableEvent* const OctagonEventJoinWithVoucher = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinWithVoucher";
135
136 CKKSAnalyticsFailableEvent* const OctagonEventPreflightVouchWithBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventPreflightVouchWithBottle";
137 CKKSAnalyticsFailableEvent* const OctagonEventVoucherWithBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventVoucherWithBottle";
138
139 CKKSAnalyticsFailableEvent* const OctagonEventPreflightVouchWithRecoveryKey = (CKKSAnalyticsFailableEvent*)@"OctagonEventPreflightVouchWithRecoveryKey";;
140 CKKSAnalyticsFailableEvent* const OctagonEventVoucherWithRecoveryKey = (CKKSAnalyticsFailableEvent*)@"OctagonEventVoucherWithRecoveryKey";
141
142 CKKSAnalyticsFailableEvent* const OctagonEventSetRecoveryKey = (CKKSAnalyticsFailableEvent*)@"OctagonEventSetRecoveryKey";
143
144 CKKSAnalyticsFailableEvent* const OctagonEventSetRecoveryKeyValidationFailed = (CKKSAnalyticsFailableEvent*)@"OctagonEventSetRecoveryKeyValidationFailed";
145 CKKSAnalyticsFailableEvent* const OctagonEventJoinRecoveryKeyValidationFailed = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinRecoveryKeyValidationFailed";
146 CKKSAnalyticsFailableEvent* const OctagonEventJoinRecoveryKeyCircleReset = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinRecoveryKeyCircleReset";
147 CKKSAnalyticsFailableEvent* const OctagonEventJoinRecoveryKeyCircleResetFailed = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinRecoveryKeyCircleResetFailed";
148 CKKSAnalyticsFailableEvent* const OctagonEventJoinRecoveryKeyEnrollFailed = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinRecoveryKeyEnrollFailed";
149 CKKSAnalyticsFailableEvent* const OctagonEventJoinRecoveryKeyFailed = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinRecoveryKeyFailed";
150
151 CKKSAnalyticsFailableEvent* const OctagonEventReset = (CKKSAnalyticsFailableEvent*)@"OctagonEventReset";
152
153 CKKSAnalyticsFailableEvent* const OctagonEventPrepareIdentity = (CKKSAnalyticsFailableEvent*)@"OctagonEventPrepareIdentity";
154
155 CKKSAnalyticsFailableEvent* const OctagonEventEstablishIdentity = (CKKSAnalyticsFailableEvent*)@"OctagonEventEstablishIdentity";
156 CKKSAnalyticsFailableEvent* const OctagonEventFetchViews = (CKKSAnalyticsFailableEvent*)@"OctagonEventFetchViews";
157
158 CKKSAnalyticsFailableEvent* const OctagonEventStateTransition = (CKKSAnalyticsFailableEvent*)@"OctagonEventStateTransition";
159
160 CKKSAnalyticsFailableEvent* const OctagonEventCompanionPairing = (CKKSAnalyticsFailableEvent*)@"OctagonEventCompanionPairing";
161
162 CKKSAnalyticsFailableEvent* const OctagonEventCheckTrustForCFU = (CKKSAnalyticsFailableEvent*)@"OctagonEventCheckTrustForCFU";
163
164 CKKSAnalyticsSignpostEvent* const CKKSEventPushNotificationReceived = (CKKSAnalyticsSignpostEvent*)@"CKKSEventPushNotificationReceived";
165 CKKSAnalyticsSignpostEvent* const CKKSEventItemAddedToOutgoingQueue = (CKKSAnalyticsSignpostEvent*)@"CKKSEventItemAddedToOutgoingQueue";
166 CKKSAnalyticsSignpostEvent* const CKKSEventMissingLocalItemsFound = (CKKSAnalyticsSignpostEvent*)@"CKKSEventMissingLocalItemsFound";
167 CKKSAnalyticsSignpostEvent* const CKKSEventReachabilityTimerExpired = (CKKSAnalyticsSignpostEvent *)@"CKKSEventReachabilityTimerExpired";
168
169 CKKSAnalyticsFailableEvent* const OctagonEventTPHHealthCheckStatus = (CKKSAnalyticsFailableEvent*)@"OctagonEventTPHHealthCheckStatus";
170
171 CKKSAnalyticsFailableEvent* const OctagonEventAuthKitDeviceList = (CKKSAnalyticsFailableEvent *)@"OctagonEventAuthKitDeviceList";
172
173 CKKSAnalyticsActivity* const CKKSActivityOTFetchRampState = (CKKSAnalyticsActivity *)@"CKKSActivityOTFetchRampState";
174 CKKSAnalyticsActivity* const CKKSActivityOctagonPreflightBottle = (CKKSAnalyticsActivity *)@"CKKSActivityOctagonPreflightBottle";
175 CKKSAnalyticsActivity* const CKKSActivityOctagonLaunchBottle = (CKKSAnalyticsActivity *)@"CKKSActivityOctagonLaunchBottle";
176 CKKSAnalyticsActivity* const CKKSActivityOctagonRestore = (CKKSAnalyticsActivity *)@"CKKSActivityOctagonRestore";
177 CKKSAnalyticsActivity* const CKKSActivityScrubBottle = (CKKSAnalyticsActivity *)@"CKKSActivityScrubBottle";
178 CKKSAnalyticsActivity* const CKKSActivityBottleCheck = (CKKSAnalyticsActivity *)@"CKKSActivityBottleCheck";
179 CKKSAnalyticsActivity* const CKKSActivityOctagonUpdateBottle = (CKKSAnalyticsActivity *)@"CKKSActivityOctagonUpdateBottle";
180
181 CKKSAnalyticsActivity* const OctagonActivityAccountAvailable = (CKKSAnalyticsActivity *)@"OctagonActivityAccountAvailable";
182 CKKSAnalyticsActivity* const OctagonActivityAccountNotAvailable = (CKKSAnalyticsActivity *)@"OctagonActivityAccountNotAvailable";
183 CKKSAnalyticsActivity* const OctagonActivityResetAndEstablish = (CKKSAnalyticsActivity *)@"OctagonActivityResetAndEstablish";
184 CKKSAnalyticsActivity* const OctagonActivityEstablish = (CKKSAnalyticsActivity *)@"OctagonActivityEstablish";
185 CKKSAnalyticsActivity* const OctagonSOSAdapterUpdateKeys = (CKKSAnalyticsActivity*)@"OctagonSOSAdapterUpdateKeys";
186
187 CKKSAnalyticsActivity* const OctagonActivityFetchAllViableBottles = (CKKSAnalyticsActivity *)@"OctagonActivityFetchAllViableBottles";
188 CKKSAnalyticsActivity* const OctagonActivityFetchEscrowContents = (CKKSAnalyticsActivity *)@"OctagonActivityFetchEscrowContents";
189 CKKSAnalyticsActivity* const OctagonActivityBottledPeerRestore = (CKKSAnalyticsActivity *)@"OctagonActivityBottledPeerRestore";
190 CKKSAnalyticsActivity* const OctagonActivitySetRecoveryKey = (CKKSAnalyticsActivity *)@"OctagonActivitySetRecoveryKey";
191 CKKSAnalyticsActivity* const OctagonActivityJoinWithRecoveryKey = (CKKSAnalyticsActivity *)@"OctagonActivityJoinWithRecoveryKey";
192
193 CKKSAnalyticsActivity* const OctagonActivityLeaveClique = (CKKSAnalyticsActivity *)@"OctagonActivityLeaveClique";
194 CKKSAnalyticsActivity* const OctagonActivityRemoveFriendsInClique = (CKKSAnalyticsActivity *)@"OctagonActivityRemoveFriendsInClique";
195
196
197
198 @implementation CKKSAnalytics
199
200 + (NSString*)databasePath
201 {
202 // This block exists because we moved database locations in 11.3 for easier sandboxing of securityuploadd, so we're cleaning up.
203 static dispatch_once_t onceToken;
204 dispatch_once(&onceToken, ^{
205 WithPathInKeychainDirectory(CFSTR("ckks_analytics_v2.db"), ^(const char *filename) {
206 remove(filename);
207 });
208 WithPathInKeychainDirectory(CFSTR("ckks_analytics_v2.db-wal"), ^(const char *filename) {
209 remove(filename);
210 });
211 WithPathInKeychainDirectory(CFSTR("ckks_analytics_v2.db-shm"), ^(const char *filename) {
212 remove(filename);
213 });
214 });
215 return [CKKSAnalytics defaultAnalyticsDatabasePath:@"ckks_analytics"];
216 }
217
218 + (instancetype)logger
219 {
220 // just here because I want it in the header for discoverability
221 return [super logger];
222 }
223
224 - (void)logSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view
225 {
226 [self logSuccessForEventNamed:[NSString stringWithFormat:@"%@-%@", view.zoneName, event]];
227 [self setDateProperty:[NSDate date] forKey:[NSString stringWithFormat:@"last_success_%@-%@", view.zoneName, event]];
228 }
229
230 - (bool)isCKPartialError:(NSError *)error
231 {
232 return [error.domain isEqualToString:CKErrorDomain] && error.code == CKErrorPartialFailure;
233 }
234
235 - (void)addCKPartialError:(NSMutableDictionary *)errorDictionary error:(NSError *)error depth:(NSUInteger)depth
236 {
237 // capture one random underlaying error
238 if ([self isCKPartialError:error]) {
239 NSDictionary<NSString *,NSError *> *partialErrors = error.userInfo[CKPartialErrorsByItemIDKey];
240 if ([partialErrors isKindOfClass:[NSDictionary class]]) {
241 for (NSString *key in partialErrors) {
242 NSError* ckError = partialErrors[key];
243 if (![ckError isKindOfClass:[NSError class]])
244 continue;
245 if ([ckError.domain isEqualToString:CKErrorDomain] && ckError.code == CKErrorBatchRequestFailed) {
246 continue;
247 }
248 NSDictionary *res = [self errorChain:ckError depth:(depth + 1)];
249 if (res) {
250 errorDictionary[@"oneCloudKitPartialFailure"] = res;
251 break;
252 }
253 }
254 }
255 }
256 }
257
258 // if we have underlying errors, capture the chain below the top-most error
259 - (NSDictionary *)errorChain:(NSError *)error depth:(NSUInteger)depth
260 {
261 NSMutableDictionary *errorDictionary = nil;
262
263 if (depth > 5 || ![error isKindOfClass:[NSError class]])
264 return nil;
265
266 errorDictionary = [@{
267 @"domain" : error.domain,
268 @"code" : @(error.code),
269 } mutableCopy];
270
271 errorDictionary[@"child"] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:(depth + 1)];
272 [self addCKPartialError:errorDictionary error:error depth:(depth + 1)];
273
274 return errorDictionary;
275 }
276
277 - (NSDictionary *)createErrorAttributes:(NSError *)error
278 depth:(NSUInteger)depth
279 attributes:(NSDictionary *)attributes
280 {
281 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
282
283 /* Don't allow caller to overwrite our attributes, lets merge them first */
284 if (attributes) {
285 [eventAttributes setValuesForKeysWithDictionary:attributes];
286 }
287
288 [eventAttributes setValuesForKeysWithDictionary:@{
289 CKKSAnalyticsAttributeRecoverableError : @(YES),
290 CKKSAnalyticsAttributeErrorDomain : error.domain,
291 CKKSAnalyticsAttributeErrorCode : @(error.code)
292 }];
293
294 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
295 [self addCKPartialError:eventAttributes error:error depth:0];
296
297 return eventAttributes;
298 }
299
300 - (void)logRecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event zoneName:(NSString*)zoneName withAttributes:(NSDictionary *)attributes
301 {
302 if (error == nil){
303 return;
304 }
305 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
306
307 /* Don't allow caller to overwrite our attributes, lets merge them first */
308 if (attributes) {
309 [eventAttributes setValuesForKeysWithDictionary:attributes];
310 }
311
312 [eventAttributes setValuesForKeysWithDictionary:@{
313 CKKSAnalyticsAttributeRecoverableError : @(YES),
314 CKKSAnalyticsAttributeZoneName : zoneName,
315 CKKSAnalyticsAttributeErrorDomain : error.domain,
316 CKKSAnalyticsAttributeErrorCode : @(error.code)
317 }];
318
319 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
320 [self addCKPartialError:eventAttributes error:error depth:0];
321
322 [super logSoftFailureForEventNamed:event withAttributes:eventAttributes];
323 }
324
325 - (void)logRecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event withAttributes:(NSDictionary *)attributes
326 {
327 if (error == nil){
328 return;
329 }
330 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
331
332 /* Don't allow caller to overwrite our attributes, lets merge them first */
333 if (attributes) {
334 [eventAttributes setValuesForKeysWithDictionary:attributes];
335 }
336
337 [eventAttributes setValuesForKeysWithDictionary:@{
338 CKKSAnalyticsAttributeRecoverableError : @(YES),
339 CKKSAnalyticsAttributeErrorDomain : error.domain,
340 CKKSAnalyticsAttributeErrorCode : @(error.code)
341 }];
342
343 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
344 [self addCKPartialError:eventAttributes error:error depth:0];
345
346 [super logSoftFailureForEventNamed:event withAttributes:eventAttributes];
347 }
348
349 - (void)logRecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view withAttributes:(NSDictionary *)attributes
350 {
351 if (error == nil){
352 return;
353 }
354 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
355
356 /* Don't allow caller to overwrite our attributes, lets merge them first */
357 if (attributes) {
358 [eventAttributes setValuesForKeysWithDictionary:attributes];
359 }
360
361 [eventAttributes setValuesForKeysWithDictionary:@{
362 CKKSAnalyticsAttributeRecoverableError : @(YES),
363 CKKSAnalyticsAttributeZoneName : view.zoneName,
364 CKKSAnalyticsAttributeErrorDomain : error.domain,
365 CKKSAnalyticsAttributeErrorCode : @(error.code)
366 }];
367
368 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
369 [self addCKPartialError:eventAttributes error:error depth:0];
370
371 [super logSoftFailureForEventNamed:event withAttributes:eventAttributes];
372 }
373
374 - (void)logUnrecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view withAttributes:(NSDictionary *)attributes
375 {
376 if (error == nil){
377 return;
378 }
379 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
380 if (attributes) {
381 [eventAttributes setValuesForKeysWithDictionary:attributes];
382 }
383
384 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
385 [self addCKPartialError:eventAttributes error:error depth:0];
386
387 [eventAttributes setValuesForKeysWithDictionary:@{
388 CKKSAnalyticsAttributeRecoverableError : @(NO),
389 CKKSAnalyticsAttributeZoneName : view.zoneName,
390 CKKSAnalyticsAttributeErrorDomain : error.domain,
391 CKKSAnalyticsAttributeErrorCode : @(error.code)
392 }];
393
394 [self logHardFailureForEventNamed:event withAttributes:eventAttributes];
395 }
396
397 - (void)logUnrecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event withAttributes:(NSDictionary *)attributes
398 {
399 if (error == nil){
400 return;
401 }
402 NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
403
404 /* Don't allow caller to overwrite our attributes, lets merge them first */
405 if (attributes) {
406 [eventAttributes setValuesForKeysWithDictionary:attributes];
407 }
408
409 eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
410 [self addCKPartialError:eventAttributes error:error depth:0];
411
412 [eventAttributes setValuesForKeysWithDictionary:@{
413 CKKSAnalyticsAttributeRecoverableError : @(NO),
414 CKKSAnalyticsAttributeZoneName : OctagonEventAttributeZoneName,
415 CKKSAnalyticsAttributeErrorDomain : error.domain,
416 CKKSAnalyticsAttributeErrorCode : @(error.code)
417 }];
418
419 [self logHardFailureForEventNamed:event withAttributes:eventAttributes];
420 }
421
422 - (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event
423 {
424 [self noteEventNamed:event];
425 }
426 - (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event inView:(CKKSKeychainView*)view
427 {
428 [self noteEventNamed:[NSString stringWithFormat:@"%@-%@", view.zoneName, event]];
429 }
430
431 - (NSDate*)dateOfLastSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view
432 {
433 return [self datePropertyForKey:[NSString stringWithFormat:@"last_success_%@-%@", view.zoneName, event]];
434 }
435
436 - (void)setDateProperty:(NSDate*)date forKey:(NSString*)key inView:(CKKSKeychainView *)view
437 {
438 [self setDateProperty:date forKey:[NSString stringWithFormat:@"%@-%@", key, view.zoneName]];
439 }
440 - (NSDate *)datePropertyForKey:(NSString *)key inView:(CKKSKeychainView *)view
441 {
442 return [self datePropertyForKey:[NSString stringWithFormat:@"%@-%@", key, view.zoneName]];
443 }
444
445 @end
446
447 #endif // OCTAGON