1
|
|
|
<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed'); |
2
|
|
|
/** |
3
|
|
|
* EED_Bot_Trap Class |
4
|
|
|
* |
5
|
|
|
* adds an email input (honeypot) to the ticket selector form submission |
6
|
|
|
* and also checks that the form is not being submitted either too fast or too slow |
7
|
|
|
* which can be an indication that the form was submitted by a bot |
8
|
|
|
* |
9
|
|
|
* @package Event Espresso |
10
|
|
|
* @subpackage /modules/bot_trap/ |
11
|
|
|
* @author Brent Christensen |
12
|
|
|
*/ |
13
|
|
|
class EED_Bot_Trap extends EED_Module { |
14
|
|
|
|
15
|
|
|
|
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* @return EED_Bot_Trap |
19
|
|
|
*/ |
20
|
|
|
public static function instance() { |
21
|
|
|
return parent::get_instance( __CLASS__ ); |
|
|
|
|
22
|
|
|
} |
23
|
|
|
|
24
|
|
|
|
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* set_hooks - for hooking into EE Core, other modules, etc |
28
|
|
|
* |
29
|
|
|
* @access public |
30
|
|
|
* @return void |
31
|
|
|
*/ |
32
|
|
|
public static function set_hooks() { |
33
|
|
|
if ( |
34
|
|
|
apply_filters( 'FHEE__EED_Bot_Trap__set_hooks__use_bot_trap', true ) && |
35
|
|
|
\EE_Registry::instance()->CFG->registration->use_bot_trap |
36
|
|
|
) { |
37
|
|
|
\EED_Bot_Trap::set_trap(); |
38
|
|
|
// redirect bots to bogus success page |
39
|
|
|
\EE_Config::register_route( 'ticket_selection_received', 'EED_Bot_Trap', 'display_bot_trap_success' ); |
40
|
|
|
} |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
|
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* set_hooks_admin - for hooking into EE Admin Core, other modules, etc |
47
|
|
|
* |
48
|
|
|
* @access public |
49
|
|
|
* @return void |
50
|
|
|
*/ |
51
|
|
|
public static function set_trap() { |
52
|
|
|
define('EE_BOT_TRAP_BASE_URL', plugin_dir_url(__FILE__) . DS); |
53
|
|
|
add_action( |
54
|
|
|
'AHEE__ticket_selector_chart__template__after_ticket_selector', |
55
|
|
|
array('EED_Bot_Trap', 'generate_bot_trap'), |
56
|
|
|
10, 2 |
57
|
|
|
); |
58
|
|
|
add_action( |
59
|
|
|
'EED_Ticket_Selector__process_ticket_selections__before', |
60
|
|
|
array('EED_Bot_Trap', 'process_bot_trap'), |
61
|
|
|
1, 2 |
62
|
|
|
); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
|
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* set_hooks_admin - for hooking into EE Admin Core, other modules, etc |
69
|
|
|
* |
70
|
|
|
* @access public |
71
|
|
|
* @return void |
72
|
|
|
*/ |
73
|
|
|
public static function set_hooks_admin() { |
74
|
|
|
if ( |
75
|
|
|
defined('DOING_AJAX') |
76
|
|
|
&& DOING_AJAX |
77
|
|
|
&& apply_filters('FHEE__EED_Bot_Trap__set_hooks__use_bot_trap', true) |
78
|
|
|
&& \EE_Registry::instance()->CFG->registration->use_bot_trap |
79
|
|
|
) { |
80
|
|
|
\EED_Bot_Trap::set_trap(); |
81
|
|
|
} |
82
|
|
|
add_action( |
83
|
|
|
'AHEE__Extend_Registration_Form_Admin_Page___reg_form_settings_template', |
84
|
|
|
array( 'EED_Bot_Trap', 'bot_trap_settings_form' ), |
85
|
|
|
10 |
86
|
|
|
); |
87
|
|
|
add_filter( |
88
|
|
|
'FHEE__Extend_Registration_Form_Admin_Page___update_reg_form_settings__CFG_registration', |
89
|
|
|
array( 'EED_Bot_Trap', 'update_bot_trap_settings_form' ), |
90
|
|
|
10, 1 |
91
|
|
|
); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
|
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* run - initial module setup |
98
|
|
|
* |
99
|
|
|
* @access public |
100
|
|
|
* @param WP $WP |
101
|
|
|
* @return void |
102
|
|
|
*/ |
103
|
|
|
public function run( $WP ) {} |
104
|
|
|
|
105
|
|
|
|
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* generate_bot_trap |
109
|
|
|
* |
110
|
|
|
* @access public |
111
|
|
|
* @return void |
112
|
|
|
*/ |
113
|
|
|
public static function generate_bot_trap() { |
114
|
|
|
$do_not_enter = esc_html__( 'please do not enter anything in this input', 'event_espresso' ); |
115
|
|
|
$html = '<div id="tkt-slctr-request-processor-dv" style="float:left; margin-left:-999em;">'; |
116
|
|
|
$html .= '<label for="tkt-slctr-request-processor-email">' . $do_not_enter . '</label>'; |
117
|
|
|
$html .= '<input type="email" name="tkt-slctr-request-processor-email" value=""/>'; |
118
|
|
|
$html .= '<input type="hidden" name="tkt-slctr-request-processor-token" value="'; |
119
|
|
|
if ( EE_Registry::instance()->CFG->registration->use_encryption ) { |
120
|
|
|
EE_Registry::instance()->load_core( 'EE_Encryption' ); |
121
|
|
|
$html .= EE_Encryption::instance()->encrypt( time() ); |
122
|
|
|
} else { |
123
|
|
|
$html .= time(); |
124
|
|
|
} |
125
|
|
|
$html .= '"/>'; |
126
|
|
|
$html .= '</div>'; |
127
|
|
|
echo $html; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* process_bot_trap |
133
|
|
|
* |
134
|
|
|
* @param array|string $triggered_trap_callback Callback that will be executed for handling the |
135
|
|
|
* response if the bot trap is triggered. |
136
|
|
|
* It should receive one argument: a boolean indicating |
137
|
|
|
* whether the trap was triggered by suspicious timing or not. |
138
|
|
|
*/ |
139
|
|
|
public static function process_bot_trap( $triggered_trap_callback = array() ) { |
140
|
|
|
// what's your email address Mr. Bot ? |
141
|
|
|
$empty_trap = isset( $_REQUEST[ 'tkt-slctr-request-processor-email' ] ) |
142
|
|
|
&& $_REQUEST[ 'tkt-slctr-request-processor-email' ] === '' |
143
|
|
|
? true |
144
|
|
|
: false; |
145
|
|
|
// get encrypted timestamp for when the form was originally displayed |
146
|
|
|
$bot_trap_timestamp = isset( $_REQUEST[ 'tkt-slctr-request-processor-token' ] ) |
147
|
|
|
? sanitize_text_field( $_REQUEST[ 'tkt-slctr-request-processor-token' ] ) |
148
|
|
|
: ''; |
149
|
|
|
// decrypt and convert to absolute integer |
150
|
|
|
if ( EE_Registry::instance()->CFG->registration->use_encryption ) { |
151
|
|
|
EE_Registry::instance()->load_core( 'EE_Encryption' ); |
152
|
|
|
$bot_trap_timestamp = absint( EE_Encryption::instance()->decrypt( $bot_trap_timestamp ) ); |
153
|
|
|
} else { |
154
|
|
|
$bot_trap_timestamp = absint( $bot_trap_timestamp ); |
155
|
|
|
} |
156
|
|
|
// ticket form submitted too impossibly fast ( after now ) or more than an hour later ??? |
157
|
|
|
$suspicious_timing = $bot_trap_timestamp > time() || $bot_trap_timestamp < ( time() - HOUR_IN_SECONDS ) |
158
|
|
|
? true |
159
|
|
|
: false; |
160
|
|
|
// are we human ? |
161
|
|
|
if ( $empty_trap && ! $suspicious_timing ) { |
162
|
|
|
do_action('AHEE__EED_Bot_Trap__process_bot_trap__trap_not_triggered'); |
163
|
|
|
return; |
164
|
|
|
} |
165
|
|
|
// check the given callback is valid first before executing |
166
|
|
|
if ( ! is_callable($triggered_trap_callback ) ) { |
167
|
|
|
// invalid callback so lets just sub in our default. |
168
|
|
|
$triggered_trap_callback = array( 'EED_Bot_Trap', 'triggered_trap_response' ); |
169
|
|
|
} |
170
|
|
|
call_user_func_array($triggered_trap_callback, array( $suspicious_timing ) ); |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
|
174
|
|
|
|
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* This is the default callback executed by EED_Bot_Trap::process_bot_trap that handles the response. |
178
|
|
|
* |
179
|
|
|
* @param bool $suspicious_timing If true, then the bot trap was triggered due to the suspicious timing test. |
180
|
|
|
*/ |
181
|
|
|
public static function triggered_trap_response( $suspicious_timing ) { |
182
|
|
|
// UH OH... |
183
|
|
|
$redirect_url = add_query_arg( |
184
|
|
|
array( 'ee' => 'ticket_selection_received' ), |
185
|
|
|
EE_Registry::instance()->CFG->core->reg_page_url() |
186
|
|
|
); |
187
|
|
|
if ( $suspicious_timing ) { |
188
|
|
|
$redirect_url = add_query_arg( |
189
|
|
|
array( 'ee-notice' => urlencode( esc_html__( 'We\'re sorry, but your ticket selections could not be processed due to a server timing error. Please hit the back button on your browser and try again.', 'event_espresso' ) ) ), |
190
|
|
|
$redirect_url |
191
|
|
|
); |
192
|
|
|
} |
193
|
|
|
$redirect_url = apply_filters('FHEE__EED_Bot_Trap__process_bot_trap__redirect_url', $redirect_url); |
194
|
|
|
// if AJAX, return the redirect URL |
195
|
|
|
if (defined('DOING_AJAX') && DOING_AJAX) { |
196
|
|
|
echo json_encode( |
197
|
|
|
array_merge( |
198
|
|
|
\EE_Error::get_notices(false), |
199
|
|
|
array( |
200
|
|
|
'redirect_url' => $redirect_url |
201
|
|
|
) |
202
|
|
|
) |
203
|
|
|
); |
204
|
|
|
exit(); |
205
|
|
|
} |
206
|
|
|
wp_safe_redirect($redirect_url); |
207
|
|
|
exit(); |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
|
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* display_bot_trap_success |
214
|
|
|
* shows a "success" screen to bots so that they (ie: the ppl managing them) think the form was submitted successfully |
215
|
|
|
* |
216
|
|
|
* @access public |
217
|
|
|
* @return void |
218
|
|
|
*/ |
219
|
|
|
public static function display_bot_trap_success() { |
220
|
|
|
add_filter( 'FHEE__EED_Single_Page_Checkout__run', '__return_false' ); |
221
|
|
|
$bot_notice = esc_html__( 'Thank you so much. Your ticket selections have been received for consideration.', 'event_espresso' ); |
222
|
|
|
$bot_notice = isset( $_REQUEST[ 'ee-notice' ] ) && $_REQUEST[ 'ee-notice' ] !== '' ? sanitize_text_field( stripslashes( $_REQUEST[ 'ee-notice' ] ) ) : $bot_notice; |
223
|
|
|
EE_Registry::instance()->REQ->add_output( EEH_HTML::div( $bot_notice, '', 'ee-attention' ) ); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
|
227
|
|
|
|
228
|
|
|
/*********************************** ADMIN **********************************/ |
229
|
|
|
|
230
|
|
|
|
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* bot_trap_settings_form |
234
|
|
|
* |
235
|
|
|
* @access public |
236
|
|
|
* @return void |
237
|
|
|
*/ |
238
|
|
|
public static function bot_trap_settings_form() { |
239
|
|
|
EED_Bot_Trap::_bot_trap_settings_form()->enqueue_js(); |
240
|
|
|
echo EED_Bot_Trap::_bot_trap_settings_form()->get_html(); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
|
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* _bot_trap_settings_form |
247
|
|
|
* |
248
|
|
|
* @access protected |
249
|
|
|
* @return EE_Form_Section_Proper |
250
|
|
|
*/ |
251
|
|
|
protected static function _bot_trap_settings_form() { |
252
|
|
|
return new EE_Form_Section_Proper( |
253
|
|
|
array( |
254
|
|
|
'name' => 'bot_trap_settings', |
255
|
|
|
'html_id' => 'bot_trap_settings', |
256
|
|
|
'layout_strategy' => new EE_Admin_Two_Column_Layout(), |
257
|
|
|
'subsections' => array( |
258
|
|
|
'bot_trap_hdr' => new EE_Form_Section_HTML( EEH_HTML::h2( esc_html__( 'Bot Trap Settings', 'event_espresso' ) ) ), |
259
|
|
|
'use_bot_trap' => new EE_Yes_No_Input( |
260
|
|
|
array( |
261
|
|
|
'html_label_text' => esc_html__( 'Enable Bot Trap', 'event_espresso' ), |
262
|
|
|
'html_help_text' => esc_html__( 'The Event Espresso Bot Trap will insert a fake input into your Ticket Selector forms that is hidden from regular site visitors, but visible to spam bots. Because the input asks for an email address, it is irresistible to spam bots who will of course enter text into it. Since regular site visitors can not see this input, any value detected during form submission means a bot has been detected, which will then be blocked from submitting the form.', 'event_espresso' ), |
263
|
|
|
'default' => isset( EE_Registry::instance()->CFG->registration->use_bot_trap ) ? EE_Registry::instance()->CFG->registration->use_bot_trap : true, |
264
|
|
|
'required' => false |
265
|
|
|
) |
266
|
|
|
), |
267
|
|
|
'use_encryption' => new EE_Yes_No_Input( |
268
|
|
|
array( |
269
|
|
|
'html_label_text' => esc_html__( 'Encrypt Bot Trap Data', 'event_espresso' ), |
270
|
|
|
'html_help_text' => esc_html__( 'One way to detect spam bots is by looking at how long it takes them to submit a form. They are often inhumanly fast, or will submit forms hours, days, or even weeks after the form was first scraped off the web. The Event Espresso Bot Trap will send a timestamp with the Ticket Selector form when it is submitted. By default, this timestamp is encrypted so that the spam bots can not change it, but encryption may cause issues on some servers due to configuration "conflicts". If you continuously get caught in the bot trap, then try setting this option to "No". This may increase the number of spam submissions you receive, but increases server compatibility.', 'event_espresso' ), |
271
|
|
|
'default' => isset( EE_Registry::instance()->CFG->registration->use_encryption ) ? EE_Registry::instance()->CFG->registration->use_encryption : true, |
272
|
|
|
'required' => false |
273
|
|
|
) |
274
|
|
|
), |
275
|
|
|
) |
276
|
|
|
) |
277
|
|
|
); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
|
281
|
|
|
|
282
|
|
|
/** |
283
|
|
|
* update_bot_trap_settings_form |
284
|
|
|
* |
285
|
|
|
* @access public |
286
|
|
|
* @param \EE_Registration_Config $EE_Registration_Config |
287
|
|
|
* @return \EE_Registration_Config |
288
|
|
|
*/ |
289
|
|
|
public static function update_bot_trap_settings_form( EE_Registration_Config $EE_Registration_Config ) { |
290
|
|
|
try { |
291
|
|
|
$bot_trap_settings_form = EED_Bot_Trap::_bot_trap_settings_form(); |
292
|
|
|
// if not displaying a form, then check for form submission |
293
|
|
|
if ( $bot_trap_settings_form->was_submitted() ) { |
294
|
|
|
// capture form data |
295
|
|
|
$bot_trap_settings_form->receive_form_submission(); |
296
|
|
|
// validate form data |
297
|
|
|
if ( $bot_trap_settings_form->is_valid() ) { |
298
|
|
|
// grab validated data from form |
299
|
|
|
$valid_data = $bot_trap_settings_form->valid_data(); |
300
|
|
|
if ( isset( $valid_data[ 'use_bot_trap' ], $valid_data[ 'use_encryption' ] ) ) { |
301
|
|
|
$EE_Registration_Config->use_bot_trap = $valid_data[ 'use_bot_trap' ]; |
302
|
|
|
$EE_Registration_Config->use_encryption = $valid_data[ 'use_encryption' ]; |
303
|
|
|
} else { |
304
|
|
|
EE_Error::add_error( esc_html__( 'Invalid or missing Bot Trap settings. Please refresh the form and try again.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ ); |
305
|
|
|
} |
306
|
|
|
} else { |
307
|
|
|
if ( $bot_trap_settings_form->submission_error_message() != '' ) { |
308
|
|
|
EE_Error::add_error( $bot_trap_settings_form->submission_error_message(), __FILE__, __FUNCTION__, __LINE__ ); |
309
|
|
|
} |
310
|
|
|
} |
311
|
|
|
} |
312
|
|
|
} catch ( EE_Error $e ) { |
313
|
|
|
$e->get_error(); |
314
|
|
|
} |
315
|
|
|
return $EE_Registration_Config; |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
|
319
|
|
|
} |
320
|
|
|
// End of file EED_Bot_Trap.module.php |
321
|
|
|
// Location: /modules/bot_trap/EED_Bot_Trap.module.php |
This check looks for a call to a parent method whose name is different than the method from which it is called.
Consider the following code:
The
getFirstName()
method in theSon
calls the wrong method in the parent class.