예제 #1
0
파일: folder.py 프로젝트: lipper/webpymail
def show_folders_view(request):
    '''Show the account folders.
    '''
    # Login to the server:
    M = serverLogin(request)

    # Special folders
    # TODO: will get this from the user config
    M.set_special_folders('INBOX', 'INBOX.Drafts', 'INBOX.Templates')

    # Expandable folders
    expand_folders = request.user.folderstoexpand_set.all()
    if expand_folders:
        M.set_expand_list(*[f.folder_name for f in expand_folders])

    # Read the subscribed folder list:
    M.refresh_folders(subscribed=True)

    # Get the default identity
    config = WebpymailConfig(request)
    identity_list = config.identities()
    default_address = identity_list[0]['mail_address']

    return render(request, 'mail/folder_list.html', {
        'server': M,
        'address': default_address
    })
예제 #2
0
def manage_address(request, address_id=None):
    '''Add an address to the user's address book'''
    context = {}
    next = request.GET.get('next', 'browse_addresses')
    context['next'] = next

    if address_id:
        try:
            address = Address.objects.get(id=int(address_id),
                                          user=request.user,
                                          ab_type=1)
        except ObjectDoesNotExist:
            raise Http404

    if request.method == 'POST':
        if 'cancel' in request.POST:
            return redirect(next)
        if address_id:
            form = AddressForm(request.POST, instance=address)
        else:
            form = AddressForm(request.POST)
        if form.is_valid():
            # Save the new address
            address = form.save(commit=False)
            address.user = request.user
            address.imap_server = request.session['host']
            address.ab_type = 1
            address.save()
            return redirect(next)
        else:
            # Show errors:
            context['form'] = form
    else:
        # Empty form
        if address_id:
            context['form'] = AddressForm(instance=address)
        else:
            # Try to get initialization values
            first_name = request.GET.get('first_name', '')
            last_name = request.GET.get('last_name', '')
            email = request.GET.get('email', '')
            context['form'] = AddressForm(data={
                'first_name': first_name,
                'last_name': last_name,
                'email': email
            })

    return render(request, 'sab/manage_address.html', context)
예제 #3
0
def create_initial_message(request,
                           text='',
                           to_addr='',
                           cc_addr='',
                           bcc_addr='',
                           subject='',
                           attachments='',
                           headers={},
                           context={}):
    initial = get_message_data(request, text, to_addr, cc_addr, bcc_addr,
                               subject, attachments)
    if attachments:
        uploaded_files = UploadFiles(request.user,
                                     old_files=attachments.split(','))
    else:
        uploaded_files = []
    form = ComposeMailForm(initial=initial, request=request)
    context['form'] = form
    context['uploaded_files'] = uploaded_files
    return render(request, 'mail/send_message.html', context)
