Exemple #1
0
def create_test_receipt(root, status, storedata=None):
    if not storedata:
        storedata = {'id': 0}
    time_ = calendar.timegm(time.gmtime())
    detail = absolutify(reverse('receipt.test.details'))
    receipt = {
        'detail': absolutify(detail),
        'exp': time_ + (60 * 60 * 24),
        'iat': time_,
        'iss': settings.SITE_URL,
        'nbf': time_,
        'product': {
            'storedata': urlencode(storedata),
            'url': root,
        },
        'reissue': detail,
        'typ': 'test-receipt',
        'user': {
            'type': 'directed-identifier',
            'value': 'none'
        },
        'verify': absolutify(reverse('receipt.test.verify',
                                     kwargs={'status': status}))

    }
    return sign(receipt)
Exemple #2
0
def send_purchase_receipt(contrib_id, **kw):
    """
    Sends an email to the purchaser of the app.
    """
    contrib = Contribution.objects.get(pk=contrib_id)
    with contrib.user.activate_lang():
        addon = contrib.addon
        version = addon.current_version or addon.latest_version
        # L10n: {0} is the app name.
        subject = _('Receipt for {0}').format(contrib.addon.name)
        data = {
            'app_name': addon.name,
            'developer_name': version.developer_name if version else '',
            'price': contrib.get_amount_locale(get_locale_from_lang(
                contrib.source_locale)),
            'date': jingo.helpers.datetime(contrib.created.date()),
            'purchaser_email': contrib.user.email,
            # 'purchaser_phone': '',  # TODO: See bug 894614.
            # 'purchaser_last_four': '',
            'transaction_id': contrib.uuid,
            'purchases_url': absolutify('/purchases'),
            'support_url': addon.support_url,
            'terms_of_service_url': absolutify('/terms-of-use'),
        }

        log.info('Sending email about purchase: %s' % contrib_id)
        text_template = 'purchase/receipt.ltxt'
        html_template = 'purchase/receipt.html'
        send_html_mail_jinja(subject, html_template, text_template, data,
                             recipient_list=[contrib.user.email])
Exemple #3
0
def send_purchase_receipt(contrib_id, **kw):
    """
    Sends an email to the purchaser of the app.
    """
    contrib = Contribution.objects.get(pk=contrib_id)

    with contrib.user.activate_lang():
        addon = contrib.addon
        version = addon.current_version or addon.latest_version
        # L10n: {0} is the app name.
        subject = _('Receipt for {0}').format(contrib.addon.name)
        data = {
            'app_name': addon.name,
            'developer_name': version.developer_name if version else '',
            'price': contrib.get_amount_locale(get_locale_from_lang(
                contrib.source_locale)),
            'date': jingo.helpers.datetime(contrib.created.date()),
            'purchaser_email': contrib.user.email,
            #'purchaser_phone': '',  # TODO: See bug 894614.
            #'purchaser_last_four': '',
            'transaction_id': contrib.uuid,
            'purchases_url': absolutify('/purchases'),
            'support_url': addon.support_url,
            'terms_of_service_url': absolutify('/terms-of-use'),
        }

        log.info('Sending email about purchase: %s' % contrib_id)
        text_template = 'purchase/receipt.ltxt'
        html_template = 'purchase/receipt.html'
        send_html_mail_jinja(subject, html_template, text_template, data,
                             recipient_list=[contrib.user.email])
Exemple #4
0
def create_test_receipt(root, status, storedata=None):
    if not storedata:
        storedata = {'id': 0}
    time_ = calendar.timegm(time.gmtime())
    detail = absolutify(reverse('receipt.test.details'))
    receipt = {
        'detail':
        absolutify(detail),
        'exp':
        time_ + (60 * 60 * 24),
        'iat':
        time_,
        'iss':
        settings.SITE_URL,
        'nbf':
        time_,
        'product': {
            'storedata': urlencode(storedata),
            'url': root,
        },
        'reissue':
        detail,
        'typ':
        'test-receipt',
        'user': {
            'type': 'directed-identifier',
            'value': 'none'
        },
        'verify':
        absolutify(reverse('receipt.test.verify', kwargs={'status': status}))
    }
    return sign(receipt)
Exemple #5
0
 def get_context_data(self):
     # We need to display the name in some language that is relevant to the
     # recipient(s) instead of using the reviewer's. addon.default_locale
     # should work.
     if self.addon.name.locale != self.addon.default_locale:
         lang = to_language(self.addon.default_locale)
         with translation.override(lang):
             app = Webapp.objects.get(id=self.addon.id)
     else:
         app = self.addon
     return {
         'name':
         app.name,
         'reviewer':
         self.request.user.name,
         'detail_url':
         absolutify(app.get_url_path()),
         'review_url':
         absolutify(reverse('reviewers.apps.review', args=[app.app_slug])),
         'status_url':
         absolutify(app.get_dev_url('versions')),
         'comments':
         self.data['comments'],
         'MKT_SUPPORT_EMAIL':
         settings.MKT_SUPPORT_EMAIL,
         'SITE_URL':
         settings.SITE_URL
     }
