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

Side by Side Diff: remoting/webapp/crd/js/identity.js

Issue 1015043002: Add optional scopes parameter to Identity.getToken(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview 6 * @fileoverview
7 * Wrapper class for Chrome's identity API. 7 * Wrapper class for Chrome's identity API.
8 */ 8 */
9 /** @suppress {duplicate} */ 9 /** @suppress {duplicate} */
10 var remoting = remoting || {}; 10 var remoting = remoting || {};
(...skipping 13 matching lines...) Expand all
24 * @param {remoting.Identity.ConsentDialog=} opt_consentDialog 24 * @param {remoting.Identity.ConsentDialog=} opt_consentDialog
25 * @constructor 25 * @constructor
26 */ 26 */
27 remoting.Identity = function(opt_consentDialog) { 27 remoting.Identity = function(opt_consentDialog) {
28 /** @private */ 28 /** @private */
29 this.consentDialog_ = opt_consentDialog; 29 this.consentDialog_ = opt_consentDialog;
30 /** @private {string} */ 30 /** @private {string} */
31 this.email_ = ''; 31 this.email_ = '';
32 /** @private {string} */ 32 /** @private {string} */
33 this.fullName_ = ''; 33 this.fullName_ = '';
34 /** @type {base.Deferred<string>} */ 34 /** @private {Object<base.Deferred<string>>} */
35 this.authTokenDeferred_ = null; 35 this.authTokensDeferred_ = {};
36 /** @private {boolean} */ 36 /** @private {boolean} */
37 this.interactive_ = false; 37 this.interactive_ = false;
38 }; 38 };
39 39
40 /** 40 /**
41 * chrome.identity.getAuthToken should be initiated from user interactions if 41 * chrome.identity.getAuthToken should be initiated from user interactions if
42 * called with interactive equals true. This interface prompts a dialog for 42 * called with interactive equals true. This interface prompts a dialog for
43 * the user's consent. 43 * the user's consent.
44 * 44 *
45 * @interface 45 * @interface
46 */ 46 */
47 remoting.Identity.ConsentDialog = function() {}; 47 remoting.Identity.ConsentDialog = function() {};
48 48
49 /** 49 /**
50 * @return {Promise} A Promise that resolves when permission to start an 50 * @return {Promise} A Promise that resolves when permission to start an
51 * interactive flow is granted. 51 * interactive flow is granted.
52 */ 52 */
53 remoting.Identity.ConsentDialog.prototype.show = function() {}; 53 remoting.Identity.ConsentDialog.prototype.show = function() {};
54 54
55 /** 55 /**
56 * Gets an access token. 56 * Gets an access token.
57 * 57 *
58 * @param {Array<string>=} opt_scopes Optional OAuth2 scopes to request. If not
59 * specified, the scopes specified in the manifest will be used. No consent
60 * prompt will be needed as long as the requested scopes are a subset of
61 * those already granted (in most cases, the remoting.Application framework
62 * ensures that the scopes specified in the manifest are already authorized
63 * before any application code is executed). Callers can request scopes not
64 * specified in the manifest, but a consent prompt will be shown.
65 *
58 * @return {!Promise<string>} A promise resolved with an access token 66 * @return {!Promise<string>} A promise resolved with an access token
59 * or rejected with a remoting.Error. 67 * or rejected with a remoting.Error.
60 */ 68 */
61 remoting.Identity.prototype.getToken = function() { 69 remoting.Identity.prototype.getToken = function(opt_scopes) {
62 /** @const */ 70 var key = getScopesKey(opt_scopes);
63 var that = this; 71 if (!this.authTokensDeferred_[key]) {
64 72 this.authTokensDeferred_[key] = new base.Deferred();
65 if (this.authTokenDeferred_ == null) { 73 var options = {
66 this.authTokenDeferred_ = new base.Deferred(); 74 'interactive': this.interactive_,
kelvinp 2015/03/18 18:51:26 Do we need to reset interactive? In the current im
Jamie 2015/03/18 19:08:49 Support for scopes is part of the reason I changed
kelvinp 2015/03/18 19:19:33 Acknowledged.
67 chrome.identity.getAuthToken( 75 'scopes': opt_scopes
68 { 'interactive': this.interactive_ }, 76 };
69 this.onAuthComplete_.bind(this)); 77 chrome.identity.getAuthToken(options,
78 this.onAuthComplete_.bind(this, opt_scopes));
kelvinp 2015/03/18 18:51:26 Why not bind the key instead, as the first thing t
Jamie 2015/03/18 19:08:49 onAuthComplete needs both the scopes and the key,
kelvinp 2015/03/18 19:19:33 Sorry. I missed that part. Acknowledged.
70 } 79 }
71 return this.authTokenDeferred_.promise(); 80 return this.authTokensDeferred_[key].promise();
72 }; 81 };
73 82
74 /** 83 /**
75 * Gets a fresh access token. 84 * Gets a fresh access token.
76 * 85 *
77 * @return {!Promise<string>} A promise resolved with an access token 86 * @return {!Promise<string>} A promise resolved with an access token
78 * or rejected with a remoting.Error. 87 * or rejected with a remoting.Error.
79 */ 88 */
80 remoting.Identity.prototype.getNewToken = function() { 89 remoting.Identity.prototype.getNewToken = function() {
81 /** @type {remoting.Identity} */ 90 /** @type {remoting.Identity} */
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 */ 169 */
161 remoting.Identity.prototype.getEmail = function() { 170 remoting.Identity.prototype.getEmail = function() {
162 return this.getUserInfo().then(function(userInfo) { 171 return this.getUserInfo().then(function(userInfo) {
163 return userInfo.email; 172 return userInfo.email;
164 }); 173 });
165 }; 174 };
166 175
167 /** 176 /**
168 * Callback for the getAuthToken API. 177 * Callback for the getAuthToken API.
169 * 178 *
179 * @param {Array<string>|undefined} scopes The explicit scopes passed to
180 * getToken, or undefined if no scopes were specified.
170 * @param {?string} token The auth token, or null if the request failed. 181 * @param {?string} token The auth token, or null if the request failed.
171 * @private 182 * @private
172 */ 183 */
173 remoting.Identity.prototype.onAuthComplete_ = function(token) { 184 remoting.Identity.prototype.onAuthComplete_ = function(scopes, token) {
174 var authTokenDeferred = this.authTokenDeferred_; 185 var key = getScopesKey(scopes);
186 var authTokenDeferred = this.authTokensDeferred_[key];
175 187
176 // Pass the token to the callback(s) if it was retrieved successfully. 188 // Pass the token to the callback(s) if it was retrieved successfully.
177 if (token) { 189 if (token) {
178 authTokenDeferred.resolve(token); 190 var promise = this.authTokensDeferred_[key];
179 this.authTokenDeferred_ = null; 191 delete this.authTokensDeferred_[key];
192 promise.resolve(token);
180 return; 193 return;
181 } 194 }
182 195
183 // If not, pass an error back to the callback(s) if we've already prompted the 196 // If not, pass an error back to the callback(s) if we've already prompted the
184 // user for permission. 197 // user for permission.
185 if (this.interactive_) { 198 if (this.interactive_) {
186 var error_message = 199 var error_message =
187 chrome.runtime.lastError ? chrome.runtime.lastError.message 200 chrome.runtime.lastError ? chrome.runtime.lastError.message
188 : 'Unknown error.'; 201 : 'Unknown error.';
189 console.error(error_message); 202 console.error(error_message);
190 var error = (error_message == USER_CANCELLED) ? 203 var error = (error_message == USER_CANCELLED) ?
191 new remoting.Error(remoting.Error.Tag.CANCELLED) : 204 new remoting.Error(remoting.Error.Tag.CANCELLED) :
192 new remoting.Error(remoting.Error.Tag.NOT_AUTHENTICATED); 205 new remoting.Error(remoting.Error.Tag.NOT_AUTHENTICATED);
193 authTokenDeferred.reject(error); 206 this.authTokensDeferred_[key].reject(error);
194 this.authTokenDeferred_ = null; 207 delete this.authTokensDeferred_[key];
195 return; 208 return;
196 } 209 }
197 210
198 // If there's no token, but we haven't yet prompted for permission, do so 211 // If there's no token, but we haven't yet prompted for permission, do so
199 // now. 212 // now.
200 var that = this; 213 var that = this;
201 var showConsentDialog = 214 var showConsentDialog =
202 (this.consentDialog_) ? this.consentDialog_.show() : Promise.resolve(); 215 (this.consentDialog_) ? this.consentDialog_.show() : Promise.resolve();
203 showConsentDialog.then(function() { 216 showConsentDialog.then(function() {
204 that.interactive_ = true; 217 that.interactive_ = true;
205 chrome.identity.getAuthToken({'interactive': that.interactive_}, 218 var options = {
206 that.onAuthComplete_.bind(that)); 219 'interactive': that.interactive_,
220 'scopes': scopes
221 };
222 chrome.identity.getAuthToken(options,
223 that.onAuthComplete_.bind(that, scopes));
207 }); 224 });
208 }; 225 };
209 226
210 /** 227 /**
211 * Returns whether the web app has authenticated with the Google services. 228 * Returns whether the web app has authenticated with the Google services.
212 * 229 *
213 * @return {boolean} 230 * @return {boolean}
214 */ 231 */
215 remoting.Identity.prototype.isAuthenticated = function() { 232 remoting.Identity.prototype.isAuthenticated = function() {
216 return remoting.identity.email_ !== ''; 233 return remoting.identity.email_ !== '';
217 }; 234 };
218 235
236
237 /**
238 * @param {Array<string>=} opt_scopes
239 * @return {string}
240 */
241 function getScopesKey(opt_scopes) {
242 return opt_scopes ? JSON.stringify(opt_scopes) : '';
kelvinp 2015/03/18 18:51:26 I think we should sort the scopes first so that or
Jamie 2015/03/18 19:08:49 I was about to do this when I considered how I cou
kelvinp 2015/03/18 19:19:33 I think the complexity would only be extra line of
Jamie 2015/03/18 20:03:59 Let's keep it simple for now.
243 }
244
219 })(); 245 })();
OLDNEW
« no previous file with comments | « no previous file | remoting/webapp/crd/js/identity_unittest.js » ('j') | remoting/webapp/crd/js/identity_unittest.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698