NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / resources / gaia_auth / main.js
blob2d19c7d419f43f375ff15a817fcaabea276bface
1 // Copyright (c) 2012 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.
5 /**
6 * Authenticator class wraps the communications between Gaia and its host.
7 */
8 function Authenticator() {
11 /**
12 * Gaia auth extension url origin.
13 * @type {string}
15 Authenticator.THIS_EXTENSION_ORIGIN =
16 'chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik';
18 /**
19 * Singleton getter of Authenticator.
20 * @return {Object} The singleton instance of Authenticator.
22 Authenticator.getInstance = function() {
23 if (!Authenticator.instance_) {
24 Authenticator.instance_ = new Authenticator();
26 return Authenticator.instance_;
29 Authenticator.prototype = {
30 email_: null,
31 password_: null,
32 attemptToken_: null,
34 // Input params from extension initialization URL.
35 inputLang_: undefined,
36 intputEmail_: undefined,
38 isSAMLFlow_: false,
39 isSAMLEnabled_: false,
40 supportChannel_: null,
42 GAIA_URL: 'https://accounts.google.com/',
43 GAIA_PAGE_PATH: 'ServiceLogin?skipvpage=true&sarp=1&rm=hide',
44 PARENT_PAGE: 'chrome://oobe/',
45 SERVICE_ID: 'chromeoslogin',
46 CONTINUE_URL: Authenticator.THIS_EXTENSION_ORIGIN + '/success.html',
47 CONSTRAINED_FLOW_SOURCE: 'chrome',
49 initialize: function() {
50 var params = getUrlSearchParams(location.search);
51 this.parentPage_ = params.parentPage || this.PARENT_PAGE;
52 this.gaiaUrl_ = params.gaiaUrl || this.GAIA_URL;
53 this.gaiaPath_ = params.gaiaPath || this.GAIA_PAGE_PATH;
54 this.inputLang_ = params.hl;
55 this.inputEmail_ = params.email;
56 this.service_ = params.service || this.SERVICE_ID;
57 this.continueUrl_ = params.continueUrl || this.CONTINUE_URL;
58 this.desktopMode_ = params.desktopMode == '1';
59 this.isConstrainedWindow_ = params.constrained == '1';
60 this.initialFrameUrl_ = params.frameUrl || this.constructInitialFrameUrl_();
61 this.initialFrameUrlWithoutParams_ = stripParams(this.initialFrameUrl_);
63 if (this.desktopMode_) {
64 this.supportChannel_ = new Channel();
65 this.supportChannel_.connect('authMain');
67 this.supportChannel_.send({
68 name: 'initDesktopFlow',
69 gaiaUrl: this.gaiaUrl_,
70 continueUrl: stripParams(this.continueUrl_),
71 isConstrainedWindow: this.isConstrainedWindow_
72 });
74 this.supportChannel_.registerMessage(
75 'switchToFullTab', this.switchToFullTab_.bind(this));
76 this.supportChannel_.registerMessage(
77 'completeLogin', this.completeLogin_.bind(this));
80 document.addEventListener('DOMContentLoaded', this.onPageLoad_.bind(this));
81 document.addEventListener('enableSAML', this.onEnableSAML_.bind(this));
84 isGaiaMessage_: function(msg) {
85 // Not quite right, but good enough.
86 return this.gaiaUrl_.indexOf(msg.origin) == 0 ||
87 this.GAIA_URL.indexOf(msg.origin) == 0;
90 isInternalMessage_: function(msg) {
91 return msg.origin == Authenticator.THIS_EXTENSION_ORIGIN;
94 isParentMessage_: function(msg) {
95 return msg.origin == this.parentPage_;
98 constructInitialFrameUrl_: function() {
99 var url = this.gaiaUrl_ + this.gaiaPath_;
101 url = appendParam(url, 'service', this.service_);
102 url = appendParam(url, 'continue', this.continueUrl_);
103 if (this.inputLang_)
104 url = appendParam(url, 'hl', this.inputLang_);
105 if (this.inputEmail_)
106 url = appendParam(url, 'Email', this.inputEmail_);
107 if (this.isConstrainedWindow_)
108 url = appendParam(url, 'source', this.CONSTRAINED_FLOW_SOURCE);
109 return url;
112 onPageLoad_: function() {
113 window.addEventListener('message', this.onMessage.bind(this), false);
114 this.loadFrame_();
117 loadFrame_: function() {
118 var gaiaFrame = $('gaia-frame');
119 gaiaFrame.src = this.initialFrameUrl_;
120 if (this.desktopMode_) {
121 var handler = function() {
122 this.onLoginUILoaded_();
123 gaiaFrame.removeEventListener('load', handler);
124 }.bind(this);
125 gaiaFrame.addEventListener('load', handler);
130 * Invoked when the login UI is initialized or reset.
132 onLoginUILoaded_: function() {
133 var msg = {
134 'method': 'loginUILoaded'
136 window.parent.postMessage(msg, this.parentPage_);
140 * Invoked when the background script sends a message to indicate that the
141 * current content does not fit in a constrained window.
142 * @param {Object=} opt_extraMsg Optional extra info to send.
144 switchToFullTab_: function(msg) {
145 var parentMsg = {
146 'method': 'switchToFullTab',
147 'url': msg.url
149 window.parent.postMessage(parentMsg, this.parentPage_);
153 * Invoked when the signin flow is complete.
154 * @param {Object=} opt_extraMsg Optional extra info to send.
156 completeLogin_: function(opt_extraMsg) {
157 var msg = {
158 'method': 'completeLogin',
159 'email': (opt_extraMsg && opt_extraMsg.email) || this.email_,
160 'password': this.password_,
161 'usingSAML': this.isSAMLFlow_,
162 'chooseWhatToSync': this.chooseWhatToSync_ || false,
163 'skipForNow': opt_extraMsg && opt_extraMsg.skipForNow,
164 'sessionIndex': opt_extraMsg && opt_extraMsg.sessionIndex
166 window.parent.postMessage(msg, this.parentPage_);
167 if (this.isSAMLEnabled_)
168 this.supportChannel_.send({name: 'resetAuth'});
172 * Invoked when 'enableSAML' event is received to initialize SAML support.
174 onEnableSAML_: function() {
175 this.isSAMLEnabled_ = true;
176 this.isSAMLFlow_ = false;
178 if (!this.supportChannel_) {
179 this.supportChannel_ = new Channel();
180 this.supportChannel_.connect('authMain');
183 this.supportChannel_.registerMessage(
184 'onAuthPageLoaded', this.onAuthPageLoaded_.bind(this));
185 this.supportChannel_.registerMessage(
186 'apiCall', this.onAPICall_.bind(this));
187 this.supportChannel_.send({
188 name: 'setGaiaUrl',
189 gaiaUrl: this.gaiaUrl_
194 * Invoked when the background page sends 'onHostedPageLoaded' message.
195 * @param {!Object} msg Details sent with the message.
197 onAuthPageLoaded_: function(msg) {
198 var isSAMLPage = msg.url.indexOf(this.gaiaUrl_) != 0;
200 if (isSAMLPage && !this.isSAMLFlow_) {
201 // GAIA redirected to a SAML login page. The credentials provided to this
202 // page will determine what user gets logged in. The credentials obtained
203 // from the GAIA login from are no longer relevant and can be discarded.
204 this.isSAMLFlow_ = true;
205 this.email_ = null;
206 this.password_ = null;
209 window.parent.postMessage({
210 'method': 'authPageLoaded',
211 'isSAML': this.isSAMLFlow_,
212 'domain': extractDomain(msg.url)
213 }, this.parentPage_);
217 * Invoked when one of the credential passing API methods is called by a SAML
218 * provider.
219 * @param {!Object} msg Details of the API call.
221 onAPICall_: function(msg) {
222 var call = msg.call;
223 if (call.method == 'add') {
224 this.apiToken_ = call.token;
225 this.email_ = call.user;
226 this.password_ = call.password;
227 } else if (call.method == 'confirm') {
228 if (call.token != this.apiToken_)
229 console.error('Authenticator.onAPICall_: token mismatch');
230 } else {
231 console.error('Authenticator.onAPICall_: unknown message');
235 onConfirmLogin_: function() {
236 if (!this.isSAMLFlow_) {
237 this.completeLogin_();
238 return;
241 var apiUsed = !!this.password_;
243 // Retrieve the e-mail address of the user who just authenticated from GAIA.
244 window.parent.postMessage({method: 'retrieveAuthenticatedUserEmail',
245 attemptToken: this.attemptToken_,
246 apiUsed: apiUsed},
247 this.parentPage_);
249 if (!apiUsed) {
250 this.supportChannel_.sendWithCallback(
251 {name: 'getScrapedPasswords'},
252 function(passwords) {
253 if (passwords.length == 0) {
254 window.parent.postMessage(
255 {method: 'noPassword', email: this.email_},
256 this.parentPage_);
257 } else {
258 window.parent.postMessage({method: 'confirmPassword',
259 email: this.email_,
260 passwordCount: passwords.length},
261 this.parentPage_);
263 }.bind(this));
267 maybeCompleteSAMLLogin_: function() {
268 // SAML login is complete when the user's e-mail address has been retrieved
269 // from GAIA and the user has successfully confirmed the password.
270 if (this.email_ !== null && this.password_ !== null)
271 this.completeLogin_();
274 onVerifyConfirmedPassword_: function(password) {
275 this.supportChannel_.sendWithCallback(
276 {name: 'getScrapedPasswords'},
277 function(passwords) {
278 for (var i = 0; i < passwords.length; ++i) {
279 if (passwords[i] == password) {
280 this.password_ = passwords[i];
281 this.maybeCompleteSAMLLogin_();
282 return;
285 window.parent.postMessage(
286 {method: 'confirmPassword', email: this.email_},
287 this.parentPage_);
288 }.bind(this));
291 onMessage: function(e) {
292 var msg = e.data;
293 if (msg.method == 'attemptLogin' && this.isGaiaMessage_(e)) {
294 this.email_ = msg.email;
295 this.password_ = msg.password;
296 this.attemptToken_ = msg.attemptToken;
297 this.chooseWhatToSync_ = msg.chooseWhatToSync;
298 this.isSAMLFlow_ = false;
299 if (this.isSAMLEnabled_)
300 this.supportChannel_.send({name: 'startAuth'});
301 } else if (msg.method == 'clearOldAttempts' && this.isGaiaMessage_(e)) {
302 this.email_ = null;
303 this.password_ = null;
304 this.attemptToken_ = null;
305 this.isSAMLFlow_ = false;
306 this.onLoginUILoaded_();
307 if (this.isSAMLEnabled_)
308 this.supportChannel_.send({name: 'resetAuth'});
309 } else if (msg.method == 'setAuthenticatedUserEmail' &&
310 this.isParentMessage_(e)) {
311 if (this.attemptToken_ == msg.attemptToken) {
312 this.email_ = msg.email;
313 this.maybeCompleteSAMLLogin_();
315 } else if (msg.method == 'confirmLogin' && this.isInternalMessage_(e)) {
316 if (this.attemptToken_ == msg.attemptToken)
317 this.onConfirmLogin_();
318 else
319 console.error('Authenticator.onMessage: unexpected attemptToken!?');
320 } else if (msg.method == 'verifyConfirmedPassword' &&
321 this.isParentMessage_(e)) {
322 this.onVerifyConfirmedPassword_(msg.password);
323 } else if (msg.method == 'navigate' &&
324 this.isParentMessage_(e)) {
325 $('gaia-frame').src = msg.src;
326 } else if (msg.method == 'redirectToSignin' &&
327 this.isParentMessage_(e)) {
328 $('gaia-frame').src = this.constructInitialFrameUrl_();
329 } else {
330 console.error('Authenticator.onMessage: unknown message + origin!?');
335 Authenticator.getInstance().initialize();