summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-21 00:21:15 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-21 00:21:15 +0000
commit285a00882abba22fee14b904db1b48a7c21371af (patch)
tree386175baba80fab8102a316f5214cc46fdb3a02a
parentc2f42890d6214938a612da4f0c096d8e970cad99 (diff)
downloadchromium_src-285a00882abba22fee14b904db1b48a7c21371af.zip
chromium_src-285a00882abba22fee14b904db1b48a7c21371af.tar.gz
chromium_src-285a00882abba22fee14b904db1b48a7c21371af.tar.bz2
Update the appengine code to use OAuth2 and break the gdata dependency.
BUG=none TEST=Connect still works. Review URL: http://codereview.chromium.org/7033042 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86183 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--remoting/client/appengine/api.py33
-rw-r--r--remoting/client/appengine/app.yaml2
-rw-r--r--remoting/client/appengine/auth.py337
-rw-r--r--remoting/client/appengine/chromoting_oauth_setup.html27
-rw-r--r--remoting/client/appengine/chromoting_session.html2
-rw-r--r--remoting/client/appengine/hostlist.html18
-rw-r--r--remoting/client/appengine/main.py7
-rw-r--r--remoting/client/appengine/static_files/client.js45
-rw-r--r--remoting/client/extension/manifest.json15
9 files changed, 206 insertions, 280 deletions
diff --git a/remoting/client/appengine/api.py b/remoting/client/appengine/api.py
index ec16fc6..e1e2ddb 100644
--- a/remoting/client/appengine/api.py
+++ b/remoting/client/appengine/api.py
@@ -10,8 +10,7 @@ import logging
from django.utils import simplejson as json
-import gdata.client
-
+from google.appengine.api import urlfetch
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp.util import login_required
@@ -30,26 +29,26 @@ class GetXmppTokenHandler(webapp.RequestHandler):
self.response.out.write('User has not authenticated')
self.set_status(400)
+
class GetHostListHandler(webapp.RequestHandler):
"""Proxies the host-list handlers on the Chromoting directory."""
@login_required
def get(self):
- try:
- client = gdata.client.GDClient()
- host_list_json = client.Request(
- method='GET',
- uri="https://www.googleapis.com/chromoting/v1/@me/hosts",
- converter=None,
- desired_class=None,
- auth_token=auth.GetChromotingToken())
+ if not auth.HasOAuth2Tokens():
+ self.response.set_status(403)
self.response.headers['Content-Type'] = 'application/json'
- self.response.out.write(host_list_json.read())
- except auth.NotAuthenticated:
- self.response.out.write('User has not authenticated')
- self.response.set_status(400)
- except (gdata.client.Unauthorized, gdata.client.RequestError), inst:
- self.response.out.write(inst.reason)
- self.response.set_status(inst.status)
+ self.response.out.write(
+ '{"error": { "code": -1, "message": "No OAuth2 token" }}')
+ return
+ result = urlfetch.fetch(
+ url = 'https://www.googleapis.com/chromoting/v1/@me/hosts',
+ method = urlfetch.GET,
+ headers = {'Authorization': 'OAuth ' + auth.GetAccessToken()})
+ self.response.set_status(result.status_code)
+ for i in result.headers:
+ self.response.headers[i] = result.headers[i]
+ self.response.out.write(result.content)
+
def main():
application = webapp.WSGIApplication(
diff --git a/remoting/client/appengine/app.yaml b/remoting/client/appengine/app.yaml
index ff9db53..a5d7436 100644
--- a/remoting/client/appengine/app.yaml
+++ b/remoting/client/appengine/app.yaml
@@ -1,5 +1,5 @@
application: google.com:chromoting
-version: 1
+version: 2
runtime: python
api_version: 1
diff --git a/remoting/client/appengine/auth.py b/remoting/client/appengine/auth.py
index 40433cc..54be383 100644
--- a/remoting/client/appengine/auth.py
+++ b/remoting/client/appengine/auth.py
@@ -12,59 +12,85 @@ initiating authentication flows, and for managing credential storage per user.
"""
import os
+import re
+import time
+import urllib
+from urlparse import urlparse
-import gdata.gauth
-import gdata.client
from google.appengine.ext import db
+from google.appengine.api import urlfetch
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp.util import login_required
+from django.utils import simplejson as json
+
SCOPES = ['https://www.googleapis.com/auth/chromoting',
'https://www.googleapis.com/auth/googletalk' ]
+# Development OAuth2 ID and keys.
+CLIENT_ID = ('440925447803-d9u05st5jjm3gbe865l0jeaujqfrufrn.'
+ 'apps.googleusercontent.com')
+CLIENT_SECRET = 'Nl4vSQEgDpPMP-1rDEsgs3V7'
+
class NotAuthenticated(Exception):
"""API requiring authentication is called with credentials."""
pass
-class OAuthInvalidSetup(Exception):
- """OAuth configuration on app is not complete."""
- pass
+class XmppToken(db.Model):
+ auth_token = db.StringProperty()
-class OAuthConfig(db.Model):
- """Stores the configuration data for OAuth.
+class OAuth2Tokens(db.Model):
+ """Stores the Refresh and Access token information for OAuth2."""
+ refresh_token = db.StringProperty()
+ access_token = db.StringProperty()
+ access_token_expiration = db.IntegerProperty()
- Currently used to store the consumer key and secret so that it does not need
- to be checked into the source tree.
- """
- consumer_key = db.StringProperty()
- consumer_secret = db.StringProperty()
- httpxmppproxy = db.StringProperty()
+def HasOAuth2Tokens(throws=True):
+ oauth2_tokens = OAuth2Tokens.get_or_insert(GetUserId())
+ if oauth2_tokens.refresh_token:
+ return True;
+ return False;
-def GetChromotingToken(throws=True):
- """Retrieves the Chromoting OAuth token for the user.
- Args:
- throws: bool (optional) Default is True. Throws if no token.
+def GetAccessToken(throws=True):
+ oauth2_tokens = OAuth2Tokens.get_or_insert(GetUserId())
- Returns:
- An gdata.gauth.OAuthHmacToken for the current user.
- """
- user = users.get_current_user()
- access_token = None
- if user:
- access_token = LoadToken('chromoting_token')
- if throws and not access_token:
+ if not oauth2_tokens.refresh_token:
raise NotAuthenticated()
- return access_token
+
+ if time.time() > oauth2_tokens.access_token_expiration:
+ form_fields = {
+ 'client_id' : CLIENT_ID,
+ 'client_secret' : CLIENT_SECRET,
+ 'refresh_token' : oauth2_tokens.refresh_token,
+ 'grant_type' : 'refresh_token'
+ }
+ form_data = urllib.urlencode(form_fields)
+ result = urlfetch.fetch(
+ url = 'https://accounts.google.com/o/oauth2/token',
+ payload = form_data,
+ method = urlfetch.POST,
+ headers = {'Content-Type': 'application/x-www-form-urlencoded'})
+ if result.status_code != 200:
+ raise 'something went wrong %d, %s <br />' % (
+ result.status_code, result.content)
+ oauth_json = json.loads(result.content)
+ oauth2_tokens.access_token = oauth_json['access_token']
+ # Give us 30 second buffer to hackily account for RTT on network request.
+ oauth2_tokens.access_token_expiration = (
+ int(oauth_json['expires_in'] + time.time() - 30))
+ oauth2_tokens.put()
+
+ return oauth2_tokens.access_token
def GetXmppToken(throws=True):
@@ -74,26 +100,22 @@ def GetXmppToken(throws=True):
throws: bool (optional) Default is True. Throws if no token.
Returns:
- An gdata.gauth.ClientLoginToken for the current user.
+ The auth token for the current user.
"""
- user = users.get_current_user()
- access_token = None
- if user:
- access_token = LoadToken('xmpp_token')
- if throws and not access_token:
+ xmpp_token = XmppToken.get_or_insert(GetUserId())
+ if throws and not xmpp_token.auth_token:
raise NotAuthenticated()
- return access_token
+ return xmpp_token.auth_token
-def ClearChromotingToken():
- """Clears all Chromoting OAuth token state from the datastore."""
- DeleteToken('request_token')
- DeleteToken('chromoting_token')
+def ClearXmppToken():
+ """Clears all Chromoting ClientLogin token state from the datastore."""
+ db.delete(db.Key.from_path('XmppToken', GetUserId()))
-def ClearXmppToken():
+def ClearOAuth2Token():
"""Clears all Chromoting ClientLogin token state from the datastore."""
- DeleteToken('xmpp_token')
+ db.delete(db.Key.from_path('OAuth2Tokens', GetUserId()))
def GetUserId():
@@ -115,116 +137,6 @@ def GetUserId():
return user.user_id()
-def LoadToken(name):
- """Leads a gdata auth token for the current user.
-
- Tokens are scoped to each user, and retrieved by a name.
-
- Args:
- name: A string with the name of the token for the current user.
-
- Returns:
- The token associated with the name for the user.
- """
- user_id = GetUserId();
- return gdata.gauth.AeLoad(user_id + name)
-
-
-def SaveToken(name, token):
- """Saves a gdata auth token for the current user.
-
- Tokens are scoped to each user, and stored by a name.
-
- Args:
- name: A string with the name of the token.
- """
- user_id = GetUserId();
- gdata.gauth.AeSave(token, user_id + name)
-
-
-def DeleteToken(name):
- """Deletes a stored gdata auth token for the current user.
-
- Tokens are scoped to each user, and stored by a name.
-
- Args:
- name: A string with the name of the token.
- """
- user_id = GetUserId();
- gdata.gauth.AeDelete(user_id + name)
-
-
-def OAuthConfigKey():
- """Generates a standard key path for this app's OAuth configuration."""
- return db.Key.from_path('OAuthConfig', 'oauth_config')
-
-
-def GetOAuthConfig(throws=True):
- """Retrieves the OAuthConfig for this app.
-
- Returns:
- The OAuthConfig object for this app.
-
- Raises:
- OAuthInvalidSetup if no OAuthConfig exists.
- """
- config = db.get(OAuthConfigKey())
- if throws and not config:
- raise OAuthInvalidSetup()
- return config
-
-
-class ChromotingAuthHandler(webapp.RequestHandler):
- """Initiates getting the OAuth access token for the user.
-
- This webapp uses 3-legged OAuth. This handlers performs the first step
- of getting the OAuth request token, and then forwarding on to the
- Google Accounts authorization endpoint for the second step. The final
- step is completed by the ChromotingAuthReturnHandler below.
-
- FYI, all three steps are collectively known as the "OAuth dance."
- """
- @login_required
- def get(self):
- ClearChromotingToken()
- client = gdata.client.GDClient()
-
- oauth_callback_url = ('http://%s/auth/chromoting_auth_return' %
- self.request.host)
- request_token = client.GetOAuthToken(
- SCOPES, oauth_callback_url, GetOAuthConfig().consumer_key,
- consumer_secret=GetOAuthConfig().consumer_secret)
-
- SaveToken('request_token', request_token)
- domain = None # Not on an Google Apps domain.
- auth_uri = request_token.generate_authorization_url()
- self.redirect(str(auth_uri))
-
-
-class ChromotingAuthReturnHandler(webapp.RequestHandler):
- """Finishes the authorization started in ChromotingAuthHandler.i
-
- After the user authorizes the OAuth request token at the OAuth request
- URL they were redirected to in ChromotingAuthHandler, OAuth will send
- them back here with an auth token in the URL.
-
- This handler retrievies the access token, and stores it completing the
- OAuth dance.
- """
- @login_required
- def get(self):
- saved_request_token = LoadToken('request_token')
- DeleteToken('request_token')
- request_token = gdata.gauth.AuthorizeRequestToken(
- saved_request_token, self.request.uri)
-
- # Upgrade the token and save in the user's datastore
- client = gdata.client.GDClient()
- access_token = client.GetAccessToken(request_token)
- SaveToken('chromoting_token', access_token)
- self.redirect("/")
-
-
class XmppAuthHandler(webapp.RequestHandler):
"""Prompts Google Accounts credentials and retrieves a ClientLogin token.
@@ -244,87 +156,102 @@ class XmppAuthHandler(webapp.RequestHandler):
self.response.out.write(template.render(path, {}))
def post(self):
- client = gdata.client.GDClient()
email = self.request.get('username')
password = self.request.get('password')
- try:
- client.ClientLogin(
- email, password, 'chromoclient', 'chromiumsync')
- SaveToken('xmpp_token', client.auth_token)
- except gdata.client.CaptchaChallenge:
- self.response.out.write('You need to solve a Captcha. '
- 'Unforutnately, we still have to implement that.')
+ form_fields = {
+ 'accountType' : 'HOSTED_OR_GOOGLE',
+ 'Email' : self.request.get('username'),
+ 'Passwd' : self.request.get('password'),
+ 'service' : 'chromiumsync',
+ 'source' : 'chromoplex'
+ }
+ form_data = urllib.urlencode(form_fields)
+ result = urlfetch.fetch(
+ url = 'https://www.google.com/accounts/ClientLogin',
+ payload = form_data,
+ method = urlfetch.POST,
+ headers = {'Content-Type': 'application/x-www-form-urlencoded'})
+ if result.status_code != 200:
+ self.response.out.write(result.content)
+ for i in result.headers:
+ self.response.headers[i] = result.headers[i]
+ self.response.set_status(result.status_code)
+ return
+
+ xmpp_token = XmppToken(key_name = GetUserId())
+ xmpp_token.auth_token = re.search("Auth=(.*)", result.content).group(1)
+ xmpp_token.put()
self.redirect('/')
-class ClearChromotingTokenHandler(webapp.RequestHandler):
- """Endpoint for dropping the user's Chromoting token."""
+class ClearXmppTokenHandler(webapp.RequestHandler):
+ """Endpoint for dropping the user's Xmpp token."""
@login_required
def get(self):
- ClearChromotingToken()
+ ClearXmppToken()
self.redirect('/')
-class ClearXmppTokenHandler(webapp.RequestHandler):
- """Endpoint for dropping the user's Xmpp token."""
+class ClearOAuth2TokenHandler(webapp.RequestHandler):
+ """Endpoint for dropping the user's OAuth2 token."""
@login_required
def get(self):
- ClearXmppToken()
+ ClearOAuth2Token()
self.redirect('/')
-class SetupOAuthHandler(webapp.RequestHandler):
- """Administrative page for specifying the OAuth consumer key/secret."""
+class OAuth2ReturnHandler(webapp.RequestHandler):
+ """Handles the redirect in the OAuth dance."""
@login_required
def get(self):
- path = os.path.join(os.path.dirname(__file__),
- 'chromoting_oauth_setup.html')
- self.response.out.write(template.render(path, {}))
-
- def post(self):
- old_consumer_secret = self.request.get('old_consumer_secret')
-
- query = OAuthConfig.all()
-
- # If there is an existing key, only allow updating if you know the old
- # key. This is a simple safeguard against random users hitting this page.
- config = GetOAuthConfig(throws=False)
- if config:
- if config.consumer_secret != old_consumer_secret:
- self.response.set_status(400)
- self.response.out.write('Incorrect old consumer secret')
- return
+ code = self.request.get('code')
+ state = self.request.get('state')
+ parsed_url = urlparse(self.request.url)
+ server = parsed_url.scheme + '://' + parsed_url.netloc
+ form_fields = {
+ 'client_id' : CLIENT_ID,
+ 'client_secret' : CLIENT_SECRET,
+ 'redirect_uri' : server + '/auth/oauth2_return',
+ 'code' : code,
+ 'grant_type' : 'authorization_code'
+ }
+ form_data = urllib.urlencode(form_fields)
+ result = urlfetch.fetch(
+ url = 'https://accounts.google.com/o/oauth2/token',
+ payload = form_data,
+ method = urlfetch.POST,
+ headers = {'Content-Type': 'application/x-www-form-urlencoded'})
+
+ if result.status_code != 200:
+ self.response.out.write('something went wrong %d, %s <br />' %
+ (result.status_code, result.content))
+ self.response.out.write(
+ 'We tried posting %s code(%s) [%s]' % (form_data, code, form_fields))
+ self.response.set_status(400)
+ return
+
+ oauth_json = json.loads(result.content)
+ oauth2_tokens = OAuth2Tokens(key_name = GetUserId())
+ oauth2_tokens.refresh_token = oauth_json['refresh_token']
+ oauth2_tokens.access_token = oauth_json['access_token']
+ # Give us 30 second buffer to hackily account for RTT on network request.
+ oauth2_tokens.access_token_expiration = (
+ int(oauth_json['expires_in'] + time.time() - 30))
+ oauth2_tokens.put()
+
+ if state:
+ self.redirect(state)
else:
- config = OAuthConfig(key_name = OAuthConfigKey().id_or_name())
-
- # TODO(ajwong): THIS IS A TOTAL HACK! FIX WITH OWN PAGE.
- # Currently, this form has one submit button, and 3 pieces of input:
- # consumer_key, oauth_secret, and the httpxmppproxy address. The
- # HTTP/XMPP proxy should really have its own configuration page.
- httpxmppproxy = self.request.get('httpxmppproxy')
- if httpxmppproxy:
- config.httpxmppproxy = httpxmppproxy
-
- config.consumer_key = self.request.get('consumer_key')
- config.consumer_secret = self.request.get('new_consumer_secret')
- config.put()
- self.redirect('/')
+ self.redirect('/')
-def GetHttpXmppProxy():
- config = GetOAuthConfig(throws=True)
- if not config.httpxmppproxy:
- raise OAuthInvalidSetup()
- return config.httpxmppproxy
def main():
application = webapp.WSGIApplication(
[
- ('/auth/chromoting_auth', ChromotingAuthHandler),
('/auth/xmpp_auth', XmppAuthHandler),
- ('/auth/chromoting_auth_return', ChromotingAuthReturnHandler),
('/auth/clear_xmpp_token', ClearXmppTokenHandler),
- ('/auth/clear_chromoting_token', ClearChromotingTokenHandler),
- ('/auth/setup_oauth', SetupOAuthHandler)
+ ('/auth/clear_oauth2_token', ClearOAuth2TokenHandler),
+ ('/auth/oauth2_return', OAuth2ReturnHandler)
],
debug=True)
util.run_wsgi_app(application)
diff --git a/remoting/client/appengine/chromoting_oauth_setup.html b/remoting/client/appengine/chromoting_oauth_setup.html
deleted file mode 100644
index 1b1537c..0000000
--- a/remoting/client/appengine/chromoting_oauth_setup.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!doctype html>
-<!--
-Copyright (c) 2011 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<html>
- <head>
- <title>Chromoting OAuth setup page.</title>
- </head>
- <body>
- <p>This is an administration page to setup the consumer key and secret
- to be used with chromoting. Please don't play with this unless you are
- on the Chromoting dev team.
- <p>
- Move the HttpXmppProxy setup out of this page, and make the semantics less
- hacky!
- <form method="post" name="auth">
- Consumer Key: <input type="text" name="consumer_key" />
- New Consumer Secret: <input type="password" name="new_consumer_secret" />
- Old Consumer Secret: <input type="password" name="old_consumer_secret" />
- HttpXmppProxy Address: <input type="text" name="httpxmppproxy" />
- <input type="submit" value="Submit" />
- </form>
- </body>
-</html>
diff --git a/remoting/client/appengine/chromoting_session.html b/remoting/client/appengine/chromoting_session.html
index 8af2190..6197d6a 100644
--- a/remoting/client/appengine/chromoting_session.html
+++ b/remoting/client/appengine/chromoting_session.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
<!--
// TODO(ajwong): Total Hack. We should be able to read the URL parameters
// from JS, and also avoid passing in the connection tokens here.
- document.xmppAuthToken="{{xmpp_token.token_string}}";
+ document.xmppAuthToken="{{xmpp_token}}";
document.httpXmppProxy="{{http_xmpp_proxy}}";
document.username="{{username}}";
document.hostname="{{hostname}}";
diff --git a/remoting/client/appengine/hostlist.html b/remoting/client/appengine/hostlist.html
index 7848db0..10138fe 100644
--- a/remoting/client/appengine/hostlist.html
+++ b/remoting/client/appengine/hostlist.html
@@ -24,6 +24,12 @@ found in the LICENSE file.
<div id="mainview-content">
<div class="page">
<section>
+ <h3>Http Xmpp Proxy</h3>
+ <input type="text" id="http_xmpp_proxy"
+ value="https://chromoting-httpxmpp-dev.corp.google.com"
+ size="50" />
+ </section>
+ <section>
<h3>Host List</h3>
<div class="hostlist">
<list id="hostlist-div">
@@ -42,21 +48,21 @@ found in the LICENSE file.
</div>
</section>
<section>
- <h3>Chromoting Token</h3>
+ <h3>OAuth2 Token</h3>
<div>
-{% ifnotequal chromoting_token None %}
+{% if has_oauth2_tokens %}
<div>Token Authenticated</div>
<button id="subitem"
- onclick="window.location='/auth/clear_chromoting_token'">
- Clear Token
+ onclick="window.location='/auth/clear_oauth2_token'">
+ Clear Token
</button>
{% else %}
<div class="error-msg">Token Not Authenticated</div>
<button id="subitem"
- onclick="window.location='/auth/chromoting_auth'">
+ onclick="authorizeOAuth2();">
Authenticate Token
</button>
-{% endifnotequal %}
+{% endif %}
</div>
</section>
<section>
diff --git a/remoting/client/appengine/main.py b/remoting/client/appengine/main.py
index 36f81d7..878e71e 100644
--- a/remoting/client/appengine/main.py
+++ b/remoting/client/appengine/main.py
@@ -9,9 +9,6 @@ import os
from django.utils import simplejson as json
-import gdata.gauth
-import gdata.client
-
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
@@ -25,7 +22,7 @@ class HostListHandler(webapp.RequestHandler):
@login_required
def get(self):
template_params = {
- 'chromoting_token': auth.GetChromotingToken(throws=False),
+ 'has_oauth2_tokens': auth.HasOAuth2Tokens(),
'xmpp_token': auth.GetXmppToken(throws=False)
}
path = os.path.join(os.path.dirname(__file__), 'hostlist.html')
@@ -43,7 +40,7 @@ class ChromotingSessionHandler(webapp.RequestHandler):
'connect_method': self.request.get('connect_method'),
'insecure': self.request.get('insecure'),
'xmpp_token': auth.GetXmppToken(),
- 'http_xmpp_proxy': auth.GetHttpXmppProxy(),
+ 'http_xmpp_proxy': self.request.get('http_xmpp_proxy')
}
path = os.path.join(os.path.dirname(__file__), 'chromoting_session.html')
self.response.out.write(template.render(path, template_params))
diff --git a/remoting/client/appengine/static_files/client.js b/remoting/client/appengine/static_files/client.js
index b485467..e2ed6f8 100644
--- a/remoting/client/appengine/static_files/client.js
+++ b/remoting/client/appengine/static_files/client.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -190,8 +190,9 @@ function addHostInfo(host) {
connect.setAttribute('type', 'button');
connect.setAttribute('value', 'Connect');
connect.setAttribute('onclick', "window.open('session?hostname=" +
- encodeURIComponent(host.hostName) + "&hostjid=" +
- encodeURIComponent(host.jabberId) + "');");
+ encodeURIComponent(host.hostName) +
+ "&hostjid=" + encodeURIComponent(host.jabberId) +
+ "');");
span.appendChild(connect);
var connectSandboxed = document.createElement('input');
@@ -200,6 +201,8 @@ function addHostInfo(host) {
connectSandboxed.setAttribute('onclick',
"window.open('session?hostname=" + encodeURIComponent(host.hostName) +
"&hostjid=" + encodeURIComponent(host.jabberId) +
+ "&http_xmpp_proxy=" + encodeURIComponent(
+ document.getElementById('http_xmpp_proxy').value) +
"&connect_method=sandboxed');");
span.appendChild(connectSandboxed);
@@ -227,3 +230,39 @@ function addHostInfo(host) {
return hostEntry;
}
+
+function updateAuthStatus_() {
+ var oauth2_status = document.getElementById('oauth2_status');
+ if (chromoting.oauth2.isAuthenticated()) {
+ oauth2_status.innerText = 'Tokens Good';
+ oauth2_status.style.color = 'green';
+ document.getElementById('oauth2_authorize_button').style.display = 'none';
+ document.getElementById('oauth2_clear_button').style.display = 'inline';
+ populateHostList();
+ } else {
+ oauth2_status.innerText = 'No Tokens';
+ oauth2_status.style.color = 'red';
+ document.getElementById('oauth2_authorize_button').style.display = 'inline';
+ document.getElementById('oauth2_clear_button').style.display = 'none';
+ }
+}
+
+function clearOAuth2() {
+ chromoting.oauth2.clear();
+ updateAuthStatus_();
+}
+
+function authorizeOAuth2() {
+ var oauth_code_url = 'https://accounts.google.com/o/oauth2/auth?'
+ + 'client_id=' + encodeURIComponent(
+ '440925447803-d9u05st5jjm3gbe865l0jeaujqfrufrn.' +
+ 'apps.googleusercontent.com')
+ + '&redirect_uri=' + window.location.origin + '/auth/oauth2_return'
+ + '&scope=' + encodeURIComponent(
+ 'https://www.googleapis.com/auth/chromoting ' +
+ 'https://www.googleapis.com/auth/googletalk')
+ + '&state=' + encodeURIComponent(window.location.href)
+ + '&response_type=code';
+ window.location.replace(oauth_code_url);
+}
+
diff --git a/remoting/client/extension/manifest.json b/remoting/client/extension/manifest.json
deleted file mode 100644
index 05d3da2..0000000
--- a/remoting/client/extension/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "Chromoting Client",
- "version": "1.1",
- "description": "Lists the Chromoting hosts that the current user can access.",
- "browser_action": {
- "default_icon": "chromoticon.png",
- "default_title": "Chromoting"
- },
- "background_page": "background.html",
- "permissions": [
- "tabs",
- "https://www.googleapis.com/chromoting/",
- "https://www.google.com/accounts/"
- ]
-}