diff --git a/mkt/reviewers/tests/test_views.py b/mkt/reviewers/tests/test_views.py index 793a20828b..57b2aa1a14 100644 --- a/mkt/reviewers/tests/test_views.py +++ b/mkt/reviewers/tests/test_views.py @@ -645,3 +645,12 @@ class TestReviewerReceipt(amo.tests.TestCase): res = self.client.post(self.url) eq_(self.log.count(), 1) eq_(res.status_code, 200) + + @mock.patch('mkt.reviewers.views.Verify') + def test_logs(self, verify): + author = UserProfile.objects.get(pk=999) + AddonUser.objects.create(addon=self.app, user=author) + verify.return_value = self.get_mock(user=author, status='ok') + res = self.client.post(self.url) + eq_(self.log.count(), 1) + eq_(res.status_code, 200) diff --git a/mkt/reviewers/views.py b/mkt/reviewers/views.py index 0f8c23ba56..55b3303e3a 100644 --- a/mkt/reviewers/views.py +++ b/mkt/reviewers/views.py @@ -276,7 +276,7 @@ def receipt(request, addon): verify = Verify(addon.pk, receipt, request) output = verify() - # Only reviewers are allowed to use this which is different + # Only reviewers or the authors can use this which is different # from the standard receipt verification. The user is contained in the # receipt. if verify.user_id: @@ -285,7 +285,8 @@ def receipt(request, addon): except UserProfile.DoesNotExist: user = None - if user and acl.action_allowed_user(user, 'Apps', 'Review'): + if user and (acl.action_allowed_user(user, 'Apps', 'Review') + or addon.has_author(user)): amo.log(amo.LOG.RECEIPT_CHECKED, addon, user=user) return http.HttpResponse(output, verify.get_headers(len(output))) diff --git a/mkt/webapps/models.py b/mkt/webapps/models.py index 0b686b3015..10f1eb35d1 100644 --- a/mkt/webapps/models.py +++ b/mkt/webapps/models.py @@ -14,6 +14,7 @@ from django.dispatch import receiver import commonware.log from tower import ugettext as _ +from access import acl import amo from amo.decorators import skip_cache from amo.helpers import absolutify @@ -350,25 +351,40 @@ def add_uuid(sender, **kw): @memoize(prefix='create-receipt', time=60 * 10) -def create_receipt(installed_pk): +def create_receipt(installed_pk, flavour=None): + assert flavour in [None, 'author', 'reviewer'], ( + 'Invalid flavour: %s' % flavour) + installed = Installed.objects.get(pk=installed_pk) addon_pk = installed.addon.pk - verify = '%s%s' % (settings.WEBAPPS_RECEIPT_URL, addon_pk) + time_ = calendar.timegm(time.gmtime()) + product = {'url': installed.addon.origin, + 'storedata': urlencode({'id': int(addon_pk)})} + + # Generate different receipts for reviewers or authors. + if flavour in ['author', 'reviewer']: + if not (acl.action_allowed_user(installed.user, 'Apps', 'Review') or + installed.addon.has_author(installed.user)): + raise ValueError('User %s is not a reviewer or author' % + installed.user.pk) + + expiry = time_ + (60 * 60 * 24) + product['type'] = flavour + verify = absolutify(reverse('reviewers.apps.receipt', + args=[installed.addon.app_slug])) + else: + expiry = time_ + settings.WEBAPPS_RECEIPT_EXPIRY_SECONDS + verify = '%s%s' % (settings.WEBAPPS_RECEIPT_URL, addon_pk) + detail = reverse('account.purchases.receipt', args=[addon_pk]) reissue = installed.addon.get_purchase_url('reissue') - time_ = calendar.timegm(time.gmtime()) - receipt = dict(typ='purchase-receipt', - product={'url': installed.addon.origin, - 'storedata': urlencode({'id': int(addon_pk)})}, + receipt = dict(detail=absolutify(detail), exp=expiry, iat=time_, + iss=settings.SITE_URL, nbf=time_, product=product, + reissue=absolutify(reissue), typ='purchase-receipt', user={'type': 'directed-identifier', 'value': installed.uuid}, - iss=settings.SITE_URL, - nbf=time_, - iat=time_, - exp=(time_ + settings.WEBAPPS_RECEIPT_EXPIRY_SECONDS), - detail=absolutify(detail), - verify=absolutify(verify), - reissue=absolutify(reissue)) + verify=absolutify(verify)) + if settings.SIGNING_SERVER_ACTIVE: # The shiny new code. return sign(receipt) diff --git a/mkt/webapps/tests/test_models.py b/mkt/webapps/tests/test_models.py index 2fee98e913..ae7a6d306f 100644 --- a/mkt/webapps/tests/test_models.py +++ b/mkt/webapps/tests/test_models.py @@ -13,14 +13,20 @@ import waffle from django.conf import settings import amo -from addons.models import (Addon, AddonDeviceType, BlacklistedSlug, DeviceType, - Preview) +from amo.helpers import absolutify +from amo.urlresolvers import reverse +from addons.models import (Addon, AddonDeviceType, AddonUser, BlacklistedSlug, + DeviceType, Preview) from mkt.developers.tests.test_views import BaseWebAppTest from mkt.webapps.models import create_receipt, get_key, Installed, Webapp from files.models import File from users.models import UserProfile from versions.models import Version +# We are testing times down to the second. To make sure we don't fail, this +# is the amount of leeway in seconds we are giving the timing tests. +TEST_LEEWAY = 100 + class TestWebapp(test_utils.TestCase): @@ -346,9 +352,42 @@ class TestReceipt(amo.tests.TestCase): eq_(receipt['product']['storedata'], 'id=%s' % int(ins.addon.pk)) assert receipt['exp'] > (calendar.timegm(time.gmtime()) + settings.WEBAPPS_RECEIPT_EXPIRY_SECONDS - - 100) + TEST_LEEWAY) eq_(receipt['reissue'], self.webapp.get_purchase_url('reissue')) + def test_receipt_not_reviewer(self): + ins = self.create_install(self.user, self.webapp) + self.assertRaises(ValueError, + create_receipt, ins.pk, flavour='reviewer') + + def test_receipt_other(self): + ins = self.create_install(self.user, self.webapp) + self.assertRaises(AssertionError, + create_receipt, ins.pk, flavour='wat') + + @mock.patch('jwt.encode') + def for_user(self, ins, flavour, encode): + encode.return_value = 'tmp-to-keep-memoize-happy' + create_receipt(ins.pk, flavour=flavour) + receipt = encode.call_args[0][0] + eq_(receipt['product']['type'], flavour) + eq_(receipt['verify'], + absolutify(reverse('reviewers.apps.receipt', + args=[self.webapp.app_slug]))) + assert receipt['exp'] > (calendar.timegm(time.gmtime()) + + (60 * 60 * 24) - TEST_LEEWAY) + + def test_receipt_data_author(self): + user = UserProfile.objects.get(pk=5497308) + ins = self.create_install(user, self.webapp) + self.for_user(ins, 'author') + + def test_receipt_data_reviewer(self): + user = UserProfile.objects.get(pk=999) + AddonUser.objects.create(addon=self.webapp, user=user) + ins = self.create_install(user, self.webapp) + self.for_user(ins, 'reviewer') + @mock.patch.object(settings, 'SIGNING_SERVER_ACTIVE', True) @mock.patch('mkt.webapps.models.sign') def test_receipt_signer(self, sign):