PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.4.0
Defender Security – Malware Scanner, Login Security & Firewall v5.4.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 / controller / class-bot-trap.php

class-bot-trap.php in Defender Security – Malware Scanner, Login Security & Firewall 5.4.0, at src/controller/class-bot-trap.php

247 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles bot trap functionality.
4 *
5 * @package WP_Defender\Controller
6 */
7
8 namespace WP_Defender\Controller;
9
10 use WP_Defender\Controller;
11 use WP_Defender\Component\Bot_Trap as Bot_Trap_Component;
12 use WP_Defender\Component\Known_Bots\Known_Bots_Factory;
13 use WP_Defender\Model\Lockout_Ip;
14 use WP_Defender\Traits\IP;
15
16 /**
17 * Handles operations to insert a weekly rotating hash URL into the footer,
18 * and blocking IP addresses that access this URL.
19 */
20 class Bot_Trap extends Controller {
21 use IP;
22
23 const URL_QUERY = 'wpdef-bot-trap-url';
24
25 /**
26 * Service for handling logic.
27 *
28 * @var Bot_Trap_Component
29 */
30 protected $service;
31
32 /**
33 * Constructor for the Bot_Trap class.
34 * Initializes the service and sets up necessary hooks.
35 *
36 * @param Bot_Trap_Component $service The service instance for bot trap functionality.
37 */
38 public function __construct( Bot_Trap_Component $service ) {
39 $this->service = $service;
40
41 if ( $this->service->is_enabled() ) {
42 add_action( 'init', array( $this, 'init' ) );
43 add_action( 'wp_footer', array( $this, 'inject_footer' ) );
44 add_action( 'wpdef_rotate_bot_trap_secret_hash', array( $this, 'rotate_hash' ) );
45 add_action( 'template_redirect', array( $this, 'handle_hash_url' ) );
46 add_filter( 'query_vars', array( $this, 'add_query_var' ) );
47 add_action( 'after_switch_theme', array( $this, 'flush_rewrite' ) );
48 }
49 }
50
51 /**
52 * Initializes the bot trap functionality.
53 * Schedules a weekly cron job to rotate the hash and registers a rewrite rule.
54 */
55 public function init() {
56 $this->schedule_cron();
57
58 if ( ! $this->service->get_hash() ) {
59 $this->service->rotate_hash();
60 }
61
62 $this->flush_rewrite();
63 $this->service->handle_robots_txt();
64 }
65
66 /**
67 * Schedules a weekly cron job to rotate the bot trap hash.
68 * This ensures that the bot trap URL changes weekly.
69 */
70 public function schedule_cron() {
71 if ( ! wp_next_scheduled( 'wpdef_rotate_bot_trap_secret_hash' ) ) {
72 wp_schedule_event( time(), 'weekly', 'wpdef_rotate_bot_trap_secret_hash' );
73 }
74 }
75
76 /**
77 * Registers a rewrite rule for the bot trap URL.
78 * The URL will be in the format: /{hash}/
79 * where {hash} is a 16-character hexadecimal string.
80 */
81 public function register_rewrite_rule() {
82 $hash = $this->service->get_hash();
83 add_rewrite_rule( "^{$hash}/?$", 'index.php?' . self::URL_QUERY . '=' . $hash, 'top' );
84 }
85
86 /**
87 * Rotates the bot trap hash and flushes rewrite rules.
88 */
89 public function rotate_hash() {
90 $this->service->rotate_hash();
91 }
92
93 /**
94 * Adds a query variable for the bot trap URL.
95 * This allows us to capture the hash from the URL.
96 *
97 * @param array $vars Existing query variables.
98 * @return array Modified query variables.
99 */
100 public function add_query_var( $vars ) {
101 $vars[] = self::URL_QUERY;
102 return $vars;
103 }
104
105 /**
106 * Handles the bot trap URL when accessed.
107 * If the hash in the URL matches the stored hash, block the IP.
108 * Otherwise, it will do nothing.
109 */
110 public function handle_hash_url() {
111 $used_hash = get_query_var( self::URL_QUERY );
112 $valid_hash = $this->service->get_hash();
113
114 if ( $used_hash === $valid_hash ) {
115 $known_bots = Known_Bots_Factory::create();
116 $bot_ips = $known_bots->get_all_bot_ips();
117
118 // Flatten 2D array into a single array.
119 $flattened_bot_ips = array();
120 foreach ( $bot_ips as $ips ) {
121 foreach ( $ips as $ip ) {
122 $flattened_bot_ips[] = $ip;
123 }
124 }
125
126 $model = $this->service->model;
127 $ips = $this->service->get_user_ip();
128
129 foreach ( $ips as $ip ) {
130 // Skip if the IP is a known bot IP.
131 if ( $this->is_ip_in_format( $ip, $flattened_bot_ips ) ) {
132 continue;
133 }
134
135 $lockout_model = Lockout_Ip::get( $ip );
136 $remaining_time = 0;
137 if ( 'permanent' === $model->bot_trap_lockout_type ) {
138 $lockout_model->attempt = 0;
139 $lockout_model->meta['login'] = array();
140 $lockout_model->meta['nf'] = array();
141 $lockout_model->save();
142
143 do_action( 'wd_blacklist_this_ip', $ip );
144 } else {
145 $lockout_model->status = Lockout_Ip::STATUS_BLOCKED;
146 $lockout_model->lock_time = time();
147
148 $this->service->create_blocked_lockout(
149 $lockout_model,
150 $model->bot_trap_message,
151 strtotime( '+' . $model->bot_trap_lockout_duration . ' ' . $model->bot_trap_lockout_duration_unit )
152 );
153
154 $remaining_time = $lockout_model->remaining_release_time();
155 }
156
157 // Need to create a log.
158 $this->service->log_event( $ip, $used_hash, Bot_Trap_Component::SCENARIO_BOT_TRAP );
159
160 wd_di()->get( Firewall::class )->actions_for_blocked(
161 $model->bot_trap_message,
162 $remaining_time,
163 Bot_Trap_Component::SCENARIO_BOT_TRAP,
164 $ips
165 );
166 }
167 }
168 }
169
170 /**
171 * Injects the bot trap URL into the footer of frontend pages.
172 * This URL is hidden.
173 */
174 public function inject_footer() {
175 if ( is_admin() ) {
176 return;
177 }
178
179 $hash = $this->service->get_hash();
180 echo '<div style="display:none;"><a href="' . esc_url( home_url( "/{$hash}" ) ) . '">Secret Link</a></div>';
181 }
182
183 /**
184 * Flushes the rewrite rules to ensure the new bot trap URL is recognized.
185 */
186 public function flush_rewrite() {
187 $this->register_rewrite_rule();
188 flush_rewrite_rules();
189 }
190
191 /**
192 * Delete all the data & the cache.
193 */
194 public function remove_data() {
195 // Remove the bot trap hash from options.
196 delete_site_option( Bot_Trap_Component::URL_HASH_KEY );
197
198 $this->service->remove_rule();
199
200 // Flush rewrite rules to remove the bot trap URL.
201 flush_rewrite_rules();
202 }
203
204 /**
205 * Exports strings.
206 *
207 * @return array An array of strings.
208 */
209 public function export_strings(): array {
210 return array();
211 }
212
213 /**
214 * Converts the object data to an array.
215 *
216 * @return array An array representation of the object.
217 */
218 public function to_array(): array {
219 return array();
220 }
221
222 /**
223 * Imports data into the model.
224 *
225 * @param array $data Data to be imported into the model.
226 *
227 * @throws Exception If table is not defined.
228 */
229 public function import_data( array $data ) {
230 }
231
232 /**
233 * Removes settings for all submodules.
234 */
235 public function remove_settings(): void {
236 }
237
238 /**
239 * Provides data for the frontend.
240 *
241 * @return array An array of data for the frontend.
242 */
243 public function data_frontend(): array {
244 return array();
245 }
246 }
247