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 })
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)
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)
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)
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, })
def browse_addresses(request): address_list = Address.objects.for_request(request) return render(request, 'sab/browse_addresses.html', {'address_list': address_list})
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)
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 })
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})
def config_menu(request): context = {} return render(request, 'config/menu.html', context)
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, })
def about(request): '''Show the account folders. ''' return render(request, 'base/about.html')