From c6dd2f1958c7e8062f149b2a2a9b4b87e9c79424 Mon Sep 17 00:00:00 2001 From: eug-L Date: Thu, 28 Nov 2024 12:46:35 +0800 Subject: [PATCH 1/2] add api key input and encryption for visitor recognition --- .eslintrc.js | 1 + tawkto/assets/js/tawk.admin.js | 20 ++++++++++ tawkto/includes/default_config.php | 1 + tawkto/tawkto.php | 59 ++++++++++++++++++++++++++++++ tawkto/templates/settings.php | 24 ++++++++++++ 5 files changed, 105 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index ad36a2c..31a2999 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,6 +1,7 @@ 'use-strict'; module.exports = { + 'root': true, 'env': { 'browser': true, 'jquery': true diff --git a/tawkto/assets/js/tawk.admin.js b/tawkto/assets/js/tawk.admin.js index 22e4f03..0062cd2 100644 --- a/tawkto/assets/js/tawk.admin.js +++ b/tawkto/assets/js/tawk.admin.js @@ -72,6 +72,26 @@ jQuery( jQuery( this ).addClass( 'reverse' ); }); + + if ( jQuery( '#enable-visitor-recognition' ).prop( 'checked' ) ) { + jQuery( '.tawk-selected-visitor' ).show(); + jQuery( '#js-api-key' ).prop( 'disabled', false ); + } else { + jQuery( '.tawk-selected-visitor' ).hide(); + jQuery( '#js-api-key' ).prop( 'disabled', true ); + } + + jQuery( '#enable-visitor-recognition' ).change( + function() { + if ( this.checked ) { + jQuery( '.tawk-selected-visitor' ).fadeIn(); + jQuery( '#js-api-key' ).prop( 'disabled', false ); + } else { + jQuery( '.tawk-selected-visitor' ).fadeOut(); + jQuery( '#js-api-key' ).prop( 'disabled', true ); + } + } + ); } ); diff --git a/tawkto/includes/default_config.php b/tawkto/includes/default_config.php index 1658e85..a5a67e5 100644 --- a/tawkto/includes/default_config.php +++ b/tawkto/includes/default_config.php @@ -16,5 +16,6 @@ 'display_on_productpage' => 0, 'display_on_producttag' => 0, 'enable_visitor_recognition' => 1, + 'js_api_key' => '', ), ); diff --git a/tawkto/tawkto.php b/tawkto/tawkto.php index 444fba6..2607b4c 100644 --- a/tawkto/tawkto.php +++ b/tawkto/tawkto.php @@ -27,6 +27,8 @@ class TawkTo_Settings { const TAWK_VISIBILITY_OPTIONS = 'tawkto-visibility-options'; const TAWK_ACTION_SET_WIDGET = 'tawkto-set-widget'; const TAWK_ACTION_REMOVE_WIDGET = 'tawkto-remove-widget'; + const CIPHER = 'AES-256-CBC'; + const CIPHER_IV_LENGTH = 16; /** * @var $plugin_ver Plugin version @@ -249,6 +251,7 @@ public function validate_options( $input ) { $visibility_text_fields = array( 'excluded_url_list', 'included_url_list', + 'js_api_key', ); self::validate_visibility_toggle_fields( $input, $visibility_toggle_fields ); @@ -329,6 +332,11 @@ private static function validate_text_fields( &$fields, $field_names ) { foreach ( $field_names as $field_name ) { if ( isset( $fields[ $field_name ] ) ) { $fields[ $field_name ] = sanitize_text_field( $fields[ $field_name ] ); + + if ( 'js_api_key' === $field_name && ! empty( $fields['js_api_key'] ) ) { + $fields['js_api_key'] = self::get_encrypted_data( $fields['js_api_key'] ); + } + continue; } @@ -365,6 +373,51 @@ public static function get_default_visibility_options() { return $config['visibility']; } + /** + * Encrypt data + * + * @param string $data - Data to be encrypted. + * @return string + */ + private static function get_encrypted_data( $data ) { + $iv = openssl_random_pseudo_bytes( self::CIPHER_IV_LENGTH ); + + $encrypted_data = openssl_encrypt( $data, self::CIPHER, SECURE_AUTH_KEY, 0, $iv ); + + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode + return base64_encode( $iv . $encrypted_data ); + } + + /** + * Decrypt data + * + * @param string $data - Data to be decrypted. + * @return string + */ + private static function get_decrypted_data( $data ) { + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode + $decoded_data = base64_decode( $data ); + + $iv = substr( $decoded_data, 0, self::CIPHER_IV_LENGTH ); + $encrypted_data = substr( $decoded_data, self::CIPHER_IV_LENGTH ); + + return openssl_decrypt( $encrypted_data, self::CIPHER, SECURE_AUTH_KEY, 0, $iv ); + } + + /** + * Retrieves JS API Key + * + * @return string + */ + public static function get_js_api_key() { + $visibility = get_option( self::TAWK_VISIBILITY_OPTIONS ); + + if ( isset( $visibility['js_api_key'] ) ) { + return self::get_decrypted_data( $visibility['js_api_key'] ); + } + + return ''; + } } } @@ -463,6 +516,12 @@ public function get_current_customer_details() { 'name' => $current_user->display_name, 'email' => $current_user->user_email, ); + + $js_api_key = TawkTo_Settings::get_js_api_key(); + if ( ! empty( $js_api_key ) ) { + $user_info['hash'] = hash_hmac( 'sha256', $user_info['email'], $js_api_key ); + } + return wp_json_encode( $user_info ); } return null; diff --git a/tawkto/templates/settings.php b/tawkto/templates/settings.php index 47650e3..9dc67f3 100644 --- a/tawkto/templates/settings.php +++ b/tawkto/templates/settings.php @@ -412,6 +412,30 @@ class="slider round" + +
+

