Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Payment session validation #497

Merged
merged 2 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions mooringlicensing/components/payments_ml/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ def post(self, request, *args, **kwargs):
booking_reference=str(dcv_admission_fee.uuid),
invoice_text='DCV Admission Fee',
)

request.session["payment_pk"] = dcv_admission.pk
request.session["payment_model"] = "dcv_admission"

logger.info('{} built payment line item {} for DcvAdmission Fee and handing over to payment gateway'.format(dcv_admission.applicant, dcv_admission.id))
return checkout_response

Expand Down Expand Up @@ -127,6 +131,9 @@ def post(self, request, *args, **kwargs):
invoice_text='DCV Permit Fee',
)

request.session["payment_pk"] = dcv_permit.pk
request.session["payment_model"] = "dcv_permit"

logger.info('{} built payment line item {} for DcvPermit Fee and handing over to payment gateway'.format(request.user, dcv_permit.id))
return checkout_response

Expand Down Expand Up @@ -202,6 +209,7 @@ def get(self, request, *args, **kwargs):
payment_session = ledger_api_client.utils.generate_payment_session(request, invoice.reference, return_url, fallback_url)
return HttpResponseRedirect(payment_session['payment_url'])


except Exception as e:
logger.error('Error Creating Application Fee: {}'.format(e))
raise
Expand Down Expand Up @@ -263,6 +271,9 @@ def post(self, request, *args, **kwargs):
invoice_text='{}'.format(application_type.description),
)

request.session["payment_pk"] = sticker_action_detail.pk
request.session["payment_model"] = "sticker"

logger.info('{} built payment line item(s) {} for Sticker Replacement Fee and handing over to payment gateway'.format('User {} with id {}'.format(request.user.get_full_name(), request.user.id), sticker_action_fee))
return checkout_response
else:
Expand Down Expand Up @@ -424,6 +435,8 @@ def post(self, request, *args, **kwargs):
)

user = proposal.applicant_obj
request.session["payment_pk"] = proposal.pk
request.session["payment_model"] = "proposal"

logger.info('{} built payment line item {} for Application Fee and handing over to payment gateway'.format('User {} with id {}'.format(user.get_full_name(), user.id), proposal.id))
return checkout_response
Expand Down
1 change: 1 addition & 0 deletions mooringlicensing/components/proposals/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1749,6 +1749,7 @@ def final_approval_for_AUA_MLA(self, request=None):
'system': settings.PAYMENT_SYSTEM_ID,
'custom_basket': True,
'booking_reference': reference,
'no_payment': False,
'tax_override': True,
}
logger.info(f'basket_params: {basket_params}')
Expand Down
8 changes: 8 additions & 0 deletions mooringlicensing/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
from mooringlicensing import settings
from ledger_api_client import utils as ledger_api_utils
import hashlib
import uuid

def mooringlicensing_processor(request):

web_url = request.META.get('HTTP_HOST', None)
lt = ledger_api_utils.get_ledger_totals()

checkouthash = None #hashlib.sha256(str(uuid.uuid4()).encode('utf-8')).hexdigest()
sessionVal = None
if 'payment_model' in request.session and 'payment_pk' in request.session:
checkouthash = hashlib.sha256(str(str(request.session["payment_model"])+str(request.session["payment_pk"])).encode('utf-8')).hexdigest()

return {
'public_url': web_url,
'template_group': 'ria',
'LEDGER_UI_URL': f'{settings.LEDGER_UI_URL}',
'LEDGER_SYSTEM_ID': f'{settings.LEDGER_SYSTEM_ID}',
'ledger_totals': lt,
'checkouthash' : checkouthash,
}
117 changes: 116 additions & 1 deletion mooringlicensing/middleware.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
from django.urls import reverse
from django.shortcuts import redirect
from urllib.parse import quote_plus

