Plugin Directory

Changeset 3449399


Ignore:
Timestamp:
01/29/2026 09:32:33 AM (2 months ago)
Author:
ecommpay
Message:

new version 4.2.2

Location:
ecommpay-payments/trunk
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • ecommpay-payments/trunk/assets/js/backend.js

    r3218798 r3449399  
    4242          action: 'ecommpay_manual_transaction_actions',
    4343          post: this.postID.val(),
     44          nonce: ajax_object.nonce,
    4445        },
    4546        dataObject
  • ecommpay-payments/trunk/common/EcpCore.php

    r3440800 r3449399  
    6161     * @since 2.0.0
    6262     */
    63     public const WC_ECP_VERSION = '4.2.1';
     63    public const WC_ECP_VERSION = '4.2.2';
    6464
    6565    public const ECOMMPAY_PAYMENT_METHOD = 'ecommpay';
  • ecommpay-payments/trunk/common/includes/EcpCallbacksHandler.php

    r3336019 r3449399  
    130130     */
    131131    private function get_order( EcpGatewayInfoCallback $info ): EcpGatewayOrder {
    132         $payment_id = $info->get_payment()->get_id() ?? $_GET['payment_id'];
     132        $payment_id = $info->get_payment()->get_id();
     133
     134        if ( ! $payment_id && isset( $_GET['payment_id'] ) ) {
     135            $payment_id = sanitize_text_field( wp_unslash( $_GET['payment_id'] ) );
     136        }
    133137
    134138        $order_number = EcpGatewayOrder::get_order_id_from_callback( $info );
  • ecommpay-payments/trunk/common/includes/EcpGatewayOrder.php

    r3440800 r3449399  
    6363    public static function get_order_id_from_callback( EcpGatewayInfoCallback $info ) {
    6464        global $wpdb;
    65         $payment_id = $info->get_payment()->get_id() ?? $_GET['payment_id'];
     65
     66        $payment_id = $info->get_payment()->get_id();
     67
     68        if ( ! $payment_id && isset( $_GET['payment_id'] ) ) {
     69            $payment_id = sanitize_text_field( wp_unslash( $_GET['payment_id'] ) );
     70        }
    6671
    6772        if ( ecp_HPOS_enabled() ) {
  • ecommpay-payments/trunk/common/includes/EcpGatewayPayment.php

    r3336019 r3449399  
    1515use DateTimeInterface;
    1616use Exception;
     17use JsonSerializable;
    1718
    1819defined( 'ABSPATH' ) || exit;
     
    2829 * @category Class
    2930 */
    30 class EcpGatewayPayment {
     31class EcpGatewayPayment implements JsonSerializable {
    3132
    3233
     
    5758     * @var ?EcpGatewayInfoCustomer
    5859     */
    59     private ?EcpGatewayInfoCustomer $customer;
     60    private ?EcpGatewayInfoCustomer $customer = null;
    6061
    6162    /**
     
    6465     * @var ?EcpGatewayInfoAccount
    6566     */
    66     private ?EcpGatewayInfoAccount $account;
     67    private ?EcpGatewayInfoAccount $account = null;
    6768
    6869    /**
     
    7172     * @var ?EcpGatewayInfoACS
    7273     */
    73     private ?EcpGatewayInfoACS $acs;
     74    private ?EcpGatewayInfoACS $acs = null;
    7475
    7576    /**
     
    155156        $this->status_transition = new EcpGatewayPaymentStatusTransition(
    156157            [
    157                 'old'  => $old_status,
    158                 'new'  => $new_status,
     158                'old' => $old_status,
     159                'new' => $new_status,
    159160                'note' => $note
    160161            ]
     
    196197
    197198            switch ( true ) {
    198                 case ! empty ( $transition->get_old() ):
     199                case ! empty( $transition->get_old() ):
    199200                    if ( ! $transition->is_changed() ) {
    200201                        return;
     
    487488        } );
    488489
    489         if ( empty ( $authorized_operations ) ) {
     490        if ( empty( $authorized_operations ) ) {
    490491            return null;
    491492        }
     
    513514        }
    514515
    515         return ! empty ( $this->info->get_sum() ) ? $this->info->get_sum()->get_amount() : null;
     516        return ! empty( $this->info->get_sum() ) ? $this->info->get_sum()->get_amount() : null;
    516517    }
    517518
     
    664665        return null;
    665666    }
     667
     668    /**
     669     * <h2>Converts payment data to array for caching.</h2>
     670     * <p>Serializes only the API data, excluding the WooCommerce order object.</p>
     671     * <p>Implements JsonSerializable interface.</p>
     672     *
     673     * @return array Payment data as associative array
     674     * @since 3.3.2
     675     */
     676    public function jsonSerialize(): array {
     677        return [
     678            'payment_id' => $this->get_id(),
     679            'info'       => $this->info ? $this->info->to_array() : null,
     680            'customer'   => $this->customer ? $this->customer->to_array() : null,
     681            'account'    => $this->account ? $this->account->to_array() : null,
     682            'acs'        => $this->acs ? $this->acs->to_array() : null,
     683            'operations' => array_map(static function (EcpGatewayInfoOperation $operation): array {
     684                return $operation->to_array();
     685            }, $this->operations ),
     686            'errors'     => array_map( static function ( EcpGatewayInfoError $error ): array {
     687                return $error->to_array();
     688            }, $this->errors ),
     689        ];
     690    }
     691
     692    /**
     693     * <h2>Restores payment data from cached array.</h2>
     694     *
     695     * @param EcpGatewayOrder $order Parent order
     696     * @param array $data Cached payment data
     697     *
     698     * @return static Restored payment object
     699     * @since 3.3.2
     700     */
     701    public static function fromCache( EcpGatewayOrder $order, array $data ): EcpGatewayPayment {
     702        $payment = new static( $order );
     703
     704        if ( ! empty( $data['info'] ) && is_array( $data['info'] ) ) {
     705            $payment->set_info( new EcpGatewayInfoPayment( $data['info'] ) );
     706        }
     707
     708        if ( ! empty( $data['customer'] ) && is_array( $data['customer'] ) ) {
     709            $payment->set_customer( new EcpGatewayInfoCustomer( $data['customer'] ) );
     710        }
     711
     712        if ( ! empty( $data['account'] ) && is_array( $data['account'] ) ) {
     713            $payment->set_account( new EcpGatewayInfoAccount( $data['account'] ) );
     714        }
     715
     716        if ( ! empty( $data['acs'] ) && is_array( $data['acs'] ) ) {
     717            $payment->set_acs( new EcpGatewayInfoACS( $data['acs'] ) );
     718        }
     719
     720        if ( ! empty( $data['operations'] ) && is_array( $data['operations'] ) ) {
     721            foreach ( $data['operations'] as $op_data ) {
     722                if ( is_array( $op_data ) ) {
     723                    $payment->add_operation( new EcpGatewayInfoOperation( $op_data ) );
     724                }
     725            }
     726        }
     727
     728        if ( ! empty( $data['errors'] ) && is_array( $data['errors'] ) ) {
     729            foreach ( $data['errors'] as $err_data ) {
     730                if ( is_array( $err_data ) ) {
     731                    $payment->errors[] = new EcpGatewayInfoError( $err_data );
     732                }
     733            }
     734        }
     735
     736        return $payment;
     737    }
    666738}
  • ecommpay-payments/trunk/common/includes/EcpGatewayPaymentProvider.php

    r3218798 r3449399  
    2828        ecp_get_log()->debug( __( 'Reload?', 'woo-ecommpay' ), $reload ? __( 'Yes', 'woo-ecommpay' ) : __( 'No', 'woo-ecommpay' ) );
    2929
    30         if ( ! $reload && $this->is_transaction_caching_enabled() ) {
    31             ecp_get_log()->info( __( 'Try loading payment data from cache...', 'woo-ecommpay' ) );
    32             $transient = get_transient( $this->get_transient_id( $order->get_payment_id() ) );
    33 
    34             if ( $transient ) {
    35                 // new EcpGatewayInfoStatus(json_decode($transient, true))
    36                 $payment = @unserialize( $transient );
    37 
    38                 if ( $payment instanceof EcpGatewayPayment ) {
    39                     ecp_get_log()->info( __( 'Payment loaded from cache. Cache data exists.', 'woo-ecommpay' ) );
    40 
    41                     return $payment;
    42                 }
    43 
    44                 ecp_get_log()->warning( __( 'Cache data corrupted:', 'woo-ecommpay' ), $transient );
    45             } else {
    46                 ecp_get_log()->info( __( 'Invalid cache data.', 'woo-ecommpay' ) );
     30        if ( ! $reload ) {
     31            $cached_payment = $this->tryLoadFromCache( $order );
     32            if ( $cached_payment ) {
     33                return $cached_payment;
    4734            }
    4835        }
     
    6350
    6451        return $payment;
     52    }
     53
     54    /**
     55     * Tries to load payment from cache.
     56     *
     57     * @param EcpGatewayOrder $order
     58     *
     59     * @return EcpGatewayPayment|null Returns payment if found in cache, null otherwise
     60     */
     61    private function tryLoadFromCache( EcpGatewayOrder $order ): ?EcpGatewayPayment {
     62        if ( ! $this->is_transaction_caching_enabled() ) {
     63            return null;
     64        }
     65
     66        ecp_get_log()->info( __( 'Try loading payment data from cache...', 'woo-ecommpay' ) );
     67
     68        $transient = get_transient( $this->get_transient_id( $order->get_payment_id() ) );
     69
     70        if ( ! $transient ) {
     71            ecp_get_log()->info( __( 'Invalid cache data.', 'woo-ecommpay' ) );
     72
     73            return null;
     74        }
     75
     76        $cached_data = json_decode( $transient, true );
     77
     78        if ( ! is_array( $cached_data ) || empty( $cached_data['payment_id'] ) ) {
     79            ecp_get_log()->warning( __( 'Cache data corrupted or invalid format', 'woo-ecommpay' ) );
     80
     81            return null;
     82        }
     83
     84        try {
     85            $payment = EcpGatewayPayment::fromCache( $order, $cached_data );
     86            ecp_get_log()->info( __( 'Payment loaded from cache. Cache data exists.', 'woo-ecommpay' ) );
     87
     88            return $payment;
     89        } catch ( Exception $e ) {
     90            ecp_get_log()->warning(
     91                __( 'Failed to restore payment from cache:', 'woo-ecommpay' ),
     92                $e->getMessage()
     93            );
     94
     95            return null;
     96        }
    6597    }
    6698
     
    90122
    91123        if ( count( $status->get_errors() ) > 0 ) {
     124            $info = null;
    92125            if ( $status->try_get_payment( $info ) ) {
    93126                $payment->set_info( $info );
     
    130163            $expiration = apply_filters( 'woocommerce_ecommpay_transaction_cache_expiration', $expiration );
    131164
     165
    132166            ecp_get_log()->debug( __( 'Expiration length:.', 'woo-ecommpay' ), $expiration );
     167
     168            $json_data = json_encode( $payment, JSON_THROW_ON_ERROR );
     169
    133170            set_transient(
    134171                $this->get_transient_id( $payment->get_id() ),
    135                 serialize( $payment ),
     172                $json_data,
    136173                $expiration
    137174            );
  • ecommpay-payments/trunk/common/models/EcpGatewayInfoOperation.php

    r3218798 r3449399  
    243243    }
    244244
     245    protected function packRules(): array {
     246        return [
     247            self::FIELD_DATE => function ( $value ) {
     248                return $value->format( DateTimeInterface::RFC3339 );
     249            },
     250            self::FIELD_CREATED_DATE => function ( $value ) {
     251                return $value->format( DateTimeInterface::RFC3339 );
     252            },
     253        ];
     254    }
     255
    245256    protected function unpackRules(): array {
    246257        return [
  • ecommpay-payments/trunk/common/models/EcpGatewayInfoProvider.php

    r3218798 r3449399  
    113113    }
    114114
     115    protected function packRules(): array {
     116        return [
     117            self::FIELD_DATE => function ( $value ) {
     118                return $value->format( DateTimeInterface::RFC3339 );
     119            },
     120        ];
     121    }
    115122
    116123    /**
  • ecommpay-payments/trunk/common/modules/EcpModuleAdminUI.php

    r3336019 r3449399  
    2828    public const ACTION_BUTTON_CLASS = 'ecp-action-button';
    2929    public const WP_REFUND_BUTTON_SELECTOR = '.button.refund-items';
     30
     31    public const ACTION_REFRESH = 'refresh';
     32    public const ACTION_CAPTURE = 'capture';
     33    public const ACTION_CANCEL = 'cancel';
     34    public const ACTION_REFUND = 'refund';
     35
     36    /**
     37     * List of all allowed payment actions for AJAX requests
     38     */
     39    private const ALLOWED_ACTIONS = [
     40        self::ACTION_REFRESH,
     41        self::ACTION_CAPTURE,
     42        self::ACTION_CANCEL,
     43        self::ACTION_REFUND,
     44    ];
     45
     46    /**
     47     * List of allowed payment actions that perform API calls
     48     */
     49    private const ALLOWED_API_ACTIONS = [
     50        self::ACTION_CAPTURE,
     51        self::ACTION_CANCEL,
     52        self::ACTION_REFUND,
     53    ];
    3054
    3155    /**
     
    370394                'ecommpay-backend',
    371395                'ajax_object',
    372                 [ 'ajax_url' => admin_url( 'admin-ajax.php' ) ]
     396                [
     397                    'ajax_url' => admin_url( 'admin-ajax.php' ),
     398                    'nonce'    => wp_create_nonce( 'ecommpay_manual_action' )
     399                ]
    373400            );
    374401        }
     
    415442     */
    416443    public function ajax_manual_request_actions(): void {
     444        // Security: Verify nonce for CSRF protection
     445        check_ajax_referer( 'ecommpay_manual_action', 'nonce' );
     446
    417447        $param_action = wc_get_var( $_REQUEST['ecommpay_action'] );
    418448        $param_post   = wc_get_var( $_REQUEST['post'] );
     
    422452        }
    423453
     454        // Security: Validate action against whitelist to prevent code injection
     455        if ( ! in_array( $param_action, self::ALLOWED_ACTIONS, true ) ) {
     456            wp_die( 'Invalid payment action requested.' );
     457        }
     458
    424459        if ( ! woocommerce_ecommpay_can_user_manage_payments( $param_action ) ) {
    425             printf( 'Your user is not capable of %s payments.', $param_action );
    426             exit;
     460            wp_die( 'Insufficient permissions for payment management.' );
    427461        }
    428462
     
    430464
    431465        switch ( $param_action ) {
    432             case 'refresh':
     466            case self::ACTION_REFRESH:
    433467                $order->get_payment( true, true );
    434468                break;
     
    454488            // Based on the current transaction state, we check if the requested action is allowed
    455489            if ( ! $order->is_action_allowed( $param_action ) ) {
    456                 // The action was not allowed.
     490                // The action was not allowed - don't expose internal details
    457491                throw new EcpGatewayAPIException(
    458492                    sprintf(
    459                         'Action: "%s", is not allowed for order #%d, with type state "%s"',
    460                         $param_action,
    461                         $order->get_id(),
    462                         $transaction_info->get_current_type()
     493                        'Action is not allowed for order #%d with current transaction state',
     494                        $order->get_id()
    463495                    )
    464496                );
    465497            }
    466498
    467             // Check if the action method is available in the payment class
    468             if ( ! method_exists( $api, $param_action ) ) {
    469                 throw new EcpGatewayAPIException(
    470                     sprintf(
    471                         'Unsupported action: "%s".',
    472                         $param_action
    473                     )
    474                 );
     499            // Security: Double-check action is in whitelist before method call
     500            if ( ! in_array( $param_action, self::ALLOWED_API_ACTIONS, true ) ) {
     501                throw new EcpGatewayAPIException( 'Invalid payment action requested.' );
    475502            }
    476503
    477             $payment_amount = wc_get_var( $_REQUEST['$payment_amount'] );
    478 
    479             // Fetch amount if sent.
    480             $amount = $payment_amount !== null
    481                 ? ecp_price_custom_to_multiplied(
    482                     $payment_amount,
    483                     $transaction_info->get_currency()
    484                 )
    485                 : $transaction_info->get_remaining_balance();
    486 
    487             // Call the action method and parse the transaction id and order object
    488             $api->$param_action(
    489                 $transaction_id,
    490                 $order,
    491                 ecp_price_multiplied_to_float( $amount, $transaction_info->get_currency() )
    492             );
     504            // Security: Use explicit method calls instead of variable function call
     505            switch ( $param_action ) {
     506                case self::ACTION_CAPTURE:
     507                    $api->capture( $order );
     508                    break;
     509                case self::ACTION_CANCEL:
     510                    $api->cancel( $order );
     511                    break;
     512                case self::ACTION_REFUND:
     513                    // For refund, find the unprocessed refund created by WooCommerce
     514                    $refund = $order->find_unprocessed_refund();
     515                    $api->refund( $refund, $order );
     516                    break;
     517                default:
     518                    throw new EcpGatewayAPIException( 'Payment action not supported.' );
     519            }
    493520        } catch ( EcpGatewayAPIException $e ) {
    494             echo $e->getMessage();
     521            echo esc_html( $e->getMessage() );
    495522            $e->write_to_logs();
    496523            exit;
  • ecommpay-payments/trunk/composer.json

    r3218798 r3449399  
    66    }
    77  },
    8   "require": {}
     8  "require": {
     9    "ext-json": "*"
     10  }
    911}
  • ecommpay-payments/trunk/gateway-ecommpay.php

    r3440800 r3449399  
    55 * GitHub Plugin URI:
    66 * Description:       Easy payment from WooCommerce by different methods in single Payment Page.
    7  * Version:           4.2.1
     7 * Version:           4.2.2
    88 * License:           GPL2
    99 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
  • ecommpay-payments/trunk/package.json

    r3218798 r3449399  
    11{
    2   "name": "woocommerce-ecommpay",
    3   "version": "1.0.0",
    4   "description": "",
    5   "scripts": {
    6     "start": "wp-scripts start",
    7     "build": "wp-scripts build",
    8     "plugin-zip": "wp-scripts plugin-zip",
    9     "check-engines": "wp-scripts check-engines",
    10     "check-licenses": "wp-scripts check-licenses",
    11     "format": "wp-scripts format",
    12     "lint:css": "wp-scripts lint-style",
    13     "lint:js": "wp-scripts lint-js",
    14     "lint:md:docs": "wp-scripts lint-md-docs",
    15     "lint:pkg-json": "wp-scripts lint-pkg-json",
    16     "packages-update": "wp-scripts packages-update",
    17     "test:e2e": "wp-scripts test-e2e",
    18     "test:unit": "wp-scripts test-unit-js"
    19   },
    20   "author": "ECOMMPAY",
    21   "license": "GPL-2.0-only",
    22   "devDependencies": {
    23     "@types/applepayjs": "^14.0.9",
    24     "@wordpress/scripts": "^26.19.0"
    25   },
    26   "dependencies": {
    27     "@wordpress/element": "^5.27.0",
    28     "@wordpress/html-entities": "^3.50.0",
    29     "use-debounce": "^10.0.0"
    30   }
     2    "name": "woocommerce-ecommpay",
     3    "version": "1.0.0",
     4    "description": "",
     5    "scripts": {
     6        "start": "wp-scripts start",
     7        "build": "wp-scripts build",
     8        "plugin-zip": "wp-scripts plugin-zip",
     9        "check-engines": "wp-scripts check-engines",
     10        "check-licenses": "wp-scripts check-licenses",
     11        "format": "wp-scripts format",
     12        "lint:css": "wp-scripts lint-style",
     13        "lint:js": "wp-scripts lint-js",
     14        "lint:md:docs": "wp-scripts lint-md-docs",
     15        "lint:pkg-json": "wp-scripts lint-pkg-json",
     16        "packages-update": "wp-scripts packages-update",
     17        "test:e2e": "wp-scripts test-e2e",
     18        "test:unit": "wp-scripts test-unit-js"
     19    },
     20    "author": "ECOMMPAY",
     21    "license": "GPL-2.0-only",
     22    "devDependencies": {
     23        "@types/applepayjs": "^14.0.9",
     24        "@wordpress/scripts": "^26.19.0"
     25    },
     26    "dependencies": {
     27        "@wordpress/element": "^5.27.0",
     28        "@wordpress/html-entities": "^3.50.0",
     29        "use-debounce": "^10.0.0"
     30    },
     31    "resolutions": {
     32        "@babel/runtime": "^7.26.10",
     33        "@babel/core": "^7.26.10"
     34    }
    3135}
  • ecommpay-payments/trunk/readme.txt

    r3440800 r3449399  
    33Tags: card payments, apple pay, google pay, open banking, subscriptions, paypal, humm, ideal, klarna, payment gateway, woocommerce
    44Requires at least: 6.2
    5 Tested up to: 6.7
    6 Stable tag: 4.2.1
     5Tested up to: 6.9
     6Stable tag: 4.2.2
    77License: GPLv2
    88License URI: http://www.gnu.org/licenses/gpl-2.0.html
  • ecommpay-payments/trunk/views/admin/sections/html-buttons.php

    r3218798 r3449399  
    1818
    1919    <button class="button button-primary <?= esc_attr( EcpModuleAdminUI::ACTION_BUTTON_CLASS ); ?>"
    20             data-ecp-action="capture"
     20            data-ecp-action="<?= esc_attr( EcpModuleAdminUI::ACTION_CAPTURE ); ?>"
    2121            data-order-id="<?= esc_attr( $order->get_id() ); ?>">
    2222        <?= ecpL( 'Capture', 'Capture payment from dashboard' ) . ' ' . $order->get_formatted_order_total(); ?>
    2323    </button>
    2424    <button class="button button-secondary <?= esc_attr( EcpModuleAdminUI::ACTION_BUTTON_CLASS ); ?>"
    25             data-ecp-action="cancel"
     25            data-ecp-action="<?= esc_attr( EcpModuleAdminUI::ACTION_CANCEL ); ?>"
    2626            data-order-id="<?= esc_attr( $order->get_id() ); ?>">
    2727        <?= esc_html( ecpL( 'Cancel payment', 'Cancel payment from dashboard' ) ); ?>
     
    3131            const refundButtonSelector = '<?= esc_js( EcpModuleAdminUI::WP_REFUND_BUTTON_SELECTOR ); ?>'
    3232            const actionButtonClass = '<?= esc_js( EcpModuleAdminUI::ACTION_BUTTON_CLASS ); ?>'
     33            const ACTION_CAPTURE = '<?= esc_js( EcpModuleAdminUI::ACTION_CAPTURE ); ?>'
     34            const ACTION_CANCEL = '<?= esc_js( EcpModuleAdminUI::ACTION_CANCEL ); ?>'
    3335
    3436            // Refund button handler
     
    4547                const action = $(this).data('ecp-action')
    4648                const confirmMessages = {
    47                     capture: 'Are you sure you wish to process this capture? This action cannot be undone.',
    48                     cancel: 'Are you sure you wish to process this cancel? This action cannot be undone.',
     49                    [ACTION_CAPTURE]: 'Are you sure you wish to process this capture? This action cannot be undone.',
     50                    [ACTION_CANCEL]: 'Are you sure you wish to process this cancel? This action cannot be undone.',
    4951                }
    5052
  • ecommpay-payments/trunk/views/html-meta-box-error.php

    r3218798 r3449399  
    33 * Template for ECOMMPAY Payment meta box error message.
    44 */
     5
     6use common\modules\EcpModuleAdminUI;
    57
    68?>
     
    2022    <li class="wide">
    2123        <strong class="ecp-amount"></strong>
    22         <button type="button" data-action="refresh" class="button refresh-info button-secondary" name="save"
     24        <button type="button" data-action="<?php echo esc_attr( EcpModuleAdminUI::ACTION_REFRESH ); ?>"
     25                class="button refresh-info button-secondary" name="save"
    2326                value="Refresh">Refresh
    2427        </button>
  • ecommpay-payments/trunk/views/html-meta-box-payment-info.php

    r3218798 r3449399  
    1818use common\helpers\EcpGatewayPaymentStatus;
    1919use common\models\EcpGatewayInfoPayment;
     20use common\modules\EcpModuleAdminUI;
    2021
    2122?>
     
    119120            <?php echo wp_kses_post( $amount ); ?>
    120121        </strong>
    121         <button type="button" data-action="refresh" class="button refresh-info button-secondary" name="save"
     122        <button type="button" data-action="<?php echo esc_attr( EcpModuleAdminUI::ACTION_REFRESH ); ?>"
     123                class="button refresh-info button-secondary" name="save"
    122124                value="Refresh">Refresh
    123125        </button>
Note: See TracChangeset for help on using the changeset viewer.