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

Side by Side Diff: remoting/webapp/me2mom/remoting.js

Issue 7046012: Basic OAuth2 support using the native app flow. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Jamie's comments. Created 9 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « remoting/webapp/me2mom/manifest.json ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 // TODO(ajwong): This seems like a bad idea. Why are we doing it like this?
5 var remoting = chrome.extension.getBackgroundPage().remoting; 6 var remoting = chrome.extension.getBackgroundPage().remoting;
7
6 XMPP_LOGIN_NAME = 'xmpp_login'; 8 XMPP_LOGIN_NAME = 'xmpp_login';
7 XMPP_TOKEN_NAME = 'xmpp_token'; 9 XMPP_TOKEN_NAME = 'xmpp_token';
8 OAUTH2_TOKEN_NAME = 'oauth2_token';
9 HOST_PLUGIN_ID = 'host_plugin_id'; 10 HOST_PLUGIN_ID = 'host_plugin_id';
10 11
Jamie 2011/05/19 21:50:50 I think this would still be better in a separate f
12 // Declare an OAuth2 class to handle retrieval/storage of an OAuth2 token.
13 //
14 // Ideally, this should implement the OAuth2 PostMessage flow to avoid needing
15 // to copy and paste a code, but that does not support extension URL schemes
16 // quite yet. Instead, we currently use the native app flow with an
17 // authorization code that the user must cut/paste.
18 function OAuth2() {
19 this.OAUTH2_REFRESH_TOKEN_NAME = 'oauth2_refresh_token';
20
21 this.client_id = encodeURIComponent(
22 '440925447803-m890isgsr23kdkcu2erd4mirnrjalf98.' +
23 'apps.googleusercontent.com');
24 this.client_secret = encodeURIComponent('TgKrL73H2kJe6Ir0ufp7bf6e');
25 this.scope = encodeURIComponent(
26 'https://www.googleapis.com/auth/chromoting ' +
27 'https://www.googleapis.com/auth/googletalk');
28 this.redirect_uri = encodeURIComponent('urn:ietf:wg:oauth:2.0:oob');
29 }
30
31 OAuth2.prototype.isAuthenticated = function() {
32 if(this.getRefreshToken()) {
33 return true;
34 }
35 return false;
36 }
37
38 OAuth2.prototype.clear = function() {
39 remoting.removeItem(this.OAUTH2_REFRESH_TOKEN_NAME);
40 delete this.access_token;
41 delete this.access_token_expiration;
42 }
43
44 OAuth2.prototype.setRefreshToken = function(token) {
45 remoting.setItem(this.OAUTH2_REFRESH_TOKEN_NAME, token);
46 }
47
48 OAuth2.prototype.getRefreshToken = function(token) {
49 return remoting.getItem(this.OAUTH2_REFRESH_TOKEN_NAME);
50 }
51
52 OAuth2.prototype.setAccessToken = function(token, expiration) {
53 this.access_token = token;
54 // Offset by 30 seconds to account for RTT issues.
55 // TODO(ajwong): See if this is necessary, or of the protocol already
56 // accounts for RTT.
57 this.access_token_expiration = expiration - 30000;
58 }
59
60 OAuth2.prototype.needsNewAccessToken = function() {
61 if (!this.isAuthenticated()) {
62 throw "Not Authenticated.";
63 }
64 if (!this.access_token) {
65 return true;
66 }
67 if (Date.now() > this.access_token_expiration) {
68 return true;
69 }
70 return false;
71 }
72
73 OAuth2.prototype.getAccessToken = function() {
74 if (this.needsNewAccessToken()) {
75 throw "Access Token expired.";
76 }
77 return this.access_token;
78 }
79
80 OAuth2.prototype.refreshAccessToken = function(on_done) {
81 if (!this.isAuthenticated()) {
82 throw "Not Authenticated.";
83 }
84 var xhr = new XMLHttpRequest();
85 var that = this;
86 xhr.onreadystatechange = function() {
87 if (xhr.readyState != 4) {
88 return;
89 }
90 if (xhr.status == 200) {
91 tokens = JSON.parse(xhr.responseText);
92 that.setAccessToken(tokens['access_token'],
93 tokens['expires_in'] * 1000 + Date.now());
94 } else {
95 console.log("Refresh access token failed. Status: " + xhr.status +
96 " response: " + xhr.responseText);
97 }
98 on_done();
99 };
100 xhr.open('POST', 'https://accounts.google.com/o/oauth2/token', true);
101 xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
102 var post_data = 'client_id=' + this.client_id
103 + '&client_secret=' + this.client_secret
104 + '&refresh_token=' + encodeURIComponent(this.getRefreshToken())
105 + '&grant_type=refresh_token';
106 xhr.send(post_data);
107 }
108
109 OAuth2.prototype.openOAuth2Window = function() {
110 var GET_CODE_URL = 'https://accounts.google.com/o/oauth2/auth?'
111 + 'client_id=' + this.client_id
112 + '&redirect_uri=' + this.redirect_uri
113 + '&scope=' + this.scope
114 + '&response_type=code';
115 window.open(GET_CODE_URL);
116 }
117
118 OAuth2.prototype.exchangeCodeForToken = function(code, on_done) {
119 var xhr = new XMLHttpRequest();
120 var that = this;
121 xhr.onreadystatechange = function() {
122 if (xhr.readyState != 4) {
123 return;
124 }
125 if (xhr.status == 200) {
126 tokens = JSON.parse(xhr.responseText);
127 that.setRefreshToken(tokens['refresh_token']);
128 that.setAccessToken(tokens['access_token'],
129 tokens['expires_in'] + Date.now());
130 } else {
131 console.log("Code exchnage failed. Status: " + xhr.status +
132 " response: " + xhr.responseText);
133 }
134 on_done();
135 };
136 xhr.open('POST', 'https://accounts.google.com/o/oauth2/token', true);
137 xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
138 var post_data = 'client_id=' + this.client_id
139 + '&client_secret=' + this.client_secret
140 + '&redirect_uri=' + this.redirect_uri
141 + '&code=' + encodeURIComponent(code)
142 + '&grant_type=authorization_code';
143 xhr.send(post_data);
144 }
145
11 function updateAuthStatus_() { 146 function updateAuthStatus_() {
12 var oauth1_status = document.getElementById('oauth1_status'); 147 var oauth2_status = document.getElementById('oauth2_status');
13 if (remoting.oauth.hasToken()) { 148 if (remoting.oauth2.isAuthenticated()) {
14 oauth1_status.innerText = 'OK'; 149 oauth2_status.innerText = 'OK';
15 oauth1_status.style.color = 'green'; 150 oauth2_status.style.color = 'green';
151 document.getElementById('oauth2_code_button').style.display = 'none';
152 document.getElementById('oauth2_clear_button').style.display = 'inline';
153 document.getElementById('oauth2_form').style.display = 'none';
16 } else { 154 } else {
17 oauth1_status.innerText = 'Unauthorized'; 155 oauth2_status.innerText = 'Unauthorized';
18 oauth1_status.style.color = 'red'; 156 oauth2_status.style.color = 'red';
157 document.getElementById('oauth2_code_button').style.display = 'inline';
158 document.getElementById('oauth2_clear_button').style.display = 'none';
159 document.getElementById('oauth2_form').style.display = 'inline';
19 } 160 }
20 var xmpp_status = document.getElementById('xmpp_status'); 161 var xmpp_status = document.getElementById('xmpp_status');
21 if (remoting.getItem(XMPP_TOKEN_NAME) && remoting.getItem(XMPP_LOGIN_NAME)) { 162 if (remoting.getItem(XMPP_TOKEN_NAME) && remoting.getItem(XMPP_LOGIN_NAME)) {
22 document.getElementById('xmpp_clear').style.display = 'inline'; 163 document.getElementById('xmpp_clear').style.display = 'inline';
23 document.getElementById('xmpp_form').style.display = 'none'; 164 document.getElementById('xmpp_form').style.display = 'none';
24 xmpp_status.innerText = 'OK'; 165 xmpp_status.innerText = 'OK';
25 xmpp_status.style.color = 'green'; 166 xmpp_status.style.color = 'green';
26 remoting.xmppAuthToken = remoting.getItem(XMPP_TOKEN_NAME); 167 remoting.xmppAuthToken = remoting.getItem(XMPP_TOKEN_NAME);
27 } else { 168 } else {
28 document.getElementById('xmpp_clear').style.display = 'none'; 169 document.getElementById('xmpp_clear').style.display = 'none';
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 212
72 function initAuthPanel_() { 213 function initAuthPanel_() {
73 updateAuthStatus_(); 214 updateAuthStatus_();
74 resetXmppErrors_(); 215 resetXmppErrors_();
75 } 216 }
76 217
77 function initBackgroundFuncs_() { 218 function initBackgroundFuncs_() {
78 remoting.getItem = chrome.extension.getBackgroundPage().getItem; 219 remoting.getItem = chrome.extension.getBackgroundPage().getItem;
79 remoting.setItem = chrome.extension.getBackgroundPage().setItem; 220 remoting.setItem = chrome.extension.getBackgroundPage().setItem;
80 remoting.removeItem = chrome.extension.getBackgroundPage().removeItem; 221 remoting.removeItem = chrome.extension.getBackgroundPage().removeItem;
81 remoting.oauth = chrome.extension.getBackgroundPage().oauth; 222 remoting.oauth2 = new OAuth2();
82 } 223 }
83 224
84 function authorizeXmpp(form) { 225 function authorizeXmpp(form) {
85 var xhr = new XMLHttpRequest(); 226 var xhr = new XMLHttpRequest();
86 var captcha_result = readAndClearCaptcha_(form); 227 var captcha_result = readAndClearCaptcha_(form);
87 228
88 xhr.onreadystatechange = function() { 229 xhr.onreadystatechange = function() {
89 if (xhr.readyState != 4) { 230 if (xhr.readyState != 4) {
90 return; 231 return;
91 } 232 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 '&Email=' + encodeURIComponent(form['xmpp_username'].value) + 265 '&Email=' + encodeURIComponent(form['xmpp_username'].value) +
125 '&Passwd=' + encodeURIComponent(form['xmpp_password'].value); 266 '&Passwd=' + encodeURIComponent(form['xmpp_password'].value);
126 267
127 if (captcha_result[0]) { 268 if (captcha_result[0]) {
128 post_data += '&logintoken=' + encodeURIComponent(captcha_result[0]) + 269 post_data += '&logintoken=' + encodeURIComponent(captcha_result[0]) +
129 '&logincaptcha=' + encodeURIComponent(captcha_result[1]); 270 '&logincaptcha=' + encodeURIComponent(captcha_result[1]);
130 } 271 }
131 xhr.send(post_data); 272 xhr.send(post_data);
132 } 273 }
133 274
134 function authorizeOAuth1() { 275 function authorizeOAuth2(code) {
135 remoting.oauth.authorize(updateAuthStatus_); 276 remoting.oauth2.exchangeCodeForToken(code, updateAuthStatus_);
136 } 277 }
137 278
138 function clearOAuth1() { 279 function clearOAuth2() {
139 remoting.oauth.clearTokens(); 280 remoting.oauth2.clear();
140 updateAuthStatus_(); 281 updateAuthStatus_();
141 } 282 }
142 283
143 function clearXmpp() { 284 function clearXmpp() {
144 remoting.removeItem(XMPP_TOKEN_NAME); 285 remoting.removeItem(XMPP_TOKEN_NAME);
145 updateAuthStatus_(); 286 updateAuthStatus_();
146 } 287 }
147 288
148 // Show the div with id |mode| and hide those with other ids in |modes|. 289 // Show the div with id |mode| and hide those with other ids in |modes|.
149 function setMode_(mode, modes) { 290 function setMode_(mode, modes) {
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 } else { 377 } else {
237 invalid.style.display = 'none'; 378 invalid.style.display = 'none';
238 other.style.display = 'block'; 379 other.style.display = 'block';
239 var responseNode = document.getElementById('server_response'); 380 var responseNode = document.getElementById('server_response');
240 responseNode.innerText = responseString + ' (' + responseCode + ')'; 381 responseNode.innerText = responseString + ' (' + responseCode + ')';
241 } 382 }
242 remoting.accessCode = ''; 383 remoting.accessCode = '';
243 setClientMode('connect_failed'); 384 setClientMode('connect_failed');
244 } 385 }
245 386
246 function parseServerResponse_(reply, xhr) { 387 function parseServerResponse_(xhr) {
247 if (xhr.status == 200) { 388 if (xhr.status == 200) {
248 var host = JSON.parse(xhr.responseText); 389 var host = JSON.parse(xhr.responseText);
249 if (host.data && host.data.jabberId) { 390 if (host.data && host.data.jabberId) {
250 remoting.hostjid = host.data.jabberId; 391 remoting.hostjid = host.data.jabberId;
251 startSession_(); 392 startSession_();
252 return; 393 return;
253 } 394 }
254 } 395 }
255 showConnectError_(xhr.status, xhr.responseText); 396 showConnectError_(xhr.status, xhr.responseText);
256 } 397 }
257 398
399 function resolveSupportId(support_id) {
400 var xhr = new XMLHttpRequest();
401 xhr.onreadystatechange = function() {
402 if (xhr.readyState != 4) {
403 return;
404 }
405 parseServerResponse_(xhr);
406 };
407
408 xhr.open('GET',
409 'https://www.googleapis.com/chromoting/v1/support-hosts/' +
410 encodeURIComponent(support_id),
411 true);
412 xhr.setRequestHeader('Authorization',
413 'OAuth ' + remoting.oauth2.getAccessToken());
414 xhr.send(null);
415 }
416
258 function tryConnect(form) { 417 function tryConnect(form) {
259 remoting.accessCode = form['access_code_entry'].value; 418 remoting.accessCode = form['access_code_entry'].value;
260 // TODO(jamiewalch): Since the mapping from (SupportId, HostSecret) to 419 // TODO(jamiewalch): Since the mapping from (SupportId, HostSecret) to
261 // AccessCode is not yet defined, assume it's hyphen-separated for now. 420 // AccessCode is not yet defined, assume it's hyphen-separated for now.
262 var parts = remoting.accessCode.split('-'); 421 var parts = remoting.accessCode.split('-');
263 if (parts.length != 2) { 422 if (parts.length != 2) {
264 showConnectError_(404); 423 showConnectError_(404);
265 } else { 424 } else {
266 setClientMode('connecting'); 425 setClientMode('connecting');
267 var urlBase = 'https://www.googleapis.com/chromoting/v1/support-hosts/'; 426 if (remoting.oauth2.needsNewAccessToken()) {
268 remoting.oauth.sendSignedRequest( 427 remoting.oauth2.refreshAccessToken(function() {
269 urlBase + '' + encodeURIComponent(parts[0]) + '', 428 resolveSupportId(parts[0]);
270 parseServerResponse_); 429 });
430 return;
431 } else {
432 resolveSupportId(parts[0]);
433 }
271 } 434 }
272 } 435 }
273 436
274 function cancelConnect() { 437 function cancelConnect() {
275 remoting.accessCode = ''; 438 remoting.accessCode = '';
276 setClientMode('unconnected'); 439 setClientMode('unconnected');
277 } 440 }
OLDNEW
« no previous file with comments | « remoting/webapp/me2mom/manifest.json ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698