예제 #4
0
def send_message(request,
                 text='',
                 to_addr='',
                 cc_addr='',
                 bcc_addr='',
                 subject='',
                 attachments='',
                 headers={},
                 context={}):
    '''Generic send message view
    '''
    # Auxiliary data initialization
    new_data = request.POST.copy()
    other_action = False
    old_files = []
    if 'saved_files' in new_data:
        if new_data['saved_files']:
            old_files = new_data['saved_files'].split(',')
    file_list = request.FILES.getlist('attachment[]')
    uploaded_files = UploadFiles(request.user,
                                 old_files=old_files,
                                 new_files=file_list)

    # Check if there is a request to delete files
    for key in new_data:
        match = delete_re.match(key)
        if match:
            id = int(match.groups()[0])
            uploaded_files.delete_id(id)
            other_action = True

    # Check if the cancel button was pressed
    if 'cancel' in new_data:
        # Delete the files
        uploaded_files.delete()
        # return
        return HttpResponseRedirect('/')

    # create an hidden field with the file list.
    # In case the form does not validate, the user doesn't have
    # to upload it again
    new_data['saved_files'] = ','.join(
        ['%d' % Xi for Xi in uploaded_files.id_list()])
    user_profile = request.user.userprofile

    temp_signature_pri_key_file = request.FILES.get('signature_pri_key_file',
                                                    None)
    if temp_signature_pri_key_file is not None:
        form = ComposeMailForm(
            new_data, {'signature_pri_key_file': temp_signature_pri_key_file},
            request=request)
    else:
        form = ComposeMailForm(new_data, request=request)

    if 'upload' in new_data:
        other_action = True

    if form.is_valid() and not other_action:
        # Read the posted data
        form_data = form.cleaned_data

        subject = form_data['subject']
        from_addr = form_data['from_addr']

        to_addr = join_address_list(form_data['to_addr'])
        cc_addr = join_address_list(form_data['cc_addr'])
        bcc_addr = join_address_list(form_data['bcc_addr'])

        text_format = form_data['text_format']
        message_text = form_data['message_text'].encode('utf-8')

        config = WebpymailConfig(request)

        # Create html message
        # if text_format == MARKDOWN and HAS_MARKDOWN:
        #     md = markdown.Markdown(output_format='HTML')
        #     message_html = md.convert(smart_text(message_text))
        #     css = config.get('message', 'css')
        #     # TODO: use a template to get the html and insert the css
        #     message_html = ('<html>\n<style>%s</style>'
        #                     '<body>\n%s\n</body>\n</html>' %
        #                     (css, message_html))
        # else:
        #     message_html = None
        message_html = None

        # signature plugin
        use_signature = form_data['use_signature']
        if use_signature:
            if form_data['signature_pri_key_file']:
                # save to temporary file
                folder_path = os.path.join('mailapp', 'savedkeys')
                if not os.path.exists(folder_path):
                    os.makedirs(folder_path)
                pri_key_path = os.path.join(folder_path, 'uploaded.pri')
                with form_data['signature_pri_key_file'] as fup, open(
                        pri_key_path, 'wb') as ftemp:
                    ftemp.write(fup.read())
                # load key
                ecc = ECC.load_key(pri_key_path, False)
                a = ecc.a
                b = ecc.b
                p = ecc.p
                d = ecc.d
                n = ecc.n
                Gx, Gy = ecc.G
            else:
                a = form_data['signature_pri_key_a']
                b = form_data['signature_pri_key_b']
                p = form_data['signature_pri_key_p']
                d = form_data['signature_pri_key_d']
                n = form_data['signature_pri_key_n']
                Gx = form_data['signature_pri_key_Gx']
                Gy = form_data['signature_pri_key_Gy']

            message_text += b'\n\n' + b'<ds>' + generate_digital_signature(
                message_text, a, b, p, d, n, Gx, Gy) + b'</ds>'

        # encryption plugin
        use_encryption = form_data['use_encryption']

        # Create the RFC822 message
        # NOTE: the current relevant RFC is RFC 5322, maybe this function
        # name should be changed to reflect this, maybe it shouldn't be
        # named after the RFC!
        if use_encryption:
            # Encryption Message
            # iv = '12345678'
            # key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF'
            iv = form_data['encryption_iv']
            key = form_data['encryption_key']

            cipher = STRAIT(key, Mode.CBC)
            message_text_enc = iv.encode('utf-8') + cipher.encrypt(
                message_text, iv)
            message_text_enc = base64.b64encode(message_text_enc)
            print('enc:', message_text_enc)

            # Build message
            message = compose_rfc822(from_addr, to_addr, cc_addr, bcc_addr,
                                     subject, message_text_enc, message_html,
                                     uploaded_files, headers)
        else:
            # Build message
            message = compose_rfc822(from_addr, to_addr, cc_addr, bcc_addr,
                                     subject, message_text, message_html,
                                     uploaded_files, headers)

        # Post the message to the SMTP server
        try:
            host = config.get('smtp', 'host')
            port = config.getint('smtp', 'port')
            user = config.get('smtp', 'user')
            passwd = config.get('smtp', 'passwd')
            security = config.get('smtp', 'security').upper()
            use_imap_auth = config.getboolean('smtp', 'use_imap_auth')
            if use_imap_auth:
                user = request.session['username']
                passwd = request.session['password']
            send_mail(message, host, port, user, passwd, security)
        except SMTPRecipientsRefused as detail:
            error_message = ''.join([
                '<p>%s' % escape(detail.recipients[Xi][1])
                for Xi in detail.recipients
            ])
            context['form'] = form
            context['server_error'] = error_message
            context['uploaded_files'] = uploaded_files
            return render(request, 'mail/send_message.html', context)
        except SMTPException as detail:
            error_message = '<p>%s' % detail
            context['form'] = form
            context['server_error'] = error_message
            context['uploaded_files'] = uploaded_files
            return render(request, 'mail/send_message.html', context)
        except Exception as detail:
            error_message = '<p>%s' % detail
            context['form'] = form
            context['server_error'] = error_message
            context['uploaded_files'] = uploaded_files
            return render(request, 'mail/send_message.html', context)

        # Store the message on the sent folder
        imap_store(request, user_profile.sent_folder, message)
        # Delete the temporary files
        uploaded_files.delete()
        return HttpResponseRedirect('/')
    else:
        # Return to the message composig view
        context['form'] = form
        context['uploaded_files'] = uploaded_files
        return render(request, 'mail/send_message.html', context)