Exemple #6
0
def get_mail_context(note, user_id):
    """
    Get context data for comm emails, specifically for review action emails.
    """
    obj = note.thread.obj

    # grep: comm-content-type.
    if obj.name and obj.__class__ == Webapp:
        # We need to display the name in some language that is relevant to the
        # recipient(s) instead of using the reviewer's. addon.default_locale
        # should work.
        lang = to_language(obj.default_locale)
        with translation.override(lang):
            obj = Webapp.with_deleted.get(id=obj.id)
    elif not obj.name:
        # For deleted objects.
        obj.name = obj.app_slug if hasattr(obj, 'app_slug') else obj.slug

    if user_id:
        UserProfile.objects.get(id=user_id)

    # grep: comm-content-type.
    manage_url = ''
    obj_type = ''
    thread_url = ''
    if obj.__class__ == Webapp:
        manage_url = absolutify(obj.get_dev_url('versions'))
        obj_type = 'app'
        thread_url = absolutify(
            reverse('commonplace.commbadge.show_thread',
                    args=[note.thread.id]))
    elif obj.__class__ == Extension:
        manage_url = absolutify(
            reverse('commonplace.content.addon_manage', args=[obj.slug]))
        # Not "Firefox OS add-on" for a/an consistency with "app".
        obj_type = 'add-on'
        if user_id:
            user = UserProfile.objects.get(id=user_id)
            if acl.action_allowed_user(user, 'ContentTools', 'AddonReview'):
                thread_url = absolutify(
                    reverse('commonplace.content.addon_review',
                            args=[obj.slug]))
            else:
                thread_url = manage_url

    return {
        'mkt': mkt,
        'comm': comm,
        'is_app': obj.__class__ == Webapp,
        'is_extension': obj.__class__ == Extension,
        'manage_url': manage_url,
        'note': note,
        'obj': obj,
        'obj_type': obj_type,
        'settings': settings,
        'thread_url': thread_url
    }
Exemple #7
0
def get_mail_context(note, user_id):
    """
    Get context data for comm emails, specifically for review action emails.
    """
    obj = note.thread.obj

    # grep: comm-content-type.
    if obj.name and obj.__class__ == Webapp:
        # We need to display the name in some language that is relevant to the
        # recipient(s) instead of using the reviewer's. addon.default_locale
        # should work.
        lang = to_language(obj.default_locale)
        with translation.override(lang):
            obj = Webapp.with_deleted.get(id=obj.id)
    elif not obj.name:
        # For deleted objects.
        obj.name = obj.app_slug if hasattr(obj, 'app_slug') else obj.slug

    if user_id:
        UserProfile.objects.get(id=user_id)

    # grep: comm-content-type.
    manage_url = ''
    obj_type = ''
    thread_url = ''
    if obj.__class__ == Webapp:
        manage_url = absolutify(obj.get_dev_url('versions'))
        obj_type = 'app'
        thread_url = absolutify(reverse('commonplace.commbadge.show_thread',
                                        args=[note.thread.id]))
    elif obj.__class__ == Extension:
        manage_url = absolutify(reverse('commonplace.content.addon_manage',
                                        args=[obj.slug]))
        # Not "Firefox OS add-on" for a/an consistency with "app".
        obj_type = 'add-on'
        if user_id:
            user = UserProfile.objects.get(id=user_id)
            if acl.action_allowed_user(user, 'ContentTools', 'AddonReview'):
                thread_url = absolutify(
                    reverse('commonplace.content.addon_review',
                            args=[obj.slug]))
            else:
                thread_url = manage_url

    return {
        'mkt': mkt,
        'comm': comm,
        'is_app': obj.__class__ == Webapp,
        'is_extension': obj.__class__ == Extension,
        'manage_url': manage_url,
        'note': note,
        'obj': obj,
        'obj_type': obj_type,
        'settings': settings,
        'thread_url': thread_url
    }
Exemple #8
0
def get_product_jwt(product, contribution):
    """
    Prepare a JWT describing the item about to be purchased when
    working with navigator.mozPay().

    See the MDN docs for details on the JWT fields:
    https://developer.mozilla.org/en-US/Marketplace/Monetization
        /In-app_payments_section/mozPay_iap
    """

    issued_at = calendar.timegm(time.gmtime())
    product_data = product.product_data(contribution)
    simulation = product.simulation()
    if not simulation and not product_data.get('public_id'):
        raise ValueError(
            'Cannot create JWT without a cached public_id for '
            'app {a}'.format(a=product.addon()))

    token_data = {
        'iss': settings.APP_PURCHASE_KEY,
        'typ': settings.APP_PURCHASE_TYP,
        'aud': settings.APP_PURCHASE_AUD,
        'iat': issued_at,
        'exp': issued_at + 3600,  # expires in 1 hour
        'request': {
            'id': product.external_id(),
            'name': unicode(product.name()),
            'defaultLocale': product.default_locale(),
            'locales': product.localized_properties(),
            'icons': product.icons(),
            'description': strip_tags(product.description()),
            'pricePoint': product.price().name,
            'productData': urlencode(product_data),
            'chargebackURL': absolutify(reverse('webpay.chargeback')),
            'postbackURL': absolutify(reverse('webpay.postback')),
        }
    }
    if simulation:
        token_data['request']['simulate'] = simulation

    token = sign_webpay_jwt(token_data)

    log.debug('Preparing webpay JWT for product {p}, contrib {c}: {t}'
              .format(p=product.id(), t=token_data, c=contribution))

    return {
        'webpayJWT': token,
        'contribStatusURL': reverse(
            'webpay-status',
            kwargs={'uuid': contribution.uuid}
        )
    }
