summaryrefslogtreecommitdiffstats
path: root/remoting/client
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-24 23:13:21 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-24 23:13:21 +0000
commit999d862cc8675b78fdeab5b0a4b1689b0505f276 (patch)
tree316c8f12dc260addddf029fb249a286d3b68cc82 /remoting/client
parent6ee62b63cec739d231bf451168219576df623e20 (diff)
downloadchromium_src-999d862cc8675b78fdeab5b0a4b1689b0505f276.zip
chromium_src-999d862cc8675b78fdeab5b0a4b1689b0505f276.tar.gz
chromium_src-999d862cc8675b78fdeab5b0a4b1689b0505f276.tar.bz2
Redo the Chromoting extension as an app-engine app.
This will allow for an easier develop/deploy cycle in the short term, which will facilitate development. BUG=none TEST=none Review URL: http://codereview.chromium.org/6580022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75987 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/client')
-rw-r--r--remoting/client/appengine/api.py67
-rw-r--r--remoting/client/appengine/app.yaml22
-rw-r--r--remoting/client/appengine/auth.py320
-rw-r--r--remoting/client/appengine/chromoting_oauth_setup.html23
-rw-r--r--remoting/client/appengine/chromoting_session.html (renamed from remoting/client/extension/chromoting_tab.html)21
-rw-r--r--remoting/client/appengine/client_login.html40
-rw-r--r--remoting/client/appengine/hostlist.html51
-rw-r--r--remoting/client/appengine/main.py56
-rw-r--r--remoting/client/appengine/static_files/base.js (renamed from remoting/client/extension/base.js)0
-rw-r--r--remoting/client/appengine/static_files/chromoticon.png (renamed from remoting/client/extension/chromoticon.png)bin332 -> 332 bytes
-rw-r--r--remoting/client/appengine/static_files/chromoting_session.js (renamed from remoting/client/extension/chromoting_tab.js)51
-rw-r--r--remoting/client/appengine/static_files/client.js (renamed from remoting/client/extension/client.js)33
-rw-r--r--remoting/client/appengine/static_files/machine.png (renamed from remoting/client/extension/machine.png)bin4992 -> 4992 bytes
-rw-r--r--remoting/client/appengine/static_files/main.css (renamed from remoting/client/extension/main.css)0
-rw-r--r--remoting/client/extension/background.html13
-rw-r--r--remoting/client/extension/background.js91
-rw-r--r--remoting/client/extension/hostlist.html74
17 files changed, 620 insertions, 242 deletions
diff --git a/remoting/client/appengine/api.py b/remoting/client/appengine/api.py
new file mode 100644
index 0000000..1b48da0
--- /dev/null
+++ b/remoting/client/appengine/api.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+
+# 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.
+
+"""API endpoints to get around javascript's single-origin restriction."""
+
+import logging
+
+from django.utils import simplejson as json
+
+import gdata.client
+
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import util
+from google.appengine.ext.webapp.util import login_required
+import auth
+
+
+class GetXmppTokenHandler(webapp.RequestHandler):
+ """Retrieves the user's XMPP token."""
+ @login_required
+ def get(self):
+ try:
+ self.response.headers['Content-Type'] = 'application/json'
+ self.response.out.write(
+ json.dumps({'xmpp_token': auth.GetXmppToken().token}))
+ except auth.NotAuthenticated:
+ self.response.out.write('User has not authenticated')
+ self.set_status(400)
+ return
+ pass
+
+
+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())
+ 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)
+ return
+
+
+def main():
+ application = webapp.WSGIApplication(
+ [
+ ('/api/get_xmpp_token', GetXmppTokenHandler),
+ ('/api/get_host_list', GetHostListHandler)
+ ],
+ debug=True)
+ util.run_wsgi_app(application)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/remoting/client/appengine/app.yaml b/remoting/client/appengine/app.yaml
new file mode 100644
index 0000000..ff9db53
--- /dev/null
+++ b/remoting/client/appengine/app.yaml
@@ -0,0 +1,22 @@
+application: google.com:chromoting
+version: 1
+runtime: python
+api_version: 1
+
+handlers:
+- url: /static_files
+ static_dir: static_files
+ secure: always
+
+- url: /api/.*
+ script: api.py
+ secure: always
+
+- url: /auth/.*
+ script: auth.py
+ secure: always
+
+- url: .*
+ script: main.py
+ secure: always
+
diff --git a/remoting/client/appengine/auth.py b/remoting/client/appengine/auth.py
new file mode 100644
index 0000000..f40cbdd
--- /dev/null
+++ b/remoting/client/appengine/auth.py
@@ -0,0 +1,320 @@
+#!/usr/bin/env python
+
+# 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.
+
+"""Provides authentcation related utilities and endpoint handlers.
+
+All authentication code for the webapp should go through this module. In
+general, credentials should be used server-side. The URL endpoints are for
+initiating authentication flows, and for managing credential storage per user.
+"""
+
+import os
+
+import gdata.gauth
+import gdata.client
+
+from google.appengine.ext import db
+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
+
+
+SCOPES = ['https://www.googleapis.com/auth/chromoting',
+ 'https://www.googleapis.com/auth/googletalk' ]
+
+
+class NotAuthenticated(Exception):
+ """API requiring authentication is called with credentials."""
+ pass
+
+
+class OAuthInvalidSetup(Exception):
+ """OAuth configuration on app is not complete."""
+ pass
+
+
+class OAuthConfig(db.Model):
+ """Stores the configuration data for OAuth.
+
+ 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()
+
+
+def GetChromotingToken(throws=True):
+ """Retrieves the Chromoting OAuth token for the user.
+
+ Args:
+ throws: bool (optional) Default is True. Throws if no token.
+
+ 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:
+ raise NotAuthenticated()
+ return access_token
+
+
+def GetXmppToken(throws=True):
+ """Retrieves the XMPP for Chromoting.
+
+ Args:
+ throws: bool (optional) Default is True. Throws if no token.
+
+ Returns:
+ An gdata.gauth.ClientLoginToken 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:
+ raise NotAuthenticated()
+ return access_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."""
+ DeleteToken('xmpp_token')
+
+
+def GetUserId():
+ """Retrieves the user id for the current user.
+
+ Returns:
+ A string with the user id of the logged in user.
+
+ Raises:
+ NotAuthenticated if the user is not logged in, or missing an id.
+ """
+ user = users.get_current_user()
+ if not user:
+ raise NotAuthenticated()
+
+ if not user.user_id():
+ raise NotAuthenticated('no e-mail with google account!')
+
+ 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.
+
+ This class takes the user's plaintext username and password, and then
+ posts a request to ClientLogin to get the access token.
+
+ THIS CLASS SHOULD NOT EXIST.
+
+ We should NOT be taking a user's Google Accounts credentials in our webapp.
+ However, we need a ClientLogin token for jingle, and this is currently the
+ only known workaround.
+ """
+ @login_required
+ def get(self):
+ ClearXmppToken()
+ path = os.path.join(os.path.dirname(__file__), 'client_login.html')
+ 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.')
+ self.redirect('/')
+
+
+class ClearChromotingTokenHandler(webapp.RequestHandler):
+ """Endpoint for dropping the user's Chromoting token."""
+ @login_required
+ def get(self):
+ ClearChromotingToken()
+ self.redirect('/')
+
+
+class ClearXmppTokenHandler(webapp.RequestHandler):
+ """Endpoint for dropping the user's Xmpp token."""
+ @login_required
+ def get(self):
+ ClearXmppToken()
+ self.redirect('/')
+
+
+class SetupOAuthHandler(webapp.RequestHandler):
+ """Administrative page for specifying the OAuth consumer key/secret."""
+ @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.out.set_status(400)
+ self.response.out.write('Incorrect old consumer secret')
+ return
+ else:
+ config = OAuthConfig(key_name = OAuthConfigKey().id_or_name())
+
+ config.consumer_key = self.request.get('consumer_key')
+ config.consumer_secret = self.request.get('new_consumer_secret')
+ config.put()
+ self.redirect('/')
+
+
+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)
+ ],
+ debug=True)
+ util.run_wsgi_app(application)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/remoting/client/appengine/chromoting_oauth_setup.html b/remoting/client/appengine/chromoting_oauth_setup.html
new file mode 100644
index 0000000..3fc4664
--- /dev/null
+++ b/remoting/client/appengine/chromoting_oauth_setup.html
@@ -0,0 +1,23 @@
+<!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.
+ <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" />
+ <input type="submit" value="Submit" />
+ </form>
+ </body>
+</html>
diff --git a/remoting/client/extension/chromoting_tab.html b/remoting/client/appengine/chromoting_session.html
index c3c7454..2d26b45 100644
--- a/remoting/client/extension/chromoting_tab.html
+++ b/remoting/client/appengine/chromoting_session.html
@@ -1,5 +1,6 @@
+<!doctype html>
<!--
-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.
-->
@@ -7,9 +8,19 @@ found in the LICENSE file.
<html>
<head>
<title id="title">Chromoting Session</title>
- <link rel="stylesheet" type="text/css" href="main.css" />
- <script type="text/javascript" src="base.js"></script>
- <script type="text/javascript" src="chromoting_tab.js"></script>
+ <link rel="stylesheet" type="text/css" href="static_files/main.css" />
+ <script type="text/javascript">
+ <!--
+ // TODO(ajwong): Total Hack. Do this nicer.
+ document.xmpp_auth_token="{{xmpp_token.token_string}}";
+ document.username="{{username}}";
+ document.hostname="{{hostname}}";
+ document.hostjid="{{hostjid}}";
+ -->
+ </script>
+ <script type="text/javascript" src="static_files/base.js"></script>
+ <script type="text/javascript" src="static_files/chromoting_session.js">
+ </script>
</head>
<body class="chromoting_body" onload="init();">
<div id="status_msg" class="status_msg"></div>
@@ -40,7 +51,7 @@ found in the LICENSE file.
onclick="submitLogin();"/></td>
</tr>
</table>
- </tr></td></table>
+ </td></tr></table>
</div>
<div id="plugin_scroll_panel" class="plugin-scroll-panel">
<embed name="chromoting" id="chromoting"
diff --git a/remoting/client/appengine/client_login.html b/remoting/client/appengine/client_login.html
new file mode 100644
index 0000000..9284109
--- /dev/null
+++ b/remoting/client/appengine/client_login.html
@@ -0,0 +1,40 @@
+<!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 Google Accounts Login (needed for XMPP)</title>
+ </head>
+
+ <body>
+ <p>Please provide your Google Accounts username/password to get a
+ ClientLogin token for Google Talk.
+
+ <p>
+ <form method="post" name="auth">
+ Username: <input type="text" name="username" /><br />
+ Password: <input type="password" name="password" /><br />
+ <input type="submit" value="Submit" />
+ </form>
+
+ <hr />
+ <p>
+ Yes, we know we're asking for your Google Accounts credentials in a webapp.
+
+ <p>
+ No we're not happy with this.
+
+ <p>
+ Yes, we (think we) need to do it this way.
+
+ <p>
+ libjingle needs a ClientLogin token and due to single-origin issues, we
+ have to proxy the request through the webapp. If anyone has a better idea,
+ please <b>please</b> <b><i>please</i></b> let us know.
+
+ </body>
+</html>
diff --git a/remoting/client/appengine/hostlist.html b/remoting/client/appengine/hostlist.html
new file mode 100644
index 0000000..2f5eb95
--- /dev/null
+++ b/remoting/client/appengine/hostlist.html
@@ -0,0 +1,51 @@
+<!--
+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>
+ <script type="text/javascript" src="static_files/base.js"></script>
+ <script type="text/javascript" src="static_files/client.js"></script>
+ <link rel="stylesheet" type="text/css" href="static_files/main.css" />
+ <title>Remote Access Host List</title>
+ </head>
+ <body class="hostlist_body"
+{% ifnotequal chromoting_token None %}
+ onload="populateHostList();"
+{% endifnotequal %}
+>
+
+ <h1>Remote Access</h1>
+
+ <div id="auth_status" class="authstatus">
+ <p>Chromoting Token:
+{% ifnotequal chromoting_token None %}
+ OK (<a href="/auth/clear_chromoting_token">clear token</a>)
+{% else %}
+ <a href="/auth/chromoting_auth">Not Authenticated</a>
+{% endifnotequal %}
+ <p>Xmpp Token:
+{% ifnotequal xmpp_token None %}
+ OK (<a href="/auth/clear_xmpp_token">clear token</a>)
+{% else %}
+ <a href="/auth/xmpp_auth">Not Authenticated</a>
+{% endifnotequal %}
+ </div>
+ <hr />
+
+ <p class="reload">
+ <a href="javascript:populateHostList()">Reload host list</a>
+ </p>
+
+ <input type=checkbox name="show_offline" id="show_offline"
+ onClick="updateShowOfflineHosts(this)"/>Show offline hosts
+
+ <div id="hostlist_div" class="hostlist">
+ <p class='message'>Initializing...</p>
+ </div>
+
+ <br />
+ </body>
+</html>
diff --git a/remoting/client/appengine/main.py b/remoting/client/appengine/main.py
new file mode 100644
index 0000000..78900c2
--- /dev/null
+++ b/remoting/client/appengine/main.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+
+import logging
+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
+from google.appengine.ext.webapp import util
+from google.appengine.ext.webapp.util import login_required
+
+import auth
+
+class HostListHandler(webapp.RequestHandler):
+ """Renders the main hostlist page."""
+ @login_required
+ def get(self):
+ template_params = {
+ 'chromoting_token': auth.GetChromotingToken(throws=False),
+ 'xmpp_token': auth.GetXmppToken(throws=False)
+ }
+ path = os.path.join(os.path.dirname(__file__), 'hostlist.html')
+ self.response.out.write(template.render(path, template_params))
+
+
+class ChromotingSessionHandler(webapp.RequestHandler):
+ """Renders one Chromoting session."""
+ @login_required
+ def get(self):
+ template_params = {
+ 'hostname': self.request.get('hostname'),
+ 'username': users.get_current_user().email(),
+ 'hostjid': self.request.get('hostjid'),
+ 'xmpp_token': auth.GetXmppToken(),
+ }
+ path = os.path.join(os.path.dirname(__file__), 'chromoting_session.html')
+ self.response.out.write(template.render(path, template_params))
+
+
+def main():
+ application = webapp.WSGIApplication(
+ [
+ ('/', HostListHandler),
+ ('/session', ChromotingSessionHandler),
+ ],
+ debug=True)
+ util.run_wsgi_app(application)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/remoting/client/extension/base.js b/remoting/client/appengine/static_files/base.js
index 2c3188d..2c3188d 100644
--- a/remoting/client/extension/base.js
+++ b/remoting/client/appengine/static_files/base.js
diff --git a/remoting/client/extension/chromoticon.png b/remoting/client/appengine/static_files/chromoticon.png
index a5cb2b2..a5cb2b2 100644
--- a/remoting/client/extension/chromoticon.png
+++ b/remoting/client/appengine/static_files/chromoticon.png
Binary files differ
diff --git a/remoting/client/extension/chromoting_tab.js b/remoting/client/appengine/static_files/chromoting_session.js
index ce13c0f4..18ee990 100644
--- a/remoting/client/extension/chromoting_tab.js
+++ b/remoting/client/appengine/static_files/chromoting_session.js
@@ -7,42 +7,13 @@
chromoting.messageId = 1;
function init() {
- // This page should only get one request, and it should be
- // from the chromoting extension asking for initial connection.
- // Later we may need to create a more persistent channel for
- // better UI communication. Then, we should probably switch
- // to chrome.extension.connect().
- chrome.extension.onRequest.addListener(requestListener);
-}
-
-function submitLogin() {
- var username = document.getElementById("username").value;
- var password = document.getElementById("password").value;
-
- // Make the login panel invisible and submit login info.
- document.getElementById("login_panel").style.display = "none";
- chromoting.plugin.submitLoginInfo(username, password);
-}
-
-/**
- * A listener function to be called when the extension fires a request.
- *
- * @param request The request sent by the calling script.
- * @param sender The MessageSender object with info about the calling script's
- * context.
- * @param sendResponse Function to call with response.
- */
-function requestListener(request, sender, sendResponse) {
- console.log(sender.tab ?
- 'from a content script: ' + sender.tab.url :
- 'from the extension');
-
// Kick off the connection.
var plugin = document.getElementById('chromoting');
chromoting.plugin = plugin;
- chromoting.username = request.username;
- chromoting.hostname = request.hostName;
+ chromoting.username = document.username;
+ chromoting.hostname = document.hostname;
+ chromoting.hostjid = document.hostjid;
// Setup the callback that the plugin will call when the connection status
// has changes and the UI needs to be updated. It needs to be an object with
@@ -55,16 +26,22 @@ function requestListener(request, sender, sendResponse) {
// TODO(garykac): Clean exit if |connect| isn't a funtion.
if (typeof plugin.connect === 'function') {
- plugin.connect(request.username, request.hostJid,
- request.xmppAuth);
+ plugin.connect(chromoting.username, chromoting.hostjid,
+ document.xmpp_auth_token);
} else {
console.log('ERROR: chromoting plugin not loaded');
}
- document.getElementById('title').innerText = request.hostName;
+ document.getElementById('title').innerText = chromoting.hostname;
+}
- // Send an empty response since we have nothing to say.
- sendResponse({});
+function submitLogin() {
+ var username = document.getElementById("username").value;
+ var password = document.getElementById("password").value;
+
+ // Make the login panel invisible and submit login info.
+ document.getElementById("login_panel").style.display = "none";
+ chromoting.plugin.submitLoginInfo(username, password);
}
/**
diff --git a/remoting/client/extension/client.js b/remoting/client/appengine/static_files/client.js
index 3ff12ac..067cedf 100644
--- a/remoting/client/extension/client.js
+++ b/remoting/client/appengine/static_files/client.js
@@ -219,25 +219,17 @@ function appendMessage(e, classname, message) {
}
function populateHostList() {
- var username = getCookie('username');
-
var hostlistDiv = document.getElementById('hostlist_div');
- if (!username) {
- displayMessage(hostlistDiv, 'message',
- 'Please sign in to see a list of available hosts.');
- return;
- }
+ displayMessage(hostlistDiv, 'message',
+ 'Hosts will appaer if Chromoting Token is "OK".');
var xhr = new XMLHttpRequest();
- var token = getCookie('chromoting_auth');
-
// Unhide host list.
hostlistDiv.style.display = "block";
xhr.onreadystatechange = function() {
if (xhr.readyState == 1) {
- displayMessage(hostlistDiv, 'message', 'Loading host list for ' +
- username);
+ displayMessage(hostlistDiv, 'message', 'Loading host list');
}
if (xhr.readyState != 4) {
return;
@@ -256,18 +248,15 @@ function populateHostList() {
clear(hostlistDiv);
if (errorResponse.error.message == "Token expired") {
appendMessage(hostlistDiv, 'message',
- 'The authentication token for ' + username +
- ' has expired. Please sign in again.');
+ 'Authentication token expired. Please sign in again.');
logout();
} else if (errorResponse.error.message == "Token invalid") {
appendMessage(hostlistDiv, 'message',
- 'Invalid authentication token for ' + username + '. ' +
- 'Please sign in again.');
+ 'Invalid authentication token. Please sign in again.');
logout();
} else {
appendMessage(hostlistDiv, 'message',
- 'Unable to load host list for ' + username + '. ' +
- 'Please try again later.');
+ 'Unable to load host list. Please try again later.');
appendMessage(hostlistDiv, 'message',
'Error code: ' + errorResponse.error.code);
appendMessage(hostlistDiv, 'message',
@@ -276,9 +265,8 @@ function populateHostList() {
}
};
- xhr.open('GET', 'https://www.googleapis.com/chromoting/v1/@me/hosts');
+ xhr.open('GET', 'api/get_host_list', true);
xhr.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8');
- xhr.setRequestHeader('Authorization', 'GoogleLogin auth=' + token);
xhr.send(null);
}
@@ -332,7 +320,7 @@ function addHostInfo(host) {
hostEntry.setAttribute('class', 'hostentry');
var hostIcon = document.createElement('img');
- hostIcon.setAttribute('src', 'machine.png');
+ hostIcon.setAttribute('src', 'static_files/machine.png');
hostIcon.setAttribute('class', 'hosticon');
hostEntry.appendChild(hostIcon);
@@ -342,8 +330,9 @@ function addHostInfo(host) {
var connect = document.createElement('input');
connect.setAttribute('type', 'button');
connect.setAttribute('value', 'Connect');
- connect.setAttribute('onclick', "openChromotingTab('" + host.hostName +
- "', '" + host.jabberId + "'); return false;");
+ connect.setAttribute('onclick', "window.open('session?hostname=" +
+ encodeURIComponent(host.hostName) + "&hostjid=" +
+ encodeURIComponent(host.jabberId) + "');");
span.appendChild(connect);
hostEntry.appendChild(span);
}
diff --git a/remoting/client/extension/machine.png b/remoting/client/appengine/static_files/machine.png
index 635a9bb..635a9bb 100644
--- a/remoting/client/extension/machine.png
+++ b/remoting/client/appengine/static_files/machine.png
Binary files differ
diff --git a/remoting/client/extension/main.css b/remoting/client/appengine/static_files/main.css
index 5e5cf29..5e5cf29 100644
--- a/remoting/client/extension/main.css
+++ b/remoting/client/appengine/static_files/main.css
diff --git a/remoting/client/extension/background.html b/remoting/client/extension/background.html
deleted file mode 100644
index 3e17fad..0000000
--- a/remoting/client/extension/background.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!--
-Copyright (c) 2010 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>
- <script type="text/javascript" src="base.js"></script>
- <script type="text/javascript" src="background.js"></script>
- </head>
- <body/>
-</html>
diff --git a/remoting/client/extension/background.js b/remoting/client/extension/background.js
deleted file mode 100644
index f417407..0000000
--- a/remoting/client/extension/background.js
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2010 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.
-
-/**
- * If there is already a tab with the given URL, switch focus to it. Otherwise,
- * create a new tab and open the URL.
- *
- * @param url The URL to open.
- */
-function focusOrCreateTab(url) {
- chrome.windows.getAll({"populate":true}, function(windows) {
- var existing_tab = null;
- for (var i in windows) {
- var tabs = windows[i].tabs;
- for (var j in tabs) {
- var tab = tabs[j];
- if (tab.url == url) {
- existing_tab = tab;
- break;
- }
- }
- }
- if (existing_tab) {
- chrome.tabs.update(existing_tab.id, {"selected": true});
- } else {
- chrome.tabs.create({"url": url, "selected": true});
- }
- });
-}
-
-/**
- * In the current tab, navigate to the specified URL.
- *
- * @param url The URL to navigate to.
- */
-function navigate(url, callback) {
- chrome.tabs.getSelected(null, function(tab) {
- chrome.tabs.update(tab.id, {url: url}, callback);
- });
-}
-
-// Open the Chromoting HostList tab when
-chrome.browserAction.onClicked.addListener(function(tab) {
- var hostlist_url = chrome.extension.getURL("hostlist.html");
- focusOrCreateTab(hostlist_url);
- });
-
-
-function openChromotingTab(hostName, hostJid) {
- var username = getCookie('username');
- var xmppAuth = getCookie('xmpp_auth');
- var newTabUrl = chrome.extension.getURL("chromoting_tab.html");
- var request = {
- username: getCookie('username'),
- xmppAuth: getCookie('xmpp_auth'),
- hostName: hostName,
- hostJid: hostJid,
- };
-
- console.log("Attempt to connect with" +
- " username='" + request.username + "'" +
- " hostName='" + request.hostName + "'" +
- " hostJid='" + request.hostJid + "'" +
- " auth_token='" + request.xmppAuth + "'");
-
- var sendRequestFunc = function (tab) {
- console.log("We're trying now to send to " + tab.id);
- chrome.tabs.sendRequest(
- tab.id, request, function() {
- console.log('Tab finished connect.');
- });
- };
-
- // This function will run when after the url for the tab is updated. If
- // the tab is not yet loaded it will wait for another 500ms to inspect
- // again.
- var checkStatusFunc = function (tab) {
- if (tab.status == "complete") {
- sendRequestFunc(tab);
- return;
- }
-
- // Wait for 500ms and then get the tab and check its status.
- setTimeout(function() {
- chrome.tabs.get(tab.id, checkStatusFunc);
- }, 500);
- }
-
- navigate(newTabUrl, checkStatusFunc);
-}
diff --git a/remoting/client/extension/hostlist.html b/remoting/client/extension/hostlist.html
deleted file mode 100644
index 2e55a36..0000000
--- a/remoting/client/extension/hostlist.html
+++ /dev/null
@@ -1,74 +0,0 @@
-<!--
-Copyright (c) 2010 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>
- <script type="text/javascript" src="base.js"></script>
- <script type="text/javascript" src="client.js"></script>
- <link rel="stylesheet" type="text/css" href="main.css" />
- <title>Remote Access</title>
- </head>
- <body class="hostlist_body" onload="init();">
-
- <h1>Remote Access</h1>
-
- <div id="login_panel" class="gaia_login_panel">
- <table cellspacing="3" cellpadding="5" border="0"><tr><td valign="top"
- style="text-align:center" nowrap="nowrap" bgcolor="#e8eefa">
- <table align="center" border="0" cellpadding="1" cellspacing="0">
- <tr>
- <td align="center" colspan="2">
- <font size="-1">Sign in with your</font>
- <table><tr>
- <td valign="top"><img src="https://www.google.com/accounts/google_transparent.gif"
- alt="Google"></img></td>
- <td valign="middle"><font size="+0"><b>Account</b></font></td>
- </tr></table>
- </td>
- </tr><tr>
- <td align="right" nowrap="nowrap">
- <span class="gaia_font">Username:</span>
- </td><td>
- <input type="text" id="username" value="" class="gaia_font"/>
- </td>
- </tr><tr>
- <td align="right" nowrap="nowrap">
- <span class="gaia_font">Password:</span>
- </td><td>
- <input type="password" id="password" value=""
- class="gaia_font"/>
- </td>
- </tr><tr>
- <td></td>
- <td align="left">
- <div class="error_msg" id="errormsg_div"></div>
- </td>
- </tr><tr>
- <td></td>
- <td><input type="button" value="Sign in" class="gaia_font"
- onclick="login();"/></td>
- </tr>
- </table>
- </tr></td></table>
- </div>
-
- <div id="login_div" class="login">
- </div>
-
- <p class="reload">
- <a href="javascript:populateHostList()">Reload host list</a>
- </p>
-
- <input type=checkbox name="show_offline" id="show_offline"
- onClick="updateShowOfflineHosts(this)"/>Show offline hosts
-
- <div id="hostlist_div" class="hostlist">
- <p class='message'>Initializing...</p>
- </div>
-
- <br />
- </body>
-</html>