Example #1
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 #2
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 #3
0
def remove_module(request, revision_id):
    """
    Remove module from PackageRevision
    """
    revision = get_object_with_related_or_404(PackageRevision, pk=revision_id)
    if request.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to remove a module from package (%s) "
                   "by non-owner (%s)" % (revision_id, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden('You are not the author of this Package')

    filenames = request.POST.get('filename').split(',')

    revision.add_commit_message('module removed')
    try:
        removed_modules, removed_dirs = revision.modules_remove_by_path(
            filenames)
    except Module.DoesNotExist:
        log_msg = 'Attempt to delete a non existing module(s) %s from %s.' % (
            str(filenames), revision_id)
        log.warning(log_msg)
        return HttpResponseForbidden('There is no such module in %s' %
                                     escape(revision.package.full_name))

    return render_json(
        request, "json/module_removed.json", {
            'revision': revision,
            'removed_modules': simplejson.dumps(removed_modules),
            'removed_dirs': simplejson.dumps(removed_dirs)
        })
Example #4
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 #5
0
def vouchify():
    """Synchronizes LDAP vouch info into database.

    This queries LDAP for users who's corresponding ``UserProfile`` has
    ``is_vouched`` as ``False``.  It then updates ``is_vouched`` and
    ``vouched_by`` with up-to-date data.
    """
    users = UserProfile.objects.filter(is_vouched=False)

    for user in users:
        person = user.get_ldap_person()
        if person and 'mozilliansVouchedBy' in person[1]:
            user.is_vouched = True
            voucher = (person[1]['mozilliansVouchedBy'][0].split(',')[0]
                                                          .split('=')[1])
            by = larper.get_user_by_uid(voucher)
            if by:
                email = by[1]['mail'][0]
                try:
                    user.vouched_by = (User.objects.get(email=email)
                                                   .get_profile())
                except User.DoesNotExist:
                    log.warning('No matching user for %s' % email)
                except UserProfile.DoesNotExist:
                    log.warning('No matching user_profile for %s' % email)
            user.save()
            log.info('Data copied for %s' % user.user.username)
        log.debug('%s is still unvouched... skipping' % user.user.username)
Example #6
0
def add_module(request, revision_id):
    """
    Add new module to the PackageRevision
    """
    revision = get_object_with_related_or_404(PackageRevision, pk=revision_id)
    if request.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to add a module 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')

    mod = Module(
        filename=filename,
        author=request.user,
        code="""// %s.js - %s's module
// author: %s""" %
        (filename, revision.package.full_name, request.user.get_profile()))
    try:
        mod.save()
        revision.module_add(mod)
    except FilenameExistException, err:
        mod.delete()
        return HttpResponseForbidden(escape(str(err)))
Example #7
0
def get_zip(request, hashtag, filename):
    """
    Download zip (it has to be ready)
    """
    if not validator.is_valid('alphanum', hashtag):
        log.warning('[security] Wrong hashtag provided')
        return HttpResponseForbidden("{'error': 'Wrong hashtag'}")
    path = os.path.join(settings.XPI_TARGETDIR, '%s.zip' % hashtag)
    log.info('[zip:%s] Downloading Addon from %s' % (filename, path))

    tend = time.time()
    tkey = _get_zip_cache_key(request, hashtag)
    tqueued = cache.get(tkey)
    if tqueued:
        ttotal = (tend - tqueued) * 1000
        statsd.timing('zip.total', ttotal)
        total = '%dms' % ttotal
    else:
        total = 'n/a'

    log.info('[zip:%s] Downloading Add-on (%s)' % (hashtag, total))

    response = serve(request, path, '/', show_indexes=False)
    response['Content-Disposition'] = ('attachment; '
                                       'filename="%s.zip"' % filename)
    return response
Example #8
0
def _migrate_approvals(items, **kw):
    log.info('[%s@%s] Migrating approval items starting with id: %s' %
             (len(items), _migrate_approvals.rate_limit, items[0]))
    for item in Approval.objects.filter(pk__in=items):
        try:
            args = (item.addon, item.file.version)
        except File.DoesNotExist:
            log.warning("Couldn't find file for approval %d" % item.id)
            continue

        kw = dict(user=item.user, created=item.created,
                  details=dict(comments=item.comments,
                               reviewtype=item.reviewtype,
                               source=item.pk))
        if item.action == amo.STATUS_PUBLIC:
            amo.log(amo.LOG.APPROVE_VERSION, *args, **kw)
        elif item.action == amo.STATUS_LITE:
            amo.log(amo.LOG.PRELIMINARY_VERSION, *args, **kw)
        elif item.action == amo.STATUS_NULL:
            amo.log(amo.LOG.REJECT_VERSION, *args, **kw)
        elif item.action in (amo.STATUS_PENDING, amo.STATUS_NOMINATED):
            amo.log(amo.LOG.ESCALATE_VERSION, *args, **kw)
        elif item.action == amo.STATUS_UNREVIEWED:
            amo.log(amo.LOG.RETAIN_VERSION, *args, **kw)
        else:
            log.warning('Unknown action: %d' % item.action)
Example #9
0
def call_signing(file_obj):
    """Get the jar signature and send it to the signing server to be signed."""
    endpoint = get_endpoint(file_obj)
    if not endpoint:
        log.warning('Not signing: no active endpoint')
        return

    timeout = settings.SIGNING_SERVER_TIMEOUT

    # We only want the (unique) temporary file name.
    with tempfile.NamedTemporaryFile() as temp_file:
        temp_filename = temp_file.name

    # Extract jar signature.
    try:
        jar = JarExtractor(path=storage.open(file_obj.file_path),
                           outpath=temp_filename,
                           omit_signature_sections=True)
    except:
        msg = 'Archive extraction failed. Bad archive?'
        log.error(msg, exc_info=True)
        raise SigningError(msg)

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

    addon_id = file_obj.version.addon.guid

    log.info('Calling signing service: %s' % endpoint)
    try:
        with statsd.timer('services.sign.addon'):
            response = requests.post(endpoint, timeout=timeout,
                                     data={'addon_id': addon_id},
                                     files={'file': ('mozilla.sf',
                                                     str(jar.signatures))})
    except requests.exceptions.HTTPError as error:
        # Will occur when a 3xx or greater code is returned.
        msg = 'Posting to add-on signing failed: %s, %s' % (
            error.response.status, error)
        log.error(msg)
        raise SigningError(msg)
    except:
        # Will occur when some other error occurs.
        msg = 'Posting to add-on signing failed'
        log.error(msg, exc_info=True)
        raise SigningError(msg)
    if response.status_code != 200:
        msg = 'Posting to add-on signing failed: %s' % response.reason
        log.error(msg)
        raise SigningError(msg)

    pkcs7 = b64decode(json.loads(response.content)['mozilla.rsa'])
    try:
        cert_serial_num = get_signature_serial_number(pkcs7)
        jar.make_signed(pkcs7, sigpath='mozilla')
    except:
        msg = 'Addon signing failed'
        log.error(msg, exc_info=True)
        raise SigningError(msg)
    shutil.move(temp_filename, file_obj.file_path)
    return cert_serial_num
Example #10
0
def prepare_zip(request, revision_id):
    """
    Prepare download zip  This package is built asynchronously and we assume
    it works. It will be downloaded in %``get_zip``
    """
    revision = get_object_with_related_or_404(PackageRevision, pk=revision_id)
    if (not revision.package.active
            and request.user != revision.package.author):
        # pretend package doesn't exist as it's private
        raise Http404()
    hashtag = request.POST.get('hashtag')
    if not hashtag:
        return HttpResponseForbidden(
            'Add-on Builder has been updated!'
            'We have updated this part of the application. Please '
            'empty your cache and reload to get changes.')
    if not validator.is_valid('alphanum', hashtag):
        log.warning('[security] Wrong hashtag provided')
        return HttpResponseBadRequest("{'error': 'Wrong hashtag'}")
    log.info('[zip:%s] Addon added to queue' % hashtag)
    # caching
    tqueued = time.time()
    tkey = _get_zip_cache_key(request, hashtag)
    cache.set(tkey, tqueued, 120)
    # create zip file
    zip_source(pk=revision.pk, hashtag=hashtag, tqueued=tqueued)
    return HttpResponse('{"delayed": true}')
Example #11
0
def browserid_login(request):
    """Multi-mode BrowserID authentication form processor.

    Handles login and register browserid verification. If
    the mode is login, we are done. If the mode is register
    then we start new profile flow. Also handles corner cases.

    Login and register sasl-browserid verification steps are very similar
    and the corner cases blur the lines, so this is best as one
    url.

    We use the form from django-browserid, but since the LDAP server
    does the BrowserID auth behind the scenes, we don't use it's auth code
    nor it's views.
    """
    form = ModalBrowserIdForm(data=request.POST)
    if form.is_valid():
        assertion = form.cleaned_data['assertion']
        store_assertion(request, assertion)
        mode = form.cleaned_data['mode']
        user = auth.authenticate(request=request, assertion=assertion)
        if user:
            auth.login(request, user)
            return redirect('profile', request.user.unique_id)
        else:
            url = absolutify("%s?link=%s" % (reverse('register'), mode))
            return redirect(url)
    else:
        msg = _('Sorry, but there were problems with the info you submitted. '
                'Please review the form, correct any errors, and try again.')
        messages.warning(request, msg)
        log.warning("Form didn't validate %s" % str(request.POST))
        return redirect('home')
Example #12
0
def vouchify():
    """Synchronizes LDAP vouch info into database.

    This queries LDAP for users who's corresponding ``UserProfile`` has
    ``is_vouched`` as ``False``.  It then updates ``is_vouched`` and
    ``vouched_by`` with up-to-date data.
    """
    users = UserProfile.objects.filter(is_vouched=False)

    for user in users:
        person = user.get_ldap_person()
        if person and 'mozilliansVouchedBy' in person[1]:
            user.is_vouched = True
            voucher = (person[1]['mozilliansVouchedBy'][0].split(',')[0].split(
                '=')[1])
            by = larper.get_user_by_uid(voucher)
            if by:
                email = by[1]['mail'][0]
                try:
                    user.vouched_by = (User.objects.get(
                        email=email).get_profile())
                except User.DoesNotExist:
                    log.warning('No matching user for %s' % email)
                except UserProfile.DoesNotExist:
                    log.warning('No matching user_profile for %s' % email)
            user.save()
            log.info('Data copied for %s' % user.user.username)
        log.debug('%s is still unvouched... skipping' % user.user.username)
Example #13
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(
                self.serializer_class(sq.execute().hits,
                                      many=True,
                                      context={
                                          'request': self.request
                                      }).data)
Example #14
0
def rename_attachment(request, revision_id):
    """
    Rename an attachment in a PackageRevision
    """
    revision = get_object_with_related_or_404(PackageRevision, pk=revision_id)
    if request.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to rename attachment in revision (%s) "
                   "by non-owner (%s)" % (revision_id, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden('You are not the author of this Package')

    uid = request.POST.get('uid', '').strip()
    try:
        attachment = revision.attachments.get(pk=uid)
    except:
        log_msg = ('Attempt to rename a non existing attachment. attachment: '
                   '%s, revision: %s.' % (uid, revision))
        log.warning(log_msg)
        return HttpResponseForbidden('There is no such attachment in %s' %
                                     escape(revision.package.full_name))

    new_name = request.POST.get('new_filename')
    new_ext = request.POST.get('new_ext') or attachment.ext

    if not revision.validate_attachment_filename(new_name, new_ext):
        return HttpResponseForbidden(
            ('Sorry, there is already an attachment in your add-on '
             'with the name "%s.%s". Each attachment in your add-on '
             'needs to have a unique name.') % (new_name, attachment.ext))
    attachment.filename = new_name
    attachment.ext = new_ext
    try:
        attachment = revision.update(attachment)
    except ValidationError, err:
        return HttpResponseForbidden(str(err))
Example #15
0
def emailchange(request, user, token, hash):
    try:
        _uid, newemail = EmailResetCode.parse(token, hash)
    except ValueError:
        return http.HttpResponse(status=400)

    if _uid != user.id:
        # I'm calling this a warning because invalid hashes up to this point
        # could be any number of things, but this is a targeted attack from
        # one user account to another
        log.warning((u"[Tampering] Valid email reset code for UID (%s) "
                     u"attempted to change email address for user (%s)") %
                    (_uid, user))
        return http.HttpResponse(status=400)

    if UserProfile.objects.filter(email=newemail).exists():
        log.warning((u"[Tampering] User (%s) tries to change his email to "
                     u"an existing account with the same email address (%s)") %
                    (user, newemail))
        return http.HttpResponse(status=400)

    user.email = newemail
    user.save()

    l = {'user': user, 'newemail': newemail}
    log.info(u"User (%(user)s) confirmed new email address (%(newemail)s)" % l)
    messages.success(
        request, _('Your email address was changed successfully'),
        _(u'From now on, please use {0} to log in.').format(newemail))

    return http.HttpResponseRedirect(reverse('users.edit'))
Example #16
0
def remove_attachment(request, revision_id):
    """
    Remove attachment from PackageRevision
    """
    revision = get_object_with_related_or_404(PackageRevision, pk=revision_id)
    if request.user.pk != revision.author.pk:
        log_msg = ('[security] Attempt to remove attachment from revision '
                   '(%s) by non-owner (%s)' % (revision_id, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden('You are not the author of this Package')

    uid = request.POST.get('uid', '').strip()
    attachment = get_object_with_related_or_404(Attachment,
                                                pk=uid,
                                                revisions=revision)

    if not attachment:
        log_msg = ('Attempt to remove a non existing attachment. attachment: '
                   '%s, revision: %s.' % (uid, revision_id))
        log.warning(log_msg)
        return HttpResponseForbidden('There is no such attachment in %s' %
                                     escape(revision.package.full_name))

    revision.attachment_remove(attachment)

    return render_json(request, "json/attachment_removed.json", {
        'revision': revision,
        'attachment': attachment
    })
Example #17
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 #18
0
def add_module(request, revision_id):
    """
    Add new module to the PackageRevision
    """
    revision = get_object_with_related_or_404(PackageRevision, pk=revision_id)
    if request.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to add a module 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')

    mod = Module(
        filename=filename,
        author=request.user,
        code="""// %s.js - %s's module
// author: %s""" % (filename, revision.package.full_name,
            request.user.get_profile())
    )
    try:
        mod.save()
        revision.module_add(mod)
    except FilenameExistException, err:
        mod.delete()
        return HttpResponseForbidden(escape(str(err)))
Example #19
0
def remove_module(request, revision_id):
    """
    Remove module from PackageRevision
    """
    revision = get_object_with_related_or_404(PackageRevision, pk=revision_id)
    if request.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to remove a module from package (%s) "
                "by non-owner (%s)" % (revision_id, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden('You are not the author of this Package')

    filenames = request.POST.get('filename').split(',')

    revision.add_commit_message('module removed')
    try:
        removed_modules, removed_dirs = revision.modules_remove_by_path(
                filenames)
    except Module.DoesNotExist:
        log_msg = 'Attempt to delete a non existing module(s) %s from %s.' % (
            str(filenames), revision_id)
        log.warning(log_msg)
        return HttpResponseForbidden(
            'There is no such module in %s' % escape(
                revision.package.full_name))

    return render_json(request,
            "json/module_removed.json",
            {'revision': revision,
            'removed_modules': simplejson.dumps(removed_modules),
            'removed_dirs': simplejson.dumps(removed_dirs)})
Example #20
0
def register(request):
    if request.user.is_authenticated():
        return redirect(reverse('profile', args=[request.user.unique_id]))

    initial = {}
    if 'code' in request.GET:
        code = request.GET['code']
        try:
            invite = get_invite(code)
            initial['email'] = invite.recipient
            initial['code'] = invite.code
        except Invite.DoesNotExist:
            log.warning('Bad register code [%s], skipping invite' % code)

    form = forms.RegistrationForm(request.POST or None, initial=initial)

    if request.method == 'POST':
        if form.is_valid():
            try:
                _save_new_user(request, form)
                _send_confirmation_email(request.user)

                msg = _(u'Your account has been created but needs to be '
                         'verified. Please check your email to verify '
                         'your account.')
                messages.info(request, msg)
                auth.logout(request)

                return redirect(reverse('login'))
            except ldap.CONSTRAINT_VIOLATION:
                _set_already_exists_error(form)
    return render(request, 'registration/register.html', dict(form=form))
Example #21
0
 def clean(self):
     amouser = self.request.user.get_profile()
     if amouser.is_developer:
         # This is tampering because the form isn't shown on the page if the
         # user is a developer
         log.warning(u"[Tampering] Attempt to delete developer account (%s)" % self.request.user)
         raise forms.ValidationError("")
Example #22
0
def upload(request):
    """Video upload page."""
    if request.method == 'POST':
        form = UploadForm(request.POST)
        if form.is_valid():
            video = form.save(commit=False)
            video.user = request.user
            video.save()

            # Celery times out sometimes; we'll catch orphaned
            # videos with a cron job.
            try:
                send_video_to_vidly.delay(video)
            except socket.timeout:
                log.warning('Timeout connecting to celery to convert video '
                            'id: %s' % video.id)

            # Update statsd graph for uploads
            statsd.incr('video_uploads')

            return render(request, 'videos/upload_complete.html')
    else:
        form = UploadForm()

    d = dict(upload_form=form,
             page_type='secondary form')

    return render(request, 'videos/upload.html', d)
Example #23
0
    def get_profile(self):
        """Retrieve the Django UserProfile for this Person.

        This is full of hacks because all the Mozillians servers are throwing
        ObjectDoesNotExist errors (even in production) if we try a straight-up
        `User.objects.get(email=self.username)`. This method now exhaustively
        tries to get a User object from the database. If it doesn't find one,
        or finds one without a UserProfile, we make one on the spot, trying
        our best to fill things in sanely. FML.

        See: https://bugzilla.mozilla.org/show_bug.cgi?id=698699

        TODO: Remove this as soon as possible. It's insane.
        """
        user = (User.objects.filter(Q(email=self.username) | Q(username=self.username)))[:1]

        if user:
            # Yes, sometimes the User exists but the UserProfile doesn't.
            # See: https://bugzilla.mozilla.org/show_bug.cgi?id=699234
            try:
                profile = user[0].get_profile()
            except ObjectDoesNotExist, e:
                statsd.incr("user.errors.profile_doesnotexist")
                log.warning(e)

                profile = UserProfile.objects.create(user=user[0])
Example #24
0
def prepare_test(r, id_number, revision_number=None):
    """
    Test XPI from data saved in the database
    """
    revision = get_object_with_related_or_404(PackageRevision,
                        package__id_number=id_number, package__type='a',
                        revision_number=revision_number)
    hashtag = r.POST.get('hashtag')
    if not hashtag:
        log.warning('[security] No hashtag provided')
        return HttpResponseForbidden('{"error": "No hashtag"}')
    if not validator.is_valid('alphanum', hashtag):
        log.warning('[security] Wrong hashtag provided')
        return HttpResponseForbidden("{'error': 'Wrong hashtag'}")
    # prepare codes to be sent to the task
    mod_codes = {}
    att_codes = {}
    if r.POST.get('live_data_testing', False):
        for mod in revision.modules.all():
            if r.POST.get(mod.filename, False):
                code = r.POST.get(mod.filename, '')
                if mod.code != code:
                    mod_codes[str(mod.pk)] = code
        for att in revision.attachments.all():
            if r.POST.get(str(att.pk), False):
                code = r.POST.get(str(att.pk))
                att_codes[str(att.pk)] = code
    tasks.xpi_build_from_model.delay(revision.pk,
            mod_codes=mod_codes, att_codes=att_codes, hashtag=hashtag)
    return HttpResponse('{"delayed": true}')
Example #25
0
def prepare_test(r, id_number, revision_number=None):
    """
    Test XPI from data saved in the database
    """
    revision = get_object_with_related_or_404(
        PackageRevision, package__id_number=id_number, package__type="a", revision_number=revision_number
    )
    hashtag = r.POST.get("hashtag")
    if not hashtag:
        log.warning("[security] No hashtag provided")
        return HttpResponseForbidden('{"error": "No hashtag"}')
    if not validator.is_valid("alphanum", hashtag):
        log.warning("[security] Wrong hashtag provided")
        return HttpResponseForbidden("{'error': 'Wrong hashtag'}")
    if r.POST.get("live_data_testing", False):
        modules = []
        for mod in revision.modules.all():
            if r.POST.get(mod.filename, False):
                code = r.POST.get(mod.filename, "")
                if mod.code != code:
                    mod.code = code
                    modules.append(mod)
        attachments = []
        for att in revision.attachments.all():
            if r.POST.get(str(att.pk), False):
                code = r.POST.get(str(att.pk))
                att.code = code
                attachments.append(att)
        response, rm_xpi_url = revision.build_xpi(modules, attachments, hashtag=hashtag)
    else:
        response, rm_xpi_url = revision.build_xpi(hashtag=hashtag)
    return HttpResponse('{"delayed": true, "rm_xpi_url": "%s"}' % rm_xpi_url)
Example #26
0
    def get_profile(self):
        """Retrieve the Django UserProfile for this Person.

        This is full of hacks because all the Mozillians servers are throwing
        ObjectDoesNotExist errors (even in production) if we try a straight-up
        `User.objects.get(email=self.username)`. This method now exhaustively
        tries to get a User object from the database. If it doesn't find one,
        or finds one without a UserProfile, we make one on the spot, trying
        our best to fill things in sanely. FML.

        See: https://bugzilla.mozilla.org/show_bug.cgi?id=698699

        TODO: Remove this as soon as possible. It's insane.
        """
        user = (User.objects.filter(
            Q(email=self.username) | Q(username=self.username)))[:1]

        if user:
            # Yes, sometimes the User exists but the UserProfile doesn't.
            # See: https://bugzilla.mozilla.org/show_bug.cgi?id=699234
            try:
                profile = user[0].get_profile()
            except ObjectDoesNotExist, e:
                statsd.incr('user.errors.profile_doesnotexist')
                log.warning(e)

                profile = UserProfile.objects.create(user=user[0])
Example #27
0
def browserid_login(request):
    """Multi-mode BrowserID authentication form processor.

    Handles login and register browserid verification. If
    the mode is login, we are done. If the mode is register
    then we start new profile flow. Also handles corner cases.

    Login and register sasl-browserid verification steps are very similar
    and the corner cases blur the lines, so this is best as one
    url.

    We use the form from django-browserid, but since the LDAP server
    does the BrowserID auth behind the scenes, we don't use it's auth code
    nor it's views.
    """
    form = ModalBrowserIdForm(data=request.POST)
    if form.is_valid():
        assertion = form.cleaned_data['assertion']
        store_assertion(request, assertion)
        mode = form.cleaned_data['mode']
        user = auth.authenticate(request=request, assertion=assertion)
        if user:
            auth.login(request, user)
            return redirect('profile', request.user.unique_id)
        else:
            url = absolutify("%s?link=%s" % (reverse('register'), mode))
            return redirect(url)
    else:
        msg = _('Sorry, but there were problems with the info you submitted. '
                'Please review the form, correct any errors, and try again.')
        messages.warning(request, msg)
        log.warning("Form didn't validate %s" % str(request.POST))
        return redirect('home')
Example #28
0
def emailchange(request, user_id, token, hash):
    user = get_object_or_404(UserProfile, id=user_id)

    try:
        _uid, newemail = EmailResetCode.parse(token, hash)
    except ValueError:
        return http.HttpResponse(status=400)

    if _uid != user.id:
        # I'm calling this a warning because invalid hashes up to this point
        # could be any number of things, but this is a targeted attack from
        # one user account to another
        log.warning((u"[Tampering] Valid email reset code for UID (%s) "
                     "attempted to change email address for user (%s)")
                                                        % (_uid, user))
        return http.HttpResponse(status=400)

    user.email = newemail
    user.save()

    l = {'user': user, 'newemail': newemail}
    log.info(u"User (%(user)s) confirmed new email address (%(newemail)s)" % l)
    messages.success(request, _('Your email address was changed successfully'),
            _(u'From now on, please use {0} to log in.').format(newemail))

    return http.HttpResponseRedirect(reverse('users.edit'))
Example #29
0
def upvote(request, video_shortlink):
    """Add an upvote to a video."""
    response = HttpResponse(mimetype='application/json')
    if video_shortlink in request.COOKIES:
        response.status_code = 403
        response.content = json.dumps({'error': 'already voted'})
        return response

    video = get_object_or_none(Video, shortlink=video_shortlink)
    if video is not None:
        try:
            video.upvote()
        except socket.timeout:
            log.warning('Timeout connecting to celery to upvote video '
                        'shortlink: %s' % video_shortlink)
            response.status_code = 500
            response.content = json.dumps({'error': 'celery timeout'})
        else:
            response.set_cookie(str(video_shortlink), value='1',
                                httponly=False,
                                max_age=settings.VOTE_COOKIE_AGE)
            response.content = json.dumps({'success': 'success'})
    else:
        response.status_code = 404
        response.content = json.dumps({'error': 'video not found'})

    return response
Example #30
0
def prepare_test(r, revision_id):
    """
    Test XPI from data saved in the database
    """
    revision = _get_addon(r.user, revision_id)
    hashtag = r.POST.get('hashtag')
    if not hashtag:
        log.warning('[security] No hashtag provided')
        return HttpResponseBadRequest('{"error": "No hashtag"}')
    if not validator.is_valid('alphanum', hashtag):
        log.warning('[security] Wrong hashtag provided')
        return HttpResponseBadRequest("{'error': 'Wrong hashtag'}")
    # prepare codes to be sent to the task
    mod_codes = {}
    att_codes = {}
    if r.POST.get('live_data_testing', False):
        for mod in revision.modules.all():
            if r.POST.get(mod.filename, False):
                code = r.POST.get(mod.filename, '')
                if mod.code != code:
                    mod_codes[str(mod.pk)] = code
        for att in revision.attachments.all():
            if r.POST.get(str(att.pk), False):
                code = r.POST.get(str(att.pk))
                att_codes[str(att.pk)] = code
    if mod_codes or att_codes or not os.path.exists('%s.xpi' %
            os.path.join(settings.XPI_TARGETDIR, hashtag)):
        log.info('[xpi:%s] Addon added to queue' % hashtag)
        tqueued = time.time()
        tkey = xpi_utils.get_queued_cache_key(hashtag, r)
        cache.set(tkey, tqueued, 120)
        tasks.xpi_build_task(rev_pk=revision.pk,
                mod_codes=mod_codes, att_codes=att_codes,
                hashtag=hashtag, tqueued=tqueued)
    return HttpResponse('{"delayed": true}')
Example #31
0
    def to_string(self, type_=None):
        log_type = amo.LOG_BY_ID[self.action]
        if type_ and hasattr(log_type, '%s_format' % type_):
            format = getattr(log_type, '%s_format' % type_)
        else:
            format = log_type.format

        # We need to copy arguments so we can remove elements from it
        # while we loop over self.arguments.
        arguments = copy(self.arguments)
        addon = None
        review = None
        version = None
        collection = None
        tag = None
        group = None

        for arg in self.arguments:
            if isinstance(arg, Addon) and not addon:
                if arg.is_listed:
                    addon = self.f(u'<a href="{0}">{1}</a>',
                                   arg.get_url_path(), arg.name)
                else:
                    addon = self.f(u'{0}', arg.name)
                arguments.remove(arg)
            if isinstance(arg, Review) and not review:
                review = self.f(u'<a href="{0}">{1}</a>',
                                arg.get_url_path(), _('Review'))
                arguments.remove(arg)
            if isinstance(arg, Version) and not version:
                text = _('Version {0}')
                if arg.is_listed:
                    version = self.f(u'<a href="{1}">%s</a>' % text,
                                     arg.version, arg.get_url_path())
                else:
                    version = self.f(text, arg.version)
                arguments.remove(arg)
            if isinstance(arg, Collection) and not collection:
                collection = self.f(u'<a href="{0}">{1}</a>',
                                    arg.get_url_path(), arg.name)
                arguments.remove(arg)
            if isinstance(arg, Tag) and not tag:
                if arg.can_reverse():
                    tag = self.f(u'<a href="{0}">{1}</a>',
                                 arg.get_url_path(), arg.tag_text)
                else:
                    tag = self.f('{0}', arg.tag_text)
            if isinstance(arg, Group) and not group:
                group = arg.name
                arguments.remove(arg)

        user = user_link(self.user)

        try:
            kw = dict(addon=addon, review=review, version=version,
                      collection=collection, tag=tag, user=user, group=group)
            return self.f(format, *arguments, **kw)
        except (AttributeError, KeyError, IndexError):
            log.warning('%d contains garbage data' % (self.id or 0))
            return 'Something magical happened.'
Example #32
0
def package_remove_attachment(r, id_number, type_id, revision_number):
    """
    Remove attachment from PackageRevision
    """
    revision = get_package_revision(id_number, type_id, revision_number)
    if r.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to remove attachment from package (%s) "
                "by non-owner (%s)" % (id_number, r.user))
        log.warning(log_msg)
        return HttpResponseForbidden('You are not the author of this Package')

    uid = r.POST.get('uid', '').strip()
    attachment = get_object_with_related_or_404(Attachment,
                                                pk=uid, revisions=revision)

    if not attachment:
        log_msg = ('Attempt to remove a non existing attachment. attachment: '
                   '%s, package: %s.' % (uid, id_number))
        log.warning(log_msg)
        return HttpResponseForbidden(
            'There is no such attachment in %s' % escape(
                revision.package.full_name))

    revision.attachment_remove(attachment)

    return render_to_response("json/attachment_removed.json",
                {'revision': revision, 'attachment': attachment},
                context_instance=RequestContext(r),
                mimetype='application/json')
Example #33
0
def package_add_module(r, id_number, type_id,
                       revision_number=None, version_name=None):
    """
    Add new module 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 add a module 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()))

    filename = pathify(r.POST.get('filename'))

    mod = Module(
        filename=filename,
        author=r.user,
        code="""// %s.js - %s's module
// author: %s""" % (filename, revision.package.full_name, r.user.get_profile())
    )
    try:
        mod.save()
        revision.module_add(mod)
    except FilenameExistException, err:
        mod.delete()
        return HttpResponseForbidden(escape(str(err)))
Example #34
0
def package_remove_module(r, id_number, type_id, revision_number):
    """
    Remove module from PackageRevision
    """
    revision = get_package_revision(id_number, type_id, revision_number)
    if r.user.pk != revision.author.pk:
        log_msg = ("[security] Attempt to remove a module from package (%s) "
                "by non-owner (%s)" % (id_number, r.user))
        log.warning(log_msg)
        return HttpResponseForbidden('You are not the author of this Package')

    filenames = r.POST.get('filename').split(',')

    revision.add_commit_message('module removed')
    try:
        removed_modules, removed_dirs = revision.modules_remove_by_path(
                filenames)
    except Module.DoesNotExist:
        log_msg = 'Attempt to delete a non existing module(s) %s from %s.' % (
            str(filenames), id_number)
        log.warning(log_msg)
        return HttpResponseForbidden(
            'There is no such module in %s' % escape(
                revision.package.full_name))

    return render_to_response("json/module_removed.json",
                {'revision': revision,
                'removed_modules': simplejson.dumps(removed_modules),
                'removed_dirs': simplejson.dumps(removed_dirs)},
                context_instance=RequestContext(r),
                mimetype='application/json')
Example #35
0
def prepare_zip(request, revision_id):
    """
    Prepare download zip  This package is built asynchronously and we assume
    it works. It will be downloaded in %``get_zip``
    """
    revision = get_object_with_related_or_404(PackageRevision, pk=revision_id)
    if not revision.package.active and request.user != revision.package.author:
        # pretend package doesn't exist as it's private
        raise Http404()
    hashtag = request.POST.get("hashtag")
    if not hashtag:
        return HttpResponseForbidden(
            "Add-on Builder has been updated!"
            "We have updated this part of the application. Please "
            "empty your cache and reload to get changes."
        )
    if not validator.is_valid("alphanum", hashtag):
        log.warning("[security] Wrong hashtag provided")
        return HttpResponseBadRequest("{'error': 'Wrong hashtag'}")
    log.info("[zip:%s] Addon added to queue" % hashtag)
    # caching
    tqueued = time.time()
    tkey = _get_zip_cache_key(request, hashtag)
    cache.set(tkey, tqueued, 120)
    # create zip file
    zip_source(pk=revision.pk, hashtag=hashtag, tqueued=tqueued)
    return HttpResponse('{"delayed": true}')
Example #36
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 #37
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 #38
0
def remove_attachment(request, revision_id):
    """
    Remove attachment from PackageRevision
    """
    revision = get_object_with_related_or_404(PackageRevision, pk=revision_id)
    if request.user.pk != revision.author.pk:
        log_msg = ('[security] Attempt to remove attachment from revision '
                '(%s) by non-owner (%s)' % (revision_id, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden('You are not the author of this Package')

    uid = request.POST.get('uid', '').strip()
    attachment = get_object_with_related_or_404(Attachment,
                                                pk=uid, revisions=revision)

    if not attachment:
        log_msg = ('Attempt to remove a non existing attachment. attachment: '
                   '%s, revision: %s.' % (uid, revision_id))
        log.warning(log_msg)
        return HttpResponseForbidden(
            'There is no such attachment in %s' % escape(
                revision.package.full_name))

    revision.attachment_remove(attachment)

    return render_json(request,
            "json/attachment_removed.json",
            {'revision': revision, 'attachment': attachment})
Example #39
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
 def add_email_to_group(cls, email, group_id):
     constituent_id = BSDClient.register_email_address_as_constituent(email)
     result = BSDClient.add_constituent_id_to_group(constituent_id,
                                                    group_id)
     if not result:
         log.warning('Failed to add email to group')
     return result
Example #41
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 #42
0
def get_download(r, hashtag, filename):
    """
    Download XPI (it has to be ready)
    """
    if not validator.is_valid('alphanum', hashtag):
        log.warning('[security] Wrong hashtag provided')
        return HttpResponseForbidden("{'error': 'Wrong hashtag'}")
    path = os.path.join(settings.XPI_TARGETDIR, '%s.xpi' % hashtag)
    log.info('[xpi:%s] Downloading Addon from %s' % (filename, path))

    tend = time.time()
    tkey = xpi_utils.get_queued_cache_key(hashtag, r)
    tqueued = cache.get(tkey)
    if tqueued:
        ttotal = (tend - tqueued) * 1000
        statsd.timing('xpi.build.total', ttotal)
        total = '%dms' % ttotal
    else:
        total = 'n/a'

    log.info('[xpi:%s] Downloading Add-on (%s)' % (hashtag, total))

    response = serve(r, path, '/', show_indexes=False)
    response['Content-Disposition'] = ('attachment; '
            'filename="%s.xpi"' % filename)
    return response
Example #43
0
def get_zip(request, hashtag, filename):
    """
    Download zip (it has to be ready)
    """
    if not validator.is_valid("alphanum", hashtag):
        log.warning("[security] Wrong hashtag provided")
        return HttpResponseForbidden("{'error': 'Wrong hashtag'}")
    path = os.path.join(settings.XPI_TARGETDIR, "%s.zip" % hashtag)
    log.info("[zip:%s] Downloading Addon from %s" % (filename, path))

    tend = time.time()
    tkey = _get_zip_cache_key(request, hashtag)
    tqueued = cache.get(tkey)
    if tqueued:
        ttotal = (tend - tqueued) * 1000
        statsd.timing("zip.total", ttotal)
        total = "%dms" % ttotal
    else:
        total = "n/a"

    log.info("[zip:%s] Downloading Add-on (%s)" % (hashtag, total))

    response = serve(request, path, "/", show_indexes=False)
    response["Content-Disposition"] = "attachment; " 'filename="%s.zip"' % filename
    return response
Example #44
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 #45
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 #46
0
    def to_string(self, type_=None):
        log_type = amo.LOG_BY_ID[self.action]
        if type_ and hasattr(log_type, '%s_format' % type_):
            format = getattr(log_type, '%s_format' % type_)
        else:
            format = log_type.format

        # We need to copy arguments so we can remove elements from it
        # while we loop over self.arguments.
        arguments = copy(self.arguments)
        addon = None
        review = None
        version = None
        collection = None
        tag = None
        group = None

        for arg in self.arguments:
            if isinstance(arg, Addon) and not addon:
                addon = self.f(u'<a href="{0}">{1}</a>', arg.get_url_path(),
                               arg.name)
                arguments.remove(arg)
            if isinstance(arg, Review) and not review:
                review = self.f(u'<a href="{0}">{1}</a>', arg.get_url_path(),
                                _('Review'))
                arguments.remove(arg)
            if isinstance(arg, Version) and not version:
                text = _('Version {0}')
                version = self.f(u'<a href="{1}">%s</a>' % text, arg.version,
                                 arg.get_url_path())
                arguments.remove(arg)
            if isinstance(arg, Collection) and not collection:
                collection = self.f(u'<a href="{0}">{1}</a>',
                                    arg.get_url_path(), arg.name)
                arguments.remove(arg)
            if isinstance(arg, Tag) and not tag:
                if arg.can_reverse():
                    tag = self.f(u'<a href="{0}">{1}</a>', arg.get_url_path(),
                                 arg.tag_text)
                else:
                    tag = self.f('{0}', arg.tag_text)
            if isinstance(arg, Group) and not group:
                group = arg.name
                arguments.remove(arg)

        user = user_link(self.user)

        try:
            kw = dict(addon=addon,
                      review=review,
                      version=version,
                      collection=collection,
                      tag=tag,
                      user=user,
                      group=group)
            return self.f(format, *arguments, **kw)
        except (AttributeError, KeyError, IndexError):
            log.warning('%d contains garbage data' % (self.id or 0))
            return 'Something magical happened.'
Example #47
0
 def clean(self):
     amouser = self.request.user.get_profile()
     if amouser.is_developer:
         # This is tampering because the form isn't shown on the page if the
         # user is a developer
         log.warning(u'[Tampering] Attempt to delete developer account (%s)'
                                                       % self.request.user)
         raise forms.ValidationError("")
Example #48
0
def clean(r, path):
    " remove whole temporary SDK on request "
    # Validate sdk_name
    if not validator.is_valid('alphanum', path):
        log.warning('[security] Wrong hashtag provided')
        return HttpResponseForbidden("{'error': 'Wrong hashtag'}")
    xpi_utils.remove(os.path.join(settings.XPI_TARGETDIR, '%s.xpi' % path))
    return HttpResponse('{"success": true}', mimetype='application/json')
Example #49
0
def register(request):
    """Multi-purpose registration view.

    Uses: legacy email url with invite code, first time edit profile
    after browserid_login. Process POST and create new users.
    """
    # Legacy URL shenanigans - A GET to register with invite code
    # is a legal way to start the BrowserID registration flow.
    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.unique_id]))

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

    email = request.session['verified_email']

    intent = 'register'

    # Check for optional invite code
    initial = {}
    if 'invite-code' in request.session:
        code = request.session['invite-code']
        try:
            invite = get_invite(code)
            initial['email'] = invite.recipient
            initial['code'] = invite.code
        except Invite.DoesNotExist:
            log.warning('Bad register code [%s], skipping invite' % code)

    form = forms.RegistrationForm(request.POST or None, initial=initial)

    if request.method == 'POST':
        if form.is_valid():
            try:
                uniq_id = _save_new_user(request, form)
                messages.info(request, _(u'Your account has been created.'))
                return redirect('profile', uniq_id)
            except ldap.CONSTRAINT_VIOLATION:
                log.error("User already exists")
                _set_already_exists_error(form)
    else:
        if 'link' in request.GET:
            intent = request.GET['link']
    anonymous = Anonymous()

    return render(
        request, 'phonebook/edit_profile.html',
        dict(form=form,
             edit_form_action=reverse('register'),
             person=anonymous,
             mode='new',
             email=email,
             intent=intent))
Example #50
0
def monitor(request):
    status = True
    data = {}

    # Check Read/Write
    filepaths = [
        (settings.UPLOAD_DIR, os.R_OK | os.W_OK, 'We want read + write.'),
    ]

    if hasattr(settings, 'XPI_TARGETDIR'):
        filepaths.append((settings.XPI_TARGETDIR, os.R_OK | os.W_OK,
                          'We want read + write. Should be a shared directory '
                          'on multiserver installations'))

    for sdk in SDK.objects.all():
        filepaths.append((sdk.get_source_dir(), os.R_OK,
                          'We want read on %s' % sdk.version), )

    filepath_results = []
    filepath_status = True

    for path, perms, notes in filepaths:
        path_exists = os.path.isdir(path)
        path_perms = os.access(path, perms)
        filepath_status = filepath_status and path_exists and path_perms
        if not filepath_status and status:
            status = False
        filepath_results.append((path, path_exists, path_perms, notes))

    # free space on XPI_TARGETDIR disk
    x_path = '%s/' % settings.XPI_TARGETDIR
    s_path = '%s/' % settings.SDKDIR_PREFIX
    x = os.statvfs(x_path)
    s = os.statvfs(s_path)
    data['free'] = [('xpi_targetdir %s' % x_path, x.f_bavail * x.f_frsize),
                    ('sdkdir_prefix %s' % s_path, s.f_bavail * s.f_frsize)]

    data['filepaths'] = filepath_results

    # Check celery
    try:
        data['celery_responses'] = CeleryResponse.objects.all()
    except:
        status = False

    # Check ElasticSearch
    try:
        es = get_es()
        data['es_health'] = es.cluster_health()
        data['es_health']['version'] = es.collect_info(
        )['server']['version']['number']
        if data['es_health']['status'] == 'red':
            status = False
            log.warning('ElasticSearch cluster health was red.')
    except Exception, e:
        status = False
        log.critical('Failed to connect to ElasticSearch: %s' % e)
Example #51
0
def _login(request, template=None, data=None, dont_redirect=False):
    data = data or {}
    data['webapp'] = True
    # In case we need it later.  See below.
    get_copy = request.GET.copy()

    if 'to' in request.GET:
        request = _clean_next_url(request)

    if request.user.is_authenticated():
        return http.HttpResponseRedirect(
            request.GET.get('to', settings.LOGIN_REDIRECT_URL))

    user = None
    login_status = None
    r = auth_login(request, template_name=template, redirect_field_name='to',
                   extra_context=data)

    if isinstance(r, http.HttpResponseRedirect):
        # Django's auth.views.login has security checks to prevent someone from
        # redirecting to another domain.  Since we want to allow this in
        # certain cases, we have to make a new response object here to replace
        # the above.

        if 'domain' in request.GET:
            request.GET = get_copy
            request = _clean_next_url(request)
            r = http.HttpResponseRedirect(request.GET['to'])

        # Succsesful log in according to django.  Now we do our checks.  I do
        # the checks here instead of the form's clean() because I want to use
        # the messages framework and it's not available in the request there.
        if user.deleted:
            logout(request)
            log.warning(u'Attempt to log in with deleted account (%s)' % user)
            messages.error(request, _('Wrong email address or password!'))
            user.log_login_attempt(False)
            log_cef('Authentication Failure', 5, request,
                    username=request.user, signature='AUTHFAIL',
                    msg='Account is deactivated')
            return render(request, template, data)

        login_status = True

        if dont_redirect:
            # We're recalling the middleware to re-initialize amo_user
            ACLMiddleware().process_request(request)
            r = render(request, template, data)

    if login_status is not None:
        user.log_login_attempt(login_status)
        log_cef('Authentication Failure', 5, request,
                username=request.POST['username'],
                signature='AUTHFAIL',
                msg='The password was incorrect')

    return r
Example #52
0
def login(request):
    logout(request)

    if 'to' in request.GET:
        request = _clean_next_url(request)

    r = auth.views.login(request,
                         template_name='users/login.html',
                         redirect_field_name='to',
                         authentication_form=forms.AuthenticationForm)

    if isinstance(r, http.HttpResponseRedirect):
        # Succsesful log in according to django.  Now we do our checks.  I do
        # the checks here instead of the form's clean() because I want to use
        # the messages framework and it's not available in the request there
        user = request.user.get_profile()

        if user.deleted:
            logout(request)
            log.warning(u'Attempt to log in with deleted account (%s)' % user)
            messages.error(request, _('Wrong email address or password!'))
            return jingo.render(request, 'users/login.html',
                                {'form': forms.AuthenticationForm()})

        if user.confirmationcode:
            logout(request)
            log.info(u'Attempt to log in with unconfirmed account (%s)' % user)
            msg1 = _(('A link to activate your user account was sent by email '
                      'to your address {0}. You have to click it before you '
                      'can log in.').format(user.email))
            url = "%s%s" % (settings.SITE_URL,
                            reverse('users.confirm.resend', args=[user.id]))
            msg2 = _(('If you did not receive the confirmation email, make '
                      'sure your email service did not mark it as "junk '
                      'mail" or "spam". If you need to, you can have us '
                      '<a href="%s">resend the confirmation message</a> '
                      'to your email address mentioned above.') % url)
            messages.error(request, _('Activation Email Sent'), msg1)
            messages.info(request, _('Having Trouble?'), msg2, title_safe=True)
            return jingo.render(request, 'users/login.html',
                                {'form': forms.AuthenticationForm()})

        rememberme = request.POST.get('rememberme', None)
        if rememberme:
            request.session.set_expiry(settings.SESSION_COOKIE_AGE)
            log.debug((u'User (%s) logged in successfully with '
                       '"remember me" set') % user)
        else:
            user.log_login_attempt(request, True)
    elif 'username' in request.POST:
        # Hitting POST directly because cleaned_data doesn't exist
        user = UserProfile.objects.filter(email=request.POST['username'])
        if user:
            user.get().log_login_attempt(request, False)

    return r
Example #53
0
def check_zip(r, hashtag):
    """Check if zip file is prepared."""
    if not validator.is_valid('alphanum', hashtag):
        log.warning('[security] Wrong hashtag provided')
        return HttpResponseForbidden("{'error': 'Wrong hashtag'}")
    path = os.path.join(settings.XPI_TARGETDIR, '%s.zip' % hashtag)
    # Check file if it exists
    if os.path.isfile(path):
        return HttpResponse('{"ready": true}')
    return HttpResponse('{"ready": false}')
Example #54
0
    def handle_user(self, request, user):
        profile, created = UserProfile.objects.get_or_create(user=user)
        if created:
            log.warning('Created profile for user with email %s' % user.email)

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

        request.session['authenticated_email'] = user.email
        return redirect(reverse('register'))
Example #55
0
def download_module(request, pk):
    """
    return a JSON with all module info
    """
    module = get_object_with_related_or_404(Module, pk=pk)
    if not module.can_view(request.user):
        log_msg = ("[security] Attempt to download private module (%s) by "
                   "non-owner (%s)" % (pk, request.user))
        log.warning(log_msg)
        return HttpResponseForbidden('You are not the author of this module.')
    return HttpResponse(module.get_json())
Example #56
0
    def login_success(self):
        user = self.user
        profile, created = UserProfile.objects.get_or_create(user=user)
        if created:
            log.warning('Created profile for user with email %s' % user.email)

        if profile.is_complete():
            return super(BrowserID, self).login_success()

        self.request.session['authenticated_email'] = user.email
        return redirect(reverse('register'))
Example #57
0
def _save_new_user(request, form):
    """
    form - must be a valid form

    We persist account to LDAP. If all goes well, we
    log the user in and persist their BID assertion to the
    session.
    """
    # Email in the form is the "username" we'll use.
    email = request.session['verified_email']
    username = email

    registrar = RegistrarSession.connect(request)

    code = request.session.get('invite-code')

    d = form.cleaned_data
    d['email'] = email
    uniq_id = registrar.create_person(d)
    voucher = None

    if code:
        try:
            invite = get_invite(code)
            voucher = invite.inviter
        except Invite.DoesNotExist:
            msg = 'Bad code in form [%s], skipping pre-vouch' % d['code']
            log.warning(msg)

    # we need to authenticate them... with their assertion
    assertion_hash, assertion = get_assertion(request)

    for i in range(1, 10):
        try:
            user = auth.authenticate(request=request, assertion=assertion)

            # Should never happen
            if not user or not user.is_authenticated():
                msg = 'Authentication for new user (%s) failed' % username
                # TODO: make this a unique exception.
                raise Exception(msg)

            statsd.incr('user.successful_registration')
            statsd.incr('user.successful_registration_attempt_%s' % i)
            break
        except Exception, e:
            statsd.incr('user.errors.registration_failed')
            statsd.incr('user.errors.registration_failed_attempt_%s' % i)
            log.warning(e)

            # All hope is lost.
            if i == 10:
                statsd.incr('user.errors.user_record_never_created')
                raise Exception(e)
Example #58
0
def profile_uid(request, unique_id):
    """View a profile by unique_id, which is a stable, random user id."""
    needs_master = (request.user.unique_id == unique_id)
    ldap = UserSession.connect(request)
    try:
        # Stale data okay when viewing others
        person = ldap.get_by_unique_id(unique_id, needs_master)
        if person.last_name:
            return _profile(request, person, needs_master)
    except NO_SUCH_PERSON:
        log.warning('profile_uid Sending 404 for [%s]' % unique_id)
        raise Http404
Example #59
0
class SessionBackend:
    supports_anonymous_user = False
    supports_object_permissions = False

    def authenticate(self, session):
        """
        Given a CakeSession object we'll authenticate it to an actual user.
        """

        if (time() > session.expires or not session.data.startswith('User|')):
            session.delete()
            return None

        try:
            serialized_data = smart_str(session.data[5:])
            php_user = phpserialize.loads(serialized_data)
        except ValueError, e:
            # Bug 553397
            log.warning("Found corrupt session (%s): %s" % (session.pk, e))
            session.delete()
            return None

        user_id = int(php_user.get('id'))

        try:
            profile = UserProfile.objects.get(pk=user_id)
        except UserProfile.DoesNotExist:
            session.delete()
            return None

        def retrieve_from_master(pk):
            return UserProfile.objects.using('default').no_cache().get(pk=pk)

        # User will hit this if they are new to zamboni.
        try:
            if profile.user is None:
                # This will catch replication lags in case we created a user.
                profile = retrieve_from_master(user_id)
                if profile.user is None:
                    profile.create_django_user()
        except User.DoesNotExist:
            log.warning('Bad user_id {0} on UserProfile {1}.'.format(
                profile.id, profile.user_id))
            # Chances are we are suffering from replication lag, but
            # let's play it safe and just not authenticate.
            return None
        except IntegrityError, e:
            # Typically a duplicate key.
            log.warning('DB Error for UserProfile {0}: {1}'.format(user_id, e))
            return None