PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 1.10.4
Fluent Support – Helpdesk & Customer Support Ticket System v1.10.4
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
fluent-support / app / Http / Controllers / AuthController.php

AuthController.php in Fluent Support – Helpdesk & Customer Support Ticket System 1.10.4, at app/Http/Controllers/AuthController.php

712 lines 23.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentSupport\App\Http\Controllers;
4
5 use FluentSupport\App\Models\Meta;
6 use FluentSupport\App\Services\Helper;
7 use FluentSupport\Framework\Support\Arr;
8 use FluentSupport\Framework\Request\Request;
9 use FluentSupport\App\Hooks\Handlers\AuthHandler;
10 use FluentSupport\App\Hooks\Handlers\ReCaptchaHandler;
11 use FluentSupport\App\Hooks\Handlers\TwoFaHandler;
12 use FluentSupport\App\Hooks\Handlers\EmailVerificationHandler;
13
14
15 class AuthController extends Controller
16 {
17 /**
18 * signUp method will create new user submitted data from sign up form
19 * @param Request $request
20 * @return \WP_REST_Response
21 * @throws \FluentSupport\Framework\Validator\ValidationException
22 */
23 public function signup(Request $request)
24 {
25
26 if(Helper::getAuthProvider() != 'fluent_support') {
27 return $this->sendError([
28 'message' => __('You are not allowed to signup using this form', 'fluent-support')
29 ]);
30 }
31
32 if (!wp_verify_nonce($request->get('_fsupport_signup_nonce'), 'fluent_support_signup_nonce')) {
33 return $this->sendError([
34 'message' => __('Security verification failed. Please try again', 'fluent-support')
35 ]);
36 }
37
38 $fields = AuthHandler::getSignupFields();
39
40 $rules = $this->getRules($fields);
41
42 $messages = $this->getMessages($rules);
43
44 /*
45 * Filter user signup form data
46 *
47 * @since v1.0.0
48 * @param array $formData
49 */
50 $formData = apply_filters('fluent_support/signup_form_data', $request->all());
51
52 /*
53 * Action before validate user signup
54 *
55 * @since v1.0.0
56 * @param array $formData
57 */
58 do_action('fluent_support/before_signup_validation', $formData);
59
60 $checkRecaptchaAvailability = $this->isRecaptchaApplicable('signup_form');
61 if ($checkRecaptchaAvailability && !$formData['_email_verification_hash']) {
62 $validateCaptcha = ReCaptchaHandler::validateRecaptcha($formData['g-recaptcha-response']);
63 if (!$validateCaptcha) {
64 return $this->response([
65 'message' => __('Your recaptcha is not verified', 'fluent-support')
66 ], 422);
67 }
68 }
69
70 $this->validate($formData, $rules, $messages);
71
72 if (empty($formData['_email_verification_token'])) {
73 $tokenHtml = EmailVerificationHandler::sendSignupEmailVerificationHtml($formData);
74
75 return $this->response([
76 'verification_html' => $tokenHtml
77 ]);
78 } else {
79 $token = $formData['_email_verification_token'];
80 $verificationHash = $formData['_email_verification_hash'];
81
82 $logHash = Meta::where('object_type', 'fs_login_hashes',)
83 ->where('key', $verificationHash)
84 ->first();
85 $logHash = Helper::safeUnserialize($logHash->value);
86
87 if (!$logHash) {
88 wp_send_json([
89 'message' => __('Please provide a valid verification code that sent to your email address', 'fluent-support')
90 ], 422);
91 }
92
93 // check if it got expired or not
94 if ($logHash['used_count'] > 5 || strtotime($logHash['valid_till']) < current_time('timestamp')) {
95 wp_send_json([
96 'message' => __('Your verification code has been expired. Please try again', 'fluent-support')
97 ], 422);
98 }
99
100 if (!wp_check_password($token, $logHash['two_fa_code_hash'])) {
101
102 $logHash['used_count'] += 1;
103 Meta::where('key', $logHash['login_hash'])->update([
104 'value' => maybe_serialize($logHash)
105 ]);
106
107 wp_send_json([
108 'message' => __('Please provide a valid verification code that sent to your email address', 'fluent-support')
109 ], 422);
110 }
111
112 $logHash['used_count'] += 1;
113 $logHash['status'] = 'used';
114
115 Meta::where('key', $logHash['login_hash'])->update([
116 'value' => maybe_serialize($logHash)
117 ]);
118 }
119
120 /*
121 * Action After validate user signup validation success
122 *
123 * @since v1.0.0
124 * @param array $formData
125 */
126 do_action('fluent_support/after_signup_validation', $formData);
127
128 $userId = $this->createUser($formData);
129
130 if (is_wp_error($userId)) {
131 return $this->response(
132 apply_filters(
133 'fluent_support/signup_create_user_error',
134 ['error' => $userId->get_error_message()]
135 ), 423);
136 }
137
138 /*
139 * Action After creating WP user from ticket sign up form
140 *
141 * @since v1.0.0
142 * @param array $formData
143 */
144 do_action('fluent_support/after_creating_user');
145
146 $this->maybeUpdateUser($userId, $formData);
147 $this->addUserMetaData($userId, $formData);
148 $this->assignRole($userId);
149 $this->login($userId);
150
151 /*
152 * Filter for user signup complete message and redirect
153 *
154 * @since v1.0.0
155 * @param array $response
156 */
157 $response = apply_filters('fluent_support/signup_complete_response', [
158 'message' => __('Successfully registered to the site.', 'fluent-support'),
159 'redirect' => Arr::get($formData, '__redirect_to', Helper::getPortalBaseUrl())
160 ]);
161
162 return $this->response($response);
163 }
164
165 /**
166 * handleLogin method will perform login functionality and redirect
167 * @param Request $request
168 * @return \WP_REST_Response
169 */
170 public function handleLogin(Request $request)
171 {
172 if(Helper::getAuthProvider() != 'fluent_support') {
173 return $this->sendError([
174 'message' => __('You are not allowed to login using this form', 'fluent-support')
175 ]);
176 }
177
178 if (!wp_verify_nonce($request->get('_support_login_nonce'), 'fsupport_login_nonce')) {
179 return $this->response([
180 'message' => __('Security verification failed', 'fluent-support')
181 ], 403);
182 }
183
184 $data = $request->all();
185
186 $checkRecaptchaAvailability = $this->isRecaptchaApplicable('login_form');
187 if ($checkRecaptchaAvailability) {
188 $validateCaptcha = ReCaptchaHandler::validateRecaptcha($data['g-recaptcha-response']);
189
190 if (!$validateCaptcha) {
191 return $this->response([
192 'message' => __('Your recaptcha is not verified', 'fluent-support')
193 ], 422);
194 }
195 }
196
197 if (empty($data['pwd']) || empty($data['log'])) {
198 return $this->response([
199 'message' => __('Email and Password is required', 'fluent-support')
200 ], 403);
201 }
202 $redirectUrl = Helper::getPortalBaseUrl();
203 if ($redirect = $request->get('redirect_to')) {
204 if (filter_var($redirect, FILTER_VALIDATE_URL)) {
205 $redirectUrl = sanitize_url($redirect);
206 }
207 }
208
209 if (get_current_user_id()) { // user already registered
210 return $this->sendSuccess([
211 'redirect' => $redirectUrl
212 ]);
213 }
214
215 $email = sanitize_user($data['log']);
216 $password = trim($data['pwd']);
217
218 if (is_email($email)) {
219 $user = get_user_by('email', $email);
220 } else {
221 $user = get_user_by('login', $email);
222 }
223
224 if (!$user) {
225 $user = new \WP_Error('authentication_failed', __('<strong>Error</strong>: Invalid username, email address or incorrect password.', 'fluent-support'));
226
227 do_action('wp_login_failed', $email, $user);
228
229 return $this->response([
230 'message' => __('Email or Password is not valid. Please try again', 'fluent-support')
231 ], 403);
232
233 }
234
235 $twoFactorEnabled = Helper::getBusinessSettings('enable_two_fa');
236 if ('yes' == $twoFactorEnabled) {
237 (new TwoFaHandler)->maybe2FaRedirect($user);
238 }
239
240 if (apply_filters('fluent_support_use_native_login', true)) {
241 $user = wp_signon();
242 if (is_wp_error($user)) {
243 return $this->response([
244 'message' => $user->get_error_message()
245 ], 403);
246 }
247
248 return $this->sendSuccess([
249 'redirect' => $redirectUrl
250 ]);
251 }
252
253 if (wp_check_password($password, $user->user_pass, $user->ID)) {
254 $this->login($user->ID);
255 return $this->sendSuccess([
256 'redirect' => $redirectUrl
257 ]);
258 }
259
260 return $this->response([
261 'message' => __('<strong>Error</strong>: Invalid username, email address or incorrect password.', 'fluent-support')
262 ], 403);
263 }
264
265 public function isRecaptchaApplicable($formName)
266 {
267 $reCaptchaSettingsData = Meta::where('object_type', '_fs_recaptcha_settings')->first();
268 if(!isset($reCaptchaSettingsData->value)){
269 return false;
270 }
271 $reCaptchaData = Helper::safeUnserialize($reCaptchaSettingsData->value, []);
272 if(!isset($reCaptchaData['is_enabled']) || !isset($reCaptchaData['formContainingReCaptcha'])){
273 return false;
274 }
275 $isEnabled = filter_var($reCaptchaData['is_enabled'], FILTER_VALIDATE_BOOLEAN);
276 if (!$isEnabled) {
277 return false;
278 }
279 $formContainingReCaptcha = $reCaptchaData['formContainingReCaptcha'];
280 return 'yes' === $formContainingReCaptcha[$formName];
281 }
282
283 private function nativeLoginHandler($user, $info, $redirectUrl = '')
284 {
285 if (!$redirectUrl) {
286 $redirectUrl = Helper::getPortalBaseUrl();
287 }
288
289 $secure_cookie = is_ssl();
290 if (!$secure_cookie && !force_ssl_admin()) {
291 if (get_user_option('use_ssl', $user->ID)) {
292 $secure_cookie = true;
293 force_ssl_admin(true);
294 }
295 }
296
297 if (class_exists('\Limit_Login_Attempts')) {
298 global $limit_login_attempts_obj;
299 $limit_login_attempts_try = $limit_login_attempts_obj->wp_authenticate_user($user, false);
300 if (is_wp_error($limit_login_attempts_try)) {
301 return $this->response([
302 'message' => implode('<br/>', $limit_login_attempts_try->get_error_messages())
303 ], 403);
304 }
305 }
306
307 $user_signon = wp_signon($info, $secure_cookie);
308
309 // Note: No sanitization needed here as we're only checking emptiness, not using the cookie value
310 if (!is_wp_error($user_signon) && empty($_COOKIE[LOGGED_IN_COOKIE])) {
311 if (headers_sent()) {
312 return $this->response([
313 // translators: %1$s is the URL to WordPress cookies documentation, %2$s is the URL to WordPress support forums
314 'message' => sprintf(__('<strong>ERROR</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.', 'fluent-support'),
315 'https://codex.wordpress.org/Cookies', 'https://wordpress.org/support/')
316 ], 403);
317 }
318 }
319
320 if (is_wp_error($user_signon)) {
321 $errorMessage = __('Email or Password is not valid. Please try again', 'fluent-support');
322
323 if (class_exists('Limit_Login_Attempts')) {
324 global $limit_login_attempts_obj;
325 if ($limit_login_attempts_obj) {
326 $limit_login_attempts_obj->limit_login_failed($user->user_login);
327 $msg = $limit_login_attempts_obj->get_message();
328 if ($msg) {
329 $errorMessage = $msg;
330 }
331 }
332 }
333
334 return $this->response([
335 'message' => $errorMessage
336 ], 403);
337 }
338
339 // WP Last Login plugin compatibility
340 if (class_exists('\Obenland_Wp_Last_Login')) {
341 update_user_meta($user_signon->ID, 'wp-last-login', time());
342 }
343
344 return $this->sendSuccess([
345 'redirect' => $redirectUrl
346 ]);
347 }
348
349 /**
350 * getRules method will prepare the rules for the input field
351 * @param array $fields
352 * @return mixed
353 */
354 protected function getRules($fields = [])
355 {
356 $rules = [];
357
358 foreach ($fields as $fieldName => $field) {
359 if (array_key_exists('required', $field)) {
360 $rules[$fieldName] = 'required';
361 }
362
363 $pipe = array_key_exists($fieldName, $rules) ? '|' : '';
364
365 if ($field['type'] === 'email') {
366 $rules[$fieldName] = $rules[$fieldName] . $pipe . 'email';
367 } elseif ($field['type'] === 'password') {
368 $rules[$fieldName] = $rules[$fieldName] . $pipe . 'min:8';
369 }
370 }
371 /*
372 * Filter user signup validation rules
373 *
374 * @since v1.0.0
375 * @param array $rules
376 */
377 return apply_filters('fluent_support/signup_validation_rules', $rules);
378 }
379
380
381 public function resetPassword(Request $request)
382 {
383
384 if(Helper::getAuthProvider() != 'fluent_support') {
385 return $this->sendError([
386 'message' => __('You are not allowed to reset password using this form', 'fluent-support')
387 ]);
388 }
389
390 $errors = new \WP_Error();
391
392 if (!wp_verify_nonce($request->get('_fsupport_reset_pass_nonce'), 'fluent_support_reset_pass_nonce')) {
393 return $this->sendError([
394 'message' => __('Security verification failed. Please try again', 'fluent-support')
395 ]);
396 }
397
398 $usernameOrEmail = trim(wp_unslash($request->get('user_login')));
399
400 if (!$usernameOrEmail) {
401 return $this->sendError([
402 'message' => 'Username or email is required'
403 ]);
404 }
405
406 $user_data = get_user_by('email', $usernameOrEmail);
407
408 if (!$user_data) {
409 $user_data = get_user_by('login', $usernameOrEmail);
410 }
411
412 if (!$user_data) {
413 return $this->sendError([
414 'message' => __('Invalid username or email', 'fluent-support')
415 ]);
416 }
417
418 $user_data = apply_filters('lostpassword_user_data', $user_data, $errors);
419
420 do_action('lostpassword_post', $errors, $user_data);
421
422 $errors = apply_filters('lostpassword_errors', $errors, $user_data);
423
424 if ($errors->has_errors()) {
425 return $this->sendError([
426 'message' => $errors->get_error_message()
427 ]);
428 }
429
430 if (!$user_data) {
431 return $this->sendError([
432 'message' => __('<strong>Error</strong>: There is no account with that username or email address.', 'fluent-support')
433 ]);
434 }
435
436 if (is_multisite() && !is_user_member_of_blog($user_data->ID, get_current_blog_id())) {
437
438 return $this->sendError([
439 'message' => __('<strong>Error</strong>: Invalid username or email', 'fluent-support')
440 ]);
441 }
442
443 // Redefining user_login ensures we return the right case in the email.
444 $user_login = $user_data->user_login;
445
446 do_action('retrieve_password', $user_login);
447
448 $allow = apply_filters('allow_password_reset', true, $user_data->ID);
449
450 if (!$allow) {
451 return $this->sendError([
452 'message' => __('Password reset is not allowed for this user', 'fluent-support')
453 ]);
454 }
455
456 if (is_wp_error($allow)) {
457 return $this->sendError([
458 'message' => $allow->get_error_message()
459 ]);
460 }
461
462
463 /*
464 * Filter reset password link text
465 *
466 * @since v1.5.7
467 * @param string $linkText
468 */
469 // translators: %s is the site name
470 $linkText = apply_filters("fluent_support/reset_password_link", sprintf(__('Reset your password for %s', 'fluent-support'), get_bloginfo('name')));
471
472 $resetUrl = add_query_arg([
473 'action' => 'rp',
474 'key' => get_password_reset_key($user_data),
475 'login' => rawurlencode($user_data->user_login)
476 ], wp_login_url());
477
478 $resetLink = '<a href="' . $resetUrl . '">' . $linkText . '</a>';
479
480 /*
481 * Filter reset password email subject
482 *
483 * @since v1.5.7
484 * @param string $mailSubject
485 */
486 // translators: %s is the site name
487 $mailSubject = apply_filters("fluent_support/reset_password_mail_subject", sprintf(__('Reset your password for %s support portal', 'fluent-support'), get_bloginfo('name')));
488
489 // translators: %s is the user's first name
490 $message = '<p>' . sprintf(__('Hi %s,', 'fluent-support'), $user_data->first_name) . '</p>' .
491 '<p>' . __('Someone has requested a new password for the following account on WordPress:', 'fluent-support') . '</p>' .
492 // translators: %s is the username
493 '<p>' . sprintf(__('Username: %s', 'fluent-support'), $user_login) . '</p>' .
494 '<p>' . $resetLink . '</p>' .
495 '<p>' . __('If you did not request to reset your password, please ignore this email.', 'fluent-support') . '</p>';
496
497 /*
498 * Filter reset password email body text
499 *
500 * @since v1.5.7
501 * @param string $message
502 * @param object $user
503 * @param string $resetLink
504 */
505 $message = apply_filters('fluent_support/reset_password_message', $message, $user_data, $resetLink);
506
507 $headers = array('Content-Type: text/html; charset=UTF-8');
508
509 wp_mail($user_data->user_email, $mailSubject, $message, $headers);
510
511 return $this->sendSuccess([
512 'message' => __('Please check your email for the reset link', 'fluent-support')
513 ]);
514 }
515
516 /**
517 * getMessages message will return the validation message regarding sign up or sign in
518 * @param array $rules
519 * @return mixed
520 */
521 protected function getMessages($rules = [])
522 {
523 /*
524 * Filter user signup validation message
525 *
526 * @since v1.0.0
527 * @param array $arg
528 * @param array $rules
529 */
530 return apply_filters('fluent_support/signup_validation_messages', [], $rules);
531 }
532
533 /**
534 * createUser method will create new user
535 * @param array $formData
536 * @return mixed
537 */
538 public function createUser($formData = [])
539 {
540 /*
541 * Filter user signup email
542 *
543 * @since v1.0.0
544 * @param string $email
545 */
546 $email = apply_filters('fluent_support/signup_email', Arr::get($formData, 'email'));
547
548 /*
549 * Filter user signup username
550 *
551 * @since v1.0.0
552 * @param string $username
553 */
554 $userName = apply_filters('fluent_support/signup_username', Arr::get($formData, 'username'));
555
556 if (empty($formData['password'])) {
557 $password = wp_generate_password(8);
558 } else {
559 $password = $formData['password'];
560 }
561
562 /*
563 * Filter user signup password
564 *
565 * @since v1.0.0
566 * @param string $password
567 */
568 $password = apply_filters('fluent_support/signup_password', $password);
569
570 /*
571 * Action before creating WP user using Fluent Support signup form
572 *
573 * @since v1.0.0
574 * @param string $userName
575 * @param string $password
576 * @param string $email
577 */
578 do_action('fluent_support/before_creating_user', $userName, $password, $email);
579
580 $userId = wp_create_user($userName, $password, $email);
581
582 if (is_wp_error($userId)) {
583 return false;
584 }
585
586 return $userId;
587
588 }
589
590 /**
591 * maybeUpdateUser method will update user information if exists
592 * @param $userId
593 * @param $formData
594 */
595 public function maybeUpdateUser($userId, $formData)
596 {
597 $name = trim(Arr::get($formData, 'first_name') . ' ' . Arr::get($formData, 'last_name'));
598
599 $data = array_filter([
600 'ID' => $userId,
601 'user_nicename' => $name,
602 'display_name' => $name,
603 'first_name' => Arr::get($formData, 'first_name'),
604 'last_name' => Arr::get($formData, 'last_name'),
605 ]);
606
607 if ($name) {
608 /*
609 * Action before updating a customer/user
610 *
611 * @since v1.0.0
612 * @param array $data
613 */
614 do_action('fluent_support/before_updating_user', $data);
615
616 /*
617 * Filter user updatable data
618 *
619 * @since v1.0.0
620 * @param $data
621 */
622 $updateUserData = apply_filters('fluent_support/update_user_data', $data);
623 wp_update_user($updateUserData);
624
625 /*
626 * Action after updating a customer/user
627 *
628 * @since v1.0.0
629 * @param array $data
630 */
631 do_action('fluent_support/after_updating_user', $data);
632 }
633 }
634
635 public function addUserMetaData($userId, $formData) {
636 $customFieldsKey = apply_filters('fluent_support/custom_registration_form_fields_key', Helper::getBusinessSettings('custom_registration_form_field'));
637
638 if (empty($customFieldsKey)) {
639 return;
640 }
641
642 foreach ($customFieldsKey as $key) {
643 if (isset($formData[$key])) {
644 $fieldValue = $formData[$key];
645 update_user_meta($userId, $key, $fieldValue);
646 }
647 }
648 }
649
650 /**
651 * assignRole method will assign role to a given user id
652 * @param $userId
653 */
654 protected function assignRole($userId)
655 {
656 $user = new \WP_User($userId);
657
658 /*
659 * Action before assigning role to registered user
660 *
661 * @since v1.0.0
662 * @param array $data
663 */
664 do_action('fluent_support/before_assigning_role', $user);
665 /*
666 * Filter user assignable role after signup
667 *
668 * @since v1.0.0
669 * @param string $setRole WordPress user role key
670 */
671 $setRole = apply_filters('fluent_support/user_role', 'subscriber');
672 $user->set_role($setRole);
673
674 /*
675 * Action after assigning role to registered user
676 *
677 * @since v1.0.0
678 * @param array $data
679 */
680 do_action('fluent_support/after_assigning_role', $user);
681 }
682
683
684 /**
685 * login method will clear existing cookies and set new cookie for a given user id
686 * @param $userId
687 */
688 protected function login($userId)
689 {
690 /*
691 * Action before login
692 *
693 * @since v1.0.0
694 * @param integer $userId
695 */
696 do_action('fluent_support/before_logging_in_user', $userId);
697
698 wp_clear_auth_cookie();
699 wp_set_current_user($userId);
700 wp_set_auth_cookie($userId);
701
702 /*
703 * Action after login
704 *
705 * @since v1.0.0
706 * @param integer $userId
707 */
708 do_action('fluent_support/after_logging_in_user', $userId);
709 }
710
711 }
712