Skip to content

Commit fecdc22

Browse files
committed
Merged in [19694] from jennifer@painless-security.com:
Better handle invalid character encodings in process_email and feedback_email commands. Add tests of this using stdin. - Legacy-Id: 19724 Note: SVN reference [19694] has been migrated to Git commit dcf4251
2 parents 7ab6bac + dcf4251 commit fecdc22

File tree

5 files changed

+66
-13
lines changed

5 files changed

+66
-13
lines changed

ietf/ipr/management/commands/process_email.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,9 @@ def add_arguments(self, parser):
2323

2424
def handle(self, *args, **options):
2525
email = options.get('email', None)
26-
if not email:
27-
msg = sys.stdin.read()
28-
self.msg_bytes = msg.encode()
29-
else:
30-
self.msg_bytes = io.open(email, "rb").read()
31-
msg = self.msg_bytes.decode()
26+
binary_input = io.open(email, 'rb') if email else sys.stdin.buffer
27+
self.msg_bytes = binary_input.read()
28+
msg = self.msg_bytes.decode()
3229

3330
try:
3431
process_response_email(msg)

ietf/ipr/management/tests.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# -*- coding: utf-8 -*-
33
"""Tests of ipr management commands"""
44
import mock
5+
import sys
56

67
from django.core.management import call_command
78
from django.test.utils import override_settings
@@ -26,7 +27,7 @@ def test_process_email(self, process_mock):
2627
@mock.patch('ietf.utils.management.base.send_smtp')
2728
@mock.patch('ietf.ipr.management.commands.process_email.process_response_email')
2829
def test_send_error_to_admin(self, process_mock, send_smtp_mock):
29-
"""The process_email command should email the admins on error"""
30+
"""The process_email command should email the admins on error in process_response_email"""
3031
# arrange an mock error during processing
3132
process_mock.side_effect = RuntimeError('mock error')
3233

@@ -47,3 +48,32 @@ def test_send_error_to_admin(self, process_mock, send_smtp_mock):
4748
self.assertIn('mock.py', content, 'File where error occurred should be included in error email')
4849
self.assertIn('traceback', traceback.lower(), 'Traceback should be attached to error email')
4950
self.assertEqual(original, 'contents', 'Original message should be attached to error email')
51+
52+
@mock.patch('ietf.utils.management.base.send_smtp')
53+
@mock.patch('ietf.ipr.management.commands.process_email.process_response_email')
54+
def test_invalid_character_encodings(self, process_mock, send_smtp_mock):
55+
"""The process_email command should attach messages with invalid encoding when using a file input"""
56+
invalid_characters = b'\xfe\xff'
57+
with name_of_file_containing(invalid_characters, mode='wb') as filename:
58+
call_command('process_email', email_file=filename)
59+
60+
self.assertFalse(process_mock.called) # should not even try to process illegally encoded messages
61+
self.assertTrue(send_smtp_mock.called)
62+
(msg,) = send_smtp_mock.call_args.args
63+
parts = msg.get_payload()
64+
self.assertEqual(len(parts), 3, 'Error email should contain message, traceback, and original message')
65+
66+
@mock.patch.object(sys.stdin.buffer, 'read')
67+
@mock.patch('ietf.utils.management.base.send_smtp')
68+
@mock.patch('ietf.ipr.management.commands.process_email.process_response_email')
69+
def test_invalid_character_encodings_via_stdin(self, process_mock, send_smtp_mock, stdin_read_mock):
70+
"""The process_email command should attach messages with invalid encoding when using stdin"""
71+
invalid_characters = b'\xfe\xff'
72+
stdin_read_mock.return_value = invalid_characters
73+
call_command('process_email')
74+
75+
self.assertFalse(process_mock.called) # should not even try to process illegally encoded messages
76+
self.assertTrue(send_smtp_mock.called)
77+
(msg,) = send_smtp_mock.call_args.args
78+
parts = msg.get_payload()
79+
self.assertEqual(len(parts), 3, 'Error email should contain message, traceback, and original message')

ietf/nomcom/management/commands/feedback_email.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,8 @@ def handle(self, *args, **options):
4242
except NomCom.DoesNotExist:
4343
raise CommandError("NomCom %s does not exist or it isn't active" % year)
4444

45-
if not email:
46-
self.msg = io.open(sys.stdin.fileno(), 'rb').read()
47-
else:
48-
self.msg = io.open(email, "rb").read()
45+
binary_input = io.open(email, 'rb') if email else sys.stdin.buffer
46+
self.msg = binary_input.read()
4947

5048
try:
5149
feedback = create_feedback_email(self.nomcom, self.msg)

ietf/nomcom/management/tests.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# -*- coding: utf-8 -*-
33
"""Tests of nomcom management commands"""
44
import mock
5+
import sys
56

67
from collections import namedtuple
78

@@ -83,3 +84,30 @@ def test_feedback_email(self, create_feedback_mock):
8384
(self.nomcom, b'feedback message'),
8485
'feedback_email should process the correct email for the correct nomcom'
8586
)
87+
88+
@mock.patch('ietf.utils.management.base.send_smtp')
89+
def test_invalid_character_encodings(self, send_smtp_mock):
90+
"""The feedback_email command should send a message when file input has invalid encoding"""
91+
# mock an exception in create_feedback_email()
92+
invalid_characters = b'\xfe\xff'
93+
with name_of_file_containing(invalid_characters, mode='wb') as filename:
94+
call_command('feedback_email', nomcom_year=self.year, email_file=filename)
95+
96+
self.assertTrue(send_smtp_mock.called)
97+
(msg,) = send_smtp_mock.call_args.args # get the message to be sent
98+
parts = msg.get_payload()
99+
self.assertEqual(len(parts), 2, 'Error email should contain message and original message')
100+
101+
@mock.patch.object(sys.stdin.buffer, 'read')
102+
@mock.patch('ietf.utils.management.base.send_smtp')
103+
def test_invalid_character_encodings_via_stdin(self, send_smtp_mock, stdin_read_mock):
104+
"""The feedback_email command should send a message when stdin input has invalid encoding"""
105+
# mock an exception in create_feedback_email()
106+
invalid_characters = b'\xfe\xff'
107+
stdin_read_mock.return_value = invalid_characters
108+
call_command('feedback_email', nomcom_year=self.year)
109+
110+
self.assertTrue(send_smtp_mock.called)
111+
(msg,) = send_smtp_mock.call_args.args # get the message to be sent
112+
parts = msg.get_payload()
113+
self.assertEqual(len(parts), 2, 'Error email should contain message and original message')

ietf/utils/test_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ def reload_db_objects(*objects):
104104
return t
105105

106106
@contextmanager
107-
def name_of_file_containing(contents):
107+
def name_of_file_containing(contents, mode='w'):
108108
"""Get a context with the name of an email file"""
109-
f = NamedTemporaryFile('w', delete=False)
109+
f = NamedTemporaryFile(mode, delete=False)
110110
f.write(contents)
111111
f.close()
112112
yield f.name # hand the filename to the context

0 commit comments

Comments
 (0)