PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13.1 1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 All 212 releases
← All changes | includes/square/gateway/class-charitable-square-webhook-processor.php +52 -7 1.8.11.3 → 1.8.13 View file →
@@ -962,9 +962,19 @@
962 962 error_log( 'Square Webhook - Transaction ID: ' . $transaction_id );
963 963 // phpcs:enable
964 964 }
965 965
966 - $refund_amount = $charge['refund']['amount_money']['amount'];
966 + $refund_amount = $charge['refund']['amount_money']['amount'];
967 + $refund_currency = $charge['refund']['amount_money']['currency'];
968 +
969 + // Square sends amounts in the smallest currency unit (cents for
970 + // USD, yen for JPY, etc.). process_refund() expects the site's
971 + // display unit, so divide by 100 unless this is a zero-decimal
972 + // currency.
973 + if ( ! Charitable_Square_Gateway_Processor::is_zero_decimal_currency( $refund_currency ) ) {
974 + $refund_amount = $refund_amount / 100;
975 + }
976 +
967 977 if ( charitable_is_debug( 'square' ) ) {
968 978 // phpcs:disable
969 979 error_log( 'Square Webhook - Refund Amount: ' . $refund_amount );
970 980 // phpcs:enable
@@ -1449,15 +1459,50 @@
1449 1459 return false;
1450 1460 }
1451 1461
1452 1462 /*
1453 - * No signing secret stored (webhook subscription not yet registered
1454 - * via the Square settings screen). Fall through to the legacy
1455 - * merchant_id presence check for backwards compatibility; such sites
1456 - * remain unverified until they register webhooks.
1463 + * No signing secret stored. Historically the processor fell through
1464 + * here to a merchant_id presence check and ACCEPTED the (unsigned)
1465 + * event, which let an unauthenticated caller forge Square webhooks on
1466 + * any site that had not yet stored a signing secret. Fail closed: the
1467 + * event is refused unless enforcement is explicitly disabled.
1468 + *
1469 + * Sites connected through the Square settings screen store a signing
1470 + * secret during onboarding, so they never reach this branch and are
1471 + * unaffected. For the rare site that has webhooks enabled but no
1472 + * stored secret, refused events stop donations/refunds from
1473 + * reconciling, which the hourly Charitable_Square_WebhooksHealthCheck
1474 + * detects and surfaces as an admin notice prompting a reconnect (which
1475 + * re-registers the subscription and stores a fresh signing secret,
1476 + * restoring verification).
1477 + *
1478 + * @since 1.8.12
1457 1479 */
1458 - if ( empty( $signature_key ) && charitable_is_debug( 'square' ) ) {
1459 - error_log( 'Square webhook WARNING: no signing secret stored - signature verification skipped. Register webhooks via Square settings to enable verification.' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
1480 + if ( empty( $signature_key ) ) {
1481 +
1482 + /**
1483 + * Filter whether to enforce Square webhook signature verification
1484 + * when no signing secret is stored.
1485 + *
1486 + * Defaults to true (fail closed). Returning false restores the
1487 + * legacy behaviour of accepting unsigned events and re-opens the
1488 + * forgery vector, so it should only be used as a temporary escape
1489 + * hatch while reconnecting Square.
1490 + *
1491 + * @since 1.8.12
1492 + *
1493 + * @param bool $enforce Whether to reject unsigned events. Default true.
1494 + */
1495 + $enforce_signature = (bool) apply_filters( 'charitable_square_webhook_enforce_signature', true );
1496 +
1497 + if ( $enforce_signature ) {
1498 + error_log( 'Square webhook REJECTED: no signing secret stored. Reconnect Square (Settings > Payment > Square) to register webhooks and enable signature verification. To temporarily accept unsigned events, use the charitable_square_webhook_enforce_signature filter.' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
1499 + return false;
1500 + }
1501 +
1502 + if ( charitable_is_debug( 'square' ) ) {
1503 + error_log( 'Square webhook WARNING: no signing secret stored and signature enforcement disabled via the charitable_square_webhook_enforce_signature filter - accepting unsigned event.' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
1504 + }
1460 1505 }
1461 1506
1462 1507 $event = json_decode( $body, true );
1463 1508