]> git.saurik.com Git - apple/security.git/blob - Keychain/SyncViewController.m
20c5e490c5b6bd59337cbb9bfdb9a8d5f19f4529
[apple/security.git] / Keychain / SyncViewController.m
1 //
2 // SyncViewController.m
3 // Keychain
4 //
5 // Created by john on 10/22/12.
6 //
7 //
8
9 #import "SyncViewController.h"
10 #import "MyKeychain.h"
11
12 #import <CKBridge/SOSCloudKeychainClient.h>
13 #import <Security/SecureObjectSync/SOSCloudCircle.h>
14 #import <Security/SecureObjectSync/SOSCloudCircleInternal.h>
15 #import <notify.h>
16 #import <dispatch/dispatch.h>
17
18 #import <CoreFoundation/CoreFoundation.h>
19 #import <CoreFoundation/CFUserNotification.h>
20
21 #import <QuartzCore/QuartzCore.h>
22 #import <Regressions/SOSTestDataSource.h>
23 #import <securityd/SOSCloudCircleServer.h>
24 #import <CKBridge/SOSCloudKeychainConstants.h>
25 #import "PeerListCell.h"
26 #import <utilities/SecCFRelease.h>
27
28 __unused static const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
29
30 @interface SyncViewController ()
31 @end
32
33 @implementation SyncViewController
34
35 - (void)viewDidLoad
36 {
37 [super viewDidLoad];
38 // Do any additional setup after loading the view, typically from a nib.
39 [self setStatus:@"Idle…"];
40 [self updateSyncingEnabledSwitch];
41
42 notify_register_dispatch(kSOSCCCircleChangedNotification, &notificationToken,
43 dispatch_get_main_queue(),
44 ^(int tokenx __unused) {
45 notificationCount++;
46 [self setStatus:@"Got circle changed notification."];
47 [self flashChangeLight];
48 [self updateSyncingEnabledSwitch];
49 [self updateMemberCounts];
50 [_peerList reloadData];
51 [_applicantList reloadData];
52 });
53 [_acceptButton setEnabled:NO];
54
55 [self updateStatusCircleColor];
56
57 // _stateChangedC.color = [UIColor redColor];
58 // [_stateChangedC setNeedsDisplay];
59 }
60
61 - (void)didReceiveMemoryWarning
62 {
63 [super didReceiveMemoryWarning];
64 // Dispose of any resources that can be recreated.
65 }
66
67 - (void)updateSyncingEnabledSwitch
68 {
69 // Set the visual state of switch based on membership in circle
70 CFErrorRef error = NULL;
71 SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error);
72 BOOL switchIsOn = (ccstatus == kSOSCCInCircle || ccstatus == kSOSCCRequestPending);
73 [_syncingEnabled setOn:switchIsOn animated:NO];
74
75 CFStringRef circleStatusStr = SOSCCGetStatusDescription(ccstatus);
76 [_circleStatus setText:CFBridgingRelease(circleStatusStr)];
77 [_updateCount setText:[NSString stringWithFormat:@"%d", notificationCount]];
78
79 // TODO: Maybe update spinny for pending?!?
80
81 NSLog(@"ccstatus: %@ (%d), error: %@", SOSCCGetStatusDescription(ccstatus), ccstatus, error);
82 }
83
84 - (void)updateStatusCircleColor
85 {
86 switch (SOSCCThisDeviceIsInCircle(NULL))
87 {
88 case kSOSCCInCircle:
89 _stateChangedC.color = [UIColor greenColor];
90 break;
91 case kSOSCCRequestPending:
92 _stateChangedC.color = [UIColor yellowColor];
93 break;
94 default:
95 _stateChangedC.color = [UIColor redColor];
96 break;
97 }
98 [_stateChangedC setNeedsDisplay];
99 }
100
101 - (void)updateMemberCounts
102 {
103 CFArrayRef foundApplicants = SOSCCCopyApplicantPeerInfo(NULL);
104 CFIndex applicantCount = foundApplicants ? CFArrayGetCount(foundApplicants) : -1;
105 [_applicantCount setText:[NSString stringWithFormat:@"%ld", (long)applicantCount]];
106
107 CFArrayRef foundPeers = SOSCCCopyPeerPeerInfo(NULL);
108 CFIndex peerCount = foundPeers ? CFArrayGetCount(foundPeers) : -1;
109 [_peerCount setText:[NSString stringWithFormat:@"%ld", (long)peerCount]];
110
111 [_acceptButton setEnabled:(applicantCount > 0)? YES: NO];
112
113 [self updateStatusCircleColor];
114
115 CFReleaseSafe(foundApplicants);
116 CFReleaseSafe(foundPeers);
117 }
118
119 + (void)requestToJoinCircle
120 {
121 // Set the visual state of switch based on membership in circle
122 bool bx = true;
123 CFErrorRef error = NULL;
124 SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error);
125
126 switch (ccstatus) {
127 case kSOSCCCircleAbsent:
128 bx = SOSCCResetToOffering(&error);
129 break;
130 case kSOSCCNotInCircle:
131 bx = SOSCCRequestToJoinCircle(&error);
132 if (bx) {
133 CFMutableSetRef viewsToEnable = CFSetCreateMutable(NULL, 0, NULL);
134 CFMutableSetRef viewsToDisable = CFSetCreateMutable(NULL, 0, NULL);
135 CFSetAddValue(viewsToEnable, (void*)kSOSViewWiFi);
136 CFSetAddValue(viewsToEnable, (void*)kSOSViewAutofillPasswords);
137 CFSetAddValue(viewsToEnable, (void*)kSOSViewSafariCreditCards);
138 CFSetAddValue(viewsToEnable, (void*)kSOSViewOtherSyncable);
139
140 bx = SOSCCViewSet(viewsToEnable, viewsToDisable);
141 CFRelease(viewsToEnable);
142 CFRelease(viewsToDisable);
143 }
144 break;
145 default:
146 NSLog(@"Request to join circle with bad status: %@ (%d)", SOSCCGetStatusDescription(ccstatus), ccstatus);
147 break;
148 }
149 if (!bx)
150 NSLog(@"requestToJoinCircle Error: %@", error);
151 }
152
153 - (IBAction)acceptAllApplicants:(id)sender
154 {
155 CFArrayRef applicants = SOSCCCopyApplicantPeerInfo(NULL);
156 if (applicants) {
157 SOSCCAcceptApplicants(applicants, NULL);
158 CFRelease(applicants);
159 }
160 }
161
162 - (IBAction)handleEnableSyncing:(id)sender
163 {
164 dispatch_queue_t workq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
165 if ([sender isOn]) // i.e. we are trying to turn on syncing
166 {
167 dispatch_async(workq, ^ {
168 NSLog(@"Keychain syncing is being turned ON");
169 [[self class] requestToJoinCircle];
170 });
171 }
172 else
173 {
174 dispatch_async(workq, ^ {
175 NSLog(@"Keychain syncing is being turned OFF");
176 CFErrorRef error = NULL;
177 bool bx = SOSCCRemoveThisDeviceFromCircle(&error);
178 if (!bx)
179 NSLog(@"SOSCCRemoveThisDeviceFromCircle: %@", error);
180 });
181 }
182 }
183
184 - (void)flashChangeLight
185 {
186 CABasicAnimation *theAnimation = NULL;
187
188 theAnimation=[CABasicAnimation animationWithKeyPath:@"opacity"];
189 theAnimation.duration=0.75;
190 theAnimation.repeatCount=5; //HUGE_VALF;
191 theAnimation.autoreverses=YES;
192 theAnimation.fromValue=[NSNumber numberWithFloat:1.0];
193 theAnimation.toValue=[NSNumber numberWithFloat:0.0];
194 [_stateChangedC.layer addAnimation:theAnimation forKey:@"animateOpacity"];
195 }
196
197 - (void)setStatus:(NSString *)message
198 {
199 NSLog(@"%@", message);
200 _statusMessage.text = message;
201 }
202
203 //
204 // MARK: Table view handling
205 //
206 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
207 {
208 PeerListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PeerTableCell" forIndexPath:(NSIndexPath *)indexPath];
209 if (cell == nil)
210 {
211 NSLog(@"cellForRowAtIndexPath : cell was nil");
212 cell = [[PeerListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"PeerTableCell"];
213 }
214
215 NSArray *list = NULL;
216 NSArray *hilighted = NULL;
217 if (tableView == _peerList) {
218 list = (__bridge_transfer NSArray*)SOSCCCopyPeerPeerInfo(NULL);
219 hilighted = (__bridge_transfer NSArray*)SOSCCCopyConcurringPeerPeerInfo(NULL);
220 } else {
221 list = (__bridge_transfer NSArray*)SOSCCCopyApplicantPeerInfo(NULL);
222 }
223
224 if (list) {
225 cell.peerCircle.text = @"A";
226 SOSPeerInfoRef pi = (__bridge SOSPeerInfoRef) list[[indexPath row]];
227 if (pi) {
228 cell.peerName.text = (__bridge NSString*) SOSPeerInfoGetPeerName(pi);
229 if ([hilighted containsObject: (__bridge id)pi])
230 cell.peerName.textColor = [UIColor greenColor];
231 }
232 } else {
233 cell.peerName.text = @"Null List";
234 }
235
236 return cell;
237 }
238
239 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
240 {
241 NSArray* list = nil;
242
243 if (tableView == _peerList) {
244 list = (__bridge_transfer NSArray*) SOSCCCopyPeerPeerInfo(NULL);
245 } else {
246 list = (__bridge_transfer NSArray*) SOSCCCopyApplicantPeerInfo(NULL);
247 }
248
249 return [list count];
250 }
251
252 @end
253