]> git.saurik.com Git - apple/security.git/blame_incremental - Keychain/KDSecCircle.m
Security-55471.tar.gz
[apple/security.git] / Keychain / KDSecCircle.m
... / ...
CommitLineData
1//
2// KDSecCircle.m
3// Security
4//
5// Created by J Osborne on 2/20/13.
6//
7//
8
9#import "KDSecCircle.h"
10#import "KDCirclePeer.h"
11#include <notify.h>
12#include <dispatch/dispatch.h>
13#import "SecureObjectSync/SOSCloudCircle.h"
14#include "SecureObjectSync/SOSPeerInfo.h"
15
16@interface KDSecCircle ()
17@property (retain) NSMutableArray *callbacks;
18
19@property (readwrite) unsigned long long changeCount;
20
21@property (readwrite) SOSCCStatus rawStatus;
22
23@property (readwrite) NSString *status;
24@property (readwrite) NSError *error;
25
26@property (readwrite) NSArray *peers;
27@property (readwrite) NSArray *applicants;
28
29@property (readwrite) dispatch_queue_t queue_;
30
31@end
32
33@implementation KDSecCircle
34
35-(void)updateCheck
36{
37 // XXX: assert not on main_queue
38 CFErrorRef err = NULL;
39 SOSCCStatus newRawStatus = SOSCCThisDeviceIsInCircle(&err);
40
41 NSArray *peerInfos = (__bridge NSArray *)(SOSCCCopyApplicantPeerInfo(&err));
42 NSMutableArray *newApplicants = [[NSMutableArray alloc] initWithCapacity:peerInfos.count];
43 [peerInfos enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
44 [newApplicants addObject:[[KDCirclePeer alloc] initWithPeerObject:obj]];
45 }];
46
47 peerInfos = (__bridge NSArray *)(SOSCCCopyPeerPeerInfo(&err));
48 NSMutableArray *newPeers = [[NSMutableArray alloc] initWithCapacity:peerInfos.count];
49 [peerInfos enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
50 [newPeers addObject:[[KDCirclePeer alloc] initWithPeerObject:obj]];
51 }];
52
53 NSLog(@"rawStatus %d, #applicants %lu, #peers %lu, err=%@", newRawStatus, (unsigned long)[newApplicants count], (unsigned long)[newPeers count], err);
54
55 dispatch_async(dispatch_get_main_queue(), ^{
56 self.rawStatus = newRawStatus;
57
58 switch (newRawStatus) {
59 case kSOSCCInCircle:
60 self.status = @"In Circle";
61 break;
62
63 case kSOSCCNotInCircle:
64 self.status = @"Not In Circle";
65 break;
66
67 case kSOSCCRequestPending:
68 self.status = @"Request Pending";
69 break;
70
71 case kSOSCCCircleAbsent:
72 self.status = @"Circle Absent";
73 break;
74
75 case kSOSCCError:
76 self.status = [NSString stringWithFormat:@"Error: %@", err];
77 break;
78
79 case kSOSCCParamErr:
80 self.status = [NSString stringWithFormat:@"ParamError: %@", err];
81 break;
82
83 default:
84 self.status = [NSString stringWithFormat:@"Unknown status code %d", self.rawStatus];
85 break;
86 }
87
88 self.applicants = [newApplicants copy];
89 self.peers = [newPeers copy];
90 self.error = (__bridge NSError *)(err);
91
92 self.changeCount++;
93 for (dispatch_block_t callback in self.callbacks) {
94 callback();
95 }
96 });
97}
98
99// XXX It's a botch to use the "name" and not applicant, but
100// it is hard to get anythign else to survive a serialastion
101// trip thoguth NSUserNotificationCenter.
102//
103// Er, now that I look more closely maybe SOSPeerInfoGetPeerID...
104
105typedef void (^applicantBlock)(id applicant);
106
107-(void)forApplicantId:(NSString*)applicantId run:(applicantBlock)applicantBlock
108{
109 dispatch_async(self.queue_, ^{
110 for (KDCirclePeer *applicant in self.applicants) {
111 if ([applicantId isEqualToString:applicantId]) {
112 applicantBlock(applicant.peerObject);
113 break;
114 }
115 }
116 });
117}
118
119-(void)acceptApplicantId:(NSString*)applicantId
120{
121 [self forApplicantId:applicantId run:^void(id applicant) {
122 CFErrorRef err;
123 bool ok = SOSCCAcceptApplicants((__bridge CFArrayRef)(@[applicant]), &err);
124 NSAssert(ok, @"Error %@ while accepting %@ (%@)", err, applicantId, applicant);
125 }];
126}
127
128-(void)rejectApplicantId:(NSString*)applicantId
129{
130 [self forApplicantId:applicantId run:^void(id applicant) {
131 CFErrorRef err;
132 bool ok = SOSCCRejectApplicants((__bridge CFArrayRef)(@[applicant]), &err);
133 NSAssert(ok, @"Error %@ while rejecting %@ (%@)", err, applicantId, applicant);
134 }];
135}
136
137-(id)init
138{
139 self = [super init];
140 int token;
141
142 self->_queue_ = dispatch_queue_create([[NSString stringWithFormat:@"KDSecCircle@%p", self] UTF8String], NULL);
143 self->_callbacks = [NSMutableArray new];
144 // Replace "com.apple.security.secureobjectsync.circlechanged" with kSOSCCCircleChangedNotification once it is exported
145 notify_register_dispatch("com.apple.security.secureobjectsync.circlechanged", &token, self.queue_, ^(int token){
146 [self updateCheck];
147 });
148
149 return self;
150}
151
152-(void)addChangeCallback:(dispatch_block_t)callback
153{
154 [self.callbacks addObject:callback];
155 if (self.changeCount) {
156 dispatch_async(dispatch_get_main_queue(), callback);
157 } else if (self.callbacks.count == 1) {
158 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
159 [self updateCheck];
160 });
161 }
162}
163
164-(BOOL)isInCircle
165{
166 return (self.rawStatus == kSOSCCInCircle) ? YES : NO;
167}
168
169-(BOOL)isOutOfCircle
170{
171 return (self.rawStatus == kSOSCCNotInCircle || self.rawStatus == kSOSCCCircleAbsent);
172}
173
174-(void)enableSync
175{
176 CFErrorRef err;
177 if (self.rawStatus == kSOSCCCircleAbsent) {
178 SOSCCResetToOffering(&err);
179 } else {
180 SOSCCRequestToJoinCircle(&err);
181 }
182}
183
184-(void)disableSync
185{
186 CFErrorRef err;
187 SOSCCRemoveThisDeviceFromCircle(&err);
188}
189
190@end