Plugin Directory

Changeset 3711360


Ignore:
Timestamp:
09/24/2026 01:17:27 PM (4 weeks ago)
Author:
inginerit
Message:

Release 3.0.1: MIA callback URL shown in settings, MIA signals endpoint fix, signal JWT always verified (bundled VictoriaBank certificates), plugin renamed

Location:
mia-payment-gateway-for-victoriabank/trunk
Files:
3 added
6 edited

Legend:

Unmodified
Added
Removed
  • mia-payment-gateway-for-victoriabank/trunk/CHANGELOG.md

    r3711285 r3711360  
    55The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
    66and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
     7
     8## [3.0.1] - 2026-09-24
     9
     10### Added
     11- MIA callback (signals) URL displayed in the MIA settings page
     12
     13### Fixed
     14- MIA signals REST route registered independently of lazy gateway loading (was 404)
     15- Signal JWT always verified (bundled VictoriaBank certificates + certificates from settings); never accepted unsigned
    716
    817## [3.0.0] - 2026-09-24
  • mia-payment-gateway-for-victoriabank/trunk/includes/class-miapg-gateway.php

    r3711259 r3711360  
    111111
    112112    /**
     113     * Public URL of the MIA signals (webhook) endpoint registered by MIAPG_Webhook_Handler.
     114     * rest_url() also covers sites without pretty permalinks (?rest_route=...).
     115     */
     116    public function get_public_key() {
     117        return (string) $this->public_key;
     118    }
     119
     120    public static function get_webhook_url() {
     121        return rest_url('miapg/v1/webhook');
     122    }
     123
     124    /**
    113125     * Initialize Gateway Settings Form Fields
    114126     */
    … …  
    150162                'description' => 'Your merchant IBAN (e.g., MD52VI225100000103171MDL)',
    151163            ),
     164            'webhook_url_info' => array(
     165                'title' => __('Callback URL (MIA signals)', 'mia-payment-gateway-for-victoriabank'),
     166                'type' => 'title',
     167                'description' => sprintf(
     168                    /* translators: %s: webhook URL */
     169                    __('<strong>Send this URL to VictoriaBank</strong> to be registered as the callback (signals) URL for your MIA account. The bank sends the JWT-signed payment notifications (POST) to it:<br><code style="font-size:13px;user-select:all;">%s</code><br><em>Use the same URL for the test and the production account. It must be publicly reachable over HTTPS.</em>', 'mia-payment-gateway-for-victoriabank'),
     170                    esc_html(self::get_webhook_url())
     171                ),
     172            ),
    152173            'public_key' => array(
    153174                'title' => 'VictoriaBank Public Key',
    154175                'type' => 'textarea',
    155                 'description' => 'VBCA.crt content for JWT signature verification',
     176                'description' => __('Optional. The current VictoriaBank signal certificate(s) are bundled with the plugin. Paste here an additional certificate (VBCA.crt) received from the bank - several certificates can be pasted one after another (useful during certificate rotation).', 'mia-payment-gateway-for-victoriabank'),
    156177                'css' => 'min-height: 150px;',
    157178            ),
  • mia-payment-gateway-for-victoriabank/trunk/includes/class-miapg-webhook-handler.php

    r3711259 r3711360  
    88 *
    99 * @package VictoriaBank_MIA_Gateway
    10  * @version 2.2.0
     10 * @version 3.0.1
    1111 */
    1212
    … …  
    2020    public function __construct($gateway) {
    2121        $this->gateway = $gateway;
    22         $this->logging = $gateway->logging ?? false;
    23        
    24         // Register REST API endpoint (WordPress.org requirement)
    25         add_action('rest_api_init', array($this, 'register_rest_route'));
    26        
    27         $this->log('Webhook handler initialized with REST API');
    28     }
    29    
    30     /**
    31      * Register REST API endpoint for webhooks
    32      *
    33      * This endpoint uses WP REST API as recommended by WordPress.org
    34      * Endpoint: POST /wp-json/miapg/v1/webhook
    35      */
    36     public function register_rest_route() {
     22        $this->logging = false;
     23    }
     24
     25    /**
     26     * Register REST API endpoint for webhooks: POST /wp-json/miapg/v1/webhook
     27     *
     28     * Hooked on rest_api_init from the main plugin file. It must NOT depend on the gateway
     29     * being instantiated: WooCommerce loads payment gateways lazily, so on a REST request
     30     * coming from the bank the gateway object does not exist yet.
     31     */
     32    public static function register_route() {
    3733        register_rest_route('miapg/v1', '/webhook', array(
    3834            'methods' => 'POST',
    39             'callback' => array($this, 'handle_rest_webhook'),
     35            'callback' => array(__CLASS__, 'rest_callback'),
    4036            'permission_callback' => '__return_true', // JWT signature provides authentication
    4137        ));
     38    }
     39
     40    /**
     41     * REST callback: loads the MIA gateway and processes the signal.
     42     *
     43     * @param WP_REST_Request $request
     44     * @return WP_REST_Response
     45     */
     46    public static function rest_callback($request) {
     47        $gateways = function_exists('WC') ? WC()->payment_gateways()->payment_gateways() : array();
     48        if (empty($gateways['mia'])) {
     49            return new WP_REST_Response(array('message' => 'MIA gateway unavailable'), 503);
     50        }
     51        $handler = new self($gateways['mia']);
     52        return $handler->handle_rest_webhook($request);
     53    }
     54
     55    /**
     56     * Public keys/certificates accepted for the signal JWT: the one(s) configured by the merchant
     57     * plus the VictoriaBank certificates bundled in includes/certs/ (several are kept during rotation).
     58     *
     59     * @return string[] PEM strings
     60     */
     61    private function get_verification_keys() {
     62        $keys = array();
     63        $configured = method_exists($this->gateway, 'get_public_key') ? (string) $this->gateway->get_public_key() : '';
     64        if (preg_match_all('/-----BEGIN (?:CERTIFICATE|PUBLIC KEY)-----.+?-----END (?:CERTIFICATE|PUBLIC KEY)-----/s', $configured, $m)) {
     65            $keys = $m[0];
     66        }
     67        foreach ((array) glob(MIAPG_PLUGIN_DIR . 'includes/certs/*.crt') as $file) {
     68            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- local bundled certificate
     69            $pem = file_get_contents($file);
     70            if ($pem) {
     71                $keys[] = $pem;
     72            }
     73        }
     74        return array_unique($keys);
    4275    }
    4376   
    … …  
    260293            }
    261294
    262             // Get public key from plugin settings
    263             $public_key = $this->gateway->public_key ?? '';
    264            
    265             if (empty($public_key)) {
    266                 $this->log('Public key not configured - SECURITY WARNING: Signature verification disabled!', 'warning');
    267                 // IMPORTANT: In production, merchants MUST configure the public key
    268                 // Without it, webhooks cannot be authenticated
    269                 // For testing/development, we allow this but log a warning
    270                 return $payload;
    271             }
    272 
    273             // CRYPTOGRAPHIC SIGNATURE VERIFICATION
    274             // Reconstruct the signed data (header + payload)
     295            // CRYPTOGRAPHIC SIGNATURE VERIFICATION (RS256) against every accepted VictoriaBank key.
     296            // A signal is NEVER accepted without a valid signature.
    275297            $data = $header_b64 . '.' . $payload_b64;
    276            
    277             // Decode signature from base64url
    278298            $signature = base64_decode(strtr($signature_b64, '-_', '+/'));
    279299
    280             // Parse VictoriaBank's RSA public key
    281             $public_key_resource = openssl_pkey_get_public($public_key);
    282            
    283             if (!$public_key_resource) {
    284                 $this->log('Invalid public key format - cannot verify signature', 'error');
    285                 return false;
    286             }
    287 
    288             // Verify RS256 signature (RSA with SHA-256)
    289             // This cryptographically proves:
    290             // - The data was signed by VictoriaBank's private key
    291             // - The data has not been modified
    292             // - The signature is mathematically valid
    293             $verified = openssl_verify($data, $signature, $public_key_resource, OPENSSL_ALGO_SHA256);
    294            
    295             // Note: openssl_free_key() removed - deprecated in PHP 8.0+
    296             // Resource is automatically freed when out of scope
    297 
    298             if ($verified === 1) {
    299                 $this->log('JWT signature cryptographically verified - data is authentic');
    300                 // Return the validated payload
    301                 // All data in this payload is now trusted as it was signed by VictoriaBank
    302                 return $payload;
    303             } elseif ($verified === 0) {
    304                 $this->log('JWT signature verification FAILED - data rejected as untrusted', 'error');
    305                 return false;
    306             } else {
    307                 $this->log('JWT signature verification ERROR - openssl_verify returned: ' . $verified, 'error');
    308                 return false;
    309             }
     300            foreach ($this->get_verification_keys() as $pem) {
     301                $public_key_resource = openssl_pkey_get_public($pem);
     302                if ($public_key_resource && 1 === openssl_verify($data, $signature, $public_key_resource, OPENSSL_ALGO_SHA256)) {
     303                    $this->log('JWT signature cryptographically verified - data is authentic');
     304                    return $payload;
     305                }
     306            }
     307
     308            $this->log('JWT signature verification FAILED with all configured VictoriaBank certificates - data rejected', 'error');
     309            return false;
    310310
    311311        } catch (Exception $e) {
  • mia-payment-gateway-for-victoriabank/trunk/includes/egateway/class-vbpg-abstract-gateway.php

    r3711285 r3711360  
    529529                    __( '<strong>Send this URL to VictoriaBank</strong> as the Notification/Callback URL for this terminal (server-to-server push):<br><code style="font-size:13px;user-select:all;">%1$s</code><br><br><em>BACKREF URL (browser redirect, set automatically in each payment request): <code>%2$s</code></em>', 'mia-payment-gateway-for-victoriabank' ),
    530530                    esc_html( $this->get_callback_url() ),
    531                     esc_html( $this->get_backref_url( 0 ) )
     531                    esc_html( remove_query_arg( 'vb_order', $this->get_backref_url( 0 ) ) )
    532532                ),
    533533            ],
  • mia-payment-gateway-for-victoriabank/trunk/mia-payment-gateway-victoriabank.php

    r3711285 r3711360  
    11<?php
    22/**
    3  * Plugin Name: MIA Payment Gateway for VictoriaBank (Community Edition)
     3 * Plugin Name: MIA, Bank Card & StarCard Payment Gateway for VictoriaBank (Community Edition)
    44 * Plugin URI: https://github.com/inginerit/MIA-Payment-Gateway-for-VictoriaBank
    55 * Description: WooCommerce payment gateway for VictoriaBank: MIA Instant Payments (QR), Visa/Mastercard, StarCard Installments and StarCard Points.
    6  * Version: 3.0.0
     6 * Version: 3.0.1
    77 * Author: Programator Independent
    88 * Author URI: https://github.com/inginerit
    … …  
    2121
    2222// Define plugin constants
    23 define('MIAPG_VERSION', '3.0.0');
     23define('MIAPG_VERSION', '3.0.1');
    2424define('MIAPG_PLUGIN_FILE', __FILE__);
    2525define('MIAPG_PLUGIN_DIR', plugin_dir_path(__FILE__));
    … …  
    6161    // Check/update database
    6262    MIAPG_Database::maybe_update_db();
     63
     64    // MIA signals (webhook) endpoint - registered independently of gateway instantiation
     65    add_action('rest_api_init', array('MIAPG_Webhook_Handler', 'register_route'));
    6366
    6467    // e-Gateway (Visa/Mastercard, StarCard Installments, StarCard Points)
  • mia-payment-gateway-for-victoriabank/trunk/readme.txt

    r3711327 r3711360  
    55Tested up to: 7.1
    66Requires PHP: 8.0
    7 Stable tag: 3.0.0
     7Stable tag: 3.0.1
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    154154== Changelog ==
    155155
     156= 3.0.1 =
     157* Added: The MIA callback (signals) URL to send to VictoriaBank is now shown in the MIA settings page (the card callback URL is shown in each card gateway settings page).
     158* Fixed: The MIA signals endpoint (`/wp-json/miapg/v1/webhook`) was not registered on REST requests (gateways are loaded lazily by WooCommerce), so bank notifications were answered with 404 and payments were confirmed only by polling.
     159* Security: MIA signals are accepted only with a valid RS256 signature. The current VictoriaBank signal certificates are bundled; additional certificates can be pasted in the settings (certificate rotation).
     160
    156161= 3.0.0 =
    157162* **Major update**: added Visa/Mastercard, StarCard Installments and StarCard Points (VictoriaBank e-Gateway) next to MIA - one plugin for all VictoriaBank payment methods
    … …  
    194199== Upgrade Notice ==
    195200
     201= 3.0.1 =
     202Fixes MIA payment notifications from the bank and shows the callback URLs to register with VictoriaBank. Recommended for all users.
     203
    196204= 3.0.0 =
    197205Major update: adds Visa/Mastercard, StarCard Installments and StarCard Points. Existing MIA settings and orders are preserved. Requires PHP 8.0+ - sites on older PHP stay on 2.2.0.
Note: See TracChangeset for help on using the changeset viewer.