1
# Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
1
# Copyright (C) 1998-2011 by the Free Software Foundation, Inc.
3
3
# This program is free software; you can redistribute it and/or
4
4
# modify it under the terms of the GNU General Public License
43
# message is translated when used.
45
REJECT = _("""Message rejected.
46
It appears that this message contains an HTML part with the
47
Approved: password line, but due to the way it is coded in the
48
HTML it can't be safely removed.
44
54
def process(mlist, msg, msgdata):
46
if msgdata.get('approved'):
56
# Do not short circuit. The problem is SpamDetect comes before Approve.
57
# Suppose a message with an Approved: header is held by SpamDetect (or
58
# any other handler that might come before Approve) and then approved
59
# by a moderator. When the approved message reaches Approve in the
60
# pipeline, we still need to remove the Approved: (pseudo-)header, so
61
# we can't short circuit.
62
#if msgdata.get('approved'):
47
63
# Digests, Usenet postings, and some other messages come pre-approved.
48
64
# TBD: we may want to further filter Usenet messages, so the test
49
65
# above may not be entirely correct.
51
67
# See if the message has an Approved or Approve header with a valid
52
68
# list-moderator, list-admin. Also look at the first non-whitespace line
53
69
# in the file to see if it looks like an Approved header. We are
55
71
# because we want to discourage the practice of sending the site admin
56
72
# password through email in the clear.
58
passwd = msg.get('approved', msg.get('approve', missing))
74
for hdr in ('approved', 'approve', 'x-approved', 'x-approve'):
75
passwd = msg.get(hdr, missing)
76
if passwd is not missing:
59
78
if passwd is missing:
60
79
# Find the first text/plain part in the message
87
110
# text part. We make a pattern from the Approved line and delete
88
111
# it from all text/* parts in which we find it. It would be
89
112
# better to just iterate forward, but email compatability for pre
90
# Python 2.2 returns a list, not a true iterator.
113
# Python 2.2 returns a list, not a true iterator. Also, there
114
# are pathological MUAs that put the HTML part first.
92
116
# This will process all the multipart/alternative parts in the
93
117
# message as well as all other text parts. We shouldn't find the
98
122
# line of HTML or other fancy text may include additional message
99
123
# text. This pattern works with HTML. It may not work with rtf
100
124
# or whatever else is possible.
101
pattern = name + ':(\s| )*' + re.escape(passwd)
126
# If we don't find the pattern in the decoded part, but we do
127
# find it after stripping HTML tags, we don't know how to remove
128
# it, so we just reject the post.
129
pattern = name + ':(\xA0|\s| )*' + re.escape(passwd)
102
130
for part in typed_subpart_iterator(msg, 'text'):
103
131
if part is not None and part.get_payload() is not None:
104
132
lines = part.get_payload(decode=True)
105
133
if re.search(pattern, lines):
106
134
reset_payload(part, re.sub(pattern, '', lines))
107
if passwd is not missing and mlist.Authenticate((mm_cfg.AuthListModerator,
135
elif re.search(pattern, re.sub('(?s)<.*?>', '', lines)):
136
raise Errors.RejectMessage, REJECT
137
if passwd is not missing and mlist.Authenticate((mm_cfg.AuthListPoster,
138
mm_cfg.AuthListModerator,
108
139
mm_cfg.AuthListAdmin),
110
141
# BAW: should we definitely deny if the password exists but does not