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

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

Issue 937593002: Changed identity API to use promises instead of callbacks. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed bad merge 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 9
10 'use strict'; 10 'use strict';
(...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 /** @type {string} @private */ 30 /** @type {string} @private */
31 this.email_ = ''; 31 this.email_ = '';
32 /** @type {string} @private */ 32 /** @type {string} @private */
33 this.fullName_ = ''; 33 this.fullName_ = '';
34 /** @type {Array<remoting.Identity.Callbacks>} */ 34 /** @type {base.Deferred<string>} */
35 this.pendingCallbacks_ = []; 35 this.authTokenDeferred_ = null;
36 }; 36 };
37 37
38 /** 38 /**
39 * chrome.identity.getAuthToken should be initiated from user interactions if 39 * chrome.identity.getAuthToken should be initiated from user interactions if
40 * called with interactive equals true. This interface prompts a dialog for 40 * called with interactive equals true. This interface prompts a dialog for
41 * the user's consent. 41 * the user's consent.
42 * 42 *
43 * @interface 43 * @interface
44 */ 44 */
45 remoting.Identity.ConsentDialog = function() {}; 45 remoting.Identity.ConsentDialog = function() {};
46 46
47 /** 47 /**
48 * @return {Promise} A Promise that resolves when permission to start an 48 * @return {Promise} A Promise that resolves when permission to start an
49 * interactive flow is granted. 49 * interactive flow is granted.
50 */ 50 */
51 remoting.Identity.ConsentDialog.prototype.show = function() {}; 51 remoting.Identity.ConsentDialog.prototype.show = function() {};
52 52
53 /** 53 /**
54 * Call a function with an access token. 54 * Gets an access token.
55 * 55 *
56 * @param {function(string):void} onOk Function to invoke with access token if 56 * @return {!Promise<string>} A promise resolved with an access token
57 * an access token was successfully retrieved. 57 * or rejected with a remoting.Error.
58 * @param {function(remoting.Error):void} onError Function to invoke with an
59 * error code on failure.
60 * @return {void} Nothing.
61 */ 58 */
62 remoting.Identity.prototype.callWithToken = function(onOk, onError) { 59 remoting.Identity.prototype.getToken = function() {
63 this.pendingCallbacks_.push(new remoting.Identity.Callbacks(onOk, onError)); 60 /** @const */
64 if (this.pendingCallbacks_.length == 1) { 61 var that = this;
62
63 if (this.authTokenDeferred_ == null) {
64 this.authTokenDeferred_ = new base.Deferred();
65 chrome.identity.getAuthToken( 65 chrome.identity.getAuthToken(
66 { 'interactive': false }, 66 { 'interactive': false },
67 this.onAuthComplete_.bind(this, false)); 67 that.onAuthComplete_.bind(that, false));
68 } 68 }
69 return this.authTokenDeferred_.promise();
69 }; 70 };
70 71
71 /** 72 /**
72 * Call a function with a fresh access token. 73 * Gets a fresh access token.
73 * 74 *
74 * @param {function(string):void} onOk Function to invoke with access token if 75 * @return {!Promise<string>} A promise resolved with an access token
75 * an access token was successfully retrieved. 76 * or rejected with a remoting.Error.
76 * @param {function(remoting.Error):void} onError Function to invoke with an
77 * error code on failure.
78 * @return {void} Nothing.
79 */ 77 */
80 remoting.Identity.prototype.callWithNewToken = function(onOk, onError) { 78 remoting.Identity.prototype.getNewToken = function() {
81 /** @type {remoting.Identity} */ 79 /** @type {remoting.Identity} */
82 var that = this; 80 var that = this;
83 81
84 /** 82 return this.getToken().then(function(/** string */ token) {
85 * @param {string} token 83 return new Promise(function(resolve, reject) {
86 */ 84 chrome.identity.removeCachedAuthToken({'token': token }, function() {
87 function revokeToken(token) { 85 resolve(that.getToken());
88 chrome.identity.removeCachedAuthToken( 86 });
89 {'token': token }, 87 });
90 that.callWithToken.bind(that, onOk, onError)); 88 });
91 }
92
93 this.callWithToken(revokeToken, onError);
94 }; 89 };
95 90
96 /** 91 /**
97 * Remove the cached auth token, if any. 92 * Removes the cached auth token, if any.
98 * 93 *
99 * @param {function():void=} opt_onDone Completion callback. 94 * @return {!Promise<null>} A promise resolved with the operation completes.
100 * @return {void} Nothing.
101 */ 95 */
102 remoting.Identity.prototype.removeCachedAuthToken = function(opt_onDone) { 96 remoting.Identity.prototype.removeCachedAuthToken = function() {
103 var onDone = (opt_onDone) ? opt_onDone : base.doNothing; 97 return new Promise(function(resolve, reject) {
104 98 /** @param {string} token */
105 /** @param {string} token */ 99 var onToken = function(token) {
106 var onToken = function(token) { 100 if (token) {
107 if (token) { 101 chrome.identity.removeCachedAuthToken(
108 chrome.identity.removeCachedAuthToken({'token': token}, onDone); 102 {'token': token}, resolve.bind(null, null));
109 } else { 103 } else {
110 onDone(); 104 resolve(null);
111 } 105 }
112 }; 106 };
113 chrome.identity.getAuthToken({'interactive': false}, onToken); 107 chrome.identity.getAuthToken({'interactive': false}, onToken);
108 });
114 }; 109 };
115 110
116 /** 111 /**
117 * Get the user's email address and full name. 112 * Gets the user's email address and full name. The full name will be
118 * The full name will be null unless the webapp has requested and been 113 * null unless the webapp has requested and been granted the
119 * granted the userinfo.profile permission. 114 * userinfo.profile permission.
120 * 115 *
121 * @param {function(string,string):void} onOk Callback invoked when the user's 116 * TODO(jrw): Type declarations say the name can't be null. Are the
122 * email address and full name are available. 117 * types wrong, or is the documentation wrong?
123 * @param {function(remoting.Error):void} onError Callback invoked if an 118 *
124 * error occurs. 119 * @return {!Promise<{email:string, name:string}>} Promise
125 * @return {void} Nothing. 120 * resolved with the user's email address and full name, or rejected
121 * with a remoting.Error.
126 */ 122 */
127 remoting.Identity.prototype.getUserInfo = function(onOk, onError) { 123 remoting.Identity.prototype.getUserInfo = function() {
128 if (this.isAuthenticated()) { 124 if (this.isAuthenticated()) {
129 onOk(this.email_, this.fullName_); 125 /**
130 return; 126 * The temp variable is needed to work around a compiler bug.
127 * @type {{email: string, name: string}}
128 */
129 var result = {email: this.email_, name: this.fullName_};
130 return Promise.resolve(result);
131 } 131 }
132 132
133 /** @type {remoting.Identity} */ 133 /** @type {remoting.Identity} */
134 var that = this; 134 var that = this;
135 135
136 /** 136 return this.getToken().then(function(token) {
137 * @param {string} email 137 return new Promise(function(resolve, reject) {
138 * @param {string} name 138 /**
139 */ 139 * @param {string} email
140 var onResponse = function(email, name) { 140 * @param {string} name
141 that.email_ = email; 141 */
142 that.fullName_ = name; 142 var onResponse = function(email, name) {
143 onOk(email, name); 143 that.email_ = email;
144 }; 144 that.fullName_ = name;
145 resolve({email: email, name: name});
146 };
145 147
146 this.callWithToken( 148 remoting.oauth2Api.getUserInfo(onResponse, reject, token);
147 remoting.oauth2Api.getUserInfo.bind( 149 });
148 remoting.oauth2Api, onResponse, onError), 150 });
149 onError);
150 }; 151 };
151 152
152 /** 153 /**
153 * Get the user's email address. 154 * Gets the user's email address.
154 * 155 *
155 * @param {function(string):void} onOk Callback invoked when the email 156 * @return {!Promise<string>} Promise resolved with the user's email
156 * address is available. 157 * address or rejected with a remoting.Error.
157 * @param {function(remoting.Error):void} onError Callback invoked if an
158 * error occurs.
159 * @return {void} Nothing.
160 */ 158 */
161 remoting.Identity.prototype.getEmail = function(onOk, onError) { 159 remoting.Identity.prototype.getEmail = function() {
162 this.getUserInfo(function(email, name) { 160 this.getUserInfo().then(function(userInfo) {
163 onOk(email); 161 return userInfo.email;
164 }, onError); 162 });
165 }; 163 };
166 164
167 /** 165 /**
168 * Get the user's email address, or null if no successful call to getUserInfo 166 * Gets the user's email address, or null if no successful call to
169 * has been made. 167 * getUserInfo has been made.
170 * 168 *
171 * @return {?string} The cached email address, if available. 169 * @return {?string} The cached email address, if available.
172 */ 170 */
173 remoting.Identity.prototype.getCachedEmail = function() { 171 remoting.Identity.prototype.getCachedEmail = function() {
174 return this.email_; 172 return this.email_;
175 }; 173 };
176 174
177 /** 175 /**
178 * Get the user's full name. 176 * Gets the user's full name.
177 *
179 * This will return null if either: 178 * This will return null if either:
180 * No successful call to getUserInfo has been made, or 179 * No successful call to getUserInfo has been made, or
181 * The webapp doesn't have permission to access this value. 180 * The webapp doesn't have permission to access this value.
182 * 181 *
183 * @return {?string} The cached user's full name, if available. 182 * @return {?string} The cached user's full name, if available.
184 */ 183 */
185 remoting.Identity.prototype.getCachedUserFullName = function() { 184 remoting.Identity.prototype.getCachedUserFullName = function() {
186 return this.fullName_; 185 return this.fullName_;
187 }; 186 };
188 187
189 /** 188 /**
190 * Callback for the getAuthToken API. 189 * Callback for the getAuthToken API.
191 * 190 *
192 * @param {boolean} interactive The value of the "interactive" parameter to 191 * @param {boolean} interactive The value of the "interactive" parameter to
193 * getAuthToken. 192 * getAuthToken.
194 * @param {?string} token The auth token, or null if the request failed. 193 * @param {?string} token The auth token, or null if the request failed.
195 * @private 194 * @private
196 */ 195 */
197 remoting.Identity.prototype.onAuthComplete_ = function(interactive, token) { 196 remoting.Identity.prototype.onAuthComplete_ = function(interactive, token) {
197 var authTokenDeferred = this.authTokenDeferred_;
198 if (authTokenDeferred == null) {
199 return;
200 }
201 this.authTokenDeferred_ = null;
202
198 // Pass the token to the callback(s) if it was retrieved successfully. 203 // Pass the token to the callback(s) if it was retrieved successfully.
199 if (token) { 204 if (token) {
200 while (this.pendingCallbacks_.length > 0) { 205 authTokenDeferred.resolve(token);
201 var callback = /** @type {remoting.Identity.Callbacks} */
202 (this.pendingCallbacks_.shift());
203 callback.onOk(token);
204 }
205 return; 206 return;
206 } 207 }
207 208
208 // If not, pass an error back to the callback(s) if we've already prompted the 209 // If not, pass an error back to the callback(s) if we've already prompted the
209 // user for permission. 210 // user for permission.
210 if (interactive) { 211 if (interactive) {
211 var error_message = 212 var error_message =
212 chrome.runtime.lastError ? chrome.runtime.lastError.message 213 chrome.runtime.lastError ? chrome.runtime.lastError.message
213 : 'Unknown error.'; 214 : 'Unknown error.';
214 console.error(error_message); 215 console.error(error_message);
215 while (this.pendingCallbacks_.length > 0) { 216 authTokenDeferred.reject(remoting.Error.NOT_AUTHENTICATED);
216 var callback = /** @type {remoting.Identity.Callbacks} */
217 (this.pendingCallbacks_.shift());
218 callback.onError(remoting.Error.NOT_AUTHENTICATED);
219 }
220 return; 217 return;
221 } 218 }
222 219
223 // If there's no token, but we haven't yet prompted for permission, do so 220 // If there's no token, but we haven't yet prompted for permission, do so
224 // now. 221 // now.
225 var that = this; 222 var that = this;
226 var showConsentDialog = 223 var showConsentDialog =
227 (this.consentDialog_) ? this.consentDialog_.show() : Promise.resolve(); 224 (this.consentDialog_) ? this.consentDialog_.show() : Promise.resolve();
228 showConsentDialog.then(function() { 225 showConsentDialog.then(function() {
229 chrome.identity.getAuthToken({'interactive': true}, 226 chrome.identity.getAuthToken(
230 that.onAuthComplete_.bind(that, true)); 227 {'interactive': true}, that.onAuthComplete_.bind(that, true));
231 }); 228 });
232 }; 229 };
233 230
234 /** 231 /**
235 * Internal representation for pair of callWithToken callbacks.
236 *
237 * @param {function(string):void} onOk
238 * @param {function(remoting.Error):void} onError
239 * @constructor
240 * @private
241 */
242 remoting.Identity.Callbacks = function(onOk, onError) {
243 /** @type {function(string):void} */
244 this.onOk = onOk;
245 /** @type {function(remoting.Error):void} */
246 this.onError = onError;
247 };
248
249 /**
250 * Returns whether the web app has authenticated with the Google services. 232 * Returns whether the web app has authenticated with the Google services.
251 * 233 *
252 * @return {boolean} 234 * @return {boolean}
253 */ 235 */
254 remoting.Identity.prototype.isAuthenticated = function() { 236 remoting.Identity.prototype.isAuthenticated = function() {
255 return remoting.identity.email_ !== ''; 237 return remoting.identity.email_ !== '';
256 }; 238 };
OLDNEW
« no previous file with comments | « remoting/webapp/crd/js/host_setup_dialog.js ('k') | remoting/webapp/crd/js/it2me_helpee_channel.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698