def get_product_jwt(product, contribution):
    """
    Prepare a JWT describing the item about to be purchased when
    working with navigator.mozPay().

    See the MDN docs for details on the JWT fields:
    https://developer.mozilla.org/en-US/Marketplace/Monetization
        /In-app_payments_section/mozPay_iap
    """

    issued_at = calendar.timegm(time.gmtime())
    product_data = product.product_data(contribution)
    simulation = product.simulation()
    if not simulation and not product_data.get('public_id'):
        raise ValueError(
            'Cannot create JWT without a cached public_id for '
            'app {a}'.format(a=product.addon()))

    token_data = {
        'iss': settings.APP_PURCHASE_KEY,
        'typ': settings.APP_PURCHASE_TYP,
        'aud': settings.APP_PURCHASE_AUD,
        'iat': issued_at,
        'exp': issued_at + 3600,  # expires in 1 hour
        'request': {
            'id': product.external_id(),
            'name': unicode(product.name()),
            'defaultLocale': product.default_locale(),
            'locales': product.localized_properties(),
            'icons': product.icons(),
            'description': strip_tags(product.description()),
            'pricePoint': product.price().name,
            'productData': urlencode(product_data),
            'chargebackURL': absolutify(reverse('webpay.chargeback')),
            'postbackURL': absolutify(reverse('webpay.postback')),
        }
    }
    if simulation:
        token_data['request']['simulate'] = simulation

    token = sign_webpay_jwt(token_data)

    log.debug('Preparing webpay JWT for product {p}, contrib {c}: {t}'
              .format(p=product.id(), t=token_data, c=contribution))

    return {
        'webpayJWT': token,
        'contribStatusURL': reverse(
            'webpay-status',
            kwargs={'uuid': contribution.uuid}
        )
    }
Exemple #10
0
 def download_url(self):
     kwargs = {
         'filename': self.fancy_filename,
         'uuid': self.extension.uuid,
         'version_id': self.pk,
     }
     return absolutify(reverse('extension.download_signed', kwargs=kwargs))
Exemple #11
0
 def test_verify(self):
     url = absolutify(reverse('receipt.test.verify',
                              kwargs={'status': 'expired'}))
     receipt = create_test_receipt('http://foo', 'expired')
     req = RawRequestFactory().post(url, receipt)
     res = devhub_verify(req, 'expired')
     eq_(json.loads(res.content)['status'], 'expired')
Exemple #12
0
 def download_url(self):
     kwargs = {
         'filename': self.filename,
         'uuid': self.extension.uuid,
         'version_id': self.pk,
     }
     return absolutify(reverse('extension.download_signed', kwargs=kwargs))
Exemple #13
0
 def icons(self):
     # TODO: Default to 64x64 icon until addressed in
     # https://bugzilla.mozilla.org/show_bug.cgi?id=981093
     return {64: absolutify(
         self.inapp.logo_url or
         urljoin(settings.MEDIA_URL, 'img/mkt/icons/rocket-64.png')
     )}
Exemple #14
0
 def icons(self):
     # TODO: Default to 64x64 icon until addressed in
     # https://bugzilla.mozilla.org/show_bug.cgi?id=981093
     return {64: absolutify(
         self.inapp.logo_url or
         urljoin(settings.MEDIA_URL, 'img/mkt/icons/rocket-64.png')
     )}
Exemple #15
0
def get_mail_context(note):
    """
    Get context data for comm emails, specifically for review action emails.
    """
    app = note.thread.webapp

    if app.name and app.name.locale != app.default_locale:
        # We need to display the name in some language that is relevant to the
        # recipient(s) instead of using the reviewer's. webapp.default_locale
        # should work.
        lang = to_language(app.default_locale)
        with translation.override(lang):
            app = Webapp.with_deleted.get(id=app.id)
    elif not app.name:
        # For deleted apps.
        app.name = app.app_slug

    return {
        'mkt': mkt,
        'app': app,
        'comm': comm,
        'note': note,
        'review_url': absolutify(reverse('reviewers.apps.review',
                                 args=[app.app_slug])),
        'settings': settings
    }
Exemple #16
0
 def get_url_path(self, src):
     from amo.helpers import urlparams
     from mkt.site.helpers import absolutify
     url = os.path.join(reverse('downloads.file', args=[self.id]),
                        self.filename)
     # Firefox's Add-on Manager needs absolute urls.
     return absolutify(urlparams(url, src=src))
Exemple #17
0
 def reviewer_mini_manifest_url(self):
     return absolutify(
         reverse('extension.mini_manifest_reviewer',
                 kwargs={
                     'uuid': self.extension.uuid,
                     'version_id': self.pk
                 }))
Exemple #18
0
 def get_url_path(self, src):
     from amo.utils import urlparams
     from mkt.site.helpers import absolutify
     url = os.path.join(reverse('downloads.file', args=[self.id]),
                        self.filename)
     # Firefox's Add-on Manager needs absolute urls.
     return absolutify(urlparams(url, src=src))
Exemple #19
0
def get_mail_context(note):
    """
    Get context data for comm emails, specifically for review action emails.
    """
    app = note.thread.addon

    if app.name and app.name.locale != app.default_locale:
        # We need to display the name in some language that is relevant to the
        # recipient(s) instead of using the reviewer's. addon.default_locale
        # should work.
        lang = to_language(app.default_locale)
        with translation.override(lang):
            app = Webapp.with_deleted.get(id=app.id)
    elif not app.name:
        # For deleted apps.
        app.name = app.app_slug

    return {
        'mkt':
        mkt,
        'app':
        app,
        'comm':
        comm,
        'note':
        note,
        'review_url':
        absolutify(reverse('reviewers.apps.review', args=[app.app_slug])),
        'settings':
        settings
    }
Exemple #20
0
def _mini_manifest(addon, version_id, token=None):
    if not addon.is_packaged:
        raise http.Http404

    version = get_object_or_404(addon.versions, pk=version_id)
    file_ = version.all_files[0]
    manifest = addon.get_manifest_json(file_)

    package_path = absolutify(
        reverse('reviewers.signed', args=[addon.app_slug, version.id]))

    if token:
        # Generate a fresh token.
        token = Token(data={'app_id': addon.id})
        token.save()
        package_path = urlparams(package_path, token=token.token)

    data = {
        'name': manifest['name'],
        'version': version.version,
        'size': file_.size,
        'release_notes': version.releasenotes,
        'package_path': package_path,
    }
    for key in ['developer', 'icons', 'locales']:
        if key in manifest:
            data[key] = manifest[key]

    return json.dumps(data, cls=JSONEncoder)
