Skip to content

Commit ef7a542

Browse files
author
Craig Christenson
committed
adding sha3 support
1 parent 43907e6 commit ef7a542

File tree

5 files changed

+137
-92
lines changed

5 files changed

+137
-92
lines changed

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
requests~=2.25.1
2+
pyjwt~=2.0.1
23

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from distutils.core import setup
33
setup(
44
name="twocheckout",
5-
version='1.0.0',
5+
version='1.1.0',
66
description="2Checkout Python SDK using API 6.0",
77
author="2Checkout",
88
author_email="support@2checkout.com",

test/test_twocheckout.py

Lines changed: 95 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
import sys
44
import datetime
55
import unittest
6-
import twocheckout
7-
from test import config
8-
import hmac
6+
import logging
7+
from freezegun import freeze_time
98

109
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
1110

11+
import twocheckout
12+
from test import config
13+
1214
NOW = datetime.datetime.now()
1315

1416
auth_params = {
@@ -176,7 +178,7 @@
176178
}
177179
],
178180
"PaymentDetails": {
179-
"Type": "CC",
181+
"Type": "TEST",
180182
"Currency": "USD",
181183
"CustomerIP": "91.220.121.21",
182184
"PaymentMethod": {
@@ -216,12 +218,12 @@
216218

217219
ipn_payload = {
218220
'GIFT_ORDER': '0',
219-
'SALEDATE': '2021-04-08 16:29:38',
220-
'PAYMENTDATE': '2021-04-08 16:29:42',
221-
'REFNO': '148998082',
221+
'SALEDATE': '2023-06-09 15:26:18',
222+
'PAYMENTDATE': '2023-06-09 15:31:18',
223+
'REFNO': '211153389',
222224
'REFNOEXT': 'REST_API_AVANGTE',
223225
'SHOPPER_REFERENCE_NUMBER': '',
224-
'ORDERNO': '8978',
226+
'ORDERNO': '25430',
225227
'ORDERSTATUS': 'COMPLETE',
226228
'PAYMETHOD': 'Visa/MasterCard',
227229
'PAYMETHOD_CODE': 'CCVISAMC',
@@ -236,41 +238,41 @@
236238
'ADDRESS1': 'Test Address',
237239
'ADDRESS2': '',
238240
'CITY': 'LA',
239-
'STATE': 'California',
240-
'ZIPCODE': '12345',
241+
'STATE': 'DF',
242+
'ZIPCODE': '70403-900',
241243
'COUNTRY': 'United States of America',
242244
'COUNTRY_CODE': 'us',
243-
'PHONE': '',
245+
'PHONE': '556133127400',
244246
'FAX': '',
245-
'CUSTOMEREMAIL': 'testcustomer@2Checkout.com',
247+
'CUSTOMEREMAIL': 'customer@2Checkout.com',
246248
'FIRSTNAME_D': 'Customer',
247249
'LASTNAME_D': '2Checkout',
248250
'COMPANY_D': '',
249251
'ADDRESS1_D': 'Test Address',
250252
'ADDRESS2_D': '',
251253
'CITY_D': 'LA',
252-
'STATE_D': 'California',
253-
'ZIPCODE_D': '12345',
254+
'STATE_D': 'DF',
255+
'ZIPCODE_D': '70403-900',
254256
'COUNTRY_D': 'United States of America',
255257
'COUNTRY_D_CODE': 'us',
256-
'PHONE_D': '',
257-
'EMAIL_D': 'testcustomer@2Checkout.com',
258+
'PHONE_D': '556133127400',
259+
'EMAIL_D': 'customer@2Checkout.com',
258260
'IPADDRESS': '91.220.121.21',
259261
'IPCOUNTRY': 'Romania',
260-
'COMPLETE_DATE': '2021-04-08 16:29:48',
262+
'COMPLETE_DATE': '2023-06-09 15:31:23',
261263
'TIMEZONE_OFFSET': 'GMT+03:00',
262-
'CURRENCY': 'USD',
264+
'CURRENCY': 'RON',
263265
'LANGUAGE': 'en',
264266
'ORDERFLOW': 'REGULAR',
265-
'IPN_PID[]': '35144095',
267+
'IPN_PID[]': '40898000',
266268
'IPN_PNAME[]': 'Dynamic product',
267269
'IPN_PCODE[]': '',
268270
'IPN_EXTERNAL_REFERENCE[]': '',
269271
'IPN_INFO[]': '',
270272
'IPN_QTY[]': '1',
271-
'IPN_PRICE[]': '107.00',
273+
'IPN_PRICE[]': '0.01',
272274
'IPN_VAT[]': '0.00',
273-
'IPN_VAT_RATE[]': '0.00',
275+
'IPN_VAT_RATE[]': '0.0000',
274276
'IPN_VER[]': '1',
275277
'IPN_DISCOUNT[]': '0.00',
276278
'IPN_PROMOTION_CATEGORY[]': '',
@@ -281,54 +283,50 @@
281283
'IPN_PARTNER_CODE': '',
282284
'IPN_PGROUP[]': '0',
283285
'IPN_PGROUP_NAME[]': '',
284-
'MESSAGE_ID': '250833683479',
286+
'MESSAGE_ID': '254514574331',
285287
'MESSAGE_TYPE': 'COMPLETE',
286-
'IPN_LICENSE_PROD[]': '35144095',
288+
'IPN_LICENSE_PROD[]': '40898000',
287289
'IPN_LICENSE_TYPE[]': 'REGULAR',
288-
'IPN_LICENSE_REF[]': '9WITYHQ6NF',
289-
'IPN_LICENSE_EXP[]': '2021-04-10 16:29:42',
290-
'IPN_LICENSE_START[]': '2021-04-08 16:29:42',
291-
'IPN_LICENSE_LIFETIME[]': 'NO',
290+
'IPN_LICENSE_REF[]': 'XRILXB9ZI3',
291+
'IPN_LICENSE_EXP[]': '9999-12-31 23:59:59',
292+
'IPN_LICENSE_START[]': '2023-06-09 15:31:18',
293+
'IPN_LICENSE_LIFETIME[]': 'YES',
292294
'IPN_LICENSE_ADDITIONAL_INFO[]': '',
293295
'IPN_DELIVEREDCODES[]': '',
294296
'IPN_DOWNLOAD_LINK': '',
295-
'IPN_TOTAL[]': '107.00',
296-
'IPN_TOTALGENERAL': '107.00',
297+
'IPN_TOTAL[]': '0.01',
298+
'IPN_TOTALGENERAL': '0.01',
297299
'IPN_SHIPPING': '0.00',
298300
'IPN_SHIPPING_TAX': '0.00',
299-
'AVANGATE_CUSTOMER_REFERENCE': '884855078',
300-
'EXTERNAL_CUSTOMER_REFERENCE': '',
301+
'AVANGATE_CUSTOMER_REFERENCE': '756227060',
302+
'EXTERNAL_CUSTOMER_REFERENCE': 'IOUER',
301303
'IPN_PARTNER_MARGIN_PERCENT': '0.00',
302304
'IPN_PARTNER_MARGIN': '0.00',
303305
'IPN_EXTRA_MARGIN': '0.00',
304306
'IPN_EXTRA_DISCOUNT': '0.00',
305307
'IPN_COUPON_DISCOUNT': '0.00',
306308
'IPN_LINK_SOURCE': 'testAPI.com',
307-
'IPN_COMMISSION': '4.1015',
309+
'IPN_COMMISSION': '2.7678',
308310
'REFUND_TYPE': '',
309-
'IPN_PRODUCT_OPTIONS_35144095_TEXT[]': 'Name LR',
310-
'IPN_PRODUCT_OPTIONS_35144095_VALUE[]': 'f21a6009c31851ab5166190e353012bd',
311-
'IPN_PRODUCT_OPTIONS_35144095_OPTIONAL_VALUE[]': 'f21a6009c31851ab5166190e353012bd',
312-
'IPN_PRODUCT_OPTIONS_35144095_PRICE[]': '7.00',
313-
'IPN_PRODUCT_OPTIONS_35144095_OPERATOR[]': 'ADD',
314-
'IPN_PRODUCT_OPTIONS_35144095_USAGE[]': 'PREPAID',
315311
'CHARGEBACK_RESOLUTION': 'NONE',
316312
'CHARGEBACK_REASON_CODE': '',
317-
'TEST_ORDER': '1',
313+
'TEST_ORDER': '0',
318314
'IPN_ORDER_ORIGIN': 'API',
319315
'FRAUD_STATUS': 'APPROVED',
320-
'CARD_TYPE': 'visa',
321-
'CARD_LAST_DIGITS': '1111',
322-
'CARD_EXPIRATION_DATE': '12/22',
316+
'CARD_TYPE': 'mastercard',
317+
'CARD_LAST_DIGITS': '5547',
318+
'CARD_EXPIRATION_DATE': '05/27',
323319
'GATEWAY_RESPONSE': 'Approved',
324-
'IPN_DATE': '20210408185911',
325-
'FX_RATE': '1',
326-
'FX_MARKUP': '0',
327-
'PAYABLE_AMOUNT': '102.90',
320+
'IPN_DATE': '20230621183208',
321+
'FX_RATE': '0.20810660205937',
322+
'FX_MARKUP': '4',
323+
'PAYABLE_AMOUNT': '-0.57',
328324
'PAYOUT_CURRENCY': 'USD',
329325
'VENDOR_CODE': '250111206876',
330326
'PROPOSAL_ID': '',
331-
'HASH': '8d05499f0933c2e07c8599ff3a2e5338'
327+
'HASH': 'c9dab0c182b551b1e5d2cc9c17d72c8a',
328+
'SIGNATURE_SHA2_256': '4e1987e54ba070da5dcb583251b71a221c64b41e7bf4d9156938ece4d536a00e',
329+
'SIGNATURE_SHA3_256': '9a4deae5e3479adcbecb7b1f8202ab86e3d3ff415b5add9c40737f1a01b400fc'
332330
}
333331

334332

@@ -350,7 +348,7 @@ def test_1_get_signature_without_token_expiration(self):
350348
config.TWOCHECKOUT_TEST_BUYLINK_SECRET_WORD,
351349
json_encoded_convert_plus_parameters)))
352350

