]>
Commit | Line | Data |
---|---|---|
427c49bc A |
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 | ||
105 | typedef 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 |