Skip to content

Commit

Permalink
Switch to libnacl
Browse files Browse the repository at this point in the history
  • Loading branch information
kroman0 committed Jul 5, 2016
1 parent ae3e267 commit 9898c07
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 49 deletions.
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@

.. image:: https://coveralls.io/repos/github/openprocurement/openprocurement.documentservice/badge.svg?branch=master
:target: https://coveralls.io/github/openprocurement/openprocurement.documentservice?branch=master

bin/docservicepython -c "from base64 import b64encode; from pyelliptic import ECC; k=ECC(curve='secp384r1'); print 'private:', b64encode(k.get_privkey()), '\npublic:', b64encode(k.get_pubkey())"
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/5c521a51a3dc417e9c718fd4e6a85157?Expires=1467637367&KeyID=ad1c8f4f&Signature=MGYCMQCJc8ZgfJXH%252BvKGogrFZmqvgINEmVo1neZiSwIKDOhlvRxCBJBcytbsZYNnF%2Fs8wRECMQCdtfP%2FT4vd%252B49gvwR0GA1%2F17pqPlIIntdC8AzzYMzXWCKnDsCInX2LOzYcRzxi7kU%253D HTTP/1.0
GET /get/9be740448a464fcd831185dafb82b70a?Expires=1467737469&KeyID=21e1b21e&Signature=EIQTMEZfOLsoHsnz0OxI3gr7nwmuAokm7p%2FW5sPwv%252BqXhc%252BV8c2%2FFBSAq2ux3ZK3dobboYI4r3gqJ0aaz0ebDQ%253D%253D HTTP/1.0
Authorization: Basic YnJva2VyOmJyb2tlcg==
Host: docs.api-sandbox.openprocurement.org

Expand Down
6 changes: 3 additions & 3 deletions docs/source/tutorial/register.http
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ hash=9a0364b9e99bb480dd25e1f0284c8555&filename=file.txt

201 Created
Content-Type: application/json; charset=UTF-8
Location: http://docs.api-sandbox.openprocurement.org/upload/5c521a51a3dc417e9c718fd4e6a85157?KeyID=ad1c8f4f&Signature=MGUCMGoyv%252BXNkAoYbPChhPZ6MnBJK3ggQJURglrm70ozbwi1D4kLgvkdy8pOWeyU2W7OiAIxALh4s0oX0XuVlvGbBBPEgNhZs8vo1nm1e6Iog%252B7S5cfFAM7jdx1Eam6dV2GbDUN1cQ%253D%253D
Location: http://docs.api-sandbox.openprocurement.org/upload/9be740448a464fcd831185dafb82b70a?KeyID=21e1b21e&Signature=Sx9PlkGNfRl839V7OTTpvspJSv99Ft%2FcOKdXXSYvy6z1HIux9m%252BrDkAArIh3FUJsbB5bW8HwFUxNiNhi43lHBQ%253D%253D

{
"upload_url": "http://docs.api-sandbox.openprocurement.org/upload/5c521a51a3dc417e9c718fd4e6a85157?KeyID=ad1c8f4f&Signature=MGUCMGoyv%252BXNkAoYbPChhPZ6MnBJK3ggQJURglrm70ozbwi1D4kLgvkdy8pOWeyU2W7OiAIxALh4s0oX0XuVlvGbBBPEgNhZs8vo1nm1e6Iog%252B7S5cfFAM7jdx1Eam6dV2GbDUN1cQ%253D%253D",
"upload_url": "http://docs.api-sandbox.openprocurement.org/upload/9be740448a464fcd831185dafb82b70a?KeyID=21e1b21e&Signature=Sx9PlkGNfRl839V7OTTpvspJSv99Ft%2FcOKdXXSYvy6z1HIux9m%252BrDkAArIh3FUJsbB5bW8HwFUxNiNhi43lHBQ%253D%253D",
"data": {
"url": "http://docs.api-sandbox.openprocurement.org/get/5c521a51a3dc417e9c718fd4e6a85157?KeyID=ad1c8f4f&Signature=MGYCMQDFt2N1hVQzSS2TZPTy7%252BdmRwb5PMxVMof2VcMk4UiO9wbPEQWF%2FYURusMGQSVgLRoCMQD2SuipLsTlEUozUvYcuqrX9Siss6knlvllRwZNuWAIKzTJcSEL3oPjzG%2FUdJumSOo%253D",
"url": "http://docs.api-sandbox.openprocurement.org/get/9be740448a464fcd831185dafb82b70a?KeyID=21e1b21e&Signature=2UyCtqlO51VlL%2FGjbymA0n%252BaMY8TUDXwMqPVHE4t9yaoctqtrOWOoKOym9q28GLJHoTg1JNWdTgBoeJBHL38AQ%253D%253D",
"hash": "9a0364b9e99bb480dd25e1f0284c8555"
}
}
Expand Down
12 changes: 6 additions & 6 deletions docs/source/tutorial/upload-file.http
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
POST /upload HTTP/1.0
Authorization: Basic YnJva2VyOmJyb2tlcg==
Content-Length: 179
Content-Type: multipart/form-data; boundary=----------a_BoUnDaRy510302448724$
Content-Type: multipart/form-data; boundary=----------a_BoUnDaRy339650440173$
Host: docs.api-sandbox.openprocurement.org

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

