| OLD | NEW |
| (Empty) |
| 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/utf_string_conversions.h" | |
| 16 #include "base/values.h" | |
| 17 #include "chrome/browser/prefs/pref_service.h" | |
| 18 #include "chrome/browser/profiles/profile.h" | |
| 19 #include "chrome/browser/sync/profile_sync_service.h" | |
| 20 #include "chrome/browser/sync/sync_setup_flow.h" | |
| 21 #include "chrome/browser/ui/webui/chrome_url_data_manager.h" | |
| 22 #include "chrome/browser/ui/webui/constrained_html_ui.h" | |
| 23 #include "chrome/browser/ui/webui/html_dialog_ui.h" | |
| 24 #include "chrome/common/chrome_notification_types.h" | |
| 25 #include "chrome/common/jstemplate_builder.h" | |
| 26 #include "chrome/common/pref_names.h" | |
| 27 #include "chrome/common/url_constants.h" | |
| 28 #include "content/browser/browser_thread.h" | |
| 29 #include "content/browser/renderer_host/render_view_host.h" | |
| 30 #include "content/browser/tab_contents/tab_contents.h" | |
| 31 #include "content/common/notification_details.h" | |
| 32 #include "content/common/notification_source.h" | |
| 33 #include "grit/browser_resources.h" | |
| 34 #include "ui/base/resource/resource_bundle.h" | |
| 35 | |
| 36 class BrowserSigninResourcesSource : public ChromeURLDataManager::DataSource { | |
| 37 public: | |
| 38 BrowserSigninResourcesSource() | |
| 39 : DataSource(chrome::kChromeUIDialogHost, MessageLoop::current()) { | |
| 40 } | |
| 41 | |
| 42 virtual void StartDataRequest(const std::string& path, | |
| 43 bool is_incognito, | |
| 44 int request_id); | |
| 45 | |
| 46 virtual std::string GetMimeType(const std::string& path) const { | |
| 47 return "text/html"; | |
| 48 } | |
| 49 | |
| 50 private: | |
| 51 virtual ~BrowserSigninResourcesSource() {} | |
| 52 | |
| 53 DISALLOW_COPY_AND_ASSIGN(BrowserSigninResourcesSource); | |
| 54 }; | |
| 55 | |
| 56 void BrowserSigninResourcesSource::StartDataRequest(const std::string& path, | |
| 57 bool is_incognito, | |
| 58 int request_id) { | |
| 59 const char kSigninPath[] = "signin"; | |
| 60 | |
| 61 std::string response; | |
| 62 if (path == kSigninPath) { | |
| 63 const base::StringPiece html( | |
| 64 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
| 65 IDR_SIGNIN_HTML)); | |
| 66 DictionaryValue dict; | |
| 67 SetFontAndTextDirection(&dict); | |
| 68 response = jstemplate_builder::GetI18nTemplateHtml(html, &dict); | |
| 69 } | |
| 70 | |
| 71 SendResponse(request_id, base::RefCountedString::TakeString(&response)); | |
| 72 } | |
| 73 | |
| 74 class BrowserSigninHtml : public HtmlDialogUIDelegate, | |
| 75 public WebUIMessageHandler { | |
| 76 public: | |
| 77 BrowserSigninHtml(BrowserSignin* signin, | |
| 78 const string16& suggested_email, | |
| 79 const string16& login_message); | |
| 80 virtual ~BrowserSigninHtml() {} | |
| 81 | |
| 82 // HtmlDialogUIDelegate implementation | |
| 83 virtual bool IsDialogModal() const OVERRIDE { | |
| 84 return false; | |
| 85 }; | |
| 86 virtual string16 GetDialogTitle() const OVERRIDE { | |
| 87 return string16(); | |
| 88 } | |
| 89 virtual GURL GetDialogContentURL() const OVERRIDE { | |
| 90 return GURL("chrome://dialog/signin"); | |
| 91 } | |
| 92 virtual void GetWebUIMessageHandlers( | |
| 93 std::vector<WebUIMessageHandler*>* handlers) const OVERRIDE { | |
| 94 const WebUIMessageHandler* handler = this; | |
| 95 handlers->push_back(const_cast<WebUIMessageHandler*>(handler)); | |
| 96 } | |
| 97 virtual void GetDialogSize(gfx::Size* size) const OVERRIDE { | |
| 98 size->set_width(600); | |
| 99 size->set_height(300); | |
| 100 } | |
| 101 virtual std::string GetDialogArgs() const OVERRIDE { | |
| 102 return UTF16ToASCII(login_message_); | |
| 103 } | |
| 104 virtual void OnDialogClosed(const std::string& json_retval) OVERRIDE { | |
| 105 closed_ = true; | |
| 106 signin_->Cancel(); | |
| 107 } | |
| 108 virtual void OnCloseContents(TabContents* source, | |
| 109 bool* out_close_dialog) OVERRIDE { | |
| 110 } | |
| 111 virtual bool ShouldShowDialogTitle() const OVERRIDE { return true; } | |
| 112 | |
| 113 // WebUIMessageHandler implementation. | |
| 114 virtual void RegisterMessages() OVERRIDE; | |
| 115 | |
| 116 // Refreshes the UI, such as after an authentication error. | |
| 117 void ReloadUI(); | |
| 118 | |
| 119 // Method which calls into javascript to force the dialog to close. | |
| 120 void ForceDialogClose(); | |
| 121 | |
| 122 private: | |
| 123 // JS callback handlers. | |
| 124 void HandleSigninInit(const ListValue* args); | |
| 125 void HandleSubmitAuth(const ListValue* args); | |
| 126 | |
| 127 // Nonowned pointer; |signin_| owns this object. | |
| 128 BrowserSignin* signin_; | |
| 129 | |
| 130 string16 suggested_email_; | |
| 131 string16 login_message_; | |
| 132 | |
| 133 bool closed_; | |
| 134 }; | |
| 135 | |
| 136 BrowserSigninHtml::BrowserSigninHtml(BrowserSignin* signin, | |
| 137 const string16& suggested_email, | |
| 138 const string16& login_message) | |
| 139 : signin_(signin), | |
| 140 suggested_email_(suggested_email), | |
| 141 login_message_(login_message), | |
| 142 closed_(false) { | |
| 143 } | |
| 144 | |
| 145 void BrowserSigninHtml::RegisterMessages() { | |
| 146 web_ui_->RegisterMessageCallback( | |
| 147 "SubmitAuth", NewCallback(this, &BrowserSigninHtml::HandleSubmitAuth)); | |
| 148 web_ui_->RegisterMessageCallback( | |
| 149 "SigninInit", NewCallback(this, &BrowserSigninHtml::HandleSigninInit)); | |
| 150 } | |
| 151 | |
| 152 void BrowserSigninHtml::ReloadUI() { | |
| 153 HandleSigninInit(NULL); | |
| 154 } | |
| 155 | |
| 156 void BrowserSigninHtml::ForceDialogClose() { | |
| 157 if (!closed_ && web_ui_) { | |
| 158 StringValue value("DialogClose"); | |
| 159 ListValue close_args; | |
| 160 close_args.Append(new StringValue("")); | |
| 161 web_ui_->CallJavascriptFunction("chrome.send", value, close_args); | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 void BrowserSigninHtml::HandleSigninInit(const ListValue* args) { | |
| 166 if (!web_ui_) | |
| 167 return; | |
| 168 | |
| 169 RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host(); | |
| 170 rvh->ExecuteJavascriptInWebFrame(ASCIIToUTF16("//iframe[@id='login']"), | |
| 171 ASCIIToUTF16("hideBlurb();")); | |
| 172 | |
| 173 DictionaryValue json_args; | |
| 174 std::string json; | |
| 175 std::wstring javascript(L""); | |
| 176 SyncSetupFlow::GetArgsForGaiaLogin(signin_->GetProfileSyncService(), | |
| 177 &json_args); | |
| 178 | |
| 179 // Replace the suggested email, unless sync has already required a | |
| 180 // particular value. | |
| 181 bool is_editable; | |
| 182 std::string user; | |
| 183 if (!json_args.GetBoolean("editable_user", &is_editable)) | |
| 184 is_editable = false; | |
| 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 | |
| 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 | |
| 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 | |
| 229 BrowserSignin::~BrowserSignin() { | |
| 230 delegate_ = NULL; | |
| 231 } | |
| 232 | |
| 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 | |
| 249 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 | |
| 256 void BrowserSignin::Observe(int type, | |
| 257 const NotificationSource& source, | |
| 258 const NotificationDetails& details) { | |
| 259 switch (type) { | |
| 260 case chrome::NOTIFICATION_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 chrome::NOTIFICATION_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 | |
| 279 void BrowserSignin::Cancel() { | |
| 280 if (delegate_) { | |
| 281 delegate_->OnLoginFailure(GoogleServiceAuthError( | |
| 282 GoogleServiceAuthError::REQUEST_CANCELED)); | |
| 283 GetProfileSyncService()->OnUserCancelledDialog(); | |
| 284 } | |
| 285 OnLoginFinished(); | |
| 286 } | |
| 287 | |
| 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 | |
| 301 ProfileSyncService* BrowserSignin::GetProfileSyncService() const { | |
| 302 return profile_->GetProfileSyncService(); | |
| 303 } | |
| 304 | |
| 305 BrowserSigninHtml* BrowserSignin::CreateHtmlDialogUI() { | |
| 306 return new BrowserSigninHtml(this, suggested_email_, login_message_); | |
| 307 } | |
| 308 | |
| 309 void BrowserSignin::RegisterAuthNotifications() { | |
| 310 registrar_.Add(this, | |
| 311 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, | |
| 312 Source<Profile>(profile_)); | |
| 313 registrar_.Add(this, | |
| 314 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, | |
| 315 Source<Profile>(profile_)); | |
| 316 } | |
| 317 | |
| 318 void BrowserSignin::UnregisterAuthNotifications() { | |
| 319 registrar_.Remove(this, | |
| 320 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, | |
| 321 Source<Profile>(profile_)); | |
| 322 registrar_.Remove(this, | |
| 323 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, | |
| 324 Source<Profile>(profile_)); | |
| 325 } | |
| 326 | |
| 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 } | |
| OLD | NEW |