66 * Plugin Name: Tawk.to Live Chat
77 * Plugin URI: https://www.tawk.to
88 * Description: Embeds Tawk.to live chat widget to your site
9- * Version: 0.9.0
9+ * Version: 0.9.1
1010 * Author: Tawkto
1111 * Text Domain: tawk-to-live-chat
1212 * License: GPLv3
@@ -27,12 +27,12 @@ class TawkTo_Settings {
2727 const TAWK_VISIBILITY_OPTIONS = 'tawkto-visibility-options ' ;
2828 const TAWK_PRIVACY_OPTIONS = 'tawkto-privacy-options ' ;
2929 const TAWK_SECURITY_OPTIONS = 'tawkto-security-options ' ;
30+ const TAWK_CONFIG_VERSION = 'tawkto-config-version ' ;
3031 const TAWK_ACTION_SET_WIDGET = 'tawkto-set-widget ' ;
3132 const TAWK_ACTION_REMOVE_WIDGET = 'tawkto-remove-widget ' ;
3233 const CIPHER = 'AES-256-CBC ' ;
3334 const CIPHER_IV_LENGTH = 16 ;
3435 const NO_CHANGE = 'nochange ' ;
35- const TAWK_API_KEY = 'tawkto-js-api-key ' ;
3636
3737 /**
3838 * @var $plugin_ver Plugin version
@@ -132,6 +132,7 @@ public function admin_init() {
132132 register_setting ( 'tawk_options ' , self ::TAWK_VISIBILITY_OPTIONS , array ( &$ this , 'validate_visibility_options ' ) );
133133 register_setting ( 'tawk_options ' , self ::TAWK_PRIVACY_OPTIONS , array ( &$ this , 'validate_privacy_options ' ) );
134134 register_setting ( 'tawk_options ' , self ::TAWK_SECURITY_OPTIONS , array ( &$ this , 'validate_security_options ' ) );
135+ register_setting ( 'tawk_options ' , self ::TAWK_CONFIG_VERSION , array ( &$ this , 'update_config_version ' ) );
135136 }
136137
137138 /**
@@ -326,6 +327,15 @@ public function validate_security_options( $input ) {
326327 return $ security ;
327328 }
328329
330+ /**
331+ * Updates the config version
332+ *
333+ * @return int
334+ */
335+ public function update_config_version () {
336+ return get_option ( self ::TAWK_CONFIG_VERSION , 0 ) + 1 ;
337+ }
338+
329339 /**
330340 * Adds the tawk.to plugin settings in the admin menu.
331341 */
@@ -418,20 +428,20 @@ private static function validate_js_api_key( &$fields ) {
418428 return ;
419429 }
420430
421- delete_transient ( self ::TAWK_API_KEY );
422-
423431 if ( '' === $ fields ['js_api_key ' ] ) {
424432 return ;
425433 }
426434
427- try {
428- if ( 40 !== strlen ( $ fields ['js_api_key ' ] ) ) {
429- throw new Exception ( 'Invalid key. Please provide value with 40 characters ' );
430- }
435+ $ fields ['js_api_key ' ] = trim ( $ fields ['js_api_key ' ] );
431436
437+ if ( 40 !== strlen ( $ fields ['js_api_key ' ] ) ) {
438+ self ::show_tawk_options_error ( 'Invalid API key ' );
439+ }
440+
441+ try {
432442 $ fields ['js_api_key ' ] = self ::get_encrypted_data ( $ fields ['js_api_key ' ] );
433443 } catch ( Exception $ e ) {
434- self ::show_tawk_options_error ( 'Javascript API Key: ' . $ e -> getMessage () );
444+ self ::show_tawk_options_error ( 'Error saving Javascript API Key' );
435445
436446 unset( $ fields ['js_api_key ' ] );
437447 }
@@ -524,12 +534,12 @@ private static function get_encrypted_data( $data ) {
524534 * @param string $data - Data to be decrypted.
525535 * @return string
526536 */
527- private static function get_decrypted_data ( $ data ) {
537+ public static function get_decrypted_data ( $ data ) {
528538 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
529539 $ decoded_data = base64_decode ( $ data );
530540
531541 if ( false === $ decoded_data ) {
532- return '' ;
542+ return null ;
533543 }
534544
535545 $ iv = substr ( $ decoded_data , 0 , self ::CIPHER_IV_LENGTH );
@@ -538,35 +548,12 @@ private static function get_decrypted_data( $data ) {
538548 $ decrypted_data = openssl_decrypt ( $ encrypted_data , self ::CIPHER , SECURE_AUTH_KEY , 0 , $ iv );
539549
540550 if ( false === $ decrypted_data ) {
541- return '' ;
551+ return null ;
542552 }
543553
544554 return $ decrypted_data ;
545555 }
546556
547- /**
548- * Retrieves JS API Key
549- *
550- * @return string
551- */
552- public static function get_js_api_key () {
553- if ( ! empty ( get_transient ( self ::TAWK_API_KEY ) ) ) {
554- return get_transient ( self ::TAWK_API_KEY );
555- }
556-
557- $ security = get_option ( self ::TAWK_SECURITY_OPTIONS );
558-
559- if ( ! isset ( $ security ['js_api_key ' ] ) ) {
560- return '' ;
561- }
562-
563- $ key = self ::get_decrypted_data ( $ security ['js_api_key ' ] );
564-
565- set_transient ( self ::TAWK_API_KEY , $ key , 60 * 60 );
566-
567- return $ key ;
568- }
569-
570557 /**
571558 * Adds settings error
572559 *
@@ -599,6 +586,7 @@ private static function show_tawk_options_error( $message ) {
599586 */
600587 class TawkTo {
601588 const PLUGIN_VERSION_VARIABLE = 'tawkto-version ' ;
589+ const TAWK_VISITOR_SESSION = 'tawkto-visitor-session ' ;
602590
603591 /**
604592 * @var $plugin_version Plugin version
@@ -613,6 +601,41 @@ class TawkTo {
613601 public function __construct () {
614602 $ tawkto_settings = new TawkTo_Settings ();
615603 add_shortcode ( 'tawkto ' , array ( $ this , 'shortcode_print_embed_code ' ) );
604+
605+ add_action ( 'init ' , array ( $ this , 'start_session ' ) );
606+ }
607+
608+
609+ /**
610+ * Starts user session
611+ *
612+ * @return void
613+ */
614+ public function start_session () {
615+ $ privacy = get_option ( TawkTo_Settings::TAWK_PRIVACY_OPTIONS );
616+
617+ if ( empty ( $ privacy ['enable_visitor_recognition ' ] ) ) {
618+ return ;
619+ }
620+
621+ $ security = get_option ( TawkTo_Settings::TAWK_SECURITY_OPTIONS );
622+
623+ if ( empty ( $ security ['js_api_key ' ] ) ) {
624+ return ;
625+ }
626+
627+ if ( session_status () === PHP_SESSION_NONE ) {
628+ session_start ();
629+
630+ // If user is not logged in, remove the visitor session and close the session.
631+ // Session cannot be updated if it is not started.
632+ if ( ! is_user_logged_in () ) {
633+ if ( isset ( $ _SESSION [ self ::TAWK_VISITOR_SESSION ] ) ) {
634+ unset( $ _SESSION [ self ::TAWK_VISITOR_SESSION ] );
635+ }
636+ session_write_close ();
637+ }
638+ }
616639 }
617640
618641 /**
@@ -658,9 +681,8 @@ public static function deactivate() {
658681 delete_option ( TawkTo_Settings::TAWK_VISIBILITY_OPTIONS );
659682 delete_option ( TawkTo_Settings::TAWK_PRIVACY_OPTIONS );
660683 delete_option ( TawkTo_Settings::TAWK_SECURITY_OPTIONS );
684+ delete_option ( TawkTo_Settings::TAWK_CONFIG_VERSION );
661685 delete_option ( self ::PLUGIN_VERSION_VARIABLE );
662-
663- delete_transient ( TawkTo_Settings::TAWK_API_KEY );
664686 }
665687
666688 /**
@@ -683,16 +705,58 @@ public function get_current_customer_details() {
683705 'email ' => $ current_user ->user_email ,
684706 );
685707
686- $ js_api_key = TawkTo_Settings:: get_js_api_key ( );
687- if ( ! empty ( $ user_info [ ' email ' ] ) && ! empty ( $ js_api_key ) ) {
688- $ user_info ['hash ' ] = hash_hmac ( ' sha256 ' , $ user_info [ ' email ' ], $ js_api_key ) ;
708+ $ hash = self :: get_visitor_hash ( $ user_info [ ' email ' ] );
709+ if ( null !== $ hash ) {
710+ $ user_info ['hash ' ] = $ hash ;
689711 }
690712
691713 return wp_json_encode ( $ user_info );
692714 }
693715 return null ;
694716 }
695717
718+ /**
719+ * Retrieves visitor hash
720+ *
721+ * @param string $email - Visitor email address.
722+ * @return string
723+ */
724+ public static function get_visitor_hash ( $ email ) {
725+ $ security = get_option ( TawkTo_Settings::TAWK_SECURITY_OPTIONS );
726+
727+ if ( empty ( $ security ['js_api_key ' ] ) ) {
728+ return null ;
729+ }
730+
731+ $ config_version = get_option ( TawkTo_Settings::TAWK_CONFIG_VERSION , 0 );
732+
733+ if ( isset ( $ _SESSION [ self ::TAWK_VISITOR_SESSION ] ) ) {
734+ $ current_session = $ _SESSION [ self ::TAWK_VISITOR_SESSION ];
735+
736+ if ( isset ( $ current_session ['hash ' ] ) &&
737+ $ current_session ['email ' ] === $ email &&
738+ $ current_session ['config_version ' ] === $ config_version ) {
739+ return $ current_session ['hash ' ];
740+ }
741+ }
742+
743+ $ key = TawkTo_Settings::get_decrypted_data ( $ security ['js_api_key ' ] );
744+
745+ if ( null === $ key ) {
746+ return null ;
747+ }
748+
749+ $ hash = hash_hmac ( 'sha256 ' , $ email , $ key );
750+
751+ $ _SESSION [ self ::TAWK_VISITOR_SESSION ] = array (
752+ 'hash ' => $ hash ,
753+ 'email ' => $ email ,
754+ 'config_version ' => $ config_version ,
755+ );
756+
757+ return $ hash ;
758+ }
759+
696760 /**
697761 * Creates the embed code
698762 */
0 commit comments