PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.2.0
Defender Security – Malware Scanner, Login Security & Firewall v6.2.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 / behavior / scan-item / class-core-integrity.php

class-core-integrity.php in Defender Security – Malware Scanner, Login Security & Firewall 6.2.0, at src/behavior/scan-item/class-core-integrity.php

253 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles core integrity scan.
4 *
5 * @package WP_Defender\Behavior\Scan_Item
6 */
7
8 namespace WP_Defender\Behavior\Scan_Item;
9
10 use WP_Error;
11 use Calotes\Base\File;
12 use WP_Defender\Traits\IO;
13 use WP_Defender\Model\Scan;
14 use Calotes\Component\Behavior;
15 use WP_Defender\Traits\Formats;
16 use WP_Defender\Model\Scan_Item;
17 use WP_Defender\Traits\File_Operations;
18 use WP_Defender\Controller\Scan as Scan_Controller;
19 use WP_Filesystem_Base;
20
21 /**
22 * This class represents a behavior related to core integrity in the WP_Defender plugin.
23 */
24 class Core_Integrity extends Behavior {
25
26 use Formats;
27 use IO;
28 use File_Operations;
29
30 /**
31 * Return general data so we can output on frontend.
32 *
33 * @return array
34 */
35 public function to_array(): array {
36 $data = $this->owner->raw_data;
37 $file = $data['file'];
38
39 list( $file_created_at, $file_size, $deleted ) = $this->get_file_meta( $file );
40
41 return array(
42 'id' => $this->owner->id,
43 'type' => Scan_Item::TYPE_INTEGRITY,
44 'file_name' => pathinfo( $file, PATHINFO_BASENAME ),
45 'full_path' => $file,
46 'date_added' => $file_created_at,
47 'size' => $file_size,
48 'scenario' => $data['type'],
49 'deleted' => $deleted,
50 'short_desc' => $this->get_short_description(),
51 );
52 }
53
54 /**
55 * We will get the origin code by looking into svn repo.
56 *
57 * @return false|string|WP_Error
58 */
59 private function get_origin_code() {
60 global $wp_filesystem;
61 // Initialize the WP filesystem, no more using 'file-put-contents' function.
62 if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
63 require_once ABSPATH . '/wp-admin/includes/file.php';
64 WP_Filesystem();
65 }
66 global $wp_version;
67 $data = $this->owner->raw_data;
68 $file = wp_normalize_path( $data['file'] );
69 $relative_path = str_replace( wp_normalize_path( ABSPATH ), '', $file );
70 $source_file_url = "http://core.svn.wordpress.org/tags/$wp_version/" . $relative_path;
71 $ds = DIRECTORY_SEPARATOR;
72 if ( ! function_exists( 'download_url' ) ) {
73 require_once ABSPATH . 'wp-admin' . $ds . 'includes' . $ds . 'file.php';
74 }
75 $tmp = download_url( $source_file_url );
76 if ( is_wp_error( $tmp ) ) {
77 return $tmp;
78 }
79 $content = $wp_filesystem->get_contents( $tmp );
80 wp_delete_file( $tmp );
81
82 return $content;
83 }
84
85 /**
86 * Restore the file with its origin content.
87 *
88 * @return void|array|WP_Error
89 */
90 public function resolve() {
91 global $wp_filesystem;
92 // Initialize the WP filesystem, no more using 'file-put-contents' function.
93 if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
94 require_once ABSPATH . '/wp-admin/includes/file.php';
95 WP_Filesystem();
96 }
97
98 $data = $this->owner->raw_data;
99 if ( 'modified' !== $data['type'] ) {
100 // Should not be here unless case changed.
101 return;
102 }
103
104 $origin = $this->get_origin_code();
105 if ( false === $origin || is_wp_error( $origin ) ) {
106 return;
107 }
108
109 $path = $data['file'];
110 $ret = $wp_filesystem->put_contents( $path, $origin );
111 if ( $ret ) {
112 $scan = Scan::get_last();
113 $scan->remove_issue( $this->owner->id );
114 $this->log( sprintf( '%s is deleted', $path ), Scan_Controller::SCAN_LOG );
115
116 do_action( 'wpdef_fixed_scan_issue', 'core_integrity', 'resolve' );
117
118 return array( 'message' => esc_html__( 'This item has been resolved.', 'defender-security' ) );
119 } else {
120 return new WP_Error(
121 'defender_permissions_denied',
122 esc_html__(
123 'Permissions Denied. Defender does not have the needed permissions to edit the file. Please change file permissions to 640 or contact your hosting provider so they could change them for you.',
124 'defender-security'
125 )
126 );
127 }
128 }
129
130 /**
131 * Ignore the suspicious file.
132 *
133 * @return array
134 */
135 public function ignore(): array {
136 $scan = Scan::get_last();
137 $data = $this->owner->raw_data;
138 $issue_name = '<b>' . pathinfo( $data['file'], PATHINFO_BASENAME ) . '</b>';
139 $res = $scan->ignore_issue( $this->owner->id );
140 if ( ! $res ) {
141 return array(
142 'type_notice' => 'error',
143 'message' => $this->get_failed_ignore_result( $issue_name ),
144 );
145 }
146
147 return array(
148 'message' => sprintf(
149 /* translators: %s: Scan issue name. */
150 esc_html__( 'You’ve successfully ignored the security issue related to %s.', 'defender-security' ),
151 $issue_name
152 ),
153 );
154 }
155
156 /**
157 * Restore the ignored suspicious file.
158 *
159 * @return array
160 */
161 public function unignore(): array {
162 $scan = Scan::get_last();
163 $scan->unignore_issue( $this->owner->id );
164
165 return array( 'message' => esc_html__( 'The suspicious file has been successfully restored.', 'defender-security' ) );
166 }
167
168 /**
169 * Delete the file or whole folder.
170 *
171 * @return array|WP_Error
172 */
173 public function delete() {
174 $data = $this->owner->raw_data;
175 $scan = Scan::get_last();
176
177 // Check if the file exists and is readable. If not, remove it from the scan result and log the result.
178 $file = $data['file'];
179 if ( ! file_exists( $file ) || ! is_readable( $file ) ) {
180 $scan->remove_issue( $this->owner->id );
181 $this->log(
182 sprintf( '%s is not readable and will be removed from the scan result', $file ),
183 Scan_Controller::SCAN_LOG
184 );
185
186 return array( 'message' => esc_html__( 'This item has been deleted.', 'defender-security' ) );
187 } elseif ( 'unversion' === $data['type'] && $this->delete_infected_file( $file ) ) {
188 return $this->after_delete( $file, $scan, 'core_integrity' );
189 } elseif ( 'dir' === $data['type'] && $this->delete_dir( $file ) ) {
190 return $this->after_delete( $file, $scan, 'core_integrity' );
191 }
192
193 return $this->get_permission_error( $file );
194 }
195
196 /**
197 * Return the source code depending on the type of the issue:
198 * If it is unversion, return full source,
199 * if it is dir, we return a list of files,
200 * if it is modified, we will return the current code & origin.
201 *
202 * @return array
203 */
204 public function pull_src(): array {
205 global $wp_filesystem;
206 // Initialize the WP filesystem, no more using 'file-put-contents' function.
207 if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
208 require_once ABSPATH . '/wp-admin/includes/file.php';
209 WP_Filesystem();
210 }
211
212 $data = $this->owner->raw_data;
213 if ( ! file_exists( $data['file'] ) && ! is_dir( $data['file'] ) ) {
214 return array(
215 'code' => '',
216 'origin' => '',
217 );
218 }
219 switch ( $data['type'] ) {
220 case 'unversion':
221 return array( 'code' => $wp_filesystem->get_contents( $data['file'] ) );
222 case 'dir':
223 $dir_tree = new File( $data['file'], true, true, array(), array(), false );
224
225 return array( 'code' => implode( PHP_EOL, $dir_tree->get_dir_tree() ) );
226 case 'modified':
227 default:
228 return array(
229 'code' => $wp_filesystem->get_contents( $data['file'] ),
230 'origin' => $this->get_origin_code(),
231 );
232 }
233 }
234
235 /**
236 * Retrieves a short description based on the type of data.
237 *
238 * @return string The short description.
239 */
240 private function get_short_description(): string {
241 $data = $this->owner->raw_data;
242 if ( 'unversion' === $data['type'] ) {
243 return esc_html__( 'Unknown file in WordPress core', 'defender-security' );
244 } elseif ( 'dir' === $data['type'] ) {
245 return esc_html__( 'This directory does not belong to WordPress core', 'defender-security' );
246 } elseif ( 'modified' === $data['type'] ) {
247 return esc_html__( 'This WordPress core file appears modified', 'defender-security' );
248 }
249
250 return '';
251 }
252 }
253