Skip to content

Commit

Permalink
Added hash type
Browse files Browse the repository at this point in the history
  • Loading branch information
kroman0 committed Jul 21, 2016
1 parent 917b90d commit 9bf59e6
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 30 deletions.
2 changes: 1 addition & 1 deletion docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def setUp(self):

def test_docs(self):
with open('docs/source/tutorial/register.http', 'w') as self.app.file_obj:
md5hash = md5('content').hexdigest()
md5hash = 'md5:' + md5('content').hexdigest()
response = self.app.post('/register', {'hash': md5hash, 'filename': 'file.txt'})
self.assertEqual(response.status, '201 Created')
self.assertEqual(response.content_type, 'application/json')
Expand Down
2 changes: 1 addition & 1 deletion docs/source/tutorial/get.http
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
GET /get/6c4503d85a614f78b1ef9cd104882e28?Expires=1469095533&KeyID=37afbb51&Signature=2HhuTEuqX2ssvMN0Um5m6J22kacJG4h5nueo8OCO%2FjmqPI29tMooAd1BJMDiINJ0XIFDNLkCDQA8N3MfWsU8Cw%253D%253D HTTP/1.0
GET /get/5859312b16d045faa41f2e1ba716b542?Expires=1469115095&KeyID=e8946325&Signature=7V9obuW0qDqsnUDABRFhpc1YMObggdSGkatCb%252BJ9S4e4Yn6KF1AiBebEs9KyfI7Yw2i30nWJZkrt3iYtWJkcCQ%253D%253D HTTP/1.0
Authorization: Basic YnJva2VyOmJyb2tlcg==
Host: docs-sandbox.openprocurement.org

Expand Down
12 changes: 6 additions & 6 deletions docs/source/tutorial/register.http
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
POST /register HTTP/1.0
Authorization: Basic YnJva2VyOmJyb2tlcg==
Content-Length: 55
Content-Length: 61
Content-Type: application/x-www-form-urlencoded
Host: docs-sandbox.openprocurement.org

hash=9a0364b9e99bb480dd25e1f0284c8555&filename=file.txt
hash=md5%3A9a0364b9e99bb480dd25e1f0284c8555&filename=file.txt


201 Created
Content-Type: application/json; charset=UTF-8
Location: http://docs-sandbox.openprocurement.org/upload/6c4503d85a614f78b1ef9cd104882e28?KeyID=37afbb51&Signature=mQyAjy41T1giTfCj2wkDmTVUlRHAzI3FrfGd5DvsmFvDCAqeQPIPP81F5jraZSffxVsGGZvCx6W1A6fVGgHQCw%253D%253D
Location: http://docs-sandbox.openprocurement.org/upload/5859312b16d045faa41f2e1ba716b542?KeyID=e8946325&Signature=3v981%252BAArkotyuG7tcEsUDu%252BDM56tTs9oKEv1mNjIWK0gKhZvVrmxjmru4gkft%252Bjbi2WmRhEv81cXNlzZoKvBg%253D%253D

{
"upload_url": "http://docs-sandbox.openprocurement.org/upload/6c4503d85a614f78b1ef9cd104882e28?KeyID=37afbb51&Signature=mQyAjy41T1giTfCj2wkDmTVUlRHAzI3FrfGd5DvsmFvDCAqeQPIPP81F5jraZSffxVsGGZvCx6W1A6fVGgHQCw%253D%253D",
"upload_url": "http://docs-sandbox.openprocurement.org/upload/5859312b16d045faa41f2e1ba716b542?KeyID=e8946325&Signature=3v981%252BAArkotyuG7tcEsUDu%252BDM56tTs9oKEv1mNjIWK0gKhZvVrmxjmru4gkft%252Bjbi2WmRhEv81cXNlzZoKvBg%253D%253D",
"data": {
"url": "http://docs-sandbox.openprocurement.org/get/6c4503d85a614f78b1ef9cd104882e28?KeyID=37afbb51&Signature=iI3lDDleJxVGWQz9fK0KWsFGwqnFxYSW4zhP0kO5uQz1%252BnoJn0mHa0F9hbJw1FRqaoDg8wseD1V0JIdR225bDQ%253D%253D",
"hash": "9a0364b9e99bb480dd25e1f0284c8555"
"url": "http://docs-sandbox.openprocurement.org/get/5859312b16d045faa41f2e1ba716b542?KeyID=e8946325&Signature=4xUKw8%2Fyj0IBulCCxqGLTbUWhtmT%2F1HUmUwBTT4%2FLc6HY%2F2xV6jtSRx%2FRSFSslSoYBzeP1YcvEVSPGwJHQ%252BkAw%253D%253D",
"hash": "md5:9a0364b9e99bb480dd25e1f0284c8555"
}
}