Exemple #21
0
def _mini_manifest(addon, version_id, token=None):
    if not addon.is_packaged:
        raise http.Http404

    version = get_object_or_404(addon.versions, pk=version_id)
    file_ = version.all_files[0]
    manifest = addon.get_manifest_json(file_)

    package_path = absolutify(
        reverse('reviewers.signed', args=[addon.app_slug, version.id]))

    if token:
        # Generate a fresh token.
        token = Token(data={'app_id': addon.id})
        token.save()
        package_path = urlparams(package_path, token=token.token)

    data = {
        'name': manifest['name'],
        'version': version.version,
        'size': file_.size,
        'release_notes': version.releasenotes,
        'package_path': package_path,
    }
    for key in ['developer', 'icons', 'locales']:
        if key in manifest:
            data[key] = manifest[key]

    return json.dumps(data, cls=JSONEncoder)
Exemple #22
0
 def _test_post_success(self, store_request_uuid):
     data = {
         'StoreRequestID':
         store_request_uuid,
         'CertID':
         unicode(uuid.uuid4()),
         'RatingList': [
             {
                 'RatingAuthorityShortText':
                 'Generic',
                 'AgeRatingText':
                 '12+',
                 'DescriptorList': [{
                     'DescriptorText': 'PEGI_Violence'
                 }],
                 'InteractiveElementList': [
                     {
                         'InteractiveElementText': 'IE_UsersInteract'
                     },
                 ]
             },
             {
                 'RatingAuthorityShortText': 'ESRB',
                 'AgeRatingText': 'Teen',
                 'DescriptorList': [],
                 'InteractiveElementList': []
             },
         ]
     }
     eq_(self.app.is_fully_complete(), False)  # Missing ratings.
     res = self.anon.post(self.url, data=json.dumps(data))
     eq_(res.status_code, 200)
     eq_(
         res.data, {
             'StoreProductID': self.app.guid,
             'StoreProductURL': absolutify(self.app.get_url_path()),
             'EmailAddress': self.profile.email,
             'CompanyName': u'',
             'StoreDeveloperID': self.app.pk,
             'StatusCode': 'Success',
             'DeveloperEmail': self.profile.email,
             'Publish': False,
             'ProductName': self.app.name
         })
     # Don't use .reload(), it doesn't clear cached one-to-one relations.
     self.app = Webapp.objects.get(pk=self.app.pk)
     with self.assertRaises(IARCRequest.DoesNotExist):
         self.app.iarc_request
     eq_(self.app.status, mkt.STATUS_PENDING)
     eq_(self.app.is_fully_complete(), True)
     eq_(uuid.UUID(self.app.iarc_cert.cert_id), uuid.UUID(data['CertID']))
     eq_(self.app.get_content_ratings_by_body(), {
         'generic': '12',
         'esrb': '13'
     })
     self.assertSetEqual(self.app.rating_descriptors.to_keys(),
                         ['has_generic_violence'])
     self.assertSetEqual(self.app.rating_interactives.to_keys(),
                         ['has_users_interact'])
Exemple #23
0
 def for_user(self, app, user, flavour, encode):
     encode.return_value = 'tmp-to-keep-memoize-happy'
     create_receipt(app, user, 'some-uuid', flavour=flavour)
     receipt = encode.call_args[0][0]
     eq_(receipt['typ'], flavour + '-receipt')
     eq_(receipt['verify'],
         absolutify(reverse('receipt.verify', args=[app.guid])))
     return receipt
Exemple #24
0
 def for_user(self, app, user, flavour, encode):
     encode.return_value = 'tmp-to-keep-memoize-happy'
     create_receipt(app, user, 'some-uuid', flavour=flavour)
     receipt = encode.call_args[0][0]
     eq_(receipt['typ'], flavour + '-receipt')
     eq_(receipt['verify'],
         absolutify(reverse('receipt.verify', args=[app.guid])))
     return receipt
Exemple #25
0
 def test_suggestions(self):
     response = self.client.get(self.url, data={'lang': 'en-US'})
     parsed = json.loads(response.content)
     eq_(parsed[0], '')
     self.assertSetEqual(
         parsed[1],
         [unicode(self.app1.name), unicode(self.app2.name)])
     self.assertSetEqual(
         parsed[2],
         [unicode(self.app1.description),
          unicode(truncate(self.app2.description))])
     self.assertSetEqual(
         parsed[3],
         [absolutify(self.app1.get_detail_url()),
          absolutify(self.app2.get_detail_url())])
     self.assertSetEqual(
         parsed[4],
         [self.app1.get_icon_url(64), self.app2.get_icon_url(64)])
Exemple #26
0
 def test_issue_expired(self):
     data = {'receipt_type': 'expired', 'manifest_url': 'http://foo.com/'}
     res = self.client.post(self.issue, data=data)
     data = decode_receipt(json.loads(res.content)['receipt']
                               .encode('ascii'))
     eq_(data['verify'], absolutify(reverse('receipt.test.verify',
                                    kwargs={'status': 'expired'})))
     ok_(data['exp'] > (calendar.timegm(time.gmtime()) +
                        (60 * 60 * 24) - TEST_LEEWAY))