예제 #5
0
def generate_ecc_key(request):
    error_message = None
    if request.method == 'POST':
        print(request.POST)
        if 'cancel' in request.POST:
            return HttpResponseRedirect('/')

        form = GenerateEccKeyForm(request.POST)
        if form.is_valid():
            # Read the posted data
            form_data = form.cleaned_data
            print(form_data)

            # get curve parameters
            a = form_data['curve_param_a']
            b = form_data['curve_param_b']
            p = form_data['curve_param_p']
            # get optional input
            Gx = form_data['curve_base_Gx']
            Gy = form_data['curve_base_Gy']
            n = form_data['curve_order_n']
            # get generated input
            d = form_data['pri_key_d']
            Qx = form_data['pub_key_Qx']
            Qy = form_data['pub_key_Qy']

            # download as file
            if 'download' in request.POST:
                if all(
                    [el is not None
                     for el in [a, b, p, Gx, Gy, n, d, Qx, Qy]]):
                    return get_zipped_key_response(a, b, p, Gx, Gy, n, d, Qx,
                                                   Qy)
                else:
                    error_message = 'Failed to download key, form is not all filled'
                    return render(request,
                                  'mail/plugins/generate_ecc_key.html', {
                                      'form': form,
                                      'error_message': error_message,
                                  })
                    return HttpResponse(
                        'Failed to Download, form is not all filled')

            # generate ecc key
            new_data = form_data.copy()
            try:
                if Gx and Gy and n:
                    # G and n supplied no need to generate group, then manually generate key after G and n assigned
                    ecc = ECC(a,
                              b,
                              p,
                              auto_gen_group=False,
                              auto_gen_key=False)
                    G = Point(Gx, Gy)
                    ecc.G = G
                    ecc.n = n
                    ecc.generate_key()
                else:
                    # G and n not supplied
                    ecc = ECC(a, b, p)

                print(ecc)
            except Exception as e:
                print('Generate Key Failed')
                error_message = 'Generate Key Failed. Error: ' + str(e)
            else:
                # update if needed (when G and n not supplied, else the value will be the same)
                new_data['curve_base_Gx'] = ecc.G.x
                new_data['curve_base_Gy'] = ecc.G.y
                new_data['curve_order_n'] = ecc.n
                # generated
                new_data['pri_key_d'] = ecc.d
                new_data['pub_key_Qx'] = ecc.Q.x
                new_data['pub_key_Qy'] = ecc.Q.y
                # show in form
                print(new_data)
                form = GenerateEccKeyForm(new_data)
    else:
        form = GenerateEccKeyForm()
    return render(request, 'mail/plugins/generate_ecc_key.html', {
        'form': form,
        'error_message': error_message,
    })
예제 #6
0
def browse_addresses(request):
    address_list = Address.objects.for_request(request)

    return render(request, 'sab/browse_addresses.html',
                  {'address_list': address_list})
