From b87b80f4396699ca26e2e78c5c035868a9086df7 Mon Sep 17 00:00:00 2001 From: StevenDufresne Date: Wed, 30 Oct 2024 11:32:30 +0900 Subject: [PATCH 1/6] Force unconfirmed tickets to log in. --- .../plugins/camptix/addons/require-login.php | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/public_html/wp-content/plugins/camptix/addons/require-login.php b/public_html/wp-content/plugins/camptix/addons/require-login.php index 53f4141cb..b6fc3cdac 100644 --- a/public_html/wp-content/plugins/camptix/addons/require-login.php +++ b/public_html/wp-content/plugins/camptix/addons/require-login.php @@ -71,16 +71,22 @@ public function block_unauthenticated_actions() { return; } - // Temporary: We don't want to block users from editing tickets. - // See: https://github.com/WordPress/wordcamp.org/issues/1393. - if ( ! is_user_logged_in() && ! $this->user_is_editing_ticket() ) { + if ( ! is_user_logged_in() ) { + + // Temporary: We don't want to block users from editing tickets unless they are unconfirmed. + // See: https://github.com/WordPress/wordcamp.org/issues/1393. + // See: https://github.com/WordPress/wordcamp.org/issues/1420. + if ( $this->user_is_editing_ticket() && ! $this->user_must_confirm_ticket( $_REQUEST['tix_attendee_id'] ) ) { + return; + } + $args = array(); - // If this was a registration, pass through the selected tickets and coupon. - if ( 'attendee_info' === $_REQUEST['tix_action'] && isset( $_REQUEST['tix_tickets_selected'] ) ) { - $args['tix_action'] = $_REQUEST['tix_action']; - $args['tix_tickets_selected'] = $_REQUEST['tix_tickets_selected']; - if ( isset( $_REQUEST['tix_coupon'] ) ) { - $args['tix_coupon'] = $_REQUEST['tix_coupon']; + if ( in_array( $_REQUEST['tix_action'], array( 'attendee_info', 'edit_attendee' ) ) ) { + // Pass along all `tix_` information. + foreach ( $_REQUEST as $key => $value ) { + if ( strpos( $key, 'tix' ) === 0 ) { + $args[$key] = $value; + } } } @@ -148,7 +154,7 @@ public function ticket_form_message() { } // Ask the attendee to confirm their registration - if ( isset( $_REQUEST['tix_action'] ) && 'edit_attendee' == $_REQUEST['tix_action'] && self::UNCONFIRMED_USERNAME == get_post_meta( $_REQUEST['tix_attendee_id'], 'tix_username', true ) ) { + if ( $this->user_is_editing_ticket() && $this->user_must_confirm_ticket( $_REQUEST['tix_attendee_id'] ) ) { $tickets_selected = array( get_post_meta( $_REQUEST['tix_attendee_id'], 'tix_ticket_id', true ) => 1 ); // mimic $_REQUEST['tix_tickets_selected'] if ( $this->tickets_have_questions( $tickets_selected ) ) { @@ -841,6 +847,18 @@ public function prevent_unknown_attendees_viewing_private_content( $parameters ) protected function user_is_editing_ticket() { return isset( $_REQUEST['tix_action'] ) && in_array( $_REQUEST['tix_action'], array( 'access_tickets', 'edit_attendee' ) ); } + + /** + * Checks if the user associated with the given attendee ID must confirm their ticket. + * Unconfirmed tickets exist when one user purchases multiple tickets. + * + * @param int $attendee_id The ID of the attendee. If null or invalid, the function returns false. + * + * @return bool True if the attendee must confirm their ticket, false otherwise. + */ + protected function user_must_confirm_ticket( $attendee_id ) { + return isset( $attendee_id ) && self::UNCONFIRMED_USERNAME == get_post_meta( $attendee_id, 'tix_username', true ); + } } // CampTix_Require_Login camptix_register_addon( 'CampTix_Require_Login' ); From 922e0401c97592207c7b39dc78f247a63e8c2a5a Mon Sep 17 00:00:00 2001 From: StevenDufresne Date: Wed, 30 Oct 2024 13:50:23 +0900 Subject: [PATCH 2/6] Fix linter. --- public_html/wp-content/plugins/camptix/addons/require-login.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public_html/wp-content/plugins/camptix/addons/require-login.php b/public_html/wp-content/plugins/camptix/addons/require-login.php index b6fc3cdac..4a23c26af 100644 --- a/public_html/wp-content/plugins/camptix/addons/require-login.php +++ b/public_html/wp-content/plugins/camptix/addons/require-login.php @@ -85,7 +85,7 @@ public function block_unauthenticated_actions() { // Pass along all `tix_` information. foreach ( $_REQUEST as $key => $value ) { if ( strpos( $key, 'tix' ) === 0 ) { - $args[$key] = $value; + $args[ $key ] = $value; } } } From ec1f58b4c3aeb8ad6626e85e9860d48112fa77ba Mon Sep 17 00:00:00 2001 From: StevenDufresne Date: Wed, 30 Oct 2024 14:35:02 +0900 Subject: [PATCH 3/6] Replace other calls for unconfirmed check. --- .../wp-content/plugins/camptix/addons/require-login.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public_html/wp-content/plugins/camptix/addons/require-login.php b/public_html/wp-content/plugins/camptix/addons/require-login.php index 4a23c26af..ba70b1b15 100644 --- a/public_html/wp-content/plugins/camptix/addons/require-login.php +++ b/public_html/wp-content/plugins/camptix/addons/require-login.php @@ -436,7 +436,7 @@ public function use_custom_email_templates( $template, $attendee ) { if ( $unknown_attendee_info['email'] == get_post_meta( $attendee->ID, 'tix_email', true ) ) { $template = 'email_template_multiple_purchase_unknown_attendee'; - } elseif ( self::UNCONFIRMED_USERNAME == get_post_meta( $attendee->ID, 'tix_username', true ) ) { + } elseif ( $this->user_must_confirm_ticket( $attendee->ID ) ) { $template = 'email_template_multiple_purchase_unconfirmed_attendee'; } @@ -761,7 +761,7 @@ public function update_attendee_post_meta( $new_ticket_info, $attendee ) { * @return string */ public function rename_save_attendee_info_label( $label, $attendee, $ticket, $questions ) { - if ( self::UNCONFIRMED_USERNAME == get_post_meta( $attendee->ID, 'tix_username', true ) ) { + if ( $this->user_must_confirm_ticket( $attendee->ID ) ) { $label = __( 'Confirm Registration', 'wordcamporg' ); } From 5346a2122cc0d528f8f3717b784e93bd412ece66 Mon Sep 17 00:00:00 2001 From: StevenDufresne Date: Thu, 31 Oct 2024 09:23:50 +0900 Subject: [PATCH 4/6] Explicitely set properties and sanitize. --- .../plugins/camptix/addons/require-login.php | 46 +++++++++++++++---- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/public_html/wp-content/plugins/camptix/addons/require-login.php b/public_html/wp-content/plugins/camptix/addons/require-login.php index ba70b1b15..8e64b566c 100644 --- a/public_html/wp-content/plugins/camptix/addons/require-login.php +++ b/public_html/wp-content/plugins/camptix/addons/require-login.php @@ -80,16 +80,7 @@ public function block_unauthenticated_actions() { return; } - $args = array(); - if ( in_array( $_REQUEST['tix_action'], array( 'attendee_info', 'edit_attendee' ) ) ) { - // Pass along all `tix_` information. - foreach ( $_REQUEST as $key => $value ) { - if ( strpos( $key, 'tix' ) === 0 ) { - $args[ $key ] = $value; - } - } - } - + $args = $this->get_sanitized_tix_parameters( $_REQUEST ); $tickets_url = add_query_arg( $args, $camptix->get_tickets_url() ); wp_safe_redirect( add_query_arg( 'wcname', get_bloginfo( 'name' ), wp_login_url( $tickets_url ) ) ); @@ -97,6 +88,41 @@ public function block_unauthenticated_actions() { } } + /** + * Get sanitized ticket parameters from request array. + * + * @param array $request_data Array of request data to sanitize. + * @return array Sanitized parameters. + */ + private function get_sanitized_tix_parameters( $request_data ) { + $allowed_parameters = array( + 'tix_action' => 'text', + 'tix_tickets_selected' => 'int', + 'tix_coupon' => 'text', + 'tix_attendee_id' => 'int', + 'tix_edit_token' => 'text', + 'tix_access_token' => 'text', + ); + + $args = array(); + foreach ( $allowed_parameters as $key => $type ) { + if ( isset( $request_data[ $key ] ) ) { + switch ( $type ) { + case 'int': + $args[ $key ] = absint( $request_data[ $key ] ); + break; + + case 'text': + default: + $args[ $key ] = sanitize_text_field( $request_data[ $key ] ); + break; + } + } + } + + return $args; + } + /** * Hide the interactive elements of the Tickets registration form if the user isn't logged in. * From e58ade339bf2478cca883fc8f6c5d51287e06f61 Mon Sep 17 00:00:00 2001 From: StevenDufresne Date: Fri, 1 Nov 2024 12:38:22 +0900 Subject: [PATCH 5/6] Add more parameters to array. --- .../plugins/camptix/addons/require-login.php | 34 ++++++-- .../camptix/inc/class-camptix-actions.php | 80 +++++++++++++++++++ .../tests/inc/test-class-camptix-actions.php | 39 +++++++++ 3 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 public_html/wp-content/plugins/camptix/inc/class-camptix-actions.php create mode 100644 public_html/wp-content/plugins/camptix/tests/inc/test-class-camptix-actions.php diff --git a/public_html/wp-content/plugins/camptix/addons/require-login.php b/public_html/wp-content/plugins/camptix/addons/require-login.php index 8e64b566c..d78e7b78e 100644 --- a/public_html/wp-content/plugins/camptix/addons/require-login.php +++ b/public_html/wp-content/plugins/camptix/addons/require-login.php @@ -94,20 +94,40 @@ public function block_unauthenticated_actions() { * @param array $request_data Array of request data to sanitize. * @return array Sanitized parameters. */ - private function get_sanitized_tix_parameters( $request_data ) { + private function get_sanitized_tix_parameters( array $request_data ): array { $allowed_parameters = array( - 'tix_action' => 'text', - 'tix_tickets_selected' => 'int', - 'tix_coupon' => 'text', - 'tix_attendee_id' => 'int', - 'tix_edit_token' => 'text', - 'tix_access_token' => 'text', + 'tix_action' => 'text', + 'tix_tickets_selected' => 'array_int', + 'tix_errors' => 'array_str', + 'tix_coupon' => 'text', + 'tix_attendee_id' => 'int', + 'tix_edit_token' => 'text', + 'tix_access_token' => 'text', + 'tix_reservation_id' => 'text', + 'tix_reservation_token' => 'text', + 'tix_single_ticket_purchase' => 'text', ); $args = array(); foreach ( $allowed_parameters as $key => $type ) { if ( isset( $request_data[ $key ] ) ) { switch ( $type ) { + case 'array_int': + if ( is_array( $request_data[ $key ] ) ) { + $args[ $key ] = array_map( 'absint', $request_data[ $key ] ); + } else { + $args[ $key ] = array( absint( $request_data[ $key ] ) ); + } + break; + + case 'array_str': + if ( is_array( $request_data[ $key ] ) ) { + $args[ $key ] = array_map( 'sanitize_text_field', $request_data[ $key ] ); + } else { + $args[ $key ] = array( sanitize_text_field( $request_data[ $key ] ) ); + } + break; + case 'int': $args[ $key ] = absint( $request_data[ $key ] ); break; diff --git a/public_html/wp-content/plugins/camptix/inc/class-camptix-actions.php b/public_html/wp-content/plugins/camptix/inc/class-camptix-actions.php new file mode 100644 index 000000000..ecff48394 --- /dev/null +++ b/public_html/wp-content/plugins/camptix/inc/class-camptix-actions.php @@ -0,0 +1,80 @@ +type = $type; + $this->sanitizer = $sanitizer; + } + + public static function TEXT(): self { + return new self( 'text', fn( $value ) => sanitize_text_field( $value ) ); + } + + public static function INTEGER(): self { + return new self( 'int', fn( $value ) => absint( $value ) ); + } + + public static function ARRAY_INTEGER(): self { + return new self( 'array_int', fn( $value ) => is_array( $value ) + ? array_map( 'absint', $value ) + : array( absint( $value ) ) + ); + } + + public static function ARRAY_STR(): self { + return new self( 'array_str', fn( $value ) => is_array( $value ) + ? array_map( 'sanitize_text_field', $value ) + : array( sanitize_text_field( $value ) ) + ); + } + + public static function get_allowed_parameters(): array { + return [ + self::TICKET_ACTION => self::TEXT(), + self::TICKETS_SELECTED => self::ARRAY_INTEGER(), + self::COUPON => self::TEXT(), + self::ATTENDEE_ID => self::INTEGER(), + self::EDIT_TOKEN => self::TEXT(), + self::ACCESS_TOKEN => self::TEXT(), + self::RESERVATION_ID => self::INTEGER(), + self::RESERVATION_TOKEN => self::TEXT(), + self::ERRORS => self::ARRAY_STR(), + ]; + } + + public function get_type(): string { + return $this->type; + } + + public function sanitize( $value ) { + return call_user_func( $this->sanitizer, $value ); + } +} diff --git a/public_html/wp-content/plugins/camptix/tests/inc/test-class-camptix-actions.php b/public_html/wp-content/plugins/camptix/tests/inc/test-class-camptix-actions.php new file mode 100644 index 000000000..05e5d65d7 --- /dev/null +++ b/public_html/wp-content/plugins/camptix/tests/inc/test-class-camptix-actions.php @@ -0,0 +1,39 @@ +assertSame( 'tix_action', Camptix_Actions::TICKET_ACTION ); + $this->assertSame( 'tix_coupon', Camptix_Actions::COUPON ); + $this->assertSame( 'tix_single_ticket_purchase', Camptix_Actions::SINGLE_TICKET_PURCHASE ); + $this->assertSame( 'tix_tickets_selected', Camptix_Actions::TICKETS_SELECTED ); + $this->assertSame( 'tix_attendee_id', Camptix_Actions::ATTENDEE_ID ); + $this->assertSame( 'tix_edit_token', Camptix_Actions::EDIT_TOKEN ); + $this->assertSame( 'tix_access_token', Camptix_Actions::ACCESS_TOKEN ); + $this->assertSame( 'tix_reservation_id', Camptix_Actions::RESERVATION_ID ); + $this->assertSame( 'tix_reservation_token', Camptix_Actions::RESERVATION_TOKEN ); + $this->assertSame( 'tix_errors', Camptix_Actions::ERRORS ); + } + + public function testGetAllowedParameters() { + $parameters = Camptix_Actions::get_allowed_parameters(); + + // Check the keys and their associated types + $this->assertArrayHasKey( Camptix_Actions::TICKET_ACTION, $parameters ); + $this->assertInstanceOf( Camptix_Actions::class, $parameters[ Camptix_Actions::TICKET_ACTION ] ); + + $this->assertArrayHasKey( Camptix_Actions::TICKETS_SELECTED, $parameters ); + $this->assertInstanceOf( Camptix_Actions::class, $parameters[ Camptix_Actions::TICKETS_SELECTED ] ); + + // More assertions for each expected key + $this->assertArrayHasKey( Camptix_Actions::COUPON, $parameters ); + $this->assertArrayHasKey( Camptix_Actions::ATTENDEE_ID, $parameters ); + $this->assertArrayHasKey( Camptix_Actions::EDIT_TOKEN, $parameters ); + $this->assertArrayHasKey( Camptix_Actions::ACCESS_TOKEN, $parameters ); + $this->assertArrayHasKey( Camptix_Actions::RESERVATION_ID, $parameters ); + $this->assertArrayHasKey( Camptix_Actions::RESERVATION_TOKEN, $parameters ); + $this->assertArrayHasKey( Camptix_Actions::ERRORS, $parameters ); + } +} From 79672cdba3eac691fd2da2dbf211fe5c941d0dbc Mon Sep 17 00:00:00 2001 From: StevenDufresne Date: Fri, 1 Nov 2024 12:51:56 +0900 Subject: [PATCH 6/6] Delete actions. --- .../camptix/inc/class-camptix-actions.php | 80 ------------------- .../tests/inc/test-class-camptix-actions.php | 39 --------- 2 files changed, 119 deletions(-) delete mode 100644 public_html/wp-content/plugins/camptix/inc/class-camptix-actions.php delete mode 100644 public_html/wp-content/plugins/camptix/tests/inc/test-class-camptix-actions.php diff --git a/public_html/wp-content/plugins/camptix/inc/class-camptix-actions.php b/public_html/wp-content/plugins/camptix/inc/class-camptix-actions.php deleted file mode 100644 index ecff48394..000000000 --- a/public_html/wp-content/plugins/camptix/inc/class-camptix-actions.php +++ /dev/null @@ -1,80 +0,0 @@ -type = $type; - $this->sanitizer = $sanitizer; - } - - public static function TEXT(): self { - return new self( 'text', fn( $value ) => sanitize_text_field( $value ) ); - } - - public static function INTEGER(): self { - return new self( 'int', fn( $value ) => absint( $value ) ); - } - - public static function ARRAY_INTEGER(): self { - return new self( 'array_int', fn( $value ) => is_array( $value ) - ? array_map( 'absint', $value ) - : array( absint( $value ) ) - ); - } - - public static function ARRAY_STR(): self { - return new self( 'array_str', fn( $value ) => is_array( $value ) - ? array_map( 'sanitize_text_field', $value ) - : array( sanitize_text_field( $value ) ) - ); - } - - public static function get_allowed_parameters(): array { - return [ - self::TICKET_ACTION => self::TEXT(), - self::TICKETS_SELECTED => self::ARRAY_INTEGER(), - self::COUPON => self::TEXT(), - self::ATTENDEE_ID => self::INTEGER(), - self::EDIT_TOKEN => self::TEXT(), - self::ACCESS_TOKEN => self::TEXT(), - self::RESERVATION_ID => self::INTEGER(), - self::RESERVATION_TOKEN => self::TEXT(), - self::ERRORS => self::ARRAY_STR(), - ]; - } - - public function get_type(): string { - return $this->type; - } - - public function sanitize( $value ) { - return call_user_func( $this->sanitizer, $value ); - } -} diff --git a/public_html/wp-content/plugins/camptix/tests/inc/test-class-camptix-actions.php b/public_html/wp-content/plugins/camptix/tests/inc/test-class-camptix-actions.php deleted file mode 100644 index 05e5d65d7..000000000 --- a/public_html/wp-content/plugins/camptix/tests/inc/test-class-camptix-actions.php +++ /dev/null @@ -1,39 +0,0 @@ -assertSame( 'tix_action', Camptix_Actions::TICKET_ACTION ); - $this->assertSame( 'tix_coupon', Camptix_Actions::COUPON ); - $this->assertSame( 'tix_single_ticket_purchase', Camptix_Actions::SINGLE_TICKET_PURCHASE ); - $this->assertSame( 'tix_tickets_selected', Camptix_Actions::TICKETS_SELECTED ); - $this->assertSame( 'tix_attendee_id', Camptix_Actions::ATTENDEE_ID ); - $this->assertSame( 'tix_edit_token', Camptix_Actions::EDIT_TOKEN ); - $this->assertSame( 'tix_access_token', Camptix_Actions::ACCESS_TOKEN ); - $this->assertSame( 'tix_reservation_id', Camptix_Actions::RESERVATION_ID ); - $this->assertSame( 'tix_reservation_token', Camptix_Actions::RESERVATION_TOKEN ); - $this->assertSame( 'tix_errors', Camptix_Actions::ERRORS ); - } - - public function testGetAllowedParameters() { - $parameters = Camptix_Actions::get_allowed_parameters(); - - // Check the keys and their associated types - $this->assertArrayHasKey( Camptix_Actions::TICKET_ACTION, $parameters ); - $this->assertInstanceOf( Camptix_Actions::class, $parameters[ Camptix_Actions::TICKET_ACTION ] ); - - $this->assertArrayHasKey( Camptix_Actions::TICKETS_SELECTED, $parameters ); - $this->assertInstanceOf( Camptix_Actions::class, $parameters[ Camptix_Actions::TICKETS_SELECTED ] ); - - // More assertions for each expected key - $this->assertArrayHasKey( Camptix_Actions::COUPON, $parameters ); - $this->assertArrayHasKey( Camptix_Actions::ATTENDEE_ID, $parameters ); - $this->assertArrayHasKey( Camptix_Actions::EDIT_TOKEN, $parameters ); - $this->assertArrayHasKey( Camptix_Actions::ACCESS_TOKEN, $parameters ); - $this->assertArrayHasKey( Camptix_Actions::RESERVATION_ID, $parameters ); - $this->assertArrayHasKey( Camptix_Actions::RESERVATION_TOKEN, $parameters ); - $this->assertArrayHasKey( Camptix_Actions::ERRORS, $parameters ); - } -}