diff --git a/.github/workflows/php-coding-standards.yml b/.github/workflows/php-coding-standards.yml index 8617dab..b7a50c9 100644 --- a/.github/workflows/php-coding-standards.yml +++ b/.github/workflows/php-coding-standards.yml @@ -48,5 +48,5 @@ jobs: run: | export PATH=$HOME/.composer/vendor/bin:$PATH composer run lint -- --report=checkstyle - # Also show warnings as PR annotations (non-blocking) + # Errors (including EscapeOutput) fail the job; remaining Security sniffs stay warnings vendor/bin/phpcs --standard=./ruleset.xml --extensions=php --error-severity=0 . --report=checkstyle || true diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index cf8cbc8..9b5f40f 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -68,10 +68,15 @@ jobs: cp -r /tmp/wordpress-develop/tests/phpunit/* /tmp/wordpress-tests-lib/ if [ "${{ matrix.wp-version }}" = "latest" ]; then - wget -O /tmp/wordpress.tar.gz https://wordpress.org/latest.tar.gz + WP_URL="https://wordpress.org/latest.tar.gz" else - wget -O /tmp/wordpress.tar.gz https://wordpress.org/wordpress-${{ matrix.wp-version }}.tar.gz + WP_URL="https://wordpress.org/wordpress-${{ matrix.wp-version }}.tar.gz" fi + for i in 1 2 3 4 5; do + wget -nv -O /tmp/wordpress.tar.gz "$WP_URL" && break + echo "Download attempt $i failed, retrying in $((i * 15))s..." + sleep $((i * 15)) + done tar -xzf /tmp/wordpress.tar.gz -C /tmp/ } diff --git a/aryo-activity-log.php b/aryo-activity-log.php index 6391310..6dab52a 100644 --- a/aryo-activity-log.php +++ b/aryo-activity-log.php @@ -35,7 +35,6 @@ include( 'classes/class-aal-settings.php' ); include( 'classes/class-aal-api.php' ); include( 'classes/class-aal-hooks.php' ); -include( 'classes/class-aal-notifications.php' ); include( 'classes/class-aal-export.php' ); include( 'classes/class-aal-privacy.php' ); include( 'classes/abstract-class-aal-exporter.php' ); @@ -76,11 +75,6 @@ final class AAL_Main { */ public $api; - /** - * @var \AAL_Notifications - */ - public $notifications; - /** * Construct */ @@ -91,7 +85,6 @@ protected function __construct() { $this->hooks = new AAL_Hooks(); $this->settings = new AAL_Settings(); $this->api = new AAL_API(); - $this->notifications = new AAL_Notifications(); new AAL_Export(); new AAL_Privacy(); @@ -112,10 +105,12 @@ protected function __construct() { public function __clone() { _doing_it_wrong( __FUNCTION__, - sprintf( - /* translators: %s: Class name. */ - __( 'Cloning instances of the singleton "%s" class is forbidden.', 'aryo-activity-log' ), - get_class( $this ) + esc_html( + sprintf( + /* translators: %s: Class name. */ + __( 'Cloning instances of the singleton "%s" class is forbidden.', 'aryo-activity-log' ), + get_class( $this ) + ) ), '2.0.7' ); @@ -130,10 +125,12 @@ public function __clone() { public function __wakeup() { _doing_it_wrong( __FUNCTION__, - sprintf( - /* translators: %s: Class name. */ - __( 'Unserializing instances of the singleton "%s" class is forbidden.', 'aryo-activity-log' ), - get_class( $this ) + esc_html( + sprintf( + /* translators: %s: Class name. */ + __( 'Unserializing instances of the singleton "%s" class is forbidden.', 'aryo-activity-log' ), + get_class( $this ) + ) ), '2.0.7' ); diff --git a/assets/js/settings.js b/assets/js/settings.js deleted file mode 100644 index 21d797f..0000000 --- a/assets/js/settings.js +++ /dev/null @@ -1,123 +0,0 @@ -'use strict'; - -jQuery( function( $ ) { - var AAL = { - $wrapper: {}, - $container: {}, - conter: 0, - - init: function () { - var _this = this; - - AAL.$wrapper = $( ".aal-notifier-settings" ); - AAL.$container = $( "ul", AAL.$wrapper ); - - AAL.counter = AAL.$container.children().length; - - // check if there's only one option - if ( 1 === AAL.counter ) { - var $temp_el = AAL.$container.children().first(); - // check if the "value" select box has no options - if ( 0 === $temp_el.find( ".aal-value option" ).length ) { - // click the button with a timeout. Note that this is a hack that will need - // to be solved server-side - setTimeout( function () { - $temp_el.find( ".aal-category" ).change(); - }, 300 ); - } - } - - // when the "add" button is clicked - AAL.$container.on( 'click', '.aal-new-rule', function ( e ) { - e.preventDefault(); - _this.addRule( $( this ).closest( 'li' ) ); - }); - - AAL.$container.on( 'click', '.aal-delete-rule', function ( e ) { - e.preventDefault(); - - // do not delete item if it's the only one left in the list - if ( 1 === AAL.$container.children().length ) { - return; - } - - _this.deleteRule( $( this ).closest( 'li' ) ); - }); - - // handle change on action category selectbox - AAL.$container.on( 'change', '.aal-category', function ( e ) { - e.preventDefault(); - - var $select = $( this ), - $siblings = $select.siblings( "select" ); - - // disable all selectboxes to prevent multiple calls - $siblings.filter( "select" ).prop( 'disabled', true ); - - // grab live data via AJAX - var data = _this.getData( $select.val(), function ( d ) { - var $target = $siblings.filter( '.aal-value' ); - $target.empty(); // clear so we can insert fresh data - - $.each( d.data, function ( k, v ) { - $target.append( $( "', __( 'All Topics', 'aryo-activity-log' ) ); - echo implode( '', $output ); echo ''; } @@ -697,13 +706,16 @@ public function extra_tablenav( $which ) { if ( ! isset( $_REQUEST['showaction'] ) ) $_REQUEST['showaction'] = ''; - $output = array(); - foreach ( $actions as $action ) - $output[] = sprintf( '', $action->action, selected( $_REQUEST['showaction'], $action->action, false ), $this->get_action_label( $action->action ) ); - echo ''; } @@ -740,7 +752,7 @@ public function extra_tablenav( $which ) { foreach ( $filters as $filter ) { if ( ! empty( $_REQUEST[ $filter ] ) ) { - echo '' . __( 'Reset Filters', 'aryo-activity-log' ) . ''; + echo '' . esc_html__( 'Reset Filters', 'aryo-activity-log' ) . ''; break; } } @@ -881,8 +893,8 @@ public function search_box( $text, $input_id ) { $input_id = $input_id . '-search-input'; ?> get_list_table()->prepare_items(); + $page_slug = isset( $_REQUEST['page'] ) ? sanitize_key( wp_unslash( $_REQUEST['page'] ) ) : 'activity-log-page'; ?>
-

