Example #1
0
    def test_hold_chain(self):
        msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: A message
Message-ID: <ant>
MIME-Version: 1.0

A message body.
""")
        msgdata = dict(moderation_reasons=[
            'TEST-REASON-1',
            'TEST-REASON-2',
            ])
        logfile = LogFileMark('mailman.vette')
        process_chain(self._mlist, msg, msgdata, start_chain='hold')
        messages = get_queue_messages('virgin', expected_count=2)
        payloads = {}
        for item in messages:
            if item.msg['to'] == '*****@*****.**':
                part = item.msg.get_payload(0)
                payloads['owner'] = part.get_payload().splitlines()
            elif item.msg['To'] == '*****@*****.**':
                payloads['sender'] = item.msg.get_payload().splitlines()
            else:
                self.fail('Unexpected message: %s' % item.msg)
        self.assertIn('    TEST-REASON-1', payloads['owner'])
        self.assertIn('    TEST-REASON-2', payloads['owner'])
        self.assertIn('    TEST-REASON-1', payloads['sender'])
        self.assertIn('    TEST-REASON-2', payloads['sender'])
        logged = logfile.read()
        self.assertIn('TEST-REASON-1', logged)
        self.assertIn('TEST-REASON-2', logged)
Example #2
0
    def test_reject(self):
        msgdata = dict(
            dmarc_action='reject',
            moderation_reasons=['DMARC violation'],
        )
        # When a message is reject, an event will be triggered and the message
        # will be bounced.
        events = []

        def handler(event):  # noqa: E306
            if isinstance(event, RejectEvent):
                events.append(event)

        with event_subscribers(handler):
            process_chain(self._mlist, self._msg, msgdata, start_chain='dmarc')
        self.assertEqual(len(events), 1)
        self.assertIs(events[0].msg, self._msg)
        items = get_queue_messages('virgin', expected_count=1)
        # Unpack the rejection message.
        rejection = items[0].msg.get_payload(0).get_payload()
        self.assertEqual(
            rejection, """\
Your message to the Ant mailing-list was rejected for the following
reasons:

DMARC violation

The original message as received by Mailman is attached.
""")
Example #3
0
 def test_hold_chain_charset(self):
     # Issue #144 - UnicodeEncodeError in the hold chain.
     self._mlist.admin_immed_notify = True
     self._mlist.respond_to_post_requests = False
     path = resource_filename('mailman.chains.tests', 'issue144.eml')
     with open(path, 'rb') as fp:
         msg = mfb(fp.read())
     msg.sender = '*****@*****.**'
     process_chain(self._mlist, msg, {}, start_chain='hold')
     # The postauth.txt message is now in the virgin queue awaiting
     # delivery to the moderators.
     items = get_queue_messages('virgin', expected_count=1)
     msgdata = items[0].msgdata
     self.assertTrue(msgdata['tomoderators'])
     self.assertEqual(msgdata['recipients'], {'*****@*****.**'})
     # Ensure that the subject looks correct in the postauth.txt.
     msg = items[0].msg
     value = None
     for line in msg.get_payload(0).get_payload().splitlines():
         if line.strip().startswith('Subject:'):
             header, colon, value = line.partition(':')
             break
     self.assertEqual(value.lstrip(), 'Vi?enamjenski pi?tolj za vodu 8/1')
     self.assertEqual(
         msg['Subject'],
         '[email protected] post from [email protected] requires approval')
Example #4
0
 def test_hold_chain_charset(self):
     # Issue #144 - UnicodeEncodeError in the hold chain.
     self._mlist.admin_immed_notify = True
     self._mlist.respond_to_post_requests = False
     bart = self._user_manager.create_user('*****@*****.**', 'Bart User')
     address = set_preferred(bart)
     self._mlist.subscribe(address, MemberRole.moderator)
     path = resource_filename('mailman.chains.tests', 'issue144.eml')
     with open(path, 'rb') as fp:
         msg = mfb(fp.read())
     msg.sender = '*****@*****.**'
     process_chain(self._mlist, msg, {}, start_chain='hold')
     # The postauth.txt message is now in the virgin queue awaiting
     # delivery to the moderators.
     items = get_queue_messages('virgin', expected_count=1)
     msgdata = items[0].msgdata
     # Should get sent to -owner address.
     self.assertEqual(msgdata['recipients'], {'*****@*****.**'})
     # Ensure that the subject looks correct in the postauth.txt.
     msg = items[0].msg
     value = None
     for line in msg.get_payload(0).get_payload().splitlines():
         if line.strip().startswith('Subject:'):
             header, colon, value = line.partition(':')
             break
     self.assertEqual(value.lstrip(), 'Vi?enamjenski pi?tolj za vodu 8/1')
     self.assertEqual(
         msg['Subject'],
         '[email protected] post from [email protected] requires approval')
Example #5
0
    def test_hold_chain_crosspost(self):
        mlist2 = create_list('*****@*****.**')
        msg = mfs("""\
