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.
7 * Wrapper class for Chrome's identity API.
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
16 * TODO(jamiewalch): Remove remoting.OAuth2 from this type annotation when
17 * the Apps v2 work is complete.
19 * @type {remoting.Identity}
21 remoting.identity = null;
24 * @param {remoting.Identity.ConsentDialog=} opt_consentDialog
27 remoting.Identity = function(opt_consentDialog) {
29 this.consentDialog_ = opt_consentDialog;
30 /** @type {string} @private */
32 /** @type {string} @private */
34 /** @type {base.Deferred<string>} */
35 this.authTokenDeferred_ = null;
39 * chrome.identity.getAuthToken should be initiated from user interactions if
40 * called with interactive equals true. This interface prompts a dialog for
45 remoting.Identity.ConsentDialog = function() {};
48 * @return {Promise} A Promise that resolves when permission to start an
49 * interactive flow is granted.
51 remoting.Identity.ConsentDialog.prototype.show = function() {};
54 * Gets an access token.
56 * @return {!Promise<string>} A promise resolved with an access token
57 * or rejected with a remoting.Error.
59 remoting.Identity.prototype.getToken = function() {
63 if (this.authTokenDeferred_ == null) {
64 this.authTokenDeferred_ = new base.Deferred();
65 chrome.identity.getAuthToken(
66 { 'interactive': false },
67 that.onAuthComplete_.bind(that, false));
69 return this.authTokenDeferred_.promise();
73 * Gets a fresh access token.
75 * @return {!Promise<string>} A promise resolved with an access token
76 * or rejected with a remoting.Error.
78 remoting.Identity.prototype.getNewToken = function() {
79 /** @type {remoting.Identity} */
82 return this.getToken().then(function(/** string */ token) {
83 return new Promise(function(resolve, reject) {
84 chrome.identity.removeCachedAuthToken({'token': token }, function() {
85 resolve(that.getToken());
92 * Removes the cached auth token, if any.
94 * @return {!Promise<null>} A promise resolved with the operation completes.
96 remoting.Identity.prototype.removeCachedAuthToken = function() {
97 return new Promise(function(resolve, reject) {
98 /** @param {string} token */
99 var onToken = function(token) {
101 chrome.identity.removeCachedAuthToken(
102 {'token': token}, resolve.bind(null, null));
107 chrome.identity.getAuthToken({'interactive': false}, onToken);
112 * Gets the user's email address and full name. The full name will be
113 * null unless the webapp has requested and been granted the
114 * userinfo.profile permission.
116 * TODO(jrw): Type declarations say the name can't be null. Are the
117 * types wrong, or is the documentation wrong?
119 * @return {!Promise<{email:string, name:string}>} Promise
120 * resolved with the user's email address and full name, or rejected
121 * with a remoting.Error.
123 remoting.Identity.prototype.getUserInfo = function() {
124 if (this.isAuthenticated()) {
126 * The temp variable is needed to work around a compiler bug.
127 * @type {{email: string, name: string}}
129 var result = {email: this.email_, name: this.fullName_};
130 return Promise.resolve(result);
133 /** @type {remoting.Identity} */
136 return this.getToken().then(function(token) {
137 return new Promise(function(resolve, reject) {
139 * @param {string} email
140 * @param {string} name
142 var onResponse = function(email, name) {
144 that.fullName_ = name;
145 resolve({email: email, name: name});
148 remoting.oauth2Api.getUserInfo(onResponse, reject, token);
154 * Gets the user's email address.
156 * @return {!Promise<string>} Promise resolved with the user's email
157 * address or rejected with a remoting.Error.
159 remoting.Identity.prototype.getEmail = function() {
160 this.getUserInfo().then(function(userInfo) {
161 return userInfo.email;
166 * Gets the user's email address, or null if no successful call to
167 * getUserInfo has been made.
169 * @return {?string} The cached email address, if available.
171 remoting.Identity.prototype.getCachedEmail = function() {
176 * Gets the user's full name.
178 * This will return null if either:
179 * No successful call to getUserInfo has been made, or
180 * The webapp doesn't have permission to access this value.
182 * @return {?string} The cached user's full name, if available.
184 remoting.Identity.prototype.getCachedUserFullName = function() {
185 return this.fullName_;
189 * Callback for the getAuthToken API.
191 * @param {boolean} interactive The value of the "interactive" parameter to
193 * @param {?string} token The auth token, or null if the request failed.
196 remoting.Identity.prototype.onAuthComplete_ = function(interactive, token) {
197 var authTokenDeferred = this.authTokenDeferred_;
198 if (authTokenDeferred == null) {
201 this.authTokenDeferred_ = null;
203 // Pass the token to the callback(s) if it was retrieved successfully.
205 authTokenDeferred.resolve(token);
209 // If not, pass an error back to the callback(s) if we've already prompted the
210 // user for permission.
213 chrome.runtime.lastError ? chrome.runtime.lastError.message
215 console.error(error_message);
216 authTokenDeferred.reject(remoting.Error.NOT_AUTHENTICATED);
220 // If there's no token, but we haven't yet prompted for permission, do so
223 var showConsentDialog =
224 (this.consentDialog_) ? this.consentDialog_.show() : Promise.resolve();
225 showConsentDialog.then(function() {
226 chrome.identity.getAuthToken(
227 {'interactive': true}, that.onAuthComplete_.bind(that, true));
232 * Returns whether the web app has authenticated with the Google services.
236 remoting.Identity.prototype.isAuthenticated = function() {
237 return remoting.identity.email_ !== '';