PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 1.10.1
Fluent Support – Helpdesk & Customer Support Ticket System v1.10.1
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.1, at app/Http/Controllers/AuthController.php

706 lines 22.8 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 if (!is_wp_error($user_signon) && empty($_COOKIE[LOGGED_IN_COOKIE])) {
310 if (headers_sent()) {
311 return $this->response([
312 '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'),
313 'https://codex.wordpress.org/Cookies', 'https://wordpress.org/support/')
314 ], 403);
315 }
316 }
317
318 if (is_wp_error($user_signon)) {
319 $errorMessage = __('Email or Password is not valid. Please try again', 'fluent-support');
320
321 if (class_exists('Limit_Login_Attempts')) {
322 global $limit_login_attempts_obj;
323 if ($limit_login_attempts_obj) {
324 $limit_login_attempts_obj->limit_login_failed($user->user_login);
325 $msg = $limit_login_attempts_obj->get_message();
326 if ($msg) {
327 $errorMessage = $msg;
328 }
329 }
330 }
331
332 return $this->response([
333 'message' => $errorMessage
334 ], 403);
335 }
336
337 // WP Last Login plugin compatibility
338 if (class_exists('\Obenland_Wp_Last_Login')) {
339 update_user_meta($user_signon->ID, 'wp-last-login', time());
340 }
341
342 return $this->sendSuccess([
343 'redirect' => $redirectUrl
344 ]);
345 }
346
347 /**
348 * getRules method will prepare the rules for the input field
349 * @param array $fields
350 * @return mixed
351 */
352 protected function getRules($fields = [])
353 {
354 $rules = [];
355
356 foreach ($fields as $fieldName => $field) {
357 if (array_key_exists('required', $field)) {
358 $rules[$fieldName] = 'required';
359 }
360
361 $pipe = array_key_exists($fieldName, $rules) ? '|' : '';
362
363 if ($field['type'] === 'email') {
364 $rules[$fieldName] = $rules[$fieldName] . $pipe . 'email';
365 } elseif ($field['type'] === 'password') {
366 $rules[$fieldName] = $rules[$fieldName] . $pipe . 'min:8';
367 }
368 }
369 /*
370 * Filter user signup validation rules
371 *
372 * @since v1.0.0
373 * @param array $rules
374 */
375 return apply_filters('fluent_support/signup_validation_rules', $rules);
376 }
377
378
379 public function resetPassword(Request $request)
380 {
381
382 if(Helper::getAuthProvider() != 'fluent_support') {
383 return $this->sendError([
384 'message' => __('You are not allowed to reset password using this form', 'fluent-support')
385 ]);
386 }
387
388 $errors = new \WP_Error();
389
390 if (!wp_verify_nonce($request->get('_fsupport_reset_pass_nonce'), 'fluent_support_reset_pass_nonce')) {
391 return $this->sendError([
392 'message' => __('Security verification failed. Please try again', 'fluent-support')
393 ]);
394 }
395
396 $usernameOrEmail = trim(wp_unslash($request->get('user_login')));
397
398 if (!$usernameOrEmail) {
399 return $this->sendError([
400 'message' => 'Username or email is required'
401 ]);
402 }
403
404 $user_data = get_user_by('email', $usernameOrEmail);
405
406 if (!$user_data) {
407 $user_data = get_user_by('login', $usernameOrEmail);
408 }
409
410 if (!$user_data) {
411 return $this->sendError([
412 'message' => __('Invalid username or email', 'fluent-support')
413 ]);
414 }
415
416 $user_data = apply_filters('lostpassword_user_data', $user_data, $errors);
417
418 do_action('lostpassword_post', $errors, $user_data);
419
420 $errors = apply_filters('lostpassword_errors', $errors, $user_data);
421
422 if ($errors->has_errors()) {
423 return $this->sendError([
424 'message' => $errors->get_error_message()
425 ]);
426 }
427
428 if (!$user_data) {
429 return $this->sendError([
430 'message' => __('<strong>Error</strong>: There is no account with that username or email address.', 'fluent-support')
431 ]);
432 }
433
434 if (is_multisite() && !is_user_member_of_blog($user_data->ID, get_current_blog_id())) {
435
436 return $this->sendError([
437 'message' => __('<strong>Error</strong>: Invalid username or email', 'fluent-support')
438 ]);
439 }
440
441 // Redefining user_login ensures we return the right case in the email.
442 $user_login = $user_data->user_login;
443
444 do_action('retrieve_password', $user_login);
445
446 $allow = apply_filters('allow_password_reset', true, $user_data->ID);
447
448 if (!$allow) {
449 return $this->sendError([
450 'message' => __('Password reset is not allowed for this user', 'fluent-support')
451 ]);
452 }
453
454 if (is_wp_error($allow)) {
455 return $this->sendError([
456 'message' => $allow->get_error_message()
457 ]);
458 }
459
460
461 /*
462 * Filter reset password link text
463 *
464 * @since v1.5.7
465 * @param string $linkText
466 */
467 $linkText = apply_filters("fluent_support/reset_password_link", sprintf(__('Reset your password for %s', 'fluent-support'), get_bloginfo('name')));
468
469 $resetUrl = add_query_arg([
470 'action' => 'rp',
471 'key' => get_password_reset_key($user_data),
472 'login' => rawurlencode($user_data->user_login)
473 ], wp_login_url());
474
475 $resetLink = '<a href="' . $resetUrl . '">' . $linkText . '</a>';
476
477 /*
478 * Filter reset password email subject
479 *
480 * @since v1.5.7
481 * @param string $mailSubject
482 */
483 $mailSubject = apply_filters("fluent_support/reset_password_mail_subject", sprintf(__('Reset your password for %s support portal', 'fluent-support'), get_bloginfo('name')));
484
485 $message = sprintf(__('<p>Hi %s,</p>', 'fluent-support'), $user_data->first_name) .
486 __('<p>Someone has requested a new password for the following account on WordPress:</p>', 'fluent-support') .
487 sprintf(__('<p>Username: %s</p>', 'fluent-support'), $user_login) .
488 sprintf(__('<p>%s</p>', 'fluent-support'), $resetLink) .
489 sprintf(__('<p>If you did not request to reset your password, please ignore this email.</p>', 'fluent-support'));
490
491 /*
492 * Filter reset password email body text
493 *
494 * @since v1.5.7
495 * @param string $message
496 * @param object $user
497 * @param string $resetLink
498 */
499 $message = apply_filters('fluent_support/reset_password_message', $message, $user_data, $resetLink);
500
501 $headers = array('Content-Type: text/html; charset=UTF-8');
502
503 wp_mail($user_data->user_email, $mailSubject, $message, $headers);
504
505 return $this->sendSuccess([
506 'message' => __('Please check your email for the reset link', 'fluent-support')
507 ]);
508 }
509
510 /**
511 * getMessages message will return the validation message regarding sign up or sign in
512 * @param array $rules
513 * @return mixed
514 */
515 protected function getMessages($rules = [])
516 {
517 /*
518 * Filter user signup validation message
519 *
520 * @since v1.0.0
521 * @param array $arg
522 * @param array $rules
523 */
524 return apply_filters('fluent_support/signup_validation_messages', [], $rules);
525 }
526
527 /**
528 * createUser method will create new user
529 * @param array $formData
530 * @return mixed
531 */
532 public function createUser($formData = [])
533 {
534 /*
535 * Filter user signup email
536 *
537 * @since v1.0.0
538 * @param string $email
539 */
540 $email = apply_filters('fluent_support/signup_email', Arr::get($formData, 'email'));
541
542 /*
543 * Filter user signup username
544 *
545 * @since v1.0.0
546 * @param string $username
547 */
548 $userName = apply_filters('fluent_support/signup_username', Arr::get($formData, 'username'));
549
550 if (empty($formData['password'])) {
551 $password = wp_generate_password(8);
552 } else {
553 $password = $formData['password'];
554 }
555
556 /*
557 * Filter user signup password
558 *
559 * @since v1.0.0
560 * @param string $password
561 */
562 $password = apply_filters('fluent_support/signup_password', $password);
563
564 /*
565 * Action before creating WP user using Fluent Support signup form
566 *
567 * @since v1.0.0
568 * @param string $userName
569 * @param string $password
570 * @param string $email
571 */
572 do_action('fluent_support/before_creating_user', $userName, $password, $email);
573
574 $userId = wp_create_user($userName, $password, $email);
575
576 if (is_wp_error($userId)) {
577 return false;
578 }
579
580 return $userId;
581
582 }
583
584 /**
585 * maybeUpdateUser method will update user information if exists
586 * @param $userId
587 * @param $formData
588 */
589 public function maybeUpdateUser($userId, $formData)
590 {
591 $name = trim(Arr::get($formData, 'first_name') . ' ' . Arr::get($formData, 'last_name'));
592
593 $data = array_filter([
594 'ID' => $userId,
595 'user_nicename' => $name,
596 'display_name' => $name,
597 'first_name' => Arr::get($formData, 'first_name'),
598 'last_name' => Arr::get($formData, 'last_name'),
599 ]);
600
601 if ($name) {
602 /*
603 * Action before updating a customer/user
604 *
605 * @since v1.0.0
606 * @param array $data
607 */
608 do_action('fluent_support/before_updating_user', $data);
609
610 /*
611 * Filter user updatable data
612 *
613 * @since v1.0.0
614 * @param $data
615 */
616 $updateUserData = apply_filters('fluent_support/update_user_data', $data);
617 wp_update_user($updateUserData);
618
619 /*
620 * Action after updating a customer/user
621 *
622 * @since v1.0.0
623 * @param array $data
624 */
625 do_action('fluent_support/after_updating_user', $data);
626 }
627 }
628
629 public function addUserMetaData($userId, $formData) {
630 $customFieldsKey = apply_filters('fluent_support/custom_registration_form_fields_key', Helper::getBusinessSettings('custom_registration_form_field'));
631
632 if (empty($customFieldsKey)) {
633 return;
634 }
635
636 foreach ($customFieldsKey as $key) {
637 if (isset($formData[$key])) {
638 $fieldValue = $formData[$key];
639 update_user_meta($userId, $key, $fieldValue);
640 }
641 }
642 }
643
644 /**
645 * assignRole method will assign role to a given user id
646 * @param $userId
647 */
648 protected function assignRole($userId)
649 {
650 $user = new \WP_User($userId);
651
652 /*
653 * Action before assigning role to registered user
654 *
655 * @since v1.0.0
656 * @param array $data
657 */
658 do_action('fluent_support/before_assigning_role', $user);
659 /*
660 * Filter user assignable role after signup
661 *
662 * @since v1.0.0
663 * @param string $setRole WordPress user role key
664 */
665 $setRole = apply_filters('fluent_support/user_role', 'subscriber');
666 $user->set_role($setRole);
667
668 /*
669 * Action after assigning role to registered user
670 *
671 * @since v1.0.0
672 * @param array $data
673 */
674 do_action('fluent_support/after_assigning_role', $user);
675 }
676
677
678 /**
679 * login method will clear existing cookies and set new cookie for a given user id
680 * @param $userId
681 */
682 protected function login($userId)
683 {
684 /*
685 * Action before login
686 *
687 * @since v1.0.0
688 * @param integer $userId
689 */
690 do_action('fluent_support/before_logging_in_user', $userId);
691
692 wp_clear_auth_cookie();
693 wp_set_current_user($userId);
694 wp_set_auth_cookie($userId);
695
696 /*
697 * Action after login
698 *
699 * @since v1.0.0
700 * @param integer $userId
701 */
702 do_action('fluent_support/after_logging_in_user', $userId);
703 }
704
705 }
706