1 #include <CoreFoundation/CoreFoundation.h>
2 #include <CoreFoundation/CFRuntime.h>
4 #include <Security/SecureObjectSync/SOSAccount.h>
5 #include <Security/SecureObjectSync/SOSAccountPriv.h>
6 #include <Security/SecureObjectSync/SOSTransport.h>
7 #import <Security/SecureObjectSync/SOSTransportKeyParameter.h>
8 #import <Security/SecureObjectSync/SOSTransportCircleKVS.h>
9 #import <Security/SecureObjectSync/SOSTransportMessageIDS.h>
10 #import <Security/SecureObjectSync/SOSTransportMessageKVS.h>
11 #include <Security/SecureObjectSync/SOSKVSKeys.h>
12 #include <Security/SecureObjectSync/SOSPeerCoder.h>
13 #include <utilities/SecCFWrappers.h>
14 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
15 #import <Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h>
16 #import <Security/SecureObjectSync/SOSAccountTrustClassic+Identity.h>
18 #include "SOSTransportTestTransports.h"
19 #include "SOSAccountTesting.h"
21 CFMutableArrayRef key_transports = NULL;
22 CFMutableArrayRef circle_transports = NULL;
23 CFMutableArrayRef message_transports = NULL;
26 //Mark Test Key Parameter Transport
29 @implementation CKKeyParameterTest
31 -(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) n andCircleName:(CFStringRef) cN
35 self.name = CFRetainSafe(n);
36 self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
38 self.circleName = CFRetainSafe(cN);
41 key_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
42 CFArrayAppendValue(key_transports, (__bridge CFTypeRef)((CKKeyParameter*)self));
44 SOSRegisterTransportKeyParameter((CKKeyParameter*)self);
49 -(bool) SOSTransportKeyParameterHandleKeyParameterChanges:(CKKeyParameterTest*) transport data:(CFDataRef) data err:(CFErrorRef) error
51 SOSAccount* acct = transport.account;
52 return SOSAccountHandleParametersChange(acct, data, &error);
56 -(void) SOSTransportKeyParameterHandleNewAccount:(CKKeyParameterTest*) transport acct:(SOSAccount*) acct
60 CFArrayRemoveAllValue(key_transports, (__bridge CFTypeRef)(acct.key_transport));
62 if(message_transports){
63 CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)acct.ids_message_transport);
64 CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)acct.kvs_message_transport);
67 CFArrayRemoveAllValue(circle_transports, (__bridge CFTypeRef)(acct.circle_transport));
69 SOSAccountSetToNew(acct);
70 SOSAccountResetToTest(acct, transport.name);
73 CFStringRef SOSTransportKeyParameterTestGetName(CKKeyParameterTest* transport){
74 return transport.name;
77 void SOSTransportKeyParameterTestSetName(CKKeyParameterTest* transport, CFStringRef accountName){
78 transport.name = accountName;
81 SOSAccount* SOSTransportKeyParameterTestGetAccount(CKKeyParameterTest* transport){
82 return ((CKKeyParameter*)transport).account;
85 CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(CKKeyParameterTest* transport){
86 return transport.changes;
89 void SOSTransportKeyParameterTestClearChanges(CKKeyParameterTest* transport){
90 transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
93 -(bool) SOSTransportKeyParameterPublishCloudParameters:(CKKeyParameterTest*) transport data:(CFDataRef)newParameters err:(CFErrorRef*) error
95 if(!transport.changes)
96 transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
98 CFDictionarySetValue(transport.changes, kSOSKVSKeyParametersKey, newParameters);
106 //MARK: Test Circle Transport
108 @implementation SOSCircleStorageTransportTest
109 @synthesize accountName = accountName;
116 CFStringRef SOSTransportCircleTestGetName(SOSCircleStorageTransportTest* transport){
117 return (__bridge CFStringRef)(transport.accountName);
119 void SOSTransportCircleTestSetName(SOSCircleStorageTransportTest* transport, CFStringRef name){
120 transport.accountName = nil;
121 transport.accountName = (__bridge NSString *)(name);
124 -(CFMutableDictionaryRef) SOSTransportCircleTestGetChanges
126 return (__bridge CFMutableDictionaryRef)(self.pending_changes);
129 void SOSTransportCircleTestClearChanges(SOSCircleStorageTransportTest* transport){
130 transport.pending_changes = [NSMutableDictionary dictionary];
133 -(id) initWithAccount:(SOSAccount *)acct andWithAccountName:(CFStringRef)acctName andCircleName:(CFStringRef)cName
138 self.accountName = (__bridge NSString *)(acctName);
139 self.circleName = (__bridge NSString*)cName;
140 self.pending_changes = [NSMutableDictionary dictionary];
141 if(!circle_transports)
142 circle_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
143 CFArrayAppendValue(circle_transports, (__bridge CFTypeRef)self);
145 SOSRegisterTransportCircle((SOSCircleStorageTransportTest*)self);
150 -(bool) kvsRingFlushChanges:(CFErrorRef*) error
155 -(bool) kvsRingPostRing:(CFStringRef) ringName ring:(CFDataRef) ring err:(CFErrorRef *)error
157 CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error);
158 CFMutableDictionaryRef changes = [self SOSTransportCircleTestGetChanges];
159 CFDictionaryAddValue(changes, ringKey, ring);
160 CFReleaseNull(ringKey);
164 -(bool) kvssendDebugInfo:(CFStringRef) type debug:(CFTypeRef) debugInfo err:(CFErrorRef *)error
166 CFMutableDictionaryRef changes = [self SOSTransportCircleTestGetChanges];
167 CFDictionaryAddValue(changes, type, debugInfo);
171 -(bool) postRetirement:(CFStringRef)cName peer:(SOSPeerInfoRef)peer err:(CFErrorRef *)error
173 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(cName, SOSPeerInfoGetPeerID(peer));
174 CFDataRef retirement_data = SOSPeerInfoCopyEncodedData(peer, kCFAllocatorDefault, error);
177 [self testAddToChanges:retirement_key data:retirement_data];
179 CFReleaseNull(retirement_key);
180 CFReleaseNull(retirement_data);
184 -(bool) flushChanges:(CFErrorRef *)error
189 -(void) testAddToChanges:(CFStringRef) message_key data:(CFDataRef) message_data
191 if (self.pending_changes == NULL) {
192 self.pending_changes = [NSMutableDictionary dictionary];
194 if (message_data == NULL) {
195 [self.pending_changes setObject:[NSNull null] forKey:(__bridge NSString*)(message_key)];
197 [self.pending_changes setObject:(__bridge NSData*)message_data forKey:(__bridge NSString*)message_key];
199 secnotice("circle-changes", "Adding circle change %@ %@->%@", self.accountName, message_key, message_data);
202 -(void) SOSTransportCircleTestAddBulkToChanges:(CFDictionaryRef) updates
204 if (self.pending_changes == NULL) {
205 self.pending_changes = [[NSMutableDictionary alloc]initWithDictionary:(__bridge NSDictionary * _Nonnull)(updates)];
209 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
210 [self.pending_changes setObject:(__bridge id _Nonnull)value forKey:(__bridge id _Nonnull)key];
216 -(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error
219 CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
221 CFDictionaryForEach(retirements, ^(const void *key, const void *value) {
222 if (isString(key) && isArray(value)) {
223 CFStringRef circle_name = (CFStringRef) key;
224 CFArrayRef retirees = (CFArrayRef) value;
226 CFArrayForEach(retirees, ^(const void *value) {
227 if (isString(value)) {
228 CFStringRef retiree_id = (CFStringRef) value;
230 CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id);
232 CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull);
234 CFReleaseSafe(kvsKey);
240 if(CFDictionaryGetCount(keysToWrite)) {
241 [self SOSTransportCircleTestAddBulkToChanges:keysToWrite];
243 CFReleaseNull(keysToWrite);
248 bool SOSTransportCircleTestRemovePendingChange(SOSCircleStorageTransportTest* transport, CFStringRef circleName, CFErrorRef *error){
249 CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error);
251 [transport.pending_changes removeObjectForKey:(__bridge NSString*)circle_key];
252 CFReleaseNull(circle_key);
256 -(bool) postCircle:(CFStringRef)cName circleData:(CFDataRef)circle_data err:(CFErrorRef *)error
258 CFStringRef circle_key = SOSCircleKeyCreateWithName(cName, error);
260 [self testAddToChanges:circle_key data:circle_data];
261 CFReleaseNull(circle_key);
266 -(CFDictionaryRef)handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error
268 return SOSAccountHandleRetirementMessages(self.account, circle_retirement_messages_table, error);
271 -(CFArrayRef) handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error
273 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
274 CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) {
275 CFErrorRef circleMessageError = NULL;
276 if (!SOSAccountHandleCircleMessage(self.account, key, value, &circleMessageError)) {
277 secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError);
280 CFStringRef circle_id = (CFStringRef) key;
281 CFArrayAppendValue(handledKeys, circle_id);
283 CFReleaseNull(circleMessageError);
289 SOSAccount* SOSTransportCircleTestGetAccount(SOSCircleStorageTransportTest* transport) {
290 return transport.account;
296 //MARK KVS Message Test Transport
301 @implementation SOSMessageKVSTest
304 -(id) initWithAccount:(SOSAccount*)acct andName:(CFStringRef)n andCircleName:(CFStringRef) cN
308 self.engine = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, cN, NULL);
310 self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
311 self.name = CFRetainSafe(n);
312 self.circleName = (__bridge NSString*)cN;
314 if(!message_transports)
315 message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
316 CFArrayAppendValue(message_transports, (__bridge const void *)((SOSMessageKVSTest*)self));
317 SOSRegisterTransportMessage((SOSMessageKVSTest*)self);
323 -(CFIndex) SOSTransportMessageGetTransportType
327 -(CFStringRef) SOSTransportMessageGetCircleName
329 return (__bridge CFStringRef)circleName;
331 -(CFTypeRef) SOSTransportMessageGetEngine
335 -(SOSAccount*) SOSTransportMessageGetAccount
340 void SOSTransportMessageKVSTestSetName(SOSMessageKVSTest* transport, CFStringRef n)
345 CFStringRef SOSTransportMessageKVSTestGetName(SOSMessageKVSTest* transport)
347 return transport.name;
350 CFMutableDictionaryRef SOSTransportMessageKVSTestGetChanges(SOSMessageKVSTest* transport)
352 return transport.changes;
355 void SOSTransportMessageTestClearChanges(SOSMessageKVSTest* transport)
357 transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
360 static void SOSTransportMessageTestAddBulkToChanges(SOSMessageKVSTest* transport, CFDictionaryRef updates)
362 #ifndef __clang_analyzer__ // The analyzer thinks transport.changes is a leak, but I don't know why.
363 if (transport.changes == NULL) {
364 transport.changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
367 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
368 CFDictionarySetValue(transport.changes, key, value);
371 #endif // __clang_analyzer__
374 static void SOSTransportMessageTestAddToChanges(SOSMessageKVSTest* transport, CFStringRef message_key, CFDataRef message_data)
376 if (transport.changes == NULL) {
377 transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
379 if (message_data == NULL) {
380 CFDictionarySetValue(transport.changes, message_key, kCFNull);
382 CFDictionarySetValue(transport.changes, message_key, message_data);
386 -(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessageKVSTest*) transport peers:(CFDictionaryRef)circle_to_peer_ids err:(CFErrorRef*) error
388 if(!transport.engine)
390 CFArrayRef enginePeers = SOSEngineGetPeerIDs((SOSEngineRef)transport.engine);
392 CFDictionaryForEach(circle_to_peer_ids, ^(const void *key, const void *value) {
393 if (isString(key) && isArray(value)) {
394 CFStringRef circle_name = (CFStringRef) key;
395 CFArrayRef peers_to_cleanup_after = (CFArrayRef) value;
397 CFArrayForEach(peers_to_cleanup_after, ^(const void *value) {
398 if (isString(value)) {
399 CFStringRef cleanup_id = (CFStringRef) value;
400 // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers
401 if (enginePeers) CFArrayForEach(enginePeers, ^(const void *value) {
402 if (isString(value)) {
403 CFStringRef in_circle_id = (CFStringRef) value;
405 CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id);
406 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
407 CFReleaseSafe(kvsKey);
409 kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id);
410 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
411 CFReleaseSafe(kvsKey);
420 return [transport SOSTransportMessageFlushChanges:transport err:error];
424 static bool sendToPeer(SOSMessageKVSTest* transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) {
426 NSString* myID = transport.account.peerID;
427 CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer((SOSMessage*)transport, (__bridge CFStringRef) myID, peerID);
428 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL);
430 SOSTransportMessageTestAddBulkToChanges(transport, a_message_to_a_peer);
431 CFReleaseNull(a_message_to_a_peer);
432 CFReleaseNull(message_to_peer_key);
437 -(bool) SOSTransportMessageSyncWithPeers:(SOSMessageKVSTest*) transport p:(CFSetRef) peers err:(CFErrorRef *)error
439 // Each entry is keyed by circle name and contains a list of peerIDs
441 __block bool result = true;
443 CFSetForEach(peers, ^(const void *value) {
444 CFStringRef peerID = asString(value, NULL);
447 SOSEngineWithPeerID((SOSEngineRef)transport.engine, peerID, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
448 SOSEnginePeerMessageSentBlock sent = NULL;
449 CFDataRef message_to_send = NULL;
450 bool ok = SOSPeerCoderSendMessageIfNeeded([transport SOSTransportMessageGetAccount], (SOSEngineRef)transport.engine, txn, peer, coder, &message_to_send, peerID, false, &sent, error);
451 if (message_to_send) {
452 CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerID, message_to_send, NULL);
453 CFDictionarySetValue(SOSTransportMessageKVSTestGetChanges(transport), (__bridge CFStringRef)self->circleName, peer_dict);
454 SOSPeerCoderConsume(&sent, ok);
455 CFReleaseSafe(peer_dict);
457 CFReleaseSafe(message_to_send);
464 -(bool) SOSTransportMessageSendMessages:(SOSMessageKVSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error
466 __block bool result = true;
468 CFDictionaryForEach(peer_messages, ^(const void *key, const void *value) {
469 if (isString(key) && isData(value)) {
470 CFStringRef peerID = (CFStringRef) key;
471 CFDataRef message = (CFDataRef) value;
472 bool rx = sendToPeer(transport, (__bridge CFStringRef)transport->circleName, peerID, message, error);
480 -(CFDictionaryRef)CF_RETURNS_RETAINED SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessageIDSTest*) transport peerMessages:(CFMutableDictionaryRef) circle_peer_messages_table err:(CFErrorRef *)error{
481 CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
482 CFDictionaryRef peerToMessage = CFDictionaryGetValue(circle_peer_messages_table, (__bridge CFStringRef)transport.circleName);
483 CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
484 CFDictionaryAddValue(handled, (__bridge CFStringRef)transport.circleName, handled_peers);
487 CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) {
488 CFStringRef peer_id = (CFStringRef) key;
489 CFDataRef peer_message = (CFDataRef) value;
490 CFErrorRef localError = NULL;
492 if ([transport SOSTransportMessageHandlePeerMessage:transport id:peer_id cm:peer_message err:&localError]){
493 CFArrayAppendValue(handled_peers, key);
495 secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError);
497 CFReleaseNull(localError);
500 CFReleaseNull(handled_peers);
505 -(bool) SOSTransportMessageFlushChanges:(SOSMessageKVSTest*) transport err:(CFErrorRef *)error
510 SOSAccount* SOSTransportMessageKVSTestGetAccount(SOSMessageKVSTest* transport) {
511 return transport.account;
516 //MARK IDS Message Test Transport
519 @implementation SOSMessageIDSTest
520 -(SOSMessageIDSTest*) initWithAccount:(SOSAccount*)acct andAccountName:(CFStringRef) aN andCircleName:(CFStringRef) cN err:(CFErrorRef *)error
524 self.engine = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, cN, NULL);
525 self.useFragmentation = kCFBooleanTrue;
527 self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
528 self.circleName = (__bridge NSString*)cN;
529 self.accountName = CFRetainSafe(aN);
531 if(!message_transports)
532 message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
533 CFArrayAppendValue(message_transports, (__bridge CFTypeRef)self);
534 SOSRegisterTransportMessage((SOSMessageIDSTest*)self);
540 -(bool) SOSTransportMessageIDSGetIDSDeviceID:(SOSAccount*)acct{
544 -(CFIndex) SOSTransportMessageGetTransportType
548 -(CFStringRef) SOSTransportMessageGetCircleName
550 return (__bridge CFStringRef)circleName;
552 -(CFTypeRef) SOSTransportMessageGetEngine
556 -(SOSAccount*) SOSTransportMessageGetAccount
561 void SOSTransportMessageIDSTestSetName(SOSMessageIDSTest* transport, CFStringRef acctName){
562 transport.accountName = acctName;
566 static HandleIDSMessageReason checkMessageValidity(SOSAccount* account, CFStringRef fromDeviceID, CFStringRef fromPeerID, CFStringRef *peerID, SOSPeerInfoRef *theirPeerInfo){
567 SOSAccountTrustClassic *trust = account.trust;
568 __block HandleIDSMessageReason reason = kHandleIDSMessageDontHandle;
570 SOSCircleForEachPeer(trust.trustedCircle, ^(SOSPeerInfoRef peer) {
571 CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer);
572 CFStringRef pID = SOSPeerInfoGetPeerID(peer);
574 if( deviceID && pID && fromPeerID && fromDeviceID && CFStringGetLength(fromPeerID) != 0 ){
575 if(CFStringCompare(pID, fromPeerID, 0) == 0){
576 if(CFStringGetLength(deviceID) == 0){
577 secnotice("ids transport", "device ID was empty in the peer list, holding on to message");
578 CFReleaseNull(deviceID);
579 reason = kHandleIDSMessageNotReady;
582 else if(CFStringCompare(fromDeviceID, deviceID, 0) != 0){ //IDSids do not match, ghost
583 reason = kHandleIDSmessageDeviceIDMismatch;
584 CFReleaseNull(deviceID);
587 else if(CFStringCompare(deviceID, fromDeviceID, 0) == 0){
589 *theirPeerInfo = peer;
590 CFReleaseNull(deviceID);
591 reason = kHandleIDSMessageSuccess;
596 CFReleaseNull(deviceID);
601 const char *kMessageKeyIDSDataMessage = "idsDataMessage";
602 const char *kMessageKeyDeviceID = "deviceID";
603 const char *kMessageKeyPeerID = "peerID";
604 const char *kMessageKeySendersPeerID = "sendersPeerID";
606 -(HandleIDSMessageReason) SOSTransportMessageIDSHandleMessage:(SOSAccount*)acct m:(CFDictionaryRef) message err:(CFErrorRef *)error
608 secnotice("IDS Transport", "SOSTransportMessageIDSHandleMessage!");
610 CFStringRef dataKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyIDSDataMessage, kCFStringEncodingASCII);
611 CFStringRef deviceIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyDeviceID, kCFStringEncodingASCII);
612 CFStringRef sendersPeerIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeySendersPeerID, kCFStringEncodingASCII);
613 CFStringRef ourPeerIdKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyPeerID, kCFStringEncodingASCII);
615 HandleIDSMessageReason result = kHandleIDSMessageSuccess;
617 CFDataRef messageData = asData(CFDictionaryGetValue(message, dataKey), NULL);
618 __block CFStringRef fromDeviceID = asString(CFDictionaryGetValue(message, deviceIDKey), NULL);
619 __block CFStringRef fromPeerID = (CFStringRef)CFDictionaryGetValue(message, sendersPeerIDKey);
620 CFStringRef ourPeerID = asString(CFDictionaryGetValue(message, ourPeerIdKey), NULL);
622 CFStringRef peerID = NULL;
623 SOSPeerInfoRef theirPeer = NULL;
625 require_action_quiet(fromDeviceID, exit, result = kHandleIDSMessageDontHandle);
626 require_action_quiet(fromPeerID, exit, result = kHandleIDSMessageDontHandle);
627 require_action_quiet(messageData && CFDataGetLength(messageData) != 0, exit, result = kHandleIDSMessageDontHandle);
628 require_action_quiet(SOSAccountHasFullPeerInfo(account, error), exit, result = kHandleIDSMessageNotReady);
629 require_action_quiet(ourPeerID && [account.peerID isEqual: (__bridge NSString*) ourPeerID], exit, result = kHandleIDSMessageDontHandle; secnotice("IDS Transport","ignoring message for: %@", ourPeerID));
631 require_quiet((result = checkMessageValidity( account, fromDeviceID, fromPeerID, &peerID, &theirPeer)) == kHandleIDSMessageSuccess, exit);
633 if ([account.ids_message_transport SOSTransportMessageHandlePeerMessage:account.ids_message_transport id:peerID cm:messageData err:error]) {
634 CFMutableDictionaryRef peersToSyncWith = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
635 CFMutableSetRef peerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
636 CFSetAddValue(peerIDs, peerID);
637 SOSAccountTrustClassic* trust = account.trust;
638 //sync using fragmentation?
639 if(SOSPeerInfoShouldUseIDSMessageFragmentation(trust.peerInfo, theirPeer)){
640 //set useFragmentation bit
641 [account.ids_message_transport SOSTransportMessageIDSSetFragmentationPreference:account.ids_message_transport pref: kCFBooleanTrue];
644 [account.ids_message_transport SOSTransportMessageIDSSetFragmentationPreference:account.ids_message_transport pref: kCFBooleanFalse];
647 if(![account.ids_message_transport SOSTransportMessageSyncWithPeers:account.ids_message_transport p:peerIDs err:error]){
648 secerror("SOSTransportMessageIDSHandleMessage Could not sync with all peers: %@", *error);
650 secnotice("IDS Transport", "Synced with all peers!");
653 CFReleaseNull(peersToSyncWith);
654 CFReleaseNull(peerIDs);
656 if(error && *error != NULL){
657 CFStringRef errorMessage = CFErrorCopyDescription(*error);
658 if (-25308 == CFErrorGetCode(*error)) { // tell KeychainSyncingOverIDSProxy to call us back when device unlocks
659 result = kHandleIDSMessageLocked;
660 }else{ //else drop it, couldn't handle the message
661 result = kHandleIDSMessageDontHandle;
663 secerror("IDS Transport Could not handle message: %@, %@", messageData, *error);
664 CFReleaseNull(errorMessage);
667 else{ //no error but failed? drop it, log message
668 secerror("IDS Transport Could not handle message: %@", messageData);
669 result = kHandleIDSMessageDontHandle;
675 CFReleaseNull(ourPeerIdKey);
676 CFReleaseNull(sendersPeerIDKey);
677 CFReleaseNull(deviceIDKey);
678 CFReleaseNull(dataKey);
682 -(CFDictionaryRef)CF_RETURNS_RETAINED SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessageIDSTest*) transport peerMessages:(CFMutableDictionaryRef)message err:(CFErrorRef *)error
685 CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
686 CFDictionaryRef peerToMessage = CFDictionaryGetValue(message, (__bridge CFTypeRef)(transport.circleName));
687 CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
689 secerror("Received IDS message!");
691 CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) {
692 CFStringRef peer_id = asString(key, NULL);
693 CFDataRef peer_message = asData(value, NULL);
694 CFErrorRef localError = NULL;
696 if (peer_id && peer_message && [transport SOSTransportMessageHandlePeerMessage:transport id:peer_id cm:peer_message err:&localError]) {
697 CFArrayAppendValue(handled_peers, key);
699 secnotice("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError);
701 CFReleaseNull(localError);
704 CFDictionaryAddValue(handled, (__bridge CFStringRef)(transport.circleName), handled_peers);
705 CFReleaseNull(handled_peers);
710 static void SOSTransportMessageIDSTestAddBulkToChanges(SOSMessageIDSTest* transport, CFDictionaryRef updates){
711 #ifndef __clang_analyzer__ // The analyzer thinks transport.changes is a leak, but I don't know why.
712 if (transport.changes == NULL) {
713 transport.changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
717 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
718 CFDictionaryAddValue(transport.changes, key, value);
723 static bool sendDataToPeerIDSTest(SOSMessageIDSTest* transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDataRef message, CFErrorRef *error)
725 secerror("sending message through test transport: %@", message);
726 NSString* myID = transport.account.peerID;
727 CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(transport, (__bridge CFStringRef) myID, peerID);
728 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL);
730 SOSTransportMessageIDSTestAddBulkToChanges(transport, a_message_to_a_peer);
732 CFReleaseNull(message_to_peer_key);
733 CFReleaseNull(a_message_to_a_peer);
737 static bool sendDictionaryToPeerIDSTest(SOSMessageIDSTest* transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDictionaryRef message, CFErrorRef *error)
739 secerror("sending message through test transport: %@", message);
740 NSString* myID = transport.account.peerID;
741 CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(transport, (__bridge CFStringRef) myID, peerID);
742 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL);
744 SOSTransportMessageIDSTestAddBulkToChanges(transport, a_message_to_a_peer);
746 CFReleaseNull(message_to_peer_key);
747 CFReleaseNull(a_message_to_a_peer);
752 -(bool) SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*) transport p:(CFSetRef)peers err:(CFErrorRef *)error
754 // Each entry is keyed by circle name and contains a list of peerIDs
755 __block bool result = true;
757 CFSetForEach(peers, ^(const void *value) {
758 CFStringRef peerID = asString(value, NULL);
760 secnotice("transport", "IDS sync with peerIDs %@", peerID);
761 result &= [transport SOSTransportMessageSendMessageIfNeeded:transport id:(__bridge CFStringRef)transport.circleName pID:peerID err:error];
768 -(bool) SOSTransportMessageSendMessages:(SOSMessageIDSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error
770 __block bool result = true;
771 CFDictionaryForEach(peer_messages, ^(const void *key, const void *value) {
772 CFStringRef idsDeviceID = NULL;;
773 CFStringRef peerID = asString(key, NULL);
774 SOSPeerInfoRef pi = NULL;
776 if(!CFEqualSafe(peerID, (__bridge CFStringRef) transport.account.peerID)){
778 pi = SOSAccountCopyPeerWithID(transport.account, peerID, NULL);
780 idsDeviceID = SOSPeerInfoCopyDeviceID(pi);
781 if(idsDeviceID != NULL){
783 CFDictionaryRef messageDictionary = asDictionary(value, NULL);
784 if (messageDictionary) {
785 result &= sendDictionaryToPeerIDSTest(transport, (__bridge CFStringRef)transport.circleName, idsDeviceID, peerID, messageDictionary, error);
787 CFDataRef messageData = asData(value, NULL);
789 result &= sendDataToPeerIDSTest(transport, (__bridge CFStringRef)transport.circleName, idsDeviceID, peerID, messageData, error);
796 CFReleaseNull(idsDeviceID);
803 -(bool) SOSTransportMessageFlushChanges:(SOSMessageIDSTest*) transport err:(CFErrorRef *)error
808 -(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessageIDSTest*) transport peers:(CFDictionaryRef) peers err:(CFErrorRef*) error
813 void SOSTransportMessageIDSTestClearChanges(SOSMessageIDSTest* transport)
815 transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
818 CFMutableDictionaryRef SOSTransportMessageIDSTestGetChanges(SOSMessageIDSTest* transport)
820 return transport.changes;
823 SOSAccount* SOSTransportMessageIDSTestGetAccount(SOSMessageIDSTest* transport)
825 return transport.account;
828 CFStringRef SOSTransportMessageIDSTestGetName(SOSMessageIDSTest* transport){
829 return transport.accountName;
835 void SOSAccountUpdateTestTransports(SOSAccount* account, CFDictionaryRef gestalt){
836 CFStringRef new_name = (CFStringRef)CFDictionaryGetValue(gestalt, kPIUserDefinedDeviceNameKey);
838 SOSTransportKeyParameterTestSetName((CKKeyParameterTest*)account.key_transport, new_name);
839 SOSTransportCircleTestSetName((SOSCircleStorageTransportTest*)account.circle_transport, new_name);
840 SOSTransportMessageKVSTestSetName((SOSMessageKVSTest*)account.kvs_message_transport, new_name);
841 SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)account.ids_message_transport, new_name);
845 static SOSCircleRef SOSAccountEnsureCircleTest(SOSAccount* a, CFStringRef name, CFStringRef accountName)
847 CFErrorRef localError = NULL;
848 SOSAccountTrustClassic *trust = a.trust;
850 SOSCircleRef circle = [a.trust getCircle:&localError];
851 if(!circle || isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle)){
852 secnotice("circle", "Error retrieving the circle: %@", localError);
853 CFReleaseNull(localError);
855 circle = SOSCircleCreate(kCFAllocatorDefault, name, &localError);
857 [trust setTrustedCircle:circle];
860 secnotice("circle", "Could not create circle: %@", localError);
862 CFReleaseNull(localError);
865 if(![trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(a.gestalt) deviceID:(__bridge CFStringRef)(a.deviceID) backupKey:(__bridge CFDataRef)(a.backup_key) err:&localError])
867 secnotice("circle", "had an error building full peer: %@", localError);
868 CFReleaseNull(localError);
872 CFReleaseNull(localError);
876 bool SOSAccountEnsureFactoryCirclesTest(SOSAccount* a, CFStringRef accountName)
883 CFStringRef circle_name = SOSDataSourceFactoryCopyName(a.factory);
886 SOSAccountEnsureCircleTest(a, (CFStringRef)circle_name, accountName);
888 CFReleaseNull(circle_name);
894 bool SOSAccountInflateTestTransportsForCircle(SOSAccount* account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error){
895 bool success = false;
897 if(account.key_transport == nil){
898 account.key_transport = (CKKeyParameter*)[[CKKeyParameterTest alloc] initWithAccount:account andName:accountName andCircleName:circleName];
899 require_quiet(account.key_transport, fail);
902 if(account.circle_transport == nil){
903 account.circle_transport = (SOSKVSCircleStorageTransport*)[[SOSCircleStorageTransportTest alloc] initWithAccount:account andWithAccountName:accountName andCircleName:circleName];
904 require_quiet(account.circle_transport, fail);
906 if(account.kvs_message_transport == nil){
907 account.kvs_message_transport = (SOSMessageKVS*)[[SOSMessageKVSTest alloc] initWithAccount:account andName:accountName andCircleName:circleName];
909 if(account.ids_message_transport == nil){
910 account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:account andAccountName:accountName andCircleName:circleName err:NULL];