예제 #7
0
파일: compose.py 프로젝트: lipper/webpymail
def send_message(request,
                 text='',
                 to_addr='',
                 cc_addr='',
                 bcc_addr='',
                 subject='',
                 attachments='',
                 headers={},
                 context={}):
    '''Generic send message view
    '''
    # Auxiliary data initialization
    new_data = request.POST.copy()
    other_action = False
    old_files = []
    if 'saved_files' in new_data:
        if new_data['saved_files']:
            old_files = new_data['saved_files'].split(',')
    file_list = request.FILES.getlist('attachment[]')
    uploaded_files = UploadFiles(request.user,
                                 old_files=old_files,
                                 new_files=file_list)

    # Check if there is a request to delete files
    for key in new_data:
        match = delete_re.match(key)
        if match:
            id = int(match.groups()[0])
            uploaded_files.delete_id(id)
            other_action = True

    # Check if the cancel button was pressed
    if 'cancel' in new_data:
        # Delete the files
        uploaded_files.delete()
        # return
        return HttpResponseRedirect('/')

    # create an hidden field with the file list.
    # In case the form does not validate, the user doesn't have
    # to upload it again
    new_data['saved_files'] = ','.join(
        ['%d' % Xi for Xi in uploaded_files.id_list()])
    user_profile = request.user.userprofile
    form = ComposeMailForm(new_data, request=request)
    if 'upload' in new_data:
        other_action = True

    if form.is_valid() and not other_action:
        # Read the posted data
        form_data = form.cleaned_data

        subject = form_data['subject']
        from_addr = form_data['from_addr']

        to_addr = join_address_list(form_data['to_addr'])
        cc_addr = join_address_list(form_data['cc_addr'])
        bcc_addr = join_address_list(form_data['bcc_addr'])

        text_format = form_data['text_format']
        message_text = form_data['message_text'].encode('utf-8')

        config = WebpymailConfig(request)

        # Create html message
        if text_format == MARKDOWN and HAS_MARKDOWN:
            md = markdown.Markdown(output_format='HTML')
            message_html = md.convert(smart_text(message_text))
            css = config.get('message', 'css')
            # TODO: use a template to get the html and insert the css
            message_html = ('<html>\n<style>%s</style>'
                            '<body>\n%s\n</body>\n</html>' %
                            (css, message_html))
        else:
            message_html = None

        # Create the RFC822 message
        # NOTE: the current relevant RFC is RFC 5322, maybe this function
        # name should be changed to reflect this, maybe it shouldn't be
        # named after the RFC!
        message = compose_rfc822(from_addr, to_addr, cc_addr, bcc_addr,
                                 subject, message_text, message_html,
                                 uploaded_files, headers)

        # Post the message to the SMTP server
        try:
            host = config.get('smtp', 'host')
            port = config.getint('smtp', 'port')
            user = config.get('smtp', 'user')
            passwd = config.get('smtp', 'passwd')
            security = config.get('smtp', 'security').upper()
            use_imap_auth = config.getboolean('smtp', 'use_imap_auth')
            if use_imap_auth:
                user = request.session['username']
                passwd = request.session['password']
            send_mail(message, host, port, user, passwd, security)
        except SMTPRecipientsRefused as detail:
            error_message = ''.join([
                '<p>%s' % escape(detail.recipients[Xi][1])
                for Xi in detail.recipients
            ])
            context['form'] = form
            context['server_error'] = error_message
            context['uploaded_files'] = uploaded_files
            return render(request, 'mail/send_message.html', context)
        except SMTPException as detail:
            error_message = '<p>%s' % detail
            context['form'] = form
            context['server_error'] = error_message
            context['uploaded_files'] = uploaded_files
            return render(request, 'mail/send_message.html', context)
        except Exception as detail:
            error_message = '<p>%s' % detail
            context['form'] = form
            context['server_error'] = error_message
            context['uploaded_files'] = uploaded_files
            return render(request, 'mail/send_message.html', context)

        # Store the message on the sent folder
        imap_store(request, user_profile.sent_folder, message)
        # Delete the temporary files
        uploaded_files.delete()
        return HttpResponseRedirect('/')
    else:
        # Return to the message composig view
        context['form'] = form
        context['uploaded_files'] = uploaded_files
        return render(request, 'mail/send_message.html', context)
