|
1
|
|
|
""" |
|
2
|
|
|
Unit tests for general project functionality. |
|
3
|
|
|
""" |
|
4
|
|
|
|
|
5
|
|
|
import datetime |
|
6
|
|
|
import logging |
|
7
|
|
|
import os |
|
8
|
|
|
|
|
9
|
|
|
from django.conf import settings |
|
10
|
|
|
from django.test import TestCase |
|
11
|
|
|
|
|
12
|
|
|
logger = logging.getLogger(__name__) |
|
13
|
|
|
|
|
14
|
|
|
|
|
15
|
|
|
class TestTest(TestCase): |
|
16
|
|
|
""" Example test case. """ |
|
17
|
|
|
|
|
18
|
|
|
def test_asserts(self): |
|
19
|
|
|
""" Example unit test. Tests unittest asserts. """ |
|
20
|
|
|
self.assertTrue(True) |
|
21
|
|
|
self.assertEqual(True, True) |
|
22
|
|
|
self.assertNotEqual(True, False) |
|
23
|
|
|
|
|
24
|
|
|
|
|
25
|
|
|
class TestLogging(TestCase): |
|
26
|
|
|
""" Unit tests for logging. """ |
|
27
|
|
|
|
|
28
|
|
|
def test_logfile(self): |
|
29
|
|
|
""" |
|
30
|
|
|
Tests that debug and error log files are created |
|
31
|
|
|
and that they contain the test log statement. |
|
32
|
|
|
""" |
|
33
|
|
|
debug_message = 'test debug log statement' |
|
34
|
|
|
debug_message += str(datetime.datetime.now()) |
|
35
|
|
|
logger.debug(debug_message) |
|
36
|
|
|
logger.info('test info log message') |
|
37
|
|
|
logger.warning('test warning log message') |
|
38
|
|
|
error_message = 'test error log message' |
|
39
|
|
|
error_message += str(datetime.datetime.now()) |
|
40
|
|
|
logger.error(error_message) |
|
41
|
|
|
logger.critical('test critical log message') |
|
42
|
|
|
|
|
43
|
|
|
# assert that the files exist |
|
44
|
|
|
debuglog_path = os.path.join(settings.LOG_DIR, 'debug.log') |
|
45
|
|
|
self.assertTrue(os.path.isfile(debuglog_path)) |
|
46
|
|
|
errorlog_path = os.path.join(settings.LOG_DIR, 'error.log') |
|
47
|
|
|
self.assertTrue(os.path.isfile(errorlog_path)) |
|
48
|
|
|
|
|
49
|
|
|
# assert that the log statements are in the files |
|
50
|
|
|
with open(debuglog_path, 'r') as file_debug: |
|
51
|
|
|
logfile_str = file_debug.read() |
|
52
|
|
|
self.assertTrue(logfile_str.find(debug_message) != -1) |
|
53
|
|
|
self.assertTrue(logfile_str.find(error_message) != -1) |
|
54
|
|
|
|
|
55
|
|
|
with open(errorlog_path, 'r') as file_error: |
|
56
|
|
|
logfile_str = file_error.read() |
|
57
|
|
|
self.assertTrue(logfile_str.find(debug_message) == -1) |
|
58
|
|
|
self.assertTrue(logfile_str.find(error_message) != -1) |
|
59
|
|
|
|
|
60
|
|
|
|
|
61
|
|
|
class TestIframeStripping(TestCase): |
|
62
|
|
|
""" |
|
63
|
|
|
Unit tests for iframe stripping (only allow YouTube video embedding). |
|
64
|
|
|
Tests the accuracy of website.utils.filters.filter_non_video_iframes. |
|
65
|
|
|
""" |
|
66
|
|
|
def test_youtube_not_stripped(self): |
|
67
|
|
|
""" |
|
68
|
|
|
Test whether an iframe containing an embedded YouTube |
|
69
|
|
|
video is indeed not stripped when passed through the filter. |
|
70
|
|
|
""" |
|
71
|
|
|
from bs4 import BeautifulSoup as bs |
|
72
|
|
|
from website.utils.filters import filter_iframes |
|
73
|
|
|
|
|
74
|
|
|
self.maxDiff = None |
|
75
|
|
|
field_value = """ |
|
76
|
|
|
<div id="test"> |
|
77
|
|
|
<p>Wit amet interdum dolor felis ut ante. Morbi a facilisis ante, in lobortis urna. Etiam ut nunc quis libero interdum aliquam eu at magna. Nunc vehicula risus eleifend molestie vulputate. Mauris diam odio, congue eget lorem id, finibus imperdiet sem.</p> |
|
78
|
|
|
<p><iframe height="315" src="//www.youtube.com/embed/-Y6ImGzTF70" width="560"></iframe></p> |
|
79
|
|
|
<p>Vestibulum eget posuere metus, vel finibus leo. Suspendisse congue orci magna, in vestibulum lacus pulvinar a. Donec egestas, felis id feugiat tempus, orci velit ullamcorper risus, et ultricies augue arcu ullamcorper dolor. Mauris eget sollicitudin purus. Aenean a cursus risus, sit amet mattis erat. Curabitur vel venenatis sem. Cras non gravida tellus, eu egestas tellus. Morbi at lorem a turpis blandit vulputate vitae a est.</p></div> |
|
80
|
|
|
""" |
|
81
|
|
|
field_value_post = """ |
|
82
|
|
|
<div id="test"> |
|
83
|
|
|
<p>Wit amet interdum dolor felis ut ante. Morbi a facilisis ante, in lobortis urna. Etiam ut nunc quis libero interdum aliquam eu at magna. Nunc vehicula risus eleifend molestie vulputate. Mauris diam odio, congue eget lorem id, finibus imperdiet sem.</p> |
|
84
|
|
|
<p><iframe height="315" src="https://www.youtube-nocookie.com/embed/-Y6ImGzTF70" width="560"></iframe></p> |
|
85
|
|
|
<p>Vestibulum eget posuere metus, vel finibus leo. Suspendisse congue orci magna, in vestibulum lacus pulvinar a. Donec egestas, felis id feugiat tempus, orci velit ullamcorper risus, et ultricies augue arcu ullamcorper dolor. Mauris eget sollicitudin purus. Aenean a cursus risus, sit amet mattis erat. Curabitur vel venenatis sem. Cras non gravida tellus, eu egestas tellus. Morbi at lorem a turpis blandit vulputate vitae a est.</p></div> |
|
86
|
|
|
""" |
|
87
|
|
|
|
|
88
|
|
|
self.assertEqual(str(bs(field_value_post, 'html.parser')), |
|
89
|
|
|
filter_iframes(field_value)) |
|
90
|
|
|
|
|
91
|
|
|
def test_vimeo_stripped(self): |
|
92
|
|
|
""" |
|
93
|
|
|
Test whether a video from a non-YouTube site is stripped |
|
94
|
|
|
when passed through the filter. |
|
95
|
|
|
""" |
|
96
|
|
|
from bs4 import BeautifulSoup as bs |
|
97
|
|
|
from website.utils.filters import filter_iframes |
|
98
|
|
|
field_value = """ |
|
99
|
|
|
<div id="test"> |
|
100
|
|
|
<p>Wit amet interdum dolor felis ut ante. Morbi a facilisis ante, in lobortis urna. Etiam ut nunc quis libero interdum aliquam eu at magna. Nunc vehicula risus eleifend molestie vulputate. Mauris diam odio, congue eget lorem id, finibus imperdiet sem.</p> |
|
101
|
|
|
<iframe src="//player.vimeo.com/video/114963142?byline=0&portrait=0&color=ff0179" width="500" height="281" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe><p><a href="http://vimeo.com/114963142">IONIAN</a> from <a href="http://vimeo.com/ryanclarke">Ryan Clarke</a> on <a href="https://vimeo.com">Vimeo</a>.</p> |
|
102
|
|
|
<p>Vestibulum eget posuere metus, vel finibus leo. Suspendisse congue orci magna, in vestibulum lacus pulvinar a. Donec egestas, felis id feugiat tempus, orci velit ullamcorper risus, et ultricies augue arcu ullamcorper dolor. Mauris eget sollicitudin purus. Aenean a cursus risus, sit amet mattis erat. Curabitur vel venenatis sem. Cras non gravida tellus, eu egestas tellus. Morbi at lorem a turpis blandit vulputate vitae a est.</p></div> |
|
103
|
|
|
""" |
|
104
|
|
|
field_value_stripped = """ |
|
105
|
|
|
<div id="test"> |
|
106
|
|
|
<p>Wit amet interdum dolor felis ut ante. Morbi a facilisis ante, in lobortis urna. Etiam ut nunc quis libero interdum aliquam eu at magna. Nunc vehicula risus eleifend molestie vulputate. Mauris diam odio, congue eget lorem id, finibus imperdiet sem.</p> |
|
107
|
|
|
<p><a href="http://vimeo.com/114963142">IONIAN</a> from <a href="http://vimeo.com/ryanclarke">Ryan Clarke</a> on <a href="https://vimeo.com">Vimeo</a>.</p> |
|
108
|
|
|
<p>Vestibulum eget posuere metus, vel finibus leo. Suspendisse congue orci magna, in vestibulum lacus pulvinar a. Donec egestas, felis id feugiat tempus, orci velit ullamcorper risus, et ultricies augue arcu ullamcorper dolor. Mauris eget sollicitudin purus. Aenean a cursus risus, sit amet mattis erat. Curabitur vel venenatis sem. Cras non gravida tellus, eu egestas tellus. Morbi at lorem a turpis blandit vulputate vitae a est.</p></div> |
|
109
|
|
|
""" |
|
110
|
|
|
self.assertEqual(str(bs(field_value_stripped, 'html.parser')), |
|
111
|
|
|
filter_iframes(field_value)) |
|
112
|
|
|
|
|
113
|
|
|
def test_nonstandard_youtube_stripped(self): |
|
114
|
|
|
""" |
|
115
|
|
|
Test whether an embedded YouTube video that does not follow |
|
116
|
|
|
the standard options gets stripped as well. |
|
117
|
|
|
""" |
|
118
|
|
|
from bs4 import BeautifulSoup as bs |
|
119
|
|
|
from website.utils.filters import filter_iframes |
|
120
|
|
|
self.maxDiff = None |
|
121
|
|
|
field_value_pre = """<div id="test"> |
|
122
|
|
|
<p>Wit amet interdum dolor felis ut ante. Morbi a facilisis ante, in lobortis urna. Etiam ut nunc quis libero interdum aliquam eu at magna. Nunc vehicula risus eleifend molestie vulputate. Mauris diam odio, congue eget lorem id, finibus imperdiet sem.</p>""" |
|
123
|
|
|
field_value_post = """<p>Vestibulum eget posuere metus, vel finibus leo. Suspendisse congue orci magna, in vestibulum lacus pulvinar a. Donec egestas, felis id feugiat tempus, orci velit ullamcorper risus, et ultricies augue arcu ullamcorper dolor. Mauris eget sollicitudin purus. Aenean a cursus risus, sit amet mattis erat. Curabitur vel venenatis sem. Cras non gravida tellus, eu egestas tellus. Morbi at lorem a turpis blandit vulputate vitae a est.</p></div>""" |
|
124
|
|
|
|
|
125
|
|
|
# First case: embed from a different URL |
|
126
|
|
|
field_value_different_src = field_value_pre + \ |
|
127
|
|
|
"""<iframe width="560" height="315" src="//www.youtub.com/embed/-Y6ImGzTF70"></iframe>""" + \ |
|
128
|
|
|
field_value_post |
|
129
|
|
|
self.assertEqual(str(bs(field_value_pre + field_value_post, 'html.parser')), |
|
130
|
|
|
filter_iframes(field_value_different_src)) |
|
131
|
|
|
|
|
132
|
|
|
# Second case: embed using an attribute other than |
|
133
|
|
|
# the ones YouTube sets by default (width, height, src, |
|
134
|
|
|
# frameborders, allowfullscreen) |
|
135
|
|
|
field_value_different_attributes = field_value_pre + \ |
|
136
|
|
|
"""<iframe id="nonstandard" width="560" height="315" src="//www.youtube.com/embed/-Y6ImGzTF70"></iframe>""" + \ |
|
137
|
|
|
field_value_post |
|
138
|
|
|
self.assertEqual(str(bs(field_value_pre + field_value_post, 'html.parser')), |
|
139
|
|
|
filter_iframes(field_value_different_attributes)) |
|
140
|
|
|
|
|
141
|
|
|
# Third case: iframe contains information. |
|
142
|
|
|
field_value_iframe_has_content = field_value_pre + \ |
|
143
|
|
|
"""<iframe width="560" height="315" src="//www.youtube.com/embed/-Y6ImGzTF70">Test Information</iframe>""" + \ |
|
144
|
|
|
field_value_post |
|
145
|
|
|
self.assertEqual(str(bs(field_value_pre + field_value_post, 'html.parser')), |
|
146
|
|
|
filter_iframes(field_value_iframe_has_content)) |
|
147
|
|
|
|
|
148
|
|
|
|
|
149
|
|
|
class TestScriptTagWhitelisting(TestCase): |
|
150
|
|
|
""" |
|
151
|
|
|
Unit tests for script tag whitelisting functionality. Tests the accuracy of |
|
152
|
|
|
website.utils.filters.strip_scripts_not_in_whitelist. |
|
153
|
|
|
""" |
|
154
|
|
|
from mezzanine.conf import settings |
|
155
|
|
|
|
|
156
|
|
|
whitelist = settings.RICHTEXT_SCRIPT_TAG_WHITELIST |
|
157
|
|
|
|
|
158
|
|
|
evil_html = """ |
|
159
|
|
|
This is inconspicuous text that contains evil JavaScript.<script src="http://ev.il/code.js"></script>""" |
|
160
|
|
|
|
|
161
|
|
|
evil_html_stripped = """ |
|
162
|
|
|
This is inconspicuous text that contains evil JavaScript.""" |
|
163
|
|
|
|
|
164
|
|
|
good_html = """ |
|
165
|
|
|
This is nice text that contains JavaScript. But don't worry: |
|
166
|
|
|
it's all good because it was whitelisted. |
|
167
|
|
|
""" |
|
168
|
|
|
|
|
169
|
|
|
if len(whitelist) > 0: |
|
170
|
|
|
good_html += whitelist[0] |
|
171
|
|
|
|
|
172
|
|
|
boring_html = """ |
|
173
|
|
|
This is nice but boring text. It contains another tag, but no scripts. |
|
174
|
|
|
<p>This is a separate paragraph.</p> |
|
175
|
|
|
""" |
|
176
|
|
|
|
|
177
|
|
|
def test_evil_is_stripped(self): |
|
178
|
|
|
""" Test if an evil script tag is indeed stripped. """ |
|
179
|
|
|
from website.utils.filters import strip_scripts_not_in_whitelist |
|
180
|
|
|
from bs4 import BeautifulSoup as bs |
|
181
|
|
|
|
|
182
|
|
|
self.assertEqual(strip_scripts_not_in_whitelist(self.evil_html), |
|
183
|
|
|
str(bs(self.evil_html_stripped, 'html.parser'))) |
|
184
|
|
|
|
|
185
|
|
|
def test_good_is_not_stripped(self): |
|
186
|
|
|
""" Test if a whitelisted script tag indeed passes unstripped. """ |
|
187
|
|
|
from website.utils.filters import strip_scripts_not_in_whitelist |
|
188
|
|
|
from bs4 import BeautifulSoup as bs |
|
189
|
|
|
|
|
190
|
|
|
self.assertEqual(strip_scripts_not_in_whitelist(self.good_html), |
|
191
|
|
|
str(bs(self.good_html, 'html.parser'))) |
|
192
|
|
|
|
|
193
|
|
|
def test_boring_is_unchanged(self): |
|
194
|
|
|
""" Test if an irrelevant HTML tag passes unstripped. """ |
|
195
|
|
|
from website.utils.filters import strip_scripts_not_in_whitelist |
|
196
|
|
|
from bs4 import BeautifulSoup as bs |
|
197
|
|
|
|
|
198
|
|
|
self.assertEqual(strip_scripts_not_in_whitelist(self.boring_html), |
|
199
|
|
|
str(bs(self.boring_html, 'html.parser'))) |
|
200
|
|
|
|
|
201
|
|
|
|
|
202
|
|
|
class TestObjectFiltering(TestCase): |
|
203
|
|
|
""" |
|
204
|
|
|
Unit tests for PDF embedding functionality. Tests the accuracy of |
|
205
|
|
|
website.utils.filters.strip_illegal_objects. |
|
206
|
|
|
""" |
|
207
|
|
|
from mezzanine.conf import settings |
|
208
|
|
|
|
|
209
|
|
|
evil_html1 = """ |
|
210
|
|
|
This is inconspicuous text that contains an evil PDF from an external website.<object data="http://ev.il/my.pdf" type="application/pdf" width="300" height="200"> |
|
211
|
|
|
Alt text |
|
212
|
|
|
</object>""" |
|
213
|
|
|
|
|
214
|
|
|
evil_html2 = """ |
|
215
|
|
|
This is inconspicuous text that contains an evil PDF from an external website.<object data="{0}my.pdf" type="application/doc" width="300" height="200"> |
|
216
|
|
|
Alt text |
|
217
|
|
|
</object>""".format(settings.MEDIA_URL) |
|
218
|
|
|
|
|
219
|
|
|
evil_html3 = """ |
|
220
|
|
|
This is inconspicuous text that contains an evil PDF from an external website.<object data="{0}my.pdf" type="application/pdf" illegal="true" width="300" height="200"> |
|
221
|
|
|
Alt text |
|
222
|
|
|
</object>""".format(settings.MEDIA_URL) |
|
223
|
|
|
|
|
224
|
|
|
evil_html_stripped = """ |
|
225
|
|
|
This is inconspicuous text that contains an evil PDF from an external website.""" |
|
226
|
|
|
|
|
227
|
|
|
good_html = """ |
|
228
|
|
|
This is nice text that contains an embedded local PDF. |
|
229
|
|
|
<object data="{0}uploads/site-1/documents/doc.pdf" type="application/pdf" width="300" height="200"> |
|
230
|
|
|
alt text |
|
231
|
|
|
</object> |
|
232
|
|
|
""".format(settings.MEDIA_URL) |
|
233
|
|
|
|
|
234
|
|
|
boring_html = """ |
|
235
|
|
|
This is nice but boring text. It contains another tag, but no objects. |
|
236
|
|
|
<p>This is a separate paragraph.</p> |
|
237
|
|
|
""" |
|
238
|
|
|
|
|
239
|
|
|
def test_evil_domain_is_stripped(self): |
|
240
|
|
|
""" Test if an object tag to an external domain is indeed stripped. """ |
|
241
|
|
|
from website.utils.filters import strip_illegal_objects |
|
242
|
|
|
from bs4 import BeautifulSoup as bs |
|
243
|
|
|
|
|
244
|
|
|
self.assertEqual(strip_illegal_objects(self.evil_html1), |
|
245
|
|
|
str(bs(self.evil_html_stripped, 'html.parser'))) |
|
246
|
|
|
|
|
247
|
|
|
def test_evil_filetype_is_stripped(self): |
|
248
|
|
|
""" Test if an object tag with an illegal filetype is indeed stripped. """ |
|
249
|
|
|
from website.utils.filters import strip_illegal_objects |
|
250
|
|
|
from bs4 import BeautifulSoup as bs |
|
251
|
|
|
|
|
252
|
|
|
self.assertEqual(strip_illegal_objects(self.evil_html2), |
|
253
|
|
|
str(bs(self.evil_html_stripped, 'html.parser'))) |
|
254
|
|
|
|
|
255
|
|
|
def test_evil_attribute_is_stripped(self): |
|
256
|
|
|
""" Test if an object tag with an illegal attribute is indeed stripped. """ |
|
257
|
|
|
from website.utils.filters import strip_illegal_objects |
|
258
|
|
|
from bs4 import BeautifulSoup as bs |
|
259
|
|
|
|
|
260
|
|
|
self.assertEqual(strip_illegal_objects(self.evil_html3), |
|
261
|
|
|
str(bs(self.evil_html_stripped, 'html.parser'))) |
|
262
|
|
|
|
|
263
|
|
|
def test_good_is_not_stripped(self): |
|
264
|
|
|
""" Test if a legal object tag indeed passes unstripped. """ |
|
265
|
|
|
from website.utils.filters import strip_illegal_objects |
|
266
|
|
|
from bs4 import BeautifulSoup as bs |
|
267
|
|
|
|
|
268
|
|
|
self.assertEqual(strip_illegal_objects(self.good_html), |
|
269
|
|
|
str(bs(self.good_html, 'html.parser'))) |
|
270
|
|
|
|
|
271
|
|
|
def test_boring_is_unchanged(self): |
|
272
|
|
|
""" Test if an irrelevant HTML tag passes unstripped. """ |
|
273
|
|
|
from website.utils.filters import strip_illegal_objects |
|
274
|
|
|
from bs4 import BeautifulSoup as bs |
|
275
|
|
|
|
|
276
|
|
|
self.assertEqual(strip_illegal_objects(self.boring_html), |
|
277
|
|
|
str(bs(self.boring_html, 'html.parser'))) |
|
278
|
|
|
|
|
279
|
|
|
|
|
280
|
|
|
class TestJaneus(TestCase): |
|
281
|
|
|
""" Test Janeus integration """ |
|
282
|
|
|
|
|
283
|
|
|
def test_no_access_by_default(self): |
|
284
|
|
|
from janeus.backend import JaneusBackend |
|
285
|
|
|
self.assertTrue(JaneusBackend().authenticate("someuser", "somepass") is None) |
|
286
|
|
|
|
|
287
|
|
|
def test_access_after_role(self): |
|
288
|
|
|
from janeus.models import JaneusRole |
|
289
|
|
|
role = JaneusRole(role="role1") |
|
290
|
|
|
role.save() |
|
291
|
|
|
|
|
292
|
|
|
from janeus.backend import JaneusBackend |
|
293
|
|
|
user = JaneusBackend().authenticate("someuser", "somepass") |
|
294
|
|
|
self.assertTrue(user is not None) |
|
295
|
|
|
self.assertTrue(user.user_permissions.count() == 0) |
|
296
|
|
|
|
|
297
|
|
|
def test_permissions(self): |
|
298
|
|
|
from janeus.models import JaneusRole |
|
299
|
|
|
role = JaneusRole(role="role1") |
|
300
|
|
|
role.save() |
|
301
|
|
|
|
|
302
|
|
|
from django.contrib.auth.models import Permission |
|
303
|
|
|
role.permissions.add(*Permission.objects.all()) |
|
304
|
|
|
|
|
305
|
|
|
from janeus.backend import JaneusBackend |
|
306
|
|
|
user = JaneusBackend().authenticate("someuser", "somepass") |
|
307
|
|
|
self.assertTrue(user is not None) |
|
308
|
|
|
self.assertTrue(len(user.get_all_permissions()) == Permission.objects.count()) |
|
309
|
|
|
|