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.
This commit is contained in:
parent
e5c30c2183
commit
a6cc821089
@ -92,6 +92,7 @@ Same for IPv6 prefixes like _2001:db8:a0b:12f0::/64_.
|
||||
|
||||
### 1.6.0 / unreleased ###
|
||||
* Minor accessibility fixes on settings page
|
||||
* Introduced new user agent filter (#20)
|
||||
|
||||
### 1.5.2 / 03.09.2020 ###
|
||||
* Minor translation updates
|
||||
|
@ -91,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' ) );
|
||||
}
|
||||
|
||||
@ -156,6 +159,11 @@ class StatifyBlacklist {
|
||||
'active' => 0,
|
||||
'blacklist' => array(),
|
||||
),
|
||||
'ua' => array(
|
||||
'active' => 0,
|
||||
'regexp' => 0,
|
||||
'blacklist' => array(),
|
||||
),
|
||||
'version' => self::VERSION_MAIN,
|
||||
);
|
||||
}
|
||||
@ -264,6 +272,59 @@ class StatifyBlacklist {
|
||||
}
|
||||
}
|
||||
|
||||
// User agent filter (since 1.6).
|
||||
if ( isset( self::$options['ua']['active'] ) && 0 !== self::$options['ua']['active'] ) {
|
||||
// Determine filter mode.
|
||||
$mode = isset( self::$options['ua']['regexp'] ) ? intval( self::$options['ua']['regexp'] ) : 0;
|
||||
|
||||
// Get full user agent string.
|
||||
if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
|
||||
$user_agent = filter_var( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ), FILTER_SANITIZE_STRING );
|
||||
|
||||
if ( $user_agent ) {
|
||||
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['ua']['blacklist'] ),
|
||||
self::MODE_REGEX_CI === self::$options['ua']['regexp']
|
||||
);
|
||||
|
||||
// Check filter (no return to continue filtering #12).
|
||||
if ( 1 === preg_match( $regexp, $user_agent ) ) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
// Keyword filter since 1.5.0 (#15).
|
||||
case self::MODE_KEYWORD:
|
||||
// Get filter.
|
||||
$blacklist = self::$options['ua']['blacklist'];
|
||||
|
||||
foreach ( array_keys( $blacklist ) as $keyword ) {
|
||||
if ( false !== strpos( strtolower( $user_agent ), strtolower( $keyword ) ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Standard exact filter.
|
||||
default:
|
||||
// Get filter.
|
||||
$blacklist = self::$options['ua']['blacklist'];
|
||||
|
||||
// Check filter.
|
||||
if ( isset( $blacklist[ $user_agent ] ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip and continue (return NULL), if all filters are inactive.
|
||||
return null;
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
|
||||
@ -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,
|
||||
);
|
||||
|
||||
@ -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,
|
||||
);
|
||||
|
||||
@ -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,
|
||||
);
|
||||
|
||||
@ -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,
|
||||
);
|
||||
|
||||
@ -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,
|
||||
);
|
||||
|
||||
|
@ -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,
|
||||
)
|
||||
);
|
||||
@ -374,6 +401,77 @@ 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', 'statify-blacklist' ); ?>">
|
||||
<hr>
|
||||
|
Loading…
x
Reference in New Issue
Block a user