1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/remoting/setup_flow_login_step.h"
6
7#include "base/json/json_reader.h"
8#include "base/json/json_writer.h"
9#include "base/string_util.h"
10#include "base/utf_string_conversions.h"
11#include "base/values.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/remoting/setup_flow_get_status_step.h"
14#include "chrome/common/net/gaia/gaia_constants.h"
15#include "chrome/common/net/gaia/google_service_auth_error.h"
16
17namespace remoting {
18
19static const wchar_t kLoginIFrameXPath[] = L"//iframe[@id='login']";
20
21SetupFlowLoginStep::SetupFlowLoginStep() { }
22
23SetupFlowLoginStep::SetupFlowLoginStep(const string16& error_message)
24    : error_message_(error_message) {
25}
26
27SetupFlowLoginStep::~SetupFlowLoginStep() { }
28
29void SetupFlowLoginStep::HandleMessage(const std::string& message,
30                                       const Value* arg) {
31  if (message == "SubmitAuth") {
32    DCHECK(arg);
33
34    std::string json;
35    if (!arg->GetAsString(&json) || json.empty()) {
36      NOTREACHED();
37      return;
38    }
39
40    scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false));
41    if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) {
42      NOTREACHED() << "Unable to parse auth data";
43      return;
44    }
45
46    CHECK(parsed_value->IsType(Value::TYPE_DICTIONARY));
47
48    std::string username, password, captcha, access_code;
49    const DictionaryValue* result =
50        static_cast<const DictionaryValue*>(parsed_value.get());
51    if (!result->GetString("user", &username) ||
52        !result->GetString("pass", &password) ||
53        !result->GetString("captcha", &captcha) ||
54        !result->GetString("access_code", &access_code)) {
55      NOTREACHED() << "Unable to parse auth data";
56      return;
57    }
58
59    OnUserSubmittedAuth(username, password, captcha, access_code);
60  }
61}
62
63void SetupFlowLoginStep::Cancel() {
64  if (authenticator_.get())
65    authenticator_->CancelRequest();
66}
67
68void SetupFlowLoginStep::OnUserSubmittedAuth(const std::string& user,
69                                             const std::string& password,
70                                             const std::string& captcha,
71                                             const std::string& access_code) {
72  flow()->context()->login = user;
73
74  // Start the authenticator.
75  authenticator_.reset(
76      new GaiaAuthFetcher(this, GaiaConstants::kChromeSource,
77                          flow()->profile()->GetRequestContext()));
78
79  std::string remoting_password;
80  if (!access_code.empty())
81    remoting_password = access_code;
82  else
83    remoting_password = password;
84
85  authenticator_->StartClientLogin(user, remoting_password,
86                                   GaiaConstants::kRemotingService,
87                                   "", captcha,
88                                   GaiaAuthFetcher::HostedAccountsAllowed);
89}
90
91void SetupFlowLoginStep::OnClientLoginSuccess(
92    const GaiaAuthConsumer::ClientLoginResult& credentials) {
93  // Save the token for remoting.
94  flow()->context()->remoting_token = credentials.token;
95
96  // After login has succeeded try to fetch the token for sync.
97  // We need the token for sync to connect to the talk network.
98  authenticator_->StartIssueAuthToken(credentials.sid, credentials.lsid,
99                                      GaiaConstants::kSyncService);
100}
101
102void SetupFlowLoginStep::OnClientLoginFailure(
103    const GoogleServiceAuthError& error) {
104  ShowGaiaFailed(error);
105  authenticator_.reset();
106}
107
108void SetupFlowLoginStep::OnIssueAuthTokenSuccess(
109    const std::string& service, const std::string& auth_token) {
110  // Save the sync token.
111  flow()->context()->talk_token = auth_token;
112  authenticator_.reset();
113
114  FinishStep(new SetupFlowGetStatusStep());
115}
116
117void SetupFlowLoginStep::OnIssueAuthTokenFailure(const std::string& service,
118    const GoogleServiceAuthError& error) {
119  ShowGaiaFailed(error);
120  authenticator_.reset();
121}
122
123void SetupFlowLoginStep::DoStart() {
124  DictionaryValue args;
125  // TODO(sergeyu): Supply current login name if the service was started before.
126  args.SetString("user", "");
127  args.SetBoolean("editable_user", true);
128  if (!error_message_.empty())
129    args.SetString("error_message", error_message_);
130  ShowGaiaLogin(args);
131}
132
133void SetupFlowLoginStep::ShowGaiaLogin(const DictionaryValue& args) {
134  WebUI* web_ui = flow()->web_ui();
135  DCHECK(web_ui);
136
137  web_ui->CallJavascriptFunction("showLogin");
138
139  std::string json;
140  base::JSONWriter::Write(&args, false, &json);
141  std::wstring javascript = std::wstring(L"showGaiaLogin(") +
142      UTF8ToWide(json) + L");";
143  ExecuteJavascriptInIFrame(kLoginIFrameXPath, javascript);
144}
145
146void SetupFlowLoginStep::ShowGaiaFailed(const GoogleServiceAuthError& error) {
147  DictionaryValue args;
148  args.SetInteger("error", error.state());
149  args.SetBoolean("editable_user", true);
150  args.SetString("captchaUrl", error.captcha().image_url.spec());
151  ShowGaiaLogin(args);
152}
153
154}  // namespace remoting
155