14 changes: 7 additions & 7 deletions docs/source/tutorial/upload-file.http
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
POST /upload HTTP/1.0
Authorization: Basic YnJva2VyOmJyb2tlcg==
Content-Length: 179
Content-Type: multipart/form-data; boundary=----------a_BoUnDaRy363349153179$
Content-Type: multipart/form-data; boundary=----------a_BoUnDaRy142627989259$
Host: docs-sandbox.openprocurement.org

------------a_BoUnDaRy363349153179$
------------a_BoUnDaRy142627989259$
Content-Disposition: form-data; name="file"; filename="file.txt"
Content-Type: text/plain

content
------------a_BoUnDaRy363349153179$--
------------a_BoUnDaRy142627989259$--



200 OK
Content-Type: application/json; charset=UTF-8
Location: http://docs-sandbox.openprocurement.org/get/5e2b0a861ac7444dbcde7c4b3db65fc8?Expires=1469095533&KeyID=37afbb51&Signature=tKNf%252BcpLDu1qPGtLWlvb4f%252BX7o%2FhQbf1CQk%2FVk14CEmikn2N10OOnYshInPT7PXdUwNv3NP%2F9jQSCWo3wXsjAA%253D%253D
Location: http://docs-sandbox.openprocurement.org/get/9a8d155e263d4ab58e89363c9d1b3050?Expires=1469115095&KeyID=e8946325&Signature=DVMXc0AFf8T9Hh5V%2FIn1KCUdYOKajUH%252BJZcVGRG3JGzKPgyzWfP%252BJJ6GEXvIvAGf%2FRCLUMWD8QCo3eZwez7RDw%253D%253D

{
"get_url": "http://docs-sandbox.openprocurement.org/get/5e2b0a861ac7444dbcde7c4b3db65fc8?Expires=1469095533&KeyID=37afbb51&Signature=tKNf%252BcpLDu1qPGtLWlvb4f%252BX7o%2FhQbf1CQk%2FVk14CEmikn2N10OOnYshInPT7PXdUwNv3NP%2F9jQSCWo3wXsjAA%253D%253D",
"get_url": "http://docs-sandbox.openprocurement.org/get/9a8d155e263d4ab58e89363c9d1b3050?Expires=1469115095&KeyID=e8946325&Signature=DVMXc0AFf8T9Hh5V%2FIn1KCUdYOKajUH%252BJZcVGRG3JGzKPgyzWfP%252BJJ6GEXvIvAGf%2FRCLUMWD8QCo3eZwez7RDw%253D%253D",
"data": {
"url": "http://docs-sandbox.openprocurement.org/get/5e2b0a861ac7444dbcde7c4b3db65fc8?KeyID=37afbb51&Signature=mAJf1vDy5TyxTQLWhqsD3tWWYJqtyu7TU5vgEx4XWGOzxjVeMYTtc3bqWw5pHBts4VKInLOF5Aehj%2FVo3XxgCA%253D%253D",
"url": "http://docs-sandbox.openprocurement.org/get/9a8d155e263d4ab58e89363c9d1b3050?KeyID=e8946325&Signature=w%2FGtRAbYPYseo8KGgu1sSi%2FiPZajIDsSYMrQVkLhpj6bNOxbYP43GyLwWJAYgWiTihkd2Y6P%2FZPvzuxoblKqCw%253D%253D",
"format": "text/plain",
"hash": "9a0364b9e99bb480dd25e1f0284c8555",
"hash": "md5:9a0364b9e99bb480dd25e1f0284c8555",
"title": "file.txt"
}
}
Expand Down
14 changes: 7 additions & 7 deletions docs/source/tutorial/upload.http
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
POST /upload/6c4503d85a614f78b1ef9cd104882e28?KeyID=37afbb51&Signature=mQyAjy41T1giTfCj2wkDmTVUlRHAzI3FrfGd5DvsmFvDCAqeQPIPP81F5jraZSffxVsGGZvCx6W1A6fVGgHQCw%253D%253D HTTP/1.0
POST /upload/5859312b16d045faa41f2e1ba716b542?KeyID=e8946325&Signature=3v981%252BAArkotyuG7tcEsUDu%252BDM56tTs9oKEv1mNjIWK0gKhZvVrmxjmru4gkft%252Bjbi2WmRhEv81cXNlzZoKvBg%253D%253D HTTP/1.0
Authorization: Basic YnJva2VyOmJyb2tlcg==
Content-Length: 179
Content-Type: multipart/form-data; boundary=----------a_BoUnDaRy679797881491$
Content-Type: multipart/form-data; boundary=----------a_BoUnDaRy614235777706$
Host: docs-sandbox.openprocurement.org