Exemple #27
0
 def test_suggestions(self):
     response = self.client.get(self.url, data={'lang': 'en-US'})
     parsed = json.loads(response.content)
     eq_(parsed[0], '')
     self.assertSetEqual(parsed[1],
                         [unicode(self.app1.name),
                          unicode(self.app2.name)])
     self.assertSetEqual(parsed[2], [
         unicode(self.app1.description),
         unicode(truncate(self.app2.description))
     ])
     self.assertSetEqual(parsed[3], [
         absolutify(self.app1.get_detail_url()),
         absolutify(self.app2.get_detail_url())
     ])
     self.assertSetEqual(
         parsed[4],
         [self.app1.get_icon_url(64),
          self.app2.get_icon_url(64)])
Exemple #28
0
def get_product_jwt(product, contribution):
    """Prepare a JWT for paid products to pass into navigator.pay()"""

    issued_at = calendar.timegm(time.gmtime())
    product_data = product.product_data(contribution)
    simulation = product.simulation()
    if not simulation and not product_data.get('public_id'):
        raise ValueError(
            'Cannot create JWT without a cached public_id for '
            'app {a}'.format(a=product.addon()))

    token_data = {
        'iss': settings.APP_PURCHASE_KEY,
        'typ': settings.APP_PURCHASE_TYP,
        'aud': settings.APP_PURCHASE_AUD,
        'iat': issued_at,
        'exp': issued_at + 3600,  # expires in 1 hour
        'request': {
            'id': product.external_id(),
            'name': unicode(product.name()),
            'icons': product.icons(),
            'description': strip_tags(product.description()),
            'pricePoint': product.price().name,
            'productData': urlencode(product_data),
            'chargebackURL': absolutify(reverse('webpay.chargeback')),
            'postbackURL': absolutify(reverse('webpay.postback')),
        }
    }
    if simulation:
        token_data['request']['simulate'] = simulation

    token = sign_webpay_jwt(token_data)

    log.debug('Preparing webpay JWT for product {p}, contrib {c}: {t}'
              .format(p=product.id(), t=token_data, c=contribution))

    return {
        'webpayJWT': token,
        'contribStatusURL': reverse(
            'webpay-status',
            kwargs={'uuid': contribution.uuid}
        )
    }
Exemple #29
0
    def test_valid_jwt(self):
        token_data = self.decode_token()
        eq_(token_data['iss'], settings.APP_PURCHASE_KEY)
        eq_(token_data['typ'], settings.APP_PURCHASE_TYP)
        eq_(token_data['aud'], settings.APP_PURCHASE_AUD)

        request = token_data['request']
        eq_(request['id'], self.product.external_id())
        eq_(request['name'], self.product.name())
        eq_(request['icons'], self.product.icons())
        eq_(request['description'], self.product.description())
        eq_(request['pricePoint'], self.product.price().name)
        eq_(request['postbackURL'], absolutify(reverse('webpay.postback')))
        eq_(request['chargebackURL'], absolutify(reverse('webpay.chargeback')))

        token_product_data = urlparse.parse_qs(request['productData'])
        expected_product_data = urlparse.parse_qs(
            urlencode(self.product.product_data(self.contribution)))
        eq_(token_product_data, expected_product_data)
Exemple #30
0
 def test_receipt_data(self, encode):
     encode.return_value = 'tmp-to-keep-memoize-happy'
     create_receipt(self.app, self.user, 'some-uuid')
     receipt = encode.call_args[0][0]
     eq_(receipt['product']['url'], self.app.manifest_url[:-1])
     eq_(receipt['product']['storedata'], 'id=%s' % int(self.app.pk))
     assert receipt['exp'] > (calendar.timegm(time.gmtime()) +
                              settings.WEBAPPS_RECEIPT_EXPIRY_SECONDS -
                              TEST_LEEWAY)
     eq_(receipt['reissue'], absolutify(reverse('receipt.reissue')))
Exemple #31
0
 def test_receipt_data(self, encode):
     encode.return_value = 'tmp-to-keep-memoize-happy'
     create_receipt(self.app, self.user, 'some-uuid')
     receipt = encode.call_args[0][0]
     eq_(receipt['product']['url'], self.app.manifest_url[:-1])
     eq_(receipt['product']['storedata'], 'id=%s' % int(self.app.pk))
     assert receipt['exp'] > (calendar.timegm(time.gmtime()) +
                              settings.WEBAPPS_RECEIPT_EXPIRY_SECONDS -
                              TEST_LEEWAY)
     eq_(receipt['reissue'], absolutify(reverse('receipt.reissue')))
Exemple #32
0
def get_product_jwt(product, contribution):
    """Prepare a JWT for paid products to pass into navigator.pay()"""

    issued_at = calendar.timegm(time.gmtime())
    product_data = product.product_data(contribution)
    simulation = product.simulation()
    if not simulation and not product_data.get('public_id'):
        raise ValueError(
            'Cannot create JWT without a cached public_id for '
            'app {a}'.format(a=product.addon()))

    token_data = {
        'iss': settings.APP_PURCHASE_KEY,
        'typ': settings.APP_PURCHASE_TYP,
        'aud': settings.APP_PURCHASE_AUD,
        'iat': issued_at,
        'exp': issued_at + 3600,  # expires in 1 hour
        'request': {
            'id': product.external_id(),
            'name': unicode(product.name()),
            'icons': product.icons(),
            'description': strip_tags(product.description()),
            'pricePoint': product.price().name,
            'productData': urlencode(product_data),
            'chargebackURL': absolutify(reverse('webpay.chargeback')),
            'postbackURL': absolutify(reverse('webpay.postback')),
        }
    }
    if simulation:
        token_data['request']['simulate'] = simulation

    token = sign_webpay_jwt(token_data)

    log.debug('Preparing webpay JWT for product {p}, contrib {c}: {t}'
              .format(p=product.id(), t=token_data, c=contribution))

    return {
        'webpayJWT': token,
        'contribStatusURL': reverse(
            'webpay-status',
            kwargs={'uuid': contribution.uuid}
        )
    }