예제 #8
0
def show_message_list_view(request, folder=settings.DEFAULT_FOLDER):
    '''Show the selected Folder message list.
    '''
    M = serverLogin(request)
    folder_name = base64.urlsafe_b64decode(str(folder))
    folder = M[folder_name]
    message_list = folder.message_list

    # Set the search criteria:
    search_criteria = 'ALL'
    message_list.set_search_expression(search_criteria)

    # Handle GET queries
    query = request.GET.copy()

    flag = request.GET.get('flag', None)
    if flag:
        search_criteria = 'KEYWORD %s' % flag

    show_style = request.GET.get('show_style', 'sorted')
    if show_style.upper() == 'THREADED':
        message_list.set_threaded()

    sort_order = request.GET.get('sort_order', 'DATE').upper()
    sort = request.GET.get('sort', 'DESCENDING').upper()
    if sort == 'DESCENDING':
        sort = '-'
    else:
        sort = ''
    if sort_order in SORT_KEYS:
        message_list.set_sort_program('%s%s' % (sort, sort_order))

    try:
        page = int(request.GET.get('page', 1))
    except:
        page = request.GET.get('page', 1)
        if page == 'all':
            message_list.paginator.msg_per_page = -1
        page = 1
    if 'page' in query:
        query.pop('page')

    # Pagination
    message_list.paginator.msg_per_page = 40
    message_list.paginator.current_page = page

    # Message action form
    message_list.refresh_messages()  # Necessary to get the flat_message_list
    raw_message_list = [(uid, uid) for uid in message_list.flat_message_list]
    form = MessageActionForm(data={}, message_list=raw_message_list, server=M)

    # If it's a POST request
    if request.method == 'POST':
        msgactions.batch_change(request, folder, raw_message_list)
        # TODO: When setting message flags the MessageList's messages objects
        # are not updated, so we have to refresh the messages to reflect the
        # changes in the message list. This should not be necessary, the set
        # and reset flags method in the Folder objects should update the
        # message information, saving this way a refresh_messages call.
        message_list.refresh_messages()

    # Get the default identity
    config = WebpymailConfig(request)
    identity_list = config.identities()
    default_address = identity_list[0]['mail_address']

    # Show the message list
    return render(
        request, 'mail/message_list.html', {
            'folder': folder,
            'address': default_address,
            'paginator': folder.paginator(),
            'query': query,
            'form': form
        })
예제 #9
0
def loginView(request):
    """Login the user on the system
    """
    if request.method == 'POST':
        form = LoginForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            next = form.cleaned_data['next']
            try:
                server = form.cleaned_data['host']
                config = server_config()
                host = config.get(server, 'host')
                port = config.getint(server, 'port')
                ssl = config.getboolean(server, 'ssl')
            except:
                return render(
                    request, 'wpmauth/login.html', {
                        'form': form,
                        'error_message': _('Invalid server. '
                                           'Please try again.')
                    })
            try:
                user = authenticate(request,
                                    username=username[:30],
                                    password=password,
                                    host=host,
                                    port=port,
                                    ssl=ssl)
            except ValueError:
                return render(
                    request, 'wpmauth/login.html', {
                        'form': form,
                        'error_message': _('Invalid login. '
                                           'Please try again.')
                    })
            if user is not None:
                if user.is_active:
                    auth_login(request, user)

                    # Not an imap user:
                    if (request.session['_auth_user_backend'] ==
                            'django.contrib.auth.backends.ModelBackend'):
                        return render(
                            request, 'wpmauth/login.html', {
                                'form':
                                form,
                                'error_message':
                                _('This is not an IMAP'
                                  ' valid account. '
                                  'Please try '
                                  'again.')
                            })

                    request.session['username'] = username
                    request.session['password'] = password
                    request.session['host'] = host
                    request.session['port'] = port
                    request.session['ssl'] = ssl

                    return HttpResponseRedirect(next)
                # Disabled account:
                else:
                    return render(
                        request, 'wpmauth/login.html', {
                            'form': form,
                            'error_message': _('Sorry, disabled '
                                               'account.')
                        })
            # Invalid user:
            else:
                return render(
                    request, 'wpmauth/login.html', {
                        'form': form,
                        'error_message': _('Invalid login. Please '
                                           'try again.')
                    })
        # Invalid form:
        else:
            return render(request, 'wpmauth/login.html', {'form': form})
    # Display the empty form:
    else:
        data = {'next': request.GET.get('next', '')}
        form = LoginForm(data)
        return render(request, 'wpmauth/login.html', {'form': form})
