Changeset 3365319
- Timestamp:
- 09/21/2025 03:07:54 PM (7 months ago)
- Location:
- webfiable-info
- Files:
-
- 31 added
- 7 edited
- 1 copied
-
assets/banner-1544x500.png (added)
-
assets/banner-772x250.png (modified) (1 prop) (previous)
-
assets/icon-128x128.png (modified) (1 prop) (previous)
-
assets/icon-256x256.png (modified) (1 prop) (previous)
-
tags/1.4.1 (copied) (copied from webfiable-info/trunk)
-
tags/1.4.1/.gitattributes (added)
-
tags/1.4.1/.github (added)
-
tags/1.4.1/.github/workflows (added)
-
tags/1.4.1/.github/workflows/release.yml (added)
-
tags/1.4.1/.gitignore (added)
-
tags/1.4.1/.wordpress-org (added)
-
tags/1.4.1/.wordpress-org/banner-1544x500.png (added)
-
tags/1.4.1/.wordpress-org/banner-772x250.png (added)
-
tags/1.4.1/.wordpress-org/icon-128x128.png (added)
-
tags/1.4.1/.wordpress-org/icon-256x256.png (added)
-
tags/1.4.1/LICENSE (added)
-
tags/1.4.1/README.md (added)
-
tags/1.4.1/composer.json (added)
-
tags/1.4.1/composer.lock (added)
-
tags/1.4.1/phpcs.xml (added)
-
tags/1.4.1/readme.txt (modified) (3 diffs)
-
tags/1.4.1/webfiable-info.php (modified) (2 diffs)
-
trunk/.gitattributes (added)
-
trunk/.github (added)
-
trunk/.github/workflows (added)
-
trunk/.github/workflows/release.yml (added)
-
trunk/.gitignore (added)
-
trunk/.wordpress-org (added)
-
trunk/.wordpress-org/banner-1544x500.png (added)
-
trunk/.wordpress-org/banner-772x250.png (added)
-
trunk/.wordpress-org/icon-128x128.png (added)
-
trunk/.wordpress-org/icon-256x256.png (added)
-
trunk/LICENSE (added)
-
trunk/README.md (added)
-
trunk/composer.json (added)
-
trunk/composer.lock (added)
-
trunk/phpcs.xml (added)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/webfiable-info.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
webfiable-info/assets/banner-772x250.png
-
Property
svn:mime-type
changed from
application/octet-streamtoimage/png
-
Property
svn:mime-type
changed from
-
webfiable-info/assets/icon-128x128.png
-
Property
svn:mime-type
changed from
application/octet-streamtoimage/png
-
Property
svn:mime-type
changed from
-
webfiable-info/assets/icon-256x256.png
-
Property
svn:mime-type
changed from
application/octet-streamtoimage/png
-
Property
svn:mime-type
changed from
-
webfiable-info/tags/1.4.1/readme.txt
r3244047 r3365319 4 4 Requires at least: 5.0 5 5 Tested up to: 6.7 6 Stable tag: 1.4 6 Stable tag: 1.4.1 7 7 License: GPLv3 or later 8 8 License URI: https://www.gnu.org/licenses/gpl-3.0.html … … 15 15 16 16 The 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/)47 17 48 18 == Features == … … 62 32 * **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. 63 33 64 == How to Verify Plugin Functionality==34 == Why It Is Secure == 65 35 66 Once installed and activated, users can verify the functionality of the Webfiable Info plugin by: 36 1. **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. 67 37 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. 38 2. **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 40 3. **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. 72 41 73 42 == Installation == -
webfiable-info/tags/1.4.1/webfiable-info.php
r3244047 r3365319 4 4 * Plugin URI: https://webfiable.com/webfiable-info 5 5 * Description: Ensure your website's security posture and configuration health with monitoring and recommendations. 6 * Version: 1.4 6 * Version: 1.4.1 7 7 * Author: Webfiable Team 8 8 * Author URI: https://webfiable.com … … 10 10 * License URI: https://www.gnu.org/licenses/gpl-3.0.html 11 11 * Text Domain: webfiable-info 12 * 13 * @package Webfiable_Info 12 14 */ 13 15 14 // Prevent direct access 15 if ( !defined('ABSPATH')) {16 exit;16 // Prevent direct access. 17 if ( ! defined( 'ABSPATH' ) ) { 18 exit; 17 19 } 18 20 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). 22 define( 23 'WEBFIABLE_RSA_PUBLIC_KEY', 24 '-----BEGIN PUBLIC KEY----- 25 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw8y6jWyyz5yJzdj1kdDJ 26 KDU54+MryJYTBHogyq8m+557Q8gciul2cAZexdhC6EkIzI/hxwNi/t6fcLiK0hdC 27 88nVaP6B/xkZPuURW/cjtKbCBXo0CLTMNnJSxhECI4Xq5l5koiThdhSvDlqsuMWy 28 xCUUlbvU9Vg+MmiaEiRtZT7Nd5/NSqftqqdiVH0Q6sUd2OEFYPwnDI5615ALLH+h 29 XeaQhTu053Tpqcw6cMNbqOCc9Gk6esoM69oNHtXR2tKxxzWldwb0+mRRypUiPLUn 30 /n/9w5jnPrNsYGu1PVLXb+wlspPyZCSItq4zkzkFPYKvQ7u+U2UY28dHqSeHJhGd 31 FQIDAQAB 32 -----END PUBLIC KEY-----' 33 ); 22 34 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 */ 43 function webfiable_register_route() { 44 add_rewrite_rule( '^webfiable$', 'index.php?webfiable_route=1', 'top' ); 45 } 46 add_action( 'init', 'webfiable_register_route' ); 26 47 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 */ 57 function webfiable_add_query_vars( $vars ) { 58 $vars[] = 'webfiable_route'; 59 return $vars; 60 } 61 add_filter( 'query_vars', 'webfiable_add_query_vars' ); 31 62 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 */ 75 function webfiable_template_redirect() { 76 if ( get_query_var( 'webfiable_route' ) ) { 36 77 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(); 42 81 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 } 46 90 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(); 51 94 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 } 57 103 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 } 59 144 } 145 add_action( 'template_redirect', 'webfiable_template_redirect' ); 60 146 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 */ 158 function webfiable_flush_rewrite_rules() { 159 webfiable_register_route(); 160 flush_rewrite_rules(); 64 161 } 65 add_action('init', 'webfiable_register_route');162 register_activation_hook( __FILE__, 'webfiable_flush_rewrite_rules' ); 66 163 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 */ 172 function webfiable_deactivate() { 173 flush_rewrite_rules(); 71 174 } 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'); 175 register_deactivation_hook( __FILE__, 'webfiable_deactivate' ); -
webfiable-info/trunk/readme.txt
r3244047 r3365319 4 4 Requires at least: 5.0 5 5 Tested up to: 6.7 6 Stable tag: 1.4 6 Stable tag: 1.4.1 7 7 License: GPLv3 or later 8 8 License URI: https://www.gnu.org/licenses/gpl-3.0.html … … 15 15 16 16 The 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/)47 17 48 18 == Features == … … 62 32 * **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. 63 33 64 == How to Verify Plugin Functionality==34 == Why It Is Secure == 65 35 66 Once installed and activated, users can verify the functionality of the Webfiable Info plugin by: 36 1. **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. 67 37 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. 38 2. **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 40 3. **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. 72 41 73 42 == Installation == -
webfiable-info/trunk/webfiable-info.php
r3244047 r3365319 4 4 * Plugin URI: https://webfiable.com/webfiable-info 5 5 * Description: Ensure your website's security posture and configuration health with monitoring and recommendations. 6 * Version: 1.4 6 * Version: 1.4.1 7 7 * Author: Webfiable Team 8 8 * Author URI: https://webfiable.com … … 10 10 * License URI: https://www.gnu.org/licenses/gpl-3.0.html 11 11 * Text Domain: webfiable-info 12 * 13 * @package Webfiable_Info 12 14 */ 13 15 14 // Prevent direct access 15 if ( !defined('ABSPATH')) {16 exit;16 // Prevent direct access. 17 if ( ! defined( 'ABSPATH' ) ) { 18 exit; 17 19 } 18 20 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). 22 define( 23 'WEBFIABLE_RSA_PUBLIC_KEY', 24 '-----BEGIN PUBLIC KEY----- 25 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw8y6jWyyz5yJzdj1kdDJ 26 KDU54+MryJYTBHogyq8m+557Q8gciul2cAZexdhC6EkIzI/hxwNi/t6fcLiK0hdC 27 88nVaP6B/xkZPuURW/cjtKbCBXo0CLTMNnJSxhECI4Xq5l5koiThdhSvDlqsuMWy 28 xCUUlbvU9Vg+MmiaEiRtZT7Nd5/NSqftqqdiVH0Q6sUd2OEFYPwnDI5615ALLH+h 29 XeaQhTu053Tpqcw6cMNbqOCc9Gk6esoM69oNHtXR2tKxxzWldwb0+mRRypUiPLUn 30 /n/9w5jnPrNsYGu1PVLXb+wlspPyZCSItq4zkzkFPYKvQ7u+U2UY28dHqSeHJhGd 31 FQIDAQAB 32 -----END PUBLIC KEY-----' 33 ); 22 34 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 */ 43 function webfiable_register_route() { 44 add_rewrite_rule( '^webfiable$', 'index.php?webfiable_route=1', 'top' ); 45 } 46 add_action( 'init', 'webfiable_register_route' ); 26 47 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 */ 57 function webfiable_add_query_vars( $vars ) { 58 $vars[] = 'webfiable_route'; 59 return $vars; 60 } 61 add_filter( 'query_vars', 'webfiable_add_query_vars' ); 31 62 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 */ 75 function webfiable_template_redirect() { 76 if ( get_query_var( 'webfiable_route' ) ) { 36 77 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(); 42 81 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 } 46 90 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(); 51 94 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 } 57 103 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 } 59 144 } 145 add_action( 'template_redirect', 'webfiable_template_redirect' ); 60 146 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 */ 158 function webfiable_flush_rewrite_rules() { 159 webfiable_register_route(); 160 flush_rewrite_rules(); 64 161 } 65 add_action('init', 'webfiable_register_route');162 register_activation_hook( __FILE__, 'webfiable_flush_rewrite_rules' ); 66 163 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 */ 172 function webfiable_deactivate() { 173 flush_rewrite_rules(); 71 174 } 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'); 175 register_deactivation_hook( __FILE__, 'webfiable_deactivate' );
Note: See TracChangeset
for help on using the changeset viewer.