Add re-registration UI.

This commit is contained in:
Matthew Chen 2018-06-18 10:54:06 -04:00
parent fc4763673f
commit bc6a4ea8d8
7 changed files with 239 additions and 50 deletions

View File

@ -24,14 +24,6 @@
NS_ASSUME_NONNULL_BEGIN
@interface TSAccountManager (DebugUI)
- (void)resetForRegistration;
@end
#pragma mark -
@interface OWSStorage (DebugUI)
- (NSData *)databasePassword;
@ -147,7 +139,12 @@ NS_ASSUME_NONNULL_BEGIN
+ (void)reregister
{
DDLogInfo(@"%@ re-registering.", self.logTag);
[[TSAccountManager sharedInstance] resetForRegistration];
if (![[TSAccountManager sharedInstance] resetForReregistration]) {
OWSFail(@"%@ could not reset for re-registration.", self.logTag);
return;
}
[[Environment current].preferences unsetRecordedAPNSTokens];
RegistrationViewController *viewController = [RegistrationViewController new];

View File

@ -5,12 +5,14 @@
#import "HomeViewController.h"
#import "AppDelegate.h"
#import "AppSettingsViewController.h"
#import "CodeVerificationViewController.h"
#import "HomeViewCell.h"
#import "NewContactThreadViewController.h"
#import "OWSNavigationController.h"
#import "OWSPrimaryStorage.h"
#import "ProfileViewController.h"
#import "PushManager.h"
#import "RegistrationViewController.h"
#import "Signal-Swift.h"
#import "SignalApp.h"
#import "TSAccountManager.h"
@ -210,11 +212,12 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
[SignalApp.sharedApp setHomeViewController:self];
}
__weak HomeViewController *weakSelf = self;
ReminderView *deregisteredView =
[ReminderView nagWithText:NSLocalizedString(@"INBOX_VIEW_DEREGISTRATION_WARNING",
[ReminderView nagWithText:NSLocalizedString(@"DEREGISTRATION_WARNING",
@"Label warning the user that they have been de-registered.")
tapAction:^{
// TODO:
[weakSelf showReRegistrationUI];
}];
[self.view addSubview:deregisteredView];
[deregisteredView autoPinWidthToSuperview];
@ -1407,6 +1410,80 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
_emptyBoxLabel.attributedText = fullLabelString;
}
- (void)showReRegistrationUI
{
UIAlertController *actionSheetController =
[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
__weak HomeViewController *weakSelf = self;
[actionSheetController
addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"DEREGISTRATION_REREGISTER_WITH_SAME_PHONE_NUMBER",
@"Label for button that lets users re-register using the same phone number.")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *action) {
[weakSelf reregisterWithSamePhoneNumber];
}]];
[actionSheetController addAction:[OWSAlerts cancelAction]];
[self presentViewController:actionSheetController animated:YES completion:nil];
}
- (void)reregisterWithSamePhoneNumber
{
DDLogInfo(@"%@ reregisterWithSamePhoneNumber.", self.logTag);
if (![[TSAccountManager sharedInstance] resetForReregistration]) {
OWSFail(@"%@ could not reset for re-registration.", self.logTag);
return;
}
[[Environment current].preferences unsetRecordedAPNSTokens];
[ModalActivityIndicatorViewController
presentFromViewController:self
canCancel:NO
backgroundBlock:^(ModalActivityIndicatorViewController *modalActivityIndicator) {
[TSAccountManager
registerWithPhoneNumber:[TSAccountManager sharedInstance].reregisterationPhoneNumber
success:^{
DDLogInfo(@"%@ re-registering: send verification code succeeded.", self.logTag);
dispatch_async(dispatch_get_main_queue(), ^{
[modalActivityIndicator dismissWithCompletion:^{
CodeVerificationViewController *viewController =
[CodeVerificationViewController new];
OWSNavigationController *navigationController =
[[OWSNavigationController alloc] initWithRootViewController:viewController];
navigationController.navigationBarHidden = YES;
[UIApplication sharedApplication].delegate.window.rootViewController
= navigationController;
}];
});
}
failure:^(NSError *error) {
DDLogError(@"%@ re-registering: send verification code failed.", self.logTag);
dispatch_async(dispatch_get_main_queue(), ^{
[modalActivityIndicator dismissWithCompletion:^{
if (error.code == 400) {
[OWSAlerts showAlertWithTitle:NSLocalizedString(@"REGISTRATION_ERROR", nil)
message:NSLocalizedString(
@"REGISTRATION_NON_VALID_NUMBER", nil)];
} else {
[OWSAlerts showAlertWithTitle:error.localizedDescription
message:error.localizedRecoverySuggestion];
}
}];
});
}
smsVerification:YES];
}];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -112,16 +112,25 @@ NS_ASSUME_NONNULL_BEGIN
[titleLabel autoSetDimension:ALDimensionHeight toSize:40];
[titleLabel autoHCenterInSuperview];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton
setTitle:NSLocalizedString(@"VERIFICATION_BACK_BUTTON", @"button text for back button on verification view")
forState:UIControlStateNormal];
[backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
backButton.titleLabel.font = [UIFont ows_mediumFontWithSize:14.f];
[header addSubview:backButton];
[backButton autoPinLeadingToSuperviewMarginWithInset:10.f];
[backButton autoAlignAxis:ALAxisHorizontal toSameAxisOfView:titleLabel];
[backButton addTarget:self action:@selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
// This view is used in more than one context.
//
// * Usually, it is pushed atop RegistrationViewController in which
// case we want a "back" button.
// * It can also be used to re-register from the app's "de-registration"
// views, in which case RegistrationViewController is not used and we
// do _not_ want a "back" button.
if (self.navigationController.viewControllers.count > 1) {
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton
setTitle:NSLocalizedString(@"VERIFICATION_BACK_BUTTON", @"button text for back button on verification view")
forState:UIControlStateNormal];
[backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
backButton.titleLabel.font = [UIFont ows_mediumFontWithSize:14.f];
[header addSubview:backButton];
[backButton autoPinLeadingToSuperviewMarginWithInset:10.f];
[backButton autoAlignAxis:ALAxisHorizontal toSameAxisOfView:titleLabel];
[backButton addTarget:self action:@selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
}
_phoneNumberLabel = [UILabel new];
_phoneNumberLabel.textColor = [UIColor ows_darkGrayColor];

View File

@ -278,6 +278,61 @@ NSString *const kKeychainKey_LastRegisteredPhoneNumber = @"kKeychainKey_LastRegi
[self.activateButton setEnabled:YES];
[self.spinnerView stopAnimating];
[self.phoneNumberTextField becomeFirstResponder];
if ([TSAccountManager sharedInstance].isReregistering) {
// If re-registering, pre-populate the country (country code, calling code, country name)
// and phone number state.
NSString *_Nullable phoneNumberE164 = [TSAccountManager sharedInstance].reregisterationPhoneNumber;
if (!phoneNumberE164) {
OWSFail(@"%@ Could not resume re-registration; missing phone number.", self.logTag);
} else if ([self tryToApplyPhoneNumberE164:phoneNumberE164]) {
// Don't let user edit their phone number while re-registering.
self.phoneNumberTextField.enabled = NO;
}
}
}
- (BOOL)tryToApplyPhoneNumberE164:(NSString *)phoneNumberE164
{
OWSAssert(phoneNumberE164);
if (phoneNumberE164.length < 1) {
OWSFail(@"%@ Could not resume re-registration; invalid phoneNumberE164.", self.logTag);
return NO;
}
PhoneNumber *_Nullable parsedPhoneNumber = [PhoneNumber phoneNumberFromE164:phoneNumberE164];
if (!parsedPhoneNumber) {
OWSFail(@"%@ Could not resume re-registration; couldn't parse phoneNumberE164.", self.logTag);
return NO;
}
NSNumber *_Nullable callingCode = parsedPhoneNumber.getCountryCode;
if (!callingCode) {
OWSFail(@"%@ Could not resume re-registration; missing callingCode.", self.logTag);
return NO;
}
NSString *callingCodeText = [NSString stringWithFormat:@"+%d", callingCode.intValue];
NSArray<NSString *> *_Nullable countryCodes =
[PhoneNumberUtil.sharedThreadLocal countryCodesFromCallingCode:callingCodeText];
if (countryCodes.count < 1) {
OWSFail(@"%@ Could not resume re-registration; unknown countryCode.", self.logTag);
return NO;
}
NSString *countryCode = countryCodes.firstObject;
NSString *_Nullable countryName = [PhoneNumberUtil countryNameFromCountryCode:countryCode];
if (!countryName) {
OWSFail(@"%@ Could not resume re-registration; unknown countryName.", self.logTag);
return NO;
}
if (![phoneNumberE164 hasPrefix:callingCodeText]) {
OWSFail(@"%@ Could not resume re-registration; non-matching calling code.", self.logTag);
return NO;
}
NSString *phoneNumberWithoutCallingCode = [phoneNumberE164 substringFromIndex:callingCodeText.length];
[self updateCountryWithName:countryName callingCode:callingCodeText countryCode:countryCode];
self.phoneNumberTextField.text = phoneNumberWithoutCallingCode;
return YES;
}
#pragma mark - Country
@ -385,6 +440,11 @@ NSString *const kKeychainKey_LastRegisteredPhoneNumber = @"kKeychainKey_LastRegi
- (void)countryCodeRowWasTapped:(UIGestureRecognizer *)sender
{
if (TSAccountManager.sharedInstance.isReregistering) {
// Don't let user edit their phone number while re-registering.
return;
}
if (sender.state == UIGestureRecognizerStateRecognized) {
[self changeCountryCodeTapped];
}

View File

@ -647,6 +647,12 @@
/* Title of the alert before redirecting to GitHub Issues. */
"DEBUG_LOG_GITHUB_ISSUE_ALERT_TITLE" = "GitHub Redirection";
/* Label for button that lets users re-register using the same phone number. */
"DEREGISTRATION_REREGISTER_WITH_SAME_PHONE_NUMBER" = "Re-register this phone number";
/* Label warning the user that they have been de-registered. */
"DEREGISTRATION_WARNING" = "Device no longer registered! This is likely because you registered your phone number with Signal on a different device. Tap to re-register.";
/* {{Short Date}} when device last communicated with Signal Server. */
"DEVICE_LAST_ACTIVE_AT_LABEL" = "Last active: %@";
@ -1022,9 +1028,6 @@
/* Label reminding the user that they are in archive mode. */
"INBOX_VIEW_ARCHIVE_MODE_REMINDER" = "These conversations are archived. They will appear in the inbox if new messages are received.";
/* Label warning the user that they have been de-registered. */
"INBOX_VIEW_DEREGISTRATION_WARNING" = "You are not logged in. Another device may have been registered with your phone number.";
/* Multi-line label explaining how to show names instead of phone numbers in your inbox */
"INBOX_VIEW_MISSING_CONTACTS_PERMISSION" = "To see the names of your contacts, update your system settings to allow contact access.";

View File

@ -18,10 +18,7 @@ extern NSString *const kNSNotificationName_LocalNumberDidChange;
@interface TSAccountManager : NSObject
// This property is exposed for testing purposes only.
#ifdef DEBUG
@property (nonatomic, nullable) NSString *phoneNumberAwaitingVerification;
#endif
@property (nonatomic, nullable, readonly) NSString *phoneNumberAwaitingVerification;
#pragma mark - Initializers
@ -117,12 +114,22 @@ extern NSString *const kNSNotificationName_LocalNumberDidChange;
+ (void)unregisterTextSecureWithSuccess:(void (^)(void))success failure:(void (^)(NSError *error))failureBlock;
#pragma mark - Deregistration
#pragma mark - De-Registration
// De-registration reflects whether or not the service has received a 403
// De-registration reflects whether or not the client has received
// a 403 from the service.
- (BOOL)isDeregistered;
- (void)setIsDeregistered:(BOOL)isDeregistered;
#pragma mark - Re-registration
// Re-registration is the process of re-registering _with the same phone number_.
// Returns YES on success.
- (BOOL)resetForReregistration;
- (NSString *)reregisterationPhoneNumber;
- (BOOL)isReregistering;
@end
NS_ASSUME_NONNULL_END

View File

@ -29,6 +29,7 @@ NSString *const kNSNotificationName_LocalNumberDidChange = @"kNSNotificationName
NSString *const TSAccountManager_RegisteredNumberKey = @"TSStorageRegisteredNumberKey";
NSString *const TSAccountManager_IsDeregisteredKey = @"TSAccountManager_IsDeregisteredKey";
NSString *const TSAccountManager_ReregisteringPhoneNumberKey = @"TSAccountManager_ReregisteringPhoneNumberKey";
NSString *const TSAccountManager_LocalRegistrationIdKey = @"TSStorageLocalRegistrationId";
NSString *const TSAccountManager_UserAccountCollection = @"TSStorageUserAccountCollection";
@ -39,10 +40,7 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling
@property (nonatomic, readonly) BOOL isRegistered;
// This property is exposed publicly for testing purposes only.
#ifndef DEBUG
@property (nonatomic, nullable) NSString *phoneNumberAwaitingVerification;
#endif
@property (nonatomic, nullable) NSString *cachedLocalNumber;
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
@ -75,6 +73,10 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling
selector:@selector(yapDatabaseModifiedExternally:)
name:YapDatabaseModifiedExternallyNotification
object:nil];
self.phoneNumberAwaitingVerification =
[self.dbConnection stringForKey:TSAccountManager_ReregisteringPhoneNumberKey
inCollection:TSAccountManager_UserAccountCollection];
}
return self;
@ -106,22 +108,6 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling
userInfo:nil];
}
- (void)resetForRegistration
{
@synchronized(self)
{
_isRegistered = NO;
_cachedLocalNumber = nil;
_phoneNumberAwaitingVerification = nil;
_cachedIsDeregistered = nil;
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
[transaction removeAllObjectsInCollection:TSAccountManager_UserAccountCollection];
[[OWSPrimaryStorage sharedManager] resetSessionStore:transaction];
}];
}
}
+ (BOOL)isRegistered
{
return [[self sharedInstance] isRegistered];
@ -198,6 +184,11 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling
[self.dbConnection setObject:localNumber
forKey:TSAccountManager_RegisteredNumberKey
inCollection:TSAccountManager_UserAccountCollection];
[self.dbConnection removeObjectForKey:TSAccountManager_ReregisteringPhoneNumberKey
inCollection:TSAccountManager_UserAccountCollection];
self.phoneNumberAwaitingVerification = nil;
}
}
@ -531,7 +522,7 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling
}
}
#pragma mark - Deregistration
#pragma mark - De-Registration
- (BOOL)isDeregistered
{
@ -571,6 +562,51 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling
userInfo:nil];
}
#pragma mark - Re-registration
- (BOOL)resetForReregistration
{
@synchronized(self) {
NSString *_Nullable localNumber = self.localNumber;
if (!localNumber) {
OWSFail(@"%@ can't re-register without valid local number.", self.logTag);
return NO;
}
_isRegistered = NO;
_cachedLocalNumber = nil;
_phoneNumberAwaitingVerification = nil;
_cachedIsDeregistered = nil;
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction removeAllObjectsInCollection:TSAccountManager_UserAccountCollection];
[[OWSPrimaryStorage sharedManager] resetSessionStore:transaction];
[transaction setObject:localNumber
forKey:TSAccountManager_ReregisteringPhoneNumberKey
inCollection:TSAccountManager_UserAccountCollection];
}];
return YES;
}
}
- (NSString *)reregisterationPhoneNumber
{
OWSAssert([self isReregistering]);
NSString *_Nullable result = [self.dbConnection stringForKey:TSAccountManager_ReregisteringPhoneNumberKey
inCollection:TSAccountManager_UserAccountCollection];
OWSAssert(result);
return result;
}
- (BOOL)isReregistering
{
return nil !=
[self.dbConnection stringForKey:TSAccountManager_ReregisteringPhoneNumberKey
inCollection:TSAccountManager_UserAccountCollection];
}
@end
NS_ASSUME_NONNULL_END