Permalink
Browse files

very basic implementation (bug 795127)

  • Loading branch information...
1 parent 2d63d64 commit a2cd01c455d17ca8ba85e1d54c7c24e092f5dd52 @andymckay andymckay committed Oct 3, 2012
Showing with 162 additions and 6 deletions.
  1. +71 −0 lib/pay/samples.py
  2. +10 −0 lib/pay/templates/base.html
  3. +8 −0 lib/pay/templates/pay/verify.html
  4. +39 −3 lib/pay/tests.py
  5. +1 −1 lib/pay/urls.py
  6. +27 −1 lib/pay/views.py
  7. +6 −1 webpay/settings/base.py
View
@@ -0,0 +1,71 @@
+# Copied from moz_inapp_pay. Will remove when tests are included in bundle.
+import calendar
+from datetime import datetime, timedelta
+import json
+import time
+import unittest
+
+import jwt
+from nose.tools import eq_, raises
+
+import moz_inapp_pay
+
+
+class JWTtester(unittest.TestCase):
+ key = 'Application key granted by Mozilla Marketplace'
+ secret = 'Application secret granted by Mozilla Marketplace'
+
+ def setUp(self):
+ self.verifier = None
+
+ def payload(self, app_id=None, exp=None, iat=None,
+ typ='mozilla/postback/pay/v1', extra_req=None, extra_res=None):
+ if not app_id:
+ app_id = self.key
+ if not iat:
+ iat = calendar.timegm(time.gmtime())
+ if not exp:
+ exp = iat + 3600 # expires in 1 hour
+
+ req = {'price': '0.99',
+ 'currency': 'USD',
+ 'name': 'My bands latest album',
+ 'description': '320kbps MP3 download, DRM free!',
+ 'productdata': 'my_product_id=1234'}
+ if extra_req:
+ req.update(extra_req)
+
+ res = {'transactionID': '1234'}
+ if extra_res:
+ res.update(extra_res)
+
+ return {
+ 'iss': 'marketplace.mozilla.org',
+ 'aud': app_id,
+ 'typ': typ,
+ 'exp': exp,
+ 'iat': iat,
+ 'request': req,
+ 'response': res,
+ }
+
+ def request(self, app_secret=None, payload=None, **payload_kw):
+ if not app_secret:
+ app_secret = self.secret
+ if not payload:
+ payload = json.dumps(self.payload(**payload_kw))
+ encoded = jwt.encode(payload, app_secret, algorithm='HS256')
+ return unicode(encoded) # e.g. django always passes unicode
+
+ def verify(self, request=None, update=None, update_request=None,
+ verifier=None):
+ if not verifier:
+ verifier = self.verifier
+ if not request:
+ payload = self.payload()
+ if update_request:
+ payload['request'].update(update_request)
+ if update:
+ payload.update(update)
+ request = self.request(payload=json.dumps(payload))
+ return verifier(request, self.key, self.secret)
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html LANG="{{ LANG }}" dir="{{ DIR }}">
+ <head>
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
+ <title>{% block page_title %}Web Pay{% endblock %}</title>
+ </head>
+ <body>
+ {% block content %}{% endblock %}
+ </body>
+</html>
@@ -0,0 +1,8 @@
+{% block content %}
+ {% if error %}
+ <h1>Error</h1>
+ <pre>{{ error }}</pre>
+ {% else %}
+ <p>JWT processed</p>
+ {% endif %}
+{% endblock %}
View
@@ -1,10 +1,46 @@
+import json
+
from django import test
+from django.conf import settings
from django.core.urlresolvers import reverse
+import jwt
+import mock
from nose.tools import eq_
+from samples import JWTtester
+
+
+@mock.patch.object(settings, 'KEY', JWTtester.key)
+@mock.patch.object(settings, 'SECRET', JWTtester.secret)
+class TestVerify(JWTtester, test.TestCase):
+
+ def setUp(self):
+ super(TestVerify, self).setUp()
+ self.url = '/en-US' + reverse('verify')
+
+ def get(self, payload):
+ return self.client.get('%s?req=%s' % (self.url, payload))
+
+ def test_post(self):
+ eq_(self.client.post(self.url).status_code, 405)
+
+ def test_get(self):
+ eq_(self.client.get(self.url).status_code, 400)
+ def test_get_some_jwt(self):
+ payload = self.request(app_secret=self.secret)
+ eq_(self.get(payload).status_code, 200)
-class TestVerify(test.TestCase):
+ def test_debug(self):
+ with self.settings(DEBUG=True):
+ payload = self.request(app_secret='foo')
+ res = self.get(payload)
+ eq_(res.status_code, 400)
+ assert res.content
- def hello(self):
- eq_(self.client.get(reverse('verify')).status_code, 200)
+ def test_not_debug(self):
+ with self.settings(DEBUG=False):
+ payload = self.request(app_secret='foo')
+ res = self.get(payload)
+ eq_(res.status_code, 400)
+ assert res.content
View
@@ -3,5 +3,5 @@
import views
urlpatterns = patterns('',
- url(r'^verify$', views.verify, name='verify'),
+ url(r'^mozpay$', views.verify, name='verify'),
)
View
@@ -1,5 +1,31 @@
+import sys
+import traceback
+
from django import http
+from django.conf import settings
+from django.shortcuts import render
+from django.views.decorators.http import require_GET
+
+import commonware.log
+
+from moz_inapp_pay.exc import InvalidJWT, RequestExpired
+from moz_inapp_pay.verify import verify_jwt
+from session_csrf import anonymous_csrf_exempt
+
+log = commonware.log.getLogger('w.pay')
+@anonymous_csrf_exempt
+@require_GET
def verify(request):
- return http.HttpResponse('Hello world.')
+ data = request.GET.get('req', '')
+ try:
+ res = verify_jwt(data, settings.KEY, settings.SECRET)
+ except (TypeError, InvalidJWT, RequestExpired):
+ error = {'Error parsing JWT'}
+ log.error(error, exc_info=True)
+ if settings.DEBUG:
+ error = '\n'.join(traceback.format_exception(*sys.exc_info()))
+ return render(request, 'pay/verify.html',
+ {'error': error}, status=400)
+ return render(request, 'pay/verify.html')
View
@@ -13,6 +13,7 @@
# Application base, containing global templates.
'%s.base' % PROJECT_MODULE,
'lib.pay',
+ 'tower'
]
LOCALE_PATHS = (
@@ -63,7 +64,7 @@
LOGGING = dict(loggers=dict(playdoh = {'level': logging.DEBUG}))
MIDDLEWARE_CLASSES = (
- #'funfactory.middleware.LocaleURLMiddleware',
+ 'funfactory.middleware.LocaleURLMiddleware',
'multidb.middleware.PinningRouterMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
@@ -74,3 +75,7 @@
'mobility.middleware.DetectMobileMiddleware',
'mobility.middleware.XMobileMiddleware',
)
+
+# This is the key and secret for the JWT.
+KEY = ''
+SECRET = ''

0 comments on commit a2cd01c

Please sign in to comment.