From: [email protected]
To: [email protected], [email protected]
Subject: A message
Message-ID: <ant>
MIME-Version: 1.0

A message body.
""")
        process_chain(self._mlist, msg, {}, start_chain='hold')
        process_chain(mlist2, msg, {}, start_chain='hold')
        # There are four items in the virgin queue.  Two of them are for the
        # list owners who need to moderate the held message, and the other is
        # for anne telling her that her message was held for approval.
        items = get_queue_messages('virgin', expected_count=4)
        anne_froms = set()
        owner_tos = set()
        for item in items:
            if item.msg['to'] == '*****@*****.**':
                anne_froms.add(item.msg['from'])
            else:
                owner_tos.add(item.msg['to'])
        self.assertEqual(
            anne_froms,
            set(['*****@*****.**', '*****@*****.**']))
        self.assertEqual(
            owner_tos,
            set(['*****@*****.**', '*****@*****.**']))
        # And the message appears in the store.
        messages = list(getUtility(IMessageStore).messages)
        self.assertEqual(len(messages), 1)
        self.assertEqual(messages[0]['message-id'], '<ant>')
Example #6
0
    def test_hold_chain_crosspost(self):
        mlist2 = create_list('*****@*****.**')
        msg = mfs("""\
From: [email protected]
To: [email protected], [email protected]
Subject: A message
Message-ID: <ant>
MIME-Version: 1.0

A message body.
""")
        process_chain(self._mlist, msg, {}, start_chain='hold')
        process_chain(mlist2, msg, {}, start_chain='hold')
        # There are four items in the virgin queue.  Two of them are for the
        # list owners who need to moderate the held message, and the other is
        # for anne telling her that her message was held for approval.
        items = get_queue_messages('virgin', expected_count=4)
        anne_froms = set()
        owner_tos = set()
        for item in items:
            if item.msg['to'] == '*****@*****.**':
                anne_froms.add(item.msg['from'])
            else:
                owner_tos.add(item.msg['to'])
        self.assertEqual(anne_froms, set(['*****@*****.**',
                                          '*****@*****.**']))
        self.assertEqual(owner_tos, set(['*****@*****.**',
                                         '*****@*****.**']))
        # And the message appears in the store.
        messages = list(getUtility(IMessageStore).messages)
        self.assertEqual(len(messages), 1)
        self.assertEqual(messages[0]['message-id'], '<ant>')
Example #7
0
 def test_discard_no_reasons(self):
     # The log message contains n/a if no moderation reasons.
     msgdata = {}
     log_file = LogFileMark('mailman.vette')
     process_chain(self._mlist, self._msg, msgdata, start_chain='discard')
     log_entry = log_file.read()
     self.assertIn('DISCARD: <*****@*****.**>', log_entry)
     self.assertIn('[n/a]', log_entry)
Example #8
0
 def test_discard_reasons(self):
     # The log message must contain the moderation reasons.
     msgdata = dict(moderation_reasons=['TEST-REASON-1', 'TEST-REASON-2'])
     log_file = LogFileMark('mailman.vette')
     process_chain(self._mlist, self._msg, msgdata, start_chain='discard')
     log_entry = log_file.read()
     self.assertIn('DISCARD: <*****@*****.**>', log_entry)
     self.assertIn('TEST-REASON-1', log_entry)
     self.assertIn('TEST-REASON-2', log_entry)
Example #9
0
 def test_rule_hits(self):
     config.chains['mine'] = MyChain()
     self.addCleanup(config.chains.pop, 'mine')
     hits = None
     def handler(event):                                # noqa: E306
         nonlocal hits
         if isinstance(event, AcceptEvent):
             hits = event.msg['x-mailman-rule-hits']
     with event_subscribers(handler):
         process_chain(self._mlist, self._msg, {}, start_chain='mine')
     self.assertEqual(hits, 'first; second; third')
Example #10
0
 def test_reject_reasons(self):
     # The bounce message must contain the moderation reasons.
     msgdata = dict(moderation_reasons=[
         'TEST-REASON-1',
         'TEST-REASON-2',
     ])
     process_chain(self._mlist, self._msg, msgdata, start_chain='reject')
     bounces = get_queue_messages('virgin', expected_count=1)
     payload = bounces[0].msg.get_payload(0).as_string()
     self.assertIn('TEST-REASON-1', payload)
     self.assertIn('TEST-REASON-2', payload)
Example #11
0
 def test_rule_hits(self):
     config.chains['mine'] = MyChain()
     self.addCleanup(config.chains.pop, 'mine')
     hits = None
     def handler(event):                         # noqa
         nonlocal hits
         if isinstance(event, AcceptEvent):
             hits = event.msg['x-mailman-rule-hits']
     with event_subscribers(handler):
         process_chain(self._mlist, self._msg, {}, start_chain='mine')
     self.assertEqual(hits, 'first; second; third')
Example #12
0
 def test_reject_reasons(self):
     # The bounce message must contain the moderation reasons.
     msgdata = dict(moderation_reasons=[
         'TEST-REASON-1',
         'TEST-REASON-2',
         ])
     process_chain(self._mlist, self._msg, msgdata, start_chain='reject')
     bounces = get_queue_messages('virgin', expected_count=1)
     payload = bounces[0].msg.get_payload(0).as_string()
     self.assertIn('TEST-REASON-1', payload)
     self.assertIn('TEST-REASON-2', payload)
Example #13
0
    def test_discard(self):
        msgdata = dict(dmarc_action='discard')
        # When a message is discarded, the only artifacts are a log message
        # and an event.  Catch the event to prove it happened.
        events = []

        def handler(event):  # noqa: E306
            if isinstance(event, DiscardEvent):
                events.append(event)

        with event_subscribers(handler):
            process_chain(self._mlist, self._msg, msgdata, start_chain='dmarc')
        self.assertEqual(len(events), 1)
        self.assertIs(events[0].msg, self._msg)
Example #14
0
    def test_hold_chain_no_reasons_given(self):
        msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: A message
Message-ID: <ant>
MIME-Version: 1.0

A message body.
""")
        process_chain(self._mlist, msg, {}, start_chain='hold')
        # No reason was given, so a default is used.
        requests = IListRequests(self._mlist)
        self.assertEqual(requests.count_of(RequestType.held_message), 1)
        request = requests.of_type(RequestType.held_message)[0]
        key, data = requests.get_request(request.id)
        self.assertEqual(data.get('_mod_reason'), 'n/a')
