From 47cad611e5a14127200747667b7ed9f50e8337ce Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 3 Nov 2016 16:10:06 -0400 Subject: [PATCH] Fix register w/o background fetch & stale push tokens * Separate account registration from push token registration * Provide better errors when validation fails (e.g. numbers don't match, numbers blank) * More logging during registration * Call success after setting phone number to avoid any future race condition This isn't currently causing problems, but it's unexpected that we'd mutate the state *after* calling a callback which might inuitively rely on that state. * Don't throw exception off thread when device keys 404's * Better async startup handling - move processing off main thread - reduce code duplication - don't wrap it in a transaction in the future case where we want to further access the DB // FREEBIE --- Example/TSKitiOSTestApp/Podfile.lock | 4 +- SignalServiceKit.podspec | 2 +- src/Account/TSAccountManager.h | 51 +++-- src/Account/TSAccountManager.m | 214 +++++++++++------- src/Account/TSPreKeyManager.h | 3 +- src/Account/TSPreKeyManager.m | 25 +- src/Messages/OWSDisappearingMessagesFinder.m | 2 +- src/Messages/OWSMessageSender.m | 12 +- src/Storage/TSStorageManager+keyingMaterial.h | 5 +- src/Storage/TSStorageManager+keyingMaterial.m | 38 +++- src/TSConstants.h | 4 - src/Util/OWSError.h | 3 +- tests/Contacts/SignalRecipientTest.m | 26 ++- tests/Messages/OWSMessageSenderTest.m | 2 +- 14 files changed, 238 insertions(+), 153 deletions(-) diff --git a/Example/TSKitiOSTestApp/Podfile.lock b/Example/TSKitiOSTestApp/Podfile.lock index 5e2057666..0e451d178 100644 --- a/Example/TSKitiOSTestApp/Podfile.lock +++ b/Example/TSKitiOSTestApp/Podfile.lock @@ -35,7 +35,7 @@ PODS: - ProtocolBuffers (1.9.10) - Reachability (3.2) - SAMKeychain (1.5.0) - - SignalServiceKit (0.3.0): + - SignalServiceKit (0.4.0): - '25519' - AFNetworking - AxolotlKit @@ -130,7 +130,7 @@ SPEC CHECKSUMS: ProtocolBuffers: d088180c10072b3d24a9939a6314b7b9bcc2340b Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 SAMKeychain: 1fc9ae02f576365395758b12888c84704eebc423 - SignalServiceKit: 8b115cfd63f9b814fa03fe61fd5d38ef9a548460 + SignalServiceKit: 5c3877241082a778c8c130e1fed17d0904085205 SocketRocket: 3f77ec2104cc113add553f817ad90a77114f5d43 SQLCipher: 4c768761421736a247ed6cf412d9045615d53dff TwistedOakCollapsingFutures: f359b90f203e9ab13dfb92c9ff41842a7fe1cd0c diff --git a/SignalServiceKit.podspec b/SignalServiceKit.podspec index 816f66caa..015d895f1 100644 --- a/SignalServiceKit.podspec +++ b/SignalServiceKit.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = "SignalServiceKit" - s.version = "0.3.0" + s.version = "0.4.0" s.summary = "An Objective-C library for communicating with the Signal messaging service." s.description = <<-DESC diff --git a/src/Account/TSAccountManager.h b/src/Account/TSAccountManager.h index 4d5c192eb..5a8e85723 100644 --- a/src/Account/TSAccountManager.h +++ b/src/Account/TSAccountManager.h @@ -9,30 +9,36 @@ #import #import "TSConstants.h" +NS_ASSUME_NONNULL_BEGIN + static NSString *const TSRegistrationErrorDomain = @"TSRegistrationErrorDomain"; static NSString *const TSRegistrationErrorUserInfoHTTPStatus = @"TSHTTPStatus"; -typedef void (^failedBlock)(NSError *error); +@class TSNetworkManager; +@class TSStorageManager; @interface TSAccountManager : NSObject +- (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager + storageManager:(TSStorageManager *)storageManager; + ++ (instancetype)sharedInstance; + /** * Returns if a user is registered or not * * @return registered or not */ + (BOOL)isRegistered; -+ (void)runIfRegistered:(void (^)())block; + +- (void)ifRegistered:(BOOL)isRegistered runAsync:(void (^)())block; /** * Returns registered number * * @return E164 formatted phone number */ - -+ (NSString *)localNumber; - -+ (void)didRegister; ++ (nullable NSString *)localNumber; /** * The registration ID is unique to an installation of TextSecure, it allows to know if the app was reinstalled @@ -45,19 +51,17 @@ typedef void (^failedBlock)(NSError *error); #pragma mark - Register with phone number + (void)registerWithPhoneNumber:(NSString *)phoneNumber - success:(successCompletionBlock)successBlock - failure:(failedBlock)failureBlock + success:(void (^)())successBlock + failure:(void (^)(NSError *error))failureBlock smsVerification:(BOOL)isSMS; -+ (void)rerequestSMSWithSuccess:(successCompletionBlock)successBlock failure:(failedBlock)failureBlock; ++ (void)rerequestSMSWithSuccess:(void (^)())successBlock failure:(void (^)(NSError *error))failureBlock; -+ (void)rerequestVoiceWithSuccess:(successCompletionBlock)successBlock failure:(failedBlock)failureBlock; ++ (void)rerequestVoiceWithSuccess:(void (^)())successBlock failure:(void (^)(NSError *error))failureBlock; -+ (void)verifyAccountWithCode:(NSString *)verificationCode - pushToken:(NSString *)pushToken - voipToken:(NSString *)voipToken - success:(successCompletionBlock)successBlock - failure:(failedBlock)failureBlock; +- (void)verifyAccountWithCode:(NSString *)verificationCode + success:(void (^)())successBlock + failure:(void (^)(NSError *error))failureBlock; #if TARGET_OS_IPHONE @@ -66,16 +70,19 @@ typedef void (^failedBlock)(NSError *error); * * @param pushToken Apple's Push Token */ +- (void)registerForPushNotificationsWithPushToken:(NSString *)pushToken + voipToken:(NSString *)voipToken + success:(void (^)())successHandler + failure:(void (^)(NSError *error))failureHandler + NS_SWIFT_NAME(registerForPushNotifications(pushToken:voipToken:success:failure:)); -+ (void)registerForPushNotifications:(NSString *)pushToken - voipToken:(NSString *)voipToken - success:(successCompletionBlock)success - failure:(failedBlock)failureBlock; - -+ (void)obtainRPRegistrationToken:(void (^)(NSString *rpRegistrationToken))success failure:(failedBlock)failureBlock; +- (void)obtainRPRegistrationTokenWithSuccess:(void (^)(NSString *rpRegistrationToken))success + failure:(void (^)(NSError *error))failureBlock; #endif -+ (void)unregisterTextSecureWithSuccess:(successCompletionBlock)success failure:(failedBlock)failureBlock; ++ (void)unregisterTextSecureWithSuccess:(void (^)())success failure:(void (^)(NSError *error))failureBlock; @end + +NS_ASSUME_NONNULL_END diff --git a/src/Account/TSAccountManager.m b/src/Account/TSAccountManager.m index 3b265940a..1761c7623 100644 --- a/src/Account/TSAccountManager.m +++ b/src/Account/TSAccountManager.m @@ -6,31 +6,52 @@ // Copyright (c) 2014 Open Whisper Systems. All rights reserved. // +#import "TSAccountManager.h" #import "NSData+Base64.h" #import "NSData+hexString.h" #import "NSURLSessionDataTask+StatusCode.h" - +#import "OWSError.h" #import "SecurityUtils.h" -#import "TSAccountManager.h" #import "TSNetworkManager.h" #import "TSPreKeyManager.h" #import "TSRedPhoneTokenRequest.h" #import "TSSocketManager.h" #import "TSStorageManager+keyingMaterial.h" + +NS_ASSUME_NONNULL_BEGIN + @interface TSAccountManager () -@property (nonatomic, retain) NSString *phoneNumberAwaitingVerification; +@property (nullable, nonatomic, retain) NSString *phoneNumberAwaitingVerification; +@property (nonatomic, strong, readonly) TSNetworkManager *networkManager; +@property (nonatomic, strong, readonly) TSStorageManager *storageManager; @end @implementation TSAccountManager -+ (instancetype)sharedInstance { +- (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager + storageManager:(TSStorageManager *)storageManager +{ + self = [super init]; + if (!self) { + return self; + } + + _networkManager = networkManager; + _storageManager = storageManager; + + return self; +} + ++ (instancetype)sharedInstance +{ static dispatch_once_t onceToken; static id sharedInstance = nil; dispatch_once(&onceToken, ^{ - sharedInstance = [self.class new]; + sharedInstance = [[self alloc] initWithNetworkManager:[TSNetworkManager sharedManager] + storageManager:[TSStorageManager sharedManager]]; }); return sharedInstance; @@ -40,23 +61,25 @@ return [TSStorageManager localNumber] ? YES : NO; } -+ (void)runIfRegistered:(void (^)())block +- (void)ifRegistered:(BOOL)isRegistered runAsync:(void (^)())block { - [[TSStorageManager sharedManager] runIfHasLocalNumber:block]; + [self.storageManager ifLocalNumberPresent:isRegistered runAsync:block]; } -+ (void)didRegister { - TSAccountManager *sharedManager = [self sharedInstance]; - __strong NSString *phoneNumber = sharedManager.phoneNumberAwaitingVerification; +- (void)didRegister +{ + DDLogInfo(@"%@ didRegister", self.tag); + NSString *phoneNumber = self.phoneNumberAwaitingVerification; if (!phoneNumber) { @throw [NSException exceptionWithName:@"RegistrationFail" reason:@"Internal Corrupted State" userInfo:nil]; } - [TSStorageManager storePhoneNumber:phoneNumber]; + [self.storageManager storePhoneNumber:phoneNumber]; } -+ (NSString *)localNumber { ++ (nullable NSString *)localNumber +{ TSAccountManager *sharedManager = [self sharedInstance]; NSString *awaitingVerif = sharedManager.phoneNumberAwaitingVerification; if (awaitingVerif) { @@ -88,23 +111,26 @@ return registrationID; } -+ (void)registerForPushNotifications:(NSString *)pushToken - voipToken:(NSString *)voipToken - success:(successCompletionBlock)success - failure:(failedBlock)failureBlock { - [[TSNetworkManager sharedManager] - makeRequest:[[TSRegisterForPushRequest alloc] initWithPushIdentifier:pushToken voipIdentifier:voipToken] +- (void)registerForPushNotificationsWithPushToken:(NSString *)pushToken + voipToken:(NSString *)voipToken + success:(void (^)())successHandler + failure:(void (^)(NSError *))failureHandler +{ + TSRegisterForPushRequest *request = + [[TSRegisterForPushRequest alloc] initWithPushIdentifier:pushToken voipIdentifier:voipToken]; + + [self.networkManager makeRequest:request success:^(NSURLSessionDataTask *task, id responseObject) { - success(); + successHandler(); } failure:^(NSURLSessionDataTask *task, NSError *error) { - failureBlock(error); + failureHandler(error); }]; } + (void)registerWithPhoneNumber:(NSString *)phoneNumber - success:(successCompletionBlock)successBlock - failure:(failedBlock)failureBlock + success:(void (^)())successBlock + failure:(void (^)(NSError *error))failureBlock smsVerification:(BOOL)isSMS { @@ -118,16 +144,22 @@ initWithPhoneNumber:phoneNumber transport:isSMS ? TSVerificationTransportSMS : TSVerificationTransportVoice] success:^(NSURLSessionDataTask *task, id responseObject) { - successBlock(); - TSAccountManager *manager = [self sharedInstance]; - manager.phoneNumberAwaitingVerification = phoneNumber; + DDLogInfo(@"%@ Successfully requested verification code request for number: %@ method:%@", + self.tag, + phoneNumber, + isSMS ? @"SMS" : @"Voice"); + TSAccountManager *manager = [self sharedInstance]; + manager.phoneNumberAwaitingVerification = phoneNumber; + successBlock(); } failure:^(NSURLSessionDataTask *task, NSError *error) { - failureBlock(error); + DDLogError(@"%@ Failed to request verification code request with error:%@", self.tag, error); + failureBlock(error); }]; } -+ (void)rerequestSMSWithSuccess:(successCompletionBlock)successBlock failure:(failedBlock)failureBlock { ++ (void)rerequestSMSWithSuccess:(void (^)())successBlock failure:(void (^)(NSError *error))failureBlock +{ TSAccountManager *manager = [self sharedInstance]; NSString *number = manager.phoneNumberAwaitingVerification; @@ -136,7 +168,8 @@ [self registerWithPhoneNumber:number success:successBlock failure:failureBlock smsVerification:YES]; } -+ (void)rerequestVoiceWithSuccess:(successCompletionBlock)successBlock failure:(failedBlock)failureBlock { ++ (void)rerequestVoiceWithSuccess:(void (^)())successBlock failure:(void (^)(NSError *error))failureBlock +{ TSAccountManager *manager = [self sharedInstance]; NSString *number = manager.phoneNumberAwaitingVerification; @@ -145,18 +178,16 @@ [self registerWithPhoneNumber:number success:successBlock failure:failureBlock smsVerification:NO]; } -+ (void)verifyAccountWithCode:(NSString *)verificationCode - pushToken:(NSString *)pushToken - voipToken:(NSString *)voipToken - success:(successCompletionBlock)successBlock - failure:(failedBlock)failureBlock { - NSString *authToken = [self generateNewAccountAuthenticationToken]; - NSString *signalingKey = [self generateNewSignalingKeyToken]; - NSString *phoneNumber = ((TSAccountManager *)[self sharedInstance]).phoneNumberAwaitingVerification; +- (void)verifyAccountWithCode:(NSString *)verificationCode + success:(void (^)())successBlock + failure:(void (^)(NSError *error))failureBlock +{ + NSString *authToken = [[self class] generateNewAccountAuthenticationToken]; + NSString *signalingKey = [[self class] generateNewSignalingKeyToken]; + NSString *phoneNumber = self.phoneNumberAwaitingVerification; assert(signalingKey); assert(authToken); - assert(pushToken); assert(phoneNumber); TSVerifyCodeRequest *request = [[TSVerifyCodeRequest alloc] initWithVerificationCode:verificationCode @@ -164,53 +195,47 @@ signalingKey:signalingKey authKey:authToken]; - [[TSNetworkManager sharedManager] makeRequest:request + [self.networkManager makeRequest:request success:^(NSURLSessionDataTask *task, id responseObject) { - NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response; - long statuscode = response.statusCode; - - if (statuscode == 200 || statuscode == 204) { - [TSStorageManager storeServerToken:authToken signalingKey:signalingKey]; - - [self registerForPushNotifications:pushToken - voipToken:voipToken - success:^{ - [self registerPreKeys:^{ - [TSSocketManager becomeActiveFromForeground]; - successBlock(); - } - failure:failureBlock]; - } - failure:^(NSError *error) { + NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response; + long statuscode = response.statusCode; + + switch (statuscode) { + case 200: + case 204: { + [TSStorageManager storeServerToken:authToken signalingKey:signalingKey]; + [self didRegister]; + [TSSocketManager becomeActiveFromForeground]; + [TSPreKeyManager registerPreKeysWithSuccess:successBlock failure:failureBlock]; + break; + } + default: { + DDLogError(@"%@ Unexpected status while verifying code: %ld", self.tag, statuscode); + NSError *error = OWSErrorMakeUnableToProcessServerResponseError(); failureBlock(error); - }]; - } + break; + } + } } failure:^(NSURLSessionDataTask *task, NSError *error) { - DDLogError(@"Error registering with TextSecure: %@", error.debugDescription); - failureBlock(error); + DDLogWarn(@"%@ Error verifying code: %@", self.tag, error.debugDescription); + switch (error.code) { + case 403: { + NSError *userError = OWSErrorWithCodeDescription(OWSErrorCodeUserError, + NSLocalizedString(@"REGISTRATION_VERIFICATION_FAILED_WRONG_CODE_DESCRIPTION", + "Alert body, during registration")); + failureBlock(userError); + break; + } + default: { + DDLogError(@"%@ verifying code failed with unhandled error: %@", self.tag, error); + failureBlock(error); + break; + } + } }]; } -+ (void)registerPreKeysAfterPush:(NSString *)pushToken - voipToken:(NSString *)voipToken - success:(successCompletionBlock)successBlock - failure:(failedBlock)failureBlock { - [self registerForPushNotifications:pushToken - voipToken:voipToken - success:^{ - [self registerPreKeys:successBlock failure:failureBlock]; - } - failure:failureBlock]; -} - -+ (void)registerPreKeys:(successCompletionBlock)successBlock failure:(failedBlock)failureBlock { - [TSPreKeyManager registerPreKeysWithSuccess:^{ - successBlock(); - } - failure:failureBlock]; -} - #pragma mark Server keying material + (NSString *)generateNewAccountAuthenticationToken { @@ -228,24 +253,45 @@ return signalingKeyTokenPrint; } -+ (void)obtainRPRegistrationToken:(void (^)(NSString *rpRegistrationToken))success failure:(failedBlock)failureBlock { - [[TSNetworkManager sharedManager] makeRequest:[[TSRedPhoneTokenRequest alloc] init] +- (void)obtainRPRegistrationTokenWithSuccess:(void (^)(NSString *rpRegistrationToken))success + failure:(void (^)(NSError *error))failureBlock +{ + [self.networkManager makeRequest:[[TSRedPhoneTokenRequest alloc] init] success:^(NSURLSessionDataTask *task, id responseObject) { - success([responseObject objectForKey:@"token"]); + DDLogInfo(@"%@ Successfully obtained Redphone token", self.tag); + success([responseObject objectForKey:@"token"]); } failure:^(NSURLSessionDataTask *task, NSError *error) { - failureBlock(error); + DDLogError(@"%@ Failed to obtain Redphone token with error: %@", self.tag, error); + failureBlock(error); }]; } -+ (void)unregisterTextSecureWithSuccess:(successCompletionBlock)success failure:(failedBlock)failureBlock { ++ (void)unregisterTextSecureWithSuccess:(void (^)())success failure:(void (^)(NSError *error))failureBlock +{ [[TSNetworkManager sharedManager] makeRequest:[[TSUnregisterAccountRequest alloc] init] success:^(NSURLSessionDataTask *task, id responseObject) { - success(); + DDLogInfo(@"%@ Successfully unregistered", self.tag); + success(); } failure:^(NSURLSessionDataTask *task, NSError *error) { - failureBlock(error); + DDLogError(@"%@ Failed to unregister with error: %@", self.tag, error); + failureBlock(error); }]; } +#pragma mark - Logging + ++ (NSString *)tag +{ + return [NSString stringWithFormat:@"[%@]", self.class]; +} + +- (NSString *)tag +{ + return self.class.tag; +} + @end + +NS_ASSUME_NONNULL_END diff --git a/src/Account/TSPreKeyManager.h b/src/Account/TSPreKeyManager.h index 3c1cb9ad2..7876ab444 100644 --- a/src/Account/TSPreKeyManager.h +++ b/src/Account/TSPreKeyManager.h @@ -8,14 +8,13 @@ #import #import "TSAccountManager.h" -#import "TSConstants.h" // Time before deletion of signed PreKeys (measured in seconds) #define SignedPreKeysDeletionTime 14 * 24 * 60 * 60 @interface TSPreKeyManager : NSObject -+ (void)registerPreKeysWithSuccess:(successCompletionBlock)success failure:(failedBlock)failureBlock; ++ (void)registerPreKeysWithSuccess:(void (^)())successHandler failure:(void (^)(NSError *error))failureHandler; + (void)refreshPreKeys; diff --git a/src/Account/TSPreKeyManager.m b/src/Account/TSPreKeyManager.m index dd66bfcb0..42a49ffc0 100644 --- a/src/Account/TSPreKeyManager.m +++ b/src/Account/TSPreKeyManager.m @@ -16,7 +16,8 @@ @implementation TSPreKeyManager -+ (void)registerPreKeysWithSuccess:(successCompletionBlock)success failure:(failedBlock)failureBlock { ++ (void)registerPreKeysWithSuccess:(void (^)())success failure:(void (^)(NSError *))failureBlock +{ TSStorageManager *storageManager = [TSStorageManager sharedManager]; ECKeyPair *identityKeyPair = [storageManager identityKeyPair]; @@ -38,13 +39,15 @@ [[TSNetworkManager sharedManager] makeRequest:request success:^(NSURLSessionDataTask *task, id responseObject) { - [storageManager storePreKeyRecords:preKeys]; - [storageManager storeSignedPreKey:signedPreKey.Id signedPreKeyRecord:signedPreKey]; + DDLogInfo(@"%@ Successfully registered pre keys.", self.tag); + [storageManager storePreKeyRecords:preKeys]; + [storageManager storeSignedPreKey:signedPreKey.Id signedPreKeyRecord:signedPreKey]; - success(); + success(); } failure:^(NSURLSessionDataTask *task, NSError *error) { - failureBlock(error); + DDLogError(@"%@ Failed to register pre keys.", self.tag); + failureBlock(error); }]; } @@ -123,4 +126,16 @@ return oldRecords; } +#pragma mark - Logging + ++ (NSString *)tag +{ + return [NSString stringWithFormat:@"[%@]", self.class]; +} + +- (NSString *)tag +{ + return self.class.tag; +} + @end diff --git a/src/Messages/OWSDisappearingMessagesFinder.m b/src/Messages/OWSDisappearingMessagesFinder.m index 7c243ccd7..7f59cc8cb 100644 --- a/src/Messages/OWSDisappearingMessagesFinder.m +++ b/src/Messages/OWSDisappearingMessagesFinder.m @@ -214,7 +214,7 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess withName:OWSDisappearingMessageFinderExpiresAtIndex completionBlock:^(BOOL ready) { if (ready) { - DDLogInfo(@"%@ completed registering extension async.", self.tag); + DDLogDebug(@"%@ completed registering extension async.", self.tag); } else { DDLogError(@"%@ failed registering extension async.", self.tag); } diff --git a/src/Messages/OWSMessageSender.m b/src/Messages/OWSMessageSender.m index f8a0db5c6..d30bc5b73 100644 --- a/src/Messages/OWSMessageSender.m +++ b/src/Messages/OWSMessageSender.m @@ -634,7 +634,7 @@ NSString *const OWSMessageSenderInvalidDeviceException = @"InvalidDeviceExceptio if (![storage containsSession:identifier deviceId:[deviceNumber intValue]]) { __block dispatch_semaphore_t sema = dispatch_semaphore_create(0); __block PreKeyBundle *bundle; - + __block NSException *exception; [self.networkManager makeRequest:[[TSRecipientPrekeyRequest alloc] initWithRecipient:identifier deviceId:[deviceNumber stringValue]] success:^(NSURLSessionDataTask *task, id responseObject) { @@ -645,13 +645,17 @@ NSString *const OWSMessageSenderInvalidDeviceException = @"InvalidDeviceExceptio DDLogError(@"Server replied on PreKeyBundle request with error: %@", error); NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response; if (response.statusCode == 404) { - @throw [NSException exceptionWithName:OWSMessageSenderInvalidDeviceException - reason:@"Device not registered" - userInfo:nil]; + // Can't throw exception from within callback as it's probabably a different thread. + exception = [NSException exceptionWithName:OWSMessageSenderInvalidDeviceException + reason:@"Device not registered" + userInfo:nil]; } dispatch_semaphore_signal(sema); }]; dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + if (exception) { + @throw exception; + } if (!bundle) { @throw [NSException exceptionWithName:InvalidVersionException diff --git a/src/Storage/TSStorageManager+keyingMaterial.h b/src/Storage/TSStorageManager+keyingMaterial.h index e87729898..580eff4b5 100644 --- a/src/Storage/TSStorageManager+keyingMaterial.h +++ b/src/Storage/TSStorageManager+keyingMaterial.h @@ -35,10 +35,11 @@ */ - (NSString *)localNumber; + (NSString *)localNumber; -- (void)runIfHasLocalNumber:(void (^)())block; + +- (void)ifLocalNumberPresent:(BOOL)isPresent runAsync:(void (^)())block; + (void)storeServerToken:(NSString *)authToken signalingKey:(NSString *)signalingKey; -+ (void)storePhoneNumber:(NSString *)phoneNumber; +- (void)storePhoneNumber:(NSString *)phoneNumber; @end diff --git a/src/Storage/TSStorageManager+keyingMaterial.m b/src/Storage/TSStorageManager+keyingMaterial.m index 06354c39b..e0be87119 100644 --- a/src/Storage/TSStorageManager+keyingMaterial.m +++ b/src/Storage/TSStorageManager+keyingMaterial.m @@ -20,15 +20,30 @@ return [self stringForKey:TSStorageRegisteredNumberKey inCollection:TSStorageUserAccountCollection]; } -- (void)runIfHasLocalNumber:(void (^)())block +- (void)ifLocalNumberPresent:(BOOL)runIfPresent runAsync:(void (^)())block; { - [self.newDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - if ([transaction objectForKey:TSStorageRegisteredNumberKey inCollection:TSStorageUserAccountCollection]) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + __block BOOL isPresent; + [self.newDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { + isPresent = [[transaction objectForKey:TSStorageRegisteredNumberKey + inCollection:TSStorageUserAccountCollection] boolValue]; + }]; + + if (isPresent == runIfPresent) { + if (runIfPresent) { + DDLogDebug(@"%@ Running existing-user block", self.logTag); + } else { + DDLogDebug(@"%@ Running new-user block", self.logTag); + } block(); } else { - DDLogDebug(@"%@ Skipping block since no local number is registered", self.logTag); + if (runIfPresent) { + DDLogDebug(@"%@ Skipping existing-user block for new-user", self.logTag); + } else { + DDLogDebug(@"%@ Skipping new-user block for existing-user", self.logTag); + } } - }]; + }); } + (NSString *)signalingKey { @@ -39,13 +54,12 @@ return [[self sharedManager] stringForKey:TSStorageServerAuthToken inCollection:TSStorageUserAccountCollection]; } -+ (void)storePhoneNumber:(NSString *)phoneNumber { - YapDatabaseConnection *dbConn = [[self sharedManager] dbConnection]; - - [dbConn readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [transaction setObject:phoneNumber - forKey:TSStorageRegisteredNumberKey - inCollection:TSStorageUserAccountCollection]; +- (void)storePhoneNumber:(NSString *)phoneNumber +{ + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [transaction setObject:phoneNumber + forKey:TSStorageRegisteredNumberKey + inCollection:TSStorageUserAccountCollection]; }]; } diff --git a/src/TSConstants.h b/src/TSConstants.h index 0c6631184..33669234d 100644 --- a/src/TSConstants.h +++ b/src/TSConstants.h @@ -40,10 +40,6 @@ typedef enum { kSMSVerification, kPhoneNumberVerification } VerificationTranspor #define textSecureDeviceProvisioningAPIFormat @"v1/provisioning/%@" #define textSecureDevicesAPIFormat @"v1/devices/%@" -typedef void (^successCompletionBlock)(void); -typedef void (^failedRegistrationRequestBlock)(void); - - #pragma mark Push RegistrationSpecific Constants typedef NS_ENUM(NSInteger, TSPushRegistrationError) { TSPushRegistrationErrorNetwork, diff --git a/src/Util/OWSError.h b/src/Util/OWSError.h index 746df5e88..9e921487c 100644 --- a/src/Util/OWSError.h +++ b/src/Util/OWSError.h @@ -13,7 +13,8 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) { OWSErrorCodePrivacyVerificationFailure = 20, OWSErrorCodeUntrustedIdentityKey = 25, OWSErrorCodeFailedToSendOutgoingMessage = 30, - OWSErrorCodeFailedToDecryptMessage = 100 + OWSErrorCodeFailedToDecryptMessage = 100, + OWSErrorCodeUserError = 2001, }; extern NSError *OWSErrorWithCodeDescription(OWSErrorCode code, NSString *description); diff --git a/tests/Contacts/SignalRecipientTest.m b/tests/Contacts/SignalRecipientTest.m index 32c96470e..d6bf20a48 100644 --- a/tests/Contacts/SignalRecipientTest.m +++ b/tests/Contacts/SignalRecipientTest.m @@ -7,39 +7,41 @@ @interface SignalRecipientTest : XCTestCase +@property (nonatomic) NSString *localNumber; + @end @implementation SignalRecipientTest -- (void)setUp { +- (void)setUp +{ [super setUp]; - [TSStorageManager storePhoneNumber:@"+13231231234"]; + self.localNumber = @"+13231231234"; + [[TSStorageManager sharedManager] storePhoneNumber:self.localNumber]; } - (void)testSelfRecipientWithExistingRecord { // Sanity Check - NSString *localNumber = @"+13231231234"; - XCTAssertNotNil(localNumber); - [[[SignalRecipient alloc] initWithTextSecureIdentifier:localNumber relay:nil supportsVoice:YES] save]; - XCTAssertNotNil([SignalRecipient recipientWithTextSecureIdentifier:localNumber]); + XCTAssertNotNil(self.localNumber); + [[[SignalRecipient alloc] initWithTextSecureIdentifier:self.localNumber relay:nil supportsVoice:YES] save]; + XCTAssertNotNil([SignalRecipient recipientWithTextSecureIdentifier:self.localNumber]); SignalRecipient *me = [SignalRecipient selfRecipient]; XCTAssert(me); - XCTAssertEqualObjects(localNumber, me.uniqueId); + XCTAssertEqualObjects(self.localNumber, me.uniqueId); } - (void)testSelfRecipientWithoutExistingRecord { - NSString *localNumber = @"+13231231234"; - XCTAssertNotNil(localNumber); - [[SignalRecipient fetchObjectWithUniqueID:localNumber] remove]; + XCTAssertNotNil(self.localNumber); + [[SignalRecipient fetchObjectWithUniqueID:self.localNumber] remove]; // Sanity Check that there's no existing user. - XCTAssertNil([SignalRecipient recipientWithTextSecureIdentifier:localNumber]); + XCTAssertNil([SignalRecipient recipientWithTextSecureIdentifier:self.localNumber]); SignalRecipient *me = [SignalRecipient selfRecipient]; XCTAssert(me); - XCTAssertEqualObjects(localNumber, me.uniqueId); + XCTAssertEqualObjects(self.localNumber, me.uniqueId); } @end diff --git a/tests/Messages/OWSMessageSenderTest.m b/tests/Messages/OWSMessageSenderTest.m index 569f84554..2e5d050e3 100644 --- a/tests/Messages/OWSMessageSenderTest.m +++ b/tests/Messages/OWSMessageSenderTest.m @@ -188,7 +188,7 @@ NS_ASSUME_NONNULL_BEGIN [super setUp]; // Hack to make sure we don't explode when sending sync message. - [TSStorageManager storePhoneNumber:@"+13231231234"]; + [[TSStorageManager sharedManager] storePhoneNumber:@"+13231231234"]; self.thread = [[TSContactThread alloc] initWithUniqueId:@"fake-thread-id"]; [self.thread save];