353-
def test_1_get_signature_with_token_expiration(self):
351+
def test_2_get_signature_with_token_expiration(self):
354352
self.assertEqual(64, len(self.cplus.get_signature(
355353
config.TWOCHECKOUT_TEST_MERCHANT_ID,
356354
config.TWOCHECKOUT_TEST_BUYLINK_SECRET_WORD,
@@ -373,7 +371,8 @@ def setUp(self):
373371

374372
# Get order test
375373
def test_1_order_get(self):
376-
self.assertEqual(order_get_test, self.order.get(order_transaction_id))
374+
response = self.order.get(order_transaction_id)
375+
self.assertEqual(order_transaction_id, response['body']['RefNo'])
377376

378377
# Create order test
379378
def test_2_order_create(self):
@@ -387,38 +386,56 @@ def setUp(self):
387386
super(IpnHelperTestCase, self).setUp()
388387
self.ipn = twocheckout.IpnHelper(config.TWOCHECKOUT_TEST_MERCHANT_SECRET_KEY)
389388

390-
def test_1_ipn_hash(self):
389+
def test_1_ipn_sha3(self):
390+
params = ipn_payload.copy()
391391

392-
self.assertEqual(True, self.ipn.is_valid(ipn_payload))
392+
self.assertEqual(True, self.ipn.is_valid(params))
393+
394+
def test_2_ipn_sha2(self):
395+
params = ipn_payload.copy()
396+
if 'SIGNATURE_SHA3_256' in params:
397+
del params['SIGNATURE_SHA3_256']
393398

394-
def test_2_ipn_calculate_response(self):
395-
expected = self.calculate_ipn_response(ipn_payload)
396-
received = self.ipn.calculate_ipn_response(ipn_payload)
397-
398-
self.assertEqual(expected, received)
399+
self.assertEqual(True, self.ipn.is_valid(params))
400+
401+
def test_3_ipn_md5(self):
402+
params = ipn_payload.copy()
403+
if 'SIGNATURE_SHA3_256' in params:
404+
del params['SIGNATURE_SHA3_256']
405+
if 'SIGNATURE_SHA2_256' in params:
406+
del params['SIGNATURE_SHA2_256']
399407

400-
def calculate_ipn_response(self, params):
401-
now = NOW
402-
result = ''
403-
ipn_response = {'IPN_PID': [params['IPN_PID[]']],
404-
'IPN_NAME': [params['IPN_PNAME[]']],
405-
'IPN_DATE': params['IPN_DATE'],
406-
'DATE': now.strftime('%Y%m%d%H%M%S')}
408+
self.assertEqual(True, self.ipn.is_valid(params))
407409

408-
for param in ipn_response:
409-
if type(ipn_response[param]) is list:
410-
result += self.expand(ipn_response[param])
411-
else:
412-
size = len(ipn_response[param])
413-
result += str(size) + ipn_response[param]
410+
@freeze_time("Jan 1st, 2023")
411+
def test_4_ipn_calculate_response_sha3(self):
412+
params = ipn_payload.copy()
413+
date = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
414+
expected = '<sig algo="sha3_256" date="' + date + '">8bfa5029589981a1f959cfb0f95fb16f1f270237bed4af3531ab2c162bf0d48c</sig>'
415+
received = self.ipn.calculate_ipn_response(params, date)
416+
417+
self.assertEqual(expected, received)
414418

415-
return '<EPAYMENT>' + ipn_response['DATE'] + '|' + hmac.new(
416-
config.TWOCHECKOUT_TEST_MERCHANT_SECRET_KEY.encode(), result.encode(),
417-
'md5').hexdigest() + '</EPAYMENT>'
419+
@freeze_time("Jan 1st, 2023")
420+
def test_5_ipn_calculate_response_sha2(self):
421+
params = ipn_payload.copy()
422+
if 'SIGNATURE_SHA3_256' in params:
423+
del params['SIGNATURE_SHA3_256']
424+
date = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
425+
expected = '<sig algo="sha256" date="' + date + '">e2594e0b3054b5d21c9ea8be18356f1ac43f5ca6bb66473556f6beb49880adf9</sig>'
426+
received = self.ipn.calculate_ipn_response(params, date)
427+
428+
self.assertEqual(expected, received)
418429

419-
def expand(self, val_list):
420-
result = ''
421-
for val in val_list:
422-
size = len(val.lstrip())
423-
result += str(size) + str(val.lstrip())
424-
return result
430+
@freeze_time("Jan 1st, 2023")
431+
def test_6_ipn_calculate_response_md5(self):
432+
params = ipn_payload.copy()
433+
if 'SIGNATURE_SHA3_256' in params:
434+
del params['SIGNATURE_SHA3_256']
435+
if 'SIGNATURE_SHA2_256' in params:
436+
del params['SIGNATURE_SHA2_256']
437+
date = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
438+
expected = '<EPAYMENT>' + date + '|8e8147a440040b520239d304735c2ef4</EPAYMENT>'
439+
received = self.ipn.calculate_ipn_response(params, date)
440+
441+
self.assertEqual(expected, received)

twocheckout/api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import datetime
55
import requests
66
import json
7-
from .error import TwocheckoutError
7+
from .error import TwocheckoutError
88

99

1010
class Api:
@@ -31,11 +31,11 @@ def get_headers(self):
3131
string = str(len(self.merchant_code)) + self.merchant_code + str(len(now)) + now
3232
string = codecs.encode(string)
3333
secret_key = codecs.encode(self.secret_key)
34-
string_hash = hmac.new(secret_key, string, hashlib.md5).hexdigest()
34+
string_hash = hmac.new(secret_key, string, hashlib.sha256).hexdigest()
3535
return {
3636
'Content-Type': 'application/json',
3737
'Accept': 'application/json',
38-
'X-Avangate-Authentication': 'code="' + self.merchant_code + '" date="' + now + '" hash="' + string_hash + '"'
38+
'X-Avangate-Authentication': 'code="' + self.merchant_code + '" date="' + now + '" hash="' + string_hash + '" algo="sha256"'
3939
}
4040

4141
# make request to 2Checkout API and returns the response

0 commit comments

Comments
 (0)