• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/browser_signin.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h"
12 #include "base/memory/singleton.h"
13 #include "base/message_loop.h"
14 #include "base/string_util.h"
15 #include "base/values.h"
16 #include "chrome/browser/prefs/pref_service.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/sync/profile_sync_service.h"
19 #include "chrome/browser/sync/sync_setup_flow.h"
20 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
21 #include "chrome/browser/ui/webui/constrained_html_ui.h"
22 #include "chrome/browser/ui/webui/html_dialog_ui.h"
23 #include "chrome/common/jstemplate_builder.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/common/url_constants.h"
26 #include "content/browser/browser_thread.h"
27 #include "content/browser/renderer_host/render_view_host.h"
28 #include "content/browser/tab_contents/tab_contents.h"
29 #include "content/common/notification_details.h"
30 #include "content/common/notification_source.h"
31 #include "content/common/notification_type.h"
32 #include "grit/browser_resources.h"
33 #include "ui/base/resource/resource_bundle.h"
34 
35 class BrowserSigninResourcesSource : public ChromeURLDataManager::DataSource {
36  public:
BrowserSigninResourcesSource()37   BrowserSigninResourcesSource()
38       : DataSource(chrome::kChromeUIDialogHost, MessageLoop::current()) {
39   }
40 
41   virtual void StartDataRequest(const std::string& path,
42                                 bool is_incognito,
43                                 int request_id);
44 
GetMimeType(const std::string & path) const45   virtual std::string GetMimeType(const std::string& path) const {
46     return "text/html";
47   }
48 
49  private:
~BrowserSigninResourcesSource()50   virtual ~BrowserSigninResourcesSource() {}
51 
52   DISALLOW_COPY_AND_ASSIGN(BrowserSigninResourcesSource);
53 };
54 
StartDataRequest(const std::string & path,bool is_incognito,int request_id)55 void BrowserSigninResourcesSource::StartDataRequest(const std::string& path,
56                                                     bool is_incognito,
57                                                     int request_id) {
58   const char kSigninPath[] = "signin";
59 
60   std::string response;
61   if (path == kSigninPath) {
62     const base::StringPiece html(
63         ResourceBundle::GetSharedInstance().GetRawDataResource(
64             IDR_SIGNIN_HTML));
65     DictionaryValue dict;
66     SetFontAndTextDirection(&dict);
67     response = jstemplate_builder::GetI18nTemplateHtml(html, &dict);
68   }
69 
70   scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
71   html_bytes->data.resize(response.size());
72   std::copy(response.begin(), response.end(), html_bytes->data.begin());
73   SendResponse(request_id, html_bytes);
74 }
75 
76 class BrowserSigninHtml : public HtmlDialogUIDelegate,
77                           public WebUIMessageHandler {
78  public:
79   BrowserSigninHtml(BrowserSignin* signin,
80                     const string16& suggested_email,
81                     const string16& login_message);
~BrowserSigninHtml()82   virtual ~BrowserSigninHtml() {}
83 
84   // HtmlDialogUIDelegate implementation
IsDialogModal() const85   virtual bool IsDialogModal() const {
86     return false;
87   };
GetDialogTitle() const88   virtual std::wstring GetDialogTitle() const {
89     return L"";
90   }
GetDialogContentURL() const91   virtual GURL GetDialogContentURL() const {
92     return GURL("chrome://dialog/signin");
93   }
GetWebUIMessageHandlers(std::vector<WebUIMessageHandler * > * handlers) const94   virtual void GetWebUIMessageHandlers(
95       std::vector<WebUIMessageHandler*>* handlers) const {
96     const WebUIMessageHandler* handler = this;
97     handlers->push_back(const_cast<WebUIMessageHandler*>(handler));
98   }
GetDialogSize(gfx::Size * size) const99   virtual void GetDialogSize(gfx::Size* size) const {
100     size->set_width(600);
101     size->set_height(300);
102   }
GetDialogArgs() const103   virtual std::string GetDialogArgs() const {
104     return UTF16ToASCII(login_message_);
105   }
OnDialogClosed(const std::string & json_retval)106   virtual void OnDialogClosed(const std::string& json_retval) {
107     closed_ = true;
108     signin_->Cancel();
109   }
OnCloseContents(TabContents * source,bool * out_close_dialog)110   virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) {
111   }
ShouldShowDialogTitle() const112   virtual bool ShouldShowDialogTitle() const { return true; }
113 
114   // WebUIMessageHandler implementation.
115   virtual void RegisterMessages();
116 
117   // Refreshes the UI, such as after an authentication error.
118   void ReloadUI();
119 
120   // Method which calls into javascript to force the dialog to close.
121   void ForceDialogClose();
122 
123  private:
124   // JS callback handlers.
125   void HandleSigninInit(const ListValue* args);
126   void HandleSubmitAuth(const ListValue* args);
127 
128   // Nonowned pointer; |signin_| owns this object.
129   BrowserSignin* signin_;
130 
131   string16 suggested_email_;
132   string16 login_message_;
133 
134   bool closed_;
135 };
136 
BrowserSigninHtml(BrowserSignin * signin,const string16 & suggested_email,const string16 & login_message)137 BrowserSigninHtml::BrowserSigninHtml(BrowserSignin* signin,
138                                      const string16& suggested_email,
139                                      const string16& login_message)
140     : signin_(signin),
141       suggested_email_(suggested_email),
142       login_message_(login_message),
143       closed_(false) {
144 }
145 
RegisterMessages()146 void BrowserSigninHtml::RegisterMessages() {
147   web_ui_->RegisterMessageCallback(
148       "SubmitAuth", NewCallback(this, &BrowserSigninHtml::HandleSubmitAuth));
149   web_ui_->RegisterMessageCallback(
150       "SigninInit", NewCallback(this, &BrowserSigninHtml::HandleSigninInit));
151 }
152 
ReloadUI()153 void BrowserSigninHtml::ReloadUI() {
154   HandleSigninInit(NULL);
155 }
156 
ForceDialogClose()157 void BrowserSigninHtml::ForceDialogClose() {
158   if (!closed_ && web_ui_) {
159     StringValue value("DialogClose");
160     ListValue close_args;
161     close_args.Append(new StringValue(""));
162     web_ui_->CallJavascriptFunction("chrome.send", value, close_args);
163   }
164 }
165 
HandleSigninInit(const ListValue * args)166 void BrowserSigninHtml::HandleSigninInit(const ListValue* args) {
167   if (!web_ui_)
168     return;
169 
170   RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
171   rvh->ExecuteJavascriptInWebFrame(ASCIIToUTF16("//iframe[@id='login']"),
172                                    ASCIIToUTF16("hideBlurb();"));
173 
174   DictionaryValue json_args;
175   std::string json;
176   std::wstring javascript(L"");
177   SyncSetupFlow::GetArgsForGaiaLogin(signin_->GetProfileSyncService(),
178                                      &json_args);
179 
180   // Replace the suggested email, unless sync has already required a
181   // particular value.
182   bool is_editable;
183   std::string user;
184   json_args.GetBoolean("editable_user", &is_editable);
185   json_args.GetString("user", &user);
186   if (is_editable && user.empty() && !suggested_email_.empty())
187     json_args.SetString("user", suggested_email_);
188 
189   base::JSONWriter::Write(&json_args, false, &json);
190   javascript += L"showGaiaLogin(" + UTF8ToWide(json) + L");";
191   rvh->ExecuteJavascriptInWebFrame(ASCIIToUTF16("//iframe[@id='login']"),
192                                    WideToUTF16Hack(javascript));
193 }
194 
HandleSubmitAuth(const ListValue * args)195 void BrowserSigninHtml::HandleSubmitAuth(const ListValue* args) {
196   std::string json;
197   if (!args->GetString(0, &json))
198     NOTREACHED() << "Could not read JSON argument";
199 
200   scoped_ptr<DictionaryValue> result(static_cast<DictionaryValue*>(
201       base::JSONReader::Read(json, false)));
202   std::string username;
203   std::string password;
204   std::string captcha;
205   std::string access_code;
206   if (!result.get() ||
207       !result->GetString("user", &username) ||
208       !result->GetString("pass", &password) ||
209       !result->GetString("captcha", &captcha) ||
210       !result->GetString("access_code", &access_code)) {
211     LOG(ERROR) << "Unintelligble format for authentication data from page.";
212     signin_->Cancel();
213   }
214   signin_->GetProfileSyncService()->OnUserSubmittedAuth(
215       username, password, captcha, access_code);
216 }
217 
BrowserSignin(Profile * profile)218 BrowserSignin::BrowserSignin(Profile* profile)
219     : profile_(profile),
220       delegate_(NULL),
221       html_dialog_ui_delegate_(NULL) {
222   // profile is NULL during testing.
223   if (profile) {
224     BrowserSigninResourcesSource* source = new BrowserSigninResourcesSource();
225     profile->GetChromeURLDataManager()->AddDataSource(source);
226   }
227 }
228 
~BrowserSignin()229 BrowserSignin::~BrowserSignin() {
230   delegate_ = NULL;
231 }
232 
RequestSignin(TabContents * tab_contents,const string16 & suggested_email,const string16 & login_message,SigninDelegate * delegate)233 void BrowserSignin::RequestSignin(TabContents* tab_contents,
234                                   const string16& suggested_email,
235                                   const string16& login_message,
236                                   SigninDelegate* delegate) {
237   CHECK(tab_contents);
238   CHECK(delegate);
239   // Cancel existing request.
240   if (delegate_)
241     Cancel();
242   delegate_ = delegate;
243   suggested_email_ = suggested_email;
244   login_message_ = login_message;
245   RegisterAuthNotifications();
246   ShowSigninTabModal(tab_contents);
247 }
248 
GetSignedInUsername() const249 std::string BrowserSignin::GetSignedInUsername() const {
250   std::string username =
251       profile_->GetPrefs()->GetString(prefs::kGoogleServicesUsername);
252   VLOG(1) << "GetSignedInUsername: " << username;
253   return username;
254 }
255 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)256 void BrowserSignin::Observe(NotificationType type,
257                             const NotificationSource& source,
258                             const NotificationDetails& details) {
259   switch (type.value) {
260     case NotificationType::GOOGLE_SIGNIN_SUCCESSFUL: {
261       VLOG(1) << "GOOGLE_SIGNIN_SUCCESSFUL";
262       if (delegate_)
263         delegate_->OnLoginSuccess();
264       // Close the dialog.
265       OnLoginFinished();
266       break;
267     }
268     case NotificationType::GOOGLE_SIGNIN_FAILED: {
269       VLOG(1) << "GOOGLE_SIGNIN_FAILED";
270       // The signin failed, refresh the UI with error information.
271       html_dialog_ui_delegate_->ReloadUI();
272       break;
273     }
274     default:
275       NOTREACHED();
276   }
277 }
278 
Cancel()279 void BrowserSignin::Cancel() {
280   if (delegate_) {
281     delegate_->OnLoginFailure(GoogleServiceAuthError(
282         GoogleServiceAuthError::REQUEST_CANCELED));
283     GetProfileSyncService()->OnUserCancelledDialog();
284   }
285   OnLoginFinished();
286 }
287 
OnLoginFinished()288 void BrowserSignin::OnLoginFinished() {
289   if (html_dialog_ui_delegate_)
290     html_dialog_ui_delegate_->ForceDialogClose();
291   // The dialog will be deleted by WebUI due to the dialog close,
292   // don't hold a reference.
293   html_dialog_ui_delegate_ = NULL;
294 
295   if (delegate_) {
296     UnregisterAuthNotifications();
297     delegate_ = NULL;
298   }
299 }
300 
GetProfileSyncService() const301 ProfileSyncService* BrowserSignin::GetProfileSyncService() const {
302   return profile_->GetProfileSyncService();
303 }
304 
CreateHtmlDialogUI()305 BrowserSigninHtml* BrowserSignin::CreateHtmlDialogUI() {
306   return new BrowserSigninHtml(this, suggested_email_, login_message_);
307 }
308 
RegisterAuthNotifications()309 void BrowserSignin::RegisterAuthNotifications() {
310   registrar_.Add(this,
311                  NotificationType::GOOGLE_SIGNIN_SUCCESSFUL,
312                  Source<Profile>(profile_));
313   registrar_.Add(this,
314                  NotificationType::GOOGLE_SIGNIN_FAILED,
315                  Source<Profile>(profile_));
316 }
317 
UnregisterAuthNotifications()318 void BrowserSignin::UnregisterAuthNotifications() {
319   registrar_.Remove(this,
320                     NotificationType::GOOGLE_SIGNIN_SUCCESSFUL,
321                     Source<Profile>(profile_));
322   registrar_.Remove(this,
323                     NotificationType::GOOGLE_SIGNIN_FAILED,
324                     Source<Profile>(profile_));
325 }
326 
ShowSigninTabModal(TabContents * tab_contents)327 void BrowserSignin::ShowSigninTabModal(TabContents* tab_contents) {
328 //  TODO(johnnyg): Need a linux views implementation for ConstrainedHtmlDialog.
329 #if defined(OS_WIN) || defined(OS_CHROMEOS) || !defined(TOOLKIT_VIEWS)
330   html_dialog_ui_delegate_ = CreateHtmlDialogUI();
331   ConstrainedHtmlUI::CreateConstrainedHtmlDialog(profile_,
332                                                  html_dialog_ui_delegate_,
333                                                  tab_contents);
334 #endif
335 }
336