]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTFollowup.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / ot / OTFollowup.m
1 /*
2 * Copyright (c) 2019 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 "OTFollowup.h"
27
28 #if __has_include(<CoreFollowUp/CoreFollowUp.h>) && !TARGET_OS_SIMULATOR
29 #import <CoreFollowUp/CoreFollowUp.h>
30 #define HAVE_COREFOLLOW_UP 1
31 #endif
32
33 #import <CoreCDP/CDPFollowUpController.h>
34 #import <CoreCDP/CDPFollowUpContext.h>
35
36 #include "utilities/debugging.h"
37
38 static NSString * const kOTFollowupEventCompleteKey = @"OTFollowupContextType";
39
40 NSString* OTFollowupContextTypeToString(OTFollowupContextType contextType)
41 {
42 switch(contextType) {
43 case OTFollowupContextTypeNone:
44 return @"none";
45 case OTFollowupContextTypeRecoveryKeyRepair:
46 return @"recovery key";
47 case OTFollowupContextTypeStateRepair:
48 return @"repair";
49 case OTFollowupContextTypeOfflinePasscodeChange:
50 return @"offline passcode change";
51 }
52 }
53
54 @interface OTFollowup()
55 @property id<OctagonFollowUpControllerProtocol> cdpd;
56 @property NSTimeInterval previousFollowupEnd;
57 @property NSTimeInterval followupStart;
58 @property NSTimeInterval followupEnd;
59
60 @property NSMutableSet<NSString*>* postedCFUTypes;
61 @end
62
63 @implementation OTFollowup : NSObject
64
65 - (id)initWithFollowupController:(id<OctagonFollowUpControllerProtocol>)cdpFollowupController
66 {
67 if (self = [super init]) {
68 self.cdpd = cdpFollowupController;
69
70 _postedCFUTypes = [NSMutableSet set];
71 }
72 return self;
73 }
74
75 - (CDPFollowUpContext *)createCDPFollowupContext:(OTFollowupContextType)contextType
76 {
77 switch (contextType) {
78 case OTFollowupContextTypeStateRepair: {
79 return [CDPFollowUpContext contextForStateRepair];
80 }
81 case OTFollowupContextTypeRecoveryKeyRepair: {
82 return [CDPFollowUpContext contextForRecoveryKeyRepair];
83 }
84 case OTFollowupContextTypeOfflinePasscodeChange: {
85 return [CDPFollowUpContext contextForOfflinePasscodeChange];
86 }
87 default: {
88 return nil;
89 }
90 }
91 }
92
93 - (BOOL)postFollowUp:(OTFollowupContextType)contextType
94 error:(NSError **)error
95 {
96 CDPFollowUpContext *context = [self createCDPFollowupContext:contextType];
97 if (!context) {
98 return NO;
99 }
100
101 NSError *followupError = nil;
102
103 secnotice("followup", "Posting a follow up (for Octagon) of type %@", OTFollowupContextTypeToString(contextType));
104 BOOL result = [self.cdpd postFollowUpWithContext:context error:&followupError];
105
106 if(result) {
107 [self.postedCFUTypes addObject:OTFollowupContextTypeToString(contextType)];
108 } else {
109 if (error) {
110 *error = followupError;
111 }
112 }
113
114 return result;
115 }
116
117 - (BOOL)clearFollowUp:(OTFollowupContextType)contextType
118 error:(NSError **)error
119 {
120 // Note(caw): we don't track metrics for clearing CFU prompts.
121 CDPFollowUpContext *context = [self createCDPFollowupContext:contextType];
122 if (!context) {
123 return NO;
124 }
125
126 secnotice("followup", "Clearing follow ups (for Octagon) of type %@", OTFollowupContextTypeToString(contextType));
127 BOOL result = [self.cdpd clearFollowUpWithContext:context error:error];
128 if(result) {
129 [self.postedCFUTypes removeObject:OTFollowupContextTypeToString(contextType)];
130 }
131
132 return result;
133 }
134
135
136 - (NSDictionary *_Nullable)sysdiagnoseStatus
137 {
138 NSMutableDictionary *pendingCFUs = nil;
139
140 #if HAVE_COREFOLLOW_UP
141 if ([FLFollowUpController class]) {
142 NSError *error = nil;
143 pendingCFUs = [NSMutableDictionary dictionary];
144
145 FLFollowUpController *followUpController = [[FLFollowUpController alloc] initWithClientIdentifier:@"com.apple.corecdp"];
146 NSArray <FLFollowUpItem*>* followUps = [followUpController pendingFollowUpItems:&error];
147 if (error) {
148 secnotice("octagon", "Fetching pending follow ups failed with: %@", error);
149 pendingCFUs[@"error"] = [error description];
150 }
151 for (FLFollowUpItem *followUp in followUps) {
152 NSDate *creationDate = followUp.notification.creationDate;
153 pendingCFUs[followUp.uniqueIdentifier] = creationDate;
154 }
155 }
156 #endif
157 return pendingCFUs;
158 }
159
160 - (NSDictionary<NSString*,NSNumber *> *)sfaStatus {
161 NSMutableDictionary<NSString*, NSNumber*>* values = [NSMutableDictionary dictionary];
162 #if HAVE_COREFOLLOW_UP
163 if ([FLFollowUpController class]) {
164 NSError *error = nil;
165
166 //pretend to be CDP
167 FLFollowUpController *followUpController = [[FLFollowUpController alloc] initWithClientIdentifier:@"com.apple.corecdp"];
168
169 NSArray <FLFollowUpItem*>* followUps = [followUpController pendingFollowUpItems:&error];
170 if (error) {
171 secnotice("octagon", "Fetching pending follow ups failed with: %@", error);
172 }
173 for (FLFollowUpItem *followUp in followUps) {
174 NSInteger created = 10000;
175
176 NSDate *creationDate = followUp.notification.creationDate;
177 if (creationDate) {
178 created = [CKKSAnalytics fuzzyDaysSinceDate:creationDate];
179 }
180 NSString *key = [NSString stringWithFormat:@"OACFU-%@", followUp.uniqueIdentifier];
181 values[key] = @(created);
182 }
183 }
184 #endif
185 return values;
186 }
187
188 @end
189
190 @implementation OTFollowup (Testing)
191 - (BOOL)hasPosted:(OTFollowupContextType)contextType
192 {
193 return [self.postedCFUTypes containsObject:OTFollowupContextTypeToString(contextType)];
194 }
195
196 - (void)clearAllPostedFlags
197 {
198 [self.postedCFUTypes removeAllObjects];
199 }
200 @end
201
202 #endif // OCTAGON