<commit_before><?php
namespace Payum\Braintree\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Request\Authorize;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Braintree\Request\ObtainPaymentMethodNonce;
use Payum\Braintree\Request\ObtainCardholderAuthentication;
use Payum\Braintree\Request\Api\FindPaymentMethodNonce;
use Payum\Braintree\Request\Api\DoSale;
use Payum\Braintree\Reply\Api\PaymentMethodNonceArray;
use Payum\Braintree\Reply\Api\TransactionResultArray;
use Braintree\Transaction;

class AuthorizeAction implements ActionInterface, GatewayAwareInterface
{
    use GatewayAwareTrait;

    protected $cardholderAuthenticationEnabled;

    public function __construct($cardholderAuthenticationEnabled = true)
    {
        $this->cardholderAuthenticationEnabled = $cardholderAuthenticationEnabled;
    }

    public function setCardholderAuthenticationEnabled($value)
    {
        $this->cardholderAuthenticationEnabled = $value;
    }

    /**
     * {@inheritDoc}
     *
     * @param Authorize $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());

        if (true == $details->offsetExists('status')) {
            return;
        }

        if (false == $details->offsetExists('paymentMethodNonce')) {
            $this->obtainPaymentMethodNonce($details);
        }

        $details->validateNotEmpty(['paymentMethodNonceInfo']);

        $paymentMethodNonceInfo = $details['paymentMethodNonceInfo'];

        if ($paymentMethodNonceInfo['type'] === 'CreditCard') {

            if (false == array_key_exists('threeDSecureInfo', $paymentMethodNonceInfo) && true == $this->cardholderAuthenticationEnabled) {
                
                if (true == $paymentMethodNonceInfo['consumed']) {

                    $details['status'] = 'failed';
                    $details['status_reason'] = 'attempted 3dsecure challenge on consumed payment method nonce';

                    return;
                }

                $this->obtainCardholderAuthentication($details);
            }

            if (false == $this->hasLiabilityShifted($details)) {

                $details['status'] = 'failed';
                $details['status_reason'] = 'failed to obtain cardholder authentication';

                return;
            }
        }

        if (false == $details->offsetExists('sale')) {

            $this->doSaleTransaction($details);
        }
<commit_msg>Check 3D secure liability shift if cardholder authentication is enabled<commit_after><?php
namespace Payum\Braintree\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Request\Authorize;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Braintree\Request\ObtainPaymentMethodNonce;
use Payum\Braintree\Request\ObtainCardholderAuthentication;
use Payum\Braintree\Request\Api\FindPaymentMethodNonce;
use Payum\Braintree\Request\Api\DoSale;
use Payum\Braintree\Reply\Api\PaymentMethodNonceArray;
use Payum\Braintree\Reply\Api\TransactionResultArray;
use Braintree\Transaction;

class AuthorizeAction implements ActionInterface, GatewayAwareInterface
{
    use GatewayAwareTrait;

    protected $cardholderAuthenticationEnabled;

    public function __construct($cardholderAuthenticationEnabled = true)
    {
        $this->cardholderAuthenticationEnabled = $cardholderAuthenticationEnabled;
    }

    public function setCardholderAuthenticationEnabled($value)
    {
        $this->cardholderAuthenticationEnabled = $value;
    }

    /**
     * {@inheritDoc}
     *
     * @param Authorize $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());

        if (true == $details->offsetExists('status')) {
            return;
        }

        if (false == $details->offsetExists('paymentMethodNonce')) {
            $this->obtainPaymentMethodNonce($details);
        }

        $details->validateNotEmpty(['paymentMethodNonceInfo']);

        $paymentMethodNonceInfo = $details['paymentMethodNonceInfo'];

        if ($paymentMethodNonceInfo['type'] === 'CreditCard') {

            if (true == $this->cardholderAuthenticationEnabled) {

                if ((false == array_key_exists('threeDSecureInfo', $paymentMethodNonceInfo) || empty($paymentMethodNonceInfo['threeDSecureInfo']))) {
                    
                    if (true == $paymentMethodNonceInfo['consumed']) {

                        $details['status'] = 'failed';
                        $details['status_reason'] = 'attempted 3dsecure challenge on consumed payment method nonce';

                        return;
                    }

                    $this->obtainCardholderAuthentication($details);
                }

                if (false == $this->hasLiabilityShifted($details)) {

                    $details['status'] = 'failed';
                    $details['status_reason'] = 'failed to obtain cardholder authentication';

                    return;
                }
            }
        }

        if (false == $details->offsetExists('sale')) {

            $this->doSaleTransaction($details);
        }

{'fraction_non_alphanumeric': 0.1098328240158188, 'fraction_numerical': 0.0005392773683264426, 'mean_word_length': 2.904561403508772, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1857640', 'n_tokens_mistral': 1500, 'n_tokens_neox': 1430, 'n_words': 235}