Additional questions about ban_list

Hello all,
I have been loosely following the discussion regarding regex in the ban_list attribute. I now find myself being asked to create a list which will most likely use the ban_list attribute. So, I have a few questions.
The ban_list attribute is to help prevent unwanted people from subscribing to a list, however, I want to restrict who can subscribe to the list and ban anyone else. I have the regex for who I want to allow to subscribe but there isn't an allow_list attribute. Is there an easy way of allowing a regex to control who is able to subscribe? Or, is there a way to easily invert the regex logic and use it in ban_list? As an example (not the real regex), say I want to only allow @gmail.com to subscribe to the list but no one else.
An additional requirement is to restrict a subgroup of the addresses from subscribing. In short, I want to allow all @gmail.com addresses to subscribe except for a known subgroup. Now the known subgroup is in a Mailman list. So, can I use a Mailman list in the ban_list attribute similar to using a list in *_these_members attributes? Or, would I have to modify the code to allow using a Mailman list in the ban_list attribute?
Thank you for your consideration, Chris

Hi Chris,
On Tuesday 06 October 2015 08:37 PM, Chris Nulk wrote:
Hello all,
I have been loosely following the discussion regarding regex in the ban_list attribute. I now find myself being asked to create a list which will most likely use the ban_list attribute. So, I have a few questions.
- The ban_list attribute is to help prevent unwanted people from subscribing to a list, however, I want to restrict who can subscribe to the list and ban anyone else. I have the regex for who I want to allow to subscribe but there isn't an allow_list attribute. Is there an easy way of allowing a regex to control who is able to subscribe? Or, is there a way to easily invert the regex logic and use it in ban_list? As an example (not the real regex), say I want to only allow @gmail.com to subscribe to the list but no one else. You can use ban_list to accomplish this. You just have to revert the matching criteria. For example if you want to allow only example.org and example.com you can use the following regex
^[^@]+@(?!(.*\.)?example\.(org|com)$)
Regards Aditya Jain

On 10/06/2015 08:07 AM, Chris Nulk wrote:
- The ban_list attribute is to help prevent unwanted people from subscribing to a list, however, I want to restrict who can subscribe to the list and ban anyone else. I have the regex for who I want to allow to subscribe but there isn't an allow_list attribute. Is there an easy way of allowing a regex to control who is able to subscribe? Or, is there a way to easily invert the regex logic and use it in ban_list? As an example (not the real regex), say I want to only allow @gmail.com to subscribe to the list but no one else.
As Aditya Jain replied, you can use Python RE negative lookahead assertions to create regexps with "doesn't match" conditions. See <https://docs.python.org/2/library/re.html#regular-expression-syntax>.
Although the posted regexp modified for gmail
^[^@]+@(?!(.*\.)?gmail\.com$)
will not match and hence allow, addresses like user@subdomain.gmail.com. To allow only '@gmail.com' addresses, e.g. to ban all non-'@gmail.com' addresses, use
^[^@]+@(?!gmail\.com$)
Often, if you have the regexp to allow, the regexp to ban may be as simple as
^(?!the_allow_regexp)
- An additional requirement is to restrict a subgroup of the addresses from subscribing. In short, I want to allow all @gmail.com addresses to subscribe except for a known subgroup. Now the known subgroup is in a Mailman list. So, can I use a Mailman list in the ban_list attribute similar to using a list in *_these_members attributes? Or, would I have to modify the code to allow using a Mailman list in the ban_list attribute?
Allowing @list_name in ban_list is a simple code modification if you don't care if various 'error' log messages such as list references itself or references non-existent list refer to 'subscribe_auto_approval' even if the error is in ban_list.
The change would be in this code in Mailman/Mail.List.py
def GetBannedPattern(self, email):
"""Returns matched entry in ban_list if email matches.
Otherwise returns None.
"""
return self.GetPattern(email, self.ban_list)
change the last line to
return self.GetPattern(email, self.ban_list, at_list=True)
Or, if you've installed the GLOBAL_BAN_LIST mod, make the change in each of the two lines in
return (self.GetPattern(email, self.ban_list) or
self.GetPattern(email, mm_cfg.GLOBAL_BAN_LIST)
)
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan

