Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 * OAuth2 class that handles retrieval/storage of an OAuth2 token. | 7 * OAuth2 class that handles retrieval/storage of an OAuth2 token. |
| 8 * | 8 * |
| 9 * Uses a content script to trampoline the OAuth redirect page back into the | 9 * Uses a content script to trampoline the OAuth redirect page back into the |
| 10 * extension context. This works around the lack of native support for | 10 * extension context. This works around the lack of native support for |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 | 21 |
| 22 | 22 |
| 23 /** @constructor */ | 23 /** @constructor */ |
| 24 remoting.OAuth2 = function() { | 24 remoting.OAuth2 = function() { |
| 25 }; | 25 }; |
| 26 | 26 |
| 27 // Constants representing keys used for storing persistent state. | 27 // Constants representing keys used for storing persistent state. |
| 28 /** @private */ | 28 /** @private */ |
| 29 remoting.OAuth2.prototype.KEY_REFRESH_TOKEN_ = 'oauth2-refresh-token'; | 29 remoting.OAuth2.prototype.KEY_REFRESH_TOKEN_ = 'oauth2-refresh-token'; |
| 30 /** @private */ | 30 /** @private */ |
| 31 remoting.OAuth2.prototype.KEY_REFRESH_TOKEN_REVOKABLE_ = | |
| 32 'oauth2-refresh-token-revokable'; | |
| 33 /** @private */ | |
| 31 remoting.OAuth2.prototype.KEY_ACCESS_TOKEN_ = 'oauth2-access-token'; | 34 remoting.OAuth2.prototype.KEY_ACCESS_TOKEN_ = 'oauth2-access-token'; |
| 32 /** @private */ | 35 /** @private */ |
| 33 remoting.OAuth2.prototype.KEY_EMAIL_ = 'remoting-email'; | 36 remoting.OAuth2.prototype.KEY_EMAIL_ = 'remoting-email'; |
| 34 | 37 |
| 35 // Constants for parameters used in retrieving the OAuth2 credentials. | 38 // Constants for parameters used in retrieving the OAuth2 credentials. |
| 36 /** @private */ | 39 /** @private */ |
| 37 remoting.OAuth2.prototype.SCOPE_ = | 40 remoting.OAuth2.prototype.SCOPE_ = |
| 38 'https://www.googleapis.com/auth/chromoting ' + | 41 'https://www.googleapis.com/auth/chromoting ' + |
| 39 'https://www.googleapis.com/auth/googletalk ' + | 42 'https://www.googleapis.com/auth/googletalk ' + |
| 40 'https://www.googleapis.com/auth/userinfo#email'; | 43 'https://www.googleapis.com/auth/userinfo#email'; |
| 41 /** @private */ | 44 /** @private */ |
| 42 remoting.OAuth2.prototype.OAUTH2_TOKEN_ENDPOINT_ = | 45 remoting.OAuth2.prototype.OAUTH2_TOKEN_ENDPOINT_ = |
| 43 'https://accounts.google.com/o/oauth2/token'; | 46 'https://accounts.google.com/o/oauth2/token'; |
| 44 | 47 /** @private */ |
| 48 remoting.OAuth2.prototype.OAUTH2_REVOKE_TOKEN_ENDPOINT_ = | |
| 49 'https://accounts.google.com/o/oauth2/revoke'; | |
| 45 /** @return {boolean} True if the app is already authenticated. */ | 50 /** @return {boolean} True if the app is already authenticated. */ |
| 46 remoting.OAuth2.prototype.isAuthenticated = function() { | 51 remoting.OAuth2.prototype.isAuthenticated = function() { |
| 47 if (this.getRefreshToken()) { | 52 if (this.getRefreshToken_()) { |
| 48 return true; | 53 return true; |
| 49 } | 54 } |
| 50 return false; | 55 return false; |
| 51 }; | 56 }; |
| 52 | 57 |
| 53 /** | 58 /** |
| 54 * Removes all storage, and effectively unauthenticates the user. | 59 * Removes all storage, and effectively unauthenticates the user. |
| 55 * | 60 * |
| 56 * @return {void} Nothing. | 61 * @return {void} Nothing. |
| 57 */ | 62 */ |
| 58 remoting.OAuth2.prototype.clear = function() { | 63 remoting.OAuth2.prototype.clear = function() { |
| 59 window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_); | |
| 60 window.localStorage.removeItem(this.KEY_EMAIL_); | 64 window.localStorage.removeItem(this.KEY_EMAIL_); |
| 61 this.clearAccessToken(); | 65 this.clearAccessToken(); |
| 66 this.clearRefreshToken_(); | |
| 62 }; | 67 }; |
| 63 | 68 |
| 64 /** | 69 /** |
| 70 * Sets the refresh token. | |
| 71 * | |
| 72 * This method also marks the token as revokable, so that this object will | |
| 73 * revoke the token when it no longer needs it. | |
| 74 * | |
| 65 * @param {string} token The new refresh token. | 75 * @param {string} token The new refresh token. |
| 66 * @return {void} Nothing. | 76 * @return {void} Nothing. |
| 67 */ | 77 */ |
| 68 remoting.OAuth2.prototype.setRefreshToken = function(token) { | 78 remoting.OAuth2.prototype.setRefreshToken = function(token) { |
| 69 window.localStorage.setItem(this.KEY_REFRESH_TOKEN_, escape(token)); | 79 window.localStorage.setItem(this.KEY_REFRESH_TOKEN_, escape(token)); |
| 80 window.localStorage.setItem(this.KEY_REFRESH_TOKEN_REVOKABLE_, true); | |
| 70 this.clearAccessToken(); | 81 this.clearAccessToken(); |
| 71 }; | 82 }; |
| 72 | 83 |
| 73 /** @return {?string} The refresh token, if authenticated, or NULL. */ | 84 /** |
| 74 remoting.OAuth2.prototype.getRefreshToken = function() { | 85 * Gets the refresh token. |
| 86 * | |
| 87 * This method also marks the refresh token as not revokable, so that this | |
| 88 * object will not revoke the token when it no longer needs it. After this | |
| 89 * object has exported the token, it cannot know whether it is still in use | |
| 90 * when this object no longer needs it. | |
| 91 * | |
| 92 * @return {?string} The refresh token, if authenticated, or NULL. | |
| 93 */ | |
| 94 remoting.OAuth2.prototype.exportRefreshToken = function() { | |
| 95 window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_REVOKABLE_); | |
| 96 return this.getRefreshToken_(); | |
| 97 }; | |
| 98 | |
| 99 /** | |
| 100 * @return {?string} The refresh token, if authenticated, or NULL. | |
| 101 * @private | |
| 102 */ | |
| 103 remoting.OAuth2.prototype.getRefreshToken_ = function() { | |
| 75 var value = window.localStorage.getItem(this.KEY_REFRESH_TOKEN_); | 104 var value = window.localStorage.getItem(this.KEY_REFRESH_TOKEN_); |
| 76 if (typeof value == 'string') { | 105 if (typeof value == 'string') { |
| 77 return unescape(value); | 106 return unescape(value); |
| 78 } | 107 } |
| 79 return null; | 108 return null; |
| 80 }; | 109 }; |
| 81 | 110 |
| 82 /** | 111 /** |
| 112 * Clears the refresh token. | |
| 113 * | |
| 114 * @return {void} Nothing. | |
| 115 * @private | |
| 116 */ | |
| 117 remoting.OAuth2.prototype.clearRefreshToken_ = function() { | |
| 118 if (window.localStorage.getItem(this.KEY_REFRESH_TOKEN_REVOKABLE_)) { | |
| 119 this.revokeToken_(this.getRefreshToken_()); | |
| 120 } | |
| 121 window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_); | |
| 122 window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_REVOKABLE_); | |
| 123 }; | |
| 124 | |
| 125 /** | |
| 83 * @param {string} token The new access token. | 126 * @param {string} token The new access token. |
| 84 * @param {number} expiration Expiration time in milliseconds since epoch. | 127 * @param {number} expiration Expiration time in milliseconds since epoch. |
| 85 * @return {void} Nothing. | 128 * @return {void} Nothing. |
| 86 */ | 129 */ |
| 87 remoting.OAuth2.prototype.setAccessToken = function(token, expiration) { | 130 remoting.OAuth2.prototype.setAccessToken = function(token, expiration) { |
| 88 var access_token = {'token': token, 'expiration': expiration}; | 131 var access_token = {'token': token, 'expiration': expiration}; |
| 89 window.localStorage.setItem(this.KEY_ACCESS_TOKEN_, | 132 window.localStorage.setItem(this.KEY_ACCESS_TOKEN_, |
| 90 JSON.stringify(access_token)); | 133 JSON.stringify(access_token)); |
| 91 }; | 134 }; |
| 92 | 135 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 193 * @return {void} Nothing. | 236 * @return {void} Nothing. |
| 194 */ | 237 */ |
| 195 remoting.OAuth2.prototype.refreshAccessToken = function(onDone) { | 238 remoting.OAuth2.prototype.refreshAccessToken = function(onDone) { |
| 196 if (!this.isAuthenticated()) { | 239 if (!this.isAuthenticated()) { |
| 197 throw 'Not Authenticated.'; | 240 throw 'Not Authenticated.'; |
| 198 } | 241 } |
| 199 | 242 |
| 200 var parameters = { | 243 var parameters = { |
| 201 'client_id': this.CLIENT_ID_, | 244 'client_id': this.CLIENT_ID_, |
| 202 'client_secret': this.CLIENT_SECRET_, | 245 'client_secret': this.CLIENT_SECRET_, |
| 203 'refresh_token': this.getRefreshToken(), | 246 'refresh_token': this.getRefreshToken_(), |
| 204 'grant_type': 'refresh_token' | 247 'grant_type': 'refresh_token' |
| 205 }; | 248 }; |
| 206 | 249 |
| 207 /** @type {remoting.OAuth2} */ | 250 /** @type {remoting.OAuth2} */ |
| 208 var that = this; | 251 var that = this; |
| 209 /** @param {XMLHttpRequest} xhr The XHR reply. */ | 252 /** @param {XMLHttpRequest} xhr The XHR reply. */ |
| 210 var processTokenResponse = function(xhr) { | 253 var processTokenResponse = function(xhr) { |
| 211 that.processTokenResponse_(xhr); | 254 that.processTokenResponse_(xhr); |
| 212 onDone(xhr); | 255 onDone(xhr); |
| 213 }; | 256 }; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 var processTokenResponse = function(xhr) { | 300 var processTokenResponse = function(xhr) { |
| 258 that.processTokenResponse_(xhr); | 301 that.processTokenResponse_(xhr); |
| 259 onDone(xhr); | 302 onDone(xhr); |
| 260 }; | 303 }; |
| 261 remoting.xhr.post(this.OAUTH2_TOKEN_ENDPOINT_, | 304 remoting.xhr.post(this.OAUTH2_TOKEN_ENDPOINT_, |
| 262 processTokenResponse, | 305 processTokenResponse, |
| 263 parameters); | 306 parameters); |
| 264 }; | 307 }; |
| 265 | 308 |
| 266 /** | 309 /** |
| 310 * Revokes a refresh or an access token. | |
| 311 * | |
| 312 * @param {string?} token An access or refresh token. | |
| 313 * @return {void} Nothing. | |
| 314 * @private | |
| 315 */ | |
| 316 remoting.OAuth2.prototype.revokeToken_ = function(token) { | |
| 317 if (!token || (token.length == 0)) { | |
| 318 return; | |
| 319 } | |
| 320 var parameters = { 'token': token }; | |
| 321 | |
| 322 /** @param {XMLHttpRequest} xhr The XHR reply. */ | |
| 323 var processResponse = function(xhr) { | |
| 324 if (xhr.status != 200) { | |
| 325 console.log('Failed to revoke token. Status: ' + xhr.status + | |
| 326 ' response: ' + xhr.responseText); | |
|
Jamie
2012/04/16 17:04:45
I think I'd probably log the xhr object itself her
simonmorris
2012/04/16 22:37:51
Done.
| |
| 327 } | |
| 328 }; | |
| 329 remoting.xhr.post(this.OAUTH2_REVOKE_TOKEN_ENDPOINT_, | |
| 330 processResponse, | |
| 331 parameters); | |
| 332 }; | |
| 333 | |
| 334 /** | |
| 267 * Call myfunc with an access token as the only parameter. | 335 * Call myfunc with an access token as the only parameter. |
| 268 * | 336 * |
| 269 * This will refresh the access token if necessary. If the access token | 337 * This will refresh the access token if necessary. If the access token |
| 270 * cannot be refreshed, an error is thrown. | 338 * cannot be refreshed, an error is thrown. |
| 271 * | 339 * |
| 272 * The access token will remain valid for at least 2 minutes. | 340 * The access token will remain valid for at least 2 minutes. |
| 273 * | 341 * |
| 274 * @param {function(string):void} myfunc | 342 * @param {function(string):void} myfunc |
| 275 * Function to invoke with access token. | 343 * Function to invoke with access token. |
| 276 * @return {void} Nothing. | 344 * @return {void} Nothing. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 330 * @return {?string} The email address, if it has been cached by a previous call | 398 * @return {?string} The email address, if it has been cached by a previous call |
| 331 * to getEmail, otherwise null. | 399 * to getEmail, otherwise null. |
| 332 */ | 400 */ |
| 333 remoting.OAuth2.prototype.getCachedEmail = function() { | 401 remoting.OAuth2.prototype.getCachedEmail = function() { |
| 334 var value = window.localStorage.getItem(this.KEY_EMAIL_); | 402 var value = window.localStorage.getItem(this.KEY_EMAIL_); |
| 335 if (typeof value == 'string') { | 403 if (typeof value == 'string') { |
| 336 return value; | 404 return value; |
| 337 } | 405 } |
| 338 return null; | 406 return null; |
| 339 }; | 407 }; |
| OLD | NEW |