------------a_BoUnDaRy679797881491$
------------a_BoUnDaRy614235777706$
Content-Disposition: form-data; name="file"; filename="file.txt"
Content-Type: text/plain

content
------------a_BoUnDaRy679797881491$--
------------a_BoUnDaRy614235777706$--



200 OK
Content-Type: application/json; charset=UTF-8

{
"get_url": "http://docs-sandbox.openprocurement.org/get/6c4503d85a614f78b1ef9cd104882e28?Expires=1469095533&KeyID=37afbb51&Signature=2HhuTEuqX2ssvMN0Um5m6J22kacJG4h5nueo8OCO%2FjmqPI29tMooAd1BJMDiINJ0XIFDNLkCDQA8N3MfWsU8Cw%253D%253D",
"get_url": "http://docs-sandbox.openprocurement.org/get/5859312b16d045faa41f2e1ba716b542?Expires=1469115095&KeyID=e8946325&Signature=7V9obuW0qDqsnUDABRFhpc1YMObggdSGkatCb%252BJ9S4e4Yn6KF1AiBebEs9KyfI7Yw2i30nWJZkrt3iYtWJkcCQ%253D%253D",
"data": {
"url": "http://docs-sandbox.openprocurement.org/get/6c4503d85a614f78b1ef9cd104882e28?KeyID=37afbb51&Signature=iI3lDDleJxVGWQz9fK0KWsFGwqnFxYSW4zhP0kO5uQz1%252BnoJn0mHa0F9hbJw1FRqaoDg8wseD1V0JIdR225bDQ%253D%253D",
"url": "http://docs-sandbox.openprocurement.org/get/5859312b16d045faa41f2e1ba716b542?KeyID=e8946325&Signature=nHKzNVNP9TjehITqsEJA3%2FliccklioZxfXoQyM8Gzn3LYbfeh7xiy82iDssKH8dDv9hMLWm1%2FzO3KOgSUcOqAw%253D%253D",
"format": "text/plain",
"hash": "9a0364b9e99bb480dd25e1f0284c8555",
"hash": "md5:9a0364b9e99bb480dd25e1f0284c8555",
"title": "file.txt"
}
}
Expand Down
4 changes: 2 additions & 2 deletions openprocurement/documentservice/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ def upload(self, post_file, uuid=None):
key = self.storage[uuid] = {}
content = in_file.read()
key_md5 = key.get('hash')
md5hash = md5(content).hexdigest()
if key_md5 and md5(content).hexdigest() != key_md5:
md5hash = 'md5:' + md5(content).hexdigest()
if key_md5 and md5hash != key_md5:
raise HashInvalid(key_md5)
key['hash'] = md5hash
key['Content-Type'] = content_type
Expand Down
32 changes: 28 additions & 4 deletions openprocurement/documentservice/tests/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,32 @@ def test_register_invalid(self):
{u'description': u'Not Found', u'location': u'body', u'name': u'hash'}
])

response = self.app.post(url, {'hash': 'hash'}, status=422)
self.assertEqual(response.status, '422 Unprocessable Entity')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.json['status'], 'error')
self.assertEqual(response.json['errors'], [
{u'description': [u'Hash type is not supported.'], u'name': u'hash', u'location': u'body'}
])

response = self.app.post(url, {'hash': 'md5:hash'}, status=422)
self.assertEqual(response.status, '422 Unprocessable Entity')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.json['status'], 'error')
self.assertEqual(response.json['errors'], [
{u'description': [u'Hash value is wrong length.'], u'name': u'hash', u'location': u'body'}
])

response = self.app.post(url, {'hash': 'md5:' + 'o' * 32}, status=422)
self.assertEqual(response.status, '422 Unprocessable Entity')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.json['status'], 'error')
self.assertEqual(response.json['errors'], [
{u'description': [u'Hash value is not hexadecimal.'], u'name': u'hash', u'location': u'body'}
])

def test_register_post(self):
response = self.app.post('/register', {'hash': 'hash', 'filename': 'file.txt'})
response = self.app.post('/register', {'hash': 'md5:' + '0' * 32, 'filename': 'file.txt'})
self.assertEqual(response.status, '201 Created')
self.assertEqual(response.content_type, 'application/json')
self.assertIn('http://localhost/upload/', response.json['upload_url'])
Expand Down Expand Up @@ -103,7 +127,7 @@ def test_upload_file_invalid(self):
])

