PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.2.6
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.2.6
4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.5.2 All 199 releases
← All changes | includes/Core/PluginInstaller.php +24 -63 4.9.14.2.6 View file →
@@ -53,68 +53,31 @@
53 53 if (empty($slug)) {
54 54 return new WP_Error('empty_arg', __('Argument should not be empty.', 'betterdocs'));
55 55 }
56 56
57 - // Use core's plugins_api() instead of a hand-rolled request. The old code
58 - // POSTed to plaintext http://api.wordpress.org and passed the response
59 - // body straight to unserialize(), so anyone able to intercept that
60 - // connection could inject a PHP-object-injection payload or a malicious
61 - // download_link. plugins_api() talks to api.wordpress.org over HTTPS and
62 - // returns a decoded object — no plaintext transport, no unserialize().
63 - if (!function_exists('plugins_api')) {
64 - include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
65 - }
57 + $response = wp_remote_post(
58 + 'http://api.wordpress.org/plugins/info/1.0/',
59 + [
60 + 'body' => [
61 + 'action' => 'plugin_information',
62 + 'request' => serialize((object) [
63 + 'slug' => $slug,
64 + 'fields' => [
65 + 'version' => false,
66 + ],
67 + ]),
68 + ],
69 + ]
70 + );
66 71
67 - $response = plugins_api('plugin_information', [
68 - 'slug' => $slug,
69 - 'fields' => [
70 - 'version' => true,
71 - ],
72 - ]);
73 -
74 - if (is_wp_error($response) || !is_object($response)) {
75 - return is_wp_error($response) ? $response : new WP_Error('plugins_api_failed', __('Could not retrieve plugin information.', 'betterdocs'));
72 + if (is_wp_error($response)) {
73 + return $response;
76 74 }
77 75
78 - // Bind the package to the requested slug and to an https WordPress.org
79 - // host before anything installs it.
80 - if (isset($response->slug) && $response->slug !== $slug) {
81 - return new WP_Error('slug_mismatch', __('Plugin information did not match the requested plugin.', 'betterdocs'));
82 - }
83 -
84 - if (isset($response->download_link) && !$this->is_allowed_package_url($response->download_link)) {
85 - return new WP_Error('bad_package_host', __('Plugin download URL is not an approved WordPress.org address.', 'betterdocs'));
86 - }
87 -
88 - return $response;
76 + return unserialize(wp_remote_retrieve_body($response));
89 77 }
90 78
91 79 /**
92 - * Whether a package URL is safe to hand to the upgrader: https on a
93 - * WordPress.org host. Prevents a tampered response from redirecting the
94 - * install to an attacker-controlled archive.
95 - *
96 - * @param string $url
97 - * @return bool
98 - */
99 - protected function is_allowed_package_url($url)
100 - {
101 - if (!is_string($url) || $url === '') {
102 - return false;
103 - }
104 -
105 - $parts = wp_parse_url($url);
106 -
107 - if (empty($parts['scheme']) || strtolower($parts['scheme']) !== 'https' || empty($parts['host'])) {
108 - return false;
109 - }
110 -
111 - $host = strtolower($parts['host']);
112 -
113 - return in_array($host, ['downloads.wordpress.org', 'wordpress.org', 'www.wordpress.org'], true);
114 - }
115 -
116 - /**
117 80 * install_plugin
118 81 *
119 82 * @param mixed $slug
120 83 * @param bool $active
@@ -166,9 +129,9 @@
166 129 * @return mixed bool|WP_Error
167 130 */
168 131 public function upgrade_plugin($basename = '')
169 132 {
170 - if (empty($basename)) {
133 + if (empty($slug)) {
171 134 return new WP_Error('empty_arg', __('Argument should not be empty.', 'betterdocs'));
172 135 }
173 136
174 137 include_once ABSPATH . 'wp-admin/includes/file.php';
@@ -188,13 +151,12 @@
188 151 if(!current_user_can( 'install_plugins' )) {
189 152 wp_send_json_error(__('you are not allowed to do this action', 'betterdocs'));
190 153 }
191 154
192 - $slug = isset( $_POST['slug'] ) ? sanitize_text_field( wp_unslash( $_POST['slug'] ) ) : '';
155 + $slug = isset( $_POST['slug'] ) ? sanitize_text_field( $_POST['slug'] ) : '';
193 156 $result = $this->install_plugin( $slug );
194 157
195 - $promotype = isset( $_POST['promotype'] ) ? sanitize_text_field( wp_unslash( $_POST['promotype'] ) ) : '';
196 - if ( 'eb-banner' === $promotype ) {
158 + if( isset( $_POST['promotype'] ) && 'eb-banner' === $_POST['promotype'] ) {
197 159 wp_remote_get( 'https://essential-addons.com/essential-blocks-install-gutenberg' );
198 160 }
199 161
200 162 if ( is_wp_error( $result ) ) {
@@ -211,9 +173,9 @@
211 173 if(!current_user_can( 'update_plugins' )) {
212 174 wp_send_json_error(__('you are not allowed to do this action', 'betterdocs'));
213 175 }
214 176
215 - $basename = isset( $_POST['basename'] ) ? sanitize_text_field( wp_unslash( $_POST['basename'] ) ) : '';
177 + $basename = isset( $_POST['basename'] ) ? sanitize_text_field( $_POST['basename'] ) : '';
216 178 $result = $this->upgrade_plugin( $basename );
217 179
218 180 if (is_wp_error($result)) {
219 181 wp_send_json_error($result->get_error_message());
@@ -230,9 +192,9 @@
230 192 if(!current_user_can( 'activate_plugins' )) {
231 193 wp_send_json_error(__('you are not allowed to do this action', 'betterdocs'));
232 194 }
233 195
234 - $basename = isset( $_POST['basename'] ) ? sanitize_text_field( wp_unslash( $_POST['basename'] ) ) : '';
196 + $basename = isset( $_POST['basename'] ) ? sanitize_text_field( $_POST['basename'] ) : '';
235 197 $result = activate_plugin( $basename, '', false, true );
236 198
237 199 if ( is_wp_error( $result ) ) {
238 200 wp_send_json_error( $result->get_error_message() );
@@ -251,9 +213,9 @@
251 213 if ( ! current_user_can( 'activate_plugins' ) ) {
252 214 wp_send_json_error( __( 'you are not allowed to do this action', 'betterdocs' ) );
253 215 }
254 216
255 - $basename = isset( $_POST['basename'] ) ? sanitize_text_field( wp_unslash( $_POST['basename'] ) ) : '';
217 + $basename = isset( $_POST['basename'] ) ? sanitize_text_field( $_POST['basename'] ) : '';
256 218 deactivate_plugins( $basename, true );
257 219
258 220 wp_send_json_success( __( 'Plugin is deactivated successfully!', 'betterdocs' ) );
259 221 }
@@ -260,10 +222,9 @@
260 222
261 223 public function ajax_auto_active_even_not_installed() {
262 224 check_ajax_referer( 'betterdocs-wpdeveloper-plugins', 'security' );
263 225
264 - $basename = isset( $_POST['basename'] ) ? sanitize_text_field( wp_unslash( $_POST['basename'] ) ) : '';
265 - if ( $this->get_local_plugin_data( $basename ) === false ) {
226 + if ( $this->get_local_plugin_data( $_POST['basename'] ) === false ) {
266 227 $this->ajax_install_plugin();
267 228 } else {
268 229 $this->ajax_activate_plugin();
269 230 }