233 lines
7.0 KiB
PHP
233 lines
7.0 KiB
PHP
<?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
|
|
); |