diff --git a/remoting/webapp/crd/js/identity.js b/remoting/webapp/crd/js/identity.js index aae7b396c760..0a020b03e6e4 100644 --- a/remoting/webapp/crd/js/identity.js +++ b/remoting/webapp/crd/js/identity.js @@ -31,6 +31,8 @@ remoting.Identity = function(consentCallback) { this.consentCallback_ = consentCallback; /** @type {?string} @private */ this.email_ = null; + /** @type {?string} @private */ + this.fullName_ = null; /** @type {Array.} */ this.pendingCallbacks_ = []; }; @@ -53,6 +55,31 @@ remoting.Identity.prototype.callWithToken = function(onOk, onError) { } }; +/** + * Call a function with a fresh 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.callWithNewToken = function(onOk, onError) { + /** @type {remoting.Identity} */ + var that = this; + + /** + * @param {string} token + */ + function revokeToken(token) { + chrome.identity.removeCachedAuthToken( + {'token': token }, + that.callWithToken.bind(that, onOk, onError)); + }; + + this.callWithToken(revokeToken, onError); +}; + /** * Remove the cached auth token, if any. * @@ -86,6 +113,7 @@ remoting.Identity.prototype.getEmail = function(onOk, onError) { /** @param {string} email */ var onResponse = function(email) { that.email_ = email; + that.fullName_ = null; onOk(email); }; @@ -93,9 +121,35 @@ remoting.Identity.prototype.getEmail = function(onOk, onError) { remoting.OAuth2Api.getEmail.bind(null, onResponse, onError), onError); }; +/** + * Get the user's email address and full name. + * + * @param {function(string,string):void} onOk Callback invoked when the user's + * email address and full name are available. + * @param {function(remoting.Error):void} onError Callback invoked if an + * error occurs. + * @return {void} Nothing. + */ +remoting.Identity.prototype.getUserInfo = function(onOk, onError) { + /** @type {remoting.Identity} */ + var that = this; + /** + * @param {string} email + * @param {string} name + */ + var onResponse = function(email, name) { + that.email_ = email; + that.fullName_ = name; + onOk(email, name); + }; + + this.callWithToken( + remoting.OAuth2Api.getUserInfo.bind(null, onResponse, onError), onError); +}; + /** * Get the user's email address, or null if no successful call to getEmail - * has been made. + * or getUserInfo has been made. * * @return {?string} The cached email address, if available. */ @@ -103,6 +157,16 @@ remoting.Identity.prototype.getCachedEmail = function() { return this.email_; }; +/** + * Get the user's full name, or null if no successful call to getUserInfo + * has been made. + * + * @return {?string} The cached user's full name, if available. + */ +remoting.Identity.prototype.getCachedUserFullName = function() { + return this.fullName_; +}; + /** * Callback for the getAuthToken API. * diff --git a/remoting/webapp/crd/js/oauth2.js b/remoting/webapp/crd/js/oauth2.js index 15ade7a370c3..ae4d3c0e93c2 100644 --- a/remoting/webapp/crd/js/oauth2.js +++ b/remoting/webapp/crd/js/oauth2.js @@ -36,6 +36,8 @@ remoting.OAuth2.prototype.KEY_ACCESS_TOKEN_ = 'oauth2-access-token'; remoting.OAuth2.prototype.KEY_XSRF_TOKEN_ = 'oauth2-xsrf-token'; /** @private */ remoting.OAuth2.prototype.KEY_EMAIL_ = 'remoting-email'; +/** @private */ +remoting.OAuth2.prototype.KEY_FULLNAME_ = 'remoting-fullname'; // Constants for parameters used in retrieving the OAuth2 credentials. /** @private */ @@ -88,6 +90,7 @@ remoting.OAuth2.prototype.isAuthenticated = function() { */ remoting.OAuth2.prototype.clear = function() { window.localStorage.removeItem(this.KEY_EMAIL_); + window.localStorage.removeItem(this.KEY_FULLNAME_); this.clearAccessToken_(); this.clearRefreshToken_(); }; @@ -102,6 +105,7 @@ remoting.OAuth2.prototype.clear = function() { remoting.OAuth2.prototype.setRefreshToken_ = function(token) { window.localStorage.setItem(this.KEY_REFRESH_TOKEN_, escape(token)); window.localStorage.removeItem(this.KEY_EMAIL_); + window.localStorage.removeItem(this.KEY_FULLNAME_); this.clearAccessToken_(); }; @@ -354,6 +358,7 @@ remoting.OAuth2.prototype.getEmail = function(onOk, onError) { /** @param {string} email */ var onResponse = function(email) { window.localStorage.setItem(that.KEY_EMAIL_, email); + window.localStorage.setItem(that.KEY_FULLNAME_, ''); onOk(email); }; @@ -361,11 +366,43 @@ remoting.OAuth2.prototype.getEmail = function(onOk, onError) { remoting.OAuth2Api.getEmail.bind(null, onResponse, onError), onError); }; +/** + * Get the user's email address and full name. + * + * @param {function(string,string):void} onOk Callback invoked when the user's + * email address and full name are available. + * @param {function(remoting.Error):void} onError Callback invoked if an + * error occurs. + * @return {void} Nothing. + */ +remoting.OAuth2.prototype.getUserInfo = function(onOk, onError) { + var cachedEmail = window.localStorage.getItem(this.KEY_EMAIL_); + var cachedName = window.localStorage.getItem(this.KEY_FULLNAME_); + if (typeof cachedEmail == 'string' && typeof cachedName == 'string') { + onOk(cachedEmail, cachedName); + return; + } + /** @type {remoting.OAuth2} */ + var that = this; + /** + * @param {string} email + * @param {string} name + */ + var onResponse = function(email, name) { + window.localStorage.setItem(that.KEY_EMAIL_, email); + window.localStorage.setItem(that.KEY_FULLNAME_, name); + onOk(email, name); + }; + + this.callWithToken( + remoting.OAuth2Api.getUserInfo.bind(null, onResponse, onError), onError); +}; + /** * If the user's email address is cached, return it, otherwise return null. * * @return {?string} The email address, if it has been cached by a previous call - * to getEmail, otherwise null. + * to getEmail or getUserInfo, otherwise null. */ remoting.OAuth2.prototype.getCachedEmail = function() { var value = window.localStorage.getItem(this.KEY_EMAIL_); @@ -374,3 +411,17 @@ remoting.OAuth2.prototype.getCachedEmail = function() { } return null; }; + +/** + * If the user's full name is cached, return it, otherwise return null. + * + * @return {?string} The user's full name, if it has been cached by a previous + * call to getUserInfo, otherwise null. + */ +remoting.OAuth2.prototype.getCachedUserFullName = function() { + var value = window.localStorage.getItem(this.KEY_FULLNAME_); + if (typeof value == 'string') { + return value; + } + return null; +}; diff --git a/remoting/webapp/crd/js/oauth2_api.js b/remoting/webapp/crd/js/oauth2_api.js index 56fa44f3e7d2..de6462acb06f 100644 --- a/remoting/webapp/crd/js/oauth2_api.js +++ b/remoting/webapp/crd/js/oauth2_api.js @@ -183,3 +183,36 @@ remoting.OAuth2Api.getEmail = function(onDone, onError, token) { remoting.xhr.get(remoting.OAuth2Api.getOAuth2ApiUserInfoEndpoint_(), onResponse, '', headers); }; + +/** + * Get the user's email address and full name. + * + * @param {function(string, string):void} onDone Callback invoked when the email + * address and full name are available. + * @param {function(remoting.Error):void} onError Callback invoked if an + * error occurs. + * @param {string} token Access token. + * @return {void} Nothing. + */ +remoting.OAuth2Api.getUserInfo = function(onDone, onError, token) { + /** @param {XMLHttpRequest} xhr */ + var onResponse = function(xhr) { + if (xhr.status == 200) { + try { + var result = JSON.parse(xhr.responseText); + onDone(result['email'], result['name']); + } catch (err) { + console.error('Invalid "userinfo" response from server:', + /** @type {*} */ (err)); + onError(remoting.Error.UNEXPECTED); + } + } else { + console.error('Failed to get user info. Status: ' + xhr.status + + ' response: ' + xhr.responseText); + onError(remoting.OAuth2Api.interpretXhrStatus_(xhr.status)); + } + }; + var headers = { 'Authorization': 'OAuth ' + token }; + remoting.xhr.get(remoting.OAuth2Api.getOAuth2ApiUserInfoEndpoint_(), + onResponse, '', headers); +};