initial import from https://downloads.wordpress.org/plugin/wp-fail2ban.4.2.5.zip
This commit is contained in:
commit
3a8e77323e
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*~
|
||||
\#*
|
||||
.#*
|
66
admin/admin.php
Normal file
66
admin/admin.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Admin
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
require __DIR__ . '/config.php';
|
||||
require __DIR__ . '/lib/about.php';
|
||||
/**
|
||||
* Register admin menus
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
function admin_menu()
|
||||
{
|
||||
global $submenu ;
|
||||
add_menu_page(
|
||||
'WP fail2ban',
|
||||
'WP fail2ban',
|
||||
'manage_options',
|
||||
'wp-fail2ban',
|
||||
__NAMESPACE__ . '\\about',
|
||||
'dashicons-analytics'
|
||||
);
|
||||
add_submenu_page(
|
||||
'wp-fail2ban',
|
||||
'Settings',
|
||||
'Settings',
|
||||
'manage_options',
|
||||
'wp-fail2ban-settings',
|
||||
__NAMESPACE__ . '\\settings'
|
||||
);
|
||||
$submenu['wp-fail2ban'][0][0] = __( 'Welcome' );
|
||||
}
|
||||
|
||||
add_action( 'admin_menu', __NAMESPACE__ . '\\admin_menu' );
|
||||
/**
|
||||
* Add Settings link on Plugins page
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param array $links
|
||||
* @param string $file
|
||||
*/
|
||||
function plugin_action_links( $links, $file )
|
||||
{
|
||||
if ( preg_match( "|{$file}\$|", WP_FAIL2BAN_FILE ) ) {
|
||||
// Add Settings at the start
|
||||
array_unshift( $links, '<a href="' . admin_url( 'admin.php' ) . '?page=wp-fail2ban-settings&tab=about">Settings</a>' );
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
|
||||
add_filter(
|
||||
'plugin_action_links',
|
||||
__NAMESPACE__ . '\\plugin_action_links',
|
||||
10,
|
||||
2
|
||||
);
|
69
admin/config.php
Normal file
69
admin/config.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Config
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
require_once 'lib/tab.php';
|
||||
foreach ( glob( __DIR__ . '/config/*.php' ) as $filename ) {
|
||||
require_once $filename;
|
||||
}
|
||||
/**
|
||||
* Render Settings
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
function settings()
|
||||
{
|
||||
$tabs = [
|
||||
'logging',
|
||||
'syslog',
|
||||
'block',
|
||||
'remote-ips',
|
||||
'plugins'
|
||||
];
|
||||
$title = 'WP fail2ban';
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php
|
||||
echo $title ;
|
||||
?></h1>
|
||||
<hr class="wp-header-end">
|
||||
|
||||
<h2 class="nav-tab-wrapper wp-clearfix">
|
||||
<?php
|
||||
$active_tab = Tab::getActiveTab( 'logging' );
|
||||
foreach ( $tabs as $slug ) {
|
||||
$class = 'nav-tab';
|
||||
if ( $active_tab->getSlug() == $slug ) {
|
||||
$class .= ' nav-tab-active';
|
||||
}
|
||||
printf(
|
||||
'<a class="%s" href="?page=wp-fail2ban-settings&tab=%s">%s</a>',
|
||||
$class,
|
||||
$slug,
|
||||
Tab::getTabName( $slug )
|
||||
);
|
||||
}
|
||||
?>
|
||||
</h2>
|
||||
|
||||
<form action="options.php?tab=<?php
|
||||
echo $active_tab->getSlug() ;
|
||||
?>" method="post">
|
||||
<?php
|
||||
settings_fields( 'wp-fail2ban' );
|
||||
$active_tab->render();
|
||||
echo '<hr><p>' . __( '<strong>Note:</strong> The Free version of <em>WP fail2ban</em> is configured by defining constants in <tt>wp-config.php</tt>; these tabs display those values.<br>Upgrade to the Premium version to enable this interface.' ) . '</p>' ;
|
||||
?>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
}
|
120
admin/config/block.php
Normal file
120
admin/config/block.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Settings - Block
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* Tab: Block
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class TabBlock extends Tab
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
add_action( 'admin_init', [ $this, 'admin_init' ] );
|
||||
parent::__construct( 'block', 'Users' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function admin_init()
|
||||
{
|
||||
// phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
|
||||
add_settings_section(
|
||||
'wp-fail2ban-block',
|
||||
__( 'Block' ),
|
||||
[ $this, 'section' ],
|
||||
'wp-fail2ban-block'
|
||||
);
|
||||
add_settings_field(
|
||||
'block-user-enumeration',
|
||||
parent::doc_link( 'WP_FAIL2BAN_BLOCK_USER_ENUMERATION', __( 'User Enumeration' ) ),
|
||||
[ $this, 'userEnumeration' ],
|
||||
'wp-fail2ban-block',
|
||||
'wp-fail2ban-block'
|
||||
);
|
||||
add_settings_field(
|
||||
'block-users',
|
||||
parent::doc_link( 'WP_FAIL2BAN_BLOCKED_USERS', __( 'Usernames' ) ),
|
||||
[ $this, 'usernames' ],
|
||||
'wp-fail2ban-block',
|
||||
'wp-fail2ban-block'
|
||||
);
|
||||
// phpcs:enable
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $settings
|
||||
* @param array $input
|
||||
*/
|
||||
public function sanitize( array $settings, array $input = null )
|
||||
{
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function section()
|
||||
{
|
||||
echo '' ;
|
||||
}
|
||||
|
||||
/**
|
||||
* User Enumeration
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function userEnumeration()
|
||||
{
|
||||
printf( '<input type="checkbox" disabled="disabled" %s>', checked( WP_FAIL2BAN_BLOCK_USER_ENUMERATION, true, false ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocked usernames
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function usernames()
|
||||
{
|
||||
|
||||
if ( defined( 'WP_FAIL2BAN_BLOCKED_USERS' ) ) {
|
||||
|
||||
if ( is_array( WP_FAIL2BAN_BLOCKED_USERS ) ) {
|
||||
$value = join( ', ', WP_FAIL2BAN_BLOCKED_USERS );
|
||||
} else {
|
||||
$value = WP_FAIL2BAN_BLOCKED_USERS;
|
||||
}
|
||||
|
||||
} else {
|
||||
$value = '';
|
||||
}
|
||||
|
||||
printf( '<input class="regular-text" type="text" disabled="disabled" value="%s">', esc_attr( $value ) );
|
||||
}
|
||||
|
||||
}
|
||||
new TabBlock();
|
255
admin/config/logging.php
Normal file
255
admin/config/logging.php
Normal file
@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Settings - Logging
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* Tab: Logging
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class TabLogging extends Tab
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
add_action( 'admin_init', [ $this, 'admin_init' ], 100 );
|
||||
parent::__construct( 'logging', 'Logging' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function admin_init()
|
||||
{
|
||||
// phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
|
||||
add_settings_section(
|
||||
'wp-fail2ban-logging',
|
||||
__( 'What & Where' ),
|
||||
[ $this, 'sectionWhatWhere' ],
|
||||
'wp-fail2ban-logging'
|
||||
);
|
||||
add_settings_field(
|
||||
'logging-log-authentication',
|
||||
parent::doc_link( 'WP_FAIL2BAN_AUTH_LOG', __( 'Authentication' ) ),
|
||||
[ $this, 'authentication' ],
|
||||
'wp-fail2ban-logging',
|
||||
'wp-fail2ban-logging'
|
||||
);
|
||||
add_settings_field(
|
||||
'logging-log-comments',
|
||||
parent::doc_link( 'WP_FAIL2BAN_LOG_COMMENTS', __( 'Comments' ) ),
|
||||
[ $this, 'comments' ],
|
||||
'wp-fail2ban-logging',
|
||||
'wp-fail2ban-logging'
|
||||
);
|
||||
add_settings_field(
|
||||
'logging-log-spam',
|
||||
parent::doc_link( 'WP_FAIL2BAN_LOG_SPAM', __( 'Spam' ) ),
|
||||
[ $this, 'spam' ],
|
||||
'wp-fail2ban-logging',
|
||||
'wp-fail2ban-logging'
|
||||
);
|
||||
add_settings_field(
|
||||
'logging-log-password-request',
|
||||
parent::doc_link( 'WP_FAIL2BAN_LOG_PASSWORD_REQUEST', __( 'Password Requests' ) ),
|
||||
[ $this, 'passwordRequest' ],
|
||||
'wp-fail2ban-logging',
|
||||
'wp-fail2ban-logging'
|
||||
);
|
||||
add_settings_field(
|
||||
'logging-log-pingbacks',
|
||||
parent::doc_link( 'WP_FAIL2BAN_LOG_PINGBACKS', __( 'Pingbacks' ) ),
|
||||
[ $this, 'pingbacks' ],
|
||||
'wp-fail2ban-logging',
|
||||
'wp-fail2ban-logging'
|
||||
);
|
||||
// phpcs:enable
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
parent::render();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $settings {@inheritDoc}
|
||||
* @param array $input {@inheritDoc}
|
||||
*
|
||||
* @return array {@inheritDoc}
|
||||
*/
|
||||
public function sanitize( array $settings, array $input = null )
|
||||
{
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Section summary.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function sectionWhatWhere()
|
||||
{
|
||||
echo '' ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function authentication()
|
||||
{
|
||||
printf( '<label>%s: %s</label>', __( 'Use facility' ), $this->getLogFacilities( 'WP_FAIL2BAN_AUTH_LOG', true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Comments.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function comments()
|
||||
{
|
||||
add_filter(
|
||||
'wp_fail2ban_log_WP_FAIL2BAN_LOG_COMMENTS',
|
||||
[ $this, 'commentsExtra' ],
|
||||
10,
|
||||
3
|
||||
);
|
||||
$this->log(
|
||||
'WP_FAIL2BAN_LOG_COMMENTS',
|
||||
'WP_FAIL2BAN_COMMENT_LOG',
|
||||
'',
|
||||
[ 'comments-extra', 'logging-comments-extra-facility' ]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comments extra helper - checked.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int $value Value to check
|
||||
*/
|
||||
protected function commentExtraChecked( $value )
|
||||
{
|
||||
if ( !defined( 'WP_FAIL2BAN_LOG_COMMENTS_EXTRA' ) ) {
|
||||
return '';
|
||||
}
|
||||
return checked( $value & WP_FAIL2BAN_LOG_COMMENTS_EXTRA, $value, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Comments extra helper - disabled.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected function commentExtraDisabled()
|
||||
{
|
||||
return 'disabled="disabled';
|
||||
}
|
||||
|
||||
/**
|
||||
* Comments extra.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $html HTML prefixed to output
|
||||
* @param string $define_name Not used
|
||||
* @param string $define_log Not used
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function commentsExtra( $html, $define_name, $define_log )
|
||||
{
|
||||
$fmt = <<<___HTML___
|
||||
<table>
|
||||
<tr>
|
||||
<th>%s</th>
|
||||
<td>
|
||||
<fieldset id="comments-extra" disabled="disabled">
|
||||
<label><input type="checkbox" %s> %s</label><br>
|
||||
<label><input type="checkbox" %s> %s</label><br>
|
||||
<label><input type="checkbox" %s> %s</label><br>
|
||||
<label><input type="checkbox" %s> %s</label><br>
|
||||
<label><input type="checkbox" %s> %s</label>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>%s</th>
|
||||
<td>%s</td>
|
||||
</tr>
|
||||
</table>
|
||||
___HTML___;
|
||||
return $html . sprintf(
|
||||
$fmt,
|
||||
parent::doc_link( 'WP_FAIL2BAN_LOG_COMMENTS_EXTRA', __( 'Also log:' ) ),
|
||||
$this->commentExtraChecked( WPF2B_EVENT_COMMENT_NOT_FOUND ),
|
||||
__( 'Post not found' ),
|
||||
$this->commentExtraChecked( WPF2B_EVENT_COMMENT_CLOSED ),
|
||||
__( 'Comments closed' ),
|
||||
$this->commentExtraChecked( WPF2B_EVENT_COMMENT_TRASH ),
|
||||
__( 'Trash post' ),
|
||||
$this->commentExtraChecked( WPF2B_EVENT_COMMENT_DRAFT ),
|
||||
__( 'Draft post' ),
|
||||
$this->commentExtraChecked( WPF2B_EVENT_COMMENT_PASSWORD ),
|
||||
__( 'Password-protected post' ),
|
||||
parent::doc_link( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG', __( 'Use facility:' ) ),
|
||||
$this->getLogFacilities( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG', false )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Password request
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function passwordRequest()
|
||||
{
|
||||
$this->log( 'WP_FAIL2BAN_LOG_PASSWORD_REQUEST', 'WP_FAIL2BAN_PASSWORD_REQUEST_LOG' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Pingbacks
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function pingbacks()
|
||||
{
|
||||
$this->log( 'WP_FAIL2BAN_LOG_PINGBACKS', 'WP_FAIL2BAN_PINGBACK_LOG' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Spam
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function spam()
|
||||
{
|
||||
$this->log( 'WP_FAIL2BAN_LOG_SPAM', 'WP_FAIL2BAN_SPAM_LOG' );
|
||||
}
|
||||
|
||||
}
|
||||
new TabLogging();
|
185
admin/config/plugins.php
Normal file
185
admin/config/plugins.php
Normal file
@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Settings - Plugins
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.2.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* Tab: Plugins
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
class TabPlugins extends Tab
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
add_action( 'admin_init', [ $this, 'admin_init' ], 100 );
|
||||
parent::__construct( 'plugins', 'Plugins' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function admin_init()
|
||||
{
|
||||
// phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
|
||||
add_settings_section(
|
||||
'wp-fail2ban-plugins',
|
||||
__( 'Event Class Facilities' ),
|
||||
[ $this, 'sectionLoggingEventClasses' ],
|
||||
'wp-fail2ban-plugins'
|
||||
);
|
||||
add_settings_field(
|
||||
'plugins-log-auth',
|
||||
parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_AUTH', __( 'Authentication' ) ),
|
||||
[ $this, 'auth' ],
|
||||
'wp-fail2ban-plugins',
|
||||
'wp-fail2ban-plugins'
|
||||
);
|
||||
add_settings_field(
|
||||
'plugins-log-comment',
|
||||
parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_COMMENT', __( 'Comment' ) ),
|
||||
[ $this, 'comment' ],
|
||||
'wp-fail2ban-plugins',
|
||||
'wp-fail2ban-plugins'
|
||||
);
|
||||
add_settings_field(
|
||||
'plugins-log-password',
|
||||
parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_PASSWORD', __( 'Password' ) ),
|
||||
[ $this, 'password' ],
|
||||
'wp-fail2ban-plugins',
|
||||
'wp-fail2ban-plugins'
|
||||
);
|
||||
add_settings_field(
|
||||
'plugins-log-rest',
|
||||
parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_REST', __( 'REST' ) ),
|
||||
[ $this, 'rest' ],
|
||||
'wp-fail2ban-plugins',
|
||||
'wp-fail2ban-plugins'
|
||||
);
|
||||
add_settings_field(
|
||||
'plugins-log-spam',
|
||||
parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_SPAM', __( 'Spam' ) ),
|
||||
[ $this, 'spam' ],
|
||||
'wp-fail2ban-plugins',
|
||||
'wp-fail2ban-plugins'
|
||||
);
|
||||
add_settings_field(
|
||||
'plugins-log-xmlrpc',
|
||||
parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_XMLRPC', __( 'XML-RPC' ) ),
|
||||
[ $this, 'xmlrpc' ],
|
||||
'wp-fail2ban-plugins',
|
||||
'wp-fail2ban-plugins'
|
||||
);
|
||||
// phpcs:enable
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
parent::render();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param array $settings {@inheritDoc}
|
||||
* @param array $input {@inheritDoc}
|
||||
*
|
||||
* @return array {@inheritDoc}
|
||||
*/
|
||||
public function sanitize( array $settings, array $input = null )
|
||||
{
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Section summary.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function sectionLoggingEventClasses()
|
||||
{
|
||||
echo __( 'Facilities to use for plugin-generated messages. The defaults follow the Core defaults.' ) ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auth
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function auth()
|
||||
{
|
||||
$this->log( 'WP_FAIL2BAN_PLUGIN_LOG_AUTH', 'WP_FAIL2BAN_PLUGIN_AUTH_LOG' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Comment
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function comment()
|
||||
{
|
||||
$this->log( 'WP_FAIL2BAN_PLUGIN_LOG_COMMENT', 'WP_FAIL2BAN_PLUGIN_COMMENT_LOG' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Password
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function password()
|
||||
{
|
||||
$this->log( 'WP_FAIL2BAN_PLUGIN_LOG_PASSWORD', 'WP_FAIL2BAN_PLUGIN_PASSWORD_LOG' );
|
||||
}
|
||||
|
||||
/**
|
||||
* REST
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function rest()
|
||||
{
|
||||
$this->log( 'WP_FAIL2BAN_PLUGIN_LOG_REST', 'WP_FAIL2BAN_PLUGIN_REST_LOG' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Spam
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function spam()
|
||||
{
|
||||
$this->log( 'WP_FAIL2BAN_PLUGIN_LOG_SPAM', 'WP_FAIL2BAN_PLUGIN_SPAM_LOG' );
|
||||
}
|
||||
|
||||
/**
|
||||
* XML-RPC
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function xmlrpc()
|
||||
{
|
||||
$this->log( 'WP_FAIL2BAN_PLUGIN_LOG_XMLRPC', 'WP_FAIL2BAN_PLUGIN_XMLRPC_LOG' );
|
||||
}
|
||||
|
||||
}
|
||||
new TabPlugins();
|
100
admin/config/remote-ips.php
Normal file
100
admin/config/remote-ips.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Settings - Remote IPs
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* Tab: Remote IPs
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class TabRemoteIPs extends Tab
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
add_action( 'admin_init', [ $this, 'admin_init' ] );
|
||||
parent::__construct( 'remote-ips', 'Remote IPs' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function admin_init()
|
||||
{
|
||||
// phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
|
||||
add_settings_section(
|
||||
'wp-fail2ban-proxies',
|
||||
__( 'Proxies' ),
|
||||
[ $this, 'section' ],
|
||||
'wp-fail2ban-remote-ips'
|
||||
);
|
||||
add_settings_field(
|
||||
'remote-ips-proxies',
|
||||
parent::doc_link( 'WP_FAIL2BAN_PROXIES', __( 'IP list' ) ),
|
||||
[ $this, 'proxies' ],
|
||||
'wp-fail2ban-remote-ips',
|
||||
'wp-fail2ban-proxies'
|
||||
);
|
||||
// phpcs:enable
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $settings
|
||||
* @param array $input
|
||||
*/
|
||||
public function sanitize( array $settings, array $input = null )
|
||||
{
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Section blurb.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function section()
|
||||
{
|
||||
echo '' ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxies.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function proxies()
|
||||
{
|
||||
$value = '';
|
||||
if ( defined( 'WP_FAIL2BAN_PROXIES' ) ) {
|
||||
|
||||
if ( is_array( WP_FAIL2BAN_PROXIES ) ) {
|
||||
$value = join( "\n", WP_FAIL2BAN_PROXIES );
|
||||
} else {
|
||||
$value = join( "\n", array_map( 'trim', explode( ',', WP_FAIL2BAN_PROXIES ) ) );
|
||||
}
|
||||
|
||||
}
|
||||
printf( '<fieldset><textarea class="code" cols="20" rows="10" disabled="disabled">%s</textarea></fieldset>', esc_html( $value ) );
|
||||
}
|
||||
|
||||
}
|
||||
new TabRemoteIPs();
|
159
admin/config/syslog.php
Normal file
159
admin/config/syslog.php
Normal file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Settings - syslog
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* Tab: Syslog
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class TabSyslog extends Tab
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
add_action( 'admin_init', [ $this, 'admin_init' ], 100 );
|
||||
parent::__construct( 'syslog', '<tt>syslog</tt>' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function admin_init()
|
||||
{
|
||||
// phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
|
||||
add_settings_section(
|
||||
'wp-fail2ban-connection',
|
||||
__( 'Connection' ),
|
||||
[ $this, 'sectionConnection' ],
|
||||
'wp-fail2ban-syslog'
|
||||
);
|
||||
add_settings_field(
|
||||
'logging-connection',
|
||||
parent::doc_link( 'WP_FAIL2BAN_OPENLOG_OPTIONS', __( 'Options' ) ),
|
||||
[ $this, 'connection' ],
|
||||
'wp-fail2ban-syslog',
|
||||
'wp-fail2ban-connection'
|
||||
);
|
||||
add_settings_section(
|
||||
'wp-fail2ban-workarounds',
|
||||
__( 'Workarounds' ),
|
||||
[ $this, 'sectionWorkarounds' ],
|
||||
'wp-fail2ban-syslog'
|
||||
);
|
||||
add_settings_field(
|
||||
'logging-workarounds',
|
||||
parent::doc_link( '../syslog', __( 'Options' ) ),
|
||||
[ $this, 'workarounds' ],
|
||||
'wp-fail2ban-syslog',
|
||||
'wp-fail2ban-workarounds'
|
||||
);
|
||||
// phpcs:enable
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $settings {@inheritDoc}
|
||||
* @param array $input {@inheritDoc}
|
||||
*
|
||||
* @return array {@inheritDoc}
|
||||
*/
|
||||
public function sanitize( array $settings, array $input = null )
|
||||
{
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connection section blurb.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function sectionConnection()
|
||||
{
|
||||
echo '' ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connection.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function connection()
|
||||
{
|
||||
$class = '';
|
||||
$fmt = <<<___STR___
|
||||
<fieldset>
|
||||
<label><input type="checkbox" disabled="disabled" %s> <code>LOG_CONS</code></label><br>
|
||||
<label><input type="checkbox" disabled="disabled" %s> <code>LOG_PERROR</code></label><br>
|
||||
<label><input type="checkbox" disabled="disabled" %s> <code>LOG_PID</code> <em>(%s)</em></label><br>
|
||||
<label><input type="radio" disabled="disabled" %s> <code>LOG_NDELAY</code> <em>(%s)</em></label><br>
|
||||
<label><input type="radio" disabled="disabled" %s> <code>LOG_ODELAY</code></label>
|
||||
</fieldset>
|
||||
___STR___;
|
||||
printf(
|
||||
$fmt,
|
||||
checked( WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_CONS, LOG_CONS, false ),
|
||||
checked( WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_PERROR, LOG_PERROR, false ),
|
||||
checked( WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_PID, LOG_PID, false ),
|
||||
__( 'default' ),
|
||||
checked( WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_NDELAY, LOG_NDELAY, false ),
|
||||
__( 'default' ),
|
||||
checked( WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_ODELAY, LOG_ODELAY, false )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Workarounds section blurb.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function sectionWorkarounds()
|
||||
{
|
||||
echo '' ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Workarounds.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function workarounds()
|
||||
{
|
||||
$fmt = <<<___STR___
|
||||
<fieldset>
|
||||
<label><input type="checkbox" disabled="disabled" %s> %s</label>
|
||||
<br>
|
||||
<label><input type="checkbox" disabled="disabled" %s> %s</label>
|
||||
<br>
|
||||
<label><input type="checkbox" disabled="disabled" %s> %s</label>
|
||||
</fieldset>
|
||||
___STR___;
|
||||
printf(
|
||||
$fmt,
|
||||
checked( @WP_FAIL2BAN_SYSLOG_SHORT_TAG, true, false ),
|
||||
__( 'Short Tag' ),
|
||||
checked( @WP_FAIL2BAN_HTTP_HOST, true, false ),
|
||||
__( 'Specify Host' ),
|
||||
checked( @WP_FAIL2BAN_TRUNCATE_HOST, true, false ),
|
||||
__( 'Truncate Host' )
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
new TabSyslog();
|
6
admin/img/docs.svg
Normal file
6
admin/img/docs.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 26 26" version="1.1" width="16px" height="16px">
|
||||
<g id="surface1">
|
||||
<path style=" " d="M 7 0 C 4.796875 0 3 1.796875 3 4 L 3 22 C 3 24.203125 4.796875 26 7 26 L 19 26 C 21.203125 26 23 24.203125 23 22 L 23 8 C 23 6.9375 22.027344 5.929688 20.28125 4.21875 C 20.039063 3.980469 19.777344 3.714844 19.53125 3.46875 C 19.285156 3.222656 19.019531 2.992188 18.78125 2.75 C 17.070313 1.003906 16.0625 0 15 0 Z M 7 2 L 14.28125 2 C 15.003906 2.183594 15 3.050781 15 3.9375 L 15 7 C 15 7.550781 15.449219 8 16 8 L 19 8 C 19.996094 8 21 8.003906 21 9 L 21 22 C 21 23.105469 20.105469 24 19 24 L 7 24 C 5.894531 24 5 23.105469 5 22 L 5 4 C 5 2.894531 5.894531 2 7 2 Z M 7.8125 10 C 7.261719 10.050781 6.855469 10.542969 6.90625 11.09375 C 6.957031 11.644531 7.449219 12.050781 8 12 L 18 12 C 18.359375 12.003906 18.695313 11.816406 18.878906 11.503906 C 19.058594 11.191406 19.058594 10.808594 18.878906 10.496094 C 18.695313 10.183594 18.359375 9.996094 18 10 L 8 10 C 7.96875 10 7.9375 10 7.90625 10 C 7.875 10 7.84375 10 7.8125 10 Z M 7.8125 14 C 7.261719 14.050781 6.855469 14.542969 6.90625 15.09375 C 6.957031 15.644531 7.449219 16.050781 8 16 L 16 16 C 16.359375 16.003906 16.695313 15.816406 16.878906 15.503906 C 17.058594 15.191406 17.058594 14.808594 16.878906 14.496094 C 16.695313 14.183594 16.359375 13.996094 16 14 L 8 14 C 7.96875 14 7.9375 14 7.90625 14 C 7.875 14 7.84375 14 7.8125 14 Z M 7.8125 18 C 7.261719 18.050781 6.855469 18.542969 6.90625 19.09375 C 6.957031 19.644531 7.449219 20.050781 8 20 L 18 20 C 18.359375 20.003906 18.695313 19.816406 18.878906 19.503906 C 19.058594 19.191406 19.058594 18.808594 18.878906 18.496094 C 18.695313 18.183594 18.359375 17.996094 18 18 L 8 18 C 7.96875 18 7.9375 18 7.90625 18 C 7.875 18 7.84375 18 7.8125 18 Z "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
143
admin/lib/about.php
Normal file
143
admin/lib/about.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* About
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.2.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* About content
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param bool $hide_title
|
||||
*/
|
||||
function about( $hide_title = false )
|
||||
{
|
||||
$wp_f2b_ver = substr( WP_FAIL2BAN_VER, 0, strrpos( WP_FAIL2BAN_VER, '.' ) );
|
||||
?>
|
||||
<div class="wrap">
|
||||
<style>
|
||||
div.inside ul {
|
||||
list-style: disc;
|
||||
padding-left: 2em;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
if ( !$hide_title ) {
|
||||
?>
|
||||
<h1>WP fail2ban</h1>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div id="poststuff">
|
||||
<div id="post-body" class="metabox-holder columns-2">
|
||||
<div id="post-body-content">
|
||||
<div class="meta-box-sortables ui-sortable">
|
||||
<div class="postbox">
|
||||
<h2>Version 4.2.5</h2>
|
||||
<div class="inside">
|
||||
<ul>
|
||||
<li>Properly fix PHP 5.3 support; tested on CentOS 6. Does not support any UI or Premium features.</li>
|
||||
<li>Fix potential issue with <tt>WP_FAIL2BAN_BLOCK_USER_ENUMERATION</tt> if calling REST API or XMLRPC from admin area.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta-box-sortables ui-sortable">
|
||||
<div class="postbox">
|
||||
<h2>Version 4.2.4</h2>
|
||||
<div class="inside">
|
||||
<ul>
|
||||
<li>Add filter for login failed message.</li>
|
||||
<li>Fix logging spam comments from admin area.</li>
|
||||
<li>Fix Settings link from Plugins page.</li>
|
||||
<li>Update Freemius library.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta-box-sortables ui-sortable">
|
||||
<div class="postbox">
|
||||
<h2>Version 4.2.3</h2>
|
||||
<div class="inside">
|
||||
<ul>
|
||||
<li>Workaround for some versions of PHP 7.x that would cause <tt>define()</tt>s to be ignored.</li>
|
||||
<li>Add config note to settings tabs.</li>
|
||||
<li>Fix documentation links.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta-box-sortables ui-sortable">
|
||||
<div class="postbox">
|
||||
<h2>Version 4.2.2</h2>
|
||||
<div class="inside">
|
||||
<ul>
|
||||
<li>Fix 5.3 compatibility.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta-box-sortables ui-sortable">
|
||||
<div class="postbox">
|
||||
<h2>Version 4.2.1</h2>
|
||||
<div class="inside">
|
||||
<ul>
|
||||
<li>Completed support for <tt><a href="https://docs.wp-fail2ban.com/en/4.2/defines/WP_FAIL2BAN_COMMENT_EXTRA_LOG.html" target="docs.wp-fail2ban.com">WP_FAIL2BAN_COMMENT_EXTRA_LOG</a></tt>.</li>
|
||||
<li>Add support for 3rd-party plugins; see <a href="https://docs.wp-fail2ban.com/en/4.2/developers.html" target="docs.wp-fail2ban.com">Developers</a>.<br>
|
||||
<p><ul>
|
||||
<li>Add-on for <a href="https://wordpress.org/plugins/wp-fail2ban-addon-contact-form-7/">Contact Form 7</a> (experimental).</li>
|
||||
<li>Add-on for <a href="https://wordpress.org/plugins/wp-fail2ban-addon-gravity-forms/">Gravity Forms</a> (experimental).</li>
|
||||
</ul></p>
|
||||
</li>
|
||||
<li>Change logging for known-user with incorrect password; previously logged as unknown user and matched by <tt>hard</tt> filters (due to limitations in older versions of WordPress), now logged as known user and matched by <tt>soft</tt>.</li>
|
||||
<li>Bugfix for email-as-username - now logged correctly and matched by <tt>soft</tt>, not <tt>hard</tt>, filters.</li>
|
||||
<li>Bugfix for regression in code to prevent Free/Premium conflict.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="postbox-container-1" class="postbox-container">
|
||||
<div class="meta-box-sortables">
|
||||
<div class="postbox">
|
||||
<h2>Getting Started</h2>
|
||||
<div class="inside">
|
||||
<ol>
|
||||
<li><a href="https://docs.wp-fail2ban.com/en/<?php
|
||||
echo $wp_f2b_ver ;
|
||||
?>/introduction.html" target="docs.wp-fail2ban.com">Introduction</a></li>
|
||||
<li><a href="https://docs.wp-fail2ban.com/en/<?php
|
||||
echo $wp_f2b_ver ;
|
||||
?>/configuration.html" target="docs.wp-fail2ban.com">Configuration</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="postbox">
|
||||
<h2>Getting Help</h2>
|
||||
<div class="inside">
|
||||
<ul>
|
||||
<?php
|
||||
if ( wf_fs()->is_free_plan() ) {
|
||||
?>
|
||||
<li><a href="https://wordpress.org/support/plugin/wp-fail2ban/" target="_blank">WordPress.org Forum</a></li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
260
admin/lib/tab.php
Normal file
260
admin/lib/tab.php
Normal file
@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tab base class
|
||||
*
|
||||
* @package wp-fail2ban-premium
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* Base Tab class
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
abstract class Tab
|
||||
{
|
||||
/**
|
||||
* @var array Array of Tab objects
|
||||
*/
|
||||
protected static $tabs = array() ;
|
||||
/**
|
||||
* @var string Active tab slug
|
||||
*/
|
||||
protected static $active_tab ;
|
||||
/**
|
||||
* @var string Tab slug
|
||||
*/
|
||||
protected $tab_slug ;
|
||||
/**
|
||||
* @var string Tab name
|
||||
*/
|
||||
protected $tab_name ;
|
||||
/**
|
||||
* Hook: admin_init
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public abstract function admin_init();
|
||||
|
||||
/**
|
||||
* Sanitize and store form fields
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $settings Settings to update
|
||||
* @param array $input Form fields
|
||||
*
|
||||
* @return array $settings
|
||||
*/
|
||||
public abstract function sanitize( array $settings, array $input = null );
|
||||
|
||||
/**
|
||||
* Contruct.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $slug Tab slug
|
||||
* @param string $name Tab name
|
||||
*/
|
||||
public function __construct( $slug, $name )
|
||||
{
|
||||
$this->tab_slug = $slug;
|
||||
$this->tab_name = $name;
|
||||
self::$tabs[$slug] = $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter - slug
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string Tab slug
|
||||
*/
|
||||
public function getSlug()
|
||||
{
|
||||
return $this->tab_slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter - name
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string Tab name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->tab_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render settings section
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
do_settings_sections( 'wp-fail2ban-' . $this->tab_slug );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper - tab
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $slug Tab slug
|
||||
*
|
||||
* @return Tab Tab
|
||||
*/
|
||||
public static function getTab( $slug )
|
||||
{
|
||||
return self::$tabs[$slug];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper - current tab
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $default Default slug
|
||||
*
|
||||
* @return Tab Tab
|
||||
*/
|
||||
public static function getActiveTab( $default = null )
|
||||
{
|
||||
if ( !empty(self::$active_tab) ) {
|
||||
return self::$active_tab;
|
||||
}
|
||||
return self::$active_tab = ( array_key_exists( @$_GET['tab'], self::$tabs ) ? self::$tabs[$_GET['tab']] : self::$tabs[$default] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper - tab name
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $slug Tab slug
|
||||
*
|
||||
* @return string Tab name
|
||||
*/
|
||||
public static function getTabName( $slug )
|
||||
{
|
||||
return self::getTab( $slug )->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Link to documentation
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param string $define
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function doc_link( $define, $name )
|
||||
{
|
||||
static $wp_f2b_ver ;
|
||||
if ( empty($wp_f2b_ver) ) {
|
||||
$wp_f2b_ver = substr( WP_FAIL2BAN_VER, 0, strrpos( WP_FAIL2BAN_VER, '.' ) );
|
||||
}
|
||||
return sprintf(
|
||||
'<a href="https://docs.wp-fail2ban.com/en/%s/defines/constants/%s.html" style="text-decoration: none;" target="_blank" title="Documentation"><span class="dashicons dashicons-external" style="vertical-align: text-bottom"></span></a> %s',
|
||||
$wp_f2b_ver,
|
||||
$define,
|
||||
$name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper - drop-down list of facilities
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $def Name of define for selected value
|
||||
* @param bool $_enabled Enabled?
|
||||
*/
|
||||
protected function getLogFacilities( $def, $_enabled = false )
|
||||
{
|
||||
$enabled = false;
|
||||
$facilities = [
|
||||
LOG_AUTH => 'LOG_AUTH',
|
||||
LOG_AUTHPRIV => 'LOG_AUTHPRIV',
|
||||
LOG_CRON => 'LOG_CRON',
|
||||
LOG_DAEMON => 'LOG_DAEMON',
|
||||
LOG_KERN => 'LOG_KERN',
|
||||
LOG_LOCAL0 => 'LOG_LOCAL0',
|
||||
LOG_LOCAL1 => 'LOG_LOCAL1',
|
||||
LOG_LOCAL2 => 'LOG_LOCAL2',
|
||||
LOG_LOCAL3 => 'LOG_LOCAL3',
|
||||
LOG_LOCAL4 => 'LOG_LOCAL4',
|
||||
LOG_LOCAL5 => 'LOG_LOCAL5',
|
||||
LOG_LOCAL6 => 'LOG_LOCAL6',
|
||||
LOG_LOCAL7 => 'LOG_LOCAL7',
|
||||
LOG_LPR => 'LOG_LPR',
|
||||
LOG_MAIL => 'LOG_MAIL',
|
||||
LOG_NEWS => 'LOG_NEWS',
|
||||
LOG_SYSLOG => 'LOG_SYSLOG',
|
||||
LOG_USER => 'LOG_USER',
|
||||
LOG_UUCP => 'LOG_UUCP',
|
||||
];
|
||||
$default = constant( "DEFAULT_{$def}" );
|
||||
$value = ( defined( $def ) ? constant( $def ) : $default );
|
||||
$str = '<select disabled="disabled">';
|
||||
foreach ( $facilities as $facility => $name ) {
|
||||
$str .= sprintf(
|
||||
'<option value="%s" %s>%s%s</option>',
|
||||
$facility,
|
||||
selected( $value, $facility, false ),
|
||||
$name,
|
||||
( $facility == $default ? __( ' (default)' ) : '' )
|
||||
);
|
||||
}
|
||||
$str .= '</select>';
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log helper - enable/disable+facility
|
||||
*
|
||||
* @since 4.2.0 Moved to Tab
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $define_name Name of define to enable logging
|
||||
* @param string $define_log Name of define for log facility
|
||||
* @param string $description Description
|
||||
* @param array $toggle Array of IDs to sync toggle state
|
||||
*/
|
||||
protected function log(
|
||||
$define_name,
|
||||
$define_log,
|
||||
$description = '',
|
||||
array $toggle = array()
|
||||
)
|
||||
{
|
||||
$enabled = defined( $define_name ) && true === constant( $define_name );
|
||||
$fmt = <<<___FMT___
|
||||
<label><input type="checkbox" disabled="disabled" %s> Enable logging</label>,
|
||||
<label>use facility: %s</label>
|
||||
<p class="description">%s</p>
|
||||
___FMT___;
|
||||
$html = sprintf(
|
||||
$fmt,
|
||||
checked( $enabled, true, false ),
|
||||
$this->getLogFacilities( $define_log ),
|
||||
$description
|
||||
);
|
||||
echo apply_filters(
|
||||
"wp_fail2ban_log_{$define_name}",
|
||||
$html,
|
||||
$define_name,
|
||||
$define_log
|
||||
) ;
|
||||
}
|
||||
|
||||
}
|
193
feature/comments.php
Normal file
193
feature/comments.php
Normal file
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Comment logging
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\notify_post_author' ) ) {
|
||||
/**
|
||||
* Log new comment
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param bool $maybe_notify
|
||||
* @param int $comment_ID
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @wp-f2b-extra Comment \d+
|
||||
*/
|
||||
function notify_post_author( $maybe_notify, $comment_ID )
|
||||
{
|
||||
openlog( 'WP_FAIL2BAN_COMMENT_LOG' );
|
||||
syslog( LOG_INFO, "Comment {$comment_ID}" );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
return $maybe_notify;
|
||||
}
|
||||
|
||||
add_filter(
|
||||
'notify_post_author',
|
||||
__NAMESPACE__ . '\\notify_post_author',
|
||||
10,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if ( defined( 'WP_FAIL2BAN_LOG_COMMENTS_EXTRA' ) ) {
|
||||
/** WPF2B_EVENT_COMMENT_NOT_FOUND */
|
||||
if ( WP_FAIL2BAN_LOG_COMMENTS_EXTRA & 0x20002 ) {
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\comment_id_not_found' ) ) {
|
||||
/**
|
||||
* Log attempted comment on non-existent post
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int $comment_post_ID
|
||||
*
|
||||
* @wp-f2b-extra Comment post not found \d+
|
||||
*/
|
||||
function comment_id_not_found( $comment_post_ID )
|
||||
{
|
||||
openlog( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' );
|
||||
syslog( LOG_NOTICE, "Comment post not found {$comment_post_ID}" );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
add_action( 'comment_id_not_found', __NAMESPACE__ . '\\comment_id_not_found' );
|
||||
}
|
||||
|
||||
}
|
||||
/** LOG_ACTION_LOG_COMMENT_CLOSED */
|
||||
if ( WP_FAIL2BAN_LOG_COMMENTS_EXTRA & 0x20004 ) {
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\comment_closed' ) ) {
|
||||
/**
|
||||
* Log attempted comment on closed post
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int $comment_post_ID
|
||||
*
|
||||
* @wp-f2b-extra Comments closed on post \d+
|
||||
*/
|
||||
function comment_closed( $comment_post_ID )
|
||||
{
|
||||
openlog( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' );
|
||||
syslog( LOG_NOTICE, "Comments closed on post {$comment_post_ID}" );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
add_action( 'comment_closed', __NAMESPACE__ . '\\comment_closed' );
|
||||
}
|
||||
|
||||
}
|
||||
/** LOG_ACTION_LOG_COMMENT_TRASH */
|
||||
if ( WP_FAIL2BAN_LOG_COMMENTS_EXTRA & 0x20008 ) {
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\comment_on_trash' ) ) {
|
||||
/**
|
||||
* Log attempted comment on trashed post
|
||||
*
|
||||
* @since 4.0.2 Fix message
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int $comment_post_ID
|
||||
*
|
||||
* @wp-f2b-extra Comment attempt on trash post \d+
|
||||
*/
|
||||
function comment_on_trash( $comment_post_ID )
|
||||
{
|
||||
openlog( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' );
|
||||
syslog( LOG_NOTICE, "Comment attempt on trash post {$comment_post_ID}" );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
add_action( 'comment_on_trash', __NAMESPACE__ . '\\comment_on_trash' );
|
||||
}
|
||||
|
||||
}
|
||||
/** LOG_ACTION_LOG_COMMENT_DRAFT */
|
||||
if ( WP_FAIL2BAN_LOG_COMMENTS_EXTRA & 0x20010 ) {
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\comment_on_draft' ) ) {
|
||||
/**
|
||||
* Log attempted comment on draft post
|
||||
*
|
||||
* @since 4.0.2 Fix message
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int $comment_post_ID
|
||||
*
|
||||
* @wp-f2b-extra Comment attempt on draft post \d+
|
||||
*/
|
||||
function comment_on_draft( $comment_post_ID )
|
||||
{
|
||||
openlog( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' );
|
||||
syslog( LOG_NOTICE, "Comment attempt on draft post {$comment_post_ID}" );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
add_action( 'comment_on_draft', __NAMESPACE__ . '\\comment_on_draft' );
|
||||
}
|
||||
|
||||
}
|
||||
/** LOG_ACTION_LOG_COMMENT_PASSWORD */
|
||||
if ( WP_FAIL2BAN_LOG_COMMENTS_EXTRA & 0x20020 ) {
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\comment_on_password_protected' ) ) {
|
||||
/**
|
||||
* Log attempted comment on password-protected post
|
||||
*
|
||||
* @since 4.0.2 Fix message
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int $comment_post_ID
|
||||
*
|
||||
* @wp-f2b-extra Comment attempt on password-protected post \d+
|
||||
*/
|
||||
function comment_on_password_protected( $comment_post_ID )
|
||||
{
|
||||
openlog( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' );
|
||||
syslog( LOG_NOTICE, "Comment attempt on password-protected post {$comment_post_ID}" );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
add_action( 'comment_on_password_protected', __NAMESPACE__ . '\\comment_on_password_protected' );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
144
feature/lib.php
Normal file
144
feature/lib.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Library functions
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* Wrapper for \openlog
|
||||
*
|
||||
* @since 3.5.0 Refactored for unit testing
|
||||
*
|
||||
* @param string $log
|
||||
*/
|
||||
function openlog( $log = 'WP_FAIL2BAN_AUTH_LOG' )
|
||||
{
|
||||
$tag = ( defined( 'WP_FAIL2BAN_SYSLOG_SHORT_TAG' ) && true === WP_FAIL2BAN_SYSLOG_SHORT_TAG ? 'wp' : 'wordpress' );
|
||||
$host = ( array_key_exists( 'WP_FAIL2BAN_HTTP_HOST', $_ENV ) ? $_ENV['WP_FAIL2BAN_HTTP_HOST'] : $_SERVER['HTTP_HOST'] );
|
||||
/**
|
||||
* Some varieties of syslogd have difficulty if $host is too long
|
||||
* @since 3.5.0
|
||||
*/
|
||||
if ( defined( 'WP_FAIL2BAN_TRUNCATE_HOST' ) && 1 < intval( WP_FAIL2BAN_TRUNCATE_HOST ) ) {
|
||||
$host = substr( $host, 0, intval( WP_FAIL2BAN_TRUNCATE_HOST ) );
|
||||
}
|
||||
|
||||
if ( false === \openlog( "{$tag}({$host})", WP_FAIL2BAN_OPENLOG_OPTIONS, constant( $log ) ) ) {
|
||||
error_log( 'WPf2b: Cannot open syslog', 0 );
|
||||
// @codeCoverageIgnore
|
||||
} elseif ( defined( 'WP_FAIL2BAN_TRACE' ) ) {
|
||||
error_log( 'WPf2b: Opened syslog', 0 );
|
||||
// @codeCoverageIgnore
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for \syslog
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param int $level
|
||||
* @param string $msg
|
||||
* @param string|null $remote_addr
|
||||
*/
|
||||
function syslog( $level, $msg, $remote_addr = null )
|
||||
{
|
||||
$msg .= ' from ';
|
||||
$msg .= ( is_null( $remote_addr ) ? remote_addr() : $remote_addr );
|
||||
|
||||
if ( false === \syslog( $level, $msg ) ) {
|
||||
error_log( "WPf2b: Cannot write to syslog: '{$msg}'", 0 );
|
||||
// @codeCoverageIgnore
|
||||
} elseif ( defined( 'WP_FAIL2BAN_TRACE' ) ) {
|
||||
error_log( "WPf2b: Wrote to syslog: '{$msg}'", 0 );
|
||||
// @codeCoverageIgnore
|
||||
}
|
||||
|
||||
\closelog();
|
||||
if ( defined( 'PHPUNIT_COMPOSER_INSTALL' ) ) {
|
||||
echo "{$level}|{$msg}" ;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Graceful immediate exit
|
||||
*
|
||||
* @since 4.0.5 Add JSON support
|
||||
* @since 3.5.0 Refactored for unit testing
|
||||
*
|
||||
* @param bool $is_json
|
||||
*/
|
||||
function bail( $is_json = false )
|
||||
{
|
||||
|
||||
if ( $is_json ) {
|
||||
return new \WP_Error( 403, 'Forbidden' );
|
||||
} else {
|
||||
wp_die( 'Forbidden', 'Forbidden', array(
|
||||
'response' => 403,
|
||||
) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute remote IP address
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @todo Test me!
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
function remote_addr()
|
||||
{
|
||||
static $remote_addr = null ;
|
||||
/**
|
||||
* @since 4.0.0
|
||||
*/
|
||||
|
||||
if ( is_null( $remote_addr ) ) {
|
||||
if ( defined( 'WP_FAIL2BAN_PROXIES' ) ) {
|
||||
|
||||
if ( array_key_exists( 'HTTP_X_FORWARDED_FOR', $_SERVER ) ) {
|
||||
$ip = ip2long( $_SERVER['REMOTE_ADDR'] );
|
||||
/**
|
||||
* PHP 7 lets you define an array
|
||||
* @since 3.5.4
|
||||
*/
|
||||
$proxies = ( is_array( WP_FAIL2BAN_PROXIES ) ? WP_FAIL2BAN_PROXIES : explode( ',', WP_FAIL2BAN_PROXIES ) );
|
||||
foreach ( $proxies as $proxy ) {
|
||||
|
||||
if ( '#' == $proxy[0] ) {
|
||||
continue;
|
||||
} elseif ( 2 == count( $cidr = explode( '/', $proxy ) ) ) {
|
||||
$net = ip2long( $cidr[0] );
|
||||
$mask = ~(pow( 2, 32 - $cidr[1] ) - 1);
|
||||
} else {
|
||||
$net = ip2long( $proxy );
|
||||
$mask = -1;
|
||||
}
|
||||
|
||||
if ( $net == ($ip & $mask) ) {
|
||||
return ( false === ($len = strpos( $_SERVER['HTTP_X_FORWARDED_FOR'], ',' )) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : substr( $_SERVER['HTTP_X_FORWARDED_FOR'], 0, $len ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* For plugins and themes that anonymise requests
|
||||
* @since 3.6.0
|
||||
*/
|
||||
$remote_addr = ( defined( 'WP_FAIL2BAN_REMOTE_ADDR' ) ? WP_FAIL2BAN_REMOTE_ADDR : $_SERVER['REMOTE_ADDR'] );
|
||||
}
|
||||
|
||||
return $remote_addr;
|
||||
}
|
37
feature/password.php
Normal file
37
feature/password.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Password-related functionality
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* @since 4.0.5
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\retrieve_password' ) ) {
|
||||
/**
|
||||
* Log password reset requests
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param string $user_login
|
||||
*
|
||||
* @wp-f2b-extra Password reset requested for .*
|
||||
*/
|
||||
function retrieve_password( $user_login )
|
||||
{
|
||||
openlog( 'WP_FAIL2BAN_PASSWORD_REQUEST_LOG' );
|
||||
syslog( LOG_NOTICE, "Password reset requested for {$user_login}" );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
add_action( 'retrieve_password', __NAMESPACE__ . '\\retrieve_password' );
|
||||
}
|
233
feature/plugins.php
Normal file
233
feature/plugins.php
Normal file
@ -0,0 +1,233 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Library functions
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.2.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* Hook: plugins_loaded
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
function plugins_loaded()
|
||||
{
|
||||
do_action( 'wp_fail2ban_register' );
|
||||
}
|
||||
|
||||
add_action( 'plugins_loaded', __NAMESPACE__ . '\\plugins_loaded' );
|
||||
/**
|
||||
* Register plugin
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param string $slug Plugin slug. This must be the actual plugin slug. Maximum length is 255 which should be more than enough.
|
||||
* @param string $name Plugin display name. This should be an unescaped string - HTML is allowed.
|
||||
*
|
||||
* @return int|false ID
|
||||
*/
|
||||
function register_plugin( $slug, $name )
|
||||
{
|
||||
global $wp_fail2ban, $wpdb ;
|
||||
if ( 255 < strlen( $slug ) ) {
|
||||
throw new \LengthException( 'slug too long' );
|
||||
}
|
||||
if ( 255 < strlen( $name ) ) {
|
||||
throw new \LengthException( 'name too long' );
|
||||
}
|
||||
if ( !is_array( @$wp_fail2ban['plugins'] ) ) {
|
||||
$wp_fail2ban['plugins'] = [];
|
||||
}
|
||||
if ( array_key_exists( $slug, $wp_fail2ban['plugins'] ) ) {
|
||||
return $wp_fail2ban['plugins'][$slug];
|
||||
}
|
||||
static $id = 0 ;
|
||||
return $wp_fail2ban['plugins'][$slug] = [
|
||||
'id' => ++$id,
|
||||
'name' => $name,
|
||||
'messages' => [],
|
||||
];
|
||||
}
|
||||
|
||||
add_action(
|
||||
'wp_fail2ban_register_plugin',
|
||||
__NAMESPACE__ . '\\register_plugin',
|
||||
1,
|
||||
2
|
||||
);
|
||||
/**
|
||||
* Check if plugin is registered.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param string $plugin_slug
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_registered_plugin( $plugin_slug )
|
||||
{
|
||||
global $wp_fail2ban ;
|
||||
return array_key_exists( $plugin_slug, $wp_fail2ban['plugins'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register plugin message.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param string $plugin_slug
|
||||
* @param array $msg [
|
||||
* string slug: Message slug
|
||||
* string fail: hard|soft|extra
|
||||
* int facility: syslog facility
|
||||
* int priority: syslog priority
|
||||
* string event_class: Event Class
|
||||
* int event_id: Event ID
|
||||
* string message: Message with placeholders
|
||||
* HOST: Remote IP
|
||||
* USER: Current user name
|
||||
* array vars: Array of [name => regex] pairs
|
||||
*/
|
||||
function register_message( $plugin_slug, array $msg )
|
||||
{
|
||||
global $wp_fail2ban ;
|
||||
$event_classes = [
|
||||
'auth' => WPF2B_EVENT_CLASS_AUTH,
|
||||
'comment' => WPF2B_EVENT_CLASS_COMMENT,
|
||||
'password' => WPF2B_EVENT_CLASS_PASSWORD,
|
||||
'rest' => WPF2B_EVENT_CLASS_REST,
|
||||
'spam' => WPF2B_EVENT_CLASS_SPAM,
|
||||
'xmlrpc' => WPF2B_EVENT_CLASS_XMLRPC,
|
||||
'other' => 0,
|
||||
];
|
||||
$args = [];
|
||||
if ( !is_registered_plugin( $plugin_slug ) ) {
|
||||
throw new \InvalidArgumentException( 'plugin not registered' );
|
||||
}
|
||||
if ( !array_key_exists( 'slug', $msg ) ) {
|
||||
throw new \InvalidArgumentException( "Missing 'slug'" );
|
||||
}
|
||||
if ( !is_string( $msg['slug'] ) ) {
|
||||
throw new \InvalidArgumentException( "'slug' must be string" );
|
||||
}
|
||||
if ( !array_key_exists( 'fail', $msg ) ) {
|
||||
throw new \InvalidArgumentException( "Missing 'fail'" );
|
||||
}
|
||||
if ( !in_array( $msg['fail'], [ 'hard', 'soft', 'extra' ] ) ) {
|
||||
throw new \UnexpectedValueException( "'fail' must be one of 'hard', 'soft', 'extra'" );
|
||||
}
|
||||
$args['fail'] = $msg['fail'];
|
||||
if ( !array_key_exists( 'priority', $msg ) ) {
|
||||
throw new \InvalidArgumentException( "Missing 'priority'" );
|
||||
}
|
||||
if ( !in_array( $msg['priority'], [
|
||||
LOG_CRIT,
|
||||
LOG_ERR,
|
||||
LOG_WARNING,
|
||||
LOG_NOTICE,
|
||||
LOG_INFO,
|
||||
LOG_DEBUG
|
||||
] ) ) {
|
||||
throw new \UnexpectedValueException( "Invalid 'priority'" );
|
||||
}
|
||||
$args['priority'] = $msg['priority'];
|
||||
if ( !array_key_exists( 'event_class', $msg ) ) {
|
||||
throw new \InvalidArgumentException( "Missing 'event_class'" );
|
||||
}
|
||||
if ( !array_key_exists( $event_class = strtolower( $msg['event_class'] ), $event_classes ) ) {
|
||||
throw new \UnexpectedValueException( "Invalid 'event_class'" );
|
||||
}
|
||||
$args['class'] = $event_class;
|
||||
$event_class = $event_classes[$event_class];
|
||||
$log = sprintf( "WP_FAIL2BAN_%s_LOG", strtoupper( $event_class ) );
|
||||
if ( !array_key_exists( 'event_id', $msg ) ) {
|
||||
throw new \InvalidArgumentException( "Missing 'event_id'" );
|
||||
}
|
||||
if ( ($msg['event_id'] & 0xffff) !== $msg['event_id'] ) {
|
||||
throw new \UnexpectedValueException( "Invalid 'event_id'" );
|
||||
}
|
||||
$args['event_id'] = WPF2B_EVENT_TYPE_PLUGIN | $event_class | $msg['event_id'];
|
||||
if ( !array_key_exists( 'message', $msg ) ) {
|
||||
throw new \InvalidArgumentException( "Missing 'message'" );
|
||||
}
|
||||
if ( !is_string( $msg['message'] ) ) {
|
||||
throw new \UnexpectedValueException( "Invalid 'message'" );
|
||||
}
|
||||
$args['message'] = $msg['message'];
|
||||
if ( !array_key_exists( 'vars', $msg ) ) {
|
||||
throw new \InvalidArgumentException( "Missing 'vars'" );
|
||||
}
|
||||
if ( !is_array( $msg['vars'] ) ) {
|
||||
throw new \UnexpectedValueException( "Invalid 'vars'" );
|
||||
}
|
||||
$args['vars'] = $msg['vars'];
|
||||
$wp_fail2ban['plugins'][$plugin_slug]['messages'][$msg['slug']] = $args;
|
||||
}
|
||||
|
||||
add_action(
|
||||
'wp_fail2ban_register_message',
|
||||
__NAMESPACE__ . '\\register_message',
|
||||
1,
|
||||
2
|
||||
);
|
||||
/**
|
||||
* Check if message is registered.
|
||||
*
|
||||
* NB: Assumes plugin is registered.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param string $plugin_slug
|
||||
* @param string $message_slug
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_registered_plugin_message( $plugin_slug, $message_slug )
|
||||
{
|
||||
global $wp_fail2ban ;
|
||||
return array_key_exists( $message_slug, $wp_fail2ban['plugins'][$plugin_slug]['messages'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Log plugin message.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param string $plugin_slug Plugin slug for registered message
|
||||
* @param string $message_slug Message slug for registered message
|
||||
* @param array $vars Substitution vars
|
||||
*/
|
||||
function log_message( $plugin_slug, $message_slug = null, array $vars = array() )
|
||||
{
|
||||
global $wp_fail2ban ;
|
||||
if ( !is_registered_plugin( $plugin_slug ) ) {
|
||||
throw new \InvalidArgumentException( 'plugin not registered' );
|
||||
}
|
||||
if ( !is_registered_plugin_message( $plugin_slug, $message_slug ) ) {
|
||||
throw new \InvalidArgumentException( 'message not registered' );
|
||||
}
|
||||
$args = $wp_fail2ban['plugins'][$plugin_slug]['messages'][$message_slug];
|
||||
$msg = $args['message'];
|
||||
foreach ( $args['vars'] as $name => $regex ) {
|
||||
if ( array_key_exists( $name, $vars ) ) {
|
||||
$msg = str_replace( "___{$name}___", $vars[$name], $msg );
|
||||
}
|
||||
}
|
||||
openlog( sprintf( 'WP_FAIL2BAN_PLUGIN_%s_LOG', strtoupper( $args['class'] ) ) );
|
||||
syslog( $args['priority'], "({$plugin_slug}) {$msg}" );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
add_action(
|
||||
'wp_fail2ban_log_message',
|
||||
__NAMESPACE__ . '\\log_message',
|
||||
1,
|
||||
3
|
||||
);
|
60
feature/spam.php
Normal file
60
feature/spam.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Spam comments
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* @since 4.0.5
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\log_spam_comment' ) ) {
|
||||
/**
|
||||
* Catch comments marked as spam
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param int $comment_id
|
||||
* @param string $comment_status
|
||||
*
|
||||
* @wp-f2b-hard Spam comment \d+
|
||||
*/
|
||||
function log_spam_comment( $comment_id, $comment_status )
|
||||
{
|
||||
if ( 'spam' === $comment_status ) {
|
||||
|
||||
if ( is_null( $comment = get_comment( $comment_id, ARRAY_A ) ) ) {
|
||||
/**
|
||||
* @todo: decide what to do about this
|
||||
*/
|
||||
} else {
|
||||
$remote_addr = ( empty($comment['comment_author_IP']) ? 'unknown' : $comment['comment_author_IP'] );
|
||||
openlog( 'WP_FAIL2BAN_SPAM_LOG' );
|
||||
syslog( LOG_NOTICE, "Spam comment {$comment_id}", $remote_addr );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
add_action(
|
||||
'comment_post',
|
||||
__NAMESPACE__ . '\\log_spam_comment',
|
||||
10,
|
||||
2
|
||||
);
|
||||
add_action(
|
||||
'wp_set_comment_status',
|
||||
__NAMESPACE__ . '\\log_spam_comment',
|
||||
10,
|
||||
2
|
||||
);
|
||||
}
|
104
feature/user-enum.php
Normal file
104
feature/user-enum.php
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* User enumeration
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
if ( !function_exists( __NAMESPACE__ . '\\_log_bail_user_enum' ) ) {
|
||||
/**
|
||||
* Common enumeration handling
|
||||
*
|
||||
* @since 4.1.0 Add JSON support
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param bool $is_json
|
||||
*
|
||||
* @return \WP_Error
|
||||
*
|
||||
* @wp-f2b-hard Blocked user enumeration attempt
|
||||
*/
|
||||
function _log_bail_user_enum( $is_json = false )
|
||||
{
|
||||
openlog();
|
||||
syslog( LOG_NOTICE, 'Blocked user enumeration attempt' );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
return bail( $is_json );
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\parse_request' ) ) {
|
||||
/**
|
||||
* Catch traditional user enum
|
||||
*
|
||||
* @see \WP::parse_request()
|
||||
*
|
||||
* @since 3.5.0 Refactored for unit testing
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @param \WP $query
|
||||
*
|
||||
* @return \WP
|
||||
*/
|
||||
function parse_request( $query )
|
||||
{
|
||||
if ( !current_user_can( 'list_users' ) && intval( @$query->query_vars['author'] ) ) {
|
||||
_log_bail_user_enum();
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
add_filter(
|
||||
'parse_request',
|
||||
__NAMESPACE__ . '\\parse_request',
|
||||
1,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\rest_user_query' ) ) {
|
||||
/**
|
||||
* Catch RESTful user list
|
||||
*
|
||||
* @see \WP_REST_Users_Controller::get_items()
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $prepared_args
|
||||
* @param \WP_REST_Request $request
|
||||
*
|
||||
* @return array|\WP_Error
|
||||
*/
|
||||
function rest_user_query( $prepared_args, $request )
|
||||
{
|
||||
if ( !current_user_can( 'list_users' ) ) {
|
||||
return _log_bail_user_enum( true );
|
||||
}
|
||||
return $prepared_args;
|
||||
}
|
||||
|
||||
add_filter(
|
||||
'rest_user_query',
|
||||
__NAMESPACE__ . '\\rest_user_query',
|
||||
10,
|
||||
2
|
||||
);
|
||||
}
|
61
feature/user.php
Normal file
61
feature/user.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Blocked user functionality
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\authenticate' ) ) {
|
||||
/**
|
||||
* Catched blocked users
|
||||
*
|
||||
* @since 3.5.0 Refactored for unit testing
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param mixed|null $user
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*
|
||||
* @return mixed|null
|
||||
*
|
||||
* @wp-f2b-hard Blocked authentication attempt for .*
|
||||
*/
|
||||
function authenticate( $user, $username, $password )
|
||||
{
|
||||
|
||||
if ( !empty($username) ) {
|
||||
/**
|
||||
* @since 3.5.0 Arrays allowed in PHP 7
|
||||
*/
|
||||
$matched = ( is_array( WP_FAIL2BAN_BLOCKED_USERS ) ? in_array( $username, WP_FAIL2BAN_BLOCKED_USERS ) : preg_match( '/' . WP_FAIL2BAN_BLOCKED_USERS . '/i', $username ) );
|
||||
|
||||
if ( $matched ) {
|
||||
openlog();
|
||||
syslog( LOG_NOTICE, "Blocked authentication attempt for {$username}" );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
bail();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
add_filter(
|
||||
'authenticate',
|
||||
__NAMESPACE__ . '\\authenticate',
|
||||
1,
|
||||
3
|
||||
);
|
||||
}
|
108
feature/xmlrpc.php
Normal file
108
feature/xmlrpc.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* XML-RPC functionality
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\xmlrpc_login_error' ) ) {
|
||||
/**
|
||||
* Catch multiple XML-RPC authentication failures
|
||||
*
|
||||
* @see \wp_xmlrpc_server::login()
|
||||
*
|
||||
* @since 4.0.0 Return $error
|
||||
* @since 3.5.0 Refactored for unit testing
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param \IXR_Error $error
|
||||
* @param \WP_Error $user
|
||||
*
|
||||
* @return \IXR_Error
|
||||
*
|
||||
* @wp-f2b-hard XML-RPC multicall authentication failure
|
||||
*/
|
||||
function xmlrpc_login_error( $error, $user )
|
||||
{
|
||||
static $attempts = 0 ;
|
||||
|
||||
if ( ++$attempts > 1 ) {
|
||||
openlog();
|
||||
syslog( LOG_NOTICE, 'XML-RPC multicall authentication failure' );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
bail();
|
||||
} else {
|
||||
return $error;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
add_action(
|
||||
'xmlrpc_login_error',
|
||||
__NAMESPACE__ . '\\xmlrpc_login_error',
|
||||
10,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\xmlrpc_pingback_error' ) ) {
|
||||
/**
|
||||
* Catch failed pingbacks
|
||||
*
|
||||
* @see \wp_xmlrpc_server::pingback_error()
|
||||
*
|
||||
* @since 4.0.0 Return $ixr_error
|
||||
* @since 3.5.0 Refactored for unit testing
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param \IXR_Error $ixr_error
|
||||
*
|
||||
* @return \IXR_Error
|
||||
*
|
||||
* @wp-f2b-hard Pingback error .* generated
|
||||
*/
|
||||
function xmlrpc_pingback_error( $ixr_error )
|
||||
{
|
||||
|
||||
if ( 48 !== $ixr_error->code ) {
|
||||
openlog();
|
||||
syslog( LOG_NOTICE, 'Pingback error ' . $ixr_error->code . ' generated' );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $ixr_error;
|
||||
}
|
||||
|
||||
add_filter( 'xmlrpc_pingback_error', __NAMESPACE__ . '\\xmlrpc_pingback_error', 5 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0.0 Refactored
|
||||
* @since 2.2.0
|
||||
*/
|
||||
if ( defined( 'WP_FAIL2BAN_LOG_PINGBACKS' ) && true === WP_FAIL2BAN_LOG_PINGBACKS ) {
|
||||
require_once 'xmlrpc/pingback.php';
|
||||
}
|
||||
/**
|
||||
* @since 4.0.0 Refactored
|
||||
* @since 3.6.0
|
||||
*/
|
||||
if ( defined( 'WP_FAIL2BAN_XMLRPC_LOG' ) && '' < WP_FAIL2BAN_XMLRPC_LOG ) {
|
||||
require_once 'xmlrpc/log.php';
|
||||
}
|
35
feature/xmlrpc/log.php
Normal file
35
feature/xmlrpc/log.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* XML-RPC Request logging
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log XML-RPC requests
|
||||
*
|
||||
* It seems attackers are doing weird things with XML-RPC. This makes it easy to
|
||||
* log them for analysis and future blocking.
|
||||
*
|
||||
* @since 4.0.0 Fix: Removed HTTP_RAW_POST_DATA
|
||||
* https://wordpress.org/support/?p=10971843
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
if (false === ($fp = fopen(WP_FAIL2BAN_XMLRPC_LOG, 'a+'))) {
|
||||
// TODO: decided whether to log this
|
||||
} else {
|
||||
$raw_data = (version_compare(PHP_VERSION, '7.0.0') >= 0)
|
||||
? file_get_contents('php://input')
|
||||
: $HTTP_RAW_POST_DATA;
|
||||
|
||||
fprintf($fp, "# ---\n# Date: %s\n# IP: %s\n\n%s\n", date(DATE_ATOM), remote_addr(), $raw_data);
|
||||
fclose($fp);
|
||||
}
|
40
feature/xmlrpc/pingback.php
Normal file
40
feature/xmlrpc/pingback.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* pingback logging
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.0.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
/**
|
||||
* @since 4.0.5 Guard
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\xmlrpc_call' ) ) {
|
||||
/**
|
||||
* Log pingbacks
|
||||
*
|
||||
* @since 3.5.0 Refactored for unit testing
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @param string $call
|
||||
*/
|
||||
function xmlrpc_call( $call )
|
||||
{
|
||||
|
||||
if ( 'pingback.ping' == $call ) {
|
||||
openlog( 'WP_FAIL2BAN_PINGBACK_LOG' );
|
||||
syslog( LOG_INFO, 'Pingback requested' );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
add_action( 'xmlrpc_call', __NAMESPACE__ . '\\xmlrpc_call' );
|
||||
}
|
27
filters.d/wordpress-extra.conf
Normal file
27
filters.d/wordpress-extra.conf
Normal file
@ -0,0 +1,27 @@
|
||||
# Fail2Ban filter for WordPress extra failures
|
||||
# Auto-generated: 2019-07-15T18:00:14+00:00
|
||||
#
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
before = common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
_daemon = (?:wordpress|wp)
|
||||
|
||||
failregex = ^%(__prefix_line)sComment \d+ from <HOST>$
|
||||
^%(__prefix_line)sComment post not found \d+ from <HOST>$
|
||||
^%(__prefix_line)sComments closed on post \d+ from <HOST>$
|
||||
^%(__prefix_line)sComment attempt on trash post \d+ from <HOST>$
|
||||
^%(__prefix_line)sComment attempt on draft post \d+ from <HOST>$
|
||||
^%(__prefix_line)sComment attempt on password-protected post \d+ from <HOST>$
|
||||
^%(__prefix_line)sPassword reset requested for .* from <HOST>$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
# DEV Notes:
|
||||
# Requires the 'WP fail2ban' plugin:
|
||||
# https://wp-fail2ban.com/
|
||||
#
|
||||
# Author: Charles Lecklider
|
28
filters.d/wordpress-hard.conf
Normal file
28
filters.d/wordpress-hard.conf
Normal file
@ -0,0 +1,28 @@
|
||||
# Fail2Ban filter for WordPress hard failures
|
||||
# Auto-generated: 2019-07-15T18:00:14+00:00
|
||||
#
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
before = common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
_daemon = (?:wordpress|wp)
|
||||
|
||||
failregex = ^%(__prefix_line)sAuthentication attempt for unknown user .* from <HOST>$
|
||||
^%(__prefix_line)sREST authentication attempt for unknown user .* from <HOST>$
|
||||
^%(__prefix_line)sXML-RPC authentication attempt for unknown user .* from <HOST>$
|
||||
^%(__prefix_line)sSpam comment \d+ from <HOST>$
|
||||
^%(__prefix_line)sBlocked user enumeration attempt from <HOST>$
|
||||
^%(__prefix_line)sBlocked authentication attempt for .* from <HOST>$
|
||||
^%(__prefix_line)sXML-RPC multicall authentication failure from <HOST>$
|
||||
^%(__prefix_line)sPingback error .* generated from <HOST>$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
# DEV Notes:
|
||||
# Requires the 'WP fail2ban' plugin:
|
||||
# https://wp-fail2ban.com/
|
||||
#
|
||||
# Author: Charles Lecklider
|
23
filters.d/wordpress-soft.conf
Normal file
23
filters.d/wordpress-soft.conf
Normal file
@ -0,0 +1,23 @@
|
||||
# Fail2Ban filter for WordPress soft failures
|
||||
# Auto-generated: 2019-07-15T18:00:14+00:00
|
||||
#
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
before = common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
_daemon = (?:wordpress|wp)
|
||||
|
||||
failregex = ^%(__prefix_line)sAuthentication failure for .* from <HOST>$
|
||||
^%(__prefix_line)sREST authentication failure for .* from <HOST>$
|
||||
^%(__prefix_line)sXML-RPC authentication failure for .* from <HOST>$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
# DEV Notes:
|
||||
# Requires the 'WP fail2ban' plugin:
|
||||
# https://wp-fail2ban.com/
|
||||
#
|
||||
# Author: Charles Lecklider
|
144
lib/constants.php
Normal file
144
lib/constants.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* Constants
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.2.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
|
||||
/**
|
||||
* Defaults
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
define('DEFAULT_WP_FAIL2BAN_OPENLOG_OPTIONS', LOG_PID|LOG_NDELAY);
|
||||
define('DEFAULT_WP_FAIL2BAN_AUTH_LOG', LOG_AUTH);
|
||||
define('DEFAULT_WP_FAIL2BAN_COMMENT_LOG', LOG_USER);
|
||||
define('DEFAULT_WP_FAIL2BAN_PINGBACK_LOG', LOG_USER);
|
||||
define('DEFAULT_WP_FAIL2BAN_PASSWORD_REQUEST_LOG', LOG_USER);
|
||||
define('DEFAULT_WP_FAIL2BAN_SPAM_LOG', LOG_AUTH);
|
||||
/**
|
||||
* @since 4.0.5
|
||||
*/
|
||||
define('DEFAULT_WP_FAIL2BAN_COMMENT_EXTRA_LOG', LOG_AUTH);
|
||||
define('DEFAULT_WP_FAIL2BAN_PINGBACK_ERROR_LOG', LOG_AUTH);
|
||||
/**
|
||||
* @since 4.2.0
|
||||
*/
|
||||
define('DEFAULT_WP_FAIL2BAN_PLUGIN_AUTH_LOG', LOG_AUTH);
|
||||
define('DEFAULT_WP_FAIL2BAN_PLUGIN_COMMENT_LOG', LOG_USER);
|
||||
define('DEFAULT_WP_FAIL2BAN_PLUGIN_OTHER_LOG', LOG_USER);
|
||||
define('DEFAULT_WP_FAIL2BAN_PLUGIN_PASSWORD_LOG', LOG_USER);
|
||||
define('DEFAULT_WP_FAIL2BAN_PLUGIN_REST_LOG', LOG_USER);
|
||||
define('DEFAULT_WP_FAIL2BAN_PLUGIN_SPAM_LOG', LOG_AUTH);
|
||||
define('DEFAULT_WP_FAIL2BAN_PLUGIN_XMLRPC_LOG', LOG_USER);
|
||||
|
||||
/*
|
||||
31 | Test
|
||||
30 | Plugin
|
||||
29 |
|
||||
28 |
|
||||
27 |
|
||||
26 |
|
||||
25 |
|
||||
24 |
|
||||
---
|
||||
23 | Event Class
|
||||
22 | ..
|
||||
21 | ..
|
||||
20 | ..
|
||||
19 | ..
|
||||
18 | ..
|
||||
17 | ..
|
||||
16 | ..
|
||||
---
|
||||
15 | ID
|
||||
14 | ..
|
||||
13 | ..
|
||||
12 | ..
|
||||
11 | ..
|
||||
10 | ..
|
||||
09 | ..
|
||||
08 | ..
|
||||
---
|
||||
07 | ..
|
||||
06 | ..
|
||||
05 | ..
|
||||
04 | ..
|
||||
03 | ..
|
||||
02 | ..
|
||||
01 | ..
|
||||
00 | ..
|
||||
*/
|
||||
|
||||
|
||||
|
||||
define('WPF2B_EVENT_CLASS_AUTH', 0x00010000);
|
||||
define('WPF2B_EVENT_CLASS_COMMENT', 0x00020000);
|
||||
define('WPF2B_EVENT_CLASS_XMLRPC', 0x00040000);
|
||||
define('WPF2B_EVENT_CLASS_PASSWORD', 0x00080000);
|
||||
define('WPF2B_EVENT_CLASS_REST', 0x00100000); /** @since 4.1.0 */
|
||||
define('WPF2B_EVENT_CLASS_SPAM', 0x00200000); /** @since 4.2.0 */
|
||||
define('WPF2B_EVENT_TYPE_PLUGIN', 0x40000000); /** @since 4.2.0 */
|
||||
define('WPF2B_EVENT_TYPE_TEST', 0x80000000); /** @since 4.2.0 */
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
define('WPF2B_EVENT_ACTIVATED', 0xffffffff);
|
||||
|
||||
|
||||
/**
|
||||
* Auth
|
||||
*/
|
||||
define('WPF2B_EVENT_AUTH_OK', WPF2B_EVENT_CLASS_AUTH | 0x0001);
|
||||
define('WPF2B_EVENT_AUTH_FAIL', WPF2B_EVENT_CLASS_AUTH | 0x0002);
|
||||
define('WPF2B_EVENT_AUTH_BLOCK_USER', WPF2B_EVENT_CLASS_AUTH | 0x0004);
|
||||
define('WPF2B_EVENT_AUTH_BLOCK_USER_ENUM', WPF2B_EVENT_CLASS_AUTH | 0x0008);
|
||||
|
||||
/**
|
||||
* Comment
|
||||
*/
|
||||
define('WPF2B_EVENT_COMMENT', WPF2B_EVENT_CLASS_COMMENT | 0x0001); // 0x00020001
|
||||
define('WPF2B_EVENT_COMMENT_SPAM', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_CLASS_SPAM | 0x0001); // 0x00220001
|
||||
// comment extra
|
||||
define('WPF2B_EVENT_COMMENT_NOT_FOUND', WPF2B_EVENT_CLASS_COMMENT | 0x0002); // 0x00020002
|
||||
define('WPF2B_EVENT_COMMENT_CLOSED', WPF2B_EVENT_CLASS_COMMENT | 0x0004); // 0x00020004
|
||||
define('WPF2B_EVENT_COMMENT_TRASH', WPF2B_EVENT_CLASS_COMMENT | 0x0008); // 0x00020008
|
||||
define('WPF2B_EVENT_COMMENT_DRAFT', WPF2B_EVENT_CLASS_COMMENT | 0x0010); // 0x00020010
|
||||
define('WPF2B_EVENT_COMMENT_PASSWORD', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_CLASS_PASSWORD | 0x0020); // 0x00020020
|
||||
|
||||
/**
|
||||
* XML-RPC
|
||||
*/
|
||||
define('WPF2B_EVENT_XMLRPC_PINGBACK', WPF2B_EVENT_CLASS_XMLRPC | 0x0001);
|
||||
define('WPF2B_EVENT_XMLRPC_PINGBACK_ERROR', WPF2B_EVENT_CLASS_XMLRPC | 0x0002);
|
||||
define('WPF2B_EVENT_XMLRPC_MULTI_AUTH_FAIL', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | 0x0004);
|
||||
define('WPF2B_EVENT_XMLRPC_AUTH_OK', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | 0x0008);
|
||||
define('WPF2B_EVENT_XMLRPC_AUTH_FAIL', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | 0x0010);
|
||||
|
||||
/**
|
||||
* Password
|
||||
*/
|
||||
define('WPF2B_ACTION_PASSWORD_REQUEST', WPF2B_EVENT_CLASS_PASSWORD | 0x0001);
|
||||
|
||||
/**
|
||||
* REST
|
||||
* @since 4.1.0
|
||||
*/
|
||||
define('WPF2B_EVENT_REST_AUTH_OK', WPF2B_EVENT_CLASS_REST | WPF2B_EVENT_CLASS_AUTH | 0x0001);
|
||||
define('WPF2B_EVENT_REST_AUTH_FAIL', WPF2B_EVENT_CLASS_REST | WPF2B_EVENT_CLASS_AUTH | 0x0002);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
define('WPF2B_EVENT_DEACTIVATED', 0x00000000);
|
||||
// phpcs:enable
|
||||
|
79
lib/defaults.php
Normal file
79
lib/defaults.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* Default Constants
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.2.0
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow custom openlog options.
|
||||
* e.g. you may not want the PID if logging remotely.
|
||||
*
|
||||
* @since 3.6.0 Add LOG_NDELAY
|
||||
* @since 3.5.0
|
||||
*/
|
||||
if (!defined('WP_FAIL2BAN_OPENLOG_OPTIONS')) {
|
||||
define('WP_FAIL2BAN_OPENLOG_OPTIONS', DEFAULT_WP_FAIL2BAN_OPENLOG_OPTIONS);
|
||||
}
|
||||
/**
|
||||
* Make sure all custom logs are defined.
|
||||
* @since 3.5.0
|
||||
*/
|
||||
if (!defined('WP_FAIL2BAN_AUTH_LOG')) {
|
||||
define('WP_FAIL2BAN_AUTH_LOG', DEFAULT_WP_FAIL2BAN_AUTH_LOG);
|
||||
}
|
||||
if (!defined('WP_FAIL2BAN_COMMENT_LOG')) {
|
||||
define('WP_FAIL2BAN_COMMENT_LOG', DEFAULT_WP_FAIL2BAN_COMMENT_LOG);
|
||||
}
|
||||
if (!defined('WP_FAIL2BAN_PINGBACK_LOG')) {
|
||||
define('WP_FAIL2BAN_PINGBACK_LOG', DEFAULT_WP_FAIL2BAN_PINGBACK_LOG);
|
||||
}
|
||||
/**
|
||||
* @since 4.0.0
|
||||
*/
|
||||
if (!defined('WP_FAIL2BAN_PASSWORD_REQUEST_LOG')) {
|
||||
define('WP_FAIL2BAN_PASSWORD_REQUEST_LOG', DEFAULT_WP_FAIL2BAN_PASSWORD_REQUEST_LOG);
|
||||
}
|
||||
if (!defined('WP_FAIL2BAN_SPAM_LOG')) {
|
||||
define('WP_FAIL2BAN_SPAM_LOG', DEFAULT_WP_FAIL2BAN_SPAM_LOG);
|
||||
}
|
||||
/**
|
||||
* @since 4.0.5
|
||||
*/
|
||||
if (!defined('WP_FAIL2BAN_COMMENT_EXTRA_LOG')) {
|
||||
define('WP_FAIL2BAN_COMMENT_EXTRA_LOG', DEFAULT_WP_FAIL2BAN_COMMENT_EXTRA_LOG);
|
||||
}
|
||||
if (!defined('WP_FAIL2BAN_PINGBACK_ERROR_LOG')) {
|
||||
define('WP_FAIL2BAN_PINGBACK_ERROR_LOG', DEFAULT_WP_FAIL2BAN_PINGBACK_ERROR_LOG);
|
||||
}
|
||||
/**
|
||||
* @since 4.2.0
|
||||
*/
|
||||
if (!defined('WP_FAIL2BAN_PLUGIN_AUTH_LOG')) {
|
||||
define('WP_FAIL2BAN_PLUGIN_AUTH_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_AUTH_LOG);
|
||||
}
|
||||
if (!defined('WP_FAIL2BAN_PLUGIN_COMMENT_LOG')) {
|
||||
define('WP_FAIL2BAN_PLUGIN_COMMENT_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_COMMENT_LOG);
|
||||
}
|
||||
if (!defined('WP_FAIL2BAN_PLUGIN_OTHER_LOG')) {
|
||||
define('WP_FAIL2BAN_PLUGIN_OTHER_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_OTHER_LOG);
|
||||
}
|
||||
if (!defined('WP_FAIL2BAN_PLUGIN_PASSWORD_LOG')) {
|
||||
define('WP_FAIL2BAN_PLUGIN_PASSWORD_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_PASSWORD_LOG);
|
||||
}
|
||||
if (!defined('WP_FAIL2BAN_PLUGIN_REST_LOG')) {
|
||||
define('WP_FAIL2BAN_PLUGIN_REST_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_REST_LOG);
|
||||
}
|
||||
if (!defined('WP_FAIL2BAN_PLUGIN_SPAM_LOG')) {
|
||||
define('WP_FAIL2BAN_PLUGIN_SPAM_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_SPAM_LOG);
|
||||
}
|
||||
if (!defined('WP_FAIL2BAN_PLUGIN_XMLRPC_LOG')) {
|
||||
define('WP_FAIL2BAN_PLUGIN_XMLRPC_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_XMLRPC_LOG);
|
||||
}
|
||||
|
327
lib/loader.php
Normal file
327
lib/loader.php
Normal file
@ -0,0 +1,327 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Loader
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
* @since 4.2.0
|
||||
*/
|
||||
namespace {
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
if ( defined( 'PHPUNIT_COMPOSER_INSTALL' ) ) {
|
||||
return;
|
||||
}
|
||||
if ( !function_exists( 'boolval' ) ) {
|
||||
/**
|
||||
* PHP 5.3 helper
|
||||
*
|
||||
* @since 4.2.5
|
||||
*
|
||||
* @param mixed $val
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function boolval( $val )
|
||||
{
|
||||
return (bool) $val;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban {
|
||||
/**
|
||||
* Helper
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $define
|
||||
* @param callable $cast
|
||||
* @param bool $unset
|
||||
* @param array $field
|
||||
*/
|
||||
function _load(
|
||||
$define,
|
||||
$cast,
|
||||
$unset,
|
||||
array $field
|
||||
)
|
||||
{
|
||||
global $wp_fail2ban ;
|
||||
$wp_fail2ban['config'][$define] = array(
|
||||
'validate' => $cast,
|
||||
'unset' => $unset,
|
||||
'field' => $field,
|
||||
'ndef' => !defined( $define ),
|
||||
);
|
||||
if ( !defined( $define ) ) {
|
||||
|
||||
if ( defined( "DEFAULT_{$define}" ) ) {
|
||||
// we've got a default
|
||||
define( $define, $cast( constant( "DEFAULT_{$define}" ) ) );
|
||||
} else {
|
||||
// bah
|
||||
define( $define, $cast( false ) );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate IP list
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array|string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function validate_ips( $value )
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
// phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
|
||||
_load(
|
||||
'WP_FAIL2BAN_AUTH_LOG',
|
||||
'intval',
|
||||
true,
|
||||
array( 'logging', 'authentication', 'facility' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_LOG_COMMENTS',
|
||||
'boolval',
|
||||
true,
|
||||
array( 'logging', 'comments', 'enabled' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_LOG_COMMENTS_EXTRA',
|
||||
'intval',
|
||||
true,
|
||||
array( 'logging', 'comments', 'extra' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_COMMENT_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array( 'logging', 'comments', 'facility' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_COMMENT_EXTRA_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array( 'logging', 'comments-extra', 'facility' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_LOG_PASSWORD_REQUEST',
|
||||
'boolval',
|
||||
true,
|
||||
array( 'logging', 'password-request', 'enabled' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PASSWORD_REQUEST_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array( 'logging', 'password-request', 'facility' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_LOG_PINGBACKS',
|
||||
'boolval',
|
||||
true,
|
||||
array( 'logging', 'pingback', 'enabled' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PINGBACK_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array( 'logging', 'pingback', 'facility' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_LOG_SPAM',
|
||||
'boolval',
|
||||
true,
|
||||
array( 'logging', 'spam', 'enabled' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_SPAM_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array( 'logging', 'spam', 'facility' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_OPENLOG_OPTIONS',
|
||||
'intval',
|
||||
true,
|
||||
array( 'syslog', 'connection' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_SYSLOG_SHORT_TAG',
|
||||
'boolval',
|
||||
true,
|
||||
array( 'syslog', 'workaround', 'short_tag' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_HTTP_HOST',
|
||||
'boolval',
|
||||
true,
|
||||
array( 'syslog', 'workaround', 'http_host' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_TRUNCATE_HOST',
|
||||
'boolval',
|
||||
true,
|
||||
array( 'syslog', 'workaround', 'truncate_host' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_BLOCK_USER_ENUMERATION',
|
||||
'boolval',
|
||||
true,
|
||||
array( 'block', 'user_enumeration' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_BLOCKED_USERS',
|
||||
'strval',
|
||||
true,
|
||||
array( 'block', 'users' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PROXIES',
|
||||
__NAMESPACE__ . '\\validate_ips',
|
||||
true,
|
||||
array( 'remote-ip', 'proxies' )
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_LOG_AUTH',
|
||||
'boolval',
|
||||
true,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'auth',
|
||||
'enabled'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_LOG_COMMENT',
|
||||
'boolval',
|
||||
true,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'comment',
|
||||
'enabled'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_LOG_PASSWORD',
|
||||
'boolval',
|
||||
true,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'password',
|
||||
'enabled'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_LOG_REST',
|
||||
'boolval',
|
||||
true,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'rest',
|
||||
'enabled'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_LOG_SPAM',
|
||||
'boolval',
|
||||
true,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'spam',
|
||||
'enabled'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_LOG_XMLRPC',
|
||||
'boolval',
|
||||
true,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'xmlrpc',
|
||||
'enabled'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_AUTH_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'auth',
|
||||
'facility'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_COMMENT_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'comment',
|
||||
'facility'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_PASSWORD_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'password',
|
||||
'facility'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_REST_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'rest',
|
||||
'facility'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_SPAM_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'spam',
|
||||
'facility'
|
||||
)
|
||||
);
|
||||
_load(
|
||||
'WP_FAIL2BAN_PLUGIN_XMLRPC_LOG',
|
||||
'intval',
|
||||
false,
|
||||
array(
|
||||
'logging',
|
||||
'plugins',
|
||||
'xmlrpc',
|
||||
'facility'
|
||||
)
|
||||
);
|
||||
// phpcs:enable
|
||||
}
|
280
readme.txt
Normal file
280
readme.txt
Normal file
@ -0,0 +1,280 @@
|
||||
=== WP fail2ban ===
|
||||
Contributors: invisnet
|
||||
Donate link: https://paypal.me/invisnet/
|
||||
Author URI: https://charles.lecklider.org/
|
||||
Plugin URI: https://wp-fail2ban.com/
|
||||
Tags: fail2ban, login, security, syslog
|
||||
Requires at least: 4.2
|
||||
Tested up to: 5.2
|
||||
Stable tag: 4.2.5
|
||||
Requires PHP: 5.3
|
||||
License: GPLv2 or later
|
||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
Write a myriad of WordPress events to syslog for integration with fail2ban.
|
||||
|
||||
== Description ==
|
||||
|
||||
[fail2ban](http://www.fail2ban.org/) is one of the simplest and most effective security measures you can implement to prevent brute-force attacks.
|
||||
|
||||
*WP fail2ban* logs all login attempts - including via XML-RPC, whether successful or not, to syslog using LOG_AUTH. For example:
|
||||
|
||||
Oct 17 20:59:54 foobar wordpress(www.example.com)[1234]: Authentication failure for admin from 192.168.0.1
|
||||
Oct 17 21:00:00 foobar wordpress(www.example.com)[2345]: Accepted password for admin from 192.168.0.1
|
||||
|
||||
*WPf2b* comes with three `fail2ban` filters: `wordpress-hard.conf`, `wordpress-soft.conf`, and `wordpress-extra.conf`. These are designed to allow a split between immediate banning (hard) and the traditional more graceful approach (soft), with extra rules for custom configurations.
|
||||
|
||||
= Features =
|
||||
|
||||
* **NEW - Support for 3rd-party Plugins**
|
||||
Version 4.2 introduces a simple API for authors to integrate their plugins with *WPf2b*, with 2 *experimental* add-ons:
|
||||
* [Contact Form 7](https://wordpress.org/plugins/wp-fail2ban-addon-contact-form-7/)
|
||||
* [Gravity Forms](https://wordpress.org/plugins/wp-fail2ban-addon-gravity-forms/)
|
||||
**NB:** Requires PHP >= 5.6
|
||||
|
||||
* **CloudFlare and Proxy Servers**
|
||||
*WPf2b* can be configured to work with CloudFlare and other proxy servers. For an overview see [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.2/defines.html#wp-fail2ban-proxies).
|
||||
|
||||
* **Comments**
|
||||
*WPf2b* can log comments (see [`WP_FAIL2BAN_LOG_COMMENTS`](https://docs.wp-fail2ban.com/en/4.2/defines.html#wp-fail2ban-log-comments)) and attempted comments (see [`WP_FAIL2BAN_LOG_COMMENTS_EXTRA`](https://docs.wp-fail2ban.com/en/4.2/defines.html#wp-fail2ban-log-comments-extra)).
|
||||
|
||||
* **Pingbacks**
|
||||
*WPf2b* logs failed pingbacks, and can log all pingbacks. For an overview see [`WP_FAIL2BAN_LOG_PINGBACKS`](https://docs.wp-fail2ban.com/en/4.2/defines.html#wp-fail2ban-log-pingbacks).
|
||||
|
||||
* **Spam**
|
||||
*WPf2b* can log comments marked as spam. See [`WP_FAIL2BAN_LOG_SPAM`](https://docs.wp-fail2ban.com/en/4.2/defines.html#wp-fail2ban-log-spam).
|
||||
|
||||
* **Block User Enumeration**
|
||||
*WPf2b* can block user enumeration. See [`WP_FAIL2BAN_BLOCK_USER_ENUMERATION`](https://docs.wp-fail2ban.com/en/4.2/defines.html#wp-fail2ban-block-user-enumeration).
|
||||
|
||||
* **Work-Arounds for Broken syslogd**
|
||||
*WPf2b* can be configured to work around most syslogd weirdness. For an overview see [`WP_FAIL2BAN_SYSLOG_SHORT_TAG`](https://docs.wp-fail2ban.com/en/4.2/defines.html#wp-fail2ban-syslog-short-tag) and [`WP_FAIL2BAN_HTTP_HOST`](https://docs.wp-fail2ban.com/en/4.2/defines.html#wp-fail2ban-http-host).
|
||||
|
||||
* **Blocking Users**
|
||||
*WPf2b* can be configured to short-cut the login process when the username matches a regex. For an overview see [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.2/defines.html#wp-fail2ban-blocked-users).
|
||||
|
||||
* **`mu-plugins` Support**
|
||||
*WPf2b* can easily be configured as a must-use plugin - see [Configuration](https://docs.wp-fail2ban.com/en/4.2/configuration.html#mu-plugins-support).
|
||||
|
||||
== Installation ==
|
||||
|
||||
1. Install via the Plugin Directory, or upload to your plugins directory.
|
||||
1. Activate the plugin through the 'Plugins' menu in WordPress.
|
||||
1. Edit `wp-config.php` to suit your needs - see [Configuration](https://docs.wp-fail2ban.com/en/4.2/configuration.html).
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 4.2.5 =
|
||||
* Properly fix PHP 5.3 support; tested on CentOS 6. Does not support any UI or Premium features.
|
||||
* Fix potential issue with `WP_FAIL2BAN_BLOCK_USER_ENUMERATION` if calling REST API or XMLRPC from admin area.
|
||||
|
||||
= 4.2.4 =
|
||||
* Add filter for login failed message.
|
||||
* Fix logging spam comments from admin area.
|
||||
* Fix Settings link from Plugins page.
|
||||
* Update Freemius library
|
||||
|
||||
= 4.2.3 =
|
||||
* Workaround for some versions of PHP 7.x that would cause `define()`s to be ignored.
|
||||
* Add config note to settings tabs.
|
||||
* Fix documentation links.
|
||||
|
||||
= 4.2.2 =
|
||||
* Fix 5.3 compatibility.
|
||||
|
||||
= 4.2.1 =
|
||||
* Completed support for [`WP_FAIL2BAN_COMMENT_EXTRA_LOG`](https://docs.wp-fail2ban.com/en/4.2/defines/WP_FAIL2BAN_COMMENT_EXTRA_LOG.html).
|
||||
* Add support for 3rd-party plugins; see [Developers](https://docs.wp-fail2ban.com/en/4.2/developers.html).
|
||||
* Add-on for [Contact Form 7](https://wordpress.org/plugins/wp-fail2ban-addon-contact-form-7/) (experimental).
|
||||
* Add-on for [Gravity Forms](https://wordpress.org/plugins/wp-fail2ban-addon-gravity-forms/) (experimental).
|
||||
* Change logging for known-user with incorrect password; previously logged as unknown user and matched by `hard` filters (due to limitations in older versions of WordPress), now logged as known user and matched by `soft`.
|
||||
* Bugfix for email-as-username - now logged correctly and matched by `soft`, not `hard`, filters.
|
||||
* Bugfix for regression in code to prevent Free/Premium conflict.
|
||||
|
||||
= 4.2.0 =
|
||||
* Not released.
|
||||
|
||||
= 4.1.0 =
|
||||
* Add separate logging for REST authentication.
|
||||
* Fix conflict with earlier versions pre-installed in `mu-plugins`. See [Is *WPf2b* Already Installed?](https://docs.wp-fail2ban.com/en/4.1/installation.html#is-wp-fail2ban-already-installed).
|
||||
|
||||
= 4.0.5 =
|
||||
* Add [`WP_FAIL2BAN_COMMENT_EXTRA_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_COMMENT_EXTRA_LOG.html).
|
||||
* Add [`WP_FAIL2BAN_PINGBACK_ERROR_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PINGBACK_ERROR_LOG.html) (future functionality).
|
||||
* Change `WP_FAIL2BAN_LOG_SPAM` to use `LOG_NOTICE`.
|
||||
* Change `WP_FAIL2BAN_SPAM_LOG` to `LOG_AUTH`.
|
||||
* Change `WP_FAIL2BAN_LOG_COMMENTS_EXTRA` events to use `LOG_NOTICE` by default.
|
||||
* Fix conflict with 3.x in `mu-plugins`.
|
||||
|
||||
= 4.0.2 =
|
||||
* Fix PHP 5.3 compatibility.
|
||||
* Bugfix for `WP_FAIL2BAN_LOG_COMMENTS_EXTRA`.
|
||||
* Bugfix for `WP_FAIL2BAN_REMOTE_ADDR` summary.
|
||||
|
||||
= 4.0.1 =
|
||||
* Add extra features via Freemius. **This is entirely optional.** *WPf2b* works as before, including new features listed here.
|
||||
* Add settings summary page (Settings -> WP fail2ban).
|
||||
* Add [`WP_FAIL2BAN_PASSWORD_REQUEST_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PASSWORD_REQUEST_LOG.html).
|
||||
* Add [`WP_FAIL2BAN_SPAM_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_SPAM_LOG.html).
|
||||
* Add [`WP_FAIL2BAN_LOG_COMMENTS_EXTRA`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_COMMENTS_EXTRA.html) - enable logging for attempted comments on posts which are:
|
||||
* not found,
|
||||
* closed for commenting,
|
||||
* in the trash,
|
||||
* drafts,
|
||||
* password protected
|
||||
* Block user enumeration via REST API.
|
||||
|
||||
= 4.0.0 =
|
||||
* Not released.
|
||||
|
||||
= 3.6.0 =
|
||||
* The [filter files](https://docs.wp-fail2ban.com/en/4.1/filters.html) are now generated from PHPDoc in the code. There were too many times when the filters were out of sync with the code (programmer error) - this should resolve that by bringing the patterns closer to the code that emits them.
|
||||
* Added [PHPUnit tests](https://docs.wp-fail2ban.com/en/4.1/tests.html). Almost 100% code coverage, with the exception of [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html) which is quite hard to test properly.
|
||||
* Bugfix for [`wordpress-soft.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html#wordpress-soft-conf).
|
||||
* Add [`WP_FAIL2BAN_XMLRPC_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_XMLRPC_LOG.html).
|
||||
* Add [`WP_FAIL2BAN_REMOTE_ADDR`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_REMOTE_ADDR.html).
|
||||
* [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html) now supports an array of IPs with PHP 7.
|
||||
* Moved all documentation to [https://docs.wp-fail2ban.com/](https://docs.wp-fail2ban.com/).
|
||||
|
||||
= 3.5.3 =
|
||||
* Bugfix for [`wordpress-hard.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html#wordpress-hard-conf).
|
||||
|
||||
= 3.5.1 =
|
||||
* Bugfix for [`WP_FAIL2BAN_BLOCK_USER_ENUMERATION`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCK_USER_ENUMERATION.html).
|
||||
|
||||
= 3.5.0 =
|
||||
* Add [`WP_FAIL2BAN_OPENLOG_OPTIONS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_OPENLOG_OPTIONS.html).
|
||||
* Add [`WP_FAIL2BAN_LOG_COMMENTS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_COMMENTS.html) and [`WP_FAIL2BAN_COMMENT_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_COMMENT_LOG.html).
|
||||
* Add [`WP_FAIL2BAN_LOG_PASSWORD_REQUEST`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_PASSWORD_REQUEST.html).
|
||||
* Add [`WP_FAIL2BAN_LOG_SPAM`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_SPAM.html).
|
||||
* Add [`WP_FAIL2BAN_TRUNCATE_HOST`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_TRUNCATE_HOST.html).
|
||||
* [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCKED_USERS.html) now supports an array of users with PHP 7.
|
||||
|
||||
= 3.0.3 =
|
||||
* Fix regex in [`wordpress-hard.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html#wordpress-hard-conf).
|
||||
|
||||
= 3.0.2 =
|
||||
* Prevent double logging in WP 4.5.x for XML-RPC authentication failure
|
||||
|
||||
= 3.0.1 =
|
||||
* Fix regex in [`wordpress-hard.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html#wordpress-hard-conf).
|
||||
|
||||
= 3.0.0 =
|
||||
* Add [`WP_FAIL2BAN_SYSLOG_SHORT_TAG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_SYSLOG_SHORT_TAG.html).
|
||||
* Add [`WP_FAIL2BAN_HTTP_HOST`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_HTTP_HOST.html).
|
||||
* Log XML-RPC authentication failure.
|
||||
* Add better support for MU deployment.
|
||||
|
||||
= 2.3.2 =
|
||||
* Bugfix [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCKED_USERS.html).
|
||||
|
||||
= 2.3.0 =
|
||||
* Bugfix in *experimental* [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html) code (thanks to KyleCartmell).
|
||||
|
||||
= 2.2.1 =
|
||||
* Fix stupid mistake with [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCKED_USERS.html).
|
||||
|
||||
= 2.2.0 =
|
||||
* Custom authentication log is now called [`WP_FAIL2BAN_AUTH_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_AUTH_LOG.html).
|
||||
* Add logging for pingbacks; see [`WP_FAIL2BAN_LOG_PINGBACKS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_PINGBACKS.html).
|
||||
* Custom pingback log is called [`WP_FAIL2BAN_PINGBACK_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PINGBACK_LOG.html).
|
||||
|
||||
= 2.1.1 =
|
||||
* Minor bugfix.
|
||||
|
||||
= 2.1.0 =
|
||||
* Add support for blocking user enumeration; see [`WP_FAIL2BAN_BLOCK_USER_ENUMERATION`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCK_USER_ENUMERATION.html).
|
||||
* Add support for CIDR notation in [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html).
|
||||
|
||||
= 2.0.1 =
|
||||
* Bugfix in *experimental* [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html) code.
|
||||
|
||||
= 2.0.0 =
|
||||
* Add *experimental* support for X-Forwarded-For header; see [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html).
|
||||
* Add *experimental* support for regex-based login blocking; see [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCKED_USERS.html).
|
||||
|
||||
= 1.2.1 =
|
||||
* Update FAQ.
|
||||
|
||||
= 1.2 =
|
||||
* Fix harmless warning.
|
||||
|
||||
= 1.1 =
|
||||
* Minor cosmetic updates.
|
||||
|
||||
= 1.0 =
|
||||
* Initial release.
|
||||
|
||||
== Upgrade Notice ==
|
||||
|
||||
= 4.2.5 =
|
||||
This is a minor release. You do not need to update your filters from 4.1.0.
|
||||
|
||||
= 4.2.4 =
|
||||
This is a minor release. You do not need to update your filters from 4.1.0.
|
||||
|
||||
= 4.2.3 =
|
||||
This is a bugfix release. You do not need to update your filters from 4.1.0.
|
||||
|
||||
= 4.2.2 =
|
||||
You do not need to update your filters from 4.1.0.
|
||||
|
||||
= 4.2.1 =
|
||||
You do not need to update your filters from 4.1.0.
|
||||
|
||||
= 4.1.0 =
|
||||
To take advantage of the new features you will need up update your `fail2ban` filters; existing filters will continue to work as before.
|
||||
|
||||
= 4.0.5 =
|
||||
This is a security fix (Freemius SDK): all 4.x users are strongly advised to upgrade immediately. You do not need to update your filters from 4.0.1.
|
||||
|
||||
= 4.0.4 =
|
||||
This is a bugfix. You do not need to update your filters from 4.0.1.
|
||||
|
||||
= 4.0.3 =
|
||||
This is a bugfix. You do not need to update your filters from 4.0.1.
|
||||
|
||||
= 4.0.2 =
|
||||
This is a bugfix. You do not need to update your filters from 4.0.1.
|
||||
|
||||
= 4.0.1 =
|
||||
To take advantage of the new features you will need up update your `fail2ban` filters; existing filters will continue to work as before.
|
||||
|
||||
= 3.6.0 =
|
||||
You will need up update your `fail2ban` filters.
|
||||
|
||||
= 3.5.3 =
|
||||
You will need up update your `fail2ban` filters.
|
||||
|
||||
= 3.5.1 =
|
||||
Bugfix: disable [`WP_FAIL2BAN_BLOCK_USER_ENUMERATION`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCK_USER_ENUMERATION.html) in admin area....
|
||||
|
||||
= 3.5.0 =
|
||||
You will need up update your `fail2ban` filters.
|
||||
|
||||
= 3.0.3 =
|
||||
You will need up update your `fail2ban` filters.
|
||||
|
||||
= 3.0.0 =
|
||||
BREAKING CHANGE: The `fail2ban` filters have been split into two files. You will need up update your `fail2ban` configuration.
|
||||
|
||||
= 2.3.0 =
|
||||
Fix for [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html); if you're not using it you can safely skip this release.
|
||||
|
||||
= 2.2.1 =
|
||||
Bugfix.
|
||||
|
||||
= 2.2.0 =
|
||||
BREAKING CHANGE: `WP_FAIL2BAN_LOG` has been renamed to [`WP_FAIL2BAN_AUTH_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_AUTH_LOG.html).
|
||||
|
||||
Pingbacks are getting a lot of attention recently, so *WPf2b* can now log them.
|
||||
The `wordpress.conf` filter has been updated; you will need to update your `fail2ban` configuration.
|
||||
|
||||
= 2.1.0 =
|
||||
The `wordpress.conf` filter has been updated; you will need to update your `fail2ban` configuration.
|
||||
|
||||
= 2.0.1 =
|
||||
Bugfix in experimental code; still an experimental release.
|
||||
|
||||
= 2.0.0 =
|
||||
This is an experimental release. If your current version is working and you're not interested in the new features, skip this version - wait for 2.1.0. For those that do want to test this release, note that `wordpress.conf` has changed - you'll need to copy it to `fail2ban/filters.d` again.
|
254
wp-fail2ban-main.php
Normal file
254
wp-fail2ban-main.php
Normal file
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* WP fail2ban main file
|
||||
*
|
||||
* @since 4.0.0
|
||||
* @package wp-fail2ban
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
if ( !defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
require_once __DIR__ . '/lib/constants.php';
|
||||
require_once __DIR__ . '/lib/loader.php';
|
||||
require_once __DIR__ . '/lib/defaults.php';
|
||||
register_activation_hook( WP_FAIL2BAN_FILE, function () {
|
||||
foreach ( get_mu_plugins() as $plugin => $data ) {
|
||||
|
||||
if ( 0 === strpos( $data['Name'], 'WP fail2ban' ) ) {
|
||||
$wp_f2b_ver = substr( WP_FAIL2BAN_VER, 0, strrpos( WP_FAIL2BAN_VER, '.' ) );
|
||||
$wpf2b = 'WP fail2ban';
|
||||
$error_msg = sprintf( __( '<h1>Cannot activate %s</h1>' ), $wpf2b );
|
||||
$mu_file = WPMU_PLUGIN_DIR . '/' . $plugin;
|
||||
|
||||
if ( is_link( $mu_file ) ) {
|
||||
|
||||
if ( false === ($link = readlink( $mu_file )) || false === ($path = realpath( $mu_file )) ) {
|
||||
$h3 = __( 'A broken symbolic link was found in <tt>mu-plugins</tt>:' );
|
||||
$error_msg .= <<<__ERROR__
|
||||
<h3>{$h3}</h3>
|
||||
<p><tt>{$mu_file}</tt></p>
|
||||
__ERROR__;
|
||||
} elseif ( WP_FAIL2BAN_FILE == $path ) {
|
||||
// OK, we're linking to ourself
|
||||
} else {
|
||||
$mu_file = str_replace( '/', '/<wbr>', $mu_file );
|
||||
$mu_file = substr( $mu_file, strlen( WPMU_PLUGIN_DIR ) - 1 );
|
||||
$h3 = __( 'A conflicting symbolic link was found in <tt>mu-plugins</tt>:' );
|
||||
$error_msg .= <<<__ERROR__
|
||||
<h3>{$h3}</h3>
|
||||
<style>
|
||||
table { text-align: center; }
|
||||
td { width: 50%; }
|
||||
th { font-size: 200%; }
|
||||
td, th { font-family: monospace; }
|
||||
span.tt { font-weight: bold; }
|
||||
</style>
|
||||
<table>
|
||||
<tr>
|
||||
<td>{$mu_file}</td>
|
||||
<th>⇒</th>
|
||||
<td>{$link}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3"><span class="tt">≡</span> <span>{$path}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3"></td>
|
||||
</tr>
|
||||
</table>
|
||||
__ERROR__;
|
||||
}
|
||||
|
||||
} else {
|
||||
$mu_file = str_replace( '/', '/<wbr>', $mu_file );
|
||||
$mu_file = substr( $mu_file, strlen( WPMU_PLUGIN_DIR ) - 1 );
|
||||
$h3 = __( 'A conflicting file was found in <tt>mu-plugins</tt>:' );
|
||||
$error_msg .= <<<__ERROR__
|
||||
<h3>{$h3}</h3>
|
||||
<p><tt>{$mu_file}</tt></p>
|
||||
__ERROR__;
|
||||
}
|
||||
|
||||
$error_msg .= sprintf( __( '<p>Please see the <a href="%s" target="_blank">documentation</a> for how to configure %s for <tt>mu-plugins</tt>.</p>' ), "https://docs.wp-fail2ban.com/en/{$wp_f2b_ver}/configuration.html#mu-plugins-support", $wpf2b );
|
||||
$error_msg .= sprintf( __( '<p>Click <a href="%s">here</a> to return to the plugins page.</p>' ), admin_url( 'plugins.php' ) );
|
||||
deactivate_plugins( plugin_basename( WP_FAIL2BAN_FILE ) );
|
||||
wp_die( $error_msg );
|
||||
}
|
||||
|
||||
}
|
||||
} );
|
||||
require __DIR__ . '/feature/lib.php';
|
||||
/**
|
||||
* @since 4.2.5
|
||||
*/
|
||||
|
||||
if ( version_compare( PHP_VERSION, '5.6.0', '>=' ) ) {
|
||||
/**
|
||||
* @since 4.2.0
|
||||
*/
|
||||
global $wp_fail2ban ;
|
||||
$wp_fail2ban['plugins'] = array();
|
||||
require __DIR__ . '/feature/plugins.php';
|
||||
if ( is_admin() ) {
|
||||
require 'admin/admin.php';
|
||||
}
|
||||
} elseif ( is_admin() ) {
|
||||
require __DIR__ . '/admin/lib/about.php';
|
||||
add_action( 'admin_menu', function () {
|
||||
add_menu_page(
|
||||
'WP fail2ban',
|
||||
'WP fail2ban',
|
||||
'manage_options',
|
||||
'wp-fail2ban',
|
||||
__NAMESPACE__ . '\\about',
|
||||
'dashicons-analytics'
|
||||
);
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0.5
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\wp_login' ) ) {
|
||||
/**
|
||||
* Hook: wp_login
|
||||
*
|
||||
* @since 4.1.0 Add REST support
|
||||
* @since 3.5.0 Refactored for unit testing
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $user_login
|
||||
* @param mixed $user
|
||||
*/
|
||||
function wp_login( $user_login, $user )
|
||||
{
|
||||
global $wp_xmlrpc_server ;
|
||||
openlog();
|
||||
syslog( LOG_INFO, "Accepted password for {$user_login}" );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
add_action(
|
||||
'wp_login',
|
||||
__NAMESPACE__ . '\\wp_login',
|
||||
10,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0.5
|
||||
*/
|
||||
|
||||
if ( !function_exists( __NAMESPACE__ . '\\wp_login_failed' ) ) {
|
||||
/**
|
||||
* Hook: wp_login_failed
|
||||
*
|
||||
* @since 4.2.4 Add message filter
|
||||
* @since 4.2.0 Change username check
|
||||
* @since 4.1.0 Add REST support
|
||||
* @since 3.5.0 Refactored for unit testing
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $username
|
||||
*
|
||||
* @wp-f2b-hard Authentication attempt for unknown user .*
|
||||
* @wp-f2b-hard REST authentication attempt for unknown user .*
|
||||
* @wp-f2b-hard XML-RPC authentication attempt for unknown user .*
|
||||
* @wp-f2b-soft Authentication failure for .*
|
||||
* @wp-f2b-soft REST authentication failure for .*
|
||||
* @wp-f2b-soft XML-RPC authentication failure for .*
|
||||
*/
|
||||
function wp_login_failed( $username )
|
||||
{
|
||||
global $wp_xmlrpc_server ;
|
||||
|
||||
if ( defined( 'REST_REQUEST' ) ) {
|
||||
$msg = 'REST a';
|
||||
$filter = '::REST';
|
||||
} elseif ( $wp_xmlrpc_server ) {
|
||||
$msg = 'XML-RPC a';
|
||||
$filter = '::XML-RPC';
|
||||
} else {
|
||||
$msg = 'A';
|
||||
$filter = '';
|
||||
}
|
||||
|
||||
$username = trim( $username );
|
||||
$msg .= ( wp_cache_get( $username, 'useremail' ) || wp_cache_get( sanitize_user( $username ), 'userlogins' ) ? "uthentication failure for {$username}" : "uthentication attempt for unknown user {$username}" );
|
||||
$msg = apply_filters( "wp_fail2ban::wp_login_failed{$filter}", $msg );
|
||||
openlog();
|
||||
syslog( LOG_NOTICE, $msg );
|
||||
closelog();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
add_action( 'wp_login_failed', __NAMESPACE__ . '\\wp_login_failed' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.2.5
|
||||
*/
|
||||
|
||||
if ( !is_admin() ) {
|
||||
/**
|
||||
* User enumeration
|
||||
*
|
||||
* @since 4.0.0 Refactored
|
||||
* @since 2.1.0
|
||||
*/
|
||||
if ( defined( 'WP_FAIL2BAN_BLOCK_USER_ENUMERATION' ) && true === WP_FAIL2BAN_BLOCK_USER_ENUMERATION ) {
|
||||
require_once __DIR__ . '/feature/user-enum.php';
|
||||
}
|
||||
/**
|
||||
* XML-RPC
|
||||
*
|
||||
* @since 4.0.0 Refactored
|
||||
* @since 3.0.0
|
||||
*/
|
||||
if ( defined( 'XMLRPC_REQUEST' ) && true === XMLRPC_REQUEST ) {
|
||||
require_once __DIR__ . '/feature/xmlrpc.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Comments
|
||||
*
|
||||
* @since 4.0.0 Refactored
|
||||
* @since 3.5.0
|
||||
*/
|
||||
if ( defined( 'WP_FAIL2BAN_LOG_COMMENTS' ) && true === WP_FAIL2BAN_LOG_COMMENTS ) {
|
||||
require_once __DIR__ . '/feature/comments.php';
|
||||
}
|
||||
/**
|
||||
* Password
|
||||
*
|
||||
* @since 4.0.0 Refactored
|
||||
* @since 3.5.0
|
||||
*/
|
||||
if ( defined( 'WP_FAIL2BAN_LOG_PASSWORD_REQUEST' ) && true === WP_FAIL2BAN_LOG_PASSWORD_REQUEST ) {
|
||||
require_once __DIR__ . '/feature/password.php';
|
||||
}
|
||||
/**
|
||||
* Spam
|
||||
*
|
||||
* @since 4.0.0 Refactored
|
||||
* @since 3.5.0
|
||||
*/
|
||||
if ( defined( 'WP_FAIL2BAN_LOG_SPAM' ) && true === WP_FAIL2BAN_LOG_SPAM ) {
|
||||
require_once __DIR__ . '/feature/spam.php';
|
||||
}
|
||||
/**
|
||||
* Users
|
||||
*
|
||||
* @since 4.0.0 Refactored
|
||||
* @since 2.0.0
|
||||
*/
|
||||
if ( defined( 'WP_FAIL2BAN_BLOCKED_USERS' ) && '' < WP_FAIL2BAN_BLOCKED_USERS ) {
|
||||
require_once __DIR__ . '/feature/user.php';
|
||||
}
|
105
wp-fail2ban.php
Normal file
105
wp-fail2ban.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Plugin Name: WP fail2ban
|
||||
* Plugin URI: https://wp-fail2ban.com/
|
||||
* Description: Write a myriad of WordPress events to syslog for integration with fail2ban.
|
||||
* Text Domain: wp-fail2ban
|
||||
* Version: 4.2.5
|
||||
* Author: Charles Lecklider
|
||||
* Author URI: https://charles.lecklider.org/
|
||||
* License: GPLv2
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
* Requires PHP: 5.3
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright 2012-19 Charles Lecklider (email : wordpress@charles.lecklider.org)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
/**
|
||||
* WP fail2ban
|
||||
*
|
||||
* @package wp-fail2ban
|
||||
*/
|
||||
namespace org\lecklider\charles\wordpress\wp_fail2ban;
|
||||
|
||||
/**
|
||||
* @since 4.0.5
|
||||
*/
|
||||
define( 'WP_FAIL2BAN_VER', '4.2.5' );
|
||||
define( 'WP_FAIL2BAN_FILE', __FILE__ );
|
||||
/**
|
||||
* Freemius integration
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
|
||||
if ( function_exists( __NAMESPACE__ . '\\wf_fs' ) ) {
|
||||
// @codeCoverageIgnoreStart
|
||||
wf_fs()->set_basename( false, __FILE__ );
|
||||
return;
|
||||
} else {
|
||||
/**
|
||||
* Create a helper function for easy SDK access.
|
||||
*/
|
||||
function wf_fs()
|
||||
{
|
||||
global $wf_fs ;
|
||||
|
||||
if ( !isset( $wf_fs ) ) {
|
||||
// Include Freemius SDK.
|
||||
require_once dirname( __FILE__ ) . '/vendor/freemius/wordpress-sdk/start.php';
|
||||
$wf_fs = fs_dynamic_init( array(
|
||||
'id' => '3072',
|
||||
'slug' => 'wp-fail2ban',
|
||||
'type' => 'plugin',
|
||||
'public_key' => 'pk_146d2c2a5bee3b157e43501ef8682',
|
||||
'is_premium' => false,
|
||||
'has_addons' => true,
|
||||
'has_paid_plans' => true,
|
||||
'trial' => array(
|
||||
'days' => 7,
|
||||
'is_require_payment' => false,
|
||||
),
|
||||
'menu' => array(
|
||||
'slug' => 'wp-fail2ban',
|
||||
'first-path' => 'admin.php?page=wp-fail2ban',
|
||||
'support' => false,
|
||||
),
|
||||
'is_live' => true,
|
||||
) );
|
||||
}
|
||||
|
||||
return $wf_fs;
|
||||
}
|
||||
|
||||
// Init Freemius.
|
||||
wf_fs();
|
||||
// Set currency to GBP
|
||||
wf_fs()->add_filter( 'default_currency', function () {
|
||||
return 'gbp';
|
||||
} );
|
||||
// Signal that SDK was initiated.
|
||||
do_action( 'wf_fs_loaded' );
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
/**
|
||||
* Freemius insists on mangling the formatting of the main plugin file
|
||||
*
|
||||
* @since 4.0.0 Refactored
|
||||
*/
|
||||
require_once 'wp-fail2ban-main.php';
|
Loading…
x
Reference in New Issue
Block a user