Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env python
      2 #
      3 # Copyright (c) 2010 The Chromium Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 # Chromoting Directory API client implementation. Used for testing/debugging
      8 # purposes. Requires Python 2.6: json module is not available in earlier
      9 # versions.
     10 
     11 import os
     12 import httplib
     13 import json
     14 import urllib
     15 import urllib2
     16 import random
     17 import sys
     18 
     19 DEFAULT_DIRECTORY_SERVER = 'www.googleapis.com'
     20 
     21 auth_filepath = os.path.join(os.path.expanduser('~'),
     22                              '.chromotingDirectoryAuthToken')
     23 
     24 def random_uuid():
     25   return ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x" %
     26     tuple(map(lambda x: random.randrange(0,65536), range(8))))
     27 
     28 class Host:
     29   def __init__(self, parameters=None):
     30     if parameters != None:
     31       self.host_id = parameters[u"hostId"]
     32       self.host_name = parameters[u"hostName"]
     33       self.public_key = parameters[u"publicKey"]
     34       # Following fields may be missing, use get() for them.
     35       self.jabber_id = parameters.get(u"jabberId")
     36       self.created_time = parameters.get(u"createdTime")
     37       self.updated_time = parameters.get(u"updatedTime")
     38       self.status = parameters.get(u"status")
     39     else:
     40       self.host_id = random_uuid()
     41       import socket
     42       self.host_name = socket.gethostname()
     43       self.public_key = None
     44       self.jabber_id = None
     45       self.created_time = None
     46       self.updated_time = None
     47       self.status = None
     48 
     49 class HostDirectoryError(Exception):
     50   def __init__(self, message, response):
     51     Exception.__init__(self, message)
     52     print response
     53     self._response = response
     54 
     55 class HostDirectory:
     56   def __init__(self, username, auth_token, server=DEFAULT_DIRECTORY_SERVER):
     57     self._username = username
     58     self._auth_token = auth_token
     59     self._base_url = '/chromoting/v1/@me/hosts'
     60 
     61     self._http = httplib.HTTPSConnection(server)
     62     self._headers = {"Authorization": "GoogleLogin auth=" + self._auth_token,
     63                      "Content-Type": "application/json" }
     64 
     65   def add_host(self, host):
     66     host_json = { 'data':
     67                     { 'hostId': host.host_id,
     68                       'hostName': host.host_name,
     69                       'publicKey': host.public_key,
     70                       }
     71                   }
     72     if host.jabber_id:
     73       host_json['data']['jabberId'] = host.jabber_id
     74     post_data = json.dumps(host_json)
     75     self._http.request("POST", self._base_url, post_data, self._headers)
     76     response = self._http.getresponse()
     77     if response.status != 200:
     78       raise HostDirectoryError(response.reason, response.read())
     79     data = response.read()
     80 
     81   def get_hosts(self):
     82     self._http.request("GET", self._base_url, headers=self._headers)
     83     response = self._http.getresponse()
     84     if response.status != 200:
     85       raise HostDirectoryError(response.reason, response.read())
     86     data = response.read()
     87     data = json.loads(data)[u'data']
     88     results = []
     89     if data.has_key(u'items'):
     90       for item in data[u'items']:
     91         results.append(Host(item))
     92     return results
     93 
     94   def delete_host(self, host_id):
     95     url = self._base_url + '/' + host_id
     96     self._http.request("DELETE", url, headers=self._headers)
     97     response = self._http.getresponse()
     98     if response.status / 100 != 2: # Normally 204 is returned
     99       raise HostDirectoryError(response.reason, response.read())
    100     data = response.read()
    101 
    102 def usage():
    103   sys.stderr.write(
    104       ("Usage:\n" +
    105        " Login: \t\t%(cmd)s login\n" +
    106        " Register host: \t%(cmd)s insert --hostId=<hostId>" +
    107        " --hostName=<hostName> \\\n" +
    108        "\t\t\t    --publicKey=<publicKey>  --jabberId=<jabberId>\n" +
    109        " List hosts: \t\t%(cmd)s list\n" +
    110        " Delete a host: \t%(cmd)s delete <host_id>\n")
    111                    % {"cmd" : sys.argv[0]})
    112   return 1
    113 
    114 class CommandError(Exception):
    115   def __init__(self, message):
    116     Exception.__init__(self, message)
    117 
    118 def load_auth_token():
    119   try:
    120     lines = open(auth_filepath).readlines()
    121   except IOError:
    122     raise CommandError(("Can't open file (%s). Please run " +
    123                         "'%s login' and try again.") %
    124                        (auth_filepath, sys.argv[0]))
    125   if len(lines) != 2:
    126     raise CommandError(("Invalid auth file (%s). Please run " +
    127                         "'%s login' and try again.") %
    128                        (auth_filepath, sys.argv[0]))
    129   return map(lambda x: x.strip(), lines)
    130 
    131 def login_cmd(args):
    132   """login command"""
    133   if len(args) != 0:
    134     return usage()
    135 
    136   import getpass
    137   import gaia_auth
    138 
    139   print "Email:",
    140   email = raw_input()
    141   passwd = getpass.getpass("Password: ")
    142 
    143   authenticator = gaia_auth.GaiaAuthenticator('chromoting');
    144   auth_token = authenticator.authenticate(email, passwd)
    145 
    146   # Set permission mask for created file.
    147   os.umask(0066)
    148   auth_file = open(auth_filepath, 'w')
    149   auth_file.write(email)
    150   auth_file.write('\n')
    151   auth_file.write(auth_token)
    152   auth_file.close()
    153 
    154   print 'Auth token: ', auth_token
    155   print '...saved in', auth_filepath
    156 
    157 def list_cmd(args):
    158   """list command"""
    159   if len(args) != 0:
    160     return usage()
    161   (username, token) = load_auth_token()
    162   client = HostDirectory(username, token)
    163   print '%36s  %30s   %s' % ("HOST ID", "HOST NAME", "JABBER ID")
    164   for host in client.get_hosts():
    165     print '%36s  %30s   %s' % (host.host_id, host.host_name, host.jabber_id)
    166   return 0
    167 
    168 def insert_cmd(args):
    169   """insert command"""
    170   (username, token) = load_auth_token()
    171   client = HostDirectory(username, token)
    172 
    173   host = Host()
    174   for arg in args:
    175     if arg.startswith("--hostId="):
    176       host.host_id = arg[len("--hostId="):]
    177     elif arg.startswith("--hostName="):
    178       host.host_name = arg[len("--hostName="):]
    179     elif arg.startswith("--publicKey="):
    180       host.public_key = arg[len("--publicKey="):]
    181     elif arg.startswith("--jabberId="):
    182       host.jabber_id = arg[len("--jabberId="):]
    183     else:
    184       return usage()
    185 
    186   client.add_host(host)
    187   return 0
    188 
    189 def delete_cmd(args):
    190   """delete command"""
    191   if len(args) != 1:
    192     return usage()
    193   host_id = args[0]
    194   (username, token) = load_auth_token()
    195   client = HostDirectory(username, token)
    196   client.delete_host(host_id)
    197   return 0
    198 
    199 def main():
    200   import sys
    201   args = sys.argv[1:]
    202   if len(args) == 0:
    203     return usage()
    204   command = args[0]
    205 
    206   try:
    207     if command == "help":
    208       usage()
    209     elif command == "login":
    210       return login_cmd(args[1:])
    211     elif command == "list":
    212       return list_cmd(args[1:])
    213     elif command == "insert":
    214       return insert_cmd(args[1:])
    215     elif command == "delete":
    216       return delete_cmd(args[1:])
    217     else:
    218       raise CommandError("Unknown command: %s" % command);
    219 
    220   except CommandError as e:
    221     sys.stderr.write("%s\n" % e.args[0])
    222     return 1
    223 
    224   return 0
    225 
    226 if __name__ == '__main__':
    227   sys.exit(main())
    228