Exemple #33
0
def get_mail_context(note):
    """
    Get context data for comm emails, specifically for review action emails.
    """
    obj = note.thread.obj

    # grep: comm-content-type.
    if obj.name and obj.__class__ == Webapp:
        # We need to display the name in some language that is relevant to the
        # recipient(s) instead of using the reviewer's. addon.default_locale
        # should work.
        lang = to_language(obj.default_locale)
        with translation.override(lang):
            obj = Webapp.with_deleted.get(id=obj.id)
    elif not obj.name:
        # For deleted objects.
        obj.name = obj.app_slug if hasattr(obj, 'app_slug') else obj.slug

    # grep: comm-content-type.
    manage_url = ''
    review_url = ''
    if obj.__class__ == Webapp:
        manage_url = absolutify(obj.get_dev_url('versions'))
        review_url = absolutify(reverse('reviewers.apps.review',
                                        args=[obj.app_slug]))
    elif obj.__class__ == Extension:
        manage_url = absolutify(reverse('commonplace.content.addon_manage',
                                        args=[obj.slug]))
        review_url = absolutify(reverse('commonplace.content.addon_review',
                                        args=[obj.slug]))

    return {
        'mkt': mkt,
        'comm': comm,
        'is_app': obj.__class__ == Webapp,
        'is_extension': obj.__class__ == Extension,
        'manage_url': manage_url,
        'note': note,
        'obj': obj,
        'review_url': review_url,
        'settings': settings
    }
Exemple #34
0
    def test_valid_jwt(self):
        token_data = self.decode_token()
        eq_(token_data["iss"], settings.APP_PURCHASE_KEY)
        eq_(token_data["typ"], settings.APP_PURCHASE_TYP)
        eq_(token_data["aud"], settings.APP_PURCHASE_AUD)

        request = token_data["request"]
        eq_(request["id"], self.product.external_id())
        eq_(request["name"], self.product.name())
        eq_(request["defaultLocale"], self.product.default_locale())
        eq_(request["icons"], self.product.icons())
        eq_(request["description"], self.product.description())
        eq_(request["pricePoint"], self.product.price().name)
        eq_(request["postbackURL"], absolutify(reverse("webpay.postback")))
        eq_(request["chargebackURL"], absolutify(reverse("webpay.chargeback")))

        product = urlparse.parse_qs(request["productData"])
        expected = urlparse.parse_qs(urlencode(self.product.product_data(self.contribution)))
        eq_(product["buyer_email"], [self.user.email])
        eq_(product, expected)
Exemple #35
0
 def get_context_data(self):
     # We need to display the name in some language that is relevant to the
     # recipient(s) instead of using the reviewer's. addon.default_locale
     # should work.
     if self.addon.name.locale != self.addon.default_locale:
         lang = to_language(self.addon.default_locale)
         with translation.override(lang):
             app = Webapp.objects.get(id=self.addon.id)
     else:
         app = self.addon
     return {'name': app.name,
             'reviewer': self.request.user.name,
             'detail_url': absolutify(
                 app.get_url_path()),
             'review_url': absolutify(reverse('reviewers.apps.review',
                                              args=[app.app_slug])),
             'status_url': absolutify(app.get_dev_url('versions')),
             'comments': self.data['comments'],
             'MKT_SUPPORT_EMAIL': settings.MKT_SUPPORT_EMAIL,
             'SITE_URL': settings.SITE_URL}
Exemple #36
0
def send_reviewer_mail(subject, template, context, emails, perm_setting=None,
                       cc=None, attachments=None, reply_to=None):
    if not reply_to:
        reply_to = settings.MKT_REVIEWERS_EMAIL

    # Link to our newfangled "Account Settings" page.
    manage_url = absolutify('/settings') + '#notifications'
    send_mail_jinja(subject, template, context, recipient_list=emails,
                    from_email=settings.MKT_REVIEWERS_EMAIL,
                    use_blacklist=False, perm_setting=perm_setting,
                    manage_url=manage_url, headers={'Reply-To': reply_to},
                    cc=cc, attachments=attachments)
Exemple #37
0
def send_reviewer_mail(subject, template, context, emails, perm_setting=None,
                       cc=None, attachments=None, reply_to=None):
    if not reply_to:
        reply_to = settings.MKT_REVIEWERS_EMAIL

    # Link to our newfangled "Account Settings" page.
    manage_url = absolutify('/settings') + '#notifications'
    send_mail_jinja(subject, template, context, recipient_list=emails,
                    from_email=settings.MKT_REVIEWERS_EMAIL,
                    use_blacklist=False, perm_setting=perm_setting,
                    manage_url=manage_url, headers={'Reply-To': reply_to},
                    cc=cc, attachments=attachments)
 def call(self, client=None):
     client = client or OAuthClient(self.access)
     # Make a fake POST somewhere. We use POST in order to properly test db
     # pinning after auth.
     url = absolutify('/api/whatever')
     req = RequestFactory().post(url,
         HTTP_HOST='testserver',
         HTTP_AUTHORIZATION=client.sign('POST', url)[1]['Authorization'])
     req.user = AnonymousUser()
     for m in self.middlewares:
         m().process_request(req)
     return req
