From 58abf762442b613e32a9a974c467df8249f7e71a Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 14 Feb 2019 12:41:48 -0500 Subject: [PATCH] Sketch out CAPTCHA onboarding view. --- .../HomeView/HomeViewController.m | 5 +- .../CodeVerificationViewController.m | 8 +- .../OnboardingBaseViewController.swift | 68 ++++++++++++ .../OnboardingCaptchaViewController.swift | 59 ++++------ .../Registration/OnboardingController.swift | 99 +++++++++++------ .../OnboardingPhoneNumberViewController.swift | 101 ++++++------------ .../Registration/RegistrationViewController.m | 1 + Signal/src/util/RegistrationUtils.m | 6 +- .../src/Account/TSAccountManager.h | 9 +- .../src/Account/TSAccountManager.m | 23 +++- .../Network/API/Requests/OWSRequestFactory.h | 3 +- .../Network/API/Requests/OWSRequestFactory.m | 14 ++- 12 files changed, 243 insertions(+), 153 deletions(-) diff --git a/Signal/src/ViewControllers/HomeView/HomeViewController.m b/Signal/src/ViewControllers/HomeView/HomeViewController.m index 167e27e05..7e7c40603 100644 --- a/Signal/src/ViewControllers/HomeView/HomeViewController.m +++ b/Signal/src/ViewControllers/HomeView/HomeViewController.m @@ -485,10 +485,11 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations dispatch_async(dispatch_get_main_queue(), ^{ OnboardingController *onboardingController = [OnboardingController new]; + [onboardingController + updateWithPhoneNumber:[[OnboardingPhoneNumber alloc] initWithE164:@"+13213214321" userInput:@"3213214321"]]; + OnboardingCaptchaViewController *view = [[OnboardingCaptchaViewController alloc] initWithOnboardingController:onboardingController]; - // OnboardingPermissionsViewController *view = - // [[OnboardingPermissionsViewController alloc] initWithOnboardingController:onboardingController]; OWSNavigationController *navigationController = [[OWSNavigationController alloc] initWithRootViewController:view]; [self presentViewController:navigationController animated:YES completion:nil]; diff --git a/Signal/src/ViewControllers/Registration/CodeVerificationViewController.m b/Signal/src/ViewControllers/Registration/CodeVerificationViewController.m index 3a168ebd5..923955f0b 100644 --- a/Signal/src/ViewControllers/Registration/CodeVerificationViewController.m +++ b/Signal/src/ViewControllers/Registration/CodeVerificationViewController.m @@ -340,8 +340,8 @@ NS_ASSUME_NONNULL_BEGIN [_requestCodeAgainSpinner startAnimating]; __weak CodeVerificationViewController *weakSelf = self; - [self.tsAccountManager - rerequestSMSWithSuccess:^{ + [self.tsAccountManager rerequestSMSWithCaptchaToken:nil + success:^{ OWSLogInfo(@"Successfully requested SMS code"); [weakSelf enableServerActions:YES]; [weakSelf.requestCodeAgainSpinner stopAnimating]; @@ -363,8 +363,8 @@ NS_ASSUME_NONNULL_BEGIN [_requestCallSpinner startAnimating]; __weak CodeVerificationViewController *weakSelf = self; - [self.tsAccountManager - rerequestVoiceWithSuccess:^{ + [self.tsAccountManager rerequestVoiceWithCaptchaToken:nil + success:^{ OWSLogInfo(@"Successfully requested voice code"); [weakSelf enableServerActions:YES]; diff --git a/Signal/src/ViewControllers/Registration/OnboardingBaseViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingBaseViewController.swift index 6027d0d00..c14bd048d 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingBaseViewController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingBaseViewController.swift @@ -7,6 +7,15 @@ import PromiseKit @objc public class OnboardingBaseViewController: OWSViewController { + + // MARK: - Dependencies + + private var tsAccountManager: TSAccountManager { + return TSAccountManager.sharedInstance() + } + + // MARK: - + // Unlike a delegate, we can and should retain a strong reference to the OnboardingController. let onboardingController: OnboardingController @@ -82,6 +91,65 @@ public class OnboardingBaseViewController: OWSViewController { } } + // MARK: - Registration + + func tryToRegister(smsVerification: Bool) { + + guard let phoneNumber = onboardingController.phoneNumber else { + owsFailDebug("Missing phoneNumber.") + return + } + + // We eagerly update this state, regardless of whether or not the + // registration request succeeds. + OnboardingController.setLastRegisteredCountryCode(value: onboardingController.countryState.countryCode) + OnboardingController.setLastRegisteredPhoneNumber(value: phoneNumber.userInput) + + let captchaToken = onboardingController.captchaToken + + ModalActivityIndicatorViewController.present(fromViewController: self, + canCancel: true) { (modal) in + + self.tsAccountManager.register(withPhoneNumber: phoneNumber.e164, + captchaToken: captchaToken, + success: { + DispatchQueue.main.async { + modal.dismiss(completion: { + self.registrationSucceeded() + }) + } + }, failure: { (error) in + Logger.error("Error: \(error)") + + DispatchQueue.main.async { + modal.dismiss(completion: { + self.registrationFailed(error: error as NSError) + }) + } + }, smsVerification: smsVerification) + } + } + + private func registrationSucceeded() { + self.onboardingController.onboardingRegistrationSucceeded(viewController: self) + } + + private func registrationFailed(error: NSError) { + if error.code == 402 { + Logger.info("Captcha requested.") + + self.onboardingController.onboardingDidRequireCaptcha(viewController: self) + return + } else if error.code == 400 { + OWSAlerts.showAlert(title: NSLocalizedString("REGISTRATION_ERROR", comment: ""), + message: NSLocalizedString("REGISTRATION_NON_VALID_NUMBER", comment: "")) + + } else { + OWSAlerts.showAlert(title: error.localizedDescription, + message: error.localizedRecoverySuggestion) + } + } + // MARK: - Orientation public override var supportedInterfaceOrientations: UIInterfaceOrientationMask { diff --git a/Signal/src/ViewControllers/Registration/OnboardingCaptchaViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingCaptchaViewController.swift index c5c8e56b5..be9665057 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingCaptchaViewController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingCaptchaViewController.swift @@ -14,7 +14,6 @@ public class OnboardingCaptchaViewController: OnboardingBaseViewController { super.loadView() view.backgroundColor = Theme.backgroundColor - view.backgroundColor = .orange view.layoutMargins = .zero // TODO: @@ -45,8 +44,8 @@ public class OnboardingCaptchaViewController: OnboardingBaseViewController { webView.allowsBackForwardNavigationGestures = false webView.customUserAgent = "Signal iOS (+https://signal.org/download)" webView.allowsLinkPreview = false -// webView.scrollView.contentInset = .zero -// webView.layoutMargins = .zero + webView.scrollView.contentInset = .zero + webView.layoutMargins = .zero let stackView = UIStackView(arrangedSubviews: [ titleRow, @@ -108,46 +107,36 @@ public class OnboardingCaptchaViewController: OnboardingBaseViewController { loadContent() } - // MARK: - Events + // MARK: - - private func didComplete(url: URL) { + private func parseCaptchaAndTryToRegister(url: URL) { + Logger.info("") + + guard let captchaToken = parseCaptcha(url: url) else { + owsFailDebug("Could not parse captcha token: \(url)") + // TODO: Alert? + // + // Reload content so user can try again. + loadContent() + return + } + onboardingController.update(captchaToken: captchaToken) + + tryToRegister(smsVerification: false) + } + + private func parseCaptcha(url: URL) -> String? { Logger.info("") // signalcaptcha://03AF6jDqXgf1PocNNrWRJEENZ9l6RAMIsUoESi2dFKkxTgE2qjdZGVjEW6SZNFQqeRRTgGqOii6zHGG--uLyC1HnhSmRt8wHeKxHcg1hsK4ucTusANIeFXVB8wPPiV7U_0w2jUFVak5clMCvW9_JBfbfzj51_e9sou8DYfwc_R6THuTBTdpSV8Nh0yJalgget-nSukCxh6FPA6hRVbw7lP3r-me1QCykHOfh-V29UVaQ4Fs5upHvwB5rtiViqT_HN8WuGmdIdGcaWxaqy1lQTgFSs2Shdj593wZiXfhJnCWAw9rMn3jSgIZhkFxdXwKOmslQ2E_I8iWkm6 guard let host = url.host, host.count > 0 else { owsFailDebug("Missing host.") - return + return nil } - onboardingController. + return host } -// -// @objc func countryRowTapped(sender: UIGestureRecognizer) { -// guard sender.state == .recognized else { -// return -// } -// showCountryPicker() -// } -// -// @objc func countryCodeTapped(sender: UIGestureRecognizer) { -// guard sender.state == .recognized else { -// return -// } -// showCountryPicker() -// } -// -// @objc func nextPressed() { -// Logger.info("") -// -// parseAndTryToRegister() -// } -// -// // MARK: - -// -// private func registrationSucceeded() { -// self.onboardingController.onboardingPhoneNumberDidComplete(viewController: self) -// } } // MARK: - @@ -164,7 +153,7 @@ extension OnboardingCaptchaViewController: WKNavigationDelegate { if url.scheme == "signalcaptcha" { decisionHandler(.cancel) DispatchQueue.main.async { - didComplete(url: url) + self.parseCaptchaAndTryToRegister(url: url) } return } @@ -202,8 +191,6 @@ extension OnboardingCaptchaViewController: WKNavigationDelegate { Logger.verbose("navigation: \(String(describing: navigation)), error: \(error)") } -// public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) - public func webViewWebContentProcessDidTerminate(_ webView: WKWebView) { Logger.verbose("") } diff --git a/Signal/src/ViewControllers/Registration/OnboardingController.swift b/Signal/src/ViewControllers/Registration/OnboardingController.swift index 5cb284c4b..89cab9233 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingController.swift @@ -5,7 +5,7 @@ import UIKit @objc -public class OnboardingState: NSObject { +public class OnboardingCountryState: NSObject { public let countryName: String public let callingCode: String public let countryCode: String @@ -19,7 +19,7 @@ public class OnboardingState: NSObject { self.countryCode = countryCode } - public static var defaultValue: OnboardingState { + public static var defaultValue: OnboardingCountryState { AssertIsOnMainThread() var countryCode: String = PhoneNumber.defaultCountryCode() @@ -36,13 +36,35 @@ public class OnboardingState: NSObject { countryName = countryNameDerived } - return OnboardingState(countryName: countryName, callingCode: callingCode, countryCode: countryCode) + return OnboardingCountryState(countryName: countryName, callingCode: callingCode, countryCode: countryCode) } } +// MARK: - + +@objc +public class OnboardingPhoneNumber: NSObject { + public let e164: String + public let userInput: String + + @objc + public init(e164: String, + userInput: String) { + self.e164 = e164 + self.userInput = userInput + } +} + +// MARK: - + @objc public class OnboardingController: NSObject { + @objc + public override init() { + super.init() + } + // MARK: - Factory Methods @objc @@ -58,6 +80,8 @@ public class OnboardingController: NSObject { public func onboardingSplashDidComplete(viewController: UIViewController) { AssertIsOnMainThread() + Logger.info("") + let view = OnboardingPermissionsViewController(onboardingController: self) viewController.navigationController?.pushViewController(view, animated: true) } @@ -65,12 +89,16 @@ public class OnboardingController: NSObject { public func onboardingPermissionsWasSkipped(viewController: UIViewController) { AssertIsOnMainThread() + Logger.info("") + pushPhoneNumberView(viewController: viewController) } public func onboardingPermissionsDidComplete(viewController: UIViewController) { AssertIsOnMainThread() + Logger.info("") + pushPhoneNumberView(viewController: viewController) } @@ -81,53 +109,64 @@ public class OnboardingController: NSObject { viewController.navigationController?.pushViewController(view, animated: true) } - public func onboardingPhoneNumberDidComplete(viewController: UIViewController) { + public func onboardingRegistrationSucceeded(viewController: UIViewController) { AssertIsOnMainThread() + Logger.info("") + // CodeVerificationViewController *vc = [CodeVerificationViewController new]; // [weakSelf.navigationController pushViewController:vc animated:YES]; } - public func onboardingPhoneNumberDidRequireCaptcha(viewController: UIViewController) { + public func onboardingDidRequireCaptcha(viewController: UIViewController) { AssertIsOnMainThread() - let view = OnboardingCaptchaViewController(onboardingController: self) - viewController.navigationController?.pushViewController(view, animated: true) - } + Logger.info("") - public func onboardingCaptchaDidComplete(viewController: UIViewController, - captchaToken: String) { - AssertIsOnMainThread() + guard let navigationController = viewController.navigationController else { + owsFailDebug("Missing navigationController.") + return + } - self.captchaToken = captchaToken + // The service could demand CAPTCHA from the "phone number" view or later + // from the "code verification" view. The "Captcha" view should always appear + // immediately after the "phone number" view. + while navigationController.viewControllers.count > 1 && + !(navigationController.topViewController is OnboardingPhoneNumberViewController) { + navigationController.popViewController(animated: false) + } -// let view = OnboardingCaptchaViewController(onboardingController: self) -// viewController.navigationController?.pushViewController(view, animated: true) + let view = OnboardingCaptchaViewController(onboardingController: self) + navigationController.pushViewController(view, animated: true) } // MARK: - State - public private(set) var state: OnboardingState = .defaultValue + public private(set) var countryState: OnboardingCountryState = .defaultValue - private var captchaToken: String + public private(set) var phoneNumber: OnboardingPhoneNumber? - public func update(withCountryName countryName: String, callingCode: String, countryCode: String) { + public private(set) var captchaToken: String? + + @objc + public func update(countryState: OnboardingCountryState) { AssertIsOnMainThread() - guard countryCode.count > 0 else { - owsFailDebug("Invalid country code.") - return - } - guard countryName.count > 0 else { - owsFailDebug("Invalid country name.") - return - } - guard callingCode.count > 0 else { - owsFailDebug("Invalid calling code.") - return - } + self.countryState = countryState + } + + @objc + public func update(phoneNumber: OnboardingPhoneNumber) { + AssertIsOnMainThread() + + self.phoneNumber = phoneNumber + } - state = OnboardingState(countryName: countryName, callingCode: callingCode, countryCode: countryCode) + @objc + public func update(captchaToken: String) { + AssertIsOnMainThread() + + self.captchaToken = captchaToken } // MARK: - Debug diff --git a/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift index 4a4ea1948..ffd677b3b 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift @@ -165,13 +165,13 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { owsFailDebug("Could not resume re-registration; couldn't parse phoneNumberE164.") return } - guard let callingCode = parsedPhoneNumber.getCountryCode() else { + guard let callingCodeNumeric = parsedPhoneNumber.getCountryCode() else { owsFailDebug("Could not resume re-registration; missing callingCode.") return } - let callingCodeText = "\(COUNTRY_CODE_PREFIX)\(callingCode)" + let callingCode = "\(COUNTRY_CODE_PREFIX)\(callingCodeNumeric)" let countryCodes: [String] = - PhoneNumberUtil.sharedThreadLocal().countryCodes(fromCallingCode: callingCodeText) + PhoneNumberUtil.sharedThreadLocal().countryCodes(fromCallingCode: callingCode) guard let countryCode = countryCodes.first else { owsFailDebug("Could not resume re-registration; unknown countryCode.") return @@ -180,13 +180,28 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { owsFailDebug("Could not resume re-registration; unknown countryName.") return } - if !phoneNumberE164.hasPrefix(callingCodeText) { + if !phoneNumberE164.hasPrefix(callingCode) { owsFailDebug("Could not resume re-registration; non-matching calling code.") return } - let phoneNumberWithoutCallingCode = phoneNumberE164.substring(from: callingCodeText.count) + let phoneNumberWithoutCallingCode = phoneNumberE164.substring(from: callingCode.count) + + guard countryCode.count > 0 else { + owsFailDebug("Invalid country code.") + return + } + guard countryName.count > 0 else { + owsFailDebug("Invalid country name.") + return + } + guard callingCode.count > 0 else { + owsFailDebug("Invalid calling code.") + return + } + + let countryState = OnboardingCountryState(countryName: countryName, callingCode: callingCode, countryCode: countryCode) + onboardingController.update(countryState: countryState) - onboardingController.update(withCountryName: countryName, callingCode: callingCodeText, countryCode: countryCode) updateState() phoneNumberTextField.text = phoneNumberWithoutCallingCode @@ -198,21 +213,21 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { private var countryName: String { get { - return onboardingController.state.countryName + return onboardingController.countryState.countryName } } private var callingCode: String { get { AssertIsOnMainThread() - return onboardingController.state.callingCode + return onboardingController.countryState.callingCode } } private var countryCode: String { get { AssertIsOnMainThread() - return onboardingController.state.countryCode + return onboardingController.countryState.countryCode } } @@ -297,10 +312,11 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { comment: "Message of alert indicating that users needs to enter a valid phone number to register.")) return } - let parsedPhoneNumber = localNumber.toE164() + let e164PhoneNumber = localNumber.toE164() + + onboardingController.update(phoneNumber: OnboardingPhoneNumber(e164: e164PhoneNumber, userInput: phoneNumberText)) if UIDevice.current.isIPad { - let countryCode = self.countryCode OWSAlerts.showConfirmationAlert(title: NSLocalizedString("REGISTRATION_IPAD_CONFIRM_TITLE", comment: "alert title when registering an iPad"), message: NSLocalizedString("REGISTRATION_IPAD_CONFIRM_BODY", @@ -308,65 +324,12 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { proceedTitle: NSLocalizedString("REGISTRATION_IPAD_CONFIRM_BUTTON", comment: "button text to proceed with registration when on an iPad"), proceedAction: { (_) in - self.tryToRegister(parsedPhoneNumber: parsedPhoneNumber, - phoneNumberText: phoneNumberText, - countryCode: countryCode) + self.tryToRegister(smsVerification: false) }) } else { - tryToRegister(parsedPhoneNumber: parsedPhoneNumber, - phoneNumberText: phoneNumberText, - countryCode: countryCode) + tryToRegister(smsVerification: false) } } - - private func tryToRegister(parsedPhoneNumber: String, - phoneNumberText: String, - countryCode: String) { - ModalActivityIndicatorViewController.present(fromViewController: self, - canCancel: true) { (modal) in - OnboardingController.setLastRegisteredCountryCode(value: countryCode) - OnboardingController.setLastRegisteredPhoneNumber(value: phoneNumberText) - - self.tsAccountManager.register(withPhoneNumber: parsedPhoneNumber, - success: { - DispatchQueue.main.async { - modal.dismiss(completion: { - self.registrationSucceeded() - }) - } - }, failure: { (error) in - Logger.error("Error: \(error)") - - DispatchQueue.main.async { - modal.dismiss(completion: { - self.registrationFailed(error: error as NSError) - }) - } - }, smsVerification: true) - } - } - - private func registrationSucceeded() { - self.onboardingController.onboardingPhoneNumberDidComplete(viewController: self) - } - - private func registrationFailed(error: NSError) { - if error.code == 402 { - Logger.info("Captcha requested.") - - self.onboardingController.onboardingPhoneNumberDidRequireCaptcha(viewController: self) - return - } else if error.code == 400 { - OWSAlerts.showAlert(title: NSLocalizedString("REGISTRATION_ERROR", comment: ""), - message: NSLocalizedString("REGISTRATION_NON_VALID_NUMBER", comment: "")) - - } else { - OWSAlerts.showAlert(title: error.localizedDescription, - message: error.localizedRecoverySuggestion) - } - - phoneNumberTextField.becomeFirstResponder() - } } // MARK: - @@ -382,7 +345,6 @@ extension OnboardingPhoneNumberViewController: UITextFieldDelegate { public func textFieldShouldReturn(_ textField: UITextField) -> Bool { parseAndTryToRegister() - textField.resignFirstResponder() return false } } @@ -404,7 +366,10 @@ extension OnboardingPhoneNumberViewController: CountryCodeViewControllerDelegate return } - onboardingController.update(withCountryName: countryName, callingCode: callingCode, countryCode: countryCode) + let countryState = OnboardingCountryState(countryName: countryName, callingCode: callingCode, countryCode: countryCode) + + onboardingController.update(countryState: countryState) + updateState() // Trigger the formatting logic with a no-op edit. diff --git a/Signal/src/ViewControllers/Registration/RegistrationViewController.m b/Signal/src/ViewControllers/Registration/RegistrationViewController.m index cbaf4172e..823d7385f 100644 --- a/Signal/src/ViewControllers/Registration/RegistrationViewController.m +++ b/Signal/src/ViewControllers/Registration/RegistrationViewController.m @@ -448,6 +448,7 @@ NSString *const kKeychainKey_LastRegisteredPhoneNumber = @"kKeychainKey_LastRegi __weak RegistrationViewController *weakSelf = self; [self.tsAccountManager registerWithPhoneNumber:parsedPhoneNumber + captchaToken:nil success:^{ OWSProdInfo([OWSAnalyticsEvents registrationRegisteredPhoneNumber]); diff --git a/Signal/src/util/RegistrationUtils.m b/Signal/src/util/RegistrationUtils.m index 2789b6108..9a245cff5 100644 --- a/Signal/src/util/RegistrationUtils.m +++ b/Signal/src/util/RegistrationUtils.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // #import "RegistrationUtils.h" @@ -59,8 +59,8 @@ NS_ASSUME_NONNULL_BEGIN presentFromViewController:fromViewController canCancel:NO backgroundBlock:^(ModalActivityIndicatorViewController *modalActivityIndicator) { - [self.tsAccountManager - registerWithPhoneNumber:self.tsAccountManager.reregisterationPhoneNumber + [self.tsAccountManager registerWithPhoneNumber:self.tsAccountManager.reregisterationPhoneNumber + captchaToken:nil success:^{ OWSLogInfo(@"re-registering: send verification code succeeded."); diff --git a/SignalServiceKit/src/Account/TSAccountManager.h b/SignalServiceKit/src/Account/TSAccountManager.h index 92c873603..a2aff043e 100644 --- a/SignalServiceKit/src/Account/TSAccountManager.h +++ b/SignalServiceKit/src/Account/TSAccountManager.h @@ -90,13 +90,18 @@ typedef NS_ENUM(NSUInteger, OWSRegistrationState) { #pragma mark - Register with phone number - (void)registerWithPhoneNumber:(NSString *)phoneNumber + captchaToken:(nullable NSString *)captchaToken success:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock smsVerification:(BOOL)isSMS; -- (void)rerequestSMSWithSuccess:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock; +- (void)rerequestSMSWithCaptchaToken:(nullable NSString *)captchaToken + success:(void (^)(void))successBlock + failure:(void (^)(NSError *error))failureBlock; -- (void)rerequestVoiceWithSuccess:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock; +- (void)rerequestVoiceWithCaptchaToken:(nullable NSString *)captchaToken + success:(void (^)(void))successBlock + failure:(void (^)(NSError *error))failureBlock; - (void)verifyAccountWithCode:(NSString *)verificationCode pin:(nullable NSString *)pin diff --git a/SignalServiceKit/src/Account/TSAccountManager.m b/SignalServiceKit/src/Account/TSAccountManager.m index d95b63c53..5e2d18a82 100644 --- a/SignalServiceKit/src/Account/TSAccountManager.m +++ b/SignalServiceKit/src/Account/TSAccountManager.m @@ -322,6 +322,7 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa } - (void)registerWithPhoneNumber:(NSString *)phoneNumber + captchaToken:(nullable NSString *)captchaToken success:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock smsVerification:(BOOL)isSMS @@ -339,6 +340,7 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa TSRequest *request = [OWSRequestFactory requestVerificationCodeRequestWithPhoneNumber:phoneNumber + captchaToken:captchaToken transport:(isSMS ? TSVerificationTransportSMS : TSVerificationTransportVoice)]; [[TSNetworkManager sharedManager] makeRequest:request @@ -357,20 +359,33 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa }]; } -- (void)rerequestSMSWithSuccess:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock +- (void)rerequestSMSWithCaptchaToken:(nullable NSString *)captchaToken + success:(void (^)(void))successBlock + failure:(void (^)(NSError *error))failureBlock { + // TODO: Can we remove phoneNumberAwaitingVerification? NSString *number = self.phoneNumberAwaitingVerification; OWSAssertDebug(number); - [self registerWithPhoneNumber:number success:successBlock failure:failureBlock smsVerification:YES]; + [self registerWithPhoneNumber:number + captchaToken:captchaToken + success:successBlock + failure:failureBlock + smsVerification:YES]; } -- (void)rerequestVoiceWithSuccess:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock +- (void)rerequestVoiceWithCaptchaToken:(nullable NSString *)captchaToken + success:(void (^)(void))successBlock + failure:(void (^)(NSError *error))failureBlock { NSString *number = self.phoneNumberAwaitingVerification; OWSAssertDebug(number); - [self registerWithPhoneNumber:number success:successBlock failure:failureBlock smsVerification:NO]; + [self registerWithPhoneNumber:number + captchaToken:captchaToken + success:successBlock + failure:failureBlock + smsVerification:NO]; } - (void)verifyAccountWithCode:(NSString *)verificationCode diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h index b7ef07a7c..82da3e28f 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN @@ -56,6 +56,7 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo + (TSRequest *)unregisterAccountRequest; + (TSRequest *)requestVerificationCodeRequestWithPhoneNumber:(NSString *)phoneNumber + captchaToken:(nullable NSString *)captchaToken transport:(TSVerificationTransport)transport; + (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m index bc2e4b6ae..ecc9a053b 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // #import "OWSRequestFactory.h" @@ -235,13 +235,21 @@ NS_ASSUME_NONNULL_BEGIN } + (TSRequest *)requestVerificationCodeRequestWithPhoneNumber:(NSString *)phoneNumber + captchaToken:(nullable NSString *)captchaToken transport:(TSVerificationTransport)transport { OWSAssertDebug(phoneNumber.length > 0); - NSString *path = [NSString stringWithFormat:@"%@/%@/code/%@?client=ios", + + NSString *querystring = @"client=ios"; + if (captchaToken.length > 0) { + querystring = [NSString stringWithFormat:@"%@&captcha=%@", querystring, captchaToken]; + } + + NSString *path = [NSString stringWithFormat:@"%@/%@/code/%@?%@", textSecureAccountsAPI, [self stringForTransport:transport], - phoneNumber]; + phoneNumber, + querystring]; TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}]; request.shouldHaveAuthorizationHeaders = NO;