lingo: check api signature with adding items to basket (#9423)
This commit is contained in:
parent
54c9af60d4
commit
5daad1b54c
|
@ -25,9 +25,12 @@ from django.template.response import TemplateResponse
|
|||
from django.utils import timezone
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import View, ListView, TemplateView
|
||||
from django.conf import settings
|
||||
|
||||
import eopayment
|
||||
|
||||
from combo.utils import check_query
|
||||
|
||||
try:
|
||||
from mellon.models import UserSAMLIdentifier
|
||||
except ImportError:
|
||||
|
@ -63,7 +66,9 @@ class AddBasketItemApiView(View):
|
|||
return d.quantize(Decimal('0.01'), ROUND_HALF_UP)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
# XXX: check request signature
|
||||
key = getattr(settings, 'LINGO_API_SIGN_KEY', '12345')
|
||||
if not check_query(request.META['QUERY_STRING'], key):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
request_body = json.loads(self.request.body)
|
||||
extra = request_body.get('extra', {})
|
||||
|
|
|
@ -63,3 +63,27 @@ def ellipsize(text, length=50):
|
|||
if len(text) < length:
|
||||
return text
|
||||
return text[:(length-10)] + '...'
|
||||
|
||||
def check_query(query, key, known_nonce=None, timedelta=30):
|
||||
parsed = urlparse.parse_qs(query)
|
||||
signature = base64.b64decode(parsed['signature'][0])
|
||||
algo = parsed['algo'][0]
|
||||
timestamp = parsed['timestamp'][0]
|
||||
timestamp = datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ')
|
||||
nonce = parsed['nonce']
|
||||
unsigned_query = query.split('&signature=')[0]
|
||||
if known_nonce is not None and known_nonce(nonce):
|
||||
return False
|
||||
if abs(datetime.datetime.utcnow() - timestamp) > datetime.timedelta(seconds=timedelta):
|
||||
return False
|
||||
return check_string(unsigned_query, signature, key, algo=algo)
|
||||
|
||||
def check_string(s, signature, key, algo='sha256'):
|
||||
# constant time compare
|
||||
signature2 = sign_string(s, key, algo=algo)
|
||||
if len(signature2) != len(signature):
|
||||
return False
|
||||
res = 0
|
||||
for a, b in zip(signature, signature2):
|
||||
res |= ord(a) ^ ord(b)
|
||||
return res == 0
|
||||
|
|
|
@ -9,5 +9,7 @@ KNOWN_SERVICES = {
|
|||
}
|
||||
}
|
||||
|
||||
LINGO_API_SIGN_KEY = '12345'
|
||||
|
||||
import tempfile
|
||||
MEDIA_ROOT = tempfile.mkdtemp('combo-test')
|
||||
|
|
|
@ -8,11 +8,13 @@ import json
|
|||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
from django.conf import settings
|
||||
from webtest import TestApp
|
||||
|
||||
from django.test import Client
|
||||
|
||||
from combo.apps.lingo.models import Regie, BasketItem, Transaction, RemoteItem
|
||||
from combo.utils import sign_url
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
@ -90,12 +92,14 @@ def test_add_amount_to_basket(regie, user):
|
|||
data = {'amount': amount, 'display_name': 'test amount',
|
||||
'url': 'http://example.com'}
|
||||
url = '%s?email=%s' % (reverse('api-add-basket-item'), user_email)
|
||||
url = sign_url(url, settings.LINGO_API_SIGN_KEY)
|
||||
resp = client.post(url, json.dumps(data), content_type='application/json')
|
||||
assert resp.status_code == 200
|
||||
assert json.loads(resp.content) == {'result': 'success'}
|
||||
assert BasketItem.objects.filter(amount=amount).exists()
|
||||
|
||||
data['extra'] = {'amount': '22.22'}
|
||||
url = sign_url(url, settings.LINGO_API_SIGN_KEY)
|
||||
resp = client.post(url, json.dumps(data), content_type='application/json')
|
||||
assert resp.status_code == 200
|
||||
assert json.loads(resp.content) == {'result': 'success'}
|
||||
|
|
Loading…
Reference in New Issue