PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
← All changes | src/behavior/scan/class-known-vulnerability.php +85 -34 5.3.1 → 6.3.0 View file →
@@ -16,8 +16,9 @@
16 16 use WP_Defender\Traits\Plugin;
17 17 use WP_Defender\Model\Scan_Item;
18 18 use WP_Defender\Behavior\WPMUDEV;
19 19 use WP_Defender\Helper\Analytics\Scan as Scan_Analytics;
20 +use WP_Defender\Component\Scan as Scan_Component;
20 21
21 22 /**
22 23 * Represents a component responsible for checking known vulnerabilities.
23 24 */
@@ -90,29 +91,41 @@
90 91 * @return array
91 92 */
92 93 private function gather_fact( string $type, &$info_cached ): array {
93 94 $items = array();
94 - $model = Scan::get_last();
95 95
96 96 if ( 'plugin' === $type ) {
97 - $get_items = $this->get_plugins();
97 + $actioned_plugins = get_site_option( Scan_Component::PLUGINS_ACTIONED );
98 + if ( Scan_Component::are_actioned_plugins( $actioned_plugins ) ) {
99 + foreach ( $actioned_plugins as $slug => $plugin_data ) {
100 + $items[ $slug ] = $plugin_data['Version'];
101 + $info_cached[ $slug ] = array( $plugin_data['Name'], $plugin_data['Version'], $plugin_data['Slug'] );
102 + }
103 + } else {
104 + // An emergency option if for some reason the plugin's quick data is not saved in the first step.
105 + foreach ( $this->get_plugins() as $slug => $plugin ) {
106 + $base_slug = $this->get_plugin_slug_by( $slug );
107 + $items[ $base_slug ] = $plugin['Version'];
108 + $info_cached[ $base_slug ] = array( $plugin['Name'], $plugin['Version'], $slug );
109 + }
110 + }
98 111 } elseif ( 'theme' === $type ) {
99 - $get_items = $this->get_themes();
112 + $model = Scan::get_last();
113 + foreach ( $this->get_themes() as $slug => $item ) {
114 + // It's actual because we don't have ignored theme slugs.
115 + if ( is_object( $model ) && $model->is_issue_ignored( $slug ) ) {
116 + continue;
117 + }
118 +
119 + $base_slug = explode( '/', $slug );
120 + $base_slug = array_shift( $base_slug );
121 + $items[ $base_slug ] = $item['Version'];
122 + $info_cached[ $base_slug ] = array( $item['Name'], $item['Version'], $slug );
123 + }
100 124 } else {
101 125 return $items;
102 126 }
103 127
104 - foreach ( $get_items as $slug => $item ) {
105 - if ( is_object( $model ) && $model->is_issue_ignored( $slug ) ) {
106 - continue;
107 - }
108 -
109 - $base_slug = explode( '/', $slug );
110 - $base_slug = array_shift( $base_slug );
111 - $items[ $base_slug ] = $item['Version'];
112 - $info_cached[ $base_slug ] = array( $item['Name'], $item['Version'], $slug );
113 - }
114 -
115 128 return $items;
116 129 }
117 130
118 131 /**
@@ -183,9 +196,9 @@
183 196 * @param string $type The type of the vulnerability check.
184 197 * @param array $ignored_issues The ignored issues.
185 198 */
186 199 private function process_result( $result, $info, $type, $ignored_issues ) {
187 - if ( empty( $result ) ) {
200 + if ( ! is_array( $result ) || array() === $result ) {
188 201 return;
189 202 }
190 203
191 204 $this->log( sprintf( 'Checking %s:', $type ) );
@@ -194,9 +207,9 @@
194 207 foreach ( $result as $base_slug => $bugs ) {
195 208 if ( 'wp_core' === $type ) {
196 209 global $wp_version;
197 210 $is_exist = false;
198 - if ( ! empty( $ignored_issues ) ) {
211 + if ( is_array( $ignored_issues ) && array() !== $ignored_issues ) {
199 212 foreach ( $ignored_issues as $issue ) {
200 213 if ( $wp_version === $issue->raw_data['version'] ) {
201 214 $is_exist = true;
202 215 }
@@ -221,30 +234,45 @@
221 234 ),
222 235 'new_structure' => '3.4.0',
223 236 );
224 237
225 - $model->add_item( Scan_Item::TYPE_VULNERABILITY, $raw_data );
238 + if ( array() !== $raw_data['bugs'] ) {
239 + $model->add_item( Scan_Item::TYPE_VULNERABILITY, $raw_data );
240 + }
226 241 }
227 242 } elseif ( 'plugin' === $type || 'theme' === $type ) {
228 - if ( empty( $info[ $base_slug ] ) ) {
243 + if ( ! isset( $info[ $base_slug ] ) || ! is_array( $info[ $base_slug ] ) ) {
229 244 continue;
230 245 }
231 246
232 - [ $name, $current_version, $slug ] = $info[ $base_slug ];
233 - $raw_data = array(
234 - 'type' => $type,
235 - 'slug' => $slug,
236 - 'base_slug' => $base_slug,
237 - 'version' => $current_version,
238 - 'name' => $name,
239 - 'bugs' => array(),
240 - );
241 -
242 247 if ( isset( $bugs['confirmed'] ) && ( is_array( $bugs['confirmed'] ) || $bugs['confirmed'] instanceof Countable ? count( $bugs['confirmed'] ) : 0 ) ) {
243 - if ( 'plugin' === $type && ! $this->is_likely_wporg_slug( $base_slug ) ) {
244 - continue;
248 + // Default conditions for wp.org and Pro plugins.
249 + $wp_org_plugin_details = array(
250 + 'is_existed' => false,
251 + 'last_version' => '0',
252 + );
253 + if ( 'plugin' === $type && $this->is_likely_wporg_slug( $base_slug ) ) {
254 + // Additional conditions for wp.org plugin.
255 + $results = $this->handle_wp_org_response_by( $base_slug );
256 + if ( $results['success'] && isset( $results['body']['version'] ) ) {
257 + $wp_org_plugin_details = array(
258 + 'is_existed' => true,
259 + 'last_version' => $results['body']['version'],
260 + );
261 + }
262 + // If there is not a plugin version, likely the plugin is closed. We'd not display Update button.
245 263 }
246 264
265 + [ $name, $current_version, $slug ] = $info[ $base_slug ];
266 + $raw_data = array(
267 + 'type' => $type,
268 + 'slug' => $slug,
269 + 'base_slug' => $base_slug,
270 + 'version' => $current_version,
271 + 'name' => $name,
272 + 'bugs' => array(),
273 + );
274 +
247 275 $confirmed_bugs = (array) $bugs['confirmed'];
248 276 // @since 3.4.0 Restructure the view in relation to the new CVSS Score field.
249 277 $raw_data['new_structure'] = '3.4.0';
250 278 $this->log( sprintf( '%s has %d known bugs', $slug, count( $confirmed_bugs ) ) );
@@ -249,8 +277,14 @@
249 277 $raw_data['new_structure'] = '3.4.0';
250 278 $this->log( sprintf( '%s has %d known bugs', $slug, count( $confirmed_bugs ) ) );
251 279
252 280 foreach ( $confirmed_bugs as $bug ) {
281 + if ( 'plugin' === $type && $wp_org_plugin_details['is_existed']
282 + && version_compare( $wp_org_plugin_details['last_version'], $bug['fixed_in'], '<=' )
283 + ) {
284 + // This is another plugin but with the same slug.
285 + continue;
286 + }
253 287 $raw_data['bugs'][] = array(
254 288 'vuln_type' => $bug['vuln_type'],
255 289 'title' => $bug['title'],
256 290 'ref' => $bug['references'],
@@ -258,9 +292,11 @@
258 292 'cvss_score' => $bug['cvss']['score'] ?? '',
259 293 );
260 294 }
261 295
262 - $model->add_item( Scan_Item::TYPE_VULNERABILITY, $raw_data );
296 + if ( array() !== $raw_data['bugs'] ) {
297 + $model->add_item( Scan_Item::TYPE_VULNERABILITY, $raw_data );
298 + }
263 299 }
264 300 }
265 301 }
266 302 }
@@ -270,11 +306,26 @@
270 306 *
271 307 * @param array $ignored_issues The array of ignored vulnerability issues to add.
272 308 */
273 309 private function add_ignored_issues( $ignored_issues ) {
274 - if ( ! empty( $ignored_issues ) ) {
275 - foreach ( $ignored_issues as $issue ) {
276 - $this->scan->add_item( Scan_Item::TYPE_VULNERABILITY, $issue->raw_data, Scan_Item::STATUS_IGNORE );
310 + if ( ! is_array( $ignored_issues ) || array() === $ignored_issues ) {
311 + return;
312 + }
313 +
314 + // wp_core issues have no slug, so carry them forward as-is.
315 + $wp_core_issues = array();
316 + $other_issues = array();
317 + foreach ( $ignored_issues as $issue ) {
318 + if ( 'wp_core' === ( $issue->raw_data['type'] ?? '' ) ) {
319 + $wp_core_issues[] = $issue;
320 + } else {
321 + $other_issues[] = $issue;
277 322 }
278 323 }
324 +
325 + foreach ( $wp_core_issues as $issue ) {
326 + $this->scan->add_item( Scan_Item::TYPE_VULNERABILITY, $issue->raw_data, Scan_Item::STATUS_IGNORE );
327 + }
328 +
329 + $this->scan->carry_forward_ignored_issues( Scan_Item::TYPE_VULNERABILITY, $other_issues, 'slug' );
279 330 }
280 331 }