Exemple #39
0
 def test_iarc_app_data(self):
     self.app = app_factory()
     self.profile = user_factory()
     self.app.addonuser_set.create(user=self.profile)
     eq_(_iarc_app_data(self.app),
         {'StoreProductID': self.app.guid,
          'StoreProductURL': absolutify(self.app.get_url_path()),
          'EmailAddress': self.profile.email,
          'CompanyName': u'',
          'StoreDeveloperID': self.app.pk,
          'DeveloperEmail': self.profile.email,
          'Publish': True,
          'ProductName': unicode(self.app.name)})
Exemple #40
0
 def test_app_data(self):
     self.app = app_factory()
     self.profile = user_factory()
     self.app.addonuser_set.create(user=self.profile)
     eq_(app_data(self.app),
         {'StoreProductID': self.app.guid,
          'StoreProductURL': absolutify(self.app.get_url_path()),
          'EmailAddress': self.profile.email,
          'CompanyName': u'',
          'StoreDeveloperID': self.app.pk,
          'DeveloperEmail': self.profile.email,
          'Publish': True,
          'ProductName': unicode(self.app.name)})
 def call(self, client=None):
     client = client or OAuthClient(self.access)
     # Make a fake POST somewhere. We use POST in order to properly test db
     # pinning after auth.
     url = absolutify('/api/whatever')
     req = RequestFactory().post(url,
                                 HTTP_HOST='testserver',
                                 HTTP_AUTHORIZATION=client.sign(
                                     'POST', url)[1]['Authorization'])
     req.user = AnonymousUser()
     for m in self.middlewares:
         m().process_request(req)
     return req
Exemple #42
0
 def _create_stub_products(self):
     for name, amount, img in (
             ('Kiwi', '0.99', 'img/developers/simulated-kiwi.png'),
             ('Rocket', '1.99', 'img/mkt/icons/rocket-64.png')):
         log.info('Creating stub in-app product {n} {p}'
                  .format(n=name, p=amount))
         # TODO: make this adjustable.
         simulate = json.dumps({'result': 'postback'})
         InAppProduct.objects.create(
             logo_url=absolutify(urljoin(settings.MEDIA_URL, img)),
             name=name,
             price=Price.objects.get(price=amount),
             simulate=simulate,
             stub=True)
Exemple #43
0
 def test_fail(self):
     url = absolutify(reverse('app-list'))
     url, auth_header = self._oauth_request_info(
         url, client_key=self.access.key,
         client_secret="none")
     auth = authentication.RestOAuthAuthentication()
     req = RequestFactory().get(
         url, HTTP_HOST='testserver',
         HTTP_AUTHORIZATION=auth_header)
     req.API = True
     req.user = AnonymousUser()
     RestOAuthMiddleware().process_request(req)
     ok_(not auth.authenticate(Request(req)))
     ok_(not req.user.is_authenticated())
Exemple #44
0
 def test_fail(self):
     url = absolutify(reverse('app-list'))
     url, auth_header = self._oauth_request_info(url,
                                                 client_key=self.access.key,
                                                 client_secret="none")
     auth = authentication.RestOAuthAuthentication()
     req = RequestFactory().get(url,
                                HTTP_HOST='testserver',
                                HTTP_AUTHORIZATION=auth_header)
     req.API = True
     req.user = AnonymousUser()
     RestOAuthMiddleware().process_request(req)
     ok_(not auth.authenticate(Request(req)))
     ok_(not req.user.is_authenticated())
Exemple #45
0
    def test_manifest_validation_failure(self, _iarc):
        # We are already mocking validator, but this test needs to make sure
        # it actually saves our custom validation result, so add that.
        def side_effect(upload_id, **kwargs):
            upload = FileUpload.objects.get(pk=upload_id)
            upload.validation = json.dumps(validation_results)
            upload.save()

        validation_results = {
            'errors':
            1,
            'messages': [{
                'context':
                None,
                'uid':
                'whatever',
                'column':
                None,
                'id': ['webapp', 'detect_webapp', 'parse_error'],
                'file':
                '',
                'tier':
                1,
                'message':
                'JSON Parse Error',
                'type':
                'error',
                'line':
                None,
                'description':
                'The webapp extension could not be parsed due '
                'to a syntax error in the JSON.'
            }]
        }
        self.validator.side_effect = side_effect

        eq_(RereviewQueue.objects.count(), 0)

        self._run()

        eq_(RereviewQueue.objects.count(), 1)
        eq_(len(mail.outbox), 1)
        msg = mail.outbox[0]
        upload = FileUpload.objects.get()
        validation_url = absolutify(
            reverse('mkt.developers.upload_detail', args=[upload.uuid]))
        ok_(msg.subject.startswith('Issue with your app'))
        ok_(validation_results['messages'][0]['message'] in msg.body)
        ok_(validation_url in msg.body)
        ok_(not _iarc.called)
Exemple #46
0
    def test_inapp_product(self):
        eq_(self.product.id(), self.inapp.pk)
        eq_(self.product.name(), unicode(self.inapp.name))
        eq_(self.product.addon(), None)
        eq_(self.product.price(), self.inapp.price)
        eq_(self.product.icons()[64], absolutify(self.inapp.logo_url))
        eq_(self.product.application_size(), None)
        eq_(self.product.description(), "This is a stub product for testing only")
        eq_(self.product.simulation(), {"result": "postback"})

        product_data = self.product.product_data(self.contribution)
        eq_(product_data["contrib_uuid"], self.contribution.uuid)
        eq_(product_data["inapp_id"], self.product.id())
        eq_(product_data["application_size"], self.product.application_size())
