Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate uploaded file type and size #4479

Merged
merged 7 commits into from
May 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ FROM python:3.7-alpine3.8

ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1
ARG PACKAGES="postgresql-libs libxml2 libxslt freetype libffi jpeg libmaxminddb bash git tar gzip inkscape"
ARG PACKAGES="postgresql-libs libxml2 libxslt freetype libffi jpeg libmaxminddb bash git tar gzip inkscape libmagic"
ARG BUILD_DEPS="gcc g++ postgresql-dev libxml2-dev libxslt-dev freetype-dev libffi-dev jpeg-dev linux-headers autoconf automake libtool make dos2unix"
WORKDIR /code

Expand Down
6 changes: 5 additions & 1 deletion app/assets/v2/js/jobs.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ const save_job_status = function() {
};

$.ajax(profile).done(function(response) {
_alert(response.message, 'info');
if (response.status == 200) {
_alert(response.message, 'info');
} else {
_alert(response.message, 'error');
}
}).fail(function(error) {
_alert(error, 'error');
});
Expand Down
36 changes: 20 additions & 16 deletions app/assets/v2/js/pages/bounty_details.js
Original file line number Diff line number Diff line change
Expand Up @@ -681,22 +681,26 @@ var show_interest_modal = function() {
};

$.ajax(ndaSend).done(function(response) {
_alert(response.message, 'info');
add_interest(document.result['pk'], {
issue_message: msg,
signed_nda: response.bounty_doc_id
}).then(success => {
if (success) {
$(self).attr('href', '/uninterested');
$(self).find('span').text(gettext('Stop Work'));
$(self).parent().attr('title', '<div class="tooltip-info tooltip-sm">' + gettext('Notify the funder that you will not be working on this project') + '</div>');
modals.bootstrapModal('hide');
}
}).catch((error) => {
if (error.responseJSON.error === 'You may only work on max of 3 issues at once.')
return;
throw error;
});
if (response.status == 200) {
_alert(response.message, 'info');
add_interest(document.result['pk'], {
issue_message: msg,
signed_nda: response.bounty_doc_id
}).then(success => {
if (success) {
$(self).attr('href', '/uninterested');
$(self).find('span').text(gettext('Stop Work'));
$(self).parent().attr('title', '<div class="tooltip-info tooltip-sm">' + gettext('Notify the funder that you will not be working on this project') + '</div>');
modals.bootstrapModal('hide');
}
}).catch((error) => {
if (error.responseJSON.error === 'You may only work on max of 3 issues at once.')
return;
throw error;
});
} else {
_alert(response.message, 'error');
}
}).fail(function(error) {
_alert(error, 'error');
});
Expand Down
14 changes: 10 additions & 4 deletions app/assets/v2/js/pages/new_bounty.js
Original file line number Diff line number Diff line change
Expand Up @@ -719,10 +719,16 @@ $('#submitBounty').validate({
};

$.ajax(settings).done(function(response) {
_alert(response.message, 'info');
ipfsBounty.payload.unsigned_nda = response.bounty_doc_id;
if (data.featuredBounty) payFeaturedBounty();
else do_bounty();
if (response.status == 200) {
_alert(response.message, 'info');
ipfsBounty.payload.unsigned_nda = response.bounty_doc_id;
if (data.featuredBounty) payFeaturedBounty();
else do_bounty();
} else {
_alert('Unable to upload NDA. ', 'error');
unloading_button($('.js-submit'));
console.log('NDA error:', response.message);
}
}).fail(function(error) {
_alert('Unable to upload NDA. ', 'error');
unloading_button($('.js-submit'));
Expand Down
46 changes: 38 additions & 8 deletions app/dashboard/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_GET, require_POST

import magic
from app.utils import clean_str, ellipses, get_default_network
from avatar.utils import get_avatar_context_for_user
from dashboard.utils import ProfileHiddenException, ProfileNotFoundException, get_bounty_from_invite_url, profile_helper
Expand Down Expand Up @@ -1767,6 +1768,11 @@ def profile_job_opportunity(request, handle):
Args:
handle (str): The profile handle.
"""
uploaded_file = request.FILES.get('job_cv')
error_response = invalid_file_response(uploaded_file, supported=['application/pdf'])
# 400 is ok because file upload is optional here
if error_response and error_response['status'] != '400':
return JsonResponse(error_response)
try:
profile = profile_helper(handle, True)
profile.job_search_status = request.POST.get('job_search_status', None)
Expand All @@ -1788,6 +1794,29 @@ def profile_job_opportunity(request, handle):
return JsonResponse(response)


def invalid_file_response(uploaded_file, supported):
response = None
if not uploaded_file:
response = {
'status': 400,
'message': 'No File Found'
}
elif uploaded_file.size > 31457280:
# 30MB max file size
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would 30 MB be too much?

response = {
'status': 413,
'message': 'File Too Large'
}
else:
file_mime = magic.from_buffer(next(uploaded_file.chunks()), mime=True)
logger.info('uploaded file: %s' % file_mime)
if file_mime not in supported:
response = {
'status': 415,
'message': 'Invalid File Type'
}
return response

@csrf_exempt
@require_POST
def bounty_upload_nda(request):
Expand All @@ -1796,22 +1825,23 @@ def bounty_upload_nda(request):
Args:
bounty_id (int): The bounty id.
"""
if request.FILES.get('docs', None):
uploaded_file = request.FILES.get('docs', None)
error_response = invalid_file_response(
uploaded_file, supported=['application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'])
if not error_response:
bountydoc = BountyDocuments.objects.create(
doc=request.FILES.get('docs', None),
doc=uploaded_file,
doc_type=request.POST.get('doc_type', None)
)
response = {
'status': 200,
'bounty_doc_id': bountydoc.pk,
'message': 'NDA saved'
}
else:
response = {
'status': 400,
'message': 'No File Found'
}
return JsonResponse(response)

return JsonResponse(error_response) if error_response else JsonResponse(response)



Expand Down
1 change: 1 addition & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,4 @@ raven==6.9.0
sentry-sdk
websocket-client
bleach
python-magic