11 Commits

Author SHA1 Message Date
a5e4225261 prepare release of v1.6.0 2020-12-09 12:44:14 +01:00
1a621b8274 add PHP 8.0 to CI roster 2020-12-09 12:13:51 +01:00
f424909515 reduce redundancies for recurring matching loops
Referer, target and user agent filter share most of their logic
for different matching methods. We introduce a common routine for
all of them to not repeat ourselves. Passing a value extractor by
reference allows lazy evaluation (filter might be disabled) and
overrides for different cases (i.e. domain extractor for exact match).
2020-10-26 19:23:32 +01:00
a6cc821089 implement user agent filter
A new live-only filter block for user agent strings is now available.
It features the known exact, keyword and regular expression modes.
2020-10-26 19:23:32 +01:00
e5c30c2183 rename test class files to comply with PHPUnit 8.5+ conventions 2020-10-19 16:19:23 +02:00
2f8939b363 ui: correct label association for target matching method 2020-10-19 12:01:23 +02:00
06a7b1677a rename plugin to "Statify Filter"
The plugins purpose is to exclude or filter certain requests from
tracking by Statify. However the current name "Statify Blacklist" is not
actually inline with today's understanding of such terms. In WordPress
Core 5.5 the word "blacklist" among others has been replaced by more
precise wording where possible.

The term "filter" has been used in various places already and clearly
describes the behavior of this plugin. So we rename the plugin to
"Statify Filter" and rephrase front-end texts.

Plugin slug (permalink), textdomain and all public class and constant
names left untouched for now, to not introduce breaking changes at this
point. To be cleaned up with next major release.
2020-10-19 10:34:09 +02:00
af2d2c5142 docs: update Travis CI badge 2020-09-09 08:58:08 +02:00
c30f07e02f prepare release of 1.5.2 and declare WP 5.5 compatibility 2020-09-03 20:49:01 +02:00
cb61210685 minor (dev-)dependency updates 2020-09-03 20:49:01 +02:00
e4fd34d036 do not rely on WP core translation and add textdomain for all texts 2020-09-03 20:49:01 +02:00
13 changed files with 446 additions and 164 deletions

View File

@ -1,9 +1,9 @@
language: php
php:
- '5.6'
- '7.2'
- '7.3'
- '7.4'
- '8.0'
before_script:
- composer install
script:

View File

