Chromium Code Reviews| Index: remoting/webapp/me2mom/remoting.js |
| diff --git a/remoting/webapp/me2mom/remoting.js b/remoting/webapp/me2mom/remoting.js |
| index 2f364c11514bc9cdf509a4438a854a45bdf54dd3..81828010871dc5998b04a796e3fcda9df400ce41 100644 |
| --- a/remoting/webapp/me2mom/remoting.js |
| +++ b/remoting/webapp/me2mom/remoting.js |
| @@ -2,20 +2,161 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| +// TODO(ajwong): This seems like a bad idea. Why are we doing it like this? |
| var remoting = chrome.extension.getBackgroundPage().remoting; |
| + |
| XMPP_LOGIN_NAME = 'xmpp_login'; |
| XMPP_TOKEN_NAME = 'xmpp_token'; |
| -OAUTH2_TOKEN_NAME = 'oauth2_token'; |
| HOST_PLUGIN_ID = 'host_plugin_id'; |
|
Jamie
2011/05/19 21:50:50
I think this would still be better in a separate f
|
| +// Declare an OAuth2 class to handle retrieval/storage of an OAuth2 token. |
| +// |
| +// Ideally, this should implement the OAuth2 PostMessage flow to avoid needing |
| +// to copy and paste a code, but that does not support extension URL schemes |
| +// quite yet. Instead, we currently use the native app flow with an |
| +// authorization code that the user must cut/paste. |
| +function OAuth2() { |
| + this.OAUTH2_REFRESH_TOKEN_NAME = 'oauth2_refresh_token'; |
| + |
| + this.client_id = encodeURIComponent( |
| + '440925447803-m890isgsr23kdkcu2erd4mirnrjalf98.' + |
| + 'apps.googleusercontent.com'); |
| + this.client_secret = encodeURIComponent('TgKrL73H2kJe6Ir0ufp7bf6e'); |
| + this.scope = encodeURIComponent( |
| + 'https://www.googleapis.com/auth/chromoting ' + |
| + 'https://www.googleapis.com/auth/googletalk'); |
| + this.redirect_uri = encodeURIComponent('urn:ietf:wg:oauth:2.0:oob'); |
| +} |
| + |
| +OAuth2.prototype.isAuthenticated = function() { |
| + if(this.getRefreshToken()) { |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +OAuth2.prototype.clear = function() { |
| + remoting.removeItem(this.OAUTH2_REFRESH_TOKEN_NAME); |
| + delete this.access_token; |
| + delete this.access_token_expiration; |
| +} |
| + |
| +OAuth2.prototype.setRefreshToken = function(token) { |
| + remoting.setItem(this.OAUTH2_REFRESH_TOKEN_NAME, token); |
| +} |
| + |
| +OAuth2.prototype.getRefreshToken = function(token) { |
| + return remoting.getItem(this.OAUTH2_REFRESH_TOKEN_NAME); |
| +} |
| + |
| +OAuth2.prototype.setAccessToken = function(token, expiration) { |
| + this.access_token = token; |
| + // Offset by 30 seconds to account for RTT issues. |
| + // TODO(ajwong): See if this is necessary, or of the protocol already |
| + // accounts for RTT. |
| + this.access_token_expiration = expiration - 30000; |
| +} |
| + |
| +OAuth2.prototype.needsNewAccessToken = function() { |
| + if (!this.isAuthenticated()) { |
| + throw "Not Authenticated."; |
| + } |
| + if (!this.access_token) { |
| + return true; |
| + } |
| + if (Date.now() > this.access_token_expiration) { |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +OAuth2.prototype.getAccessToken = function() { |
| + if (this.needsNewAccessToken()) { |
| + throw "Access Token expired."; |
| + } |
| + return this.access_token; |
| +} |
| + |
| +OAuth2.prototype.refreshAccessToken = function(on_done) { |
| + if (!this.isAuthenticated()) { |
| + throw "Not Authenticated."; |
| + } |
| + var xhr = new XMLHttpRequest(); |
| + var that = this; |
| + xhr.onreadystatechange = function() { |
| + if (xhr.readyState != 4) { |
| + return; |
| + } |
| + if (xhr.status == 200) { |
| + tokens = JSON.parse(xhr.responseText); |
| + that.setAccessToken(tokens['access_token'], |
| + tokens['expires_in'] * 1000 + Date.now()); |
| + } else { |
| + console.log("Refresh access token failed. Status: " + xhr.status + |
| + " response: " + xhr.responseText); |
| + } |
| + on_done(); |
| + }; |
| + xhr.open('POST', 'https://accounts.google.com/o/oauth2/token', true); |
| + xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); |
| + var post_data = 'client_id=' + this.client_id |
| + + '&client_secret=' + this.client_secret |
| + + '&refresh_token=' + encodeURIComponent(this.getRefreshToken()) |
| + + '&grant_type=refresh_token'; |
| + xhr.send(post_data); |
| +} |
| + |
| +OAuth2.prototype.openOAuth2Window = function() { |
| + var GET_CODE_URL = 'https://accounts.google.com/o/oauth2/auth?' |
| + + 'client_id=' + this.client_id |
| + + '&redirect_uri=' + this.redirect_uri |
| + + '&scope=' + this.scope |
| + + '&response_type=code'; |
| + window.open(GET_CODE_URL); |
| +} |
| + |
| +OAuth2.prototype.exchangeCodeForToken = function(code, on_done) { |
| + var xhr = new XMLHttpRequest(); |
| + var that = this; |
| + xhr.onreadystatechange = function() { |
| + if (xhr.readyState != 4) { |
| + return; |
| + } |
| + if (xhr.status == 200) { |
| + tokens = JSON.parse(xhr.responseText); |
| + that.setRefreshToken(tokens['refresh_token']); |
| + that.setAccessToken(tokens['access_token'], |
| + tokens['expires_in'] + Date.now()); |
| + } else { |
| + console.log("Code exchnage failed. Status: " + xhr.status + |
| + " response: " + xhr.responseText); |
| + } |
| + on_done(); |
| + }; |
| + xhr.open('POST', 'https://accounts.google.com/o/oauth2/token', true); |
| + xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); |
| + var post_data = 'client_id=' + this.client_id |
| + + '&client_secret=' + this.client_secret |
| + + '&redirect_uri=' + this.redirect_uri |
| + + '&code=' + encodeURIComponent(code) |
| + + '&grant_type=authorization_code'; |
| + xhr.send(post_data); |
| +} |
| + |
| function updateAuthStatus_() { |
| - var oauth1_status = document.getElementById('oauth1_status'); |
| - if (remoting.oauth.hasToken()) { |
| - oauth1_status.innerText = 'OK'; |
| - oauth1_status.style.color = 'green'; |
| + var oauth2_status = document.getElementById('oauth2_status'); |
| + if (remoting.oauth2.isAuthenticated()) { |
| + oauth2_status.innerText = 'OK'; |
| + oauth2_status.style.color = 'green'; |
| + document.getElementById('oauth2_code_button').style.display = 'none'; |
| + document.getElementById('oauth2_clear_button').style.display = 'inline'; |
| + document.getElementById('oauth2_form').style.display = 'none'; |
| } else { |
| - oauth1_status.innerText = 'Unauthorized'; |
| - oauth1_status.style.color = 'red'; |
| + oauth2_status.innerText = 'Unauthorized'; |
| + oauth2_status.style.color = 'red'; |
| + document.getElementById('oauth2_code_button').style.display = 'inline'; |
| + document.getElementById('oauth2_clear_button').style.display = 'none'; |
| + document.getElementById('oauth2_form').style.display = 'inline'; |
| } |
| var xmpp_status = document.getElementById('xmpp_status'); |
| if (remoting.getItem(XMPP_TOKEN_NAME) && remoting.getItem(XMPP_LOGIN_NAME)) { |
| @@ -78,7 +219,7 @@ function initBackgroundFuncs_() { |
| remoting.getItem = chrome.extension.getBackgroundPage().getItem; |
| remoting.setItem = chrome.extension.getBackgroundPage().setItem; |
| remoting.removeItem = chrome.extension.getBackgroundPage().removeItem; |
| - remoting.oauth = chrome.extension.getBackgroundPage().oauth; |
| + remoting.oauth2 = new OAuth2(); |
| } |
| function authorizeXmpp(form) { |
| @@ -131,12 +272,12 @@ function authorizeXmpp(form) { |
| xhr.send(post_data); |
| } |
| -function authorizeOAuth1() { |
| - remoting.oauth.authorize(updateAuthStatus_); |
| +function authorizeOAuth2(code) { |
| + remoting.oauth2.exchangeCodeForToken(code, updateAuthStatus_); |
| } |
| -function clearOAuth1() { |
| - remoting.oauth.clearTokens(); |
| +function clearOAuth2() { |
| + remoting.oauth2.clear(); |
| updateAuthStatus_(); |
| } |
| @@ -243,7 +384,7 @@ function showConnectError_(responseCode, responseString) { |
| setClientMode('connect_failed'); |
| } |
| -function parseServerResponse_(reply, xhr) { |
| +function parseServerResponse_(xhr) { |
| if (xhr.status == 200) { |
| var host = JSON.parse(xhr.responseText); |
| if (host.data && host.data.jabberId) { |
| @@ -255,6 +396,24 @@ function parseServerResponse_(reply, xhr) { |
| showConnectError_(xhr.status, xhr.responseText); |
| } |
| +function resolveSupportId(support_id) { |
| + var xhr = new XMLHttpRequest(); |
| + xhr.onreadystatechange = function() { |
| + if (xhr.readyState != 4) { |
| + return; |
| + } |
| + parseServerResponse_(xhr); |
| + }; |
| + |
| + xhr.open('GET', |
| + 'https://www.googleapis.com/chromoting/v1/support-hosts/' + |
| + encodeURIComponent(support_id), |
| + true); |
| + xhr.setRequestHeader('Authorization', |
| + 'OAuth ' + remoting.oauth2.getAccessToken()); |
| + xhr.send(null); |
| +} |
| + |
| function tryConnect(form) { |
| remoting.accessCode = form['access_code_entry'].value; |
| // TODO(jamiewalch): Since the mapping from (SupportId, HostSecret) to |
| @@ -264,10 +423,14 @@ function tryConnect(form) { |
| showConnectError_(404); |
| } else { |
| setClientMode('connecting'); |
| - var urlBase = 'https://www.googleapis.com/chromoting/v1/support-hosts/'; |
| - remoting.oauth.sendSignedRequest( |
| - urlBase + '' + encodeURIComponent(parts[0]) + '', |
| - parseServerResponse_); |
| + if (remoting.oauth2.needsNewAccessToken()) { |
| + remoting.oauth2.refreshAccessToken(function() { |
| + resolveSupportId(parts[0]); |
| + }); |
| + return; |
| + } else { |
| + resolveSupportId(parts[0]); |
| + } |
| } |
| } |