Plugin Directory

source: password-protected/trunk/admin/class-recaptcha.php

Last change on this file was 3375673, checked in by wpexpertsio, 6 months ago

Release 2.7.12

File size: 22.4 KB
Line 
1<?php
2
3if ( ! defined( 'ABSPATH' ) ) {
4        exit; // Exit if accessed directly
5}
6
7/**
8 * @package     Password Protected
9 * @subpackage  reCAPTCHA
10 *
11 * @since  2.6
12 */
13
14class Password_Protected_reCAPTCHA {
15
16        public $options_group = 'password-protected-all-captchas';
17        public $options_name  = 'password_protected_recaptcha';
18        public $tab           = 'password-protected&tab=advanced';
19        public $settings      = array();
20        /**
21         * Constructor
22         *
23         * @since  2.6
24         *
25         * @internal  public. This class should only be instantiated once by the plugin.
26         */
27        public function __construct() {
28
29                $options = get_option( $this->options_name );
30
31                if ( empty( $options ) || ! $options ) {
32                        $this->settings = $this->get_default_reCAPTCHA_settings();
33                } else {
34                        $this->settings = get_option( $this->options_name );
35                }
36
37                add_action( 'admin_init', array( $this, 'register_reCAPTCHA_settings' ), 6 );
38        // add_action( 'password_protected_subtab_google-recaptcha_content', array( $this, 'google_recaptcha_settings' ) );
39        add_action( 'password_protected_all_captchas', array( $this, 'google_recaptcha_settings' ) );
40
41                add_action( 'password_protected_after_password_field', array( $this, 'add_recaptcha' ) );
42
43                add_filter( 'password_protected_verify_recaptcha', array( $this, 'verify_recaptcha' ) );
44        }
45
46        /**
47         * reCAPTCHA Default Settings
48         *
49         * @return array
50         * @since  2.6
51         */
52        private function get_default_reCAPTCHA_settings(): array {
53                return array(
54                        'enable'        => 0,
55                        'version'       => 'google_recaptcha_v2',
56                        'v2_site_key'   => null,
57                        'v3_site_key'   => null,
58                        'v2_secret_key' => null,
59                        'v3_secret_key' => null,
60                        'v3_score'      => 0.3,
61                        'v3_badge'      => 'bottomright',
62                        'v2_theme'      => 'light',
63                );
64        }
65
66    public function google_recaptcha_settings() {
67        ?>
68        <div class="reCaptchaTab">
69            <h1><?php _e( 'Google reCAPTCHA Settings', 'password-protected' ); ?></h1>
70            <!-- <form method="post" action="options.php"> -->
71                <?php
72                // settings_fields( 'password-protected-google-recaptcha-advanced' );
73                do_settings_sections( 'password-protected&tab=advanced' );
74                // submit_button();
75                ?>
76            <!-- </form> -->
77        </div>
78        <?php
79    }
80
81        /**
82         * reCAPTCHA  Settings Info
83         *
84         * Displays information on the settings page for helping
85         * to configure Password Protected to work with Google reCAPTCHA v2 and v3.
86         *
87         * @since  2.6
88         */
89        public function register_reCAPTCHA_settings() {
90                // reCAPTCHA Section
91                add_settings_section(
92                        $this->options_group,
93                        __( ' ', 'password-protected' ),
94                        array( $this, 'reCAPTCHA_section' ),
95                        $this->tab
96                );
97
98                // Enable reCAPTCHA
99                add_settings_field(
100                        'password_protected_enable_recaptcha',
101                        __( 'Enable reCAPTCHA ', 'password-protected' ),
102                        array( $this, 'reCAPTCHA_enable' ),
103                        $this->tab,
104                        $this->options_group
105                );
106
107                // reCAPTCHA version v2/v3
108                add_settings_field(
109                        'password_protected_recaptcha_settings',
110                        __( 'Captcha Settings', 'password-protected' ),
111                        array( $this, 'reCAPTCHA_setting' ),
112                        $this->tab,
113                        $this->options_group
114                );
115
116                // reCAPTCHA v2/v3 sitekey
117                add_settings_field(
118                        'password_protected_recaptcha_v2_site_key',
119                        __( 'Site Key', 'password-protected' ),
120                        array( $this, 'reCAPTCHA_site_key' ),
121                        $this->tab,
122                        $this->options_group
123                );
124
125                // reCAPTCHA v2/v3 secretkey
126                add_settings_field(
127                        'password_protected_recaptcha_v2_secret_key',
128                        __( 'Secret Key', 'password-protected' ),
129                        array( $this, 'reCAPTCHA_secret_key' ),
130                        $this->tab,
131                        $this->options_group
132                );
133
134                // reCAPTCHA v3 score
135                add_settings_field(
136                        'password_protected_recaptcha_score',
137                        __( 'Score', 'password-protected' ),
138                        array( $this, 'reCAPTCHA_score' ),
139                        $this->tab,
140                        $this->options_group
141                );
142
143                // reCAPTCHA v3 badgeposition
144                add_settings_field(
145                        'password_protected_recaptcha_badge_position',
146                        __( 'Badge Position', 'password-protected' ),
147                        array( $this, 'reCAPTCHA_badge_position' ),
148                        $this->tab,
149                        $this->options_group
150                );
151
152                // reCAPTCHA v2 theme
153                add_settings_field(
154                        'password_protected_recaptcha_theme',
155                        __( 'Theme', 'password-protected' ),
156                        array( $this, 'reCAPTCHA_theme' ),
157                        $this->tab,
158                        $this->options_group
159                );
160
161                // register settings in an array group.
162                register_setting( $this->options_group, $this->options_name, array( 'type' => 'array' ) );
163        }
164
165        /**
166         * reCAPTCHA Screen
167         *
168         * @since  2.6
169         *
170         * @return  void  password protected reCAPTCHA settings
171         */
172        public static function recpatcha_screen() {
173                do_settings_sections( 'password-protected&tab=advanced' );
174                // submit_button();
175        }
176
177        /**
178         * reCAPTCHA Section
179         *
180         * @return  void  password protected reCAPTCHA section
181         */
182        public function reCAPTCHA_section() {
183                return 1;
184        }
185
186        /**
187         * ENable reCAPTCHA
188         *
189         * @since  2.6
190         *
191         * @return  void  password protected reCAPTCHA status field
192         */
193        public function reCAPTCHA_enable() {
194        $checked = isset( $this->settings['enable'] ) ? 'checked' : '';
195        echo '<div class="pp-toggle-wrapper">
196            <input
197                name="' . esc_attr( $this->options_name ) . '[enable]"
198                id="pp_enable_recaptcha"
199                type="checkbox"
200                value="1" ' . $checked . '
201            />
202            <label class="pp-toggle" for="pp_enable_recaptcha">
203                <span class="pp-toggle-slider"></span>
204            </label>
205        </div>
206        <label for="pp_enable_recaptcha">
207                 ' .
208                                __( 'Enabled', 'password-protected' ) . '
209        </label>';
210        }
211
212        /**
213         * reCAPTCHA Version
214         *
215         * @since  2.6
216         *
217         * @return  void  password protected reCAPTCHA version field
218         */
219        public function reCAPTCHA_setting() {
220                echo '<label>
221                <input
222                    ' . checked( 'google_recaptcha_v2', $this->settings['version'], false ) . '
223                    type="radio"
224                    name="' . esc_attr( $this->options_name ) . '[version]"
225                    value="google_recaptcha_v2"
226                />
227                <span>Google reCAPTCHA Version 2</span>
228            </label>
229            <br />
230            <label>
231                <input
232                    ' . checked( 'google_recaptcha_v3', $this->settings['version'], false ) . '
233                    type="radio"
234                    name="' . esc_attr( $this->options_name ) . '[version]"
235                    value="google_recaptcha_v3"
236                />
237                <span>Google reCAPTCHA Version 3</span>
238            </label>';
239        }
240
241        /**
242         * reCAPTCHA Site Key
243         *
244         * @since  2.6
245         *
246         * @return  void  password protected v2/v3 sitekey field
247         */
248        public function reCAPTCHA_site_key() {
249
250                echo '<div>
251                <input
252                    name="' . esc_attr( $this->options_name ) . '[v2_site_key]"
253                    type="text"
254                    id="pp_google_recaptcha_v2_site_key"
255                    value="' . esc_attr( $this->settings['v2_site_key'] ) . '"
256                    class="regular-text"
257                />
258                <p class="description">
259                    Enter Google reCAPTCHA v2 Site Key.&nbsp;
260                    <a target="_blank" href="https://developers.google.com/recaptcha/intro#recaptcha-overview">
261                        Click Here
262                    </a>
263                </p>
264            </div>';
265
266                        echo '<div>
267                    <input
268                        name="' . esc_attr( $this->options_name ) . '[v3_site_key]"
269                        type="text"
270                        id="pp_google_recaptcha_v3_site_key"
271                        value="' . esc_attr( $this->settings['v3_site_key'] ) . '"
272                        class="regular-text"
273                    />
274                <p class="description">
275                    Enter Google reCAPTCHA v3 Site Key.&nbsp;
276                    <a target="_blank" href="https://developers.google.com/recaptcha/intro#recaptcha-overview">
277                        Click Here
278                    </a>
279                </p>
280            </div>';
281        }
282
283        /**
284         * reCAPTCHA Secret Key
285         *
286         * @since  2.6
287         *
288         * @return  void  password protected v2/v3 secretkey field
289         */
290        public function reCAPTCHA_secret_key() {
291
292                echo '<div>
293                <input
294                    name="' . esc_attr( $this->options_name ) . '[v2_secret_key]"
295                    type="text"
296                    id="pp_google_recaptcha_v2_secret_key"
297                    value="' . esc_attr( $this->settings['v2_secret_key'] ) . '"
298                    class="regular-text"
299                />
300                <p class="description">
301                    Enter Google reCAPTCHA v2 Secret Key.&nbsp;
302                    <a target="_blank" href="https://developers.google.com/recaptcha/intro#recaptcha-overview">
303                        Click Here
304                    </a>
305                </p>
306            </div>';
307                echo '<div>
308                <input
309                    name="' . esc_attr( $this->options_name ) . '[v3_secret_key]"
310                    type="text"
311                    id="pp_google_recaptcha_v3_secret_key"
312                    value="' . esc_attr( $this->settings['v3_secret_key'] ) . '"
313                    class="regular-text"
314                />
315                <p class="description">
316                    Enter Google reCAPTCHA v3 Secret Key.&nbsp;
317                    <a target="_blank" href="https://developers.google.com/recaptcha/intro#recaptcha-overview">
318                        Click Here
319                    </a>
320                </p>
321            </div>';
322        }
323
324        /**
325         * reCAPTCHA V3 Score
326         *
327         * @since  2.6
328         *
329         * @return  void  password protected v3 score field
330         */
331        public function reCAPTCHA_score() {
332                echo '<fieldset id="pp_google_recpatcha_v3_score">
333                <label>
334                    <input
335                        type="radio"
336                        name="' . esc_attr( $this->options_name ) . '[v3_score]"
337                        value="0.1"
338                        ' . checked( 0.1, $this->settings['v3_score'], false ) . '
339                    />
340                    <span>0.1</span>
341                </label>
342                &nbsp;
343                <label>
344                    <input
345                        type="radio"
346                        name="' . esc_attr( $this->options_name ) . '[v3_score]"
347                        value="0.2"
348                        ' . checked( 0.2, $this->settings['v3_score'], false ) . '
349                    />
350                    <span>0.2</span>
351                </label>
352                &nbsp;
353                <label>
354                    <input
355                        type="radio"
356                        name="' . esc_attr( $this->options_name ) . '[v3_score]"
357                        value="0.3"
358                        ' . checked( 0.3, $this->settings['v3_score'], false ) . '
359                    />
360                    <span>0.3</span>
361                </label>
362                &nbsp;
363                <label>
364                    <input
365                        type="radio"
366                        name="' . esc_attr( $this->options_name ) . '[v3_score]"
367                        value="0.4"
368                        ' . checked( 0.4, $this->settings['v3_score'], false ) . '
369                    />
370                    <span>0.4</span>
371                </label>
372                &nbsp;
373                <label>
374                    <input
375                        type="radio"
376                        name="' . esc_attr( $this->options_name ) . '[v3_score]"
377                        value="0.5"
378                        ' . checked( 0.5, $this->settings['v3_score'], false ) . '
379                    />
380                    <span>0.5</span>
381                </label>
382                &nbsp;
383                <p class="description">Select Google Version 3 Score.</p>
384            </fieldset>';
385        }
386
387        /**
388         * reCAPTCHA V3 Badge Position
389         *
390         * @since  2.6
391         *
392         * @return  void  password protected v3 badgeposition field
393         */
394        public function reCAPTCHA_badge_position() {
395                echo '<fieldset id="pp_google_recpatcha_v3_badge">
396                    <label>
397                        <input
398                            type="radio"
399                            name="' . esc_attr( $this->options_name ) . '[v3_badge]"
400                            value="inline"
401                            ' . checked( 'inline', $this->settings['v3_badge'], false ) . '
402                        />
403                        <span>Inline</span>
404                    </label>
405                    &nbsp;&nbsp;                                                       
406                    <label>
407                        <input
408                            type="radio"
409                            name="' . esc_attr( $this->options_name ) . '[v3_badge]"
410                            value="bottomleft"
411                            ' . checked( 'bottomleft', $this->settings['v3_badge'], false ) . '
412                        />
413                        <span>Bottom - Left</span>
414                    </label>
415                    &nbsp;&nbsp;                                                       
416                    <label>
417                        <input
418                            type="radio"
419                            name="' . esc_attr( $this->options_name ) . '[v3_badge]"
420                            value="bottomright"
421                            ' . checked( 'bottomright', $this->settings['v3_badge'], false ) . '
422                        />
423                        <span>Bottom - Right</span>
424                </label>
425            </fieldset>';
426        }
427
428        /**
429         * reCAPTCHA V2 Theme
430         *
431         * @since  2.6
432         *
433         * @return  void  password protected v2 theme field
434         */
435        public function reCAPTCHA_theme() {
436                echo '<label>
437                <input
438                    checked="checked"
439                    type="radio"
440                    name="' . esc_attr( $this->options_name ) . '[v2_theme]"
441                    value="light"
442                    ' . checked( 'light', $this->settings['v2_theme'], false ) . '
443                />
444                <span>Light</span>
445            </label>
446            <br />
447            <label>
448                <input
449                    type="radio"
450                    name="' . esc_attr( $this->options_name ) . '[v2_theme]"
451                    value="dark"
452                    ' . checked( 'dark', $this->settings['v2_theme'], false ) . '
453                />
454                <span>Dark</span>
455            </label>
456            <p class="description">Select Google reCAPTCHA Version 2 Theme.</p>';
457        }
458
459        /**
460         * Add reCAPTCHA on Password Protected Form
461         *
462         * @since  2.6
463         *
464         * @return  void  password protected reCAPTCHA v2 OR v3
465         */
466        public function add_recaptcha() {
467                if ( ! @$this->settings['enable'] ) {
468                        return; // recpatcha is disabled
469                }
470
471                if ( $this->settings['version'] === 'google_recaptcha_v2' ) {
472                        $this->display_recaptcha_v2();
473                }
474
475                if ( $this->settings['version'] === 'google_recaptcha_v3' ) {
476                        $this->display_recaptcha_v3();
477                }
478        }
479
480        /**
481         * Diaplay reCAPTCHA V2
482         *
483         * @since  2.6
484         *
485         * @return  void  password protected reCAPTCHA v2 field
486         */
487        public function display_recaptcha_v2() {
488        global $Password_Protected;
489                wp_enqueue_style( 'pp-recaptcha-style', plugin_dir_url( __DIR__ ) . 'assets/css/recaptcha.css', array(), $Password_Protected->version );
490                wp_enqueue_script( 'pp-recaptcha-api-v2', esc_url( 'https://www.google.com/recaptcha/api.js' ), array(), null );
491                echo '<div
492                class="g-recaptcha"
493                data-sitekey="' . esc_attr( $this->settings['v2_site_key'] ) . '"
494                data-theme="' . esc_attr( $this->settings['v2_theme'] ) . '"
495                >
496            </div>';
497        }
498
499        /**
500         * Diaplay reCAPTCHA V3
501         *
502         * @since  2.6
503         *
504         * @return  void  password protected reCAPTCHA v3 field
505         */
506        public function display_recaptcha_v3() {
507                $grecaptcha_v3_site_key = isset( $this->settings['v3_site_key'] ) ? esc_attr( $this->settings['v3_site_key'] ) : '';
508                $grecaptcha_v3_badge    = isset( $this->settings['v3_badge'] ) ? esc_attr( $this->settings['v3_badge'] ) : 'bottomright';
509
510                $script = <<<EOT
511            if('function' !== typeof pprecaptcha) {
512                function pprecaptcha() {
513                    grecaptcha.ready(function() {
514                        [].forEach.call(document.querySelectorAll('.pp-g-recaptcha'), function(el) {
515                            const action = el.getAttribute('data-action');
516                            const form = el.form;
517                            form.addEventListener('submit', function(e) {
518                                e.preventDefault();
519                                grecaptcha.execute('$grecaptcha_v3_site_key', {action: action}).then(function(token) {
520                                    el.setAttribute('value', token);
521                                    const button = form.querySelector('[type="submit"]');
522                                    if(button) {
523                                        const input = document.createElement('input');
524                                        input.type = 'hidden';
525                                        input.name = button.getAttribute('name');
526                                        input.value = button.value;
527                                        input.classList.add('pp-submit-input');
528                                        var inputEls = document.querySelectorAll('.pp-submit-input');
529                                        [].forEach.call(inputEls, function(inputEl) {
530                                            inputEl.remove();
531                                        });
532                                        form.appendChild(input);
533                                    }
534                                    HTMLFormElement.prototype.submit.call(form);
535                                });
536                            });
537                        });
538                    });
539                }
540            }
541EOT;
542
543                wp_enqueue_script( 'recaptcha-api-v3', ( 'https://www.google.com/recaptcha/api.js?onload=pprecaptcha&render=' . esc_attr( $grecaptcha_v3_site_key ) . '&badge=' . esc_attr( $grecaptcha_v3_badge ) ), array(), null );
544                wp_add_inline_script( 'recaptcha-api-v3', $script ); ?>
545                <input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response-password_protected" class="pp-g-recaptcha" data-action="password_protected">
546                <?php
547        }
548
549        /**
550         * Verify reCAPTCHA
551         * process reCAPTCHA
552         *
553         * @since  2.6
554         *
555         * @return  object  WP_Error
556         */
557        public function verify_recaptcha( $errors ) {
558
559                if ( ! @$this->settings['enable'] ) {
560                        return $errors; // return errors
561                }
562
563                if ( $this->settings['version'] === 'google_recaptcha_v2' ) {
564
565                        $grecaptcha_v2_site_key   = isset( $this->settings['v2_site_key'] ) ? esc_attr( $this->settings['v2_site_key'] ) : '';
566                        $grecaptcha_v2_secret_key = isset( $this->settings['v2_secret_key'] ) ? esc_attr( $this->settings['v2_secret_key'] ) : '';
567
568                        if ( empty( $grecaptcha_v2_site_key ) || empty( $grecaptcha_v2_secret_key ) ) {
569                                $errors->add( 001, 'Google reCaptcha keys not found.' );
570                        }
571
572                        if ( isset( $_POST['g-recaptcha-response'] ) && ! empty( $_POST['g-recaptcha-response'] ) ) {
573                                $response = wp_remote_post(
574                                        'https://www.google.com/recaptcha/api/siteverify',
575                                        array(
576                                                'body' => array(
577                                                        'secret'   => $grecaptcha_v2_secret_key,
578                                                        'response' => sanitize_text_field( $_POST['g-recaptcha-response'] ),
579                                                ),
580                                        )
581                                );
582
583                                $data = wp_remote_retrieve_body( $response );
584                                $data = json_decode( $data );
585
586                                if ( isset( $data->{'error-codes'} ) && is_array( $data->{'error-codes'} ) && count( $data->{'error-codes'} ) ) {
587                                        foreach ( $data->{'error-codes'} as $index => $error_code ) {
588                                                $errors->add( $index, $error_code );
589                                        }
590                                }
591
592                                if ( isset( $data->success ) && true === $data->success ) {
593                                        return $errors;
594                                }
595                        }
596                        $error_message = wp_kses( __( '<strong>ERROR:</strong> Please confirm you are not a robot.', 'password-protected' ), array( 'strong' => array() ) );
597                        $errors->add( 'captcha_invalid', $error_message );
598
599                        return $errors;
600
601                } elseif ( $this->settings['version'] === 'google_recaptcha_v3' ) {
602
603                        $grecaptcha_v3_site_key   = isset( $this->settings['v3_site_key'] ) ? esc_attr( $this->settings['v3_site_key'] ) : '';
604                        $grecaptcha_v3_secret_key = isset( $this->settings['v3_secret_key'] ) ? esc_attr( $this->settings['v3_secret_key'] ) : '';
605                        $grecaptcha_v3_score      = isset( $this->settings['v3_score'] ) ? esc_attr( $this->settings['v3_score'] ) : '0.3';
606
607                        if ( empty( $grecaptcha_v3_site_key ) || empty( $grecaptcha_v3_secret_key ) ) {
608                                $errors->add( 001, 'Google reCaptcha keys not found.' );
609                        }
610
611                        if ( isset( $_POST['g-recaptcha-response'] ) && ! empty( $_POST['g-recaptcha-response'] ) ) {
612                                $response = wp_remote_post(
613                                        'https://www.google.com/recaptcha/api/siteverify',
614                                        array(
615                                                'body' => array(
616                                                        'secret'   => $grecaptcha_v3_secret_key,
617                                                        'response' => sanitize_text_field( $_POST['g-recaptcha-response'] ),
618                                                        'remoteip' => self::get_ip_address(),
619                                                ),
620                                        )
621                                );
622
623                                $data = wp_remote_retrieve_body( $response );
624                                $data = json_decode( $data );
625
626                                if ( isset( $data->{'error-codes'} ) && is_array( $data->{'error-codes'} ) && count( $data->{'error-codes'} ) ) {
627                                        foreach ( $data->{'error-codes'} as $index => $error_code ) {
628                                                $errors->add( $index, $error_code );
629                                        }
630                                }
631
632                                if ( isset( $data->success ) && true === $data->success ) {
633                                        $grecaptcha_v3_score = (float) $grecaptcha_v3_score;
634                                        if ( isset( $data->action ) && ( 'password_protected' === $data->action ) && isset( $data->score ) && $data->score >= $grecaptcha_v3_score ) {
635                                                return $errors;
636                                        } else {
637                                                $error_message = wp_kses( __( '<strong>ERROR:</strong> Low Score ', 'password-protected' ) . ':' . esc_html( $data->score ), array( 'strong' => array() ) );
638                                                $errors->add( 002, $error_message );
639                                        }
640                                }
641                        }
642
643                        return $errors;
644                }
645
646        }
647
648        /**
649         * Get IP Address
650         *
651         * @since  2.6
652         *
653         * @return  string  client IP address
654         */
655        private static function get_ip_address() {
656                $ipaddress = '';
657                if ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
658                        $ipaddress = sanitize_text_field( $_SERVER['HTTP_CLIENT_IP'] );
659                } elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
660                        $ipaddress = sanitize_text_field( $_SERVER['HTTP_X_FORWARDED_FOR'] );
661                } elseif ( isset( $_SERVER['HTTP_X_FORWARDED'] ) ) {
662                        $ipaddress = sanitize_text_field( $_SERVER['HTTP_X_FORWARDED'] );
663                } elseif ( isset( $_SERVER['HTTP_FORWARDED_FOR'] ) ) {
664                        $ipaddress = sanitize_text_field( $_SERVER['HTTP_FORWARDED_FOR'] );
665                } elseif ( isset( $_SERVER['HTTP_FORWARDED'] ) ) {
666                        $ipaddress = sanitize_text_field( $_SERVER['HTTP_FORWARDED'] );
667                } elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
668                        $ipaddress = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
669                } else {
670                        $ipaddress = 'UNKNOWN';
671                }
672                return $ipaddress;
673        }
674
675}
Note: See TracBrowser for help on using the repository browser.