summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorjfriedli2020-04-26 09:50:14 -0700
committerjfriedli2020-04-26 09:50:14 -0700
commitc301e472bd7fd79d675c5df089db0b16fd1e2cfe (patch)
treec3332e0f974edc09881b5534c35becc5b9fffa3b /test
parente1bac8b6a7fd857f38b7bcb678398c82baaa8fd5 (diff)
Resolve "Use a HMAC instead of a hash"
Diffstat (limited to '')
-rw-r--r--test/test.py89
-rw-r--r--test/test_api.py74
2 files changed, 96 insertions, 67 deletions
diff --git a/test/test.py b/test/test.py
index 02216ac..2d09662 100644
--- a/test/test.py
+++ b/test/test.py
@@ -6,12 +6,13 @@ import io
6import os 6import os
7 7
8from unittest.mock import patch 8from unittest.mock import patch
9from flask_testing import TestCase
9 10
10import main 11import main
11 12
12 13
13class Mat2WebTestCase(unittest.TestCase): 14class Mat2WebTestCase(TestCase):
14 def setUp(self): 15 def create_app(self):
15 os.environ.setdefault('MAT2_ALLOW_ORIGIN_WHITELIST', 'origin1.gnu origin2.gnu') 16 os.environ.setdefault('MAT2_ALLOW_ORIGIN_WHITELIST', 'origin1.gnu origin2.gnu')
16 self.upload_folder = tempfile.mkdtemp() 17 self.upload_folder = tempfile.mkdtemp()
17 app = main.create_app( 18 app = main.create_app(
@@ -20,45 +21,45 @@ class Mat2WebTestCase(unittest.TestCase):
20 'UPLOAD_FOLDER': self.upload_folder 21 'UPLOAD_FOLDER': self.upload_folder
21 } 22 }
22 ) 23 )
23 self.app = app.test_client() 24 return app
24 25
25 def tearDown(self): 26 def tearDown(self):
26 shutil.rmtree(self.upload_folder) 27 shutil.rmtree(self.upload_folder)
27 28
28 def test_get_root(self): 29 def test_get_root(self):
29 rv = self.app.get('/') 30 rv = self.client.get('/')
30 self.assertIn(b'mat2-web', rv.data) 31 self.assertIn(b'mat2-web', rv.data)
31 32
32 def test_check_mimetypes(self): 33 def test_check_mimetypes(self):
33 rv = self.app.get('/') 34 rv = self.client.get('/')
34 self.assertIn(b'.torrent', rv.data) 35 self.assertIn(b'.torrent', rv.data)
35 self.assertIn(b'.ods', rv.data) 36 self.assertIn(b'.ods', rv.data)
36 37
37 def test_get_download_dangerous_file(self): 38 def test_get_download_dangerous_file(self):
38 rv = self.app.get('/download/1337/\..\filename') 39 rv = self.client.get('/download/1337/aabb/\..\filename')
39 self.assertEqual(rv.status_code, 302) 40 self.assertEqual(rv.status_code, 302)
40 41
41 def test_get_download_without_key_file(self): 42 def test_get_download_without_key_file(self):
42 rv = self.app.get('/download/non_existant') 43 rv = self.client.get('/download/non_existant')
43 self.assertEqual(rv.status_code, 404) 44 self.assertEqual(rv.status_code, 404)
44 45
45 def test_get_download_nonexistant_file(self): 46 def test_get_download_nonexistant_file(self):
46 rv = self.app.get('/download/1337/non_existant') 47 rv = self.client.get('/download/1337/aabb/non_existant')
47 self.assertEqual(rv.status_code, 302) 48 self.assertEqual(rv.status_code, 302)
48 49
49 def test_get_upload_without_file(self): 50 def test_get_upload_without_file(self):
50 rv = self.app.post('/') 51 rv = self.client.post('/')
51 self.assertEqual(rv.status_code, 302) 52 self.assertEqual(rv.status_code, 302)
52 53
53 def test_get_upload_empty_file(self): 54 def test_get_upload_empty_file(self):
54 rv = self.app.post('/', 55 rv = self.client.post('/',
55 data=dict( 56 data=dict(
56 file=(io.BytesIO(b""), 'test.pdf'), 57 file=(io.BytesIO(b""), 'test.pdf'),
57 ), follow_redirects=False) 58 ), follow_redirects=False)
58 self.assertEqual(rv.status_code, 302) 59 self.assertEqual(rv.status_code, 302)
59 60
60 def test_get_upload_empty_file_redir(self): 61 def test_get_upload_empty_file_redir(self):
61 rv = self.app.post('/', 62 rv = self.client.post('/',
62 data=dict( 63 data=dict(
63 file=(io.BytesIO(b""), 'test.pdf'), 64 file=(io.BytesIO(b""), 'test.pdf'),
64 ), follow_redirects=True) 65 ), follow_redirects=True)
@@ -67,7 +68,7 @@ class Mat2WebTestCase(unittest.TestCase):
67 self.assertEqual(rv.status_code, 200) 68 self.assertEqual(rv.status_code, 200)
68 69
69 def test_get_upload_no_selected_file(self): 70 def test_get_upload_no_selected_file(self):
70 rv = self.app.post('/', 71 rv = self.client.post('/',
71 data=dict( 72 data=dict(
72 file=(io.BytesIO(b""), ''), 73 file=(io.BytesIO(b""), ''),
73 ), follow_redirects=True) 74 ), follow_redirects=True)
@@ -86,7 +87,7 @@ class Mat2WebTestCase(unittest.TestCase):
86 'AAAAAAAAAAApIFnAAAAdGVzdC5qc29uVVQNAAfomo9d6JqPXeiaj111eAsAAQTpAwAABOkDAAB' 87 'AAAAAAAAAAApIFnAAAAdGVzdC5qc29uVVQNAAfomo9d6JqPXeiaj111eAsAAQTpAwAABOkDAAB'
87 'QSwUGAAAAAAIAAgC8AAAAwAAAAAAA' 88 'QSwUGAAAAAAIAAgC8AAAAwAAAAAAA'
88 ) 89 )
89 rv = self.app.post('/', 90 rv = self.client.post('/',
90 data=dict( 91 data=dict(
91 file=(io.BytesIO(zip_file_bytes), 'test.zip'), 92 file=(io.BytesIO(zip_file_bytes), 'test.zip'),
92 ), follow_redirects=True) 93 ), follow_redirects=True)
@@ -94,7 +95,7 @@ class Mat2WebTestCase(unittest.TestCase):
94 self.assertEqual(rv.status_code, 200) 95 self.assertEqual(rv.status_code, 200)
95 96
96 def test_get_upload_no_file_name(self): 97 def test_get_upload_no_file_name(self):
97 rv = self.app.post('/', 98 rv = self.client.post('/',
98 data=dict( 99 data=dict(
99 file=(io.BytesIO(b"aaa")), 100 file=(io.BytesIO(b"aaa")),
100 ), follow_redirects=True) 101 ), follow_redirects=True)
@@ -102,30 +103,51 @@ class Mat2WebTestCase(unittest.TestCase):
102 self.assertEqual(rv.status_code, 200) 103 self.assertEqual(rv.status_code, 200)
103 104
104 def test_get_upload_harmless_file(self): 105 def test_get_upload_harmless_file(self):
105 rv = self.app.post('/', 106 rv = self.client.post(
106 data=dict( 107 '/',
107 file=(io.BytesIO(b"Some text"), 'test.txt'), 108 data=dict(
108 ), follow_redirects=True) 109 file=(io.BytesIO(b"Some text"), 'test.txt'),
109 self.assertIn(b'/download/4c2e9e6da31a64c70623619c449a040968cdbea85945bf384fa30ed2d5d24fa3/test.cleaned.txt', rv.data) 110 ),
111 follow_redirects=True
112 )
113 download_uri = self.get_context_variable('download_uri')
114 self.assertIn('/test.cleaned.txt', download_uri)
110 self.assertEqual(rv.status_code, 200) 115 self.assertEqual(rv.status_code, 200)
111 self.assertNotIn('Access-Control-Allow-Origin', rv.headers) 116 self.assertNotIn('Access-Control-Allow-Origin', rv.headers)
112 117
113 rv = self.app.get('/download/4c2e9e6da31a64c70623619c449a040968cdbea85945bf384fa30ed2d5d24fa3/test.cleaned.txt') 118 rv = self.client.get(download_uri)
114 self.assertEqual(rv.status_code, 200) 119 self.assertEqual(rv.status_code, 200)
115 120
116 rv = self.app.get('/download/4c2e9e6da31a64c70623619c449a040968cdbea85945bf384fa30ed2d5d24fa3/test.cleaned.txt') 121 rv = self.client.get(download_uri)
117 self.assertEqual(rv.status_code, 302) 122 self.assertEqual(rv.status_code, 302)
118 123
119 def test_upload_wrong_hash(self): 124 def test_upload_wrong_hash_or_secret(self):
120 rv = self.app.post('/', 125 rv = self.client.post(
121 data=dict( 126 '/',
122 file=(io.BytesIO(b"Some text"), 'test.txt'), 127 data=dict(
123 ), follow_redirects=True) 128 file=(io.BytesIO(b"Some text"), 'test.txt'),
124 self.assertIn(b'/download/4c2e9e6da31a64c70623619c449a040968cdbea85945bf384fa30ed2d5d24fa3/test.cleaned.txt', 129 ),
125 rv.data) 130 follow_redirects=True
131 )
132
133 download_uri = self.get_context_variable('download_uri')
134
135 self.assertIn('/test.cleaned.txt', download_uri)
136 self.assertIn('/download', download_uri)
126 self.assertEqual(rv.status_code, 200) 137 self.assertEqual(rv.status_code, 200)
127 138
128 rv = self.app.get('/download/70623619c449a040968cdbea85945bf384fa30ed2d5d24fa3/test.cleaned.txt') 139 uri_parts = download_uri.split("/")
140 self.assertEqual(len(uri_parts[2]), len(uri_parts[3]))
141 self.assertEqual(64, len(uri_parts[2]))
142
143 key_uri_parts = uri_parts
144 key_uri_parts[2] = '70623619c'
145 rv = self.client.get("/".join(key_uri_parts))
146 self.assertEqual(rv.status_code, 302)
147
148 key_uri_parts = uri_parts
149 key_uri_parts[3] = '70623619c'
150 rv = self.client.get("/".join(key_uri_parts))
129 self.assertEqual(rv.status_code, 302) 151 self.assertEqual(rv.status_code, 302)
130 152
131 @patch('matweb.file_removal_scheduler.random.randint') 153 @patch('matweb.file_removal_scheduler.random.randint')
@@ -140,19 +162,18 @@ class Mat2WebTestCase(unittest.TestCase):
140 ) 162 )
141 app = app.test_client() 163 app = app.test_client()
142 164
143 request = self.app.post('/', 165 request = self.client.post('/',
144 data=dict( 166 data=dict(
145 file=(io.BytesIO(b"Some text"), 'test.txt'), 167 file=(io.BytesIO(b"Some text"), 'test.txt'),
146 ), follow_redirects=True) 168 ), follow_redirects=True)
147 self.assertEqual(request.status_code, 200) 169 self.assertEqual(request.status_code, 200)
148 request = app.get( 170
149 b'/download/4c2e9e6da31a64c70623619c449a040968cdbea85945bf384fa30ed2d5d24fa3/test.cleaned.txt' 171 request = app.get(self.get_context_variable('download_uri'))
150 )
151 self.assertEqual(302, request.status_code) 172 self.assertEqual(302, request.status_code)
152 os.environ['MAT2_MAX_FILE_AGE_FOR_REMOVAL'] = '9999' 173 os.environ['MAT2_MAX_FILE_AGE_FOR_REMOVAL'] = '9999'
153 174
154 def test_info_page(self): 175 def test_info_page(self):
155 rv = self.app.get('/info') 176 rv = self.client.get('/info')
156 self.assertIn(b'What are metadata?', rv.data) 177 self.assertIn(b'What are metadata?', rv.data)
157 self.assertIn(b'.asc', rv.data) 178 self.assertIn(b'.asc', rv.data)
158 self.assertIn(b'.mp2', rv.data) 179 self.assertIn(b'.mp2', rv.data)
diff --git a/test/test_api.py b/test/test_api.py
index 36aae9d..4925d9e 100644
--- a/test/test_api.py
+++ b/test/test_api.py
@@ -30,33 +30,26 @@ class Mat2APITestCase(unittest.TestCase):
30 del os.environ['MAT2_ALLOW_ORIGIN_WHITELIST'] 30 del os.environ['MAT2_ALLOW_ORIGIN_WHITELIST']
31 31
32 def test_api_upload_valid(self): 32 def test_api_upload_valid(self):
33 request = self.app.post('/api/upload', 33 request = self.app.post(
34 data='{"file_name": "test_name.jpg", ' 34 '/api/upload',
35 '"file": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAf' 35 data='{"file_name": "test_name.jpg", '
36 'FcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="}', 36 '"file": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAf'
37 headers={'content-type': 'application/json'} 37 'FcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="}',
38 ) 38 headers={'content-type': 'application/json'}
39 )
39 self.assertEqual(request.headers['Content-Type'], 'application/json') 40 self.assertEqual(request.headers['Content-Type'], 'application/json')
40 self.assertEqual(request.headers['Access-Control-Allow-Origin'], 'origin1.gnu') 41 self.assertEqual(request.headers['Access-Control-Allow-Origin'], 'origin1.gnu')
41 self.assertEqual(request.status_code, 200) 42 self.assertEqual(request.status_code, 200)
42 43
43 data = request.get_json() 44 data = request.get_json()
44 expected = { 45 self.assertEqual(data['output_filename'], 'test_name.cleaned.jpg')
45 'output_filename': 'test_name.cleaned.jpg', 46 self.assertEqual(data['output_filename'], 'test_name.cleaned.jpg')
46 'mime': 'image/jpeg', 47 self.assertEqual(data['mime'], 'image/jpeg')
47 'key': '81a541f9ebc0233d419d25ed39908b16f82be26a783f32d56c381559e84e6161', 48 self.assertEqual(len(data['secret']), 64)
48 'meta': { 49 self.assertEqual(len(data['key']), 64)
49 'BitDepth': 8, 50 self.assertNotEqual(data['key'], data['secret'])
50 'ColorType': 'RGB with Alpha', 51 self.assertTrue('http://localhost/api/download/' in data['download_link'])
51 'Compression': 'Deflate/Inflate', 52 self.assertTrue('test_name.cleaned.jpg' in data['download_link'])
52 'Filter': 'Adaptive',
53 'Interlace': 'Noninterlaced'
54 },
55 'meta_after': {},
56 'download_link': 'http://localhost/api/download/'
57 '81a541f9ebc0233d419d25ed39908b16f82be26a783f32d56c381559e84e6161/test_name.cleaned.jpg'
58 }
59 self.assertEqual(data, expected)
60 53
61 def test_api_upload_missing_params(self): 54 def test_api_upload_missing_params(self):
62 request = self.app.post('/api/upload', 55 request = self.app.post('/api/upload',
@@ -141,7 +134,6 @@ class Mat2APITestCase(unittest.TestCase):
141 error = request.get_json()['message'] 134 error = request.get_json()['message']
142 self.assertEqual(error, 'Unable to clean application/zip') 135 self.assertEqual(error, 'Unable to clean application/zip')
143 136
144
145 def test_api_download(self): 137 def test_api_download(self):
146 request = self.app.post('/api/upload', 138 request = self.app.post('/api/upload',
147 data='{"file_name": "test_name.jpg", ' 139 data='{"file_name": "test_name.jpg", '
@@ -152,25 +144,36 @@ class Mat2APITestCase(unittest.TestCase):
152 self.assertEqual(request.status_code, 200) 144 self.assertEqual(request.status_code, 200)
153 data = request.get_json() 145 data = request.get_json()
154 146
155 request = self.app.get('http://localhost/api/download/' 147 request = self.app.get('http://localhost/api/download/161/'
156 '81a541f9ebc0233d419d25ed39908b16f82be26a783f32d56c381559e84e6161/test name.cleaned.jpg') 148 '81a541f9ebc0233d419d25ed39908b16f82be26a783f32d56c381559e84e6161/test name.cleaned.jpg')
157 self.assertEqual(request.status_code, 400) 149 self.assertEqual(request.status_code, 400)
158 error = request.get_json()['message'] 150 error = request.get_json()['message']
159 self.assertEqual(error, 'Insecure filename') 151 self.assertEqual(error, 'Insecure filename')
160 152
161 request = self.app.get('http://localhost/api/download/' 153 request = self.app.get(data['download_link'].replace('test_name', 'wrong_test'))
162 '81a541f9ebc0233d419d25ed39908b16f82be26a783f32d56c381559e84e6161/'
163 'wrong_file_name.jpg')
164 self.assertEqual(request.status_code, 404) 154 self.assertEqual(request.status_code, 404)
165 error = request.get_json()['message'] 155 error = request.get_json()['message']
166 self.assertEqual(error, 'File not found') 156 self.assertEqual(error, 'File not found')
167 157
168 request = self.app.get('http://localhost/api/download/81a541f9e/test_name.cleaned.jpg') 158 uri_parts = data['download_link'].split("/")
159 self.assertEqual(len(uri_parts[5]), len(uri_parts[6]))
160 self.assertEqual(64, len(uri_parts[5]))
161
162 key_uri_parts = uri_parts
163 key_uri_parts[5] = '70623619c'
164 request = self.app.get("/".join(key_uri_parts))
169 self.assertEqual(request.status_code, 400) 165 self.assertEqual(request.status_code, 400)
170 166
171 error = request.get_json()['message'] 167 error = request.get_json()['message']
172 self.assertEqual(error, 'The file hash does not match') 168 self.assertEqual(error, 'The file hash does not match')
173 169
170 key_uri_parts = uri_parts
171 key_uri_parts[6] = '70623619c'
172 request = self.app.get("/".join(key_uri_parts))
173 self.assertEqual(request.status_code, 400)
174 error = request.get_json()['message']
175 self.assertEqual(error, 'The file hash does not match')
176
174 request = self.app.head(data['download_link']) 177 request = self.app.head(data['download_link'])
175 self.assertEqual(request.status_code, 200) 178 self.assertEqual(request.status_code, 200)
176 self.assertEqual(request.headers['Content-Length'], '633') 179 self.assertEqual(request.headers['Content-Length'], '633')
@@ -205,11 +208,13 @@ class Mat2APITestCase(unittest.TestCase):
205 u'download_list': [ 208 u'download_list': [
206 { 209 {
207 u'file_name': upload_one['output_filename'], 210 u'file_name': upload_one['output_filename'],
208 u'key': upload_one['key'] 211 u'key': upload_one['key'],
212 u'secret': upload_one['secret']
209 }, 213 },
210 { 214 {
211 u'file_name': upload_two['output_filename'], 215 u'file_name': upload_two['output_filename'],
212 u'key': upload_two['key'] 216 u'key': upload_two['key'],
217 u'secret': upload_two['secret']
213 } 218 }
214 ] 219 ]
215 } 220 }
@@ -261,7 +266,8 @@ class Mat2APITestCase(unittest.TestCase):
261 u'download_list': [ 266 u'download_list': [
262 { 267 {
263 u'file_name': 'invalid_file_name', 268 u'file_name': 'invalid_file_name',
264 u'key': 'invalid_key' 269 u'key': 'invalid_key',
270 u'secret': 'invalid_secret'
265 } 271 }
266 ] 272 ]
267 } 273 }
@@ -348,11 +354,13 @@ class Mat2APITestCase(unittest.TestCase):
348 u'download_list': [ 354 u'download_list': [
349 { 355 {
350 u'file_name': 'invalid_file_name1', 356 u'file_name': 'invalid_file_name1',
351 u'key': 'invalid_key1' 357 u'key': 'invalid_key1',
358 u'secret': 'invalid_secret1'
352 }, 359 },
353 { 360 {
354 u'file_name': 'invalid_file_name2', 361 u'file_name': 'invalid_file_name2',
355 u'key': 'invalid_key2' 362 u'key': 'invalid_key2',
363 u'secret': 'invalid_secret2'
356 } 364 }
357 ] 365 ]
358 } 366 }