Files
odoo_source/addons/payment_sips/controllers/main.py
T
Adrien Widart 0a87cd21fd [FIX] payment_sips: prevent clearing the session cookie
When buying a product on website shop, after the payment with SIPS, the
page is redirected to an Error message: "We are not able to find your
payment, but don't worry. You should receive an email confirming your
payment in a few minutes. If the payment hasn't been confirmed you can
contact us."

To reproduce the error:
1. In Payment Acquirers, enable Sips
2. Go on website shop
3. Add a product to the cart, Checkout
4. Pay with Sips
    - Visa card number: 4100000000000000
5. Back to Web-shop, if the payment has been successfully processed,
repeat steps 2 -> 4

Error: The message "Your payment has been successfully processed. Thank
you!" is not displayed. Instead, the message "We are not able [...] you
can contact us." is displayed.

This message is displayed when:
https://github.com/odoo/odoo/blob/5945806c151b13d9d4cc13aa0a6c96a6b1bbad5f/addons/payment/controllers/portal.py#L65-L69
i.e., when the transactions list is empty. Here is how to get the list:
https://github.com/odoo/odoo/blob/5945806c151b13d9d4cc13aa0a6c96a6b1bbad5f/addons/payment/controllers/portal.py#L38-L42
It uses the session of the request. The cookie `session_id` is used to
identify the current session. However, after the payment on SIPS, the
page is redirected to `/payment/sips/dpn` with a POST request. Since the
session cookie has the attribute `SameSite=Lax` and the HTTP request is
a POST, the cookie will be filtered out:
https://drive.google.com/file/d/1xfx3YWkfonO3nK-8Rew45uSoR4lkpjpY/view?usp=sharing
(Browser information: This cookie didn't specify a "SameSite" attribute
when it was stored and was defaulted to "SameSite=Lax," and was blocked
because the request was made from a different site and was not initiated
by a top-level navigation. The cookie had to have been set with
"SameSite=None" to enable cross-site usage)
As a result, the server creates a new one. This is the reason why the
transactions list is empty: the list is based on a new session.

Adding the attribute `save_session = False` to the route will prevent
the server from creating a new session cookie and add it in the POST
response.

OPW-2518377

closes odoo/odoo#72611

X-original-commit: 9637a287923c6b82acfd487ed32d6bbc1fdf74b6
Signed-off-by: Antoine Vandevenne (anv) <AntoineVDV@users.noreply.github.com>
Signed-off-by: Adrien Widart <adwid@users.noreply.github.com>
2021-06-23 10:21:04 +00:00

64 lines
2.8 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
# Original Copyright 2015 Eezee-It, modified and maintained by Odoo.
import logging
import pprint
import werkzeug
from odoo import http
from odoo.exceptions import ValidationError
from odoo.http import request
_logger = logging.getLogger(__name__)
class SipsController(http.Controller):
_return_url = '/payment/sips/dpn/'
_notify_url = '/payment/sips/ipn/'
@http.route(_return_url, type='http', auth='public', methods=['POST'], csrf=False, save_session=False)
def sips_dpn(self, **post):
""" Sips DPN
The session cookie created by Odoo has not the attribute SameSite. Most of browsers will force this attribute
with the value 'Lax'. After the payment, Sips will perform a POST request on this route. For all these reasons,
the cookie won't be added to the request. As a result, if we want to save the session, the server will create
a new session cookie. Therefore, the previous session and all related information will be lost, so it will lead
to undesirable behaviors. This is the reason why `save_session=False` is needed.
"""
_logger.info("beginning Sips DPN _handle_feedback_data with data %s", pprint.pformat(post))
try:
if self._sips_validate_data(post):
request.env['payment.transaction'].sudo()._handle_feedback_data('sips', post)
except ValidationError:
pass
return werkzeug.utils.redirect('/payment/status')
@http.route(_notify_url, type='http', auth='public', methods=['POST'], csrf=False)
def sips_ipn(self, **post):
""" Sips IPN. """
_logger.info("beginning Sips IPN _handle_feedback_data with data %s", pprint.pformat(post))
if not post:
# SIPS sometimes sends empty notifications, the reason why is unclear but they tend to
# pollute logs and do not provide any meaningful information; log as a warning instead
# of a traceback.
_logger.warning("received empty notification; skip.")
else:
try:
if self._sips_validate_data(post):
request.env['payment.transaction'].sudo()._handle_feedback_data('sips', post)
except ValidationError:
pass # Acknowledge the notification to avoid getting spammed
return ''
def _sips_validate_data(self, post):
tx_sudo = request.env['payment.transaction'].sudo()._get_tx_from_feedback_data('sips', post)
acquirer_sudo = tx_sudo.acquirer_id
security = acquirer_sudo._sips_generate_shasign(post['Data'])
if security == post['Seal']:
_logger.debug('validated data')
return True
else:
_logger.warning('data are tampered')
return False