PluginProbe
Yatra – Travel Booking & Tour Operator Software / trunk
Yatra – Travel Booking & Tour Operator Software vtrunk
3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 2.0.10 2.0.11 All 82 releases
← All changes | app/Controllers/AuthController.php +96 -11 3.0.3trunk View file →
@@ -293,8 +293,21 @@
293 293 'message' => __('New customer registration is disabled.', 'yatra'),
294 294 ], 403);
295 295 }
296 296
297 + // reCAPTCHA v3 (no-op unless the registration form is protected in settings).
298 + $recaptcha = \Yatra\Services\RecaptchaService::verifyForm(
299 + 'registration',
300 + (string) ($request->get_param('recaptcha_token') ?? ''),
301 + $_SERVER['REMOTE_ADDR'] ?? null
302 + );
303 + if (empty($recaptcha['success'])) {
304 + return new \WP_REST_Response([
305 + 'success' => false,
306 + 'message' => $recaptcha['message'] ?? __('reCAPTCHA verification failed.', 'yatra'),
307 + ], 400);
308 + }
309 +
297 310 $first_name = sanitize_text_field($request->get_param('first_name') ?? '');
298 311 $last_name = sanitize_text_field($request->get_param('last_name') ?? '');
299 312 $email = sanitize_email($request->get_param('email') ?? '');
300 313 $phone = sanitize_text_field($request->get_param('phone') ?? '');
@@ -529,27 +542,38 @@
529 542 }
530 543
531 544 $stored_token = get_user_meta($user_id, 'yatra_verification_token', true);
532 545 $token_expiry = get_user_meta($user_id, 'yatra_verification_token_expiry', true);
533 -
546 +
547 + // Idempotent path: the token+expiry are deleted as soon as a successful
548 + // verification completes (see below), so a second click on the same
549 + // link previously fell into the "Invalid or expired" branch and made
550 + // already-verified customers believe their account was broken. Detect
551 + // the prior-success state explicitly and reuse the success page so the
552 + // outcome is clear regardless of how many times the link is clicked.
553 + $already_verified = get_user_meta($user_id, 'yatra_email_verified', true) === '1';
554 + if ($already_verified) {
555 + self::showVerificationSuccess(true);
556 + return;
557 + }
558 +
534 559 if (empty($stored_token) || $stored_token !== $token) {
535 560 self::showVerificationError(__('Invalid or expired verification link.', 'yatra'));
536 561 return;
537 562 }
538 -
563 +
539 564 if ($token_expiry && time() > (int) $token_expiry) {
540 565 self::showVerificationError(__('This verification link has expired. Please register again.', 'yatra'));
541 566 return;
542 567 }
543 -
568 +
544 569 // Mark as verified
545 570 update_user_meta($user_id, 'yatra_email_verified', '1');
546 571 delete_user_meta($user_id, 'yatra_verification_token');
547 572 delete_user_meta($user_id, 'yatra_verification_token_expiry');
548 -
549 - $redirect_url = add_query_arg(['email_verified' => '1'], yatra_get_checkout_url());
550 - wp_safe_redirect($redirect_url);
551 - exit;
573 +
574 + self::showVerificationSuccess(false);
575 + return;
552 576 }
553 577
554 578 /**
555 579 * Send verification email
@@ -578,9 +602,9 @@
578 602 : __('If you did not create this account, you can ignore this email.', 'yatra');
579 603
580 604 $expiryNoticeHtml = esc_html(
581 605 sprintf(
582 - /* translators: %d: hours until expiry */
606 + /* translators: %d: hours until link expiry */
583 607 __('This verification link expires in %d hours for your security.', 'yatra'),
584 608 24
585 609 )
586 610 );
@@ -590,8 +614,9 @@
590 614 $email,
591 615 [
592 616 'customer_first_name' => $first_name,
593 617 'customer_name' => $first_name,
618 + 'customer_email' => $email,
594 619 'verification_link' => $verificationUrl,
595 620 'intro_paragraph' => $introParagraph,
596 621 'footer_note' => $footerNote,
597 622 'expiry_notice_html' => $expiryNoticeHtml,
@@ -599,21 +624,81 @@
599 624 );
600 625 }
601 626
602 627 /**
603 - * Show verification error page
628 + * Show verification error page (hard-fail dead-end with a route back home).
629 + * Every string is translatable — operators run Yatra in many locales and
630 + * the pre-3.0.5 hardcoded "Verification Failed" heading was untranslatable.
604 631 */
605 632 private static function showVerificationError(string $message): void
606 633 {
634 + $heading = esc_html__('Verification Failed', 'yatra');
635 + $cta = esc_html__('Go to Homepage', 'yatra');
636 +
607 637 wp_die(
608 638 '<div style="text-align: center; padding: 50px; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;">
609 - <h1 style="color: #dc2626; margin-bottom: 20px;">Verification Failed</h1>
639 + <h1 style="color: #dc2626; margin-bottom: 20px;">' . $heading . '</h1>
610 640 <p style="color: #4b5563; font-size: 16px; margin-bottom: 30px;">' . esc_html($message) . '</p>
611 - <a href="' . esc_url(home_url()) . '" style="display: inline-block; background: #3b82f6; color: #fff; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600;">Go to Homepage</a>
641 + <a href="' . esc_url(home_url()) . '" style="display: inline-block; background: #3b82f6; color: #fff; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600;">' . $cta . '</a>
612 642 </div>',
613 643 __('Verification Failed', 'yatra'),
614 644 ['response' => 400]
615 645 );
646 + }
647 +
648 + /**
649 + * Render an unambiguous "email verified" confirmation page.
650 + *
651 + * The pre-3.0.5 flow silently 302-redirected to the checkout URL with a
652 + * `?email_verified=1` flag, relying on `booking-auth.php` to surface a
653 + * one-liner notice. That notice only renders when the auth form itself
654 + * renders (no booking session / logged-in user → notice never shown), so
655 + * customers regularly saw "nothing happened" after clicking the link.
656 + *
657 + * Now we render a dedicated success page with explicit confirmation, the
658 + * verified email-state, and a primary CTA back into the booking flow.
659 + * Idempotent: a second click on the same link reaches `$already=true`
660 + * and shows "Your email is already verified" instead of the misleading
661 + * "Invalid or expired link" error.
662 + *
663 + * @param bool $already True when the user has already been verified by an
664 + * earlier click on the same link (idempotent path).
665 + */
666 + private static function showVerificationSuccess(bool $already): void
667 + {
668 + $checkoutUrl = function_exists('yatra_get_checkout_url')
669 + ? yatra_get_checkout_url()
670 + : home_url('/');
671 + $continueUrl = add_query_arg(['email_verified' => '1'], $checkoutUrl);
672 +
673 + $heading = $already
674 + ? esc_html__('Email Already Verified', 'yatra')
675 + : esc_html__('Email Verified', 'yatra');
676 + $message = $already
677 + ? esc_html__('Your email address is already verified — no further action is needed. You can continue with your booking.', 'yatra')
678 + : esc_html__('Your email address has been verified successfully. You can now log in and continue with your booking.', 'yatra');
679 + $cta = esc_html__('Continue to Checkout', 'yatra');
680 + $homeCta = esc_html__('Go to Homepage', 'yatra');
681 + $title = $already
682 + ? __('Email Already Verified', 'yatra')
683 + : __('Email Verified', 'yatra');
684 +
685 + // Inline-only styling so the page renders correctly regardless of
686 + // theme stylesheet load order (wp_die() can fire before themes
687 + // enqueue their styles).
688 + $body = '<div style="text-align: center; padding: 50px 20px; max-width: 520px; margin: 0 auto; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;">'
689 + . '<div style="display: inline-flex; align-items: center; justify-content: center; width: 72px; height: 72px; border-radius: 50%; background: #d1fae5; margin: 0 auto 24px;">'
690 + . '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">'
691 + . '<polyline points="20 6 9 17 4 12"></polyline>'
692 + . '</svg>'
693 + . '</div>'
694 + . '<h1 style="color: #065f46; margin: 0 0 12px; font-size: 26px;">' . $heading . '</h1>'
695 + . '<p style="color: #4b5563; font-size: 16px; line-height: 1.6; margin: 0 0 28px;">' . $message . '</p>'
696 + . '<a href="' . esc_url($continueUrl) . '" style="display: inline-block; background: #059669; color: #fff; padding: 12px 28px; border-radius: 8px; text-decoration: none; font-weight: 600; margin-right: 8px;">' . $cta . '</a>'
697 + . '<a href="' . esc_url(home_url()) . '" style="display: inline-block; color: #4b5563; padding: 12px 16px; text-decoration: none; font-weight: 500;">' . $homeCta . '</a>'
698 + . '</div>';
699 +
700 + wp_die($body, $title, ['response' => 200]);
616 701 }
617 702
618 703 /**
619 704 * Inform users that the link is only for email template previews.