aboutsummaryrefslogtreecommitdiffstats
path: root/Mailman
diff options
context:
space:
mode:
authorMark Sapiro <mark@msapiro.net>2020-01-09 17:00:40 -0800
committerMark Sapiro <mark@msapiro.net>2020-01-09 17:00:40 -0800
commit300671a6c0181f9792cb6bdc9d03f9016d3d1327 (patch)
treedf6af1a3727112ac3a1c37547df69c9120af8126 /Mailman
parentcf47ad68d9cdb269f3c1ea3d57f8b484141bfad5 (diff)
downloadmailman2-300671a6c0181f9792cb6bdc9d03f9016d3d1327.tar.gz
mailman2-300671a6c0181f9792cb6bdc9d03f9016d3d1327.tar.xz
mailman2-300671a6c0181f9792cb6bdc9d03f9016d3d1327.zip
Implement REFUSE_SECOND_PENDING setting to prevent multiple pending subscribes.
Diffstat (limited to 'Mailman')
-rw-r--r--Mailman/Cgi/subscribe.py3
-rw-r--r--Mailman/Commands/cmd_subscribe.py4
-rwxr-xr-xMailman/Defaults.py.in8
-rw-r--r--Mailman/Errors.py1
-rw-r--r--Mailman/MailList.py21
5 files changed, 37 insertions, 0 deletions
diff --git a/Mailman/Cgi/subscribe.py b/Mailman/Cgi/subscribe.py
index ce7940f9..795fc81b 100644
--- a/Mailman/Cgi/subscribe.py
+++ b/Mailman/Cgi/subscribe.py
@@ -291,6 +291,9 @@ your subscription.""")
Your subscription request was deferred because %(x)s. Your request has been
forwarded to the list moderator. You will receive email informing you of the
moderator's decision when they get to your request.""")
+ except Errors.MMAlreadyPending:
+ # User already has a subscription pending
+ results = _('You already have a subscription pending confirmation')
except Errors.MMAlreadyAMember:
# Results string depends on whether we have private rosters or not
if not privacy_results:
diff --git a/Mailman/Commands/cmd_subscribe.py b/Mailman/Commands/cmd_subscribe.py
index abe8b762..098740c8 100644
--- a/Mailman/Commands/cmd_subscribe.py
+++ b/Mailman/Commands/cmd_subscribe.py
@@ -128,6 +128,10 @@ the email address you gave is insecure."""))
except Errors.MMAlreadyAMember:
res.results.append(_('You are already subscribed!'))
return STOP
+ except Errors.MMAlreadyPending:
+ res.results.append(
+ _('You already have a subscription pending confirmation'))
+ return STOP
except Errors.MMCantDigestError:
res.results.append(
_('No one can subscribe to the digest of this list!'))
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in
index b45abf7b..277e3ab0 100755
--- a/Mailman/Defaults.py.in
+++ b/Mailman/Defaults.py.in
@@ -1122,6 +1122,14 @@ ANONYMOUS_LIST_KEEP_HEADERS = ['^(?!x-)', '^x-mailman-',
'^x-ack:', '^x-beenthere:',
'^x-list-administrivia:', '^x-spam-',
]
+#
+# It is possible to mailbomb a third party by repeatrdly posting the subscribe
+# form. You can prevent this by setting the following to Yes which will refuse
+# pending a subscription confirmation when one is already pending. The down
+# side to this is if a subscriber loses or doesn't receive the confirmation
+# request email, she has to wait PENDING_REQUEST_LIFE (default 3 days) before
+# she can request another.
+REFUSE_SECOND_PENDING = No
diff --git a/Mailman/Errors.py b/Mailman/Errors.py
index f4895248..b502ffbf 100644
--- a/Mailman/Errors.py
+++ b/Mailman/Errors.py
@@ -31,6 +31,7 @@ class BadListNameError(MMListError): pass
class MMMemberError(Exception): pass
class MMBadUserError(MMMemberError): pass
class MMAlreadyAMember(MMMemberError): pass
+class MMAlreadyPending(MMMemberError): pass
# "New" style membership exceptions (new w/ MM2.1)
class MemberError(Exception): pass
diff --git a/Mailman/MailList.py b/Mailman/MailList.py
index 12d75aff..9e6bbcb6 100644
--- a/Mailman/MailList.py
+++ b/Mailman/MailList.py
@@ -833,6 +833,25 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
#
# Membership management front-ends and assertion checks
#
+ def CheckPending(self, email):
+ """Check if there is already an unexpired pending subscription for
+ this email.
+ """
+ if not mm_cfg.REFUSE_SECOND_PENDING:
+ return False
+ pends = self._Pending__load()
+ # Save and reload the db to evict expired pendings.
+ self._Pending__save(pends)
+ pends = self._Pending__load()
+ for k, v in pends.items():
+ if k in ('evictions', 'version'):
+ continue
+ op, data = v
+ if (op == Pending.SUBSCRIPTION and
+ data.address.lower() == email.lower()):
+ return True
+ return False
+
def InviteNewMember(self, userdesc, text=''):
"""Invite a new member to the list.
@@ -919,6 +938,8 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
Utils.ValidateEmail(email)
if self.isMember(email):
raise Errors.MMAlreadyAMember, email
+ if self.CheckPending(email):
+ raise Errors.MMAlreadyPending, email
if email.lower() == self.GetListEmail().lower():
# Trying to subscribe the list to itself!
raise Errors.MMBadEmailError