PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.6.0
Defender Security – Malware Scanner, Login Security & Firewall v5.6.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 / class-central.php

class-central.php in Defender Security – Malware Scanner, Login Security & Firewall 5.6.0, at src/class-central.php

312 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles all AJAX requests in this plugin.
4 *
5 * @package WP_Defender
6 */
7
8 namespace WP_Defender;
9
10 use Exception;
11 use Calotes\Helper\HTTP;
12 use WP_Defender\Traits\IO;
13 use Calotes\Component\Request;
14 use Calotes\Component\Response;
15 use WP_Defender\Traits\Permission;
16
17 /**
18 * Handles all AJAX requests in this plugin.
19 */
20 class Central extends Component {
21
22 use IO;
23 use Permission;
24
25 public const INTERNAL_LOG = 'internal.log';
26
27 /**
28 * This will hold the db data of each module, all data must be getting through this.
29 *
30 * @var array
31 */
32 protected $states = array();
33
34 /**
35 * This should be constructed only once.
36 */
37 public function __construct() {
38 $action = defender_base_action();
39 add_action( 'wp_ajax_' . $action, array( $this, 'routing' ) );
40 add_action( 'wp_ajax_nopriv_' . $action, array( $this, 'routing' ) );
41 }
42
43 /**
44 * This is a global ajax call, receive all the requests and dispatch to the right controller.
45 */
46 public function routing() {
47 // This is the intention, we will use it to find the data stored in DI.
48 $route = HTTP::get( 'route', false );
49 $nonce = HTTP::get( '_def_nonce', false );
50 if ( empty( $route ) || empty( $nonce ) ) {
51 exit;
52 }
53
54 $this->check_opcache();
55
56 $route = wp_unslash( $route );
57
58 if (
59 ! is_user_logged_in() &&
60 $this->is_private_access( $route )
61 ) {
62 $data = array(
63 'message' => esc_html__( 'Your session expired. Please login to continue.', 'defender-security' ),
64 'type_notice' => 'session_out',
65 );
66
67 if ( $this->is_redirect( $route ) ) {
68 $data['redirect'] = wp_login_url( wp_get_referer() );
69 }
70
71 wp_send_json_error( $data );
72 }
73
74 // Nonce is not valid.
75 if ( ! wp_verify_nonce( $nonce, $route ) ) {
76 wp_send_json_error(
77 array(
78 'message' => esc_html__( 'Invalid API request.', 'defender-security' ),
79 'type_notice' => 'invalid_request',
80 )
81 );
82 }
83
84 $key = sprintf( 'controller.%s', $route );
85
86 try {
87 $package = wd_di()->get( $key );
88 [ $class, $method, $is_private ] = $package;
89 if ( $is_private && ! $this->check_permission() ) {
90 wp_send_json_error(
91 array(
92 'message' => esc_html__( 'You shall not pass.', 'defender-security' ),
93 'type_notice' => 'not_allowed',
94 )
95 );
96 }
97 if ( $is_private ) {
98 if ( ! wp_next_scheduled( 'defender_hub_sync' ) ) {
99 // Sync with HUB on every request it made, but not on public call.
100 wp_schedule_single_event( time(), 'defender_hub_sync' );
101 }
102 }
103 $this->execute_intention( $class, $method );
104 } catch ( Exception $e ) {
105 $this->log( $e->getMessage(), self::INTERNAL_LOG );
106 }
107 }
108
109 /**
110 * Execute the method, return should be various base on the method.
111 *
112 * @param string $class_name Class name.
113 * @param string $method The function to call.
114 *
115 * @return Response|void
116 */
117 private function execute_intention( $class_name, $method ) {
118 $object = wd_di()->get( $class_name );
119 if ( is_object( $object ) ) {
120 $request = new Request();
121 // Because the method is getting params from $_REQUEST directly, we don't need to pass any args, just call.
122 // No use reflection method for performance, also this just a simple call.
123 // Manipulate the POST as raw data.
124 $_POST = $request->get_data();
125
126 return $object->$method( $request );
127 } else {
128 $this->log( sprintf( 'class not found when executing: %s %s', $class_name, $method ), self::INTERNAL_LOG );
129 }
130 }
131
132 /**
133 * Setting up routes for different controller methods.
134 *
135 * @param string $method The function to call.
136 * @param string $class_name Class name.
137 * @param bool $is_private Should this expose for non-auth user.
138 * @param bool $is_redirect Include redirect URL in response if necessary.
139 *
140 * @return void
141 */
142 public function add_route( $method, $class_name, $is_private = true, $is_redirect = false ) {
143 $intention = $this->get_intention( $class_name, $method );
144
145 wd_di()->set(
146 sprintf( 'controller.%s', $intention ),
147 array(
148 $class_name,
149 $method,
150 $is_private,
151 $is_redirect,
152 )
153 );
154 wd_di()->set( sprintf( 'route.%s', $intention ), $intention );
155 wd_di()->set( sprintf( 'nonce.%s', $intention ), wp_create_nonce( $intention ) );
156 }
157
158 /**
159 * Retrieves the route for a given method and class name.
160 *
161 * @param string $method The method name.
162 * @param string $class_name The class name.
163 *
164 * @return mixed The route associated with the intention, or null if not found.
165 */
166 public function get_route( $method, $class_name ) {
167 $intention = $this->get_intention( $class_name, $method );
168
169 try {
170 return wd_di()->get( sprintf( 'route.%s', $intention ) );
171 } catch ( Exception $e ) {
172 $this->log( $e->getMessage(), self::INTERNAL_LOG );
173 }
174 }
175
176 /**
177 * Retrieves the nonce for a given method and class name.
178 *
179 * @param string $method The method name.
180 * @param string $class_name The class name.
181 *
182 * @return mixed The nonce associated with the intention, or null if not found.
183 */
184 public function get_nonce( $method, $class_name ) {
185 $intention = $this->get_intention( $class_name, $method );
186
187 try {
188 return wd_di()->get( sprintf( 'nonce.%s', $intention ) );
189 } catch ( Exception $e ) {
190 $this->log( $e->getMessage(), self::INTERNAL_LOG );
191 }
192 }
193
194 /**
195 * Check OPcache is enabled or not.
196 */
197 private function check_opcache() {
198 if ( $this->is_opcache_save_comments_disabled() ) {
199 wp_send_json_error(
200 array(
201 'message' => sprintf(
202 /* translators: %s: Name settings. */
203 esc_html__( '%s is disabled. Please contact your hosting provider to enable it.', 'defender-security' ),
204 '<strong>OPcache Save Comments</strong>'
205 ),
206 'type_notice' => 'opcache_disabled',
207 )
208 );
209 }
210 }
211
212 /**
213 * Check OPcache is enabled or not.
214 *
215 * @return bool
216 */
217 public function is_opcache_save_comments_disabled() {
218 // If OPcache is disabled.
219 if ( ini_get( 'opcache.enable' ) !== '1' ) {
220 return false;
221 }
222
223 // If OPcache is enabled and save comments disabled.
224 if ( ini_get( 'opcache.save_comments' ) !== '1' ) {
225 return true;
226 }
227
228 // Any other case.
229 return false;
230 }
231
232 /**
233 * Display message if OPcache is disabled.
234 *
235 * @return string
236 */
237 public function display_opcache_message() {
238 return sprintf(
239 /* translators: 1. Option settings. 2. Name settings. */
240 esc_html__(
241 'We have detected that your %1$s is disabled on your hosting. For Defender to function properly, please contact your hosting provider and ask them to enable %2$s.',
242 'defender-security'
243 ),
244 '<strong>opcache.save_comments</strong>',
245 '<strong>OPcache Save Comments</strong>'
246 );
247 }
248
249 /**
250 * Verify is ajax call is private.
251 * Here private stands for only authenticated user can do ajax call.
252 *
253 * @param string $route Route md5 hash.
254 *
255 * @return bool Return true if the request is private else false.
256 */
257 private function is_private_access( $route ) {
258 $key = sprintf( 'controller.%s', $route );
259
260 try {
261 $package = wd_di()->get( $key );
262
263 return isset( $package[2] ) && $package[2];
264 } catch ( Exception $e ) {
265 $this->log( $e->getMessage(), self::INTERNAL_LOG );
266 }
267
268 return false;
269 }
270
271 /**
272 * Get intention.
273 *
274 * @param string $class_name Class name.
275 * @param string $method Method name.
276 *
277 * @return string
278 * @since 3.11.0
279 */
280 private function get_intention( string $class_name, string $method ) {
281 $intention = sprintf( '%s.%s', $class_name, $method );
282
283 if ( ! defined( 'DEFENDER_DEBUG' ) || false === DEFENDER_DEBUG ) {
284 $intention = hash( 'md5', $intention );
285 }
286
287 return $intention;
288 }
289
290 /**
291 * Add redirect URL in response.
292 *
293 * @param string $route Route md5 hash.
294 *
295 * @return bool Return true if redirect URL is required in response else false.
296 * @since 3.11.0
297 */
298 private function is_redirect( $route ) {
299 $key = sprintf( 'controller.%s', $route );
300
301 try {
302 $package = wd_di()->get( $key );
303
304 return isset( $package[3] ) && $package[3];
305 } catch ( Exception $e ) {
306 $this->log( $e->getMessage(), self::INTERNAL_LOG );
307 }
308
309 return false;
310 }
311 }
312