Completed
Branch BUG-9871-email-validation (e62b1a)
by
unknown
350:41 queued 333:27
created

EED_Bot_Trap::run()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 1
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 1
rs 10
c 0
b 0
f 0
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__ );
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (get_instance() instead of instance()). Are you sure this is correct? If so, you might want to change this to $this->get_instance().

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:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
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