PluginProbe
Password Protected — Lock Entire Site, Pages, Posts, Categories, and Partial Content / 2.8.4
Password Protected — Lock Entire Site, Pages, Posts, Categories, and Partial Content v2.8.4
2.8.4 2.8.3 2.8.2 2.8.1 trunk 1.0 1.1 1.2 1.2.1 1.2.2 1.3 1.4 1.5 1.6 1.6.1 1.6.2 1.7 1.7.1 1.7.2 1.8 1.9 2.0 2.0.1 2.0.2 2.0.3 All 63 releases
password-protected / password-protected.php

password-protected.php in Password Protected — Lock Entire Site, Pages, Posts, Categories, and Partial Content 2.8.4, at password-protected.php

1,036 lines 28.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Password Protected
4 Plugin URI: https://wordpress.org/plugins/password-protected/
5 Description: A very simple way to quickly password protect your WordPress site with a single password. Please note: This plugin does not restrict access to uploaded files and images and does not work with some caching setups.
6 Version: 2.8.4
7 Author: Password Protected
8 Text Domain: password-protected
9 Author URI: https://passwordprotectedwp.com/
10 License: GPLv2
11 */
12 /*
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License, version 2, as
15 published by the Free Software Foundation.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 */
26
27 if ( ! defined( 'ABSPATH' ) ) {
28 exit;
29 }
30
31 /**
32 * @todo Use wp_hash_password() ?
33 * @todo Remember me
34 */
35
36
37 define( 'PASSWORD_PROTECTED_SUBDIR', '/' . str_replace( basename( __FILE__ ), '', plugin_basename( __FILE__ ) ) );
38 define( 'PASSWORD_PROTECTED_URL', plugins_url( PASSWORD_PROTECTED_SUBDIR ) );
39 define( 'PASSWORD_PROTECTED_DIR', plugin_dir_path( __FILE__ ) );
40
41 require_once PASSWORD_PROTECTED_DIR . 'includes/freemius.php';
42
43 global $Password_Protected;
44 $Password_Protected = new Password_Protected();
45
46 class Password_Protected {
47
48 var $version = '2.8.4';
49 var $admin = null;
50 var $errors = null;
51 var $admin_caching = null;
52
53 /**
54 * Constructor
55 */
56 public function __construct() {
57
58 $this->errors = new WP_Error();
59
60 register_activation_hook( __FILE__, array( &$this, 'install' ) );
61
62
63 add_filter( 'password_protected_is_active', array( $this, 'allow_ip_addresses' ) );
64 add_filter( 'password_protected_is_active', array( $this, 'elementor_compatibility' ) );
65
66 add_action( 'init', array( $this, 'disable_caching' ), 1 );
67 add_action( 'init', array( $this, 'maybe_process_logout' ), 1 );
68 add_action( 'init', array( $this, 'maybe_process_login' ), 1 );
69 add_action( 'wp', array( $this, 'disable_feeds' ) );
70 add_action( 'template_redirect', array( $this, 'maybe_show_login' ), -10 );
71 add_filter( 'pre_option_password_protected_status', array( $this, 'allow_feeds' ) );
72 add_filter( 'pre_option_password_protected_status', array( $this, 'allow_administrators' ) );
73 add_filter( 'pre_option_password_protected_status', array( $this, 'allow_users' ) );
74 add_filter( 'rest_authentication_errors', array( $this, 'only_allow_logged_in_rest_access' ) );
75 add_action( 'init', array( $this, 'compat' ) );
76 add_action( 'password_protected_login_messages', array( $this, 'login_messages' ) );
77 add_action( 'login_enqueue_scripts', array( $this, 'load_theme_stylesheet' ), 5 );
78
79 add_action('password_protected_above_password_field', array( $this, 'password_protected_above_password_field' ));
80 add_action('password_protected_below_password_field', array( $this, 'password_protected_below_password_field' ));
81
82
83
84
85 // Available from WordPress 4.3+
86 if ( function_exists( 'wp_site_icon' ) ) {
87 add_action( 'password_protected_login_head', 'wp_site_icon' );
88 }
89
90 add_shortcode( 'password_protected_logout_link', array( $this, 'logout_link_shortcode' ) );
91
92 include_once dirname( __FILE__ ) . '/admin/admin-bar.php';
93 include_once dirname( __FILE__ ) . '/includes/compatibility.php';
94 if ( is_admin() ) {
95
96 include_once dirname( __FILE__ ) . '/admin/admin-caching.php';
97 include_once dirname( __FILE__ ) . '/admin/admin.php';
98
99 $this->admin_caching = new Password_Protected_Admin_Caching( $this );
100 $this->admin = new Password_Protected_Admin();
101
102
103 }
104 include_once dirname( __FILE__ ) . '/admin/class-recaptcha.php';
105 new Password_Protected_reCAPTCHA();
106
107 include_once dirname( __FILE__ ) . '/includes/transient-functions.php';
108 include_once dirname( __FILE__ ) . '/includes/activity-report-email/class-password-protected-activity-report-settings.php';
109
110 include_once dirname( __FILE__ ) . '/admin/class-pp-all-captcha-tabs.php';
111 include_once dirname( __FILE__ ) . '/includes/class-customize.php';
112 new Password_Protected_Free_allCaptchas();
113
114 }
115
116 /**
117 * Disable Page Caching
118 */
119 public function disable_caching() {
120
121 if ( $this->is_active() && ! defined( 'DONOTCACHEPAGE' ) ) {
122 define( 'DONOTCACHEPAGE', true );
123 }
124
125 }
126
127 /**
128 * Is Active?
129 *
130 * @return boolean Is password protection active?
131 */
132 public function is_active() {
133
134 global $wp_query;
135
136 // Always allow access to robots.txt
137 if ( isset( $wp_query ) && is_robots() ) {
138 return false;
139 }
140
141 if ( (bool) get_option( 'password_protected_status' ) ) {
142 $is_active = true;
143 } else {
144 $is_active = false;
145 }
146
147 $is_active = apply_filters( 'password_protected_is_active', $is_active );
148
149 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Login page query arg forces protection UI.
150 if ( isset( $_GET['password-protected'] ) ) {
151 $is_active = true;
152 }
153
154 return $is_active;
155
156 }
157
158 /**
159 * Disable Feeds
160 *
161 * @todo An option/filter to prevent disabling of feeds.
162 */
163 public function disable_feeds() {
164
165 if ( $this->is_active() ) {
166 add_action( 'do_feed', array( $this, 'disable_feed' ), 1 );
167 add_action( 'do_feed_rdf', array( $this, 'disable_feed' ), 1 );
168 add_action( 'do_feed_rss', array( $this, 'disable_feed' ), 1 );
169 add_action( 'do_feed_rss2', array( $this, 'disable_feed' ), 1 );
170 add_action( 'do_feed_atom', array( $this, 'disable_feed' ), 1 );
171 }
172
173 }
174
175 /**
176 * Disable Feed
177 *
178 * @todo Make Translatable
179 */
180 public function disable_feed() {
181
182 wp_die(
183 wp_kses_post(
184 sprintf(
185 /* translators: %s: site URL. */
186 __( 'Feeds are not available for this site. Please visit the <a href="%s">website</a>.', 'password-protected' ),
187 esc_url( get_bloginfo( 'url' ) )
188 )
189 )
190 );
191
192 }
193
194 /**
195 * Allow Feeds
196 *
197 * @param boolean $bool Allow feeds.
198 * @return boolean True/false.
199 */
200 public function allow_feeds( $bool ) {
201
202 if ( is_feed() && (bool) get_option( 'password_protected_feeds' ) ) {
203 return 0;
204 }
205
206 return $bool;
207
208 }
209
210 /**
211 * Allow Administrators
212 *
213 * @param boolean $bool Allow administrators.
214 * @return boolean True/false.
215 */
216 public function allow_administrators( $bool ) {
217
218 if ( ! is_admin() && current_user_can( 'manage_options' ) && (bool) get_option( 'password_protected_administrators' ) ) {
219 return 0;
220 }
221
222 return $bool;
223
224 }
225
226 /**
227 * Allow Users
228 *
229 * @param boolean $bool Allow administrators.
230 * @return boolean True/false.
231 */
232 public function allow_users( $bool ) {
233
234 if ( ! is_admin() && is_user_logged_in() && (bool) get_option( 'password_protected_users' ) ) {
235 return 0;
236 }
237
238 return $bool;
239
240 }
241
242 /**
243 * Allow IP Addresses
244 *
245 * If user has a valid email address, return false to disable password protection.
246 *
247 * @param boolean $bool Allow IP addresses.
248 * @return boolean True/false.
249 */
250 public function allow_ip_addresses( $bool ) {
251
252 $ip_addresses = $this->get_allowed_ip_addresses();
253
254 $remote_addr = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
255
256 if ( $remote_addr && in_array( $remote_addr, $ip_addresses, true ) ) {
257 $bool = false;
258 } else {
259 $bool = apply_filters( 'password_protected__allowed_ip_ranges', $bool, $ip_addresses, $remote_addr );
260 }
261
262 return $bool;
263
264 }
265
266
267 /**
268 * Is protection active.
269 *
270 * @param bool $is_active is active {true|false}.
271 *
272 * @return bool
273 */
274 public function elementor_compatibility( $is_active ) {
275 if ( class_exists( '\\Elementor\\plugin' ) ) {
276 if ( \Elementor\Plugin::$instance->preview->is_preview_mode() ) {
277 $is_active = false;
278 }
279 }
280 return $is_active;
281 }
282
283 /**
284 * Get Allowed IP Addresses
285 *
286 * @return array IP addresses.
287 */
288 public function get_allowed_ip_addresses() {
289 $allowed_ip_address = get_option( 'password_protected_allowed_ip_addresses' );
290 if ( empty( $allowed_ip_address ) ) {
291 return array();
292 }
293 return explode( "\n", $allowed_ip_address );
294
295 }
296
297 /**
298 * Allow the remember me function
299 *
300 * @return. boolean
301 */
302 public function allow_remember_me() {
303
304 return (bool) get_option( 'password_protected_remember_me' );
305
306 }
307
308 /**
309 * Encrypt Password
310 *
311 * @param string $password Password.
312 * @return string Encrypted password.
313 */
314 public function encrypt_password( $password ) {
315
316 return md5( $password );
317
318 }
319
320 /**
321 * Maybe Process Logout
322 */
323 public function maybe_process_logout() {
324
325 // phpcs:disable WordPress.Security.NonceVerification.Recommended
326 if ( isset( $_REQUEST['password-protected'] ) && 'logout' === sanitize_text_field( wp_unslash( $_REQUEST['password-protected'] ) ) ) {
327
328 $this->logout();
329
330 if ( isset( $_REQUEST['redirect_to'] ) ) {
331 $redirect_to = remove_query_arg( 'password-protected', esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ), array( 'http', 'https' ) ) );
332 } else {
333 $redirect_to = home_url( '/' );
334 }
335
336 $this->safe_redirect( $redirect_to );
337 exit();
338
339 }
340 // phpcs:enable
341
342 }
343
344 /**
345 * Maybe Process Login
346 */
347 public function maybe_process_login() {
348
349 // phpcs:disable WordPress.Security.NonceVerification.Recommended
350 if ( $this->is_active() && isset( $_REQUEST['password_protected_pwd'] ) ) {
351
352 $password_protected_pwd = sanitize_text_field( wp_unslash( $_REQUEST['password_protected_pwd'] ) );
353 $default_password = get_option( 'password_protected_password' );
354
355 $auth = false;
356 $p_id = 0;
357
358 if ( empty( $default_password ) ) {
359
360 $authentication = $this->password_protected_check_pro_password( $password_protected_pwd );
361 $auth = $authentication['auth'];
362 $p_id = $authentication['p_id'];
363
364 } else {
365
366 if ( ( hash_equals( $default_password, $this->encrypt_password( $password_protected_pwd ) ) && $default_password != '' ) || apply_filters( 'password_protected_process_login', false, $password_protected_pwd ) ) {
367 $auth = true;
368 }
369
370 if ( ! $auth ) {
371
372 $authentication = $this->password_protected_check_pro_password( $password_protected_pwd );
373 $auth = $authentication['auth'];
374 $p_id = $authentication['p_id'];
375 }
376
377 }
378
379 $this->errors = apply_filters( 'password_protected_verify_recaptcha', $this->errors );
380
381 if( count( @$this->errors->errors ) > 0 ) return;
382
383 $this->password_protected_process_login( $auth, $password_protected_pwd, $p_id );
384
385 }
386 // phpcs:enable
387
388 }
389
390 public function password_protected_process_login( bool $auth, $requested_password, $password_id ) {
391
392 if( $auth )
393 $throttle = apply_filters( 'password_protected_check_for_throttling', true );
394
395
396 if( $auth && $throttle ) {
397
398 do_action( 'password_protected_success_login_attempt', 'global', $requested_password, $password_id );
399 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public password login form.
400 $remember = isset( $_REQUEST['password_protected_rememberme'] ) ? boolval( wp_unslash( $_REQUEST['password_protected_rememberme'] ) ) : false;
401
402 if ( ! $this->allow_remember_me() ) {
403 $remember = false;
404 }
405 $this->set_auth_cookie( $remember );
406
407 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public password login form.
408 $redirect_to = isset( $_REQUEST['redirect_to'] ) ? esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ) ) : '';
409
410 $redirect_to = apply_filters( 'password_protected_login_redirect', $redirect_to, $requested_password );
411
412 if ( ! empty( $redirect_to ) ) {
413 $this->safe_redirect( remove_query_arg( 'password-protected', $redirect_to ) );
414 exit;
415 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public password login form.
416 } elseif ( isset( $_GET['password_protected_pwd'] ) ) {
417 $this->safe_redirect( remove_query_arg( 'password-protected' ) );
418 exit;
419 } else {
420 $this->safe_redirect( site_url() );
421 exit;
422 }
423 } else {
424 do_action( 'password_protected_failure_login_attempt', 'global', $requested_password, $password_id );
425
426 // ... otherwise incorrect password
427 $this->clear_auth_cookie();
428
429 $show_default_error = apply_filters( 'password_protected_throttling_error_messages', true );
430
431 if( $show_default_error )
432 $this->errors->add( 'incorrect_password', __( 'Incorrect Password', 'password-protected' ) );
433 }
434 }
435
436 /**
437 * password_protected_check_pro_password
438 *
439 * @param mixed $requested_password
440 * @return void
441 */
442 public function password_protected_check_pro_password( $requested_password ) {
443
444 $pro_passwords = apply_filters( 'password_protected_passwords', array() );
445 $pro_passwords = array_filter( $pro_passwords );
446 $auth = false;
447 $p_id = 0;
448
449 if( is_array( $pro_passwords ) && count( $pro_passwords ) > 0 ) {
450
451 foreach( $pro_passwords as $i => $p ) {
452
453 if ( ( hash_equals( $p, $this->encrypt_password( $requested_password ) ) && $pro_passwords != '' ) || apply_filters( 'password_protected_process_login', false, $requested_password ) ) {
454
455 $auth = apply_filters( 'password_protected_login_password_matched', $p, $this->errors );
456 $p_id = $i;
457 break;
458
459 }
460
461 }
462
463 } else {
464
465 $auth = false;
466
467 }
468
469 return array(
470 'auth' => $auth,
471 'p_id' => $p_id,
472 );
473 }
474
475 /**
476 * Is User Logged In?
477 *
478 * @return boolean
479 */
480 public function is_user_logged_in() {
481
482 return $this->is_active() && $this->validate_auth_cookie();
483
484 }
485
486 /**
487 * Maybe Show Login
488 */
489 public function maybe_show_login() {
490
491 if ( class_exists( 'Login_designer' ) || class_exists( 'Password_Protected_Pro_Customizer' ) ) {
492 if ( is_customize_preview() ) {
493 return 1;
494 }
495 }
496
497 // Filter for adding exceptions.
498 $show_login = apply_filters( 'password_protected_show_login', $this->is_active() );
499
500 // Logged in
501 if ( $this->is_user_logged_in() ) {
502 $show_login = false;
503 }
504
505 if ( ! $show_login ) {
506 return 1;
507 }
508
509 // Show login form
510 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public password login flow.
511 if ( isset( $_REQUEST['password-protected'] ) && 'login' === sanitize_text_field( wp_unslash( $_REQUEST['password-protected'] ) ) ) {
512
513 $default_theme_file = locate_template( array( 'password-protected-login.php' ) );
514
515 if ( empty( $default_theme_file ) ) {
516 $default_theme_file = dirname( __FILE__ ) . '/theme/password-protected-login.php';
517 }
518
519 $theme_file = apply_filters( 'password_protected_theme_file', $default_theme_file );
520 if ( ! file_exists( $theme_file ) ) {
521 $theme_file = $default_theme_file;
522 }
523
524 load_template( $theme_file );
525 exit();
526
527 } else {
528 global $wp;
529
530 $query_string = isset( $_SERVER['QUERY_STRING'] ) ? sanitize_text_field( wp_unslash( $_SERVER['QUERY_STRING'] ) ) : '';
531 $redirect_to = add_query_arg( 'password-protected', 'login', home_url( $wp->request . ( $query_string ? '?' . $query_string : '' ) ) );
532 $redirect_to = pp__add_dynamic_arg( $redirect_to );
533
534 // URL to redirect back to after login
535 $redirect_to_url = '';
536 if ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) {
537 $redirect_to_url = esc_url_raw(
538 ( is_ssl() ? 'https://' : 'http://' ) . sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) . wp_unslash( $_SERVER['REQUEST_URI'] )
539 );
540 }
541 $redirect_to_url = apply_filters( 'password_protected_login_redirect_url', $redirect_to_url );
542 $redirect_to_url = pp__add_dynamic_arg( $redirect_to_url );
543 if ( ! empty( $redirect_to_url ) ) {
544 $redirect_to = add_query_arg( 'redirect_to', urlencode( $redirect_to_url ), $redirect_to );
545 }
546
547 nocache_headers();
548 $this->safe_redirect( $redirect_to );
549 exit();
550
551 }
552 }
553
554 /**
555 * Get Site ID
556 *
557 * @return string Site ID.
558 */
559 public function get_site_id() {
560
561 global $blog_id;
562 return 'bid_' . apply_filters( 'password_protected_blog_id', $blog_id );
563
564 }
565
566 /**
567 * Login URL
568 *
569 * @return string Login URL.
570 */
571 public function login_url() {
572 global $wp;
573 $query_string = isset( $_SERVER['QUERY_STRING'] ) ? sanitize_text_field( wp_unslash( $_SERVER['QUERY_STRING'] ) ) : '';
574 return add_query_arg( 'password-protected', 'login', home_url( $wp->request . ( $query_string ? '?' . $query_string : '' ) ) );
575
576 }
577
578 /**
579 * Logout
580 */
581 public function logout() {
582
583 $this->clear_auth_cookie();
584 do_action( 'password_protected_logout' );
585
586 }
587
588 /**
589 * Logout URL
590 *
591 * @param string $redirect_to Optional. Redirect URL.
592 * @return string Logout URL.
593 */
594 public function logout_url( $redirect_to = '' ) {
595
596 $query = array(
597 'password-protected' => 'logout',
598 'redirect_to' => esc_url_raw( $redirect_to ),
599 );
600
601 if ( empty( $query['redirect_to'] ) ) {
602 unset( $query['redirect_to'] );
603 }
604
605 return add_query_arg( $query, home_url() );
606
607 }
608
609 /**
610 * Logout Link
611 *
612 * @param array $args Link args.
613 * @return string HTML link tag.
614 */
615 public function logout_link( $args = null ) {
616
617 // Only show if user is logged in
618 if ( ! $this->is_user_logged_in() ) {
619 return '';
620 }
621
622 $args = wp_parse_args(
623 $args,
624 array(
625 'redirect_to' => '',
626 'text' => __( 'Logout', 'password-protected' ),
627 )
628 );
629
630 if ( empty( $args['text'] ) ) {
631 $args['text'] = __( 'Logout', 'password-protected' );
632 }
633
634 return sprintf( '<a href="%s">%s</a>', esc_url( $this->logout_url( $args['redirect_to'] ) ), esc_html( $args['text'] ) );
635
636 }
637
638 /**
639 * Logout Link Shortcode
640 *
641 * @param array $args Link args.
642 * @return string HTML link tag.
643 */
644 public function logout_link_shortcode( $atts, $content = null ) {
645
646 $atts = shortcode_atts(
647 array(
648 'redirect_to' => '',
649 'text' => $content,
650 ),
651 $atts,
652 'logout_link_shortcode'
653 );
654
655 return $this->logout_link( $atts );
656
657 }
658
659 /**
660 * Get Hashed Password
661 *
662 * @return string Hashed password.
663 */
664 public function get_hashed_password() {
665
666 return md5( get_option( 'password_protected_password' ) . wp_salt() );
667
668 }
669
670 /**
671 * Validate Auth Cookie
672 *
673 * @param string $cookie Cookie string.
674 * @param string $scheme Cookie scheme.
675 * @return boolean Validation successful?
676 */
677 public function validate_auth_cookie( $cookie = '', $scheme = '', $hashed_password = '' ) {
678
679 if ( ! $cookie_elements = $this->parse_auth_cookie( $cookie, $scheme ) ) {
680 do_action( 'password_protected_auth_cookie_malformed', $cookie, $scheme );
681 return false;
682 }
683
684 extract( $cookie_elements, EXTR_OVERWRITE );
685
686 $expired = $expiration;
687
688 // Allow a grace period for POST and AJAX requests
689 $request_method = isset( $_SERVER['REQUEST_METHOD'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) : '';
690 if ( defined( 'DOING_AJAX' ) || 'POST' === $request_method ) {
691 $expired += 3600;
692 }
693
694 // Quick check to see if an honest cookie has expired
695 if ( $expired < current_time( 'timestamp' ) ) {
696 do_action( 'password_protected_auth_cookie_expired', $cookie_elements );
697 return false;
698 }
699
700 if ( empty( $hashed_password ) ) {
701 $hashed_password = $this->get_hashed_password();
702 }
703 $key = md5( $this->get_site_id() . $hashed_password . '|' . $expiration ); // need to modify
704 $hash = hash_hmac( 'md5', $this->get_site_id() . '|' . $expiration, $key );
705
706 if ( $hmac != $hash ) {
707 do_action( 'password_protected_auth_cookie_bad_hash', $cookie_elements );
708 return false;
709 }
710
711 if ( $expiration < current_time( 'timestamp' ) ) { // AJAX/POST grace period set above
712 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- WordPress auth cookie grace period global.
713 $GLOBALS['login_grace_period'] = 1;
714 }
715
716 return true;
717
718 }
719
720 /**
721 * Generate Auth Cookie
722 *
723 * @param int $expiration Expiration time in seconds.
724 * @param string $scheme Cookie scheme.
725 * @return string Cookie.
726 */
727 public function generate_auth_cookie( $expiration, $scheme = 'auth', $hashed_password = '' ) {
728
729 if ( empty( $hashed_password ) ) {
730 $hashed_password = $this->get_hashed_password();
731 }
732 $key = md5( $this->get_site_id() . $hashed_password . '|' . $expiration ); // need to modify
733 $hash = hash_hmac( 'md5', $this->get_site_id() . '|' . $expiration, $key );
734 $cookie = $this->get_site_id() . '|' . $expiration . '|' . $hash;
735
736 return $cookie;
737
738 }
739
740 /**
741 * Parse Auth Cookie
742 *
743 * @param string $cookie Cookie string.
744 * @param string $scheme Cookie scheme.
745 * @return string Cookie string.
746 */
747 public function parse_auth_cookie( $cookie = '', $scheme = '' ) {
748 if ( empty( $cookie ) ) {
749
750 $cookie_name = $this->cookie_name();
751 $use_transient = get_option( 'password_protected_use_transient', 'default' );
752
753 $cookie = password_protected_cookie( 'get', array( 'name' => $cookie_name ) );
754
755 if ( empty( $cookie ) ) {
756 return false;
757 }
758 }
759
760 $cookie_elements = explode( '|', $cookie );
761
762 if ( count( $cookie_elements ) != 3 ) {
763 return false;
764 }
765
766 list( $site_id, $expiration, $hmac ) = $cookie_elements;
767
768 return compact( 'site_id', 'expiration', 'hmac', 'scheme' );
769
770 }
771
772 /**
773 * Set Auth Cookie
774 *
775 * @todo
776 *
777 * @param boolean $remember Remember logged in.
778 * @param string $secure Secure cookie.
779 */
780 public function set_auth_cookie( $remember = false, $secure = '' ) {
781
782 if ( $remember ) {
783 $expiration_time = apply_filters( 'password_protected_auth_cookie_expiration', get_option( 'password_protected_remember_me_lifetime', 14 ) * DAY_IN_SECONDS, $remember );
784 $expiration = $expire = current_time( 'timestamp' ) + $expiration_time;
785 } else {
786 $expiration_time = apply_filters( 'password_protected_auth_cookie_expiration', DAY_IN_SECONDS * 20, $remember );
787 $expiration = current_time( 'timestamp' ) + $expiration_time;
788 $expire = 0;
789 }
790
791 if ( '' === $secure ) {
792 $secure = is_ssl();
793 }
794
795 $secure_password_protected_cookie = apply_filters( 'password_protected_secure_password_protected_cookie', false, $secure );
796 $password_protected_cookie = $this->generate_auth_cookie( $expiration, 'password_protected' );
797
798 $use_transient = get_option( 'password_protected_use_transient', 'default' );
799
800
801 password_protected_cookie(
802 'set',
803 array(
804 'name' => $this->cookie_name(),
805 'data' => $password_protected_cookie,
806 'secure' => $secure_password_protected_cookie,
807 'expire' => $expire,
808 )
809 );
810
811 }
812
813 /**
814 * Clear Auth Cookie
815 */
816 public function clear_auth_cookie() {
817 $use_transient = get_option( 'password_protected_use_transient', 'default' );
818 password_protected_cookie( 'delete', array( 'name' => $this->cookie_name() ) );
819 }
820
821 /**
822 * Cookie Name
823 *
824 * @return string Cookie name.
825 */
826 public function cookie_name() {
827
828 /**
829 * Filters the cookie name
830 */
831 return apply_filters( 'password_protected_cookie_name', $this->get_site_id() . '_password_protected_auth', $this );
832
833 }
834
835 /**
836 * Install
837 */
838 public function install() {
839
840 $old_version = get_option( 'password_protected_version' );
841
842 // 1.1 - Upgrade to MD5
843 if ( empty( $old_version ) || $old_version == '1.1' ) {
844 $pwd = get_option( 'password_protected_password' );
845 if ( ! empty( $pwd ) ) {
846 $new_pwd = $this->encrypt_password( $pwd );
847 update_option( 'password_protected_password', $new_pwd );
848 }
849 }
850
851 update_option( 'password_protected_version', $this->version );
852
853 }
854
855 /**
856 * Compat
857 *
858 * Support for 3rd party plugins:
859 *
860 * - Login Logo https://wordpress.org/plugins/login-logo/
861 * - Uber Login Logo https://wordpress.org/plugins/uber-login-logo/
862 */
863 public function compat() {
864
865 if ( class_exists( 'CWS_Login_Logo_Plugin' ) ) {
866
867 // Add support for Mark Jaquith's Login Logo plugin
868 add_action( 'password_protected_login_head', array( new CWS_Login_Logo_Plugin(), 'login_head' ) );
869
870 } elseif ( class_exists( 'UberLoginLogo' ) ) {
871
872 // Add support for Uber Login Logo plugin
873 add_action( 'password_protected_login_head', array( 'UberLoginLogo', 'replaceLoginLogo' ) );
874
875 }
876
877 }
878
879 /**
880 * Login Messages
881 * Outputs messages and errors in the login template.
882 */
883 public function login_messages() {
884
885 // Add message
886 $message = apply_filters( 'password_protected_login_message', '' );
887 if ( ! empty( $message ) ) {
888 echo wp_kses_post( $message ) . "\n";
889 }
890
891 if ( $this->errors->get_error_code() ) {
892
893 $errors = '';
894 $messages = '';
895
896 foreach ( $this->errors->get_error_codes() as $code ) {
897 $severity = $this->errors->get_error_data( $code );
898 foreach ( $this->errors->get_error_messages( $code ) as $error ) {
899 if ( 'message' == $severity ) {
900 $messages .= $error . '<br />';
901 } else {
902 $errors .= $error . '<br />';
903 }
904 }
905 }
906
907 if ( ! empty( $errors ) ) {
908 echo '<div id="login_error" class="notice notice-error">' . wp_kses_post( apply_filters( 'password_protected_login_errors', $errors ) ) . "</div>\n";
909 }
910 if ( ! empty( $messages ) ) {
911 echo '<p class="message">' . wp_kses_post( apply_filters( 'password_protected_login_messages', $messages ) ) . "</p>\n";
912 }
913 }
914
915 }
916
917 /**
918 * Load Theme Stylesheet
919 *
920 * Check wether a 'password-protected-login.css' stylesheet exists in your theme
921 * and if so loads it.
922 *
923 * Works with child themes.
924 *
925 * Possible to specify a different file in the theme folder via the
926 * 'password_protected_stylesheet_file' filter (allows for theme subfolders).
927 */
928 public function load_theme_stylesheet() {
929
930 $filename = apply_filters( 'password_protected_stylesheet_file', 'password-protected-login.css' );
931
932 $located = locate_template( $filename );
933
934 if ( ! empty( $located ) ) {
935
936 $stylesheet_directory = trailingslashit( get_stylesheet_directory() );
937 $template_directory = trailingslashit( get_template_directory() );
938 $style_version = (string) filemtime( $located );
939
940 if ( $stylesheet_directory == substr( $located, 0, strlen( $stylesheet_directory ) ) ) {
941 wp_enqueue_style( 'password-protected-login', get_stylesheet_directory_uri() . '/' . $filename, array(), $style_version );
942 } elseif ( $template_directory == substr( $located, 0, strlen( $template_directory ) ) ) {
943 wp_enqueue_style( 'password-protected-login', get_template_directory_uri() . '/' . $filename, array(), $style_version );
944 }
945 }
946
947 }
948
949 /**
950 * Safe Redirect
951 *
952 * Ensure the redirect is to the same site or pluggable list of allowed domains.
953 * If invalid will redirect to ...
954 * Based on the WordPress wp_safe_redirect() function.
955 */
956 public function safe_redirect( $location, $status = 302 ) {
957
958 $location = wp_sanitize_redirect( $location );
959 $location = wp_validate_redirect( $location, home_url() );
960
961 // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- Validated redirect target.
962 wp_redirect( $location, $status );
963
964 }
965
966 /**
967 * Is Plugin Supported?
968 *
969 * Check to see if there are any known reasons why this plugin may not work in
970 * the user's hosting environment.
971 *
972 * @return boolean
973 */
974 static function is_plugin_supported() {
975
976 return true;
977
978 }
979
980 /**
981 * Check whether a given request has permissions
982 *
983 * Always allow logged in users who require REST API for Gutenberg
984 * and other admin/plugin compatibility.
985 *
986 * @param WP_REST_Request $access Full details about the request.
987 * @return WP_Error|boolean
988 */
989 public function only_allow_logged_in_rest_access( $access ) {
990 if ( $this->is_active() ) {
991 if ( is_user_logged_in() ) {
992 global $current_user;
993 if ( $current_user->has_cap( 'edit_posts' ) || $current_user->has_cap( 'edit_pages' ) ) {
994 return $access;
995 }
996 }
997
998 if ( $this->is_user_logged_in() ) {
999 return $access;
1000 }
1001
1002 if ( get_option( 'password_protected_rest' ) && is_user_logged_in() ) {
1003 return $access;
1004 }
1005 return new WP_Error( 'rest_cannot_access', __( 'Only authenticated users can access the REST API.', 'password-protected' ), array( 'status' => rest_authorization_required_code() ) );
1006 }
1007
1008 return $access;
1009 }
1010
1011 /**
1012 * Print text above password field
1013 * @return void.
1014 */
1015 public function password_protected_above_password_field() {
1016 $text = get_option('password_protected_text_above_password');
1017 if( ! empty( $text ) ) {
1018 echo '<div class="password-protected-text-above" style="width:100%;">' . wp_kses_post( $text ) . '</div>';
1019 }
1020 }
1021
1022 /**
1023 * Print text below password field
1024 * @return void.
1025 */
1026 public function password_protected_below_password_field() {
1027 $text = get_option('password_protected_text_below_password');
1028 if( ! empty( $text ) ) {
1029 echo '<div class="password-protected-text-below" style="width:100%">' . wp_kses_post( $text ) . '</div>';
1030 }
1031 }
1032
1033 }
1034
1035
1036