1 #!/usr/bin/python 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 from google.appengine.ext import webapp 7 from google.appengine.ext.webapp import util 8 from google.appengine.api import users 9 from google.appengine.api import urlfetch 10 from google.appengine.ext.webapp import template 11 from google.appengine.api.urlfetch import DownloadError 12 import oauth2 13 import urllib 14 import logging 15 import os 16 import time 17 from django.utils import simplejson 18 19 # Configuration 20 21 CONFIG = { 22 'oauth_consumer_key': 'anonymous', 23 'oauth_consumer_secret': 'anonymous', 24 'license_server': 'https://www.googleapis.com', 25 'license_path': '%(server)s/chromewebstore/v1/licenses/%(appid)s/%(userid)s', 26 'oauth_token': 'INSERT OAUTH TOKEN HERE', 27 'oauth_token_secret': 'INSERT OAUTH TOKEN SECRET HERE', 28 'app_id': 'INSERT APPLICATION ID HERE', 29 } 30 31 # Check to see if the server has been deployed. In the dev server, this 32 # env variable will start with 'Development', in production, it will start with 33 # 'Google App Engine' 34 IS_PRODUCTION = os.environ['SERVER_SOFTWARE'].startswith('Google App Engine') 35 36 # Valid access levels that may be returned by the license server. 37 VALID_ACCESS_LEVELS = ['FREE_TRIAL', 'FULL'] 38 39 def fetch_license_data(userid): 40 """Fetches the license for a given user by making an OAuth signed request 41 to the license server. 42 43 Args: 44 userid OpenID of the user you are checking access for. 45 46 Returns: 47 The server's response as text. 48 """ 49 url = CONFIG['license_path'] % { 50 'server': CONFIG['license_server'], 51 'appid': CONFIG['app_id'], 52 'userid': urllib.quote_plus(userid), 53 } 54 55 oauth_token = oauth2.Token(**{ 56 'key': CONFIG['oauth_token'], 57 'secret': CONFIG['oauth_token_secret'] 58 }) 59 60 oauth_consumer = oauth2.Consumer(**{ 61 'key': CONFIG['oauth_consumer_key'], 62 'secret': CONFIG['oauth_consumer_secret'] 63 }) 64 65 logging.debug('Requesting %s' % url) 66 client = oauth2.Client(oauth_consumer, oauth_token) 67 resp, content = client.request(url, 'GET') 68 logging.debug('Got response code %s, content %s' % (resp, content)) 69 return content 70 71 def parse_license_data(userid): 72 """Returns the license for a given user as a structured object. 73 74 Args: 75 userid: The OpenID of the user to check. 76 77 Returns: 78 An object with the following parameters: 79 error: True if something went wrong, False otherwise. 80 message: A descriptive message if error is True. 81 access: One of 'NO', 'FREE_TRIAL', or 'FULL' depending on the access. 82 """ 83 license = {'error': False, 'message': '', 'access': 'NO'} 84 try: 85 response_text = fetch_license_data(userid) 86 try: 87 logging.debug('Attempting to JSON parse: %s' % response_text) 88 json = simplejson.loads(response_text) 89 logging.debug('Got license server response: %s' % json) 90 except ValueError: 91 logging.exception('Could not parse response as JSON: %s' % response_text) 92 license['error'] = True 93 license['message'] = 'Could not parse the license server response' 94 except DownloadError: 95 logging.exception('Could not fetch license data') 96 license['error'] = True 97 license['message'] = 'Could not fetch license data' 98 99 if json.has_key('error'): 100 license['error'] = True 101 license['message'] = json['error']['message'] 102 elif json['result'] == 'YES' and json['accessLevel'] in VALID_ACCESS_LEVELS: 103 license['access'] = json['accessLevel'] 104 105 return license 106 107 class MainHandler(webapp.RequestHandler): 108 """Request handler class.""" 109 def get(self): 110 """Handler for GET requests.""" 111 user = users.get_current_user() 112 if user: 113 if IS_PRODUCTION: 114 # We should use federated_identity in production, since the license 115 # server requires an OpenID 116 userid = user.federated_identity() 117 else: 118 # On the dev server, we won't have access to federated_identity, so 119 # just use a default OpenID which will never return YES. 120 # If you want to test different response values on the development 121 # server, just change this default value (e.g. append '-yes' or 122 # '-trial'). 123 userid = ('https://www.google.com/accounts/o8/id?' 124 'id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') 125 license_data = parse_license_data(userid) 126 template_data = { 127 'license': license_data, 128 'user_name': user.nickname(), 129 'user_id': userid, 130 'user_logout': users.create_logout_url(self.request.uri), 131 } 132 else: 133 # Force the OpenID login endpoint to be for Google accounts only, since 134 # the license server doesn't support any other type of OpenID provider. 135 login_url = users.create_login_url(dest_url='/', 136 federated_identity='google.com/accounts/o8/id') 137 template_data = { 138 'user_login': login_url, 139 } 140 141 # Render a simple template 142 path = os.path.join(os.path.dirname(__file__), 'templates', 'index.html') 143 self.response.out.write(template.render(path, template_data)) 144 145 if __name__ == '__main__': 146 application = webapp.WSGIApplication([ 147 ('/', MainHandler), 148 ], debug=False) 149 util.run_wsgi_app(application) 150