strangerstudios / paid-memberships-pro

WordPress membership plugin to restrict access to content and charge recurring subscriptions using Stripe, PayPal, and more. Fully open source. 100% GPL.
https://www.paidmembershipspro.com
Other
462 stars 357 forks source link

Required fields not validated before checking out #1806

Open sc0ttkclark opened 2 years ago

sc0ttkclark commented 2 years ago

To Reproduce Steps to reproduce the behavior:

  1. Ensure you have Apple Pay / Stripe set up
  2. Go to checkout page for any membership level $1+
  3. Don't fill out any required information, including any required RH fields
  4. Click Apple Pay or Google Pay etc
  5. Notice that the required fields are not checked and the checkout process continues regardless

Expected behavior If a field is empty and required, it should at minimal throw a notice or an alert on the screen and prevent continuing the checkout process.

Isolating the problem (mark completed items with an [x]):

Other Notes This appears to be pretty tricky to workaround since our checkout pages are one-page checkouts. That means that for solutions like Apple Pay and Google Pay which are embedded by Stripe, may be a little more tricky to interject before it starts the payment process if required fields are empty.

Reported here: https://wordpress.org/support/topic/apple-pay-google-pay-etc-checkout-issue/

mircobabini commented 2 years ago

As far as I know this happens for standard Stripe Credit Card default integration as well, not necessary on Google Pay / Apple Pay. When hitting the "Proceed" button the Stripe's JS SDK is sending the fields to Stripe and just after the credit card details are validated, it checks the mandatory billing fields.

But they only checks the fields which are mandatory for them, not for us. It's totally ignoring Register Helper mandatory additional fields (ex. vat number, company name and any other). I've faced the same issue when I was working on PayPal Checkout implementation which is working the same way (Javascript SDK).

I was working on that this way:

  1. javascript hook just before the request is sent to the gateway
  2. send an ajax to our backend to simulate the checkout page submission
  3. check if any error was generated and reply back with a simple json { success: bool, error_msg: string }
  4. manage the situation accordingly

I think this would work for any Javascript SDK then.

Bullet n. 2 is the tricky one.

Javascript for PayPal Checkout Buttons:

paypal.Buttons({
    env: 'live' === pmproPayPalCheckout.environment ? 'production' : 'sandbox',

    // validation
    // https://developer.paypal.com/docs/checkout/integration-features/validation/
    onClick: function (data, actions) {
        let form_data = new FormData(document.getElementById('pmpro_form'));

        // go for server-side validation using wp ajax
        form_data.append('action', 'pmpro_checkout_validation');
        // additions to process the request by pmpro/preheaders/checkout
        form_data.append('javascriptok', '1');
        form_data.append('submit-checkout', '1');
        // todo should we use a nonce here?
        // data.append( 'nonce', pmproPayPalCheckout.nonce );

        return fetch(pmpro.ajaxurl, {
            method: 'POST',
            credentials: 'same-origin',
            body: form_data
        })
            .then((response) => response.json())
            .then((data) => {
                if (data.success) {
                    return actions.resolve();
                } else {
                    // todo should use data.error or data.pmpro_msg...
                    return actions.reject();
                }
            })
            .catch((error) => {
                // todo should handle ajax errors
                console.log('[PMPro PayPal Checkout]');
                console.error(error);
            });
    },

In Gateway's class init() method:

// server side validation
add_action( 'wp_ajax_pmpro_checkout_validation', array(
    'PMProGateway_paypalcheckout',
    'pmpro_checkout_validation'
) );
add_action( 'wp_ajax_nopriv_pmpro_checkout_validation', array(
    'PMProGateway_paypalcheckout',
    'pmpro_checkout_validation'
) );

Then:

/**
 * Ajax request for checkout form validation
 */
public static function pmpro_checkout_validation() {
    global $pmpro_msg, $pmpro_msgt;

    require_once( PMPRO_DIR . "/preheaders/checkout.php" );

    // simulate something went wrong
    $something_went_wrong = ! empty( $pmpro_msg );

    // ajax json reply
    if ( $something_went_wrong ) {
        wp_send_json_error( array(
            'pmpro_msg' => 'Eeeeeerror.'
        ) );
    } else {
        wp_send_json_success();
    }
}

As you can see it simulates the POST request 100%. Hope this can be helpful somehow.

mircobabini commented 2 years ago

This is causing issues with Vat Tax Add On as well. The vat number is not VIES-validated if not provided.

Then, taxes may not be applied even if the vat number is just a random number.