diff --git a/README.md b/README.md index 9f1cdac..555d3ca 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **Tags:** custom sidebar, sidebar manager, custom widget areas, widgets, conditional sidebar **Requires at least:** 4.0 **Tested up to:** 6.7 -**Stable tag:** 1.1.8 +**Stable tag:** 1.1.9 **License:** GPLv2 or later **License URI:** https://www.gnu.org/licenses/gpl-2.0.html @@ -53,6 +53,9 @@ Other plugins we found are heavy with ugly interface, non supported, developed o ## Changelog ## +### 1.1.9 ### +- Fix: Fixed security issue from astra-notice library. + ### 1.1.8 ### - Fix: Sidebar rendering issue where specifying "All Singulars from {{category}}" resulted in incorrect display of "{{category}} - Category" after saving. diff --git a/lib/notices/class-astra-notices.php b/lib/notices/class-astra-notices.php index 8a00bf9..9f9940c 100644 --- a/lib/notices/class-astra-notices.php +++ b/lib/notices/class-astra-notices.php @@ -1,18 +1,11 @@ Create custom close notice link in the notice markup. E.g. - * `` - * It close the notice for 30 days. - * - * @package Astra Sites - * @since 1.4.0 + * @package Astra Notices + * @since 1.0.0 */ if ( ! defined( 'ABSPATH' ) ) { @@ -24,7 +17,7 @@ /** * Astra_Notices * - * @since 1.4.0 + * @since 1.0.0 */ class Astra_Notices { @@ -33,16 +26,16 @@ class Astra_Notices { * * @access private * @var array Notices. - * @since 1.4.0 + * @since 1.0.0 */ - private static $version = '1.1.5'; + private static $version = '1.1.14'; /** * Notices * * @access private * @var array Notices. - * @since 1.4.0 + * @since 1.0.0 */ private static $notices = array(); @@ -51,14 +44,14 @@ class Astra_Notices { * * @access private * @var object Class object. - * @since 1.4.0 + * @since 1.0.0 */ private static $instance; /** * Initiator * - * @since 1.4.0 + * @since 1.0.0 * @return object initialized object of class. */ public static function get_instance() { @@ -71,7 +64,7 @@ public static function get_instance() { /** * Constructor * - * @since 1.4.0 + * @since 1.0.0 */ public function __construct() { add_action( 'admin_notices', array( $this, 'show_notices' ), 30 ); @@ -83,12 +76,12 @@ public function __construct() { /** * Filters and Returns a list of allowed tags and attributes for a given context. * - * @param Array $allowedposttags Array of allowed tags. - * @param String $context Context type (explicit). - * @since 1.4.0 - * @return Array + * @param array $allowedposttags array of allowed tags. + * @param string $context Context type (explicit). + * @since 1.0.0 + * @return array */ - public function add_data_attributes( $allowedposttags, $context ) { + public function add_data_attributes( $allowedposttags, $context ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed $allowedposttags['a']['data-repeat-notice-after'] = true; return $allowedposttags; @@ -97,37 +90,69 @@ public function add_data_attributes( $allowedposttags, $context ) { /** * Add Notice. * - * @since 1.4.0 + * @since 1.0.0 * @param array $args Notice arguments. * @return void */ public static function add_notice( $args = array() ) { self::$notices[] = $args; + + if ( ! isset( $args['id'] ) ) { + return; + } + + $notice_id = sanitize_key( $args['id'] ); // Notice ID. + $notices = get_option( 'allowed_astra_notices', array() ); + if ( ! in_array( $notice_id, $notices, true ) ) { + $notices[] = $notice_id; // Add notice id to the array. + update_option( 'allowed_astra_notices', $notices ); // Update the option. + } } /** * Dismiss Notice. * - * @since 1.4.0 + * @since 1.0.0 * @return void */ public function dismiss_notice() { + $notice_id = ( isset( $_POST['notice_id'] ) ) ? sanitize_key( $_POST['notice_id'] ) : ''; + $repeat_notice_after = ( isset( $_POST['repeat_notice_after'] ) ) ? absint( $_POST['repeat_notice_after'] ) : ''; + $nonce = ( isset( $_POST['nonce'] ) ) ? sanitize_key( $_POST['nonce'] ) : ''; + $notice = $this->get_notice_by_id( $notice_id ); + $capability = isset( $notice['capability'] ) ? $notice['capability'] : 'manage_options'; - if ( ! apply_filters( 'astra_notices_user_cap_check', current_user_can( 'manage_options' ) ) ) { + if ( ! apply_filters( 'astra_notices_user_cap_check', current_user_can( $capability ) ) ) { return; } - $notice_id = ( isset( $_POST['notice_id'] ) ) ? sanitize_key( $_POST['notice_id'] ) : ''; - $repeat_notice_after = ( isset( $_POST['repeat_notice_after'] ) ) ? absint( $_POST['repeat_notice_after'] ) : ''; - $nonce = ( isset( $_POST['nonce'] ) ) ? sanitize_key( $_POST['nonce'] ) : ''; + $allowed_notices = get_option( 'allowed_astra_notices', array() ); // Get allowed notices. + + // Define restricted user meta keys. + $wp_default_meta_keys = array( + 'wp_capabilities', + 'wp_user_level', + 'wp_user-settings', + 'account_status', + 'session_tokens', + ); + + // if $notice_id does not start with astra-notices-id and notice_id is not from the allowed notices, then return. + if ( strpos( $notice_id, 'astra-notices-id-' ) !== 0 && ( ! in_array( $notice_id, $allowed_notices, true ) ) ) { + return; + } if ( false === wp_verify_nonce( $nonce, 'astra-notices' ) ) { - wp_send_json_error( esc_html_e( 'WordPress Nonce not validated.', 'sidebar-manager' ) ); + wp_send_json_error( esc_html_e( 'WordPress Nonce not validated.' ) ); } // Valid inputs? if ( ! empty( $notice_id ) ) { + if ( in_array( $notice_id, $wp_default_meta_keys, true ) ) { + wp_send_json_error( esc_html_e( 'Invalid notice ID.' ) ); + } + if ( ! empty( $repeat_notice_after ) ) { set_transient( $notice_id, true, $repeat_notice_after ); } else { @@ -143,11 +168,12 @@ public function dismiss_notice() { /** * Enqueue Scripts. * - * @since 1.4.0 + * @since 1.0.0 * @return void */ public function enqueue_scripts() { - wp_register_script( 'astra-notices', self::_get_uri() . 'notices.js', array( 'jquery' ), self::$version, true ); + wp_register_style( 'astra-notices', self::get_url() . 'notices.css', array(), self::$version ); + wp_register_script( 'astra-notices', self::get_url() . 'notices.js', array( 'jquery' ), self::$version, true ); wp_localize_script( 'astra-notices', 'astraNotices', @@ -158,32 +184,67 @@ public function enqueue_scripts() { } /** - * Rating priority sort + * Sort the notices based on the given priority of the notice. + * This function is called from usort() * * @since 1.5.2 - * @param array $array1 array one. - * @param array $array2 array two. + * @param array $notice_1 First notice. + * @param array $notice_2 Second Notice. * @return array */ - public function sort_notices( $array1, $array2 ) { - if ( ! isset( $array1['priority'] ) ) { - $array1['priority'] = 10; + public function sort_notices( $notice_1, $notice_2 ) { + if ( ! isset( $notice_1['priority'] ) ) { + $notice_1['priority'] = 10; } - if ( ! isset( $array2['priority'] ) ) { - $array2['priority'] = 10; + if ( ! isset( $notice_2['priority'] ) ) { + $notice_2['priority'] = 10; } - return $array1['priority'] - $array2['priority']; + return $notice_1['priority'] - $notice_2['priority']; } /** - * Notice Types + * Get all registered notices. + * Since v1.1.8 it is recommended to register the notices on * - * @since 1.4.0 + * @return array|null + */ + private function get_notices() { + usort( self::$notices, array( $this, 'sort_notices' ) ); + + return self::$notices; + } + + /** + * Get notice by notice_id + * + * @param string $notice_id Notice id. + * + * @return array notice based on the notice id. + */ + private function get_notice_by_id( $notice_id ) { + if ( empty( $notice_id ) ) { + return array(); + } + + $notices = $this->get_notices(); + $notice = wp_list_filter( + $notices, + array( + 'id' => $notice_id, + ) + ); + + return ( ! empty( $notice ) && isset( $notice[0] ) ) ? $notice[0] : array(); + } + + /** + * Display the notices in the WordPress admin. + * + * @since 1.0.0 * @return void */ public function show_notices() { - $defaults = array( 'id' => '', // Optional, Notice ID. If empty it set `astra-notices-id-<$array-index>`. 'type' => 'info', // Optional, Notice type. Default `info`. Expected [info, warning, notice, error]. @@ -195,20 +256,22 @@ public function show_notices() { 'priority' => 10, // Priority of the notice. 'display-with-other-notices' => true, // Should the notice be displayed if other notices are being displayed from Astra_Notices. 'is_dismissible' => true, + 'capability' => 'manage_options', // User capability - This capability is required for the current user to see this notice. ); // Count for the notices that are rendered. $notices_displayed = 0; + $notices = $this->get_notices(); - // sort the array with priority. - usort( self::$notices, array( $this, 'sort_notices' ) ); - - foreach ( self::$notices as $key => $notice ) { - + foreach ( $notices as $key => $notice ) { $notice = wp_parse_args( $notice, $defaults ); - $notice['id'] = self::get_notice_id( $notice, $key ); + // Show notices only for users with `manage_options` cap. + if ( ! current_user_can( $notice['capability'] ) ) { + continue; + } + $notice['id'] = self::get_notice_id( $notice, $key ); $notice['classes'] = self::get_wrap_classes( $notice ); // Notices visible after transient expire. @@ -226,27 +289,26 @@ public function show_notices() { } } } - } /** - * Markup Notice. + * Render a notice. * - * @since 1.4.0 + * @since 1.0.0 * @param array $notice Notice markup. * @return void */ public static function markup( $notice = array() ) { - wp_enqueue_script( 'astra-notices' ); + wp_enqueue_style( 'astra-notices' ); do_action( 'astra_notice_before_markup' ); do_action( "astra_notice_before_markup_{$notice['id']}" ); ?> -
-
+
+
@@ -256,13 +318,12 @@ public static function markup( $notice = array() ) { do_action( "astra_notice_after_markup_{$notice['id']}" ); do_action( 'astra_notice_after_markup' ); - } /** - * Notice classes. + * Get wrapper classes for a notice. * - * @since 1.4.0 + * @since 1.0.0 * * @param array $notice Notice arguments. * @return array Notice wrapper classes. @@ -283,13 +344,13 @@ private static function get_wrap_classes( $notice ) { } /** - * Get Notice ID. + * Get HTML ID for a given notice. * - * @since 1.4.0 + * @since 1.0.0 * * @param array $notice Notice arguments. - * @param int $key Notice array index. - * @return string Notice id. + * @param int $key Notice array index. + * @return string HTML if for the notice. */ private static function get_notice_id( $notice, $key ) { if ( isset( $notice['id'] ) && ! empty( $notice['id'] ) ) { @@ -300,9 +361,9 @@ private static function get_notice_id( $notice, $key ) { } /** - * Is notice expired? + * Check if the notice is expires. * - * @since 1.4.0 + * @since 1.0.0 * * @param array $notice Notice arguments. * @return boolean @@ -335,26 +396,20 @@ private static function is_expired( $notice ) { } /** - * Get URI + * Get base URL for the astra-notices. * * @return mixed URL. */ - public static function _get_uri() { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore - $path = wp_normalize_path( dirname( __FILE__ ) ); - $theme_dir = wp_normalize_path( get_template_directory() ); - $plugin_dir = wp_normalize_path( WP_PLUGIN_DIR ); + public static function get_url() { + $path = wp_normalize_path( dirname( __FILE__ ) ); // phpcs:ignore Modernize.FunctionCalls.Dirname.FileConstant + $theme_dir = wp_normalize_path( get_template_directory() ); if ( strpos( $path, $theme_dir ) !== false ) { return trailingslashit( get_template_directory_uri() . str_replace( $theme_dir, '', $path ) ); - } elseif ( strpos( $path, $plugin_dir ) !== false ) { - return plugin_dir_url( __FILE__ ); - } elseif ( strpos( $path, dirname( plugin_basename( __FILE__ ) ) ) !== false ) { + } else { return plugin_dir_url( __FILE__ ); } - - return; // phpcs:ignore Squiz.PHP.NonExecutableCode.ReturnNotRequired } - } /** diff --git a/lib/notices/composer.json b/lib/notices/composer.json new file mode 100644 index 0000000..3d5717d --- /dev/null +++ b/lib/notices/composer.json @@ -0,0 +1,38 @@ +{ + "name": "brainstormforce/astra-notices", + "type": "wordpress-plugin", + "description": "Easily create admin notices", + "license": "GPL-3.0-or-later", + "authors": [ + { + "name": "Brainstorm Force", + "email": "hello@bsf.io" + } + ], + "require": { + "composer/installers": "^2.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2", + "phpcompatibility/phpcompatibility-wp": "2.1.4", + "phpunit/phpunit": "^9.0", + "wp-cli/dist-archive-command": "^2.0", + "wp-coding-standards/wpcs": "^3.0", + "wp-phpunit/wp-phpunit": "^6.0", + "roots/wordpress": "^6.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "config": { + "allow-plugins": { + "composer/installers": true, + "dealerdirect/phpcodesniffer-composer-installer": true, + "roots/wordpress-core-installer": true + } + }, + "minimum-stability": "stable", + "scripts": { + "format": "vendor/bin/phpcbf", + "lint": "vendor/bin/phpcs", + "test": "vendor/bin/phpunit" + } +} diff --git a/lib/notices/notices.css b/lib/notices/notices.css new file mode 100644 index 0000000..ce9e8a3 --- /dev/null +++ b/lib/notices/notices.css @@ -0,0 +1,39 @@ +.astra-review-notice-container { + display: flex; + align-items: center; + padding-top: 10px; +} + +.astra-review-notice-container .dashicons { + font-size: 1.4em; + padding-left: 10px; +} + +.astra-review-notice-container a { + padding-left: 5px; + text-decoration: none; +} + +.astra-review-notice-container .dashicons:first-child { + padding-left: 0; +} + +.astra-notice-container .notice-image img { + max-width: 90px; +} + +.astra-notice-container .notice-content .notice-heading { + padding-bottom: 5px; +} + +.astra-notice-container .notice-content { + margin-left: 15px; +} + +.astra-notice-container { + padding-top: 10px; + padding-bottom: 10px; + display: flex; + justify-content: left; + align-items: center; +} \ No newline at end of file diff --git a/package.json b/package.json index 6fa486a..119f79e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sidebar-manager", - "version": "1.1.8", + "version": "1.1.9", "main": "Gruntfile.js", "author": "Brainstorm Force", "devDependencies": { diff --git a/readme.txt b/readme.txt index 88fd738..27a4fad 100644 --- a/readme.txt +++ b/readme.txt @@ -54,6 +54,9 @@ Other plugins we found are heavy with ugly interface, non supported, developed o == Changelog == += 1.1.9 = +- Fix: Fixed security issue from astra-notice library. + = 1.1.8 = - Fix: Sidebar rendering issue where specifying "All Singulars from {{category}}" resulted in incorrect display of "{{category}} - Category" after saving. diff --git a/sidebar-manager.php b/sidebar-manager.php index 430ab52..607e052 100644 --- a/sidebar-manager.php +++ b/sidebar-manager.php @@ -3,7 +3,7 @@ * Plugin Name: Sidebar Manager * Plugin URI: http://www.brainstormforce.com * Description: This is the plugin to create custom siderbars to your site. - * Version: 1.1.8 + * Version: 1.1.9 * Author: Brainstorm Force * Author URI: https://www.brainstormforce.com/ * Text Domain: bsfsidebars @@ -25,7 +25,7 @@ define( 'BSF_SB_BASE', plugin_basename( BSF_SB_FILE ) ); define( 'BSF_SB_DIR', plugin_dir_path( BSF_SB_FILE ) ); define( 'BSF_SB_URL', plugins_url( '/', BSF_SB_FILE ) ); -define( 'BSF_SB_VER', '1.1.8' ); +define( 'BSF_SB_VER', '1.1.9' ); define( 'BSF_SB_PREFIX', 'bsf-sb' ); define( 'BSF_SB_POST_TYPE', 'bsf-sidebar' );