PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.14
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.14
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Modules / Form / HoneyPot.php

HoneyPot.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.14, at app/Modules/Form/HoneyPot.php

108 lines 3.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Modules\Form;
4
5 use FluentForm\App\Helpers\Helper;
6 use FluentForm\Framework\Foundation\Application;
7 use FluentForm\Framework\Helpers\ArrayHelper;
8
9 class HoneyPot
10 {
11 private $app;
12
13 public function __construct(Application $application)
14 {
15 $this->app = $application;
16 }
17
18 public function renderHoneyPot($form)
19 {
20 if (!$this->isEnabled($form->id)) {
21 return;
22 }
23
24 $fieldName = $this->getFieldName($form->id);
25 $fieldId = 'ff_' . $form->id . '_item_sf' ;
26 $labels = ['Newsletter', 'Updates', 'Contact', 'Subscribe', 'Notify'];
27 $randomLabel = $labels[array_rand($labels)];
28 ?>
29 <div
30 style="display: none!important; position: absolute!important; transform: translateX(1000%)!important;"
31 class="ff-el-group ff-hpsf-container"
32 >
33 <div class="ff-el-input--label asterisk-right">
34 <label for="<?php echo esc_attr($fieldId); ?>" aria-label="<?php echo esc_attr($randomLabel); ?>">
35 <?php echo esc_html($randomLabel); ?>
36 </label>
37 </div>
38 <div class="ff-el-input--content">
39 <input type="text"
40 name="<?php echo esc_attr($fieldName); ?>"
41 class="ff-el-form-control"
42 id="<?php echo esc_attr($fieldId); ?>"
43 />
44 </div>
45 </div>
46 <?php
47 }
48
49 public function verify($insertData, $requestData, $formId)
50 {
51 // SECURITY (FINDING-25): do NOT skip the check for conversational forms based on the
52 // client-supplied isFFConversational flag. The conversational renderer now injects the
53 // honeypot field (empty) into the submission (getConversationalHoneypotInput via
54 // extra_inputs), so the "present and empty" check passes for legitimate conversational
55 // submissions and the control can no longer be bypassed with a single flag.
56 if (!$this->isEnabled($formId)) {
57 return;
58 }
59
60 $honeyPotName = $this->getFieldName($formId);
61
62 if (
63 !ArrayHelper::exists($requestData, $honeyPotName) ||
64 !empty(ArrayHelper::get($requestData, $honeyPotName))
65 ) {
66 $message = apply_filters(
67 'fluentform/honeypot_spam_message',
68 __('Sorry! You can not submit this form at this moment!', 'fluentform'),
69 $formId
70 );
71 wp_send_json(['errors' => $message], 422);
72 }
73 return;
74 }
75
76 public function isEnabled($formId = false)
77 {
78 $option = get_option('_fluentform_global_form_settings');
79 $status = 'yes' == ArrayHelper::get($option, 'misc.honeypotStatus');
80 return apply_filters('fluentform/honeypot_status', $status, $formId);
81 }
82
83 /**
84 * SECURITY (FINDING-25): the conversational form is a JS app that never renders the DOM
85 * honeypot field, so verify() previously had to be skipped for it (via the client-controlled
86 * isFFConversational flag). Return the honeypot field pre-filled EMPTY so the conversational
87 * JS carries it in the submission and the "present and empty" check passes for a legitimate
88 * submission while the control is enforced server-side rather than bypassable by a flag.
89 *
90 * @param int $formId
91 * @return array
92 */
93 public function getConversationalHoneypotInput($formId)
94 {
95 if (!$this->isEnabled($formId)) {
96 return [];
97 }
98
99 return [$this->getFieldName($formId) => ''];
100 }
101
102 private function getFieldName($formId)
103 {
104 $honeyPotName = 'item_' . $formId . '__fluent_sf';
105 return apply_filters('fluentform/honeypot_name', $honeyPotName, $formId);
106 }
107 }
108