Plugin Directory

Changeset 3365319


Ignore:
Timestamp:
09/21/2025 03:07:54 PM (7 months ago)
Author:
webfiable
Message:

Update to version 1.4.1 from GitHub

Location:
webfiable-info
Files:
31 added
7 edited
1 copied

Legend:

Unmodified
Added
Removed
  • webfiable-info/assets/banner-772x250.png

    • Property svn:mime-type changed from application/octet-stream to image/png
  • webfiable-info/assets/icon-128x128.png

    • Property svn:mime-type changed from application/octet-stream to image/png
  • webfiable-info/assets/icon-256x256.png

    • Property svn:mime-type changed from application/octet-stream to image/png
  • webfiable-info/tags/1.4.1/readme.txt

    r3244047 r3365319  
    44Requires at least: 5.0
    55Tested up to: 6.7
    6 Stable tag: 1.4
     6Stable tag: 1.4.1
    77License: GPLv3 or later
    88License URI: https://www.gnu.org/licenses/gpl-3.0.html
     
    1515
    1616The Webfiable Info plugin is a component of the Webfiable security service, designed to help you maintain a robust security posture for your WordPress website. By securely gathering information about your site's plugins, themes, and WordPress version, the plugin enables the Webfiable service to perform in-depth analysis and provide weekly recommendations tailored to your specific configuration.
    17 
    18 To verify the plugin's functionality, users and reviewers can visit the **`/webfiable` endpoint** on their website after activation. This endpoint provides encrypted website configuration data for security monitoring. An example of this can be seen at:
    19 
    20 * **Live Example:** [https://webfiable.com/webfiable/](https://webfiable.com/webfiable/)
    21 
    22 == External Services ==
    23 
    24 This plugin connects to the **Webfiable API** to:
    25 1. **Retrieve an RSA public key**, which is required for encrypting website configuration data before making it available to the Webfiable service.
    26 2. **Expose encrypted website configuration data** through the `/webfiable` endpoint, which is queried by `app.webfiable.com` to generate a **security posture report**.
    27 
    28 **Data Sent:** 
    29 - **Public Key Retrieval:** No user-specific data is sent; only a request to retrieve the RSA public key. 
    30 - **Configuration Data Transmission:** The plugin encrypts and exposes the following website information at the `/webfiable` endpoint: 
    31   - Installed plugins (names, slugs, and versions). 
    32   - Installed themes (names, slugs, and versions). 
    33   - WordPress version. 
    34 
    35 **When Data is Sent:** 
    36 - **Public Key Retrieval:** Occurs when encryption is required for the `/webfiable` endpoint. 
    37 - **Configuration Data Transmission:** Happens when `app.webfiable.com` queries the `/webfiable` endpoint to fetch encrypted data for security posture reporting. 
    38 
    39 **Service URL:** 
    40 - [https://app.webfiable.com/public-key.json](https://app.webfiable.com/public-key.json) *(for RSA key retrieval)* 
    41 
    42 **Terms of Service:** 
    43 - [https://webfiable.com/terminos-de-servicio/](https://webfiable.com/terminos-de-servicio/) 
    44 
    45 **Privacy Policy:** 
    46 - [https://webfiable.com/politica-privacidad/](https://webfiable.com/politica-privacidad/) 
    4717
    4818== Features ==
     
    6232* **RSA Key Management**: The RSA encryption ensures that only the Webfiable service can decrypt the transmitted data, using a private key that remains secure on the Webfiable infrastructure.
    6333
    64 == How to Verify Plugin Functionality ==
     34== Why It Is Secure ==
    6535
    66 Once installed and activated, users can verify the functionality of the Webfiable Info plugin by:
     361. **Advanced Encryption Techniques**: Webfiable Info employs AES-256 for data encryption, a standard widely recognized for its strength and security. The AES key is then encrypted with RSA-2048, ensuring that even if the data is intercepted, it cannot be decrypted without the corresponding private RSA key, which is securely stored by Webfiable.
    6737
    68 1. **Checking the `/webfiable` Endpoint**: Visit `https://yourwebsite.com/webfiable/` to confirm that the plugin is providing encrypted configuration data.
    69 2. **Comparing with an Example Site**: You can see an example of the plugin's functionality at:
    70    - [https://webfiable.com/webfiable/](https://webfiable.com/webfiable/)
    71 3. **Ensuring Data Security**: The data exposed at this endpoint is encrypted and can only be decrypted by the Webfiable service.
     382. **Data Integrity**: The use of a unique IV for each transmission guarantees that your data remains confidential and secure, preventing any potential attackers from predicting or replicating encrypted data streams.
     39
     403. **Confidentiality by Design**: The plugin is designed to collect only the necessary information for security analysis, ensuring that your website's sensitive data is handled with the utmost care and never exposed.
    7241
    7342== Installation ==
  • webfiable-info/tags/1.4.1/webfiable-info.php

    r3244047 r3365319  
    44 * Plugin URI: https://webfiable.com/webfiable-info
    55 * Description: Ensure your website's security posture and configuration health with monitoring and recommendations.
    6  * Version: 1.4
     6 * Version: 1.4.1
    77 * Author: Webfiable Team
    88 * Author URI: https://webfiable.com
     
    1010 * License URI: https://www.gnu.org/licenses/gpl-3.0.html
    1111 * Text Domain: webfiable-info
     12 *
     13 * @package Webfiable_Info
    1214 */
    1315
    14 // Prevent direct access
    15 if (!defined('ABSPATH')) {
    16     exit;
     16// Prevent direct access.
     17if ( ! defined( 'ABSPATH' ) ) {
     18    exit;
    1719}
    1820
    19 // Fetch RSA public key dynamically from Webfiable API
    20 function webfiable_get_public_key() {
    21     $response = wp_remote_get('https://app.webfiable.com/public-key.json');
     21// RSA public key (provided by the user).
     22define(
     23    'WEBFIABLE_RSA_PUBLIC_KEY',
     24    '-----BEGIN PUBLIC KEY-----
     25MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw8y6jWyyz5yJzdj1kdDJ
     26KDU54+MryJYTBHogyq8m+557Q8gciul2cAZexdhC6EkIzI/hxwNi/t6fcLiK0hdC
     2788nVaP6B/xkZPuURW/cjtKbCBXo0CLTMNnJSxhECI4Xq5l5koiThdhSvDlqsuMWy
     28xCUUlbvU9Vg+MmiaEiRtZT7Nd5/NSqftqqdiVH0Q6sUd2OEFYPwnDI5615ALLH+h
     29XeaQhTu053Tpqcw6cMNbqOCc9Gk6esoM69oNHtXR2tKxxzWldwb0+mRRypUiPLUn
     30/n/9w5jnPrNsYGu1PVLXb+wlspPyZCSItq4zkzkFPYKvQ7u+U2UY28dHqSeHJhGd
     31FQIDAQAB
     32-----END PUBLIC KEY-----'
     33);
    2234
    23     if (is_wp_error($response)) {
    24         return null;
    25     }
     35/**
     36 * Registers the custom rewrite rule for the `webfiable` endpoint.
     37 *
     38 * Hooked to `init`.
     39 *
     40 * @since 1.4
     41 * @return void
     42 */
     43function webfiable_register_route() {
     44    add_rewrite_rule( '^webfiable$', 'index.php?webfiable_route=1', 'top' );
     45}
     46add_action( 'init', 'webfiable_register_route' );
    2647
    27     $status_code = wp_remote_retrieve_response_code($response);
    28     if ($status_code !== 200) {
    29         return null;
    30     }
     48/**
     49 * Adds the `webfiable_route` query var so WordPress recognizes the endpoint.
     50 *
     51 * Hooked to `query_vars`.
     52 *
     53 * @since 1.4
     54 * @param string[] $vars List of public query vars.
     55 * @return string[] Modified list of query vars.
     56 */
     57function webfiable_add_query_vars( $vars ) {
     58    $vars[] = 'webfiable_route';
     59    return $vars;
     60}
     61add_filter( 'query_vars', 'webfiable_add_query_vars' );
    3162
    32     $body = wp_remote_retrieve_body($response);
    33     if (empty($body)) {
    34         return null;
    35     }
     63/**
     64 * Handles the request to the `webfiable` endpoint and outputs an encrypted JSON payload.
     65 *
     66 * Hooked to `template_redirect`.
     67 *
     68 * Collects WP version, installed plugins and themes, builds a payload, encrypts it
     69 * with a random AES-256-CBC key/IV, encrypts that key with the RSA public key,
     70 * and returns base64-encoded values.
     71 *
     72 * @since 1.4
     73 * @return void
     74 */
     75function webfiable_template_redirect() {
     76    if ( get_query_var( 'webfiable_route' ) ) {
    3677
    37     // Decode JSON
    38     $decoded = json_decode($body, true);
    39     if (json_last_error() !== JSON_ERROR_NONE) {
    40         return null;
    41     }
     78        // Get all installed plugins.
     79        $installed_plugins = get_plugins();
     80        $plugins_info      = array();
    4281
    43     if (!isset($decoded['PublicKey']) || empty($decoded['PublicKey'])) {
    44         return null;
    45     }
     82        foreach ( $installed_plugins as $plugin_slug => $plugin_data ) {
     83            $plugins_info[] = array(
     84                'name'        => $plugin_data['Name'],
     85                'slug'        => dirname( $plugin_slug ),
     86                'version'     => $plugin_data['Version'],
     87                'description' => wp_strip_all_tags( $plugin_data['Description'] ),  // Remove HTML tags from description.
     88            );
     89        }
    4690
    47     // Restore proper RSA key formatting
    48     $public_key = "-----BEGIN PUBLIC KEY-----\n" .
    49                   wordwrap(trim($decoded['PublicKey']), 64, "\n", true) .
    50                   "\n-----END PUBLIC KEY-----";
     91        // Get all installed themes.
     92        $installed_themes = wp_get_themes();
     93        $themes_info      = array();
    5194
    52     // Verify if OpenSSL recognizes the key
    53     $openssl_key = openssl_pkey_get_public($public_key);
    54     if (!$openssl_key) {
    55         return null;
    56     }
     95        foreach ( $installed_themes as $theme_slug => $theme_data ) {
     96            $themes_info[] = array(
     97                'name'        => $theme_data->get( 'Name' ),
     98                'slug'        => $theme_data->get_stylesheet(),
     99                'version'     => $theme_data->get( 'Version' ),
     100                'description' => wp_strip_all_tags( $theme_data->get( 'Description' ) ),  // Remove HTML tags from description.
     101            );
     102        }
    57103
    58     return $public_key;
     104        // Get the WordPress version.
     105        $wordpress_version = get_bloginfo( 'version' );
     106
     107        // Merge all info into one array.
     108        $all_info = array(
     109            'wordpress_version' => $wordpress_version,
     110            'plugins'           => $plugins_info,
     111            'themes'            => $themes_info,
     112        );
     113
     114        // Convert to JSON.
     115        $json_data = wp_json_encode( $all_info );
     116
     117        // Generate a 256-bit AES key.
     118        $aes_key = openssl_random_pseudo_bytes( 32 );
     119
     120        // Encrypt the JSON data with the AES key.
     121        $encrypted_data = openssl_encrypt( $json_data, 'AES-256-CBC', $aes_key, OPENSSL_RAW_DATA, $iv = openssl_random_pseudo_bytes( 16 ) );
     122
     123        // Encrypt the AES key with the RSA public key.
     124        openssl_public_encrypt( $aes_key, $encrypted_key, WEBFIABLE_RSA_PUBLIC_KEY );
     125
     126        // Return both the encrypted AES key and the encrypted JSON data.
     127        // We base64-encode binary values to transport them safely in JSON.
     128        // phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Transport encoding, not obfuscation.
     129        $encoded_key  = base64_encode( $encrypted_key );
     130        $encoded_iv   = base64_encode( $iv );
     131        $encoded_data = base64_encode( $encrypted_data );
     132        // phpcs:enable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
     133
     134        $response = array(
     135            'encrypted_key' => $encoded_key,
     136            'iv'            => $encoded_iv,
     137            'data'          => $encoded_data,
     138        );
     139
     140        // Send JSON response.
     141        wp_send_json( $response );
     142        exit;
     143    }
    59144}
     145add_action( 'template_redirect', 'webfiable_template_redirect' );
    60146
    61 // Register the custom endpoint
    62 function webfiable_register_route() {
    63     add_rewrite_rule('^webfiable$', 'index.php?webfiable_route=1', 'top');
     147/**
     148 * Flushes rewrite rules on plugin activation so the custom endpoint works immediately.
     149 *
     150 * Calls our route registrar and then flushes the rules. This should only run on activation,
     151 * never on every request (for performance reasons).
     152 *
     153 * Hooked via `register_activation_hook()`.
     154 *
     155 * @since 1.4
     156 * @return void
     157 */
     158function webfiable_flush_rewrite_rules() {
     159    webfiable_register_route();
     160    flush_rewrite_rules();
    64161}
    65 add_action('init', 'webfiable_register_route');
     162register_activation_hook( __FILE__, 'webfiable_flush_rewrite_rules' );
    66163
    67 // Add the query var so WP recognizes the custom route
    68 function webfiable_add_query_vars($vars) {
    69     $vars[] = 'webfiable_route';
    70     return $vars;
     164/**
     165 * Flushes rewrite rules on plugin deactivation to remove the custom endpoint.
     166 *
     167 * Hooked via `register_deactivation_hook()`.
     168 *
     169 * @since 1.4
     170 * @return void
     171 */
     172function webfiable_deactivate() {
     173    flush_rewrite_rules();
    71174}
    72 add_filter('query_vars', 'webfiable_add_query_vars');
    73 
    74 // Handle the request and return encrypted JSON response
    75 function webfiable_template_redirect() {
    76     if (get_query_var('webfiable_route')) {
    77 
    78         // Fetch the public key dynamically when handling requests
    79         $public_key = webfiable_get_public_key();
    80         if (!$public_key) {
    81             wp_send_json_error(['error' => 'Failed to retrieve public key. Cannot proceed with encryption.'], 500);
    82             exit;
    83         }
    84 
    85         // Get all installed plugins
    86         $installed_plugins = get_plugins();
    87         $plugins_info = [];
    88 
    89         foreach ($installed_plugins as $plugin_slug => $plugin_data) {
    90             $plugins_info[] = [
    91                 'name'        => $plugin_data['Name'],
    92                 'slug'        => dirname($plugin_slug),
    93                 'version'     => $plugin_data['Version'],
    94                 'description' => wp_strip_all_tags($plugin_data['Description']),
    95             ];
    96         }
    97 
    98         // Get all installed themes
    99         $installed_themes = wp_get_themes();
    100         $themes_info = [];
    101 
    102         foreach ($installed_themes as $theme_slug => $theme_data) {
    103             $themes_info[] = [
    104                 'name'        => $theme_data->get('Name'),
    105                 'slug'        => $theme_data->get_stylesheet(),
    106                 'version'     => $theme_data->get('Version'),
    107                 'description' => wp_strip_all_tags($theme_data->get('Description')),
    108             ];
    109         }
    110 
    111         // Get the WordPress version
    112         $wordpress_version = get_bloginfo('version');
    113 
    114         // Merge all info into one array
    115         $all_info = [
    116             'wordpress_version' => $wordpress_version,
    117             'plugins'           => $plugins_info,
    118             'themes'            => $themes_info,
    119         ];
    120 
    121         // Convert to JSON
    122         $json_data = json_encode($all_info);
    123 
    124         // Generate a 256-bit AES key
    125         $aes_key = openssl_random_pseudo_bytes(32);
    126         $iv = openssl_random_pseudo_bytes(16);
    127 
    128         // Encrypt the JSON data with the AES key
    129         $encrypted_data = openssl_encrypt($json_data, 'AES-256-CBC', $aes_key, OPENSSL_RAW_DATA, $iv);
    130 
    131         // Ensure that AES encryption worked before proceeding
    132         if ($encrypted_data === false) {
    133             wp_send_json_error(['error' => 'AES encryption failed.'], 500);
    134             exit;
    135         }
    136 
    137         // Encrypt the AES key with the fetched RSA public key
    138         if (!openssl_public_encrypt($aes_key, $encrypted_key, $public_key)) {
    139             wp_send_json_error(['error' => 'RSA encryption failed. Invalid public key.'], 500);
    140             exit;
    141         }
    142 
    143         // Return both the encrypted AES key and the encrypted JSON data
    144         $response = [
    145             'encrypted_key' => base64_encode($encrypted_key),
    146             'iv'            => base64_encode($iv),
    147             'data'          => base64_encode($encrypted_data),
    148         ];
    149 
    150         // Send JSON response
    151         wp_send_json($response);
    152         exit;
    153     }
    154 }
    155 add_action('template_redirect', 'webfiable_template_redirect');
    156 
    157 // Ensure that the rewrite rules are flushed after the plugin is activated
    158 function webfiable_flush_rewrite_rules() {
    159     webfiable_register_route();
    160     flush_rewrite_rules();
    161 }
    162 register_activation_hook(__FILE__, 'webfiable_flush_rewrite_rules');
    163 
    164 // Flush rewrite rules on deactivation to avoid conflicts
    165 function webfiable_deactivate() {
    166     flush_rewrite_rules();
    167 }
    168 register_deactivation_hook(__FILE__, 'webfiable_deactivate');
     175register_deactivation_hook( __FILE__, 'webfiable_deactivate' );
  • webfiable-info/trunk/readme.txt

    r3244047 r3365319  
    44Requires at least: 5.0
    55Tested up to: 6.7
    6 Stable tag: 1.4
     6Stable tag: 1.4.1
    77License: GPLv3 or later
    88License URI: https://www.gnu.org/licenses/gpl-3.0.html
     
    1515
    1616The Webfiable Info plugin is a component of the Webfiable security service, designed to help you maintain a robust security posture for your WordPress website. By securely gathering information about your site's plugins, themes, and WordPress version, the plugin enables the Webfiable service to perform in-depth analysis and provide weekly recommendations tailored to your specific configuration.
    17 
    18 To verify the plugin's functionality, users and reviewers can visit the **`/webfiable` endpoint** on their website after activation. This endpoint provides encrypted website configuration data for security monitoring. An example of this can be seen at:
    19 
    20 * **Live Example:** [https://webfiable.com/webfiable/](https://webfiable.com/webfiable/)
    21 
    22 == External Services ==
    23 
    24 This plugin connects to the **Webfiable API** to:
    25 1. **Retrieve an RSA public key**, which is required for encrypting website configuration data before making it available to the Webfiable service.
    26 2. **Expose encrypted website configuration data** through the `/webfiable` endpoint, which is queried by `app.webfiable.com` to generate a **security posture report**.
    27 
    28 **Data Sent:** 
    29 - **Public Key Retrieval:** No user-specific data is sent; only a request to retrieve the RSA public key. 
    30 - **Configuration Data Transmission:** The plugin encrypts and exposes the following website information at the `/webfiable` endpoint: 
    31   - Installed plugins (names, slugs, and versions). 
    32   - Installed themes (names, slugs, and versions). 
    33   - WordPress version. 
    34 
    35 **When Data is Sent:** 
    36 - **Public Key Retrieval:** Occurs when encryption is required for the `/webfiable` endpoint. 
    37 - **Configuration Data Transmission:** Happens when `app.webfiable.com` queries the `/webfiable` endpoint to fetch encrypted data for security posture reporting. 
    38 
    39 **Service URL:** 
    40 - [https://app.webfiable.com/public-key.json](https://app.webfiable.com/public-key.json) *(for RSA key retrieval)* 
    41 
    42 **Terms of Service:** 
    43 - [https://webfiable.com/terminos-de-servicio/](https://webfiable.com/terminos-de-servicio/) 
    44 
    45 **Privacy Policy:** 
    46 - [https://webfiable.com/politica-privacidad/](https://webfiable.com/politica-privacidad/) 
    4717
    4818== Features ==
     
    6232* **RSA Key Management**: The RSA encryption ensures that only the Webfiable service can decrypt the transmitted data, using a private key that remains secure on the Webfiable infrastructure.
    6333
    64 == How to Verify Plugin Functionality ==
     34== Why It Is Secure ==
    6535
    66 Once installed and activated, users can verify the functionality of the Webfiable Info plugin by:
     361. **Advanced Encryption Techniques**: Webfiable Info employs AES-256 for data encryption, a standard widely recognized for its strength and security. The AES key is then encrypted with RSA-2048, ensuring that even if the data is intercepted, it cannot be decrypted without the corresponding private RSA key, which is securely stored by Webfiable.
    6737
    68 1. **Checking the `/webfiable` Endpoint**: Visit `https://yourwebsite.com/webfiable/` to confirm that the plugin is providing encrypted configuration data.
    69 2. **Comparing with an Example Site**: You can see an example of the plugin's functionality at:
    70    - [https://webfiable.com/webfiable/](https://webfiable.com/webfiable/)
    71 3. **Ensuring Data Security**: The data exposed at this endpoint is encrypted and can only be decrypted by the Webfiable service.
     382. **Data Integrity**: The use of a unique IV for each transmission guarantees that your data remains confidential and secure, preventing any potential attackers from predicting or replicating encrypted data streams.
     39
     403. **Confidentiality by Design**: The plugin is designed to collect only the necessary information for security analysis, ensuring that your website's sensitive data is handled with the utmost care and never exposed.
    7241
    7342== Installation ==
  • webfiable-info/trunk/webfiable-info.php

    r3244047 r3365319  
    44 * Plugin URI: https://webfiable.com/webfiable-info
    55 * Description: Ensure your website's security posture and configuration health with monitoring and recommendations.
    6  * Version: 1.4
     6 * Version: 1.4.1
    77 * Author: Webfiable Team
    88 * Author URI: https://webfiable.com
     
    1010 * License URI: https://www.gnu.org/licenses/gpl-3.0.html
    1111 * Text Domain: webfiable-info
     12 *
     13 * @package Webfiable_Info
    1214 */
    1315
    14 // Prevent direct access
    15 if (!defined('ABSPATH')) {
    16     exit;
     16// Prevent direct access.
     17if ( ! defined( 'ABSPATH' ) ) {
     18    exit;
    1719}
    1820
    19 // Fetch RSA public key dynamically from Webfiable API
    20 function webfiable_get_public_key() {
    21     $response = wp_remote_get('https://app.webfiable.com/public-key.json');
     21// RSA public key (provided by the user).
     22define(
     23    'WEBFIABLE_RSA_PUBLIC_KEY',
     24    '-----BEGIN PUBLIC KEY-----
     25MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw8y6jWyyz5yJzdj1kdDJ
     26KDU54+MryJYTBHogyq8m+557Q8gciul2cAZexdhC6EkIzI/hxwNi/t6fcLiK0hdC
     2788nVaP6B/xkZPuURW/cjtKbCBXo0CLTMNnJSxhECI4Xq5l5koiThdhSvDlqsuMWy
     28xCUUlbvU9Vg+MmiaEiRtZT7Nd5/NSqftqqdiVH0Q6sUd2OEFYPwnDI5615ALLH+h
     29XeaQhTu053Tpqcw6cMNbqOCc9Gk6esoM69oNHtXR2tKxxzWldwb0+mRRypUiPLUn
     30/n/9w5jnPrNsYGu1PVLXb+wlspPyZCSItq4zkzkFPYKvQ7u+U2UY28dHqSeHJhGd
     31FQIDAQAB
     32-----END PUBLIC KEY-----'
     33);
    2234
    23     if (is_wp_error($response)) {
    24         return null;
    25     }
     35/**
     36 * Registers the custom rewrite rule for the `webfiable` endpoint.
     37 *
     38 * Hooked to `init`.
     39 *
     40 * @since 1.4
     41 * @return void
     42 */
     43function webfiable_register_route() {
     44    add_rewrite_rule( '^webfiable$', 'index.php?webfiable_route=1', 'top' );
     45}
     46add_action( 'init', 'webfiable_register_route' );
    2647
    27     $status_code = wp_remote_retrieve_response_code($response);
    28     if ($status_code !== 200) {
    29         return null;
    30     }
     48/**
     49 * Adds the `webfiable_route` query var so WordPress recognizes the endpoint.
     50 *
     51 * Hooked to `query_vars`.
     52 *
     53 * @since 1.4
     54 * @param string[] $vars List of public query vars.
     55 * @return string[] Modified list of query vars.
     56 */
     57function webfiable_add_query_vars( $vars ) {
     58    $vars[] = 'webfiable_route';
     59    return $vars;
     60}
     61add_filter( 'query_vars', 'webfiable_add_query_vars' );
    3162
    32     $body = wp_remote_retrieve_body($response);
    33     if (empty($body)) {
    34         return null;
    35     }
     63/**
     64 * Handles the request to the `webfiable` endpoint and outputs an encrypted JSON payload.
     65 *
     66 * Hooked to `template_redirect`.
     67 *
     68 * Collects WP version, installed plugins and themes, builds a payload, encrypts it
     69 * with a random AES-256-CBC key/IV, encrypts that key with the RSA public key,
     70 * and returns base64-encoded values.
     71 *
     72 * @since 1.4
     73 * @return void
     74 */
     75function webfiable_template_redirect() {
     76    if ( get_query_var( 'webfiable_route' ) ) {
    3677
    37     // Decode JSON
    38     $decoded = json_decode($body, true);
    39     if (json_last_error() !== JSON_ERROR_NONE) {
    40         return null;
    41     }
     78        // Get all installed plugins.
     79        $installed_plugins = get_plugins();
     80        $plugins_info      = array();
    4281
    43     if (!isset($decoded['PublicKey']) || empty($decoded['PublicKey'])) {
    44         return null;
    45     }
     82        foreach ( $installed_plugins as $plugin_slug => $plugin_data ) {
     83            $plugins_info[] = array(
     84                'name'        => $plugin_data['Name'],
     85                'slug'        => dirname( $plugin_slug ),
     86                'version'     => $plugin_data['Version'],
     87                'description' => wp_strip_all_tags( $plugin_data['Description'] ),  // Remove HTML tags from description.
     88            );
     89        }
    4690
    47     // Restore proper RSA key formatting
    48     $public_key = "-----BEGIN PUBLIC KEY-----\n" .
    49                   wordwrap(trim($decoded['PublicKey']), 64, "\n", true) .
    50                   "\n-----END PUBLIC KEY-----";
     91        // Get all installed themes.
     92        $installed_themes = wp_get_themes();
     93        $themes_info      = array();
    5194
    52     // Verify if OpenSSL recognizes the key
    53     $openssl_key = openssl_pkey_get_public($public_key);
    54     if (!$openssl_key) {
    55         return null;
    56     }
     95        foreach ( $installed_themes as $theme_slug => $theme_data ) {
     96            $themes_info[] = array(
     97                'name'        => $theme_data->get( 'Name' ),
     98                'slug'        => $theme_data->get_stylesheet(),
     99                'version'     => $theme_data->get( 'Version' ),
     100                'description' => wp_strip_all_tags( $theme_data->get( 'Description' ) ),  // Remove HTML tags from description.
     101            );
     102        }
    57103
    58     return $public_key;
     104        // Get the WordPress version.
     105        $wordpress_version = get_bloginfo( 'version' );
     106
     107        // Merge all info into one array.
     108        $all_info = array(
     109            'wordpress_version' => $wordpress_version,
     110            'plugins'           => $plugins_info,
     111            'themes'            => $themes_info,
     112        );
     113
     114        // Convert to JSON.
     115        $json_data = wp_json_encode( $all_info );
     116
     117        // Generate a 256-bit AES key.
     118        $aes_key = openssl_random_pseudo_bytes( 32 );
     119
     120        // Encrypt the JSON data with the AES key.
     121        $encrypted_data = openssl_encrypt( $json_data, 'AES-256-CBC', $aes_key, OPENSSL_RAW_DATA, $iv = openssl_random_pseudo_bytes( 16 ) );
     122
     123        // Encrypt the AES key with the RSA public key.
     124        openssl_public_encrypt( $aes_key, $encrypted_key, WEBFIABLE_RSA_PUBLIC_KEY );
     125
     126        // Return both the encrypted AES key and the encrypted JSON data.
     127        // We base64-encode binary values to transport them safely in JSON.
     128        // phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Transport encoding, not obfuscation.
     129        $encoded_key  = base64_encode( $encrypted_key );
     130        $encoded_iv   = base64_encode( $iv );
     131        $encoded_data = base64_encode( $encrypted_data );
     132        // phpcs:enable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
     133
     134        $response = array(
     135            'encrypted_key' => $encoded_key,
     136            'iv'            => $encoded_iv,
     137            'data'          => $encoded_data,
     138        );
     139
     140        // Send JSON response.
     141        wp_send_json( $response );
     142        exit;
     143    }
    59144}
     145add_action( 'template_redirect', 'webfiable_template_redirect' );
    60146
    61 // Register the custom endpoint
    62 function webfiable_register_route() {
    63     add_rewrite_rule('^webfiable$', 'index.php?webfiable_route=1', 'top');
     147/**
     148 * Flushes rewrite rules on plugin activation so the custom endpoint works immediately.
     149 *
     150 * Calls our route registrar and then flushes the rules. This should only run on activation,
     151 * never on every request (for performance reasons).
     152 *
     153 * Hooked via `register_activation_hook()`.
     154 *
     155 * @since 1.4
     156 * @return void
     157 */
     158function webfiable_flush_rewrite_rules() {
     159    webfiable_register_route();
     160    flush_rewrite_rules();
    64161}
    65 add_action('init', 'webfiable_register_route');
     162register_activation_hook( __FILE__, 'webfiable_flush_rewrite_rules' );
    66163
    67 // Add the query var so WP recognizes the custom route
    68 function webfiable_add_query_vars($vars) {
    69     $vars[] = 'webfiable_route';
    70     return $vars;
     164/**
     165 * Flushes rewrite rules on plugin deactivation to remove the custom endpoint.
     166 *
     167 * Hooked via `register_deactivation_hook()`.
     168 *
     169 * @since 1.4
     170 * @return void
     171 */
     172function webfiable_deactivate() {
     173    flush_rewrite_rules();
    71174}
    72 add_filter('query_vars', 'webfiable_add_query_vars');
    73 
    74 // Handle the request and return encrypted JSON response
    75 function webfiable_template_redirect() {
    76     if (get_query_var('webfiable_route')) {
    77 
    78         // Fetch the public key dynamically when handling requests
    79         $public_key = webfiable_get_public_key();
    80         if (!$public_key) {
    81             wp_send_json_error(['error' => 'Failed to retrieve public key. Cannot proceed with encryption.'], 500);
    82             exit;
    83         }
    84 
    85         // Get all installed plugins
    86         $installed_plugins = get_plugins();
    87         $plugins_info = [];
    88 
    89         foreach ($installed_plugins as $plugin_slug => $plugin_data) {
    90             $plugins_info[] = [
    91                 'name'        => $plugin_data['Name'],
    92                 'slug'        => dirname($plugin_slug),
    93                 'version'     => $plugin_data['Version'],
    94                 'description' => wp_strip_all_tags($plugin_data['Description']),
    95             ];
    96         }
    97 
    98         // Get all installed themes
    99         $installed_themes = wp_get_themes();
    100         $themes_info = [];
    101 
    102         foreach ($installed_themes as $theme_slug => $theme_data) {
    103             $themes_info[] = [
    104                 'name'        => $theme_data->get('Name'),
    105                 'slug'        => $theme_data->get_stylesheet(),
    106                 'version'     => $theme_data->get('Version'),
    107                 'description' => wp_strip_all_tags($theme_data->get('Description')),
    108             ];
    109         }
    110 
    111         // Get the WordPress version
    112         $wordpress_version = get_bloginfo('version');
    113 
    114         // Merge all info into one array
    115         $all_info = [
    116             'wordpress_version' => $wordpress_version,
    117             'plugins'           => $plugins_info,
    118             'themes'            => $themes_info,
    119         ];
    120 
    121         // Convert to JSON
    122         $json_data = json_encode($all_info);
    123 
    124         // Generate a 256-bit AES key
    125         $aes_key = openssl_random_pseudo_bytes(32);
    126         $iv = openssl_random_pseudo_bytes(16);
    127 
    128         // Encrypt the JSON data with the AES key
    129         $encrypted_data = openssl_encrypt($json_data, 'AES-256-CBC', $aes_key, OPENSSL_RAW_DATA, $iv);
    130 
    131         // Ensure that AES encryption worked before proceeding
    132         if ($encrypted_data === false) {
    133             wp_send_json_error(['error' => 'AES encryption failed.'], 500);
    134             exit;
    135         }
    136 
    137         // Encrypt the AES key with the fetched RSA public key
    138         if (!openssl_public_encrypt($aes_key, $encrypted_key, $public_key)) {
    139             wp_send_json_error(['error' => 'RSA encryption failed. Invalid public key.'], 500);
    140             exit;
    141         }
    142 
    143         // Return both the encrypted AES key and the encrypted JSON data
    144         $response = [
    145             'encrypted_key' => base64_encode($encrypted_key),
    146             'iv'            => base64_encode($iv),
    147             'data'          => base64_encode($encrypted_data),
    148         ];
    149 
    150         // Send JSON response
    151         wp_send_json($response);
    152         exit;
    153     }
    154 }
    155 add_action('template_redirect', 'webfiable_template_redirect');
    156 
    157 // Ensure that the rewrite rules are flushed after the plugin is activated
    158 function webfiable_flush_rewrite_rules() {
    159     webfiable_register_route();
    160     flush_rewrite_rules();
    161 }
    162 register_activation_hook(__FILE__, 'webfiable_flush_rewrite_rules');
    163 
    164 // Flush rewrite rules on deactivation to avoid conflicts
    165 function webfiable_deactivate() {
    166     flush_rewrite_rules();
    167 }
    168 register_deactivation_hook(__FILE__, 'webfiable_deactivate');
     175register_deactivation_hook( __FILE__, 'webfiable_deactivate' );
Note: See TracChangeset for help on using the changeset viewer.