diff --git a/WordPress/Classes/ViewRelated/NUX/LoginEmailViewController.swift b/WordPress/Classes/ViewRelated/NUX/LoginEmailViewController.swift index aaf35781a9b4..9b78e387b5ad 100644 --- a/WordPress/Classes/ViewRelated/NUX/LoginEmailViewController.swift +++ b/WordPress/Classes/ViewRelated/NUX/LoginEmailViewController.swift @@ -158,6 +158,8 @@ class LoginEmailViewController: LoginViewController, SigninKeyboardResponder { func googleLoginTapped() { awaitingGoogle = true + configureViewLoading(true) + GIDSignIn.sharedInstance().disconnect() // Flag this as a social sign in. @@ -329,8 +331,19 @@ class LoginEmailViewController: LoginViewController, SigninKeyboardResponder { if awaitingGoogle { awaitingGoogle = false + GIDSignIn.sharedInstance().disconnect() + + let errorTitle: String + let errorDescription: String + if (error as NSError).code == WordPressComOAuthError.unknownUser.rawValue { + errorTitle = NSLocalizedString("Connected But…", comment: "Title shown when a user logs in with Google but no matching WordPress.com account is found") + errorDescription = NSLocalizedString("The Google account \"\(loginFields.username)\" doesn't match any account on WordPress.com", comment: "Description shown when a user logs in with Google but no matching WordPress.com account is found") + } else { + errorTitle = NSLocalizedString("Unable To Connect", comment: "Shown when a user logs in with Google but it subsequently fails to work as login to WordPress.com") + errorDescription = error.localizedDescription + } - let socialErrorVC = LoginSocialErrorViewController(title: NSLocalizedString("Unable To Connect", comment: "Shown when a user logs in with Google but it subsequently fails to work as login to WordPress.com"), description: error.localizedDescription) + let socialErrorVC = LoginSocialErrorViewController(title: errorTitle, description: errorDescription) let socialErrorNav = LoginNavigationController(rootViewController: socialErrorVC) socialErrorVC.delegate = self present(socialErrorNav, animated: true) {} @@ -458,6 +471,7 @@ extension LoginEmailViewController: GIDSignInDelegate { let email = user.profile.email else { // The Google SignIn for may have been canceled. //TODO: Add analytis + configureViewLoading(false) return } @@ -466,8 +480,6 @@ extension LoginEmailViewController: GIDSignInDelegate { loginFields.username = email loginFields.meta.socialServiceIDToken = token - configureViewLoading(true) - loginFacade.loginToWordPressDotCom(withGoogleIDToken: token) //TODO: Add analytis diff --git a/WordPressKit/WordPressKit/WordPressComOAuthClient.swift b/WordPressKit/WordPressKit/WordPressComOAuthClient.swift index 131146806023..04cb67ae3e91 100644 --- a/WordPressKit/WordPressKit/WordPressComOAuthClient.swift +++ b/WordPressKit/WordPressKit/WordPressComOAuthClient.swift @@ -10,6 +10,7 @@ import CocoaLumberjack case invalidOneTimePassword case socialLoginExistingUserUnconnected case invalidTwoStepCode + case unknownUser } /// `WordPressComOAuthClient` encapsulates the pattern of authenticating against WordPress.com OAuth2 service. @@ -344,7 +345,8 @@ final class WordPressComOAuthResponseSerializer: AFJSONResponseSerializer { "needs_2fa": WordPressComOAuthError.needsMultifactorCode, "invalid_otp": WordPressComOAuthError.invalidOneTimePassword, "user_exists": WordPressComOAuthError.socialLoginExistingUserUnconnected, - "invalid_two_step_code": WordPressComOAuthError.invalidTwoStepCode + "invalid_two_step_code": WordPressComOAuthError.invalidTwoStepCode, + "unknown_user": WordPressComOAuthError.unknownUser ] @@ -365,44 +367,34 @@ final class WordPressComOAuthResponseSerializer: AFJSONResponseSerializer { return responseObject } - // Handle known 400 errors. - if httpResponse.statusCode == 400 { - // REST API Error format - if let responseDictionary = responseObject as? [String: AnyObject], - let errorCode = responseDictionary["error"] as? String, - let errorDescription = responseDictionary["error_description"] as? String { - - error?.pointee = errorFor(errorCode: errorCode, errorDescription: errorDescription, responseObject: responseObject) - } - - } else if httpResponse.statusCode == 409 { - // Social login user-exists error - if let responseDict = responseObject as? [String: AnyObject], - let data = responseDict["data"] as? [String: AnyObject], - let errors = data["errors"] as? NSArray, - let err = errors[0] as? [String: AnyObject], - let errorCode = err["code"] as? String, - let errorDescription = err["message"] as? String { - - error?.pointee = errorFor(errorCode: errorCode, errorDescription: errorDescription, responseObject: responseObject) - } - } else if httpResponse.statusCode == 403 { - // Social 2FA token wasn't good - if let responseDict = responseObject as? [String: AnyObject], - let data = responseDict["data"] as? [String: AnyObject], - let newNonce = data["two_step_nonce"] as? String, - let errors = data["errors"] as? NSArray, - let err = errors[0] as? [String: AnyObject], - let errorCode = err["code"] as? String, - let errorDescription = err["message"] as? String { - - error?.pointee = errorFor(errorCode: errorCode, errorDescription: errorDescription, responseObject: responseObject, newNonce: newNonce) - } + if [400, 409, 403].contains(httpResponse.statusCode), + let responseDictionary = responseObject as? [String: AnyObject] { + error?.pointee = parseError(from: responseDictionary) } return responseObject as AnyObject? } + /// Create the NSError from the response dictionary + private func parseError(from responseDict: [String: AnyObject]) -> NSError { + var errorCode = "" + var errorDescription = "" + var newNonce: String? + + // there's either a data object, or an error. + if let errorStr = responseDict["error"] as? String { + errorCode = errorStr + errorDescription = responseDict["error_description"] as? String ?? "" + } else if let data = responseDict["data"] as? [String: AnyObject], + let errors = data["errors"] as? NSArray, + let err = errors[0] as? [String: AnyObject] { + errorCode = err["code"] as? String ?? "" + errorDescription = err["message"] as? String ?? "" + newNonce = data["two_step_nonce"] as? String + } + + return errorFor(errorCode: errorCode, errorDescription: errorDescription, responseObject: responseDict, newNonce: newNonce) + } /// Creates an NSError from the supplied arguements. The response object is /// added to the error's userInfo dictionary.