add Validation function for cybersource receipt POST

This commit is contained in:
Jason Bau
2013-08-08 21:55:08 -07:00
committed by Diana Huang
parent 3f9c52cd1c
commit ff5ca76aa6
3 changed files with 48 additions and 15 deletions

View File

@@ -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'),
)

View File

@@ -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

View File

@@ -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>