Hello all,
I would like to thank Aditya Jain and Mark Sapiro for the help with adding my negative regexp to the ban_list. I apologize for being late in my response. I was OBE'd.
Next, in my original message, I forgot to mention I am using Mailman v2.1.18-1 so the kind code assistance Mark provided doesn't quite match. My fault for not putting in the version of Mailman. However, looking at the code, it seems to be remarkably similar to code I had to modify when using an earlier version of Mailman.
The question now is if I change the following in Mailman/MailList.py
def GetBannedPattern(self, email):
"""Returns matched entry in ban_list if email matches.
Otherwise returns None.
"""
ban = False
for pattern in self.ban_list:
if pattern.startswith('^'):
# This is a regular expression match
try:
if re.search(pattern, email, re.IGNORECASE):
ban = True
break
except re.error:
# BAW: we should probably remove this pattern
pass
else:
# Do the comparison case insensitively
if pattern.lower() == email.lower():
ban = True
break
if ban:
return pattern
else:
return None
to the following ( I have added ** at the beginning of the lines I added to indicate the changes - in practice the ** would be spaces)
def GetBannedPattern(self, email):
"""Returns matched entry in ban_list if email matches.
Otherwise returns None.
"""
ban = False
for pattern in self.ban_list:
if pattern.startswith('^'):
# This is a regular expression match
try:
if re.search(pattern, email, re.IGNORECASE):
ban = True
break
except re.error:
# BAW: we should probably remove this pattern
pass
** elif pattern.startswith('@'): ** listname = self.internal_name() # is this correct? ** try: ** mname = pattern[1:].lower().strip() ** if mname == listname: ** # don't reference your own list ** syslog('error', ** 'Ban_list listfor %s references own list', ** listname) ** else: ** mother = MailList(mname, lock=0) ** if mother.isMember(email): ** ban = True ** break ** except Errors.MMUnknownListError: ** syslog('error', ** 'Ban_list for list %s references non-existent list %s', ** listname, mname) else: # Do the comparison case insensitively if pattern.lower() == email.lower(): ban = True break if ban: return pattern else: return None
Am I on the correct path?
Mark, if you have the time and/or inclination, could you explain your comments about
Allowing @list_name in ban_list is a simple code modification if you
don't care if various 'error' log messages such as list references
itself or references non-existent list refer to
'subscribe_auto_approval' even if the error is in ban_list.
Thanks to everyone for the help, Chris
On 10/6/2015 5:43 PM, Mark Sapiro wrote:
On 10/06/2015 08:07 AM, Chris Nulk wrote:
- The ban_list attribute is to help prevent unwanted people from subscribing to a list, however, I want to restrict who can subscribe to the list and ban anyone else. I have the regex for who I want to allow to subscribe but there isn't an allow_list attribute. Is there an easy way of allowing a regex to control who is able to subscribe? Or, is there a way to easily invert the regex logic and use it in ban_list? As an example (not the real regex), say I want to only allow @gmail.com to subscribe to the list but no one else.
As Aditya Jain replied, you can use Python RE negative lookahead assertions to create regexps with "doesn't match" conditions. See <https://docs.python.org/2/library/re.html#regular-expression-syntax>.
Although the posted regexp modified for gmail
^[^@]+@(?!(.*\.)?gmail\.com$)
will not match and hence allow, addresses like user@subdomain.gmail.com. To allow only '@gmail.com' addresses, e.g. to ban all non-'@gmail.com' addresses, use
^[^@]+@(?!gmail\.com$)
Often, if you have the regexp to allow, the regexp to ban may be as simple as
^(?!the_allow_regexp)
- An additional requirement is to restrict a subgroup of the addresses from subscribing. In short, I want to allow all @gmail.com addresses to subscribe except for a known subgroup. Now the known subgroup is in a Mailman list. So, can I use a Mailman list in the ban_list attribute similar to using a list in *_these_members attributes? Or, would I have to modify the code to allow using a Mailman list in the ban_list attribute?
Allowing @list_name in ban_list is a simple code modification if you don't care if various 'error' log messages such as list references itself or references non-existent list refer to 'subscribe_auto_approval' even if the error is in ban_list.
The change would be in this code in Mailman/Mail.List.py
def GetBannedPattern(self, email): """Returns matched entry in ban_list if email matches. Otherwise returns None. """ return self.GetPattern(email, self.ban_list)
change the last line to
return self.GetPattern(email, self.ban_list, at_list=True)
Or, if you've installed the GLOBAL_BAN_LIST mod, make the change in each of the two lines in
return (self.GetPattern(email, self.ban_list) or self.GetPattern(email, mm_cfg.GLOBAL_BAN_LIST) )

