mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-23 11:53:12 +00:00
Stockage en BDD des identifiants comnpay.
This commit is contained in:
parent
c57f155e24
commit
d694330149
7 changed files with 139 additions and 6 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,3 +5,4 @@ re2o.png
|
||||||
__pycache__/*
|
__pycache__/*
|
||||||
static_files/*
|
static_files/*
|
||||||
static/logo/*
|
static/logo/*
|
||||||
|
media/*
|
||||||
|
|
|
@ -11,6 +11,8 @@ from django.utils.datastructures import MultiValueDictKeyError
|
||||||
from django.http import HttpResponse, HttpResponseBadRequest
|
from django.http import HttpResponse, HttpResponseBadRequest
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
from preferences.models import AssoOption
|
||||||
from .models import Facture
|
from .models import Facture
|
||||||
from .payment_utils.comnpay import Payment as ComnpayPayment
|
from .payment_utils.comnpay import Payment as ComnpayPayment
|
||||||
|
|
||||||
|
@ -36,6 +38,7 @@ def refuse_payment(request):
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def ipn(request):
|
def ipn(request):
|
||||||
|
option, _created = AssoOption.objects.get_or_create()
|
||||||
p = ComnpayPayment()
|
p = ComnpayPayment()
|
||||||
order = ('idTpe', 'idTransaction', 'montant', 'result', 'sec', )
|
order = ('idTpe', 'idTransaction', 'montant', 'result', 'sec', )
|
||||||
try:
|
try:
|
||||||
|
@ -43,7 +46,7 @@ def ipn(request):
|
||||||
except MultiValueDictKeyError:
|
except MultiValueDictKeyError:
|
||||||
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
|
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
|
||||||
|
|
||||||
if not p.validSec(data, "DEMO"):
|
if not p.validSec(data, option.payment_pass):
|
||||||
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
|
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
|
||||||
|
|
||||||
result = True if (request.POST['result'] == 'OK') else False
|
result = True if (request.POST['result'] == 'OK') else False
|
||||||
|
@ -51,7 +54,7 @@ def ipn(request):
|
||||||
idTransaction = request.POST['idTransaction']
|
idTransaction = request.POST['idTransaction']
|
||||||
|
|
||||||
# On vérifie que le paiement nous est destiné
|
# On vérifie que le paiement nous est destiné
|
||||||
if not idTpe == "DEMO":
|
if not idTpe == option.payment_id:
|
||||||
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
|
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -78,10 +81,14 @@ def ipn(request):
|
||||||
|
|
||||||
def comnpay(facture, request):
|
def comnpay(facture, request):
|
||||||
host = request.get_host()
|
host = request.get_host()
|
||||||
|
option, _created = AssoOption.objects.get_or_create()
|
||||||
p = ComnpayPayment(
|
p = ComnpayPayment(
|
||||||
"DEMO",
|
str(option.payment_id),
|
||||||
"DEMO",
|
str(option.payment_pass),
|
||||||
'https://' + host + reverse('cotisations:accept_payment', kwargs={'factureid':facture.id}),
|
'https://' + host + reverse(
|
||||||
|
'cotisations:accept_payment',
|
||||||
|
kwargs={'factureid':facture.id}
|
||||||
|
),
|
||||||
'https://' + host + reverse('cotisations:refuse_payment'),
|
'https://' + host + reverse('cotisations:refuse_payment'),
|
||||||
'https://' + host + reverse('cotisations:ipn'),
|
'https://' + host + reverse('cotisations:ipn'),
|
||||||
"",
|
"",
|
||||||
|
@ -90,7 +97,11 @@ def comnpay(facture, request):
|
||||||
r = {
|
r = {
|
||||||
'action' : 'https://secure.homologation.comnpay.com',
|
'action' : 'https://secure.homologation.comnpay.com',
|
||||||
'method' : 'POST',
|
'method' : 'POST',
|
||||||
'content' : p.buildSecretHTML("Rechargement du solde", facture.prix(), idTransaction=str(facture.id)),
|
'content' : p.buildSecretHTML(
|
||||||
|
"Rechargement du solde",
|
||||||
|
facture.prix(),
|
||||||
|
idTransaction=str(facture.id)
|
||||||
|
),
|
||||||
'amount' : facture.prix,
|
'amount' : facture.prix,
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
|
|
53
preferences/aes_field.py
Normal file
53
preferences/aes_field.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import string
|
||||||
|
import binascii
|
||||||
|
from random import choice
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
EOD = '`%EofD%`' # This should be something that will not occur in strings
|
||||||
|
|
||||||
|
|
||||||
|
def genstring(length=16, chars=string.printable):
|
||||||
|
return ''.join([choice(chars) for i in range(length)])
|
||||||
|
|
||||||
|
|
||||||
|
def encrypt(key, s):
|
||||||
|
obj = AES.new(key)
|
||||||
|
datalength = len(s) + len(EOD)
|
||||||
|
if datalength < 16:
|
||||||
|
saltlength = 16 - datalength
|
||||||
|
else:
|
||||||
|
saltlength = 16 - datalength % 16
|
||||||
|
ss = ''.join([s, EOD, genstring(saltlength)])
|
||||||
|
return obj.encrypt(ss)
|
||||||
|
|
||||||
|
|
||||||
|
def decrypt(key, s):
|
||||||
|
obj = AES.new(key)
|
||||||
|
ss = obj.decrypt(s)
|
||||||
|
return ss.split(bytes(EOD, 'utf-8'))[0]
|
||||||
|
|
||||||
|
|
||||||
|
class AESEncryptedField(models.CharField):
|
||||||
|
def save_form_data(self, instance, data):
|
||||||
|
setattr(instance, self.name,
|
||||||
|
binascii.b2a_base64(encrypt(settings.AES_KEY, data)))
|
||||||
|
|
||||||
|
def value_from_object(self, obj):
|
||||||
|
return decrypt(settings.AES_KEY,
|
||||||
|
binascii.a2b_base64(getattr(obj, self.attname))).decode('utf-8')
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
return decrypt(settings.AES_KEY,
|
||||||
|
binascii.a2b_base64(value)).decode('utf-8')
|
||||||
|
|
||||||
|
def from_db_value(self, value, expression, connection, *args):
|
||||||
|
|
||||||
|
if value is None:
|
||||||
|
return value
|
||||||
|
return decrypt(settings.AES_KEY,
|
||||||
|
binascii.a2b_base64(value)).decode('utf-8')
|
26
preferences/migrations/0039_auto_20180115_0003.py
Normal file
26
preferences/migrations/0039_auto_20180115_0003.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.7 on 2018-01-14 23:03
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import preferences.aes_field
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('preferences', '0038_auto_20180114_2209'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assooption',
|
||||||
|
name='payment_id',
|
||||||
|
field=models.CharField(max_length=255, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assooption',
|
||||||
|
name='payment_pass',
|
||||||
|
field=preferences.aes_field.AESEncryptedField(max_length=255, null=True),
|
||||||
|
),
|
||||||
|
]
|
26
preferences/migrations/0040_auto_20180115_0010.py
Normal file
26
preferences/migrations/0040_auto_20180115_0010.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.7 on 2018-01-14 23:10
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import preferences.aes_field
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('preferences', '0039_auto_20180115_0003'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='assooption',
|
||||||
|
name='payment_id',
|
||||||
|
field=models.CharField(default='', max_length=255),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='assooption',
|
||||||
|
name='payment_pass',
|
||||||
|
field=preferences.aes_field.AESEncryptedField(default='', max_length=255),
|
||||||
|
),
|
||||||
|
]
|
|
@ -28,6 +28,8 @@ from __future__ import unicode_literals
|
||||||
from django.db import models
|
from django.db import models
|
||||||
import cotisations.models
|
import cotisations.models
|
||||||
|
|
||||||
|
from .aes_field import AESEncryptedField
|
||||||
|
|
||||||
|
|
||||||
class OptionalUser(models.Model):
|
class OptionalUser(models.Model):
|
||||||
"""Options pour l'user : obligation ou nom du telephone,
|
"""Options pour l'user : obligation ou nom du telephone,
|
||||||
|
@ -471,6 +473,16 @@ class AssoOption(models.Model):
|
||||||
choices=PAYMENT,
|
choices=PAYMENT,
|
||||||
default='NONE',
|
default='NONE',
|
||||||
)
|
)
|
||||||
|
payment_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
default='',
|
||||||
|
)
|
||||||
|
payment_pass = AESEncryptedField(
|
||||||
|
max_length=255,
|
||||||
|
default='',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
permissions = (
|
permissions = (
|
||||||
("view_assooption", "Peut voir les options de l'asso"),
|
("view_assooption", "Peut voir les options de l'asso"),
|
||||||
|
|
|
@ -26,6 +26,10 @@ SECRET_KEY = 'SUPER_SECRET_KEY'
|
||||||
|
|
||||||
DB_PASSWORD = 'SUPER_SECRET_DB'
|
DB_PASSWORD = 'SUPER_SECRET_DB'
|
||||||
|
|
||||||
|
# AES key for secret key encryption
|
||||||
|
AES_KEY = 'WHAT_A_WONDERFULL_KEY'
|
||||||
|
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue