PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / 3.6.1
JetFormBuilder — Dynamic Blocks Form Builder v3.6.1
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 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.1.0 2.1.1 2.1.10 2.1.11 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.0 3.0.0.1 3.0.0.2 3.0.0.3 3.0.1 3.0.1.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.0.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.3.1 3.3.4 3.3.4.1 3.3.4.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.5.1 3.4.5.2 3.4.6 3.4.7 3.4.7.1 3.5.0 3.5.1 3.5.1.1 3.5.1.2 3.5.2 3.5.2.1 3.5.3 3.5.4 3.5.5 3.5.6 3.5.6.1 3.5.6.2 3.5.6.3 3.6.0
jetformbuilder / modules / captcha / module.php
jetformbuilder / modules / captcha Last commit date
abstract-captcha 2 years ago admin-tabs 2 years ago assets 1 month ago block-types 2 months ago blocks-metadata 2 months ago friendly-captcha 1 month ago hcaptcha 1 year ago re-captcha-v3 1 year ago turnstile 1 month ago .eslintrc.js 1 year ago module.php 1 month ago
module.php
410 lines
1 <?php
2
3
4 namespace JFB_Modules\Captcha;
5
6 // If this file is called directly, abort.
7 if ( ! defined( 'WPINC' ) ) {
8 die;
9 }
10
11 use Jet_Form_Builder\Admin\Tabs_Handlers\Tab_Handler_Manager;
12 use Jet_Form_Builder\Blocks\Block_Helper;
13 use Jet_Form_Builder\Blocks\Exceptions\Render_Empty_Field;
14 use JFB_Components\Repository\Repository_Pattern_Trait;
15 use Jet_Form_Builder\Classes\Tools;
16 use Jet_Form_Builder\Exceptions\Repository_Exception;
17 use JFB_Modules\Captcha\Abstract_Captcha\Base_Captcha;
18 use JFB_Modules\Captcha\Abstract_Captcha\Captcha_Frontend_Style_It;
19 use JFB_Modules\Captcha\Abstract_Captcha\Captcha_Separate_Editor_Script;
20 use JFB_Modules\Captcha\Abstract_Captcha\Captcha_Separate_Frontend_Script;
21 use JFB_Modules\Captcha\Abstract_Captcha\Captcha_Settings_From_Options;
22 use JFB_Modules\Captcha\Friendly_Captcha\Friendly_Captcha;
23 use JFB_Modules\Captcha\Hcaptcha\Hcaptcha;
24 use JFB_Modules\Captcha\Re_Captcha_V3\Re_Captcha_V3;
25 use JFB_Modules\Captcha\Turnstile\Turnstile;
26 use JFB_Components\Module\Base_Module_After_Install_It;
27 use JFB_Components\Module\Base_Module_Dir_It;
28 use JFB_Components\Module\Base_Module_Dir_Trait;
29 use JFB_Components\Module\Base_Module_Handle_It;
30 use JFB_Components\Module\Base_Module_Handle_Trait;
31 use JFB_Components\Module\Base_Module_It;
32 use JFB_Components\Module\Base_Module_Url_It;
33 use JFB_Components\Module\Base_Module_Url_Trait;
34 use JFB_Modules\Security\Exceptions\Spam_Exception;
35 use Jet_Form_Builder\Plugin;
36
37 /**
38 * @since 3.1.0
39 *
40 * Class Module
41 * @package JFB_Modules\Captcha
42 */
43 final class Module implements
44 Base_Module_It,
45 Base_Module_Url_It,
46 Base_Module_Dir_It,
47 Base_Module_After_Install_It,
48 Base_Module_Handle_It {
49
50 use Base_Module_Handle_Trait;
51 use Base_Module_Url_Trait;
52 use Base_Module_Dir_Trait;
53
54 use Repository_Pattern_Trait;
55
56 const PREFIX = 'jet_form_builder_captcha__';
57 /**
58 * Cloudflare Turnstile limits the "action" parameter to 32 characters.
59 * Use a shorter prefix to keep the generated action within this limit.
60 */
61 const PREFIX_TURNSTILE = 'jfb_turnstile__';
62 const SPAM_EXCEPTION = 'captcha_failed';
63
64 /**
65 * @var Base_Captcha[]
66 */
67 private $current = array();
68
69 /**
70 * It becomes false inside `on_render_field`, if it renders the captcha.
71 * And if it true - captcha renders inside the `on_end_render_form` method
72 *
73 * @var bool
74 */
75 private $should_render = true;
76
77 public function rep_item_id() {
78 return 'captcha';
79 }
80
81 public function __construct() {
82 add_action( 'jet-form-builder/security/spam-statuses', array( $this, 'add_spam_statuses' ) );
83 }
84 public function add_spam_statuses( $statuses ) {
85 $statuses[] = self::SPAM_EXCEPTION;
86 return $statuses;
87 }
88
89 public function on_install() {
90 $this->rep_install();
91
92 Tab_Handler_Manager::instance()->install( new Admin_Tabs\Captcha_Handler() );
93 }
94
95 public function on_uninstall() {
96 $this->rep_clear();
97
98 Tab_Handler_Manager::instance()->uninstall( 'captcha-tab' );
99 }
100
101 public function rep_instances(): array {
102 return apply_filters(
103 'jet-form-builder/captcha/types',
104 array(
105 new Re_Captcha_V3(),
106 new Hcaptcha(),
107 new Turnstile(),
108 new Friendly_Captcha(),
109 )
110 );
111 }
112
113 public function condition(): bool {
114 return true;
115 }
116
117 public function init_hooks() {
118 add_filter( 'jet-form-builder/request-handler/request', array( $this, 'on_request' ) );
119 add_filter( 'jet-form-builder/before-render-field', array( $this, 'on_render_field' ), 10, 3 );
120 add_filter( 'jet-form-builder/page-config/jfb-settings', array( $this, 'on_localize_config' ) );
121 add_filter( 'jet-form-builder/editor/config', array( $this, 'on_localize_config' ) );
122 add_filter( 'jet-form-builder/setup-blocks', array( $this, 'check_is_container_exist' ) );
123 add_filter( 'jet-form-builder/before-end-form', array( $this, 'on_end_render_form' ) );
124 add_filter( 'jet-form-builder/blocks/items', array( $this, 'add_blocks_types' ) );
125
126 add_action( 'jet-form-builder/editor-assets/before', array( $this, 'enqueue_editor_assets' ) );
127 add_action( 'jet-form-builder/editor-assets/before', array( $this, 'enqueue_editor_package_assets' ), 0 );
128 add_action( 'wp_enqueue_scripts', array( $this, 'register_frontend_scripts' ) );
129 add_action( 'jet_plugins/frontend/register_scripts', array( $this, 'register_frontend_scripts' ) );
130 add_action( 'jet-form-builder/enqueue-style', array( $this, 'register_frontend_styles' ) );
131 }
132
133 public function remove_hooks() {
134 remove_filter( 'jet-form-builder/request-handler/request', array( $this, 'on_request' ) );
135 remove_filter( 'jet-form-builder/before-render-field', array( $this, 'on_render_field' ) );
136 remove_filter( 'jet-form-builder/page-config/jfb-settings', array( $this, 'on_localize_config' ) );
137 remove_filter( 'jet-form-builder/editor/config', array( $this, 'on_localize_config' ) );
138 remove_filter( 'jet-form-builder/setup-blocks', array( $this, 'check_is_container_exist' ) );
139 remove_filter( 'jet-form-builder/before-end-form', array( $this, 'on_end_render_form' ) );
140 remove_filter( 'jet-form-builder/blocks/items', array( $this, 'add_blocks_types' ) );
141
142 remove_action( 'jet-form-builder/editor-assets/before', array( $this, 'enqueue_editor_assets' ) );
143 remove_action(
144 'jet-form-builder/editor-assets/before',
145 array( $this, 'enqueue_editor_package_assets' ),
146 0
147 );
148 remove_action( 'wp_enqueue_scripts', array( $this, 'register_frontend_scripts' ) );
149 remove_action( 'jet_plugins/frontend/register_scripts', array( $this, 'register_frontend_scripts' ) );
150 remove_action( 'jet-form-builder/enqueue-style', array( $this, 'register_frontend_styles' ) );
151 }
152
153 /**
154 * @param $request
155 *
156 * @return mixed
157 * @throws Spam_Exception
158 */
159 public function on_request( $request ) {
160 $this->verify( $request );
161
162 return $request;
163 }
164
165 /**
166 * By default, the captcha is displayed before the submit button.
167 * But if the Captcha Container block is present in the form, we can check it in advance.
168 * This is necessary because the captcha and the button can be in parallel columns.
169 *
170 * @param string $content
171 * @param string $field_name
172 * @param array $attrs
173 *
174 * @return string
175 * @see Forms_Captcha::check_is_container_exist
176 */
177 public function on_render_field( string $content, string $field_name, array $attrs ): string {
178 $type = $attrs['action_type'] ?? '';
179
180 if ( 'submit-field' !== $field_name || 'submit' !== $type ) {
181 return $content;
182 }
183
184 try {
185 $current = $this->get_current();
186 } catch ( Repository_Exception $exception ) {
187 return $content;
188 }
189
190 $this->should_render = false;
191
192 if ( $current->is_exist_container() ) {
193 return $content;
194 }
195
196 return ( $content . $this->render() );
197 }
198
199 /**
200 * If for some reason the submit button has not been rendered in the form,
201 * then to make sure that we have displayed the captcha,
202 * we display it at the end of the rendering of the entire form.
203 *
204 * @param string $content
205 *
206 * @return string
207 */
208 public function on_end_render_form( string $content ): string {
209 $should_render = $this->should_render;
210 $this->should_render = true;
211
212 if ( $should_render ) {
213 $content .= $this->render();
214 }
215
216 return $content;
217 }
218
219 public function add_blocks_types( array $block_types ): array {
220 $block_types[] = new Block_Types\Captcha_Container();
221
222 return $block_types;
223 }
224
225 public function register_frontend_scripts() {
226 /** @var Base_Captcha $captcha */
227 foreach ( $this->rep_generate_items() as $captcha ) {
228 if ( ! ( $captcha instanceof Captcha_Separate_Frontend_Script ) ) {
229 continue;
230 }
231 $captcha->register_frontend_scripts();
232 }
233 }
234
235 public function register_frontend_styles() {
236 try {
237 $current = $this->get_current();
238 } catch ( Repository_Exception $exception ) {
239 return;
240 }
241 if ( ! ( $current instanceof Captcha_Frontend_Style_It ) ) {
242 return;
243 }
244 $current->register_frontend_styles();
245 }
246
247 public function enqueue_editor_assets() {
248 $script_asset = require_once $this->get_dir( 'assets/build/editor.asset.php' );
249
250 wp_enqueue_script(
251 $this->get_handle(),
252 $this->get_url( 'assets/build/editor.js' ),
253 $script_asset['dependencies'],
254 $script_asset['version'],
255 true
256 );
257
258 /** @var Base_Captcha $captcha */
259 foreach ( $this->rep_generate_items() as $captcha ) {
260 if ( ! ( $captcha instanceof Captcha_Separate_Editor_Script ) ) {
261 continue;
262 }
263 $captcha->enqueue_editor_script();
264 }
265 }
266
267 public function enqueue_editor_package_assets() {
268 $script_asset = require_once $this->get_dir( 'assets/build/editor.package.asset.php' );
269
270 wp_enqueue_script(
271 $this->get_handle( 'package' ),
272 $this->get_url( 'assets/build/editor.package.js' ),
273 $script_asset['dependencies'],
274 $script_asset['version'],
275 true
276 );
277 }
278
279 /**
280 * @param $request
281 *
282 * @throws Spam_Exception
283 */
284 protected function verify( $request ) {
285 try {
286 $this->get_current()->verify( $request );
287 } catch ( Repository_Exception $exception ) {
288 return;
289 }
290 }
291
292 public function render(): string {
293 try {
294 return $this->get_current()->get_output();
295 } catch ( Repository_Exception $exception ) {
296 return '';
297 } catch ( Render_Empty_Field $exception ) {
298 return '';
299 }
300 }
301
302 /**
303 * Returns captcha settings for current form
304 *
305 * @return Base_Captcha
306 * @throws Repository_Exception
307 */
308 public function get_current(): Base_Captcha {
309 if ( ! jet_fb_live()->form_id ) {
310 throw new Repository_Exception( 'no_captcha' );
311 }
312
313 if ( array_key_exists( (int) jet_fb_live()->form_id, $this->current ) ) {
314 if ( $this->current[ jet_fb_live()->form_id ] instanceof Base_Captcha ) {
315 return $this->current[ jet_fb_live()->form_id ];
316 }
317
318 throw new Repository_Exception( 'no_captcha' );
319 }
320
321 $settings = Plugin::instance()->post_type->get_captcha( jet_fb_live()->form_id );
322
323 if ( ! $settings || ! is_array( $settings ) ) {
324 $this->current[ jet_fb_live()->form_id ] = false;
325
326 throw new Repository_Exception( 'no_captcha' );
327 }
328
329 $captcha = $settings['captcha'] ?? false;
330
331 /**
332 * For backward compatibility
333 */
334 if ( false === $captcha && ! empty( $settings['enabled'] ) ) {
335 $captcha = Re_Captcha_V3::class;
336 }
337
338 /**
339 * @var Base_Captcha $current
340 */
341 $current = $this->rep_clone_item( $captcha );
342
343 $this->current[ jet_fb_live()->form_id ] = $current->sanitize_options( $settings );
344
345 return $this->current[ jet_fb_live()->form_id ];
346 }
347
348 public function on_localize_config( array $config ): array {
349 $captcha_config = array();
350
351 /** @var Base_Captcha $captcha */
352 foreach ( $this->rep_generate_items() as $captcha ) {
353 if ( ! ( $captcha instanceof Captcha_Settings_From_Options ) ) {
354 continue;
355 }
356 $captcha_config[] = $captcha->to_array();
357 }
358
359 $config['captcha-tab-config'] = $captcha_config;
360
361 return $config;
362 }
363
364 public function check_is_container_exist( array $blocks ): array {
365 try {
366 $current = $this->get_current();
367 } catch ( Repository_Exception $exception ) {
368 return $blocks;
369 }
370
371 if ( ! is_null( $current->is_exist_container() ) ) {
372 return $blocks;
373 }
374
375 $current->set_exist_container(
376 ! empty(
377 Block_Helper::find_by_block_name(
378 $blocks,
379 'jet-forms/captcha-container'
380 )
381 )
382 );
383
384 return $blocks;
385 }
386
387 /**
388 * @param string|array $config
389 * @param string $handle
390 *
391 * @return bool
392 */
393 public function add_inline_config( $config, string $handle = '' ): bool {
394 $form_id = jet_fb_live()->form_id;
395
396 if ( ! is_string( $config ) ) {
397 $config = Tools::encode_json( $config );
398 }
399
400 return wp_add_inline_script(
401 $handle ?: Base_Captcha::HANDLE_USER,
402 "
403 window.JetFormBuilderCaptchaConfig = window.JetFormBuilderCaptchaConfig || {};
404 window.JetFormBuilderCaptchaConfig[ $form_id ] = {$config};
405 ",
406 'before'
407 );
408 }
409 }
410