185 lines
8.3 KiB
Objective-C
185 lines
8.3 KiB
Objective-C
//
|
|
// ContactsManager+updater.m
|
|
// Signal
|
|
//
|
|
// Created by Frederic Jacobs on 21/11/15.
|
|
// Copyright © 2015 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
#import "ContactsManager+updater.h"
|
|
|
|
#import "Cryptography.h"
|
|
#import "Environment.h"
|
|
#import "TSContactsIntersectionRequest.h"
|
|
#import "TSNetworkManager.h"
|
|
|
|
@implementation ContactsManager (updater)
|
|
|
|
- (void)synchronousLookup:(NSString*)identifier
|
|
success:(void (^)(SignalRecipient*))success
|
|
failure:(void (^)(NSError *error))failure
|
|
{
|
|
__block dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
|
__block SignalRecipient *recipient = nil;
|
|
__block NSError *error = nil;
|
|
|
|
[self lookupIdentifier:identifier
|
|
success:^(NSSet<NSString *> *matchedIds) {
|
|
if ([matchedIds count] == 1) {
|
|
[[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
|
|
recipient = [SignalRecipient recipientWithTextSecureIdentifier:identifier withTransaction:transaction];
|
|
}];
|
|
} else {
|
|
error = [NSError errorWithDomain:@"contactsmanager.notfound" code:NOTFOUND_ERROR userInfo:nil];
|
|
}
|
|
dispatch_semaphore_signal(sema);
|
|
} failure:^(NSError *blockerror) {
|
|
error = blockerror;
|
|
dispatch_semaphore_signal(sema);
|
|
}];
|
|
|
|
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
|
if (error) {
|
|
SYNC_BLOCK_SAFE_RUN(failure, error);
|
|
} else {
|
|
SYNC_BLOCK_SAFE_RUN(success, recipient);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
- (void)lookupIdentifier:(NSString*)identifier
|
|
success:(void (^)(NSSet<NSString*> *matchedIds))success
|
|
failure:(void (^)(NSError *error))failure
|
|
{
|
|
[self contactIntersectionWithSet:[NSSet setWithObject:identifier]
|
|
success:^(NSSet<NSString *> *matchedIds){
|
|
BLOCK_SAFE_RUN(success, matchedIds);
|
|
}
|
|
failure:^(NSError *error) {
|
|
BLOCK_SAFE_RUN(failure, error);
|
|
}];
|
|
}
|
|
|
|
- (void)intersectContacts {
|
|
[self updateSignalContactIntersectionWithSuccess:nil failure:^(NSError *error) {
|
|
[NSTimer scheduledTimerWithTimeInterval:60
|
|
target:self
|
|
selector:@selector(intersectContacts)
|
|
userInfo:nil
|
|
repeats:NO];
|
|
}];
|
|
}
|
|
|
|
- (void)updateSignalContactIntersectionWithSuccess:(void (^)())success
|
|
failure:(void (^)(NSError *error))failure
|
|
{
|
|
NSArray<Contact*> *abContacts = [[[Environment getCurrent] contactsManager] allContacts];
|
|
NSMutableSet<NSString*> *abPhoneNumbers = [NSMutableSet set];
|
|
|
|
for (Contact *contact in abContacts) {
|
|
for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) {
|
|
[abPhoneNumbers addObject:phoneNumber.toE164];
|
|
}
|
|
}
|
|
|
|
__block NSMutableSet *recipientIds = [NSMutableSet set];
|
|
[[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
|
|
NSArray *allRecipientKeys = [transaction allKeysInCollection:[SignalRecipient collection]];
|
|
[recipientIds addObjectsFromArray:allRecipientKeys];
|
|
}];
|
|
|
|
NSMutableSet<NSString*> *allContacts = [[abPhoneNumbers setByAddingObjectsFromSet:recipientIds] mutableCopy];
|
|
|
|
[self contactIntersectionWithSet:allContacts
|
|
success:^(NSSet<NSString *> *matchedIds) {
|
|
[recipientIds minusSet:matchedIds];
|
|
|
|
// Cleaning up unregistered identifiers
|
|
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
|
|
for (NSString *identifier in recipientIds) {
|
|
SignalRecipient *recipient = [SignalRecipient fetchObjectWithUniqueID:identifier transaction:transaction];
|
|
[recipient removeWithTransaction:transaction];
|
|
}
|
|
}];
|
|
|
|
BLOCK_SAFE_RUN(success);
|
|
} failure:^(NSError *error) {
|
|
BLOCK_SAFE_RUN(failure, error);
|
|
}];
|
|
}
|
|
|
|
- (void) contactIntersectionWithSet:(NSSet<NSString*>*)idSet
|
|
success:(void (^)(NSSet<NSString*> *matchedIds))success
|
|
failure:(void (^)(NSError *error))failure
|
|
{
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
NSMutableDictionary *phoneNumbersByHashes = [NSMutableDictionary dictionary];
|
|
for (NSString *identifier in idSet) {
|
|
[phoneNumbersByHashes setObject:identifier
|
|
forKey:[Cryptography truncatedSHA1Base64EncodedWithoutPadding:identifier]];
|
|
}
|
|
NSArray *hashes = [phoneNumbersByHashes allKeys];
|
|
|
|
TSRequest *request = [[TSContactsIntersectionRequest alloc] initWithHashesArray:hashes];
|
|
[[TSNetworkManager sharedManager] queueAuthenticatedRequest:request success:^(NSURLSessionDataTask *tsTask, id responseDict) {
|
|
NSMutableDictionary *attributesForIdentifier = [NSMutableDictionary dictionary];
|
|
NSArray *contactsArray = [(NSDictionary*)responseDict objectForKey:@"contacts"];
|
|
|
|
// Map attributes to phone numbers
|
|
if (contactsArray) {
|
|
for (NSDictionary *dict in contactsArray) {
|
|
NSString *hash = [dict objectForKey:@"token"];
|
|
NSString *identifier = [phoneNumbersByHashes objectForKey:hash];
|
|
|
|
if (!identifier) {
|
|
DDLogWarn(@"An interesecting hash wasn't found in the mapping.");
|
|
break;
|
|
}
|
|
|
|
[attributesForIdentifier setObject:dict forKey:identifier];
|
|
}
|
|
}
|
|
|
|
// Insert or update contact attributes
|
|
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
for (NSString *identifier in attributesForIdentifier) {
|
|
SignalRecipient *recipient = [SignalRecipient recipientWithTextSecureIdentifier:identifier
|
|
withTransaction:transaction];
|
|
if (!recipient) {
|
|
recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:identifier
|
|
relay:nil
|
|
supportsVoice:NO];
|
|
}
|
|
|
|
NSDictionary *attributes = [attributesForIdentifier objectForKey:identifier];
|
|
|
|
NSString *relay = [attributes objectForKey:@"relay"];
|
|
if (relay) {
|
|
recipient.relay = relay;
|
|
} else {
|
|
recipient.relay = nil;
|
|
}
|
|
|
|
BOOL supportsVoice = [[attributes objectForKey:@"voice"] boolValue];
|
|
if (supportsVoice) {
|
|
recipient.supportsVoice = YES;
|
|
} else {
|
|
recipient.supportsVoice = NO;
|
|
}
|
|
|
|
[recipient saveWithTransaction:transaction];
|
|
}
|
|
}];
|
|
|
|
BLOCK_SAFE_RUN(success, [NSSet setWithArray:attributesForIdentifier.allKeys]);
|
|
} failure:^(NSURLSessionDataTask *task, NSError *error) {
|
|
BLOCK_SAFE_RUN(failure, error);
|
|
}];
|
|
});
|
|
}
|
|
|
|
@end
|