Changeset 3711360
- Timestamp:
- 09/24/2026 01:17:27 PM (4 weeks ago)
- Location:
- mia-payment-gateway-for-victoriabank/trunk
- Files:
-
- 3 added
- 6 edited
-
CHANGELOG.md (modified) (1 diff)
-
includes/certs (added)
-
includes/certs/VBCA-2027.crt (added)
-
includes/certs/VBCA1-2028.crt (added)
-
includes/class-miapg-gateway.php (modified) (2 diffs)
-
includes/class-miapg-webhook-handler.php (modified) (3 diffs)
-
includes/egateway/class-vbpg-abstract-gateway.php (modified) (1 diff)
-
mia-payment-gateway-victoriabank.php (modified) (3 diffs)
-
readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
mia-payment-gateway-for-victoriabank/trunk/CHANGELOG.md
r3711285 r3711360 5 5 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 6 and 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 7 16 8 17 ## [3.0.0] - 2026-09-24 -
mia-payment-gateway-for-victoriabank/trunk/includes/class-miapg-gateway.php
r3711259 r3711360 111 111 112 112 /** 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 /** 113 125 * Initialize Gateway Settings Form Fields 114 126 */ … … 150 162 'description' => 'Your merchant IBAN (e.g., MD52VI225100000103171MDL)', 151 163 ), 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 ), 152 173 'public_key' => array( 153 174 'title' => 'VictoriaBank Public Key', 154 175 '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'), 156 177 'css' => 'min-height: 150px;', 157 178 ), -
mia-payment-gateway-for-victoriabank/trunk/includes/class-miapg-webhook-handler.php
r3711259 r3711360 8 8 * 9 9 * @package VictoriaBank_MIA_Gateway 10 * @version 2.2.010 * @version 3.0.1 11 11 */ 12 12 … … 20 20 public function __construct($gateway) { 21 21 $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() { 37 33 register_rest_route('miapg/v1', '/webhook', array( 38 34 'methods' => 'POST', 39 'callback' => array( $this, 'handle_rest_webhook'),35 'callback' => array(__CLASS__, 'rest_callback'), 40 36 'permission_callback' => '__return_true', // JWT signature provides authentication 41 37 )); 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); 42 75 } 43 76 … … 260 293 } 261 294 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. 275 297 $data = $header_b64 . '.' . $payload_b64; 276 277 // Decode signature from base64url278 298 $signature = base64_decode(strtr($signature_b64, '-_', '+/')); 279 299 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; 310 310 311 311 } catch (Exception $e) { -
mia-payment-gateway-for-victoriabank/trunk/includes/egateway/class-vbpg-abstract-gateway.php
r3711285 r3711360 529 529 __( '<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' ), 530 530 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 ) ) ) 532 532 ), 533 533 ], -
mia-payment-gateway-for-victoriabank/trunk/mia-payment-gateway-victoriabank.php
r3711285 r3711360 1 1 <?php 2 2 /** 3 * Plugin Name: MIA Payment Gateway for VictoriaBank (Community Edition)3 * Plugin Name: MIA, Bank Card & StarCard Payment Gateway for VictoriaBank (Community Edition) 4 4 * Plugin URI: https://github.com/inginerit/MIA-Payment-Gateway-for-VictoriaBank 5 5 * Description: WooCommerce payment gateway for VictoriaBank: MIA Instant Payments (QR), Visa/Mastercard, StarCard Installments and StarCard Points. 6 * Version: 3.0. 06 * Version: 3.0.1 7 7 * Author: Programator Independent 8 8 * Author URI: https://github.com/inginerit … … 21 21 22 22 // Define plugin constants 23 define('MIAPG_VERSION', '3.0. 0');23 define('MIAPG_VERSION', '3.0.1'); 24 24 define('MIAPG_PLUGIN_FILE', __FILE__); 25 25 define('MIAPG_PLUGIN_DIR', plugin_dir_path(__FILE__)); … … 61 61 // Check/update database 62 62 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')); 63 66 64 67 // e-Gateway (Visa/Mastercard, StarCard Installments, StarCard Points) -
mia-payment-gateway-for-victoriabank/trunk/readme.txt
r3711327 r3711360 5 5 Tested up to: 7.1 6 6 Requires PHP: 8.0 7 Stable tag: 3.0. 07 Stable tag: 3.0.1 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 154 154 == Changelog == 155 155 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 156 161 = 3.0.0 = 157 162 * **Major update**: added Visa/Mastercard, StarCard Installments and StarCard Points (VictoriaBank e-Gateway) next to MIA - one plugin for all VictoriaBank payment methods … … 194 199 == Upgrade Notice == 195 200 201 = 3.0.1 = 202 Fixes MIA payment notifications from the bank and shows the callback URLs to register with VictoriaBank. Recommended for all users. 203 196 204 = 3.0.0 = 197 205 Major 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.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)