Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/event-tickets/common/vendor/vendor-prefixed/autoload.php
+++ b/event-tickets/common/vendor/vendor-prefixed/autoload.php
@@ -19,4 +19,4 @@
require_once __DIR__ . '/composer/autoload_real.php';
-return ComposerAutoloaderInitb01fb95bfc826db970c13b89d5ca02f1::getLoader();
+return ComposerAutoloaderInit8392b95f95880e2ae43d23da0eb6490e::getLoader();
--- a/event-tickets/common/vendor/vendor-prefixed/composer/autoload_real.php
+++ b/event-tickets/common/vendor/vendor-prefixed/composer/autoload_real.php
@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
-class ComposerAutoloaderInitb01fb95bfc826db970c13b89d5ca02f1
+class ComposerAutoloaderInit8392b95f95880e2ae43d23da0eb6490e
{
private static $loader;
@@ -24,12 +24,12 @@
require __DIR__ . '/platform_check.php';
- spl_autoload_register(array('ComposerAutoloaderInitb01fb95bfc826db970c13b89d5ca02f1', 'loadClassLoader'), true, true);
+ spl_autoload_register(array('ComposerAutoloaderInit8392b95f95880e2ae43d23da0eb6490e', 'loadClassLoader'), true, true);
self::$loader = $loader = new TECCommonComposerAutoloadClassLoader(dirname(__DIR__));
- spl_autoload_unregister(array('ComposerAutoloaderInitb01fb95bfc826db970c13b89d5ca02f1', 'loadClassLoader'));
+ spl_autoload_unregister(array('ComposerAutoloaderInit8392b95f95880e2ae43d23da0eb6490e', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
- call_user_func(TECCommonComposerAutoloadComposerStaticInitb01fb95bfc826db970c13b89d5ca02f1::getInitializer($loader));
+ call_user_func(TECCommonComposerAutoloadComposerStaticInit8392b95f95880e2ae43d23da0eb6490e::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
--- a/event-tickets/common/vendor/vendor-prefixed/composer/autoload_static.php
+++ b/event-tickets/common/vendor/vendor-prefixed/composer/autoload_static.php
@@ -4,7 +4,7 @@
namespace TECCommonComposerAutoload;
-class ComposerStaticInitb01fb95bfc826db970c13b89d5ca02f1
+class ComposerStaticInit8392b95f95880e2ae43d23da0eb6490e
{
public static $prefixLengthsPsr4 = array (
'T' =>
@@ -584,9 +584,9 @@
public static function getInitializer(ClassLoader $loader)
{
return Closure::bind(function () use ($loader) {
- $loader->prefixLengthsPsr4 = ComposerStaticInitb01fb95bfc826db970c13b89d5ca02f1::$prefixLengthsPsr4;
- $loader->prefixDirsPsr4 = ComposerStaticInitb01fb95bfc826db970c13b89d5ca02f1::$prefixDirsPsr4;
- $loader->classMap = ComposerStaticInitb01fb95bfc826db970c13b89d5ca02f1::$classMap;
+ $loader->prefixLengthsPsr4 = ComposerStaticInit8392b95f95880e2ae43d23da0eb6490e::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInit8392b95f95880e2ae43d23da0eb6490e::$prefixDirsPsr4;
+ $loader->classMap = ComposerStaticInit8392b95f95880e2ae43d23da0eb6490e::$classMap;
}, null, ClassLoader::class);
}
--- a/event-tickets/event-tickets.php
+++ b/event-tickets/event-tickets.php
@@ -3,7 +3,7 @@
* Plugin Name: Event Tickets
* Plugin URI: https://evnt.is/1acb
* Description: Event Tickets allows you to sell basic tickets and collect RSVPs from any post, page, or event.
- * Version: 5.27.5
+ * Version: 5.27.6.1
* Requires at least: 6.7
* Requires PHP: 7.4
* Author: The Events Calendar
--- a/event-tickets/src/Tickets/Commerce/Gateways/PayPal/REST/Order_Endpoint.php
+++ b/event-tickets/src/Tickets/Commerce/Gateways/PayPal/REST/Order_Endpoint.php
@@ -11,8 +11,10 @@
use TECTicketsCommerceGatewaysPayPalClient;
use TECTicketsCommerceStatusDenied;
+use TECTicketsCommerceStatusNot_Completed;
use TECTicketsCommerceStatusPending;
use TECTicketsCommerceStatusStatus_Handler;
+use TECTicketsCommerceStatusVoided;
use TECTicketsCommerceSuccess;
use TECTicketsCommerceValuesLegacy_Value_Factory;
use Tribe__Tickets__Tickets as Tickets;
@@ -93,6 +95,7 @@
*
* @since 5.1.9
* @since 5.6.4 Include Event/Post title in the Ticket name.
+ * @since 5.27.6.1 Removed order data from response for failed orders.
*
* @param WP_REST_Request $request The request object.
*
@@ -122,7 +125,7 @@
$order = tribe( Order::class )->create_from_cart( tribe( Gateway::class ), $purchaser );
if ( ! $order ) {
- return new WP_Error( 'tec-tc-gateway-paypal-failed-creating-order', $messages['failed-creating-order'], $order );
+ return new WP_Error( 'tec-tc-gateway-paypal-failed-creating-order', $messages['failed-creating-order'] );
}
$unit = [
@@ -152,7 +155,7 @@
$paypal_order = tribe( Client::class )->create_order( $unit );
if ( empty( $paypal_order['id'] ) || empty( $paypal_order['create_time'] ) ) {
- return new WP_Error( 'tec-tc-gateway-paypal-failed-creating-order', $messages['failed-creating-order'], $order );
+ return new WP_Error( 'tec-tc-gateway-paypal-failed-creating-order', $messages['failed-creating-order'] );
}
$debug_header = tribe( Client::class )->get_debug_header();
@@ -281,6 +284,7 @@
* Handles the request that updates an order with Tickets Commerce and the PayPal gateway.
*
* @since 5.1.9
+ * @since 5.27.6.1 Removed order data from response for failed orders.
*
* @param WP_REST_Request $request The request object.
*
@@ -301,7 +305,7 @@
] )->first();
if ( ! $order ) {
- return new WP_Error( 'tec-tc-gateway-paypal-nonexistent-order-id', $messages['nonexistent-order-id'], $order );
+ return new WP_Error( 'tec-tc-gateway-paypal-nonexistent-order-id', $messages['nonexistent-order-id'] );
}
$recheck = $request->get_param( 'recheck' );
@@ -327,7 +331,10 @@
'gateway_payload' => $paypal_capture_response,
] );
- return new WP_Error( 'tec-tc-gateway-paypal-failed-capture', $messages['failed-capture'], $paypal_capture_response );
+ return new WP_Error( 'tec-tc-gateway-paypal-failed-capture', $messages['failed-capture'], [
+ 'name' => Arr::get( $paypal_capture_response, 'name' ),
+ 'details' => Arr::get( $paypal_capture_response, 'details', [] ),
+ ] );
}
$response['success'] = true;
@@ -340,6 +347,7 @@
* Gets the Order object again, in another request, to check for purchases possibly denied after creation.
*
* @since 5.4.0.2
+ * @since 5.27.6.1 Removed order data from response for failed orders.
*
* @param string $order_id The PayPal order ID.
* @param WP_Post $order The TC Order object.
@@ -382,7 +390,7 @@
$status = tribe( Status::class )->convert_to_commerce_status( $paypal_order_status );
if ( ! $status ) {
- return new WP_Error( 'tec-tc-gateway-paypal-invalid-capture-status', $messages['invalid-capture-status'], $paypal_order_response );
+ return new WP_Error( 'tec-tc-gateway-paypal-invalid-capture-status', $messages['invalid-capture-status'] );
}
$updated = tribe( Order::class )->modify_status( $order->ID, $status->get_slug(), [
@@ -394,7 +402,7 @@
}
if ( in_array( $paypal_order_status, [ Status::FAILED, Status::DECLINED ], true ) ) {
- return new WP_Error( 'tec-tc-gateway-paypal-capture-declined', $messages['capture-declined'], $paypal_order_response );
+ return new WP_Error( 'tec-tc-gateway-paypal-capture-declined', $messages['capture-declined'] );
}
$response['success'] = true;
@@ -413,6 +421,7 @@
* Handles the request that handles failing an order with Tickets Commerce and the PayPal gateway.
*
* @since 5.2.0
+ * @since 5.27.6.1 Removed order data from response for failed orders.
*
* @param WP_REST_Request $request The request object.
*
@@ -432,7 +441,7 @@
$messages = $this->get_error_messages();
if ( ! $order ) {
- return new WP_Error( 'tec-tc-gateway-paypal-nonexistent-order-id', null, $order );
+ return new WP_Error( 'tec-tc-gateway-paypal-nonexistent-order-id', null );
}
$failed_reason = $request->get_param( 'failed_reason' );
@@ -441,13 +450,16 @@
$failed_status = 'not-completed';
}
+ $allowed_failure_statuses = [ Not_Completed::SLUG, Denied::SLUG, Voided::SLUG ];
+
+ if ( ! in_array( $failed_status, $allowed_failure_statuses, true ) ) {
+ return new WP_Error( 'tec-tc-gateway-paypal-invalid-failed-status', null );
+ }
+
$status = tribe( Status_Handler::class )->get_by_slug( $failed_status );
if ( ! $status ) {
- return new WP_Error( 'tec-tc-gateway-paypal-invalid-failed-status', null, [
- 'failed_status' => $failed_status,
- 'failed_reason' => $failed_reason
- ] );
+ return new WP_Error( 'tec-tc-gateway-paypal-invalid-failed-status', null );
}
/**
@@ -520,6 +532,7 @@
* Arguments used for the deleting order for PayPal.
*
* @since 5.2.0
+ * @since 5.27.6.1 Removed order data from response for failed orders.
*
* @return array
*/
@@ -543,8 +556,9 @@
'required' => false,
'type' => 'string',
'validate_callback' => static function ( $value ) {
- if ( ! is_string( $value ) ) {
- return new WP_Error( 'rest_invalid_param', 'The failed status argument must be a string.', [ 'status' => 400 ] );
+ $allowed = [ Not_Completed::SLUG, Denied::SLUG, Voided::SLUG ];
+ if ( ! is_string( $value ) || ! in_array( $value, $allowed, true ) ) {
+ return new WP_Error( 'rest_invalid_param', 'The failed status argument must be a valid failure status.', [ 'status' => 400 ] );
}
return $value;
--- a/event-tickets/src/Tickets/Commerce/Gateways/Square/REST/Order_Endpoint.php
+++ b/event-tickets/src/Tickets/Commerce/Gateways/Square/REST/Order_Endpoint.php
@@ -18,7 +18,10 @@
use TECTicketsCommerceGatewaysSquareStatus;
use TECTicketsCommerceStock_Validator;
use TECTicketsCommerceStatusCreated;
+use TECTicketsCommerceStatusDenied;
+use TECTicketsCommerceStatusNot_Completed;
use TECTicketsCommerceStatusPending;
+use TECTicketsCommerceStatusVoided;
use TECTicketsCommerceSuccess;
use WP_Error;
@@ -95,6 +98,7 @@
* Handles the request that creates an order with Tickets Commerce and the Square gateway.
*
* @since 5.24.0
+ * @since 5.27.6.1 Removed order data from response for failed orders.
*
* @param WP_REST_Request $request The request object.
*
@@ -117,11 +121,7 @@
if ( ! tribe( Cart::class )->has_items() ) {
return new WP_Error(
'tec-tc-empty-cart',
- $messages['empty-cart'],
- [
- 'purchaser' => $purchaser,
- 'data' => $data,
- ]
+ $messages['empty-cart']
);
}
@@ -138,12 +138,7 @@
if ( ! $order instanceof WP_Post ) {
return new WP_Error(
'tec-tc-gateway-square-order-creation-failed',
- $messages['failed-order-creation'],
- [
- 'cart_items' => tribe( Cart::class )->get_items_in_cart(),
- 'order' => $order,
- 'purchaser' => $purchaser,
- ]
+ $messages['failed-order-creation']
);
}
@@ -153,7 +148,7 @@
try {
$square_order_id = tribe( Square_Order::class )->upsert_square_from_local_order( $order );
} catch ( RuntimeException $e ) {
- return new WP_Error( 'tec-tc-gateway-square-failed-creating-order', $messages['failed-creating-order'], $order );
+ return new WP_Error( 'tec-tc-gateway-square-failed-creating-order', $messages['failed-creating-order'] );
}
// Get the order object from the database, since the order object might have been updated by the Square_Order::upsert_square_from_local_order method.
@@ -167,13 +162,13 @@
}
if ( empty( $payment['id'] ) || empty( $payment['created_at'] ) || empty( $payment['status'] ) ) {
- return new WP_Error( 'tec-tc-gateway-square-failed-creating-payment', $messages['failed-creating-payment'], $order );
+ return new WP_Error( 'tec-tc-gateway-square-failed-creating-payment', $messages['failed-creating-payment'] );
}
tribe( Square_Order::class )->add_payment_id( $order, $payment['id'] );
if ( 'COMPLETED' !== $payment['status'] ) {
- return new WP_Error( 'tec-tc-gateway-square-failed-creating-payment', $messages['failed-creating-payment'], $order );
+ return new WP_Error( 'tec-tc-gateway-square-failed-creating-payment', $messages['failed-creating-payment'] );
}
tec_tc_orders()
@@ -220,6 +215,7 @@
* Arguments used for the fail order endpoint.
*
* @since 5.24.0
+ * @since 5.27.6.1 Added allowed failure statuses to the response for failed orders.
*
* @return array
*/
@@ -243,8 +239,9 @@
'required' => false,
'type' => 'string',
'validate_callback' => static function ( $value ) {
- if ( ! is_string( $value ) ) {
- return new WP_Error( 'rest_invalid_param', 'The failed status argument must be a string.', [ 'status' => 400 ] );
+ $allowed = [ Not_Completed::SLUG, Denied::SLUG, Voided::SLUG ];
+ if ( ! is_string( $value ) || ! in_array( $value, $allowed, true ) ) {
+ return new WP_Error( 'rest_invalid_param', 'The failed status argument must be a valid failure status.', [ 'status' => 400 ] );
}
return $value;
@@ -272,53 +269,16 @@
*
* @since 5.24.0
*
+ * @deprecated 5.27.6.1
+ *
* @param WP_REST_Request $request The request object.
*
* @return WP_Error|WP_REST_Response An array containing the data on success or a WP_Error instance on failure.
*/
public function handle_fail_order( WP_REST_Request $request ) {
- $response = [
- 'success' => false,
- ];
-
- $messages = $this->get_error_messages();
- $order_id = $request->get_param( 'order_id' );
- $failed_status = $request->get_param( 'failed_status' );
- $failed_reason = $request->get_param( 'failed_reason' );
-
- $order = tec_tc_orders()->by_args(
- [
- 'status' => [
- tribe( Created::class )->get_wp_slug(),
- tribe( Pending::class )->get_wp_slug(),
- ],
- 'gateway_order_id' => $order_id,
- ]
- )->first();
-
- if ( is_wp_error( $order ) || empty( $order ) ) {
- return new WP_Error( 'tec-tc-gateway-square-order-not-found', $messages['order-not-found'], $order );
- }
+ _deprecated_function( __METHOD__, '5.27.6.1', 'This endpoint is no longer used and will be removed in a future release.' );
- $orders = tribe( Order::class );
-
- // Mark the order as failed.
- $orders->modify_status(
- $order->ID,
- $failed_status ?: 'failed',
- [
- 'gateway_payload' => [
- 'failed_reason' => $failed_reason,
- ],
- 'gateway_order_id' => $order_id,
- ]
- );
-
- $response['success'] = true;
- $response['status'] = $failed_status ?: 'failed';
- $response['message'] = $failed_reason ?: $messages['failed-payment'];
-
- return new WP_REST_Response( $response );
+ return new WP_REST_Response( [] );
}
/**
--- a/event-tickets/src/Tribe/Main.php
+++ b/event-tickets/src/Tribe/Main.php
@@ -18,7 +18,7 @@
/**
* Current version of this plugin.
*/
- const VERSION = '5.27.5';
+ const VERSION = '5.27.6.1';
/**
* Used to store the version history.
--- a/event-tickets/src/Tribe/REST/V1/Endpoints/Single_Attendee.php
+++ b/event-tickets/src/Tribe/REST/V1/Endpoints/Single_Attendee.php
@@ -87,9 +87,23 @@
* {@inheritdoc}
*
* @since 4.12.0 Returns 401 Unauthorized if Event Tickets Plus is not loaded.
+ * @since 5.27.6 Added event visibility checks for private, password-protected, and hidden attendee list events.
*/
public function get( WP_REST_Request $request ) {
- return tribe_attendees( 'restv1' )->by_primary_key( $request['id'] );
+ $attendee_id = (int) $request['id'];
+
+ if ( tribe( 'tickets.rest-v1.main' )->request_has_manage_access() ) {
+ return tribe_attendees( 'restv1' )->by_primary_key( $attendee_id );
+ }
+
+ if ( ! $this->is_publicly_visible_attendee_event( $attendee_id ) ) {
+ /** @var Tribe__Tickets__REST__V1__Messages $messages */
+ $messages = tribe( 'tickets.rest-v1.messages' );
+
+ return new WP_Error( 'attendee-not-accessible', $messages->get_message( 'attendee-not-accessible' ), [ 'status' => 401 ] );
+ }
+
+ return tribe_attendees( 'restv1' )->by_primary_key( $attendee_id );
}
/**
@@ -411,4 +425,56 @@
return $check_in;
}
+
+ /**
+ * Checks if the attendee's parent event is publicly visible.
+ *
+ * Blocks access when the event is private, password-protected,
+ * or hides attendees from public listing.
+ *
+ * @since 5.27.6
+ *
+ * @param int $attendee_id The attendee post ID.
+ *
+ * @return bool True if publicly visible, false otherwise.
+ */
+ private function is_publicly_visible_attendee_event( int $attendee_id ): bool {
+ if ( ! $attendee_id ) {
+ return false;
+ }
+
+ /** @var Tribe__Tickets__Attendee_Repository $attendee_repository */
+ $attendee_repository = tribe( 'tickets.attendee-repository' );
+
+ $event_id = 0;
+ foreach ( $attendee_repository->attendee_to_event_keys() as $event_meta_key ) {
+ $event_id = (int) get_post_meta( $attendee_id, $event_meta_key, true );
+ if ( $event_id ) {
+ break;
+ }
+ }
+
+ if ( ! $event_id ) {
+ return false;
+ }
+
+ $event = get_post( $event_id );
+
+ if ( ! $event instanceof WP_Post ) {
+ return false;
+ }
+
+ // Event must be published (not private or draft).
+ if ( 'publish' !== $event->post_status ) {
+ return false;
+ }
+
+ // Password-protected event.
+ if ( post_password_required( $event ) ) {
+ return false;
+ }
+
+ // Event must not hide attendees from public listing.
+ return ! tribe_is_truthy( get_post_meta( $event_id, '_tribe_hide_attendees_list', true ) );
+ }
}
--- a/event-tickets/vendor/composer/installed.php
+++ b/event-tickets/vendor/composer/installed.php
@@ -1,9 +1,9 @@
<?php return array(
'root' => array(
'name' => 'the-events-calendar/event-tickets',
- 'pretty_version' => 'dev-release/M26.chikorita',
- 'version' => 'dev-release/M26.chikorita',
- 'reference' => 'f6981c7b1fdfbd0cbaece2acc4b01ce575cfe14a',
+ 'pretty_version' => 'dev-fix/SVUL-71-paypal-square-vulnerabilities-fix',
+ 'version' => 'dev-fix/SVUL-71-paypal-square-vulnerabilities-fix',
+ 'reference' => 'aa341460fd50c3c60cee41f2411c319d8391b7e1',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -11,9 +11,9 @@
),
'versions' => array(
'the-events-calendar/event-tickets' => array(
- 'pretty_version' => 'dev-release/M26.chikorita',
- 'version' => 'dev-release/M26.chikorita',
- 'reference' => 'f6981c7b1fdfbd0cbaece2acc4b01ce575cfe14a',
+ 'pretty_version' => 'dev-fix/SVUL-71-paypal-square-vulnerabilities-fix',
+ 'version' => 'dev-fix/SVUL-71-paypal-square-vulnerabilities-fix',
+ 'reference' => 'aa341460fd50c3c60cee41f2411c319d8391b7e1',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),