+

- + get_list_table()->display(); ?>
diff --git a/classes/class-aal-api.php b/classes/class-aal-api.php index 7996200..3ce6d2b 100644 --- a/classes/class-aal-api.php +++ b/classes/class-aal-api.php @@ -75,7 +75,7 @@ protected function _get_ip_address() { $visitor_ip_address = ''; if ( ! empty( $_SERVER[ $header_key ] ) ) { - $visitor_ip_address = $_SERVER[ $header_key ]; + $visitor_ip_address = sanitize_text_field( wp_unslash( $_SERVER[ $header_key ] ) ); } $remote_address = apply_filters( 'aal_get_ip_address', $visitor_ip_address ); diff --git a/classes/class-aal-maintenance.php b/classes/class-aal-maintenance.php index 372c2d7..71bb51c 100644 --- a/classes/class-aal-maintenance.php +++ b/classes/class-aal-maintenance.php @@ -242,7 +242,7 @@ public static function upgrade_notice() { public static function handle_manual_upgrade() { if ( ! current_user_can( 'manage_options' ) ) { - wp_die( __( 'You do not have sufficient permissions to access this page.', 'aryo-activity-log' ) ); + wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'aryo-activity-log' ) ); } check_admin_referer( 'aal_run_db_upgrade' ); diff --git a/classes/class-aal-notifications.php b/classes/class-aal-notifications.php deleted file mode 100644 index 893be4f..0000000 --- a/classes/class-aal-notifications.php +++ /dev/null @@ -1,306 +0,0 @@ -get_enabled_handlers(); - - // if we can't find any enabled event handlers, bail. - if ( empty( $enabled_handlers ) ) - return; - - // calculate if this type event is set in the rules - $options = AAL_Main::instance()->settings->get_options(); - - // if there are no rules set, bail. - if ( empty( $options['notification_rules'] ) || ! is_array( $options['notification_rules'] ) ) - return; - - $notification_matched_rules = array(); - - // loop through the set of rules, and figure out if this current action meets a set rule - foreach ( $options['notification_rules'] as $notification_rule ) { - list( $n_key, $n_condition, $n_value ) = array_values( $notification_rule ); - - switch ( $n_key ) { - case 'action-type': - if ( $n_value == $args['object_type'] ) - $notification_matched_rules[] = $notification_rule; - break; - } - } - - // did we find any matches? if not, let's pretend as if nothing has happened here ;) - if ( ! empty( $notification_matched_rules ) ) { - // cycle through enabled handlers and trigger them - foreach ( $enabled_handlers as $enabled_handler ) { - $enabled_handler->trigger( $args ); - } - } - } - - public function get_object_types() { - // TODO: It's need to be integration from the plugin - $opts = apply_filters( - 'aal_notification_get_object_types', - array( - 'Core', - 'Export', - 'Posts', - 'Taxonomies', - 'Users', - 'Options', - 'Attachments', - 'Plugins', - 'Widgets', - 'Themes', - 'Menus', - 'Comments', - - // BC - 'Post', - 'Taxonomy', - 'User', - 'Plugin', - 'Widget', - 'Theme', - 'Menu', - ) - ); - - return array_combine( $opts, $opts ); - } - - public function get_actions() { - // TODO: It's need to be integration from the plugin - $opts = apply_filters( - 'aal_notification_get_actions', - array( - 'created', - 'deleted', - 'updated', - 'trashed', - 'untrashed', - 'spammed', - 'unspammed', - 'downloaded', - 'installed', - 'uploaded', - 'activated', - 'deactivated', - 'accessed', - 'file_updated', - 'logged_in', - 'logged_out', - 'failed_login', - ) - ); - $ready = array(); - - // make key => value pairs (where slug in key) - foreach ( $opts as $opt ) { - $ready[ $opt ] = ucwords( str_replace( '_', ' ', __( $opt, 'aryo-activity-log' ) ) ); - } - - return $ready; - } - - /** - * Returns values for the dropdown in the settings page (the last dropdown in each conditions row) - * - * @param string $row_key type - * @return array - */ - public function get_settings_dropdown_values( $row_key ) { - $results = array(); - - /** - * @todo allow this switch to be extensible by other plugins (see example) - */ - switch ( $row_key ) { - case 'user': - // cache all data in case we need the same data twice on the same/upcoming pageloads - if ( false === ( $results = wp_cache_get( $cache_key = 'notifications-users', 'aal' ) ) ) { - // get all users - $all_users = get_users(); - $preped_users = array(); - - // prepare users - foreach ( $all_users as $user ) { - $user_role = $user->roles; - - // if user has no role (shouldn't happen, but just in case) - if ( empty( $user_role ) ) - continue; - - $user_role_obj = get_role( $user_role[0] ); - $user_role_name = isset( $user_role_obj->name ) ? $user_role_obj->name : $user_role[0]; - - $preped_users[ $user->ID ] = apply_filters( 'aal_notifications_user_format', sprintf( '%s - %s (ID #%d)', $user->display_name, $user_role_name, $user->ID ), $user ); - } - - wp_cache_set( $cache_key, $results = $preped_users, 'aal' ); // no need for expiration time - } - break; - - case 'action-type': - $results = $this->get_object_types(); - break; - - case 'action-value': - $results = $this->get_actions(); - break; - - default: - // @todo allow plugins to extend and handle custom field types - $results = apply_filters( 'aal_settings_dropdown_values', $results, $row_key ); - break; - } - - return $results; - } - - /** - * Returns a list of handlers, in a key-value format. - * Key holds the classname, value holds the name of the transport. - */ - public function get_handlers() { - if ( empty( $this->handlers ) || ! did_action( 'aal_load_notification_handlers' ) ) - return array(); - - $handlers = array(); - - foreach ( $this->handlers as $handler ) { - $handler_obj = $this->handlers_loaded[ $handler ]; - - // if we got the name of the handler, use it. otherwise, use the classname. - $handler_name = isset( $handler_obj->name ) ? $handler_obj->name : $handler; - - $handlers[ $handler_obj->id ] = $handler_name; - } - - return $handlers; - } - - /** - * Returns a handler object - * - * @param string $id - * @return AAL_Notification_Base|bool - */ - public function get_handler_object( $id ) { - return isset( $this->handlers_loaded[ $id ] ) ? $this->handlers_loaded[ $id ] : false; - } - - /** - * Returns all available handlers - * @return array - */ - public function get_available_handlers() { - $handlers = array(); - - foreach ( $this->handlers_loaded as $handler_classname => $handler_obj ) { - $handlers[ $handler_obj->id ] = $handler_obj; - } - - return apply_filters( 'aal_available_handlers', $handlers ); - } - - /** - * Returns the active handlers that were activated through the settings page - * - * @return array - */ - public function get_enabled_handlers() { - $enabled = array(); - $options = AAL_Main::instance()->settings->get_options(); - - foreach ( $this->get_available_handlers() as $id => $handler_obj ) { - // make sure handler is active - if ( isset( $options['notification_handlers'][ $id ] ) && 1 == $options['notification_handlers'][ $id ] ) { - $enabled[ $id ] = $handler_obj; - } - } - - return $enabled; - } - - /** - * Runs during aal_load_notification_handlers, - * includes the necessary files to register default notification handlers. - */ - public function load_default_handlers() { - $default_handlers = apply_filters( 'aal_default_addons', array( - 'email' => $this->get_default_handler_path( 'class-aal-notification-email.php' ), - ) ); - - foreach ( $default_handlers as $filename ) - include_once $filename; - } - - /** - * Returns path to notification handler file - * - * @param string $filename - * @return string - */ - public function get_default_handler_path( $filename ) { - return plugin_dir_path( ACTIVITY_LOG__FILE__ ) . "notifications/$filename"; - } - - /** - * Fired before $this->init() - * - * @todo maybe check $classname's inheritance tree and signal if it's not a AAL_Notification_Base - */ - public function load_handlers() { - do_action( 'aal_load_notification_handlers' ); - - foreach ( $this->handlers as $handler_classname ) { - if ( class_exists( $handler_classname ) ) { - $obj = new $handler_classname; - - // is this handler extending AAL_Notification_Base? - if ( ! is_a( $obj, 'AAL_Notification_Base' ) ) - continue; - - $this->handlers_loaded[ $handler_classname ] = $obj; - } - } - } - - /** - * Registers a handler class, which is then loaded in $this->load_handlers - * - * @param string $classname The name of the class to create an instance for - * @return bool - */ - public function register_handler( $classname ) { - if ( ! class_exists( $classname ) ) { - trigger_error( __( 'The AAL notification handler you are trying to register does not exist.', 'aryo-activity-log' ) ); - return false; - } - - $this->handlers[] = $classname; - return true; - } -} diff --git a/classes/class-aal-settings.php b/classes/class-aal-settings.php index 1e8bc7e..ed72167 100644 --- a/classes/class-aal-settings.php +++ b/classes/class-aal-settings.php @@ -15,7 +15,6 @@ public function __construct() { add_filter( 'plugin_action_links_' . ACTIVITY_LOG_BASE, array( &$this, 'plugin_action_links' ) ); add_action( 'wp_ajax_aal_reset_items', array( &$this, 'ajax_aal_reset_items' ) ); - add_action( 'wp_ajax_aal_get_properties', array( &$this, 'ajax_aal_get_properties' ) ); } public function init() { @@ -59,7 +58,6 @@ public function action_admin_menu() { * @since 1.0 */ public function scripts_n_styles() { - wp_enqueue_script( 'aal-settings', plugins_url( 'assets/js/settings.js', ACTIVITY_LOG__FILE__ ), array( 'jquery' ) ); wp_enqueue_style( 'aal-settings', plugins_url( 'assets/css/settings.css', ACTIVITY_LOG__FILE__ ) ); } @@ -182,60 +180,6 @@ public function register_settings() { } break; - case 'notifications': - // Email Notifications Settings - add_settings_section( - 'email_notifications', // ID used to identify this section and with which to register options - __( 'Notifications', 'aryo-activity-log' ), // Title to be displayed on the administration page - array( 'AAL_Settings_Fields', 'email_notifications_section_header' ), // Callback used to render the description of the section - $this->slug // Page on which to add this section of options - ); - - add_settings_field( - 'notification_rules', - __( 'Notification Events', 'aryo-activity-log' ), - array( 'AAL_Settings_Fields', 'email_notification_buffer_field' ), - $this->slug, - 'email_notifications', - array( - 'id' => 'notification_rules', - 'page' => $this->slug, - 'desc' => __( 'Maximum number of days to keep activity log. Leave blank to keep activity log forever (not recommended).', 'aryo-activity-log' ), - ) - ); - - $notification_handlers = AAL_Main::instance()->notifications->get_available_handlers(); - $enabled_notification_handlers = AAL_Main::instance()->settings->get_option( 'notification_handlers' ); - - // Loop through custom notification handlers - foreach ( $notification_handlers as $handler_id => $handler_obj ) { - if ( ! is_object( $handler_obj ) ) - continue; - - add_settings_section( - "notification_$handler_id", - $handler_obj->name, - array( $handler_obj, '_settings_section_callback' ), - $this->slug - ); - - add_settings_field( - "notification_handler_{$handler_id}_enabled", - __( 'Enable?', 'aryo-activity-log' ), - array( $handler_obj, '_settings_enabled_field_callback' ), - $this->slug, - "notification_$handler_id", - array( - 'id' => 'notification_transport', - 'page' => $this->slug, - 'name' => "{$this->slug}[notification_handlers][{$handler_id}]", - 'value' => isset( $enabled_notification_handlers[ $handler_id ] ) && ( 1 == $enabled_notification_handlers[ $handler_id ] ), - ) - ); - - $handler_obj->settings_fields(); - } - break; } } @@ -260,13 +204,6 @@ private function menu_print_tabs() { 'general' => __( 'General', 'aryo-activity-log' ), ); - $enabled_notification_handlers = AAL_Main::instance()->settings->get_option( 'notification_handlers' ); - - // Hide notifications tab if not used before.. - if ( ! empty( $enabled_notification_handlers ) ) { - $sections['notifications'] = __( 'Notifications', 'aryo-activity-log' ); - } - $sections = apply_filters( 'aal_setup_sections', $sections ); if ( 1 >= count( $sections ) ) { @@ -276,7 +213,7 @@ private function menu_print_tabs() { foreach ( $sections as $section_key => $section_caption ) { $active = $current_section === $section_key ? 'nav-tab-active' : ''; $url = add_query_arg( 'aal_section', $section_key ); - echo '' . esc_html( $section_caption ) . ''; + echo '' . esc_html( $section_caption ) . ''; } } @@ -297,7 +234,7 @@ public function display_settings_page() {
-

+

@@ -316,7 +253,7 @@ public function display_settings_page() { public function admin_notices() { switch ( filter_input( INPUT_GET, 'message' ) ) { case 'data_erased': - printf( '

%s

', __( 'All activities have been successfully deleted.', 'aryo-activity-log' ) ); + printf( '

%s

', esc_html__( 'All activities have been successfully deleted.', 'aryo-activity-log' ) ); break; } } @@ -327,7 +264,7 @@ public function admin_footer() {