Example #1
0
def revision_add_attachment(request, pk):
    """Add attachment, download if necessary
    """
    revision = get_object_or_404(PackageRevision, pk=pk)
    if request.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to add attachment to package (%s) by "
                   "non-owner (%s)" % (revision.package, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden(
            'You are not the author of this %s' % escape(
                revision.package.get_type_name()))
    url = request.POST.get('url', None)
    filename = request.POST.get('filename', None)
    if not filename or filename == "":
        log.error('Trying to create an attachment without name')
        return HttpResponseBadRequest('Path not found.')
    content = ''
    if url:
        log.info(('[%s] Preparing to download %s as an attachment of '
            'PackageRevision %d') % (filename, url, revision.pk))
        # validate url
        field = URLField(verify_exists=True)
        encoding = request.POST.get('force_contenttype', False)
        try:
            url = field.clean(url)
        except ValidationError, err:
            log.warning('[%s] Invalid url provided\n%s' % (url,
                '\n'.join(err.messages)))
            return HttpResponseBadRequest(("Loading attachment failed\n"
                "%s") % parse_validation_messages(err))
        except Exception, err:
            log.warning('[%s] Exception raised\n%s' % (url, str(err)))
            return HttpResponseBadRequest(str(err))
Example #2
0
def _get_registered_user(directory, request):
    """Checks the directory for a registered user.

    Function returns a tuple of registered and details.
    Registered is True if a user is found and False otherwise.
    If registered is True then details contains info about
    the known user.

    The statsd timer ``larper.sasl_bind_time`` allows IT to detect
    timeouts between ldap and https://browserid.org/verify. If this
    counter gets large, check DNS routes between slapd servers and
    browserid.org.

    The statsd counter
    ``browserid.unknown_error_checking_registered_user``
    allows IT to detect a problem with the backend auth system.
    """
    registered = False
    details = None
    try:
        (registered, details) = directory.registered_user()
        if registered:
            request.session['unique_id'] = details
        else:
            request.session['verified_email'] = details
    except Exception, e:
        # Look at syslogs on slapd hosts to investigate unknown issues
        messages.error(request,
                       _("We're Sorry, but Something Went Wrong!"))
        statsd.incr('browserid.unknown_error_checking_registered_user')
        log.error("Unknown error, clearing session assertion [%s]", e)
        store_assertion(request, None)
Example #3
0
def revision_add_attachment(request, pk):
    """Add attachment, download if necessary
    """
    revision = get_object_or_404(PackageRevision, pk=pk)
    if request.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to add attachment to package (%s) by "
                   "non-owner (%s)" % (revision.package, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden(
            'You are not the author of this %s' % escape(
                revision.package.get_type_name()))
    url = request.POST.get('url', None)
    filename = request.POST.get('filename', None)
    log.debug(filename)
    if not filename or filename == "":
        log.error('Trying to create an attachment without name')
        return HttpResponseForbidden('Path not found.')
    content = ''
    if url:
        # validate url
        field = URLField(verify_exists=True)
        try:
            url = field.clean(url)
        except ValidationError, err:
            log.debug('Invalid url provided (%s)\n%s' % (url,
                '\n'.join(err.messages)))
            return HttpResponseForbidden(("Loading attachment failed<br/>"
                "%s") % '<br/>'.join(err.messages))
        except Exception, err:
            return HttpResponseForbidden(str(err))
Example #4
0
def json_upload_detail(upload):
    if not settings.VALIDATE_ADDONS:
        upload.task_error = ''
        upload.validation = json.dumps({'errors': 0, 'messages': [],
                                        'notices': 0, 'warnings': 0})
        upload.save()

    validation = json.loads(upload.validation) if upload.validation else ""
    url = reverse('devhub.upload_detail', args=[upload.uuid, 'json'])
    full_report_url = reverse('devhub.upload_detail', args=[upload.uuid])
    plat_exclude = []

    if validation:
        if validation['errors'] == 0:
            try:
                apps = parse_addon(upload.path).get('apps', [])
                app_ids = set([a.id for a in apps])
                supported_platforms = []
                if amo.MOBILE.id in app_ids:
                    supported_platforms.extend(amo.MOBILE_PLATFORMS.keys())
                    app_ids.remove(amo.MOBILE.id)
                if len(app_ids):
                    # Targets any other non-mobile app:
                    supported_platforms.extend(amo.DESKTOP_PLATFORMS.keys())
                s = amo.SUPPORTED_PLATFORMS.keys()
                plat_exclude = set(s) - set(supported_platforms)
                plat_exclude = [str(p) for p in plat_exclude]
            except django_forms.ValidationError, exc:
                # XPI parsing errors will be reported in the form submission
                # (next request).
                # TODO(Kumar) It would be nicer to present errors to the user
                # right here to avoid confusion about platform selection.
                log.error("XPI parsing error, ignored: %s" % exc)
Example #5
0
def upload_attachment(request, revision_id):
    """ Upload new attachment to the PackageRevision
    """
    revision = get_object_with_related_or_404(PackageRevision, pk=revision_id)
    log.debug(revision)
    if request.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to upload attachment to package (%s) "
                "by non-owner (%s)" % (revision_id, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden(
            'You are not the author of this %s' % escape(
                revision.package.get_type_name()))

    f = request.FILES.get('upload_attachment')
    filename = request.META.get('HTTP_X_FILE_NAME')

    if not f:
        log_msg = 'Path not found: %s, revision: %s.' % (
            filename, revision_id)
        log.error(log_msg)
        return HttpResponseServerError('Path not found.')

    content = f.read()
    # try to force UTF-8 code, on error continue with original data
    try:
        content = unicode(content, 'utf-8')
    except:
        pass

    try:
        attachment = revision.attachment_create_by_filename(
            request.user, filename, content)
    except ValidationError, e:
        return HttpResponseForbidden(
                'Validation errors.\n%s' % parse_validation_messages(e))
Example #6
0
    def is_authenticated(self, request):
        try:
            params = dict(request.POST.items())
            if 'Authorization' not in request.META and \
                'HTTP_AUTHORIZATION' in request.META:
                request.META['Authorization'] = request.META['HTTP_AUTHORIZATION']

            oauth_req = oauth.Request.from_request(
                request.method,
                request.build_absolute_uri(),
                headers=request.META,
                parameters=params,
                query_string=request.environ.get('QUERY_STRING', ''))

            if oauth_req is None:
                raise oauth.Error

            key = oauth_req.get_parameter('oauth_consumer_key')
            r = ConsumerModel.objects.get(key=key)
            consumer = oauth.Consumer(key=r.key, secret=r.secret)

            self.server.verify_request(oauth_req, consumer, None)
            return True
        except ConsumerModel.DoesNotExist, e:
            log.error(e)
            return False
Example #7
0
def upload_attachments(request, id_number, type_id,
                           revision_number=None, version_name=None):
    """ Upload new attachments to the PackageRevision
    """
    revision = get_package_revision(None, id_number, type_id, revision_number,
                                    version_name)
    if request.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to upload attachment to package (%s) "
                "by non-owner (%s)" % (id_number, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden(
            'You are not the author of this %s' % escape(
                revision.package.get_type_name()))

    content = request.raw_post_data
    filename = request.META.get('HTTP_X_FILE_NAME')

    if not filename:
        log_msg = 'Path not found: %s, package: %s.' % (
            filename, id_number)
        log.error(log_msg)
        return HttpResponseServerError('Path not found.')

    try:
        attachment = revision.attachment_create_by_filename(
            request.user, filename, content)
    except ValidationError, e:
        return HttpResponseForbidden(
                'Validation errors.\n%s' % parse_validation_messages(e))
Example #8
0
def verify(request):
    form = BrowserIDForm(data=request.POST)
    if form.is_valid():
        url = settings.BROWSERID_VERIFICATION_URL
        audience = get_audience(request)
        extra_params = {'experimental_forceIssuer': settings.BROWSERID_UNVERIFIED_ISSUER,
                        'experimental_allowUnverified': 'true'}
        assertion = form.cleaned_data['assertion']

        log.info('verifying Persona assertion. url: %s, audience: %s, '
                 'extra_params: %s, assertion: %s' % (url, audience,
                                                      extra_params, assertion))
        result = verify_assertion(assertion, audience, extra_params)
        if result:
            log.info('Persona assertion ok: %s' % result)
            email = result.get('unverified-email', result.get('email'))
            user_hash = set_user(request, email)
            redirect_url = check_pin_status(request)
            return {
                'needs_redirect': redirect_url is not None,
                'redirect_url': redirect_url,
                'user_hash': user_hash
            }

        log.error('Persona assertion failed.')

    request.session.flush()
    return http.HttpResponseBadRequest()
Example #9
0
def support_mail(subject, template, context, sender, recipients):
    try:
        return send_mail_jinja(subject, template, context, from_email=sender,
                               recipient_list=recipients)
    except SMTPRecipientsRefused, e:
        log.error('Tried to send mail from %s to %s: %s' %
                  (sender, ', '.join(recipients), e), exc_info=True)
Example #10
0
def request(action, params, notify_url, user_id=VIDLY_USER_ID,
            user_key=VIDLY_USER_KEY, api_url=VIDLY_API_URL):
    """Call the vid.ly API with the supplied parameters."""
    if user_id is None or user_key is None:
        log.warning('You are missing a user id and/or key for vidly. You '
                    'should pass these to the function you called or specify '
                    'them in settings.VIDLY_USER_ID and '
                    'settings.VIDLY_USER_KEY.')
        return None

    # Build XML Query
    query = ET.Element('Query')
    ET.SubElement(query, 'Action').text = action
    ET.SubElement(query, 'UserID').text = user_id
    ET.SubElement(query, 'UserKey').text = user_key
    ET.SubElement(query, 'Notify').text = notify_url

    _build_param_xml(query, params)

    # Getting an xml version header out of ElementTree is tough.
    # It's easier for our use case to just prepend it.
    xml_str = '<?xml version="1.0"?>%s' % ET.tostring(query)
    log.error('Vidly Request: %s' % xml_str)

    try:
        res = requests.post(api_url, data={'xml': xml_str})
    except RequestException, e:
        log.error('Error connecting to Vidly: %s' % e)
        return None
Example #11
0
def sign_app(src, dest, reviewer=False):
    """
    Generate a manifest and signature and send signature to signing server to
    be signed.
    """
    active_endpoint = _get_endpoint(reviewer)
    timeout = settings.SIGNED_APPS_SERVER_TIMEOUT

    if not active_endpoint:
        _no_sign(src, dest)
        return

    # Extract necessary info from the archive
    try:
        jar = JarExtractor(
            storage.open(src, 'r'), storage.open(dest, 'w'),
            omit_signature_sections=settings.SIGNED_APPS_OMIT_PER_FILE_SIGS)
    except:
        log.error('Archive extraction failed. Bad archive?', exc_info=True)
        raise SigningError('Archive extraction failed. Bad archive?')

    log.info('App signature contents: %s' % jar.signatures)

    log.info('Calling service: %s' % active_endpoint)
    try:
        with statsd.timer('services.sign.app'):
            response = requests.post(active_endpoint, timeout=timeout,
                                     files={'file': ('zigbert.sf',
                                                     str(jar.signatures))})
    except requests.exceptions.HTTPError, error:
        # Will occur when a 3xx or greater code is returned.
        log.error('Posting to app signing failed: %s, %s' % (
            error.response.status, error))
        raise SigningError('Posting to app signing failed: %s, %s' % (
            error.response.status, error))
Example #12
0
def _update_mdn_items(items):
    batch_updated = datetime.now()
    for item in items:
        for locale in locales:

            url = item['mdn'] % {'locale': locale}
            name = item['name'] + '.' + locale

            log.info('Fetching MDN article "%s": %s' % (name, url))

            try:
                content = _fetch_mdn_page(url)
            except Http404:
                log.error(u'404 on MDN article "%s": %s' % (name, url))
                continue
            except Exception as e:
                log.error(u'Error fetching MDN article "%s" reason: %s' %
                    (name, e))
                raise

            model, created = MdnCache.objects.get_or_create(
                name=item['name'], locale=locale)

            model.title = item['title']
            model.content = content
            model.permalink = url
            model.save()

            log.info(u'Updated MDN article "%s"' % name)

    MdnCache.objects.filter(modified__lt=batch_updated).delete()
Example #13
0
def access_request(request):
    try:
        oauth_req = server._create_request(request.build_absolute_uri(),
                                           request.method, request.body,
                                           get_request_headers(request))
        valid, oauth_req = server.validate_access_token_request(oauth_req)
    except ValueError:
        valid = False
    if valid:
        req_t = Token.objects.get(
            token_type=REQUEST_TOKEN,
            key=oauth_req.resource_owner_key)
        t = Token.generate_new(
            token_type=ACCESS_TOKEN,
            creds=req_t.creds,
            user=req_t.user)
        # Clean up as we go.
        req_t.delete()
        return HttpResponse(
            urlencode({'oauth_token': t.key,
                       'oauth_token_secret': t.secret}),
            content_type='application/x-www-form-urlencoded')
    else:
        log.error('Invalid OAuth request for acquiring access token')
        return HttpResponse(status=401)
Example #14
0
    def is_authenticated(self, request, **kwargs):
        oauth_server, oauth_request = initialize_oauth_server_request(request)

        try:
            auth_header_value = request.META.get('HTTP_AUTHORIZATION')
            key = get_oauth_consumer_key_from_header(auth_header_value)

            if not key:
                return None

            consumer = get_consumer(key)
            oauth_server.verify_request(oauth_request, consumer, None)
            # Set the current user to be the consumer owner.
            request.user = consumer.user

        except:
            log.error(u'Error get OAuth headers', exc_info=True)
            request.user = AnonymousUser()
            return False

        # Check that consumer is valid.
        if consumer.status != 'accepted':
            log.info(u'Consumer not accepted: %s' % consumer)
            return False

        ACLMiddleware().process_request(request)
        # Do not allow any user with any roles to use the API.
        # Just in case.
        if request.amo_user.groups.all():
            log.info(u'Attempt to use API with roles, user: %s'
                     % request.amo_user.pk)
            return False

        return True
Example #15
0
def authorize(request):
    if request.method == 'GET' and 'oauth_token' in request.GET:
        try:
            t = Token.objects.get(token_type=REQUEST_TOKEN,
                                  key=request.GET['oauth_token'])
        except Token.DoesNotExist:
            log.error('Invalid OAuth request for obtaining user authorization')
            return HttpResponse(status=401)
        return render(request, 'developers/oauth_authorize.html',
                      {'app_name': t.creds.app_name,
                       'oauth_token': request.GET['oauth_token']})
    elif request.method == 'POST':
        token = request.POST.get('oauth_token')
        try:
            t = Token.objects.get(token_type=REQUEST_TOKEN,
                                  key=token)
        except Token.DoesNotExist:
            return HttpResponse(status=401)
        if 'grant' in request.POST:
            t.user = request.user
            t.save()
            return HttpResponseRedirect(
                urlparams(t.creds.redirect_uri, oauth_token=token,
                          oauth_verifier=t.verifier))
        elif 'deny' in request.POST:
            t.delete()
            return HttpResponse(status=200)
    else:
        log.error('Invalid OAuth request for user access authorization')
        return HttpResponse(status=401)
Example #16
0
def sign(receipt):
    """
    Send the receipt to the signing service.

    This could possibly be made async via celery.
    """
    destination = settings.SIGNING_SERVER
    # If no destination is set. Just ignore this request.
    if not destination:
        return

    destination += '/1.0/sign'
    timeout = settings.SIGNING_SERVER_TIMEOUT

    receipt_json = json.dumps(receipt)
    log.info('Calling service: %s' % destination)
    log.info('Receipt contents: %s' % receipt_json)
    headers = {'Content-Type': 'application/json'}
    data = receipt if isinstance(receipt, basestring) else receipt_json
    request = urllib2.Request(destination, data, headers)

    try:
        with statsd.timer('services.sign'):
            response = urllib2.urlopen(request, timeout=timeout)
    except urllib2.HTTPError, error:
        # Will occur when a 3xx or greater code is returned
        log.error('Posting to signing failed: %s'
                  % (error.code))
        raise SigningError
Example #17
0
def access_request(request):
    oa = OAuthServer()
    try:
        valid, oauth_request = oa.verify_access_token_request(
            request.build_absolute_uri(),
            request.method,
            request.body,
            {'Authorization': request.META.get('HTTP_AUTHORIZATION'),
             'Content-Type':  request.META.get('CONTENT_TYPE')
             })
    except ValueError:
        valid = False
    if valid:
        req_t = Token.objects.get(
            token_type=REQUEST_TOKEN,
            key=oauth_request.resource_owner_key)
        t = Token.generate_new(
            token_type=ACCESS_TOKEN,
            creds=req_t.creds,
            user=req_t.user)
        # Clean up as we go.
        req_t.delete()
        return HttpResponse(
            urlencode({'oauth_token': t.key,
                       'oauth_token_secret': t.secret}),
            content_type='application/x-www-form-urlencoded')
    else:
        log.error('Invalid OAuth request for acquiring access token')
        return HttpResponse(status=401)
Example #18
0
def pay_status(request, config_pk, status):
    tpl_path = 'inapp_pay/'
    with transaction.commit_on_success():
        cfg = get_object_or_404(InappConfig, pk=config_pk)
        uuid_ = None
        try:
            uuid_ = str(request.GET['uuid'])
            cnt = Contribution.objects.get(uuid=uuid_)
        except (KeyError, UnicodeEncodeError, ValueError,
                Contribution.DoesNotExist), exc:
            log.error('PayPal returned invalid uuid %r from in-app payment'
                      % uuid_, exc_info=True)
            inapp_cef.log(request, cfg.addon, 'inapp_pay_status',
                          'PayPal or someone sent invalid uuid %r for '
                          'in-app pay config %r; exception: %s: %s'
                          % (uuid_, cfg.pk, exc.__class__.__name__, exc),
                          severity=4)
            return render_error(request, exc)
        payment = InappPayment.objects.get(config=cfg, contribution=cnt)
        if status == 'complete':
            cnt.update(type=amo.CONTRIB_INAPP)
            tpl = tpl_path + 'complete.html'
            action = 'PAY_COMPLETE'
        elif status == 'cancel':
            tpl = tpl_path + 'payment_cancel.html'
            action = 'PAY_CANCEL'
        else:
            raise ValueError('Unexpected status: %r' % status)
Example #19
0
def verify_webpay_jwt(signed_jwt):
    # This can probably be deleted depending upon solitude.
    try:
        jwt.decode(signed_jwt.encode('ascii'), secret)
    except Exception, e:
        log.error('Error decoding webpay jwt: %s' % e, exc_info=True)
        return {'valid': False}
Example #20
0
def call_signing(file_obj, endpoint):
    """Get the jar signature and send it to the signing server to be signed."""
    # We only want the (unique) temporary file name.
    with tempfile.NamedTemporaryFile() as temp_file:
        temp_filename = temp_file.name

    # Extract jar signature.
    jar = JarExtractor(path=storage.open(file_obj.file_path),
                       outpath=temp_filename,
                       omit_signature_sections=True,
                       extra_newlines=True)

    log.debug(u'File signature contents: {0}'.format(jar.signatures))

    log.debug(u'Calling signing service: {0}'.format(endpoint))
    with statsd.timer('services.sign.addon'):
        response = requests.post(
            endpoint,
            timeout=settings.SIGNING_SERVER_TIMEOUT,
            data={'addon_id': get_id(file_obj.version.addon)},
            files={'file': (u'mozilla.sf', unicode(jar.signatures))})
    if response.status_code != 200:
        msg = u'Posting to add-on signing failed: {0}'.format(response.reason)
        log.error(msg)
        raise SigningError(msg)

    pkcs7 = b64decode(json.loads(response.content)['mozilla.rsa'])
    cert_serial_num = get_signature_serial_number(pkcs7)
    jar.make_signed(pkcs7, sigpath=u'mozilla')
    shutil.move(temp_filename, file_obj.file_path)
    return cert_serial_num
Example #21
0
 def wrapper(request, addon, *args, **kw):
     if not waffle.switch_is_active('marketplace'):
         log.error('Marketplace waffle switch is off')
         raise http.Http404
     if not addon.can_be_purchased():
         return http.HttpResponseForbidden()
     return f(request, addon, *args, **kw)
Example #22
0
def package_upload_attachment(r, id_number, type_id,
                           revision_number=None, version_name=None):
    """ Upload new attachment to the PackageRevision
    """
    revision = get_package_revision(id_number, type_id, revision_number,
                                    version_name)
    if r.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to upload attachment to package (%s) "
                "by non-owner (%s)" % (id_number, r.user))
        log.warning(log_msg)
        return HttpResponseForbidden(
            'You are not the author of this %s' \
                % escape(revision.package.get_type_name()))

    file = r.FILES.get('upload_attachment')
    filename = r.META.get('HTTP_X_FILE_NAME')

    if not file:
        log_msg = 'Path not found: %s, package: %s.' % (
            filename, id_number)
        log.error(log_msg)
        return HttpResponseServerError('Path not found.')

    content = file.read()

    try:
        attachment = revision.attachment_create_by_filename(
            r.user, filename, content)
    except ValidationError, e:
        return HttpResponseForbidden('Validation errors.')
Example #23
0
def delete_incomplete_addons(items, **kw):
    log.info("[%s@%s] Deleting incomplete add-ons" % (len(items), delete_incomplete_addons.rate_limit))
    for addon in Addon.objects.filter(highest_status=0, status=0, pk__in=items):
        try:
            addon.delete("Deleted for incompleteness")
        except Exception as e:
            log.error("Couldn't delete add-on %s: %s" % (addon.id, e))
Example #24
0
def set_modified_on_object(obj, **kw):
    """Sets modified on one object at a time."""
    try:
        log.info("Setting modified on object: %s, %s" % (obj.__class__.__name__, obj.pk))
        obj.update(modified=datetime.datetime.now(), **kw)
    except Exception, e:
        log.error("Failed to set modified on: %s, %s - %s" % (obj.__class__.__name__, obj.pk, e))
Example #25
0
def purchase_complete(request, addon, status):
    result = ''
    if status == 'complete':
        con = Contribution.objects.get(uuid=request.GET.get('uuid'),
                                       type=amo.CONTRIB_PENDING)
        log.debug('Check purchase paypal addon: %s, user: %s, paykey: %s'
                  % (addon.pk, request.amo_user.pk, con.paykey[:10]))
        try:
            result = paypal.check_purchase(con.paykey)
        except:
            log.error('Check purchase paypal addon: %s, user: %s, paykey: %s'
                      % (addon.pk, request.amo_user.pk, con.paykey[:10]),
                      exc_info=True)
            result = 'ERROR'
            status = 'error'

        log.debug('Paypal returned: %s for paykey: %s'
                  % (result, con.paykey[:10]))
        if result == 'COMPLETED':
            # Markup the contribution suitably
            con.type = amo.CONTRIB_PURCHASE
            con.uuid = None
            con.save()

    response = jingo.render(request, 'addons/paypal_result.html',
                            {'addon': addon,
                             'realurl': request.GET.get('realurl', ''),
                             # What the client claimed they did.
                             'status': status,
                             # And what paypal thought of that claim.
                             'result': result})
    response['x-frame-options'] = 'allow'
    return response
Example #26
0
def verify(request):
    form = BrowserIDForm(data=request.POST)
    if form.is_valid():
        url = settings.BROWSERID_VERIFICATION_URL
        audience = get_audience(request)
        extra_params = {'forceIssuer': settings.BROWSERID_UNVERIFIED_ISSUER,
                        'allowUnverified': 'true'}
        assertion = form.cleaned_data['assertion']

        log.info('verifying Persona assertion. url: %s, audience: %s, '
                 'extra_params: %s, assertion: %s' % (url, audience,
                                                      extra_params, assertion))
        result = verify_assertion(assertion, audience, extra_params)
        if result:
            log.info('Persona assertion ok: %s' % result)
            email = result.get('unverified-email', result.get('email'))
            user_hash = set_user(request, email)
            return {'has_pin': request.session.get('uuid_has_pin'),
                    'pin_create': reverse('pin.create'),
                    'user_hash': user_hash}

        log.error('Persona assertion failed.')

    request.session.clear()
    return http.HttpResponseBadRequest()
Example #27
0
def authorize(request):
    if request.method == "GET" and "oauth_token" in request.GET:
        try:
            t = Token.objects.get(token_type=REQUEST_TOKEN, key=request.GET["oauth_token"])
        except Token.DoesNotExist:
            log.error("Invalid OAuth request for obtaining user authorization")
            return HttpResponse(status=401)
        return render(
            request,
            "developers/oauth_authorize.html",
            {"app_name": t.creds.app_name, "oauth_token": request.GET["oauth_token"]},
        )
    elif request.method == "POST":
        token = request.POST.get("oauth_token")
        try:
            t = Token.objects.get(token_type=REQUEST_TOKEN, key=token)
        except Token.DoesNotExist:
            return HttpResponse(status=401)
        if "grant" in request.POST:
            t.user = request.user
            t.save()
            return HttpResponseRedirect(urlparams(t.creds.redirect_uri, oauth_token=token, oauth_verifier=t.verifier))
        elif "deny" in request.POST:
            t.delete()
            return HttpResponse(status=200)
    else:
        log.error("Invalid OAuth request for user access authorization")
        return HttpResponse(status=401)
Example #28
0
def refresh_mdn_cache(**kw):
    log.info('Refreshing MDN Cache')
    try:
        _update_mdn_items(tutorials)
    except Exception as e:
        log.error(u'Failed to update MDN articles, reason: %s' % e,
            exc_info=True)
Example #29
0
def add_empty_attachment(request, id_number, type_id,
                           revision_number=None, version_name=None):
    """ Add new empty attachment to the PackageRevision
    """
    revision = get_package_revision(None, id_number, type_id, revision_number,
                                    version_name)
    if request.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to add attachment to package (%s) by "
                   "non-owner (%s)" % (id_number, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden(
            'You are not the author of this %s' % escape(
                revision.package.get_type_name()))

    filename = request.POST.get('filename', False)

    if not filename:
        log_msg = 'Path not found: %s, package: %s.' % (
            filename, id_number)
        log.error(log_msg)
        return HttpResponseServerError('Path not found.')

    try:
        attachment = revision.attachment_create_by_filename(request.user,
                filename, '')
    except ValidationError, e:
        return HttpResponseForbidden(
                'Validation errors.\n%s' % parse_validation_messages(e))
Example #30
0
    def list(self, request, *args, **kwargs):
        if (not settings.RECOMMENDATIONS_ENABLED or
                not settings.RECOMMENDATIONS_API_URL or
                not self.request.user.is_authenticated()):
            return self._popular()
        else:
            app_ids = []
            url = '{base_url}/api/v2/recommend/{limit}/{user_hash}/'.format(
                base_url=settings.RECOMMENDATIONS_API_URL,
                limit=20, user_hash=self.request.user.recommendation_hash)

            try:
                with statsd.timer('recommendation.get'):
                    resp = requests.get(
                        url, timeout=settings.RECOMMENDATIONS_API_TIMEOUT)
                if resp.status_code == 200:
                    app_ids = resp.json()['recommendations']
            except Timeout as e:
                log.warning(u'Recommendation timeout: {error}'.format(error=e))
            except RequestException as e:
                # On recommendation API exceptions we return popular.
                log.error(u'Recommendation exception: {error}'.format(error=e))

            if not app_ids:
                # Fall back to a popularity search.
                return self._popular()

            sq = WebappIndexer.get_app_filter(self.request, app_ids=app_ids)
            return Response({
                'objects': self.serializer_class(
                    sq.execute().hits, many=True,
                    context={'request': self.request}).data})
Example #31
0
    def list(self, request, *args, **kwargs):
        if (not settings.RECOMMENDATIONS_ENABLED
                or not settings.RECOMMENDATIONS_API_URL
                or not self.request.user.is_authenticated()):
            return self._popular()
        else:
            app_ids = []
            url = '{base_url}/api/v2/recommend/{limit}/{user_hash}/'.format(
                base_url=settings.RECOMMENDATIONS_API_URL,
                limit=20,
                user_hash=self.request.user.recommendation_hash)

            try:
                with statsd.timer('recommendation.get'):
                    resp = requests.get(
                        url, timeout=settings.RECOMMENDATIONS_API_TIMEOUT)
                if resp.status_code == 200:
                    app_ids = resp.json()['recommendations']
            except Timeout as e:
                log.warning(u'Recommendation timeout: {error}'.format(error=e))
            except RequestException as e:
                # On recommendation API exceptions we return popular.
                log.error(u'Recommendation exception: {error}'.format(error=e))

            if not app_ids:
                # Fall back to a popularity search.
                return self._popular()

            # Get list of installed apps and remove from app_ids.
            installed = list(
                request.user.installed_set.values_list('addon_id', flat=True))
            app_ids = filter(lambda a: a not in installed, app_ids)

            device = get_device_id(request)
            filters = {'device': device} if device else None

            sq = WebappIndexer.get_app_filter(self.request,
                                              filters,
                                              app_ids=app_ids)
            return Response({
                'objects':
                self.serializer_class(sq.execute().hits,
                                      many=True,
                                      context={
                                          'request': self.request
                                      }).data
            })
Example #32
0
def recommendations(request, version, platform, limit=9):
    """
    Figure out recommended add-ons for an anonymous user based on POSTed guids.

    POST body looks like {"guids": [...]} with an optional "token" key if
    they've been here before.
    """
    try:
        POST = json.loads(request.raw_post_data)
        guids = POST['guids']
    except (ValueError, TypeError, KeyError):
        # Errors: invalid json, didn't get a dict, didn't find "guids".
        return http.HttpResponseBadRequest()

    addon_ids = get_addon_ids(guids)
    index = Collection.make_index(addon_ids)

    ids, recs = Collection.get_recs_from_ids(addon_ids, request.APP, version)
    recs = _recommendations(request, version, platform, limit, index, ids,
                            recs)

    # Users have a token2 if they've been here before. The token matches
    # addon_index in their SyncedCollection.
    if 'token2' in POST:
        token = POST['token2']
        if token == index:
            # We've seen them before and their add-ons have not changed.
            return recs
        elif token != index:
            # We've seen them before and their add-ons changed. Remove the
            # reference to their old synced collection.
            (SyncedCollection.objects.filter(addon_index=index).update(
                count=F('count') - 1))

    # Try to create the SyncedCollection. There's a unique constraint on
    # addon_index so it will fail if this addon_index already exists. If we
    # checked for existence first and then created a collection there would
    # be a race condition between multiple users with the same addon_index.
    try:
        c = SyncedCollection.objects.create(addon_index=index, count=1)
        c.set_addons(addon_ids)
    except IntegrityError:
        try:
            (SyncedCollection.objects.filter(addon_index=index).update(
                count=F('count') + 1))
        except Exception, e:
            log.error(u'Could not count++ "%s" (%s).' % (index, e))
Example #33
0
def sign(version_id, reviewer=False, resign=False, **kw):
    version = Version.objects.get(pk=version_id)
    app = version.addon
    log.info('Signing version: %s of app: %s' % (version_id, app))

    if not app.is_packaged:
        log.error('[Webapp:%s] Attempt to sign a non-packaged app.' % app.id)
        raise SigningError('Not packaged')

    try:
        file_obj = version.all_files[0]
    except IndexError:
        log.error(
            '[Webapp:%s] Attempt to sign an app with no files in version.' %
            app.id)
        raise SigningError('No file')

    path = (file_obj.signed_reviewer_file_path
            if reviewer else file_obj.signed_file_path)

    if storage.exists(path) and not resign:
        log.info('[Webapp:%s] Already signed app exists.' % app.id)
        return path

    if reviewer:
        # Reviewers get a unique 'id' so the reviewer installed app won't
        # conflict with the public app, and also so multiple versions of the
        # same app won't conflict with themselves.
        ids = json.dumps({
            'id':
            'reviewer-{guid}-{version_id}'.format(guid=app.guid,
                                                  version_id=version_id),
            'version':
            version_id
        })
    else:
        ids = json.dumps({'id': app.guid, 'version': version_id})
    with statsd.timer('services.sign.app'):
        try:
            sign_app(file_obj.file_path, path, ids, reviewer)
        except SigningError:
            log.info('[Webapp:%s] Signing failed' % app.id)
            if storage.exists(path):
                storage.delete(path)
            raise
    log.info('[Webapp:%s] Signing complete.' % app.id)
    return path
Example #34
0
def process_failure_signal(exception, traceback, sender, task_id, signal, args,
                           kwargs, einfo, **kw):
    """Catch any task failure signals from within our worker processes and log
    them as exceptions, so they appear in Sentry and ordinary logging
    output."""

    exc_info = (type(exception), exception, traceback)
    log.error(u'Celery TASK exception: {0.__name__}: {1}'.format(*exc_info),
              exc_info=exc_info,
              extra={
                  'data': {
                      'task_id': task_id,
                      'sender': sender,
                      'args': args,
                      'kwargs': kwargs
                  }
              })
Example #35
0
def register(request):
    """Registers Users.

    Pulls out an invite code if it exists and auto validates the user
    if so. Single-purpose view.
    """
    if 'code' in request.GET:
        request.session['invite-code'] = request.GET['code']
        return redirect('home')

    if request.user.is_authenticated():
        return redirect(reverse('profile', args=[request.user.username]))

    authenticated_email = request.session.get('authenticated_email')
    if not authenticated_email:
        log.error('Browserid registration, but no verified email in session')
        return redirect('home')

    user = auth.authenticate(authenticated_email=authenticated_email)
    if not user:
        return redirect('home')

    user_form = UserForm(request.POST or None, instance=user)
    profile_form = RegisterForm(request.POST or None,
                                instance=user.get_profile())

    if request.method == 'POST':
        if (user_form.is_valid() and profile_form.is_valid()):
            user_form.save()
            profile_form.save()
            auth.login(request, user)
            _update_invites(request)
            messages.info(request, _(u'Your account has been created.'))
            return redirect(reverse('profile', args=[request.user.username]))

    # 'user' object must be passed in because we are not logged in
    return render(
        request, 'registration/register.html',
        dict(
            profile_form=profile_form,
            user_form=user_form,
            edit_form_action=reverse('register'),
            mode='new',
            profile=user.get_profile(),
            user=user,
        ))
Example #36
0
def purchase_complete(request, addon, status):
    result = ''
    if status == 'complete':
        uuid_ = request.GET.get('uuid')
        log.debug('Looking up contrib for uuid: %s' % uuid_)

        # The IPN may, or may not have come through. Which means looking for
        # a for pre or post IPN contributions. If both fail, then we've not
        # got a matching contribution.
        lookup = (Q(uuid=uuid_, type=amo.CONTRIB_PENDING) |
                  Q(transaction_id=uuid_, type=amo.CONTRIB_PURCHASE))
        con = get_object_or_404(Contribution, lookup)

        log.debug('Check purchase paypal addon: %s, user: %s, paykey: %s'
                  % (addon.pk, request.amo_user.pk, con.paykey[:10]))
        try:
            result = paypal.check_purchase(con.paykey)
            if result == 'ERROR':
                paypal.paypal_log_cef(request, addon, uuid_,
                              'Purchase Fail', 'PURCHASEFAIL',
                              'Checking purchase state returned error')
                raise
        except:
            paypal.paypal_log_cef(request, addon, uuid_,
                              'Purchase Fail', 'PURCHASEFAIL',
                              'There was an error checking purchase state')
            log.error('Check purchase paypal addon: %s, user: %s, paykey: %s'
                      % (addon.pk, request.amo_user.pk, con.paykey[:10]),
                      exc_info=True)
            result = 'ERROR'
            status = 'error'

        log.debug('Paypal returned: %s for paykey: %s'
                  % (result, con.paykey[:10]))
        if result == 'COMPLETED' and con.type == amo.CONTRIB_PENDING:
            con.update(type=amo.CONTRIB_PURCHASE)

    response = jingo.render(request, 'addons/paypal_result.html',
                            {'addon': addon,
                             'realurl': request.GET.get('realurl', ''),
                             # What the client claimed they did.
                             'status': status,
                             # And what paypal thought of that claim.
                             'result': result})
    response['x-frame-options'] = 'allow'
    return response
Example #37
0
def landing(request):
    """Developer Hub landing page."""
    videos = [
        {
            'name': 'airbnb',
            'path': 'FirefoxMarketplace-airbnb-BR-RC-SD1%20640'
        },
        {
            'name': 'evernote',
            'path': 'FirefoxMarketplace-Evernote_BR-RC-SD1%20640'
        },
        {
            'name': 'uken',
            'path': 'FirefoxMarketplace-uken-BR-RC-SD1%20640'
        },
        {
            'name': 'soundcloud',
            'path': 'FirefoxMarketplace-Soundcloud-BR-RC-SD1%20640'
        },
        {
            'name': 'box',
            'path': 'FirefoxMarketplace_box-BR-RC-SD1%20640'
        }
    ]

    form = DevNewsletterForm(request.LANG, request.POST or None)

    if request.method == 'POST' and form.is_valid():
        data = form.cleaned_data

        try:
            basket.subscribe(data['email'],
                             'app-dev',
                             format=data['email_format'],
                             source_url=settings.SITE_URL)
            messages.success(request, _('Thank you for subscribing!'))
            return redirect('ecosystem.landing')
        except basket.BasketException as e:
            log.error(
                'Basket exception in ecosystem newsletter: %s' % e)
            messages.error(
                request, _('We apologize, but an error occurred in our '
                           'system. Please try again later.'))

    return jingo.render(request, 'ecosystem/landing.html',
        {'videos': videos, 'newsletter_form': form})
Example #38
0
def register(request):
    if request.user.is_authenticated():
        messages.info(request, _("You are already logged in to an account."))
        form = None
    elif request.method == 'POST':

        form = forms.UserRegisterForm(request.POST)

        if form.is_valid():
            try:
                u = form.save(commit=False)
                u.set_password(form.cleaned_data['password'])
                u.generate_confirmationcode()
                u.save()
                u.create_django_user()
                log.info(u"Registered new account for user (%s)", u)

                u.email_confirmation_code()

                msg = _('Congratulations! Your user account was successfully '
                        'created.')
                messages.success(request, msg)

                msg = _(('An email has been sent to your address {0} to '
                         'confirm your account. Before you can log in, you '
                         'have to activate your account by clicking on the '
                         'link provided in this email.').format(u.email))
                messages.info(request, _('Confirmation Email Sent'), msg)
            except IntegrityError, e:
                # I was unable to reproduce this, but I suspect it happens
                # when they POST twice quickly and the slaves don't have the
                # new info yet (total guess).  Anyway, I'm assuming the
                # first one worked properly, so this is still a success
                # case to tne end user so we just log it...
                log.error("Failed to register new user (%s): %s" % (u, e))

            amo.utils.clear_messages(request)
            return http.HttpResponseRedirect(reverse('users.login') + '?m=3')
            # TODO POSTREMORA Replace the above two lines
            # when remora goes away with this:
            #return http.HttpResponseRedirect(reverse('users.login'))

        else:
            messages.error(request, _('There are errors in this form'),
                           _('Please correct them and resubmit.'))
Example #39
0
 def save(self, **kw):
     if not self.users_cache:
         log.info("Unknown email used for password reset: {email}".format(
             **self.cleaned_data))
         return
     for user in self.users_cache:
         if user.needs_tougher_password:
             log.info(
                 u'Password reset email sent for privileged user (%s)' %
                 user)
         else:
             log.info(u'Password reset email sent for user (%s)' % user)
     try:
         # Django calls send_mail() directly and has no option to pass
         # in fail_silently, so we have to catch the SMTP error ourselves
         self.base_save(**kw)
     except SMTPException, e:
         log.error("Failed to send mail for (%s): %s" % (user, e))
Example #40
0
 def save(self, **kw):
     for user in self.users_cache:
         log.info(u'Password reset email sent for user (%s)' % user)
         if user.needs_tougher_password:
             log_cef('Password Reset', 5, self.request,
                     username=user,
                     signature='PASSWORDRESET',
                     msg='Privileged user requested password reset')
         else:
             log_cef('Password Reset', 5, self.request,
                     username=user,
                     signature='PASSWORDRESET',
                     msg='User requested password reset')
     try:
         # Django calls send_mail() directly and has no option to pass
         # in fail_silently, so we have to catch the SMTP error ourselves
         super(PasswordResetForm, self).save(**kw)
     except SMTPException, e:
         log.error("Failed to send mail for (%s): %s" % (user, e))
Example #41
0
 def save(self, *args, **kw):
     if not self.version_int and self.version:
         v_int = version_int(self.version)
         # Magic number warning, this is the maximum size
         # of a big int in MySQL to prevent version_int overflow, for
         # people who have rather crazy version numbers.
         # http://dev.mysql.com/doc/refman/5.5/en/numeric-types.html
         if v_int < 9223372036854775807:
             self.version_int = v_int
         else:
             log.error('No version_int written for version %s, %s' %
                       (self.pk, self.version))
     creating = not self.id
     super(Version, self).save(*args, **kw)
     if creating:
         from mkt.webapps.models import AppFeatures
         if self.addon.type == amo.ADDON_WEBAPP:
             AppFeatures.objects.create(version=self)
     return self
Example #42
0
def save_from_email_reply(reply_text):
    parser = CommEmailParser(reply_text)
    uuid = parser.get_uuid()

    if not uuid:
        return False
    try:
        tok = CommunicationThreadToken.objects.get(uuid=uuid)
    except CommunicationThreadToken.DoesNotExist:
        log.error('An email was skipped with non-existing uuid %s' % uuid)
        return False

    if (user_has_perm_thread(tok.thread, tok.user) and tok.is_valid()):
        n = CommunicationNote.objects.create(note_type=comm.NO_ACTION,
            thread=tok.thread, author=tok.user, body=parser.get_body())
        log.info('A new note has been created (from %s using tokenid %s)' %
                 (tok.user.id, uuid))
        return n
    return False
Example #43
0
def get_locale_directory(project, locale):
    """
    Get path to the directory with locale files.

    Args:
        project: Project instance
        locale: Locale instance
    Returns:
        Dict with directory name and path as keys.
    """

    path = get_repository_path_master(project)

    for root, dirnames, filenames in os.walk(path):
        # Ignore hidden folders
        dirnames[:] = [d for d in dirnames if not d[0] == '.']

        for dirname in fnmatch.filter(dirnames, locale.code):
            return {
                'name': dirname,
                'path': os.path.join(root, dirname),
            }

        # Also check for locale variants with underscore, e.g. de_AT
        for dirname in fnmatch.filter(dirnames, locale.code.replace('-', '_')):
            return {
                'name': dirname,
                'path': os.path.join(root, dirname),
            }

    # Projects not using locale directories (.ini, file)
    formats = Resource.objects.filter(project=project).values_list(
        'format', flat=True).distinct()
    if 'ini' in formats or project.repository_type == 'file':
        return {
            'name': '',
            'path': path,
        }

    error = "Directory for locale %s not found." % locale.code
    log.error(error)
    raise Exception(error)
Example #44
0
def get_object_with_related_or_404(klass, *args, **kwargs):
    """
    Uses get() to return an object, or raises a Http404 exception if the object
    does not exist.

    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the get() query.

    Note: Like with get(), an MultipleObjectsReturned will be raised if more
    than one object is found.
    """
    queryset = _get_queryset(klass).select_related()

    try:
        return queryset.get(*args, **kwargs)
    except queryset.model.DoesNotExist:
        pass
    except Exception, err:
        log.error("Getting %s failed (%s)" %
                  (queryset.model._meta.object_name, str(err)))
Example #45
0
def token_request(request):
    try:
        oauth_req = server._create_request(request.build_absolute_uri(),
                                           request.method, request.body,
                                           get_request_headers(request))
        valid, oauth_req = server.validate_request_token_request(oauth_req)
    except ValueError:
        valid = False
    if valid:
        consumer = Access.objects.get(key=oauth_req.client_key)
        t = Token.generate_new(token_type=REQUEST_TOKEN, creds=consumer)
        return HttpResponse(urlencode({
            'oauth_token': t.key,
            'oauth_token_secret': t.secret,
            'oauth_callback_confirmed': True
        }),
                            content_type='application/x-www-form-urlencoded')
    else:
        log.error('Invalid OAuth request for acquiring request token')
        return HttpResponse(status=401)
Example #46
0
    def run_indexing(cls, ids, ES=None, index=None, **kw):
        """Override run_indexing to use app transformers."""
        from mkt.webapps.models import Webapp

        log.info('Indexing %s webapps' % len(ids))

        qs = Webapp.with_deleted.filter(id__in=ids)
        ES = ES or cls.get_es()

        docs = []
        for obj in list(qs):
            try:
                docs.append(cls.extract_document(obj.id, obj=obj))
            except Exception as e:
                log.error(
                    'Failed to index webapp {0}: {1}'.format(obj.id, repr(e)),
                    # Trying to chase down a cache-machine problem.
                    exc_info="marketplace:" in str(e))

        cls.bulk_index(docs, es=ES, index=index or cls.get_index())
Example #47
0
    def is_authenticated(self, request, **kwargs):
        oauth_server, oauth_request = initialize_oauth_server_request(request)

        try:
            auth_header_value = request.META.get('HTTP_AUTHORIZATION')
            key = get_oauth_consumer_key_from_header(auth_header_value)

            if not key:
                return None

            consumer = Access.objects.get(key=key)
            oauth_server.verify_request(oauth_request, consumer, None)
            # Set the current user to be the consumer owner.
            request.user = consumer.user

        except Access.DoesNotExist:
            log.error(u'Cannot find APIAccess token with that key: %s' % key)
            request.user = AnonymousUser()
            return self._error('headers')

        except:
            log.error(u'Error getting OAuth headers', exc_info=True)
            request.user = AnonymousUser()
            return self._error('headers')

        ACLMiddleware().process_request(request)

        # Do not allow access without agreeing to the dev agreement.
        if not request.amo_user.read_dev_agreement:
            log.info(u'Attempt to use API without dev agreement: %s'
                     % request.amo_user.pk)
            return self._error('terms')

        # Do not allow any user with any roles to use the API.
        # Just in case.
        if request.amo_user.groups.all():
            log.info(u'Attempt to use API with roles, user: %s'
                     % request.amo_user.pk)
            return self._error('roles')

        return True
Example #48
0
    def get_manifest_json(self, file_obj=None):
        file_ = file_obj or self.get_latest_file()
        if not file_:
            return

        file_path = file_.file_path
        try:
            if zipfile.is_zipfile(file_path):
                zf = zipfile.ZipFile(file_path)
                data = zf.open('manifest.webapp').read()
                zf.close()
                return json.loads(data)
            else:
                file = storage.open(file_path, 'r')
                data = file.read()
                return json.loads(data)

        except Exception, e:
            log.error(u'[Webapp:%s] Failed to open saved file %r, %s.' %
                      (self, file_path, e))
            raise
Example #49
0
def unhide_disabled_files():
    # Files are getting stuck in /guarded-addons for some reason. This job
    # makes sure guarded add-ons are supposed to be disabled.
    log = logging.getLogger('z.files.disabled')
    q = (Q(version__addon__status=amo.STATUS_DISABLED)
         | Q(version__addon__disabled_by_user=True))
    files = set(File.objects.filter(q | Q(status=amo.STATUS_DISABLED))
                .values_list('version__addon', 'filename'))
    for filepath in walkfiles(settings.GUARDED_ADDONS_PATH):
        addon, filename = filepath.split('/')[-2:]
        if tuple([int(addon), filename]) not in files:
            log.warning('File that should not be guarded: %s.' % filepath)
            try:
                file_ = (File.objects.select_related('version__addon')
                         .get(version__addon=addon, filename=filename))
                file_.unhide_disabled_file()
            except File.DoesNotExist:
                log.warning('File object does not exist for: %s.' % filepath)
            except Exception:
                log.error('Could not unhide file: %s.' % filepath,
                          exc_info=True)
Example #50
0
def process_file(user_email, filename, session_key, **kw):
    sp = subprocess.Popen([
        'ffprobe', '-v', 'quiet', '-print_format', 'json', '-show_format',
        '-show_streams', filename
    ],
                          stdout=subprocess.PIPE)
    data = json.load(sp.stdout)
    ret = sp.wait()
    if ret != 0:
        raise RuntimeError('ffprobe failed')
    artist = data['format']['tags']['artist']
    album = data['format']['tags']['album']
    track = data['format']['tags']['title']
    track_num = data['format']['tags']['track']
    track_num = track_num.split('/')[0]  # 1/30
    try:
        track_num = int(track_num) if track_num else None
    except ValueError, exc:
        log.error('Unable to decipher track number from %r: %s' %
                  (data['format']['tags']['track'], exc))
        track_num = None
Example #51
0
def sign(version_id, reviewer=False):
    version = Version.objects.get(pk=version_id)
    app = version.addon
    log.info('Signing version: %s of app: %s' % (version_id, app))

    if not app.type == amo.ADDON_WEBAPP:
        log.error('Attempt to sign something other than an app.')
        raise SigningError('Not an app')

    if not app.is_packaged:
        log.error('Attempt to sign a non-packaged app.')
        raise SigningError('Not packaged')

    try:
        file_obj = version.all_files[0]
    except IndexError:
        log.error('Attempt to sign an app with no files in version.')
        raise SigningError('No file')

    path = (file_obj.signed_reviewer_file_path
            if reviewer else file_obj.signed_file_path)
    if storage.exists(path):
        log.info('Already signed app exists.')
        return path

    # When we know how to sign, we will sign. For the moment, let's copy.
    with statsd.timer('services.sign.app'):
        sign_app(file_obj.file_path, path)
    log.info('Signing complete.')
    return path
Example #52
0
def pay(request, signed_req, pay_req):
    amount = pay_req['request']['price']
    currency = pay_req['request']['currency']
    source = request.POST.get('source', '')
    product = pay_req['_config'].addon
    # L10n: {0} is the product name. {1} is the application name.
    contrib_for = (
        _(u'Mozilla Marketplace in-app payment for {0} to {1}').format(
            pay_req['request']['name'], product.name))
    uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest()

    paykey, status = '', ''
    preapproval = None
    if request.amo_user:
        preapproval = request.amo_user.get_preapproval()

    try:
        paykey, status = paypal.get_paykey(
            dict(
                amount=amount,
                chains=settings.PAYPAL_CHAINS,
                currency=currency,
                email=product.paypal_id,
                ip=request.META.get('REMOTE_ADDR'),
                memo=contrib_for,
                pattern='inapp_pay.pay_status',
                preapproval=preapproval,
                qs={'realurl': request.POST.get('realurl')},
                slug=pay_req['_config'].
                pk,  # passed to pay_done() via reverse()
                uuid=uuid_))
    except paypal.PaypalError, exc:
        paypal.paypal_log_cef(request, product, uuid_, 'in-app PayKey Failure',
                              'PAYKEYFAIL',
                              'There was an error getting the paykey')
        log.error(u'Error getting paykey, in-app payment: %s' %
                  pay_req['_config'].pk,
                  exc_info=True)
        InappPayLog.log(request, 'PAY_ERROR', config=pay_req['_config'])
        return render_error(request, exc)
Example #53
0
def save_from_email_reply(reply_text):
    parser = CommEmailParser(reply_text)
    if hasattr(parser, 'decode_error'):
        return False

    uuid = parser.get_uuid()

    if not uuid:
        return False
    try:
        tok = CommunicationThreadToken.objects.get(uuid=uuid)
    except CommunicationThreadToken.DoesNotExist:
        log.error('An email was skipped with non-existing uuid %s.' % uuid)
        return False

    if user_has_perm_thread(tok.thread, tok.user) and tok.is_valid():
        t, note = create_comm_note(tok.thread.addon, tok.thread.version,
                                   tok.user, parser.get_body())
        log.info('A new note has been created (from %s using tokenid %s).' %
                 (tok.user.id, uuid))
        return note
    elif tok.is_valid():
        log.error('%s did not have perms to reply to comm email thread %s.' %
                  (tok.user.email, tok.thread.id))
    else:
        log.error('%s tried to use an invalid comm token for thread %s.' %
                  (tok.user.email, tok.thread.id))

    return False
Example #54
0
    def verify_data(self, data):
        client = lib.iarc.client.get_iarc_client('services')
        xml = lib.iarc.utils.render_xml('get_app_info.xml', data)
        resp = client.Get_App_Info(XMLString=xml)
        check_data = lib.iarc.utils.IARC_XML_Parser().parse_string(resp)
        try:
            check_data = check_data.get('rows', [])[0]
        except IndexError:
            return False

        rates_bad = data.get('ratings') != check_data.get('ratings')
        inter_bad = (set(data.get('interactives', [])) != set(
            check_data.get('interactives', [])))
        descs_bad = (set(data.get('descriptors', [])) != set(
            check_data.get('descriptors', [])))
        if rates_bad:
            log.error('IARC pingback did not match rating %s vs %s' %
                      (data.get('ratings'), check_data.get('ratings')))
        if inter_bad:
            log.error(
                'IARC pingback did not match interactives %s vs %s' %
                (data.get('interactives'), check_data.get('interactives')))
        if descs_bad:
            log.error('IARC pingback did not match descriptors %s vs %s' %
                      (data.get('descriptors'), check_data.get('descriptors')))
        if rates_bad or inter_bad or descs_bad:
            return False

        return True
Example #55
0
def token_request(request):
    oa = OAuthServer()
    try:
        valid, oauth_request = oa.verify_request_token_request(
            request.build_absolute_uri(), request.method, request.body, {
                'Authorization': request.META.get('HTTP_AUTHORIZATION'),
                'Content-Type': request.META.get('CONTENT_TYPE')
            })
    except ValueError:
        valid = False
    if valid:
        consumer = Access.objects.get(key=oauth_request.client_key)
        t = Token.generate_new(token_type=REQUEST_TOKEN, creds=consumer)
        return HttpResponse(urlencode({
            'oauth_token': t.key,
            'oauth_token_secret': t.secret,
            'oauth_callback_confirmed': True
        }),
                            content_type='application/x-www-form-urlencoded')
    else:
        log.error('Invalid OAuth request for acquiring request token')
        return HttpResponse(status=401)
Example #56
0
def sign_app(src, dest, ids, reviewer=False):
    """
    Generate a manifest and signature and send signature to signing server to
    be signed.
    """
    active_endpoint = _get_endpoint(reviewer)
    timeout = settings.SIGNED_APPS_SERVER_TIMEOUT

    if not active_endpoint:
        _no_sign(src, dest)
        return

    # Extract necessary info from the archive
    tempname = tempfile.mktemp()
    try:
        jar = JarExtractor(
            storage.open(src, 'r'),
            tempname,
            ids,
            omit_signature_sections=settings.SIGNED_APPS_OMIT_PER_FILE_SIGS)
    except:
        log.error('Archive extraction failed. Bad archive?', exc_info=True)
        raise SigningError('Archive extraction failed. Bad archive?')

    log.info('App signature contents: %s' % jar.signatures)

    log.info('Calling service: %s' % active_endpoint)
    try:
        with statsd.timer('services.sign.app'):
            response = requests.post(
                active_endpoint,
                timeout=timeout,
                files={'file': ('zigbert.sf', str(jar.signatures))})
    except requests.exceptions.HTTPError, error:
        # Will occur when a 3xx or greater code is returned.
        log.error('Posting to app signing failed: %s, %s' %
                  (error.response.status, error))
        raise SigningError('Posting to app signing failed: %s, %s' %
                           (error.response.status, error))
Example #57
0
def process_email(message, **kwargs):
    """Parse emails and save activity log entry."""
    # Some emails (gmail, at least) come with Message-ID instead of MessageId.
    msg_id = message.get('MessageId')
    if not msg_id:
        custom_headers = message.get('CustomHeaders', [])
        for header in custom_headers:
            if header.get('Name') == 'Message-ID':
                msg_id = header.get('Value')
    if not msg_id:
        log.error('No MessageId in message, aborting.')
        log.error(message)
        return
    _, created = ActivityLogEmails.objects.get_or_create(messageid=msg_id)
    if not created:
        log.error('Already processed [%s], skipping' % msg_id)
        log.error(message)
        return
    res = add_email_to_activity_log_wrapper(message)

    if not res:
        log.error('Failed to save email.')
Example #58
0
    def cancel(self, disable_refs=False):
        """Cancels the payment account.

        If `disable_refs` is set, existing apps that use this payment account
        will be set to STATUS_NULL.

        """
        account_refs = AddonPaymentAccount.objects.filter(account_uri=self.uri)
        if self.shared and account_refs:
            # With sharing a payment account comes great responsibility. It
            # would be really mean to create a payment account, share it
            # and have lots of apps use it. Then one day you remove it and
            # make a whole pile of apps in the marketplace get removed from
            # the store, or have in-app payments fail.
            #
            # For the moment I'm just stopping this completely, if this ever
            # happens, we'll have to go through a deprecation phase.
            # - let all the apps that use it know
            # - when they have all stopped sharing it
            # - re-run this
            log.error('Cannot cancel a shared payment account that has '
                      'apps using it.')
            raise CantCancel('You cannot cancel a shared payment account.')

        self.update(inactive=True)
        log.info('Soft-deleted payment account (uri: %s)' % self.uri)

        for acc_ref in account_refs:
            if (disable_refs
                    and not acc_ref.addon.has_multiple_payment_accounts()):
                log.info('Changing app status to NULL for app: {0}'
                         'because of payment account deletion'.format(
                             acc_ref.addon_id))

                acc_ref.addon.update(status=amo.STATUS_NULL)
            log.info('Deleting AddonPaymentAccount for app: {0} because of '
                     'payment account deletion'.format(acc_ref.addon_id))
            acc_ref.delete()
Example #59
0
def reverify(request):
    form = BrowserIDForm(data=request.POST)
    if form.is_valid():
        url = settings.BROWSERID_VERIFICATION_URL
        audience = get_audience(request)
        # TODO: when we want to require a forced-auth login across the
        # entire site then how do we do it?
        # See bug 836060.
        extra_params = {
            'experimental_forceIssuer': settings.BROWSERID_UNVERIFIED_ISSUER,
            # TODO: how do we make sure this is a proper forced
            #       auth assertion?
            # This can also be addressed in bug 836060
            'experimental_forceAuthentication': 'true',
            'experimental_allowUnverified': 'true'
        }

        log.info('Re-verifying Persona assertion. url: %s, audience: %s, '
                 'extra_params: %s' % (url, audience, extra_params))
        result = verify_assertion(form.cleaned_data['assertion'], audience,
                                  extra_params)

        log.info('Reverify got result: %s')
        if result:
            logged_user = request.session.get('uuid')
            email = result.get('unverified-email', result.get('email'))
            reverified_user = get_uuid(email)
            if logged_user and logged_user != reverified_user:
                # TODO: Should we try to support this?
                raise ValueError('A user tried to reverify herself with a '
                                 'new email: %s' % email)

            return {'user_hash': reverified_user}

        log.error('Persona assertion failed.')

    request.session.clear()
    return http.HttpResponseBadRequest()
Example #60
0
def purchase(request, addon):
    log.debug('Starting purchase of addon: %s by user: %s'
              % (addon.pk, request.amo_user.pk))
    amount = addon.premium.get_price()
    source = request.GET.get('source', '')
    uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest()
    # l10n: {0} is the addon name
    contrib_for = _(u'Purchase of {0}').format(jinja2.escape(addon.name))

    paykey, error = '', ''
    try:
        paykey = paypal.get_paykey(dict(uuid=uuid_, slug=addon.slug,
                    amount=amount, memo=contrib_for, email=addon.paypal_id,
                    ip=request.META.get('REMOTE_ADDR'),
                    pattern='addons.purchase.finished',
                    qs={'realurl': request.GET.get('realurl')},
                    ipn=False))
    except:
        log.error('Error getting paykey, purchase of addon: %s' % addon.pk,
                  exc_info=True)
        error = _('There was an error communicating with PayPal.')

    if paykey:
        contrib = Contribution(addon_id=addon.id, amount=amount,
                               source=source, source_locale=request.LANG,
                               uuid=str(uuid_), type=amo.CONTRIB_PENDING,
                               paykey=paykey, user=request.amo_user)
        contrib.save()

    log.debug('Got paykey for addon: %s by user: %s'
              % (addon.pk, request.amo_user.pk))
    url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey)
    if request.GET.get('result_type') == 'json' or request.is_ajax():
        return http.HttpResponse(json.dumps({'url': url,
                                             'paykey': paykey,
                                             'error': error}),
                                 content_type='application/json')
    return http.HttpResponseRedirect(url)