You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-ios/SignalServiceKit/src/Contacts/ContactsUpdater.m

196 lines
7.9 KiB
Matlab

//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
10 years ago
#import "ContactsUpdater.h"
#import "Contact.h"
#import "Cryptography.h"
#import "OWSError.h"
#import "OWSPrimaryStorage.h"
#import "OWSRequestFactory.h"
#import "PhoneNumber.h"
10 years ago
#import "TSNetworkManager.h"
#import <YapDatabase/YapDatabase.h>
10 years ago
NS_ASSUME_NONNULL_BEGIN
10 years ago
@implementation ContactsUpdater
+ (instancetype)sharedUpdater {
static dispatch_once_t onceToken;
static id sharedInstance = nil;
dispatch_once(&onceToken, ^{
sharedInstance = [self new];
10 years ago
});
return sharedInstance;
}
- (instancetype)init
{
self = [super init];
if (!self) {
return self;
}
OWSSingletonAssert();
return self;
}
- (SignalRecipient *)signalRecipientForRegisteredRecipientId:(NSString *)recipientId
{
__block SignalRecipient *recipient;
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
recipient =
[SignalRecipient ensureRecipientExistsWithRegisteredRecipientId:recipientId transaction:transaction];
}];
return recipient;
}
10 years ago
- (void)lookupIdentifier:(NSString *)identifier
success:(void (^)(SignalRecipient *recipient))success
failure:(void (^)(NSError *error))failure
{
// This should never happen according to nullability annotations... but IIRC it does. =/
if (!identifier) {
OWSFail(@"%@ Cannot lookup nil identifier", self.logTag);
failure(OWSErrorWithCodeDescription(OWSErrorCodeInvalidMethodParameters, @"Cannot lookup nil identifier"));
return;
}
[self contactIntersectionWithSet:[NSSet setWithObject:identifier]
success:^(NSSet<NSString *> *_Nonnull matchedIds) {
if (matchedIds.count == 1) {
success([self signalRecipientForRegisteredRecipientId:identifier]);
} else {
failure(OWSErrorMakeNoSuchSignalRecipientError());
}
}
failure:failure];
10 years ago
}
- (void)lookupIdentifiers:(NSArray<NSString *> *)identifiers
success:(void (^)(NSArray<SignalRecipient *> *recipients))success
failure:(void (^)(NSError *error))failure
{
if (identifiers.count < 1) {
OWSFail(@"%@ Cannot lookup zero identifiers", self.logTag);
failure(OWSErrorWithCodeDescription(OWSErrorCodeInvalidMethodParameters, @"Cannot lookup zero identifiers"));
return;
}
[self contactIntersectionWithSet:[NSSet setWithArray:identifiers]
success:^(NSSet<NSString *> *_Nonnull matchedIds) {
if (matchedIds.count > 0) {
NSMutableArray<SignalRecipient *> *recipients = [NSMutableArray new];
for (NSString *identifier in matchedIds) {
[recipients
addObject:[self signalRecipientForRegisteredRecipientId:identifier]];
}
success([recipients copy]);
} else {
failure(OWSErrorMakeNoSuchSignalRecipientError());
}
}
failure:failure];
}
10 years ago
- (void)updateSignalContactIntersectionWithABContacts:(NSArray<Contact *> *)abContacts
success:(void (^)(void))success
failure:(void (^)(NSError *error))failure
{
10 years ago
NSMutableSet<NSString *> *abPhoneNumbers = [NSMutableSet set];
for (Contact *contact in abContacts) {
for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) {
[abPhoneNumbers addObject:phoneNumber.toE164];
}
}
NSMutableSet *recipientIds = [NSMutableSet set];
[OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
NSArray *allRecipientKeys = [transaction allKeysInCollection:[SignalRecipient collection]];
[recipientIds addObjectsFromArray:allRecipientKeys];
}];
10 years ago
NSMutableSet<NSString *> *allContacts = [[abPhoneNumbers setByAddingObjectsFromSet:recipientIds] mutableCopy];
[self contactIntersectionWithSet:allContacts
success:^(NSSet<NSString *> *matchedIds) {
[recipientIds minusSet:matchedIds];
// TODO:
//
// Update cache of registered identifiers.
DDLogInfo(@"%@ successfully intersected contacts.", self.logTag);
success();
}
failure:failure];
10 years ago
}
- (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 = [OWSRequestFactory contactsIntersectionRequestWithHashesArray:hashes];
10 years ago
[[TSNetworkManager sharedManager] makeRequest:request
success:^(NSURLSessionDataTask *tsTask, id responseDict) {
NSMutableSet *identifiers = [NSMutableSet new];
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.length < 1) {
DDLogWarn(@"%@ An interesecting hash wasn't found in the mapping.", self.logTag);
continue;
}
[identifiers addObject:identifier];
}
}
// Insert or update contact attributes
//
// TODO: Do we need to _eagerly_ ensure a SignalRecipient instance exists?
[OWSPrimaryStorage.dbReadWriteConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
for (NSString *identifier in identifiers) {
[SignalRecipient ensureRecipientExistsWithRegisteredRecipientId:identifier
transaction:transaction];
}
}];
success([identifiers copy]);
10 years ago
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
if (!IsNSErrorNetworkFailure(error)) {
OWSProdError([OWSAnalyticsEvents contactsErrorContactsIntersectionFailed]);
}
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
if (response.statusCode == 413) {
failure(OWSErrorWithCodeDescription(
OWSErrorCodeContactsUpdaterRateLimit, @"Contacts Intersection Rate Limit"));
} else {
failure(error);
}
10 years ago
}];
});
}
@end
NS_ASSUME_NONNULL_END