| 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 13 matching lines...) Expand all Loading... |
| 24 | 24 |
| 25 | 25 |
| 26 /** @constructor */ | 26 /** @constructor */ |
| 27 remoting.OAuth2 = function() { | 27 remoting.OAuth2 = function() { |
| 28 }; | 28 }; |
| 29 | 29 |
| 30 // Constants representing keys used for storing persistent state. | 30 // Constants representing keys used for storing persistent state. |
| 31 /** @private */ | 31 /** @private */ |
| 32 remoting.OAuth2.prototype.KEY_REFRESH_TOKEN_ = 'oauth2-refresh-token'; | 32 remoting.OAuth2.prototype.KEY_REFRESH_TOKEN_ = 'oauth2-refresh-token'; |
| 33 /** @private */ | 33 /** @private */ |
| 34 remoting.OAuth2.prototype.KEY_REFRESH_TOKEN_REVOKABLE_ = | |
| 35 'oauth2-refresh-token-revokable'; | |
| 36 /** @private */ | |
| 37 remoting.OAuth2.prototype.KEY_ACCESS_TOKEN_ = 'oauth2-access-token'; | 34 remoting.OAuth2.prototype.KEY_ACCESS_TOKEN_ = 'oauth2-access-token'; |
| 38 /** @private */ | 35 /** @private */ |
| 39 remoting.OAuth2.prototype.KEY_XSRF_TOKEN_ = 'oauth2-xsrf-token'; | 36 remoting.OAuth2.prototype.KEY_XSRF_TOKEN_ = 'oauth2-xsrf-token'; |
| 40 /** @private */ | 37 /** @private */ |
| 41 remoting.OAuth2.prototype.KEY_EMAIL_ = 'remoting-email'; | 38 remoting.OAuth2.prototype.KEY_EMAIL_ = 'remoting-email'; |
| 42 | 39 |
| 43 // Constants for parameters used in retrieving the OAuth2 credentials. | 40 // Constants for parameters used in retrieving the OAuth2 credentials. |
| 44 /** @private */ | 41 /** @private */ |
| 45 remoting.OAuth2.prototype.SCOPE_ = | 42 remoting.OAuth2.prototype.SCOPE_ = |
| 46 'https://www.googleapis.com/auth/chromoting ' + | 43 'https://www.googleapis.com/auth/chromoting ' + |
| (...skipping 24 matching lines...) Expand all Loading... |
| 71 | 68 |
| 72 /** @private | 69 /** @private |
| 73 * @return {string} OAuth2 authentication URL. | 70 * @return {string} OAuth2 authentication URL. |
| 74 */ | 71 */ |
| 75 remoting.OAuth2.prototype.getOAuth2AuthEndpoint_ = function() { | 72 remoting.OAuth2.prototype.getOAuth2AuthEndpoint_ = function() { |
| 76 return remoting.settings.OAUTH2_BASE_URL + '/auth'; | 73 return remoting.settings.OAUTH2_BASE_URL + '/auth'; |
| 77 }; | 74 }; |
| 78 | 75 |
| 79 /** @return {boolean} True if the app is already authenticated. */ | 76 /** @return {boolean} True if the app is already authenticated. */ |
| 80 remoting.OAuth2.prototype.isAuthenticated = function() { | 77 remoting.OAuth2.prototype.isAuthenticated = function() { |
| 81 if (this.getRefreshToken_()) { | 78 if (this.getRefreshToken()) { |
| 82 return true; | 79 return true; |
| 83 } | 80 } |
| 84 return false; | 81 return false; |
| 85 }; | 82 }; |
| 86 | 83 |
| 87 /** | 84 /** |
| 88 * Removes all storage, and effectively unauthenticates the user. | 85 * Removes all storage, and effectively unauthenticates the user. |
| 89 * | 86 * |
| 90 * @return {void} Nothing. | 87 * @return {void} Nothing. |
| 91 */ | 88 */ |
| 92 remoting.OAuth2.prototype.clear = function() { | 89 remoting.OAuth2.prototype.clear = function() { |
| 93 window.localStorage.removeItem(this.KEY_EMAIL_); | 90 window.localStorage.removeItem(this.KEY_EMAIL_); |
| 94 this.clearAccessToken_(); | 91 this.clearAccessToken_(); |
| 95 this.clearRefreshToken_(); | 92 this.clearRefreshToken_(); |
| 96 }; | 93 }; |
| 97 | 94 |
| 98 /** | 95 /** |
| 99 * Sets the refresh token. | 96 * Sets the refresh token. |
| 100 * | 97 * |
| 101 * This method also marks the token as revokable, so that this object will | |
| 102 * revoke the token when it no longer needs it. | |
| 103 * | |
| 104 * @param {string} token The new refresh token. | 98 * @param {string} token The new refresh token. |
| 105 * @return {void} Nothing. | 99 * @return {void} Nothing. |
| 106 * @private | 100 * @private |
| 107 */ | 101 */ |
| 108 remoting.OAuth2.prototype.setRefreshToken_ = function(token) { | 102 remoting.OAuth2.prototype.setRefreshToken_ = function(token) { |
| 109 window.localStorage.setItem(this.KEY_REFRESH_TOKEN_, escape(token)); | 103 window.localStorage.setItem(this.KEY_REFRESH_TOKEN_, escape(token)); |
| 110 window.localStorage.setItem(this.KEY_REFRESH_TOKEN_REVOKABLE_, true); | |
| 111 window.localStorage.removeItem(this.KEY_EMAIL_); | 104 window.localStorage.removeItem(this.KEY_EMAIL_); |
| 112 this.clearAccessToken_(); | 105 this.clearAccessToken_(); |
| 113 }; | 106 }; |
| 114 | 107 |
| 115 /** | 108 /** |
| 116 * Gets the refresh token. | |
| 117 * | |
| 118 * This method also marks the refresh token as not revokable, so that this | |
| 119 * object will not revoke the token when it no longer needs it. After this | |
| 120 * object has exported the token, it cannot know whether it is still in use | |
| 121 * when this object no longer needs it. | |
| 122 * | |
| 123 * @return {?string} The refresh token, if authenticated, or NULL. | 109 * @return {?string} The refresh token, if authenticated, or NULL. |
| 124 */ | 110 */ |
| 125 remoting.OAuth2.prototype.exportRefreshToken = function() { | 111 remoting.OAuth2.prototype.getRefreshToken = function() { |
| 126 window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_REVOKABLE_); | |
| 127 return this.getRefreshToken_(); | |
| 128 }; | |
| 129 | |
| 130 /** | |
| 131 * @return {?string} The refresh token, if authenticated, or NULL. | |
| 132 * @private | |
| 133 */ | |
| 134 remoting.OAuth2.prototype.getRefreshToken_ = function() { | |
| 135 var value = window.localStorage.getItem(this.KEY_REFRESH_TOKEN_); | 112 var value = window.localStorage.getItem(this.KEY_REFRESH_TOKEN_); |
| 136 if (typeof value == 'string') { | 113 if (typeof value == 'string') { |
| 137 return unescape(value); | 114 return unescape(value); |
| 138 } | 115 } |
| 139 return null; | 116 return null; |
| 140 }; | 117 }; |
| 141 | 118 |
| 142 /** | 119 /** |
| 143 * Clears the refresh token. | 120 * Clears the refresh token. |
| 144 * | 121 * |
| 145 * @return {void} Nothing. | 122 * @return {void} Nothing. |
| 146 * @private | 123 * @private |
| 147 */ | 124 */ |
| 148 remoting.OAuth2.prototype.clearRefreshToken_ = function() { | 125 remoting.OAuth2.prototype.clearRefreshToken_ = function() { |
| 149 if (window.localStorage.getItem(this.KEY_REFRESH_TOKEN_REVOKABLE_)) { | |
| 150 this.revokeToken_(this.getRefreshToken_()); | |
| 151 } | |
| 152 window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_); | 126 window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_); |
| 153 window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_REVOKABLE_); | |
| 154 }; | 127 }; |
| 155 | 128 |
| 156 /** | 129 /** |
| 157 * @param {string} token The new access token. | 130 * @param {string} token The new access token. |
| 158 * @param {number} expiration Expiration time in milliseconds since epoch. | 131 * @param {number} expiration Expiration time in milliseconds since epoch. |
| 159 * @return {void} Nothing. | 132 * @return {void} Nothing. |
| 160 * @private | 133 * @private |
| 161 */ | 134 */ |
| 162 remoting.OAuth2.prototype.setAccessToken_ = function(token, expiration) { | 135 remoting.OAuth2.prototype.setAccessToken_ = function(token, expiration) { |
| 163 // Offset expiration by 120 seconds so that we can guarantee that the token | 136 // Offset expiration by 120 seconds so that we can guarantee that the token |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 console.error('Unable to exchange code for token: ', error); | 304 console.error('Unable to exchange code for token: ', error); |
| 332 }; | 305 }; |
| 333 | 306 |
| 334 remoting.OAuth2Api.exchangeCodeForTokens( | 307 remoting.OAuth2Api.exchangeCodeForTokens( |
| 335 this.onTokens_.bind(this, onDone), onError, | 308 this.onTokens_.bind(this, onDone), onError, |
| 336 this.getClientId_(), this.getClientSecret_(), code, | 309 this.getClientId_(), this.getClientSecret_(), code, |
| 337 this.getRedirectUri_()); | 310 this.getRedirectUri_()); |
| 338 }; | 311 }; |
| 339 | 312 |
| 340 /** | 313 /** |
| 341 * Revokes a refresh or an access token. | |
| 342 * | |
| 343 * @param {string?} token An access or refresh token. | |
| 344 * @return {void} Nothing. | |
| 345 * @private | |
| 346 */ | |
| 347 remoting.OAuth2.prototype.revokeToken_ = function(token) { | |
| 348 if (!token || (token.length == 0)) { | |
| 349 return; | |
| 350 } | |
| 351 | |
| 352 remoting.OAuth2Api.revokeToken(function() {}, function() {}, token); | |
| 353 }; | |
| 354 | |
| 355 /** | |
| 356 * Call a function with an access token, refreshing it first if necessary. | 314 * Call a function with an access token, refreshing it first if necessary. |
| 357 * The access token will remain valid for at least 2 minutes. | 315 * The access token will remain valid for at least 2 minutes. |
| 358 * | 316 * |
| 359 * @param {function(string):void} onOk Function to invoke with access token if | 317 * @param {function(string):void} onOk Function to invoke with access token if |
| 360 * an access token was successfully retrieved. | 318 * an access token was successfully retrieved. |
| 361 * @param {function(remoting.Error):void} onError Function to invoke with an | 319 * @param {function(remoting.Error):void} onError Function to invoke with an |
| 362 * error code on failure. | 320 * error code on failure. |
| 363 * @return {void} Nothing. | 321 * @return {void} Nothing. |
| 364 */ | 322 */ |
| 365 remoting.OAuth2.prototype.callWithToken = function(onOk, onError) { | 323 remoting.OAuth2.prototype.callWithToken = function(onOk, onError) { |
| 366 var refreshToken = this.getRefreshToken_(); | 324 var refreshToken = this.getRefreshToken(); |
| 367 if (refreshToken) { | 325 if (refreshToken) { |
| 368 if (this.needsNewAccessToken_()) { | 326 if (this.needsNewAccessToken_()) { |
| 369 remoting.OAuth2Api.refreshAccessToken( | 327 remoting.OAuth2Api.refreshAccessToken( |
| 370 this.onAccessToken_.bind(this, onOk), onError, | 328 this.onAccessToken_.bind(this, onOk), onError, |
| 371 this.getClientId_(), this.getClientSecret_(), | 329 this.getClientId_(), this.getClientSecret_(), |
| 372 refreshToken); | 330 refreshToken); |
| 373 } else { | 331 } else { |
| 374 onOk(this.getAccessTokenInternal_()['token']); | 332 onOk(this.getAccessTokenInternal_()['token']); |
| 375 } | 333 } |
| 376 } else { | 334 } else { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 411 * @return {?string} The email address, if it has been cached by a previous call | 369 * @return {?string} The email address, if it has been cached by a previous call |
| 412 * to getEmail, otherwise null. | 370 * to getEmail, otherwise null. |
| 413 */ | 371 */ |
| 414 remoting.OAuth2.prototype.getCachedEmail = function() { | 372 remoting.OAuth2.prototype.getCachedEmail = function() { |
| 415 var value = window.localStorage.getItem(this.KEY_EMAIL_); | 373 var value = window.localStorage.getItem(this.KEY_EMAIL_); |
| 416 if (typeof value == 'string') { | 374 if (typeof value == 'string') { |
| 417 return value; | 375 return value; |
| 418 } | 376 } |
| 419 return null; | 377 return null; |
| 420 }; | 378 }; |
| OLD | NEW |