content
------------a_BoUnDaRy510302448724$--
------------a_BoUnDaRy339650440173$--



200 OK
Content-Type: application/json; charset=UTF-8
Location: http://docs.api-sandbox.openprocurement.org/get/1d8f71249398428792506f12c6071f24?Expires=1467637367&KeyID=ad1c8f4f&Signature=MGUCMQCcwML4hKp8CDJyzkDU%2F0LBxoNdgMqOusm6LdXH33hjpT73RmXvLSqMsOg%2F%2FHde2bYCMFMquxwj4imqKlG0FpnX7vuzn5xKgOydvGdaae6rna3jEfRAg%2Fg876vDF%252BfBMXTQGg%253D%253D
Location: http://docs.api-sandbox.openprocurement.org/get/1a4ccd22ac4d4d288e27e6ed37f9c322?Expires=1467737469&KeyID=21e1b21e&Signature=QcFwJWPxaa%252Bvp5MyNiMLn10T0GnsepVdkkD9W84UXr3govyJ2sU1oFVmf1vptx2DUAwdWi56VfOqyFWJbtKzAw%253D%253D

{
"get_url": "http://docs.api-sandbox.openprocurement.org/get/1d8f71249398428792506f12c6071f24?Expires=1467637367&KeyID=ad1c8f4f&Signature=MGUCMQCcwML4hKp8CDJyzkDU%2F0LBxoNdgMqOusm6LdXH33hjpT73RmXvLSqMsOg%2F%2FHde2bYCMFMquxwj4imqKlG0FpnX7vuzn5xKgOydvGdaae6rna3jEfRAg%2Fg876vDF%252BfBMXTQGg%253D%253D",
"get_url": "http://docs.api-sandbox.openprocurement.org/get/1a4ccd22ac4d4d288e27e6ed37f9c322?Expires=1467737469&KeyID=21e1b21e&Signature=QcFwJWPxaa%252Bvp5MyNiMLn10T0GnsepVdkkD9W84UXr3govyJ2sU1oFVmf1vptx2DUAwdWi56VfOqyFWJbtKzAw%253D%253D",
"data": {
"url": "http://docs.api-sandbox.openprocurement.org/get/1d8f71249398428792506f12c6071f24?KeyID=ad1c8f4f&Signature=MGUCMQCfllpotQXrT%2FRyVKFCSWwiAdebP2VNSu%2F6qxFYeaSjYHUWZ0XdFXshuKwFZA1xjwoCMDVFPQ42ILxenhJWUR8xz1THjwCEQvJJvccpvHipCW3IBR9RKPtafF6yXD4DVRKajw%253D%253D",
"url": "http://docs.api-sandbox.openprocurement.org/get/1a4ccd22ac4d4d288e27e6ed37f9c322?KeyID=21e1b21e&Signature=RbT3RyJSRLt9FCjv2w%252BtoJT1bWJC9af84eR773RCBI8UsDpir6MZGS4ps7ik5icoUlf%2FfpmJkDZWlg72%252Bp66Dw%253D%253D",
"format": "text/plain",
"hash": "9a0364b9e99bb480dd25e1f0284c8555",
"title": "file.txt"
Expand Down
12 changes: 6 additions & 6 deletions docs/source/tutorial/upload.http
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
POST /upload/5c521a51a3dc417e9c718fd4e6a85157?KeyID=ad1c8f4f&Signature=MGUCMGoyv%252BXNkAoYbPChhPZ6MnBJK3ggQJURglrm70ozbwi1D4kLgvkdy8pOWeyU2W7OiAIxALh4s0oX0XuVlvGbBBPEgNhZs8vo1nm1e6Iog%252B7S5cfFAM7jdx1Eam6dV2GbDUN1cQ%253D%253D HTTP/1.0
POST /upload/9be740448a464fcd831185dafb82b70a?KeyID=21e1b21e&Signature=Sx9PlkGNfRl839V7OTTpvspJSv99Ft%2FcOKdXXSYvy6z1HIux9m%252BrDkAArIh3FUJsbB5bW8HwFUxNiNhi43lHBQ%253D%253D HTTP/1.0
Authorization: Basic YnJva2VyOmJyb2tlcg==
Content-Length: 179
Content-Type: multipart/form-data; boundary=----------a_BoUnDaRy674897056583$
Content-Type: multipart/form-data; boundary=----------a_BoUnDaRy460497694743$
Host: docs.api-sandbox.openprocurement.org

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

content
------------a_BoUnDaRy674897056583$--
------------a_BoUnDaRy460497694743$--



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

{
"get_url": "http://docs.api-sandbox.openprocurement.org/get/5c521a51a3dc417e9c718fd4e6a85157?Expires=1467637367&KeyID=ad1c8f4f&Signature=MGYCMQCJc8ZgfJXH%252BvKGogrFZmqvgINEmVo1neZiSwIKDOhlvRxCBJBcytbsZYNnF%2Fs8wRECMQCdtfP%2FT4vd%252B49gvwR0GA1%2F17pqPlIIntdC8AzzYMzXWCKnDsCInX2LOzYcRzxi7kU%253D",
"get_url": "http://docs.api-sandbox.openprocurement.org/get/9be740448a464fcd831185dafb82b70a?Expires=1467737469&KeyID=21e1b21e&Signature=EIQTMEZfOLsoHsnz0OxI3gr7nwmuAokm7p%2FW5sPwv%252BqXhc%252BV8c2%2FFBSAq2ux3ZK3dobboYI4r3gqJ0aaz0ebDQ%253D%253D",
"data": {
"url": "http://docs.api-sandbox.openprocurement.org/get/5c521a51a3dc417e9c718fd4e6a85157?KeyID=ad1c8f4f&Signature=MGYCMQDCSlYiZi2F81shpDJB8%252BTqJdWDuBEOllSKPOHiUCpDrWtjstpAyEUEbTwksrZ0OoECMQDgeqykJoF76JPn%2FM%2FKISnByQQzKeFvYJcOpdqqqwoIg7ZQmzvTdB8CmBvzaOggbjk%253D",
"url": "http://docs.api-sandbox.openprocurement.org/get/9be740448a464fcd831185dafb82b70a?KeyID=21e1b21e&Signature=2UyCtqlO51VlL%2FGjbymA0n%252BaMY8TUDXwMqPVHE4t9yaoctqtrOWOoKOym9q28GLJHoTg1JNWdTgBoeJBHL38AQ%253D%253D",
"format": "text/plain",
"hash": "9a0364b9e99bb480dd25e1f0284c8555",
"title": "file.txt"
Expand Down
38 changes: 16 additions & 22 deletions openprocurement/documentservice/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import gevent.monkey
gevent.monkey.patch_all()
import os
from ConfigParser import ConfigParser
from base64 import b64encode, b64decode
from hashlib import sha512
from libnacl.sign import Signer, Verifier
from logging import getLogger
from pkg_resources import iter_entry_points
from pyramid.config import Configurator
from pyramid.authentication import BasicAuthAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.config import Configurator
from pyramid.security import Allow
from pytz import timezone
from pyelliptic import ECC
from base64 import b64encode, b64decode
from ConfigParser import ConfigParser
from hashlib import sha512


LOGGER = getLogger(__name__)
TZ = timezone(os.environ['TZ'] if 'TZ' in os.environ else 'Europe/Kiev')
Expand All @@ -23,7 +23,6 @@ def auth_check(username, password, request):
return ['g:{}'.format(USERS[username]['group'])]


from pyramid.security import Allow
class Root(object):
def __init__(self, request):
pass
Expand Down Expand Up @@ -67,23 +66,18 @@ def main(global_config, **settings):
config.add_route('get', '/get/{doc_id}')
config.scan(ignore='openprocurement.documentservice.tests')

curve = settings.get('curve', 'secp384r1')
privkey = b64decode(settings.get('privkey')) if 'privkey' in settings else None
pubkey = b64decode(settings.get('pubkey')) if 'pubkey' in settings else None
dockeys = settings.get('dockeys') if 'dockeys' in settings else b64encode(ECC(curve=curve).get_pubkey())
dockey = ECC(pubkey=pubkey, privkey=privkey, curve=curve)
config.registry.dockey = dockey.get_pubkey().encode('hex')[2:10]
config.registry.dockeyring = dockeyring = {config.registry.dockey: dockey}
config.registry.signer = signer = Signer(settings.get('dockey', '').decode('hex'))
config.registry.dockey = dockey = signer.hex_vk()[:8]
verifier = Verifier(signer.hex_vk())
config.registry.dockeyring = dockeyring = {dockey: verifier}
dockeys = settings.get('dockeys') if 'dockeys' in settings else Signer().hex_vk()
for key in dockeys.split('\0'):
decoded_key = b64decode(key)
dockeyring[decoded_key.encode('hex')[2:10]] = ECC(pubkey=decoded_key, curve=curve)
apikeys = settings.get('apikeys') if 'apikeys' in settings else b64encode(ECC(curve=curve).get_pubkey())
config.registry.dockey = dockey.get_pubkey().encode('hex')[2:10]
config.registry.keyring = keyring = {config.registry.dockey: dockey}
dockeyring[key[:8]] = Verifier(key)
config.registry.keyring = keyring = {dockey: verifier}
apikeys = settings.get('apikeys') if 'apikeys' in settings else Signer().hex_vk()
for key in apikeys.split('\0'):
decoded_key = b64decode(key)
keyring[decoded_key.encode('hex')[2:10]] = ECC(pubkey=decoded_key, curve=curve)
config.registry.apikey = decoded_key.encode('hex')[2:10]
keyring[key[:8]] = Verifier(key)
config.registry.apikey = key[:8]

# search for storage
storage = settings.get('storage')
Expand Down
24 changes: 14 additions & 10 deletions openprocurement/documentservice/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ def register_view(request):
}
md5 = request.POST['hash']
uuid = request.registry.storage.register(md5)
signature = quote(b64encode(request.registry.dockeyring[request.registry.dockey].sign(uuid)))
signature = quote(b64encode(request.registry.signer.signature(uuid)))
upload_url = request.route_url('upload_file', doc_id=uuid, _query={'Signature': signature, 'KeyID': request.registry.dockey})
signature = quote(b64encode(request.registry.keyring[request.registry.dockey].sign("{}\0{}".format(uuid, md5))))
signature = quote(b64encode(request.registry.signer.signature("{}\0{}".format(uuid, md5))))
url = request.route_url('get', doc_id=uuid, _query={'Signature': signature, 'KeyID': request.registry.dockey})
request.response.status = 201
request.response.headers['Location'] = upload_url
Expand All @@ -37,10 +37,9 @@ def upload_view(request):
post_file = request.POST['file']
uuid, md5, content_type, filename = request.registry.storage.upload(post_file)
expires = int(time()) + EXPIRES
mess = "{}\0{}".format(uuid, expires)
signature = quote(b64encode(request.registry.keyring[request.registry.dockey].sign("{}\0{}".format(uuid, md5))))
signature = quote(b64encode(request.registry.signer.signature("{}\0{}".format(uuid, md5))))
url = request.route_url('get', doc_id=uuid, _query={'Signature': signature, 'KeyID': request.registry.dockey})
signature = quote(b64encode(request.registry.keyring[request.registry.dockey].sign(mess)))
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})
request.response.headers['Location'] = get_url
return {'data': {'url': url, 'hash': md5, 'format': content_type, 'title': filename}, 'get_url': get_url}
Expand Down Expand Up @@ -78,7 +77,10 @@ def upload_file_view(request):
"status": "error",
"errors": [{"location": "url", "name": "Signature", "description": "Signature invalid"}]
}
if not key.verify(signature, uuid):
try:
if uuid != key.verify(signature + uuid.encode("utf-8")):
raise ValueError
except ValueError:
request.response.status = 403
return {
"status": "error",
Expand Down Expand Up @@ -106,10 +108,9 @@ def upload_file_view(request):
"errors": [{"location": "body", "name": "file", "description": "Invalid checksum"}]
}
expires = int(time()) + EXPIRES
mess = "{}\0{}".format(uuid, expires)
signature = quote(b64encode(request.registry.keyring[request.registry.dockey].sign("{}\0{}".format(uuid, md5))))
signature = quote(b64encode(request.registry.signer.signature("{}\0{}".format(uuid, md5))))
url = request.route_url('get', doc_id=uuid, _query={'Signature': signature, 'KeyID': request.registry.dockey})
signature = quote(b64encode(request.registry.keyring[request.registry.dockey].sign(mess)))
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})
return {'data': {'url': url, 'hash': md5, 'format': content_type, 'title': filename}, 'get_url': get_url}

Expand Down Expand Up @@ -158,7 +159,10 @@ def get_view(request):
"status": "error",
"errors": [{"location": "url", "name": "Signature", "description": "Signature invalid"}]
}
if not key.verify(signature, mess):
try:
if mess != key.verify(signature + mess.encode("utf-8")):
raise ValueError
except ValueError:
request.response.status = 403
return {
"status": "error",
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
requires = [
'chaussette',
'gevent',
'pyelliptic',
'libnacl',
'pyramid',
'pyramid_exclog',
'pytz',
Expand Down

0 comments on commit 9898c07

Please sign in to comment.