+ + + + + +

+ + + + + + +
+ + + +
+
From a011f8f29703637359f23cc3b1f6bc425afe4ba4 Mon Sep 17 00:00:00 2001 From: eug-L Date: Thu, 28 Nov 2024 15:09:01 +0800 Subject: [PATCH 2/2] encryption error handling, check email on hashing & input pattern validation --- tawkto/tawkto.php | 32 ++++++++++++++++++++++++++++---- tawkto/templates/settings.php | 4 +++- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/tawkto/tawkto.php b/tawkto/tawkto.php index 2607b4c..6866dad 100644 --- a/tawkto/tawkto.php +++ b/tawkto/tawkto.php @@ -380,12 +380,26 @@ public static function get_default_visibility_options() { * @return string */ private static function get_encrypted_data( $data ) { - $iv = openssl_random_pseudo_bytes( self::CIPHER_IV_LENGTH ); + try { + $iv = random_bytes( self::CIPHER_IV_LENGTH ); + } catch ( Exception $e ) { + return ''; + } $encrypted_data = openssl_encrypt( $data, self::CIPHER, SECURE_AUTH_KEY, 0, $iv ); + if ( false === $encrypted_data ) { + return ''; + } + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode - return base64_encode( $iv . $encrypted_data ); + $encrypted_data = base64_encode( $iv . $encrypted_data ); + + if ( false === $encrypted_data ) { + return ''; + } + + return $encrypted_data; } /** @@ -398,10 +412,20 @@ private static function get_decrypted_data( $data ) { // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode $decoded_data = base64_decode( $data ); + if ( false === $decoded_data ) { + return ''; + } + $iv = substr( $decoded_data, 0, self::CIPHER_IV_LENGTH ); $encrypted_data = substr( $decoded_data, self::CIPHER_IV_LENGTH ); - return openssl_decrypt( $encrypted_data, self::CIPHER, SECURE_AUTH_KEY, 0, $iv ); + $decrypted_data = openssl_decrypt( $encrypted_data, self::CIPHER, SECURE_AUTH_KEY, 0, $iv ); + + if ( false === $decrypted_data ) { + return ''; + } + + return $decrypted_data; } /** @@ -518,7 +542,7 @@ public function get_current_customer_details() { ); $js_api_key = TawkTo_Settings::get_js_api_key(); - if ( ! empty( $js_api_key ) ) { + if ( ! empty( $user_info['email'] ) && ! empty( $js_api_key ) ) { $user_info['hash'] = hash_hmac( 'sha256', $user_info['email'], $js_api_key ); } diff --git a/tawkto/templates/settings.php b/tawkto/templates/settings.php index 9dc67f3..1cc2c8b 100644 --- a/tawkto/templates/settings.php +++ b/tawkto/templates/settings.php @@ -431,7 +431,9 @@ class="slider round" + value="" + pattern="^[a-zA-Z0-9]+$" + autocomplete="off" />