On 10/15/2015 02:37 PM, Chris Nulk wrote:
The question now is if I change the following in Mailman/MailList.py
def GetBannedPattern(self, email): """Returns matched entry in ban_list if email matches. Otherwise returns None. """ ban = False for pattern in self.ban_list: if pattern.startswith('^'): # This is a regular expression match try: if re.search(pattern, email, re.IGNORECASE): ban = True break except re.error: # BAW: we should probably remove this pattern pass else: # Do the comparison case insensitively if pattern.lower() == email.lower(): ban = True break if ban: return pattern else: return None
to the following ( I have added ** at the beginning of the lines I added to indicate the changes - in practice the ** would be spaces)
def GetBannedPattern(self, email): """Returns matched entry in ban_list if email matches. Otherwise returns None. """ ban = False for pattern in self.ban_list: if pattern.startswith('^'): # This is a regular expression match try: if re.search(pattern, email, re.IGNORECASE): ban = True break except re.error: # BAW: we should probably remove this pattern pass
** elif pattern.startswith('@'): ** listname = self.internal_name() # is this correct? ** try: ** mname = pattern[1:].lower().strip() ** if mname == listname: ** # don't reference your own list ** syslog('error', ** 'Ban_list listfor %s references own list', ** listname) ** else: ** mother = MailList(mname, lock=0) ** if mother.isMember(email): ** ban = True ** break ** except Errors.MMUnknownListError: ** syslog('error', ** 'Ban_list for list %s references non-existent list %s', ** listname, mname) else: # Do the comparison case insensitively if pattern.lower() == email.lower(): ban = True break if ban: return pattern else: return None
Am I on the correct path?
Yes.
Mark, if you have the time and/or inclination, could you explain your comments about
Allowing @list_name in ban_list is a simple code modification if you don't care if various 'error' log messages such as list references itself or references non-existent list refer to 'subscribe_auto_approval' even if the error is in ban_list.
In Mailman 2.1.19 much of the code in the GetBannedPattern() method was moved to a new GetPattern() method which optionally supports the @listname convention. This was done for subscribe_auto_approval, and while it's kind of kludgy, the error log messages that you have above for 'Ban_list listfor %s references own list' and 'Ban_list for list %s references non-existent list %s' refer to subscribe_auto_approval rather than ban_list or something variable.
Thus if you had 2.1.19 or later, the code change is much simpler if you don't mind the error log messages saying subscribe_auto_approval when they might mean ban_list.
See <http://bazaar.launchpad.net/~mailman-coders/mailman/2.1/view/head:/Mailman/M...>.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan

