Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/secure-mode-support #39

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

feature/secure-mode-support #39

wants to merge 2 commits into from

Conversation

eug-L
Copy link
Contributor

@eug-L eug-L commented Nov 28, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new input field for the JavaScript API key under "Privacy Options" for visitor recognition.
    • Added functionality to toggle visibility elements based on the visitor recognition checkbox.
  • Enhancements

    • Improved security by implementing encryption for the JavaScript API key.
    • Enhanced visibility options with clearer descriptions and structured formatting.
  • Bug Fixes

    • Streamlined logic for displaying widget settings to improve readability.

Copy link

coderabbitai bot commented Nov 28, 2024

Walkthrough

The changes in this pull request encompass updates across multiple files to enhance the functionality and security of the Tawk.to plugin. Key modifications include the addition of a root property in the ESLint configuration, new visitor recognition features in JavaScript, the introduction of a JavaScript API key in the configuration, and significant updates to the TawkTo_Settings class for improved data handling and encryption. Additionally, a new input field for the API key has been integrated into the settings template, along with various refinements to the user interface and validation processes.

Changes

File Change Summary
.eslintrc.js Added property 'root': true to indicate root configuration for ESLint.
tawkto/assets/js/tawk.admin.js Introduced visitor recognition functionality based on the #enable-visitor-recognition checkbox.
tawkto/includes/default_config.php Added new configuration option 'js_api_key' => '' in the visibility array.
tawkto/tawkto.php Added constants for encryption, updated validation methods, and introduced methods for data encryption/decryption.
tawkto/templates/settings.php Added a new input field for the JavaScript API key and refined the settings display and logic.

Poem

In the burrow where changes bloom,
A key for JavaScript finds its room.
With toggles and checks, the visitors see,
A world of options, as bright as can be!
Encryption whispers, secrets kept tight,
Hopping along, all feels just right! 🐇✨


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (6)
tawkto/includes/default_config.php (1)

19-19: Consider separating security configurations from visibility settings

The js_api_key is placed within the visibility array, but it's a security credential rather than a visibility setting. Consider creating a separate security or authentication configuration section to better organize and maintain security-related settings.

 return array(
 	'visibility' => array(
 		'always_display'             => 1,
 		// ... other visibility settings ...
-		'js_api_key'                 => '',
 	),
+	'security' => array(
+		'js_api_key'                 => '',
+	),
 );
tawkto/assets/js/tawk.admin.js (3)

76-82: Consider clearing the API key field when disabled

When visitor recognition is disabled, consider clearing the API key field value in addition to disabling it. This prevents any stored API key from being visible in the DOM when the feature is disabled.

 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( '#js-api-key' ).val('');
 }

84-94: Enhance change handler implementation

Two suggestions for improvement:

  1. Clear the API key field when disabling visitor recognition
  2. Add a consistent animation duration for better UX alignment with other animations in the file
 jQuery( '#enable-visitor-recognition' ).change(
   function() {
     if ( this.checked ) {
-      jQuery( '.tawk-selected-visitor' ).fadeIn();
+      jQuery( '.tawk-selected-visitor' ).fadeIn(400);
       jQuery( '#js-api-key' ).prop( 'disabled', false );
     } else {
-      jQuery( '.tawk-selected-visitor' ).fadeOut();
+      jQuery( '.tawk-selected-visitor' ).fadeOut(400);
       jQuery( '#js-api-key' ).prop( 'disabled', true );
+      jQuery( '#js-api-key' ).val('');
     }
   }
 );

75-94: Consider additional security measures for API key handling

Since this code handles sensitive API key information, consider implementing these security measures:

  1. Add input validation for the API key format
  2. Consider implementing a secure way to test the API key validity
  3. Ensure the API key is properly sanitized before being saved

Would you like assistance in implementing any of these security measures?

tawkto/templates/settings.php (1)

416-423: Enhance the notice with additional context and documentation

Consider adding a link to the Tawk.to documentation about Secure Mode and its benefits to help users make informed decisions.

 <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' ); ?>
+  <br/>
+  <a href="https://www.tawk.to/knowledgebase/secure-mode" target="_blank" rel="noopener noreferrer">
+    <?php esc_html_e( 'Learn more about Secure Mode', 'tawk-to-live-chat' ); ?>
+  </a>
 </p>
tawkto/tawkto.php (1)

30-31: Use openssl_cipher_iv_length() to determine IV length instead of hardcoding

To ensure compatibility with the specified cipher and improve maintainability, consider using openssl_cipher_iv_length(self::CIPHER) to dynamically determine the IV length instead of hardcoding CIPHER_IV_LENGTH as 16. This approach ensures that the IV length always matches the requirements of the cipher algorithm.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 740763d and c6dd2f1.

