diff --git a/django_mailbox/__init__.py b/django_mailbox/__init__.py index 176119c3..0b472167 100644 --- a/django_mailbox/__init__.py +++ b/django_mailbox/__init__.py @@ -1,3 +1,3 @@ -__version__ = '4.7.1' +__version__ = '4.7.2' default_app_config = 'django_mailbox.apps.MailBoxConfig' diff --git a/django_mailbox/admin.py b/django_mailbox/admin.py index c586b406..b953947c 100644 --- a/django_mailbox/admin.py +++ b/django_mailbox/admin.py @@ -8,6 +8,7 @@ import logging +from django import forms from django.conf import settings from django.contrib import admin from django.utils.translation import ugettext_lazy as _ @@ -39,11 +40,29 @@ def resend_message_received_signal(message_admin, request, queryset): _('Re-send message received signal') ) +class MailboxForm(forms.ModelForm): + uri = forms.CharField(widget=forms.PasswordInput, + help_text="For security, the URI will not be shown and will " + "be encrypted in database " + "
" + "Example: imap+ssl://myusername:mypassword@someserver
" + "
" + "Internet transports include 'imap' and 'pop3'; " + "common local file transports include 'maildir', 'mbox', " + "and less commonly 'babyl', 'mh', and 'mmdf'.
" + "
" + "Be sure to urlencode your username and password should they " + "contain illegal characters (like @, :, etc)." + ) + + class Meta: + model = Mailbox + fields = ('name', 'uri', 'from_email', 'active',) class MailboxAdmin(admin.ModelAdmin): + form = MailboxForm list_display = ( 'name', - 'uri', 'from_email', 'active', 'last_polling', @@ -51,6 +70,10 @@ class MailboxAdmin(admin.ModelAdmin): readonly_fields = ['last_polling', ] actions = [get_new_mail] + def save_model(self, request, obj, form, change): + if request: + obj.uri = obj.encrypt_uri() + obj.save() class MessageAttachmentAdmin(admin.ModelAdmin): raw_id_fields = ('message', ) diff --git a/django_mailbox/models.py b/django_mailbox/models.py index 9f7ffc21..f24dc4e2 100644 --- a/django_mailbox/models.py +++ b/django_mailbox/models.py @@ -17,6 +17,7 @@ import sys import uuid from tempfile import NamedTemporaryFile +from Crypto.Cipher import AES import six from six.moves.urllib.parse import parse_qs, unquote, urlparse @@ -113,9 +114,39 @@ class Mailbox(models.Model): objects = models.Manager() active_mailboxes = ActiveMailboxManager() + def pad(self, key): + length = 32 - (len(key) % 32) + return key + chr(length).encode('utf-8') * length + + def unpad(self, key): + return key[0:-ord(key[-1])] + + def encrypt_uri(self): + secret_key = self.pad(django_settings.SECRET_KEY) + self.uri = unicode(self.pad(self.uri)).encode('utf-8') + + cipher = AES.new(secret_key) + self.uri = cipher.encrypt(self.uri) + self.uri = base64.b64encode(self.uri) + + return self.uri + + def decrypt_uri(self): + secret_key = self.pad(django_settings.SECRET_KEY) + uri = self.uri + uri = self.pad(uri) + uri = base64.b64decode(uri) + + cipher = AES.new(secret_key) + uri = cipher.decrypt(uri) + + return self.unpad(uri) + @property def _protocol_info(self): - return urlparse(self.uri) + uri = self.uri + uri = self.decrypt_uri() + return urlparse(uri) @property def _query_string(self): diff --git a/django_mailbox/utils.py b/django_mailbox/utils.py index 48e76be3..eda4f35f 100644 --- a/django_mailbox/utils.py +++ b/django_mailbox/utils.py @@ -66,8 +66,8 @@ def get_settings(): ), 'default_charset': getattr( settings, - 'DJANGO_MAILBOX_default_charset', - 'iso8859-1', + 'DJANGO_MAILBOX_DEFAULT_CHARSET', + 'utf8', ) } diff --git a/rtd_requirements.txt b/rtd_requirements.txt index 18684b76..8e20bd23 100644 --- a/rtd_requirements.txt +++ b/rtd_requirements.txt @@ -1,2 +1,3 @@ django>=1.9,<1.10 six +pycrypto==2.6.1 diff --git a/setup.py b/setup.py index d6e46258..7eaed7e2 100755 --- a/setup.py +++ b/setup.py @@ -54,6 +54,7 @@ packages=find_packages(), include_package_data=True, install_requires=[ - 'six>=1.6.1' + 'six>=1.6.1', + 'pycrypto==2.6.1' ] )