diff --git a/CHANGELOG.md b/CHANGELOG.md index c91fb60..a362d4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [2.2] - 2018-05-25 + +### Added +- Admin bar icon to indicate wether password protection is enabled/disabled. +- Option to show "Remember me" checkbox. Props [Christian Güdel](https://github.com/cguedel). +- REST API access disabled if password not entered. +- Admin option to allow REST API access. + +### Security +- More robust checking of password hashes. + ## [2.1] - 2017-07-27 ### Added @@ -175,7 +186,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - First Release. If you spot any bugs or issues please [log them here](https://github.com/benhuson/password-protected/issues). -[Unreleased]: https://github.com/benhuson/password-protected/compare/2.1...HEAD +[Unreleased]: https://github.com/benhuson/password-protected/compare/2.2...HEAD +[2.2]: https://github.com/benhuson/password-protected/compare/2.1...2.2 [2.1]: https://github.com/benhuson/password-protected/compare/2.0.3...2.1 [2.0.3]: https://github.com/benhuson/password-protected/compare/2.0.2...2.0.3 [2.0.2]: https://github.com/benhuson/password-protected/compare/2.0.1...2.0.2 diff --git a/README.md b/README.md index 887c2fb..c598a11 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,9 @@ More instructions can be found at [wp-translations.org](http://wp-translations.o Upgrade Notice -------------- +### 2.2 +Added admin bar icon to indicate wether password protection is enabled/disabled. Options to enable REST API access and show "Remember me" checkbox. + ### 2.1 Update caching notes for WP Engine and W3 Total Cache plugin. diff --git a/admin/admin-bar.php b/admin/admin-bar.php new file mode 100644 index 0000000..be33f38 --- /dev/null +++ b/admin/admin-bar.php @@ -0,0 +1,137 @@ +add_menu( array( + 'id' => 'password_protected', + 'title' => __( '', 'password-protected' ), + 'href' => self::get_toolbar_item_url(), + 'meta' => array( + 'title' => self::get_toolbar_item_title() + ) + ) ); + + } + + } + + /** + * Get Toolbar Item URL + * + * @return string + */ + private static function get_toolbar_item_url() { + + if ( current_user_can( 'manage_options' ) ) { + return admin_url( 'options-general.php?page=password-protected' ); + } + + return ''; + + } + + /** + * Get Toolbar Item Title + * + * @return string + */ + private static function get_toolbar_item_title() { + + if ( self::is_enabled() ) { + return __( 'Password Protection is enabled.', 'password-protected' ); + } + + return __( 'Password Protection is disabled.', 'password-protected' ); + + } + + /** + * Styles + * + * @internal Private. Called via `wp_head` and `admin_head` actions. + */ + public static function styles() { + + if ( self::allow_current_user() ) { + + if ( self::is_enabled() ) { + $icon = '\f160'; // Locked + $background = '#C00'; + } else { + $icon = '\f528'; // Unlocked + $background = 'transparent'; + } + + ?> + + ' . __( 'Password Protected does not always work well with sites that use caching.', 'password-protected' ) . '
- ' . __( 'If your site uses a caching plugin or yur web hosting uses server-side caching, you may need to configure your setup to disable caching for the Password Protected cookie:', 'password-protected' ) . '

'; + ' . __( 'If your site uses a caching plugin or your web hosting uses server-side caching, you may need to configure your setup to disable caching for the Password Protected cookie:', 'password-protected' ) . '