📒 Files selected for processing (5)
  • .eslintrc.js (1 hunks)
  • tawkto/assets/js/tawk.admin.js (1 hunks)
  • tawkto/includes/default_config.php (1 hunks)
  • tawkto/tawkto.php (5 hunks)
  • tawkto/templates/settings.php (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .eslintrc.js
🔇 Additional comments (2)
tawkto/includes/default_config.php (1)

19-19: Verify secure handling of the API key

Since this is a sensitive credential being introduced as part of secure mode support, let's verify the implementation of proper security measures in the related files.

✅ Verification successful

Let me verify the encryption functions to ensure complete security. I'll check the implementation of encryption/decryption methods.


Let me try a different approach to check the encryption methods and frontend usage.


Let me check one final aspect about the cipher configuration and usage.


API key implementation follows security best practices

The implementation shows proper security measures:

  • The API key is encrypted using AES-256-CBC with a random IV before storage
  • Encryption uses WordPress's SECURE_AUTH_KEY constant
  • The key is properly escaped when output in forms
  • No direct exposure of the key in JavaScript
  • Key is only used server-side for HMAC generation
  • Decryption is properly handled with base64 decode and IV separation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for proper encryption and secure handling of js_api_key

# Check if the key is properly encrypted when stored
rg -A 5 "js_api_key" --type php

# Look for encryption-related functions handling this key
ast-grep --pattern 'function $_($$js_api_key) {
  $$$
}'

# Check for any direct/unencrypted usage of the key
rg -i "js_api_key.*=.*['\"]\w+['\"]" --type php

Length of output: 2304


Script:

#!/bin/bash
# Check the implementation of encryption/decryption methods
ast-grep --pattern 'function get_encrypted_data($_) {
  $$$
}'

ast-grep --pattern 'function get_decrypted_data($_) {
  $$$
}'

# Check how the key is used in frontend/output
rg -A 3 "wp_localize_script.*js_api" --type php

Length of output: 179


Script:

#!/bin/bash
# Search for encryption-related functions in the class
rg -A 10 "function get_(en|de)crypted_data" --type php

# Check how the API key is passed to frontend
rg -A 5 "wp_localize_script|wp_add_inline_script" --type php

# Look for any direct output of the key
rg "echo.*js_api" --type php

Length of output: 1757


Script:

#!/bin/bash
# Check cipher configuration
rg -A 2 "CIPHER.*=" --type php

# Check if the key is used in any JavaScript
rg -g "*.js" "js_api|api_key" 

# Check for any WordPress hooks/filters related to the key
rg "add_filter|apply_filters.*js_api" --type php

Length of output: 394

tawkto/templates/settings.php (1)

415-438: Add API key validation and test functionality

Consider adding immediate validation feedback and a test connection feature to help users verify their configuration.

 <div class="tawk-selected-visitor">
   <!-- ... existing code ... -->
   <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'] ); ?>" />
+        <button type="button" 
+          class="button" 
+          id="test-api-key"
+          onclick="testApiKey()"
+          <?php echo empty($visibility['js_api_key']) ? 'disabled' : ''; ?>>
+          <?php esc_html_e( 'Test Connection', 'tawk-to-live-chat' ); ?>
+        </button>
+        <p class="description" id="js-api-key-status"></p>
       </td>
     </tr>
   </table>
 </div>

Add this JavaScript to handle the test functionality:

function testApiKey() {
  const apiKey = document.getElementById('js-api-key').value;
  const statusEl = document.getElementById('js-api-key-status');
  
  // Show loading state
  statusEl.textContent = 'Testing connection...';
  
  // Make an AJAX call to test the API key
  // This requires implementing an endpoint in the plugin's PHP code
  jQuery.post(ajaxurl, {
    action: 'test_tawkto_api_key',
    api_key: apiKey,
    nonce: tawktoSettings.nonce
  })
  .done(function(response) {
    if (response.success) {
      statusEl.style.color = '#00a32a';
      statusEl.textContent = 'Connection successful!';
    } else {
      statusEl.style.color = '#d63638';
      statusEl.textContent = response.data.message || 'Connection failed!';
    }
  })
  .fail(function() {
    statusEl.style.color = '#d63638';
    statusEl.textContent = 'Connection test failed. Please try again.';
  });
}

// Enable/disable test button based on API key input
document.getElementById('js-api-key').addEventListener('input', function() {
  document.getElementById('test-api-key').disabled = !this.value;
});