@ -1,38 +1,41 @@
[![Build Status](https://travis-ci.org/stklcode/statify-blacklist.svg?branch=master)](https://travis-ci.org/stklcode/statify-blacklist)
[![Build Status](https://travis-ci.com/stklcode/statify-blacklist.svg?branch=master)](https://travis-ci.com/stklcode/statify-blacklist)
[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=de.stklcode.web.wordpress.plugins%3Astatify-blacklist&metric=alert_status)](https://sonarcloud.io/dashboard?id=de.stklcode.web.wordpress.plugins%3Astatify-blacklist)
[![Packagist Version](https://img.shields.io/packagist/v/stklcode/statify-blacklist.svg)](https://packagist.org/packages/stklcode/statify-blacklist)
[![License](https://img.shields.io/badge/license-GPL%20v2-blue.svg)](https://github.com/stklcode/statify-blacklist/blob/master/LICENSE.md)
# Statify Blacklist #
# Statify Filter #
* Contributors: Stefan Kalscheuer
* Requires at least: 4.7
* Tested up to: 5.4
* Tested up to: 5.6
* Requires PHP: 5.5
* Stable tag: 1.5.1
* Stable tag: 1.6.0
* License: GPLv2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
## Description ##
A blacklist extension for the famous [Statify](https://wordpress.org/plugins/statify/) Wordpress plugin.
A filter extension for the famous [Statify](https://wordpress.org/plugins/statify/) Wordpress plugin.
This plugin adds a customizable blacklist to Statify to allow blocking of referer spam or internal interactions.
This plugin adds customizable filters to Statify to allow blocking of referer spam or internal interactions.
### Features ##
#### Referer Blacklist ####
#### Referer Filter ####
Add a list of domains (for simplicity only second-level, e.g. _example.com_ which blocks _everything.example.com_).
#### Target Blacklist ####
#### Target Filter ####
Add a list of target pages (e.g. _/test/page/_, _/?page_id=123_) that will be excluded from tracking.
#### IP Blacklist ####
#### IP Filter ####
Add a list of IP addresses or subnets (e.g. _192.0.2.123_, _198.51.100.0/24_, _2001:db8:a0b:12f0::/64_).
#### User Agent Filter ####
Add a list of (partial) user agent strings to exclude (e.g. _curl_, _my/bot_, _Firefox_).
#### CleanUp Database ####
Filters can be applied to data stored in database after modifying filter rules or for one-time clean-up.
#### Compatibility ####
This plugin requires Statify to be installed. The extension has been tested with Statify up to version 1.7
This plugin requires Statify to be installed. The extension has been tested with Statify up to version 1.8
The plugin is capable of handling multisite installations.
### Support & Contributions ###
@ -47,7 +50,7 @@ The plugin is capable of handling multisite installations.
## Installation ##
* If you dont know how to install a plugin for WordPress, [heres how](https://wordpress.org/support/article/managing-plugins/#installing-plugins).
* Make sure _Statify_ plugin is installed and active
* Goto _Settings_ -> _Statify Blacklist_ to configure the plugin
* Goto _Settings_ -> _Statify Filter_ to configure the plugin
### Requirements ###
* PHP 5.5 or above
@ -57,9 +60,9 @@ The plugin is capable of handling multisite installations.
## Frequently Asked Questions ##
### What is blocked by default? ###
Nothing. By default, all blacklists are empty and disabled. They can and have to be filled by the blog administrator.
Nothing. By default, all filters are empty and disabled. They can and have to be filled by the blog administrator.
A default blacklist is not provided, as the plugin itself is totally neutral. If you want to filter out referer spam,
A default filter is not provided, as the plugin itself is totally neutral. If you want to filter out referer spam,
visitors from search engines, just "false" referrers from 301 redirects or you own IP address used for testing only depends on you.
### Does the filter effect user experience? ###
@ -75,21 +78,43 @@ No. The privacy policy of _Statify_ is untouched. Data is only processed, not st
### Are regular expression filters possible? ###
Yes, it is. Just select regular expressions (case-sensitive or insensitive) as matching method instead of exact or keyword match.
### Why is IP filtering only available as live filter? ###
### Why is IP and User Agent filtering only available as live filter? ###
As you might know, _Statify_ does not store any personal information, including IP addresses in the database.
Because of this, an IP blacklist can only be applied while processing the request and not afterwards.
Because of this, these filters can only be applied while processing the request and not afterwards.
### Can whole IP subnet be blocked? ###
Yes. The plugin features subnet blacklists using CIDR notation.
For example _198.51.100.0/24_ blacklists all sources from _198.51.100.1_ to _198.51.100.254_.
Yes. The plugin features subnet filters using CIDR notation.
For example _198.51.100.0/24_ filters all sources from _198.51.100.1_ to _198.51.100.254_.
Same for IPv6 prefixes like _2001:db8:a0b:12f0::/64_.
## Screenshots ##
1. Statify Blacklist settings page
1. Statify Filter settings page
## Upgrade Notice ##
### 1.6.0 ###
The plugin has been renamed from _Statify Blacklist_ to _Statify Filter_.
This does not imply any changes in functionality, rather than using a better wording.
In addition, there is a new filter by User Agent along with some minor corrections.
This version should be compatible with latest WordPress 5.6.
## Changelog ##
### 1.6.0 / 09.12.2020 ###
Plugin renamed to _Statify Filter_.
* Minor accessibility fixes on settings page
* Introduced new user agent filter (#20)
* Declared compatibility with WordPress 5.6
### 1.5.2 / 03.09.2020 ###
* Minor translation updates
* Declared compatibility with WordPress 5.5
### 1.5.1 / 20.05.2020 ###
* Fix initialization on AJAX calls for _Statify_ 1.7 compatibility (#22)

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist Robo build script.
* Statify Filter Robo build script.
*
* This file contains the Robo tasks for building a distributable plugin package.
* Should not be included in final package.
@ -8,7 +8,7 @@
* @author Stefan Kalscheuer <stefan@stklcode.de>
*
* @package Statify_Blacklist
* @version 1.5.1
* @version 1.0.0
*/
use Robo\Exception\TaskException;

View File

@ -1,12 +1,12 @@
{
"name": "stklcode/statify-blacklist",
"version": "1.5.1",
"description": "A blacklist extension for the famous Statify WordPress plugin",
"version": "1.6.0",
"description": "A filter extension for the famous Statify WordPress plugin",
"keywords": [
"wordpress",
"plugin",
"statistics",
"blacklist"
"filter"
],
"license": "GPL-2.0-or-later",
"authors": [
@ -19,17 +19,17 @@
"type": "wordpress-plugin",
"require": {
"php": ">=5.5",
"composer/installers": "~1.7"
"composer/installers": "~1.9"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7",
"consolidation/robo": "^1.4",
"phpunit/phpunit": "*",
"phpunit/php-code-coverage": "*",
"slowprog/composer-copy-file": "~0.2",
"slowprog/composer-copy-file": "~0.3",
"squizlabs/php_codesniffer": "^3.5",
"phpcompatibility/php-compatibility": "^9.3",
"wp-coding-standards/wpcs": "^2.1"
"phpcompatibility/phpcompatibility-wp": "^2.1",
"wp-coding-standards/wpcs": "^2.3"
},
"scripts": {
"build": [

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist: StatifyBlacklist_Admin class
* Statify Filter: StatifyBlacklist_Admin class
*
* This file contains the derived class for the plugin's administration features.
*
@ -15,7 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
/**
* Statify Blacklist admin configuration.
* Statify Filter admin configuration.
*
* @since 1.0.0
*/
@ -137,7 +137,7 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
* @since 1.0.0
*/
public static function add_menu_page() {
$title = __( 'Statify Blacklist', 'statify-blacklist' );
$title = __( 'Statify Filter', 'statify-blacklist' );
if ( self::$multisite ) {
add_submenu_page(
'settings.php',
@ -209,7 +209,7 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
if ( STATIFYBLACKLIST_BASE === $file && current_user_can( 'manage_options' ) ) {
array_unshift(
$links,
sprintf( '<a href="%s">%s</a>', esc_attr( add_query_arg( 'page', 'statify-blacklist', $base ) ), __( 'Settings' ) )
sprintf( '<a href="%s">%s</a>', esc_attr( add_query_arg( 'page', 'statify-blacklist', $base ) ), __( 'Settings', 'statify-blacklist' ) )
);
}
@ -226,7 +226,7 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
public static function cleanup_database() {
// Check user permissions.
if ( ! current_user_can( 'manage_options' ) && ! ( defined( 'DOING_CRON' ) && DOING_CRON ) ) {
die( esc_html__( 'Are you sure you want to do this?' ) );
die( esc_html__( 'Are you sure you want to do this?', 'statify-blacklist' ) );
}
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist: StatifyBlacklist_System class
* Statify Filter: StatifyBlacklist_System class
*
* This file contains the derived class for the plugin's system operations.
*
@ -15,7 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
/**
* Statify Blacklist system configuration.
* Statify Filter system configuration.
*
* @since 1.0.0
*/

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist: StatifyBlacklist class
* Statify Filter: StatifyBlacklist class
*
* This file contains the plugin's base class.
*
@ -14,9 +14,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
/**
* Statify Blacklist.
*
* @since 1.0.0
* Statify Filter.
*/
class StatifyBlacklist {
@ -93,7 +91,10 @@ class StatifyBlacklist {
self::update_options();
// Add Filter to statify hook if enabled.
if ( 0 !== self::$options['referer']['active'] || 0 !== self::$options['target']['active'] || 0 !== self::$options['ip']['active'] ) {
if ( 0 !== self::$options['referer']['active'] ||
0 !== self::$options['target']['active'] ||
0 !== self::$options['ip']['active'] ||
0 !== self::$options['ua']['active'] ) {
add_filter( 'statify__skip_tracking', array( 'StatifyBlacklist', 'apply_blacklist_filter' ) );
}
@ -158,103 +159,42 @@ class StatifyBlacklist {
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => 0,
'blacklist' => array(),
),
'version' => self::VERSION_MAIN,
);
}
/**
* Apply the blacklist filter if active
* Apply the filter if active
*
* @since 1.0.0
*
* @return bool TRUE if referer matches blacklist.
* @return bool TRUE if referer matches filter.
*/
public static function apply_blacklist_filter() {
// Referer blacklist.
if ( isset( self::$options['referer']['active'] ) && 0 !== self::$options['referer']['active'] ) {
// Determine filter mode.
$mode = isset( self::$options['referer']['regexp'] ) ? intval( self::$options['referer']['regexp'] ) : 0;
// Get full referer string.
$referer = wp_get_raw_referer();
if ( ! $referer ) {
$referer = '';
}
switch ( $mode ) {
// Regular Expression filtering since 1.3.0.
case self::MODE_REGEX:
case self::MODE_REGEX_CI:
// Merge given regular expressions into one.
$regexp = self::regex(
array_keys( self::$options['referer']['blacklist'] ),
self::MODE_REGEX_CI === self::$options['referer']['regexp']
);
// Check blacklist (no return to continue filtering #12).
if ( 1 === preg_match( $regexp, $referer ) ) {
return true;
}
break;
// Keyword filter since 1.5.0 (#15).
case self::MODE_KEYWORD:
// Get blacklist.
$blacklist = self::$options['referer']['blacklist'];
foreach ( array_keys( $blacklist ) as $keyword ) {
if ( false !== strpos( strtolower( $referer ), strtolower( $keyword ) ) ) {
return true;
}
}
break;
// Standard domain filter.
default:
// Extract relevant domain parts.
$referer = wp_parse_url( $referer );
$referer = strtolower( ( isset( $referer['host'] ) ? $referer['host'] : '' ) );
// Get blacklist.
$blacklist = self::$options['referer']['blacklist'];
// Check blacklist.
if ( isset( $blacklist[ $referer ] ) ) {
return true;
}
}
// Referer filter.
if (
self::apply_single_filter(
self::$options['referer'],
array(
__CLASS__,
( ! isset( self::$options['referer']['regexp'] ) || self::MODE_NORMAL === self::$options['referer']['regexp'] ) ? 'get_referer_domain' : 'get_referer',
)
)
) {
return true;
}
// Target blacklist (since 1.4.0).
if ( isset( self::$options['target']['active'] ) && 0 !== self::$options['target']['active'] ) {
// Regular Expression filtering since 1.3.0.
if ( isset( self::$options['target']['regexp'] ) && 0 < self::$options['target']['regexp'] ) {
// Get full referer string.
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL ) : '/' );
// Merge given regular expressions into one.
$regexp = self::regex(
array_keys( self::$options['target']['blacklist'] ),
self::MODE_REGEX_CI === self::$options['target']['regexp']
);
// Check blacklist (no return to continue filtering #12).
if ( 1 === preg_match( $regexp, $target ) ) {
return true;
}
} else {
// Extract target page.
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL ) : '/' );
// Get blacklist.
$blacklist = self::$options['target']['blacklist'];
// Check blacklist.
if ( isset( $blacklist[ $target ] ) ) {
return true;
}
}
// Target filter (since 1.4.0).
if ( self::apply_single_filter( self::$options['target'], array( __CLASS__, 'get_target' ) ) ) {
return true;
}
// IP blacklist (since 1.4.0).
// IP filter (since 1.4.0).
if ( isset( self::$options['ip']['active'] ) && 0 !== self::$options['ip']['active'] ) {
$ip = self::get_ip();
if ( false !== ( $ip ) ) {
@ -266,10 +206,73 @@ class StatifyBlacklist {
}
}
// Skip and continue (return NULL), if all blacklists are inactive.
// User agent filter (since 1.6).
if ( self::apply_single_filter( self::$options['ua'], array( __CLASS__, 'get_user_agent' ) ) ) {
return true;
}
// Skip and continue (return NULL), if all filters are inactive.
return null;
}
/**
* Apply a single filter, if active.
*
* @param array $config Configuration array from plugin options.
* @param callable $value_fn Extractor function for filterable value.
*
* @return bool TRUE if referer matches filter.
*
* @since 1.6 Extracted from "apply_blacklist_filter" to reduce redundancies.
*/
private static function apply_single_filter( $config, $value_fn ) {
// Is the filter active?
if ( ! isset( $config['active'] ) || 0 === $config['active'] ) {
return false;
}
// Extract the filterable value.
$value = call_user_func( $value_fn );
$mode = isset( $config['regexp'] ) ? intval( $config['regexp'] ) : self::MODE_NORMAL;
switch ( $mode ) {
case self::MODE_REGEX:
case self::MODE_REGEX_CI:
// Regular Expression filtering since 1.3.0.
// Merge given regular expressions into one.
$regexp = self::regex(
array_keys( $config['blacklist'] ),
self::MODE_REGEX_CI === $config['regexp']
);
// Check filter (no return to continue filtering #12).
if ( 1 === preg_match( $regexp, $value ) ) {
return true;
}
break;
case self::MODE_KEYWORD:
// Keyword filter since 1.5.0 (#15).
foreach ( array_keys( $config['blacklist'] ) as $keyword ) {
if ( false !== strpos( strtolower( $value ), strtolower( $keyword ) ) ) {
return true;
}
}
break;
default:
// Standard exact filter.
if ( isset( $config['blacklist'][ $value ] ) ) {
return true;
}
}
return false;
}
/**
* Preprocess regular expression provided by the user, i.e. add delimiters and optional ci flag.
*
@ -301,6 +304,47 @@ class StatifyBlacklist {
return $res;
}
/**
* Helper method to determine the client's referer.
*
* @return string The referer.
*/
private static function get_referer() {
$referer = wp_get_raw_referer();
if ( ! $referer ) {
$referer = '';
}
return $referer;
}
/**
* Helper method to determine the host part of the client's referer.
*
* @return string Referer domain.
*/
private static function get_referer_domain() {
$referer = wp_parse_url( self::get_referer() );
return strtolower( ( isset( $referer['host'] ) ? $referer['host'] : '' ) );
}
/**
* Helper method to determine the client's referer.
*
* @return string The referer.
*/
private static function get_target() {
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
$target = filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL );
if ( $target ) {
return $target;
}
}
return '';
}
/**
* Helper method to determine the client's IP address.
*
@ -337,6 +381,22 @@ class StatifyBlacklist {
return false;
}
/**
* Helper method to determine the user agent.
*
* @return string The user agent string.
*/
private static function get_user_agent() {
if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
$user_agent = filter_var( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ), FILTER_SANITIZE_STRING );
if ( $user_agent ) {
return $user_agent;
}
}
return '';
}
/**
* Helper function to check if an IP address matches a given subnet.
*

View File

@ -1,7 +1,7 @@
{
"name": "statify-blacklist",
"version": "1.5.1",
"description": "A blacklist extension for the famous Statify WordPress plugin",
"version": "1.6.0",
"description": "A filter extension for the famous Statify WordPress plugin",
"author": "Stefan Kalscheuer",
"license": "GPL-2.0+"
}

View File

@ -18,7 +18,13 @@
<exclude name="WordPress.DB.DirectDatabaseQuery.NoCaching"/>
</rule>
<rule ref="WordPress.WP.I18n">
<properties>
<property name="text_domain" type="array" value="statify-blacklist"/>
</properties>
</rule>
<!-- PHP compatibility level -->
<config name="testVersion" value="5.5-"/>
<rule ref="PHPCompatibility"/>
<rule ref="PHPCompatibilityWP"/>
</ruleset>

View File

@ -2,7 +2,7 @@
<phpunit bootstrap="./vendor/autoload.php">
<testsuites>
<testsuite name="Statify Blacklist TestSuite">
<directory suffix="-test.php">./test/</directory>
<directory suffix="_Test.php">./test/</directory>
</testsuite>
</testsuites>
<filter>

View File

@ -1,33 +1,33 @@
<?php
/**
* Statify Blacklist
* Statify Filter
*
* @package PluginPackage
* @author Stefan Kalscheuer <stefan@stklcode.de>
* @license GPL-2.0+
*
* @wordpress-plugin
* Plugin Name: Statify Blacklist
* Plugin Name: Statify Filter
* Plugin URI: https://wordpress.org/plugins/statify-blacklist/
* Description: Extension for the Statify plugin to add a customizable blacklists.
* Version: 1.5.1
* Description: Extension for the Statify plugin to add customizable filters. (formerly "Statify Blacklist)
* Version: 1.6.0
* Author: Stefan Kalscheuer (@stklcode)
* Author URI: https://www.stklcode.de
* Text Domain: statify-blacklist
* License: GPLv2 or later
*
* Statify Blacklist is free software: you can redistribute it and/or modify
* Statify Filter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* any later version.
*
* Statify Blacklist is distributed in the hope that it will be useful,
* Statify Filter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Statify Blacklist. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
* along with Statify Filter. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
*/
// Quit if accessed directly.
@ -124,7 +124,7 @@ function statify_blacklist_disabled_notice() {
echo '<div class="notice notice-error is-dismissible"><p><strong>';
printf(
/* translators: minimum version numbers for WordPress and PHP inserted at placeholders */
esc_html__( 'Statify Blacklist requires at least WordPress %1$s and PHP %2$s.', 'statify-blacklist' ),
esc_html__( 'Statify Filter requires at least WordPress %1$s and PHP %2$s.', 'statify-blacklist' ),
'4.7',
'5.5'
);

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist: Unit Test
* Statify Filter: Unit Test
*
* This is a PHPunit test class for the plugin's functionality
*
@ -47,7 +47,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
* @return void
*/
public function test_referer_filter() {
// Prepare Options: 2 blacklisted domains, disabled.
// Prepare Options: 2 filtered domains, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
@ -68,6 +68,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -77,13 +82,13 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// No referer.
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-blacklisted referer.
// Non-filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://example.org';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer.
// Filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://example.com';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer with path.
// Filtered referer with path.
$_SERVER['HTTP_REFERER'] = 'http://example.net/foo/bar.html';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@ -130,6 +135,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -139,13 +149,13 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// No referer.
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-blacklisted referer.
// Non-filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://not.evil';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer.
// Filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://example.com';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer with path.
// Filtered referer with path.
$_SERVER['HTTP_REFERER'] = 'http://foobar.net/test/me';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Matching both.
@ -187,6 +197,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -196,13 +211,13 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// No referer.
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-blacklisted referer.
// Non-filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://not.evil';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer.
// Filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://example.com';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer with path.
// Filtered referer with path.
$_SERVER['HTTP_REFERER'] = 'http://foobar.net/test/me';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Matching both.
@ -405,7 +420,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
* @return void
*/
public function test_ip_filter() {
// Prepare Options: 2 blacklisted IPs, disabled.
// Prepare Options: 2 filtered IPs, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
@ -426,6 +441,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'2001:db8:a0b:12f0::1',
),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -477,7 +497,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
* @return void
*/
public function test_target_filter() {
// Prepare Options: 2 blacklisted domains, disabled.
// Prepare Options: 2 filtered domains, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
@ -498,6 +518,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -507,14 +532,14 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// Empty target.
unset( $_SERVER['REQUEST_URI'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-blacklisted targets.
// Non-filtered targets.
$_SERVER['REQUEST_URI'] = '';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REQUEST_URI'] = '/';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REQUEST_URI'] = '/?page_id=1';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer.
// Filtered referer.
$_SERVER['REQUEST_URI'] = '/excluded/page/';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REQUEST_URI'] = '/?page_id=3';
@ -544,6 +569,69 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// TODO: Test target regex filter.
/**
* Test user agent filter (#20).
*
* @return void
*/
public function test_ua_filter() {
// Prepare Options: 2 filtered IPs, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
'cron' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'target' => array(
'active' => 0,
'cron' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'ip' => array(
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(
'TestBot/1.23' => 0,
),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
// No multisite.
StatifyBlacklist::$multisite = false;
// Set matching user agent.
$_SERVER['HTTP_USER_AGENT'] = 'TestBot/1.23';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter.
StatifyBlacklist::$options['ua']['active'] = 1;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Non-matching addresses.
$_SERVER['HTTP_USER_AGENT'] = 'Another Browser 4.5.6 (Linux)';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['HTTP_USER_AGENT'] = 'TestBot/2.34';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Keyword matching.
StatifyBlacklist::$options['ua']['blacklist'] = array( 'TestBot' => 0 );
StatifyBlacklist::$options['ua']['regexp'] = StatifyBlacklist::MODE_KEYWORD;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// RegEx.
StatifyBlacklist::$options['ua']['blacklist'] = array( 'T[a-z]+B[a-z]+' => 0 );
StatifyBlacklist::$options['ua']['regexp'] = StatifyBlacklist::MODE_REGEX;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
StatifyBlacklist::$options['ua']['blacklist'] = array( 't[a-z]+' => 0 );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
StatifyBlacklist::$options['ua']['regexp'] = StatifyBlacklist::MODE_REGEX_CI;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
}
/**
* Test combined filters.
*
@ -576,6 +664,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'192.0.2.123',
),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist: Settings View
* Statify Filter: Settings View
*
* This file contains the dynamic HTML skeleton for the plugin's settings page.
*
@ -21,7 +21,7 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
// Check user capabilities.
if ( ! current_user_can( 'manage_options' ) ) {
die( esc_html__( 'Are you sure you want to do this?' ) );
die( esc_html__( 'Are you sure you want to do this?', 'statify-blacklist' ) );
}
if ( ! empty( $_POST['cleanUp'] ) ) {
@ -88,6 +88,26 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
);
}
// TODO: Extract user agent array.
if ( isset( $_POST['statifyblacklist']['ua']['blacklist'] ) ) {
$ua_string = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['ua']['blacklist'] ) );
}
if ( empty( trim( $ua_string ) ) ) {
$ua = array();
} else {
$ua = array_filter(
array_map(
function ( $a ) {
return trim( $a );
},
explode( "\r\n", str_replace( '\\\\', '\\', $ua_string ) )
),
function ( $a ) {
return ! empty( $a );
}
);
}
// Update options (data will be sanitized).
$statifyblacklist_update_result = StatifyBlacklist_Admin::update_options(
array(
@ -114,6 +134,13 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
? (int) $_POST['statifyblacklist']['ip']['active'] : 0,
'blacklist' => $ip,
),
'ua' => array(
'active' => isset( $_POST['statifyblacklist']['ua']['active'] )
? (int) $_POST['statifyblacklist']['ua']['active'] : 0,
'regexp' => isset( $_POST['statifyblacklist']['ua']['regexp'] )
? (int) $_POST['statifyblacklist']['ua']['regexp'] : 0,
'blacklist' => $ua,
),
'version' => StatifyBlacklist::VERSION_MAIN,
)
);
@ -146,7 +173,7 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
?>
<div class="wrap">
<h1><?php esc_html_e( 'Statify Blacklist', 'statify-blacklist' ); ?></h1>
<h1><?php esc_html_e( 'Statify Filter', 'statify-blacklist' ); ?></h1>
<?php
if ( is_plugin_inactive( 'statify/statify.php' ) ) {
print '<div class="notice notice-warning"><p>';
@ -170,7 +197,7 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
<form action="" method="post" id="statify-blacklist-settings">
<?php wp_nonce_field( 'statify-blacklist-settings' ); ?>
<h2><?php esc_html_e( 'Referer blacklist', 'statify-blacklist' ); ?></h2>
<h2><?php esc_html_e( 'Referer filter', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
@ -232,7 +259,7 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_referer"><?php esc_html_e( 'Referer blacklist', 'statify-blacklist' ); ?></label>
<label for="statify-blacklist_referer"><?php esc_html_e( 'Referer filter', 'statify-blacklist' ); ?></label>
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[referer][blacklist]" id="statify-blacklist_referer"><?php
@ -250,7 +277,7 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
</tbody>
</table>
<h2><?php esc_html_e( 'Target blacklist', 'statify-blacklist' ); ?></h2>
<h2><?php esc_html_e( 'Target filter', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
@ -290,7 +317,7 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
</label>
</th>
<td>
<select name="statifyblacklist[target][regexp]" id="statify-blacklist_referer_regexp">
<select name="statifyblacklist[target][regexp]" id="statify-blacklist_target_regexp">
<option value="<?php print esc_attr( StatifyBlacklist::MODE_NORMAL ); ?>" <?php selected( StatifyBlacklist::$options['target']['regexp'], StatifyBlacklist::MODE_NORMAL ); ?>>
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?>
</option>
@ -312,7 +339,7 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
<tr>
<th scope="row">
<label for="statify-blacklist_target">
<?php esc_html_e( 'Target blacklist', 'statify-blacklist' ); ?>
<?php esc_html_e( 'Target filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
@ -325,14 +352,14 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
?></textarea>
<p class="description">
(<?php esc_html_e( 'Add one target URL each line, e.g.', 'statify-blacklist' ); ?> /, /test/page/, /?page_id=123)
<?php esc_html_e( 'Add one target URL each line, e.g.', 'statify-blacklist' ); ?> /, /test/page/, /?page_id=123
</p>
</td>
</tr>
</tbody>
</table>
<h2><?php esc_html_e( 'IP blacklist', 'statify-blacklist' ); ?></h2>
<h2><?php esc_html_e( 'IP filter', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
@ -354,7 +381,7 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_ip"><?php esc_html_e( 'IP blacklist', 'statify-blacklist' ); ?></label>:
<label for="statify-blacklist_ip"><?php esc_html_e( 'IP filter', 'statify-blacklist' ); ?></label>:
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[ip][blacklist]" id="statify-blacklist_ip"><?php
@ -374,8 +401,79 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
</tbody>
</table>
<h2><?php esc_html_e( 'User agent filter', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_ua">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[ua][active]" id="statify-blacklist_active_ua"
value="1" <?php checked( StatifyBlacklist::$options['ua']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'Cron execution is not possible for user agent filter, because the user agent is stored.', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_ua_regexp"><?php esc_html_e( 'Matching method', 'statify-blacklist' ); ?></label>
</th>
<td>
<select name="statifyblacklist[ua][regexp]" id="statify-blacklist_ua_regexp">
<option value="<?php print esc_attr( StatifyBlacklist::MODE_NORMAL ); ?>" <?php selected( StatifyBlacklist::$options['ua']['regexp'], StatifyBlacklist::MODE_NORMAL ); ?>>
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_KEYWORD ); ?>" <?php selected( StatifyBlacklist::$options['ua']['regexp'], StatifyBlacklist::MODE_KEYWORD ); ?>>
<?php esc_html_e( 'Keyword', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX ); ?>" <?php selected( StatifyBlacklist::$options['ua']['regexp'], StatifyBlacklist::MODE_REGEX ); ?>>
<?php esc_html_e( 'RegEx case-sensitive', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX_CI ); ?>" <?php selected( StatifyBlacklist::$options['ua']['regexp'], StatifyBlacklist::MODE_REGEX_CI ); ?>>
<?php esc_html_e( 'RegEx case-insensitive', 'statify-blacklist' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match only given user agents', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'Keyword', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match every referer that contains one of the keywords', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'RegEx', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match user agent by regular expression', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_ua"><?php esc_html_e( 'User agent filter', 'statify-blacklist' ); ?></label>:
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[ua][blacklist]" id="statify-blacklist_ua"><?php
if ( empty( $statifyblacklist_update_result['ua'] ) ) {
print esc_html( implode( "\r\n", StatifyBlacklist::$options['ua']['blacklist'] ) );
} else {
print esc_html( implode( "\r\n", $statifyblacklist_update_result['ua']['sanitized'] ) );
}
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one user agent string per line, e.g.', 'statify-blacklist' ); ?>
MyBot/1.23
</p>
</td>
</tr>
</tbody>
</table>
<p class="submit">
<input class="button-primary" type="submit" name="submit" value="<?php esc_html_e( 'Save Changes' ); ?>">
<input class="button-primary" type="submit" name="submit" value="<?php esc_html_e( 'Save Changes', 'statify-blacklist' ); ?>">
<hr>
<input class="button-secondary" type="submit" name="cleanUp"
value="<?php esc_html_e( 'CleanUp Database', 'statify-blacklist' ); ?>"