Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use-strict';

module.exports = {
'root': true,
'env': {
'browser': true,
'jquery': true
Expand Down
20 changes: 20 additions & 0 deletions tawkto/assets/js/tawk.admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}
}
);
}
);

Expand Down
1 change: 1 addition & 0 deletions tawkto/includes/default_config.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@
'display_on_productpage' => 0,
'display_on_producttag' => 0,
'enable_visitor_recognition' => 1,
'js_api_key' => '',
),
);
59 changes: 59 additions & 0 deletions tawkto/tawkto.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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 );
}
Comment on lines +494 to +519
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for openssl_encrypt failures.

The encryption method needs additional error handling:

  1. Check if the OpenSSL extension is loaded
  2. Verify the cipher method exists

Apply this diff to improve error handling:

 private static function get_encrypted_data( $data ) {
+    if (!extension_loaded('openssl')) {
+        throw new Exception('OpenSSL extension is not loaded');
+    }
+
+    if (!in_array(self::CIPHER, openssl_get_cipher_methods())) {
+        throw new Exception('Cipher method not supported');
+    }
+
     if ( ! defined( 'SECURE_AUTH_KEY' ) ) {
         throw new Exception( 'SECURE_AUTH_KEY is not defined' );
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static function get_encrypted_data( $data ) {
if ( ! defined( 'SECURE_AUTH_KEY' ) ) {
throw new Exception( 'SECURE_AUTH_KEY is not defined' );
}
try {
$iv = random_bytes( self::CIPHER_IV_LENGTH );
} catch ( Exception $e ) {
throw new Exception( 'Error generating IV' );
}
$encrypted_data = openssl_encrypt( $data, self::CIPHER, SECURE_AUTH_KEY, 0, $iv );
if ( false === $encrypted_data ) {
throw new Exception( 'Error encrypting data' );
}
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
$encrypted_data = base64_encode( $iv . $encrypted_data );
if ( false === $encrypted_data ) {
throw new Exception( 'Error encoding data' );
}
return $encrypted_data;
}
private static function get_encrypted_data( $data ) {
if (!extension_loaded('openssl')) {
throw new Exception('OpenSSL extension is not loaded');
}
if (!in_array(self::CIPHER, openssl_get_cipher_methods())) {
throw new Exception('Cipher method not supported');
}
if ( ! defined( 'SECURE_AUTH_KEY' ) ) {
throw new Exception( 'SECURE_AUTH_KEY is not defined' );
}
try {
$iv = random_bytes( self::CIPHER_IV_LENGTH );
} catch ( Exception $e ) {
throw new Exception( 'Error generating IV' );
}
$encrypted_data = openssl_encrypt( $data, self::CIPHER, SECURE_AUTH_KEY, 0, $iv );
if ( false === $encrypted_data ) {
throw new Exception( 'Error encrypting data' );
}
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
$encrypted_data = base64_encode( $iv . $encrypted_data );
if ( false === $encrypted_data ) {
throw new Exception( 'Error encoding data' );
}
return $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 '';
}
}
}

Expand Down Expand Up @@ -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;
Expand Down
24 changes: 24 additions & 0 deletions tawkto/templates/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,30 @@ class="slider round"
</td>
</tr>
</table>

<div class="tawk-selected-visitor">
<p class='tawk-notice'>
<?php esc_html_e( 'Note: If ', 'tawk-to-live-chat' ); ?>
<b><?php esc_html_e( 'Secure Mode', 'tawk-to-live-chat' ); ?></b>
<?php esc_html_e( ' is enabled on your property, please enter your ', 'tawk-to-live-chat' ); ?>
<b><?php esc_html_e( 'Javascript API Key', 'tawk-to-live-chat' ); ?></b>
<?php esc_html_e( ' for visitor recognition to work correctly.', 'tawk-to-live-chat' ); ?>
</p>

<table class="form-table">
<tr valign="top">
<th class="tawk-setting" scope="row">
<?php esc_html_e( 'Javascript API Key', 'tawk-to-live-chat' ); ?>
</th>
<td>
<input type="password"
id="js-api-key"
name="tawkto-visibility-options[js_api_key]"
value="<?php echo esc_attr( $visibility['js_api_key'] ); ?>" />
</td>
</tr>
</table>
</div>
</div>
</form>
</div>
Expand Down