Example #15
0
    def test_hold_chain(self):
        msg = mfs("""\
From: [email protected]
To: [email protected]
Subject: A message
Message-ID: <ant>
MIME-Version: 1.0

A message body.
""")
        msgdata = dict(moderation_reasons=[
            'TEST-REASON-1',
            'TEST-REASON-2',
            ('TEST-{}-REASON-{}', 'FORMAT', 3),
            ])
        logfile = LogFileMark('mailman.vette')
        process_chain(self._mlist, msg, msgdata, start_chain='hold')
        messages = get_queue_messages('virgin', expected_count=2)
        payloads = {}
        for item in messages:
            if item.msg['to'] == '*****@*****.**':
                part = item.msg.get_payload(0)
                payloads['owner'] = part.get_payload().splitlines()
            elif item.msg['To'] == '*****@*****.**':
                payloads['sender'] = item.msg.get_payload().splitlines()
            else:
                self.fail('Unexpected message: %s' % item.msg)
        self.assertIn('    TEST-REASON-1', payloads['owner'])
        self.assertIn('    TEST-REASON-2', payloads['owner'])
        self.assertIn('    TEST-FORMAT-REASON-3', payloads['owner'])
        self.assertIn('    TEST-REASON-1', payloads['sender'])
        self.assertIn('    TEST-REASON-2', payloads['sender'])
        self.assertIn('    TEST-FORMAT-REASON-3', payloads['sender'])
        logged = logfile.read()
        self.assertIn('TEST-REASON-1', logged)
        self.assertIn('TEST-REASON-2', logged)
        self.assertIn('TEST-FORMAT-REASON-3', logged)
        # Check the reason passed to hold_message().
        requests = IListRequests(self._mlist)
        self.assertEqual(requests.count_of(RequestType.held_message), 1)
        request = requests.of_type(RequestType.held_message)[0]
        key, data = requests.get_request(request.id)
        self.assertEqual(
            data.get('_mod_reason'),
            'TEST-REASON-1; TEST-REASON-2; TEST-FORMAT-REASON-3')
Example #16
0
 def test_no_reason(self):
     # There may be no moderation reasons.
     process_chain(self._mlist, self._msg, {}, start_chain='reject')
     bounces = get_queue_messages('virgin', expected_count=1)
     payload = bounces[0].msg.get_payload(0).as_string()
     self.assertIn('No bounce details are available', payload)
Example #17
0
 def test_no_reason(self):
     # There may be no moderation reasons.
     process_chain(self._mlist, self._msg, {}, start_chain='reject')
     bounces = get_queue_messages('virgin', expected_count=1)
     payload = bounces[0].msg.get_payload(0).as_string()
     self.assertIn('No bounce details are available', payload)