On 10/15/2015 02:37 PM, Chris Nulk wrote:
The question now is if I change the following in Mailman/MailList.py
def GetBannedPattern(self, email): """Returns matched entry in ban_list if email matches. Otherwise returns None.
Am I on the correct path?
Yes. Great. Thank you for the help.
Mark, if you have the time and/or inclination, could you explain your comments about
Allowing @list_name in ban_list is a simple code modification if you don't care if various 'error' log messages such as list references itself or references non-existent list refer to 'subscribe_auto_approval' even if the error is in ban_list.
In Mailman 2.1.19 much of the code in the GetBannedPattern() method was moved to a new GetPattern() method which optionally supports the @listname convention. Okay. I have made a number of code changes to 2.1.9 and several of the dropped out/were not needed when we went to 2.1.18-1. There still are a number of changes that keep us from switching without taking a close look at needs to be done. I have recorded all the changes I have made,
On 10/15/2015 3:07 PM, Mark Sapiro wrote: the problem is finding the time to work on it.
Thank you for the information though.
This was done for subscribe_auto_approval, and while it's kind of kludgy, the error log messages that you have above for 'Ban_list listfor %s references own list' and 'Ban_list for list %s references non-existent list %s' refer to subscribe_auto_approval rather than ban_list or something variable.
Thus if you had 2.1.19 or later, the code change is much simpler if you don't mind the error log messages saying subscribe_auto_approval when they might mean ban_list. Okay. That makes sense.
Thanks again for the help.
Chris

On 10/15/2015 03:25 PM, Chris Nulk wrote:
On 10/15/2015 3:07 PM, Mark Sapiro wrote:
This was done for subscribe_auto_approval, and while it's kind of kludgy, the error log messages that you have above for 'Ban_list listfor %s references own list' and 'Ban_list for list %s references non-existent list %s' refer to subscribe_auto_approval rather than ban_list or something variable.
Thus if you had 2.1.19 or later, the code change is much simpler if you don't mind the error log messages saying subscribe_auto_approval when they might mean ban_list. Okay. That makes sense.
I have decided to refactor this code to allow the attribute name to be passed as the argument to GetPattern that says to allow @listname syntax. This will make the error messages log the correct attribute name and will simplify extending @listname recognition to other attributes in the future. Along with this, I'm replacing the matches_p() function in Moderate.py with calls to the GetPattern() method so all this is in one place.
I haven't committed this change yet as it still needs testing, but I expect it to be in 2.1.21.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan

On 10/15/2015 4:01 PM, Mark Sapiro wrote:
On 10/15/2015 03:25 PM, Chris Nulk wrote:
On 10/15/2015 3:07 PM, Mark Sapiro wrote:
This was done for subscribe_auto_approval, and while it's kind of kludgy, the error log messages that you have above for 'Ban_list listfor %s references own list' and 'Ban_list for list %s references non-existent list %s' refer to subscribe_auto_approval rather than ban_list or something variable.
Thus if you had 2.1.19 or later, the code change is much simpler if you don't mind the error log messages saying subscribe_auto_approval when they might mean ban_list. Okay. That makes sense.
I have decided to refactor this code to allow the attribute name to be passed as the argument to GetPattern that says to allow @listname syntax. This will make the error messages log the correct attribute name and will simplify extending @listname recognition to other attributes in the future. Along with this, I'm replacing the matches_p() function in Moderate.py with calls to the GetPattern() method so all this is in one place.
I haven't committed this change yet as it still needs testing, but I expect it to be in 2.1.21.
Excellent. Thank you for the hard work.
Chris

Mark Sapiro wrote:
On 10/15/2015 02:37 PM, Chris Nulk wrote:
to the following ( I have added ** at the beginning of the lines I added to indicate the changes - in practice the ** would be spaces)
def GetBannedPattern(self, email): """Returns matched entry in ban_list if email matches. Otherwise returns None. """ ban = False for pattern in self.ban_list: if pattern.startswith('^'): # This is a regular expression match try: if re.search(pattern, email, re.IGNORECASE): ban = True break except re.error: # BAW: we should probably remove this pattern pass
** elif pattern.startswith('@'): ** listname = self.internal_name() # is this correct? ** try: ** mname = pattern[1:].lower().strip() ** if mname == listname: ** # don't reference your own list ** syslog('error', ** 'Ban_list listfor %s references own list', ** listname) ** else: ** mother = MailList(mname, lock=0) ** if mother.isMember(email): ** ban = True ** break ** except Errors.MMUnknownListError: ** syslog('error', ** 'Ban_list for list %s references non-existent list %s', ** listname, mname) else: # Do the comparison case insensitively if pattern.lower() == email.lower(): ban = True break if ban: return pattern else: return None
Am I on the correct path?
Yes.
One more thing however. While the above code looks good for processing @listname entries in ban_list, you won't be able to add them via the list admin GUI unless you also modify Mailman/Gui/GUIBase.py. You need to find the lines in that module that in 2.1.18-1 are
elif (wtype == mm_cfg.EmailListEx and addr.startswith('@')
and property.endswith('_these_nonmembers')):
only indented more than above and change them to
elif (wtype == mm_cfg.EmailListEx and addr.startswith('@')
and (property.endswith('_these_nonmembers') or
property == 'ban_list')):
If you don't make that change, you will still be able to add @listname entries to a list's ban_list with withlist or other scripts, but the web admin GUI will report them as bad email addresses.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan

On 10/15/2015 9:33 PM, Mark Sapiro wrote:
Mark Sapiro wrote:
On 10/15/2015 02:37 PM, Chris Nulk wrote:
to the following ( I have added ** at the beginning of the lines I added to indicate the changes - in practice the ** would be spaces)
def GetBannedPattern(self, email): """Returns matched entry in ban_list if email matches. Otherwise returns None. """ ban = False for pattern in self.ban_list: if pattern.startswith('^'): # This is a regular expression match try: if re.search(pattern, email, re.IGNORECASE): ban = True break except re.error: # BAW: we should probably remove this pattern pass
** elif pattern.startswith('@'): ** listname = self.internal_name() # is this correct? ** try: ** mname = pattern[1:].lower().strip() ** if mname == listname: ** # don't reference your own list ** syslog('error', ** 'Ban_list listfor %s references own list', ** listname) ** else: ** mother = MailList(mname, lock=0) ** if mother.isMember(email): ** ban = True ** break ** except Errors.MMUnknownListError: ** syslog('error', ** 'Ban_list for list %s references non-existent list %s', ** listname, mname) else: # Do the comparison case insensitively if pattern.lower() == email.lower(): ban = True break if ban: return pattern else: return None
Am I on the correct path?
Yes.
One more thing however. While the above code looks good for processing @listname entries in ban_list, you won't be able to add them via the list admin GUI unless you also modify Mailman/Gui/GUIBase.py. You need to find the lines in that module that in 2.1.18-1 are
elif (wtype == mm_cfg.EmailListEx and addr.startswith('@') and property.endswith('_these_nonmembers')):
only indented more than above and change them to
elif (wtype == mm_cfg.EmailListEx and addr.startswith('@') and (property.endswith('_these_nonmembers') or property == 'ban_list')):
If you don't make that change, you will still be able to add @listname entries to a list's ban_list with withlist or other scripts, but the web admin GUI will report them as bad email addresses.
Thank you for letting me know. I am going to try to make the changes soon. We try not to make changes on Fridays unless we really want to come in on Saturday to fix things.
Thanks, Chris
participants (3)
-
Aditya Jain
-
Chris Nulk
-
Mark Sapiro