Exemple #47
0
 def _create_stub_products(self):
     for name, amount, img in (
             ('Kiwi', '0.99', 'img/developers/simulated-kiwi.png'),
             ('Rocket', '1.99', 'img/mkt/icons/rocket-64.png')):
         log.info('Creating stub in-app product {n} {p}'
                  .format(n=name, p=amount))
         # TODO: make this adjustable.
         simulate = json.dumps({'result': 'postback'})
         InAppProduct.objects.create(
             logo_url=absolutify(urljoin(settings.MEDIA_URL, img)),
             name=name,
             price=Price.objects.get(price=amount),
             simulate=simulate,
             stub=True)
Exemple #48
0
    def test_inapp_product(self):
        eq_(self.product.id(), self.inapp.pk)
        eq_(self.product.name(), unicode(self.inapp.name))
        eq_(self.product.addon(), None)
        eq_(self.product.price(), self.inapp.price)
        eq_(self.product.icons()[64], absolutify(self.inapp.logo_url))
        eq_(self.product.application_size(), None)
        eq_(self.product.description(),
            'This is a stub product for testing only')
        eq_(self.product.simulation(), {'result': 'postback'})

        product_data = self.product.product_data(self.contribution)
        eq_(product_data['contrib_uuid'], self.contribution.uuid)
        eq_(product_data['inapp_id'], self.product.id())
        eq_(product_data['application_size'], self.product.application_size())
Exemple #49
0
 def test_app_data_not_public(self):
     self.app = app_factory()
     self.profile = user_factory()
     self.app.addonuser_set.create(user=self.profile)
     with mock.patch.object(self.app, 'is_public') as is_public_mock:
         is_public_mock.return_value = False
         eq_(app_data(self.app),
             {'StoreProductID': self.app.guid,
              'StoreProductURL': absolutify(self.app.get_url_path()),
              'EmailAddress': self.profile.email,
              'CompanyName': u'',
              'StoreDeveloperID': self.app.pk,
              'DeveloperEmail': self.profile.email,
              'Publish': False,
              'ProductName': unicode(self.app.name)})
Exemple #50
0
 def test_iarc_app_data_not_public(self):
     self.app = app_factory()
     self.profile = user_factory()
     self.app.addonuser_set.create(user=self.profile)
     with mock.patch.object(self.app, 'is_public') as is_public_mock:
         is_public_mock.return_value = False
         eq_(_iarc_app_data(self.app),
             {'StoreProductID': self.app.guid,
              'StoreProductURL': absolutify(self.app.get_url_path()),
              'EmailAddress': self.profile.email,
              'CompanyName': u'',
              'StoreDeveloperID': self.app.pk,
              'DeveloperEmail': self.profile.email,
              'Publish': False,
              'ProductName': unicode(self.app.name)})
Exemple #51
0
    def test_inapp_product(self):
        eq_(self.product.id(), self.inapp.pk)
        eq_(self.product.name(), unicode(self.inapp.name))
        eq_(self.product.addon(), self.inapp.webapp)
        eq_(self.product.price(), self.inapp.price)
        eq_(self.product.icons()[64], absolutify(self.inapp.logo_url))
        eq_(self.product.description(), self.inapp.webapp.description)
        eq_(self.product.application_size(), None)
        eq_(self.product.simulation(), None)

        product_data = self.product.product_data(self.contribution)
        eq_(product_data['contrib_uuid'], self.contribution.uuid)
        eq_(product_data['addon_id'], self.product.addon().pk)
        eq_(product_data['inapp_id'], self.product.id())
        eq_(product_data['application_size'], self.product.application_size())
        eq_(product_data['public_id'], self.public_id)
Exemple #52
0
 def test_bad_access_token(self):
     url = absolutify(reverse('app-list'))
     Token.generate_new(ACCESS_TOKEN, creds=self.access, user=self.user2)
     url, auth_header = self._oauth_request_info(
         url, client_key=self.access.key,
         client_secret=self.access.secret, resource_owner_key=generate(),
         resource_owner_secret=generate())
     auth = authentication.RestOAuthAuthentication()
     req = RequestFactory().get(
         url, HTTP_HOST='testserver',
         HTTP_AUTHORIZATION=auth_header)
     req.API = True
     req.user = AnonymousUser()
     RestOAuthMiddleware().process_request(req)
     ok_(not auth.authenticate(Request(req)))
     ok_(not req.user.is_authenticated())
Exemple #53
0
def fxa_preverify_token(user, expiry):
    """
    Takes a user and a timedelta and generates a preverify token for FxA OAuth.
    See https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#preverifytoken
    for details.
    """
    msg = {
        'exp': get_token_expiry(expiry),
        'aud': settings.FXA_AUTH_DOMAIN,
        'sub': user.email,
        'typ': 'mozilla/fxa/preVerifyToken/v1',
    }
    jws = JWS(msg, cty='JWT', alg='RS256',
              kid=PREVERIFY_KEY.kid,
              jku=absolutify(reverse('fxa-preverify-key')))
    return jws.sign_compact([PREVERIFY_KEY])
Exemple #54
0
    def test_webapp_product(self):
        eq_(self.product.id(), self.addon.pk)
        eq_(self.product.name(), unicode(self.addon.name))
        eq_(self.product.addon(), self.addon)
        eq_(self.product.price(), self.addon.premium.price)
        eq_(self.product.icons()['64'],
            absolutify(self.addon.get_icon_url(64)))
        eq_(self.product.description(), self.addon.description)
        eq_(self.product.application_size(),
            self.addon.current_version.all_files[0].size)
        eq_(self.product.simulation(), None)

        product_data = self.product.product_data(self.contribution)
        eq_(product_data['contrib_uuid'], self.contribution.uuid)
        eq_(product_data['public_id'], self.public_id)
        eq_(product_data['addon_id'], self.product.addon().pk)
        eq_(product_data['application_size'], self.product.application_size())