summaryrefslogtreecommitdiff
path: root/Mailman/Handlers/Approve.py
diff options
context:
space:
mode:
Diffstat (limited to 'Mailman/Handlers/Approve.py')
-rw-r--r--Mailman/Handlers/Approve.py64
1 files changed, 26 insertions, 38 deletions
diff --git a/Mailman/Handlers/Approve.py b/Mailman/Handlers/Approve.py
index 1ff58abf0..1198e6ea7 100644
--- a/Mailman/Handlers/Approve.py
+++ b/Mailman/Handlers/Approve.py
@@ -15,13 +15,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
-"""Determine whether the message is approved for delivery.
-
-This module only tests for definitive approvals. IOW, this module only
-determines whether the message is definitively approved or definitively
-denied. Situations that could hold a message for approval or confirmation are
-not tested by this module.
-"""
+"""Determine whether the message is pre-approved for delivery."""
import re
@@ -30,7 +24,7 @@ from email.Iterators import typed_subpart_iterator
from Mailman import Errors
from Mailman.configuration import config
-NL = '\n'
+EMPTYSTRING = ''
@@ -38,18 +32,15 @@ def process(mlist, msg, msgdata):
# Short circuits
if msgdata.get('approved'):
# Digests, Usenet postings, and some other messages come pre-approved.
- # TBD: we may want to further filter Usenet messages, so the test
- # above may not be entirely correct.
+ # XXX we may want to further filter Usenet messages, so the test above
+ # may not be entirely correct.
return
# See if the message has an Approved or Approve header with a valid
- # list-moderator, list-admin. Also look at the first non-whitespace line
- # in the file to see if it looks like an Approved header. We are
- # specifically /not/ allowing the site admins password to work here
- # because we want to discourage the practice of sending the site admin
- # password through email in the clear.
- missing = []
- passwd = msg.get('approved', msg.get('approve', missing))
- if passwd is missing:
+ # moderator password. Also look at the first non-whitespace line in the
+ # file to see if it looks like an Approved header.
+ missing = object()
+ password = msg.get('approved', msg.get('approve', missing))
+ if password is missing:
# Find the first text/plain part in the message
part = None
stripped = False
@@ -57,22 +48,19 @@ def process(mlist, msg, msgdata):
break
# XXX I'm not entirely sure why, but it is possible for the payload of
# the part to be None, and you can't splitlines() on None.
- if part is not None and part.get_payload() is not None:
- lines = part.get_payload(decode=True).splitlines()
- line = ''
- for lineno, line in zip(range(len(lines)), lines):
+ if part and part.get_payload() is not None:
+ lines = part.get_payload(decode=True).splitlines(True)
+ for lineno, line in enumerate(lines):
if line.strip():
break
- i = line.find(':')
- if i >= 0:
- name = line[:i]
- value = line[i+1:]
- if name.lower() in ('approve', 'approved'):
- passwd = value.lstrip()
+ if ':' in line:
+ header, value = line.split(':', 1)
+ if header.lower() in ('approved', 'approve'):
+ password = value.strip()
# Now strip the first line from the payload so the
# password doesn't leak.
del lines[lineno]
- reset_payload(part, NL.join(lines))
+ reset_payload(part, EMPTYSTRING.join(lines))
stripped = True
if stripped:
# MAS: Bug 1181161 - Now try all the text parts in case it's
@@ -84,35 +72,35 @@ def process(mlist, msg, msgdata):
#
# This will process all the multipart/alternative parts in the
# message as well as all other text parts. We shouldn't find the
- # pattern outside the mp/a parts, but if we do, it is probably
- # best to delete it anyway as it does contain the password.
+ # pattern outside the multipart/alternative parts, but if we do,
+ # it is probably best to delete it anyway as it does contain the
+ # password.
#
# Make a pattern to delete. We can't just delete a line because
# line of HTML or other fancy text may include additional message
# text. This pattern works with HTML. It may not work with rtf
# or whatever else is possible.
- pattern = name + ':(\s| )*' + re.escape(passwd)
+ pattern = header + ':(\s| )*' + re.escape(password)
for part in typed_subpart_iterator(msg, 'text'):
if part is not None and part.get_payload() is not None:
lines = part.get_payload(decode=True)
if re.search(pattern, lines):
reset_payload(part, re.sub(pattern, '', lines))
- if passwd is not missing and mlist.Authenticate((config.AuthListModerator,
- config.AuthListAdmin),
- passwd):
+ if password is not missing and password == mlist.moderator_password:
# BAW: should we definitely deny if the password exists but does not
# match? For now we'll let it percolate up for further determination.
msgdata['approved'] = True
# Used by the Emergency module
msgdata['adminapproved'] = True
- # has this message already been posted to this list?
+ # Has this message already been posted to this list?
beentheres = [s.strip().lower() for s in msg.get_all('x-beenthere', [])]
- if mlist.GetListEmail().lower() in beentheres:
+ if mlist.posting_address in beentheres:
raise Errors.LoopError
+
def reset_payload(part, payload):
# Set decoded payload maintaining content-type, format and delsp.
- # TK: Message with 'charset=' cause trouble. So, instead of
+ # TK: Messages with 'charset=' cause trouble. So, instead of
# part.get_content_charset('us-ascii') ...
cset = part.get_content_charset() or 'us-ascii'
ctype = part.get_content_type()