PluginProbe
JetFormBuilder — Dynamic Blocks Form Builder / 3.6.6
JetFormBuilder — Dynamic Blocks Form Builder v3.6.6
3.6.6.1 3.6.6 3.6.5.4 3.6.5.3 3.6.5.2 3.6.5.1 3.6.5 3.6.4.2 3.6.4.1 3.6.4 3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 All 134 releases
← All changes | modules/security/honeypot/module.php +140 -43 3.6.0.1 → 3.6.6 View file →
@@ -2,9 +2,8 @@
2 2
3 3
4 4 namespace JFB_Modules\Security\Honeypot;
5 5
6 -use Jet_Form_Builder\Exceptions\Request_Exception;
7 6 use Jet_Form_Builder\Live_Form;
8 7 use JFB_Components\Module\Base_Module_It;
9 8 use JFB_Modules\Security\Exceptions\Spam_Exception;
10 9
@@ -14,10 +13,22 @@
14 13 }
15 14
16 15 class Module implements Base_Module_It {
17 16
18 - const FIELD = '_jfb_email_hp_';
19 17
18 + const FIELD_NAME = 'name';
19 + const FIELD_EMAIL = 'email';
20 + const FIELD_PHONE = 'phone';
21 + const FIELD_COMPANY = 'company';
22 +
23 + const SPAM_EXCEPTION = 'honeypot';
24 +
25 + const HONEYPOT_STYLE_HANDLE = 'jet-form-builder-honeypot';
26 +
27 + public function __construct() {
28 + add_filter( 'jet-form-builder/security/spam-statuses', array( $this, 'add_spam_statuses' ) );
29 + }
30 +
20 31 public function rep_item_id() {
21 32 return 'honeypot';
22 33 }
23 34
@@ -24,14 +35,11 @@
24 35 public function condition(): bool {
25 36 return true;
26 37 }
27 38
28 - const SPAM_EXCEPTION = 'honeypot';
29 - public function __construct() {
30 - add_filter( 'jet-form-builder/security/spam-statuses', array( $this, 'add_spam_statuses' ) );
31 - }
32 39 public function add_spam_statuses( $statuses ) {
33 40 $statuses[] = self::SPAM_EXCEPTION;
41 +
34 42 return $statuses;
35 43 }
36 44
37 45 public function init_hooks() {
@@ -40,16 +48,24 @@
40 48 array( $this, 'on_render_field' ),
41 49 10,
42 50 3
43 51 );
52 +
44 53 add_filter(
45 54 'jet-form-builder/request-handler/request',
46 55 array( $this, 'handle_request' )
47 56 );
57 +
48 58 add_filter(
49 59 'jet-form-builder/message-types',
50 60 array( $this, 'handle_global_messages' )
51 61 );
62 +
63 + add_action(
64 + 'wp_enqueue_scripts',
65 + array( $this, 'enqueue_styles' ),
66 + 20
67 + );
52 68 }
53 69
54 70 public function remove_hooks() {
55 71 remove_filter(
@@ -55,53 +71,131 @@
55 71 remove_filter(
56 72 'jet-form-builder/before-render-field',
57 73 array( $this, 'on_render_field' )
58 74 );
75 +
59 76 remove_filter(
60 77 'jet-form-builder/request-handler/request',
61 78 array( $this, 'handle_request' )
62 79 );
80 +
63 81 remove_filter(
64 82 'jet-form-builder/message-types',
65 83 array( $this, 'handle_global_messages' )
66 84 );
85 +
86 + remove_action(
87 + 'wp_enqueue_scripts',
88 + array( $this, 'enqueue_styles' ),
89 + 20
90 + );
67 91 }
68 92
69 - private function find_email_field_name( array $blocks ): string {
70 - $result = array(
71 - 'has_email' => false,
72 - 'has__email' => false,
93 + public function enqueue_styles() {
94 + wp_register_style(
95 + self::HONEYPOT_STYLE_HANDLE,
96 + false,
97 + array(),
98 + jet_form_builder()->get_version()
73 99 );
100 + wp_enqueue_style( self::HONEYPOT_STYLE_HANDLE );
101 + wp_add_inline_style(
102 + self::HONEYPOT_STYLE_HANDLE,
103 + '
104 + .jfb-user-info,
105 + .jfb-user-info input {
106 + position: absolute !important;
107 + top: 0 !important;
108 + left: 0 !important;
109 + width: 1px !important;
110 + height: 1px !important;
111 + overflow: hidden !important;
112 + clip-path: inset(50%) !important;
113 + white-space: nowrap !important;
114 + user-select: none !important;
115 + -webkit-user-select: none !important;
116 + pointer-events: none !important;
117 + }
118 + '
119 + );
120 + }
74 121
75 - $this->walk_blocks_for_email( $blocks, $result );
122 + private function get_honeypot_base_names(): array {
123 + return array(
124 + self::FIELD_NAME,
125 + self::FIELD_EMAIL,
126 + self::FIELD_PHONE,
127 + self::FIELD_COMPANY,
128 + );
129 + }
76 130
77 - if ( $result['has_email'] ) {
78 - if ( $result['has__email'] ) {
79 - return self::FIELD;
131 + private function get_honeypot_field_names( array $blocks ): array {
132 + $existing_names = array_fill_keys(
133 + $this->get_existing_field_names( $blocks ),
134 + true
135 + );
136 +
137 + $honeypot_names = array();
138 +
139 + foreach ( $this->get_honeypot_base_names() as $base_name ) {
140 + $honeypot_names[] = $this->resolve_honeypot_field_name(
141 + $base_name,
142 + $existing_names
143 + );
144 +
145 + $existing_names[ end( $honeypot_names ) ] = true;
146 + }
147 +
148 + return $honeypot_names;
149 + }
150 +
151 + private function resolve_honeypot_field_name( string $base_name, array $existing_names ): string {
152 + $candidates = array(
153 + $base_name,
154 + '_' . $base_name,
155 + sprintf( '_jfb_%s_hp_', $base_name ),
156 + );
157 +
158 + foreach ( $candidates as $candidate ) {
159 + if ( empty( $existing_names[ $candidate ] ) ) {
160 + return $candidate;
80 161 }
81 - return '_email';
82 162 }
83 163
84 - return 'email';
164 + $index = 2;
165 +
166 + do {
167 + $candidate = sprintf( '_jfb_%s_hp_%d', $base_name, $index );
168 + ++$index;
169 + } while ( ! empty( $existing_names[ $candidate ] ) );
170 +
171 + return $candidate;
85 172 }
86 173
87 - private function walk_blocks_for_email( array $blocks, array &$result ) {
174 + private function get_existing_field_names( array $blocks ): array {
175 + $result = array();
176 +
177 + $this->walk_blocks_for_field_names( $blocks, $result );
178 +
179 + return array_values( array_unique( $result ) );
180 + }
181 +
182 + private function walk_blocks_for_field_names( array $blocks, array &$result ) {
88 183 foreach ( $blocks as $block ) {
89 184 if ( ! is_array( $block ) ) {
90 185 continue;
91 186 }
92 187
93 - if ( isset( $block['attrs']['name'] ) ) {
94 - if ( 'email' === $block['attrs']['name'] ) {
95 - $result['has_email'] = true;
96 - }
97 - if ( '_email' === $block['attrs']['name'] ) {
98 - $result['has__email'] = true;
99 - }
188 + if ( isset( $block['attrs']['name'] ) && is_string( $block['attrs']['name'] ) ) {
189 + $result[] = $block['attrs']['name'];
100 190 }
101 191
192 + if ( isset( $block['name'] ) && is_string( $block['name'] ) ) {
193 + $result[] = $block['name'];
194 + }
195 +
102 196 if ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ) {
103 - $this->walk_blocks_for_email( $block['innerBlocks'], $result );
197 + $this->walk_blocks_for_field_names( $block['innerBlocks'], $result );
104 198 }
105 199 }
106 200 }
107 201
@@ -106,31 +200,31 @@
106 200 }
107 201
108 202 public function on_render_field( string $content, string $field_name, array $attrs ): string {
109 203 $type = $attrs['action_type'] ?? '';
204 +
110 205 if ( 'submit-field' !== $field_name || 'submit' !== $type ) {
111 206 return $content;
112 207 }
113 208
114 209 $args = jet_form_builder()->post_type->get_args();
210 +
115 211 if ( empty( $args['use_honeypot'] ) ) {
116 212 return $content;
117 213 }
118 214
119 - $name = $this->find_email_field_name( Live_Form::instance()->blocks );
215 + $fields = '';
120 216
121 - $field = Live_Form::force_render_field(
122 - 'text-field',
123 - array(
124 - 'field_type' => 'email',
125 - 'name' => $name,
126 - 'autocomplete' => 'off',
127 - )
128 - );
217 + foreach ( $this->get_honeypot_field_names( Live_Form::instance()->blocks ) as $name ) {
218 + $fields .= sprintf(
219 + '<input type="text" name="%s" autocomplete="one-time-code">',
220 + esc_attr( $name )
221 + );
222 + }
129 223
130 224 $content .= sprintf(
131 - '<div class="jfb-visually-hidden" tabindex="-1">%s</div>',
132 - $field
225 + '<div class="jfb-user-info" inert>%s</div>',
226 + $fields
133 227 );
134 228
135 229 return $content;
136 230 }
@@ -147,17 +241,21 @@
147 241 if ( empty( $args['use_honeypot'] ) ) {
148 242 return $request;
149 243 }
150 244
151 - $honeypot_name = $this->find_email_field_name( jet_form_builder()->form_handler->request_handler->_fields );
245 + $honeypot_names = $this->get_honeypot_field_names(
246 + jet_form_builder()->form_handler->request_handler->_fields
247 + );
152 248
153 - if ( ! empty( $request[ $honeypot_name ] ) ) {
154 - // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
155 - throw new Spam_Exception( self::SPAM_EXCEPTION );
249 + foreach ( $honeypot_names as $honeypot_name ) {
250 + if ( ! empty( $request[ $honeypot_name ] ) ) {
251 + // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
252 + throw new Spam_Exception( self::SPAM_EXCEPTION );
253 + }
254 +
255 + unset( $request[ $honeypot_name ] );
156 256 }
157 257
158 - unset( $request[ $honeypot_name ] );
159 -
160 258 return $request;
161 259 }
162 260
163 261 public function handle_global_messages( array $types ): array {
@@ -167,6 +265,5 @@
167 265 );
168 266
169 267 return $types;
170 268 }
171 -
172 269 }