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 |