from django.http import HttpResponse
import hashlib
import re
from reversion.middleware import RevisionMiddleware
from reversion.views import _request_creates_revision
from ledger_api_client.managed_models import SystemUser, SystemUserAddress
from django.core.exceptions import ObjectDoesNotExist
from mooringlicensing.helpers import is_internal
from mooringlicensing.components.proposals.models import Proposal
from mooringlicensing.components.approvals.models import DcvAdmission, DcvPermit, StickerActionDetail

import logging

Expand Down Expand Up @@ -79,3 +83,114 @@ class RevisionOverrideMiddleware(RevisionMiddleware):
# exclude ledger payments/checkout from revision - hack to overcome basket (lagging status) issue/conflict with reversion
def request_creates_revision(self, request):
return _request_creates_revision(request) and 'checkout' not in request.get_full_path()

class PaymentSessionMiddleware(object):

def __init__(self, get_response):
self.get_response = get_response

def process_view(self, request, view_func, view_args, view_kwargs):

redirect_path = 'internal' if is_internal(request) else 'external'

if (request.user.is_authenticated
and (CHECKOUT_PATH.match(request.path)
or request.path.startswith("/ledger-api/process-payment")
or request.path.startswith('/ledger-api/payment-details'))):
if 'payment_model' in request.session and 'payment_pk' in request.session:
if request.path.startswith("/ledger-api/process-payment"):

checkouthash = hashlib.sha256(str(str(request.session["payment_model"])+str(request.session["payment_pk"])).encode('utf-8')).hexdigest()
checkouthash_cookie = request.COOKIES.get('checkouthash')
validation_cookie = request.COOKIES.get(request.POST['payment-csrfmiddlewaretoken'])

if request.session['payment_model'] == "proposal":
proposal_count = Proposal.objects.filter(pk=request.session['payment_pk']).count()
elif request.session['payment_model'] == "dcv_permit":
proposal_count = DcvPermit.objects.filter(pk=request.session['payment_pk']).count()
elif request.session['payment_model'] == "dcv_admission":
proposal_count = DcvAdmission.objects.filter(pk=request.session['payment_pk']).count()
elif request.session['payment_model'] == "sticker":
proposal_count = StickerActionDetail.objects.filter(pk=request.session['payment_pk']).count()
else:
proposal_count = 0

if checkouthash_cookie != checkouthash or checkouthash_cookie != validation_cookie or proposal_count == 0:
url_redirect = reverse(redirect_path)
response = HttpResponse("<script> window.location='"+url_redirect+"';</script> <center><div class='container'><div class='alert alert-primary' role='alert'><a href='"+url_redirect+"'> Redirecting please wait: "+url_redirect+"</a><div></div></center>")
return response
else:
if request.path.startswith("/ledger-api/process-payment"):
url_redirect = reverse(redirect_path)
response = HttpResponse("<script> window.location='"+url_redirect+"';</script> <center><div class='container'><div class='alert alert-primary' role='alert'><a href='"+url_redirect+"'> Redirecting please wait: "+url_redirect+"</a><div></div></center>")
return response

return None


def __call__(self, request):

response= self.get_response(request)
redirect_path = 'internal' if is_internal(request) else 'external'

if (request.user.is_authenticated
and (CHECKOUT_PATH.match(request.path)
or request.path.startswith("/ledger-api/process-payment")
or request.path.startswith('/ledger-api/payment-details'))):
if 'payment_model' in request.session and 'payment_pk' in request.session:
try:
if request.session['payment_model'] == "proposal":
proposal_count = Proposal.objects.get(pk=request.session['payment_pk'])
elif request.session['payment_model'] == "dcv_permit":
proposal_count = DcvPermit.objects.get(pk=request.session['payment_pk'])
elif request.session['payment_model'] == "dcv_admission":
proposal_count = DcvAdmission.objects.get(pk=request.session['payment_pk'])
elif request.session['payment_model'] == "sticker":
proposal_count = StickerActionDetail.objects.get(pk=request.session['payment_pk'])
else:
proposal_count = 0

