PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.0
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.0
2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 All 68 releases
← All changes | app/Http/Controllers/AuthController.php +41 -53 2.3.12.4.0 View file →
@@ -56,11 +56,17 @@
56 56 * @param array $formData
57 57 */
58 58 do_action('fluent_support/before_signup_validation', $formData);
59 59
60 - $checkRecaptchaAvailability = $this->isRecaptchaApplicable('signup_form');
61 - if ($checkRecaptchaAvailability && !$formData['_email_verification_hash']) {
62 - $validateCaptcha = ReCaptchaHandler::validateRecaptcha($formData['g-recaptcha-response']);
60 + // the verification code is only submitted on the second step, after the customer has
61 + // already passed the captcha and received the email; that step validates the hash
62 + // against an issued record below, so the captcha can be skipped there. The first
63 + // submit (which sends the verification email) always has to pass the captcha.
64 + $isVerificationStep = !empty($formData['_email_verification_token']);
65 +
66 + $checkRecaptchaAvailability = ReCaptchaHandler::isRecaptchaApplicable('signup_form');
67 + if ($checkRecaptchaAvailability && !$isVerificationStep) {
68 + $validateCaptcha = ReCaptchaHandler::validateRecaptcha($formData['g-recaptcha-response'] ?? '', null, null, 'signup');
63 69 if (!$validateCaptcha) {
64 70 return $this->response([
65 71 'message' => __('Your recaptcha is not verified', 'fluent-support')
66 72 ], 422);
@@ -68,9 +74,9 @@
68 74 }
69 75
70 76 $this->validate($formData, $rules, $messages);
71 77
72 - if (empty($formData['_email_verification_token'])) {
78 + if (!$isVerificationStep) {
73 79 $tokenHtml = EmailVerificationHandler::sendSignupEmailVerificationHtml($formData);
74 80
75 81 return $this->response([
76 82 'verification_html' => $tokenHtml
@@ -76,9 +82,9 @@
76 82 'verification_html' => $tokenHtml
77 83 ]);
78 84 } else {
79 85 $token = $formData['_email_verification_token'];
80 - $verificationHash = $formData['_email_verification_hash'];
86 + $verificationHash = $formData['_email_verification_hash'] ?? '';
81 87
82 88 $logHashMeta = Meta::where('object_type', 'fs_login_hashes',)
83 89 ->where('key', $verificationHash)
84 90 ->first();
@@ -112,10 +118,15 @@
112 118 ], 422);
113 119 }
114 120
115 121 // check if it got expired or not
122 + // valid_till is written via gmdate() on a current_time('timestamp') basis (always
123 + // UTC-equivalent, since WP resets the runtime timezone to UTC on every request), so
124 + // it must be parsed back as UTC here - otherwise strtotime() would silently reinterpret
125 + // it under whatever timezone a plugin/theme may have switched to via
126 + // date_default_timezone_set() without restoring it, causing false expiry (or non-expiry)
116 127 $validTill = $logHash['valid_till'] ?? '';
117 - if (($logHash['used_count'] ?? 0) > 5 || ($validTill && strtotime($validTill) < current_time('timestamp'))) {
128 + if (($logHash['used_count'] ?? 0) > 5 || ($validTill && strtotime($validTill . ' UTC') < current_time('timestamp'))) {
118 129 wp_send_json([
119 130 'message' => __('Your verification code has been expired. Please try again', 'fluent-support')
120 131 ], 422);
121 132 }
@@ -221,11 +232,11 @@
221 232 }
222 233
223 234 $data = $request->all();
224 235
225 - $checkRecaptchaAvailability = $this->isRecaptchaApplicable('login_form');
236 + $checkRecaptchaAvailability = ReCaptchaHandler::isRecaptchaApplicable('login_form');
226 237 if ($checkRecaptchaAvailability) {
227 - $validateCaptcha = ReCaptchaHandler::validateRecaptcha($data['g-recaptcha-response']);
238 + $validateCaptcha = ReCaptchaHandler::validateRecaptcha($data['g-recaptcha-response'] ?? '', null, null, 'login');
228 239
229 240 if (!$validateCaptcha) {
230 241 return $this->response([
231 242 'message' => __('Your recaptcha is not verified', 'fluent-support')
@@ -349,26 +360,8 @@
349 360 set_transient($rateLimitKey, $attempts + 1, 15 * MINUTE_IN_SECONDS);
350 361 }
351 362 }
352 363
353 - public function isRecaptchaApplicable($formName)
354 - {
355 - $reCaptchaSettingsData = Meta::where('object_type', '_fs_recaptcha_settings')->first();
356 - if(!isset($reCaptchaSettingsData->value)){
357 - return false;
358 - }
359 - $reCaptchaData = Helper::safeUnserialize($reCaptchaSettingsData->value, []);
360 - if(!isset($reCaptchaData['is_enabled']) || !isset($reCaptchaData['formContainingReCaptcha'])){
361 - return false;
362 - }
363 - $isEnabled = filter_var($reCaptchaData['is_enabled'], FILTER_VALIDATE_BOOLEAN);
364 - if (!$isEnabled) {
365 - return false;
366 - }
367 - $formContainingReCaptcha = $reCaptchaData['formContainingReCaptcha'];
368 - return 'yes' === $formContainingReCaptcha[$formName];
369 - }
370 -
371 364 private function nativeLoginHandler($user, $info, $redirectUrl = '')
372 365 {
373 366 if (!$redirectUrl) {
374 367 $redirectUrl = Helper::getPortalBaseUrl();
@@ -507,11 +500,9 @@
507 500 $user_data = get_user_by('login', $usernameOrEmail);
508 501 }
509 502
510 503 if (!$user_data) {
511 - return $this->sendError([
512 - 'message' => __('Invalid username or email', 'fluent-support')
513 - ]);
504 + return $this->sendResetPassResponse();
514 505 }
515 506
516 507 $user_data = apply_filters('lostpassword_user_data', $user_data, $errors);
517 508
@@ -519,24 +510,17 @@
519 510
520 511 $errors = apply_filters('lostpassword_errors', $errors, $user_data);
521 512
522 513 if ($errors->has_errors()) {
523 - return $this->sendError([
524 - 'message' => $errors->get_error_message()
525 - ]);
514 + return $this->sendResetPassResponse();
526 515 }
527 516
528 517 if (!$user_data) {
529 - return $this->sendError([
530 - 'message' => __('There is no account with that username or email address.', 'fluent-support')
531 - ]);
518 + return $this->sendResetPassResponse();
532 519 }
533 520
534 521 if (is_multisite() && !is_user_member_of_blog($user_data->ID, get_current_blog_id())) {
535 -
536 - return $this->sendError([
537 - 'message' => __('Invalid username or email', 'fluent-support')
538 - ]);
522 + return $this->sendResetPassResponse();
539 523 }
540 524
541 525 // Redefining user_login ensures we return the right case in the email.
542 526 $user_login = $user_data->user_login;
@@ -544,21 +528,13 @@
544 528 do_action('retrieve_password', $user_login);
545 529
546 530 $allow = apply_filters('allow_password_reset', true, $user_data->ID);
547 531
548 - if (!$allow) {
549 - return $this->sendError([
550 - 'message' => __('Password reset is not allowed for this user', 'fluent-support')
551 - ]);
532 + if (!$allow || is_wp_error($allow)) {
533 + return $this->sendResetPassResponse();
552 534 }
553 535
554 - if (is_wp_error($allow)) {
555 - return $this->sendError([
556 - 'message' => $allow->get_error_message()
557 - ]);
558 - }
559 536
560 -
561 537 /*
562 538 * Filter reset password link text
563 539 *
564 540 * @since v1.5.7
@@ -574,11 +550,9 @@
574 550 // first send has already put a working link in that inbox.
575 551 $cooldownKey = 'fs_reset_pass_sent_' . wp_hash($user_data->ID);
576 552
577 553 if (get_transient($cooldownKey)) {
578 - return $this->sendError([
579 - 'message' => __('A password reset link was already sent to this account recently. Please check your email, including the spam folder, or try again in a few minutes.', 'fluent-support')
580 - ], 429);
554 + return $this->sendResetPassResponse();
581 555 }
582 556
583 557 set_transient($cooldownKey, 1, 5 * MINUTE_IN_SECONDS);
584 558
@@ -620,10 +594,24 @@
620 594 $headers = array('Content-Type: text/html; charset=UTF-8');
621 595
622 596 wp_mail($user_data->user_email, $mailSubject, $message, $headers);
623 597
598 + return $this->sendResetPassResponse();
599 + }
600 +
601 + /**
602 + * Single response for every password reset outcome.
603 + *
604 + * Whether the account exists, is disallowed, is not a member of this site or is
605 + * inside the resend cooldown, the caller sees the same thing — otherwise the form
606 + * confirms which usernames and email addresses are real.
607 + *
608 + * @return mixed
609 + */
610 + protected function sendResetPassResponse()
611 + {
624 612 return $this->sendSuccess([
625 - 'message' => __('Please check your email for the reset link', 'fluent-support')
613 + 'message' => __('If an account matches that username or email, a password reset link has been sent. Please check your inbox, including the spam folder.', 'fluent-support')
626 614 ]);
627 615 }
628 616
629 617 /**