'; } diff --git a/admin/admin.php b/admin/admin.php index 5aba2e3..93033ed 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -130,12 +130,31 @@ public function password_protected_settings() { 'password_protected' ); + add_settings_field( + 'password_protected_remember_me', + __( 'Allow Remember me', 'password-protected' ), + array( $this, 'password_protected_remember_me_field' ), + $this->options_group, + 'password_protected' + ); + + add_settings_field( + 'password_protected_remember_me_lifetime', + __( 'Remember for this many days', 'password-protected' ), + array( $this, 'password_protected_remember_me_lifetime_field' ), + $this->options_group, + 'password_protected' + ); + register_setting( $this->options_group, 'password_protected_status', 'intval' ); register_setting( $this->options_group, 'password_protected_feeds', 'intval' ); + register_setting( $this->options_group, 'password_protected_rest', 'intval' ); register_setting( $this->options_group, 'password_protected_administrators', 'intval' ); register_setting( $this->options_group, 'password_protected_users', 'intval' ); register_setting( $this->options_group, 'password_protected_password', array( $this, 'sanitize_password_protected_password' ) ); register_setting( $this->options_group, 'password_protected_allowed_ip_addresses', array( $this, 'sanitize_ip_addresses' ) ); + register_setting( $this->options_group, 'password_protected_remember_me', 'boolval' ); + register_setting( $this->options_group, 'password_protected_remember_me_lifetime', 'intval' ); } @@ -228,6 +247,7 @@ public function password_protected_permissions_field() { echo ''; echo ''; echo ''; + echo ''; } @@ -251,6 +271,24 @@ public function password_protected_allowed_ip_addresses_field() { } + /** + * Remember Me Field + */ + public function password_protected_remember_me_field() { + + echo ''; + + } + + /** + * Remember Me lifetime field + */ + public function password_protected_remember_me_lifetime_field() { + + echo ''; + + } + /** * Pre-update 'password_protected_password' Option * @@ -289,7 +327,7 @@ public function plugin_row_meta( $plugin_meta, $plugin_file, $plugin_data, $stat if ( 'password-protected/password-protected.php' == $plugin_file ) { $plugin_meta[] = sprintf( '%s', __( 'http://github.com/benhuson/password-protected', 'password-protected' ), __( 'GitHub', 'password-protected' ) ); - $plugin_meta[] = sprintf( '%s', __( 'https://www.transifex.com/projects/p/password-protected/resource/password-protected/', 'password-protected' ), __( 'Translate', 'password-protected' ) ); + $plugin_meta[] = sprintf( '%s', __( 'https://translate.wordpress.org/projects/wp-plugins/password-protected', 'password-protected' ), __( 'Translate', 'password-protected' ) ); } return $plugin_meta; diff --git a/password-protected.php b/password-protected.php index aef5719..f0e5e60 100644 --- a/password-protected.php +++ b/password-protected.php @@ -4,7 +4,7 @@ Plugin Name: Password Protected Plugin URI: https://wordpress.org/plugins/password-protected/ 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. -Version: 2.1 +Version: 2.2 Author: Ben Huson Text Domain: password-protected Author URI: http://github.com/benhuson/password-protected/ @@ -42,7 +42,7 @@ class Password_Protected { - var $version = '2.1'; + var $version = '2.2'; var $admin = null; var $errors = null; @@ -67,12 +67,15 @@ public function __construct() { add_filter( 'pre_option_password_protected_status', array( $this, 'allow_feeds' ) ); add_filter( 'pre_option_password_protected_status', array( $this, 'allow_administrators' ) ); add_filter( 'pre_option_password_protected_status', array( $this, 'allow_users' ) ); + add_filter( 'rest_authentication_errors', array( $this, 'only_allow_logged_in_rest_access' ) ); add_action( 'init', array( $this, 'compat' ) ); add_action( 'password_protected_login_messages', array( $this, 'login_messages' ) ); add_action( 'login_enqueue_scripts', array( $this, 'load_theme_stylesheet' ), 5 ); add_shortcode( 'password_protected_logout_link', array( $this, 'logout_link_shortcode' ) ); + include_once( dirname( __FILE__ ) . '/admin/admin-bar.php' ); + if ( is_admin() ) { include_once( dirname( __FILE__ ) . '/admin/admin-caching.php' ); @@ -242,6 +245,17 @@ public function get_allowed_ip_addresses() { } + /** + * Allow the remember me function + * + * @return. boolean + */ + public function allow_remember_me() { + + return (bool) get_option( 'password_protected_remember_me' ); + + } + /** * Encrypt Password * @@ -288,7 +302,13 @@ public function maybe_process_login() { // If correct password... if ( ( hash_equals( $pwd, $this->encrypt_password( $password_protected_pwd ) ) && $pwd != '' ) || apply_filters( 'password_protected_process_login', false, $password_protected_pwd ) ) { - $this->set_auth_cookie(); + $remember = isset( $_REQUEST['password_protected_rememberme'] ) ? boolval( $_REQUEST['password_protected_rememberme'] ) : false; + + if ( ! $this->allow_remember_me() ) { + $remember = false; + } + + $this->set_auth_cookie( $remember ); $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : ''; $redirect_to = apply_filters( 'password_protected_login_redirect', $redirect_to ); @@ -548,15 +568,19 @@ public function generate_auth_cookie( $expiration, $scheme = 'auth' ) { public function parse_auth_cookie( $cookie = '', $scheme = '' ) { if ( empty( $cookie ) ) { + $cookie_name = $this->cookie_name(); - if ( empty( $_COOKIE[$cookie_name] ) ) { + if ( empty( $_COOKIE[ $cookie_name ] ) ) { return false; } - $cookie = $_COOKIE[$cookie_name]; + + $cookie = $_COOKIE[ $cookie_name ]; + } $cookie_elements = explode( '|', $cookie ); + if ( count( $cookie_elements ) != 3 ) { return false; } @@ -578,9 +602,11 @@ public function parse_auth_cookie( $cookie = '', $scheme = '' ) { public function set_auth_cookie( $remember = false, $secure = '') { if ( $remember ) { - $expiration = $expire = current_time( 'timestamp' ) + apply_filters( 'password_protected_auth_cookie_expiration', 1209600, $remember ); + $expiration_time = apply_filters( 'password_protected_auth_cookie_expiration', get_option( 'password_protected_remember_me_lifetime', 14 ) * DAY_IN_SECONDS, $remember ); + $expiration = $expire = current_time( 'timestamp' ) + $expiration_time; } else { - $expiration = current_time( 'timestamp' ) + apply_filters( 'password_protected_auth_cookie_expiration', 172800, $remember ); + $expiration_time + apply_filters( 'password_protected_auth_cookie_expiration', DAY_IN_SECONDS * 20, $remember ); + $expiration = current_time( 'timestamp' ) + $expiration_time; $expire = 0; } @@ -684,9 +710,9 @@ public function login_messages() { $severity = $this->errors->get_error_data( $code ); foreach ( $this->errors->get_error_messages( $code ) as $error ) { if ( 'message' == $severity ) { - $messages .= ' ' . $error . "
\n"; + $messages .= $error . '
'; } else { - $errors .= ' ' . $error . "
\n"; + $errors .= $error . '
'; } } } @@ -764,4 +790,21 @@ static function is_plugin_supported() { } + /** + * Check whether a given request has permissions + * + * @param WP_REST_Request $access Full details about the request. + * @return WP_Error|boolean + */ + public function only_allow_logged_in_rest_access( $access ) { + + // If user is not logged in + if ( ! $this->is_user_logged_in() && ! (bool) get_option( 'password_protected_rest' ) ) {die(); + return new WP_Error( 'rest_cannot_access', __( 'Only authenticated users can access the REST API.', 'password-protected' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return $access; + + } + } diff --git a/readme.txt b/readme.txt index 67bb5c4..4d312ab 100644 --- a/readme.txt +++ b/readme.txt @@ -2,10 +2,10 @@ Contributors: husobj Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DXRJDNCMK9U3N Tags: password, protect, password protect, login -Requires at least: 3.5 -Tested up to: 4.8 +Requires at least: 3.9 +Tested up to: 4.9.6 Requires PHP: 5.6 -Stable tag: 2.1 +Stable tag: 2.2 License: GPLv2 or later A very simple way to quickly password protect your WordPress site with a single password. @@ -82,7 +82,12 @@ More instructions can be found at [wp-translations.org](http://wp-translations.o == Changelog == -= Unreleased = += 2.2 = +* Added admin bar icon to indicate wether password protection is enabled/disabled. +* Option to show "Remember me" checkbox. Props [Christian Güdel](https://github.com/cguedel). +* REST API access disabled if password not entered. +* Admin option to allow REST API access. +* More robust checking of password hashes. = 2.1 = * Update caching notes for WP Engine and W3 Total Cache plugin. @@ -187,6 +192,9 @@ More instructions can be found at [wp-translations.org](http://wp-translations.o == Upgrade Notice == += 2.2 = +Added admin bar icon to indicate wether password protection is enabled/disabled and disable REST API access (admin option to allow). + = 2.1 = Update caching notes for WP Engine and W3 Total Cache plugin. diff --git a/theme/password-protected-login.php b/theme/password-protected-login.php index 5125859..491ddf4 100644 --- a/theme/password-protected-login.php +++ b/theme/password-protected-login.php @@ -107,9 +107,13 @@ function shake(id,a,d){c=a.shift();s(id,c);if(a.length>0){setTimeout(function(){

- + + allow_remember_me() ) : ?> +

+ +

+ +