except Exception as e:
del request.session['payment_model']
del request.session['payment_pk']
return response

if request.path.startswith("/ledger-api/process-payment"):

if "payment_pk" not in request.session:
url_redirect = reverse(redirect_path)
response = HttpResponse("<script> window.location='"+url_redirect+"';</script> <center><div class='container'><div class='alert alert-primary' role='alert'><a href='"+url_redirect+"'> Redirecting please wait: "+url_redirect+"</a><div></div></center>")
return response

checkouthash = hashlib.sha256(str(str(request.session["payment_model"])+str(request.session["payment_pk"])).encode('utf-8')).hexdigest()
checkouthash_cookie = request.COOKIES.get('checkouthash')
validation_cookie = request.COOKIES.get(request.POST['payment-csrfmiddlewaretoken'])

if request.session['payment_model'] == "proposal":
proposal_count = Proposal.objects.filter(pk=request.session['payment_pk']).count()
elif request.session['payment_model'] == "dcv_permit":
proposal_count = DcvPermit.objects.filter(pk=request.session['payment_pk']).count()
elif request.session['payment_model'] == "dcv_admission":
proposal_count = DcvAdmission.objects.filter(pk=request.session['payment_pk']).count()
elif request.session['payment_model'] == "sticker":
proposal_count = StickerActionDetail.objects.filter(pk=request.session['payment_pk']).count()
else:
proposal_count = 0

if checkouthash_cookie != checkouthash or checkouthash_cookie != validation_cookie or proposal_count == 0:
url_redirect = reverse(redirect_path)
response = HttpResponse("<script> window.location='"+url_redirect+"';</script> <center><div class='container'><div class='alert alert-primary' role='alert'><a href='"+url_redirect+"'> Redirecting please wait: "+url_redirect+"</a><div></div></center>")
return response
else:
if request.path.startswith("/ledger-api/process-payment"):
url_redirect = reverse(redirect_path)
response = HttpResponse("<script> window.location='"+url_redirect+"';</script> <center><div class='container'><div class='alert alert-primary' role='alert'><a href='"+url_redirect+"'> Redirecting please wait: "+url_redirect+"</a><div></div></center>")
return response

# force a redirect if in the checkout
if ('payment_pk' not in request.session or 'payment_model' not in request.session) and CHECKOUT_PATH.match(request.path):
url_redirect = reverse(redirect_path)
response = HttpResponse("<script> window.location='"+url_redirect+"';</script> <center><div class='container'><div class='alert alert-primary' role='alert'><a href='"+url_redirect+"'> Redirecting please wait: "+url_redirect+"</a><div></div></center>")
return response

return response
1 change: 1 addition & 0 deletions mooringlicensing/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def show_toolbar(request):

MIDDLEWARE_CLASSES += [
'mooringlicensing.middleware.FirstTimeNagScreenMiddleware',
'mooringlicensing.middleware.PaymentSessionMiddleware',
'mooringlicensing.middleware.RevisionOverrideMiddleware',
'mooringlicensing.middleware.CacheControlMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,50 @@
<li><a class="dropdown-item" href="/external/dcv_admission">DCV Admission</a></li>
</ul>
</li>

<script>
var payment_processing =
{
var: { checkouthash: "{{ checkouthash }}"}
}

function createCookie(name, value, days) {
var expires;

if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toGMTString();
} else {
expires = "";
}
document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/";
}

function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}

createCookie('checkouthash', "{{ checkouthash }}");

if (window.location.href.indexOf("payment-details") != -1) {
setInterval(function() {
createCookie(document.getElementById('payment-csrfmiddlewaretoken').value, "{{ checkouthash }}");
var checkouthash_cookie = readCookie("checkouthash");
if (payment_processing.var.checkouthash != checkouthash_cookie) {
if ("{{is_internal_login}}" == "True") {
window.location = "/internal"
} else {
window.location = "/external"
}
}
},"500");
}
</script>
Loading