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 6from google.appengine.ext import webapp 7from google.appengine.ext.webapp import util 8from google.appengine.api import users 9from google.appengine.api import urlfetch 10from google.appengine.ext.webapp import template 11from google.appengine.api.urlfetch import DownloadError 12import oauth2 13import urllib 14import logging 15import os 16import time 17from django.utils import simplejson 18 19# Configuration 20 21CONFIG = { 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' 34IS_PRODUCTION = os.environ['SERVER_SOFTWARE'].startswith('Google App Engine') 35 36# Valid access levels that may be returned by the license server. 37VALID_ACCESS_LEVELS = ['FREE_TRIAL', 'FULL'] 38 39def 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 71def 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 107class 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 145if __name__ == '__main__': 146 application = webapp.WSGIApplication([ 147 ('/', MainHandler), 148 ], debug=False) 149 util.run_wsgi_app(application) 150