diff --git a/lms/djangoapps/shoppingcart/urls.py b/lms/djangoapps/shoppingcart/urls.py index 80653f93cb..99d5217813 100644 --- a/lms/djangoapps/shoppingcart/urls.py +++ b/lms/djangoapps/shoppingcart/urls.py @@ -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 diff --git a/lms/djangoapps/shoppingcart/views.py b/lms/djangoapps/shoppingcart/views.py index 4c2a4dd091..f0558d3003 100644 --- a/lms/djangoapps/shoppingcart/views.py +++ b/lms/djangoapps/shoppingcart/views.py @@ -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 + diff --git a/lms/templates/shoppingcart/list.html b/lms/templates/shoppingcart/list.html index a37aa0fb5f..0ff97aa6ae 100644 --- a/lms/templates/shoppingcart/list.html +++ b/lms/templates/shoppingcart/list.html @@ -14,11 +14,12 @@
% for item in shoppingcart_items: -