1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
from __future__ import unicode_literals
import binascii
from Crypto.Cipher import AES
from django.core.exceptions import ImproperlyConfigured
from django.shortcuts import redirect
from ..core import BasicProvider
class SagepayProvider(BasicProvider):
'''
sagepay.com payment provider
vendor:
vendor name
encryption_key:
encryption key
endpoint:
gateway URL to post transaction data to
'''
_version = '2.23'
_action = 'https://test.sagepay.com/Simulator/VSPFormGateway.asp'
def __init__(self, vendor, encryption_key, endpoint=_action, **kwargs):
self._vendor = vendor
self._enckey = encryption_key.encode('utf-8')
self._action = endpoint
super(SagepayProvider, self).__init__(**kwargs)
if not self._capture:
raise ImproperlyConfigured(
'Sagepay does not support pre-authorization.')
def _aes_pad(self, crypt):
padding = ""
padlength = 16 - (len(crypt.encode('utf-8')) % 16)
for _i in range(1, padlength + 1):
padding += chr(padlength)
return crypt + padding
def aes_enc(self, data):
aes = AES.new(self._enckey, AES.MODE_CBC, self._enckey)
data = self._aes_pad(data)
enc = aes.encrypt(data.encode('utf-8'))
enc = b"@" + binascii.hexlify(enc)
return enc
def aes_dec(self, data):
data = data.lstrip(b'@').decode('utf-8')
aes = AES.new(self._enckey, AES.MODE_CBC, self._enckey)
dec = binascii.unhexlify(data)
dec = aes.decrypt(dec)
return dec
def get_hidden_fields(self, payment):
payment.save()
return_url = self.get_return_url(payment)
data = {
'VendorTxCode': payment.pk,
'Amount': "%.2f" % (payment.total,),
'Currency': payment.currency,
'SuccessURL': return_url,
'FailureURL': return_url,
'Description': "Payment #%s" % (payment.pk,),
'BillingSurname': payment.billing_last_name,
'BillingFirstnames': payment.billing_first_name,
'BillingAddress1': payment.billing_address_1,
'BillingAddress2': payment.billing_address_2,
'BillingCity': payment.billing_city,
'BillingPostCode': payment.billing_postcode,
'BillingCountry': payment.billing_country_code,
'DeliverySurname': payment.billing_last_name,
'DeliveryFirstnames': payment.billing_first_name,
'DeliveryAddress1': payment.billing_address_1,
'DeliveryAddress2': payment.billing_address_2,
'DeliveryCity': payment.billing_city,
'DeliveryPostCode': payment.billing_postcode,
'DeliveryCountry': payment.billing_country_code}
udata = "&".join("%s=%s" % kv for kv in data.items())
crypt = self.aes_enc(udata)
return {'VPSProtocol': self._version, 'TxType': 'PAYMENT',
'Vendor': self._vendor, 'Crypt': crypt}
def process_data(self, payment, request):
udata = self.aes_dec(request.GET['crypt'])
data = {}
for kv in udata.split('&'):
k, v = kv.split('=')
data[k] = v
success_url = payment.get_success_url()
if payment.status == 'waiting':
# If the payment is not in waiting state, we probably have a page reload.
# We should neither throw 404 nor alter the payment again in such case.
if data['Status'] == 'OK':
payment.captured_amount = payment.total
payment.change_status('confirmed')
return redirect(success_url)
else:
# XXX: We should recognize AUTHENTICATED and REGISTERED in the future.
payment.change_status('rejected')
return redirect(payment.get_failure_url())
return redirect(success_url)
|