PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 3.1.0
Defender Security – Malware Scanner, Login Security & Firewall v3.1.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
defender-security / src / component / legacy-versions.php

legacy-versions.php in Defender Security – Malware Scanner, Login Security & Firewall 3.1.0, at src/component/legacy-versions.php

338 lines 9.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WP_Defender\Component;
4
5 use WP_Defender\Component;
6 use WP_Defender\Model\Scan as Model_Scan;
7 use WP_Defender\Model\Scan_Item;
8
9 /**
10 * Class Legacy_Versions
11 * @package WP_Defender\Component
12 * @since 2.5.6
13 */
14 class Legacy_Versions extends Component {
15 public const IGNORE_LIST = 'wdfscanignore';
16
17 /**
18 * @return array
19 */
20 private function find_all_scan_issue_items() {
21 global $wpdb;
22
23 $sql = 'SELECT t0.ID AS id,t0.post_parent AS parentId,t1.meta_value AS type,t2.meta_value AS raw';
24 $sql .= ' FROM ' . $wpdb->posts . ' AS t0';
25 $sql .= ' LEFT JOIN ' . $wpdb->postmeta . " as t1 ON t1.post_id=ID AND t1.meta_key='type'";
26 $sql .= ' LEFT JOIN ' . $wpdb->postmeta . " as t2 ON t2.post_id=ID AND t2.meta_key='raw'";
27 $sql .= " WHERE t0.post_type='wdf_scan_item' AND t0.post_status = 'issue'";
28 $sql .= ' GROUP BY ID';
29
30 return $wpdb->get_results( $sql, ARRAY_A );// phpcs:ignore
31 }
32
33 /**
34 * @param array $ids
35 *
36 * @return array
37 */
38 private function find_all_scan_ignored_items( $ids ) {
39 global $wpdb;
40
41 if ( is_array( $ids ) && count( $ids ) > 0 ) {
42 $sql = 'SELECT t0.ID AS id,t0.post_parent AS parentId,t1.meta_value AS type,t2.meta_value AS raw';
43 $sql .= ' FROM ' . $wpdb->posts . ' AS t0';
44 $sql .= ' LEFT JOIN ' . $wpdb->postmeta . " as t1 ON t1.post_id=ID AND t1.meta_key='type'";
45 $sql .= ' LEFT JOIN ' . $wpdb->postmeta . " as t2 ON t2.post_id=ID AND t2.meta_key='raw'";
46 $sql .= " WHERE t0.post_type='wdf_scan_item' AND t0.post_status = 'ignored'";
47 $sql .= ' AND t0.ID IN (' . implode( ', ', $ids ) . ')';
48
49 return $wpdb->get_results( $sql, ARRAY_A );// phpcs:ignore
50 }
51
52 return array();
53 }
54
55 /**
56 * @param array $old_data
57 *
58 * @return array
59 */
60 private function adapt_scan_data( $old_data ) {
61 $raw = '';
62 switch ( $old_data['type'] ) {
63 case 'vuln':
64 $new_type = Scan_Item::TYPE_VULNERABILITY;
65 if ( isset( $old_data['raw'] ) && ! empty( $old_data['raw'] ) ) {
66 $raw = maybe_unserialize( $old_data['raw'] );
67 /**
68 * Different $raw['slug'] values depending on the type:
69 * 'type' => 'theme', 'slug' => {THEME_SLUG}, ...
70 * 'type' => 'plugin', 'slug' => {PLUGIN_SLUG}, ...
71 * 'type' => 'WordPress', 'slug' => 'WordPress', ...
72 */
73 $file = is_array( $raw ) && isset( $raw['slug'] ) ? $raw['slug'] : '';
74 } else {
75 $file = '';
76 }
77
78 if ( is_array( $raw ) && 'WordPress' !== $raw['type'] ) {
79 $raw_data = array(
80 'type' => $raw['type'],
81 'slug' => $raw['slug'],
82 'base_slug' => $raw['slug'],
83 'version' => '',
84 'name' => $raw['slug'],
85 'bugs' => $raw['bugs'],
86 );
87 } else {
88 $raw_data = $old_data['raw'];
89 }
90 break;
91 case 'content':
92 $new_type = Scan_Item::TYPE_SUSPICIOUS;
93 if ( isset( $old_data['raw'] ) && ! empty( $old_data['raw'] ) ) {
94 $raw = maybe_unserialize( $old_data['raw'] );
95 $file = is_array( $raw ) && isset( $raw['file'] ) ? $raw['file'] : '';
96 } else {
97 $file = '';
98 }
99
100 $raw_data = is_array( $raw ) && isset( $raw['meta'] ) ? $raw['meta'] : array();
101 $raw_data['file'] = $file;
102 break;
103 case 'core':
104 default:
105 $new_type = Scan_Item::TYPE_INTEGRITY;
106 if ( isset( $old_data['raw'] ) && ! empty( $old_data['raw'] ) ) {
107 $raw = maybe_unserialize( $old_data['raw'] );
108 $file = is_array( $raw ) && isset( $raw['file'] ) ? $raw['file'] : '';
109 } else {
110 $file = '';
111 }
112
113 if ( is_array( $raw ) && isset( $raw['type'] ) ) {
114 // Change 'unknown' -> 'unversion'.
115 $short_desc = 'unknown' === $raw['type'] ? 'unversion' : $raw['type'];
116 } else {
117 $short_desc = '';
118 }
119 $raw_data = array(
120 'file' => $file,
121 'type' => $short_desc,
122 );
123 break;
124 }
125
126 return array(
127 'type' => $new_type,
128 'file' => $file,
129 'raw' => $raw_data,
130 );
131 }
132
133 /**
134 * @param array $issue_items
135 * @param object $model
136 *
137 * @return mixed
138 */
139 private function save_scan_issue_data( $issue_items, $model ) {
140 if ( empty( $issue_items ) ) {
141 return;
142 }
143 // Get existed issues.
144 $existed_issues = $model->get_issues( null, Scan_Item::STATUS_ACTIVE );
145 $unique_arr = array();
146 foreach ( $issue_items as $item ) {
147 $data = $this->adapt_scan_data( $item );
148 if ( empty( $data['file'] ) ) {
149 continue;
150 }
151 if ( ! empty( $existed_issues ) ) {
152 // Scan was started in version > 2.3.2.
153 foreach ( $existed_issues as $issue ) {
154 if ( Scan_Item::TYPE_VULNERABILITY === $data['type'] ) {
155 $file_name = $issue->raw_data['base_slug'] ?? '';
156 } else {
157 $file_name = $issue->raw_data['file'] ?? '';
158 }
159 // Check for uniqueness of elements.
160 if ( $data['file'] !== $file_name && ! in_array( $file_name, $unique_arr, true ) ) {
161 $unique_arr[] = $file_name;
162 $model->add_item( $data['type'], $data['raw'], Scan_Item::STATUS_ACTIVE );
163 }
164 }
165 } else {
166 $file_name = $data['file'] ?? $data['raw']['file'] ?? false;
167 // Scan wasn't start.
168 if ( $file_name && ! in_array( $file_name, $unique_arr, true ) ) {
169 $unique_arr[] = $file_name;
170 $model->add_item( $data['type'], $data['raw'], Scan_Item::STATUS_ACTIVE );
171 }
172 }
173 }
174 }
175
176 /**
177 * @param array $ignored_items
178 * @param object $model
179 *
180 * @return mixed
181 */
182 private function save_scan_ignored_data( $ignored_items, $model ) {
183 if ( empty( $ignored_items ) ) {
184 return;
185 }
186 // Get INDEXER of ignored issues.
187 $index_lists = get_site_option( Model_Scan::IGNORE_INDEXER, array() );
188 // Get existed ignored issues.
189 $existed_issues = $model->get_issues( null, Scan_Item::STATUS_IGNORE );
190 foreach ( $ignored_items as $item ) {
191 $data = $this->adapt_scan_data( $item );
192 if ( empty( $data['file'] ) ) {
193 continue;
194 }
195 if ( ! empty( $existed_issues ) ) {
196 // Scan was started in version > 2.3.2
197 foreach ( $existed_issues as $issue ) {
198 if ( Scan_Item::TYPE_VULNERABILITY === $data['type'] ) {
199 $file_name = $issue->raw_data['base_slug'] ?? '';
200 } else {
201 $file_name = $issue->raw_data['file'] ?? '';
202 }
203 // Check for uniqueness of elements.
204 if ( $data['file'] !== $file_name && ! in_array( $file_name, $index_lists, true ) ) {
205 if ( isset( $data['file'] ) ) {
206 $index_lists[] = $data['file'];
207 } elseif ( isset( $data['raw']['slug'] ) ) {
208 $index_lists[] = $data['raw']['slug'];
209 }
210 $model->add_item( $data['type'], $data['raw'], Scan_Item::STATUS_IGNORE );
211 }
212 }
213 } else {
214 $file_name = $data['file'] ?? $data['raw']['slug'] ?? false;
215 // Scan wasn't start.
216 if ( $file_name && ! in_array( $file_name, $index_lists, true ) ) {
217 $index_lists[] = $file_name;
218 $model->add_item( $data['type'], $data['raw'], Scan_Item::STATUS_IGNORE );
219 }
220 }
221 }
222 // Update IGNORE_INDEXER.
223 $model->update_ignore_list( $index_lists );
224 }
225
226 /**
227 * @return array
228 */
229 public function get_scan_issue_data() {
230
231 return $this->find_all_scan_issue_items();
232 }
233
234 /**
235 * @return array
236 */
237 public function get_scan_ignored_data() {
238 $ids = get_option( self::IGNORE_LIST, false );
239 if ( ! is_array( $ids ) ) {
240 $ids = get_site_option( self::IGNORE_LIST, array() );
241 if ( ! is_array( $ids ) ) {
242 return array();
243 }
244 }
245
246 return $this->find_all_scan_ignored_items( $ids );
247 }
248
249 /**
250 * @return int
251 */
252 private function run_simlpe_scan() {
253 $scan_component = new \WP_Defender\Component\Scan();
254 $scan_model = new Model_Scan();
255 // The simplest data:
256 $scan_model->percent = 100;
257 $scan_model->total_tasks = 1;
258 $scan_model->task_checkpoint = '';
259 $scan_model->status = Model_Scan::STATUS_FINISH;
260 $scan_model->date_start = gmdate( 'Y-m-d H:i:s' );
261 $scan_model->date_end = gmdate( 'Y-m-d H:i:s' );
262 $scan_model->is_automation = false;
263 $last_id = $scan_model->save();
264 $this->log( 'Scan ID during data migration: ' . $last_id, 'scan.log' );
265 $scan_component->advanced_scan_actions( $scan_model );
266
267 return $last_id;
268 }
269
270 /**
271 * Migrate scan data.
272 * First we save the ignored list to exclude them for the issue list.
273 * @param array $issue_list
274 * @param array $ignored_list
275 *
276 * @return mixed
277 */
278 public function migrate_scan_data( $issue_list, $ignored_list ) {
279 $scan = Model_Scan::get_active();
280 if ( is_object( $scan ) ) {
281 $this->log( 'Scan is still running', 'scan.log' );
282 return;
283 }
284 $model = Model_Scan::get_last();
285 // Scan was started and finished before.
286 if ( is_object( $model ) && ! is_wp_error( $model ) ) {
287 $this->save_scan_ignored_data( $ignored_list, $model );
288 $this->save_scan_issue_data( $issue_list, $model );
289 } else {
290 /**
291 * Scan hasn't started before. Next steps:
292 * create Scan record,
293 * no send notification,
294 * create Scan items.
295 */
296 $this->run_simlpe_scan();
297 $model = Model_Scan::get_last();
298 if ( is_object( $model ) && ! is_wp_error( $model ) ) {
299 $this->save_scan_ignored_data( $ignored_list, $model );
300 $this->save_scan_issue_data( $issue_list, $model );
301 }
302 }
303 }
304
305 /**
306 * @param array $issue_list
307 */
308 public function remove_old_scan_data( $issue_list, $ignored_list ) {
309 // Delete the list of scan issues.
310 if ( ! empty( $issue_list ) ) {
311 $parent_post_id = (int) $issue_list[0]['parentId'];
312 foreach ( $issue_list as $key => $issue ) {
313 // Delete scan items.
314 wp_delete_post( (int) $issue['id'] );
315 }
316 // Delete scan.
317 wp_delete_post( $parent_post_id );
318 }
319 // Delete the ignored list.
320 if ( ! empty( $ignored_list ) ) {
321 $parent_post_id = (int) $ignored_list[0]['parentId'];
322 foreach ( $ignored_list as $key => $item ) {
323 // Delete scan items.
324 wp_delete_post( (int) $item['id'] );
325 }
326 // Delete scan.
327 wp_delete_post( $parent_post_id );
328
329 delete_site_option( self::IGNORE_LIST );
330 delete_option( self::IGNORE_LIST );
331 }
332 }
333
334 public function change_onboarding_status() {
335 update_site_option( 'wp_defender_shown_activator', true );
336 }
337 }
338