def test_upload_file_hash(self):
response = self.app.post('/register', {'hash': 'hash', 'filename': 'file.txt'})
response = self.app.post('/register', {'hash': 'md5:' + '0' * 32, 'filename': 'file.txt'})
self.assertEqual(response.status, '201 Created')
self.assertEqual(response.content_type, 'application/json')
self.assertIn('http://localhost/upload/', response.json['upload_url'])
Expand All @@ -118,7 +142,7 @@ def test_upload_file_hash(self):

def test_upload_file_post(self):
content = 'content'
md5hash = md5(content).hexdigest()
md5hash = 'md5:' + md5(content).hexdigest()
response = self.app.post('/register', {'hash': md5hash, 'filename': 'file.txt'})
self.assertEqual(response.status, '201 Created')
self.assertEqual(response.content_type, 'application/json')
Expand Down Expand Up @@ -203,7 +227,7 @@ def test_get_invalid(self):
self.assertEqual(response.status, '204 No Content')

def test_get_hash(self):
md5hash = md5('content').hexdigest()
md5hash = 'md5:' + md5('content').hexdigest()
response = self.app.post('/register', {'hash': md5hash, 'filename': 'file.txt'})
self.assertEqual(response.status, '201 Created')
self.assertEqual(response.content_type, 'application/json')
Expand Down
10 changes: 8 additions & 2 deletions openprocurement/documentservice/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ def register_view(request):
if 'hash' not in request.POST:
return error_handler(request, 404, {"location": "body", "name": "hash", "description": "Not Found"})
md5 = request.POST['hash']
if not md5.startswith('md5:'):
return error_handler(request, 422, {"location": "body", "name": "hash", "description": [u'Hash type is not supported.']})
if len(md5) != 36:
return error_handler(request, 422, {"location": "body", "name": "hash", "description": [u'Hash value is wrong length.']})
if set(md5[5:]).difference('0123456789abcdef'):
return error_handler(request, 422, {"location": "body", "name": "hash", "description": [u'Hash value is not hexadecimal.']})
uuid = request.registry.storage.register(md5)
LOGGER.info('Registered new document upload {}'.format(uuid),
extra=context_unpack(request, {'MESSAGE_ID': 'registered_upload'}, {'doc_id': uuid, 'doc_hash': md5}))
Expand All @@ -42,7 +48,7 @@ def upload_view(request):
LOGGER.info('Uploaded new document {}'.format(uuid),
extra=context_unpack(request, {'MESSAGE_ID': 'uploaded_new_document'}, {'doc_id': uuid, 'doc_hash': md5}))
expires = int(time()) + EXPIRES
signature = quote(b64encode(request.registry.signer.signature("{}\0{}".format(uuid, md5))))
signature = quote(b64encode(request.registry.signer.signature("{}\0{}".format(uuid, md5[5:]))))
url = request.route_url('get', doc_id=uuid, _query={'Signature': signature, 'KeyID': request.registry.dockey}, _host=request.registry.get_host or request.domain)
signature = quote(b64encode(request.registry.signer.signature("{}\0{}".format(uuid, expires))))
get_url = request.route_url('get', doc_id=uuid, _query={'Signature': signature, 'Expires': expires, 'KeyID': request.registry.dockey}, _host=request.registry.get_host or request.domain)
Expand Down Expand Up @@ -83,7 +89,7 @@ def upload_file_view(request):
LOGGER.info('Uploaded document {}'.format(uuid),
extra=context_unpack(request, {'MESSAGE_ID': 'uploaded_document'}, {'doc_hash': md5}))
expires = int(time()) + EXPIRES
signature = quote(b64encode(request.registry.signer.signature("{}\0{}".format(uuid, md5))))
signature = quote(b64encode(request.registry.signer.signature("{}\0{}".format(uuid, md5[5:]))))
url = request.route_url('get', doc_id=uuid, _query={'Signature': signature, 'KeyID': request.registry.dockey}, _host=request.registry.get_host or request.domain)
signature = quote(b64encode(request.registry.signer.signature("{}\0{}".format(uuid, expires))))
get_url = request.route_url('get', doc_id=uuid, _query={'Signature': signature, 'Expires': expires, 'KeyID': request.registry.dockey}, _host=request.registry.get_host or request.domain)
Expand Down

0 comments on commit 9bf59e6

Please sign in to comment.