blob: 8c657f0571be4c35d5e847250ee4b9a3845be8da [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "google_apis/gaia/google_service_auth_error.h"
#include <string>
#include <utility>
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "net/base/net_errors.h"
GoogleServiceAuthError::Captcha::Captcha() : image_width(0), image_height(0) {
}
GoogleServiceAuthError::Captcha::Captcha(
const std::string& token, const GURL& audio, const GURL& img,
const GURL& unlock, int width, int height)
: token(token), audio_url(audio), image_url(img), unlock_url(unlock),
image_width(width), image_height(height) {
}
GoogleServiceAuthError::Captcha::Captcha(const Captcha& other) = default;
GoogleServiceAuthError::Captcha::~Captcha() {
}
bool GoogleServiceAuthError::Captcha::operator==(const Captcha& b) const {
return (token == b.token &&
audio_url == b.audio_url &&
image_url == b.image_url &&
unlock_url == b.unlock_url &&
image_width == b.image_width &&
image_height == b.image_height);
}
GoogleServiceAuthError::SecondFactor::SecondFactor() : field_length(0) {
}
GoogleServiceAuthError::SecondFactor::SecondFactor(
const std::string& token, const std::string& prompt,
const std::string& alternate, int length)
: token(token), prompt_text(prompt), alternate_text(alternate),
field_length(length) {
}
GoogleServiceAuthError::SecondFactor::SecondFactor(const SecondFactor& other) =
default;
GoogleServiceAuthError::SecondFactor::~SecondFactor() {
}
bool GoogleServiceAuthError::SecondFactor::operator==(
const SecondFactor& b) const {
return (token == b.token &&
prompt_text == b.prompt_text &&
alternate_text == b.alternate_text &&
field_length == b.field_length);
}
bool GoogleServiceAuthError::operator==(
const GoogleServiceAuthError& b) const {
return (state_ == b.state_ &&
network_error_ == b.network_error_ &&
captcha_ == b.captcha_ &&
second_factor_ == b.second_factor_);
}
bool GoogleServiceAuthError::operator!=(
const GoogleServiceAuthError& b) const {
return !(*this == b);
}
GoogleServiceAuthError::GoogleServiceAuthError()
: state_(NONE), network_error_(0) {}
GoogleServiceAuthError::GoogleServiceAuthError(State s)
: state_(s),
network_error_(0) {
// If the caller has no idea, then we just set it to a generic failure.
if (s == CONNECTION_FAILED) {
network_error_ = net::ERR_FAILED;
}
}
GoogleServiceAuthError::GoogleServiceAuthError(
State state,
const std::string& error_message)
: state_(state),
network_error_(0),
error_message_(error_message) {
}
GoogleServiceAuthError::GoogleServiceAuthError(
const GoogleServiceAuthError& other) = default;
// static
GoogleServiceAuthError
GoogleServiceAuthError::FromConnectionError(int error) {
return GoogleServiceAuthError(CONNECTION_FAILED, error);
}
// static
GoogleServiceAuthError GoogleServiceAuthError::FromClientLoginCaptchaChallenge(
const std::string& captcha_token,
const GURL& captcha_image_url,
const GURL& captcha_unlock_url) {
return GoogleServiceAuthError(CAPTCHA_REQUIRED, captcha_token, GURL(),
captcha_image_url, captcha_unlock_url, 0, 0);
}
// static
GoogleServiceAuthError GoogleServiceAuthError::FromServiceError(
const std::string& error_message) {
return GoogleServiceAuthError(SERVICE_ERROR, error_message);
}
// static
GoogleServiceAuthError GoogleServiceAuthError::FromUnexpectedServiceResponse(
const std::string& error_message) {
return GoogleServiceAuthError(UNEXPECTED_SERVICE_RESPONSE, error_message);
}
// static
GoogleServiceAuthError GoogleServiceAuthError::AuthErrorNone() {
return GoogleServiceAuthError(NONE);
}
// static
bool GoogleServiceAuthError::IsDeprecated(State state) {
return state == HOSTED_NOT_ALLOWED_DEPRECATED;
}
GoogleServiceAuthError::State GoogleServiceAuthError::state() const {
return state_;
}
const GoogleServiceAuthError::Captcha& GoogleServiceAuthError::captcha() const {
return captcha_;
}
const GoogleServiceAuthError::SecondFactor&
GoogleServiceAuthError::second_factor() const {
return second_factor_;
}
int GoogleServiceAuthError::network_error() const {
return network_error_;
}
const std::string& GoogleServiceAuthError::token() const {
switch (state_) {
case CAPTCHA_REQUIRED:
return captcha_.token;
break;
case TWO_FACTOR:
return second_factor_.token;
break;
default:
NOTREACHED();
}
return base::EmptyString();
}
const std::string& GoogleServiceAuthError::error_message() const {
return error_message_;
}
base::DictionaryValue* GoogleServiceAuthError::ToValue() const {
base::DictionaryValue* value = new base::DictionaryValue();
std::string state_str;
switch (state_) {
#define STATE_CASE(x) case x: state_str = #x; break
STATE_CASE(NONE);
STATE_CASE(INVALID_GAIA_CREDENTIALS);
STATE_CASE(USER_NOT_SIGNED_UP);
STATE_CASE(CONNECTION_FAILED);
STATE_CASE(CAPTCHA_REQUIRED);
STATE_CASE(ACCOUNT_DELETED);
STATE_CASE(ACCOUNT_DISABLED);
STATE_CASE(SERVICE_UNAVAILABLE);
STATE_CASE(TWO_FACTOR);
STATE_CASE(REQUEST_CANCELED);
STATE_CASE(UNEXPECTED_SERVICE_RESPONSE);
STATE_CASE(SERVICE_ERROR);
STATE_CASE(WEB_LOGIN_REQUIRED);
#undef STATE_CASE
default:
NOTREACHED();
break;
}
value->SetString("state", state_str);
if (!error_message_.empty()) {
value->SetString("errorMessage", error_message_);
}
if (state_ == CAPTCHA_REQUIRED) {
auto captcha_value = base::MakeUnique<base::DictionaryValue>();
captcha_value->SetString("token", captcha_.token);
captcha_value->SetString("audioUrl", captcha_.audio_url.spec());
captcha_value->SetString("imageUrl", captcha_.image_url.spec());
captcha_value->SetString("unlockUrl", captcha_.unlock_url.spec());
captcha_value->SetInteger("imageWidth", captcha_.image_width);
captcha_value->SetInteger("imageHeight", captcha_.image_height);
value->Set("captcha", std::move(captcha_value));
} else if (state_ == CONNECTION_FAILED) {
value->SetString("networkError", net::ErrorToString(network_error_));
} else if (state_ == TWO_FACTOR) {
auto two_factor_value = base::MakeUnique<base::DictionaryValue>();
two_factor_value->SetString("token", second_factor_.token);
two_factor_value->SetString("promptText", second_factor_.prompt_text);
two_factor_value->SetString("alternateText", second_factor_.alternate_text);
two_factor_value->SetInteger("fieldLength", second_factor_.field_length);
value->Set("two_factor", std::move(two_factor_value));
}
return value;
}
std::string GoogleServiceAuthError::ToString() const {
switch (state_) {
case NONE:
return std::string();
case INVALID_GAIA_CREDENTIALS:
return "Invalid credentials.";
case USER_NOT_SIGNED_UP:
return "Not authorized.";
case CONNECTION_FAILED:
return base::StringPrintf("Connection failed (%d).", network_error_);
case CAPTCHA_REQUIRED:
return base::StringPrintf("CAPTCHA required (%s).",
captcha_.token.c_str());
case ACCOUNT_DELETED:
return "Account deleted.";
case ACCOUNT_DISABLED:
return "Account disabled.";
case SERVICE_UNAVAILABLE:
return "Service unavailable; try again later.";
case TWO_FACTOR:
return base::StringPrintf("2-step verification required (%s).",
second_factor_.token.c_str());
case REQUEST_CANCELED:
return "Request canceled.";
case UNEXPECTED_SERVICE_RESPONSE:
return base::StringPrintf("Unexpected service response (%s)",
error_message_.c_str());
case SERVICE_ERROR:
return base::StringPrintf("Service responded with error: '%s'",
error_message_.c_str());
case WEB_LOGIN_REQUIRED:
return "Less secure apps may not authenticate with this account. "
"Please visit: "
"https://www.google.com/settings/security/lesssecureapps";
default:
NOTREACHED();
return std::string();
}
}
bool GoogleServiceAuthError::IsPersistentError() const {
if (state_ == GoogleServiceAuthError::NONE) return false;
return !IsTransientError();
}
bool GoogleServiceAuthError::IsTransientError() const {
switch (state_) {
// These are failures that are likely to succeed if tried again.
case GoogleServiceAuthError::CONNECTION_FAILED:
case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
case GoogleServiceAuthError::REQUEST_CANCELED:
return true;
// Everything else will have the same result.
default:
return false;
}
}
GoogleServiceAuthError::GoogleServiceAuthError(State s, int error)
: state_(s),
network_error_(error) {
}
GoogleServiceAuthError::GoogleServiceAuthError(
State s,
const std::string& captcha_token,
const GURL& captcha_audio_url,
const GURL& captcha_image_url,
const GURL& captcha_unlock_url,
int image_width,
int image_height)
: state_(s),
captcha_(captcha_token, captcha_audio_url, captcha_image_url,
captcha_unlock_url, image_width, image_height),
network_error_(0) {
}