addons-server/mkt/receipts/views.py

239 строки
7.7 KiB
Python

from django import http
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import csrf_exempt
import commonware.log
import jingo
from session_csrf import anonymous_csrf_exempt
from tower import ugettext as _
from access import acl
from addons.decorators import addon_view_factory
from addons.models import Addon
import amo
import amo.log
from amo.decorators import json_view, login_required, post_required, write
from amo.urlresolvers import reverse
from devhub.models import AppLog
from editors.views import reviewer_required
from lib.metrics import record_action
from lib.crypto.receipt import SigningError
from lib.cef_loggers import receipt_cef
import mkt
from mkt.constants import apps
from mkt.receipts.utils import create_test_receipt
from mkt.webapps.models import Installed, Webapp
from services.verify import get_headers, Verify
from stats.models import ClientData
from users.models import UserProfile
from zadmin.models import DownloadSource
from . import forms
from .utils import create_receipt
log = commonware.log.getLogger('z.receipts')
addon_view = addon_view_factory(qs=Webapp.objects.valid)
addon_all_view = addon_view_factory(qs=Webapp.objects.all)
def _record(request, addon):
# TODO(andym): we have an API now, replace this with that.
logged = request.user.is_authenticated()
premium = addon.is_premium()
# Require login for premium.
if not logged and premium:
return http.HttpResponseRedirect(reverse('users.login'))
ctx = {'addon': addon.pk}
# Don't generate receipts if we're allowing logged-out install.
if logged:
is_dev = request.check_ownership(addon, require_owner=False,
ignore_disabled=True, admin=False)
is_reviewer = acl.check_reviewer(request)
if (not addon.is_webapp() or not addon.is_public() and
not (is_reviewer or is_dev)):
raise http.Http404
if (premium and
not addon.has_purchased(request.amo_user) and
not is_reviewer and not is_dev):
raise PermissionDenied
# If you are reviewer, you get a user receipt. Use the reviewer tools
# to get a reviewer receipt. App developers still get their special
# receipt.
install_type = (apps.INSTALL_TYPE_DEVELOPER if is_dev
else apps.INSTALL_TYPE_USER)
# Log the install.
installed, c = Installed.objects.get_or_create(addon=addon,
user=request.amo_user, install_type=install_type)
# Get download source from GET if it exists, if so get the download
# source object if it exists. Then grab a client data object to hook up
# with the Installed object.
download_source = DownloadSource.objects.filter(
name=request.REQUEST.get('src', None))
download_source = download_source[0] if download_source else None
try:
region = request.REGION.id
except AttributeError:
region = mkt.regions.WORLDWIDE.id
client_data, c = ClientData.objects.get_or_create(
download_source=download_source,
device_type=request.POST.get('device_type', ''),
user_agent=request.META.get('HTTP_USER_AGENT', ''),
is_chromeless=request.POST.get('chromeless', False),
language=request.LANG,
region=region)
installed.update(client_data=client_data)
error = ''
receipt_cef.log(request, addon, 'sign', 'Receipt requested')
try:
receipt = create_receipt(installed)
except SigningError:
error = _('There was a problem installing the app.')
ctx.update(receipt=receipt, error=error)
else:
if not addon.is_public() or not addon.is_webapp():
raise http.Http404
amo.log(amo.LOG.INSTALL_ADDON, addon)
record_action('install', request, {
'app-domain': addon.domain_from_url(addon.origin, allow_none=True),
'app-id': addon.pk,
'anonymous': request.user.is_anonymous(),
})
return ctx
@anonymous_csrf_exempt
@json_view
@addon_all_view
@post_required
@write
def record_anon(request, addon):
return _record(request, addon)
@json_view
@addon_all_view
@post_required
@write
def record(request, addon):
return _record(request, addon)
# Set the CORS headers on the response by calling get_headers.
def response(data):
response = http.HttpResponse(data)
for header, value in get_headers(len(data)):
response[header] = value
return response
@csrf_exempt
@post_required
def verify(request, uuid):
# Because this will be called at any point in the future,
# use guid in the URL.
addon = get_object_or_404(Addon, guid=uuid)
receipt = request.read()
verify = Verify(receipt, request.META)
output = verify.check_without_purchase()
# Only reviewers or the developers can use this which is different
# from the standard receipt verification. The user is contained in the
# receipt.
if verify.user_id:
try:
user = UserProfile.objects.get(pk=verify.user_id)
except UserProfile.DoesNotExist:
user = None
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 response(output)
return response(verify.invalid())
@addon_all_view
@json_view
@post_required
def issue(request, addon):
user = request.amo_user
review = acl.action_allowed_user(user, 'Apps', 'Review') if user else None
developer = addon.has_author(user)
if not (review or developer):
raise PermissionDenied
install, flavour = ((apps.INSTALL_TYPE_REVIEWER, 'reviewer') if review
else (apps.INSTALL_TYPE_DEVELOPER, 'developer'))
installed, c = Installed.objects.safer_get_or_create(addon=addon,
user=request.amo_user, install_type=install)
error = ''
receipt_cef.log(request, addon, 'sign', 'Receipt signing for %s' % flavour)
receipt = None
try:
receipt = create_receipt(installed, flavour=flavour)
except SigningError:
error = _('There was a problem installing the app.')
return {'addon': addon.pk, 'receipt': receipt, 'error': error}
@json_view
@reviewer_required
def check(request, uuid):
# Because this will be called at any point in the future,
# use guid in the URL.
addon = get_object_or_404(Addon, guid=uuid)
qs = (AppLog.objects.order_by('-created')
.filter(addon=addon,
activity_log__action=amo.LOG.RECEIPT_CHECKED.id))
return {'status': qs.exists()}
# These methods are for the test of receipts in the devhub.
def devhub_install(request):
return jingo.render(request, 'receipts/test_manifest.html',
{'form': forms.TestInstall()})
@anonymous_csrf_exempt
@json_view
@post_required
def devhub_receipt(request):
form = forms.TestInstall(request.POST)
if form.is_valid():
data = form.cleaned_data
if data['receipt_type'] == 'none':
return {'receipt': '', 'error': ''}
receipt_cef.log(request, None, 'sign', 'Test receipt signing')
receipt = create_test_receipt(data['root'], data['receipt_type'])
return {'receipt': receipt, 'error': ''}
return {'receipt': '', 'error': form.errors}
def devhub_details(request):
return jingo.render(request, 'receipts/test_details.html')
@csrf_exempt
@post_required
def devhub_verify(request, status):
receipt = request.read()
verify = Verify(receipt, request.META)
return response(verify.check_without_db(status))