summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerghei Mihai <smihai@entrouvert.com>2020-09-15 12:54:38 (GMT)
committerSerghei Mihai <smihai@entrouvert.com>2020-09-15 13:20:10 (GMT)
commitcae250d132c3c9b35916d7eceebef538d56e98ec (patch)
tree79796a5cb4227c956bbb0812e2ab3c01e1681fc2
parentf7d698c71f7dfdb9ba4570dd66d5f95698fb8b5e (diff)
downloadeopayment-cae250d132c3c9b35916d7eceebef538d56e98ec.zip
eopayment-cae250d132c3c9b35916d7eceebef538d56e98ec.tar.gz
eopayment-cae250d132c3c9b35916d7eceebef538d56e98ec.tar.bz2
systempayv2: implement HMAC SHA256 signature (#46658)v1.56
-rw-r--r--eopayment/systempayv2.py25
-rw-r--r--tests/test_systempayv2.py16
2 files changed, 37 insertions, 4 deletions
diff --git a/eopayment/systempayv2.py b/eopayment/systempayv2.py
index 6ff2b1a..99f1cb4 100644
--- a/eopayment/systempayv2.py
+++ b/eopayment/systempayv2.py
@@ -15,9 +15,11 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import base64
import pytz
import datetime as dt
import hashlib
+import hmac
import string
from six.moves.urllib import parse as urlparse
import warnings
@@ -270,6 +272,13 @@ class Payment(PaymentCommon):
{'name': 'secret_production',
'caption': _(u'Secret pour la configuration de PRODUCTION'),
'validation': lambda value: str.isalnum(value), },
+ {'name': 'signature_algo',
+ 'caption': _(u'Algorithme de signature'),
+ 'default': 'hmac_sha256',
+ 'choices': (
+ ('sha1', 'SHA-1'),
+ ('hmac_sha256', 'HMAC-SHA-256'),
+ )},
{
'name': 'manual_validation',
'caption': 'Validation manuelle',
@@ -462,16 +471,24 @@ class Payment(PaymentCommon):
test=test)
return response
+ def sha1_sign(self, secret, signed_data):
+ return hashlib.sha1(signed_data).hexdigest()
+
+ def hmac_sha256_sign(self, secret, signed_data):
+ digest = hmac.HMAC(secret, digestmod=hashlib.sha256, msg=signed_data).digest()
+ return base64.b64encode(digest)
+
def signature(self, fields):
self.logger.debug('got fields %s to sign' % fields)
ordered_keys = sorted(
[key for key in fields.keys() if key.startswith('vads_')])
self.logger.debug('ordered keys %s' % ordered_keys)
ordered_fields = [force_byte(fields[key]) for key in ordered_keys]
- secret = getattr(self, 'secret_%s' % fields['vads_ctx_mode'].lower())
+ secret = force_byte(getattr(self, 'secret_%s' % fields['vads_ctx_mode'].lower()))
signed_data = b'+'.join(ordered_fields)
- signed_data = b'%s+%s' % (signed_data, force_byte(secret))
+ signed_data = b'%s+%s' % (signed_data, secret)
self.logger.debug(u'generating signature on «%s»', signed_data)
- sign = hashlib.sha1(signed_data).hexdigest()
+ sign_method = getattr(self, '%s_sign' % self.signature_algo)
+ sign = sign_method(secret, signed_data)
self.logger.debug(u'signature «%s»', sign)
- return sign
+ return force_text(sign)
diff --git a/tests/test_systempayv2.py b/tests/test_systempayv2.py
index 240f936..e796360 100644
--- a/tests/test_systempayv2.py
+++ b/tests/test_systempayv2.py
@@ -31,6 +31,7 @@ PARAMS = {
'vads_site_id': u'12345678',
'vads_ctx_mode': u'TEST',
'vads_trans_date': u'20090501193530',
+ 'signature_algo': 'sha1'
}
@@ -80,6 +81,21 @@ def test_systempayv2():
assert response.transaction_date
assert response.transaction_date.isoformat() == '2020-03-30T16:25:30+00:00'
+ PARAMS['signature_algo'] = 'hmac_sha256'
+ p = Payment(PARAMS)
+ assert p.signature(qs) == 'aHrJ7IzSGFa4pcYA8kh99+M/xBzoQ4Odnu3f4BUrpIA='
+ response_qs = 'vads_amount=1042&vads_auth_mode=FULL&vads_auth_number=3feadf' \
+ '&vads_auth_result=00&vads_capture_delay=0&vads_card_brand=CB' \
+ '&vads_card_number=497010XXXXXX0000' \
+ '&vads_payment_certificate=582ba2b725057618706d7a06e9e59acdbf69ff53' \
+ '&vads_ctx_mode=TEST&vads_currency=978&vads_effective_amount=1042' \
+ '&vads_site_id=70168983&vads_trans_date=20161013101355' \
+ '&vads_trans_id=226787&vads_trans_uuid=4b5053b3b1fe4b02a07753e7a' \
+ '&vads_effective_creation_date=20200330162530' \
+ '&signature=PeU30M6ilqwhligBAIMQIR3yqxWFGZHJ8Hwtb%2B3IrOM%3D'
+ response = p.response(response_qs)
+ assert response.signed
+
# bad response
with pytest.raises(ResponseError, match='missing signature, vads_ctx_mode or vads_auth_result'):
p.response('foo=bar')