summaryrefslogtreecommitdiff
path: root/src/mailman
diff options
context:
space:
mode:
authorAurélien Bompard2016-09-27 18:40:30 +0200
committerAurélien Bompard2016-10-27 10:29:03 +0200
commit54136248b53411cd0e2c65ec4d846edee6ef0dec (patch)
tree3078fad18d6684a39ac04c97c73d04ea63bc319a /src/mailman
parentd2f59ff1d0d2b30763529543a68b0a4fdb9e28c6 (diff)
downloadmailman-54136248b53411cd0e2c65ec4d846edee6ef0dec.tar.gz
mailman-54136248b53411cd0e2c65ec4d846edee6ef0dec.tar.zst
mailman-54136248b53411cd0e2c65ec4d846edee6ef0dec.zip
Diffstat (limited to 'src/mailman')
-rw-r--r--src/mailman/chains/builtin.py2
-rw-r--r--src/mailman/chains/docs/moderation.rst5
-rw-r--r--src/mailman/core/docs/chains.rst8
-rw-r--r--src/mailman/rules/banned_address.py42
-rw-r--r--src/mailman/rules/docs/rules.rst1
-rw-r--r--src/mailman/rules/tests/test_banned_address.py119
-rw-r--r--src/mailman/runners/docs/incoming.rst7
7 files changed, 178 insertions, 6 deletions
diff --git a/src/mailman/chains/builtin.py b/src/mailman/chains/builtin.py
index f3ff501be..b805fca0f 100644
--- a/src/mailman/chains/builtin.py
+++ b/src/mailman/chains/builtin.py
@@ -41,6 +41,8 @@ class BuiltInChain:
('approved', LinkAction.jump, 'accept'),
('emergency', LinkAction.jump, 'hold'),
('loop', LinkAction.jump, 'discard'),
+ # Discard emails from banned addresses.
+ ('banned-address', LinkAction.jump, 'discard'),
# Determine whether the member or nonmember has an action shortcut.
('member-moderation', LinkAction.jump, 'moderation'),
# Take a detour through the header matching chain.
diff --git a/src/mailman/chains/docs/moderation.rst b/src/mailman/chains/docs/moderation.rst
index 880f9b63c..3b40c7293 100644
--- a/src/mailman/chains/docs/moderation.rst
+++ b/src/mailman/chains/docs/moderation.rst
@@ -90,6 +90,7 @@ built-in chain. No rules hit and so the message is accepted.
approved
emergency
loop
+ banned-address
member-moderation
nonmember-moderation
administrivia
@@ -126,6 +127,7 @@ moderator approval.
approved
emergency
loop
+ banned-address
Anne's moderation action can also be set to `discard`...
::
@@ -151,6 +153,7 @@ Anne's moderation action can also be set to `discard`...
approved
emergency
loop
+ banned-address
... or `reject`.
@@ -175,6 +178,7 @@ Anne's moderation action can also be set to `discard`...
approved
emergency
loop
+ banned-address
Nonmembers
@@ -214,6 +218,7 @@ moderator approval.
approved
emergency
loop
+ banned-address
member-moderation
>>> nonmember = mlist.nonmembers.get_member('bart@example.com')
diff --git a/src/mailman/core/docs/chains.rst b/src/mailman/core/docs/chains.rst
index f5cbf2d89..2b30a25e4 100644
--- a/src/mailman/core/docs/chains.rst
+++ b/src/mailman/core/docs/chains.rst
@@ -268,9 +268,10 @@ This message will end up in the `pipeline` queue.
Message-ID: <first>
Message-ID-Hash: 4CMWUN6BHVCMHMDAOSJZ2Q72G5M32MWB
X-Message-ID-Hash: 4CMWUN6BHVCMHMDAOSJZ2Q72G5M32MWB
- X-Mailman-Rule-Misses: approved; emergency; loop; member-moderation;
- nonmember-moderation; administrivia; implicit-dest; max-recipients;
- max-size; news-moderation; no-subject; suspicious-header
+ X-Mailman-Rule-Misses: approved; emergency; loop; banned-address;
+ member-moderation; nonmember-moderation; administrivia; implicit-dest;
+ max-recipients; max-size; news-moderation; no-subject;
+ suspicious-header
<BLANKLINE>
An important message.
<BLANKLINE>
@@ -283,6 +284,7 @@ hit and all rules that have missed.
>>> dump_list(qfiles[0].msgdata['rule_misses'])
administrivia
approved
+ banned-address
emergency
implicit-dest
loop
diff --git a/src/mailman/rules/banned_address.py b/src/mailman/rules/banned_address.py
new file mode 100644
index 000000000..8ed33a5e6
--- /dev/null
+++ b/src/mailman/rules/banned_address.py
@@ -0,0 +1,42 @@
+# Copyright (C) 2016 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Banned addresses rule."""
+
+from mailman import public
+from mailman.core.i18n import _
+from mailman.interfaces.bans import IBanManager
+from mailman.interfaces.rules import IRule
+from zope.interface import implementer
+
+
+@public
+@implementer(IRule)
+class BannedAddress:
+ """The banned address rule."""
+
+ name = 'banned-address'
+ description = _('Match messages sent by banned addresses.')
+ record = True
+
+ def check(self, mlist, msg, msgdata):
+ """See `IRule`."""
+ ban_manager = IBanManager(mlist)
+ for sender in msg.senders:
+ if ban_manager.is_banned(sender):
+ return True
+ return False
diff --git a/src/mailman/rules/docs/rules.rst b/src/mailman/rules/docs/rules.rst
index f82167a55..812486b45 100644
--- a/src/mailman/rules/docs/rules.rst
+++ b/src/mailman/rules/docs/rules.rst
@@ -21,6 +21,7 @@ names to rule objects.
administrivia True
any True
approved True
+ banned-address True
emergency True
implicit-dest True
loop True
diff --git a/src/mailman/rules/tests/test_banned_address.py b/src/mailman/rules/tests/test_banned_address.py
new file mode 100644
index 000000000..5a0f50b65
--- /dev/null
+++ b/src/mailman/rules/tests/test_banned_address.py
@@ -0,0 +1,119 @@
+# Copyright (C) 2016 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Test the `banned-address` rule."""
+
+import unittest
+
+from mailman.app.lifecycle import create_list
+from mailman.interfaces.bans import IBanManager
+from mailman.interfaces.usermanager import IUserManager
+from mailman.rules import banned_address
+from mailman.testing.helpers import (
+ set_preferred, specialized_message_from_string as mfs)
+from mailman.testing.layers import ConfigLayer
+from zope.component import getUtility
+
+
+class TestBannedAddress(unittest.TestCase):
+ """Test the banned-address rule."""
+
+ layer = ConfigLayer
+
+ def setUp(self):
+ self._mlist = create_list('test@example.com')
+
+ def test_no_banned_sender(self):
+ # Simple case where the sender is not banned.
+ user_manager = getUtility(IUserManager)
+ anne = user_manager.create_user('anne@example.com')
+ set_preferred(anne)
+ msg = mfs("""\
+From: anne@example.com
+To: test@example.com
+Subject: A test message
+Message-ID: <ant>
+MIME-Version: 1.0
+
+A message body.
+""")
+ rule = banned_address.BannedAddress()
+ result = rule.check(self._mlist, msg, {})
+ self.assertFalse(result)
+
+ def test_simple_banned_sender(self):
+ # Simple case where the sender is banned.
+ user_manager = getUtility(IUserManager)
+ anne = user_manager.create_user('anne@example.com')
+ set_preferred(anne)
+ IBanManager(self._mlist).ban('anne@example.com')
+ msg = mfs("""\
+From: anne@example.com
+To: test@example.com
+Subject: A test message
+Message-ID: <ant>
+MIME-Version: 1.0
+
+A message body.
+""")
+ rule = banned_address.BannedAddress()
+ result = rule.check(self._mlist, msg, {})
+ self.assertTrue(result)
+
+ def test_banned_address_linked_to_user(self):
+ # Anne is subscribed to a mailing list as a user with her preferred
+ # address. She also has a secondary address which is banned and which
+ # she uses to post to the mailing list. The rule matches because the
+ # posting address is banned.
+ user_manager = getUtility(IUserManager)
+ anne = user_manager.create_user('anne@example.com')
+ set_preferred(anne)
+ anne.link(user_manager.create_address('anne.person@example.com'))
+ IBanManager(self._mlist).ban('anne.person@example.com')
+ msg = mfs("""\
+From: anne.person@example.com
+To: test@example.com
+Subject: A test message
+Message-ID: <ant>
+MIME-Version: 1.0
+
+A message body.
+""")
+ rule = banned_address.BannedAddress()
+ result = rule.check(self._mlist, msg, {})
+ self.assertTrue(result)
+
+ def test_banned_sender_among_multiple_senders(self):
+ # Two addresses are created, one of which is banned. The rule matches
+ # because all senders are checked.
+ user_manager = getUtility(IUserManager)
+ user_manager.create_address('anne@example.com')
+ user_manager.create_address('bart@example.com')
+ IBanManager(self._mlist).ban('bart@example.com')
+ msg = mfs("""\
+From: anne@example.com
+Sender: bart@example.com
+To: test@example.com
+Subject: A test message
+Message-ID: <ant>
+MIME-Version: 1.0
+
+A message body.
+""")
+ rule = banned_address.BannedAddress()
+ result = rule.check(self._mlist, msg, {})
+ self.assertTrue(result)
diff --git a/src/mailman/runners/docs/incoming.rst b/src/mailman/runners/docs/incoming.rst
index c5a354bde..70b870d18 100644
--- a/src/mailman/runners/docs/incoming.rst
+++ b/src/mailman/runners/docs/incoming.rst
@@ -128,9 +128,10 @@ Now the message is in the pipeline queue.
Message-ID-Hash: 4CMWUN6BHVCMHMDAOSJZ2Q72G5M32MWB
X-Message-ID-Hash: 4CMWUN6BHVCMHMDAOSJZ2Q72G5M32MWB
Date: ...
- X-Mailman-Rule-Misses: approved; emergency; loop; member-moderation;
- nonmember-moderation; administrivia; implicit-dest; max-recipients;
- max-size; news-moderation; no-subject; suspicious-header
+ X-Mailman-Rule-Misses: approved; emergency; loop; banned-address;
+ member-moderation; nonmember-moderation; administrivia; implicit-dest;
+ max-recipients; max-size; news-moderation; no-subject;
+ suspicious-header
<BLANKLINE>
First post!
<BLANKLINE>