From baf6fcc535ed935b637c334ea821a03e42331114 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 1 Mar 2018 14:42:54 -0500 Subject: [PATCH 1/3] Add 2FA registration view. --- Signal.xcodeproj/project.pbxproj | 6 + Signal/src/Models/AccountManager.swift | 34 +- .../CodeVerificationViewController.m | 40 ++- .../ConversationViewController.m | 2 +- .../OWS2FARegistrationViewController.h | 15 + .../OWS2FARegistrationViewController.m | 291 ++++++++++++++++++ .../OWS2FASettingsViewController.m | 62 +--- .../ViewControllers/ProfileViewController.m | 4 +- Signal/src/util/NumberUtil.m | 6 +- .../translations/en.lproj/Localizable.strings | 27 +- .../contacts/ViewControllerUtils.h | 7 + .../contacts/ViewControllerUtils.m | 42 ++- SignalMessaging/views/OWSAlerts.swift | 6 +- .../src/Account/TSAccountManager.h | 1 + .../src/Account/TSAccountManager.m | 19 +- .../API/Requests/TSVerifyCodeRequest.h | 11 +- .../API/Requests/TSVerifyCodeRequest.m | 18 +- SignalServiceKit/src/Util/Cryptography.m | 4 +- SignalServiceKit/src/Util/OWSError.h | 3 +- 19 files changed, 489 insertions(+), 109 deletions(-) create mode 100644 Signal/src/ViewControllers/OWS2FARegistrationViewController.h create mode 100644 Signal/src/ViewControllers/OWS2FARegistrationViewController.m diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 9d17a0c6d..bc28411d8 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -131,6 +131,7 @@ 347E0B7B2003CD7500BC2F76 /* OWSBackupImportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 347E0B782003CD7400BC2F76 /* OWSBackupImportViewController.m */; }; 3497DBEC1ECE257500DB2605 /* OWSCountryMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 3497DBEB1ECE257500DB2605 /* OWSCountryMetadata.m */; }; 3497DBEF1ECE2E4700DB2605 /* DomainFrontingCountryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3497DBEE1ECE2E4700DB2605 /* DomainFrontingCountryViewController.m */; }; + 34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */; }; 34A910601FFEB114000C4745 /* OWSBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A9105F1FFEB114000C4745 /* OWSBackup.m */; }; 34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B0796B1FCF46B000E248C2 /* MainAppContext.m */; }; 34B3F8711E8DF1700035BE1A /* AboutTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8351E8DF1700035BE1A /* AboutTableViewController.m */; }; @@ -656,6 +657,8 @@ 3497DBEB1ECE257500DB2605 /* OWSCountryMetadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSCountryMetadata.m; sourceTree = ""; }; 3497DBED1ECE2E4700DB2605 /* DomainFrontingCountryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DomainFrontingCountryViewController.h; sourceTree = ""; }; 3497DBEE1ECE2E4700DB2605 /* DomainFrontingCountryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DomainFrontingCountryViewController.m; sourceTree = ""; }; + 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS2FARegistrationViewController.m; sourceTree = ""; }; + 34A55F3620485464002CC6DE /* OWS2FARegistrationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS2FARegistrationViewController.h; sourceTree = ""; }; 34A9105E1FFEB113000C4745 /* OWSBackup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackup.h; sourceTree = ""; }; 34A9105F1FFEB114000C4745 /* OWSBackup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackup.m; sourceTree = ""; }; 34B0796B1FCF46B000E248C2 /* MainAppContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainAppContext.m; sourceTree = ""; }; @@ -1472,6 +1475,8 @@ 34B3F8571E8DF1700035BE1A /* NotificationSettingsOptionsViewController.m */, 34B3F8581E8DF1700035BE1A /* NotificationSettingsViewController.h */, 34B3F8591E8DF1700035BE1A /* NotificationSettingsViewController.m */, + 34A55F3620485464002CC6DE /* OWS2FARegistrationViewController.h */, + 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */, 345BC30A2047030600257B7C /* OWS2FASettingsViewController.h */, 345BC30B2047030600257B7C /* OWS2FASettingsViewController.m */, 34CCAF391F0C2748004084F4 /* OWSAddToContactViewController.h */, @@ -3041,6 +3046,7 @@ 34B3F88F1E8DF1710035BE1A /* RegistrationViewController.m in Sources */, 451166C01FD86B98000739BA /* AccountManager.swift in Sources */, 3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */, + 34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */, 34B3F8901E8DF1710035BE1A /* AppSettingsViewController.m in Sources */, 34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */, 34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */, diff --git a/Signal/src/Models/AccountManager.swift b/Signal/src/Models/AccountManager.swift index 191eace3a..c9c344621 100644 --- a/Signal/src/Models/AccountManager.swift +++ b/Signal/src/Models/AccountManager.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // import Foundation @@ -34,11 +34,13 @@ class AccountManager: NSObject { // MARK: registration - @objc func register(verificationCode: String) -> AnyPromise { - return AnyPromise(register(verificationCode: verificationCode)) + @objc func register(verificationCode: String, + pin: String?) -> AnyPromise { + return AnyPromise(register(verificationCode: verificationCode, pin: pin)) } - func register(verificationCode: String) -> Promise { + func register(verificationCode: String, + pin: String?) -> Promise { guard verificationCode.count > 0 else { let error = OWSErrorWithCodeDescription(.userError, NSLocalizedString("REGISTRATION_ERROR_BLANK_VERIFICATION_CODE", @@ -48,7 +50,7 @@ class AccountManager: NSObject { Logger.debug("\(self.TAG) registering with signal server") let registrationPromise: Promise = firstly { - self.registerForTextSecure(verificationCode: verificationCode) + self.registerForTextSecure(verificationCode: verificationCode, pin: pin) }.then { self.syncPushTokens() }.recover { (error) -> Promise in @@ -71,11 +73,13 @@ class AccountManager: NSObject { return registrationPromise } - private func registerForTextSecure(verificationCode: String) -> Promise { + private func registerForTextSecure(verificationCode: String, + pin: String?) -> Promise { return Promise { fulfill, reject in - self.textSecureAccountManager.verifyAccount(withCode:verificationCode, - success:fulfill, - failure:reject) + self.textSecureAccountManager.verifyAccount(withCode: verificationCode, + pin: pin, + success: fulfill, + failure: reject) } } @@ -95,16 +99,16 @@ class AccountManager: NSObject { func updatePushTokens(pushToken: String, voipToken: String) -> Promise { return Promise { fulfill, reject in - self.textSecureAccountManager.registerForPushNotifications(pushToken:pushToken, - voipToken:voipToken, - success:fulfill, - failure:reject) + self.textSecureAccountManager.registerForPushNotifications(pushToken: pushToken, + voipToken: voipToken, + success: fulfill, + failure: reject) } } func registerForManualMessageFetching() -> Promise { return Promise { fulfill, reject in - self.textSecureAccountManager.registerForManualMessageFetching(success:fulfill, failure:reject) + self.textSecureAccountManager.registerForManualMessageFetching(success: fulfill, failure: reject) } } @@ -119,7 +123,7 @@ class AccountManager: NSObject { } if let responseDictionary = responseObject as? [String: AnyObject] { - if let turnServerInfo = TurnServerInfo(attributes:responseDictionary) { + if let turnServerInfo = TurnServerInfo(attributes: responseDictionary) { return fulfill(turnServerInfo) } Logger.error("\(self.TAG) unexpected server response:\(responseDictionary)") diff --git a/Signal/src/ViewControllers/CodeVerificationViewController.m b/Signal/src/ViewControllers/CodeVerificationViewController.m index 0c0697147..972b2175a 100644 --- a/Signal/src/ViewControllers/CodeVerificationViewController.m +++ b/Signal/src/ViewControllers/CodeVerificationViewController.m @@ -1,12 +1,13 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "CodeVerificationViewController.h" +#import "OWS2FARegistrationViewController.h" #import "ProfileViewController.h" #import "Signal-Swift.h" -#import "UIViewController+OWS.h" #import +#import #import #import #import @@ -65,7 +66,13 @@ NS_ASSUME_NONNULL_BEGIN - (void)viewDidLoad { [super viewDidLoad]; - + + self.navigationItem.backBarButtonItem = + [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"BACK_BUTTON", @"button text for back button") + style:UIBarButtonItemStylePlain + target:self + action:@selector(backButtonWasPressed)]; + [self createViews]; [self initializeKeyboardHandlers]; @@ -259,7 +266,7 @@ NS_ASSUME_NONNULL_BEGIN [self startActivityIndicator]; OWSProdInfo([OWSAnalyticsEvents registrationRegisteringCode]); __weak CodeVerificationViewController *weakSelf = self; - [self.accountManager registerWithVerificationCode:[self validationCodeFromTextField]] + [self.accountManager registerWithVerificationCode:[self validationCodeFromTextField] pin:nil] .then(^{ OWSProdInfo([OWSAnalyticsEvents registrationRegisteringSubmittedCode]); @@ -269,13 +276,27 @@ NS_ASSUME_NONNULL_BEGIN [weakSelf vericationWasCompleted]; }); }) - .catch(^(NSError *_Nonnull error) { + .catch(^(NSError *error) { + DDLogError(@"%@ error: %@, %@, %zd", weakSelf.logTag, [error class], error.domain, error.code); OWSProdInfo([OWSAnalyticsEvents registrationRegistrationFailed]); DDLogError(@"%@ error verifying challenge: %@", weakSelf.logTag, error); dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf stopActivityIndicator]; - [weakSelf presentAlertWithVerificationError:error]; - [weakSelf.challengeTextField becomeFirstResponder]; + + if ([error.domain isEqualToString:OWSSignalServiceKitErrorDomain] + && error.code == OWSErrorCodeRegistrationMissing2FAPIN) { + CodeVerificationViewController *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + DDLogInfo(@"%@ Showing 2FA registration view.", strongSelf.logTag); + OWS2FARegistrationViewController *viewController = [OWS2FARegistrationViewController new]; + viewController.verificationCode = strongSelf.validationCodeFromTextField; + [strongSelf.navigationController pushViewController:viewController animated:YES]; + } else { + [weakSelf presentAlertWithVerificationError:error]; + [weakSelf.challengeTextField becomeFirstResponder]; + } }); }); } @@ -471,6 +492,11 @@ NS_ASSUME_NONNULL_BEGIN [self submitVerificationCode]; } +- (void)backButtonWasPressed +{ + [self.navigationController popViewControllerAnimated:YES]; +} + @end NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index a84559528..67b5ffb36 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -42,7 +42,6 @@ #import "TSInfoMessage.h" #import "TSInvalidIdentityKeyErrorMessage.h" #import "UIFont+OWS.h" -#import "UIViewController+OWS.h" #import "UIViewController+Permissions.h" #import "ViewControllerUtils.h" #import @@ -68,6 +67,7 @@ #import #import #import +#import #import #import #import diff --git a/Signal/src/ViewControllers/OWS2FARegistrationViewController.h b/Signal/src/ViewControllers/OWS2FARegistrationViewController.h new file mode 100644 index 000000000..2b6bcd050 --- /dev/null +++ b/Signal/src/ViewControllers/OWS2FARegistrationViewController.h @@ -0,0 +1,15 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface OWS2FARegistrationViewController : OWSViewController + +@property (nonatomic) NSString *verificationCode; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/OWS2FARegistrationViewController.m b/Signal/src/ViewControllers/OWS2FARegistrationViewController.m new file mode 100644 index 000000000..21f0cca11 --- /dev/null +++ b/Signal/src/ViewControllers/OWS2FARegistrationViewController.m @@ -0,0 +1,291 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +#import "OWS2FARegistrationViewController.h" +#import "ProfileViewController.h" +#import "Signal-Swift.h" +#import +#import +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface OWS2FARegistrationViewController () + +@property (nonatomic, readonly) AccountManager *accountManager; + +@property (nonatomic) UITextField *pinTextfield; + +@property (nonatomic) OWSFlatButton *submitButton; + +@end + +#pragma mark - + +@implementation OWS2FARegistrationViewController + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if (!self) { + return self; + } + + _accountManager = SignalApp.sharedApp.accountManager; + + return self; +} + +- (instancetype)init +{ + self = [super init]; + if (!self) { + return self; + } + + _accountManager = SignalApp.sharedApp.accountManager; + + return self; +} + +#pragma mark - View Lifecycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.whiteColor; + + [self createContents]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + [self updateEnabling]; +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + + // If we're using a PIN textfield, select it. + [self.pinTextfield becomeFirstResponder]; +} + +- (UILabel *)createLabelWithText:(NSString *)text +{ + UILabel *label = [UILabel new]; + label.textColor = [UIColor blackColor]; + label.text = text; + label.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(14.f, 16.f)]; + label.numberOfLines = 0; + label.lineBreakMode = NSLineBreakByWordWrapping; + label.textAlignment = NSTextAlignmentCenter; + [self.view addSubview:label]; + return label; +} + +- (void)createPinTextfield +{ + self.pinTextfield = [UITextField new]; + self.pinTextfield.textColor = [UIColor blackColor]; + self.pinTextfield.placeholder + = NSLocalizedString(@"2FA_PIN_DEFAULT_TEXT", @"Text field placeholder when entering a 'two-factor auth pin'."); + self.pinTextfield.font = [UIFont ows_mediumFontWithSize:ScaleFromIPhone5To7Plus(30.f, 36.f)]; + self.pinTextfield.textAlignment = NSTextAlignmentCenter; + self.pinTextfield.keyboardType = UIKeyboardTypeNumberPad; + self.pinTextfield.delegate = self; + self.pinTextfield.secureTextEntry = YES; + self.pinTextfield.textAlignment = NSTextAlignmentCenter; + [self.view addSubview:self.pinTextfield]; +} + +- (UILabel *)createForgotLink +{ + UILabel *label = [UILabel new]; + label.textColor = [UIColor ows_materialBlueColor]; + NSString *text = NSLocalizedString( + @"REGISTER_2FA_FORGOT_PIN", @"Label for 'I forgot my PIN' link in the 2FA registration view."); + label.attributedText = [[NSAttributedString alloc] + initWithString:text + attributes:@{ + NSForegroundColorAttributeName : [UIColor ows_materialBlueColor], + NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) + }]; + label.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(14.f, 16.f)]; + label.numberOfLines = 0; + label.lineBreakMode = NSLineBreakByWordWrapping; + label.textAlignment = NSTextAlignmentCenter; + label.userInteractionEnabled = YES; + [label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(forgotPinLinkTapped:)]]; + [self.view addSubview:label]; + return label; +} + +- (void)createSubmitButton +{ + const CGFloat kSubmitButtonHeight = 47.f; + // NOTE: We use ows_signalBrandBlueColor instead of ows_materialBlueColor + // throughout the onboarding flow to be consistent with the headers. + OWSFlatButton *submitButton = + [OWSFlatButton buttonWithTitle:NSLocalizedString(@"REGISTER_2FA_SUBMIT_BUTTON", + @"Label for 'submit' button in the 2FA registration view.") + font:[OWSFlatButton fontForHeight:kSubmitButtonHeight] + titleColor:[UIColor whiteColor] + backgroundColor:[UIColor ows_signalBrandBlueColor] + target:self + selector:@selector(submitButtonWasPressed)]; + self.submitButton = submitButton; + [self.view addSubview:self.submitButton]; + [self.submitButton autoSetDimension:ALDimensionHeight toSize:kSubmitButtonHeight]; +} + +- (CGFloat)hMargin +{ + return 20.f; +} + +- (void)createContents +{ + const CGFloat kVSpacing = 30.f; + + NSString *instructionsText = NSLocalizedString( + @"REGISTER_2FA_INSTRUCTIONS", @"Instructions to enter the 'two-factor auth pin' in the 2FA registration view."); + UILabel *instructionsLabel = [self createLabelWithText:instructionsText]; + [instructionsLabel autoPinTopToSuperviewWithMargin:kVSpacing]; + [instructionsLabel autoPinWidthToSuperviewWithMargin:self.hMargin]; + + UILabel *createForgotLink = [self createForgotLink]; + [createForgotLink autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:instructionsLabel withOffset:5]; + [createForgotLink autoPinWidthToSuperviewWithMargin:self.hMargin]; + + [self createPinTextfield]; + [self.pinTextfield autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:createForgotLink withOffset:kVSpacing]; + [self.pinTextfield autoPinWidthToSuperviewWithMargin:self.hMargin]; + + UIView *underscoreView = [UIView new]; + underscoreView.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1.f]; + [self.view addSubview:underscoreView]; + [underscoreView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.pinTextfield withOffset:3]; + [underscoreView autoPinWidthToSuperviewWithMargin:self.hMargin]; + [underscoreView autoSetDimension:ALDimensionHeight toSize:1.f]; + + [self createSubmitButton]; + [self.submitButton autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:underscoreView withOffset:kVSpacing]; + [self.submitButton autoPinWidthToSuperviewWithMargin:self.hMargin]; + + [self updateEnabling]; +} + +- (void)updateEnabling +{ + [self.submitButton setEnabled:self.hasValidPin]; +} + +#pragma mark - UITextFieldDelegate + +- (BOOL)textField:(UITextField *)textField + shouldChangeCharactersInRange:(NSRange)range + replacementString:(NSString *)insertionText +{ + + [ViewControllerUtils ows2FAPINTextField:textField + shouldChangeCharactersInRange:range + replacementString:insertionText]; + + [self updateEnabling]; + + return NO; +} + +#pragma mark - Events + +- (void)submitButtonWasPressed +{ + OWSAssert(self.hasValidPin); + + [self tryToRegister]; +} + +- (BOOL)hasValidPin +{ + return self.pinTextfield.text.length >= kMin2FAPinLength; +} + +- (void)tryToRegister +{ + OWSAssert(self.hasValidPin); + OWSAssert(self.verificationCode.length > 0); + NSString *pin = self.pinTextfield.text; + OWSAssert(pin.length > 0); + + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + __weak OWS2FARegistrationViewController *weakSelf = self; + + [ModalActivityIndicatorViewController + presentFromViewController:self + canCancel:NO + backgroundBlock:^(ModalActivityIndicatorViewController *modalActivityIndicator) { + OWSProdInfo([OWSAnalyticsEvents registrationRegisteringCode]); + [self.accountManager registerWithVerificationCode:self.verificationCode pin:pin] + .then(^{ + OWSAssertIsOnMainThread(); + OWSProdInfo([OWSAnalyticsEvents registrationRegisteringSubmittedCode]); + + DDLogInfo(@"%@ Successfully registered Signal account.", weakSelf.logTag); + dispatch_async(dispatch_get_main_queue(), ^{ + [modalActivityIndicator dismissWithCompletion:^{ + OWSAssertIsOnMainThread(); + + [weakSelf vericationWasCompleted]; + }]; + }); + }) + .catch(^(NSError *error) { + OWSAssertIsOnMainThread(); + OWSProdInfo([OWSAnalyticsEvents registrationRegistrationFailed]); + DDLogError(@"%@ error verifying challenge: %@", weakSelf.logTag, error); + dispatch_async(dispatch_get_main_queue(), ^{ + [modalActivityIndicator dismissWithCompletion:^{ + OWSAssertIsOnMainThread(); + + [OWSAlerts + showAlertWithTitle:NSLocalizedString(@"ALERT_ERROR_TITLE", @"") + message:NSLocalizedString(@"REGISTER_2FA_REGISTRATION_FAILED", + @"Error indicating that attempt to register with " + @"'two-factor " + @"auth' failed.")]; + + [weakSelf.pinTextfield becomeFirstResponder]; + }]; + }); + }); + }]; +} + +- (void)vericationWasCompleted +{ + [ProfileViewController presentForRegistration:self.navigationController]; +} + +- (void)forgotPinLinkTapped:(UIGestureRecognizer *)sender +{ + if (sender.state == UIGestureRecognizerStateRecognized) { + [OWSAlerts + showAlertWithTitle:nil + message:NSLocalizedString(@"REGISTER_2FA_FORGOT_PIN_ALERT_MESSAGE", + @"Alert message explaining what happens if you forget your 'two-factor auth pin'.")]; + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/OWS2FASettingsViewController.m b/Signal/src/ViewControllers/OWS2FASettingsViewController.m index 5c9cd5873..979cc0e00 100644 --- a/Signal/src/ViewControllers/OWS2FASettingsViewController.m +++ b/Signal/src/ViewControllers/OWS2FASettingsViewController.m @@ -113,18 +113,8 @@ NS_ASSUME_NONNULL_BEGIN { self.pinTextfield = [UITextField new]; self.pinTextfield.textColor = [UIColor blackColor]; - switch (self.mode) { - case OWS2FASettingsMode_SelectPIN: - self.pinTextfield.placeholder = NSLocalizedString(@"ENABLE_2FA_VIEW_SELECT_PIN_DEFAULT_TEXT", - @"Text field placeholder for 'two factor auth pin' when selecting a pin."); - break; - case OWS2FASettingsMode_ConfirmPIN: - self.pinTextfield.placeholder = NSLocalizedString(@"ENABLE_2FA_VIEW_CONFIRM_PIN_DEFAULT_TEXT", - @"Text field placeholder for 'two factor auth pin' when confirming a pin."); - break; - case OWS2FASettingsMode_Status: - OWSFail(@"%@ invalid mode.", self.logTag) break; - } + self.pinTextfield.placeholder + = NSLocalizedString(@"2FA_PIN_DEFAULT_TEXT", @"Text field placeholder when entering a 'two-factor auth pin'."); self.pinTextfield.font = [UIFont ows_mediumFontWithSize:ScaleFromIPhone5To7Plus(30.f, 36.f)]; self.pinTextfield.textAlignment = NSTextAlignmentCenter; self.pinTextfield.keyboardType = UIKeyboardTypeNumberPad; @@ -203,14 +193,12 @@ NS_ASSUME_NONNULL_BEGIN [self.pinTextfield autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:instructionsLabel withOffset:kVSpacing]; [self.pinTextfield autoPinWidthToSuperviewWithMargin:self.hMargin]; - [self.pinTextfield autoHCenterInSuperview]; UIView *underscoreView = [UIView new]; underscoreView.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1.f]; [self.view addSubview:underscoreView]; [underscoreView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.pinTextfield withOffset:3]; [underscoreView autoPinWidthToSuperviewWithMargin:self.hMargin]; - [underscoreView autoHCenterInSuperview]; [underscoreView autoSetDimension:ALDimensionHeight toSize:1.f]; [self updateNavigationItems]; @@ -269,8 +257,7 @@ NS_ASSUME_NONNULL_BEGIN // view is pushed on top of this one, not how the "back" // button looks when this view is visible. self.navigationItem.backBarButtonItem = - [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"VERIFICATION_BACK_BUTTON", - @"button text for back button on verification view") + [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"BACK_BUTTON", @"button text for back button") style:UIBarButtonItemStylePlain target:self action:@selector(backButtonWasPressed)]; @@ -293,41 +280,9 @@ NS_ASSUME_NONNULL_BEGIN shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)insertionText { - // TODO: ? - const NSUInteger kMaxPinLength = 14; - - // * We only want to let the user enter decimal digits. - // * The user should be able to copy and paste freely. - // * Invalid input should be simply ignored. - // - // We accomplish this by being permissive and trying to "take as much of the user - // input as possible". - // - // * Always accept deletes. - // * Ignore invalid input. - // * Take partial input if possible. - - NSString *oldText = textField.text; - // Construct the new contents of the text field by: - // 1. Determining the "left" substring: the contents of the old text _before_ the deletion range. - // Filtering will remove non-decimal digit characters. - NSString *left = [oldText substringToIndex:range.location].digitsOnly; - // 2. Determining the "right" substring: the contents of the old text _after_ the deletion range. - NSString *right = [oldText substringFromIndex:range.location + range.length].digitsOnly; - // 3. Determining the "center" substring: the contents of the new insertion text. - NSString *center = insertionText.digitsOnly; - // 4. Construct the "raw" new text by concatenating left, center and right. - NSString *textAfterChange = [[left stringByAppendingString:center] stringByAppendingString:right]; - // 5. Ensure we don't exceed the maximum length for a PIN. - if (textAfterChange.length > kMaxPinLength) { - textAfterChange = [textAfterChange substringToIndex:kMaxPinLength]; - } - // 6. Construct the final text. - textField.text = textAfterChange; - NSUInteger cursorPositionAfterChange = MIN(left.length + center.length, textAfterChange.length); - UITextPosition *pos = - [textField positionFromPosition:textField.beginningOfDocument offset:(NSInteger)cursorPositionAfterChange]; - [textField setSelectedTextRange:[textField textRangeFromPosition:pos toPosition:pos]]; + [ViewControllerUtils ows2FAPINTextField:textField + shouldChangeCharactersInRange:range + replacementString:insertionText]; [self updateNavigationItems]; @@ -379,8 +334,7 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)hasValidPin { - const NSUInteger kMinPinLength = 4; - return self.pinTextfield.text.length >= kMinPinLength; + return self.pinTextfield.text.length >= kMin2FAPinLength; } - (void)showEnable2FAWorkUI @@ -470,7 +424,7 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); - [self.navigationController popToViewController:self.root2FAViewController animated:NO]; + [self.navigationController popToViewController:self.root2FAViewController animated:YES]; } - (void)backButtonWasPressed diff --git a/Signal/src/ViewControllers/ProfileViewController.m b/Signal/src/ViewControllers/ProfileViewController.m index 48459054c..fdd7e3222 100644 --- a/Signal/src/ViewControllers/ProfileViewController.m +++ b/Signal/src/ViewControllers/ProfileViewController.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "ProfileViewController.h" @@ -12,9 +12,9 @@ #import "UIColor+OWS.h" #import "UIFont+OWS.h" #import "UIView+OWS.h" -#import "UIViewController+OWS.h" #import #import +#import #import #import diff --git a/Signal/src/util/NumberUtil.m b/Signal/src/util/NumberUtil.m index 1bf02ce2d..4e225c602 100644 --- a/Signal/src/util/NumberUtil.m +++ b/Signal/src/util/NumberUtil.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "NumberUtil.h" @@ -83,7 +83,7 @@ } + (NSUInteger)assertConvertIntToNSUInteger:(int)value { - assert(0 <= value); + OWSAssert(0 <= value); return (NSUInteger)value; } @@ -93,7 +93,7 @@ } + (int)assertConvertNSUIntegerToInt:(NSUInteger)value { - assert(value <= INT32_MAX); + OWSAssert(value <= INT32_MAX); return (int)value; } diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 5299108f8..c1e01f3ea 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -1,3 +1,6 @@ +/* Text field placeholder when entering a 'two-factor auth pin'. */ +"2FA_PIN_DEFAULT_TEXT" = "••••••"; + /* Button text to dismiss missing contacts permission alert */ "AB_PERMISSION_MISSING_ACTION_NOT_NOW" = "Not Now"; @@ -151,6 +154,9 @@ /* action sheet button title to enable built in speaker during a call */ "AUDIO_ROUTE_BUILT_IN_SPEAKER" = "Speaker"; +/* button text for back button */ +"BACK_BUTTON" = "Back"; + /* Message indicating that backup export is complete. */ "BACKUP_EXPORT_COMPLETE_MESSAGE" = "Backup complete."; @@ -643,9 +649,6 @@ /* No comment provided by engineer. */ "EMPTY_INBOX_TITLE" = "Squeaky Freaking Clean."; -/* Text field placeholder for 'two factor auth pin' when confirming a pin. */ -"ENABLE_2FA_VIEW_CONFIRM_PIN_DEFAULT_TEXT" = "••••••"; - /* Indicates that user should confirm their 'two factor auth pin'. */ "ENABLE_2FA_VIEW_CONFIRM_PIN_INSTRUCTIONS" = "Confirm your PIN."; @@ -667,9 +670,6 @@ /* Error indicating that the entered 'two-factor auth PINs' do not match. */ "ENABLE_2FA_VIEW_PIN_DOES_NOT_MATCH" = "Pin does not match."; -/* Text field placeholder for 'two factor auth pin' when selecting a pin. */ -"ENABLE_2FA_VIEW_SELECT_PIN_DEFAULT_TEXT" = "******"; - /* Indicates that user should select a 'two factor auth pin'. */ "ENABLE_2FA_VIEW_SELECT_PIN_INSTRUCTIONS" = "Enter a PIN which you'll be asked for when you register your phone number with Signal. Your PIN must have at least 4 digits."; @@ -1383,6 +1383,21 @@ /* No comment provided by engineer. */ "RATING_TITLE" = "Support Signal!"; +/* Label for 'I forgot my PIN' link in the 2FA registration view. */ +"REGISTER_2FA_FORGOT_PIN" = "I forgot my PIN."; + +/* Alert message explaining what happens if you forget your 'two-factor auth pin'. */ +"REGISTER_2FA_FORGOT_PIN_ALERT_MESSAGE" = "Registration of this phone number will be possible without your Registration Lock PIN after 7 days have passed since the phone number was last active on Signal."; + +/* Instructions to enter the 'two-factor auth pin' in the 2FA registration view. */ +"REGISTER_2FA_INSTRUCTIONS" = "This phone number has Registration Lock enabled. Please enter the Registration Lock PIN.\n\nYour Registration Lock PIN is separate from the automated verification code that was sent to your phone during the last step."; + +/* Error indicating that attempt to register with 'two-factor auth' failed. */ +"REGISTER_2FA_REGISTRATION_FAILED" = "Registration failed."; + +/* Label for 'submit' button in the 2FA registration view. */ +"REGISTER_2FA_SUBMIT_BUTTON" = "Submit"; + /* No comment provided by engineer. */ "REGISTER_CONTACTS_WELCOME" = "Welcome!"; diff --git a/SignalMessaging/contacts/ViewControllerUtils.h b/SignalMessaging/contacts/ViewControllerUtils.h index 630b4041d..168c3d553 100644 --- a/SignalMessaging/contacts/ViewControllerUtils.h +++ b/SignalMessaging/contacts/ViewControllerUtils.h @@ -6,6 +6,9 @@ NS_ASSUME_NONNULL_BEGIN +extern const NSUInteger kMin2FAPinLength; +extern const NSUInteger kMax2FAPinLength; + @interface ViewControllerUtils : NSObject - (instancetype)init NS_UNAVAILABLE; @@ -18,6 +21,10 @@ NS_ASSUME_NONNULL_BEGIN replacementString:(NSString *)insertionText countryCode:(NSString *)countryCode; ++ (void)ows2FAPINTextField:(UITextField *)textField + shouldChangeCharactersInRange:(NSRange)range + replacementString:(NSString *)insertionText; + + (NSString *)examplePhoneNumberForCountryCode:(NSString *)countryCode callingCode:(NSString *)callingCode; @end diff --git a/SignalMessaging/contacts/ViewControllerUtils.m b/SignalMessaging/contacts/ViewControllerUtils.m index 482b593e3..a5808dc4d 100644 --- a/SignalMessaging/contacts/ViewControllerUtils.m +++ b/SignalMessaging/contacts/ViewControllerUtils.m @@ -12,7 +12,9 @@ NS_ASSUME_NONNULL_BEGIN -#pragma mark - +// TODO: ? +const NSUInteger kMin2FAPinLength = 4; +const NSUInteger kMax2FAPinLength = 14; @implementation ViewControllerUtils @@ -74,6 +76,44 @@ NS_ASSUME_NONNULL_BEGIN [textField setSelectedTextRange:[textField textRangeFromPosition:pos toPosition:pos]]; } ++ (void)ows2FAPINTextField:(UITextField *)textField + shouldChangeCharactersInRange:(NSRange)range + replacementString:(NSString *)insertionText +{ + // * We only want to let the user enter decimal digits. + // * The user should be able to copy and paste freely. + // * Invalid input should be simply ignored. + // + // We accomplish this by being permissive and trying to "take as much of the user + // input as possible". + // + // * Always accept deletes. + // * Ignore invalid input. + // * Take partial input if possible. + + NSString *oldText = textField.text; + // Construct the new contents of the text field by: + // 1. Determining the "left" substring: the contents of the old text _before_ the deletion range. + // Filtering will remove non-decimal digit characters. + NSString *left = [oldText substringToIndex:range.location].digitsOnly; + // 2. Determining the "right" substring: the contents of the old text _after_ the deletion range. + NSString *right = [oldText substringFromIndex:range.location + range.length].digitsOnly; + // 3. Determining the "center" substring: the contents of the new insertion text. + NSString *center = insertionText.digitsOnly; + // 4. Construct the "raw" new text by concatenating left, center and right. + NSString *textAfterChange = [[left stringByAppendingString:center] stringByAppendingString:right]; + // 5. Ensure we don't exceed the maximum length for a PIN. + if (textAfterChange.length > kMax2FAPinLength) { + textAfterChange = [textAfterChange substringToIndex:kMax2FAPinLength]; + } + // 6. Construct the final text. + textField.text = textAfterChange; + NSUInteger cursorPositionAfterChange = MIN(left.length + center.length, textAfterChange.length); + UITextPosition *pos = + [textField positionFromPosition:textField.beginningOfDocument offset:(NSInteger)cursorPositionAfterChange]; + [textField setSelectedTextRange:[textField textRangeFromPosition:pos toPosition:pos]]; +} + + (NSString *)examplePhoneNumberForCountryCode:(NSString *)countryCode callingCode:(NSString *)callingCode { OWSAssert(countryCode.length > 0); diff --git a/SignalMessaging/views/OWSAlerts.swift b/SignalMessaging/views/OWSAlerts.swift index 5b39c59d6..c9c161909 100644 --- a/SignalMessaging/views/OWSAlerts.swift +++ b/SignalMessaging/views/OWSAlerts.swift @@ -28,14 +28,12 @@ import Foundation } @objc - public class func showAlert(withTitle title: String, message: String) { + public class func showAlert(withTitle title: String?, message: String) { self.showAlert(withTitle: title, message: message, buttonTitle: nil) } @objc - public class func showAlert(withTitle title: String, message: String? = nil, buttonTitle: String? = nil, buttonAction: ((UIAlertAction) -> Void)? = nil) { - assert(title.count > 0) - + public class func showAlert(withTitle title: String?, message: String? = nil, buttonTitle: String? = nil, buttonAction: ((UIAlertAction) -> Void)? = nil) { let actionTitle = buttonTitle ?? NSLocalizedString("OK", comment: "") let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) diff --git a/SignalServiceKit/src/Account/TSAccountManager.h b/SignalServiceKit/src/Account/TSAccountManager.h index c1b5f44eb..4294fd90b 100644 --- a/SignalServiceKit/src/Account/TSAccountManager.h +++ b/SignalServiceKit/src/Account/TSAccountManager.h @@ -80,6 +80,7 @@ extern NSString *const kNSNotificationName_LocalNumberDidChange; + (void)rerequestVoiceWithSuccess:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock; - (void)verifyAccountWithCode:(NSString *)verificationCode + pin:(nullable NSString *)pin success:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock; diff --git a/SignalServiceKit/src/Account/TSAccountManager.m b/SignalServiceKit/src/Account/TSAccountManager.m index 344f161b9..02de64eb3 100644 --- a/SignalServiceKit/src/Account/TSAccountManager.m +++ b/SignalServiceKit/src/Account/TSAccountManager.m @@ -309,7 +309,7 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling TSAccountManager *manager = [self sharedInstance]; NSString *number = manager.phoneNumberAwaitingVerification; - assert(number); + OWSAssert(number); [self registerWithPhoneNumber:number success:successBlock failure:failureBlock smsVerification:YES]; } @@ -319,7 +319,7 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling TSAccountManager *manager = [self sharedInstance]; NSString *number = manager.phoneNumberAwaitingVerification; - assert(number); + OWSAssert(number); [self registerWithPhoneNumber:number success:successBlock failure:failureBlock smsVerification:NO]; } @@ -340,6 +340,7 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling } - (void)verifyAccountWithCode:(NSString *)verificationCode + pin:(nullable NSString *)pin success:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock { @@ -347,12 +348,13 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling NSString *signalingKey = [[self class] generateNewSignalingKeyToken]; NSString *phoneNumber = self.phoneNumberAwaitingVerification; - assert(signalingKey); - assert(authToken); - assert(phoneNumber); + OWSAssert(signalingKey); + OWSAssert(authToken); + OWSAssert(phoneNumber); TSVerifyCodeRequest *request = [[TSVerifyCodeRequest alloc] initWithVerificationCode:verificationCode forNumber:phoneNumber + pin:pin signalingKey:signalingKey authKey:authToken]; @@ -392,6 +394,13 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling failureBlock(userError); break; } + case 423: { + DDLogError(@"%@ 2FA PIN required: %ld", self.logTag, error.code); + NSError *error = OWSErrorWithCodeDescription( + OWSErrorCodeRegistrationMissing2FAPIN, @"Registration missing 2FA PIN."); + failureBlock(error); + break; + } default: { DDLogError(@"%@ verifying code failed with unhandled error: %@", self.logTag, error); failureBlock(error); diff --git a/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.h b/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.h index 496777be9..4eb9b2678 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.h +++ b/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.h @@ -1,20 +1,21 @@ // -// TSVerifyCodeRequest.h -// TextSecureKit -// -// Created by Frederic Jacobs on 14/11/14. -// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "TSRequest.h" +NS_ASSUME_NONNULL_BEGIN + @interface TSVerifyCodeRequest : TSRequest - (TSRequest *)initWithVerificationCode:(NSString *)verificationCode forNumber:(NSString *)phoneNumber + pin:(nullable NSString *)pin signalingKey:(NSString *)signalingKey authKey:(NSString *)authKey; @property (nonatomic, readonly) NSString *numberToValidate; @end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m b/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m index 309132c74..cb1c53adc 100644 --- a/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m +++ b/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m @@ -7,20 +7,30 @@ #import "TSAttributes.h" #import "TSConstants.h" +NS_ASSUME_NONNULL_BEGIN + @implementation TSVerifyCodeRequest - (TSRequest *)initWithVerificationCode:(NSString *)verificationCode forNumber:(NSString *)phoneNumber + pin:(nullable NSString *)pin signalingKey:(NSString *)signalingKey - authKey:(NSString *)authKey { + authKey:(NSString *)authKey +{ self = [super initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/code/%@", textSecureAccountsAPI, verificationCode]]]; _numberToValidate = phoneNumber; - self.parameters = - [TSAttributes attributesWithSignalingKey:signalingKey serverAuthToken:authKey manualMessageFetching:NO]; + NSMutableDictionary *parameters = + [[TSAttributes attributesWithSignalingKey:signalingKey serverAuthToken:authKey manualMessageFetching:NO] + mutableCopy]; + if (pin) { + OWSAssert(pin.length > 0); + parameters[@"pin"] = pin; + } + self.parameters = parameters; [self setHTTPMethod:@"PUT"]; @@ -28,3 +38,5 @@ } @end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/Cryptography.m b/SignalServiceKit/src/Util/Cryptography.m index 761f24090..e11773a65 100755 --- a/SignalServiceKit/src/Util/Cryptography.m +++ b/SignalServiceKit/src/Util/Cryptography.m @@ -272,8 +272,8 @@ const NSUInteger kAES256_KeyByteLength = 32; #pragma mark methods which use AES CBC + (NSData *)decryptAppleMessagePayload:(NSData *)payload withSignalingKey:(NSString *)signalingKeyString { - assert(payload); - assert(signalingKeyString); + OWSAssert(payload); + OWSAssert(signalingKeyString); unsigned char version[1]; unsigned char iv[16]; diff --git a/SignalServiceKit/src/Util/OWSError.h b/SignalServiceKit/src/Util/OWSError.h index 828d5401f..ad252ec2c 100644 --- a/SignalServiceKit/src/Util/OWSError.h +++ b/SignalServiceKit/src/Util/OWSError.h @@ -28,7 +28,8 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) { OWSErrorCodeCouldNotWriteAttachmentData = 777409, OWSErrorCodeMessageDeletedBeforeSent = 777410, OWSErrorCodeDatabaseConversionFatalError = 777411, - OWSErrorCodeMoveFileToSharedDataContainerError = 777412 + OWSErrorCodeMoveFileToSharedDataContainerError = 777412, + OWSErrorCodeRegistrationMissing2FAPIN = 777413 }; extern NSString *const OWSErrorRecipientIdentifierKey; From 288d049ceea1fb584e5cb0c1ef8a103a5ef267a6 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 1 Mar 2018 16:11:25 -0500 Subject: [PATCH 2/3] Update l10n strings. --- Signal/translations/en.lproj/Localizable.strings | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index c1e01f3ea..5b616497d 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -653,10 +653,10 @@ "ENABLE_2FA_VIEW_CONFIRM_PIN_INSTRUCTIONS" = "Confirm your PIN."; /* Error indicating that attempt to disable 'two-factor auth' failed. */ -"ENABLE_2FA_VIEW_COULD_NOT_DISABLE_2FA" = "Could not disable two-step verification."; +"ENABLE_2FA_VIEW_COULD_NOT_DISABLE_2FA" = "Could not disable Registration Lock."; /* Error indicating that attempt to enable 'two-factor auth' failed. */ -"ENABLE_2FA_VIEW_COULD_NOT_ENABLE_2FA" = "Could not enable two-step verification."; +"ENABLE_2FA_VIEW_COULD_NOT_ENABLE_2FA" = "Could not enable Registration Lock."; /* Label for the 'enable two-factor auth' item in the settings view */ "ENABLE_2FA_VIEW_DISABLE_2FA" = "Disable"; @@ -671,16 +671,16 @@ "ENABLE_2FA_VIEW_PIN_DOES_NOT_MATCH" = "Pin does not match."; /* Indicates that user should select a 'two factor auth pin'. */ -"ENABLE_2FA_VIEW_SELECT_PIN_INSTRUCTIONS" = "Enter a PIN which you'll be asked for when you register your phone number with Signal. Your PIN must have at least 4 digits."; +"ENABLE_2FA_VIEW_SELECT_PIN_INSTRUCTIONS" = "Enter a Registration Lock PIN. You will be asked to enter this PIN the next time you register this phone number with Signal."; /* Indicates that user has 'two factor auth pin' disabled. */ -"ENABLE_2FA_VIEW_STATUS_DISABLED_INSTRUCTIONS" = "For added security, enable two-step verification, which will require a PIN when registering your phone number with Signal again."; +"ENABLE_2FA_VIEW_STATUS_DISABLED_INSTRUCTIONS" = "For increased security, enable a Registration Lock PIN that will be required in order to register this phone number with Signal again."; /* Indicates that user has 'two factor auth pin' enabled. */ -"ENABLE_2FA_VIEW_STATUS_ENABLED_INSTRUCTIONS" = "Two-step verification is enabled. You'll need to enter your PIN when registering your phone number with Signal again."; +"ENABLE_2FA_VIEW_STATUS_ENABLED_INSTRUCTIONS" = "Registration Lock is enabled. You'll need to enter your PIN when registering your phone number with Signal again."; /* Title for the 'enable two factor auth PIN' views. */ -"ENABLE_2FA_VIEW_TITLE" = "Two-Step Verification"; +"ENABLE_2FA_VIEW_TITLE" = "Registration Lock"; /* Call setup status label */ "END_CALL_RESPONDER_IS_BUSY" = "Busy."; From a87b79341f5861e7acc16cef143ca49b405bd866 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 2 Mar 2018 11:10:09 -0500 Subject: [PATCH 3/3] Respond to CR. --- Pods | 2 +- .../CodeVerificationViewController.m | 15 ++------------- .../OWS2FARegistrationViewController.m | 15 +++++++-------- Signal/translations/en.lproj/Localizable.strings | 7 ++----- SignalMessaging/contacts/ViewControllerUtils.m | 3 +-- 5 files changed, 13 insertions(+), 29 deletions(-) diff --git a/Pods b/Pods index 267e347b1..9a4161d91 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit 267e347b1eb97f8fd2e03a881b1a1c0c1de20e0f +Subproject commit 9a4161d91bf218604eefef73a6ba237cc2f3188d diff --git a/Signal/src/ViewControllers/CodeVerificationViewController.m b/Signal/src/ViewControllers/CodeVerificationViewController.m index 972b2175a..0fd43b98f 100644 --- a/Signal/src/ViewControllers/CodeVerificationViewController.m +++ b/Signal/src/ViewControllers/CodeVerificationViewController.m @@ -67,12 +67,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)viewDidLoad { [super viewDidLoad]; - self.navigationItem.backBarButtonItem = - [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"BACK_BUTTON", @"button text for back button") - style:UIBarButtonItemStylePlain - target:self - action:@selector(backButtonWasPressed)]; - [self createViews]; [self initializeKeyboardHandlers]; @@ -273,7 +267,7 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"%@ Successfully registered Signal account.", weakSelf.logTag); dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf stopActivityIndicator]; - [weakSelf vericationWasCompleted]; + [weakSelf verificationWasCompleted]; }); }) .catch(^(NSError *error) { @@ -301,7 +295,7 @@ NS_ASSUME_NONNULL_BEGIN }); } -- (void)vericationWasCompleted +- (void)verificationWasCompleted { [ProfileViewController presentForRegistration:self.navigationController]; } @@ -492,11 +486,6 @@ NS_ASSUME_NONNULL_BEGIN [self submitVerificationCode]; } -- (void)backButtonWasPressed -{ - [self.navigationController popViewControllerAnimated:YES]; -} - @end NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/OWS2FARegistrationViewController.m b/Signal/src/ViewControllers/OWS2FARegistrationViewController.m index 21f0cca11..50ec4ce91 100644 --- a/Signal/src/ViewControllers/OWS2FARegistrationViewController.m +++ b/Signal/src/ViewControllers/OWS2FARegistrationViewController.m @@ -245,7 +245,7 @@ NS_ASSUME_NONNULL_BEGIN [modalActivityIndicator dismissWithCompletion:^{ OWSAssertIsOnMainThread(); - [weakSelf vericationWasCompleted]; + [weakSelf verificationWasCompleted]; }]; }); }) @@ -257,12 +257,11 @@ NS_ASSUME_NONNULL_BEGIN [modalActivityIndicator dismissWithCompletion:^{ OWSAssertIsOnMainThread(); - [OWSAlerts - showAlertWithTitle:NSLocalizedString(@"ALERT_ERROR_TITLE", @"") - message:NSLocalizedString(@"REGISTER_2FA_REGISTRATION_FAILED", - @"Error indicating that attempt to register with " - @"'two-factor " - @"auth' failed.")]; + [OWSAlerts showAlertWithTitle:NSLocalizedString( + @"REGISTER_2FA_REGISTRATION_FAILED_ALERT_TITLE", + @"Title for alert indicating that attempt to " + @"register with 'two-factor auth' failed.") + message:error.localizedDescription]; [weakSelf.pinTextfield becomeFirstResponder]; }]; @@ -271,7 +270,7 @@ NS_ASSUME_NONNULL_BEGIN }]; } -- (void)vericationWasCompleted +- (void)verificationWasCompleted { [ProfileViewController presentForRegistration:self.navigationController]; } diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 5b616497d..9bf4624a8 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -280,9 +280,6 @@ /* Accessibilty label for placing call button */ "CALL_LABEL" = "Call"; -/* Text shown on call screen in place of remote video */ -"CALL_REMOTE_VIDEO_DISABLED" = "Please upgrade to iOS 9 or newer to see remote video."; - /* Call setup status label after outgoing call times out */ "CALL_SCREEN_STATUS_NO_ANSWER" = "No Answer."; @@ -1392,8 +1389,8 @@ /* Instructions to enter the 'two-factor auth pin' in the 2FA registration view. */ "REGISTER_2FA_INSTRUCTIONS" = "This phone number has Registration Lock enabled. Please enter the Registration Lock PIN.\n\nYour Registration Lock PIN is separate from the automated verification code that was sent to your phone during the last step."; -/* Error indicating that attempt to register with 'two-factor auth' failed. */ -"REGISTER_2FA_REGISTRATION_FAILED" = "Registration failed."; +/* Title for alert indicating that attempt to register with 'two-factor auth' failed. */ +"REGISTER_2FA_REGISTRATION_FAILED_ALERT_TITLE" = "Registration Failed"; /* Label for 'submit' button in the 2FA registration view. */ "REGISTER_2FA_SUBMIT_BUTTON" = "Submit"; diff --git a/SignalMessaging/contacts/ViewControllerUtils.m b/SignalMessaging/contacts/ViewControllerUtils.m index a5808dc4d..c4bc0b66c 100644 --- a/SignalMessaging/contacts/ViewControllerUtils.m +++ b/SignalMessaging/contacts/ViewControllerUtils.m @@ -12,9 +12,8 @@ NS_ASSUME_NONNULL_BEGIN -// TODO: ? const NSUInteger kMin2FAPinLength = 4; -const NSUInteger kMax2FAPinLength = 14; +const NSUInteger kMax2FAPinLength = 16; @implementation ViewControllerUtils