예제 #10
0
파일: views.py 프로젝트: lipper/webpymail
def config_menu(request):
    context = {}
    return render(request, 'config/menu.html', context)
예제 #11
0
def message_process(request, folder, uid):
    if request.method == 'POST':
        form = ProcessEmailForm(request.POST, request.FILES)
        if form.is_valid():
            # get form data
            form_data = form.cleaned_data

            # get message object
            config = WebpymailConfig(request)
            folder_name = base64.urlsafe_b64decode(str(folder))
            M = serverLogin(request)
            folder = M[folder_name]
            message = folder[int(uid)]

            # Get text/plain part
            text_plain = get_text_plain(message)

            # decryption plugin
            use_decryption = form_data['use_decryption']
            message_text_dec = None
            decryption_error = None
            if use_decryption:
                try:
                    # decrypt
                    # decryption_key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF'
                    decryption_key = form_data['decryption_key'].ljust(32, '0')[:32]
                    text_plain = base64.b64decode(text_plain)
                    cipher = STRAIT(decryption_key, Mode.CBC)
                    iv, message_text_enc = text_plain[:8].decode('utf-8'), text_plain[8:]
                    message_text_dec = cipher.decrypt(message_text_enc, iv).decode('utf-8', 'ignore')
                    text_to_validate = message_text_dec
                except Exception as e:
                    decryption_error = 'Failed to decrypt email content: ' + str(e)
                    text_to_validate = ''
            else:
                text_to_validate = text_plain

            # validation plugin
            use_validation = form_data['use_validation']
            validation = None
            validation_error = None
            if use_validation:
                try:
                    # validate
                    if form_data['validation_pub_key_file']:
                        # save to temporary file
                        folder_path = os.path.join('mailapp', 'savedkeys')
                        if not os.path.exists(folder_path):
                            os.makedirs(folder_path)
                        pub_key_path = os.path.join(folder_path, 'uploaded.pub')
                        with form_data['validation_pub_key_file'] as fup, open(pub_key_path, 'wb') as ftemp:
                            ftemp.write(fup.read())
                        # load key
                        try:
                            ecc = ECC.load_key(pub_key_path, True)
                        except Exception as e:
                            raise Exception('Load public key from file failed')
                        else:
                            a = ecc.a
                            b = ecc.b
                            p = ecc.p
                            Qx, Qy = ecc.Q
                            n = ecc.n
                            Gx, Gy = ecc.G
                    else:
                        a = form_data['validation_pub_key_a']
                        b = form_data['validation_pub_key_b']
                        p = form_data['validation_pub_key_p']
                        Qx = form_data['validation_pub_key_Qx']
                        Qy = form_data['validation_pub_key_Qy']
                        n = form_data['validation_pub_key_n']
                        Gx = form_data['validation_pub_key_Gx']
                        Gy = form_data['validation_pub_key_Gy']
                    # validate digital signature
                    validation = check_digital_signature(text_to_validate, a, b, p, Qx, Qy, n, Gx, Gy)
                except Exception as e:
                    validation_error = 'Failed to validate signature: ' + str(e)

            # Check the query string
            try:
                external_images = config.getboolean('message', 'external_images')
                external_images = request.GET.get('external_images', external_images)
                external_images = bool(int(external_images))
            except ValueError:
                external_images = config.getboolean('message', 'external_images')

            return render(request, 'mail/plugins/message_process.html', {
                'folder': folder,
                'message': message,
                'show_images_inline': config.getboolean('message',
                                                        'show_images_inline'),
                'show_html': config.getboolean('message', 'show_html'),
                'external_images': external_images,
                'use_validation': use_validation,
                'validation': validation,
                'validation_error': validation_error,
                'use_decryption': use_decryption,
                'message_text_dec': message_text_dec,
                'decryption_error': decryption_error,
                })

    else:
        form = ProcessEmailForm()

    return render(request, 'mail/plugins/message_process_form.html', {
        'folder': folder,
        'uid': uid,
        'form': form,
        })
예제 #12
0
def about(request):
    '''Show the account folders.
    '''
    return render(request, 'base/about.html')