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/ui/webui/chromeos/enterprise_enrollment_ui.h"
6
7#include "base/json/json_reader.h"
8#include "base/json/json_writer.h"
9#include "base/lazy_instance.h"
10#include "base/memory/ref_counted_memory.h"
11#include "base/message_loop.h"
12#include "base/stringprintf.h"
13#include "base/values.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
16#include "chrome/common/jstemplate_builder.h"
17#include "chrome/common/url_constants.h"
18#include "content/browser/renderer_host/render_view_host.h"
19#include "content/browser/tab_contents/tab_contents.h"
20#include "content/common/bindings_policy.h"
21#include "content/common/property_bag.h"
22#include "grit/browser_resources.h"
23#include "grit/chromium_strings.h"
24#include "grit/generated_resources.h"
25#include "ui/base/l10n/l10n_util.h"
26#include "ui/base/resource/resource_bundle.h"
27
28namespace chromeos {
29
30static base::LazyInstance<
31    PropertyAccessor<EnterpriseEnrollmentUI::Controller*> >
32        g_enrollment_ui_controller_property(base::LINKER_INITIALIZED);
33
34static const char kEnterpriseEnrollmentGaiaLoginPath[] = "gaialogin";
35
36// WebUIMessageHandler implementation which handles events occuring on the page,
37// such as the user pressing the signin button.
38class EnterpriseEnrollmentMessageHandler : public WebUIMessageHandler {
39 public:
40  EnterpriseEnrollmentMessageHandler();
41  virtual ~EnterpriseEnrollmentMessageHandler();
42
43  // WebUIMessageHandler implementation.
44  virtual void RegisterMessages() OVERRIDE;
45
46 private:
47  // Handlers for WebUI messages.
48  void HandleSubmitAuth(const ListValue* args);
49  void HandleCancelAuth(const ListValue* args);
50  void HandleConfirmationClose(const ListValue* args);
51
52  // Gets the currently installed enrollment controller (if any).
53  EnterpriseEnrollmentUI::Controller* GetController();
54
55  DISALLOW_COPY_AND_ASSIGN(EnterpriseEnrollmentMessageHandler);
56};
57
58// A data source that provides the resources for the enterprise enrollment page.
59// The enterprise enrollment page requests the HTML and other resources from
60// this source.
61class EnterpriseEnrollmentDataSource : public ChromeURLDataManager::DataSource {
62 public:
63  EnterpriseEnrollmentDataSource();
64
65  // DataSource implementation.
66  virtual void StartDataRequest(const std::string& path,
67                                bool is_off_the_record,
68                                int request_id) OVERRIDE;
69  virtual std::string GetMimeType(const std::string& path) const OVERRIDE;
70
71 private:
72  virtual ~EnterpriseEnrollmentDataSource();
73
74  // Saves i18n string for |resource_id| to the |key| property of |dictionary|.
75  static void AddString(DictionaryValue* dictionary,
76                        const std::string& key,
77                        int resource_id);
78  static void AddString(DictionaryValue* dictionary,
79                        const std::string& key,
80                        int resource_id,
81                        const string16& arg1);
82
83  DISALLOW_COPY_AND_ASSIGN(EnterpriseEnrollmentDataSource);
84};
85
86EnterpriseEnrollmentMessageHandler::EnterpriseEnrollmentMessageHandler() {}
87
88EnterpriseEnrollmentMessageHandler::~EnterpriseEnrollmentMessageHandler() {}
89
90void EnterpriseEnrollmentMessageHandler::RegisterMessages() {
91  web_ui_->RegisterMessageCallback(
92      "SubmitAuth",
93      NewCallback(
94          this, &EnterpriseEnrollmentMessageHandler::HandleSubmitAuth));
95  web_ui_->RegisterMessageCallback(
96      "DialogClose",
97      NewCallback(
98          this, &EnterpriseEnrollmentMessageHandler::HandleCancelAuth));
99  web_ui_->RegisterMessageCallback(
100      "confirmationClose",
101      NewCallback(
102          this, &EnterpriseEnrollmentMessageHandler::HandleConfirmationClose));
103}
104
105void EnterpriseEnrollmentMessageHandler::HandleSubmitAuth(
106    const ListValue* value) {
107  EnterpriseEnrollmentUI::Controller* controller = GetController();
108  if (!controller) {
109    NOTREACHED();
110    return;
111  }
112
113  // Value carries single list entry, which is a json-encoded string that
114  // contains the auth parameters (see gaia_login.js).
115  std::string json_params;
116  if (!value->GetString(0, &json_params)) {
117    NOTREACHED();
118    return;
119  }
120
121  // Check the value type.
122  scoped_ptr<Value> params(base::JSONReader::Read(json_params, false));
123  if (!params.get() || !params->IsType(Value::TYPE_DICTIONARY)) {
124    NOTREACHED();
125    return;
126  }
127
128  // Read the parameters.
129  DictionaryValue* params_dict = static_cast<DictionaryValue*>(params.get());
130  std::string user;
131  std::string pass;
132  std::string captcha;
133  std::string access_code;
134  if (!params_dict->GetString("user", &user) ||
135      !params_dict->GetString("pass", &pass) ||
136      !params_dict->GetString("captcha", &captcha) ||
137      !params_dict->GetString("access_code", &access_code)) {
138    NOTREACHED();
139    return;
140  }
141
142  controller->OnAuthSubmitted(user, pass, captcha, access_code);
143}
144
145void EnterpriseEnrollmentMessageHandler::HandleCancelAuth(
146    const ListValue* value) {
147  EnterpriseEnrollmentUI::Controller* controller = GetController();
148  if (!controller) {
149    NOTREACHED();
150    return;
151  }
152
153  controller->OnAuthCancelled();
154}
155
156void EnterpriseEnrollmentMessageHandler::HandleConfirmationClose(
157    const ListValue* value) {
158  EnterpriseEnrollmentUI::Controller* controller = GetController();
159  if (!controller) {
160    NOTREACHED();
161    return;
162  }
163
164  controller->OnConfirmationClosed();
165}
166
167EnterpriseEnrollmentUI::Controller*
168    EnterpriseEnrollmentMessageHandler::GetController() {
169  return EnterpriseEnrollmentUI::GetController(web_ui_);
170}
171
172EnterpriseEnrollmentDataSource::EnterpriseEnrollmentDataSource()
173    : DataSource(chrome::kChromeUIEnterpriseEnrollmentHost,
174                 MessageLoop::current()) {}
175
176void EnterpriseEnrollmentDataSource::StartDataRequest(const std::string& path,
177                                                      bool is_off_the_record,
178                                                      int request_id) {
179  ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
180
181  DictionaryValue strings;
182  std::string response;
183  if (path.empty()) {
184    AddString(&strings, "loginHeader",
185              IDS_ENTERPRISE_ENROLLMENT_LOGIN_HEADER),
186    AddString(&strings, "loginExplain",
187              IDS_ENTERPRISE_ENROLLMENT_LOGIN_EXPLAIN,
188              l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
189    AddString(&strings, "cloudHeader",
190              IDS_ENTERPRISE_ENROLLMENT_CLOUD_HEADER),
191    AddString(&strings, "cloudExplain",
192              IDS_ENTERPRISE_ENROLLMENT_CLOUD_EXPLAIN);
193    AddString(&strings, "accesscontrolHeader",
194              IDS_ENTERPRISE_ENROLLMENT_ACCESSCONTROL_HEADER),
195    AddString(&strings, "accesscontrolExplain",
196              IDS_ENTERPRISE_ENROLLMENT_ACCESSCONTROL_EXPLAIN);
197    AddString(&strings, "confirmationHeader",
198              IDS_ENTERPRISE_ENROLLMENT_CONFIRMATION_HEADER);
199    AddString(&strings, "confirmationMessage",
200              IDS_ENTERPRISE_ENROLLMENT_CONFIRMATION_MESSAGE);
201    AddString(&strings, "confirmationClose",
202              IDS_ENTERPRISE_ENROLLMENT_CONFIRMATION_CLOSE);
203
204    static const base::StringPiece html(
205        resource_bundle.GetRawDataResource(IDR_ENTERPRISE_ENROLLMENT_HTML));
206    SetFontAndTextDirection(&strings);
207    response = jstemplate_builder::GetI18nTemplateHtml(html, &strings);
208  } else if (path == kEnterpriseEnrollmentGaiaLoginPath) {
209    strings.SetString("invalidpasswordhelpurl", "");
210    strings.SetString("invalidaccessaccounturl", "");
211    strings.SetString("cannotaccessaccount", "");
212    strings.SetString("cannotaccessaccounturl", "");
213    strings.SetString("createaccount", "");
214    strings.SetString("createnewaccounturl", "");
215    strings.SetString("getaccesscodehelp", "");
216    strings.SetString("getaccesscodeurl", "");
217
218    // None of the strings used here currently have sync-specific wording in
219    // them.  We have a unit test to catch if that happens.
220    strings.SetString("introduction", "");
221    AddString(&strings, "signinprefix", IDS_SYNC_LOGIN_SIGNIN_PREFIX);
222    AddString(&strings, "signinsuffix", IDS_SYNC_LOGIN_SIGNIN_SUFFIX);
223    AddString(&strings, "cannotbeblank", IDS_SYNC_CANNOT_BE_BLANK);
224    AddString(&strings, "emaillabel", IDS_SYNC_LOGIN_EMAIL);
225    AddString(&strings, "passwordlabel", IDS_SYNC_LOGIN_PASSWORD);
226    AddString(&strings, "invalidcredentials",
227              IDS_SYNC_INVALID_USER_CREDENTIALS);
228    AddString(&strings, "signin", IDS_SYNC_SIGNIN);
229    AddString(&strings, "couldnotconnect", IDS_SYNC_LOGIN_COULD_NOT_CONNECT);
230    AddString(&strings, "cancel", IDS_CANCEL);
231    AddString(&strings, "settingup", IDS_SYNC_LOGIN_SETTING_UP);
232    AddString(&strings, "success", IDS_SYNC_SUCCESS);
233    AddString(&strings, "errorsigningin", IDS_SYNC_ERROR_SIGNING_IN);
234    AddString(&strings, "captchainstructions",
235              IDS_SYNC_GAIA_CAPTCHA_INSTRUCTIONS);
236    AddString(&strings, "invalidaccesscode",
237              IDS_SYNC_INVALID_ACCESS_CODE_LABEL);
238    AddString(&strings, "enteraccesscode", IDS_SYNC_ENTER_ACCESS_CODE_LABEL);
239
240    static const base::StringPiece html(resource_bundle.GetRawDataResource(
241        IDR_GAIA_LOGIN_HTML));
242    SetFontAndTextDirection(&strings);
243    response = jstemplate_builder::GetI18nTemplateHtml(html, &strings);
244  }
245
246  // Send the response.
247  scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes());
248  html_bytes->data.resize(response.size());
249  std::copy(response.begin(), response.end(), html_bytes->data.begin());
250  SendResponse(request_id, html_bytes);
251}
252
253std::string EnterpriseEnrollmentDataSource::GetMimeType(
254    const std::string& path) const {
255  return "text/html";
256}
257
258EnterpriseEnrollmentDataSource::~EnterpriseEnrollmentDataSource() {}
259
260void EnterpriseEnrollmentDataSource::AddString(DictionaryValue* dictionary,
261                                               const std::string& key,
262                                               int resource_id) {
263  dictionary->SetString(key, l10n_util::GetStringUTF16(resource_id));
264}
265
266void EnterpriseEnrollmentDataSource::AddString(DictionaryValue* dictionary,
267                                               const std::string& key,
268                                               int resource_id,
269                                               const string16& arg1) {
270  dictionary->SetString(key, l10n_util::GetStringFUTF16(resource_id, arg1));
271}
272
273EnterpriseEnrollmentUI::EnterpriseEnrollmentUI(TabContents* contents)
274    : WebUI(contents) {}
275
276EnterpriseEnrollmentUI::~EnterpriseEnrollmentUI() {}
277
278void EnterpriseEnrollmentUI::RenderViewCreated(
279    RenderViewHost* render_view_host) {
280  // Bail out early if the controller doesn't exist or web ui is disabled.
281  if (!GetController(this) || !(bindings_ & BindingsPolicy::WEB_UI))
282    return;
283
284  WebUIMessageHandler* handler = new EnterpriseEnrollmentMessageHandler();
285  AddMessageHandler(handler->Attach(this));
286
287  // Set up the data source, so the enrollment page can be loaded.
288  tab_contents()->profile()->GetChromeURLDataManager()->AddDataSource(
289      new EnterpriseEnrollmentDataSource());
290
291  std::string user;
292  bool has_init_user = GetController(this)->GetInitialUser(&user);
293  if (!has_init_user)
294    user = "";
295  // Set the arguments for showing the gaia login page.
296  DictionaryValue args;
297  args.SetString("user", user);
298  args.SetInteger("error", 0);
299  args.SetBoolean("editable_user", !has_init_user);
300  args.SetString("initialScreen", "login-screen");
301  std::string json_args;
302  base::JSONWriter::Write(&args, false, &json_args);
303  render_view_host->SetWebUIProperty("dialogArguments", json_args);
304}
305
306// static
307EnterpriseEnrollmentUI::Controller* EnterpriseEnrollmentUI::GetController(
308    WebUI* ui) {
309  Controller** controller =
310      g_enrollment_ui_controller_property.Get().GetProperty(
311          ui->tab_contents()->property_bag());
312
313  return controller ? *controller : NULL;
314}
315
316// static
317void EnterpriseEnrollmentUI::SetController(
318    TabContents* contents,
319    EnterpriseEnrollmentUI::Controller* controller) {
320  g_enrollment_ui_controller_property.Get().SetProperty(
321      contents->property_bag(),
322      controller);
323}
324
325}  // namespace chromeos
326