1 | # -*- coding: utf-8 -*-
|
---|
2 | #
|
---|
3 | # Copyright (C) 2006 Edgewall Software
|
---|
4 | # All rights reserved.
|
---|
5 | #
|
---|
6 | # This software is licensed as described in the file COPYING, which
|
---|
7 | # you should have received as part of this distribution. The terms
|
---|
8 | # are also available at http://trac.edgewall.com/license.html.
|
---|
9 | #
|
---|
10 | # This software consists of voluntary contributions made by many
|
---|
11 | # individuals. For the exact contribution history, see the revision
|
---|
12 | # history and logs, available at http://projects.edgewall.com/trac/.
|
---|
13 |
|
---|
14 | from trac.attachment import IAttachmentManipulator
|
---|
15 | from trac.config import IntOption
|
---|
16 | from trac.core import Component, implements
|
---|
17 | from trac.mimeview import is_binary
|
---|
18 | from trac.ticket import ITicketManipulator, TicketSystem
|
---|
19 | from trac.util.text import to_unicode
|
---|
20 | from trac.wiki.api import IWikiPageManipulator
|
---|
21 |
|
---|
22 | from tracspamfilter.filtersystem import FilterSystem
|
---|
23 |
|
---|
24 |
|
---|
25 | class TicketFilterAdapter(Component):
|
---|
26 | """Interface to check ticket changes for spam.
|
---|
27 | """
|
---|
28 | implements(ITicketManipulator)
|
---|
29 |
|
---|
30 | # ITicketManipulator methods
|
---|
31 |
|
---|
32 | def prepare_ticket(self, req, ticket, fields, actions):
|
---|
33 | pass
|
---|
34 |
|
---|
35 | def validate_ticket(self, req, ticket):
|
---|
36 | if 'TICKET_ADMIN' in req.perm:
|
---|
37 | # An administrator is allowed to spam
|
---|
38 | return []
|
---|
39 |
|
---|
40 | if 'preview' in req.args:
|
---|
41 | # Only a preview, no need to filter the submission yet
|
---|
42 | return []
|
---|
43 |
|
---|
44 | changes = []
|
---|
45 |
|
---|
46 | # Add the author/reporter name
|
---|
47 | if req.authname and req.authname != 'anonymous':
|
---|
48 | author = req.authname
|
---|
49 | elif not ticket.exists:
|
---|
50 | author = ticket['reporter']
|
---|
51 | else:
|
---|
52 | author = req.args.get('author', req.authname)
|
---|
53 |
|
---|
54 | # Add any modified text fields of the ticket
|
---|
55 | fields = [f['name'] for f in
|
---|
56 | TicketSystem(self.env).get_ticket_fields()
|
---|
57 | if f['type'] in ('textarea', 'text')]
|
---|
58 | for field in fields:
|
---|
59 | if field in ticket._old:
|
---|
60 | changes.append((ticket._old[field], ticket[field]))
|
---|
61 |
|
---|
62 | if 'comment' in req.args:
|
---|
63 | changes.append((None, req.args.get('comment')))
|
---|
64 |
|
---|
65 | FilterSystem(self.env).test(req, author, changes)
|
---|
66 | return []
|
---|
67 |
|
---|
68 | class WikiFilterAdapter(Component):
|
---|
69 | """Interface to check wiki changes for spam.
|
---|
70 | """
|
---|
71 | implements(IWikiPageManipulator)
|
---|
72 |
|
---|
73 | # IWikiPageManipulator methods
|
---|
74 |
|
---|
75 | def prepare_wiki_page(self, req, page, fields):
|
---|
76 | pass
|
---|
77 |
|
---|
78 | def validate_wiki_page(self, req, page):
|
---|
79 | if 'WIKI_ADMIN' in req.perm:
|
---|
80 | # An administrator is allowed to spam
|
---|
81 | return []
|
---|
82 |
|
---|
83 | if 'preview' in req.args:
|
---|
84 | # Only a preview, no need to filter the submission yet
|
---|
85 | return []
|
---|
86 |
|
---|
87 | old_text = page.old_text
|
---|
88 | text = page.text
|
---|
89 | author = req.args.get('author', req.authname)
|
---|
90 | comment = req.args.get('comment')
|
---|
91 |
|
---|
92 | # Test the actual page changes as well as the comment
|
---|
93 | changes = [(old_text, text)]
|
---|
94 | if comment:
|
---|
95 | changes += [(None, comment)]
|
---|
96 |
|
---|
97 | FilterSystem(self.env).test(req, author, changes)
|
---|
98 | return []
|
---|
99 |
|
---|
100 |
|
---|
101 | class AttachmentFilterAdapter(Component):
|
---|
102 | """Interface to check attachment uploads for spam.
|
---|
103 | """
|
---|
104 | implements(IAttachmentManipulator)
|
---|
105 |
|
---|
106 | sample_size = IntOption('spam-filter', 'attachment_sample_size', 16384,
|
---|
107 | """The maximum number of bytes from an attachment to pass through
|
---|
108 | the spam filters.""", doc_domain='tracspamfilter')
|
---|
109 |
|
---|
110 | # ITicketManipulator methods
|
---|
111 |
|
---|
112 | def prepare_attachment(self, req, attachment, fields):
|
---|
113 | pass
|
---|
114 |
|
---|
115 | def validate_attachment(self, req, attachment):
|
---|
116 | if 'WIKI_ADMIN' in req.perm:
|
---|
117 | # An administrator is allowed to spam
|
---|
118 | return []
|
---|
119 |
|
---|
120 | author = req.args.get('author', req.authname)
|
---|
121 | description = req.args.get('description')
|
---|
122 |
|
---|
123 | filename = None
|
---|
124 | upload = req.args.get('attachment')
|
---|
125 | content = ''
|
---|
126 | if upload is not None:
|
---|
127 | try:
|
---|
128 | data = upload.file.read(self.sample_size)
|
---|
129 | if not is_binary(data):
|
---|
130 | content = to_unicode(data)
|
---|
131 | finally:
|
---|
132 | upload.file.seek(0)
|
---|
133 | filename = upload.filename
|
---|
134 |
|
---|
135 | changes = []
|
---|
136 | for field in filter(None, [description, filename, content]):
|
---|
137 | changes += [(None, field)]
|
---|
138 |
|
---|
139 | FilterSystem(self.env).test(req, author, changes)
|
---|
140 | return []
|
---|