add Validation function for cybersource receipt POST
This commit is contained in:
@@ -7,4 +7,5 @@ urlpatterns = patterns('shoppingcart.views', # nopep8
|
||||
url(r'^clear/$','clear_cart'),
|
||||
url(r'^remove_item/$', 'remove_item'),
|
||||
url(r'^purchased/$', 'purchased'),
|
||||
url(r'^receipt/$', 'receipt'),
|
||||
)
|
||||
@@ -4,16 +4,22 @@ import time
|
||||
import hmac
|
||||
import binascii
|
||||
from hashlib import sha1
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
from collections import OrderedDict
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from mitxmako.shortcuts import render_to_response
|
||||
from .models import *
|
||||
|
||||
log = logging.getLogger("shoppingcart")
|
||||
|
||||
shared_secret = settings.CYBERSOURCE.get('SHARED_SECRET','')
|
||||
merchant_id = settings.CYBERSOURCE.get('MERCHANT_ID','')
|
||||
serial_number = settings.CYBERSOURCE.get('SERIAL_NUMBER','')
|
||||
orderPage_version = settings.CYBERSOURCE.get('ORDERPAGE_VERSION','7')
|
||||
|
||||
|
||||
def test(request, course_id):
|
||||
item1 = PaidCourseRegistration(course_id, 200)
|
||||
@@ -39,9 +45,11 @@ def add_course_to_cart(request, course_id):
|
||||
def show_cart(request):
|
||||
cart = Order.get_cart_for_user(request.user)
|
||||
total_cost = cart.total_cost
|
||||
amount = "{0:0.2f}".format(total_cost)
|
||||
cart_items = cart.orderitem_set.all()
|
||||
params = OrderedDict()
|
||||
params['amount'] = total_cost
|
||||
params['comment'] = 'Stanford OpenEdX Purchase'
|
||||
params['amount'] = amount
|
||||
params['currency'] = 'usd'
|
||||
params['orderPage_transactionType'] = 'sale'
|
||||
params['orderNumber'] = "{0:d}".format(cart.id)
|
||||
@@ -57,7 +65,7 @@ def show_cart(request):
|
||||
signed_param_dict = cybersource_sign(params)
|
||||
return render_to_response("shoppingcart/list.html",
|
||||
{'shoppingcart_items': cart_items,
|
||||
'total_cost': total_cost,
|
||||
'amount': amount,
|
||||
'params': signed_param_dict,
|
||||
})
|
||||
|
||||
@@ -78,27 +86,50 @@ def remove_item(request):
|
||||
log.exception('Cannot remove cart OrderItem id={0}. DoesNotExist or item is already purchased'.format(item_id))
|
||||
return HttpResponse('OK')
|
||||
|
||||
@csrf_exempt
|
||||
def receipt(request):
|
||||
"""
|
||||
Receives the POST-back from Cybersource and performs the validation and displays a receipt
|
||||
and does some other stuff
|
||||
"""
|
||||
if cybersource_verify(request.POST):
|
||||
return HttpResponse("Validated")
|
||||
else:
|
||||
return HttpResponse("Not Validated")
|
||||
|
||||
def cybersource_hash(value):
|
||||
"""
|
||||
Performs the base64(HMAC_SHA1(key, value)) used by CyberSource Hosted Order Page
|
||||
"""
|
||||
hash_obj = hmac.new(shared_secret, value, sha1)
|
||||
return binascii.b2a_base64(hash_obj.digest())[:-1] # last character is a '\n', which we don't want
|
||||
|
||||
|
||||
def cybersource_sign(params):
|
||||
"""
|
||||
params needs to be an ordered dict, b/c cybersource documentation states that order is important.
|
||||
Reverse engineered from PHP version provided by cybersource
|
||||
"""
|
||||
shared_secret = settings.CYBERSOURCE.get('SHARED_SECRET','')
|
||||
merchant_id = settings.CYBERSOURCE.get('MERCHANT_ID','')
|
||||
serial_number = settings.CYBERSOURCE.get('SERIAL_NUMBER','')
|
||||
orderPage_version = settings.CYBERSOURCE.get('ORDERPAGE_VERSION','7')
|
||||
params['merchantID'] = merchant_id
|
||||
params['orderPage_timestamp'] = int(time.time()*1000)
|
||||
params['orderPage_version'] = orderPage_version
|
||||
params['orderPage_serialNumber'] = serial_number
|
||||
fields = ",".join(params.keys())
|
||||
values = ",".join(["{0}={1}".format(i,params[i]) for i in params.keys()])
|
||||
fields_hash_obj = hmac.new(shared_secret, fields, sha1)
|
||||
fields_sig = binascii.b2a_base64(fields_hash_obj.digest())[:-1] # last character is a '\n', which we don't want
|
||||
fields_sig = cybersource_hash(fields)
|
||||
values += ",signedFieldsPublicSignature=" + fields_sig
|
||||
values_hash_obj = hmac.new(shared_secret, values, sha1)
|
||||
params['orderPage_signaturePublic'] = binascii.b2a_base64(values_hash_obj.digest())[:-1]
|
||||
params['orderPage_signaturePublic'] = cybersource_hash(values)
|
||||
params['orderPage_signedFields'] = fields
|
||||
|
||||
return params
|
||||
return params
|
||||
|
||||
def cybersource_verify(params):
|
||||
signed_fields = params.get('signedFields', '').split(',')
|
||||
data = ",".join(["{0}={1}".format(k, params.get(k, '')) for k in signed_fields])
|
||||
signed_fields_sig = cybersource_hash(params.get('signedFields', ''))
|
||||
data += ",signedFieldsPublicSignature=" + signed_fields_sig
|
||||
returned_sig = params.get('signedDataPublicSignature','')
|
||||
if not returned_sig:
|
||||
return False
|
||||
return cybersource_hash(data) == returned_sig
|
||||
|
||||
|
||||
@@ -14,11 +14,12 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
% for item in shoppingcart_items:
|
||||
<tr><td>${item.qty}</td><td>${item.line_desc}</td><td>${item.unit_cost}</td><td>${item.line_cost}</td>
|
||||
<tr><td>${item.qty}</td><td>${item.line_desc}</td>
|
||||
<td>${"{0:0.2f}".format(item.unit_cost)}</td><td>${"{0:0.2f}".format(item.line_cost)}</td>
|
||||
<td><a data-item-id="${item.id}" class='remove_line_item' href='#'>[x]</a></td></tr>
|
||||
% endfor
|
||||
<tr><td></td><td></td><td></td><td>Total Cost</td></tr>
|
||||
<tr><td></td><td></td><td></td><td>${total_cost}</td></tr>
|
||||
<tr><td></td><td></td><td></td><td>Total Amount</td></tr>
|
||||
<tr><td></td><td></td><td></td><td>${amount}</td></tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user