PluginProbe
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent / 3.5.4
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent v3.5.4
3.5.4 3.5.3 3.5.2 3.5.1 3.4.9 3.5.0 3.4.8 3.4.7 trunk 2.3.1 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6
← All changes | includes/class-wpsc-current-user.php +231 -39 3.4.0 → 3.5.4 View file →
@@ -164,8 +164,24 @@
164 164 }
165 165 }
166 166
167 167 /**
168 + * Return customer object by WordPress user ID.
169 + *
170 + * @param int $user_id - WordPress user ID.
171 + * @return WPSC_Customer
172 + */
173 + public static function get_customer_by_user_id( $user_id ) {
174 +
175 + $user_id = absint( $user_id );
176 + if ( ! $user_id ) {
177 + return new WPSC_Customer();
178 + }
179 +
180 + return WPSC_Customer::get_by_user_id( $user_id );
181 + }
182 +
183 + /**
168 184 * Load current wpsc user
169 185 *
170 186 * @return void
171 187 */
@@ -170,12 +186,20 @@
170 186 * @return void
171 187 */
172 188 public static function load_current_user() {
173 189
174 - global $current_user;
190 + // Use wp_get_current_user() rather than the raw global - the
191 + // global is only populated once something has actually called
192 + // wp_get_current_user() (or a function that does, like
193 + // is_user_logged_in()) earlier in the request. Nothing guarantees
194 + // that has happened yet by the 'init' hook (where this runs), so
195 + // reading the raw global directly can see an empty, not-yet-resolved
196 + // WP_User and wrongly treat a logged-in visitor as a guest for the
197 + // rest of the request.
198 + $wp_user = wp_get_current_user();
175 199
176 200 // wp logged-in user.
177 - $email = $current_user && $current_user->ID ? $current_user->user_email : '';
201 + $email = $wp_user && $wp_user->ID ? $wp_user->user_email : '';
178 202 if ( $email ) {
179 203 self::$current_user = new WPSC_Current_User( $email );
180 204 self::$login_type = 'registered';
181 205 return;
@@ -186,14 +210,14 @@
186 210
187 211 $login_auth = isset( $_COOKIE['wpsc_guest_login_auth'] ) ? sanitize_text_field( wp_unslash( $_COOKIE['wpsc_guest_login_auth'] ) ) : '';
188 212 $login_auth = $login_auth ? json_decode( $login_auth ) : false;
189 213
190 - if ( ! $login_auth ) {
214 + if ( ! $login_auth || ! is_object( $login_auth ) || ! isset( $login_auth->token ) || ! is_string( $login_auth->token ) ) {
191 215 self::$current_user = new WPSC_Current_User();
192 216 return;
193 217 }
194 218
195 - $login_auth->email = $login_auth->email ? sanitize_email( $login_auth->email ) : '';
219 + $login_auth->email = isset( $login_auth->email ) && is_string( $login_auth->email ) ? sanitize_email( $login_auth->email ) : '';
196 220 if ( ! $login_auth->email ) {
197 221 self::$current_user = new WPSC_Current_User();
198 222 return;
199 223 }
@@ -236,9 +260,9 @@
236 260 $default_filters = get_option( $this->is_agent ? 'wpsc-atl-default-filters' : 'wpsc-ctl-default-filters' );
237 261 foreach ( $default_filters as $index => $filter ) {
238 262
239 263 // exclude if current user does not have access to deleted filter.
240 - if ( $index == 'deleted' && ! $this->agent->has_cap( 'dtt-access' ) ) {
264 + if ( $index === 'deleted' && ! $this->agent->has_cap( 'dtt-access' ) ) {
241 265 continue;
242 266 }
243 267
244 268 // exclude if filter is not enabled.
@@ -366,8 +390,54 @@
366 390 return apply_filters( 'wpsc_tl_current_user_system_query', $system_query, $filters, $this );
367 391 }
368 392
369 393 /**
394 + * Return system query for the current user for ticket list
395 + *
396 + * @param array $filters - filters.
397 + * @return array
398 + */
399 + public function get_atl_system_query( $filters ) {
400 +
401 + $system_query = array( 'relation' => 'OR' );
402 +
403 + $system_query[] = array(
404 + 'slug' => 'customer',
405 + 'compare' => '=',
406 + 'val' => $this->customer->id,
407 + );
408 +
409 + if ( $this->is_agent ) {
410 +
411 + if ( $this->agent->has_cap( 'at-assigned-me' ) ) {
412 + $system_query[] = array(
413 + 'slug' => 'assigned_agent',
414 + 'compare' => '=',
415 + 'val' => $this->agent->id,
416 + );
417 + }
418 +
419 + if ( $this->agent->has_cap( 'at-unassigned' ) ) {
420 + $system_query[] = array(
421 + 'slug' => 'assigned_agent',
422 + 'compare' => '=',
423 + 'val' => '',
424 + );
425 + }
426 +
427 + if ( $this->agent->has_cap( 'at-assigned-others' ) ) {
428 + $system_query[] = array(
429 + 'slug' => 'assigned_agent',
430 + 'compare' => 'NOT IN',
431 + 'val' => array( $this->agent->id, '' ),
432 + );
433 + }
434 + }
435 +
436 + return apply_filters( 'wpsc_atl_current_user_system_query', $system_query, $filters, $this );
437 + }
438 +
439 + /**
370 440 * Check login for default login form
371 441 *
372 442 * @return void
373 443 */
@@ -373,9 +443,9 @@
373 443 */
374 444 public static function check_user_login() {
375 445
376 446 if ( check_ajax_referer( 'wpsc_default_login', '_ajax_nonce', false ) != 1 ) {
377 - wp_send_json_error( 'Unauthorised request!', 401 );
447 + wp_send_json_error( 'Unauthorized request!', 401 );
378 448 }
379 449
380 450 WPSC_MS_Recaptcha::validate( 'submit_login' );
381 451
@@ -398,10 +468,37 @@
398 468 'remember' => $remember_me,
399 469 )
400 470 );
401 471
402 - $success = is_wp_error( $user ) ? 0 : 1;
403 - wp_send_json( array( 'success' => $success ) );
472 + if ( is_wp_error( $user ) ) {
473 +
474 + $auth_errors = array(
475 + 'incorrect_password',
476 + 'invalid_username',
477 + 'empty_username',
478 + 'empty_password',
479 + );
480 + $code = $user->get_error_code();
481 + if ( in_array( $code, $auth_errors, true ) ) {
482 +
483 + wp_send_json_error(
484 + array(
485 + 'code' => 'invalid_login',
486 + 'message' => __( 'Invalid username or password.', 'supportcandy' ),
487 + ),
488 + 401
489 + );
490 + }
491 +
492 + wp_send_json_error(
493 + array(
494 + 'code' => $code,
495 + 'message' => wp_strip_all_tags( $user->get_error_message() ),
496 + ),
497 + 400
498 + );
499 + }
500 + wp_send_json_success();
404 501 }
405 502
406 503 /**
407 504 * Get user registration
@@ -448,13 +545,12 @@
448 545 </div>
449 546
450 547 <div style="margin: 0 0 5px !important;">
451 548 <input id="wpsc-email" type="text" name="email_address" style="margin-bottom: 0px !important;" placeholder="<?php esc_attr_e( 'Email Address', 'supportcandy' ); ?>" autocomplete="off"/>
452 - <small id="wpsc-email-unavailable" style="color: #e84118;font-style:italic;display:none;"><?php esc_attr_e( 'Email is already taken!', 'supportcandy' ); ?></small>
549 + <small id="wpsc-email-unavailable" style="color: #e84118;font-style:italic;display:none;"><?php esc_attr_e( 'Email is already taken or not allowed!', 'supportcandy' ); ?></small>
453 550 <small id="wpsc-email-available" style="color: #4cd137;font-style:italic;display:none;"><?php esc_attr_e( 'Email is available!', 'supportcandy' ); ?></small>
454 551 <script>
455 552 jQuery('#wpsc-email').change(function(){
456 - console.log('email changed');
457 553 jQuery('#wpsc-email-available').hide();
458 554 jQuery('#wpsc-email-unavailable').hide();
459 555 var email = jQuery(this).val().trim();
460 556 const data = { action: 'wpsc_check_user_availability', type: 'email', email, _ajax_nonce: '<?php echo esc_attr( wp_create_nonce( 'wpsc_check_user_availability' ) ); ?>' };
@@ -475,31 +571,104 @@
475 571 <input type="password" name="confirm_password" placeholder="<?php esc_attr_e( 'Confirm Password', 'supportcandy' ); ?>"/>
476 572 <?php
477 573
478 574 // recaptcha.
479 - if ( $recaptcha['allow-recaptcha'] === 1 && $recaptcha['recaptcha-version'] == 2 && $recaptcha['recaptcha-site-key'] && $recaptcha['recaptcha-secret-key'] ) {
575 + if ( $recaptcha['captcha-provider'] === 'google-recaptcha' && $recaptcha['recaptcha-version'] == 2 && $recaptcha['recaptcha-site-key'] && $recaptcha['recaptcha-secret-key'] ) {
480 576 $unique_id = uniqid( 'wpsc_' );
481 577 ?>
482 - <script src="https://www.google.com/recaptcha/api.js?onload=recaptchaCallback&render=explicit" async defer></script> <?php // phpcs:ignore ?>
483 - <div id="<?php echo esc_attr( $unique_id ); ?>" data-sitekey="" style="margin-bottom: 5px;"></div>
484 - <script>
485 - var recaptchaCallback = function() {
486 - var obj = jQuery('#<?php echo esc_attr( $unique_id ); ?>');
487 - grecaptcha.render(obj.attr("id"), {
488 - "sitekey" : "<?php echo esc_attr( $recaptcha['recaptcha-site-key'] ); ?>",
489 - "callback" : function(token) {
490 - obj.closest('form').find(".g-recaptcha-response").val(token);
491 - }
492 - });
493 - }
494 - </script>
578 + <script src="https://www.google.com/recaptcha/api.js?onload=recaptchaCallback&render=explicit" async defer></script> <?php // phpcs:ignore ?>
579 + <div id="<?php echo esc_attr( $unique_id ); ?>" data-sitekey="" style="margin-bottom: 5px;"></div>
580 + <script>
581 + var recaptchaCallback = function() {
582 + var obj = jQuery('#<?php echo esc_attr( $unique_id ); ?>');
583 + grecaptcha.render(obj.attr("id"), {
584 + "sitekey" : "<?php echo esc_attr( $recaptcha['recaptcha-site-key'] ); ?>",
585 + "callback" : function(token) {
586 + obj.closest('form').find(".g-recaptcha-response").val(token);
587 + }
588 + });
589 + }
590 + </script>
495 591 <?php
496 592 }
497 - if ( $recaptcha['allow-recaptcha'] === 1 && $recaptcha['recaptcha-version'] == 3 && $recaptcha['recaptcha-site-key'] && $recaptcha['recaptcha-secret-key'] ) {
593 + if ( $recaptcha['captcha-provider'] === 'google-recaptcha' && $recaptcha['recaptcha-version'] == 3 && $recaptcha['recaptcha-site-key'] && $recaptcha['recaptcha-secret-key'] ) {
498 594 ?>
499 595 <script src="https://www.google.com/recaptcha/api.js?render=<?php echo esc_attr( $recaptcha['recaptcha-site-key'] ); ?>"></script> <?php // phpcs:ignore ?>
500 596 <?php
501 597 }
598 + if ( $recaptcha['captcha-provider'] === 'cloudflare-turnstile' && $recaptcha['cloudflare-site-key'] && $recaptcha['cloudflare-secret-key'] ) {
599 + ?>
600 + <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> <?php // phpcs:ignore ?>
601 + <div class="wpsc-tff turnstile wpsc-xs-12 wpsc-sm-12 wpsc-md-12 wpsc-lg-12 required wpsc-visible" data-cft="turnstile">
602 + <div class="cf-turnstile" data-sitekey="<?php echo esc_attr( $recaptcha['cloudflare-site-key'] ); ?>"></div>
603 + </div>
604 + <script>
605 + jQuery(document).ready(function() {
606 +
607 + function wpscInitTurnstileWidgets() {
608 +
609 + if (
610 + typeof window.turnstile === 'undefined' ||
611 + typeof window.turnstile.render !== 'function'
612 + ) {
613 + return false;
614 + }
615 +
616 + jQuery('.cf-turnstile').each(function() {
617 +
618 + var widget = jQuery(this);
619 +
620 + if (
621 + widget.find('input[name="cf-turnstile-response"]').length ||
622 + widget.find('iframe').length ||
623 + widget.attr('data-wpsc-rendered') === '1'
624 + ) {
625 +
626 + widget.attr('data-wpsc-rendered', '1');
627 +
628 + return;
629 + }
630 +
631 + window.turnstile.render(
632 + this,
633 + {
634 + sitekey: widget.data('sitekey')
635 + }
636 + );
637 +
638 + widget.attr('data-wpsc-rendered', '1');
639 + });
640 +
641 + return true;
642 + }
643 +
644 + if (wpscInitTurnstileWidgets()) {
645 + return;
646 + }
647 +
648 + var attempts = 0;
649 +
650 + var timer = setInterval(
651 + function() {
652 +
653 + attempts++;
654 +
655 + if (
656 + wpscInitTurnstileWidgets() ||
657 + attempts > 50
658 + ) {
659 +
660 + clearInterval(timer);
661 + }
662 +
663 + },
664 + 100
665 + );
666 +
667 + });
668 + </script>
669 + <?php
670 + }
502 671 do_action( 'wpsc_registration_form' );
503 672 ?>
504 673 <div class="wpsc-reg-user">
505 674 <?php
@@ -532,9 +701,9 @@
532 701 </div>
533 702 <?php
534 703 }
535 704 ?>
536 - <div>
705 + </div>
537 706
538 707 <button class="wpsc-button normal primary" onclick="wpsc_set_default_registration(this)"><?php esc_attr_e( 'Sign Up', 'supportcandy' ); ?></button>
539 708 <button class="wpsc-button normal secondary" onclick="window.location.reload();"><?php esc_attr_e( 'Cancel', 'supportcandy' ); ?></button>
540 709 <input type="hidden" name="action" value="wpsc_authenticate_registration"/>
@@ -553,9 +722,9 @@
553 722 */
554 723 public static function check_user_availability() {
555 724
556 725 if ( check_ajax_referer( 'wpsc_check_user_availability', '_ajax_nonce', false ) != 1 ) {
557 - wp_send_json_error( 'Unauthorised request!', 401 );
726 + wp_send_json_error( 'Unauthorized request!', 401 );
558 727 }
559 728
560 729 $page_settings = get_option( 'wpsc-gs-page-settings' );
561 730 if ( $page_settings['user-registration'] !== 'default' ) {
@@ -567,14 +736,14 @@
567 736 wp_send_json_error( 'Something went wrong', 400 );
568 737 }
569 738
570 739 if ( $type === 'username' ) {
571 - $username = isset( $_POST['username'] ) ? sanitize_text_field( wp_unslash( $_POST['username'] ) ) : '';
740 + $username = isset( $_POST['username'] ) ? sanitize_user( wp_unslash( $_POST['username'] ) ) : '';
572 741 if ( ! $username ) {
573 742 wp_send_json_error( 'Something went wrong', 400 );
574 743 }
575 744 } elseif ( $type === 'email' ) {
576 - $email = isset( $_POST['email'] ) && filter_var( wp_unslash( $_POST['email'] ), FILTER_VALIDATE_EMAIL ) ? sanitize_text_field( wp_unslash( $_POST['email'] ) ) : '';
745 + $email = isset( $_POST['email'] ) && filter_var( wp_unslash( $_POST['email'] ), FILTER_VALIDATE_EMAIL ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
577 746 if ( ! $email ) {
578 747 wp_send_json_error( 'Something went wrong', 400 );
579 748 }
580 749 }
@@ -590,9 +759,9 @@
590 759 */
591 760 public static function send_registration_otp() {
592 761
593 762 if ( check_ajax_referer( 'wpsc_authenticate_registration', '_ajax_nonce', false ) != 1 ) {
594 - wp_send_json_error( 'Unauthorised request!', 401 );
763 + wp_send_json_error( 'Unauthorized request!', 401 );
595 764 }
596 765 $page_settings = get_option( 'wpsc-gs-page-settings' );
597 766 if ( $page_settings['user-registration'] !== 'default' ) {
598 767 wp_send_json_error( __( 'Unauthorized', 'supportcandy' ), 401 );
@@ -609,9 +778,9 @@
609 778 if ( ! $lastname ) {
610 779 wp_send_json_error( 'Bad request', 400 );
611 780 }
612 781
613 - $username = isset( $_POST['username'] ) ? sanitize_text_field( wp_unslash( $_POST['username'] ) ) : '';
782 + $username = isset( $_POST['username'] ) ? sanitize_user( wp_unslash( $_POST['username'] ) ) : '';
614 783 if ( ! $username ) {
615 784 wp_send_json_error( 'Bad request', 400 );
616 785 }
617 786
@@ -618,9 +787,9 @@
618 787 if ( self::is_username_available( $username ) ) {
619 788 wp_send_json_error( 'Bad request', 400 );
620 789 }
621 790
622 - $email_address = isset( $_POST['email_address'] ) && filter_var( wp_unslash( $_POST['email_address'] ), FILTER_VALIDATE_EMAIL ) ? sanitize_text_field( wp_unslash( $_POST['email_address'] ) ) : '';
791 + $email_address = isset( $_POST['email_address'] ) && filter_var( wp_unslash( $_POST['email_address'] ), FILTER_VALIDATE_EMAIL ) ? sanitize_email( wp_unslash( $_POST['email_address'] ) ) : '';
623 792 if ( ! $email_address ) {
624 793 wp_send_json_error( 'Bad request', 400 );
625 794 }
626 795
@@ -655,9 +824,9 @@
655 824 WPSC_EN_User_Reg_OTP::send_otp( $otp );
656 825 ?>
657 826
658 827 <h2><?php esc_attr_e( 'Please sign up', 'supportcandy' ); ?></h2>
659 - <small style="margin: 0 0 5px;"><?php esc_attr_e( 'We have sent a 6-digit one-time pass code to the email address you provided.', 'supportcandy' ); ?></small>
828 + <small style="margin: 0 0 5px;"><?php esc_attr_e( 'We have sent a one-time verification code to your email address.', 'supportcandy' ); ?></small>
660 829 <form onsubmit="return false;" class="wpsc-login wpsc-confirm-registration">
661 830 <input type="text" name="otp" autocomplete="off"/>
662 831 <button class="wpsc-button normal primary" onclick="wpsc_confirm_registration(this)"><?php esc_attr_e( 'Submit', 'supportcandy' ); ?></button>
663 832 <input type="hidden" name="action" value="wpsc_confirm_registration"/>
@@ -688,8 +857,15 @@
688 857 */
689 858 public static function is_email_available( $email ) {
690 859
691 860 $user = get_user_by( 'email', $email );
861 +
862 + // check allowed email domains.
863 + $allowed_domains = apply_filters( 'wpsc_registration_allowed_email_domains', array() );
864 + $domain = substr( strrchr( $email, '@' ), 1 );
865 + if ( $allowed_domains && ! in_array( $domain, $allowed_domains, true ) ) {
866 + return true;
867 + }
692 868 return $user ? true : false;
693 869 }
694 870
695 871 /**
@@ -699,9 +875,9 @@
699 875 */
700 876 public static function register_user() {
701 877
702 878 if ( check_ajax_referer( 'wpsc_confirm_registration', '_ajax_nonce', false ) != 1 ) {
703 - wp_send_json_error( 'Unauthorised request!', 401 );
879 + wp_send_json_error( 'Unauthorized request!', 401 );
704 880 }
705 881
706 882 $page_settings = get_option( 'wpsc-gs-page-settings' );
707 883 if ( $page_settings['user-registration'] !== 'default' ) {
@@ -729,8 +905,21 @@
729 905 }
730 906
731 907 $data = json_decode( $otp->data );
732 908
909 + // check allowed email domains.
910 + $allowed_domains = apply_filters( 'wpsc_registration_allowed_email_domains', array() );
911 + $domain = substr( strrchr( $data->email_address, '@' ), 1 );
912 + if ( $allowed_domains && ! in_array( $domain, $allowed_domains, true ) ) {
913 + wp_send_json_error(
914 + array(
915 + 'isSuccess' => 0,
916 + 'message' => __( 'Email domain is not allowed.', 'supportcandy' ),
917 + ),
918 + 403
919 + );
920 + }
921 +
733 922 // insert user.
734 923 $display_name = $data->firstname . ' ' . $data->lastname;
735 924 $user_id = wp_insert_user(
736 925 array(
@@ -809,9 +998,9 @@
809 998 */
810 999 public static function get_guest_sign_in_auth() {
811 1000
812 1001 if ( check_ajax_referer( 'wpsc_authenticate_guest_login', '_ajax_nonce', false ) != 1 ) {
813 - wp_send_json_error( 'Unauthorised request!', 401 );
1002 + wp_send_json_error( 'Unauthorized request!', 401 );
814 1003 }
815 1004 $gs = get_option( 'wpsc-gs-general' );
816 1005 $page_settings = get_option( 'wpsc-gs-page-settings' );
817 1006 if ( ! ( $page_settings['otp-login'] && in_array( 'guest', $gs['allow-create-ticket'] ) ) ) {
@@ -845,9 +1034,9 @@
845 1034 WPSC_EN_Guest_Login_OTP::send_otp( $otp );
846 1035 ?>
847 1036
848 1037 <h2><?php esc_attr_e( 'Please sign in', 'supportcandy' ); ?></h2>
849 - <small style="margin: 0 0 5px;"><?php esc_attr_e( 'We have sent a 6-digit one-time pass code to the email address you provided.', 'supportcandy' ); ?></small>
1038 + <small style="margin: 0 0 5px;"><?php esc_attr_e( 'We have sent a one-time verification code to your email address.', 'supportcandy' ); ?></small>
850 1039 <form onsubmit="return false;" class="wpsc-login wpsc-confirm-guest-login">
851 1040 <input type="text" name="otp" autocomplete="off"/>
852 1041 <button class="wpsc-button normal primary" onclick="wpsc_confirm_guest_login(this)"><?php esc_attr_e( 'Submit', 'supportcandy' ); ?></button>
853 1042 <input type="hidden" name="action" value="wpsc_confirm_guest_login"/>
@@ -875,9 +1064,9 @@
875 1064 wp_send_json_error( 'Too many attempts. Please try again later.', 429 );
876 1065 }
877 1066
878 1067 if ( check_ajax_referer( 'wpsc_confirm_guest_login', '_ajax_nonce', false ) != 1 ) {
879 - wp_send_json_error( 'Unauthorised request!', 401 );
1068 + wp_send_json_error( 'Unauthorized request!', 401 );
880 1069 }
881 1070
882 1071 $gs = get_option( 'wpsc-gs-general' );
883 1072 $page_settings = get_option( 'wpsc-gs-page-settings' );
@@ -1002,11 +1191,14 @@
1002 1191 $now = new DateTime();
1003 1192 $data = json_decode( $otp->data );
1004 1193
1005 1194 if (
1006 - isset( $data->auth_type ) &&
1195 + isset( $data->auth_type, $data->auth_token, $login_auth->token ) &&
1196 + is_string( $data->auth_token ) && $data->auth_token !== '' &&
1197 + is_string( $login_auth->token ) &&
1007 1198 ( ( $data->auth_type == 'login' && $page_settings['otp-login'] && in_array( 'guest', $gs['allow-create-ticket'] ) ) || $data->auth_type == 'open-ticket' ) &&
1008 - ( $otp->date_expiry > $now && $data->auth_token == $login_auth->token )
1199 + $otp->date_expiry > $now &&
1200 + hash_equals( $data->auth_token, $login_auth->token )
1009 1201 ) {
1010 1202 self::$login_type = 'guest';
1011 1203 self::$guest_login_type = $data->auth_type;
1012 1204 return true;