Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(287)

Unified Diff: remoting/webapp/identity.js

Issue 11769002: Apps v2 identity integration. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed identity.js from html. Fixed patch. Created 7 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: remoting/webapp/identity.js
diff --git a/remoting/webapp/identity.js b/remoting/webapp/identity.js
new file mode 100644
index 0000000000000000000000000000000000000000..3734bc6530eab4e0688257a026ea9b4ed8ef2de9
--- /dev/null
+++ b/remoting/webapp/identity.js
@@ -0,0 +1,193 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * Wrapper class for Chrome's identity API.
+ */
+
+'use strict';
+
+/** @suppress {duplicate} */
+var remoting = remoting || {};
+
+/**
+ * TODO(jamiewalch): Remove the remoting.OAuth2 possibility when the Apps v2
Wez 2013/01/05 00:04:24 nit: "the" and "possibility" are redundant here.
Jamie 2013/01/05 01:32:54 Done.
+ * work is complete.
+ *
+ * @type {remoting.Identity|remoting.OAuth2}
+ */
+remoting.identity = null;
+
+
+/**
+ * @param {HTMLElement} authDialog The authentication dialog, to be displayed
+ * if user permission is required to obtain an access token.
+ * @param {HTMLElement} authButton The "Continue" button, which must be a
+ * visible child of the dialog.
+ * @constructor
+ */
+remoting.Identity = function(authDialog, authButton) {
Wez 2013/01/05 00:04:24 This arrangement is a little strange; this class s
Jamie 2013/01/05 01:32:54 Done.
+ /** @private */
+ this.dialog_ = authDialog;
+ /** @type {?string} @private */
+ this.email_ = null;
+ /** @type {Array.<remoting.Identity.Callbacks>} */
+ this.pendingCallbacks_ = [];
+ authButton.addEventListener('click', this.onAuthContinue_.bind(this), false);
+};
+
+/**
+ * Call a function with an access token.
+ *
+ * @param {function(string):void} onOk Function to invoke with access token if
+ * an access token was successfully retrieved.
+ * @param {function(remoting.Error):void} onError Function to invoke with an
+ * error code on failure.
+ * @return {void} Nothing.
+ */
+remoting.Identity.prototype.callWithToken = function(onOk, onError) {
+ this.pendingCallbacks_.push(new remoting.Identity.Callbacks(onOk, onError));
+ if (this.pendingCallbacks_.length == 1) {
+ chrome.experimental.identity.getAuthToken(
+ { 'interactive': false },
+ this.onAuthComplete_.bind(this, false));
+ }
+};
+
+/**
+ * Get the user's email address.
+ *
+ * @param {function(string):void} onOk Callback invoked when the email
+ * address is available.
+ * @param {function(remoting.Error):void} onError Callback invoked if an
+ * error occurs.
+ * @return {void} Nothing.
+ */
+remoting.Identity.prototype.getEmail = function(onOk, onError) {
+ /** @type {remoting.Identity} */
+ var that = this;
+ /** @param {XMLHttpRequest} xhr The XHR response. */
+ var onResponse = function(xhr) {
+ var email = null;
+ if (xhr.status == 200) {
+ // TODO(ajwong): See if we can't find a JSON endpoint.
Wez 2013/01/05 00:04:24 What does this TODO mean?
Jamie 2013/01/05 01:32:54 It's essentially the same as the next TODO. I've r
+ email = xhr.responseText.split('&')[0].split('=')[1];
+ that.email_ = email;
+ onOk(email);
+ return;
+ }
+ console.error('Unable to get email address:', xhr.status, xhr);
+ if (xhr.status == 401) {
+ onError(remoting.Error.AUTHENTICATION_FAILED);
+ } else {
+ onError(that.interpretUnexpectedXhrStatus_(xhr.status));
+ }
+ };
+
+ /** @param {string} token The access token. */
+ var getEmailFromToken = function(token) {
+ var headers = { 'Authorization': 'OAuth ' + token };
+ // TODO(ajwong): Update to new v2 API.
Wez 2013/01/05 00:04:24 Does this mean use a new v2 Google API, or use an
Jamie 2013/01/05 01:32:54 There's an endpoint, https://www.googleapis.com/oa
Wez 2013/01/07 23:52:44 OK, great - can you create a bug for migrating to
Jamie 2013/01/08 22:09:10 I think Renato is in the process of fixing it as w
+ remoting.xhr.get('https://www.googleapis.com/userinfo/email',
+ onResponse, '', headers);
+ };
+
+ this.callWithToken(getEmailFromToken, onError);
+};
+
+/**
+ * Get the user's email address, or null if no successful call to getEmail
+ * has been made.
Wez 2013/01/05 00:04:24 nit: Worth noting that this may return a valid ema
Jamie 2013/01/05 01:32:54 I don't think that would add much.
+ *
+ * @return {?string} The cached email address, if available.
+ */
+remoting.Identity.prototype.getCachedEmail = function() {
+ return this.email_;
+};
+
+/**
+ * Interprets unexpected HTTP response codes to authentication XMLHttpRequests.
+ * The caller should handle the usual expected responses (200, 400) separately.
+ *
+ * @param {number} xhrStatus Status (HTTP response code) of the XMLHttpRequest.
+ * @return {remoting.Error} An error code to be raised.
+ * @private
+ */
+remoting.Identity.prototype.interpretUnexpectedXhrStatus_ = function(
+ xhrStatus) {
+ // Return AUTHENTICATION_FAILED by default, so that the user can try to
+ // recover from an unexpected failure by signing in again.
+ /** @type {remoting.Error} */
+ var error = remoting.Error.AUTHENTICATION_FAILED;
+ if (xhrStatus == 502 || xhrStatus == 503) {
+ error = remoting.Error.SERVICE_UNAVAILABLE;
+ } else if (xhrStatus == 0) {
+ error = remoting.Error.NETWORK_FAILURE;
+ } else {
+ console.warn('Unexpected authentication response code: ' + xhrStatus);
+ }
+ return error;
+};
+
+/**
+ * Callback for the getAuthToken API.
+ *
+ * @param {boolean} interactive
+ * @param {?string} token
+ * @private
+ */
+remoting.Identity.prototype.onAuthComplete_ = function(interactive, token) {
Wez 2013/01/05 00:04:24 nit: interactive -> was_interactive?
Jamie 2013/01/05 01:32:54 I've left this as it was, but added some descripti
+ // Pass the token to the callback(s) if it was retrieved successfully.
+ if (token) {
+ for (var i = 0; i < this.pendingCallbacks_.length; ++i) {
+ this.pendingCallbacks_[i].onOk(token);
Wez 2013/01/05 00:04:24 nit: Can you re-write this as a while(!empty) loop
Jamie 2013/01/05 01:32:54 Done, and also below.
+ }
+ this.pendingCallbacks_ = [];
+ return;
+ }
+
+ // If not, pass an error back to the callback(s) if we've already prompted the
+ // user for permission.
+ // TODO(jamiewalch): Figure out what to do with the error in this case.
+ if (interactive) {
+ console.error(chrome.runtime.lastError);
+ for (var i = 0; i < this.pendingCallbacks_.length; ++i) {
+ this.pendingCallbacks_[i].onError(remoting.Error.UNEXPECTED);
+ }
+ this.pendingCallbacks_ = [];
+ return;
+ }
+
+ // If there's no token, but we haven't yet prompted for permission, do so
+ // now. The flow will continue via the Continue button event handler.
+ this.dialog_.hidden = false;
+};
+
+/**
+ * Called in response to the user signing in to the web-app.
+ *
+ * @private
+ */
+remoting.Identity.prototype.onAuthContinue_ = function() {
+ this.dialog_.hidden = true;
+ chrome.experimental.identity.getAuthToken(
+ { 'interactive': true },
+ this.onAuthComplete_.bind(this, true));
+};
+
+/**
+ * Internal representation for pair of callWithToken callbacks.
+ *
+ * @param {function(string):void} onOk
+ * @param {function(remoting.Error):void} onError
+ * @constructor
+ * @private
+ */
+remoting.Identity.Callbacks = function(onOk, onError) {
+ /** @type {function(string):void} */
+ this.onOk = onOk;
+ /** @type {function(remoting.Error):void} */
+ this.onError = onError;
+};

Powered by Google App Engine
This is Rietveld 408576698