From 792407be592b8e7d523cb134a01b09101cbc2cad Mon Sep 17 00:00:00 2001 From: Mark Sapiro Date: Fri, 23 Jan 2015 15:50:47 -0800 Subject: Implemented the equivalent domains feature for list posting/moderation. --- Mailman/Defaults.py.in | 22 +++++++++++++++++++++- Mailman/Gui/Privacy.py | 27 +++++++++++++++++++++++++++ Mailman/Handlers/Moderate.py | 6 ++++++ Mailman/MailList.py | 2 ++ Mailman/Utils.py | 34 ++++++++++++++++++++++++++++++++++ Mailman/versions.py | 2 ++ NEWS | 7 +++++++ 7 files changed, 99 insertions(+), 1 deletion(-) diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in index 8a5e6b0e..8049c36c 100755 --- a/Mailman/Defaults.py.in +++ b/Mailman/Defaults.py.in @@ -1101,7 +1101,27 @@ DMARC_RESOLVER_TIMEOUT = seconds(3) # The total time to spend trying to get an answer to the question. DMARC_RESOLVER_LIFETIME = seconds(5) -# What shold happen to non-member posts which are do not match explicit +# What domains should be considered equivalent when testing list membership +# for posting/moderation. +# If two poster addresses with the same local part but +# different domains are to be considered equivalents for list +# membership tests, the domains are put here. The format is +# one or more groups of equivalent domains. Within a group, +# the domains are separated by commas and multiple groups are +# separated by semicolons. White space is ignored. +# For example: +# +# 'example.com,mail.example.com;mac.com,me.com,icloud.com' +# +# In this example, if user@example.com is a list member, +# a post from user@mail.example.com will be treated as if it is +# from user@example.com for list membership/moderation purposes, +# and likewise, if user@me.com is a list member, posts from +# user@mac.com or user@icloud.com will be treated as if from +# user@me.com. +DEFAULT_EQUIVALENT_DOMAINS = '' + +# What should happen to non-member posts which are do not match explicit # non-member actions? # 0 = Accept # 1 = Hold diff --git a/Mailman/Gui/Privacy.py b/Mailman/Gui/Privacy.py index 3c32bf50..905532ae 100644 --- a/Mailman/Gui/Privacy.py +++ b/Mailman/Gui/Privacy.py @@ -302,6 +302,33 @@ class Privacy(GUIBase): be sent to anyone who posts to this list from a domain with a DMARC Reject%(quarantine)s Policy.""")), + ('equivalent_domains', mm_cfg.Text, (10, WIDTH), 1, + _("""A 'two dimensional' list of email address domains which are + considered equivalent when checking if a post is from a list + member."""), + + _("""If two poster addresses with the same local part but + different domains are to be considered equivalents for list + membership tests, the domains are put here. The format is + one or more groups of equivalent domains. Within a group, + the domains are separated by commas and multiple groups are + separated by semicolons. White space is ignored. +

For example:

+               example.com,mail.example.com;mac.com,me.com,icloud.com
+               
+

In this example, if user@example.com is a list member, + a post from user@mail.example.com will be treated as if it is + from user@example.com for list membership/moderation purposes, + and likewise, if user@me.com is a list member, posts from + user@mac.com or user@icloud.com will be treated as if from + user@me.com. +

Note that the poster's address is first tested for list + membership, and the equivalent domain addresses are only tested + if the poster's address is not that of a member. +

Also note that moderation of the equivalent domain address + will apply to the post, but other options such as 'ack' or + 'not metoo' will not.""")), + _('Non-member filters'), ('accept_these_nonmembers', mm_cfg.EmailListEx, (10, WIDTH), 1, diff --git a/Mailman/Handlers/Moderate.py b/Mailman/Handlers/Moderate.py index 225ee37f..dfc2c567 100644 --- a/Mailman/Handlers/Moderate.py +++ b/Mailman/Handlers/Moderate.py @@ -54,6 +54,12 @@ def process(mlist, msg, msgdata): for sender in msg.get_senders(): if mlist.isMember(sender): break + for sender in Utils.check_eq_domains(sender, + mlist.equivalent_domains): + if mlist.isMember(sender): + break + if mlist.isMember(sender): + break else: sender = None if sender: diff --git a/Mailman/MailList.py b/Mailman/MailList.py index dca8c8f5..88bd320b 100755 --- a/Mailman/MailList.py +++ b/Mailman/MailList.py @@ -395,6 +395,8 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin, self.dmarc_quarantine_moderation_action = ( mm_cfg.DEFAULT_DMARC_QUARANTINE_MODERATION_ACTION) self.dmarc_moderation_notice = '' + self.equivalent_domains = ( + mm_cfg.DEFAULT_EQUIVALENT_DOMAINS) self.accept_these_nonmembers = [] self.hold_these_nonmembers = [] self.reject_these_nonmembers = [] diff --git a/Mailman/Utils.py b/Mailman/Utils.py index 0cb9f122..13c4ed8b 100644 --- a/Mailman/Utils.py +++ b/Mailman/Utils.py @@ -1216,3 +1216,37 @@ def IsDMARCProhibited(mlist, email): return False + +def check_eq_domains(email, domains_list): + """The arguments are an email address and a string representing a + list of lists in a form like 'a,b,c;1,2' representing [['a', 'b', + 'c'],['1', '2']]. The inner lists are domains which are + equivalent in some sense. The return is an empty list or a list + of email addresses equivalent to the first argument. + For example, given + + email = 'user@me.com' + domains_list = '''domain1, domain2; mac.com, me.com, icloud.com; + domaina, domainb + ''' + + check_eq_domains(email, domains_list) will return + ['user@mac.com', 'user@icloud.com'] + """ + if not domains_list: + return [] + try: + local, domain = email.rsplit('@', 1) + except ValueError: + return [] + domain = domain.lower() + domains_list = re.sub('\s', '', domains_list).lower() + domains = domains_list.split(';') + domains_list = [] + for d in domains: + domains_list.append(d.split(',')) + for domains in domains_list: + if domain in domains: + return [local + '@' + x for x in domains if x != domain] + return [] + diff --git a/Mailman/versions.py b/Mailman/versions.py index d0960e0d..ffcd49e5 100755 --- a/Mailman/versions.py +++ b/Mailman/versions.py @@ -407,6 +407,8 @@ def NewVars(l): add_only_if_missing('dmarc_quarantine_moderation_action', mm_cfg.DEFAULT_DMARC_QUARANTINE_MODERATION_ACTION) add_only_if_missing('dmarc_moderation_notice', '') + add_only_if_missing('equivalent_domains', + mm_cfg.DEFAULT_EQUIVALENT_DOMAINS) add_only_if_missing('new_member_options', mm_cfg.DEFAULT_NEW_MEMBER_OPTIONS) # Emergency moderation flag diff --git a/NEWS b/NEWS index 2b736f0f..4dad342c 100755 --- a/NEWS +++ b/NEWS @@ -64,6 +64,13 @@ Here is a history of user visible changes to Mailman. New Features + - There is a new list attribute equivalent_domains and a + DEFAULT_EQUIVALENT_DOMAINS setting to set the default for new lists which + in turn defaults to the empty string. This provides a way to specify one + or more groups of domains, e.g., mac.com, me.com, icloud.com, which are + considered equivalent for validating list membership for posting and + moderation purposes. + - There is a new WEB_HEAD_ADD setting to specify text to be added to the section of Mailman's internally generated web pages. This doesn't apply to pages built from templates, but in those cases, custom templates -- cgit v1.2.3