summaryrefslogtreecommitdiff
path: root/src/mailman/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailman/app')
-rw-r--r--src/mailman/app/docs/bans.rst167
-rw-r--r--src/mailman/app/membership.py7
-rw-r--r--src/mailman/app/tests/test_membership.py57
3 files changed, 226 insertions, 5 deletions
diff --git a/src/mailman/app/docs/bans.rst b/src/mailman/app/docs/bans.rst
new file mode 100644
index 000000000..bb6d5902e
--- /dev/null
+++ b/src/mailman/app/docs/bans.rst
@@ -0,0 +1,167 @@
+=======================
+Banning email addresses
+=======================
+
+Email addresses can be banned from ever subscribing, either to a specific
+mailing list or globally within the Mailman system. Both explicit email
+addresses and email address patterns can be banned.
+
+Bans are managed through the `Ban Manager`.
+
+ >>> from zope.component import getUtility
+ >>> from mailman.interfaces.bans import IBanManager
+ >>> ban_manager = getUtility(IBanManager)
+
+At first, no email addresses are banned, either globally...
+
+ >>> ban_manager.is_banned('anne@example.com')
+ False
+
+...or for a specific mailing list.
+
+ >>> ban_manager.is_banned('bart@example.com', 'test@example.com')
+ False
+
+
+Specific bans
+=============
+
+An email address can be banned from a specific mailing list by adding a ban to
+the ban manager.
+
+ >>> ban_manager.ban('cris@example.com', 'test@example.com')
+ >>> ban_manager.is_banned('cris@example.com', 'test@example.com')
+ True
+ >>> ban_manager.is_banned('bart@example.com', 'test@example.com')
+ False
+
+However, this is not a global ban.
+
+ >>> ban_manager.is_banned('cris@example.com')
+ False
+
+
+Global bans
+===========
+
+An email address can be banned globally, so that it cannot be subscribed to
+any mailing list.
+
+ >>> ban_manager.ban('dave@example.com')
+
+Dave is banned from the test mailing list...
+
+ >>> ban_manager.is_banned('dave@example.com', 'test@example.com')
+ True
+
+...and the sample mailing list.
+
+ >>> ban_manager.is_banned('dave@example.com', 'sample@example.com')
+ True
+
+Dave is also banned globally.
+
+ >>> ban_manager.is_banned('dave@example.com')
+ True
+
+Cris however is not banned globally.
+
+ >>> ban_manager.is_banned('cris@example.com')
+ False
+
+Even though Cris is not banned globally, we can add a global ban for her.
+
+ >>> ban_manager.ban('cris@example.com')
+ >>> ban_manager.is_banned('cris@example.com')
+ True
+
+Cris is obviously still banned from specific mailing lists.
+
+ >>> ban_manager.is_banned('cris@example.com', 'test@example.com')
+ True
+ >>> ban_manager.is_banned('cris@example.com', 'sample@example.com')
+ True
+
+We can remove the global ban to once again just ban her address from the test
+list.
+
+ >>> ban_manager.unban('cris@example.com')
+ >>> ban_manager.is_banned('cris@example.com', 'test@example.com')
+ True
+ >>> ban_manager.is_banned('cris@example.com', 'sample@example.com')
+ False
+
+
+Regular expression bans
+=======================
+
+Entire email address patterns can be banned, both for a specific mailing list
+and globally, just as specific addresses can be banned. Use this for example,
+when an entire domain is a spam faucet. When using a pattern, the email
+address must start with a caret (^).
+
+ >>> ban_manager.ban('^.*@example.org', 'test@example.com')
+
+Now, no one from example.org can subscribe to the test list.
+
+ >>> ban_manager.is_banned('elle@example.org', 'test@example.com')
+ True
+ >>> ban_manager.is_banned('eperson@example.org', 'test@example.com')
+ True
+ >>> ban_manager.is_banned('elle@example.com', 'test@example.com')
+ False
+
+They are not, however banned globally.
+
+ >>> ban_manager.is_banned('elle@example.org', 'sample@example.com')
+ False
+ >>> ban_manager.is_banned('elle@example.org')
+ False
+
+Of course, we can ban everyone from example.org globally too.
+
+ >>> ban_manager.ban('^.*@example.org')
+ >>> ban_manager.is_banned('elle@example.org', 'sample@example.com')
+ True
+ >>> ban_manager.is_banned('elle@example.org')
+ True
+
+We can remove the mailing list ban on the pattern, though the global ban will
+still be in place.
+
+ >>> ban_manager.unban('^.*@example.org', 'test@example.com')
+ >>> ban_manager.is_banned('elle@example.org', 'test@example.com')
+ True
+ >>> ban_manager.is_banned('elle@example.org', 'sample@example.com')
+ True
+ >>> ban_manager.is_banned('elle@example.org')
+ True
+
+But once the global ban is removed, everyone from example.org can subscribe to
+the mailing lists.
+
+ >>> ban_manager.unban('^.*@example.org')
+ >>> ban_manager.is_banned('elle@example.org', 'test@example.com')
+ False
+ >>> ban_manager.is_banned('elle@example.org', 'sample@example.com')
+ False
+ >>> ban_manager.is_banned('elle@example.org')
+ False
+
+
+Adding and removing bans
+========================
+
+It is not an error to add a ban more than once. These are just ignored.
+
+ >>> ban_manager.ban('fred@example.com', 'test@example.com')
+ >>> ban_manager.ban('fred@example.com', 'test@example.com')
+ >>> ban_manager.is_banned('fred@example.com', 'test@example.com')
+ True
+
+Nor is it an error to remove a ban more than once.
+
+ >>> ban_manager.unban('fred@example.com', 'test@example.com')
+ >>> ban_manager.unban('fred@example.com', 'test@example.com')
+ >>> ban_manager.is_banned('fred@example.com', 'test@example.com')
+ False
diff --git a/src/mailman/app/membership.py b/src/mailman/app/membership.py
index 32ba1ff42..8723fd781 100644
--- a/src/mailman/app/membership.py
+++ b/src/mailman/app/membership.py
@@ -34,6 +34,7 @@ from mailman.app.notifications import send_goodbye_message
from mailman.core.i18n import _
from mailman.email.message import OwnerNotification
from mailman.interfaces.address import IEmailValidator
+from mailman.interfaces.bans import IBanManager
from mailman.interfaces.member import (
AlreadySubscribedError, MemberRole, MembershipIsBannedError,
NotAMemberError)
@@ -71,10 +72,8 @@ def add_member(mlist, email, realname, password, delivery_mode, language):
if mlist.members.get_member(email) is not None:
raise AlreadySubscribedError(
mlist.fqdn_listname, email, MemberRole.member)
- # Check for banned email addresses here too for administrative mass
- # subscribes and confirmations.
- pattern = Utils.get_pattern(email, mlist.ban_list)
- if pattern:
+ # Check to see if the email address is banned.
+ if getUtility(IBanManager).is_banned(email, mlist.fqdn_listname):
raise MembershipIsBannedError(mlist, email)
# See if there's already a user linked with the given address.
user_manager = getUtility(IUserManager)
diff --git a/src/mailman/app/tests/test_membership.py b/src/mailman/app/tests/test_membership.py
index dc8009f65..b0e1bae5d 100644
--- a/src/mailman/app/tests/test_membership.py
+++ b/src/mailman/app/tests/test_membership.py
@@ -32,7 +32,8 @@ from zope.component import getUtility
from mailman.app.lifecycle import create_list
from mailman.app.membership import add_member
from mailman.core.constants import system_preferences
-from mailman.interfaces.member import DeliveryMode
+from mailman.interfaces.bans import IBanManager
+from mailman.interfaces.member import DeliveryMode, MembershipIsBannedError
from mailman.interfaces.usermanager import IUserManager
from mailman.testing.helpers import reset_the_world
from mailman.testing.layers import ConfigLayer
@@ -68,6 +69,60 @@ class AddMemberTest(unittest.TestCase):
self.assertEqual(member.address.email, 'aperson@example.com')
self.assertEqual(member.mailing_list, 'test@example.com')
+ def test_add_member_banned(self):
+ # Test that members who are banned by specific address cannot
+ # subscribe to the mailing list.
+ getUtility(IBanManager).ban('anne@example.com', 'test@example.com')
+ self.assertRaises(
+ MembershipIsBannedError,
+ add_member, self._mlist, 'anne@example.com', 'Anne Person',
+ '123', DeliveryMode.regular, system_preferences.preferred_language)
+
+ def test_add_member_globally_banned(self):
+ # Test that members who are banned by specific address cannot
+ # subscribe to the mailing list.
+ getUtility(IBanManager).ban('anne@example.com')
+ self.assertRaises(
+ MembershipIsBannedError,
+ add_member, self._mlist, 'anne@example.com', 'Anne Person',
+ '123', DeliveryMode.regular, system_preferences.preferred_language)
+
+ def test_add_member_banned_from_different_list(self):
+ # Test that members who are banned by specific address cannot
+ # subscribe to the mailing list.
+ getUtility(IBanManager).ban('anne@example.com', 'sample@example.com')
+ member = add_member(self._mlist, 'anne@example.com',
+ 'Anne Person', '123', DeliveryMode.regular,
+ system_preferences.preferred_language)
+ self.assertEqual(member.address.email, 'anne@example.com')
+
+ def test_add_member_banned_by_pattern(self):
+ # Test that members who are banned by specific address cannot
+ # subscribe to the mailing list.
+ getUtility(IBanManager).ban('^.*@example.com', 'test@example.com')
+ self.assertRaises(
+ MembershipIsBannedError,
+ add_member, self._mlist, 'anne@example.com', 'Anne Person',
+ '123', DeliveryMode.regular, system_preferences.preferred_language)
+
+ def test_add_member_globally_banned_by_pattern(self):
+ # Test that members who are banned by specific address cannot
+ # subscribe to the mailing list.
+ getUtility(IBanManager).ban('^.*@example.com')
+ self.assertRaises(
+ MembershipIsBannedError,
+ add_member, self._mlist, 'anne@example.com', 'Anne Person',
+ '123', DeliveryMode.regular, system_preferences.preferred_language)
+
+ def test_add_member_banned_from_different_list_by_pattern(self):
+ # Test that members who are banned by specific address cannot
+ # subscribe to the mailing list.
+ getUtility(IBanManager).ban('^.*@example.com', 'sample@example.com')
+ member = add_member(self._mlist, 'anne@example.com',
+ 'Anne Person', '123', DeliveryMode.regular,
+ system_preferences.preferred_language)
+ self.assertEqual(member.address.email, 'anne@example.com')
+
def test_suite():