2 * Copyright (c) 2019 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #import "OTFollowup.h"
28 #if __has_include(<CoreFollowUp/CoreFollowUp.h>) && !TARGET_OS_SIMULATOR
29 #import <CoreFollowUp/CoreFollowUp.h>
30 #define HAVE_COREFOLLOW_UP 1
33 #import <CoreCDP/CDPFollowUpController.h>
34 #import <CoreCDP/CDPFollowUpContext.h>
36 #include "utilities/debugging.h"
38 static NSString * const kOTFollowupEventCompleteKey = @"OTFollowupContextType";
40 NSString* OTFollowupContextTypeToString(OTFollowupContextType contextType)
43 case OTFollowupContextTypeNone:
45 case OTFollowupContextTypeRecoveryKeyRepair:
46 return @"recovery key";
47 case OTFollowupContextTypeStateRepair:
49 case OTFollowupContextTypeOfflinePasscodeChange:
50 return @"offline passcode change";
54 @interface OTFollowup()
55 @property id<OctagonFollowUpControllerProtocol> cdpd;
56 @property NSTimeInterval previousFollowupEnd;
57 @property NSTimeInterval followupStart;
58 @property NSTimeInterval followupEnd;
61 @implementation OTFollowup : NSObject
63 - (id)initWithFollowupController:(id<OctagonFollowUpControllerProtocol>)cdpFollowupController
65 if (self = [super init]) {
66 self.cdpd = cdpFollowupController;
71 - (CDPFollowUpContext *)createCDPFollowupContext:(OTFollowupContextType)contextType
73 switch (contextType) {
74 case OTFollowupContextTypeStateRepair: {
75 return [CDPFollowUpContext contextForStateRepair];
77 case OTFollowupContextTypeRecoveryKeyRepair: {
78 return [CDPFollowUpContext contextForRecoveryKeyRepair];
80 case OTFollowupContextTypeOfflinePasscodeChange: {
81 return [CDPFollowUpContext contextForOfflinePasscodeChange];
89 - (BOOL)postFollowUp:(OTFollowupContextType)contextType
90 error:(NSError **)error
92 CDPFollowUpContext *context = [self createCDPFollowupContext:contextType];
97 NSError *followupError = nil;
98 BOOL result = [self.cdpd postFollowUpWithContext:context error:&followupError];
100 *error = followupError;
106 - (BOOL)clearFollowUp:(OTFollowupContextType)contextType
107 error:(NSError **)error
109 // Note(caw): we don't track metrics for clearing CFU prompts.
110 CDPFollowUpContext *context = [self createCDPFollowupContext:contextType];
115 return [self.cdpd clearFollowUpWithContext:context error:error];
119 - (NSDictionary *)sysdiagnoseStatus
121 NSMutableDictionary *pendingCFUs = nil;
123 #if HAVE_COREFOLLOW_UP
124 if ([FLFollowUpController class]) {
125 NSError *error = nil;
126 pendingCFUs = [NSMutableDictionary dictionary];
128 FLFollowUpController *followUpController = [[FLFollowUpController alloc] initWithClientIdentifier:@"com.apple.corecdp"];
129 NSArray <FLFollowUpItem*>* followUps = [followUpController pendingFollowUpItems:&error];
131 secnotice("octagon", "Fetching pending follow ups failed with: %@", error);
132 pendingCFUs[@"error"] = [error description];
134 for (FLFollowUpItem *followUp in followUps) {
135 NSDate *creationDate = followUp.notification.creationDate;
136 pendingCFUs[followUp.uniqueIdentifier] = creationDate;
143 - (NSDictionary<NSString*,NSNumber *> *)sfaStatus {
144 NSMutableDictionary<NSString*, NSNumber*>* values = [NSMutableDictionary dictionary];
145 #if HAVE_COREFOLLOW_UP
146 if ([FLFollowUpController class]) {
147 NSError *error = nil;
150 FLFollowUpController *followUpController = [[FLFollowUpController alloc] initWithClientIdentifier:@"com.apple.corecdp"];
152 NSArray <FLFollowUpItem*>* followUps = [followUpController pendingFollowUpItems:&error];
154 secnotice("octagon", "Fetching pending follow ups failed with: %@", error);
156 for (FLFollowUpItem *followUp in followUps) {
157 NSInteger created = 10000;
159 NSDate *creationDate = followUp.notification.creationDate;
161 created = [CKKSAnalytics fuzzyDaysSinceDate:creationDate];
163 NSString *key = [NSString stringWithFormat:@"OACFU-%@", followUp.uniqueIdentifier];
164 values[key] = @(created);