tawkto/templates/settings.php Outdated Show resolved Hide resolved
tawkto/tawkto.php Show resolved Hide resolved
tawkto/tawkto.php Outdated Show resolved Hide resolved
tawkto/tawkto.php Outdated Show resolved Hide resolved
tawkto/tawkto.php Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (3)
tawkto/tawkto.php (1)

376-403: Improve error handling in encryption method.

While the method handles basic error cases, it could be enhanced:

  1. Add logging for encryption failures
  2. Consider throwing exceptions instead of returning empty strings
 private static function get_encrypted_data( $data ) {
     try {
         $iv = random_bytes( self::CIPHER_IV_LENGTH );
     } catch ( Exception $e ) {
+        error_log( 'Failed to generate IV: ' . $e->getMessage() );
         return '';
     }

     $encrypted_data = openssl_encrypt( $data, self::CIPHER, SECURE_AUTH_KEY, 0, $iv );

     if ( false === $encrypted_data ) {
+        error_log( 'Failed to encrypt data with OpenSSL' );
         return '';
     }

     // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
     $encrypted_data = base64_encode( $iv . $encrypted_data );

     if ( false === $encrypted_data ) {
+        error_log( 'Failed to base64 encode encrypted data' );
         return '';
     }

     return $encrypted_data;
 }
tawkto/templates/settings.php (2)

418-422: Typographical correction: 'Javascript' should be 'JavaScript'

In the notice text, "Javascript API Key" should be spelled "JavaScript API Key" to reflect the correct spelling of "JavaScript".


428-428: Typographical correction: 'Javascript' should be 'JavaScript'

In the label, "Javascript API Key" should be updated to "JavaScript API Key" for accurate spelling.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c6dd2f1 and a011f8f.

📒 Files selected for processing (2)
  • tawkto/tawkto.php (5 hunks)
  • tawkto/templates/settings.php (1 hunks)
🔇 Additional comments (8)
tawkto/tawkto.php (5)

30-31: LGTM! Encryption configuration looks secure.

The chosen cipher (AES-256-CBC) and IV length (16 bytes) follow cryptographic best practices.


254-254: Consider using a more appropriate sanitization method for API keys.

The current implementation uses sanitize_text_field() which might alter special characters in the API key.

Also applies to: 335-339


436-444: LGTM! API key getter implementation is secure.

The method properly handles missing or invalid API keys by returning an empty string.


543-548: LGTM! Secure implementation of visitor recognition.

The code correctly:

  1. Checks for empty email and API key before computing hash
  2. Uses HMAC-SHA256 for secure hash generation

411-429: 🛠️ Refactor suggestion

Add input validation in decryption method.

The method should validate the input length before attempting decryption.

 private static function get_decrypted_data( $data ) {
+    if ( empty( $data ) ) {
+        return '';
+    }
+
     // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
     $decoded_data = base64_decode( $data );

     if ( false === $decoded_data ) {
+        error_log( 'Failed to base64 decode encrypted data' );
         return '';
     }

+    if ( strlen( $decoded_data ) <= self::CIPHER_IV_LENGTH ) {
+        error_log( 'Decoded data is too short' );
+        return '';
+    }

     $iv             = substr( $decoded_data, 0, self::CIPHER_IV_LENGTH );
     $encrypted_data = substr( $decoded_data, self::CIPHER_IV_LENGTH );

     $decrypted_data = openssl_decrypt( $encrypted_data, self::CIPHER, SECURE_AUTH_KEY, 0, $iv );

     if ( false === $decrypted_data ) {
+        error_log( 'Failed to decrypt data with OpenSSL' );
         return '';
     }

     return $decrypted_data;
 }

Likely invalid or redundant comment.

tawkto/templates/settings.php (3)

435-435: Reconsider the input validation pattern for 'JavaScript API Key'

The current pattern ^[a-zA-Z0-9]+$ allows only letters and digits. If the API key may include other characters such as hyphens or underscores, consider updating the pattern to accommodate them.

You can adjust the pattern as follows:

-								pattern="^[a-zA-Z0-9]+$"
+								pattern="^[a-zA-Z0-9-_]+$"

434-436: Add a placeholder to the API key input field for better user guidance

Including a placeholder can improve user experience by indicating what the user should enter.

You can add the placeholder attribute:

								value="<?php echo esc_attr( $visibility['js_api_key'] ); ?>"
+								placeholder="<?php esc_attr_e( 'Enter your JavaScript API Key', 'tawk-to-live-chat' ); ?>"
								pattern="^[a-zA-Z0-9]+$"

431-436: Enhance the API key input field with a show/hide toggle

Adding a toggle button to show or hide the API key can improve usability while maintaining security.

If you'd like assistance implementing this feature, I can help provide the necessary code or open a GitHub issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant