Commit 1f6bdca6 by Jason Bau Committed by Diana Huang

add Validation function for cybersource receipt POST

parent ed4e7f54
......@@ -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'),
)
\ No newline at end of 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
\ No newline at end of file
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>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment