PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.12.8
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.12.8
2.12.8 2.12.7 2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 All 98 releases
← All changes | inc/payments/front-end.php +69 -4 2.12.2 → 2.12.8 View file →
@@ -9,8 +9,9 @@
9 9 namespace SRFM\Inc\Payments;
10 10
11 11 use SRFM\Inc\Database\Tables\Payments;
12 12 use SRFM\Inc\Field_Validation;
13 +use SRFM\Inc\Helper;
13 14 use SRFM\Inc\Payments\Stripe\Stripe_Helper;
14 15 use SRFM\Inc\Submit_Token;
15 16 use SRFM\Inc\Traits\Get_Instance;
16 17
@@ -131,9 +132,10 @@
131 132 ]
132 133 );
133 134 }
134 135
135 - $license_key = Stripe_Helper::get_license_key();
136 + // Public checkout request - never block the visitor on a SureCart license call.
137 + $license_key = Stripe_Helper::get_license_key( false );
136 138
137 139 // Create payment intent with confirm: true for immediate processing.
138 140 $payment_intent_data = [
139 141 'secret_key' => $secret_key,
@@ -357,9 +359,10 @@
357 359 if ( ! $customer_id ) {
358 360 throw new \Exception( __( 'Failed to create customer for subscription.', 'sureforms' ) );
359 361 }
360 362
361 - $license_key = Stripe_Helper::get_license_key();
363 + // Public checkout request - never block the visitor on a SureCart license call.
364 + $license_key = Stripe_Helper::get_license_key( false );
362 365 // Prepare subscription data for middleware.
363 366 $subscription_data = apply_filters(
364 367 'srfm_create_subscription_data',
365 368 [
@@ -480,8 +483,20 @@
480 483 }
481 484
482 485 $payment_response = [];
483 486
487 + // Block IDs that produced a verified payment on this submission.
488 + $verified_block_ids = [];
489 +
490 + // Field keys of every payment field seen in this submission, and the
491 + // subset whose payment we actually verified below. A payment field's
492 + // value is only a trustworthy payment-record id once verified here; any
493 + // field left unverified is cleared before it reaches the submission data,
494 + // so the {form-payment} smart tag can never resolve a client-supplied id
495 + // to an arbitrary payment row.
496 + $payment_field_names = [];
497 + $verified_field_names = [];
498 +
484 499 // Loop through form data to find payment fields.
485 500 foreach ( $form_data as $field_name => $field_value ) {
486 501 // Check if field name contains "-lbl-" pattern.
487 502 if ( strpos( $field_name, '-lbl-' ) === false ) {
@@ -500,8 +515,10 @@
500 515 if ( ! ( strpos( $name_parts[0], 'srfm-payment-' ) === 0 ) ) {
501 516 continue;
502 517 }
503 518
519 + $payment_field_names[] = $field_name;
520 +
504 521 // Value will be in the form of the json string.
505 522 $payment_value = json_decode( $field_value, true );
506 523
507 524 if ( empty( $payment_value ) || ! is_array( $payment_value ) ) {
@@ -545,16 +562,28 @@
545 562
546 563 if ( ! empty( $payment_response ) && isset( $payment_response['payment_id'] ) ) {
547 564 // Modify the form data with the payment ID.
548 565 $form_data[ $field_name ] = $payment_response['payment_id'];
566 +
567 + $verified_block_ids[ Helper::get_string_value( $block_id ) ] = true;
568 +
569 + $verified_field_names[ $field_name ] = true;
549 570 }
550 571 }
551 572
573 + // Deny-by-default: drop any payment field we did not verify this request,
574 + // so its raw client value cannot later be read back as a payment-record id.
575 + foreach ( $payment_field_names as $payment_field_name ) {
576 + if ( ! isset( $verified_field_names[ $payment_field_name ] ) ) {
577 + $form_data[ $payment_field_name ] = '';
578 + }
579 + }
580 +
552 581 if ( ! empty( $payment_response ) && isset( $payment_response['error'] ) ) {
553 - $form_data = array_merge( $form_data, $payment_response );
582 + return array_merge( $form_data, $payment_response );
554 583 }
555 584
556 - return $form_data;
585 + return $this->require_verified_payments( $form_data, $verified_block_ids );
557 586 }
558 587
559 588 /**
560 589 * Verify Stripe payment
@@ -1130,8 +1159,44 @@
1130 1159 return true;
1131 1160 }
1132 1161
1133 1162 return $default_value;
1163 + }
1164 +
1165 + /**
1166 + * Fail closed when a form's payment field carries no verified payment.
1167 + *
1168 + * SECURITY INVARIANT — the payment requirement must come from the stored form
1169 + * config, never from the submitted payload. Verification driven by what the client
1170 + * sent can only confirm the payments it was given; it cannot know about one that
1171 + * was never presented. Deriving the requirement from the saved form keeps a
1172 + * submission that carries no payment field from being treated as complete.
1173 + *
1174 + * @param array<mixed> $form_data Form data.
1175 + * @param array<string,true> $verified_block_ids Payment block IDs verified on this submission.
1176 + *
1177 + * @since 2.12.3
1178 + * @return array<mixed> Form data, carrying an `error` key when a payment is missing.
1179 + */
1180 + private function require_verified_payments( $form_data, $verified_block_ids ) {
1181 + // absint() to match the normalisation the submit token was verified against.
1182 + $form_id = isset( $form_data['form-id'] ) ? absint( Helper::get_string_value( $form_data['form-id'] ) ) : 0;
1183 +
1184 + if ( 0 === $form_id ) {
1185 + return $form_data;
1186 + }
1187 +
1188 + foreach ( Payment_Helper::get_required_payment_block_ids( $form_id ) as $block_id ) {
1189 + if ( isset( $verified_block_ids[ Helper::get_string_value( $block_id ) ] ) ) {
1190 + continue;
1191 + }
1192 +
1193 + $form_data['error'] = Payment_Helper::get_error_message_by_key( 'payment_required' );
1194 +
1195 + break;
1196 + }
1197 +
1198 + return $form_data;
1134 1199 }
1135 1200
1136 1201 /**
1137 1202 * Verify payment intent status