Skip to content
Open
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
8 changes: 8 additions & 0 deletions attachments/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
class VirusFoundException(Exception):
"""Exception raised for detecting a virus in a file upload"""
pass

class FileSizeException(Exception):
"""Exception raised for too large file size in a file upload"""
pass

class FileTypeException(Exception):
"""Exception raised for unallowable type in a file upload"""
pass
1 change: 1 addition & 0 deletions attachments/templates/attachments/virus_email.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ user|default_if_none:"A User" }} attempted to upload this file: {{ filename }} with virus signature: {{ virus_signature }} at {% now 'c' %}}.
1 change: 1 addition & 0 deletions attachments/templates/attachments/virus_subject.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VIRUS UPLOAD ALERT: {{ user|default_if_none:"A user" }} attempted to upload a file containing a virus to the system
7 changes: 7 additions & 0 deletions attachments/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
import uuid


def sizeof_fmt(num, suffix='B'):
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f%s%s" % (num, 'Yi', suffix)

def get_context_key(context):
if context:
return 'attachments-%s' % context
Expand Down
30 changes: 27 additions & 3 deletions attachments/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
from django.template import loader
from django.utils.encoding import force_text
from django.views.decorators.csrf import csrf_exempt
from django.core.mail import send_mail

from attachments.exceptions import VirusFoundException

from attachments.exceptions import VirusFoundException, FileSizeException, FileTypeException

from .forms import PropertyForm
from .models import Attachment, Session
Expand All @@ -30,6 +32,12 @@ def attach(request, session_id):
content_type = 'text/plain' if request.POST.get('X-Requested-With', '') == 'IFrame' else 'application/json'
try:
f = request.FILES['attachment']
max_file_size = getattr(settings, 'ATTACHMENTS_MAXIMUM_FILE_SIZE', False)
if max_file_size and f.size > max_file_size:
raise FileSizeException("File is too large to be uploaded, file cannot be greater than %s" % sizeof_fmt(max_file_size))
allowed_file_types = getattr(settings, 'ATTACHMENTS_ALLOWED_FILE_TYPES', False)
if allowed_file_types and f.content_type not in allowed_file_types and f.content_type.split('/') not in allowed_file_types:
raise FileTypeException("You cannot upload this file type")
file_uploaded.send(sender=f, request=request, session=session)
# Copy the Django attachment (which may be a file or in memory) over to a temp file.
temp_dir = getattr(settings, 'ATTACHMENT_TEMP_DIR', None)
Expand All @@ -45,7 +53,7 @@ def attach(request, session_id):
cd = pyclamd.ClamdUnixSocket()
virus = cd.scan_file(path)
if virus is not None:
# if ATTACHMENTS_QUARANTINE_PATH is set, move the offending file to the quaranine, otherwise delete
#if ATTACHMENTS_QUARANTINE_PATH is set, move the offending file to the quarantine, otherwise delete
if getattr(settings, 'ATTACHMENTS_QUARANTINE_PATH', False):
quarantine_path = os.path.join(getattr(settings, 'ATTACHMENTS_QUARANTINE_PATH'), os.path.basename(path))
os.rename(path, quarantine_path)
Expand All @@ -60,8 +68,24 @@ def attach(request, session_id):
session.data = {key: value}
session.save()
return JsonResponse({'ok': True, 'file_name': f.name, 'file_size': f.size}, content_type=content_type)
except FileSizeException as ex:
return JsonResponse({'ok': False, 'error': unicode(ex)}, content_type=content_type)
except FileTypeException as ex:
return JsonResponse({'ok': False, 'error': unicode(ex)}, content_type=content_type)
except VirusFoundException as ex:
logger.exception(str(ex))
user = getattr(request, 'user', None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would just pass user into the template and let it decide, via something like {{ user|default_if_none:"Some Guy" }}. The less formatting in code the better.

log_message = loader.render_to_string('attachments/virus_email.txt',
{'user': user,
'filename' : f.name,
'virus_signature' : virus[path][1],
})
logger.exception(log_message)
#if ATTACHMENTS_VIRUS_EMAIL is set to a list/tuple of email addresses to send to it will send email alert
if getattr(settings, 'ATTACHMENTS_VIRUS_EMAIL', False):
#send email to email list
email_list = getattr(settings, 'ATTACHMENTS_VIRUS_EMAIL')
subject = loader.render_to_string('attachments/virus_subject.txt', {'user': user })
send_mail(subject, log_message, settings.DEFAULT_FROM_EMAIL, email_list)
return JsonResponse({'ok': False, 'error': force_text(ex)}, content_type=content_type)
except Exception as ex:
logger.exception('Error attaching file to session %s', session_id)
Expand Down
6 changes: 5 additions & 1 deletion docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,8 @@ Quickstart Guide

6. Set the ``ATTACHMENT_TEMP_DIR`` setting to the temporary directory you would like files to save in a settings file

7. (OPTIONAL) If you have the clamav daemon running on your server set ``ATTACHMENTS_CLAMD`` to true in a settings file. If you would like to set a path to quarantine infected files that are uploaded set ``ATTACHMENTS_QUARANTINE_PATH`` to desired path, if not set the default behavior will be to remove the files. Note that this currently only works for linux servers and the path to the clam socket will need to be set in /etc/clamav/clamd.conf or /etc/clamd.conf for this to work.
7. (OPTIONAL) If you have the clamav daemon running on your server set ``ATTACHMENTS_CLAMD`` to true in a settings file. If you would like email alerts set ``ATTACHMENTS_VIRUS_EMAIL`` to a list of recipients. If you would like to set a path to quarantine infected files that are uploaded set ``ATTACHMENTS_QUARANTINE_PATH`` to desired path, if not set the default behavior will be to remove the files. Note that this currently only works for linux servers and the path to the clam socket will need to be set in /etc/clamav/clamd.conf or /etc/clamd.conf for this to work.

8. (OPTIONAL) If you would like to limit the the file types users are able to upload set ``ATTACHMENTS_ALLOWED_FILE_TYPES`` to a list or tuple of mimetypes in a settings file. IE: ALLOWED_FILE_TYPES = ['text/html'] (allowing only html files. You can also just set it to the the text after the first '/' as in [html]. Note that for some files like excel they have mimetypes like `application/vnd.ms-excel` so make sure that you check the mimetypes you want before setting them!

9. (OPTIONAL) If you would like to set a maximum file size that users are able to upload set ``ATTACHMENTS_MAXIMUM_FILE_SIZE`` to an int of the maximum bytes you would like to allow. So a maximum size of 10MB would be MAXIMUM_FILE_SIZE = 10485760 Note that it is the binary bytes not the decimal!