Update the ticketvalidemail plugin to work as part of the spam filter.

Update the url info and add some logging.
master
i-nod 2012-01-26 10:52:50 -05:00 committed by dak180
parent 03189536cf
commit 4af296f79a
5 changed files with 81 additions and 15 deletions

View File

@ -1,5 +1,6 @@
Copyright (C) 2001-2002, Paul Warren
Copyright (c) 2010, Giel van Schijndel
Copyright (C) 2006 Edgewall Software
Copyright (C) 2001-2002 Paul Warren
Copyright (C) 2010-2012 Giel van Schijndel
All rights reserved.

View File

@ -6,20 +6,23 @@ from setuptools import setup
setup(
name = 'TicketValidEmail',
version = '0.1',
version = '0.2',
packages = [
'ticketvalidemail',
],
install_requires = ['trac>=0.11'],
extras_require = {
'TracSpamFilter': ['tracspamfilter>0.4.7']
},
author = 'Giel van Schijndel',
author_email = 'me@mortis.eu',
description = 'Extends Trac to only accept anonymous tickets when the reporter name is a valid RFC822 e-mail address.',
license = 'BSD',
keywords = 'trac plugin ticket create reporter valid rfc822 e-mail',
url = 'http://developer.wz2100.net/browser/trunk/tools/trac/plugins/ticketvalidemail',
url = 'https://github.com/Warzone2100/warzone2100/tree/master/tools/trac/plugins/ticketvalidemail',
classifiers = [
'Framework :: Trac',
'License :: OSI Approved :: BSD License',
@ -27,7 +30,8 @@ setup(
entry_points = {
'trac.plugins': [
'ticketvalidemail.main = ticketvalidemail.main',
'ticketvalidemail.validator = ticketvalidemail.validator',
'ticketvalidemail.spamfilter = ticketvalidemail.spamfilter[TracSpamFilter]',
],
},
)

View File

@ -4,7 +4,7 @@
# - original Perl version
# Copyright (C) 2010 Giel van Schijndel
# - Python conversion
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
@ -12,14 +12,14 @@
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions: The above copyright notice and this
# permission notice shall be included in all copies or substantial portions of
# the Software.
#
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import re
@ -37,7 +37,7 @@ def make_rfc822re():
"""
# Basic lexical tokens are specials, domain_literal, quoted_string, atom, and
# comment. We must allow for lwsp (or comments) after each of these.
# This regexp will only work on addresses which have had comments stripped
# This regexp will only work on addresses which have had comments stripped
# and replaced with lwsp.
specials = '()<>@,;:\\\\".\\[\\]'
@ -48,7 +48,7 @@ def make_rfc822re():
quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|" + lwsp + ")*\"" + lwsp + "*"
# Use zero-width assertion to spot the limit of an atom. A simple
# Use zero-width assertion to spot the limit of an atom. A simple
# $lwsp* causes the regexp engine to hang occasionally.
atom = "[^" + specials + " " + controls + "]+(?:" + lwsp + "+|\\Z|(?=[\\[\"" + specials + "]))"
word = "(?:" + atom + "|" + quoted_string + ")"
@ -172,7 +172,7 @@ if __name__ == "__main__":
r"""phrase: abigail@example.com abigail@example.com ;""",
u"""invalid£char@example.com""",
]
lists = [
('abc@foo.com, abc@blort.foo', ['abc@foo.com', 'abc@blort.foo']),
('abc@foo.com, abcblort.foo', None),

View File

@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2006 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.com/license.html.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://projects.edgewall.com/trac/.
from email.Utils import parseaddr
import re
import rfc822
from trac.config import IntOption
from trac.core import *
from tracspamfilter.api import IFilterStrategy
class ValidEmailFilterStrategy(Component):
"""This strategy grants positive karma points to anonymous users with a valid RFC822 e-mail address."""
implements(IFilterStrategy)
karma_points = IntOption('ticketvalidemail', 'validemail_karma', '10',
"""By how many points a valid RFC822 e-mail address improves the overall karma of
the submission for anonymous users. Invalid e-mail will lower karma by that value.""")
reject_emails_re = re.compile(r'^\w+@example\.(org|net|com)$')
# IFilterStrategy implementation
def is_external(self):
return False
def test(self, req, author, content, ip):
points = -abs(self.karma_points)
if req.authname and req.authname != 'anonymous':
self.log.debug("Authenticated user, skipping...")
return
# Split up author into name and email, if possible
author = author.encode('utf-8')
author_name, author_email = parseaddr(author)
self.log.debug("Author name is [%s] and e-mail is [%s]", author_name, author_email)
if not author_email:
return points, 'No e-mail found'
elif self.reject_emails_re.match(author_email.lower()):
return points, 'Example e-mail detected'
elif rfc822.valid(author_email):
points = abs(self.karma_points)
return points, 'Valid e-mail found'
else:
return points, 'No valid RFC822 e-mail address found in reporter field'
def train(self, req, author, content, ip, spam=True):
pass

View File

@ -1,7 +1,7 @@
# vim: set et sts=4 sw=4 encoding=utf8:
# -*- coding: utf-8 -*-
import address
import rfc822
from email.utils import parseaddr
import re
from trac.core import *
@ -24,7 +24,7 @@ class TicketValidEmail(Component):
def validate_ticket(self, req, ticket):
"""Validate a ticket after it's been populated from user input.
Must return a list of `(field, message)` tuples, one for each problem
detected. `field` can be `None` to indicate an overall problem with the
ticket. Therefore, a return value of `[]` means everything is OK."""
@ -32,7 +32,7 @@ class TicketValidEmail(Component):
mail = parseaddr(ticket['reporter'])[1]
if self.reject_emails_re.match(mail.lower()):
return [('reporter', '"%s" isn\'t acceptable as e-mail address' % (mail))]
elif req.authname and req.authname != 'anonymous' or address.valid(ticket['reporter']):
elif req.authname and req.authname != 'anonymous' or rfc822.valid(ticket['reporter']):
return []
else:
return [(None, 'Either use a valid reporter address or log in.'),