PluginProbe
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent / 3.4.8
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent v3.4.8
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
supportcandy / includes / class-wpsc-current-user.php

class-wpsc-current-user.php in SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent 3.4.8, at includes/class-wpsc-current-user.php

1,235 lines 36.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit; // Exit if accessed directly!
4 }
5
6 if ( ! class_exists( 'WPSC_Current_User' ) ) :
7
8 final class WPSC_Current_User {
9
10 /**
11 * Current user object to access
12 *
13 * @var WPSC_Current_User
14 */
15 public static $current_user;
16
17 /**
18 * Login type
19 *
20 * @var string
21 */
22 public static $login_type = '';
23
24 /**
25 * Guest login type
26 *
27 * @var string
28 */
29 public static $guest_login_type = '';
30
31 /**
32 * Current user WP object
33 *
34 * @var WP_User
35 */
36 public $user;
37
38 /**
39 * Check whether user is guest
40 *
41 * @var boolean
42 */
43 public $is_guest = false;
44
45 /**
46 * Check whether user is customer or not
47 *
48 * @var boolean
49 */
50 public $is_customer = false;
51
52 /**
53 * Customer object for current user
54 *
55 * @var WPSC_Customer
56 */
57 public $customer;
58
59 /**
60 * Check whether user is an agent or not
61 *
62 * @var boolean
63 */
64 public $is_agent = false;
65
66 /**
67 * Agent object for current user
68 *
69 * @var WPSC_Agent
70 */
71 public $agent;
72
73 /**
74 * Current user level. e.g. customer, agent or admin
75 *
76 * @var string
77 */
78 public $level;
79
80 /**
81 * Initialize this class
82 *
83 * @return void
84 */
85 public static function init() {
86
87 add_action( 'init', array( __CLASS__, 'load_current_user' ) );
88
89 // default login.
90 add_action( 'wp_ajax_nopriv_wpsc_default_login', array( __CLASS__, 'check_user_login' ) );
91
92 // default registration.
93 add_action( 'wp_ajax_nopriv_wpsc_get_default_registration', array( __CLASS__, 'get_user_registration' ) );
94 add_action( 'wp_ajax_nopriv_wpsc_check_user_availability', array( __CLASS__, 'check_user_availability' ) );
95 add_action( 'wp_ajax_nopriv_wpsc_authenticate_registration', array( __CLASS__, 'send_registration_otp' ) );
96 add_action( 'wp_ajax_nopriv_wpsc_confirm_registration', array( __CLASS__, 'register_user' ) );
97
98 // sign-in using otp.
99 add_action( 'wp_ajax_nopriv_wpsc_get_guest_sign_in', array( __CLASS__, 'get_guest_sign_in' ) );
100 add_action( 'wp_ajax_nopriv_wpsc_authenticate_guest_login', array( __CLASS__, 'get_guest_sign_in_auth' ) );
101 add_action( 'wp_ajax_nopriv_wpsc_confirm_guest_login', array( __CLASS__, 'confirm_guest_login' ) );
102
103 // user registration email template.
104 add_filter( 'wpsc_email_notification_page_sections', array( __CLASS__, 'registration_email_template_section' ) );
105
106 // guest login email template.
107 add_filter( 'wpsc_email_notification_page_sections', array( __CLASS__, 'guest_login_email_template_section' ) );
108 }
109
110 /**
111 * Initialize the object
112 *
113 * @param string $email - email address.
114 */
115 public function __construct( $email = '' ) {
116
117 $user = $email ? get_user_by( 'email', $email ) : new WP_User();
118 if ( $user === false ) {
119 $user = new WP_User();
120 }
121 $this->user = $user;
122
123 // is guest.
124 $this->is_guest = $this->user->ID ? false : true;
125
126 // Set customer object.
127 if ( $this->user->ID ) {
128
129 $this->is_customer = true;
130 $customer = WPSC_Customer::get_by_email( $this->user->user_email );
131 if ( $customer->id ) {
132 $this->customer = $customer;
133 } else {
134 $this->customer = WPSC_Customer::insert(
135 array(
136 'user' => $this->user->ID,
137 'name' => $this->user->display_name,
138 'email' => $this->user->user_email,
139 )
140 );
141 }
142 } elseif ( $email ) {
143
144 $this->is_customer = true;
145 $this->customer = WPSC_Customer::get_by_email( $email );
146 }
147
148 // Set agent object.
149 $agent = WPSC_Agent::get_by_user_id( $this->user->ID );
150 if ( $agent->id && $agent->is_active ) {
151 $this->is_agent = true;
152 $this->agent = $agent;
153 }
154
155 // set leval.
156 if ( WPSC_Functions::is_site_admin() ) {
157 $this->level = 'admin';
158 } elseif ( $this->is_agent ) {
159 $this->level = 'agent';
160 } elseif ( $this->is_customer ) {
161 $this->level = 'customer';
162 } else {
163 $this->level = 'none';
164 }
165 }
166
167 /**
168 * Load current wpsc user
169 *
170 * @return void
171 */
172 public static function load_current_user() {
173
174 global $current_user;
175
176 // wp logged-in user.
177 $email = $current_user && $current_user->ID ? $current_user->user_email : '';
178 if ( $email ) {
179 self::$current_user = new WPSC_Current_User( $email );
180 self::$login_type = 'registered';
181 return;
182 }
183
184 // guest login.
185 $gs = get_option( 'wpsc-gs-general' );
186
187 $login_auth = isset( $_COOKIE['wpsc_guest_login_auth'] ) ? sanitize_text_field( wp_unslash( $_COOKIE['wpsc_guest_login_auth'] ) ) : '';
188 $login_auth = $login_auth ? json_decode( $login_auth ) : false;
189
190 if ( ! $login_auth ) {
191 self::$current_user = new WPSC_Current_User();
192 return;
193 }
194
195 $login_auth->email = $login_auth->email ? sanitize_email( $login_auth->email ) : '';
196 if ( ! $login_auth->email ) {
197 self::$current_user = new WPSC_Current_User();
198 return;
199 }
200
201 if ( $login_auth && self::validate_guest_login( $login_auth ) ) {
202 self::$current_user = new WPSC_Current_User( $login_auth->email );
203 return;
204 }
205
206 self::$current_user = new WPSC_Current_User();
207 }
208
209 /**
210 * Change current user
211 *
212 * @param string $email - email string.
213 *
214 * @return string
215 */
216 public static function change_current_user( $email ) {
217
218 $current_user = new WPSC_Current_User( $email );
219 self::$current_user = $current_user;
220 return self::$current_user;
221 }
222
223 /**
224 * Return ticket list filters for the user.
225 *
226 * @return array
227 */
228 public function get_tl_filters() {
229
230 $filters = array(
231 'default' => array(),
232 'saved' => array(),
233 );
234
235 // default filters.
236 $default_filters = get_option( $this->is_agent ? 'wpsc-atl-default-filters' : 'wpsc-ctl-default-filters' );
237 foreach ( $default_filters as $index => $filter ) {
238
239 // exclude if current user does not have access to deleted filter.
240 if ( $index === 'deleted' && ! $this->agent->has_cap( 'dtt-access' ) ) {
241 continue;
242 }
243
244 // exclude if filter is not enabled.
245 if ( ! $filter['is_enable'] ) {
246 continue;
247 }
248
249 $filters['default'][ $index ] = $filter;
250 }
251
252 // saved filters.
253 $filters['saved'] = $this->get_saved_filters();
254
255 // return filters.
256 return $filters;
257 }
258
259 /**
260 * Return all saved filters for current user
261 *
262 * @return array
263 */
264 public function get_saved_filters() {
265
266 $saved_filters = ! $this->is_guest && $this->user->ID ? get_user_meta( $this->user->ID, get_current_blog_id() . '-wpsc-tl-saved-filters', true ) : array();
267 return $saved_filters ? $saved_filters : array();
268 }
269
270 /**
271 * Return attachment auth for URLs created in rest api
272 *
273 * @return string
274 */
275 public function get_attachment_auth() {
276
277 $now = new DateTime();
278 $diff = new DateInterval( 'PT1H' );
279
280 $auth = get_user_meta( $this->user->ID, get_current_blog_id() . '-wpsc-rest-attachment-auth', true );
281 if ( $auth ) {
282 $dt = new DateTime( $auth['date'] );
283 if ( $now < $dt->add( $diff ) ) {
284 return $auth['key'];
285 }
286 }
287
288 $auth = array(
289 'key' => WPSC_Functions::get_random_string( 12 ),
290 'date' => $now->format( 'Y-m-d H:i:s' ),
291 );
292 update_user_meta( $this->user->ID, get_current_blog_id() . '-wpsc-rest-attachment-auth', $auth );
293 return $auth['key'];
294 }
295
296 /**
297 * Get ticket list items
298 *
299 * @return array
300 */
301 public function get_tl_list_items() {
302
303 return $this->is_agent ? get_option( 'wpsc-atl-list-items' ) : get_option( 'wpsc-ctl-list-items' );
304 }
305
306 /**
307 * Get default orderby
308 *
309 * @return array
310 */
311 public function get_tl_default_settings() {
312
313 return $this->is_agent ? get_option( 'wpsc-tl-ms-agent-view' ) : get_option( 'wpsc-tl-ms-customer-view' );
314 }
315
316 /**
317 * Return system query for the current user for ticket list
318 *
319 * @param array $filters - filters.
320 * @return array
321 */
322 public function get_tl_system_query( $filters ) {
323
324 $current_user = self::$current_user;
325
326 $adv_setting = get_option( 'wpsc-ms-advanced-settings' );
327 if ( $adv_setting['public-mode'] && ! $current_user->is_agent ) {
328 return $filters;
329 }
330
331 $system_query = array( 'relation' => 'OR' );
332
333 $system_query[] = array(
334 'slug' => 'customer',
335 'compare' => '=',
336 'val' => $this->customer->id,
337 );
338
339 if ( $this->is_agent ) {
340
341 if ( $this->agent->has_cap( 'view-assigned-me' ) ) {
342 $system_query[] = array(
343 'slug' => 'assigned_agent',
344 'compare' => '=',
345 'val' => $this->agent->id,
346 );
347 }
348
349 if ( $this->agent->has_cap( 'view-unassigned' ) ) {
350 $system_query[] = array(
351 'slug' => 'assigned_agent',
352 'compare' => '=',
353 'val' => '',
354 );
355 }
356
357 if ( $this->agent->has_cap( 'view-assigned-others' ) ) {
358 $system_query[] = array(
359 'slug' => 'assigned_agent',
360 'compare' => 'NOT IN',
361 'val' => array( $this->agent->id, '' ),
362 );
363 }
364 }
365
366 return apply_filters( 'wpsc_tl_current_user_system_query', $system_query, $filters, $this );
367 }
368
369 /**
370 * Return system query for the current user for ticket list
371 *
372 * @param array $filters - filters.
373 * @return array
374 */
375 public function get_atl_system_query( $filters ) {
376
377 $system_query = array( 'relation' => 'OR' );
378
379 $system_query[] = array(
380 'slug' => 'customer',
381 'compare' => '=',
382 'val' => $this->customer->id,
383 );
384
385 if ( $this->is_agent ) {
386
387 if ( $this->agent->has_cap( 'at-assigned-me' ) ) {
388 $system_query[] = array(
389 'slug' => 'assigned_agent',
390 'compare' => '=',
391 'val' => $this->agent->id,
392 );
393 }
394
395 if ( $this->agent->has_cap( 'at-unassigned' ) ) {
396 $system_query[] = array(
397 'slug' => 'assigned_agent',
398 'compare' => '=',
399 'val' => '',
400 );
401 }
402
403 if ( $this->agent->has_cap( 'at-assigned-others' ) ) {
404 $system_query[] = array(
405 'slug' => 'assigned_agent',
406 'compare' => 'NOT IN',
407 'val' => array( $this->agent->id, '' ),
408 );
409 }
410 }
411
412 return apply_filters( 'wpsc_atl_current_user_system_query', $system_query, $filters, $this );
413 }
414
415 /**
416 * Check login for default login form
417 *
418 * @return void
419 */
420 public static function check_user_login() {
421
422 if ( check_ajax_referer( 'wpsc_default_login', '_ajax_nonce', false ) != 1 ) {
423 wp_send_json_error( 'Unauthorized request!', 401 );
424 }
425
426 WPSC_MS_Recaptcha::validate( 'submit_login' );
427
428 $username = isset( $_POST['username'] ) ? sanitize_text_field( wp_unslash( $_POST['username'] ) ) : '';
429 if ( ! $username ) {
430 wp_send_json_error( 'Bad request', 400 );
431 }
432
433 $password = isset( $_POST['password'] ) ? $_POST['password'] : ''; // phpcs:ignore
434 if ( ! $password ) {
435 wp_send_json_error( 'Bad request', 400 );
436 }
437
438 $remember_me = isset( $_POST['remember_me'] ) ? true : false;
439
440 $user = wp_signon(
441 array(
442 'user_login' => $username,
443 'user_password' => $password,
444 'remember' => $remember_me,
445 )
446 );
447
448 if ( is_wp_error( $user ) ) {
449
450 $auth_errors = array(
451 'incorrect_password',
452 'invalid_username',
453 'empty_username',
454 'empty_password',
455 );
456 $code = $user->get_error_code();
457 if ( in_array( $code, $auth_errors, true ) ) {
458
459 wp_send_json_error(
460 array(
461 'code' => 'invalid_login',
462 'message' => __( 'Invalid username or password.', 'supportcandy' ),
463 ),
464 401
465 );
466 }
467
468 wp_send_json_error(
469 array(
470 'code' => $code,
471 'message' => wp_strip_all_tags( $user->get_error_message() ),
472 ),
473 400
474 );
475 }
476 wp_send_json_success();
477 }
478
479 /**
480 * Get user registration
481 *
482 * @return void
483 */
484 public static function get_user_registration() {
485
486 $page_settings = get_option( 'wpsc-gs-page-settings' );
487 $recaptcha = get_option( 'wpsc-recaptcha-settings' );
488 $tc = get_option( 'wpsc-term-and-conditions' );
489 $gdpr = get_option( 'wpsc-gdpr-settings' );
490 if ( $page_settings['user-registration'] !== 'default' ) {
491 wp_send_json_error( __( 'Unauthorized', 'supportcandy' ), 401 );
492 }?>
493
494 <h2><?php esc_attr_e( 'Please sign up', 'supportcandy' ); ?></h2>
495 <form onsubmit="return false;" class="wpsc-login wpsc-authenticate-registration">
496 <input type="text" name="firstname" placeholder="<?php esc_attr_e( 'First Name', 'supportcandy' ); ?>" autocomplete="off"/>
497 <input type="text" name="lastname" placeholder="<?php esc_attr_e( 'Last Name', 'supportcandy' ); ?>" autocomplete="off"/>
498
499 <div style="margin: 0 0 5px !important;">
500 <input id="wpsc-username" type="text" name="username" style="margin-bottom: 0px !important;" placeholder="<?php esc_attr_e( 'Username', 'supportcandy' ); ?>" autocomplete="off"/>
501 <small id="wpsc-username-unavailable" style="color: #e84118;font-style:italic;display:none;"><?php esc_attr_e( 'Username is already taken!', 'supportcandy' ); ?></small>
502 <small id="wpsc-username-available" style="color: #4cd137;font-style:italic;display:none;"><?php esc_attr_e( 'Username is available!', 'supportcandy' ); ?></small>
503 <script>
504 jQuery('#wpsc-username').change(function(){
505 jQuery('#wpsc-username-available').hide();
506 jQuery('#wpsc-username-unavailable').hide();
507 var username = jQuery(this).val().trim();
508 const data = { action: 'wpsc_check_user_availability', type : 'username', username, _ajax_nonce: '<?php echo esc_attr( wp_create_nonce( 'wpsc_check_user_availability' ) ); ?>' };
509 jQuery.post(supportcandy.ajax_url, data, function (response) {
510 jQuery('input[name=is_username]').val(response.isAvailable);
511 if (response.isAvailable == 1) {
512 jQuery('#wpsc-username-unavailable').hide();
513 jQuery('#wpsc-username-available').show();
514 } else {
515 jQuery('#wpsc-username-available').hide();
516 jQuery('#wpsc-username-unavailable').show();
517 }
518 });
519 });
520 </script>
521 </div>
522
523 <div style="margin: 0 0 5px !important;">
524 <input id="wpsc-email" type="text" name="email_address" style="margin-bottom: 0px !important;" placeholder="<?php esc_attr_e( 'Email Address', 'supportcandy' ); ?>" autocomplete="off"/>
525 <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>
526 <small id="wpsc-email-available" style="color: #4cd137;font-style:italic;display:none;"><?php esc_attr_e( 'Email is available!', 'supportcandy' ); ?></small>
527 <script>
528 jQuery('#wpsc-email').change(function(){
529 jQuery('#wpsc-email-available').hide();
530 jQuery('#wpsc-email-unavailable').hide();
531 var email = jQuery(this).val().trim();
532 const data = { action: 'wpsc_check_user_availability', type: 'email', email, _ajax_nonce: '<?php echo esc_attr( wp_create_nonce( 'wpsc_check_user_availability' ) ); ?>' };
533 jQuery.post(supportcandy.ajax_url, data, function (response) {
534 jQuery('input[name=is_email]').val(response.isAvailable);
535 if (response.isAvailable == 1) {
536 jQuery('#wpsc-email-unavailable').hide();
537 jQuery('#wpsc-email-available').show();
538 } else {
539 jQuery('#wpsc-email-available').hide();
540 jQuery('#wpsc-email-unavailable').show();
541 }
542 });
543 });
544 </script>
545 </div>
546 <input type="password" name="password" placeholder="<?php esc_attr_e( 'Password', 'supportcandy' ); ?>"/>
547 <input type="password" name="confirm_password" placeholder="<?php esc_attr_e( 'Confirm Password', 'supportcandy' ); ?>"/>
548 <?php
549
550 // recaptcha.
551 if ( $recaptcha['captcha-provider'] === 'google-recaptcha' && $recaptcha['recaptcha-version'] == 2 && $recaptcha['recaptcha-site-key'] && $recaptcha['recaptcha-secret-key'] ) {
552 $unique_id = uniqid( 'wpsc_' );
553 ?>
554 <script src="https://www.google.com/recaptcha/api.js?onload=recaptchaCallback&render=explicit" async defer></script> <?php // phpcs:ignore ?>
555 <div id="<?php echo esc_attr( $unique_id ); ?>" data-sitekey="" style="margin-bottom: 5px;"></div>
556 <script>
557 var recaptchaCallback = function() {
558 var obj = jQuery('#<?php echo esc_attr( $unique_id ); ?>');
559 grecaptcha.render(obj.attr("id"), {
560 "sitekey" : "<?php echo esc_attr( $recaptcha['recaptcha-site-key'] ); ?>",
561 "callback" : function(token) {
562 obj.closest('form').find(".g-recaptcha-response").val(token);
563 }
564 });
565 }
566 </script>
567 <?php
568 }
569 if ( $recaptcha['captcha-provider'] === 'google-recaptcha' && $recaptcha['recaptcha-version'] == 3 && $recaptcha['recaptcha-site-key'] && $recaptcha['recaptcha-secret-key'] ) {
570 ?>
571 <script src="https://www.google.com/recaptcha/api.js?render=<?php echo esc_attr( $recaptcha['recaptcha-site-key'] ); ?>"></script> <?php // phpcs:ignore ?>
572 <?php
573 }
574 if ( $recaptcha['captcha-provider'] === 'cloudflare-turnstile' && $recaptcha['cloudflare-site-key'] && $recaptcha['cloudflare-secret-key'] ) {
575 ?>
576 <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> <?php // phpcs:ignore ?>
577 <div class="wpsc-tff turnstile wpsc-xs-12 wpsc-sm-12 wpsc-md-12 wpsc-lg-12 required wpsc-visible" data-cft="turnstile">
578 <div class="cf-turnstile" data-sitekey="<?php echo esc_attr( $recaptcha['cloudflare-site-key'] ); ?>"></div>
579 </div>
580 <script>
581 jQuery(document).ready(function() {
582
583 function wpscInitTurnstileWidgets() {
584
585 if (
586 typeof window.turnstile === 'undefined' ||
587 typeof window.turnstile.render !== 'function'
588 ) {
589 return false;
590 }
591
592 jQuery('.cf-turnstile').each(function() {
593
594 var widget = jQuery(this);
595
596 if (
597 widget.find('input[name="cf-turnstile-response"]').length ||
598 widget.find('iframe').length ||
599 widget.attr('data-wpsc-rendered') === '1'
600 ) {
601
602 widget.attr('data-wpsc-rendered', '1');
603
604 return;
605 }
606
607 window.turnstile.render(
608 this,
609 {
610 sitekey: widget.data('sitekey')
611 }
612 );
613
614 widget.attr('data-wpsc-rendered', '1');
615 });
616
617 return true;
618 }
619
620 if (wpscInitTurnstileWidgets()) {
621 return;
622 }
623
624 var attempts = 0;
625
626 var timer = setInterval(
627 function() {
628
629 attempts++;
630
631 if (
632 wpscInitTurnstileWidgets() ||
633 attempts > 50
634 ) {
635
636 clearInterval(timer);
637 }
638
639 },
640 100
641 );
642
643 });
644 </script>
645 <?php
646 }
647 do_action( 'wpsc_registration_form' );
648 ?>
649 <div class="wpsc-reg-user">
650 <?php
651 if ( $tc['allow-term-and-conditions-reg-user'] ) :
652 ?>
653 <div class="wpsc-tff term-and-conditions wpsc-xs-12 wpsc-sm-12 wpsc-md-12 wpsc-lg-12 required wpsc-visible" data-cft="term-and-conditions-reg-user">
654 <div class="checkbox-container">
655 <?php $unique_id = uniqid( 'wpsc_' ); ?>
656 <input name="wpsc-tandc-reg-user" id="<?php echo esc_attr( $unique_id ); ?>" type="checkbox" value="1"/>
657 <?php
658 $name = WPSC_Translations::get( 'wpsc-term-and-conditions-reg-user', stripslashes( $tc['tandc-text-reg-user'] ) );
659 ?>
660 <label for="<?php echo esc_attr( $unique_id ); ?>"><?php echo wp_kses_post( $name ); ?></label>
661 </div>
662 </div>
663 <?php
664 endif;
665
666 if ( $gdpr['allow-gdpr-reg-user'] ) {
667 ?>
668 <div class="wpsc-tff wpsc-gdpr wpsc-xs-12 wpsc-sm-12 wpsc-md-12 wpsc-lg-12 required wpsc-visible" data-cft="gdpr-reg-user">
669 <div class="checkbox-container">
670 <?php $unique_id = uniqid( 'wpsc_' ); ?>
671 <input name="wpsc-gdpr-reg-user" id="<?php echo esc_attr( $unique_id ); ?>" type="checkbox" value="1"/>
672 <?php
673 $name = WPSC_Translations::get( 'wpsc-gdpr-reg-user', stripslashes( $gdpr['gdpr-text-reg-user'] ) );
674 ?>
675 <label for="<?php echo esc_attr( $unique_id ); ?>"><?php echo wp_kses_post( $name ); ?></label>
676 </div>
677 </div>
678 <?php
679 }
680 ?>
681 </div>
682
683 <button class="wpsc-button normal primary" onclick="wpsc_set_default_registration(this)"><?php esc_attr_e( 'Sign Up', 'supportcandy' ); ?></button>
684 <button class="wpsc-button normal secondary" onclick="window.location.reload();"><?php esc_attr_e( 'Cancel', 'supportcandy' ); ?></button>
685 <input type="hidden" name="action" value="wpsc_authenticate_registration"/>
686 <input type="hidden" name="is_username" value="0"/>
687 <input type="hidden" name="is_email" value="0"/>
688 <input type="hidden" name="_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wpsc_authenticate_registration' ) ); ?>">
689 </form>
690 <?php
691 wp_die();
692 }
693
694 /**
695 * Check username availability
696 *
697 * @return void
698 */
699 public static function check_user_availability() {
700
701 if ( check_ajax_referer( 'wpsc_check_user_availability', '_ajax_nonce', false ) != 1 ) {
702 wp_send_json_error( 'Unauthorized request!', 401 );
703 }
704
705 $page_settings = get_option( 'wpsc-gs-page-settings' );
706 if ( $page_settings['user-registration'] !== 'default' ) {
707 wp_send_json_error( __( 'Unauthorized', 'supportcandy' ), 401 );
708 }
709
710 $type = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';
711 if ( in_array( $type, array( 'username', 'email' ) ) === false ) {
712 wp_send_json_error( 'Something went wrong', 400 );
713 }
714
715 if ( $type === 'username' ) {
716 $username = isset( $_POST['username'] ) ? sanitize_user( wp_unslash( $_POST['username'] ) ) : '';
717 if ( ! $username ) {
718 wp_send_json_error( 'Something went wrong', 400 );
719 }
720 } elseif ( $type === 'email' ) {
721 $email = isset( $_POST['email'] ) && filter_var( wp_unslash( $_POST['email'] ), FILTER_VALIDATE_EMAIL ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
722 if ( ! $email ) {
723 wp_send_json_error( 'Something went wrong', 400 );
724 }
725 }
726 $flag = $type === 'username' ? self::is_username_available( $username ) : self::is_email_available( $email );
727
728 wp_send_json( array( 'isAvailable' => $flag ? 0 : 1 ) );
729 }
730
731 /**
732 * Send registration OTP for email authentication
733 *
734 * @return void
735 */
736 public static function send_registration_otp() {
737
738 if ( check_ajax_referer( 'wpsc_authenticate_registration', '_ajax_nonce', false ) != 1 ) {
739 wp_send_json_error( 'Unauthorized request!', 401 );
740 }
741 $page_settings = get_option( 'wpsc-gs-page-settings' );
742 if ( $page_settings['user-registration'] !== 'default' ) {
743 wp_send_json_error( __( 'Unauthorized', 'supportcandy' ), 401 );
744 }
745
746 WPSC_MS_Recaptcha::validate( 'submit_registration' );
747
748 $firstname = isset( $_POST['firstname'] ) ? sanitize_text_field( wp_unslash( $_POST['firstname'] ) ) : '';
749 if ( ! $firstname ) {
750 wp_send_json_error( 'Bad request', 400 );
751 }
752
753 $lastname = isset( $_POST['lastname'] ) ? sanitize_text_field( wp_unslash( $_POST['lastname'] ) ) : '';
754 if ( ! $lastname ) {
755 wp_send_json_error( 'Bad request', 400 );
756 }
757
758 $username = isset( $_POST['username'] ) ? sanitize_user( wp_unslash( $_POST['username'] ) ) : '';
759 if ( ! $username ) {
760 wp_send_json_error( 'Bad request', 400 );
761 }
762
763 if ( self::is_username_available( $username ) ) {
764 wp_send_json_error( 'Bad request', 400 );
765 }
766
767 $email_address = isset( $_POST['email_address'] ) && filter_var( wp_unslash( $_POST['email_address'] ), FILTER_VALIDATE_EMAIL ) ? sanitize_email( wp_unslash( $_POST['email_address'] ) ) : '';
768 if ( ! $email_address ) {
769 wp_send_json_error( 'Bad request', 400 );
770 }
771
772 if ( self::is_email_available( $email_address ) ) {
773 wp_send_json_error( 'Bad request', 400 );
774 }
775
776 $password = isset( $_POST['password'] ) ? wp_unslash( $_POST['password'] ) : ''; // phpcs:ignore
777 if ( ! $password ) {
778 wp_send_json_error( 'Bad request', 400 );
779 }
780
781 $data = array(
782 'firstname' => $firstname,
783 'lastname' => $lastname,
784 'username' => $username,
785 'email_address' => $email_address,
786 'password' => $password,
787 );
788
789 $data = apply_filters( 'wpsc_register_user_data', $data );
790
791 $otp = WPSC_Email_OTP::insert(
792 array(
793 'email' => $email_address,
794 'date_expiry' => ( new DateTime() )->add( new DateInterval( 'PT1H' ) )->format( 'Y-m-d H:i:s' ),
795 'data' => wp_json_encode( $data ),
796 )
797 );
798
799 // send email notification.
800 WPSC_EN_User_Reg_OTP::send_otp( $otp );
801 ?>
802
803 <h2><?php esc_attr_e( 'Please sign up', 'supportcandy' ); ?></h2>
804 <small style="margin: 0 0 5px;"><?php esc_attr_e( 'We have sent a one-time verification code to your email address.', 'supportcandy' ); ?></small>
805 <form onsubmit="return false;" class="wpsc-login wpsc-confirm-registration">
806 <input type="text" name="otp" autocomplete="off"/>
807 <button class="wpsc-button normal primary" onclick="wpsc_confirm_registration(this)"><?php esc_attr_e( 'Submit', 'supportcandy' ); ?></button>
808 <input type="hidden" name="action" value="wpsc_confirm_registration"/>
809 <input type="hidden" name="otp_id" value="<?php echo esc_attr( $otp->id ); ?>">
810 <input type="hidden" name="_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wpsc_confirm_registration' ) ); ?>"/>
811 </form>
812 <?php
813 wp_die();
814 }
815
816 /**
817 * Checks whether username is available or not
818 *
819 * @param string $username - user name string.
820 * @return boolean
821 */
822 public static function is_username_available( $username ) {
823
824 $user = get_user_by( 'login', $username );
825 return $user ? true : false;
826 }
827
828 /**
829 * Checks whether email is available or not
830 *
831 * @param string $email - email string.
832 * @return boolean
833 */
834 public static function is_email_available( $email ) {
835
836 $user = get_user_by( 'email', $email );
837
838 // check allowed email domains.
839 $allowed_domains = apply_filters( 'wpsc_registration_allowed_email_domains', array() );
840 $domain = substr( strrchr( $email, '@' ), 1 );
841 if ( $allowed_domains && ! in_array( $domain, $allowed_domains, true ) ) {
842 return true;
843 }
844 return $user ? true : false;
845 }
846
847 /**
848 * Register user after OTP matched
849 *
850 * @return void
851 */
852 public static function register_user() {
853
854 if ( check_ajax_referer( 'wpsc_confirm_registration', '_ajax_nonce', false ) != 1 ) {
855 wp_send_json_error( 'Unauthorized request!', 401 );
856 }
857
858 $page_settings = get_option( 'wpsc-gs-page-settings' );
859 if ( $page_settings['user-registration'] !== 'default' ) {
860 wp_send_json_error( __( 'Unauthorized', 'supportcandy' ), 401 );
861 }
862
863 $verification_otp = isset( $_POST['otp'] ) ? sanitize_text_field( wp_unslash( $_POST['otp'] ) ) : '';
864 if ( ! $verification_otp ) {
865 wp_send_json_error( 'Bad request', 400 );
866 }
867
868 $id = isset( $_POST['otp_id'] ) ? intval( $_POST['otp_id'] ) : '';
869 if ( ! $id ) {
870 wp_send_json_error( 'Bad request', 400 );
871 }
872
873 $otp = new WPSC_Email_OTP( $id );
874 if ( ! $otp->id ) {
875 wp_send_json_error( 'Bad request', 400 );
876 }
877
878 if ( ! $otp->is_valid( $verification_otp ) ) {
879 wp_send_json( array( 'isSuccess' => 0 ) );
880 wp_die();
881 }
882
883 $data = json_decode( $otp->data );
884
885 // check allowed email domains.
886 $allowed_domains = apply_filters( 'wpsc_registration_allowed_email_domains', array() );
887 $domain = substr( strrchr( $data->email_address, '@' ), 1 );
888 if ( $allowed_domains && ! in_array( $domain, $allowed_domains, true ) ) {
889 wp_send_json_error(
890 array(
891 'isSuccess' => 0,
892 'message' => __( 'Email domain is not allowed.', 'supportcandy' ),
893 ),
894 403
895 );
896 }
897
898 // insert user.
899 $display_name = $data->firstname . ' ' . $data->lastname;
900 $user_id = wp_insert_user(
901 array(
902 'user_login' => $data->username,
903 'user_pass' => $data->password,
904 'user_email' => $data->email_address,
905 'first_name' => $data->firstname,
906 'last_name' => $data->lastname,
907 'display_name' => $display_name,
908 'role' => 'subscriber',
909 )
910 );
911 if ( is_wp_error( $user_id ) ) {
912 wp_send_json( array( 'isSuccess' => 0 ) );
913 wp_die();
914 }
915
916 $user = wp_signon(
917 array(
918 'user_login' => $data->username,
919 'user_password' => $data->password,
920 )
921 );
922 wp_new_user_notification( $user_id, null, 'admin' );
923 do_action( 'wpsc_after_user_registration', $user, $data );
924 wp_send_json( array( 'isSuccess' => 1 ) );
925 }
926
927 /**
928 * User registrstion OTP email template section
929 *
930 * @param array $sections - section name.
931 * @return array
932 */
933 public static function registration_email_template_section( $sections ) {
934
935 $sections['registration-otp'] = array(
936 'slug' => 'registration_otp',
937 'icon' => 'unlock',
938 'label' => esc_attr__( 'User Registration OTP', 'supportcandy' ),
939 'callback' => 'wpsc_get_en_user_reg_otp',
940 );
941 return $sections;
942 }
943
944 /**
945 * Get guest sign in screen
946 *
947 * @return void
948 */
949 public static function get_guest_sign_in() {
950
951 $gs = get_option( 'wpsc-gs-general' );
952 $page_settings = get_option( 'wpsc-gs-page-settings' );
953 if ( ! ( $page_settings['otp-login'] && in_array( 'guest', $gs['allow-create-ticket'] ) ) ) {
954 wp_send_json_error( 'Unauthorozed', 400 );
955 }
956 ?>
957
958 <h2><?php esc_attr_e( 'Please sign in', 'supportcandy' ); ?></h2>
959 <form onsubmit="return false;" class="wpsc-login authenticate-guest-login">
960 <input type="text" name="email_address" placeholder="<?php esc_attr_e( 'Email Address', 'supportcandy' ); ?>" autocomplete="off"/>
961 <button class="wpsc-button normal primary" onclick="wpsc_authenticate_guest_login(this)"><?php esc_attr_e( 'Sign In', 'supportcandy' ); ?></button>
962 <button class="wpsc-button normal secondary" onclick="window.location.reload();"><?php esc_attr_e( 'Cancel', 'supportcandy' ); ?></button>
963 <input type="hidden" name="action" value="wpsc_authenticate_guest_login"/>
964 <input type="hidden" name="_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wpsc_authenticate_guest_login' ) ); ?>">
965 </form>
966 <?php
967 wp_die();
968 }
969
970 /**
971 * Get OTP screen
972 *
973 * @return void
974 */
975 public static function get_guest_sign_in_auth() {
976
977 if ( check_ajax_referer( 'wpsc_authenticate_guest_login', '_ajax_nonce', false ) != 1 ) {
978 wp_send_json_error( 'Unauthorized request!', 401 );
979 }
980 $gs = get_option( 'wpsc-gs-general' );
981 $page_settings = get_option( 'wpsc-gs-page-settings' );
982 if ( ! ( $page_settings['otp-login'] && in_array( 'guest', $gs['allow-create-ticket'] ) ) ) {
983 wp_send_json_error( 'Unauthorozed', 400 );
984 }
985
986 $email_address = isset( $_POST['email_address'] ) && filter_var( wp_unslash( $_POST['email_address'] ), FILTER_VALIDATE_EMAIL ) ? sanitize_text_field( wp_unslash( $_POST['email_address'] ) ) : '';
987 if ( ! $email_address ) {
988 wp_send_json_error( 'Bad request', 400 );
989 }
990
991 $customer = WPSC_Customer::get_by_email( $email_address );
992 if ( ! $customer->id ) {
993 esc_attr_e( 'Invalid email address!', 'supportcandy' );
994 wp_die();
995 }
996
997 $otp = WPSC_Email_OTP::insert(
998 array(
999 'email' => $email_address,
1000 'date_expiry' => ( new DateTime() )->add( new DateInterval( 'P1D' ) )->format( 'Y-m-d H:i:s' ),
1001 'data' => wp_json_encode(
1002 array(
1003 'email' => $email_address,
1004 )
1005 ),
1006 )
1007 );
1008
1009 // Send OTP for login.
1010 WPSC_EN_Guest_Login_OTP::send_otp( $otp );
1011 ?>
1012
1013 <h2><?php esc_attr_e( 'Please sign in', 'supportcandy' ); ?></h2>
1014 <small style="margin: 0 0 5px;"><?php esc_attr_e( 'We have sent a one-time verification code to your email address.', 'supportcandy' ); ?></small>
1015 <form onsubmit="return false;" class="wpsc-login wpsc-confirm-guest-login">
1016 <input type="text" name="otp" autocomplete="off"/>
1017 <button class="wpsc-button normal primary" onclick="wpsc_confirm_guest_login(this)"><?php esc_attr_e( 'Submit', 'supportcandy' ); ?></button>
1018 <input type="hidden" name="action" value="wpsc_confirm_guest_login"/>
1019 <input type="hidden" name="otp_id" value="<?php echo esc_attr( $otp->id ); ?>">
1020 <input type="hidden" name="_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wpsc_confirm_guest_login' ) ); ?>">
1021 </form>
1022 <?php
1023 wp_die();
1024 }
1025
1026 /**
1027 * Confirm guest login
1028 *
1029 * @return void
1030 */
1031 public static function confirm_guest_login() {
1032
1033 // Add rate limiting.
1034 $ip_address = WPSC_DF_IP_Address::get_current_user_ip();
1035 $attempt_key = 'wpsc_otp_attempts_' . md5( $ip_address );
1036 $attempts = get_transient( $attempt_key );
1037 $attempts = $attempts ? $attempts : 1;
1038
1039 if ( $attempts >= 5 ) {
1040 wp_send_json_error( 'Too many attempts. Please try again later.', 429 );
1041 }
1042
1043 if ( check_ajax_referer( 'wpsc_confirm_guest_login', '_ajax_nonce', false ) != 1 ) {
1044 wp_send_json_error( 'Unauthorized request!', 401 );
1045 }
1046
1047 $gs = get_option( 'wpsc-gs-general' );
1048 $page_settings = get_option( 'wpsc-gs-page-settings' );
1049 if ( ! ( $page_settings['otp-login'] && in_array( 'guest', $gs['allow-create-ticket'] ) ) ) {
1050 wp_send_json_error( 'Unauthorozed', 400 );
1051 }
1052
1053 $verification_otp = isset( $_POST['otp'] ) ? sanitize_text_field( wp_unslash( $_POST['otp'] ) ) : '';
1054 if ( ! $verification_otp ) {
1055 wp_send_json_error( 'Bad request', 400 );
1056 }
1057
1058 $id = isset( $_POST['otp_id'] ) ? intval( $_POST['otp_id'] ) : '';
1059 if ( ! $id ) {
1060 wp_send_json_error( 'Bad request', 400 );
1061 }
1062
1063 $otp = new WPSC_Email_OTP( $id );
1064 if ( ! $otp->id ) {
1065 wp_send_json_error( 'Bad request', 400 );
1066 }
1067
1068 if ( ! $otp->is_valid( $verification_otp ) ) {
1069
1070 // Increment attempt counter.
1071 ++$attempts;
1072 set_transient( $attempt_key, $attempts, 300 ); // 5 minute lockout.
1073
1074 // Add per-OTP attempt tracking.
1075 $otp_attempt_key = 'wpsc_otp_' . $id . '_attempts';
1076 $otp_attempts = get_transient( $otp_attempt_key );
1077 $otp_attempts = $otp_attempts ? $otp_attempts + 1 : 1;
1078 set_transient( $otp_attempt_key, $otp_attempts, 600 );
1079
1080 if ( $otp_attempts >= 3 ) {
1081 WPSC_Email_OTP::destroy( $otp );
1082 wp_send_json_error( 'OTP has been invalidated due to too many failed attempts', 403 );
1083 }
1084
1085 wp_send_json( array( 'isSuccess' => 0 ) );
1086 wp_die();
1087 }
1088
1089 $data = json_decode( $otp->data, true );
1090 $data['auth_token'] = WPSC_Functions::get_random_string( 100 );
1091 $data['auth_type'] = 'login';
1092 $otp->data = wp_json_encode( $data );
1093 $otp->save();
1094
1095 // Clear rate limiting on success.
1096 delete_transient( $attempt_key );
1097
1098 // add customer record if not set.
1099 $customer = WPSC_Customer::get_by_email( $data['email'] );
1100 if ( ! $customer->id ) {
1101 $user = get_user_by( 'email', $data['email'] );
1102 if ( $user ) {
1103
1104 WPSC_Customer::insert(
1105 array(
1106 'user' => $user->ID,
1107 'name' => $user->display_name,
1108 'email' => $user->user_email,
1109 )
1110 );
1111
1112 } else {
1113
1114 WPSC_Customer::insert(
1115 array(
1116 'user' => 0,
1117 'name' => $data['name'],
1118 'email' => $data['email'],
1119 )
1120 );
1121 }
1122 }
1123
1124 $auth = array(
1125 'email' => $otp->email,
1126 'token' => $data['auth_token'],
1127 );
1128
1129 setcookie( 'wpsc_guest_login_auth', wp_json_encode( $auth ), $otp->date_expiry->getTimestamp(), '/' );
1130
1131 wp_send_json( array( 'isSuccess' => 1 ) );
1132 }
1133
1134 /**
1135 * Validate login auth token
1136 *
1137 * @param object $login_auth - login auth details.
1138 * @return boolean
1139 */
1140 public static function validate_guest_login( $login_auth ) {
1141
1142 $gs = get_option( 'wpsc-gs-general' );
1143 $page_settings = get_option( 'wpsc-gs-page-settings' );
1144
1145 $results = WPSC_Email_OTP::find(
1146 array(
1147 'meta_query' => array(
1148 'relation' => 'AND',
1149 array(
1150 'slug' => 'email',
1151 'compare' => '=',
1152 'val' => $login_auth->email,
1153 ),
1154 ),
1155 )
1156 )['results'];
1157
1158 if ( ! $results ) {
1159 return false;
1160 }
1161
1162 $otp = $results[0];
1163 if ( ! $otp->id ) {
1164 return false;
1165 }
1166
1167 $now = new DateTime();
1168 $data = json_decode( $otp->data );
1169
1170 if (
1171 isset( $data->auth_type ) &&
1172 ( ( $data->auth_type == 'login' && $page_settings['otp-login'] && in_array( 'guest', $gs['allow-create-ticket'] ) ) || $data->auth_type == 'open-ticket' ) &&
1173 ( $otp->date_expiry > $now && $data->auth_token == $login_auth->token )
1174 ) {
1175 self::$login_type = 'guest';
1176 self::$guest_login_type = $data->auth_type;
1177 return true;
1178 }
1179
1180 return false;
1181 }
1182
1183 /**
1184 * Add guest login email template
1185 *
1186 * @param array $sections - section name.
1187 * @return array
1188 */
1189 public static function guest_login_email_template_section( $sections ) {
1190
1191 $sections['guest-login-otp'] = array(
1192 'slug' => 'guest_login_otp',
1193 'icon' => 'unlock',
1194 'label' => esc_attr__( 'Guest Login OTP', 'supportcandy' ),
1195 'callback' => 'wpsc_get_en_guest_login_otp',
1196 );
1197 return $sections;
1198 }
1199
1200 /**
1201 * Logout current user
1202 *
1203 * @return void
1204 */
1205 public function logout() {
1206
1207 global $current_user;
1208
1209 $otp = WPSC_Email_OTP::find(
1210 array(
1211 'meta_query' => array(
1212 'relation' => 'AND',
1213 array(
1214 'slug' => 'email',
1215 'compare' => '=',
1216 'val' => $this->customer->email,
1217 ),
1218 ),
1219 )
1220 )['results'];
1221
1222 if ( $otp ) :
1223 WPSC_Email_OTP::destroy( $otp[0] );
1224 @setcookie( 'wpsc_guest_login_auth', '', time(), '/' ); //phpcs:ignore
1225 endif;
1226
1227 if ( $current_user->ID ) {
1228 wp_logout();
1229 }
1230 }
1231 }
1232 endif;
1233
1234 WPSC_Current_User::init();
1235