WP fail2ban - Version 4.3.0.4

Version Description

To take advantage of the new features you will need up update your fail2ban filters; existing filters will continue to work as before. Premium users: Please backup your database before upgrading.

Download this release

Release Info

Developer invisnet
Plugin Icon 128x128 WP fail2ban
Version 4.3.0.4
Comparing to
See all releases

Code changes from version 4.2.8.1 to 4.3.0.4

Files changed (48) hide show
  1. admin/admin.php +232 -63
  2. admin/config.php +115 -87
  3. admin/config/block.php +77 -53
  4. admin/config/logging.php +120 -115
  5. admin/config/plugins.php +32 -93
  6. admin/config/remote-ips.php +58 -46
  7. admin/config/syslog.php +102 -67
  8. admin/css/widgets.css +1 -0
  9. admin/img/docs.svg +1 -6
  10. admin/lib/about.php +100 -133
  11. admin/lib/logging.php +103 -0
  12. admin/lib/tab.php +320 -127
  13. admin/tools.php +53 -0
  14. admin/widgets.php +92 -0
  15. assets/icon.svg +1 -0
  16. assets/menu.svg +1 -0
  17. constants.php +30 -0
  18. core.php +115 -0
  19. feature/comments.php +117 -173
  20. feature/lib.php +0 -137
  21. feature/password.php +21 -24
  22. feature/plugins.php +109 -109
  23. feature/spam.php +32 -45
  24. feature/user-enum.php +87 -118
  25. feature/user.php +59 -44
  26. feature/xmlrpc.php +104 -80
  27. feature/xmlrpc/log.php +0 -35
  28. feature/xmlrpc/pingback.php +0 -40
  29. filters.d/wordpress-extra.conf +3 -3
  30. filters.d/wordpress-hard.conf +7 -6
  31. filters.d/wordpress-soft.conf +3 -2
  32. freemius.php +96 -0
  33. functions.php +238 -0
  34. init.php +208 -0
  35. lib/activation.php +85 -0
  36. lib/constants.php +147 -131
  37. lib/convert-data.php +143 -0
  38. lib/defaults.php +37 -66
  39. lib/loader.php +466 -302
  40. readme.txt +86 -65
  41. vendor/freemius/wordpress-sdk/assets/css/admin/add-ons.css +2 -2
  42. vendor/freemius/wordpress-sdk/assets/img/wp-fail2ban.png +0 -0
  43. vendor/freemius/wordpress-sdk/assets/scss/admin/add-ons.scss +1 -9
  44. vendor/freemius/wordpress-sdk/includes/class-freemius.php +12 -8
  45. vendor/freemius/wordpress-sdk/includes/fs-plugin-info-dialog.php +9 -10
  46. vendor/freemius/wordpress-sdk/templates/add-ons.php +7 -8
  47. wp-fail2ban-main.php +0 -297
  48. wp-fail2ban.php +14 -92
admin/admin.php CHANGED
@@ -1,99 +1,268 @@
1
  <?php
2
-
3
  /**
4
  * Admin
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.0.0
8
  */
9
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  }
14
- require __DIR__ . '/config.php';
15
- require __DIR__ . '/lib/about.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  /**
17
  * Register admin menus
18
  *
19
  * @since 4.0.0
 
 
20
  */
21
  function admin_menu()
22
  {
23
- global $submenu ;
24
- add_menu_page(
25
- 'WP fail2ban',
26
- 'WP fail2ban',
27
- 'manage_options',
28
- 'wp-fail2ban',
29
- __NAMESPACE__ . '\\about',
30
- 'dashicons-analytics'
31
- );
32
-
33
- if ( function_exists( '\\add_security_page' ) ) {
34
- $slug = 'wp-fail2ban';
35
- add_security_page(
36
  'WP fail2ban',
37
  'WP fail2ban',
38
- $slug,
39
- __NAMESPACE__ . '\\security'
40
- );
41
- } else {
42
- add_submenu_page(
43
- 'wp-fail2ban',
44
- 'Settings',
45
- 'Settings',
46
  'manage_options',
47
- 'wpf2b-settings',
48
- __NAMESPACE__ . '\\settings'
 
49
  );
 
 
 
 
 
50
  }
51
-
52
- $hook = add_submenu_page(
53
- 'wp-fail2ban',
54
- 'WP fail2ban - Remote Tools',
55
- 'Remote Tools',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  'manage_options',
57
- 'wp-fail2ban-tools',
58
- __NAMESPACE__ . '\\remote_tools'
 
59
  );
60
- add_action( "load-{$hook}", function () {
61
- if ( function_exists( '\\org\\lecklider\\charles\\wordpress\\wp_fail2ban\\addons\\remote_tools\\help' ) ) {
62
- \org\lecklider\charles\wordpress\wp_fail2ban\addons\remote_tools\help();
63
- }
64
- } );
65
- if ( array_key_exists( 'wp-fail2ban', $submenu ) ) {
66
- $submenu['wp-fail2ban'][0][0] = __( 'Welcome' );
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
  }
69
 
70
- add_action( 'admin_menu', __NAMESPACE__ . '\\admin_menu' );
71
  /**
72
  * Add Settings link on Plugins page
73
  *
74
- * @since 4.2.6 Add support for ClassicPress security page
75
  * @since 4.2.0
76
  *
77
- * @param array $links
78
- * @param string $file
 
 
 
 
 
 
 
 
79
  */
80
- function plugin_action_links( $links, $file )
81
  {
82
- if ( preg_match( "|{$file}\$|", WP_FAIL2BAN_FILE ) ) {
83
- array_unshift( $links, sprintf(
84
- '<a href="%s?page=%s" title="%s">%s</a>',
85
- admin_url( 'admin.php' ),
86
- 'wpf2b-settings',
87
- __( 'Settings' ),
88
- ( function_exists( '\\add_security_page' ) ? '<span class="dashicon dashicons-admin-generic"></span>' : __( 'Settings' ) )
89
- ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
91
- return $links;
92
  }
 
93
 
94
- add_filter(
95
- 'plugin_action_links',
96
- __NAMESPACE__ . '\\plugin_action_links',
97
- 10,
98
- 2
99
- );
1
  <?php
 
2
  /**
3
  * Admin
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
 
10
+ defined('ABSPATH') or exit;
11
+
12
+ require_once __DIR__.'/config.php';
13
+ require_once __DIR__.'/tools.php';
14
+ require_once __DIR__.'/widgets.php';
15
+ require_once __DIR__.'/lib/about.php';
16
+
17
+ /**
18
+ * Helper: Security and Settings menu
19
+ *
20
+ * @since 4.3.0
21
+ *
22
+ * @param string $capability Capability
23
+ *
24
+ * @return void
25
+ */
26
+ function _security_settings($capability = 'manage_options')
27
+ {
28
+ if (function_exists('\add_security_page')) {
29
+ $hook = add_security_page(
30
+ 'WP fail2ban',
31
+ 'WP fail2ban',
32
+ plugin_basename(WP_FAIL2BAN_DIR),
33
+ __NAMESPACE__.'\security'
34
+ );
35
+ add_action("load-$hook", function () {
36
+ apply_filters('wp_fail2ban_init_tabs', false);
37
+ TabBase::setDefaultTab('logging');
38
+ TabBase::getActiveTab()->current_screen();
39
+ });
40
+ if (class_exists(__NAMESPACE__.'\premium\WPf2b')) {
41
+ _settings('status', $capability);
42
+ }
43
+ } else {
44
+ _settings(apply_filters(__METHOD__.'.page', 'logging'), $capability);
45
+ }
46
  }
47
+
48
+ /**
49
+ * Helper: Settings menu
50
+ *
51
+ * @since 4.3.0
52
+ *
53
+ * @param $page string|null
54
+ * @param $capability string
55
+ *
56
+ * @return void
57
+ */
58
+ function _settings($page = null, $capability = 'manage_options')
59
+ {
60
+ do_action('wp_fail2ban_menu_settings::before');
61
+ $hook = add_submenu_page(
62
+ 'wp-fail2ban-menu',
63
+ __('Settings', 'wp-fail2ban'),
64
+ __('Settings', 'wp-fail2ban'),
65
+ $capability,
66
+ 'wpf2b-settings',
67
+ __NAMESPACE__.'\settings'
68
+ );
69
+ add_action("load-$hook", function () use ($page) {
70
+ apply_filters('wp_fail2ban_init_tabs', false);
71
+ TabBase::setDefaultTab($page);
72
+ TabBase::getActiveTab()->current_screen();
73
+ });
74
+ do_action('wp_fail2ban_menu_settings::after');
75
+ }
76
+
77
+ /**
78
+ * Helper: Remote Tools menu
79
+ *
80
+ * @since 4.3.0
81
+ *
82
+ * @param string $capability Capability
83
+ *
84
+ * @return void
85
+ */
86
+ function _remote_tools($capability = 'manage_options')
87
+ {
88
+ do_action('wp_fail2ban_menu_tools::before');
89
+ add_submenu_page(
90
+ 'wp-fail2ban-menu',
91
+ __('Tools', 'wp-fail2ban'),
92
+ __(' - Remote Tools (&beta;)', 'wp-fail2ban'),
93
+ $capability,
94
+ 'wp-fail2ban-tools',
95
+ __NAMESPACE__.'\remote_tools'
96
+ );
97
+ do_action('wp_fail2ban_menu_tools::after');
98
+ }
99
+
100
  /**
101
  * Register admin menus
102
  *
103
  * @since 4.0.0
104
+ *
105
+ * @return void
106
  */
107
  function admin_menu()
108
  {
109
+ if (!is_multisite() && !wf_fs()->can_use_premium_code()) {
110
+ add_menu_page(
 
 
 
 
 
 
 
 
 
 
 
111
  'WP fail2ban',
112
  'WP fail2ban',
 
 
 
 
 
 
 
 
113
  'manage_options',
114
+ 'wp-fail2ban-menu',
115
+ __NAMESPACE__.'\about',
116
+ plugin_dir_url(WP_FAIL2BAN_FILE).'assets/menu.svg'
117
  );
118
+ add_action('admin_menu', __NAMESPACE__.'\admin_menu_fix', PHP_INT_MAX);
119
+ do_action('wp_fail2ban_menu');
120
+
121
+ _security_settings();
122
+ _remote_tools();
123
  }
124
+ }
125
+ add_action('admin_menu', __NAMESPACE__.'\admin_menu');
126
+
127
+ /**
128
+ * Register network admin menus
129
+ *
130
+ * @since 4.3.0
131
+ *
132
+ * @return void
133
+ */
134
+ function network_admin_menu()
135
+ {
136
+ if (!wf_fs()->can_use_premium_code()) {
137
+ _network_admin_menu();
138
+ }
139
+ }
140
+ add_action('network_admin_menu', __NAMESPACE__.'\network_admin_menu');
141
+
142
+ /**
143
+ * Actual network admin menu handler
144
+ *
145
+ * @since 4.3.0
146
+ *
147
+ * @return void
148
+ */
149
+ function _network_admin_menu()
150
+ {
151
+ add_menu_page(
152
+ 'WP fail2ban',
153
+ 'WP fail2ban',
154
  'manage_options',
155
+ 'wp-fail2ban-menu',
156
+ __NAMESPACE__.'\about',
157
+ plugin_dir_url(WP_FAIL2BAN_FILE).'assets/menu.svg'
158
  );
159
+ add_action('network_admin_menu', __NAMESPACE__.'\admin_menu_fix', PHP_INT_MAX);
160
+ do_action('wp_fail2ban_menu');
161
+
162
+ _security_settings();
163
+ _remote_tools();
164
+ }
165
+
166
+ /**
167
+ * Fix first submenu name.
168
+ *
169
+ * @since 4.3.0
170
+ *
171
+ * @return void
172
+ */
173
+ function admin_menu_fix()
174
+ {
175
+ global $submenu;
176
+
177
+ if (isset($submenu['wp-fail2ban-menu']) && 'WP fail2ban' == @$submenu['wp-fail2ban-menu'][0][0]) {
178
+ $submenu['wp-fail2ban-menu'][0][0] = __('Welcome', 'wp-fail2ban');
179
  }
180
  }
181
 
 
182
  /**
183
  * Add Settings link on Plugins page
184
  *
 
185
  * @since 4.2.0
186
  *
187
+ * @param string[] $actions An array of plugin action links. By default this can include 'activate',
188
+ * 'deactivate', and 'delete'.
189
+ * @param string $plugin_file Path to the plugin file relative to the plugins directory.
190
+ * @param array $plugin_data An array of plugin data. See `get_plugin_data()`.
191
+ * @param string $context The plugin context. By default this can include 'all', 'active', 'inactive',
192
+ * 'recently_activated', 'upgrade', 'mustuse', 'dropins', and 'search'.
193
+ *
194
+ * @return string[]
195
+ *
196
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
197
  */
198
+ function plugin_action_links($actions, $plugin_file, $plugin_data, $context)
199
  {
200
+ if (preg_match("|$plugin_file\$|", WP_FAIL2BAN_FILE) &&
201
+ (!is_multisite() || is_network_admin()))
202
+ {
203
+ if (function_exists('\add_security_page')) {
204
+ if (wf_fs()->can_use_premium_code()) {
205
+ $page = 'wpf2b-settings';
206
+ } else {
207
+ return $actions;
208
+ }
209
+ } else {
210
+ $page = 'wpf2b-fail2ban-menu';
211
+ }
212
+ $settings = sprintf(
213
+ '<a href="%s?page=wpf2b-settings&tab=about" title="%s">%s</a>',
214
+ network_admin_url('admin.php'),
215
+ __('Settings', 'wp-fail2ban'),
216
+ (function_exists('\add_security_page'))
217
+ ? '<span class="dashicon dashicons-admin-generic"></span>'
218
+ : __('Settings', 'wp-fail2ban')
219
+ );
220
+ // Add Settings at the start
221
+ $actions = array_merge([
222
+ 'settings' => $settings
223
+ ], $actions);
224
+ }
225
+
226
+ return $actions;
227
+ }
228
+ add_filter('plugin_action_links', __NAMESPACE__.'\plugin_action_links', 10, 4);
229
+ add_filter('network_admin_plugin_action_links', __NAMESPACE__.'\plugin_action_links', 10, 4);
230
+
231
+ /**
232
+ * Add help tab to Dashboard
233
+ *
234
+ * @since 4.3.0
235
+ *
236
+ * @return void
237
+ */
238
+ function admin_head_dashboard()
239
+ {
240
+ $content = '';
241
+
242
+ if ((!is_multisite() && current_user_can('manage_options')) ||
243
+ (is_network_admin() && current_user_can('manage_network_options')))
244
+ {
245
+ $message = __('Shows the last 5 messages sent to <code>syslog</code> - provides simple status at a glance and can be helpful for debugging.', 'wp-fail2ban');
246
+ if (!wf_fs()->can_use_premium_code()) {
247
+ $message .= sprintf(
248
+ __('The <a href="%s">Premium version</a> provides more advanced views.', 'wp-fail2ban'),
249
+ network_admin_url('admin.php?page=wp-fail2ban-menu-pricing')
250
+ );
251
+ }
252
+
253
+ $content = sprintf(
254
+ '<p><strong>%s</strong> &mdash; %s.</p>',
255
+ __('Last 5 Messages', 'wp-fail2ban'),
256
+ $message
257
+ );
258
+ }
259
+ if (!empty($content = apply_filters('wp_fail2ban_dashboard_help', $content))) {
260
+ get_current_screen()->add_help_tab([
261
+ 'id' => 'wp-fail2ban',
262
+ 'title' => 'WP fail2ban',
263
+ 'content' => $content
264
+ ]);
265
  }
 
266
  }
267
+ add_action('admin_head-index.php', __NAMESPACE__.'\admin_head_dashboard', 9999);
268
 
 
 
 
 
 
 
admin/config.php CHANGED
@@ -1,24 +1,83 @@
1
  <?php
2
-
3
  /**
4
  * Config
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.0.0
8
  */
9
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  require_once 'lib/tab.php';
15
- foreach ( glob( __DIR__ . '/config/*.php' ) as $filename ) {
16
- require_once $filename;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  /**
19
  * Render Security settings.
20
  *
21
- * @since 4.2.6
22
  */
23
  function security()
24
  {
@@ -26,135 +85,104 @@ function security()
26
  'logging',
27
  'syslog',
28
  'block',
29
- 'remote-ips'
 
30
  ];
31
- if ( version_compare( PHP_VERSION, '5.6.0', '>=' ) ) {
32
- $tabs[] = 'plugins';
33
- }
34
- $page = 'wp-fail2ban';
35
- if ( wf_fs()->is_premium() ) {
36
- $page .= '-premium';
37
- }
38
- render_tabs( $tabs, 'logging', $page );
39
  }
40
 
41
  /**
42
  * Render Settings.
43
  *
44
- * @since 4.2.6
45
  */
46
  function settings()
47
  {
48
  $tabs = [];
49
-
50
- if ( !function_exists( '\\add_security_page' ) ) {
51
  $tabs = [
52
  'logging',
53
  'syslog',
54
  'block',
55
  'remote-ips'
56
  ];
57
- if ( version_compare( PHP_VERSION, '5.6.0', '>=' ) ) {
58
  $tabs[] = 'plugins';
59
  }
60
  }
61
-
62
- $default = 'logging';
63
- render_tabs( $tabs, $default, 'wpf2b-settings' );
64
  }
65
 
66
  /**
67
  * Render Tabs.
68
  *
69
- * @since 4.2.6
70
  *
71
  * @param array $tabs List of slugs of tabs to render
72
- * @param string $default Default tab slug
73
  * @param string $menu Menu slug
74
  */
75
- function render_tabs( array $tabs, $default, $menu )
76
  {
 
 
77
  ?>
78
  <div class="wrap">
79
- <?php
80
- echo apply_filters( __METHOD__ . '.title', "<h1>WP fail2ban</h1>" ) ;
81
- ?>
82
  <hr class="wp-header-end">
83
 
84
  <h2 class="nav-tab-wrapper wp-clearfix">
85
- <?php
86
- $active_tab = Tab::getActiveTab( $default );
87
- foreach ( $tabs as $slug ) {
88
  $class = 'nav-tab';
89
- if ( $active_tab->getSlug() == $slug ) {
90
  $class .= ' nav-tab-active';
91
  }
92
- $params = apply_filters( __METHOD__ . '.params', [
93
  'page' => $menu,
94
- 'tab' => $slug,
95
- ] );
96
- printf(
97
- '<a class="%s" href="?%s">%s</a>',
98
- $class,
99
- http_build_query( $params ),
100
- Tab::getTabName( $slug )
101
- );
102
  }
103
  ?>
104
  </h2>
105
 
106
- <form action="options.php?tab=<?php
107
- echo $active_tab->getSlug() ;
108
- ?>" method="post">
109
- <?php
110
- settings_fields( 'wp-fail2ban' );
 
 
 
 
 
 
 
 
 
111
  $active_tab->render();
112
- 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>' ;
113
  ?>
114
  </form>
115
  </div>
116
- <?php
117
  }
118
 
119
  /**
120
- * Proxy for api.wp-fail2ban.com
121
  *
122
- * @since 4.2.6
 
 
 
123
  */
124
- function remote_tools()
125
  {
126
- global $current_user ;
127
- ?>
128
- <div class="wrap">
129
- <h1>Remote Tools (&beta;)</h1>
130
- <hr class="wp-header-end">
131
- <?php
132
-
133
- if ( function_exists( '\\org\\lecklider\\charles\\wordpress\\wp_fail2ban\\addons\\remote_tools\\tab' ) ) {
134
- \org\lecklider\charles\wordpress\wp_fail2ban\addons\remote_tools\tab();
135
- } else {
136
- ?>
137
- <h2 class="nav-tab-wrapper wp-clearfix">
138
- <a class="nav-tab nav-tab-active" href="#">Overview</a>
139
- </h2>
140
- <div class="card">
141
- <h2>Remote Tools Add-on</h2>
142
- <p>This add-on provides features that make life with WP fail2ban easier, all from a remote server. This gives access to valuable but infrequently used tools without bloating the core plugin.</p>
143
- <p>The first of these is a <strong>Custom Filter Tool</strong> (CFT).</p>
144
- <blockquote>
145
- <p>The filter files included are intended only as a starting point for those who want <em>WPf2b</em> to work “out of the box”.</p>
146
- <p>There is no &ldquo;one size fits all&rdquo; configuration possible for <em>fail2ban</em> - what may be a soft failure for one site should be treated as a hard failure for another, and vice versa.</p>
147
- </blockquote>
148
- <p>You could simply edit the filter files included, but it&lsquo;s surprisingly easy to make a mistake; I learned this the hard way with earlier versions of <em>WPf2b</em>.... The CFT removes most of the opportunities for human error - always a good thing!</p>
149
- <hr>
150
- <p>The Remote Tools Add-on is available from the <a href="<?php
151
- echo admin_url( 'admin.php?page=wp-fail2ban-addons' ) ;
152
- ?>">Add-Ons menu</a>.</p>
153
- </div>
154
- <?php
155
- }
156
-
157
- ?>
158
- </div>
159
- <?php
160
  }
 
1
  <?php
 
2
  /**
3
  * Config
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
 
10
+ defined('ABSPATH') or exit;
11
+
 
12
  require_once 'lib/tab.php';
13
+ require_once 'lib/logging.php';
14
+ require_once 'config/block.php';
15
+ require_once 'config/logging.php';
16
+ require_once 'config/plugins.php';
17
+ require_once 'config/remote-ips.php';
18
+ require_once 'config/syslog.php';
19
+
20
+ /**
21
+ * Init
22
+ *
23
+ */
24
+ function init_tabs($init)
25
+ {
26
+ if (!$init) {
27
+ new TabBlock();
28
+ new TabLogging();
29
+ new TabPlugins();
30
+ new TabRemoteIPs();
31
+ new TabSyslog();
32
+ }
33
+ return true;
34
+ }
35
+ add_filter('wp_fail2ban_init_tabs', __NAMESPACE__.'\init_tabs');
36
+
37
+ /**
38
+ * Display settings messages.
39
+ *
40
+ * @since 4.3.0
41
+ */
42
+ function admin_notices()
43
+ {
44
+ $screen = get_current_screen();
45
+ switch ($screen->id) {
46
+ case 'security_page_wp-fail2ban-premium':
47
+ case 'wp-fail2ban_page_wpf2b-settings':
48
+ settings_errors();
49
+ break;
50
+ }
51
  }
52
+ add_action('admin_notices', __NAMESPACE__.'\admin_notices');
53
+
54
+ /**
55
+ * Get network settings messages.
56
+ *
57
+ * @since 4.3.0
58
+ */
59
+ function network_admin_notices()
60
+ {
61
+ $screen = get_current_screen();
62
+ switch ($screen->id) {
63
+ case 'security_page_wp-fail2ban-premium-network':
64
+ case 'wp-fail2ban_page_wpf2b-settings-network':
65
+ if ($transients = get_site_transient('settings_errors')) {
66
+ global $wp_settings_errors;
67
+
68
+ $wp_settings_errors = array_merge((array)$wp_settings_errors, $transients);
69
+ delete_site_transient('settings_errors');
70
+ }
71
+ settings_errors();
72
+ break;
73
+ }
74
+ }
75
+ add_action('network_admin_notices', __NAMESPACE__.'\network_admin_notices');
76
+
77
  /**
78
  * Render Security settings.
79
  *
80
+ * @since 4.3.0
81
  */
82
  function security()
83
  {
85
  'logging',
86
  'syslog',
87
  'block',
88
+ 'remote-ips',
89
+ 'plugins'
90
  ];
91
+ $tabs = apply_filters(__METHOD__.'.tabs', $tabs);
92
+ $page = apply_filters(__METHOD__.'.page', plugin_basename(WP_FAIL2BAN_DIR));
93
+
94
+ render_tabs($tabs, $page);
 
 
 
 
95
  }
96
 
97
  /**
98
  * Render Settings.
99
  *
100
+ * @since 4.0.0
101
  */
102
  function settings()
103
  {
104
  $tabs = [];
105
+
106
+ if (!function_exists('\add_security_page')) {
107
  $tabs = [
108
  'logging',
109
  'syslog',
110
  'block',
111
  'remote-ips'
112
  ];
113
+ if (version_compare(PHP_VERSION, '5.6.0', '>=')) {
114
  $tabs[] = 'plugins';
115
  }
116
  }
117
+ $tabs = apply_filters(__METHOD__.'.tabs', $tabs);
118
+
119
+ render_tabs($tabs, 'wpf2b-settings');
120
  }
121
 
122
  /**
123
  * Render Tabs.
124
  *
125
+ * @since 4.3.0
126
  *
127
  * @param array $tabs List of slugs of tabs to render
 
128
  * @param string $menu Menu slug
129
  */
130
+ function render_tabs(array $tabs, $menu)
131
  {
132
+ $active_tab = TabBase::getActiveTab();
133
+
134
  ?>
135
  <div class="wrap">
136
+ <?=apply_filters(__METHOD__.'.title', sprintf('<h1>%s</h1>', __('Settings', 'wp-fail2ban')))?>
 
 
137
  <hr class="wp-header-end">
138
 
139
  <h2 class="nav-tab-wrapper wp-clearfix">
140
+ <?php
141
+ foreach ($tabs as $slug) {
 
142
  $class = 'nav-tab';
143
+ if ($active_tab->getSlug() == $slug) {
144
  $class .= ' nav-tab-active';
145
  }
146
+ $params = apply_filters(__METHOD__.'.params', [
147
  'page' => $menu,
148
+ 'tab' => $slug
149
+ ]);
150
+ printf('<a class="%s" href="?%s">%s</a>', $class, http_build_query($params), TabBase::getTabName($slug));
 
 
 
 
 
151
  }
152
  ?>
153
  </h2>
154
 
155
+ <?php
156
+ // Because the settings API was never finished we need an ugly hack
157
+ $action = sprintf(
158
+ '%s?tab=%s',
159
+ admin_url(is_network_admin()
160
+ ? 'admin-post.php'
161
+ : 'options.php'),
162
+ $active_tab->getSlug()
163
+ );
164
+ ?>
165
+
166
+ <form action="<?=$action?>" method="post">
167
+ <?php
168
+ settings_fields('wp-fail2ban');
169
  $active_tab->render();
 
170
  ?>
171
  </form>
172
  </div>
173
+ <?php
174
  }
175
 
176
  /**
177
+ * Helper: filtered defined(...)
178
  *
179
+ * @since 4.3.0
180
+ *
181
+ * @param string $define
182
+ * @return mixed
183
  */
184
+ function have_defined($define)
185
  {
186
+ return apply_filters(__NAMESPACE__.'\have_defined', defined($define), $define);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  }
188
+
admin/config/block.php CHANGED
@@ -1,22 +1,20 @@
1
  <?php
2
-
3
  /**
4
  * Settings - Block
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.0.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
  * Tab: Block
16
  *
17
  * @since 4.0.0
18
  */
19
- class TabBlock extends Tab
20
  {
21
  /**
22
  * {@inheritDoc}
@@ -25,10 +23,16 @@ class TabBlock extends Tab
25
  */
26
  public function __construct()
27
  {
28
- add_action( 'admin_init', [ $this, 'admin_init' ] );
29
- parent::__construct( 'block', 'Users' );
 
 
 
 
 
 
30
  }
31
-
32
  /**
33
  * {@inheritDoc}
34
  *
@@ -37,42 +41,54 @@ class TabBlock extends Tab
37
  public function admin_init()
38
  {
39
  // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
40
- add_settings_section(
41
- 'wp-fail2ban-block',
42
- __( 'Block' ),
43
- [ $this, 'section' ],
44
- 'wp-fail2ban-block'
45
- );
46
- add_settings_field(
47
- 'block-user-enumeration',
48
- parent::doc_link( 'WP_FAIL2BAN_BLOCK_USER_ENUMERATION', __( 'User Enumeration' ) ),
49
- [ $this, 'userEnumeration' ],
50
- 'wp-fail2ban-block',
51
- 'wp-fail2ban-block'
52
- );
53
- add_settings_field(
54
- 'block-users',
55
- parent::doc_link( 'WP_FAIL2BAN_BLOCKED_USERS', __( 'Usernames' ) ),
56
- [ $this, 'usernames' ],
57
- 'wp-fail2ban-block',
58
- 'wp-fail2ban-block'
59
- );
60
  // phpcs:enable
61
  }
62
-
63
  /**
64
- * {@inheritDoc}
65
- *
66
- * @since 4.0.0
67
  *
68
- * @param array $settings
69
- * @param array $input
70
  */
71
- public function sanitize( array $settings, array $input = null )
72
  {
73
- return $settings;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  }
75
-
76
  /**
77
  * {@inheritDoc}
78
  *
@@ -80,9 +96,9 @@ class TabBlock extends Tab
80
  */
81
  public function section()
82
  {
83
- echo '' ;
84
  }
85
-
86
  /**
87
  * User Enumeration
88
  *
@@ -90,31 +106,39 @@ class TabBlock extends Tab
90
  */
91
  public function userEnumeration()
92
  {
93
- printf( '<input type="checkbox" disabled="disabled" %s>', checked( WP_FAIL2BAN_BLOCK_USER_ENUMERATION, true, false ) );
94
  }
95
-
96
  /**
97
  * Blocked usernames
98
  *
99
  * @since 4.0.0
100
  */
101
- public function usernames()
102
  {
103
-
104
- if ( defined( 'WP_FAIL2BAN_BLOCKED_USERS' ) ) {
105
-
106
- if ( is_array( WP_FAIL2BAN_BLOCKED_USERS ) ) {
107
- $value = join( ', ', WP_FAIL2BAN_BLOCKED_USERS );
108
  } else {
109
  $value = WP_FAIL2BAN_BLOCKED_USERS;
110
  }
111
-
112
  } else {
113
  $value = '';
114
  }
115
-
116
- printf( '<input class="regular-text" type="text" disabled="disabled" value="%s">', esc_attr( $value ) );
 
 
117
  }
118
 
 
 
 
 
 
 
 
 
 
119
  }
120
- new TabBlock();
1
  <?php
 
2
  /**
3
  * Settings - Block
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ defined('ABSPATH') or exit;
11
 
 
 
 
12
  /**
13
  * Tab: Block
14
  *
15
  * @since 4.0.0
16
  */
17
+ class TabBlock extends TabBase
18
  {
19
  /**
20
  * {@inheritDoc}
23
  */
24
  public function __construct()
25
  {
26
+ // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
27
+ $this->__['users'] = __('Users', 'wp-fail2ban');
28
+ $this->__['user-enumeration'] = __('Block User Enumeration', 'wp-fail2ban');
29
+ $this->__['blacklist'] = __('Blacklisted Usernames', 'wp-fail2ban');
30
+ $this->__['username-login'] = __('Block username logins', 'wp-fail2ban');
31
+ // phpcs:enable
32
+
33
+ parent::__construct('block', __('Block', 'wp-fail2ban'));
34
  }
35
+
36
  /**
37
  * {@inheritDoc}
38
  *
41
  public function admin_init()
42
  {
43
  // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
44
+ add_settings_section('wp-fail2ban-users', $this->__['users'], [$this, 'section'], 'wp-fail2ban-block');
45
+ add_settings_field('user-enumeration', $this->__['user-enumeration'], [$this, 'userEnumeration'], 'wp-fail2ban-block', 'wp-fail2ban-users');
46
+ add_settings_field('blacklist', $this->__['blacklist'], [$this, 'users'], 'wp-fail2ban-block', 'wp-fail2ban-users');
47
+ add_settings_field('username-login', $this->__['username-login'], [$this, 'usernames'], 'wp-fail2ban-block', 'wp-fail2ban-users');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  // phpcs:enable
49
  }
50
+
51
  /**
52
+ * {*inheritDoc}
 
 
53
  *
54
+ * @since 4.3.0
 
55
  */
56
+ public function current_screen()
57
  {
58
+ $fmt = <<<___FMT___
59
+ <dl><style>dt{font-weight:bold;}</style>
60
+ <dt>%s</dt>
61
+ <dd><p>%s</p><p>%s</p><p>%s</p>%s</dd>
62
+ <dt>%s</dt>
63
+ <dd><p>%s</p><p>%s</p>%s</dd>
64
+ <dt>%s</dt>
65
+ <dd><p>%s</p><p>%s</p>%s</dd>
66
+ </dl>
67
+ ___FMT___;
68
+ get_current_screen()->add_help_tab([
69
+ 'id' => 'users',
70
+ 'title' => $this->__['users'],
71
+ 'content' => sprintf(
72
+ $fmt,
73
+ $this->__['user-enumeration'],
74
+ __('Automated brute-force attacks ("bots") typically start by getting a list of valid usernames ("user enumeration").', 'wp-fail2ban'),
75
+ __('Blocking user enumeration can force attackers to guess usernames, making these attacks much less likely to succeed.', 'wp-fail2ban'),
76
+ __('<strong>N.B.</strong> Some Themes "leak" usernames (for example, via Author profile pages); see <strong>Block username logins</strong> for an alternative.', 'wp-fail2ban'),
77
+ $this->see_also(['WP_FAIL2BAN_BLOCK_USER_ENUMERATION']),
78
+ $this->__['blacklist'],
79
+ __('Automated brute-force attacks ("bots") will often use well-known usernames, e.g. <tt>admin</tt>.', 'wp-fail2ban'),
80
+ __('Blacklisted usernames are blocked early in the login process, reducing server load.', 'wp-fail2ban'),
81
+ $this->see_also(['WP_FAIL2BAN_BLOCKED_USERS']),
82
+ $this->__['username-login'],
83
+ __('It is sometimes not possible to block user enumeration (for example, if your theme provides Author profiles). An alternative is to require users to login with their email address.', 'wp-fail2ban'),
84
+ __('<strong>N.B.</strong> This also applies to Blacklisted Usernames; you must list <em>email addresses</em>, not usernames.', 'wp-fail2ban'),
85
+ $this->see_also(['WP_FAIL2BAN_BLOCK_USERNAME_LOGIN'])
86
+ )
87
+ ]);
88
+
89
+ parent::current_screen();
90
  }
91
+
92
  /**
93
  * {@inheritDoc}
94
  *
96
  */
97
  public function section()
98
  {
99
+ echo '';
100
  }
101
+
102
  /**
103
  * User Enumeration
104
  *
106
  */
107
  public function userEnumeration()
108
  {
109
+ $this->checkbox('WP_FAIL2BAN_BLOCK_USER_ENUMERATION');
110
  }
111
+
112
  /**
113
  * Blocked usernames
114
  *
115
  * @since 4.0.0
116
  */
117
+ public function users()
118
  {
119
+ if (defined('WP_FAIL2BAN_BLOCKED_USERS')) {
120
+ if (is_array(WP_FAIL2BAN_BLOCKED_USERS)) {
121
+ $value = join(', ', WP_FAIL2BAN_BLOCKED_USERS);
 
 
122
  } else {
123
  $value = WP_FAIL2BAN_BLOCKED_USERS;
124
  }
 
125
  } else {
126
  $value = '';
127
  }
128
+ printf(
129
+ '<input class="regular-text" type="text" disabled="disabled" value="%s">',
130
+ esc_attr($value)
131
+ );
132
  }
133
 
134
+ /**
135
+ * Block username logins
136
+ *
137
+ * @since 4.3.0
138
+ */
139
+ public function usernames()
140
+ {
141
+ $this->checkbox('WP_FAIL2BAN_BLOCK_USERNAME_LOGIN');
142
+ }
143
  }
144
+
admin/config/logging.php CHANGED
@@ -1,32 +1,38 @@
1
  <?php
2
-
3
  /**
4
  * Settings - Logging
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.0.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
  * Tab: Logging
16
  *
17
  * @since 4.0.0
18
  */
19
- class TabLogging extends Tab
20
  {
21
  /**
22
  * {@inheritDoc}
23
  */
24
  public function __construct()
25
  {
26
- add_action( 'admin_init', [ $this, 'admin_init' ], 100 );
27
- parent::__construct( 'logging', 'Logging' );
 
 
 
 
 
 
 
 
28
  }
29
-
30
  /**
31
  * {@inheritDoc}
32
  *
@@ -35,75 +41,66 @@ class TabLogging extends Tab
35
  public function admin_init()
36
  {
37
  // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
38
- add_settings_section(
39
- 'wp-fail2ban-logging',
40
- __( 'What & Where' ),
41
- [ $this, 'sectionWhatWhere' ],
42
- 'wp-fail2ban-logging'
43
- );
44
- add_settings_field(
45
- 'logging-log-authentication',
46
- parent::doc_link( 'WP_FAIL2BAN_AUTH_LOG', __( 'Authentication' ) ),
47
- [ $this, 'authentication' ],
48
- 'wp-fail2ban-logging',
49
- 'wp-fail2ban-logging'
50
- );
51
- add_settings_field(
52
- 'logging-log-comments',
53
- parent::doc_link( 'WP_FAIL2BAN_LOG_COMMENTS', __( 'Comments' ) ),
54
- [ $this, 'comments' ],
55
- 'wp-fail2ban-logging',
56
- 'wp-fail2ban-logging'
57
- );
58
- add_settings_field(
59
- 'logging-log-spam',
60
- parent::doc_link( 'WP_FAIL2BAN_LOG_SPAM', __( 'Spam' ) ),
61
- [ $this, 'spam' ],
62
- 'wp-fail2ban-logging',
63
- 'wp-fail2ban-logging'
64
- );
65
- add_settings_field(
66
- 'logging-log-password-request',
67
- parent::doc_link( 'WP_FAIL2BAN_LOG_PASSWORD_REQUEST', __( 'Password Requests' ) ),
68
- [ $this, 'passwordRequest' ],
69
- 'wp-fail2ban-logging',
70
- 'wp-fail2ban-logging'
71
- );
72
- add_settings_field(
73
- 'logging-log-pingbacks',
74
- parent::doc_link( 'WP_FAIL2BAN_LOG_PINGBACKS', __( 'Pingbacks' ) ),
75
- [ $this, 'pingbacks' ],
76
- 'wp-fail2ban-logging',
77
- 'wp-fail2ban-logging'
78
- );
79
  // phpcs:enable
80
  }
81
-
82
  /**
83
  * {@inheritDoc}
84
  *
85
- * @since 4.0.0
86
  */
87
- public function render()
88
  {
89
- parent::render();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
91
-
92
- /**
93
- * {@inheritDoc}
94
- *
95
- * @since 4.0.0
96
- *
97
- * @param array $settings {@inheritDoc}
98
- * @param array $input {@inheritDoc}
99
- *
100
- * @return array {@inheritDoc}
101
- */
102
- public function sanitize( array $settings, array $input = null )
103
- {
104
- return $settings;
105
- }
106
-
107
  /**
108
  * Section summary.
109
  *
@@ -111,9 +108,9 @@ class TabLogging extends Tab
111
  */
112
  public function sectionWhatWhere()
113
  {
114
- echo '' ;
115
  }
116
-
117
  /**
118
  * Authentication.
119
  *
@@ -121,9 +118,14 @@ class TabLogging extends Tab
121
  */
122
  public function authentication()
123
  {
124
- printf( '<label>%s: %s</label>', __( 'Use facility' ), $this->getLogFacilities( 'WP_FAIL2BAN_AUTH_LOG', true ) );
 
 
 
 
 
125
  }
126
-
127
  /**
128
  * Comments.
129
  *
@@ -131,20 +133,15 @@ class TabLogging extends Tab
131
  */
132
  public function comments()
133
  {
134
- add_filter(
135
- 'wp_fail2ban_log_WP_FAIL2BAN_LOG_COMMENTS',
136
- [ $this, 'commentsExtra' ],
137
- 10,
138
- 3
139
- );
140
  $this->log(
141
  'WP_FAIL2BAN_LOG_COMMENTS',
142
  'WP_FAIL2BAN_COMMENT_LOG',
143
- '',
144
- [ 'comments-extra', 'logging-comments-extra-facility' ]
145
  );
146
  }
147
-
148
  /**
149
  * Comments extra helper - checked.
150
  *
@@ -152,14 +149,11 @@ class TabLogging extends Tab
152
  *
153
  * @param int $value Value to check
154
  */
155
- protected function commentExtraChecked( $value )
156
  {
157
- if ( !defined( 'WP_FAIL2BAN_LOG_COMMENTS_EXTRA' ) ) {
158
- return '';
159
- }
160
- return checked( $value & WP_FAIL2BAN_LOG_COMMENTS_EXTRA, $value, false );
161
  }
162
-
163
  /**
164
  * Comments extra helper - disabled.
165
  *
@@ -169,7 +163,7 @@ class TabLogging extends Tab
169
  {
170
  return 'disabled="disabled';
171
  }
172
-
173
  /**
174
  * Comments extra.
175
  *
@@ -180,10 +174,12 @@ class TabLogging extends Tab
180
  * @param string $define_log Not used
181
  *
182
  * @return string
 
 
183
  */
184
- public function commentsExtra( $html, $define_name, $define_log )
185
  {
186
- $fmt = <<<___HTML___
187
  <table>
188
  <tr>
189
  <th>%s</th>
@@ -203,24 +199,25 @@ class TabLogging extends Tab
203
  </tr>
204
  </table>
205
  ___HTML___;
206
- return $html . sprintf(
 
207
  $fmt,
208
- parent::doc_link( 'WP_FAIL2BAN_LOG_COMMENTS_EXTRA', __( 'Also log:' ) ),
209
- $this->commentExtraChecked( WPF2B_EVENT_COMMENT_NOT_FOUND ),
210
- __( 'Post not found' ),
211
- $this->commentExtraChecked( WPF2B_EVENT_COMMENT_CLOSED ),
212
- __( 'Comments closed' ),
213
- $this->commentExtraChecked( WPF2B_EVENT_COMMENT_TRASH ),
214
- __( 'Trash post' ),
215
- $this->commentExtraChecked( WPF2B_EVENT_COMMENT_DRAFT ),
216
- __( 'Draft post' ),
217
- $this->commentExtraChecked( WPF2B_EVENT_COMMENT_PASSWORD ),
218
- __( 'Password-protected post' ),
219
- parent::doc_link( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG', __( 'Use facility:' ) ),
220
- $this->getLogFacilities( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG', false )
221
  );
222
  }
223
-
224
  /**
225
  * Password request
226
  *
@@ -228,9 +225,12 @@ ___HTML___;
228
  */
229
  public function passwordRequest()
230
  {
231
- $this->log( 'WP_FAIL2BAN_LOG_PASSWORD_REQUEST', 'WP_FAIL2BAN_PASSWORD_REQUEST_LOG' );
 
 
 
232
  }
233
-
234
  /**
235
  * Pingbacks
236
  *
@@ -238,9 +238,12 @@ ___HTML___;
238
  */
239
  public function pingbacks()
240
  {
241
- $this->log( 'WP_FAIL2BAN_LOG_PINGBACKS', 'WP_FAIL2BAN_PINGBACK_LOG' );
 
 
 
242
  }
243
-
244
  /**
245
  * Spam
246
  *
@@ -248,8 +251,10 @@ ___HTML___;
248
  */
249
  public function spam()
250
  {
251
- $this->log( 'WP_FAIL2BAN_LOG_SPAM', 'WP_FAIL2BAN_SPAM_LOG' );
 
 
 
252
  }
253
-
254
  }
255
- new TabLogging();
1
  <?php
 
2
  /**
3
  * Settings - Logging
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ defined('ABSPATH') or exit;
11
 
 
 
 
12
  /**
13
  * Tab: Logging
14
  *
15
  * @since 4.0.0
16
  */
17
+ class TabLogging extends TabLoggingBase
18
  {
19
  /**
20
  * {@inheritDoc}
21
  */
22
  public function __construct()
23
  {
24
+ // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
25
+ $this->__['what-where'] = __('What & Where', 'wp-fail2ban');
26
+ $this->__['authentication'] = __('Authentication', 'wp-fail2ban');
27
+ $this->__['comments'] = __('Comments', 'wp-fail2ban');
28
+ $this->__['spam'] = __('Spam', 'wp-fail2ban');
29
+ $this->__['password-request'] = __('Password Requests', 'wp-fail2ban');
30
+ $this->__['pingbacks'] = __('Pingbacks', 'wp-fail2ban');
31
+ // phpcs:enable
32
+
33
+ parent::__construct('logging', __('Logging', 'wp-fail2ban'));
34
  }
35
+
36
  /**
37
  * {@inheritDoc}
38
  *
41
  public function admin_init()
42
  {
43
  // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
44
+ add_settings_section('wp-fail2ban-logging', $this->__['what-where'], [$this, 'sectionWhatWhere'],'wp-fail2ban-logging');
45
+ add_settings_field('logging-log-authentication', $this->__['authentication'], [$this, 'authentication'], 'wp-fail2ban-logging', 'wp-fail2ban-logging');
46
+ add_settings_field('logging-log-comments', $this->__['comments'], [$this, 'comments'], 'wp-fail2ban-logging', 'wp-fail2ban-logging');
47
+ add_settings_field('logging-log-spam', $this->__['spam'], [$this, 'spam'], 'wp-fail2ban-logging', 'wp-fail2ban-logging');
48
+ add_settings_field('logging-log-password-request', $this->__['password-request'], [$this, 'passwordRequest'], 'wp-fail2ban-logging', 'wp-fail2ban-logging');
49
+ add_settings_field('logging-log-pingbacks', $this->__['pingbacks'], [$this, 'pingbacks'], 'wp-fail2ban-logging', 'wp-fail2ban-logging');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  // phpcs:enable
51
  }
52
+
53
  /**
54
  * {@inheritDoc}
55
  *
56
+ * @since 4.3.0
57
  */
58
+ public function current_screen()
59
  {
60
+ $fmt = <<<___FMT___
61
+ <dl><style>dt{font-weight:bold;}</style>
62
+ <dt>%s</dt><dd>%s</dd>
63
+ <dt>%s</dt><dd>%s</dd>
64
+ <dt>%s</dt><dd>%s</dd>
65
+ <dt>%s</dt><dd>%s</dd>
66
+ <dt>%s</dt><dd>%s</dd>
67
+ </dl>
68
+ ___FMT___;
69
+ get_current_screen()->add_help_tab([
70
+ 'id' => 'what-where',
71
+ 'title' => $this->__['what-where'],
72
+ 'content' => sprintf(
73
+ $fmt,
74
+ $this->__['authentication'],
75
+ $this->see_also([
76
+ 'WP_FAIL2BAN_AUTH_LOG'
77
+ ], false),
78
+ $this->__['comments'],
79
+ $this->see_also([
80
+ 'WP_FAIL2BAN_LOG_COMMENTS',
81
+ 'WP_FAIL2BAN_LOG_COMMENTS_EXTRA',
82
+ 'WP_FAIL2BAN_COMMENT_EXTRA_LOG'
83
+ ], false),
84
+ $this->__['spam'],
85
+ $this->see_also([
86
+ 'WP_FAIL2BAN_LOG_SPAM',
87
+ 'WP_FAIL2BAN_SPAM_LOG'
88
+ ], false),
89
+ $this->__['password-request'],
90
+ $this->see_also([
91
+ 'WP_FAIL2BAN_LOG_PASSWORD_REQUEST',
92
+ 'WP_FAIL2BAN_PASSWORD_REQUEST_LOG'
93
+ ], false),
94
+ $this->__['pingbacks'],
95
+ $this->see_also([
96
+ 'WP_FAIL2BAN_LOG_PINGBACKS',
97
+ 'WP_FAIL2BAN_PINGBACK_LOG'
98
+ ], false)
99
+ )
100
+ ]);
101
+ parent::current_screen();
102
  }
103
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  /**
105
  * Section summary.
106
  *
108
  */
109
  public function sectionWhatWhere()
110
  {
111
+ // noop
112
  }
113
+
114
  /**
115
  * Authentication.
116
  *
118
  */
119
  public function authentication()
120
  {
121
+ printf(
122
+ '<label>%s: %s</label><p class="description">%s</p>',
123
+ __('Use facility', 'wp-fail2ban'),
124
+ $this->getLogFacilities('WP_FAIL2BAN_AUTH_LOG', true),
125
+ Config::desc('WP_FAIL2BAN_AUTH_LOG')
126
+ );
127
  }
128
+
129
  /**
130
  * Comments.
131
  *
133
  */
134
  public function comments()
135
  {
136
+ add_filter('wp_fail2ban_log_WP_FAIL2BAN_LOG_COMMENTS', [$this, 'commentsExtra'], 10, 3);
137
+
 
 
 
 
138
  $this->log(
139
  'WP_FAIL2BAN_LOG_COMMENTS',
140
  'WP_FAIL2BAN_COMMENT_LOG',
141
+ ['comments-extra', 'logging-comments-extra-facility']
 
142
  );
143
  }
144
+
145
  /**
146
  * Comments extra helper - checked.
147
  *
149
  *
150
  * @param int $value Value to check
151
  */
152
+ protected function commentExtraChecked($value)
153
  {
154
+ return checked($value == ($value & Config::get('WP_FAIL2BAN_LOG_COMMENTS_EXTRA')), true, false);
 
 
 
155
  }
156
+
157
  /**
158
  * Comments extra helper - disabled.
159
  *
163
  {
164
  return 'disabled="disabled';
165
  }
166
+
167
  /**
168
  * Comments extra.
169
  *
174
  * @param string $define_log Not used
175
  *
176
  * @return string
177
+ *
178
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
179
  */
180
+ public function commentsExtra($html, $define_name, $define_log)
181
  {
182
+ $fmt = <<< ___HTML___
183
  <table>
184
  <tr>
185
  <th>%s</th>
199
  </tr>
200
  </table>
201
  ___HTML___;
202
+
203
+ return $html.sprintf(
204
  $fmt,
205
+ __('Also log:', 'wp-fail2ban'),
206
+ $this->commentExtraChecked(WPF2B_EVENT_COMMENT_NOT_FOUND),
207
+ __('Post not found', 'wp-fail2ban'),
208
+ $this->commentExtraChecked(WPF2B_EVENT_COMMENT_CLOSED),
209
+ __('Comments closed', 'wp-fail2ban'),
210
+ $this->commentExtraChecked(WPF2B_EVENT_COMMENT_TRASH),
211
+ __('Trash post', 'wp-fail2ban'),
212
+ $this->commentExtraChecked(WPF2B_EVENT_COMMENT_DRAFT),
213
+ __('Draft post', 'wp-fail2ban'),
214
+ $this->commentExtraChecked(WPF2B_EVENT_COMMENT_PASSWORD),
215
+ __('Password-protected post', 'wp-fail2ban'),
216
+ __('Use facility:', 'wp-fail2ban'),
217
+ $this->getLogFacilities('WP_FAIL2BAN_COMMENT_EXTRA_LOG', false)
218
  );
219
  }
220
+
221
  /**
222
  * Password request
223
  *
225
  */
226
  public function passwordRequest()
227
  {
228
+ $this->log(
229
+ 'WP_FAIL2BAN_LOG_PASSWORD_REQUEST',
230
+ 'WP_FAIL2BAN_PASSWORD_REQUEST_LOG'
231
+ );
232
  }
233
+
234
  /**
235
  * Pingbacks
236
  *
238
  */
239
  public function pingbacks()
240
  {
241
+ $this->log(
242
+ 'WP_FAIL2BAN_LOG_PINGBACKS',
243
+ 'WP_FAIL2BAN_PINGBACK_LOG'
244
+ );
245
  }
246
+
247
  /**
248
  * Spam
249
  *
251
  */
252
  public function spam()
253
  {
254
+ $this->log(
255
+ 'WP_FAIL2BAN_LOG_SPAM',
256
+ 'WP_FAIL2BAN_SPAM_LOG'
257
+ );
258
  }
 
259
  }
260
+
admin/config/plugins.php CHANGED
@@ -1,32 +1,29 @@
1
  <?php
2
-
3
  /**
4
  * Settings - Plugins
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.2.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
  * Tab: Plugins
16
  *
17
  * @since 4.2.0
18
  */
19
- class TabPlugins extends Tab
20
  {
21
  /**
22
  * {@inheritDoc}
23
  */
24
  public function __construct()
25
  {
26
- add_action( 'admin_init', [ $this, 'admin_init' ], 100 );
27
- parent::__construct( 'plugins', 'Plugins' );
28
  }
29
-
30
  /**
31
  * {@inheritDoc}
32
  *
@@ -35,82 +32,25 @@ class TabPlugins extends Tab
35
  public function admin_init()
36
  {
37
  // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
38
- add_settings_section(
39
- 'wp-fail2ban-plugins',
40
- __( 'Event Class Facilities' ),
41
- [ $this, 'sectionLoggingEventClasses' ],
42
- 'wp-fail2ban-plugins'
43
- );
44
- add_settings_field(
45
- 'plugins-log-auth',
46
- parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_AUTH', __( 'Authentication' ) ),
47
- [ $this, 'auth' ],
48
- 'wp-fail2ban-plugins',
49
- 'wp-fail2ban-plugins'
50
- );
51
- add_settings_field(
52
- 'plugins-log-comment',
53
- parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_COMMENT', __( 'Comment' ) ),
54
- [ $this, 'comment' ],
55
- 'wp-fail2ban-plugins',
56
- 'wp-fail2ban-plugins'
57
- );
58
- add_settings_field(
59
- 'plugins-log-password',
60
- parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_PASSWORD', __( 'Password' ) ),
61
- [ $this, 'password' ],
62
- 'wp-fail2ban-plugins',
63
- 'wp-fail2ban-plugins'
64
- );
65
- add_settings_field(
66
- 'plugins-log-rest',
67
- parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_REST', __( 'REST' ) ),
68
- [ $this, 'rest' ],
69
- 'wp-fail2ban-plugins',
70
- 'wp-fail2ban-plugins'
71
- );
72
- add_settings_field(
73
- 'plugins-log-spam',
74
- parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_SPAM', __( 'Spam' ) ),
75
- [ $this, 'spam' ],
76
- 'wp-fail2ban-plugins',
77
- 'wp-fail2ban-plugins'
78
- );
79
- add_settings_field(
80
- 'plugins-log-xmlrpc',
81
- parent::doc_link( 'WP_FAIL2BAN_PLUGIN_LOG_XMLRPC', __( 'XML-RPC' ) ),
82
- [ $this, 'xmlrpc' ],
83
- 'wp-fail2ban-plugins',
84
- 'wp-fail2ban-plugins'
85
- );
86
  // phpcs:enable
87
  }
88
-
89
  /**
90
  * {@inheritDoc}
91
  *
92
- * @since 4.2.0
93
  */
94
- public function render()
95
  {
96
- parent::render();
97
  }
98
-
99
- /**
100
- * {@inheritDoc}
101
- *
102
- * @since 4.2.0
103
- *
104
- * @param array $settings {@inheritDoc}
105
- * @param array $input {@inheritDoc}
106
- *
107
- * @return array {@inheritDoc}
108
- */
109
- public function sanitize( array $settings, array $input = null )
110
- {
111
- return $settings;
112
- }
113
-
114
  /**
115
  * Section summary.
116
  *
@@ -118,9 +58,9 @@ class TabPlugins extends Tab
118
  */
119
  public function sectionLoggingEventClasses()
120
  {
121
- echo __( 'Facilities to use for plugin-generated messages. The defaults follow the Core defaults.' ) ;
122
  }
123
-
124
  /**
125
  * Auth
126
  *
@@ -128,9 +68,9 @@ class TabPlugins extends Tab
128
  */
129
  public function auth()
130
  {
131
- $this->log( 'WP_FAIL2BAN_PLUGIN_LOG_AUTH', 'WP_FAIL2BAN_PLUGIN_AUTH_LOG' );
132
  }
133
-
134
  /**
135
  * Comment
136
  *
@@ -138,9 +78,9 @@ class TabPlugins extends Tab
138
  */
139
  public function comment()
140
  {
141
- $this->log( 'WP_FAIL2BAN_PLUGIN_LOG_COMMENT', 'WP_FAIL2BAN_PLUGIN_COMMENT_LOG' );
142
  }
143
-
144
  /**
145
  * Password
146
  *
@@ -148,9 +88,9 @@ class TabPlugins extends Tab
148
  */
149
  public function password()
150
  {
151
- $this->log( 'WP_FAIL2BAN_PLUGIN_LOG_PASSWORD', 'WP_FAIL2BAN_PLUGIN_PASSWORD_LOG' );
152
  }
153
-
154
  /**
155
  * REST
156
  *
@@ -158,9 +98,9 @@ class TabPlugins extends Tab
158
  */
159
  public function rest()
160
  {
161
- $this->log( 'WP_FAIL2BAN_PLUGIN_LOG_REST', 'WP_FAIL2BAN_PLUGIN_REST_LOG' );
162
  }
163
-
164
  /**
165
  * Spam
166
  *
@@ -168,9 +108,9 @@ class TabPlugins extends Tab
168
  */
169
  public function spam()
170
  {
171
- $this->log( 'WP_FAIL2BAN_PLUGIN_LOG_SPAM', 'WP_FAIL2BAN_PLUGIN_SPAM_LOG' );
172
  }
173
-
174
  /**
175
  * XML-RPC
176
  *
@@ -178,8 +118,7 @@ class TabPlugins extends Tab
178
  */
179
  public function xmlrpc()
180
  {
181
- $this->log( 'WP_FAIL2BAN_PLUGIN_LOG_XMLRPC', 'WP_FAIL2BAN_PLUGIN_XMLRPC_LOG' );
182
  }
183
-
184
  }
185
- new TabPlugins();
1
  <?php
 
2
  /**
3
  * Settings - Plugins
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.2.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ defined('ABSPATH') or exit;
11
 
 
 
 
12
  /**
13
  * Tab: Plugins
14
  *
15
  * @since 4.2.0
16
  */
17
+ class TabPlugins extends TabLoggingBase
18
  {
19
  /**
20
  * {@inheritDoc}
21
  */
22
  public function __construct()
23
  {
24
+ parent::__construct('plugins', __('Plugins', 'wp-fail2ban'));
 
25
  }
26
+
27
  /**
28
  * {@inheritDoc}
29
  *
32
  public function admin_init()
33
  {
34
  // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
35
+ add_settings_section('wp-fail2ban-plugins', __('Event Class Facilities', 'wp-fail2ban'), [$this, 'sectionLoggingEventClasses'], 'wp-fail2ban-plugins');
36
+ add_settings_field('plugins-log-auth', __('Authentication', 'wp-fail2ban'), [$this, 'auth'], 'wp-fail2ban-plugins', 'wp-fail2ban-plugins');
37
+ add_settings_field('plugins-log-comment', __('Comment', 'wp-fail2ban'), [$this, 'comment'], 'wp-fail2ban-plugins', 'wp-fail2ban-plugins');
38
+ add_settings_field('plugins-log-password', __('Password', 'wp-fail2ban'), [$this, 'password'], 'wp-fail2ban-plugins', 'wp-fail2ban-plugins');
39
+ add_settings_field('plugins-log-rest', __('REST', 'wp-fail2ban'), [$this, 'rest'], 'wp-fail2ban-plugins', 'wp-fail2ban-plugins');
40
+ add_settings_field('plugins-log-spam', __('Spam', 'wp-fail2ban'), [$this, 'spam'], 'wp-fail2ban-plugins', 'wp-fail2ban-plugins');
41
+ add_settings_field('plugins-log-xmlrpc', __('XML-RPC', 'wp-fail2ban'), [$this, 'xmlrpc'], 'wp-fail2ban-plugins', 'wp-fail2ban-plugins');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  // phpcs:enable
43
  }
44
+
45
  /**
46
  * {@inheritDoc}
47
  *
48
+ * @since 4.3.0
49
  */
50
+ public function current_screen()
51
  {
 
52
  }
53
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  /**
55
  * Section summary.
56
  *
58
  */
59
  public function sectionLoggingEventClasses()
60
  {
61
+ echo __('Facilities to use for plugin-generated messages. The defaults follow the Core defaults.', 'wp-fail2ban');
62
  }
63
+
64
  /**
65
  * Auth
66
  *
68
  */
69
  public function auth()
70
  {
71
+ $this->log('WP_FAIL2BAN_PLUGIN_LOG_AUTH', 'WP_FAIL2BAN_PLUGIN_AUTH_LOG');
72
  }
73
+
74
  /**
75
  * Comment
76
  *
78
  */
79
  public function comment()
80
  {
81
+ $this->log('WP_FAIL2BAN_PLUGIN_LOG_COMMENT', 'WP_FAIL2BAN_PLUGIN_COMMENT_LOG');
82
  }
83
+
84
  /**
85
  * Password
86
  *
88
  */
89
  public function password()
90
  {
91
+ $this->log('WP_FAIL2BAN_PLUGIN_LOG_PASSWORD', 'WP_FAIL2BAN_PLUGIN_PASSWORD_LOG');
92
  }
93
+
94
  /**
95
  * REST
96
  *
98
  */
99
  public function rest()
100
  {
101
+ $this->log('WP_FAIL2BAN_PLUGIN_LOG_REST', 'WP_FAIL2BAN_PLUGIN_REST_LOG');
102
  }
103
+
104
  /**
105
  * Spam
106
  *
108
  */
109
  public function spam()
110
  {
111
+ $this->log('WP_FAIL2BAN_PLUGIN_LOG_SPAM', 'WP_FAIL2BAN_PLUGIN_SPAM_LOG');
112
  }
113
+
114
  /**
115
  * XML-RPC
116
  *
118
  */
119
  public function xmlrpc()
120
  {
121
+ $this->log('WP_FAIL2BAN_PLUGIN_LOG_XMLRPC', 'WP_FAIL2BAN_PLUGIN_XMLRPC_LOG');
122
  }
 
123
  }
124
+
admin/config/remote-ips.php CHANGED
@@ -1,22 +1,20 @@
1
  <?php
2
-
3
  /**
4
  * Settings - Remote IPs
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.0.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
  * Tab: Remote IPs
16
  *
17
  * @since 4.0.0
18
  */
19
- class TabRemoteIPs extends Tab
20
  {
21
  /**
22
  * {@inheritDoc}
@@ -25,10 +23,12 @@ class TabRemoteIPs extends Tab
25
  */
26
  public function __construct()
27
  {
28
- add_action( 'admin_init', [ $this, 'admin_init' ] );
29
- parent::__construct( 'remote-ips', 'Remote IPs' );
 
 
30
  }
31
-
32
  /**
33
  * {@inheritDoc}
34
  *
@@ -37,35 +37,38 @@ class TabRemoteIPs extends Tab
37
  public function admin_init()
38
  {
39
  // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
40
- add_settings_section(
41
- 'wp-fail2ban-proxies',
42
- __( 'Proxies' ),
43
- [ $this, 'section' ],
44
- 'wp-fail2ban-remote-ips'
45
- );
46
- add_settings_field(
47
- 'remote-ips-proxies',
48
- parent::doc_link( 'WP_FAIL2BAN_PROXIES', __( 'IP list' ) ),
49
- [ $this, 'proxies' ],
50
- 'wp-fail2ban-remote-ips',
51
- 'wp-fail2ban-proxies'
52
- );
53
  // phpcs:enable
54
  }
55
-
56
  /**
57
  * {@inheritDoc}
58
  *
59
- * @since 4.0.0
60
- *
61
- * @param array $settings
62
- * @param array $input
63
  */
64
- public function sanitize( array $settings, array $input = null )
65
  {
66
- return $settings;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
-
69
  /**
70
  * Section blurb.
71
  *
@@ -73,28 +76,37 @@ class TabRemoteIPs extends Tab
73
  */
74
  public function section()
75
  {
76
- echo '' ;
77
  }
78
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  /**
80
  * Proxies.
81
  *
 
82
  * @since 4.0.0
83
  */
84
  public function proxies()
85
  {
86
- $value = '';
87
- if ( defined( 'WP_FAIL2BAN_PROXIES' ) ) {
88
-
89
- if ( is_array( WP_FAIL2BAN_PROXIES ) ) {
90
- $value = join( "\n", WP_FAIL2BAN_PROXIES );
91
- } else {
92
- $value = join( "\n", array_map( 'trim', explode( ',', WP_FAIL2BAN_PROXIES ) ) );
93
- }
94
-
95
- }
96
- printf( '<fieldset><textarea class="code" cols="20" rows="10" disabled="disabled">%s</textarea></fieldset>', esc_html( $value ) );
97
  }
98
-
99
  }
100
- new TabRemoteIPs();
1
  <?php
 
2
  /**
3
  * Settings - Remote IPs
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ defined('ABSPATH') or exit;
11
 
 
 
 
12
  /**
13
  * Tab: Remote IPs
14
  *
15
  * @since 4.0.0
16
  */
17
+ class TabRemoteIPs extends TabBase
18
  {
19
  /**
20
  * {@inheritDoc}
23
  */
24
  public function __construct()
25
  {
26
+ $this->__['wp-fail2ban-proxies'] = __('Proxies', 'wp-fail2ban');
27
+ $this->__['remote-ips-proxies'] = __('IP list', 'wp-fail2ban');
28
+
29
+ parent::__construct('remote-ips', __('Remote IPs', 'wp-fail2ban'));
30
  }
31
+
32
  /**
33
  * {@inheritDoc}
34
  *
37
  public function admin_init()
38
  {
39
  // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
40
+ add_settings_section('wp-fail2ban-proxies', $this->__['wp-fail2ban-proxies'], [$this, 'section'], 'wp-fail2ban-remote-ips');
41
+ add_settings_field('remote-ips-proxies', $this->__['remote-ips-proxies'], [$this, 'proxies'], 'wp-fail2ban-remote-ips', 'wp-fail2ban-proxies');
 
 
 
 
 
 
 
 
 
 
 
42
  // phpcs:enable
43
  }
44
+
45
  /**
46
  * {@inheritDoc}
47
  *
48
+ * @since 4.3.0
 
 
 
49
  */
50
+ public function current_screen()
51
  {
52
+ $fmt = <<<___FMT___
53
+ <dl><style>dt{font-weight:bold;}</style>
54
+ <dt>%s</dt>
55
+ <dd><p>%s</p><p>%s</p>%s</dd>
56
+ </dl>
57
+ ___FMT___;
58
+ get_current_screen()->add_help_tab([
59
+ 'id' => 'remote-ips-proxies',
60
+ 'title' => $this->__['wp-fail2ban-proxies'],
61
+ 'content' => sprintf(
62
+ $fmt,
63
+ $this->__['remote-ips-proxies'],
64
+ __('A list of IPv4 addresses in CIDR notation. The list of CloudFlare IPs can be found <a href="https://www.cloudflare.com/ips-v4" rel="noopener" target="_blank">here</a>', 'wp-fail2ban'),
65
+ __('<strong>NB:</strong> IPv6 is not yet supported.', 'wp-fail2ban'),
66
+ $this->doc_link('WP_FAIL2BAN_PROXIES')
67
+ )
68
+ ]);
69
+ parent::current_screen();
70
  }
71
+
72
  /**
73
  * Section blurb.
74
  *
76
  */
77
  public function section()
78
  {
79
+ echo '';
80
  }
81
+
82
+ /**
83
+ * Helper - multi-line string from proxies list.
84
+ *
85
+ * @since 4.3.0
86
+ *
87
+ * @return string
88
+ */
89
+ protected function proxies_value()
90
+ {
91
+ $proxies = Config::get('WP_FAIL2BAN_PROXIES');
92
+ return (is_array($proxies))
93
+ ? join("\n", $proxies)
94
+ : join("\n", array_map('trim', explode(',', $proxies)));
95
+ }
96
+
97
  /**
98
  * Proxies.
99
  *
100
+ * @since 4.3.0 Refactored.
101
  * @since 4.0.0
102
  */
103
  public function proxies()
104
  {
105
+ printf(
106
+ '<fieldset><textarea class="code" cols="20" rows="10" disabled="disabled">%s</textarea></fieldset>',
107
+ esc_html($this->proxies_value())
108
+ );
109
+ $this->description('WP_FAIL2BAN_PROXIES');
 
 
 
 
 
 
110
  }
 
111
  }
112
+
admin/config/syslog.php CHANGED
@@ -1,32 +1,36 @@
1
  <?php
2
-
3
  /**
4
  * Settings - syslog
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.0.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
  * Tab: Syslog
16
  *
17
  * @since 4.0.0
18
  */
19
- class TabSyslog extends Tab
20
  {
21
  /**
22
  * {@inheritDoc}
23
  */
24
  public function __construct()
25
  {
26
- add_action( 'admin_init', [ $this, 'admin_init' ], 100 );
27
- parent::__construct( 'syslog', '<tt>syslog</tt>' );
 
 
 
 
 
 
28
  }
29
-
30
  /**
31
  * {@inheritDoc}
32
  *
@@ -35,50 +39,81 @@ class TabSyslog extends Tab
35
  public function admin_init()
36
  {
37
  // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
38
- add_settings_section(
39
- 'wp-fail2ban-connection',
40
- __( 'Connection' ),
41
- [ $this, 'sectionConnection' ],
42
- 'wp-fail2ban-syslog'
43
- );
44
- add_settings_field(
45
- 'logging-connection',
46
- parent::doc_link( 'WP_FAIL2BAN_OPENLOG_OPTIONS', __( 'Options' ) ),
47
- [ $this, 'connection' ],
48
- 'wp-fail2ban-syslog',
49
- 'wp-fail2ban-connection'
50
- );
51
- add_settings_section(
52
- 'wp-fail2ban-workarounds',
53
- __( 'Workarounds' ),
54
- [ $this, 'sectionWorkarounds' ],
55
- 'wp-fail2ban-syslog'
56
- );
57
- add_settings_field(
58
- 'logging-workarounds',
59
- parent::doc_link( '../syslog', __( 'Options' ) ),
60
- [ $this, 'workarounds' ],
61
- 'wp-fail2ban-syslog',
62
- 'wp-fail2ban-workarounds'
63
- );
64
  // phpcs:enable
65
  }
66
-
67
  /**
68
  * {@inheritDoc}
69
  *
70
- * @since 4.0.0
71
- *
72
- * @param array $settings {@inheritDoc}
73
- * @param array $input {@inheritDoc}
74
- *
75
- * @return array {@inheritDoc}
76
  */
77
- public function sanitize( array $settings, array $input = null )
78
  {
79
- return $settings;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  }
81
-
82
  /**
83
  * Connection section blurb.
84
  *
@@ -86,17 +121,17 @@ class TabSyslog extends Tab
86
  */
87
  public function sectionConnection()
88
  {
89
- echo '' ;
90
  }
91
-
92
  /**
93
  * Connection.
94
  *
 
95
  * @since 4.0.0
96
  */
97
  public function connection()
98
  {
99
- $class = '';
100
  $fmt = <<<___STR___
101
  <fieldset>
102
  <label><input type="checkbox" disabled="disabled" %s> <code>LOG_CONS</code></label><br>
@@ -106,18 +141,18 @@ class TabSyslog extends Tab
106
  <label><input type="radio" disabled="disabled" %s> <code>LOG_ODELAY</code></label>
107
  </fieldset>
108
  ___STR___;
 
109
  printf(
110
  $fmt,
111
- checked( WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_CONS, LOG_CONS, false ),
112
- checked( WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_PERROR, LOG_PERROR, false ),
113
- checked( WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_PID, LOG_PID, false ),
114
- __( 'default' ),
115
- checked( WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_NDELAY, LOG_NDELAY, false ),
116
- __( 'default' ),
117
- checked( WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_ODELAY, LOG_ODELAY, false )
118
  );
 
119
  }
120
-
121
  /**
122
  * Workarounds section blurb.
123
  *
@@ -125,12 +160,13 @@ ___STR___;
125
  */
126
  public function sectionWorkarounds()
127
  {
128
- echo '' ;
129
  }
130
-
131
  /**
132
  * Workarounds.
133
  *
 
134
  * @since 4.0.0
135
  */
136
  public function workarounds()
@@ -146,14 +182,13 @@ ___STR___;
146
  ___STR___;
147
  printf(
148
  $fmt,
149
- checked( @WP_FAIL2BAN_SYSLOG_SHORT_TAG, true, false ),
150
- __( 'Short Tag' ),
151
- checked( @WP_FAIL2BAN_HTTP_HOST, true, false ),
152
- __( 'Specify Host' ),
153
- checked( @WP_FAIL2BAN_TRUNCATE_HOST, true, false ),
154
- __( 'Truncate Host' )
155
  );
156
  }
157
-
158
  }
159
- new TabSyslog();
1
  <?php
 
2
  /**
3
  * Settings - syslog
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ defined('ABSPATH') or exit;
11
 
 
 
 
12
  /**
13
  * Tab: Syslog
14
  *
15
  * @since 4.0.0
16
  */
17
+ class TabSyslog extends TabBase
18
  {
19
  /**
20
  * {@inheritDoc}
21
  */
22
  public function __construct()
23
  {
24
+ // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
25
+ $this->__['wp-fail2ban-connection'] = __('Connection', 'wp-fail2ban');
26
+ $this->__['syslog-connection-options'] = __('Options', 'wp-fail2ban');
27
+ $this->__['wp-fail2ban-workarounds'] = __('Workarounds', 'wp-fail2ban');
28
+ $this->__['syslog-workarounds'] = __('Options', 'wp-fail2ban');
29
+ // phpcs:enable
30
+
31
+ parent::__construct('syslog', 'syslog');
32
  }
33
+
34
  /**
35
  * {@inheritDoc}
36
  *
39
  public function admin_init()
40
  {
41
  // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
42
+ add_settings_section('wp-fail2ban-connection', $this->__['wp-fail2ban-connection'], [$this, 'sectionConnection'], 'wp-fail2ban-syslog');
43
+ add_settings_field('syslog-connection-options', $this->__['syslog-connection-options'], [$this, 'connection'], 'wp-fail2ban-syslog', 'wp-fail2ban-connection');
44
+
45
+ add_settings_section('wp-fail2ban-workarounds', $this->__['wp-fail2ban-workarounds'], [$this, 'sectionWorkarounds'], 'wp-fail2ban-syslog');
46
+ add_settings_field('syslog-workarounds', $this->__['syslog-workarounds'], [$this, 'workarounds'], 'wp-fail2ban-syslog', 'wp-fail2ban-workarounds');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  // phpcs:enable
48
  }
49
+
50
  /**
51
  * {@inheritDoc}
52
  *
53
+ * @since 4.3.0
 
 
 
 
 
54
  */
55
+ public function current_screen()
56
  {
57
+ $fmt = <<<___FMT___
58
+ <p>%s</p>
59
+ <table><style>th{text-align:left;vertical-align:top;}</style>
60
+ <tr><th scope="row">LOG_CONS</th><td>%s</td></tr>
61
+ <tr><th scope="row">LOG_NDELAY</th><td>%s</td></tr>
62
+ <tr><th scope="row">LOG_ODELAY</th><td>%s</td></tr>
63
+ <tr><th scope="row">LOG_PERROR</th><td>%s</td></tr>
64
+ <tr><th scope="row">LOG_PID</th><td>%s</td></tr>
65
+ </table>
66
+ %s
67
+ ___FMT___;
68
+ get_current_screen()->add_help_tab([
69
+ 'id' => 'syslog-connection-options',
70
+ 'title' => $this->__['wp-fail2ban-connection'],
71
+ 'content' => sprintf(
72
+ $fmt,
73
+ __('Used to indicate what logging options will be used when generating a log message.', 'wp-fail2ban'),
74
+ __('if there is an error while sending data to the system logger, write directly to the system console', 'wp-fail2ban'),
75
+ __('open the connection to the logger immediately', 'wp-fail2ban'),
76
+ __('(default) delay opening the connection until the first message is logged', 'wp-fail2ban'),
77
+ __('print log message also to standard error', 'wp-fail2ban'),
78
+ __('include PID with each message', 'wp-fail2ban'),
79
+ $this->see_also(['WP_FAIL2BAN_OPENLOG_OPTIONS'])
80
+ )
81
+ ]);
82
+ $fmt = <<<___FMT___
83
+ <p>%s</p>
84
+ <p>%s</p>
85
+ <dl><style>dt{font-weight:bold;}</style>
86
+ <dt>%s</dt>
87
+ <dd><p>%s</p>%s</dd>
88
+ <dt>%s</dt>
89
+ <dd><p>%s</p>%s</dd>
90
+ <dt>%s</dt>
91
+ <dd><p>%s</p><p>%s</p>%s</dd>
92
+ </dl>
93
+ ___FMT___;
94
+ get_current_screen()->add_help_tab([
95
+ 'id' => 'syslog-workarounds',
96
+ 'title' => $this->__['wp-fail2ban-workarounds'],
97
+ 'content' => sprintf(
98
+ $fmt,
99
+ __('<tt>syslog</tt> was only <a href="https://tools.ietf.org/html/rfc5424" target="_blank">standardised</a> in 2009, so unfortunately there are still implementations that need some help.', 'wp-fail2ban'),
100
+ __('By far the most common limitation is the length of the initial information fields; these options provide ways to shorten the data in those fields.', 'wp-fail2ban'),
101
+ __('Short Tag', 'wp-fail2ban'),
102
+ __('Some syslog implementations assume that the first part of the message (the tag) won&lsquo;t exceed some (small) number of characters. This option tells <em>WPf2b</em> to use <tt>wp</tt> instead of <tt>wordpress</tt>, thereby saving 7 characters; this may be enough to make syslog happy.', 'wp-fail2ban'),
103
+ $this->see_also(['WP_FAIL2BAN_SYSLOG_SHORT_TAG']),
104
+ __('Specify Host', 'wp-fail2ban'),
105
+ __('"Short Tag" may not be enough, so this allows you to specify the hostname. See the <a href="https://docs.wp-fail2ban.com/en/___WPF2BVER___/defines/constants/WP_FAIL2BAN_HTTP_HOST.html" target="_blank">documentation</a> for more details.', 'wp-fail2ban'),
106
+ $this->see_also(['WP_FAIL2BAN_HTTP_HOST']),
107
+ __('Truncate Host', 'wp-fail2ban'),
108
+ __('When all else fails, this allows you to truncate the hostname after a number of characters.', 'wp-fail2ban'),
109
+ __('<strong>N.B.</strong> This may be removed in a future release; it was broken prior to 4.3 and there were no bug reports, so it seems likely absolutely no-one is using it.', 'wp-fail2ban'),
110
+ $this->see_also(['WP_FAIL2BAN_TRUNCATE_HOST'])
111
+ )
112
+ ]);
113
+
114
+ parent::current_screen();
115
  }
116
+
117
  /**
118
  * Connection section blurb.
119
  *
121
  */
122
  public function sectionConnection()
123
  {
124
+ echo '';
125
  }
126
+
127
  /**
128
  * Connection.
129
  *
130
+ * @since 4.3.0 Refactor to premium.
131
  * @since 4.0.0
132
  */
133
  public function connection()
134
  {
 
135
  $fmt = <<<___STR___
136
  <fieldset>
137
  <label><input type="checkbox" disabled="disabled" %s> <code>LOG_CONS</code></label><br>
141
  <label><input type="radio" disabled="disabled" %s> <code>LOG_ODELAY</code></label>
142
  </fieldset>
143
  ___STR___;
144
+ // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing, PSR2.Methods.FunctionCallSignature.MultipleArguments
145
  printf(
146
  $fmt,
147
+ checked(WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_CONS, LOG_CONS, false),
148
+ checked(WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_PERROR, LOG_PERROR, false),
149
+ checked(WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_PID, LOG_PID, false), __('default'),
150
+ checked(WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_NDELAY, LOG_NDELAY, false), __('default'),
151
+ checked(WP_FAIL2BAN_OPENLOG_OPTIONS & LOG_ODELAY, LOG_ODELAY, false)
 
 
152
  );
153
+ // phpcs:enable
154
  }
155
+
156
  /**
157
  * Workarounds section blurb.
158
  *
160
  */
161
  public function sectionWorkarounds()
162
  {
163
+ echo '';
164
  }
165
+
166
  /**
167
  * Workarounds.
168
  *
169
+ * @since 4.3.0 Refactor to premium.
170
  * @since 4.0.0
171
  */
172
  public function workarounds()
182
  ___STR___;
183
  printf(
184
  $fmt,
185
+ checked(@WP_FAIL2BAN_SYSLOG_SHORT_TAG, true, false),
186
+ __('Short Tag', 'wp-fail2ban'),
187
+ checked(@WP_FAIL2BAN_HTTP_HOST, true, false),
188
+ __('Specify Host', 'wp-fail2ban'),
189
+ checked(@WP_FAIL2BAN_TRUNCATE_HOST, true, false),
190
+ __('Truncate Host', 'wp-fail2ban')
191
  );
192
  }
 
193
  }
194
+
admin/css/widgets.css ADDED
@@ -0,0 +1 @@
 
1
+ #wp_fail2ban_last_messages.postbox div.inside{margin:0;padding:0}#wp_fail2ban_last_messages.postbox div.inside table{width:100%}#wp_fail2ban_last_messages.postbox div.inside table tr th{padding-left:12px;text-align:left}#wp_fail2ban_last_messages.postbox div.inside table td{padding-left:12px;vertical-align:top}#wp_fail2ban_last_messages.postbox div.inside table td.dt{font-size:85%}#wp_fail2ban_last_messages.postbox div.inside table td.priority-critical{color:red;font-weight:700}#wp_fail2ban_last_messages.postbox div.inside table td.priority-error{color:red}#wp_fail2ban_last_messages.postbox div.inside table td.priority-warning{color:#ff0}#wp_fail2ban_last_messages.postbox div.inside table td.priority-notice{color:purple}#wp_fail2ban_last_messages.postbox div.inside table td.priority-info{color:green}#wp_fail2ban_last_messages.postbox div.inside table td.priority-debug{color:#00f}#wp_fail2ban_last_messages.postbox div.inside table td div.dismiss{float:right}
admin/img/docs.svg CHANGED
@@ -1,6 +1 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <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">
3
- <g id="surface1">
4
- <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 "/>
5
- </g>
6
- </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="16" height="16"><path d="M7 0C4.797 0 3 1.797 3 4v18c0 2.203 1.797 4 4 4h12c2.203 0 4-1.797 4-4V8c0-1.063-.973-2.07-2.719-3.781-.242-.239-.504-.504-.75-.75s-.511-.477-.75-.719C17.071 1.004 16.063 0 15 0zm0 2h7.281c.723.184.719 1.05.719 1.938V7c0 .55.45 1 1 1h3c.996 0 2 .004 2 1v13a2 2 0 01-2 2H7a2 2 0 01-2-2V4a2 2 0 012-2zm.813 8c-.551.05-.958.543-.907 1.094.051.55.543.957 1.094.906h10c.36.004.695-.184.879-.496a1.01 1.01 0 000-1.008c-.184-.312-.52-.5-.879-.496H7.813zm0 4c-.551.05-.958.543-.907 1.094.051.55.543.957 1.094.906h8c.36.004.695-.184.879-.496a1.01 1.01 0 000-1.008c-.184-.312-.52-.5-.879-.496H7.813zm0 4c-.551.05-.958.543-.907 1.094.051.55.543.957 1.094.906h10c.36.004.695-.184.879-.496a1.01 1.01 0 000-1.008c-.184-.312-.52-.5-.879-.496H7.813z"/></svg>
 
 
 
 
 
admin/lib/about.php CHANGED
@@ -1,14 +1,47 @@
1
  <?php
 
2
  /**
3
  * About
4
  *
5
  * @package wp-fail2ban
6
- * @since 4.2.0
7
  */
8
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
 
10
- if (!defined('ABSPATH')) {
11
- exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  }
13
 
14
  /**
@@ -18,143 +51,54 @@ if (!defined('ABSPATH')) {
18
  *
19
  * @param bool $hide_title
20
  */
21
- function about($hide_title = false)
22
  {
23
- $wp_f2b_ver = substr(WP_FAIL2BAN_VER, 0, strrpos(WP_FAIL2BAN_VER, '.'));
24
- $notice = version_compare(PHP_VERSION, '5.6.0', '<');
25
- ?>
 
26
  <div class="wrap">
27
  <style>
28
  div.inside ul {
29
  list-style: disc;
30
  padding-left: 2em;
31
  }
 
 
 
32
  </style>
33
- <?php if (!$hide_title): ?>
 
 
34
  <h1>WP fail2ban</h1>
35
- <?php endif; ?>
 
 
36
  <div id="poststuff">
37
  <div id="post-body" class="metabox-holder columns-2">
38
  <div id="post-body-content">
39
  <div class="meta-box-sortables ui-sortable">
 
 
 
40
  <div class="postbox">
41
- <h2>Version 4.2.8</h2>
42
- <div class="inside">
43
- <h4>News</h4>
44
- <ul>
45
- <?php if (strtotime('1 May 2020') > time()): ?>
46
- <li><a href="https://forums.invis.net/?utm_source=about&utm_medium=about&utm_campaign=4.2.8" target="_blank"><strong>Support has moved</strong></a>. Please come join the new <em>WPf2b</em> community!</li>
47
- <?php endif; ?>
48
- <li><a href="https://wp-fail2ban.com/blog/2020/04/16/testers-needed-v4-3-0-is-imminent/?utm_source=about&utm_medium=about&utm_campaign=4.2.8" target="_blank">Testers needed</a>! Version 4.3.0 will be released soon - I need your help to make sure it works properly.</li>
49
- <?php if ($notice): ?>
50
- <li><strong>This is the last release that supports PHP <?php echo PHP_VERSION; ?></strong>.<br>The <strong>minimum version</strong> required for <strong>v4.3.0</strong> is <strong>PHP 5.6</strong>.<br>Please <a href="https://wordpress.org/support/update-php/" target="_blank"><strong>update your PHP</strong></a>.</li>
51
- <?php endif; ?>
52
- </ul>
53
- <h4>Changes</h4>
54
- <ul>
55
- <li>Add link to new <a href="https://forums.invis.net/c/wp-fail2ban/?utm_source=about&utm_medium=about&utm_campaign=4.2.8" target="_blank">support forum</a>.</li>
56
- <li>Fix user enumeration conflict with Gutenberg (h/t @dinghy).</li>
57
- <li>Fix notices wrt admin menu (h/t @marioivangf).</li>
58
- <li>Fix harmless XDebug notice (h/t @dinghy).</li>
59
- <li>Update Freemius library.</li>
60
- </ul>
61
- </div>
62
- </div>
63
- </div>
64
- <div class="meta-box-sortables ui-sortable">
65
- <div class="postbox">
66
- <h2>Version 4.2.7.1</h2>
67
- <div class="inside">
68
- <ul>
69
- <li>Fix error when blocking user enumeration via <tt>oembed</tt>.</li>
70
- </ul>
71
- </div>
72
- </div>
73
- </div>
74
- <div class="meta-box-sortables ui-sortable">
75
- <div class="postbox">
76
- <h2>Version 4.2.7</h2>
77
- <div class="inside">
78
- <ul>
79
- <li>Fix error when blocking user enumeration via REST.</li>
80
- <li>Fix buttons on Settings tabs.</li>
81
- </ul>
82
- </div>
83
- </div>
84
- </div>
85
- <div class="meta-box-sortables ui-sortable">
86
- <div class="postbox">
87
- <h2>Version 4.2.6</h2>
88
- <div class="inside">
89
- <ul>
90
- <li>Add support for <a href="<?php echo admin_url('admin.php?page=wp-fail2ban-tools'); ?>">Remote Tools</a> add-on.
91
- <li>Add support for the new ClassicPress security page.</li>
92
- <li>Improved user enumeration blocking.</li>
93
- </ul>
94
- </div>
95
- </div>
96
- </div>
97
- <div class="meta-box-sortables ui-sortable">
98
- <div class="postbox">
99
- <h2>Version 4.2.5</h2>
100
- <div class="inside">
101
- <ul>
102
- <li>Properly fix PHP 5.3 support; tested on CentOS 6. Does not support any UI or Premium features.</li>
103
- <li>Fix potential issue with <tt>WP_FAIL2BAN_BLOCK_USER_ENUMERATION</tt> if calling REST API or XMLRPC from admin area.</li>
104
- </ul>
105
- </div>
106
- </div>
107
- </div>
108
- <div class="meta-box-sortables ui-sortable">
109
- <div class="postbox">
110
- <h2>Version 4.2.4</h2>
111
- <div class="inside">
112
- <ul>
113
- <li>Add filter for login failed message.</li>
114
- <li>Fix logging spam comments from admin area.</li>
115
- <li>Fix Settings link from Plugins page.</li>
116
- <li>Update Freemius library.</li>
117
- </ul>
118
- </div>
119
- </div>
120
- </div>
121
- <div class="meta-box-sortables ui-sortable">
122
- <div class="postbox">
123
- <h2>Version 4.2.3</h2>
124
  <div class="inside">
125
  <ul>
126
- <li>Workaround for some versions of PHP 7.x that would cause <tt>define()</tt>s to be ignored.</li>
127
- <li>Add config note to settings tabs.</li>
128
- <li>Fix documentation links.</li>
129
- </ul>
130
- </div>
131
- </div>
132
- </div>
133
- <div class="meta-box-sortables ui-sortable">
134
- <div class="postbox">
135
- <h2>Version 4.2.2</h2>
136
- <div class="inside">
137
- <ul>
138
- <li>Fix 5.3 compatibility.</li>
139
- </ul>
140
- </div>
141
- </div>
142
- </div>
143
- <div class="meta-box-sortables ui-sortable">
144
- <div class="postbox">
145
- <h2>Version 4.2.1</h2>
146
- <div class="inside">
147
- <ul>
148
- <li>Completed support for <tt><a href="https://docs.wp-fail2ban.com/en/4.2/defines/WP_FAIL2BAN_COMMENT_EXTRA_LOG.html?utm_source=about&utm_medium=about&utm_campaign=4.2.8" target="docs.wp-fail2ban.com">WP_FAIL2BAN_COMMENT_EXTRA_LOG</a></tt>.</li>
149
- <li>Add support for 3rd-party plugins; see <a href="https://docs.wp-fail2ban.com/en/4.2/developers.html?utm_source=about&utm_medium=about&utm_campaign=4.2.8" target="docs.wp-fail2ban.com">Developers</a>.<br>
150
- <p><ul>
151
- <li>Add-on for <a href="https://wordpress.org/plugins/wp-fail2ban-addon-contact-form-7/">Contact Form 7</a> (experimental).</li>
152
- <li>Add-on for <a href="https://wordpress.org/plugins/wp-fail2ban-addon-gravity-forms/">Gravity Forms</a> (experimental).</li>
153
- </ul></p>
154
- </li>
155
- <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>
156
- <li>Bugfix for email-as-username - now logged correctly and matched by <tt>soft</tt>, not <tt>hard</tt>, filters.</li>
157
- <li>Bugfix for regression in code to prevent Free/Premium conflict.</li>
158
  </ul>
159
  </div>
160
  </div>
@@ -163,21 +107,45 @@ function about($hide_title = false)
163
  <div id="postbox-container-1" class="postbox-container">
164
  <div class="meta-box-sortables">
165
  <div class="postbox">
166
- <h2>Getting Started</h2>
167
  <div class="inside">
168
  <ol>
169
- <li><a href="https://docs.wp-fail2ban.com/en/<?=$wp_f2b_ver?>/introduction.html?utm_source=about&utm_medium=about&utm_campaign=4.2.8" target="docs.wp-fail2ban.com">Introduction</a></li>
170
- <li><a href="https://docs.wp-fail2ban.com/en/<?=$wp_f2b_ver?>/configuration.html?utm_source=about&utm_medium=about&utm_campaign=4.2.8" target="docs.wp-fail2ban.com">Configuration</a></li>
 
 
 
 
 
 
 
 
171
  </ol>
172
  </div>
173
  </div>
174
  <div class="postbox">
175
- <h2>Getting Help</h2>
176
  <div class="inside">
177
  <ul>
178
- <li><a href="<?=wf_fs()->apply_filters('support_forum_url', '')?>?utm_source=about&utm_medium=about&utm_campaign=4.2.8" target="_blank">Support Forum</a></li>
179
- </ul>
180
- <p><strong>Note:</strong> The WordPress.org forum is no longer used for support. Please do not ask questions there as they are likely to go unanswered.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  </div>
182
  </div>
183
  </div>
@@ -186,6 +154,5 @@ function about($hide_title = false)
186
  &nbsp;
187
  </div>
188
  </div>
189
- <?php
190
  }
191
-
1
  <?php
2
+
3
  /**
4
  * About
5
  *
6
  * @package wp-fail2ban
7
+ * @since 4.2.0
8
  */
9
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
10
 
11
+ defined( 'ABSPATH' ) or exit;
12
+ /**
13
+ * Pull in extra "about" information
14
+ *
15
+ * @since 4.3.0
16
+ *
17
+ * @return string
18
+ */
19
+ function _get_extra_about()
20
+ {
21
+ $extra = '';
22
+ /**
23
+ * Don't make a remote call if the user hasn't opted in
24
+ */
25
+
26
+ if ( !wf_fs()->is_tracking_prohibited() ) {
27
+ $extra = get_site_transient( 'wp_fail2ban_extra_about' );
28
+
29
+ if ( false === apply_filters( 'wp_fail2ban_extra_about_transient', $extra ) ) {
30
+ $url = apply_filters( 'wp_fail2ban_extra_about_url', 'https://wp-fail2ban.com/extra-about/?version=' . WP_FAIL2BAN_VER );
31
+
32
+ if ( !is_wp_error( $rv = wp_remote_get( $url ) ) ) {
33
+ /**
34
+ * Try not to fetch more than once per day
35
+ */
36
+ set_site_transient( 'wp_fail2ban_extra_about', $rv['body'], DAY_IN_SECONDS );
37
+ $extra = $rv['body'];
38
+ }
39
+
40
+ }
41
+
42
+ }
43
+
44
+ return $extra;
45
  }
46
 
47
  /**
51
  *
52
  * @param bool $hide_title
53
  */
54
+ function about( $hide_title = false )
55
  {
56
+ $wp_f2b_ver = substr( WP_FAIL2BAN_VER, 0, strrpos( WP_FAIL2BAN_VER, '.' ) );
57
+ $extra = _get_extra_about();
58
+ $utm = '?utm_source=about&utm_medium=about&utm_campaign=' . WP_FAIL2BAN_VER;
59
+ ?>
60
  <div class="wrap">
61
  <style>
62
  div.inside ul {
63
  list-style: disc;
64
  padding-left: 2em;
65
  }
66
+ h2#4-3-0 {
67
+ font-size: 18px !important;
68
+ }
69
  </style>
70
+ <?php
71
+ if ( !$hide_title ) {
72
+ ?>
73
  <h1>WP fail2ban</h1>
74
+ <?php
75
+ }
76
+ ?>
77
  <div id="poststuff">
78
  <div id="post-body" class="metabox-holder columns-2">
79
  <div id="post-body-content">
80
  <div class="meta-box-sortables ui-sortable">
81
+ <?php
82
+ echo $extra ;
83
+ ?>
84
  <div class="postbox">
85
+ <h2 id="4-3-0" style="font-size: 18px">Version 4.3.0</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  <div class="inside">
87
  <ul>
88
+ <li>Add new dashboard widget: last 5 <tt>syslog</tt> messages.</li>
89
+ <li>Add full <a href="https://wp-fail2ban.com/features/multisite-networks/<?php
90
+ echo $utm ;
91
+ ?>" rel="noopener" target="_blank">multisite support</a>.</li>
92
+ <li>Add <a href="https://wp-fail2ban.com/features/block-username-logins/<?php
93
+ echo $utm ;
94
+ ?>" rel="noopener" target="_blank">username login blocking</a> (force login with email).</li>
95
+ <li>Add <a href="https://wp-fail2ban.com/features/empty-username-logging/<?php
96
+ echo $utm ;
97
+ ?>" rel="noopener" target="_blank">separate logging</a> for login attempts with an empty username.</li>
98
+ <li>Improve <a href="https://wp-fail2ban.com/features/block-user-enumeration/<?php
99
+ echo $utm ;
100
+ ?>" rel="noopener" target="_blank">user enumeration blocking</a> compatibility with the WordPress block editor (Gutenberg).</li>
101
+ <li>Bump the minimum PHP version to 5.6.</li>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  </ul>
103
  </div>
104
  </div>
107
  <div id="postbox-container-1" class="postbox-container">
108
  <div class="meta-box-sortables">
109
  <div class="postbox">
110
+ <h3>Getting Started</h3>
111
  <div class="inside">
112
  <ol>
113
+ <li><a href="https://docs.wp-fail2ban.com/en/<?php
114
+ echo $wp_f2b_ver ;
115
+ ?>/installation.html<?php
116
+ echo $utm ;
117
+ ?>" rel="noopener" target="docs.wp-fail2ban.com">Installation</a></li>
118
+ <li><a href="https://docs.wp-fail2ban.com/en/<?php
119
+ echo $wp_f2b_ver ;
120
+ ?>/configuration.html<?php
121
+ echo $utm ;
122
+ ?>" rel="noopener" target="docs.wp-fail2ban.com">Configuration</a></li>
123
  </ol>
124
  </div>
125
  </div>
126
  <div class="postbox">
127
+ <h3>Getting Help</h3>
128
  <div class="inside">
129
  <ul>
130
+ <?php
131
+
132
+ if ( wf_fs()->is_trial() ) {
133
+ ?>
134
+ <li><a href="https://forums.invis.net/c/wp-fail2ban-premium/support-trial/<?php
135
+ echo $utm ;
136
+ ?>" rel="noopener" target="_blank">Trial Support Forum</a></li>
137
+ <?php
138
+ } elseif ( wf_fs()->is_free_plan() ) {
139
+ ?>
140
+ <li><a href="https://forums.invis.net/c/wp-fail2ban/support/<?php
141
+ echo $utm ;
142
+ ?>" rel="noopener" target="_blank">Free Support Forum</a></li>
143
+ <?php
144
+ }
145
+
146
+ ?>
147
+ <?php
148
+ ?>
149
  </div>
150
  </div>
151
  </div>
154
  &nbsp;
155
  </div>
156
  </div>
157
+ <?php
158
  }
 
admin/lib/logging.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Config
4
+ *
5
+ * @package wp-fail2ban
6
+ * @since 4.0.0
7
+ */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ defined('ABSPATH') or exit;
11
+
12
+ /**
13
+ * Tab: Logging Base class
14
+ *
15
+ * @since 4.3.0
16
+ */
17
+ abstract class TabLoggingBase extends TabBase
18
+ {
19
+ /**
20
+ * Helper - build drop-down list of facilities
21
+ *
22
+ * @since 4.3.0
23
+ *
24
+ * @param string $def Name of define for selected value
25
+ * @param string $str Opening select html
26
+ *
27
+ * @return string
28
+ */
29
+ protected function getLogFacilitiesOptions($def, $str)
30
+ {
31
+ $default = Config::get_default($def);
32
+ $value = Config::get($def);
33
+
34
+ foreach (ConvertData::$FacilityName2Value as $name => $facility) {
35
+ $str .= sprintf(
36
+ '<option value="%s" %s>%s%s</option>',
37
+ $facility,
38
+ selected($value, $facility, false),
39
+ $name,
40
+ ($facility == $default) ? __(' (default)') : ''
41
+ );
42
+ }
43
+ $str .= '</select>';
44
+
45
+ return $str;
46
+ }
47
+
48
+ /**
49
+ * Helper - drop-down list of facilities
50
+ *
51
+ * @since 4.3.0 Refactored.
52
+ * @since 4.0.0
53
+ *
54
+ * @param string $def Name of define for selected value
55
+ * @param bool $_enabled Enabled?
56
+ *
57
+ * @return string
58
+ *
59
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
60
+ */
61
+ protected function getLogFacilities($def, $_enabled = false)
62
+ {
63
+ return $this->getLogFacilitiesOptions($def, '<select disabled="disabled">');
64
+ }
65
+
66
+ /**
67
+ * Log helper - enable/disable+facility
68
+ *
69
+ * @since 4.3.0 Refactored
70
+ * @since 4.2.0 Moved to Tab
71
+ * @since 4.0.0
72
+ *
73
+ * @param string $define_name Name of define to enable logging
74
+ * @param string $define_log Name of define for log facility
75
+ * @param array $toggle Array of IDs to sync toggle state
76
+ * @param bool $echo Echo?
77
+ *
78
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
79
+ */
80
+ protected function log($define_name, $define_log, array $toggle = [], $echo = true)
81
+ {
82
+ $enabled = (true === Config::get($define_name)); // @TODO
83
+ $fmt = <<<___FMT___
84
+ <input type="checkbox" disabled="disabled" %s> <label>%s</label>,
85
+ <label>%s:</label> %s
86
+ ___FMT___;
87
+ $html = sprintf(
88
+ $fmt,
89
+ checked($enabled, true, false),
90
+ __('Enable logging', 'wp-fail2ban'),
91
+ __('use facility', 'wp-fail2ban'),
92
+ $this->getLogFacilities($define_log)
93
+ );
94
+ $html .= sprintf('<p class="description">%s</p>', Config::desc($define_name));
95
+ $rv = apply_filters("wp_fail2ban_log_{$define_name}", $html, $define_name, $define_log);
96
+ if ($echo) {
97
+ echo $rv;
98
+ } else {
99
+ return $rv;
100
+ }
101
+ }
102
+ }
103
+
admin/lib/tab.php CHANGED
@@ -1,58 +1,90 @@
1
  <?php
2
-
3
  /**
4
  * Tab base class
5
  *
6
- * @package wp-fail2ban-premium
7
- * @since 4.0.0
8
  */
9
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
- * Base Tab class
16
  *
17
  * @since 4.0.0
18
  */
19
- abstract class Tab
20
  {
21
  /**
22
  * @var array Array of Tab objects
23
  */
24
- protected static $tabs = array() ;
 
 
 
 
25
  /**
26
  * @var string Active tab slug
27
  */
28
- protected static $active_tab ;
 
29
  /**
30
  * @var string Tab slug
31
  */
32
- protected $tab_slug ;
33
  /**
34
  * @var string Tab name
35
  */
36
- protected $tab_name ;
 
 
 
 
 
 
 
 
 
 
 
 
37
  /**
38
  * Hook: admin_init
39
  *
40
  * @since 4.0.0
41
  */
42
- public abstract function admin_init();
43
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  /**
45
  * Sanitize and store form fields
46
  *
 
47
  * @since 4.0.0
48
  *
49
- * @param array $settings Settings to update
50
- * @param array $input Form fields
51
  *
52
- * @return array $settings
53
  */
54
- public abstract function sanitize( array $settings, array $input = null );
55
-
 
 
 
56
  /**
57
  * Contruct.
58
  *
@@ -60,14 +92,38 @@ abstract class Tab
60
  *
61
  * @param string $slug Tab slug
62
  * @param string $name Tab name
 
63
  */
64
- public function __construct( $slug, $name )
65
  {
66
- $this->tab_slug = $slug;
67
- $this->tab_name = $name;
 
 
68
  self::$tabs[$slug] = $this;
 
 
 
 
69
  }
70
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  /**
72
  * Getter - slug
73
  *
@@ -79,7 +135,7 @@ abstract class Tab
79
  {
80
  return $this->tab_slug;
81
  }
82
-
83
  /**
84
  * Getter - name
85
  *
@@ -91,170 +147,307 @@ abstract class Tab
91
  {
92
  return $this->tab_name;
93
  }
94
-
95
  /**
96
  * Render settings section
97
  *
 
98
  * @since 4.0.0
99
  */
100
  public function render()
101
  {
102
- do_settings_sections( 'wp-fail2ban-' . $this->tab_slug );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  }
104
-
 
 
 
 
 
 
 
 
 
 
 
 
105
  /**
106
  * Helper - tab
107
  *
108
  * @since 4.0.0
109
  *
110
- * @param string $slug Tab slug
111
- *
112
- * @return Tab Tab
113
  */
114
- public static function getTab( $slug )
115
  {
116
  return self::$tabs[$slug];
117
  }
118
-
 
 
 
 
 
 
 
 
 
 
 
 
119
  /**
120
  * Helper - current tab
121
  *
122
  * @since 4.0.0
123
  *
124
- * @param string $default Default slug
125
- *
126
- * @return Tab Tab
127
  */
128
- public static function getActiveTab( $default = null )
129
  {
130
- if ( !empty(self::$active_tab) ) {
131
  return self::$active_tab;
132
  }
133
- return self::$active_tab = ( array_key_exists( @$_GET['tab'], self::$tabs ) ? self::$tabs[$_GET['tab']] : self::$tabs[$default] );
 
 
 
 
134
  }
135
-
136
  /**
137
  * Helper - tab name
138
  *
139
  * @since 4.0.0
140
  *
141
- * @param string $slug Tab slug
 
 
 
 
 
 
 
 
 
142
  *
143
- * @return string Tab name
 
 
 
144
  */
145
- public static function getTabName( $slug )
146
  {
147
- return self::getTab( $slug )->getName();
148
  }
149
-
150
  /**
151
  * Link to documentation
152
  *
 
153
  * @since 4.2.0
154
  *
155
- * @param string $define
156
- * @param string $name
157
- *
158
  * @return string
159
  */
160
- public static function doc_link( $define, $name )
161
  {
162
- static $wp_f2b_ver ;
163
- if ( empty($wp_f2b_ver) ) {
164
- $wp_f2b_ver = substr( WP_FAIL2BAN_VER, 0, strrpos( WP_FAIL2BAN_VER, '.' ) );
 
165
  }
166
- return sprintf(
167
- '<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',
168
- $wp_f2b_ver,
169
- $define,
170
- $name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  );
 
 
 
 
172
  }
173
-
174
  /**
175
- * Helper - drop-down list of facilities
176
  *
 
177
  * @since 4.0.0
178
  *
179
- * @param string $def Name of define for selected value
180
- * @param bool $_enabled Enabled?
 
181
  */
182
- protected function getLogFacilities( $def, $_enabled = false )
183
  {
184
- $enabled = false;
185
- $facilities = [
186
- LOG_AUTH => 'LOG_AUTH',
187
- LOG_AUTHPRIV => 'LOG_AUTHPRIV',
188
- LOG_CRON => 'LOG_CRON',
189
- LOG_DAEMON => 'LOG_DAEMON',
190
- LOG_KERN => 'LOG_KERN',
191
- LOG_LOCAL0 => 'LOG_LOCAL0',
192
- LOG_LOCAL1 => 'LOG_LOCAL1',
193
- LOG_LOCAL2 => 'LOG_LOCAL2',
194
- LOG_LOCAL3 => 'LOG_LOCAL3',
195
- LOG_LOCAL4 => 'LOG_LOCAL4',
196
- LOG_LOCAL5 => 'LOG_LOCAL5',
197
- LOG_LOCAL6 => 'LOG_LOCAL6',
198
- LOG_LOCAL7 => 'LOG_LOCAL7',
199
- LOG_LPR => 'LOG_LPR',
200
- LOG_MAIL => 'LOG_MAIL',
201
- LOG_NEWS => 'LOG_NEWS',
202
- LOG_SYSLOG => 'LOG_SYSLOG',
203
- LOG_USER => 'LOG_USER',
204
- LOG_UUCP => 'LOG_UUCP',
205
- ];
206
- $default = constant( "DEFAULT_{$def}" );
207
- $value = ( defined( $def ) ? constant( $def ) : $default );
208
- $str = '<select disabled="disabled">';
209
- foreach ( $facilities as $facility => $name ) {
210
- $str .= sprintf(
211
- '<option value="%s" %s>%s%s</option>',
212
- $facility,
213
- selected( $value, $facility, false ),
214
- $name,
215
- ( $facility == $default ? __( ' (default)' ) : '' )
216
- );
217
- }
218
- $str .= '</select>';
219
- return $str;
220
  }
221
-
222
  /**
223
- * Log helper - enable/disable+facility
224
  *
225
- * @since 4.2.0 Moved to Tab
226
  * @since 4.0.0
227
  *
228
- * @param string $define_name Name of define to enable logging
229
- * @param string $define_log Name of define for log facility
230
- * @param string $description Description
231
- * @param array $toggle Array of IDs to sync toggle state
232
  */
233
- protected function log(
234
- $define_name,
235
- $define_log,
236
- $description = '',
237
- array $toggle = array()
238
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  {
240
- $enabled = defined( $define_name ) && true === constant( $define_name );
241
- $fmt = <<<___FMT___
242
- <label><input type="checkbox" disabled="disabled" %s> Enable logging</label>,
243
- <label>use facility: %s</label>
244
- <p class="description">%s</p>
245
- ___FMT___;
246
  $html = sprintf(
247
- $fmt,
248
- checked( $enabled, true, false ),
249
- $this->getLogFacilities( $define_log ),
250
- $description
251
  );
252
- echo apply_filters(
253
- "wp_fail2ban_log_{$define_name}",
254
- $html,
255
- $define_name,
256
- $define_log
257
- ) ;
 
258
  }
259
 
260
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
  /**
3
  * Tab base class
4
  *
5
+ * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
 
10
+ defined('ABSPATH') or exit;
11
+
 
12
  /**
13
+ * Tab: Base class
14
  *
15
  * @since 4.0.0
16
  */
17
+ abstract class TabBase
18
  {
19
  /**
20
  * @var array Array of Tab objects
21
  */
22
+ protected static $tabs = [];
23
+ /**
24
+ * @var string Default tab slug
25
+ */
26
+ protected static $default_tab;
27
  /**
28
  * @var string Active tab slug
29
  */
30
+ protected static $active_tab;
31
+
32
  /**
33
  * @var string Tab slug
34
  */
35
+ protected $tab_slug;
36
  /**
37
  * @var string Tab name
38
  */
39
+ protected $tab_name;
40
+ /**
41
+ * @since 4.3.0
42
+ * @var bool Apply/Reset buttons?
43
+ */
44
+ protected $tab_apply;
45
+
46
+ /**
47
+ * @var int admin_init priority
48
+ * @since 4.3.0
49
+ */
50
+ protected $admin_init_priority = 10;
51
+
52
  /**
53
  * Hook: admin_init
54
  *
55
  * @since 4.0.0
56
  */
57
+ abstract public function admin_init();
58
+
59
+ /**
60
+ * Hook: current_screen
61
+ *
62
+ * @since 4.3.0
63
+ */
64
+ public function current_screen()
65
+ {
66
+ get_current_screen()->set_help_sidebar(
67
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
68
+ '<p>' . __('<a href="https://docs.wp-fail2ban.com">Documentation</a>', 'wp-fail2ban') . '</p>' .
69
+ '<p><a href="https://forums.invis.net/c/wp-fail2ban/support/">'.__('Support').'</a></p>'
70
+ );
71
+ }
72
+
73
  /**
74
  * Sanitize and store form fields
75
  *
76
+ * @since 4.3.0 Refactor
77
  * @since 4.0.0
78
  *
79
+ * @param array $input Form fields
 
80
  *
81
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
82
  */
83
+ public function sanitize(array $input = null)
84
+ {
85
+ return [];
86
+ }
87
+
88
  /**
89
  * Contruct.
90
  *
92
  *
93
  * @param string $slug Tab slug
94
  * @param string $name Tab name
95
+ * @param bool $apply Show Apply/Reset buttons
96
  */
97
+ public function __construct($slug, $name, $apply = true)
98
  {
99
+ $this->tab_slug = $slug;
100
+ $this->tab_name = $name;
101
+ $this->tab_apply = $apply;
102
+
103
  self::$tabs[$slug] = $this;
104
+
105
+ $this->admin_init();
106
+
107
+ add_filter('gettext', [$this, 'gettext'], PHP_INT_MAX, 3);
108
  }
109
+
110
+ /**
111
+ * Hook: gettext
112
+ *
113
+ * @since 4.3.0
114
+ *
115
+ * @param string $translation
116
+ * @param string $text
117
+ * @param string $domain
118
+ * @return string
119
+ *
120
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
121
+ */
122
+ public function gettext($translation, $text, $domain)
123
+ {
124
+ return str_replace('___WPF2BVER___', WP_FAIL2BAN_VER_SHORT, $translation);
125
+ }
126
+
127
  /**
128
  * Getter - slug
129
  *
135
  {
136
  return $this->tab_slug;
137
  }
138
+
139
  /**
140
  * Getter - name
141
  *
147
  {
148
  return $this->tab_name;
149
  }
150
+
151
  /**
152
  * Render settings section
153
  *
154
+ * @since 4.3.0 Refactored.
155
  * @since 4.0.0
156
  */
157
  public function render()
158
  {
159
+ do_settings_sections('wp-fail2ban-'.$this->tab_slug);
160
+ $this->render_buttons();
161
+ }
162
+
163
+ /**
164
+ * Render settings section buttons
165
+ *
166
+ * @since 4.3.0
167
+ */
168
+ protected function render_buttons()
169
+ {
170
+ printf(
171
+ '<hr><p><strong>%s:</strong> %s<br>%s</p>',
172
+ __('Note', 'wp-fail2ban'),
173
+ __('The Free version of <em>WP fail2ban</em> is configured by defining constants in <code>wp-config.php</code>;
174
+ these tabs reflect those values.', 'wp-fail2ban'),
175
+ __('Upgrade to the Premium version to enable this interface.', 'wp-fail2ban')
176
+ );
177
  }
178
+
179
+ /**
180
+ * Helper: is this the active tab?
181
+ *
182
+ * @since 4.3.0
183
+ *
184
+ * @return bool
185
+ */
186
+ protected function isActiveTab()
187
+ {
188
+ return ($this->tab_name == self::getActiveTab()->getName());
189
+ }
190
+
191
  /**
192
  * Helper - tab
193
  *
194
  * @since 4.0.0
195
  *
196
+ * @param string $slug Tab slug
197
+ * @return Tab Tab
 
198
  */
199
+ public static function getTab($slug)
200
  {
201
  return self::$tabs[$slug];
202
  }
203
+
204
+ /**
205
+ * Helper - set the default tab.
206
+ *
207
+ * @since 4.3.0
208
+ *
209
+ * @param string $default Default tab slug
210
+ */
211
+ public static function setDefaultTab($default)
212
+ {
213
+ self::$default_tab = $default;
214
+ }
215
+
216
  /**
217
  * Helper - current tab
218
  *
219
  * @since 4.0.0
220
  *
221
+ * @return TabBase Tab
 
 
222
  */
223
+ public static function getActiveTab()
224
  {
225
+ if (!empty(self::$active_tab)) {
226
  return self::$active_tab;
227
  }
228
+
229
+ return (self::$active_tab = (array_key_exists(@$_GET['tab'], self::$tabs))
230
+ ? self::$tabs[$_GET['tab']]
231
+ : self::$tabs[self::$default_tab]
232
+ );
233
  }
234
+
235
  /**
236
  * Helper - tab name
237
  *
238
  * @since 4.0.0
239
  *
240
+ * @param string $slug Tab slug
241
+ * @return string Tab name
242
+ */
243
+ public static function getTabName($slug)
244
+ {
245
+ return self::getTab($slug)->getName();
246
+ }
247
+
248
+ /**
249
+ * Helper - tab exists?
250
  *
251
+ * @since 4.3.0
252
+ *
253
+ * @param string $slug Tab slug
254
+ * @return bool
255
  */
256
+ public static function tabExists($slug)
257
  {
258
+ return array_key_exists($slug, self::$tabs);
259
  }
260
+
261
  /**
262
  * Link to documentation
263
  *
264
+ * @since 4.3.0 Protected
265
  * @since 4.2.0
266
  *
267
+ * @param string $define
 
 
268
  * @return string
269
  */
270
+ protected function doc_link($define)
271
  {
272
+ static $wp_f2b_ver;
273
+
274
+ if (empty($wp_f2b_ver)) {
275
+ $wp_f2b_ver = substr(WP_FAIL2BAN_VER, 0, strrpos(WP_FAIL2BAN_VER, '.'));
276
  }
277
+
278
+ return sprintf('<a href="https://docs.wp-fail2ban.com/en/%s/defines/constants/%s.html" style="text-decoration: none;" target="_blank" title="%s">%s<span class="dashicons dashicons-external" style="vertical-align: text-bottom"></span></a>', $wp_f2b_ver, $define, __('Documentation', 'wp-fail2ban'), $define);
279
+ }
280
+
281
+ /**
282
+ * Standard list of links to docs
283
+ *
284
+ * @since 4.3.0
285
+ *
286
+ * @param array $defines List of defines
287
+ * @param bool $para Wrap in <p>
288
+ * @return string HTML
289
+ */
290
+ protected function see_also(array $defines, $para = true)
291
+ {
292
+ $html = sprintf(
293
+ '<em>%s</em>&nbsp;&nbsp;%s',
294
+ __('See also:', 'wp-fail2ban'),
295
+ implode('&nbsp;/&nbsp;', array_map(function ($i) {
296
+ return $this->doc_link($i);
297
+ }, $defines))
298
  );
299
+ if ($para) {
300
+ $html = '<p>'.$html.'</p>';
301
+ }
302
+ return $html;
303
  }
304
+
305
  /**
306
+ * id="%s" Helper
307
  *
308
+ * @since 4.3.0 Moved here.
309
  * @since 4.0.0
310
  *
311
+ * @param string $define
312
+ *
313
+ * @return string
314
  */
315
+ protected function field_name($define)
316
  {
317
+ global $wp_fail2ban;
318
+
319
+ return 'wp-fail2ban['.join('][', $wp_fail2ban['config'][$define]['field']).']';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  }
321
+
322
  /**
323
+ * name="%s" Helper
324
  *
325
+ * @since 4.3.0 Moved here.
326
  * @since 4.0.0
327
  *
328
+ * @param string $define
329
+ *
330
+ * @return string
 
331
  */
332
+ protected function field_id($define)
333
+ {
334
+ global $wp_fail2ban;
335
+
336
+ return join('-', $wp_fail2ban['config'][$define]['field']);
337
+ }
338
+
339
+ /**
340
+ * Helper: checked()
341
+ *
342
+ * @since 4.3.0
343
+ *
344
+ * @param string $define
345
+ * @param bool $current
346
+ * @param bool $echo
347
+ * @return mixed
348
+ */
349
+ protected function def_checked($define, $current = true, $echo = true)
350
+ {
351
+ return checked(Config::get($define), $current, $echo);
352
+ }
353
+
354
+ /**
355
+ * NDEF disabled helper
356
+ *
357
+ * @since 4.3.0 Add $override; moved here.
358
+ * @since 4.0.0
359
+ *
360
+ * @param string $define
361
+ * @param bool $override
362
+ * @return string
363
+ */
364
+ protected function ndef_disabled($define, $override = false)
365
+ {
366
+ return disabled(Config::def($define) || $override, true, false);
367
+ }
368
+
369
+ /**
370
+ * Display standard checkbox
371
+ *
372
+ * @since 4.3.0
373
+ *
374
+ * @param string $define Constant
375
+ * @param bool $show_desc Show description?
376
+ * @param string $plan Freemius plan
377
+ * @param bool $echo Echo?
378
+ *
379
+ * @return string HTML
380
+ *
381
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
382
+ */
383
+ protected function checkbox($define, $show_desc = true, $plan = 'bronze', $echo = true)
384
  {
 
 
 
 
 
 
385
  $html = sprintf(
386
+ '<input type="checkbox" disabled="disabled" %s>',
387
+ checked(constant($define), true, false)
 
 
388
  );
389
+ if ($show_desc) {
390
+ $html = '<label>'.$html.' '.$this->description($define, false).'</label>';
391
+ }
392
+ if ($echo) {
393
+ echo $html;
394
+ }
395
+ return $html;
396
  }
397
 
398
+ /**
399
+ * Display standard text input
400
+ *
401
+ * @since 4.3.0
402
+ *
403
+ * @param string $define Constant
404
+ * @param string $value Text value
405
+ * @param bool $show_desc Show description?
406
+ * @param string $plan Freemius plan
407
+ * @param bool $echo Echo?
408
+ * @param string $cssClass CSS class
409
+ *
410
+ * @return string HTML
411
+ *
412
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
413
+ */
414
+ protected function inputText($define, $value = '', $show_desc = true, $plan = 'bronze', $echo = true, $cssClass = 'regular-text')
415
+ {
416
+ $html = sprintf(
417
+ '<input class="%s" type="text" value="%s" %s>',
418
+ $cssClass,
419
+ esc_attr($value),
420
+ $this->ndef_disabled($define)
421
+ );
422
+ if ($show_desc) {
423
+ $html = '<label>'.$html.' '.$this->description($define, false).'</label>';
424
+ }
425
+ if ($echo) {
426
+ echo $html;
427
+ }
428
+ return $html;
429
+ }
430
+
431
+ /**
432
+ * Helper: setting description
433
+ *
434
+ * @since 4.3.0
435
+ *
436
+ * @param string $define
437
+ * @param bool $echo
438
+ *
439
+ * @return string
440
+ */
441
+ protected function description($define, $echo = true)
442
+ {
443
+ if (!is_null($desc = Config::desc($define))) {
444
+ if ($echo) {
445
+ echo '<p class="description">'.$desc.'</p>';
446
+ }
447
+ return $desc;
448
+ } else {
449
+ return '';
450
+ }
451
+ }
452
+ }
453
+
admin/tools.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Tools
4
+ *
5
+ * @package wp-fail2ban
6
+ * @since 4.3.0
7
+ */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ defined('ABSPATH') or exit;
11
+
12
+ /**
13
+ * Proxy for api.wp-fail2ban.com
14
+ *
15
+ * @since 4.2.6
16
+ */
17
+ function remote_tools()
18
+ {
19
+ ?>
20
+ <div class="wrap">
21
+ <h1><?=__('Remote Tools (&beta;)', 'wp-fail2ban')?></h1>
22
+ <hr class="wp-header-end">
23
+ <?php
24
+ if (function_exists(__NAMESPACE__.'\addons\remote_tools\tab')) {
25
+ addons\remote_tools\tab();
26
+ } elseif (defined('WP_FAIL2BAN_ADDON_REMOTE_TOOLS_NS') && function_exists(WP_FAIL2BAN_ADDON_REMOTE_TOOLS_NS.'\tab')) {
27
+ $func = WP_FAIL2BAN_ADDON_REMOTE_TOOLS_NS.'\tab';
28
+ $func();
29
+ } else {
30
+ ?>
31
+ <h2 class="nav-tab-wrapper wp-clearfix">
32
+ <a class="nav-tab nav-tab-active" href="#"><?=__('Overview', 'wp-fail2ban')?></a>
33
+ </h2>
34
+ <div class="card">
35
+ <h2>Remote Tools Add-on</h2>
36
+ <p>This add-on provides features that make life with WP fail2ban easier, all from a remote server. This gives access to valuable but infrequently used tools without bloating the core plugin.</p>
37
+ <p>The first of these is a <strong>Custom Filter Tool</strong> (CFT).</p>
38
+ <blockquote>
39
+ <p>The filter files included are intended only as a starting point for those who want <em>WPf2b</em> to work &ldquo;out of the box&rdquo;.</p>
40
+ <p>There is no &ldquo;one size fits all&rdquo; configuration possible for <em>fail2ban</em> - what may be a soft failure for one site should be treated as a hard failure for another, and vice versa.</p>
41
+ </blockquote>
42
+ <p>You could simply edit the filter files included, but it&lsquo;s surprisingly easy to make a mistake; I learned this the hard way with earlier versions of <em>WPf2b</em>.... The CFT removes most of the opportunities for human error - always a good thing!</p>
43
+ <hr>
44
+ <p>The Remote Tools Add-on is available from the <a href="<?php echo admin_url('admin.php?page=wp-fail2ban-addons') ?>">Add-Ons menu</a>.</p>
45
+ </div>
46
+ <?php
47
+ }
48
+
49
+ ?>
50
+ </div>
51
+ <?php
52
+ }
53
+
admin/widgets.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Dashboard Widgets
4
+ *
5
+ * @package wp-fail2ban
6
+ * @since 4.3.0
7
+ */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ (defined('ABSPATH') && (!defined('WP_FAIL2BAN_LOG_DISABLE_LAST') || true !== WP_FAIL2BAN_LOG_DISABLE_LAST)) or exit;
11
+
12
+ /**
13
+ * Last 5 Messages Widget
14
+ *
15
+ * @since 4.3.0
16
+ */
17
+ function dashboard_widget_last_messages()
18
+ {
19
+ if (!is_array($messages = get_site_option('wp-fail2ban-messages', []))) {
20
+ $messages = [];
21
+ }
22
+
23
+ printf(
24
+ '<table><thead><tr><th class="dt">%s</th><th>%s</th><th>%s</th></tr></thead><tbody>',
25
+ __('Date/Time', 'wp-fail2ban'),
26
+ __('Priority', 'wp-fail2ban'),
27
+ __('Message', 'wp-fail2ban')
28
+ );
29
+ if (count($messages)) {
30
+ $alt = true;
31
+ foreach ($messages as $message) {
32
+ printf(
33
+ '<tr class="%s"><td class="dt"><nobr><tt>%s&nbsp;Z</tt></nobr></td><td class="priority-%s">%s</td><td>%s</td></tr>',
34
+ $alt ? 'alternate' : '',
35
+ str_replace(' ', '&nbsp;<wbr>', $message['dt']),
36
+ strtolower($message['lvl']),
37
+ $message['lvl'],
38
+ htmlentities($message['msg'], ENT_SUBSTITUTE|ENT_HTML5, 'UTF-8')
39
+ );
40
+ $alt = !$alt;
41
+ }
42
+
43
+ } else {
44
+ printf('<tr><td colspan="3"><em>%s</em></td></tr>', __('No messages found.', 'wp-fail2ban'));
45
+ }
46
+ echo '</tbody>';
47
+
48
+ if (null === ($tfoot = apply_filters(__METHOD__.'::tfoot', null))) {
49
+ $dismiss = 'wp-fail2ban-'.WP_FAIL2BAN_VER_SHORT.'-last-5-messages-upgrade';
50
+ if (array_key_exists($dismiss, $_GET)) {
51
+ update_site_option($dismiss, intval($_GET[$dismiss]));
52
+ }
53
+ if (get_site_option($dismiss, 1) ||
54
+ array_key_exists($dismiss.'-debug', $_GET))
55
+ {
56
+ $tfoot .= sprintf(
57
+ '<tr><td colspan="3"><a href="%s">%s</a><div class="dismiss"><a href="%s">%s</a></div></td></tr>',
58
+ network_admin_url('admin.php?page=wp-fail2ban-menu-pricing'),
59
+ __('Upgrade to WP fail2ban Premium for a full event log', 'wp-fail2ban'),
60
+ network_admin_url("?{$dismiss}=0"),
61
+ __('Dismiss')
62
+ );
63
+ }
64
+ }
65
+ echo "<tfoot>{$tfoot}</tfoot>";
66
+
67
+ echo '</table>';
68
+ }
69
+
70
+ /**
71
+ * wp_dashboard_setup action hook
72
+ *
73
+ * @since 4.3.0
74
+ *
75
+ * @see https://codex.wordpress.org/Function_Reference/wp_add_dashboard_widget
76
+ */
77
+ function wp_dashboard_setup()
78
+ {
79
+ if ((!is_multisite() && current_user_can('manage_options')) ||
80
+ (is_network_admin() && current_user_can('manage_network_options')))
81
+ {
82
+ wp_add_dashboard_widget(
83
+ 'wp_fail2ban_last_messages',
84
+ __('Last 5 Messages [WPf2b]', 'wp-fail2ban'),
85
+ __NAMESPACE__.'\dashboard_widget_last_messages'
86
+ );
87
+ wp_enqueue_style('wp-fail2ban-last-messages', plugins_url('css/widgets.css', __FILE__));
88
+ }
89
+ }
90
+ add_action('wp_dashboard_setup', __NAMESPACE__.'\wp_dashboard_setup');
91
+ add_action('wp_network_dashboard_setup', __NAMESPACE__.'\wp_dashboard_setup');
92
+
assets/icon.svg ADDED
@@ -0,0 +1 @@
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-4 -4 40 40" stroke-width="0" fill="#180c30" style="background-color:#fff"><path d="M16 0l6.5 6.5L19 10l-3-3-9 9 3 3-3.5 3.5L0 16zM0 31L31 0l1 1L1 32zm16 1l16-16-6.5-6.5L22 13l3 3-9 9-3-3-3.5 3.5z"/></svg>
assets/menu.svg ADDED
@@ -0,0 +1 @@
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-1 -1 34 34" fill="#fff" stroke="#fff" width="20" height="20"><path d="M16 0l7 7-4 4-3-3-8 8 3 3-4 4-7-7zm0 32l16-16-7-7-4 4 3 3-8 8-3-3-4 4zM2 31l-1-1L30 1l1 1z"/></svg>
constants.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP fail2ban
4
+ *
5
+ * Outside the guard for building
6
+ *
7
+ * @since 4.0.5
8
+ *
9
+ * @package wp-fail2ban
10
+ */
11
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
12
+
13
+ // @codeCoverageIgnoreStart
14
+
15
+ if (!defined('WP_FAIL2BAN_VER')) {
16
+ define('WP_FAIL2BAN_VER', '4.3.0.4');
17
+ }
18
+ if (!defined('WP_FAIL2BAN_VER_SHORT')) {
19
+ define('WP_FAIL2BAN_VER_SHORT', '4.3');
20
+ }
21
+ if (!defined('WP_FAIL2BAN_DIR')) {
22
+ define('WP_FAIL2BAN_DIR', __DIR__);
23
+ }
24
+ if (!defined('WP_FAIL2BAN_FILE')) {
25
+ define('WP_FAIL2BAN_FILE', __FILE__);
26
+ }
27
+ if (!defined('WP_FAIL2BAN_NS')) {
28
+ define('WP_FAIL2BAN_NS', __NAMESPACE__);
29
+ }
30
+
core.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP fail2ban core
4
+ *
5
+ * @package wp-fail2ban
6
+ * @since 4.3.0
7
+ */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban\core;
9
+
10
+ use function org\lecklider\charles\wordpress\wp_fail2ban\openlog;
11
+ use function org\lecklider\charles\wordpress\wp_fail2ban\syslog;
12
+ use function org\lecklider\charles\wordpress\wp_fail2ban\closelog;
13
+
14
+ defined('ABSPATH') or exit;
15
+
16
+ /**
17
+ * Catch empty usernames
18
+ *
19
+ * @see \wp_authenticate()
20
+ *
21
+ * @since 4.3.0
22
+ *
23
+ * @param mixed|null $user
24
+ * @param string $username
25
+ * @param string $password
26
+ *
27
+ * @return mixed|null
28
+ *
29
+ * @wp-f2b-soft Empty username
30
+ */
31
+ function authenticate($user, $username, $password)
32
+ {
33
+ if (empty($username) && isset($_POST['log'])) {
34
+ if (openlog()) {
35
+ syslog(LOG_NOTICE, 'Empty username');
36
+ closelog();
37
+ }
38
+
39
+ do_action(__FUNCTION__, $user, $username, $password);
40
+ }
41
+
42
+ return $user;
43
+ }
44
+
45
+ /**
46
+ * Hook: wp_login
47
+ *
48
+ * @since 4.3.0 Add action
49
+ * @since 4.1.0 Add REST support
50
+ * @since 3.5.0 Refactored for unit testing
51
+ * @since 1.0.0
52
+ *
53
+ * @param string $user_login
54
+ * @param mixed $user
55
+ *
56
+ * @codeCoverageIgnore
57
+ */
58
+ function wp_login($user_login, $user)
59
+ {
60
+ if (openlog()) {
61
+ syslog(LOG_INFO, "Accepted password for {$user_login}");
62
+ closelog();
63
+ }
64
+
65
+ do_action(__FUNCTION__, $user_login, $user);
66
+ }
67
+
68
+ /**
69
+ * Hook: wp_login_failed
70
+ *
71
+ * @since 4.3.0 Add action
72
+ * @since 4.2.4 Add message filter
73
+ * @since 4.2.0 Change username check
74
+ * @since 4.1.0 Add REST support
75
+ * @since 3.5.0 Refactored for unit testing
76
+ * @since 1.0.0
77
+ *
78
+ * @param string $username
79
+ *
80
+ * @wp-f2b-hard Authentication attempt for unknown user .*
81
+ * @wp-f2b-hard REST authentication attempt for unknown user .*
82
+ * @wp-f2b-hard XML-RPC authentication attempt for unknown user .*
83
+ * @wp-f2b-soft Authentication failure for .*
84
+ * @wp-f2b-soft REST authentication failure for .*
85
+ * @wp-f2b-soft XML-RPC authentication failure for .*
86
+ */
87
+ function wp_login_failed($username)
88
+ {
89
+ global $wp_xmlrpc_server;
90
+
91
+ if (defined('REST_REQUEST')) {
92
+ $msg = 'REST a';
93
+ $filter = '::REST';
94
+ } elseif ($wp_xmlrpc_server) {
95
+ $msg = 'XML-RPC a';
96
+ $filter = '::XML-RPC';
97
+ } else {
98
+ $msg = 'A';
99
+ $filter = '';
100
+ }
101
+
102
+ $username = trim($username);
103
+ $msg .= (wp_cache_get($username, 'useremail') || wp_cache_get(sanitize_user($username), 'userlogins'))
104
+ ? "uthentication failure for {$username}"
105
+ : "uthentication attempt for unknown user {$username}";
106
+ $msg = apply_filters("wp_fail2ban::wp_login_failed{$filter}", $msg);
107
+
108
+ if (openlog()) {
109
+ syslog(LOG_NOTICE, $msg);
110
+ closelog();
111
+ }
112
+
113
+ do_action(__FUNCTION__, $username);
114
+ }
115
+
feature/comments.php CHANGED
@@ -1,193 +1,137 @@
1
  <?php
2
-
3
  /**
4
  * Comment logging
5
  *
6
  * @package wp-fail2ban
7
  * @since 4.0.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
 
 
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
- * @since 4.0.5 Guard
 
 
 
 
 
 
 
 
 
16
  */
17
-
18
- if ( !function_exists( __NAMESPACE__ . '\\notify_post_author' ) ) {
19
- /**
20
- * Log new comment
21
- *
22
- * @since 3.5.0
23
- *
24
- * @param bool $maybe_notify
25
- * @param int $comment_ID
26
- *
27
- * @return bool
28
- *
29
- * @wp-f2b-extra Comment \d+
30
- */
31
- function notify_post_author( $maybe_notify, $comment_ID )
32
- {
33
- openlog( 'WP_FAIL2BAN_COMMENT_LOG' );
34
- syslog( LOG_INFO, "Comment {$comment_ID}" );
35
  closelog();
36
- // @codeCoverageIgnoreEnd
37
- return $maybe_notify;
38
  }
39
-
40
- add_filter(
41
- 'notify_post_author',
42
- __NAMESPACE__ . '\\notify_post_author',
43
- 10,
44
- 2
45
- );
46
- }
47
 
 
 
 
 
48
 
49
- if ( defined( 'WP_FAIL2BAN_LOG_COMMENTS_EXTRA' ) ) {
50
- /** WPF2B_EVENT_COMMENT_NOT_FOUND */
51
- if ( WP_FAIL2BAN_LOG_COMMENTS_EXTRA & 0x20002 ) {
52
- /**
53
- * @since 4.0.5 Guard
54
- */
55
-
56
- if ( !function_exists( __NAMESPACE__ . '\\comment_id_not_found' ) ) {
57
- /**
58
- * Log attempted comment on non-existent post
59
- *
60
- * @since 4.0.0
61
- *
62
- * @param int $comment_post_ID
63
- *
64
- * @wp-f2b-extra Comment post not found \d+
65
- */
66
- function comment_id_not_found( $comment_post_ID )
67
- {
68
- openlog( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' );
69
- syslog( LOG_NOTICE, "Comment post not found {$comment_post_ID}" );
70
- closelog();
71
- // @codeCoverageIgnoreEnd
72
- }
73
-
74
- add_action( 'comment_id_not_found', __NAMESPACE__ . '\\comment_id_not_found' );
75
- }
76
-
77
  }
78
- /** LOG_ACTION_LOG_COMMENT_CLOSED */
79
- if ( WP_FAIL2BAN_LOG_COMMENTS_EXTRA & 0x20004 ) {
80
- /**
81
- * @since 4.0.5 Guard
82
- */
83
-
84
- if ( !function_exists( __NAMESPACE__ . '\\comment_closed' ) ) {
85
- /**
86
- * Log attempted comment on closed post
87
- *
88
- * @since 4.0.0
89
- *
90
- * @param int $comment_post_ID
91
- *
92
- * @wp-f2b-extra Comments closed on post \d+
93
- */
94
- function comment_closed( $comment_post_ID )
95
- {
96
- openlog( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' );
97
- syslog( LOG_NOTICE, "Comments closed on post {$comment_post_ID}" );
98
- closelog();
99
- // @codeCoverageIgnoreEnd
100
- }
101
-
102
- add_action( 'comment_closed', __NAMESPACE__ . '\\comment_closed' );
103
- }
104
-
105
  }
106
- /** LOG_ACTION_LOG_COMMENT_TRASH */
107
- if ( WP_FAIL2BAN_LOG_COMMENTS_EXTRA & 0x20008 ) {
108
- /**
109
- * @since 4.0.5 Guard
110
- */
111
-
112
- if ( !function_exists( __NAMESPACE__ . '\\comment_on_trash' ) ) {
113
- /**
114
- * Log attempted comment on trashed post
115
- *
116
- * @since 4.0.2 Fix message
117
- * @since 4.0.0
118
- *
119
- * @param int $comment_post_ID
120
- *
121
- * @wp-f2b-extra Comment attempt on trash post \d+
122
- */
123
- function comment_on_trash( $comment_post_ID )
124
- {
125
- openlog( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' );
126
- syslog( LOG_NOTICE, "Comment attempt on trash post {$comment_post_ID}" );
127
- closelog();
128
- // @codeCoverageIgnoreEnd
129
- }
130
-
131
- add_action( 'comment_on_trash', __NAMESPACE__ . '\\comment_on_trash' );
132
- }
133
-
134
  }
135
- /** LOG_ACTION_LOG_COMMENT_DRAFT */
136
- if ( WP_FAIL2BAN_LOG_COMMENTS_EXTRA & 0x20010 ) {
137
- /**
138
- * @since 4.0.5 Guard
139
- */
140
-
141
- if ( !function_exists( __NAMESPACE__ . '\\comment_on_draft' ) ) {
142
- /**
143
- * Log attempted comment on draft post
144
- *
145
- * @since 4.0.2 Fix message
146
- * @since 4.0.0
147
- *
148
- * @param int $comment_post_ID
149
- *
150
- * @wp-f2b-extra Comment attempt on draft post \d+
151
- */
152
- function comment_on_draft( $comment_post_ID )
153
- {
154
- openlog( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' );
155
- syslog( LOG_NOTICE, "Comment attempt on draft post {$comment_post_ID}" );
156
- closelog();
157
- // @codeCoverageIgnoreEnd
158
- }
159
-
160
- add_action( 'comment_on_draft', __NAMESPACE__ . '\\comment_on_draft' );
161
- }
162
-
163
  }
164
- /** LOG_ACTION_LOG_COMMENT_PASSWORD */
165
- if ( WP_FAIL2BAN_LOG_COMMENTS_EXTRA & 0x20020 ) {
166
- /**
167
- * @since 4.0.5 Guard
168
- */
169
-
170
- if ( !function_exists( __NAMESPACE__ . '\\comment_on_password_protected' ) ) {
171
- /**
172
- * Log attempted comment on password-protected post
173
- *
174
- * @since 4.0.2 Fix message
175
- * @since 4.0.0
176
- *
177
- * @param int $comment_post_ID
178
- *
179
- * @wp-f2b-extra Comment attempt on password-protected post \d+
180
- */
181
- function comment_on_password_protected( $comment_post_ID )
182
- {
183
- openlog( 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' );
184
- syslog( LOG_NOTICE, "Comment attempt on password-protected post {$comment_post_ID}" );
185
- closelog();
186
- // @codeCoverageIgnoreEnd
187
- }
188
-
189
- add_action( 'comment_on_password_protected', __NAMESPACE__ . '\\comment_on_password_protected' );
190
- }
191
-
192
  }
 
 
193
  }
 
1
  <?php
 
2
  /**
3
  * Comment logging
4
  *
5
  * @package wp-fail2ban
6
  * @since 4.0.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban\feature;
9
+
10
+ use function org\lecklider\charles\wordpress\wp_fail2ban\openlog;
11
+ use function org\lecklider\charles\wordpress\wp_fail2ban\syslog;
12
+ use function org\lecklider\charles\wordpress\wp_fail2ban\closelog;
13
+
14
+ defined('ABSPATH') or exit;
15
 
 
 
 
16
  /**
17
+ * Log new comment
18
+ *
19
+ * @since 3.5.0
20
+ *
21
+ * @param bool $maybe_notify
22
+ * @param int $comment_ID
23
+ *
24
+ * @return bool
25
+ *
26
+ * @wp-f2b-extra Comment \d+
27
  */
28
+ function notify_post_author($maybe_notify, $comment_ID)
29
+ {
30
+ if (openlog('WP_FAIL2BAN_COMMENT_LOG')) {
31
+ syslog(LOG_INFO, "Comment {$comment_ID}");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  closelog();
 
 
33
  }
 
 
 
 
 
 
 
 
34
 
35
+ do_action(__FUNCTION__, $maybe_notify, $comment_ID);
36
+
37
+ return $maybe_notify;
38
+ }
39
 
40
+ /**
41
+ * Log attempted comment on non-existent post
42
+ *
43
+ * @since 4.0.0
44
+ *
45
+ * @param int $comment_post_ID
46
+ *
47
+ * @wp-f2b-extra Comment post not found \d+
48
+ */
49
+ function comment_id_not_found($comment_post_ID)
50
+ {
51
+ if (openlog('WP_FAIL2BAN_COMMENT_EXTRA_LOG')) {
52
+ syslog(LOG_NOTICE, "Comment post not found {$comment_post_ID}");
53
+ closelog();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
55
+
56
+ do_action(__FUNCTION__, $comment_post_ID);
57
+ }
58
+
59
+ /**
60
+ * Log attempted comment on closed post
61
+ *
62
+ * @since 4.0.0
63
+ *
64
+ * @param int $comment_post_ID
65
+ *
66
+ * @wp-f2b-extra Comments closed on post \d+
67
+ */
68
+ function comment_closed($comment_post_ID)
69
+ {
70
+ if (openlog('WP_FAIL2BAN_COMMENT_EXTRA_LOG')) {
71
+ syslog(LOG_NOTICE, "Comments closed on post {$comment_post_ID}");
72
+ closelog();
 
 
 
 
 
 
 
 
 
73
  }
74
+
75
+ do_action(__FUNCTION__, $comment_post_ID);
76
+ }
77
+
78
+ /**
79
+ * Log attempted comment on trashed post
80
+ *
81
+ * @since 4.0.2 Fix message
82
+ * @since 4.0.0
83
+ *
84
+ * @param int $comment_post_ID
85
+ *
86
+ * @wp-f2b-extra Comment attempt on trash post \d+
87
+ */
88
+ function comment_on_trash($comment_post_ID)
89
+ {
90
+ if (openlog('WP_FAIL2BAN_COMMENT_EXTRA_LOG')) {
91
+ syslog(LOG_NOTICE, "Comment attempt on trash post {$comment_post_ID}");
92
+ closelog();
 
 
 
 
 
 
 
 
 
93
  }
94
+
95
+ do_action(__FUNCTION__, $comment_post_ID);
96
+ }
97
+
98
+ /**
99
+ * Log attempted comment on draft post
100
+ *
101
+ * @since 4.0.2 Fix message
102
+ * @since 4.0.0
103
+ *
104
+ * @param int $comment_post_ID
105
+ *
106
+ * @wp-f2b-extra Comment attempt on draft post \d+
107
+ */
108
+ function comment_on_draft($comment_post_ID)
109
+ {
110
+ if (openlog('WP_FAIL2BAN_COMMENT_EXTRA_LOG')) {
111
+ syslog(LOG_NOTICE, "Comment attempt on draft post {$comment_post_ID}");
112
+ closelog();
 
 
 
 
 
 
 
 
 
113
  }
114
+
115
+ do_action(__FUNCTION__, $comment_post_ID);
116
+ }
117
+
118
+ /**
119
+ * Log attempted comment on password-protected post
120
+ *
121
+ * @since 4.0.2 Fix message
122
+ * @since 4.0.0
123
+ *
124
+ * @param int $comment_post_ID
125
+ *
126
+ * @wp-f2b-extra Comment attempt on password-protected post \d+
127
+ */
128
+ function comment_on_password_protected($comment_post_ID)
129
+ {
130
+ if (openlog('WP_FAIL2BAN_COMMENT_EXTRA_LOG')) {
131
+ syslog(LOG_NOTICE, "Comment attempt on password-protected post {$comment_post_ID}");
132
+ closelog();
 
 
 
 
 
 
 
 
 
133
  }
134
+
135
+ do_action(__FUNCTION__, $comment_post_ID);
136
  }
137
+
feature/lib.php DELETED
@@ -1,137 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Library functions
5
- *
6
- * @package wp-fail2ban
7
- * @since 4.0.0
8
- */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
10
-
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
- /**
15
- * Wrapper for \openlog
16
- *
17
- * @since 3.5.0 Refactored for unit testing
18
- *
19
- * @param string $log
20
- */
21
- function openlog( $log = 'WP_FAIL2BAN_AUTH_LOG' )
22
- {
23
- $tag = ( defined( 'WP_FAIL2BAN_SYSLOG_SHORT_TAG' ) && true === WP_FAIL2BAN_SYSLOG_SHORT_TAG ? 'wp' : 'wordpress' );
24
- $host = ( array_key_exists( 'WP_FAIL2BAN_HTTP_HOST', $_ENV ) ? $_ENV['WP_FAIL2BAN_HTTP_HOST'] : $_SERVER['HTTP_HOST'] );
25
- /**
26
- * Some varieties of syslogd have difficulty if $host is too long
27
- * @since 3.5.0
28
- */
29
- if ( defined( 'WP_FAIL2BAN_TRUNCATE_HOST' ) && 1 < intval( WP_FAIL2BAN_TRUNCATE_HOST ) ) {
30
- $host = substr( $host, 0, intval( WP_FAIL2BAN_TRUNCATE_HOST ) );
31
- }
32
-
33
- if ( false === \openlog( "{$tag}({$host})", WP_FAIL2BAN_OPENLOG_OPTIONS, constant( $log ) ) ) {
34
- error_log( 'WPf2b: Cannot open syslog', 0 );
35
- // @codeCoverageIgnore
36
- } elseif ( defined( 'WP_FAIL2BAN_TRACE' ) ) {
37
- error_log( 'WPf2b: Opened syslog', 0 );
38
- // @codeCoverageIgnore
39
- }
40
-
41
- }
42
-
43
- /**
44
- * Wrapper for \syslog
45
- *
46
- * @since 3.5.0
47
- *
48
- * @param int $level
49
- * @param string $msg
50
- * @param string|null $remote_addr
51
- */
52
- function syslog( $level, $msg, $remote_addr = null )
53
- {
54
- $msg .= ' from ';
55
- $msg .= ( is_null( $remote_addr ) ? remote_addr() : $remote_addr );
56
-
57
- if ( false === \syslog( $level, $msg ) ) {
58
- error_log( "WPf2b: Cannot write to syslog: '{$msg}'", 0 );
59
- // @codeCoverageIgnore
60
- } elseif ( defined( 'WP_FAIL2BAN_TRACE' ) ) {
61
- error_log( "WPf2b: Wrote to syslog: '{$msg}'", 0 );
62
- // @codeCoverageIgnore
63
- }
64
-
65
- \closelog();
66
- if ( defined( 'PHPUNIT_COMPOSER_INSTALL' ) ) {
67
- echo "{$level}|{$msg}" ;
68
- }
69
- }
70
-
71
- /**
72
- * Graceful immediate exit
73
- *
74
- * @since 4.2.7 Remove JSON support
75
- * @since 4.0.5 Add JSON support
76
- * @since 3.5.0 Refactored for unit testing
77
- */
78
- function bail()
79
- {
80
- wp_die( 'Forbidden', 'Forbidden', array(
81
- 'response' => 403,
82
- ) );
83
- }
84
-
85
- /**
86
- * Compute remote IP address
87
- *
88
- * @return string
89
- *
90
- * @todo Test me!
91
- * @codeCoverageIgnore
92
- */
93
- function remote_addr()
94
- {
95
- static $remote_addr = null ;
96
- /**
97
- * @since 4.0.0
98
- */
99
-
100
- if ( is_null( $remote_addr ) ) {
101
- if ( defined( 'WP_FAIL2BAN_PROXIES' ) ) {
102
-
103
- if ( array_key_exists( 'HTTP_X_FORWARDED_FOR', $_SERVER ) ) {
104
- $ip = ip2long( $_SERVER['REMOTE_ADDR'] );
105
- /**
106
- * PHP 7 lets you define an array
107
- * @since 3.5.4
108
- */
109
- $proxies = ( is_array( WP_FAIL2BAN_PROXIES ) ? WP_FAIL2BAN_PROXIES : explode( ',', WP_FAIL2BAN_PROXIES ) );
110
- foreach ( $proxies as $proxy ) {
111
-
112
- if ( '#' == $proxy[0] ) {
113
- continue;
114
- } elseif ( 2 == count( $cidr = explode( '/', $proxy ) ) ) {
115
- $net = ip2long( $cidr[0] );
116
- $mask = ~(pow( 2, 32 - $cidr[1] ) - 1);
117
- } else {
118
- $net = ip2long( $proxy );
119
- $mask = -1;
120
- }
121
-
122
- if ( $net == ($ip & $mask) ) {
123
- return ( false === ($len = strpos( $_SERVER['HTTP_X_FORWARDED_FOR'], ',' )) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : substr( $_SERVER['HTTP_X_FORWARDED_FOR'], 0, $len ) );
124
- }
125
- }
126
- }
127
-
128
- }
129
- /**
130
- * For plugins and themes that anonymise requests
131
- * @since 3.6.0
132
- */
133
- $remote_addr = ( defined( 'WP_FAIL2BAN_REMOTE_ADDR' ) ? WP_FAIL2BAN_REMOTE_ADDR : $_SERVER['REMOTE_ADDR'] );
134
- }
135
-
136
- return $remote_addr;
137
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
feature/password.php CHANGED
@@ -1,37 +1,34 @@
1
  <?php
2
-
3
  /**
4
  * Password-related functionality
5
  *
6
  * @package wp-fail2ban
7
  * @since 4.0.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
 
 
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
- * @since 4.0.5
 
 
 
 
 
 
16
  */
17
-
18
- if ( !function_exists( __NAMESPACE__ . '\\retrieve_password' ) ) {
19
- /**
20
- * Log password reset requests
21
- *
22
- * @since 3.5.0
23
- *
24
- * @param string $user_login
25
- *
26
- * @wp-f2b-extra Password reset requested for .*
27
- */
28
- function retrieve_password( $user_login )
29
- {
30
- openlog( 'WP_FAIL2BAN_PASSWORD_REQUEST_LOG' );
31
- syslog( LOG_NOTICE, "Password reset requested for {$user_login}" );
32
  closelog();
33
- // @codeCoverageIgnoreEnd
34
  }
35
-
36
- add_action( 'retrieve_password', __NAMESPACE__ . '\\retrieve_password' );
37
  }
 
1
  <?php
 
2
  /**
3
  * Password-related functionality
4
  *
5
  * @package wp-fail2ban
6
  * @since 4.0.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban\feature;
9
+
10
+ use function org\lecklider\charles\wordpress\wp_fail2ban\openlog;
11
+ use function org\lecklider\charles\wordpress\wp_fail2ban\syslog;
12
+ use function org\lecklider\charles\wordpress\wp_fail2ban\closelog;
13
+
14
+ defined('ABSPATH') or exit;
15
 
 
 
 
16
  /**
17
+ * Log password reset requests
18
+ *
19
+ * @since 3.5.0
20
+ *
21
+ * @param string $user_login
22
+ *
23
+ * @wp-f2b-extra Password reset requested for .*
24
  */
25
+ function retrieve_password($user_login)
26
+ {
27
+ if (openlog('WP_FAIL2BAN_PASSWORD_REQUEST_LOG')) {
28
+ syslog(LOG_NOTICE, "Password reset requested for {$user_login}");
 
 
 
 
 
 
 
 
 
 
 
29
  closelog();
 
30
  }
31
+
32
+ do_action(__FUNCTION__, $user_login);
33
  }
34
+
feature/plugins.php CHANGED
@@ -1,27 +1,18 @@
1
  <?php
2
-
3
  /**
4
  * Library functions
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.2.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
- /**
15
- * Hook: plugins_loaded
16
- *
17
- * @since 4.2.0
18
- */
19
- function plugins_loaded()
20
- {
21
- do_action( 'wp_fail2ban_register' );
22
- }
23
 
24
- add_action( 'plugins_loaded', __NAMESPACE__ . '\\plugins_loaded' );
25
  /**
26
  * Register plugin
27
  *
@@ -32,35 +23,39 @@ add_action( 'plugins_loaded', __NAMESPACE__ . '\\plugins_loaded' );
32
  *
33
  * @return int|false ID
34
  */
35
- function register_plugin( $slug, $name )
36
  {
37
- global $wp_fail2ban, $wpdb ;
38
- if ( 255 < strlen( $slug ) ) {
39
- throw new \LengthException( 'slug too long' );
 
40
  }
41
- if ( 255 < strlen( $name ) ) {
42
- throw new \LengthException( 'name too long' );
 
43
  }
44
- if ( !is_array( @$wp_fail2ban['plugins'] ) ) {
45
- $wp_fail2ban['plugins'] = [];
 
46
  }
47
- if ( array_key_exists( $slug, $wp_fail2ban['plugins'] ) ) {
 
48
  return $wp_fail2ban['plugins'][$slug];
49
  }
50
- static $id = 0 ;
51
- return $wp_fail2ban['plugins'][$slug] = [
52
- 'id' => ++$id,
53
- 'name' => $name,
54
- 'messages' => [],
55
- ];
 
 
 
 
 
 
56
  }
57
 
58
- add_action(
59
- 'wp_fail2ban_register_plugin',
60
- __NAMESPACE__ . '\\register_plugin',
61
- 1,
62
- 2
63
- );
64
  /**
65
  * Check if plugin is registered.
66
  *
@@ -70,10 +65,11 @@ add_action(
70
  *
71
  * @return bool
72
  */
73
- function is_registered_plugin( $plugin_slug )
74
  {
75
- global $wp_fail2ban ;
76
- return array_key_exists( $plugin_slug, $wp_fail2ban['plugins'] );
 
77
  }
78
 
79
  /**
@@ -94,88 +90,91 @@ function is_registered_plugin( $plugin_slug )
94
  * USER: Current user name
95
  * array vars: Array of [name => regex] pairs
96
  */
97
- function register_message( $plugin_slug, array $msg )
98
  {
99
- global $wp_fail2ban ;
100
  $event_classes = [
101
- 'auth' => WPF2B_EVENT_CLASS_AUTH,
102
- 'comment' => WPF2B_EVENT_CLASS_COMMENT,
103
- 'password' => WPF2B_EVENT_CLASS_PASSWORD,
104
- 'rest' => WPF2B_EVENT_CLASS_REST,
105
- 'spam' => WPF2B_EVENT_CLASS_SPAM,
106
- 'xmlrpc' => WPF2B_EVENT_CLASS_XMLRPC,
107
- 'other' => 0,
108
  ];
 
109
  $args = [];
110
- if ( !is_registered_plugin( $plugin_slug ) ) {
111
- throw new \InvalidArgumentException( 'plugin not registered' );
 
112
  }
113
- if ( !array_key_exists( 'slug', $msg ) ) {
114
- throw new \InvalidArgumentException( "Missing 'slug'" );
 
115
  }
116
- if ( !is_string( $msg['slug'] ) ) {
117
- throw new \InvalidArgumentException( "'slug' must be string" );
118
  }
119
- if ( !array_key_exists( 'fail', $msg ) ) {
120
- throw new \InvalidArgumentException( "Missing 'fail'" );
 
121
  }
122
- if ( !in_array( $msg['fail'], [ 'hard', 'soft', 'extra' ] ) ) {
123
- throw new \UnexpectedValueException( "'fail' must be one of 'hard', 'soft', 'extra'" );
124
  }
125
  $args['fail'] = $msg['fail'];
126
- if ( !array_key_exists( 'priority', $msg ) ) {
127
- throw new \InvalidArgumentException( "Missing 'priority'" );
 
128
  }
129
- if ( !in_array( $msg['priority'], [
130
  LOG_CRIT,
131
  LOG_ERR,
132
  LOG_WARNING,
133
  LOG_NOTICE,
134
  LOG_INFO,
135
  LOG_DEBUG
136
- ] ) ) {
137
- throw new \UnexpectedValueException( "Invalid 'priority'" );
138
  }
139
  $args['priority'] = $msg['priority'];
140
- if ( !array_key_exists( 'event_class', $msg ) ) {
141
- throw new \InvalidArgumentException( "Missing 'event_class'" );
 
142
  }
143
- if ( !array_key_exists( $event_class = strtolower( $msg['event_class'] ), $event_classes ) ) {
144
- throw new \UnexpectedValueException( "Invalid 'event_class'" );
145
  }
146
  $args['class'] = $event_class;
147
  $event_class = $event_classes[$event_class];
148
- $log = sprintf( "WP_FAIL2BAN_%s_LOG", strtoupper( $event_class ) );
149
- if ( !array_key_exists( 'event_id', $msg ) ) {
150
- throw new \InvalidArgumentException( "Missing 'event_id'" );
151
  }
152
- if ( ($msg['event_id'] & 0xffff) !== $msg['event_id'] ) {
153
- throw new \UnexpectedValueException( "Invalid 'event_id'" );
154
  }
155
  $args['event_id'] = WPF2B_EVENT_TYPE_PLUGIN | $event_class | $msg['event_id'];
156
- if ( !array_key_exists( 'message', $msg ) ) {
157
- throw new \InvalidArgumentException( "Missing 'message'" );
 
158
  }
159
- if ( !is_string( $msg['message'] ) ) {
160
- throw new \UnexpectedValueException( "Invalid 'message'" );
161
  }
162
  $args['message'] = $msg['message'];
163
- if ( !array_key_exists( 'vars', $msg ) ) {
164
- throw new \InvalidArgumentException( "Missing 'vars'" );
 
165
  }
166
- if ( !is_array( $msg['vars'] ) ) {
167
- throw new \UnexpectedValueException( "Invalid 'vars'" );
168
  }
169
  $args['vars'] = $msg['vars'];
 
170
  $wp_fail2ban['plugins'][$plugin_slug]['messages'][$msg['slug']] = $args;
171
  }
172
 
173
- add_action(
174
- 'wp_fail2ban_register_message',
175
- __NAMESPACE__ . '\\register_message',
176
- 1,
177
- 2
178
- );
179
  /**
180
  * Check if message is registered.
181
  *
@@ -188,10 +187,11 @@ add_action(
188
  *
189
  * @return bool
190
  */
191
- function is_registered_plugin_message( $plugin_slug, $message_slug )
192
  {
193
- global $wp_fail2ban ;
194
- return array_key_exists( $message_slug, $wp_fail2ban['plugins'][$plugin_slug]['messages'] );
 
195
  }
196
 
197
  /**
@@ -203,31 +203,31 @@ function is_registered_plugin_message( $plugin_slug, $message_slug )
203
  * @param string $message_slug Message slug for registered message
204
  * @param array $vars Substitution vars
205
  */
206
- function log_message( $plugin_slug, $message_slug = null, array $vars = array() )
207
  {
208
- global $wp_fail2ban ;
209
- if ( !is_registered_plugin( $plugin_slug ) ) {
210
- throw new \InvalidArgumentException( 'plugin not registered' );
 
211
  }
212
- if ( !is_registered_plugin_message( $plugin_slug, $message_slug ) ) {
213
- throw new \InvalidArgumentException( 'message not registered' );
 
214
  }
 
215
  $args = $wp_fail2ban['plugins'][$plugin_slug]['messages'][$message_slug];
216
  $msg = $args['message'];
217
- foreach ( $args['vars'] as $name => $regex ) {
218
- if ( array_key_exists( $name, $vars ) ) {
219
- $msg = str_replace( "___{$name}___", $vars[$name], $msg );
220
  }
221
  }
222
- openlog( sprintf( 'WP_FAIL2BAN_PLUGIN_%s_LOG', strtoupper( $args['class'] ) ) );
223
- syslog( $args['priority'], "({$plugin_slug}) {$msg}" );
224
- closelog();
225
- // @codeCoverageIgnoreEnd
 
 
 
226
  }
227
 
228
- add_action(
229
- 'wp_fail2ban_log_message',
230
- __NAMESPACE__ . '\\log_message',
231
- 1,
232
- 3
233
- );
1
  <?php
 
2
  /**
3
  * Library functions
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.2.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban\feature;
9
 
10
+ use function org\lecklider\charles\wordpress\wp_fail2ban\openlog;
11
+ use function org\lecklider\charles\wordpress\wp_fail2ban\syslog;
12
+ use function org\lecklider\charles\wordpress\wp_fail2ban\closelog;
13
+
14
+ defined('ABSPATH') or exit;
 
 
 
 
 
 
 
15
 
 
16
  /**
17
  * Register plugin
18
  *
23
  *
24
  * @return int|false ID
25
  */
26
+ function register_plugin($slug, $name)
27
  {
28
+ global $wp_fail2ban;
29
+
30
+ if (255 < strlen($slug)) {
31
+ throw new \LengthException('slug too long');
32
  }
33
+
34
+ if (255 < strlen($name)) {
35
+ throw new \LengthException('name too long');
36
  }
37
+
38
+ if (!array_key_exists('plugins', $wp_fail2ban) || !is_array($wp_fail2ban['plugins'])) {
39
+ $wp_fail2ban['plugins'] = []; //@codeCoverageIgnore
40
  }
41
+
42
+ if (array_key_exists($slug, $wp_fail2ban['plugins'])) {
43
  return $wp_fail2ban['plugins'][$slug];
44
  }
45
+
46
+ if (is_null($rv = apply_filters(__FUNCTION__, null, $slug, $name))) {
47
+ static $id = 0;
48
+
49
+ return ($wp_fail2ban['plugins'][$slug] = [
50
+ 'id' => ++$id,
51
+ 'name' => $name,
52
+ 'messages' => []
53
+ ]);
54
+ } else {
55
+ return $rv; // @codeCoverageIgnore
56
+ }
57
  }
58
 
 
 
 
 
 
 
59
  /**
60
  * Check if plugin is registered.
61
  *
65
  *
66
  * @return bool
67
  */
68
+ function is_registered_plugin($plugin_slug)
69
  {
70
+ global $wp_fail2ban;
71
+
72
+ return (array_key_exists('plugins', $wp_fail2ban) && is_array($wp_fail2ban['plugins']) && array_key_exists($plugin_slug, $wp_fail2ban['plugins']));
73
  }
74
 
75
  /**
90
  * USER: Current user name
91
  * array vars: Array of [name => regex] pairs
92
  */
93
+ function register_message($plugin_slug, array $msg)
94
  {
95
+ global $wp_fail2ban;
96
  $event_classes = [
97
+ 'auth' => WPF2B_EVENT_CLASS_AUTH,
98
+ 'comment' => WPF2B_EVENT_CLASS_COMMENT,
99
+ 'password' => WPF2B_EVENT_CLASS_PASSWORD,
100
+ 'rest' => WPF2B_EVENT_CLASS_REST,
101
+ 'spam' => WPF2B_EVENT_CLASS_SPAM,
102
+ 'xmlrpc' => WPF2B_EVENT_CLASS_XMLRPC,
103
+ 'other' => 0
104
  ];
105
+
106
  $args = [];
107
+
108
+ if (!is_registered_plugin($plugin_slug)) {
109
+ throw new \InvalidArgumentException('plugin not registered');
110
  }
111
+
112
+ if (!array_key_exists('slug', $msg)) {
113
+ throw new \InvalidArgumentException("Missing 'slug'");
114
  }
115
+ if (!is_string($msg['slug'])) {
116
+ throw new \InvalidArgumentException("'slug' must be string");
117
  }
118
+
119
+ if (!array_key_exists('fail', $msg)) {
120
+ throw new \InvalidArgumentException("Missing 'fail'");
121
  }
122
+ if (!in_array($msg['fail'], ['hard', 'soft', 'extra'])) {
123
+ throw new \UnexpectedValueException("'fail' must be one of 'hard', 'soft', 'extra'");
124
  }
125
  $args['fail'] = $msg['fail'];
126
+
127
+ if (!array_key_exists('priority', $msg)) {
128
+ throw new \InvalidArgumentException("Missing 'priority'");
129
  }
130
+ if (!in_array($msg['priority'], [
131
  LOG_CRIT,
132
  LOG_ERR,
133
  LOG_WARNING,
134
  LOG_NOTICE,
135
  LOG_INFO,
136
  LOG_DEBUG
137
+ ])) {
138
+ throw new \UnexpectedValueException("Invalid 'priority'");
139
  }
140
  $args['priority'] = $msg['priority'];
141
+
142
+ if (!array_key_exists('event_class', $msg)) {
143
+ throw new \InvalidArgumentException("Missing 'event_class'");
144
  }
145
+ if (!array_key_exists($event_class = strtolower($msg['event_class']), $event_classes)) {
146
+ throw new \UnexpectedValueException("Invalid 'event_class'");
147
  }
148
  $args['class'] = $event_class;
149
  $event_class = $event_classes[$event_class];
150
+
151
+ if (!array_key_exists('event_id', $msg)) {
152
+ throw new \InvalidArgumentException("Missing 'event_id'");
153
  }
154
+ if (($msg['event_id'] & 0x0000FFFF) !== $msg['event_id']) {
155
+ throw new \UnexpectedValueException("Invalid 'event_id'");
156
  }
157
  $args['event_id'] = WPF2B_EVENT_TYPE_PLUGIN | $event_class | $msg['event_id'];
158
+
159
+ if (!array_key_exists('message', $msg)) {
160
+ throw new \InvalidArgumentException("Missing 'message'");
161
  }
162
+ if (!is_string($msg['message'])) {
163
+ throw new \UnexpectedValueException("Invalid 'message'");
164
  }
165
  $args['message'] = $msg['message'];
166
+
167
+ if (!array_key_exists('vars', $msg)) {
168
+ throw new \InvalidArgumentException("Missing 'vars'");
169
  }
170
+ if (!is_array($msg['vars'])) {
171
+ throw new \UnexpectedValueException("Invalid 'vars'");
172
  }
173
  $args['vars'] = $msg['vars'];
174
+
175
  $wp_fail2ban['plugins'][$plugin_slug]['messages'][$msg['slug']] = $args;
176
  }
177
 
 
 
 
 
 
 
178
  /**
179
  * Check if message is registered.
180
  *
187
  *
188
  * @return bool
189
  */
190
+ function is_registered_plugin_message($plugin_slug, $message_slug)
191
  {
192
+ global $wp_fail2ban;
193
+
194
+ return array_key_exists($message_slug, $wp_fail2ban['plugins'][$plugin_slug]['messages']);
195
  }
196
 
197
  /**
203
  * @param string $message_slug Message slug for registered message
204
  * @param array $vars Substitution vars
205
  */
206
+ function log_message($plugin_slug, $message_slug = null, array $vars = [])
207
  {
208
+ global $wp_fail2ban;
209
+
210
+ if (!is_registered_plugin($plugin_slug)) {
211
+ throw new \InvalidArgumentException('plugin not registered');
212
  }
213
+
214
+ if (!is_registered_plugin_message($plugin_slug, $message_slug)) {
215
+ throw new \InvalidArgumentException('message not registered');
216
  }
217
+
218
  $args = $wp_fail2ban['plugins'][$plugin_slug]['messages'][$message_slug];
219
  $msg = $args['message'];
220
+ foreach (array_keys($args['vars']) as $name) {
221
+ if (array_key_exists($name, $vars)) {
222
+ $msg = str_replace("___{$name}___", $vars[$name], $msg);
223
  }
224
  }
225
+
226
+ if (openlog(sprintf('WP_FAIL2BAN_PLUGIN_%s_LOG', strtoupper($args['class'])))) {
227
+ syslog($args['priority'], "($plugin_slug) $msg");
228
+ closelog();
229
+ }
230
+
231
+ do_action(__FUNCTION__, $plugin_slug, $message_slug, $vars, $args);
232
  }
233
 
 
 
 
 
 
 
feature/spam.php CHANGED
@@ -1,60 +1,47 @@
1
  <?php
2
-
3
  /**
4
  * Spam comments
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.0.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
 
 
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
- * @since 4.0.5
 
 
 
 
 
 
 
16
  */
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- if ( !function_exists( __NAMESPACE__ . '\\log_spam_comment' ) ) {
19
- /**
20
- * Catch comments marked as spam
21
- *
22
- * @since 3.5.0
23
- *
24
- * @param int $comment_id
25
- * @param string $comment_status
26
- *
27
- * @wp-f2b-hard Spam comment \d+
28
- */
29
- function log_spam_comment( $comment_id, $comment_status )
30
- {
31
- if ( 'spam' === $comment_status ) {
32
-
33
- if ( is_null( $comment = get_comment( $comment_id, ARRAY_A ) ) ) {
34
- /**
35
- * @todo: decide what to do about this
36
- */
37
- } else {
38
- $remote_addr = ( empty($comment['comment_author_IP']) ? 'unknown' : $comment['comment_author_IP'] );
39
- openlog( 'WP_FAIL2BAN_SPAM_LOG' );
40
- syslog( LOG_NOTICE, "Spam comment {$comment_id}", $remote_addr );
41
  closelog();
42
- // @codeCoverageIgnoreEnd
43
  }
44
-
 
45
  }
46
  }
47
-
48
- add_action(
49
- 'comment_post',
50
- __NAMESPACE__ . '\\log_spam_comment',
51
- 10,
52
- 2
53
- );
54
- add_action(
55
- 'wp_set_comment_status',
56
- __NAMESPACE__ . '\\log_spam_comment',
57
- 10,
58
- 2
59
- );
60
  }
 
1
  <?php
 
2
  /**
3
  * Spam comments
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban\feature;
9
+
10
+ use function org\lecklider\charles\wordpress\wp_fail2ban\openlog;
11
+ use function org\lecklider\charles\wordpress\wp_fail2ban\syslog;
12
+ use function org\lecklider\charles\wordpress\wp_fail2ban\closelog;
13
+
14
+ defined('ABSPATH') or exit;
15
 
 
 
 
16
  /**
17
+ * Catch comments marked as spam
18
+ *
19
+ * @since 3.5.0
20
+ *
21
+ * @param int $comment_id
22
+ * @param string $comment_status
23
+ *
24
+ * @wp-f2b-hard Spam comment \d+
25
  */
26
+ function log_spam_comment($comment_id, $comment_status)
27
+ {
28
+ if ('spam' === $comment_status) {
29
+ if (is_null($comment = get_comment($comment_id, ARRAY_A))) {
30
+ /**
31
+ * @todo: decide what to do about this
32
+ */
33
+ } else {
34
+ $remote_addr = (empty($comment['comment_author_IP']))
35
+ ? 'unknown' // @codeCoverageIgnore
36
+ : $comment['comment_author_IP'];
37
 
38
+ if (openlog('WP_FAIL2BAN_SPAM_LOG')) {
39
+ syslog(LOG_NOTICE, "Spam comment {$comment_id}", $remote_addr);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  closelog();
 
41
  }
42
+
43
+ do_action(__FUNCTION__, $comment_id, $comment_status);
44
  }
45
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
+
feature/user-enum.php CHANGED
@@ -1,145 +1,114 @@
1
  <?php
2
-
3
  /**
4
  * User enumeration
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.0.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
 
 
 
 
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
- * @since 4.0.5 Guard
 
 
 
 
 
 
 
 
 
 
16
  */
17
- if ( !function_exists( __NAMESPACE__ . '\\_log_bail_user_enum' ) ) {
18
- /**
19
- * Common enumeration handling
20
- *
21
- * @since 4.2.7 Remove JSON support
22
- * @since 4.1.0 Add JSON support
23
- * @since 4.0.0
24
- *
25
- * @return \WP_Error
26
- *
27
- * @wp-f2b-hard Blocked user enumeration attempt
28
- */
29
- function _log_bail_user_enum()
30
- {
31
- openlog();
32
- syslog( LOG_NOTICE, 'Blocked user enumeration attempt' );
33
  closelog();
34
- // @codeCoverageIgnoreEnd
35
- return bail();
36
  }
37
 
 
 
 
38
  }
 
39
  /**
40
- * @since 4.0.5 Guard
 
 
 
 
 
 
 
 
 
 
 
41
  */
42
-
43
- if ( !function_exists( __NAMESPACE__ . '\\parse_request' ) ) {
44
- /**
45
- * Catch traditional user enum
46
- *
47
- * @see \WP::parse_request()
48
- *
49
- * @since 4.2.8 Refactor to make XDebug happy (h/t @dinghy)
50
- * @since 3.5.0 Refactored for unit testing
51
- * @since 2.1.0
52
- *
53
- * @param \WP $query
54
- *
55
- * @return \WP
56
- */
57
- function parse_request( $query )
58
- {
59
- if ( !current_user_can( 'list_users' ) && array_key_exists( 'author', $query->query_vars ) && intval( $query->query_vars['author'] ) ) {
60
- _log_bail_user_enum();
61
- }
62
- return $query;
63
  }
64
-
65
- add_filter(
66
- 'parse_request',
67
- __NAMESPACE__ . '\\parse_request',
68
- 1,
69
- 2
70
- );
71
  }
72
 
73
  /**
74
- * @since 4.0.5 Guard
 
 
 
 
 
 
 
 
 
 
 
 
75
  */
76
-
77
- if ( !function_exists( __NAMESPACE__ . '\\rest_user_query' ) ) {
78
- /**
79
- * Catch RESTful user list
80
- *
81
- * @see \WP_REST_Users_Controller::get_items()
82
- *
83
- * @since 4.2.8 Change cap to edit_others_posts to play better with GB
84
- * @since 4.0.0
85
- *
86
- * @param array $prepared_args
87
- * @param \WP_REST_Request $request
88
- *
89
- * @return array|\WP_Error
90
- */
91
- function rest_user_query( $prepared_args, $request )
92
- {
93
- if ( !current_user_can( 'edit_others_posts' ) ) {
94
- return _log_bail_user_enum();
95
- }
96
- return $prepared_args;
97
  }
98
-
99
- add_filter(
100
- 'rest_user_query',
101
- __NAMESPACE__ . '\\rest_user_query',
102
- 10,
103
- 2
104
- );
105
  }
106
 
107
  /**
108
- * @since 4.2.6 Guard
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  */
 
 
 
 
110
 
111
- if ( !function_exists( __NAMESPACE__ . '\\oembed_response_data' ) ) {
112
- /**
113
- *
114
- * @see \get_oembed_response_data()
115
- *
116
- * @since 4.2.7.1 Fix `add_filter()` params
117
- * @since 4.2.6
118
- *
119
- * @param array $data The response data.
120
- * @param \WP_Post $post The post object.
121
- * @param int $width The requested width.
122
- * @param int $height The calculated height.
123
- *
124
- * @return array
125
- */
126
- function oembed_response_data(
127
- $data,
128
- $post,
129
- $width,
130
- $height
131
- )
132
- {
133
- unset( $data['author_name'] );
134
- unset( $data['author_url'] );
135
- return $data;
136
- }
137
-
138
- add_filter(
139
- 'oembed_response_data',
140
- __NAMESPACE__ . '\\oembed_response_data',
141
- PHP_INT_MAX - 1,
142
- // almost last in case something expects author_xxx to be set
143
- 4
144
- );
145
  }
 
1
  <?php
 
2
  /**
3
  * User enumeration
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban\feature;
9
+
10
+ use function org\lecklider\charles\wordpress\wp_fail2ban\array_value;
11
+ use function org\lecklider\charles\wordpress\wp_fail2ban\bail;
12
+ use function org\lecklider\charles\wordpress\wp_fail2ban\openlog;
13
+ use function org\lecklider\charles\wordpress\wp_fail2ban\syslog;
14
+ use function org\lecklider\charles\wordpress\wp_fail2ban\closelog;
15
+
16
+ defined('ABSPATH') or exit;
17
 
 
 
 
18
  /**
19
+ * Common enumeration handling
20
+ *
21
+ * @since 4.3.0 Remove JSON support
22
+ * @since 4.1.0 Add JSON support
23
+ * @since 4.0.0
24
+ *
25
+ * @param bool $is_json
26
+ *
27
+ * @return \WP_Error
28
+ *
29
+ * @wp-f2b-hard Blocked user enumeration attempt
30
  */
31
+ function _log_bail_user_enum()
32
+ {
33
+ if (openlog()) {
34
+ syslog(LOG_NOTICE, 'Blocked user enumeration attempt');
 
 
 
 
 
 
 
 
 
 
 
 
35
  closelog();
 
 
36
  }
37
 
38
+ do_action(__FUNCTION__);
39
+
40
+ return bail();
41
  }
42
+
43
  /**
44
+ * Catch traditional user enum
45
+ *
46
+ * @see \WP::parse_request()
47
+ *
48
+ * @since 4.3.0 Refactored to make XDebug happy; h/t @dinghy
49
+ * Changed cap to 'edit_others_posts'
50
+ * @since 3.5.0 Refactored for unit testing
51
+ * @since 2.1.0
52
+ *
53
+ * @param \WP $query
54
+ *
55
+ * @return \WP
56
  */
57
+ function parse_request($query)
58
+ {
59
+ if (!current_user_can('edit_others_posts') && intval(array_value('author', $query->query_vars))) {
60
+ _log_bail_user_enum();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
62
+
63
+ return $query;
 
 
 
 
 
64
  }
65
 
66
  /**
67
+ * Catch RESTful user list
68
+ *
69
+ * @see \WP_REST_Users_Controller::get_items()
70
+ *
71
+ * @since 4.3.0 Change to 'edit_others_posts'
72
+ * @since 4.0.0
73
+ *
74
+ * @param array $prepared_args
75
+ * @param \WP_REST_Request $request
76
+ *
77
+ * @return array|\WP_Error
78
+ *
79
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
80
  */
81
+ function rest_user_query($prepared_args, $request)
82
+ {
83
+ if (!current_user_can('edit_others_posts')) {
84
+ return _log_bail_user_enum();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  }
86
+
87
+ return $prepared_args;
 
 
 
 
 
88
  }
89
 
90
  /**
91
+ * Catch oembed user info
92
+ *
93
+ * @see \get_oembed_response_data()
94
+ *
95
+ * @since 4.2.7
96
+ *
97
+ * @param array $data The response data.
98
+ * @param WP_Post $post The post object.
99
+ * @param int $width The requested width.
100
+ * @param int $height The calculated height.
101
+ *
102
+ * @return array
103
+ *
104
+ * @codeCoverageIgnore
105
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
106
  */
107
+ function oembed_response_data($data, $post, $width, $height)
108
+ {
109
+ unset($data['author_name']);
110
+ unset($data['author_url']);
111
 
112
+ return $data;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
114
+
feature/user.php CHANGED
@@ -1,61 +1,76 @@
1
  <?php
2
-
3
  /**
4
  * Blocked user functionality
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.0.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
 
 
 
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
- * @since 4.0.5 Guard
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  */
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- if ( !function_exists( __NAMESPACE__ . '\\authenticate' ) ) {
19
- /**
20
- * Catched blocked users
21
- *
22
- * @since 3.5.0 Refactored for unit testing
23
- * @since 2.0.0
24
- *
25
- * @param mixed|null $user
26
- * @param string $username
27
- * @param string $password
28
- *
29
- * @return mixed|null
30
- *
31
- * @wp-f2b-hard Blocked authentication attempt for .*
32
- */
33
- function authenticate( $user, $username, $password )
34
- {
35
-
36
- if ( !empty($username) ) {
37
  /**
38
  * @since 3.5.0 Arrays allowed in PHP 7
39
  */
40
- $matched = ( is_array( WP_FAIL2BAN_BLOCKED_USERS ) ? in_array( $username, WP_FAIL2BAN_BLOCKED_USERS ) : preg_match( '/' . WP_FAIL2BAN_BLOCKED_USERS . '/i', $username ) );
41
-
42
- if ( $matched ) {
43
- openlog();
44
- syslog( LOG_NOTICE, "Blocked authentication attempt for {$username}" );
45
- closelog();
46
- // @codeCoverageIgnoreEnd
47
- bail();
 
 
 
 
 
48
  }
49
-
50
  }
51
-
52
- return $user;
53
  }
54
-
55
- add_filter(
56
- 'authenticate',
57
- __NAMESPACE__ . '\\authenticate',
58
- 1,
59
- 3
60
- );
61
  }
 
1
  <?php
 
2
  /**
3
  * Blocked user functionality
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban\feature;
9
+
10
+ use function org\lecklider\charles\wordpress\wp_fail2ban\bail;
11
+ use function org\lecklider\charles\wordpress\wp_fail2ban\openlog;
12
+ use function org\lecklider\charles\wordpress\wp_fail2ban\syslog;
13
+ use function org\lecklider\charles\wordpress\wp_fail2ban\closelog;
14
+
15
+ defined('ABSPATH') or exit;
16
 
 
 
 
17
  /**
18
+ * Catch blocked users
19
+ *
20
+ * @see \wp_authenticate()
21
+ *
22
+ * @since 4.3.0 Add blocking username logins
23
+ * @since 3.5.0 Refactored for unit testing
24
+ * @since 2.0.0
25
+ *
26
+ * @param mixed|null $user
27
+ * @param string $username
28
+ * @param string $password
29
+ *
30
+ * @return mixed|null
31
+ *
32
+ * @wp-f2b-hard Blocked authentication attempt for .*
33
+ * @wp-f2b-hard Blocked username authentication attempt for .*
34
  */
35
+ function block_users($user, $username, $password)
36
+ {
37
+ if (!empty($username)) {
38
+ if (defined('WP_FAIL2BAN_BLOCK_USERNAME_LOGIN') && WP_FAIL2BAN_BLOCK_USERNAME_LOGIN) {
39
+ if (is_email($username)) {
40
+ // OK!
41
+ } else {
42
+ if (openlog()) {
43
+ syslog(LOG_NOTICE, "Blocked username authentication attempt for {$username}");
44
+ closelog();
45
+ }
46
 
47
+ do_action(__FUNCTION__.'.block_username_login', $user, $username, $password);
48
+
49
+ return bail(); // for testing
50
+ }
51
+ }
52
+
53
+ if (defined('WP_FAIL2BAN_BLOCKED_USERS') && !empty(WP_FAIL2BAN_BLOCKED_USERS)) {
 
 
 
 
 
 
 
 
 
 
 
 
54
  /**
55
  * @since 3.5.0 Arrays allowed in PHP 7
56
  */
57
+ $matched = (is_array(WP_FAIL2BAN_BLOCKED_USERS))
58
+ ? in_array($username, WP_FAIL2BAN_BLOCKED_USERS)
59
+ : preg_match('/'.WP_FAIL2BAN_BLOCKED_USERS.'/i', $username);
60
+
61
+ if ($matched) {
62
+ if (openlog()) {
63
+ syslog(LOG_NOTICE, "Blocked authentication attempt for {$username}");
64
+ closelog();
65
+ }
66
+
67
+ do_action(__FUNCTION__.'.blocked_users', $user, $username, $password);
68
+
69
+ return bail(); // for testing
70
  }
 
71
  }
 
 
72
  }
73
+
74
+ return $user;
 
 
 
 
 
75
  }
76
+
feature/xmlrpc.php CHANGED
@@ -1,108 +1,132 @@
1
  <?php
2
-
3
  /**
4
  * XML-RPC functionality
5
  *
6
  * @package wp-fail2ban
7
- * @since 4.0.0
8
  */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
 
 
 
 
 
 
 
10
 
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
  /**
15
- * @since 4.0.5 Guard
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  */
 
 
 
17
 
18
- if ( !function_exists( __NAMESPACE__ . '\\xmlrpc_login_error' ) ) {
19
- /**
20
- * Catch multiple XML-RPC authentication failures
21
- *
22
- * @see \wp_xmlrpc_server::login()
23
- *
24
- * @since 4.0.0 Return $error
25
- * @since 3.5.0 Refactored for unit testing
26
- * @since 3.0.0
27
- *
28
- * @param \IXR_Error $error
29
- * @param \WP_Error $user
30
- *
31
- * @return \IXR_Error
32
- *
33
- * @wp-f2b-hard XML-RPC multicall authentication failure
34
- */
35
- function xmlrpc_login_error( $error, $user )
36
- {
37
- static $attempts = 0 ;
38
-
39
- if ( ++$attempts > 1 ) {
40
- openlog();
41
- syslog( LOG_NOTICE, 'XML-RPC multicall authentication failure' );
42
  closelog();
43
- // @codeCoverageIgnoreEnd
44
- bail();
45
- } else {
46
- return $error;
47
  }
48
-
 
 
 
 
 
49
  }
50
-
51
- add_action(
52
- 'xmlrpc_login_error',
53
- __NAMESPACE__ . '\\xmlrpc_login_error',
54
- 10,
55
- 2
56
- );
57
- }
58
 
59
  /**
60
- * @since 4.0.5 Guard
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  */
62
-
63
- if ( !function_exists( __NAMESPACE__ . '\\xmlrpc_pingback_error' ) ) {
64
- /**
65
- * Catch failed pingbacks
66
- *
67
- * @see \wp_xmlrpc_server::pingback_error()
68
- *
69
- * @since 4.0.0 Return $ixr_error
70
- * @since 3.5.0 Refactored for unit testing
71
- * @since 3.0.0
72
- *
73
- * @param \IXR_Error $ixr_error
74
- *
75
- * @return \IXR_Error
76
- *
77
- * @wp-f2b-hard Pingback error .* generated
78
- */
79
- function xmlrpc_pingback_error( $ixr_error )
80
- {
81
-
82
- if ( 48 !== $ixr_error->code ) {
83
- openlog();
84
- syslog( LOG_NOTICE, 'Pingback error ' . $ixr_error->code . ' generated' );
85
  closelog();
86
- // @codeCoverageIgnoreEnd
87
  }
88
-
89
- return $ixr_error;
90
  }
91
-
92
- add_filter( 'xmlrpc_pingback_error', __NAMESPACE__ . '\\xmlrpc_pingback_error', 5 );
93
  }
94
 
95
  /**
96
- * @since 4.0.0 Refactored
 
 
 
97
  * @since 2.2.0
 
 
98
  */
99
- if ( defined( 'WP_FAIL2BAN_LOG_PINGBACKS' ) && true === WP_FAIL2BAN_LOG_PINGBACKS ) {
100
- require_once 'xmlrpc/pingback.php';
 
 
 
 
 
 
 
 
 
 
101
  }
 
102
  /**
103
- * @since 4.0.0 Refactored
 
 
 
 
 
 
 
104
  * @since 3.6.0
 
 
105
  */
106
- if ( defined( 'WP_FAIL2BAN_XMLRPC_LOG' ) && '' < WP_FAIL2BAN_XMLRPC_LOG ) {
107
- require_once 'xmlrpc/log.php';
108
- }
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
  /**
3
  * XML-RPC functionality
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.0.0
7
  */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban\feature;
9
+
10
+ use function org\lecklider\charles\wordpress\wp_fail2ban\bail;
11
+ use function org\lecklider\charles\wordpress\wp_fail2ban\openlog;
12
+ use function org\lecklider\charles\wordpress\wp_fail2ban\syslog;
13
+ use function org\lecklider\charles\wordpress\wp_fail2ban\closelog;
14
+
15
+ defined('ABSPATH') or exit;
16
 
 
 
 
17
  /**
18
+ * Catch multiple XML-RPC authentication failures
19
+ *
20
+ * This is redundant in CP and newer versions of WP
21
+ *
22
+ * @see \wp_xmlrpc_server::login()
23
+ *
24
+ * @since 4.3.0 Added action
25
+ * @since 4.0.0 Return $error
26
+ * @since 3.5.0 Refactored for unit testing
27
+ * @since 3.0.0
28
+ *
29
+ * @param \IXR_Error $error
30
+ * @param \WP_Error $user
31
+ *
32
+ * @return \IXR_Error
33
+ *
34
+ * @wp-f2b-hard XML-RPC multicall authentication failure
35
  */
36
+ function xmlrpc_login_error($error, $user)
37
+ {
38
+ static $attempts = 0;
39
 
40
+ if (++$attempts > 1) {
41
+ if (openlog()) {
42
+ syslog(LOG_NOTICE, 'XML-RPC multicall authentication failure');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  closelog();
 
 
 
 
44
  }
45
+
46
+ do_action(__FUNCTION__, $error, $user);
47
+
48
+ bail();
49
+ } else {
50
+ return $error;
51
  }
52
+ } // @codeCoverageIgnore
 
 
 
 
 
 
 
53
 
54
  /**
55
+ * Catch failed pingbacks
56
+ *
57
+ * @see \wp_xmlrpc_server::pingback_error()
58
+ *
59
+ * @since 4.3.0 Added action
60
+ * @since 4.0.0 Return $ixr_error
61
+ * @since 3.5.0 Refactored for unit testing
62
+ * @since 3.0.0
63
+ *
64
+ * @param \IXR_Error $ixr_error
65
+ *
66
+ * @return \IXR_Error
67
+ *
68
+ * @wp-f2b-hard Pingback error .* generated
69
  */
70
+ function xmlrpc_pingback_error($ixr_error)
71
+ {
72
+ if (48 !== $ixr_error->code) {
73
+ if (openlog()) {
74
+ syslog(LOG_NOTICE, 'Pingback error '.$ixr_error->code.' generated');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  closelog();
 
76
  }
77
+
78
+ do_action(__FUNCTION__, $ixr_error);
79
  }
80
+ return $ixr_error;
 
81
  }
82
 
83
  /**
84
+ * Log pingbacks
85
+ *
86
+ * @since 4.3.0 Added actions
87
+ * @since 3.5.0 Refactored for unit testing
88
  * @since 2.2.0
89
+ *
90
+ * @param string $call
91
  */
92
+ function xmlrpc_call($call)
93
+ {
94
+ if ('pingback.ping' == $call) {
95
+ if (openlog('WP_FAIL2BAN_PINGBACK_LOG')) {
96
+ syslog(LOG_INFO, 'Pingback requested');
97
+ closelog();
98
+ }
99
+
100
+ do_action(__FUNCTION__.'::pingback.ping');
101
+ }
102
+
103
+ do_action(__FUNCTION__, $call);
104
  }
105
+
106
  /**
107
+ * Log XML-RPC requests
108
+ *
109
+ * It seems attackers are doing weird things with XML-RPC. This makes it easy to
110
+ * log them for analysis and future blocking.
111
+ *
112
+ * @since 4.3.0 Refactored
113
+ * @since 4.0.0 Fix: Removed HTTP_RAW_POST_DATA
114
+ * https://wordpress.org/support/?p=10971843
115
  * @since 3.6.0
116
+ *
117
+ * @codeCoverageIgnore
118
  */
119
+ function xmlrpc_log()
120
+ {
121
+ if (false === ($fp = fopen(WP_FAIL2BAN_XMLRPC_LOG, 'a+'))) {
122
+ // TODO: decided whether to log this
123
+ } else {
124
+ $raw_data = (version_compare(PHP_VERSION, '7.0.0') >= 0)
125
+ ? file_get_contents('php://input')
126
+ : $HTTP_RAW_POST_DATA;
127
+
128
+ fprintf($fp, "# ---\n# Date: %s\n# IP: %s\n\n%s\n", date(DATE_ATOM), remote_addr(), $raw_data);
129
+ fclose($fp);
130
+ }
131
+ }
132
+
feature/xmlrpc/log.php DELETED
@@ -1,35 +0,0 @@
1
- <?php
2
- /**
3
- * XML-RPC Request logging
4
- *
5
- * @package wp-fail2ban
6
- * @since 4.0.0
7
- */
8
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
-
10
- if (!defined('ABSPATH')) {
11
- exit;
12
- }
13
-
14
- /**
15
- * Log XML-RPC requests
16
- *
17
- * It seems attackers are doing weird things with XML-RPC. This makes it easy to
18
- * log them for analysis and future blocking.
19
- *
20
- * @since 4.0.0 Fix: Removed HTTP_RAW_POST_DATA
21
- * https://wordpress.org/support/?p=10971843
22
- * @since 3.6.0
23
- *
24
- * @codeCoverageIgnore
25
- */
26
- if (false === ($fp = fopen(WP_FAIL2BAN_XMLRPC_LOG, 'a+'))) {
27
- // TODO: decided whether to log this
28
- } else {
29
- $raw_data = (version_compare(PHP_VERSION, '7.0.0') >= 0)
30
- ? file_get_contents('php://input')
31
- : $HTTP_RAW_POST_DATA;
32
-
33
- fprintf($fp, "# ---\n# Date: %s\n# IP: %s\n\n%s\n", date(DATE_ATOM), remote_addr(), $raw_data);
34
- fclose($fp);
35
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
feature/xmlrpc/pingback.php DELETED
@@ -1,40 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * pingback logging
5
- *
6
- * @package wp-fail2ban
7
- * @since 4.0.0
8
- */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
10
-
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
- /**
15
- * @since 4.0.5 Guard
16
- */
17
-
18
- if ( !function_exists( __NAMESPACE__ . '\\xmlrpc_call' ) ) {
19
- /**
20
- * Log pingbacks
21
- *
22
- * @since 3.5.0 Refactored for unit testing
23
- * @since 2.2.0
24
- *
25
- * @param string $call
26
- */
27
- function xmlrpc_call( $call )
28
- {
29
-
30
- if ( 'pingback.ping' == $call ) {
31
- openlog( 'WP_FAIL2BAN_PINGBACK_LOG' );
32
- syslog( LOG_INFO, 'Pingback requested' );
33
- closelog();
34
- // @codeCoverageIgnoreEnd
35
- }
36
-
37
- }
38
-
39
- add_action( 'xmlrpc_call', __NAMESPACE__ . '\\xmlrpc_call' );
40
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
filters.d/wordpress-extra.conf CHANGED
@@ -1,5 +1,5 @@
1
  # Fail2Ban filter for WordPress extra failures
2
- # Auto-generated: 2020-04-17T15:52:10+00:00
3
  #
4
 
5
  [INCLUDES]
@@ -10,13 +10,13 @@ before = common.conf
10
 
11
  _daemon = (?:wordpress|wp)
12
 
13
- failregex = ^%(__prefix_line)sComment \d+ from <HOST>$
 
14
  ^%(__prefix_line)sComment post not found \d+ from <HOST>$
15
  ^%(__prefix_line)sComments closed on post \d+ from <HOST>$
16
  ^%(__prefix_line)sComment attempt on trash post \d+ from <HOST>$
17
  ^%(__prefix_line)sComment attempt on draft post \d+ from <HOST>$
18
  ^%(__prefix_line)sComment attempt on password-protected post \d+ from <HOST>$
19
- ^%(__prefix_line)sPassword reset requested for .* from <HOST>$
20
 
21
  ignoreregex =
22
 
1
  # Fail2Ban filter for WordPress extra failures
2
+ # Auto-generated: 2020-07-27T10:41:08+00:00
3
  #
4
 
5
  [INCLUDES]
10
 
11
  _daemon = (?:wordpress|wp)
12
 
13
+ failregex = ^%(__prefix_line)sPassword reset requested for .* from <HOST>$
14
+ ^%(__prefix_line)sComment \d+ from <HOST>$
15
  ^%(__prefix_line)sComment post not found \d+ from <HOST>$
16
  ^%(__prefix_line)sComments closed on post \d+ from <HOST>$
17
  ^%(__prefix_line)sComment attempt on trash post \d+ from <HOST>$
18
  ^%(__prefix_line)sComment attempt on draft post \d+ from <HOST>$
19
  ^%(__prefix_line)sComment attempt on password-protected post \d+ from <HOST>$
 
20
 
21
  ignoreregex =
22
 
filters.d/wordpress-hard.conf CHANGED
@@ -1,5 +1,5 @@
1
  # Fail2Ban filter for WordPress hard failures
2
- # Auto-generated: 2020-04-17T15:52:10+00:00
3
  #
4
 
5
  [INCLUDES]
@@ -10,14 +10,15 @@ before = common.conf
10
 
11
  _daemon = (?:wordpress|wp)
12
 
13
- failregex = ^%(__prefix_line)sAuthentication attempt for unknown user .* from <HOST>$
14
- ^%(__prefix_line)sREST authentication attempt for unknown user .* from <HOST>$
15
- ^%(__prefix_line)sXML-RPC authentication attempt for unknown user .* from <HOST>$
16
- ^%(__prefix_line)sSpam comment \d+ from <HOST>$
17
- ^%(__prefix_line)sBlocked user enumeration attempt from <HOST>$
18
  ^%(__prefix_line)sBlocked authentication attempt for .* from <HOST>$
 
19
  ^%(__prefix_line)sXML-RPC multicall authentication failure from <HOST>$
20
  ^%(__prefix_line)sPingback error .* generated from <HOST>$
 
 
 
 
21
 
22
  ignoreregex =
23
 
1
  # Fail2Ban filter for WordPress hard failures
2
+ # Auto-generated: 2020-07-27T10:41:08+00:00
3
  #
4
 
5
  [INCLUDES]
10
 
11
  _daemon = (?:wordpress|wp)
12
 
13
+ failregex = ^%(__prefix_line)sSpam comment \d+ from <HOST>$
 
 
 
 
14
  ^%(__prefix_line)sBlocked authentication attempt for .* from <HOST>$
15
+ ^%(__prefix_line)sBlocked username authentication attempt for .* from <HOST>$
16
  ^%(__prefix_line)sXML-RPC multicall authentication failure from <HOST>$
17
  ^%(__prefix_line)sPingback error .* generated from <HOST>$
18
+ ^%(__prefix_line)sBlocked user enumeration attempt from <HOST>$
19
+ ^%(__prefix_line)sAuthentication attempt for unknown user .* from <HOST>$
20
+ ^%(__prefix_line)sREST authentication attempt for unknown user .* from <HOST>$
21
+ ^%(__prefix_line)sXML-RPC authentication attempt for unknown user .* from <HOST>$
22
 
23
  ignoreregex =
24
 
filters.d/wordpress-soft.conf CHANGED
@@ -1,5 +1,5 @@
1
  # Fail2Ban filter for WordPress soft failures
2
- # Auto-generated: 2020-04-17T15:52:10+00:00
3
  #
4
 
5
  [INCLUDES]
@@ -10,7 +10,8 @@ before = common.conf
10
 
11
  _daemon = (?:wordpress|wp)
12
 
13
- failregex = ^%(__prefix_line)sAuthentication failure for .* from <HOST>$
 
14
  ^%(__prefix_line)sREST authentication failure for .* from <HOST>$
15
  ^%(__prefix_line)sXML-RPC authentication failure for .* from <HOST>$
16
 
1
  # Fail2Ban filter for WordPress soft failures
2
+ # Auto-generated: 2020-07-27T10:41:08+00:00
3
  #
4
 
5
  [INCLUDES]
10
 
11
  _daemon = (?:wordpress|wp)
12
 
13
+ failregex = ^%(__prefix_line)sEmpty username from <HOST>$
14
+ ^%(__prefix_line)sAuthentication failure for .* from <HOST>$
15
  ^%(__prefix_line)sREST authentication failure for .* from <HOST>$
16
  ^%(__prefix_line)sXML-RPC authentication failure for .* from <HOST>$
17
 
freemius.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * WP fail2ban premium
5
+ *
6
+ * @package wp-fail2ban
7
+ * @since 4.3.0
8
+ */
9
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
10
+
11
+ // @codeCoverageIgnoreStart
12
+ defined( 'ABSPATH' ) or exit;
13
+ /**
14
+ * Freemius integration
15
+ *
16
+ * @since 4.0.0
17
+ */
18
+
19
+ if ( function_exists( __NAMESPACE__ . '\\wf_fs' ) ) {
20
+ wf_fs()->set_basename( true, WP_FAIL2BAN_FILE );
21
+ return;
22
+ } else {
23
+ /**
24
+ * Create a helper function for easy SDK access.
25
+ *
26
+ * @since 4.0.0
27
+ */
28
+ function wf_fs()
29
+ {
30
+ global $wf_fs ;
31
+
32
+ if ( !isset( $wf_fs ) ) {
33
+ // Activate multisite network integration.
34
+ if ( !defined( 'WP_FS__PRODUCT_3072_MULTISITE' ) ) {
35
+ define( 'WP_FS__PRODUCT_3072_MULTISITE', true );
36
+ }
37
+ // Include Freemius SDK.
38
+ require_once __DIR__ . '/vendor/freemius/wordpress-sdk/start.php';
39
+ $wf_fs = fs_dynamic_init( array(
40
+ 'id' => '3072',
41
+ 'slug' => 'wp-fail2ban',
42
+ 'type' => 'plugin',
43
+ 'public_key' => 'pk_146d2c2a5bee3b157e43501ef8682',
44
+ 'is_premium' => false,
45
+ 'has_addons' => true,
46
+ 'has_paid_plans' => true,
47
+ 'trial' => array(
48
+ 'days' => 14,
49
+ 'is_require_payment' => false,
50
+ ),
51
+ 'menu' => array(
52
+ 'slug' => 'wp-fail2ban-menu',
53
+ 'contact' => true,
54
+ 'support' => true,
55
+ 'network' => true,
56
+ ),
57
+ 'is_live' => true,
58
+ ) );
59
+ }
60
+
61
+ return $wf_fs;
62
+ }
63
+
64
+ // Init Freemius.
65
+ wf_fs();
66
+ // Set currency to GBP
67
+ wf_fs()->add_filter( 'default_currency', function () {
68
+ return 'gbp';
69
+ } );
70
+ // Set custom icon
71
+ wf_fs()->add_filter( 'plugin_icon', function () {
72
+ return __DIR__ . '/assets/icon.svg';
73
+ } );
74
+ // Set forum URL
75
+ wf_fs()->add_filter( 'support_forum_url', function () {
76
+ if ( wf_fs()->is_trial() ) {
77
+ /** Trial forum: Invite-only */
78
+ return 'https://forums.invis.net/c/wp-fail2ban-premium/support-trial/';
79
+ }
80
+ if ( wf_fs()->is_free_plan() ) {
81
+ /** Free forum: available to all */
82
+ return 'https://forums.invis.net/c/wp-fail2ban/support/';
83
+ }
84
+ if ( wf_fs()->is_paying() ) {
85
+ /** Paying forum: Invite-only */
86
+ return 'https://forums.invis.net/c/wp-fail2ban-premium/support/';
87
+ }
88
+ /** Just in case... */
89
+ return 'https://forums.invis.net/c/wp-fail2ban/';
90
+ } );
91
+ wf_fs()->add_filter( 'show_delegation_option', false );
92
+ // Signal that SDK was initiated.
93
+ do_action( 'wf_fs_loaded' );
94
+ require_once 'functions.php';
95
+ require_once 'init.php';
96
+ }
functions.php ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP fail2ban main file
4
+ *
5
+ * @package wp-fail2ban
6
+ * @since 4.0.0
7
+ */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ defined('ABSPATH') or exit;
11
+
12
+ require_once 'lib/constants.php'; // @wpf2b exclude[lite]
13
+ require_once 'lib/convert-data.php'; // @wpf2b exclude[lite]
14
+
15
+ require_once 'lib/defaults.php';
16
+ require_once 'lib/activation.php';
17
+ require_once 'lib/loader.php';
18
+
19
+ require_once 'core.php';
20
+ require_once 'feature/comments.php';
21
+ require_once 'feature/password.php';
22
+ require_once 'feature/plugins.php';
23
+ require_once 'feature/spam.php';
24
+ require_once 'feature/user-enum.php';
25
+ require_once 'feature/user.php';
26
+ require_once 'feature/xmlrpc.php';
27
+
28
+ /**
29
+ * Helper.
30
+ *
31
+ * @since 4.3.0
32
+ *
33
+ * @param mixed $key
34
+ * @param array $ary
35
+ * @return mixed|null Array value if present, null otherwise.
36
+ */
37
+ function array_value($key, array $ary)
38
+ {
39
+ return (array_key_exists($key, $ary))
40
+ ? $ary[$key]
41
+ : null;
42
+ }
43
+
44
+ /**
45
+ * Wrapper for \openlog
46
+ *
47
+ * @since 3.5.0 Refactored for unit testing
48
+ *
49
+ * @param string $log
50
+ */
51
+ function openlog($log = 'WP_FAIL2BAN_AUTH_LOG')
52
+ {
53
+ $tag = (defined('WP_FAIL2BAN_SYSLOG_SHORT_TAG') && true === WP_FAIL2BAN_SYSLOG_SHORT_TAG)
54
+ ? 'wp' // @codeCoverageIgnore
55
+ : 'wordpress';
56
+ $host = (array_key_exists('WP_FAIL2BAN_HTTP_HOST', $_ENV))
57
+ ? $_ENV['WP_FAIL2BAN_HTTP_HOST'] // @codeCoverageIgnore
58
+ : $_SERVER['HTTP_HOST'];
59
+ if (is_multisite() && !SUBDOMAIN_INSTALL) {
60
+ /**
61
+ * @todo Test me!
62
+ */
63
+ // @codeCoverageIgnoreStart
64
+ if (!is_main_site()) {
65
+ $blog = get_blog_details(get_current_blog_id(), false);
66
+ $host .= '/'.trim($blog->path, '/');
67
+ } // @codeCoverageIgnoreEnd
68
+ }
69
+ /**
70
+ * Some varieties of syslogd have difficulty if $host is too long
71
+ * @since 3.5.0
72
+ */
73
+ if (defined('WP_FAIL2BAN_TRUNCATE_HOST') && 1 < intval(WP_FAIL2BAN_TRUNCATE_HOST)) {
74
+ $host = substr($host, 0, intval(WP_FAIL2BAN_TRUNCATE_HOST));
75
+ }
76
+ /**
77
+ * Refactor for unit testing.
78
+ * @since 4.3.0
79
+ */
80
+ $options = (defined('WP_FAIL2BAN_OPENLOG_OPTIONS'))
81
+ ? WP_FAIL2BAN_OPENLOG_OPTIONS // @codeCoverageIgnore
82
+ : null;
83
+ $ident = "$tag($host)";
84
+ if (true !== apply_filters(__FUNCTION__, true, $ident, $options, constant($log))) {
85
+ return true; // @codeCoverageIgnore
86
+ } elseif (false === \openlog($ident, $options, constant($log))) {
87
+ error_log('WPf2b: Cannot open syslog', 0); // @codeCoverageIgnore
88
+ } elseif (defined('WP_FAIL2BAN_TRACE')) {
89
+ error_log('WPf2b: Opened syslog', 0); // @codeCoverageIgnore
90
+ } else {
91
+ return true;
92
+ }
93
+ } // @codeCoverageIgnore
94
+
95
+ /**
96
+ * Wrapper for \syslog
97
+ *
98
+ * @since 3.5.0
99
+ *
100
+ * @param int $level
101
+ * @param string $msg
102
+ * @param string|null $remote_addr
103
+ */
104
+ function syslog($level, $msg, $remote_addr = null)
105
+ {
106
+ if (true === apply_filters(__FUNCTION__, true, $level, $msg, $remote_addr)) {
107
+ $msg .= ' from ';
108
+ $msg .= (is_null($remote_addr))
109
+ ? remote_addr()
110
+ : $remote_addr;
111
+
112
+ if (false === \syslog($level, $msg)) {
113
+ error_log("WPf2b: Cannot write to syslog: '{$msg}'", 0); // @codeCoverageIgnore
114
+ } elseif (defined('WP_FAIL2BAN_TRACE')) {
115
+ error_log("WPf2b: Wrote to syslog: '{$msg}'", 0); // @codeCoverageIgnore
116
+ }
117
+ }
118
+
119
+ if (defined('PHPUNIT_COMPOSER_INSTALL')) {
120
+ echo "$level|$msg";
121
+ }
122
+
123
+ /**
124
+ * @since 4.3.0
125
+ */
126
+ if (!defined('WP_FAIL2BAN_DISABLE_LAST_LOG') || true !== WP_FAIL2BAN_DISABLE_LAST_LOG) {
127
+ if (!is_array($last_messages = get_site_option('wp-fail2ban-messages', []))) {
128
+ $last_messages = [];
129
+ }
130
+ $message = [
131
+ 'dt' => gmdate('Y-m-d H:i:s'),
132
+ 'lvl' => ConvertData::intToSyslogPriorityName($level),
133
+ 'msg' => $msg
134
+ ];
135
+ array_unshift($last_messages, $message);
136
+ while (5 < count($last_messages)) {
137
+ array_pop($last_messages); // @codeCoverageIgnore
138
+ }
139
+ update_site_option('wp-fail2ban-messages', $last_messages);
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Wrapper for \closelog
145
+ *
146
+ * @since 4.3.0
147
+ */
148
+ function closelog()
149
+ {
150
+ if (true === apply_filters(__FUNCTION__, true)) {
151
+ \closelog();
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Graceful immediate exit
157
+ *
158
+ * @since 4.3.0 Remove JSON support
159
+ * @since 4.0.5 Add JSON support
160
+ * @since 3.5.0 Refactored for unit testing
161
+ *
162
+ * @param bool $is_json
163
+ *
164
+ * @SuppressWarnings(PHPMD.ExitExpression)
165
+ */
166
+ function bail()
167
+ {
168
+ if (false === apply_filters(__FUNCTION__, true)) {
169
+ return false; // @codeCoverageIgnore
170
+ }
171
+
172
+ \wp_die('Forbidden', 'Forbidden', array('exit' => false, 'response' => 403));
173
+
174
+ if (defined('PHPUNIT_COMPOSER_INSTALL')) {
175
+ return false; // for testing
176
+ } else {
177
+ exit; // @codeCoverageIgnore
178
+ }
179
+ }
180
+
181
+
182
+ /**
183
+ * Compute remote IP address
184
+ *
185
+ * @return string
186
+ *
187
+ * @todo Test me!
188
+ * @codeCoverageIgnore
189
+ */
190
+ function remote_addr()
191
+ {
192
+ static $remote_addr = null;
193
+
194
+ /**
195
+ * @since 4.0.0
196
+ */
197
+ if (is_null($remote_addr)) {
198
+ if (defined('WP_FAIL2BAN_PROXIES')) {
199
+ if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
200
+ $ip = ip2long($_SERVER['REMOTE_ADDR']);
201
+ /**
202
+ * PHP 7 lets you define an array
203
+ * @since 3.5.4
204
+ */
205
+ $proxies = (is_array(WP_FAIL2BAN_PROXIES))
206
+ ? WP_FAIL2BAN_PROXIES
207
+ : explode(',', WP_FAIL2BAN_PROXIES);
208
+ foreach ($proxies as $proxy) {
209
+ if ('#' == $proxy[0]) {
210
+ continue;
211
+ } elseif (2 == count($cidr = explode('/', $proxy))) {
212
+ $net = ip2long($cidr[0]);
213
+ $mask = ~ ( pow(2, (32 - $cidr[1])) - 1 );
214
+ } else {
215
+ $net = ip2long($proxy);
216
+ $mask = -1;
217
+ }
218
+ if ($net == ($ip & $mask)) {
219
+ return (false === ($len = strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',')))
220
+ ? $_SERVER['HTTP_X_FORWARDED_FOR']
221
+ : substr($_SERVER['HTTP_X_FORWARDED_FOR'], 0, $len);
222
+ }
223
+ }
224
+ }
225
+ }
226
+
227
+ /**
228
+ * For plugins and themes that anonymise requests
229
+ * @since 3.6.0
230
+ */
231
+ $remote_addr = (defined('WP_FAIL2BAN_REMOTE_ADDR'))
232
+ ? WP_FAIL2BAN_REMOTE_ADDR
233
+ : $_SERVER['REMOTE_ADDR'];
234
+ }
235
+
236
+ return $remote_addr;
237
+ }
238
+
init.php ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP fail2ban features
4
+ *
5
+ * @package wp-fail2ban
6
+ * @since 4.0.0
7
+ * @php 5.3
8
+ */
9
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
10
+
11
+ defined('ABSPATH') or exit;
12
+
13
+ /**
14
+ * Hook: plugins_loaded
15
+ *
16
+ * Run slightly earlier than the main hook
17
+ *
18
+ * @since 4.3.0
19
+ *
20
+ * @return void
21
+ */
22
+ function plugins_loaded__early()
23
+ {
24
+ Config::load();
25
+ }
26
+ add_action('plugins_loaded', __NAMESPACE__.'\plugins_loaded__early', 9);
27
+
28
+ /**
29
+ * Load all enabled features.
30
+ *
31
+ * @since 4.3.0
32
+ *
33
+ * @return void
34
+ */
35
+ function plugins_loaded()
36
+ {
37
+ /**
38
+ * Core
39
+ *
40
+ * @since 4.3.0
41
+ */
42
+ add_action('authenticate', __NAMESPACE__.'\core\authenticate', 1, 3);
43
+ add_action('wp_login', __NAMESPACE__.'\core\wp_login', 10, 2);
44
+ add_action('wp_login_failed', __NAMESPACE__.'\core\wp_login_failed');
45
+
46
+ /**
47
+ * Comments
48
+ *
49
+ * @since 4.0.0 Refactored
50
+ * @since 3.5.0
51
+ */
52
+ if (defined('WP_FAIL2BAN_LOG_COMMENTS') && true === WP_FAIL2BAN_LOG_COMMENTS) {
53
+ add_filter('notify_post_author', __NAMESPACE__.'\feature\notify_post_author', 10, 2);
54
+
55
+ if (defined('WP_FAIL2BAN_LOG_COMMENTS_EXTRA')) {
56
+ if (WP_FAIL2BAN_LOG_COMMENTS_EXTRA & WPF2B_EVENT_COMMENT_NOT_FOUND) {
57
+ add_action('comment_id_not_found', __NAMESPACE__.'\feature\comment_id_not_found');
58
+ }
59
+ if (WP_FAIL2BAN_LOG_COMMENTS_EXTRA & WPF2B_EVENT_COMMENT_CLOSED) {
60
+ add_action('comment_closed', __NAMESPACE__.'\feature\comment_closed');
61
+ }
62
+ if (WP_FAIL2BAN_LOG_COMMENTS_EXTRA & WPF2B_EVENT_COMMENT_TRASH) {
63
+ add_action('comment_on_trash', __NAMESPACE__.'\feature\comment_on_trash');
64
+ }
65
+ if (WP_FAIL2BAN_LOG_COMMENTS_EXTRA & WPF2B_EVENT_COMMENT_DRAFT) {
66
+ add_action('comment_on_draft', __NAMESPACE__.'\feature\comment_on_draft');
67
+ }
68
+ if (WP_FAIL2BAN_LOG_COMMENTS_EXTRA & WPF2B_EVENT_COMMENT_PASSWORD) {
69
+ add_action('comment_on_password_protected', __NAMESPACE__.'\feature\comment_on_password_protected');
70
+ }
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Password
76
+ *
77
+ * @since 4.0.0 Refactored
78
+ * @since 3.5.0
79
+ */
80
+ if (defined('WP_FAIL2BAN_LOG_PASSWORD_REQUEST') && true === WP_FAIL2BAN_LOG_PASSWORD_REQUEST) {
81
+ add_action('retrieve_password', __NAMESPACE__.'\feature\retrieve_password');
82
+ }
83
+
84
+
85
+ /**
86
+ * Spam
87
+ *
88
+ * @since 4.0.0 Refactored
89
+ * @since 3.5.0
90
+ */
91
+ if (defined('WP_FAIL2BAN_LOG_SPAM') && true === WP_FAIL2BAN_LOG_SPAM) {
92
+ add_action('comment_post', __NAMESPACE__.'\feature\log_spam_comment', 10, 2);
93
+ add_action('wp_set_comment_status', __NAMESPACE__.'\feature\log_spam_comment', 10, 2);
94
+ }
95
+
96
+ /**
97
+ * User enumeration
98
+ *
99
+ * @since 4.0.0 Refactored
100
+ * @since 2.1.0
101
+ */
102
+ if (defined('WP_FAIL2BAN_BLOCK_USER_ENUMERATION') && true === WP_FAIL2BAN_BLOCK_USER_ENUMERATION) {
103
+ add_filter('parse_request', __NAMESPACE__.'\feature\parse_request', 1);
104
+ add_filter('rest_user_query', __NAMESPACE__.'\feature\rest_user_query', 10, 2);
105
+ add_filter('oembed_response_data', __NAMESPACE__.'\feature\oembed_response_data', PHP_INT_MAX-1, 4);
106
+ }
107
+
108
+ /**
109
+ * Users
110
+ *
111
+ * @since 4.3.0 Better test
112
+ * @since 4.0.0 Refactored
113
+ * @since 2.0.0
114
+ */
115
+ if ((defined('WP_FAIL2BAN_BLOCKED_USERS') && WP_FAIL2BAN_BLOCKED_USERS) ||
116
+ (defined('WP_FAIL2BAN_BLOCK_USERNAME_LOGIN') && WP_FAIL2BAN_BLOCK_USERNAME_LOGIN))
117
+ {
118
+ add_filter('authenticate', __NAMESPACE__.'\feature\block_users', 1, 3);
119
+ }
120
+
121
+ /**
122
+ * Set up for plugins
123
+ *
124
+ * @since 4.3.0
125
+ */
126
+ add_action('wp_fail2ban_register_plugin', __NAMESPACE__.'\feature\register_plugin', 1, 2);
127
+ add_action('wp_fail2ban_register_message', __NAMESPACE__.'\feature\register_message', 1, 2);
128
+ add_action('wp_fail2ban_log_message', __NAMESPACE__.'\feature\log_message', 1, 3);
129
+ }
130
+ /**
131
+ * Load nice and early.
132
+ *
133
+ * @since 4.3.0
134
+ */
135
+ add_action('plugins_loaded', __NAMESPACE__.'\plugins_loaded');
136
+
137
+ /**
138
+ * Things we need a current user for.
139
+ *
140
+ * @since 4.3.0
141
+ */
142
+ function init()
143
+ {
144
+ /**
145
+ * @since 4.3.0 Check for logged in
146
+ * @since 4.2.5 Check for admin
147
+ */
148
+ if (!is_user_logged_in()) {
149
+ /**
150
+ * XML-RPC
151
+ *
152
+ * @since 4.0.0 Refactored
153
+ * @since 3.0.0
154
+ */
155
+ if (defined('XMLRPC_REQUEST') && true === XMLRPC_REQUEST) {
156
+ add_action('xmlrpc_login_error', __NAMESPACE__.'\feature\xmlrpc_login_error', 10, 2);
157
+ add_filter('xmlrpc_pingback_error', __NAMESPACE__.'\feature\xmlrpc_pingback_error', 5);
158
+
159
+ /**
160
+ * @since 4.3.0 Refactored
161
+ * @since 4.0.0 Refactored
162
+ * @since 3.6.0
163
+ */
164
+ if (defined('WP_FAIL2BAN_XMLRPC_LOG') && '' < WP_FAIL2BAN_XMLRPC_LOG) {
165
+ xmlrpc_log(); // @codeCoverageIgnore
166
+ }
167
+ /**
168
+ * @since 4.3.0 Refactored
169
+ * @since 4.0.0 Refactored
170
+ * @since 2.2.0
171
+ */
172
+ if (defined('WP_FAIL2BAN_LOG_PINGBACKS') && true === WP_FAIL2BAN_LOG_PINGBACKS) {
173
+ add_action('xmlrpc_call', __NAMESPACE__.'\feature\xmlrpc_call');
174
+ }
175
+ }
176
+ }
177
+
178
+ /**
179
+ * @since 4.3.0 Relocate.
180
+ * @since 4.2.5
181
+ */
182
+ if (defined('WP_ADMIN') && WP_ADMIN) {
183
+ require_once __DIR__.'/admin/admin.php'; // @codeCoverageIgnore
184
+ }
185
+ }
186
+ add_action('init', __NAMESPACE__.'\init');
187
+
188
+ /**
189
+ * Init as late as possible.
190
+ *
191
+ * @since 4.3.0.4
192
+ *
193
+ * @return void
194
+ */
195
+ function init__late()
196
+ {
197
+ /**
198
+ * Let other plugins register their messages
199
+ *
200
+ * @since 4.3.0
201
+ */
202
+ global $wp_fail2ban;
203
+ $wp_fail2ban['plugins'] = [];
204
+
205
+ do_action('wp_fail2ban_register');
206
+ }
207
+ add_action('init', __NAMESPACE__.'\init__late', PHP_INT_MAX);
208
+
lib/activation.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WP fail2ban activation
4
+ *
5
+ * @package wp-fail2ban
6
+ * @since 4.3.0
7
+ */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ // @codeCoverageIgnoreStart
11
+
12
+ defined('ABSPATH') or exit;
13
+
14
+ \register_activation_hook(WP_FAIL2BAN_FILE, function () {
15
+ foreach (get_mu_plugins() as $plugin => $data) {
16
+ if (0 === strpos($data['Name'], 'WP fail2ban')) {
17
+ $wp_f2b_ver = substr(WP_FAIL2BAN_VER, 0, strrpos(WP_FAIL2BAN_VER, '.'));
18
+ $error_msg = __('<h1>Cannot activate WP fail2ban</h1>', 'wp-fail2ban');
19
+ $mu_file = WPMU_PLUGIN_DIR.'/'.$plugin;
20
+ if (is_link($mu_file)) {
21
+ if (false === ($link = readlink($mu_file)) ||
22
+ false === ($path = realpath($mu_file)))
23
+ {
24
+ $h3 = __('A broken symbolic link was found in <tt>mu-plugins</tt>:');
25
+ $error_msg .= <<<__ERROR__
26
+ <h3>{$h3}</h3>
27
+ <p><tt>{$mu_file}</tt></p>
28
+ __ERROR__;
29
+ } elseif (WP_FAIL2BAN_FILE == $path) {
30
+ // OK, we're linking to ourself
31
+ } else {
32
+ $mu_file = str_replace('/', '/<wbr>', $mu_file);
33
+ $mu_file = substr($mu_file, strlen(WPMU_PLUGIN_DIR)-1);
34
+
35
+ $h3 = __('A conflicting symbolic link was found in <tt>mu-plugins</tt>:');
36
+ $error_msg .= <<<__ERROR__
37
+ <h3>{$h3}</h3>
38
+ <style>
39
+ table { text-align: center; }
40
+ td { width: 50%; }
41
+ th { font-size: 200%; }
42
+ td, th { font-family: monospace; }
43
+ span.tt { font-weight: bold; }
44
+ </style>
45
+ <table>
46
+ <tr>
47
+ <td>{$mu_file}</td>
48
+ <th>&DoubleRightArrow;</th>
49
+ <td>{$link}</td>
50
+ </tr>
51
+ <tr>
52
+ <td colspan="3"><span class="tt">&equiv;</span> <span>{$path}</span></td>
53
+ </tr>
54
+ <tr>
55
+ <td colspan="3"></td>
56
+ </tr>
57
+ </table>
58
+ __ERROR__;
59
+ }
60
+
61
+ } else {
62
+ $mu_file = str_replace('/', '/<wbr>', $mu_file);
63
+ $mu_file = substr($mu_file, strlen(WPMU_PLUGIN_DIR)-1);
64
+
65
+ $h3 = __('A conflicting file was found in <tt>mu-plugins</tt>:');
66
+ $error_msg .= <<<__ERROR__
67
+ <h3>{$h3}</h3>
68
+ <p><tt>{$mu_file}</tt></p>
69
+ __ERROR__;
70
+ }
71
+ $error_msg .= sprintf(
72
+ __('<p>Please see the <a href="%s" target="_blank">documentation</a> for how to configure %s for <tt>mu-plugins</tt>.</p>'),
73
+ "https://docs.wp-fail2ban.com/en/{$wp_f2b_ver}/configuration.html#mu-plugins-support",
74
+ $wpf2b
75
+ );
76
+ $error_msg .= sprintf(__('<p>Click <a href="%s">here</a> to return to the plugins page.</p>'), admin_url('plugins.php'));
77
+
78
+ deactivate_plugins(plugin_basename(WP_FAIL2BAN_FILE));
79
+ wp_die($error_msg);
80
+ }
81
+ }
82
+
83
+ @include_once WP_FAIL2BAN_DIR.'/premium/activation.php';
84
+ });
85
+
lib/constants.php CHANGED
@@ -3,142 +3,158 @@
3
  * Constants
4
  *
5
  * @package wp-fail2ban
6
- * @since 4.2.0
7
  */
8
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
 
10
- if (!defined('ABSPATH')) {
11
- exit;
12
- }
13
 
14
- // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
15
  /**
16
- * Defaults
17
  *
18
- * @since 4.0.0
19
- */
20
- define('DEFAULT_WP_FAIL2BAN_OPENLOG_OPTIONS', LOG_PID|LOG_NDELAY);
21
- define('DEFAULT_WP_FAIL2BAN_AUTH_LOG', LOG_AUTH);
22
- define('DEFAULT_WP_FAIL2BAN_COMMENT_LOG', LOG_USER);
23
- define('DEFAULT_WP_FAIL2BAN_PINGBACK_LOG', LOG_USER);
24
- define('DEFAULT_WP_FAIL2BAN_PASSWORD_REQUEST_LOG', LOG_USER);
25
- define('DEFAULT_WP_FAIL2BAN_SPAM_LOG', LOG_AUTH);
26
- /**
27
- * @since 4.0.5
28
- */
29
- define('DEFAULT_WP_FAIL2BAN_COMMENT_EXTRA_LOG', LOG_AUTH);
30
- define('DEFAULT_WP_FAIL2BAN_PINGBACK_ERROR_LOG', LOG_AUTH);
31
- /**
32
- * @since 4.2.0
33
- */
34
- define('DEFAULT_WP_FAIL2BAN_PLUGIN_AUTH_LOG', LOG_AUTH);
35
- define('DEFAULT_WP_FAIL2BAN_PLUGIN_COMMENT_LOG', LOG_USER);
36
- define('DEFAULT_WP_FAIL2BAN_PLUGIN_OTHER_LOG', LOG_USER);
37
- define('DEFAULT_WP_FAIL2BAN_PLUGIN_PASSWORD_LOG', LOG_USER);
38
- define('DEFAULT_WP_FAIL2BAN_PLUGIN_REST_LOG', LOG_USER);
39
- define('DEFAULT_WP_FAIL2BAN_PLUGIN_SPAM_LOG', LOG_AUTH);
40
- define('DEFAULT_WP_FAIL2BAN_PLUGIN_XMLRPC_LOG', LOG_USER);
41
-
42
- /*
43
- 31 | Test
44
- 30 | Plugin
45
- 29 |
46
- 28 |
47
- 27 |
48
- 26 |
49
- 25 |
50
- 24 |
51
- ---
52
- 23 | Event Class
53
- 22 | ..
54
- 21 | ..
55
- 20 | ..
56
- 19 | ..
57
- 18 | ..
58
- 17 | ..
59
- 16 | ..
60
- ---
61
- 15 | ID
62
- 14 | ..
63
- 13 | ..
64
- 12 | ..
65
- 11 | ..
66
- 10 | ..
67
- 09 | ..
68
- 08 | ..
69
- ---
70
- 07 | ..
71
- 06 | ..
72
- 05 | ..
73
- 04 | ..
74
- 03 | ..
75
- 02 | ..
76
- 01 | ..
77
- 00 | ..
78
- */
79
-
80
-
81
-
82
- define('WPF2B_EVENT_CLASS_AUTH', 0x00010000);
83
- define('WPF2B_EVENT_CLASS_COMMENT', 0x00020000);
84
- define('WPF2B_EVENT_CLASS_XMLRPC', 0x00040000);
85
- define('WPF2B_EVENT_CLASS_PASSWORD', 0x00080000);
86
- define('WPF2B_EVENT_CLASS_REST', 0x00100000); /** @since 4.1.0 */
87
- define('WPF2B_EVENT_CLASS_SPAM', 0x00200000); /** @since 4.2.0 */
88
- define('WPF2B_EVENT_TYPE_PLUGIN', 0x40000000); /** @since 4.2.0 */
89
- define('WPF2B_EVENT_TYPE_TEST', 0x80000000); /** @since 4.2.0 */
90
-
91
-
92
- /**
93
  *
 
94
  */
95
- define('WPF2B_EVENT_ACTIVATED', 0xffffffff);
96
-
97
-
98
- /**
99
- * Auth
100
- */
101
- define('WPF2B_EVENT_AUTH_OK', WPF2B_EVENT_CLASS_AUTH | 0x0001);
102
- define('WPF2B_EVENT_AUTH_FAIL', WPF2B_EVENT_CLASS_AUTH | 0x0002);
103
- define('WPF2B_EVENT_AUTH_BLOCK_USER', WPF2B_EVENT_CLASS_AUTH | 0x0004);
104
- define('WPF2B_EVENT_AUTH_BLOCK_USER_ENUM', WPF2B_EVENT_CLASS_AUTH | 0x0008);
105
-
106
- /**
107
- * Comment
108
- */
109
- define('WPF2B_EVENT_COMMENT', WPF2B_EVENT_CLASS_COMMENT | 0x0001); // 0x00020001
110
- define('WPF2B_EVENT_COMMENT_SPAM', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_CLASS_SPAM | 0x0001); // 0x00220001
111
- // comment extra
112
- define('WPF2B_EVENT_COMMENT_NOT_FOUND', WPF2B_EVENT_CLASS_COMMENT | 0x0002); // 0x00020002
113
- define('WPF2B_EVENT_COMMENT_CLOSED', WPF2B_EVENT_CLASS_COMMENT | 0x0004); // 0x00020004
114
- define('WPF2B_EVENT_COMMENT_TRASH', WPF2B_EVENT_CLASS_COMMENT | 0x0008); // 0x00020008
115
- define('WPF2B_EVENT_COMMENT_DRAFT', WPF2B_EVENT_CLASS_COMMENT | 0x0010); // 0x00020010
116
- define('WPF2B_EVENT_COMMENT_PASSWORD', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_CLASS_PASSWORD | 0x0020); // 0x00020020
117
-
118
- /**
119
- * XML-RPC
120
- */
121
- define('WPF2B_EVENT_XMLRPC_PINGBACK', WPF2B_EVENT_CLASS_XMLRPC | 0x0001);
122
- define('WPF2B_EVENT_XMLRPC_PINGBACK_ERROR', WPF2B_EVENT_CLASS_XMLRPC | 0x0002);
123
- define('WPF2B_EVENT_XMLRPC_MULTI_AUTH_FAIL', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | 0x0004);
124
- define('WPF2B_EVENT_XMLRPC_AUTH_OK', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | 0x0008);
125
- define('WPF2B_EVENT_XMLRPC_AUTH_FAIL', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | 0x0010);
126
-
127
- /**
128
- * Password
129
- */
130
- define('WPF2B_ACTION_PASSWORD_REQUEST', WPF2B_EVENT_CLASS_PASSWORD | 0x0001);
131
-
132
- /**
133
- * REST
134
- * @since 4.1.0
135
- */
136
- define('WPF2B_EVENT_REST_AUTH_OK', WPF2B_EVENT_CLASS_REST | WPF2B_EVENT_CLASS_AUTH | 0x0001);
137
- define('WPF2B_EVENT_REST_AUTH_FAIL', WPF2B_EVENT_CLASS_REST | WPF2B_EVENT_CLASS_AUTH | 0x0002);
138
-
139
- /**
140
- *
141
- */
142
- define('WPF2B_EVENT_DEACTIVATED', 0x00000000);
143
- // phpcs:enable
144
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  * Constants
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.2.0
7
  */
8
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
 
10
+ defined('ABSPATH') or exit;
 
 
11
 
 
12
  /**
13
+ * Init constants
14
  *
15
+ * @since 4.3.0 Refactored
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  *
17
+ * @return void
18
  */
19
+ function init_constants()
20
+ {
21
+ // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
22
+ /*
23
+ 31 | Test
24
+ 30 | Plugin
25
+ 29 |
26
+ 28 |
27
+ 27 |
28
+ 26 |
29
+ 25 |
30
+ 24 |
31
+ ---
32
+ 23 | Event Class
33
+ 22 | ..
34
+ 21 | ..
35
+ 20 | ..
36
+ 19 | ..
37
+ 18 | ..
38
+ 17 | ..
39
+ 16 | ..
40
+ ---
41
+ 15 | ID
42
+ 14 | ..
43
+ 13 | ..
44
+ 12 | ..
45
+ 11 | ..
46
+ 10 | ..
47
+ 09 | ..
48
+ 08 | ..
49
+ ---
50
+ 07 | ..
51
+ 06 | ..
52
+ 05 | ..
53
+ 04 | ..
54
+ 03 | ..
55
+ 02 | ..
56
+ 01 | Failure
57
+ 00 | Success
58
+ */
59
+
60
+ define('WPF2B_EVENT_A', 0x0004);
61
+ define('WPF2B_EVENT_B', 0x0008);
62
+ define('WPF2B_EVENT_C', 0x0010);
63
+ define('WPF2B_EVENT_D', 0x0020);
64
+ define('WPF2B_EVENT_E', 0x0040);
65
+ define('WPF2B_EVENT_F', 0x0080);
66
+ define('WPF2B_EVENT_G', 0x0100);
67
+ define('WPF2B_EVENT_H', 0x0200);
68
+ define('WPF2B_EVENT_I', 0x0400);
69
+ define('WPF2B_EVENT_J', 0x0800);
70
+ define('WPF2B_EVENT_K', 0x1000);
71
+ define('WPF2B_EVENT_L', 0x2000);
72
+ define('WPF2B_EVENT_M', 0x4000);
73
+ define('WPF2B_EVENT_N', 0x8000);
74
+
75
+ define('WPF2B_EVENT_CLASS_AUTH', 0x00010000);
76
+ define('WPF2B_EVENT_CLASS_COMMENT', 0x00020000);
77
+ define('WPF2B_EVENT_CLASS_XMLRPC', 0x00040000);
78
+ define('WPF2B_EVENT_CLASS_PASSWORD', 0x00080000);
79
+ define('WPF2B_EVENT_CLASS_REST', 0x00100000); /** @since 4.1.0 */
80
+ define('WPF2B_EVENT_CLASS_SPAM', 0x00200000); /** @since 4.2.0 */
81
+ define('WPF2B_EVENT_CLASS_BLOCK', 0x00400000); /** @since 4.3.0 */
82
+ define('WPF2B_EVENT_TYPE_PLUGIN', 0x40000000); /** @since 4.2.0 */
83
+ define('WPF2B_EVENT_TYPE_TEST', 0x80000000); /** @since 4.2.0 */
84
+ define('WPF2B_EVENT_SUCCESS', 0x00000001); /** @since 4.3.0 */
85
+ define('WPF2B_EVENT_FAILURE', 0x00000002); /** @since 4.3.0 */
86
+
87
+
88
+ /**
89
+ *
90
+ */
91
+ define('WPF2B_EVENT_ACTIVATED', 0xffffffff);
92
+
93
+
94
+ /**
95
+ * Auth
96
+ */
97
+ define('WPF2B_EVENT_AUTH_OK', WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_SUCCESS);
98
+ define('WPF2B_EVENT_AUTH_FAIL', WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_FAILURE);
99
+ define('WPF2B_EVENT_AUTH_BLOCK_USER', WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_CLASS_BLOCK | WPF2B_EVENT_A);
100
+ define('WPF2B_EVENT_AUTH_BLOCK_USER_ENUM', WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_CLASS_BLOCK | WPF2B_EVENT_B);
101
+ define('WPF2B_EVENT_AUTH_EMPTY_USER', WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_FAILURE | WPF2B_EVENT_C);
102
+ define('WPF2B_EVENT_AUTH_BLOCK_USERNAME_LOGIN', WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_CLASS_BLOCK | WPF2B_EVENT_D); /** @since 4.3.0 */
103
+
104
+ /**
105
+ * Comment
106
+ */
107
+ define('WPF2B_EVENT_COMMENT', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_SUCCESS);
108
+ define('WPF2B_EVENT_COMMENT_SPAM', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_CLASS_SPAM);
109
+ // comment extra
110
+ define('WPF2B_EVENT_COMMENT_NOT_FOUND', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_FAILURE | WPF2B_EVENT_A);
111
+ define('WPF2B_EVENT_COMMENT_CLOSED', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_FAILURE | WPF2B_EVENT_B);
112
+ define('WPF2B_EVENT_COMMENT_TRASH', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_FAILURE | WPF2B_EVENT_C);
113
+ define('WPF2B_EVENT_COMMENT_DRAFT', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_FAILURE | WPF2B_EVENT_D);
114
+ define('WPF2B_EVENT_COMMENT_PASSWORD', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_CLASS_PASSWORD | WPF2B_EVENT_FAILURE | WPF2B_EVENT_E);
115
+
116
+ /**
117
+ * XML-RPC
118
+ */
119
+ define('WPF2B_EVENT_XMLRPC_PINGBACK', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_SUCCESS | WPF2B_EVENT_A);
120
+ define('WPF2B_EVENT_XMLRPC_PINGBACK_ERROR', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_FAILURE | WPF2B_EVENT_A);
121
+ define('WPF2B_EVENT_XMLRPC_MULTI_AUTH_FAIL', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_FAILURE | WPF2B_EVENT_B);
122
+ define('WPF2B_EVENT_XMLRPC_AUTH_OK', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_SUCCESS);
123
+ define('WPF2B_EVENT_XMLRPC_AUTH_FAIL', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_FAILURE);
124
+
125
+ /**
126
+ * Password
127
+ */
128
+ define('WPF2B_EVENT_PASSWORD_REQUEST', WPF2B_EVENT_CLASS_PASSWORD | WPF2B_EVENT_SUCCESS);
129
+
130
+ /**
131
+ * REST
132
+ * @since 4.1.0
133
+ */
134
+ define('WPF2B_EVENT_REST_AUTH_OK', WPF2B_EVENT_CLASS_REST | WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_SUCCESS);
135
+ define('WPF2B_EVENT_REST_AUTH_FAIL', WPF2B_EVENT_CLASS_REST | WPF2B_EVENT_CLASS_AUTH | WPF2B_EVENT_FAILURE);
136
+
137
+ /**
138
+ *
139
+ */
140
+ define('WPF2B_EVENT_DEACTIVATED', 0x00000000);
141
+
142
+
143
+ /**
144
+ * @deprecated 4.3.0
145
+ */
146
+ define('WPF2B_EVENT_AUTH_BLOCK_USER__', WPF2B_EVENT_CLASS_AUTH | 0x0004); /** @deprecated 4.3.0 */
147
+ define('WPF2B_EVENT_AUTH_BLOCK_USER_ENUM__', WPF2B_EVENT_CLASS_AUTH | 0x0008); /** @deprecated 4.3.0 */
148
+ define('WPF2B_EVENT_COMMENT_SPAM__', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_CLASS_SPAM | 0x0001); /** @deprecated 4.3.0 */
149
+ define('WPF2B_EVENT_COMMENT_NOT_FOUND__', WPF2B_EVENT_CLASS_COMMENT | 0x0002); /** @deprecated 4.3.0 */
150
+ define('WPF2B_EVENT_COMMENT_CLOSED__', WPF2B_EVENT_CLASS_COMMENT | 0x0004); /** @deprecated 4.3.0 */
151
+ define('WPF2B_EVENT_COMMENT_TRASH__', WPF2B_EVENT_CLASS_COMMENT | 0x0010); /** @deprecated 4.3.0 */
152
+ define('WPF2B_EVENT_COMMENT_DRAFT__', WPF2B_EVENT_CLASS_COMMENT | 0x0010); /** @deprecated 4.3.0 */
153
+ define('WPF2B_EVENT_COMMENT_PASSWORD__', WPF2B_EVENT_CLASS_COMMENT | WPF2B_EVENT_CLASS_PASSWORD | 0x0020); /** @deprecated 4.3.0 */
154
+ define('WPF2B_EVENT_XMLRPC_PINGBACK__', WPF2B_EVENT_CLASS_XMLRPC | 0x0001);
155
+ define('WPF2B_EVENT_XMLRPC_PINGBACK_ERROR__', WPF2B_EVENT_CLASS_XMLRPC | 0x0002);
156
+ define('WPF2B_EVENT_XMLRPC_MULTI_AUTH_FAIL__', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | 0x0004); /** @deprecated 4.3.0 */
157
+ define('WPF2B_EVENT_XMLRPC_AUTH_OK__', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | 0x0008); /** @deprecated 4.3.0 */
158
+ define('WPF2B_EVENT_XMLRPC_AUTH_FAIL__', WPF2B_EVENT_CLASS_XMLRPC | WPF2B_EVENT_CLASS_AUTH | 0x0010); /** @deprecated 4.3.0 */
159
+ // phpcs:enable
160
+ }
lib/convert-data.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Convertors
4
+ *
5
+ * @package wp-fail2ban
6
+ * @since 4.3.0
7
+ */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ defined('ABSPATH') or exit;
11
+
12
+ /**
13
+ * Convert various things to various other things.
14
+ *
15
+ * @since 4.3.0
16
+ */
17
+ abstract class ConvertData
18
+ {
19
+ /**
20
+ * @since 4.3.0
21
+ *
22
+ * @var array Map priority value to name.
23
+ */
24
+ public static $Priority2Name = [
25
+ LOG_CRIT => 'critical',
26
+ LOG_ERR => 'error',
27
+ LOG_WARNING => 'warning',
28
+ LOG_NOTICE => 'notice',
29
+ LOG_INFO => 'info',
30
+ LOG_DEBUG => 'debug'
31
+ ];
32
+
33
+ /**
34
+ * @var string[] Map Event ID to Slug.
35
+ */
36
+ public static $Event2Slug = array(
37
+ 0x00000000 => 'deactivated',
38
+ WPF2B_EVENT_AUTH_OK => 'auth_ok',
39
+ WPF2B_EVENT_AUTH_FAIL => 'auth_fail',
40
+ WPF2B_EVENT_AUTH_BLOCK_USER => 'auth_block_user',
41
+ WPF2B_EVENT_AUTH_BLOCK_USER_ENUM => 'auth_block_user_enum',
42
+ WPF2B_EVENT_AUTH_BLOCK_USERNAME_LOGIN => 'auth_block_usernames',
43
+ WPF2B_EVENT_AUTH_EMPTY_USER => 'auth_empty_user',
44
+ WPF2B_EVENT_COMMENT => 'comment',
45
+ WPF2B_EVENT_COMMENT_SPAM => 'comment_spam',
46
+ WPF2B_EVENT_COMMENT_NOT_FOUND => 'comment_not_found',
47
+ WPF2B_EVENT_COMMENT_CLOSED => 'comment_closed',
48
+ WPF2B_EVENT_COMMENT_TRASH => 'comment_trash',
49
+ WPF2B_EVENT_COMMENT_DRAFT => 'comment_draft',
50
+ WPF2B_EVENT_COMMENT_PASSWORD => 'comment_password',
51
+ WPF2B_EVENT_XMLRPC_PINGBACK => 'xmlrpc_pingback',
52
+ WPF2B_EVENT_XMLRPC_PINGBACK_ERROR => 'xmlrpc_pingback_error',
53
+ WPF2B_EVENT_XMLRPC_MULTI_AUTH_FAIL => 'xmlrpc_multi_auth_fail',
54
+ WPF2B_EVENT_XMLRPC_AUTH_OK => 'xmlrpc_auth_ok',
55
+ WPF2B_EVENT_XMLRPC_AUTH_FAIL => 'xmlrpc_auth_fail',
56
+ WPF2B_EVENT_PASSWORD_REQUEST => 'password_request',
57
+ WPF2B_EVENT_REST_AUTH_OK => 'rest_auth_ok',
58
+ WPF2B_EVENT_REST_AUTH_FAIL => 'rest_auth_fail',
59
+ 0xFFFFFFFF => 'activated',
60
+ );
61
+
62
+ /**
63
+ * @var int[] Map Event Slug to ID.
64
+ */
65
+ public static $Slug2Event = array(
66
+ 'deactivated' => 0x00000000,
67
+ 'auth_ok' => WPF2B_EVENT_AUTH_OK,
68
+ 'auth_fail' => WPF2B_EVENT_AUTH_FAIL,
69
+ 'auth_block_user' => WPF2B_EVENT_AUTH_BLOCK_USER,
70
+ 'auth_block_user_enum' => WPF2B_EVENT_AUTH_BLOCK_USER_ENUM,
71
+ 'auth_block_usernames' => WPF2B_EVENT_AUTH_BLOCK_USERNAME_LOGIN,
72
+ 'auth_empty_user' => WPF2B_EVENT_AUTH_EMPTY_USER,
73
+ 'comment_spam' => WPF2B_EVENT_COMMENT_SPAM,
74
+ 'comment_not_found' => WPF2B_EVENT_COMMENT_NOT_FOUND,
75
+ 'comment_closed' => WPF2B_EVENT_COMMENT_CLOSED,
76
+ 'comment_trash' => WPF2B_EVENT_COMMENT_TRASH,
77
+ 'comment_draft' => WPF2B_EVENT_COMMENT_DRAFT,
78
+ 'comment_password' => WPF2B_EVENT_COMMENT_PASSWORD,
79
+ 'xmlrpc_pingback' => WPF2B_EVENT_XMLRPC_PINGBACK,
80
+ 'xmlrpc_pingback_error' => WPF2B_EVENT_XMLRPC_PINGBACK_ERROR,
81
+ 'xmlrpc_multi_auth_fail' => WPF2B_EVENT_XMLRPC_MULTI_AUTH_FAIL,
82
+ 'xmlrpc_auth_ok' => WPF2B_EVENT_XMLRPC_AUTH_OK,
83
+ 'xmlrpc_auth_fail' => WPF2B_EVENT_XMLRPC_AUTH_FAIL,
84
+ 'password_request' => WPF2B_EVENT_PASSWORD_REQUEST,
85
+ 'rest_auth_ok' => WPF2B_EVENT_REST_AUTH_OK,
86
+ 'rest_auth_fail' => WPF2B_EVENT_REST_AUTH_FAIL,
87
+ 'activated' => 0xFFFFFFFF,
88
+ );
89
+
90
+ /**
91
+ * @var int[] Map syslog facility name to value.
92
+ */
93
+ public static $FacilityName2Value = array(
94
+ 'LOG_AUTH' => LOG_AUTH,
95
+ 'LOG_AUTHPRIV' => LOG_AUTHPRIV,
96
+ 'LOG_CRON' => LOG_CRON,
97
+ 'LOG_DAEMON' => LOG_DAEMON,
98
+ 'LOG_KERN' => LOG_KERN,
99
+ 'LOG_LOCAL0' => LOG_LOCAL0,
100
+ 'LOG_LOCAL1' => LOG_LOCAL1,
101
+ 'LOG_LOCAL2' => LOG_LOCAL2,
102
+ 'LOG_LOCAL3' => LOG_LOCAL3,
103
+ 'LOG_LOCAL4' => LOG_LOCAL4,
104
+ 'LOG_LOCAL5' => LOG_LOCAL5,
105
+ 'LOG_LOCAL6' => LOG_LOCAL6,
106
+ 'LOG_LOCAL7' => LOG_LOCAL7,
107
+ 'LOG_LPR' => LOG_LPR,
108
+ 'LOG_MAIL' => LOG_MAIL,
109
+ 'LOG_NEWS' => LOG_NEWS,
110
+ 'LOG_SYSLOG' => LOG_SYSLOG,
111
+ 'LOG_USER' => LOG_USER,
112
+ 'LOG_UUCP' => LOG_UUCP,
113
+ );
114
+
115
+ /**
116
+ * Convert: Syslog Priority value to slug.
117
+ *
118
+ * @since 4.3.0
119
+ *
120
+ * @param int $val Syslog priority value.
121
+ * @return string|null Syslog priority slug.
122
+ */
123
+ public static function intToSyslogPrioritySlug($val)
124
+ {
125
+ return array_value($val, self::$Priority2Name);
126
+ }
127
+
128
+ /**
129
+ * Convert: Syslog Priority value to name.
130
+ *
131
+ * @since 4.3.0
132
+ *
133
+ * @param int $val Syslog priority value.
134
+ * @return string|null Syslog priority slug.
135
+ */
136
+ public static function intToSyslogPriorityName($val)
137
+ {
138
+ return (is_null($name = self::intToSyslogPrioritySlug($val)))
139
+ ? null
140
+ : ucfirst($name);
141
+ }
142
+ }
143
+
lib/defaults.php CHANGED
@@ -1,79 +1,50 @@
1
  <?php
2
  /**
3
- * Default Constants
4
  *
5
  * @package wp-fail2ban
6
- * @since 4.2.0
7
  */
8
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
 
10
- if (!defined('ABSPATH')) {
11
- exit;
12
- }
13
 
14
  /**
15
- * Allow custom openlog options.
16
- * e.g. you may not want the PID if logging remotely.
17
  *
18
- * @since 3.6.0 Add LOG_NDELAY
19
- * @since 3.5.0
20
- */
21
- if (!defined('WP_FAIL2BAN_OPENLOG_OPTIONS')) {
22
- define('WP_FAIL2BAN_OPENLOG_OPTIONS', DEFAULT_WP_FAIL2BAN_OPENLOG_OPTIONS);
23
- }
24
- /**
25
- * Make sure all custom logs are defined.
26
- * @since 3.5.0
27
- */
28
- if (!defined('WP_FAIL2BAN_AUTH_LOG')) {
29
- define('WP_FAIL2BAN_AUTH_LOG', DEFAULT_WP_FAIL2BAN_AUTH_LOG);
30
- }
31
- if (!defined('WP_FAIL2BAN_COMMENT_LOG')) {
32
- define('WP_FAIL2BAN_COMMENT_LOG', DEFAULT_WP_FAIL2BAN_COMMENT_LOG);
33
- }
34
- if (!defined('WP_FAIL2BAN_PINGBACK_LOG')) {
35
- define('WP_FAIL2BAN_PINGBACK_LOG', DEFAULT_WP_FAIL2BAN_PINGBACK_LOG);
36
- }
37
- /**
38
- * @since 4.0.0
39
- */
40
- if (!defined('WP_FAIL2BAN_PASSWORD_REQUEST_LOG')) {
41
- define('WP_FAIL2BAN_PASSWORD_REQUEST_LOG', DEFAULT_WP_FAIL2BAN_PASSWORD_REQUEST_LOG);
42
- }
43
- if (!defined('WP_FAIL2BAN_SPAM_LOG')) {
44
- define('WP_FAIL2BAN_SPAM_LOG', DEFAULT_WP_FAIL2BAN_SPAM_LOG);
45
- }
46
- /**
47
- * @since 4.0.5
48
- */
49
- if (!defined('WP_FAIL2BAN_COMMENT_EXTRA_LOG')) {
50
- define('WP_FAIL2BAN_COMMENT_EXTRA_LOG', DEFAULT_WP_FAIL2BAN_COMMENT_EXTRA_LOG);
51
- }
52
- if (!defined('WP_FAIL2BAN_PINGBACK_ERROR_LOG')) {
53
- define('WP_FAIL2BAN_PINGBACK_ERROR_LOG', DEFAULT_WP_FAIL2BAN_PINGBACK_ERROR_LOG);
54
- }
55
- /**
56
- * @since 4.2.0
57
  */
58
- if (!defined('WP_FAIL2BAN_PLUGIN_AUTH_LOG')) {
59
- define('WP_FAIL2BAN_PLUGIN_AUTH_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_AUTH_LOG);
60
- }
61
- if (!defined('WP_FAIL2BAN_PLUGIN_COMMENT_LOG')) {
62
- define('WP_FAIL2BAN_PLUGIN_COMMENT_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_COMMENT_LOG);
63
- }
64
- if (!defined('WP_FAIL2BAN_PLUGIN_OTHER_LOG')) {
65
- define('WP_FAIL2BAN_PLUGIN_OTHER_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_OTHER_LOG);
66
- }
67
- if (!defined('WP_FAIL2BAN_PLUGIN_PASSWORD_LOG')) {
68
- define('WP_FAIL2BAN_PLUGIN_PASSWORD_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_PASSWORD_LOG);
69
- }
70
- if (!defined('WP_FAIL2BAN_PLUGIN_REST_LOG')) {
71
- define('WP_FAIL2BAN_PLUGIN_REST_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_REST_LOG);
72
- }
73
- if (!defined('WP_FAIL2BAN_PLUGIN_SPAM_LOG')) {
74
- define('WP_FAIL2BAN_PLUGIN_SPAM_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_SPAM_LOG);
75
- }
76
- if (!defined('WP_FAIL2BAN_PLUGIN_XMLRPC_LOG')) {
77
- define('WP_FAIL2BAN_PLUGIN_XMLRPC_LOG', DEFAULT_WP_FAIL2BAN_PLUGIN_XMLRPC_LOG);
 
 
 
 
 
 
 
 
 
 
78
  }
79
 
1
  <?php
2
  /**
3
+ * Defaults
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.3.0
7
  */
8
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
 
10
+ defined('ABSPATH') or exit;
 
 
11
 
12
  /**
13
+ * Define default values
 
14
  *
15
+ * @since 4.3.0 Refactored
16
+ *
17
+ * @return void
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  */
19
+ function init_defaults()
20
+ {
21
+ // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
22
+ /**
23
+ * Defaults
24
+ *
25
+ * @since 4.0.0
26
+ */
27
+ define('DEFAULT_WP_FAIL2BAN_OPENLOG_OPTIONS', LOG_PID|LOG_NDELAY);
28
+ define('DEFAULT_WP_FAIL2BAN_AUTH_LOG', LOG_AUTH);
29
+ define('DEFAULT_WP_FAIL2BAN_COMMENT_LOG', LOG_USER);
30
+ define('DEFAULT_WP_FAIL2BAN_PINGBACK_LOG', LOG_USER);
31
+ define('DEFAULT_WP_FAIL2BAN_PASSWORD_REQUEST_LOG', LOG_USER);
32
+ define('DEFAULT_WP_FAIL2BAN_SPAM_LOG', LOG_AUTH);
33
+ /**
34
+ * @since 4.0.5
35
+ */
36
+ define('DEFAULT_WP_FAIL2BAN_COMMENT_EXTRA_LOG', LOG_AUTH);
37
+ define('DEFAULT_WP_FAIL2BAN_PINGBACK_ERROR_LOG', LOG_AUTH);
38
+ /**
39
+ * @since 4.2.0
40
+ */
41
+ define('DEFAULT_WP_FAIL2BAN_PLUGIN_AUTH_LOG', LOG_AUTH);
42
+ define('DEFAULT_WP_FAIL2BAN_PLUGIN_COMMENT_LOG', LOG_USER);
43
+ define('DEFAULT_WP_FAIL2BAN_PLUGIN_OTHER_LOG', LOG_USER);
44
+ define('DEFAULT_WP_FAIL2BAN_PLUGIN_PASSWORD_LOG', LOG_USER);
45
+ define('DEFAULT_WP_FAIL2BAN_PLUGIN_REST_LOG', LOG_USER);
46
+ define('DEFAULT_WP_FAIL2BAN_PLUGIN_SPAM_LOG', LOG_AUTH);
47
+ define('DEFAULT_WP_FAIL2BAN_PLUGIN_XMLRPC_LOG', LOG_USER);
48
+ // phpcs:enable
49
  }
50
 
lib/loader.php CHANGED
@@ -1,327 +1,491 @@
1
  <?php
2
-
3
  /**
4
  * Loader
5
  *
6
  * @package wp-fail2ban
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  * @since 4.2.0
8
  */
9
- namespace {
10
- if ( !defined( 'ABSPATH' ) ) {
11
- exit;
12
- }
13
- if ( defined( 'PHPUNIT_COMPOSER_INSTALL' ) ) {
14
- return;
15
- }
16
- if ( !function_exists( 'boolval' ) ) {
17
- /**
18
- * PHP 5.3 helper
19
- *
20
- * @since 4.2.5
21
- *
22
- * @param mixed $val
23
- *
24
- * @return bool
25
- */
26
- function boolval( $val )
27
- {
28
- return (bool) $val;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  }
30
-
31
  }
32
- }
33
- namespace org\lecklider\charles\wordpress\wp_fail2ban {
34
  /**
35
- * Helper
36
- *
37
- * @since 4.0.0
38
  *
39
- * @param string $define
40
- * @param callable $cast
41
- * @param bool $unset
42
- * @param array $field
43
  */
44
- function _load(
45
- $define,
46
- $cast,
47
- $unset,
48
- array $field
49
- )
50
  {
51
- global $wp_fail2ban ;
52
- $wp_fail2ban['config'][$define] = array(
53
- 'validate' => $cast,
54
- 'unset' => $unset,
55
- 'field' => $field,
56
- 'ndef' => !defined( $define ),
57
- );
58
- if ( !defined( $define ) ) {
59
-
60
- if ( defined( "DEFAULT_{$define}" ) ) {
61
- // we've got a default
62
- define( $define, $cast( constant( "DEFAULT_{$define}" ) ) );
63
- } else {
64
- // bah
65
- define( $define, $cast( false ) );
66
  }
67
-
68
  }
69
  }
70
-
71
  /**
72
- * Validate IP list
73
  *
 
74
  * @since 4.0.0
75
  *
76
- * @param array|string $value
77
- *
78
  * @return string
79
  */
80
- function validate_ips( $value )
 
 
 
 
 
 
 
 
 
 
81
  {
82
- return $value;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
84
-
85
- // phpcs:disable Generic.Functions.FunctionCallArgumentSpacing
86
- _load(
87
- 'WP_FAIL2BAN_AUTH_LOG',
88
- 'intval',
89
- true,
90
- array( 'logging', 'authentication', 'facility' )
91
- );
92
- _load(
93
- 'WP_FAIL2BAN_LOG_COMMENTS',
94
- 'boolval',
95
- true,
96
- array( 'logging', 'comments', 'enabled' )
97
- );
98
- _load(
99
- 'WP_FAIL2BAN_LOG_COMMENTS_EXTRA',
100
- 'intval',
101
- true,
102
- array( 'logging', 'comments', 'extra' )
103
- );
104
- _load(
105
- 'WP_FAIL2BAN_COMMENT_LOG',
106
- 'intval',
107
- false,
108
- array( 'logging', 'comments', 'facility' )
109
- );
110
- _load(
111
- 'WP_FAIL2BAN_COMMENT_EXTRA_LOG',
112
- 'intval',
113
- false,
114
- array( 'logging', 'comments-extra', 'facility' )
115
- );
116
- _load(
117
- 'WP_FAIL2BAN_LOG_PASSWORD_REQUEST',
118
- 'boolval',
119
- true,
120
- array( 'logging', 'password-request', 'enabled' )
121
- );
122
- _load(
123
- 'WP_FAIL2BAN_PASSWORD_REQUEST_LOG',
124
- 'intval',
125
- false,
126
- array( 'logging', 'password-request', 'facility' )
127
- );
128
- _load(
129
- 'WP_FAIL2BAN_LOG_PINGBACKS',
130
- 'boolval',
131
- true,
132
- array( 'logging', 'pingback', 'enabled' )
133
- );
134
- _load(
135
- 'WP_FAIL2BAN_PINGBACK_LOG',
136
- 'intval',
137
- false,
138
- array( 'logging', 'pingback', 'facility' )
139
- );
140
- _load(
141
- 'WP_FAIL2BAN_LOG_SPAM',
142
- 'boolval',
143
- true,
144
- array( 'logging', 'spam', 'enabled' )
145
- );
146
- _load(
147
- 'WP_FAIL2BAN_SPAM_LOG',
148
- 'intval',
149
- false,
150
- array( 'logging', 'spam', 'facility' )
151
- );
152
- _load(
153
- 'WP_FAIL2BAN_OPENLOG_OPTIONS',
154
- 'intval',
155
- true,
156
- array( 'syslog', 'connection' )
157
- );
158
- _load(
159
- 'WP_FAIL2BAN_SYSLOG_SHORT_TAG',
160
- 'boolval',
161
- true,
162
- array( 'syslog', 'workaround', 'short_tag' )
163
- );
164
- _load(
165
- 'WP_FAIL2BAN_HTTP_HOST',
166
- 'boolval',
167
- true,
168
- array( 'syslog', 'workaround', 'http_host' )
169
- );
170
- _load(
171
- 'WP_FAIL2BAN_TRUNCATE_HOST',
172
- 'boolval',
173
- true,
174
- array( 'syslog', 'workaround', 'truncate_host' )
175
- );
176
- _load(
177
- 'WP_FAIL2BAN_BLOCK_USER_ENUMERATION',
178
- 'boolval',
179
- true,
180
- array( 'block', 'user_enumeration' )
181
- );
182
- _load(
183
- 'WP_FAIL2BAN_BLOCKED_USERS',
184
- 'strval',
185
- true,
186
- array( 'block', 'users' )
187
- );
188
- _load(
189
- 'WP_FAIL2BAN_PROXIES',
190
- __NAMESPACE__ . '\\validate_ips',
191
- true,
192
- array( 'remote-ip', 'proxies' )
193
- );
194
- _load(
195
- 'WP_FAIL2BAN_PLUGIN_LOG_AUTH',
196
- 'boolval',
197
- true,
198
- array(
199
- 'logging',
200
- 'plugins',
201
- 'auth',
202
- 'enabled'
203
- )
204
- );
205
- _load(
206
- 'WP_FAIL2BAN_PLUGIN_LOG_COMMENT',
207
- 'boolval',
208
- true,
209
- array(
210
- 'logging',
211
- 'plugins',
212
- 'comment',
213
- 'enabled'
214
- )
215
- );
216
- _load(
217
- 'WP_FAIL2BAN_PLUGIN_LOG_PASSWORD',
218
- 'boolval',
219
- true,
220
- array(
221
- 'logging',
222
- 'plugins',
223
- 'password',
224
- 'enabled'
225
- )
226
- );
227
- _load(
228
- 'WP_FAIL2BAN_PLUGIN_LOG_REST',
229
- 'boolval',
230
- true,
231
- array(
232
- 'logging',
233
- 'plugins',
234
- 'rest',
235
- 'enabled'
236
- )
237
- );
238
- _load(
239
- 'WP_FAIL2BAN_PLUGIN_LOG_SPAM',
240
- 'boolval',
241
- true,
242
- array(
243
- 'logging',
244
- 'plugins',
245
- 'spam',
246
- 'enabled'
247
- )
248
- );
249
- _load(
250
- 'WP_FAIL2BAN_PLUGIN_LOG_XMLRPC',
251
- 'boolval',
252
- true,
253
- array(
254
- 'logging',
255
- 'plugins',
256
- 'xmlrpc',
257
- 'enabled'
258
- )
259
- );
260
- _load(
261
- 'WP_FAIL2BAN_PLUGIN_AUTH_LOG',
262
- 'intval',
263
- false,
264
- array(
265
- 'logging',
266
- 'plugins',
267
- 'auth',
268
- 'facility'
269
- )
270
- );
271
- _load(
272
- 'WP_FAIL2BAN_PLUGIN_COMMENT_LOG',
273
- 'intval',
274
- false,
275
- array(
276
- 'logging',
277
- 'plugins',
278
- 'comment',
279
- 'facility'
280
- )
281
- );
282
- _load(
283
- 'WP_FAIL2BAN_PLUGIN_PASSWORD_LOG',
284
- 'intval',
285
- false,
286
- array(
287
- 'logging',
288
- 'plugins',
289
- 'password',
290
- 'facility'
291
- )
292
- );
293
- _load(
294
- 'WP_FAIL2BAN_PLUGIN_REST_LOG',
295
- 'intval',
296
- false,
297
- array(
298
- 'logging',
299
- 'plugins',
300
- 'rest',
301
- 'facility'
302
- )
303
- );
304
- _load(
305
- 'WP_FAIL2BAN_PLUGIN_SPAM_LOG',
306
- 'intval',
307
- false,
308
- array(
309
- 'logging',
310
- 'plugins',
311
- 'spam',
312
- 'facility'
313
- )
314
- );
315
- _load(
316
- 'WP_FAIL2BAN_PLUGIN_XMLRPC_LOG',
317
- 'intval',
318
- false,
319
- array(
320
- 'logging',
321
- 'plugins',
322
- 'xmlrpc',
323
- 'facility'
324
- )
325
- );
326
  // phpcs:enable
327
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
  /**
3
  * Loader
4
  *
5
  * @package wp-fail2ban
6
+ * @since 4.2.0
7
+ */
8
+ namespace org\lecklider\charles\wordpress\wp_fail2ban;
9
+
10
+ if (defined('PHPUNIT_COMPOSER_INSTALL')) {
11
+ return;
12
+
13
+ } elseif (!defined('ABSPATH')) {
14
+ exit;
15
+ }
16
+
17
+ /**
18
+ * Config
19
+ *
20
  * @since 4.2.0
21
  */
22
+ class Config
23
+ {
24
+ /**
25
+ * @var array Settings
26
+ * @since 4.3.0
27
+ */
28
+ protected static $settings = null;
29
+ /**
30
+ * @var Config Instance.
31
+ * @since 4.3.0
32
+ */
33
+ protected static $instance = null;
34
+
35
+ /**
36
+ * Construct
37
+ *
38
+ * @since 4.3.0
39
+ *
40
+ * @param array $config Existing config options
41
+ */
42
+ public static function load(array $config = [])
43
+ {
44
+ if (is_null(self::$instance)) {
45
+ global $wp_fail2ban;
46
+
47
+ init_constants();
48
+ init_defaults();
49
+
50
+ $class = get_called_class();
51
+ self::$instance = new $class();
52
+
53
+ $wp_fail2ban['config'] = apply_filters(
54
+ __METHOD__.'.config',
55
+ array_merge(
56
+ $config,
57
+ array(
58
+ 'WP_FAIL2BAN_AUTH_LOG' => array(
59
+ 'validate' => 'intval',
60
+ 'unset' => true,
61
+ 'field' => array(
62
+ 'logging',
63
+ 'authentication',
64
+ 'facility')),
65
+ 'WP_FAIL2BAN_LOG_COMMENTS' => array(
66
+ 'validate' => 'boolval',
67
+ 'unset' => true,
68
+ 'field' => array(
69
+ 'logging',
70
+ 'comments',
71
+ 'enabled')),
72
+ 'WP_FAIL2BAN_LOG_COMMENTS_EXTRA' => array(
73
+ 'validate' => 'intval',
74
+ 'unset' => true,
75
+ 'field' => array(
76
+ 'logging',
77
+ 'comments',
78
+ 'extra')),
79
+ 'WP_FAIL2BAN_COMMENT_LOG' => array(
80
+ 'validate' => 'intval',
81
+ 'unset' => false,
82
+ 'field' => array(
83
+ 'logging',
84
+ 'comments',
85
+ 'facility')),
86
+ 'WP_FAIL2BAN_COMMENT_EXTRA_LOG' => array(
87
+ 'validate' => 'intval',
88
+ 'unset' => false,
89
+ 'field' => array(
90
+ 'logging',
91
+ 'comments-extra',
92
+ 'facility')),
93
+ 'WP_FAIL2BAN_LOG_PASSWORD_REQUEST' => array(
94
+ 'validate' => 'boolval',
95
+ 'unset' => true,
96
+ 'field' => array(
97
+ 'logging',
98
+ 'password-request',
99
+ 'enabled')),
100
+ 'WP_FAIL2BAN_PASSWORD_REQUEST_LOG' => array(
101
+ 'validate' => 'intval',
102
+ 'unset' => false,
103
+ 'field' => array(
104
+ 'logging',
105
+ 'password-request',
106
+ 'facility')),
107
+ 'WP_FAIL2BAN_LOG_PINGBACKS' => array(
108
+ 'validate' => 'boolval',
109
+ 'unset' => true,
110
+ 'field' => array(
111
+ 'logging',
112
+ 'pingback',
113
+ 'enabled')),
114
+ 'WP_FAIL2BAN_PINGBACK_LOG' => array(
115
+ 'validate' => 'intval',
116
+ 'unset' => false,
117
+ 'field' => array(
118
+ 'logging',
119
+ 'pingback',
120
+ 'facility')),
121
+ 'WP_FAIL2BAN_LOG_SPAM' => array(
122
+ 'validate' => 'boolval',
123
+ 'unset' => true,
124
+ 'field' => array(
125
+ 'logging',
126
+ 'spam',
127
+ 'enabled')),
128
+ 'WP_FAIL2BAN_SPAM_LOG' => array(
129
+ 'validate' => 'intval',
130
+ 'unset' => false,
131
+ 'field' => array(
132
+ 'logging',
133
+ 'spam',
134
+ 'facility')),
135
+
136
+ /**
137
+ * syslog
138
+ */
139
+ 'WP_FAIL2BAN_OPENLOG_OPTIONS' => array(
140
+ 'validate' => 'intval',
141
+ 'unset' => true,
142
+ 'field' => array(
143
+ 'syslog',
144
+ 'connection')),
145
+ 'WP_FAIL2BAN_SYSLOG_SHORT_TAG' => array(
146
+ 'validate' => 'boolval',
147
+ 'unset' => true,
148
+ 'field' => array(
149
+ 'syslog',
150
+ 'workaround',
151
+ 'short_tag')),
152
+ 'WP_FAIL2BAN_HTTP_HOST' => array(
153
+ 'validate' => 'boolval',
154
+ 'unset' => true,
155
+ 'field' => array(
156
+ 'syslog',
157
+ 'workaround',
158
+ 'http_host')),
159
+ 'WP_FAIL2BAN_TRUNCATE_HOST' => array(
160
+ 'validate' => 'boolval',
161
+ 'unset' => true,
162
+ 'field' => array(
163
+ 'syslog',
164
+ 'workaround',
165
+ 'truncate_host')),
166
+
167
+ /**
168
+ * Block
169
+ */
170
+ 'WP_FAIL2BAN_BLOCK_USER_ENUMERATION' => array(
171
+ 'validate' => 'boolval',
172
+ 'unset' => true,
173
+ 'field' => array(
174
+ 'block',
175
+ 'user_enumeration')),
176
+ 'WP_FAIL2BAN_BLOCKED_USERS' => array(
177
+ 'validate' => 'strval',
178
+ 'unset' => true,
179
+ 'field' => array(
180
+ 'block',
181
+ 'users')),
182
+ 'WP_FAIL2BAN_BLOCK_USERNAME_LOGIN' => array(
183
+ 'validate' => 'boolval',
184
+ 'unset' => true,
185
+ 'field' => array(
186
+ 'block',
187
+ 'usernames')),
188
+
189
+ /**
190
+ * Plugins
191
+ */
192
+ 'WP_FAIL2BAN_PLUGIN_LOG_AUTH' => array(
193
+ 'validate' => 'boolval',
194
+ 'unset' => true,
195
+ 'field' => array(
196
+ 'logging',
197
+ 'plugins',
198
+ 'auth',
199
+ 'enabled')),
200
+ 'WP_FAIL2BAN_PLUGIN_LOG_COMMENT' => array(
201
+ 'validate' => 'boolval',
202
+ 'unset' => true,
203
+ 'field' => array(
204
+ 'logging',
205
+ 'plugins',
206
+ 'comment',
207
+ 'enabled')),
208
+ 'WP_FAIL2BAN_PLUGIN_LOG_PASSWORD' => array(
209
+ 'validate' => 'boolval',
210
+ 'unset' => true,
211
+ 'field' => array(
212
+ 'logging',
213
+ 'plugins',
214
+ 'password',
215
+ 'enabled')),
216
+ 'WP_FAIL2BAN_PLUGIN_LOG_REST' => array(
217
+ 'validate' => 'boolval',
218
+ 'unset' => true,
219
+ 'field' => array(
220
+ 'logging',
221
+ 'plugins',
222
+ 'rest',
223
+ 'enabled')),
224
+ 'WP_FAIL2BAN_PLUGIN_LOG_SPAM' => array(
225
+ 'validate' => 'boolval',
226
+ 'unset' => true,
227
+ 'field' => array(
228
+ 'logging',
229
+ 'plugins',
230
+ 'spam',
231
+ 'enabled')),
232
+ 'WP_FAIL2BAN_PLUGIN_LOG_XMLRPC' => array(
233
+ 'validate' => 'boolval',
234
+ 'unset' => true,
235
+ 'field' => array(
236
+ 'logging',
237
+ 'plugins',
238
+ 'xmlrpc',
239
+ 'enabled')),
240
+ 'WP_FAIL2BAN_PLUGIN_AUTH_LOG' => array(
241
+ 'validate' => 'intval',
242
+ 'unset' => false,
243
+ 'field' => array(
244
+ 'logging',
245
+ 'plugins',
246
+ 'auth',
247
+ 'facility')),
248
+ 'WP_FAIL2BAN_PLUGIN_COMMENT_LOG' => array(
249
+ 'validate' => 'intval',
250
+ 'unset' => false,
251
+ 'field' => array(
252
+ 'logging',
253
+ 'plugins',
254
+ 'comment',
255
+ 'facility')),
256
+ 'WP_FAIL2BAN_PLUGIN_PASSWORD_LOG' => array(
257
+ 'validate' => 'intval',
258
+ 'unset' => false,
259
+ 'field' => array(
260
+ 'logging',
261
+ 'plugins',
262
+ 'password',
263
+ 'facility')),
264
+ 'WP_FAIL2BAN_PLUGIN_REST_LOG' => array(
265
+ 'validate' => 'intval',
266
+ 'unset' => false,
267
+ 'field' => array(
268
+ 'logging',
269
+ 'plugins',
270
+ 'rest',
271
+ 'facility')),
272
+ 'WP_FAIL2BAN_PLUGIN_SPAM_LOG' => array(
273
+ 'validate' => 'intval',
274
+ 'unset' => false,
275
+ 'field' => array(
276
+ 'logging',
277
+ 'plugins',
278
+ 'spam',
279
+ 'facility')),
280
+ 'WP_FAIL2BAN_PLUGIN_XMLRPC_LOG' => array(
281
+ 'validate' => 'intval',
282
+ 'unset' => false,
283
+ 'field' => array(
284
+ 'logging',
285
+ 'plugins',
286
+ 'xmlrpc',
287
+ 'facility')),
288
+
289
+ 'WP_FAIL2BAN_PROXIES' => array(
290
+ 'validate' => __CLASS__.'::validate_ips',
291
+ 'unset' => true,
292
+ 'field' => array(
293
+ 'remote-ip',
294
+ 'proxies')),
295
+ )
296
+ )
297
+ );
298
+
299
+ static::init();
300
  }
 
301
  }
302
+
 
303
  /**
304
+ * Static initialiser
 
 
305
  *
306
+ * @since 4.3.0
 
 
 
307
  */
308
+ protected static function init()
 
 
 
 
 
309
  {
310
+ global $wp_fail2ban;
311
+
312
+ self::$settings = array();
313
+
314
+ foreach ($wp_fail2ban['config'] as $define => $args) {
315
+ if ($wp_fail2ban['config'][$define]['ndef'] = !defined($define)) {
316
+ if (defined("DEFAULT_{$define}")) {
317
+ define($define, $args['validate'](constant("DEFAULT_{$define}")));
318
+ } else {
319
+ // bah
320
+ define($define, call_user_func($args['validate'], false));
321
+ }
 
 
 
322
  }
 
323
  }
324
  }
325
+
326
  /**
327
+ * Validate IP list.
328
  *
329
+ * @since 4.3.0 Refactored
330
  * @since 4.0.0
331
  *
332
+ * @param array|string $value
 
333
  * @return string
334
  */
335
+ public static function validate_ips($value)
336
+ {
337
+ return self::$instance->validateIPs($value);
338
+ }
339
+
340
+ /**
341
+ * Pretend to validate IPs.
342
+ *
343
+ * @see premium\Config\validateIPs()
344
+ */
345
+ public function validateIPs($value)
346
  {
347
+ return (false === $value) ? '' : $value;
348
+ }
349
+
350
+ /**
351
+ * Helper: filtered get_site_option('wp-fail2ban')
352
+ *
353
+ * @since 4.3.0
354
+ *
355
+ * @param bool $filter
356
+ * @return array
357
+ */
358
+ public static function settings($filter = true)
359
+ {
360
+ return self::$instance->getSettings($filter);
361
+ }
362
+
363
+ /**
364
+ * Helper: filtered get_site_option('wp-fail2ban')
365
+ *
366
+ * @since 4.3.0
367
+ *
368
+ * @param bool $filter
369
+ * @return array
370
+ *
371
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
372
+ */
373
+ public function getSettings($filter = true)
374
+ {
375
+ return self::$settings;
376
+ }
377
+
378
+ // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
379
+ /**
380
+ * Helper: default value
381
+ *
382
+ * @since 4.3.0
383
+ *
384
+ * @param string $define
385
+ * @return mixed
386
+ */
387
+ public static function get_default($define)
388
+ {
389
+ $const = "DEFAULT_{$define}";
390
+
391
+ return (defined($const))
392
+ ? constant($const)
393
+ : null;
394
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
  // phpcs:enable
396
+
397
+ /**
398
+ * Help:er: is defined?
399
+ *
400
+ * @since 4.3.0
401
+ *
402
+ * @param string $define Constant name
403
+ * @return bool Is defined?
404
+ */
405
+ public static function def($define)
406
+ {
407
+ return !self::ndef($define);
408
+ }
409
+
410
+ /**
411
+ * Helper: is not defined?
412
+ *
413
+ * @since 4.3.0
414
+ *
415
+ * @param string $define Constant name
416
+ * @return bool Is not defined?
417
+ */
418
+ public static function ndef($define)
419
+ {
420
+ return self::$instance->getNdef($define);
421
+ }
422
+
423
+ public function getNdef($define)
424
+ {
425
+ global $wp_fail2ban;
426
+
427
+ return @$wp_fail2ban['config'][$define]['ndef'];
428
+ }
429
+
430
+ /**
431
+ * Helper: get value
432
+ *
433
+ * @since 4.3.0
434
+ *
435
+ * @param string $define Constant name
436
+ * @param array $settings Premium: settings to use
437
+ * @return mixed Constant value
438
+ */
439
+ public static function get($define, array $settings = null)
440
+ {
441
+ return self::$instance->getter($define, $settings);
442
+ }
443
+
444
+ /**
445
+ * Helper: get value
446
+ *
447
+ * @since 4.3.0
448
+ *
449
+ * @param string $define Constant name
450
+ * @param array $settings Premium: settings to use
451
+ * @return mixed Constant value
452
+ *
453
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
454
+ */
455
+ public function getter($define, array $settings = null)
456
+ {
457
+ return (defined($define)) ? constant($define) : null;
458
+ }
459
+
460
+ /**
461
+ * Helper: get description
462
+ *
463
+ * @since 4.3.0
464
+ *
465
+ * @param string $define Constant name.
466
+ * @return string|null Description.
467
+ */
468
+ public static function desc($define)
469
+ {
470
+ return self::$instance->getDesc($define);
471
+ }
472
+
473
+ public function getDesc($define)
474
+ {
475
+ switch ($define) {
476
+ case 'WP_FAIL2BAN_AUTH_LOG':
477
+ return __('Logins and attempted logins.', 'wp-fail2ban');
478
+ case 'WP_FAIL2BAN_LOG_SPAM':
479
+ return __('Log comments marked as spam.', 'wp-fail2ban');
480
+ case 'WP_FAIL2BAN_BLOCK_USER_ENUMERATION':
481
+ return __('Stop attackers listing existing usernames.', 'wp-fail2ban');
482
+ case 'WP_FAIL2BAN_BLOCK_USERNAME_LOGIN':
483
+ return __('Allow <b>email addresses only</b> for login.', 'wp-fail2ban');
484
+ case 'WP_FAIL2BAN_PROXIES':
485
+ return __('Trusted IPv4 list.', 'wp-fail2ban');
486
+ default:
487
+ return null;
488
+ }
489
+ }
490
+ }
491
+
readme.txt CHANGED
@@ -1,13 +1,13 @@
1
  === WP fail2ban ===
2
  Contributors: invisnet
3
  Donate link: https://paypal.me/invisnet/
4
- Author URI: https://charles.lecklider.org/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8
5
- Plugin URI: https://wp-fail2ban.com/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8
6
  Tags: fail2ban, login, security, syslog, brute force, protection, classicpress
7
  Requires at least: 4.2
8
- Tested up to: 5.4
9
- Stable tag: 4.2.8
10
- Requires PHP: 5.3
11
  License: GPLv2 or later
12
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
13
 
@@ -15,7 +15,7 @@ Write a myriad of WordPress events to syslog for integration with fail2ban.
15
 
16
  == Description ==
17
 
18
- [fail2ban](http://www.fail2ban.org/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) is one of the simplest and most effective security measures you can implement to prevent brute-force attacks.
19
 
20
  *WP fail2ban* logs all login attempts - including via XML-RPC, whether successful or not, to syslog using LOG_AUTH. For example:
21
 
@@ -26,50 +26,66 @@ Write a myriad of WordPress events to syslog for integration with fail2ban.
26
 
27
  = Features =
28
 
29
- * **NEW - Remote Tools Add-on**
30
- The Remote Tools add-on provides extra features without adding bloat to the core plugin. For more details see the [add-on page](https://wp-fail2ban.com/add-ons/remote-tools/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
31
 
32
- **NB:** Requires PHP >= 5.6
 
33
 
34
- * **NEW - Support for 3rd-party Plugins**
35
- Version 4.2 introduces a simple API for authors to integrate their plugins with *WPf2b*, with 2 *experimental* add-ons:
 
 
 
 
 
 
 
 
 
36
  * [Contact Form 7](https://wordpress.org/plugins/wp-fail2ban-addon-contact-form-7/)
37
  * [Gravity Forms](https://wordpress.org/plugins/wp-fail2ban-addon-gravity-forms/)
38
 
39
- **NB:** Requires PHP >= 5.6
40
-
41
  * **CloudFlare and Proxy Servers**
42
- *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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#wp-fail2ban-proxies).
43
 
44
  * **Comments**
45
- *WPf2b* can log comments (see [`WP_FAIL2BAN_LOG_COMMENTS`](https://docs.wp-fail2ban.com/en/4.2/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#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)).
46
 
47
  * **Pingbacks**
48
- *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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#wp-fail2ban-log-pingbacks).
49
 
50
  * **Spam**
51
- *WPf2b* can log comments marked as spam. See [`WP_FAIL2BAN_LOG_SPAM`](https://docs.wp-fail2ban.com/en/4.2/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#wp-fail2ban-log-spam).
52
 
53
  * **Block User Enumeration**
54
- *WPf2b* can block user enumeration. See [`WP_FAIL2BAN_BLOCK_USER_ENUMERATION`](https://docs.wp-fail2ban.com/en/4.2/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#wp-fail2ban-block-user-enumeration).
55
 
56
  * **Work-Arounds for Broken syslogd**
57
- *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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#wp-fail2ban-syslog-short-tag) and [`WP_FAIL2BAN_HTTP_HOST`](https://docs.wp-fail2ban.com/en/4.2/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#wp-fail2ban-http-host).
58
 
59
  * **Blocking Users**
60
- *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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#wp-fail2ban-blocked-users).
61
 
62
  * **`mu-plugins` Support**
63
- *WPf2b* can easily be configured as a must-use plugin - see [Configuration](https://docs.wp-fail2ban.com/en/4.2/configuration.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#mu-plugins-support).
64
 
65
  == Installation ==
66
 
67
  1. Install via the Plugin Directory, or upload to your plugins directory.
68
  1. Activate the plugin through the 'Plugins' menu in WordPress.
69
- 1. Edit `wp-config.php` to suit your needs - see [Configuration](https://docs.wp-fail2ban.com/en/4.2/configuration.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
70
 
71
  == Changelog ==
72
 
 
 
 
 
 
 
 
 
73
  = 4.2.8 =
74
  * Add link to new [support forum](https://forums.invis.net/c/wp-fail2ban/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
75
  * Fix user enumeration conflict with Gutenberg (h/t @dinghy).
@@ -85,7 +101,7 @@ Write a myriad of WordPress events to syslog for integration with fail2ban.
85
  * Fix buttons on Settings tabs.
86
 
87
  = 4.2.6 =
88
- * Add support for [Remote Tools](https://wp-fail2ban.com/add-ons/remote-tools/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) add-on.
89
  * Add support for the new ClassicPress security page.
90
  * Improved user enumeration blocking.
91
 
@@ -111,8 +127,8 @@ Write a myriad of WordPress events to syslog for integration with fail2ban.
111
  * Fix 5.3 compatibility.
112
 
113
  = 4.2.1 =
114
- * Completed support for [`WP_FAIL2BAN_COMMENT_EXTRA_LOG`](https://docs.wp-fail2ban.com/en/4.2/defines/WP_FAIL2BAN_COMMENT_EXTRA_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
115
- * Add support for 3rd-party plugins; see [Developers](https://docs.wp-fail2ban.com/en/4.2/developers.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
116
  * Add-on for [Contact Form 7](https://wordpress.org/plugins/wp-fail2ban-addon-contact-form-7/) (experimental).
117
  * Add-on for [Gravity Forms](https://wordpress.org/plugins/wp-fail2ban-addon-gravity-forms/) (experimental).
118
  * 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`.
@@ -124,11 +140,11 @@ Write a myriad of WordPress events to syslog for integration with fail2ban.
124
 
125
  = 4.1.0 =
126
  * Add separate logging for REST authentication.
127
- * 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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#is-wp-fail2ban-already-installed).
128
 
129
  = 4.0.5 =
130
- * Add [`WP_FAIL2BAN_COMMENT_EXTRA_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_COMMENT_EXTRA_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
131
- * Add [`WP_FAIL2BAN_PINGBACK_ERROR_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PINGBACK_ERROR_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) (future functionality).
132
  * Change `WP_FAIL2BAN_LOG_SPAM` to use `LOG_NOTICE`.
133
  * Change `WP_FAIL2BAN_SPAM_LOG` to `LOG_AUTH`.
134
  * Change `WP_FAIL2BAN_LOG_COMMENTS_EXTRA` events to use `LOG_NOTICE` by default.
@@ -142,9 +158,9 @@ Write a myriad of WordPress events to syslog for integration with fail2ban.
142
  = 4.0.1 =
143
  * Add extra features via Freemius. **This is entirely optional.** *WPf2b* works as before, including new features listed here.
144
  * Add settings summary page (Settings -> WP fail2ban).
145
- * Add [`WP_FAIL2BAN_PASSWORD_REQUEST_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PASSWORD_REQUEST_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
146
- * Add [`WP_FAIL2BAN_SPAM_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_SPAM_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
147
- * Add [`WP_FAIL2BAN_LOG_COMMENTS_EXTRA`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_COMMENTS_EXTRA.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) - enable logging for attempted comments on posts which are:
148
  * not found,
149
  * closed for commenting,
150
  * in the trash,
@@ -156,70 +172,70 @@ Write a myriad of WordPress events to syslog for integration with fail2ban.
156
  * Not released.
157
 
158
  = 3.6.0 =
159
- * The [filter files](https://docs.wp-fail2ban.com/en/4.1/filters.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) 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.
160
- * Added [PHPUnit tests](https://docs.wp-fail2ban.com/en/4.1/tests.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8). 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.
161
- * Bugfix for [`wordpress-soft.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#wordpress-soft-conf).
162
- * Add [`WP_FAIL2BAN_XMLRPC_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_XMLRPC_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
163
- * Add [`WP_FAIL2BAN_REMOTE_ADDR`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_REMOTE_ADDR.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
164
- * [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) now supports an array of IPs with PHP 7.
165
- * Moved all documentation to [https://docs.wp-fail2ban.com/](https://docs.wp-fail2ban.com/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
166
 
167
  = 3.5.3 =
168
- * Bugfix for [`wordpress-hard.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8#wordpress-hard-conf).
169
 
170
  = 3.5.1 =
171
- * Bugfix for [`WP_FAIL2BAN_BLOCK_USER_ENUMERATION`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCK_USER_ENUMERATION.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
172
 
173
  = 3.5.0 =
174
- * Add [`WP_FAIL2BAN_OPENLOG_OPTIONS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_OPENLOG_OPTIONS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
175
- * Add [`WP_FAIL2BAN_LOG_COMMENTS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_COMMENTS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) and [`WP_FAIL2BAN_COMMENT_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_COMMENT_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
176
- * Add [`WP_FAIL2BAN_LOG_PASSWORD_REQUEST`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_PASSWORD_REQUEST.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
177
- * Add [`WP_FAIL2BAN_LOG_SPAM`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_SPAM.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
178
- * Add [`WP_FAIL2BAN_TRUNCATE_HOST`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_TRUNCATE_HOST.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
179
- * [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCKED_USERS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) now supports an array of users with PHP 7.
180
 
181
  = 3.0.3 =
182
- * Fix regex in [`wordpress-hard.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html#wordpress-hard-conf?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
183
 
184
  = 3.0.2 =
185
  * Prevent double logging in WP 4.5.x for XML-RPC authentication failure
186
 
187
  = 3.0.1 =
188
- * Fix regex in [`wordpress-hard.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html#wordpress-hard-conf?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
189
 
190
  = 3.0.0 =
191
- * Add [`WP_FAIL2BAN_SYSLOG_SHORT_TAG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_SYSLOG_SHORT_TAG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
192
- * Add [`WP_FAIL2BAN_HTTP_HOST`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_HTTP_HOST.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
193
  * Log XML-RPC authentication failure.
194
  * Add better support for MU deployment.
195
 
196
  = 2.3.2 =
197
- * Bugfix [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCKED_USERS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
198
 
199
  = 2.3.0 =
200
- * Bugfix in *experimental* [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) code (thanks to KyleCartmell).
201
 
202
  = 2.2.1 =
203
- * Fix stupid mistake with [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCKED_USERS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
204
 
205
  = 2.2.0 =
206
- * Custom authentication log is now called [`WP_FAIL2BAN_AUTH_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_AUTH_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
207
- * Add logging for pingbacks; see [`WP_FAIL2BAN_LOG_PINGBACKS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_PINGBACKS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
208
- * Custom pingback log is called [`WP_FAIL2BAN_PINGBACK_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PINGBACK_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
209
 
210
  = 2.1.1 =
211
  * Minor bugfix.
212
 
213
  = 2.1.0 =
214
- * 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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
215
- * Add support for CIDR notation in [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
216
 
217
  = 2.0.1 =
218
- * Bugfix in *experimental* [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) code.
219
 
220
  = 2.0.0 =
221
- * 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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
222
- * 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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
223
 
224
  = 1.2.1 =
225
  * Update FAQ.
@@ -235,8 +251,11 @@ Write a myriad of WordPress events to syslog for integration with fail2ban.
235
 
236
  == Upgrade Notice ==
237
 
 
 
 
238
  = 4.2.8 =
239
- This is a bugfix release. You do not need to update your filters from 4.1.0. This is the *last* release that supports PHP 5.3.
240
 
241
  = 4.2.7.1 =
242
  This is a bugfix release. You do not need to update your filters from 4.1.0.
@@ -290,7 +309,7 @@ You will need up update your `fail2ban` filters.
290
  You will need up update your `fail2ban` filters.
291
 
292
  = 3.5.1 =
293
- Bugfix: disable [`WP_FAIL2BAN_BLOCK_USER_ENUMERATION`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCK_USER_ENUMERATION.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8) in admin area....
294
 
295
  = 3.5.0 =
296
  You will need up update your `fail2ban` filters.
@@ -302,13 +321,13 @@ You will need up update your `fail2ban` filters.
302
  BREAKING CHANGE: The `fail2ban` filters have been split into two files. You will need up update your `fail2ban` configuration.
303
 
304
  = 2.3.0 =
305
- Fix for [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8); if you're not using it you can safely skip this release.
306
 
307
  = 2.2.1 =
308
  Bugfix.
309
 
310
  = 2.2.0 =
311
- 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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
312
 
313
  Pingbacks are getting a lot of attention recently, so *WPf2b* can now log them.
314
  The `wordpress.conf` filter has been updated; you will need to update your `fail2ban` configuration.
@@ -321,3 +340,5 @@ Bugfix in experimental code; still an experimental release.
321
 
322
  = 2.0.0 =
323
  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.
 
 
1
  === WP fail2ban ===
2
  Contributors: invisnet
3
  Donate link: https://paypal.me/invisnet/
4
+ Author URI: https://invis.net/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0
5
+ Plugin URI: https://wp-fail2ban.com/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0
6
  Tags: fail2ban, login, security, syslog, brute force, protection, classicpress
7
  Requires at least: 4.2
8
+ Tested up to: 5.4.2
9
+ Stable tag: 4.3.0.4
10
+ Requires PHP: 5.6
11
  License: GPLv2 or later
12
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
13
 
15
 
16
  == Description ==
17
 
18
+ [fail2ban](http://www.fail2ban.org/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) is one of the simplest and most effective security measures you can implement to prevent brute-force attacks.
19
 
20
  *WP fail2ban* logs all login attempts - including via XML-RPC, whether successful or not, to syslog using LOG_AUTH. For example:
21
 
26
 
27
  = Features =
28
 
29
+ * **NEW - Multisite Support**
30
+ Version 4.3 introduces [proper support for multisite networks](https://wp-fail2ban.com/features/multisite-networks/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
31
 
32
+ * **NEW - Block username logins**
33
+ Sometimes it's not possible to block user enumeration (for example, if your theme provides Author profiles). Version 4.3 adds support for requiring the use of email addresses for login.
34
 
35
+ * **NEW - Filter for Empty Username Login Attempts**
36
+ Some bots will try to login without a username. Version 4.3 logs these attempts and provides an "extra" filter to match them.
37
+
38
+ * **NEW - syslog Dashboard Widget**
39
+ Ever wondered what's being logged? The new dashboard widget shows the last 5 messages; the Premium version keeps a full history to help you analyse and prevent attacks.
40
+
41
+ * **Remote Tools Add-on**
42
+ The Remote Tools add-on provides extra features without adding bloat to the core plugin. For more details see the [add-on page](https://wp-fail2ban.com/add-ons/remote-tools/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
43
+
44
+ * **Support for 3rd-party Plugins**
45
+ Version 4.2 introduced a simple API for authors to integrate their plugins with *WPf2b*, with 2 *experimental* add-ons:
46
  * [Contact Form 7](https://wordpress.org/plugins/wp-fail2ban-addon-contact-form-7/)
47
  * [Gravity Forms](https://wordpress.org/plugins/wp-fail2ban-addon-gravity-forms/)
48
 
 
 
49
  * **CloudFlare and Proxy Servers**
50
+ *WPf2b* can be configured to work with [CloudFlare and other proxy servers](https://wp-fail2ban.com/features/cloudflare-and-proxy-servers/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
51
 
52
  * **Comments**
53
+ *WPf2b* can log comments (see [`WP_FAIL2BAN_LOG_COMMENTS`](https://docs.wp-fail2ban.com/en/4.3/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wp-fail2ban-log-comments)) and attempted comments (see [`WP_FAIL2BAN_LOG_COMMENTS_EXTRA`](https://docs.wp-fail2ban.com/en/4.3/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wp-fail2ban-log-comments-extra)).
54
 
55
  * **Pingbacks**
56
+ *WPf2b* logs failed pingbacks, and can log all pingbacks. For an overview see [`WP_FAIL2BAN_LOG_PINGBACKS`](https://docs.wp-fail2ban.com/en/4.3/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wp-fail2ban-log-pingbacks).
57
 
58
  * **Spam**
59
+ *WPf2b* can log comments marked as spam. See [`WP_FAIL2BAN_LOG_SPAM`](https://docs.wp-fail2ban.com/en/4.3/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wp-fail2ban-log-spam).
60
 
61
  * **Block User Enumeration**
62
+ *WPf2b* can [block user enumeration](https://wp-fail2ban.com/features/block-user-enumeration/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
63
 
64
  * **Work-Arounds for Broken syslogd**
65
+ *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.3/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wp-fail2ban-syslog-short-tag) and [`WP_FAIL2BAN_HTTP_HOST`](https://docs.wp-fail2ban.com/en/4.3/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wp-fail2ban-http-host).
66
 
67
  * **Blocking Users**
68
+ *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.3/defines.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wp-fail2ban-blocked-users).
69
 
70
  * **`mu-plugins` Support**
71
+ *WPf2b* can easily be configured as a must-use plugin - see [Configuration](https://docs.wp-fail2ban.com/en/4.3/configuration.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#mu-plugins-support).
72
 
73
  == Installation ==
74
 
75
  1. Install via the Plugin Directory, or upload to your plugins directory.
76
  1. Activate the plugin through the 'Plugins' menu in WordPress.
77
+ 1. Edit `wp-config.php` to suit your needs - see [Configuration](https://docs.wp-fail2ban.com/en/4.3/configuration.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
78
 
79
  == Changelog ==
80
 
81
+ = 4.3.0.4 "Columbo" =
82
+ * Add new dashboard widget: last 5 `syslog` messages.
83
+ * Add full [multisite support](https://wp-fail2ban.com/features/multisite-networks/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
84
+ * Add [username login blocking](https://wp-fail2ban.com/features/block-username-logins/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) (force login with email).
85
+ * Add [separate logging](https://wp-fail2ban.com/features/empty-username-logging/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) for login attempts with an empty username.
86
+ * Improve [user enumeration blocking](https://wp-fail2ban.com/features/block-user-enumeration/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) compatibility with the WordPress block editor (Gutenberg).
87
+ * Bump the minimum PHP version to 5.6.
88
+
89
  = 4.2.8 =
90
  * Add link to new [support forum](https://forums.invis.net/c/wp-fail2ban/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=4.2.8).
91
  * Fix user enumeration conflict with Gutenberg (h/t @dinghy).
101
  * Fix buttons on Settings tabs.
102
 
103
  = 4.2.6 =
104
+ * Add support for [Remote Tools](https://wp-fail2ban.com/add-ons/remote-tools/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) add-on.
105
  * Add support for the new ClassicPress security page.
106
  * Improved user enumeration blocking.
107
 
127
  * Fix 5.3 compatibility.
128
 
129
  = 4.2.1 =
130
+ * Completed support for [`WP_FAIL2BAN_COMMENT_EXTRA_LOG`](https://docs.wp-fail2ban.com/en/4.2/defines/WP_FAIL2BAN_COMMENT_EXTRA_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
131
+ * Add support for 3rd-party plugins; see [Developers](https://docs.wp-fail2ban.com/en/4.2/developers.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
132
  * Add-on for [Contact Form 7](https://wordpress.org/plugins/wp-fail2ban-addon-contact-form-7/) (experimental).
133
  * Add-on for [Gravity Forms](https://wordpress.org/plugins/wp-fail2ban-addon-gravity-forms/) (experimental).
134
  * 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`.
140
 
141
  = 4.1.0 =
142
  * Add separate logging for REST authentication.
143
+ * 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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
144
 
145
  = 4.0.5 =
146
+ * Add [`WP_FAIL2BAN_COMMENT_EXTRA_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_COMMENT_EXTRA_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
147
+ * Add [`WP_FAIL2BAN_PINGBACK_ERROR_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PINGBACK_ERROR_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) (future functionality).
148
  * Change `WP_FAIL2BAN_LOG_SPAM` to use `LOG_NOTICE`.
149
  * Change `WP_FAIL2BAN_SPAM_LOG` to `LOG_AUTH`.
150
  * Change `WP_FAIL2BAN_LOG_COMMENTS_EXTRA` events to use `LOG_NOTICE` by default.
158
  = 4.0.1 =
159
  * Add extra features via Freemius. **This is entirely optional.** *WPf2b* works as before, including new features listed here.
160
  * Add settings summary page (Settings -> WP fail2ban).
161
+ * Add [`WP_FAIL2BAN_PASSWORD_REQUEST_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PASSWORD_REQUEST_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
162
+ * Add [`WP_FAIL2BAN_SPAM_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_SPAM_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
163
+ * Add [`WP_FAIL2BAN_LOG_COMMENTS_EXTRA`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_COMMENTS_EXTRA.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) - enable logging for attempted comments on posts which are:
164
  * not found,
165
  * closed for commenting,
166
  * in the trash,
172
  * Not released.
173
 
174
  = 3.6.0 =
175
+ * The [filter files](https://docs.wp-fail2ban.com/en/4.1/filters.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) 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.
176
+ * Added [PHPUnit tests](https://docs.wp-fail2ban.com/en/4.1/tests.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0). Almost 100% code coverage, with the exception of [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) which is quite hard to test properly.
177
+ * Bugfix for [`wordpress-soft.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wordpress-soft-conf).
178
+ * Add [`WP_FAIL2BAN_XMLRPC_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_XMLRPC_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
179
+ * Add [`WP_FAIL2BAN_REMOTE_ADDR`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_REMOTE_ADDR.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
180
+ * [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) now supports an array of IPs with PHP 7.
181
+ * Moved all documentation to [https://docs.wp-fail2ban.com/](https://docs.wp-fail2ban.com/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
182
 
183
  = 3.5.3 =
184
+ * Bugfix for [`wordpress-hard.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wordpress-hard-conf).
185
 
186
  = 3.5.1 =
187
+ * Bugfix for [`WP_FAIL2BAN_BLOCK_USER_ENUMERATION`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCK_USER_ENUMERATION.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
188
 
189
  = 3.5.0 =
190
+ * Add [`WP_FAIL2BAN_OPENLOG_OPTIONS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_OPENLOG_OPTIONS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
191
+ * Add [`WP_FAIL2BAN_LOG_COMMENTS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_COMMENTS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) and [`WP_FAIL2BAN_COMMENT_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_COMMENT_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
192
+ * Add [`WP_FAIL2BAN_LOG_PASSWORD_REQUEST`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_PASSWORD_REQUEST.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
193
+ * Add [`WP_FAIL2BAN_LOG_SPAM`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_SPAM.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
194
+ * Add [`WP_FAIL2BAN_TRUNCATE_HOST`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_TRUNCATE_HOST.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
195
+ * [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCKED_USERS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) now supports an array of users with PHP 7.
196
 
197
  = 3.0.3 =
198
+ * Fix regex in [`wordpress-hard.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wordpress-hard-conf).
199
 
200
  = 3.0.2 =
201
  * Prevent double logging in WP 4.5.x for XML-RPC authentication failure
202
 
203
  = 3.0.1 =
204
+ * Fix regex in [`wordpress-hard.conf`](https://docs.wp-fail2ban.com/en/4.1/filters.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0#wordpress-hard-conf).
205
 
206
  = 3.0.0 =
207
+ * Add [`WP_FAIL2BAN_SYSLOG_SHORT_TAG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_SYSLOG_SHORT_TAG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
208
+ * Add [`WP_FAIL2BAN_HTTP_HOST`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_HTTP_HOST.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
209
  * Log XML-RPC authentication failure.
210
  * Add better support for MU deployment.
211
 
212
  = 2.3.2 =
213
+ * Bugfix [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCKED_USERS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
214
 
215
  = 2.3.0 =
216
+ * Bugfix in *experimental* [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) code (thanks to KyleCartmell).
217
 
218
  = 2.2.1 =
219
+ * Fix stupid mistake with [`WP_FAIL2BAN_BLOCKED_USERS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCKED_USERS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
220
 
221
  = 2.2.0 =
222
+ * Custom authentication log is now called [`WP_FAIL2BAN_AUTH_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_AUTH_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
223
+ * Add logging for pingbacks; see [`WP_FAIL2BAN_LOG_PINGBACKS`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_LOG_PINGBACKS.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
224
+ * Custom pingback log is called [`WP_FAIL2BAN_PINGBACK_LOG`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PINGBACK_LOG.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
225
 
226
  = 2.1.1 =
227
  * Minor bugfix.
228
 
229
  = 2.1.0 =
230
+ * 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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
231
+ * Add support for CIDR notation in [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
232
 
233
  = 2.0.1 =
234
+ * Bugfix in *experimental* [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) code.
235
 
236
  = 2.0.0 =
237
+ * 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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
238
+ * 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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
239
 
240
  = 1.2.1 =
241
  * Update FAQ.
251
 
252
  == Upgrade Notice ==
253
 
254
+ = 4.3.0.4 =
255
+ To take advantage of the new features you will need up update your `fail2ban` filters; existing filters will continue to work as before. Premium users: Please backup your database before upgrading.
256
+
257
  = 4.2.8 =
258
+ This is a bugfix release. You do not need to update your filters from 4.1.0.
259
 
260
  = 4.2.7.1 =
261
  This is a bugfix release. You do not need to update your filters from 4.1.0.
309
  You will need up update your `fail2ban` filters.
310
 
311
  = 3.5.1 =
312
+ Bugfix: disable [`WP_FAIL2BAN_BLOCK_USER_ENUMERATION`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_BLOCK_USER_ENUMERATION.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0) in admin area....
313
 
314
  = 3.5.0 =
315
  You will need up update your `fail2ban` filters.
321
  BREAKING CHANGE: The `fail2ban` filters have been split into two files. You will need up update your `fail2ban` configuration.
322
 
323
  = 2.3.0 =
324
+ Fix for [`WP_FAIL2BAN_PROXIES`](https://docs.wp-fail2ban.com/en/4.1/defines/WP_FAIL2BAN_PROXIES.html?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0); if you're not using it you can safely skip this release.
325
 
326
  = 2.2.1 =
327
  Bugfix.
328
 
329
  = 2.2.0 =
330
+ 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?utm_source=wordpress.org&utm_medium=readme&utm_campaign=wp-fail2ban-4.3.0).
331
 
332
  Pingbacks are getting a lot of attention recently, so *WPf2b* can now log them.
333
  The `wordpress.conf` filter has been updated; you will need to update your `fail2ban` configuration.
340
 
341
  = 2.0.0 =
342
  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.
343
+
344
+
vendor/freemius/wordpress-sdk/assets/css/admin/add-ons.css CHANGED
@@ -1,2 +1,2 @@
1
- .fs-badge{position:absolute;top:10px;right:0;background:#71ae00;color:white;text-transform:uppercase;padding:5px 10px;-moz-border-radius:3px 0 0 3px;-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;font-weight:bold;border-right:0;-moz-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);box-shadow:0 2px 1px -1px rgba(0,0,0,0.3)}#fs_addons .fs-cards-list{list-style:none}#fs_addons .fs-cards-list .fs-card{float:left;height:152px;width:310px;padding:0;margin:0 0 30px 30px;font-size:14px;list-style:none;border:1px solid #ddd;cursor:pointer;position:relative}#fs_addons .fs-cards-list .fs-card .fs-overlay{position:absolute;left:0;right:0;bottom:0;top:0;z-index:9}#fs_addons .fs-cards-list .fs-card .fs-inner{background-color:#fff;overflow:hidden;height:100%;position:relative}#fs_addons .fs-cards-list .fs-card .fs-inner>ul{-moz-transition:all,0.15s;-o-transition:all,0.15s;-ms-transition:all,0.15s;-webkit-transition:all,0.15s;transition:all,0.15s;left:0;right:0;top:0;position:absolute}#fs_addons .fs-cards-list .fs-card .fs-inner>ul>li{list-style:none;line-height:18px;padding:0 15px;width:100%;display:block;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-card-banner{padding:0;margin:0;line-height:0;display:block;height:100px;background-repeat:repeat-x;background-size:100% 100%;-moz-transition:all,0.15s;-o-transition:all,0.15s;-ms-transition:all,0.15s;-webkit-transition:all,0.15s;transition:all,0.15s}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-card-banner .fs-badge.fs-installed-addon-badge{font-size:1.02em;line-height:1.3em}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-title{margin:10px 0 0 0;height:18px;overflow:hidden;color:#000;white-space:nowrap;text-overflow:ellipsis;font-weight:bold}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-offer{font-size:0.9em}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-description{background-color:#f9f9f9;padding:10px 15px 100px 15px;border-top:1px solid #eee;margin:0 0 10px 0;color:#777}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-tag{position:absolute;top:10px;right:0px;background:greenyellow;display:block;padding:2px 10px;-moz-box-shadow:1px 1px 1px rgba(0,0,0,0.3);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,0.3);box-shadow:1px 1px 1px rgba(0,0,0,0.3);text-transform:uppercase;font-size:0.9em;font-weight:bold}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-cta .button,#fs_addons .fs-cards-list .fs-card .fs-inner .fs-cta .button-group{position:absolute;top:112px;right:10px}@media screen and (min-width: 960px){#fs_addons .fs-cards-list .fs-card:hover .fs-overlay{border:2px solid #29abe1;margin-left:-1px;margin-top:-1px}#fs_addons .fs-cards-list .fs-card:hover .fs-inner ul{top:-100px}#fs_addons .fs-cards-list .fs-card:hover .fs-inner .fs-title,#fs_addons .fs-cards-list .fs-card:hover .fs-inner .fs-offer{color:#29abe1}}
2
- #TB_window,#TB_window iframe{width:821px !important}#plugin-information .fyi{width:266px !important}#plugin-information #section-holder{margin-right:299px}#plugin-information #section-description h2,#plugin-information #section-description h3,#plugin-information #section-description p,#plugin-information #section-description b,#plugin-information #section-description i,#plugin-information #section-description blockquote,#plugin-information #section-description li,#plugin-information #section-description ul,#plugin-information #section-description ol{clear:none}#plugin-information #section-description .fs-selling-points{padding-bottom:10px;border-bottom:1px solid #ddd}#plugin-information #section-description .fs-selling-points ul{margin:0}#plugin-information #section-description .fs-selling-points ul li{padding:0;list-style:none outside none}#plugin-information #section-description .fs-selling-points ul li i.dashicons{color:#71ae00;font-size:3em;vertical-align:middle;line-height:30px;float:left;margin:0 0 0 -15px}#plugin-information #section-description .fs-selling-points ul li h3{margin:1em 30px !important}#plugin-information #section-description .fs-screenshots:after{content:"";display:table;clear:both}#plugin-information #section-description .fs-screenshots ul{list-style:none;margin:0}#plugin-information #section-description .fs-screenshots ul li{width:225px;height:225px;float:left;margin-bottom:20px;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}#plugin-information #section-description .fs-screenshots ul li a{display:block;width:100%;height:100%;border:1px solid;-moz-box-shadow:1px 1px 1px rgba(0,0,0,0.2);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,0.2);box-shadow:1px 1px 1px rgba(0,0,0,0.2);background-size:cover}#plugin-information #section-description .fs-screenshots ul li.odd{margin-right:20px}#plugin-information .plugin-information-pricing{margin:-16px;border-bottom:1px solid #ddd}#plugin-information .plugin-information-pricing .fs-plan h3{margin-top:0;padding:20px;font-size:16px}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper{border-bottom:1px solid #ddd}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper .nav-tab{cursor:pointer;position:relative;padding:0 10px;font-size:0.9em}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper .nav-tab label{text-transform:uppercase;color:green;background:greenyellow;position:absolute;left:-1px;right:-1px;bottom:100%;border:1px solid darkgreen;padding:2px;text-align:center;font-size:0.9em;line-height:1em}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper .nav-tab.nav-tab-active{cursor:default;background:#fffeec;border-bottom-color:#fffeec}#plugin-information .plugin-information-pricing .fs-plan.fs-single-cycle h3{background:#fffeec;margin:0;padding-bottom:0;color:#0073aa}#plugin-information .plugin-information-pricing .fs-plan.fs-single-cycle .nav-tab-wrapper,#plugin-information .plugin-information-pricing .fs-plan.fs-single-cycle .fs-billing-frequency{display:none}#plugin-information .plugin-information-pricing .fs-plan .fs-pricing-body{background:#fffeec;padding:20px}#plugin-information .plugin-information-pricing .fs-plan .button{width:100%;text-align:center;font-weight:bold;text-transform:uppercase;font-size:1.1em}#plugin-information .plugin-information-pricing .fs-plan label{white-space:nowrap}#plugin-information .plugin-information-pricing .fs-plan var{font-style:normal}#plugin-information .plugin-information-pricing .fs-plan .fs-billing-frequency,#plugin-information .plugin-information-pricing .fs-plan .fs-annual-discount{text-align:center;display:block;font-weight:bold;margin-bottom:10px;text-transform:uppercase;background:#F3F3F3;padding:2px;border:1px solid #ccc}#plugin-information .plugin-information-pricing .fs-plan .fs-annual-discount{text-transform:none;color:green;background:greenyellow}#plugin-information .plugin-information-pricing .fs-plan ul.fs-trial-terms{font-size:0.9em}#plugin-information .plugin-information-pricing .fs-plan ul.fs-trial-terms i{float:left;margin:0 0 0 -15px}#plugin-information .plugin-information-pricing .fs-plan ul.fs-trial-terms li{margin:10px 0 0 0}#plugin-information #section-features .fs-features{margin:-20px -26px}#plugin-information #section-features table{width:100%;border-spacing:0;border-collapse:separate}#plugin-information #section-features table thead th{padding:10px 0}#plugin-information #section-features table thead .fs-price{color:#71ae00;font-weight:normal;display:block;text-align:center}#plugin-information #section-features table tbody td{border-top:1px solid #ccc;padding:10px 0;text-align:center;width:100px;color:#71ae00}#plugin-information #section-features table tbody td:first-child{text-align:left;width:auto;color:inherit;padding-left:26px}#plugin-information #section-features table tbody tr.fs-odd td{background:#fefefe}#plugin-information #section-features .dashicons-yes{width:30px;height:30px;font-size:30px}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .button,#plugin-information .fs-dropdown .button-group .button{position:relative;width:auto;top:0;right:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .button:focus,#plugin-information .fs-dropdown .button-group .button:focus{z-index:10}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .fs-dropdown-arrow,#plugin-information .fs-dropdown .button-group .fs-dropdown-arrow{border-top:6px solid white;border-right:4px solid transparent;border-left:4px solid transparent;top:12px;position:relative}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active:not(.up) .button:not(.fs-dropdown-arrow-button),#plugin-information .fs-dropdown.active:not(.up) .button:not(.fs-dropdown-arrow-button){border-bottom-left-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active:not(.up) .fs-dropdown-arrow-button,#plugin-information .fs-dropdown.active:not(.up) .fs-dropdown-arrow-button{border-bottom-right-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active.up .button:not(.fs-dropdown-arrow-button),#plugin-information .fs-dropdown.active.up .button:not(.fs-dropdown-arrow-button){border-top-left-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active.up .fs-dropdown-arrow-button,#plugin-information .fs-dropdown.active.up .fs-dropdown-arrow-button{border-top-right-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list,#plugin-information .fs-dropdown .fs-dropdown-list{position:absolute;right:-1px;top:100%;margin-left:auto;padding:3px 0;border:1px solid #bfbfbf;background-color:#fff;z-index:1;width:230px;text-align:left;-moz-box-shadow:0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);-webkit-box-shadow:0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);box-shadow:0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li,#plugin-information .fs-dropdown .fs-dropdown-list li{margin:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li a,#plugin-information .fs-dropdown .fs-dropdown-list li a{display:block;padding:5px 10px;text-decoration:none;text-shadow:none}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li:hover,#plugin-information .fs-dropdown .fs-dropdown-list li:hover{background-color:#0074a3;color:#fff}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li:hover a,#plugin-information .fs-dropdown .fs-dropdown-list li:hover a{color:#fff}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown:not(.up) .fs-dropdown-list,#plugin-information .fs-dropdown:not(.up) .fs-dropdown-list{-moz-border-radius:3px 0 3px 3px;-webkit-border-radius:3px 0 3px 3px;border-radius:3px 0 3px 3px}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.up .fs-dropdown-list,#plugin-information .fs-dropdown.up .fs-dropdown-list{-moz-border-radius:3px 3px 0 3px;-webkit-border-radius:3px 3px 0 3px;border-radius:3px 3px 0 3px}#plugin-information .fs-dropdown .button-group{width:100%}#plugin-information .fs-dropdown .button-group .button{float:none;font-size:14px;font-weight:normal;text-transform:none}#plugin-information .fs-dropdown .fs-dropdown-list{margin-top:1px}#plugin-information .fs-dropdown.up .fs-dropdown-list{top:auto;bottom:100%;margin-bottom:2px}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group{text-align:center;display:table}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group .button{display:table-cell}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group .button:not(.fs-dropdown-arrow-button){left:1px;width:100%}#plugin-information-footer>.button,#plugin-information-footer .fs-dropdown{position:relative;top:3px}#plugin-information-footer>.button.left,#plugin-information-footer .fs-dropdown.left{float:left}#plugin-information-footer>.right,#plugin-information-footer .fs-dropdown{float:right}@media screen and (max-width: 961px){#fs_addons .fs-cards-list .fs-card{height:265px}}
1
+ .fs-badge{position:absolute;top:10px;right:0;background:#71ae00;color:white;text-transform:uppercase;padding:5px 10px;-moz-border-radius:3px 0 0 3px;-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;font-weight:bold;border-right:0;-moz-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);box-shadow:0 2px 1px -1px rgba(0,0,0,0.3)}#fs_addons .fs-cards-list{list-style:none}#fs_addons .fs-cards-list .fs-card{float:left;height:152px;width:300px;padding:0;margin:0 0 30px 30px;font-size:14px;list-style:none;border:1px solid #ddd;cursor:pointer;position:relative}#fs_addons .fs-cards-list .fs-card .fs-overlay{position:absolute;left:0;right:0;bottom:0;top:0;z-index:9}#fs_addons .fs-cards-list .fs-card .fs-inner{background-color:#fff;overflow:hidden;height:100%;position:relative}#fs_addons .fs-cards-list .fs-card .fs-inner>ul{-moz-transition:all,0.15s;-o-transition:all,0.15s;-ms-transition:all,0.15s;-webkit-transition:all,0.15s;transition:all,0.15s;left:0;right:0;top:0;position:absolute}#fs_addons .fs-cards-list .fs-card .fs-inner>ul>li{list-style:none;line-height:18px;padding:0 15px;width:100%;display:block;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-card-banner{padding:0;margin:0;line-height:0;display:block;height:100px;background-repeat:repeat-x;background-size:100% 100%;-moz-transition:all,0.15s;-o-transition:all,0.15s;-ms-transition:all,0.15s;-webkit-transition:all,0.15s;transition:all,0.15s}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-card-banner .fs-badge.fs-installed-addon-badge{font-size:1.02em;line-height:1.3em}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-title{margin:10px 0 0 0;height:18px;overflow:hidden;color:#000;white-space:nowrap;text-overflow:ellipsis;font-weight:bold}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-offer{font-size:0.9em}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-description{background-color:#f9f9f9;padding:10px 15px 100px 15px;border-top:1px solid #eee;margin:0 0 10px 0;color:#777}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-tag{position:absolute;top:10px;right:0px;background:greenyellow;display:block;padding:2px 10px;-moz-box-shadow:1px 1px 1px rgba(0,0,0,0.3);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,0.3);box-shadow:1px 1px 1px rgba(0,0,0,0.3);text-transform:uppercase;font-size:0.9em;font-weight:bold}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-cta .button,#fs_addons .fs-cards-list .fs-card .fs-inner .fs-cta .button-group{position:absolute;top:112px;right:10px}@media screen and (min-width: 960px){#fs_addons .fs-cards-list .fs-card:hover .fs-overlay{border:2px solid #29abe1;margin-left:-1px;margin-top:-1px}#fs_addons .fs-cards-list .fs-card:hover .fs-inner ul{top:-100px}#fs_addons .fs-cards-list .fs-card:hover .fs-inner .fs-title,#fs_addons .fs-cards-list .fs-card:hover .fs-inner .fs-offer{color:#29abe1}}
2
+ #plugin-information .fyi{width:266px !important}#plugin-information #section-holder{margin-right:299px}#plugin-information #section-description h2,#plugin-information #section-description h3,#plugin-information #section-description p,#plugin-information #section-description b,#plugin-information #section-description i,#plugin-information #section-description blockquote,#plugin-information #section-description li,#plugin-information #section-description ul,#plugin-information #section-description ol{clear:none}#plugin-information #section-description .fs-selling-points{padding-bottom:10px;border-bottom:1px solid #ddd}#plugin-information #section-description .fs-selling-points ul{margin:0}#plugin-information #section-description .fs-selling-points ul li{padding:0;list-style:none outside none}#plugin-information #section-description .fs-selling-points ul li i.dashicons{color:#71ae00;font-size:3em;vertical-align:middle;line-height:30px;float:left;margin:0 0 0 -15px}#plugin-information #section-description .fs-selling-points ul li h3{margin:1em 30px !important}#plugin-information #section-description .fs-screenshots:after{content:"";display:table;clear:both}#plugin-information #section-description .fs-screenshots ul{list-style:none;margin:0}#plugin-information #section-description .fs-screenshots ul li{width:225px;height:225px;float:left;margin-bottom:20px;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}#plugin-information #section-description .fs-screenshots ul li a{display:block;width:100%;height:100%;border:1px solid;-moz-box-shadow:1px 1px 1px rgba(0,0,0,0.2);-webkit-box-shadow:1px 1px 1px rgba(0,0,0,0.2);box-shadow:1px 1px 1px rgba(0,0,0,0.2);background-size:cover}#plugin-information #section-description .fs-screenshots ul li.odd{margin-right:20px}#plugin-information .plugin-information-pricing{margin:-16px;border-bottom:1px solid #ddd}#plugin-information .plugin-information-pricing .fs-plan h3{margin-top:0;padding:20px;font-size:16px}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper{border-bottom:1px solid #ddd}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper .nav-tab{cursor:pointer;position:relative;padding:0 10px;font-size:0.9em}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper .nav-tab label{text-transform:uppercase;color:green;background:greenyellow;position:absolute;left:-1px;right:-1px;bottom:100%;border:1px solid darkgreen;padding:2px;text-align:center;font-size:0.9em;line-height:1em}#plugin-information .plugin-information-pricing .fs-plan .nav-tab-wrapper .nav-tab.nav-tab-active{cursor:default;background:#fffeec;border-bottom-color:#fffeec}#plugin-information .plugin-information-pricing .fs-plan.fs-single-cycle h3{background:#fffeec;margin:0;padding-bottom:0;color:#0073aa}#plugin-information .plugin-information-pricing .fs-plan.fs-single-cycle .nav-tab-wrapper,#plugin-information .plugin-information-pricing .fs-plan.fs-single-cycle .fs-billing-frequency{display:none}#plugin-information .plugin-information-pricing .fs-plan .fs-pricing-body{background:#fffeec;padding:20px}#plugin-information .plugin-information-pricing .fs-plan .button{width:100%;text-align:center;font-weight:bold;text-transform:uppercase;font-size:1.1em}#plugin-information .plugin-information-pricing .fs-plan label{white-space:nowrap}#plugin-information .plugin-information-pricing .fs-plan var{font-style:normal}#plugin-information .plugin-information-pricing .fs-plan .fs-billing-frequency,#plugin-information .plugin-information-pricing .fs-plan .fs-annual-discount{text-align:center;display:block;font-weight:bold;margin-bottom:10px;text-transform:uppercase;background:#F3F3F3;padding:2px;border:1px solid #ccc}#plugin-information .plugin-information-pricing .fs-plan .fs-annual-discount{text-transform:none;color:green;background:greenyellow}#plugin-information .plugin-information-pricing .fs-plan ul.fs-trial-terms{font-size:0.9em}#plugin-information .plugin-information-pricing .fs-plan ul.fs-trial-terms i{float:left;margin:0 0 0 -15px}#plugin-information .plugin-information-pricing .fs-plan ul.fs-trial-terms li{margin:10px 0 0 0}#plugin-information #section-features .fs-features{margin:-20px -26px}#plugin-information #section-features table{width:100%;border-spacing:0;border-collapse:separate}#plugin-information #section-features table thead th{padding:10px 0}#plugin-information #section-features table thead .fs-price{color:#71ae00;font-weight:normal;display:block;text-align:center}#plugin-information #section-features table tbody td{border-top:1px solid #ccc;padding:10px 0;text-align:center;width:100px;color:#71ae00}#plugin-information #section-features table tbody td:first-child{text-align:left;width:auto;color:inherit;padding-left:26px}#plugin-information #section-features table tbody tr.fs-odd td{background:#fefefe}#plugin-information #section-features .dashicons-yes{width:30px;height:30px;font-size:30px}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .button,#plugin-information .fs-dropdown .button-group .button{position:relative;width:auto;top:0;right:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .button:focus,#plugin-information .fs-dropdown .button-group .button:focus{z-index:10}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .button-group .fs-dropdown-arrow,#plugin-information .fs-dropdown .button-group .fs-dropdown-arrow{border-top:6px solid white;border-right:4px solid transparent;border-left:4px solid transparent;top:12px;position:relative}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active:not(.up) .button:not(.fs-dropdown-arrow-button),#plugin-information .fs-dropdown.active:not(.up) .button:not(.fs-dropdown-arrow-button){border-bottom-left-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active:not(.up) .fs-dropdown-arrow-button,#plugin-information .fs-dropdown.active:not(.up) .fs-dropdown-arrow-button{border-bottom-right-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active.up .button:not(.fs-dropdown-arrow-button),#plugin-information .fs-dropdown.active.up .button:not(.fs-dropdown-arrow-button){border-top-left-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.active.up .fs-dropdown-arrow-button,#plugin-information .fs-dropdown.active.up .fs-dropdown-arrow-button{border-top-right-radius:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list,#plugin-information .fs-dropdown .fs-dropdown-list{position:absolute;right:-1px;top:100%;margin-left:auto;padding:3px 0;border:1px solid #bfbfbf;background-color:#fff;z-index:1;width:230px;text-align:left;-moz-box-shadow:0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);-webkit-box-shadow:0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);box-shadow:0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li,#plugin-information .fs-dropdown .fs-dropdown-list li{margin:0}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li a,#plugin-information .fs-dropdown .fs-dropdown-list li a{display:block;padding:5px 10px;text-decoration:none;text-shadow:none}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li:hover,#plugin-information .fs-dropdown .fs-dropdown-list li:hover{background-color:#0074a3;color:#fff}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown .fs-dropdown-list li:hover a,#plugin-information .fs-dropdown .fs-dropdown-list li:hover a{color:#fff}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown:not(.up) .fs-dropdown-list,#plugin-information .fs-dropdown:not(.up) .fs-dropdown-list{-moz-border-radius:3px 0 3px 3px;-webkit-border-radius:3px 0 3px 3px;border-radius:3px 0 3px 3px}#fs_addons .fs-cards-list .fs-card .fs-inner .fs-dropdown.up .fs-dropdown-list,#plugin-information .fs-dropdown.up .fs-dropdown-list{-moz-border-radius:3px 3px 0 3px;-webkit-border-radius:3px 3px 0 3px;border-radius:3px 3px 0 3px}#plugin-information .fs-dropdown .button-group{width:100%}#plugin-information .fs-dropdown .button-group .button{float:none;font-size:14px;font-weight:normal;text-transform:none}#plugin-information .fs-dropdown .fs-dropdown-list{margin-top:1px}#plugin-information .fs-dropdown.up .fs-dropdown-list{top:auto;bottom:100%;margin-bottom:2px}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group{text-align:center;display:table}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group .button{display:table-cell}#plugin-information.wp-core-ui .fs-pricing-body .fs-dropdown .button-group .button:not(.fs-dropdown-arrow-button){left:1px;width:100%}#plugin-information-footer>.button,#plugin-information-footer .fs-dropdown{position:relative;top:3px}#plugin-information-footer>.button.left,#plugin-information-footer .fs-dropdown.left{float:left}#plugin-information-footer>.right,#plugin-information-footer .fs-dropdown{float:right}@media screen and (max-width: 961px){#fs_addons .fs-cards-list .fs-card{height:265px}}
vendor/freemius/wordpress-sdk/assets/img/wp-fail2ban.png DELETED
Binary file
vendor/freemius/wordpress-sdk/assets/scss/admin/add-ons.scss CHANGED
@@ -12,7 +12,7 @@
12
  float: left;
13
  // height: 185px; // With reviews/ratings
14
  height: 152px;
15
- width: 310px;
16
  padding: 0;
17
  margin: 0 0 30px 30px;
18
  font-size: 14px;
@@ -158,14 +158,6 @@
158
  }
159
  }
160
 
161
- #TB_window
162
- {
163
- &, iframe
164
- {
165
- width: 821px !important;
166
- }
167
- }
168
-
169
  #plugin-information
170
  {
171
  .fyi {
12
  float: left;
13
  // height: 185px; // With reviews/ratings
14
  height: 152px;
15
+ width: 300px;
16
  padding: 0;
17
  margin: 0 0 30px 30px;
18
  font-size: 14px;
158
  }
159
  }
160
 
 
 
 
 
 
 
 
 
161
  #plugin-information
162
  {
163
  .fyi {
vendor/freemius/wordpress-sdk/includes/class-freemius.php CHANGED
@@ -12733,9 +12733,7 @@
12733
  return;
12734
  }
12735
 
12736
- $installs_ids_with_foreign_licenses = $this->get_installs_ids_with_foreign_licenses();
12737
-
12738
- if ( empty( $installs_ids_with_foreign_licenses ) ) {
12739
  // Handle user change only when the parent product or one of its add-ons is activated with a foreign license.
12740
  return;
12741
  }
@@ -13326,7 +13324,7 @@
13326
 
13327
  $addon_info = $fs->_get_addon_info( $addon_id, $is_installed );
13328
 
13329
- if ( ! $addon_info['is_connected'] ) {
13330
  // Add-on is not associated with an install entity.
13331
  continue;
13332
  }
@@ -22780,10 +22778,11 @@
22780
  function get_after_plugin_activation_redirect_url() {
22781
  $url = false;
22782
 
 
 
 
 
22783
  if ( ! $this->is_addon() || ! $this->has_free_plan() ) {
22784
- $first_time_path = $this->_menu->get_first_time_path(
22785
- fs_is_network_admin() && $this->_is_network_active
22786
- );
22787
 
22788
  if ( $this->is_activation_mode() ) {
22789
  $url = $this->get_activation_url();
@@ -22809,13 +22808,18 @@
22809
  }
22810
 
22811
  if ( is_object( $plugin_fs ) ) {
22812
- if ( ! $plugin_fs->is_registered() ) {
22813
  // Forward to parent plugin connect when parent not registered.
22814
  $url = $plugin_fs->get_activation_url();
 
 
22815
  } else {
22816
  // Forward to account page.
22817
  $url = $plugin_fs->_get_admin_page_url( 'account' );
22818
  }
 
 
 
22819
  }
22820
  }
22821
 
12733
  return;
12734
  }
12735
 
12736
+ if ( empty( $this->get_installs_ids_with_foreign_licenses() ) ) {
 
 
12737
  // Handle user change only when the parent product or one of its add-ons is activated with a foreign license.
12738
  return;
12739
  }
13324
 
13325
  $addon_info = $fs->_get_addon_info( $addon_id, $is_installed );
13326
 
13327
+ if ( ! isset( $addon_info['is_connected'] ) || ! $addon_info['is_connected'] ) {
13328
  // Add-on is not associated with an install entity.
13329
  continue;
13330
  }
22778
  function get_after_plugin_activation_redirect_url() {
22779
  $url = false;
22780
 
22781
+ $first_time_path = $this->_menu->get_first_time_path(
22782
+ fs_is_network_admin() && $this->_is_network_active
22783
+ );
22784
+
22785
  if ( ! $this->is_addon() || ! $this->has_free_plan() ) {
 
 
 
22786
 
22787
  if ( $this->is_activation_mode() ) {
22788
  $url = $this->get_activation_url();
22808
  }
22809
 
22810
  if ( is_object( $plugin_fs ) ) {
22811
+ if ( ! $plugin_fs->is_anonymous() && ! $plugin_fs->is_registered() ) {
22812
  // Forward to parent plugin connect when parent not registered.
22813
  $url = $plugin_fs->get_activation_url();
22814
+ } else if ( ! empty( $first_time_path ) ) {
22815
+ $url = $first_time_path;
22816
  } else {
22817
  // Forward to account page.
22818
  $url = $plugin_fs->_get_admin_page_url( 'account' );
22819
  }
22820
+ } else if ( ! empty( $first_time_path ) ) {
22821
+ // not sure how we'd get here, but just in case...
22822
+ $url = $first_time_path;
22823
  }
22824
  }
22825
 
vendor/freemius/wordpress-sdk/includes/fs-plugin-info-dialog.php CHANGED
@@ -150,13 +150,12 @@
150
  foreach ( $pricing as $prices ) {
151
  $prices = new FS_Pricing( $prices );
152
 
153
- if ( ! $prices->is_usd() ) {
154
- /**
155
- * Skip non-USD pricing.
156
- *
157
- * @author Leo Fajardo (@leorw)
158
- * @since 2.3.1
159
- */
160
  continue;
161
  }
162
 
@@ -415,7 +414,7 @@
415
  $price_tag = $pricing->lifetime_price;
416
  }
417
 
418
- return '$' . $price_tag;
419
  }
420
 
421
  /**
@@ -1182,7 +1181,7 @@
1182
  }
1183
 
1184
  if (!multipleLicenses && 1 == pricing.licenses) {
1185
- return '$' + pricing.price + priceCycle;
1186
  }
1187
 
1188
  return _formatLicensesTitle(pricing) + ' - <var class="fs-price">$' + pricing.price + priceCycle + '</var>';
@@ -1470,7 +1469,7 @@
1470
  <?php } ?>
1471
  <?php } ?>
1472
  </div>
1473
- <div id="section-holder" class="wrap">
1474
  <?php
1475
  if ( ! empty( $api->tested ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->tested ) ), $api->tested, '>' ) ) {
1476
  echo '<div class="notice notice-warning"><p>' . '<strong>' . fs_text_inline( 'Warning', 'warning', $api->slug ) . ':</strong> ' . fs_text_inline( 'This plugin has not been tested with your current version of WordPress.', 'not-tested-warning', $api->slug ) . '</p></div>';
150
  foreach ( $pricing as $prices ) {
151
  $prices = new FS_Pricing( $prices );
152
 
153
+ /**
154
+ * Force GBP prices
155
+ *
156
+ * @author @invisnet
157
+ */
158
+ if ('gbp' != $prices->currency) {
 
159
  continue;
160
  }
161
 
414
  $price_tag = $pricing->lifetime_price;
415
  }
416
 
417
+ return '&pound;' . $price_tag;
418
  }
419
 
420
  /**
1181
  }
1182
 
1183
  if (!multipleLicenses && 1 == pricing.licenses) {
1184
+ return '&pound;' + pricing.price + priceCycle;
1185
  }
1186
 
1187
  return _formatLicensesTitle(pricing) + ' - <var class="fs-price">$' + pricing.price + priceCycle + '</var>';
1469
  <?php } ?>
1470
  <?php } ?>
1471
  </div>
1472
+ <div id="section-holder">
1473
  <?php
1474
  if ( ! empty( $api->tested ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->tested ) ), $api->tested, '>' ) ) {
1475
  echo '<div class="notice notice-warning"><p>' . '<strong>' . fs_text_inline( 'Warning', 'warning', $api->slug ) . ':</strong> ' . fs_text_inline( 'This plugin has not been tested with your current version of WordPress.', 'not-tested-warning', $api->slug ) . '</p></div>';
vendor/freemius/wordpress-sdk/templates/add-ons.php CHANGED
@@ -149,13 +149,12 @@
149
  foreach ( $plan->pricing as $pricing ) {
150
  $pricing = new FS_Pricing( $pricing );
151
 
152
- if ( ! $pricing->is_usd() ) {
153
- /**
154
- * Skip non-USD pricing.
155
- *
156
- * @author Leo Fajardo (@leorw)
157
- * @since 2.3.1
158
- */
159
  continue;
160
  }
161
 
@@ -245,7 +244,7 @@
245
  if ($has_free_plan)
246
  $descriptors[] = fs_text_inline( 'Free', 'free', $slug );
247
  if ($has_paid_plan && $price > 0)
248
- $descriptors[] = '$' . number_format( $price, 2 );
249
  if ($has_trial)
250
  $descriptors[] = fs_text_x_inline( 'Trial', 'trial period', 'trial', $slug );
251
 
149
  foreach ( $plan->pricing as $pricing ) {
150
  $pricing = new FS_Pricing( $pricing );
151
 
152
+ /**
153
+ * Force GBP pricing
154
+ *
155
+ * @author @invisnet
156
+ */
157
+ if ('gbp' != $pricing->currency) {
 
158
  continue;
159
  }
160
 
244
  if ($has_free_plan)
245
  $descriptors[] = fs_text_inline( 'Free', 'free', $slug );
246
  if ($has_paid_plan && $price > 0)
247
+ $descriptors[] = '&pound;' . number_format( $price, 2 );
248
  if ($has_trial)
249
  $descriptors[] = fs_text_x_inline( 'Trial', 'trial period', 'trial', $slug );
250
 
wp-fail2ban-main.php DELETED
@@ -1,297 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * WP fail2ban main file
5
- *
6
- * @since 4.0.0
7
- * @package wp-fail2ban
8
- */
9
- namespace org\lecklider\charles\wordpress\wp_fail2ban;
10
-
11
- if ( !defined( 'ABSPATH' ) ) {
12
- exit;
13
- }
14
- require_once __DIR__ . '/lib/constants.php';
15
- require_once __DIR__ . '/lib/loader.php';
16
- require_once __DIR__ . '/lib/defaults.php';
17
- register_activation_hook( WP_FAIL2BAN_FILE, function () {
18
- foreach ( get_mu_plugins() as $plugin => $data ) {
19
-
20
- if ( 0 === strpos( $data['Name'], 'WP fail2ban' ) ) {
21
- $wp_f2b_ver = substr( WP_FAIL2BAN_VER, 0, strrpos( WP_FAIL2BAN_VER, '.' ) );
22
- $wpf2b = 'WP fail2ban';
23
- $error_msg = sprintf( __( '<h1>Cannot activate %s</h1>' ), $wpf2b );
24
- $mu_file = WPMU_PLUGIN_DIR . '/' . $plugin;
25
-
26
- if ( is_link( $mu_file ) ) {
27
-
28
- if ( false === ($link = readlink( $mu_file )) || false === ($path = realpath( $mu_file )) ) {
29
- $h3 = __( 'A broken symbolic link was found in <tt>mu-plugins</tt>:' );
30
- $error_msg .= <<<__ERROR__
31
- <h3>{$h3}</h3>
32
- <p><tt>{$mu_file}</tt></p>
33
- __ERROR__;
34
- } elseif ( WP_FAIL2BAN_FILE == $path ) {
35
- // OK, we're linking to ourself
36
- } else {
37
- $mu_file = str_replace( '/', '/<wbr>', $mu_file );
38
- $mu_file = substr( $mu_file, strlen( WPMU_PLUGIN_DIR ) - 1 );
39
- $h3 = __( 'A conflicting symbolic link was found in <tt>mu-plugins</tt>:' );
40
- $error_msg .= <<<__ERROR__
41
- <h3>{$h3}</h3>
42
- <style>
43
- table { text-align: center; }
44
- td { width: 50%; }
45
- th { font-size: 200%; }
46
- td, th { font-family: monospace; }
47
- span.tt { font-weight: bold; }
48
- </style>
49
- <table>
50
- <tr>
51
- <td>{$mu_file}</td>
52
- <th>&DoubleRightArrow;</th>
53
- <td>{$link}</td>
54
- </tr>
55
- <tr>
56
- <td colspan="3"><span class="tt">&equiv;</span> <span>{$path}</span></td>
57
- </tr>
58
- <tr>
59
- <td colspan="3"></td>
60
- </tr>
61
- </table>
62
- __ERROR__;
63
- }
64
-
65
- } else {
66
- $mu_file = str_replace( '/', '/<wbr>', $mu_file );
67
- $mu_file = substr( $mu_file, strlen( WPMU_PLUGIN_DIR ) - 1 );
68
- $h3 = __( 'A conflicting file was found in <tt>mu-plugins</tt>:' );
69
- $error_msg .= <<<__ERROR__
70
- <h3>{$h3}</h3>
71
- <p><tt>{$mu_file}</tt></p>
72
- __ERROR__;
73
- }
74
-
75
- $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 );
76
- $error_msg .= sprintf( __( '<p>Click <a href="%s">here</a> to return to the plugins page.</p>' ), admin_url( 'plugins.php' ) );
77
- deactivate_plugins( plugin_basename( WP_FAIL2BAN_FILE ) );
78
- wp_die( $error_msg );
79
- }
80
-
81
- }
82
- } );
83
- /**
84
- * @since 4.2.8
85
- */
86
- if ( !function_exists( __NAMESPACE__ . '\\release_notes_message' ) ) {
87
- /**
88
- * CTA for release notes
89
- *
90
- * @since 4.2.8
91
- *
92
- * @param string $link Link to release notes page or tab
93
- */
94
- function release_notes_message( $link )
95
- {
96
-
97
- if ( !defined( 'PHPUNIT_COMPOSER_INSTALL' ) ) {
98
- $msg = sprintf( ' - please check the <a href="%s">release notes</a>.', $link );
99
- add_action( 'init', function () use( $msg ) {
100
- if ( current_user_can( 'manage_options' ) ) {
101
-
102
- if ( isset( $_GET['wp-fail2ban-notice'] ) || false === ($notice = get_site_option( 'wp-fail2ban-notice' )) || !isset( $notice['4.2.8'] ) || false === $notice['4.2.8'] ) {
103
- wf_fs()->add_sticky_admin_message(
104
- $msg,
105
- 'wpf2b-4.2.8',
106
- 'Important news',
107
- 'info'
108
- );
109
- update_site_option( 'wp-fail2ban-notice', array(
110
- '4.2.8' => true,
111
- ) );
112
- }
113
-
114
- }
115
- } );
116
- }
117
-
118
- }
119
-
120
- }
121
- require __DIR__ . '/feature/lib.php';
122
- /**
123
- * @since 4.2.5
124
- */
125
-
126
- if ( version_compare( PHP_VERSION, '5.6.0', '>=' ) ) {
127
- /**
128
- * @since 4.2.0
129
- */
130
- global $wp_fail2ban ;
131
- $wp_fail2ban['plugins'] = array();
132
- require __DIR__ . '/feature/plugins.php';
133
-
134
- if ( is_admin() ) {
135
- $page = ( wf_fs()->is_free_plan() ? 'wp-fail2ban' : 'wpf2b-settings&tab=about' );
136
- release_notes_message( admin_url( 'admin.php?page=' . $page ) );
137
- require 'admin/admin.php';
138
- }
139
-
140
- } elseif ( is_admin() ) {
141
- release_notes_message( admin_url( 'admin.php?page=wp-fail2ban' ) );
142
- require __DIR__ . '/admin/lib/about.php';
143
- add_action( 'admin_menu', function () {
144
- add_menu_page(
145
- 'WP fail2ban',
146
- 'WP fail2ban',
147
- 'manage_options',
148
- 'wp-fail2ban',
149
- __NAMESPACE__ . '\\about',
150
- 'dashicons-analytics'
151
- );
152
- } );
153
- }
154
-
155
- /**
156
- * @since 4.0.5
157
- */
158
-
159
- if ( !function_exists( __NAMESPACE__ . '\\wp_login' ) ) {
160
- /**
161
- * Hook: wp_login
162
- *
163
- * @since 4.1.0 Add REST support
164
- * @since 3.5.0 Refactored for unit testing
165
- * @since 1.0.0
166
- *
167
- * @param string $user_login
168
- * @param mixed $user
169
- */
170
- function wp_login( $user_login, $user )
171
- {
172
- global $wp_xmlrpc_server ;
173
- openlog();
174
- syslog( LOG_INFO, "Accepted password for {$user_login}" );
175
- closelog();
176
- // @codeCoverageIgnoreEnd
177
- }
178
-
179
- add_action(
180
- 'wp_login',
181
- __NAMESPACE__ . '\\wp_login',
182
- 10,
183
- 2
184
- );
185
- }
186
-
187
- /**
188
- * @since 4.0.5
189
- */
190
-
191
- if ( !function_exists( __NAMESPACE__ . '\\wp_login_failed' ) ) {
192
- /**
193
- * Hook: wp_login_failed
194
- *
195
- * @since 4.2.4 Add message filter
196
- * @since 4.2.0 Change username check
197
- * @since 4.1.0 Add REST support
198
- * @since 3.5.0 Refactored for unit testing
199
- * @since 1.0.0
200
- *
201
- * @param string $username
202
- *
203
- * @wp-f2b-hard Authentication attempt for unknown user .*
204
- * @wp-f2b-hard REST authentication attempt for unknown user .*
205
- * @wp-f2b-hard XML-RPC authentication attempt for unknown user .*
206
- * @wp-f2b-soft Authentication failure for .*
207
- * @wp-f2b-soft REST authentication failure for .*
208
- * @wp-f2b-soft XML-RPC authentication failure for .*
209
- */
210
- function wp_login_failed( $username )
211
- {
212
- global $wp_xmlrpc_server ;
213
-
214
- if ( defined( 'REST_REQUEST' ) ) {
215
- $msg = 'REST a';
216
- $filter = '::REST';
217
- } elseif ( $wp_xmlrpc_server ) {
218
- $msg = 'XML-RPC a';
219
- $filter = '::XML-RPC';
220
- } else {
221
- $msg = 'A';
222
- $filter = '';
223
- }
224
-
225
- $username = trim( $username );
226
- $msg .= ( wp_cache_get( $username, 'useremail' ) || wp_cache_get( sanitize_user( $username ), 'userlogins' ) ? "uthentication failure for {$username}" : "uthentication attempt for unknown user {$username}" );
227
- $msg = apply_filters( "wp_fail2ban::wp_login_failed{$filter}", $msg );
228
- openlog();
229
- syslog( LOG_NOTICE, $msg );
230
- closelog();
231
- // @codeCoverageIgnoreEnd
232
- }
233
-
234
- add_action( 'wp_login_failed', __NAMESPACE__ . '\\wp_login_failed' );
235
- }
236
-
237
- /**
238
- * @since 4.2.5
239
- */
240
-
241
- if ( !is_admin() ) {
242
- /**
243
- * User enumeration
244
- *
245
- * @since 4.0.0 Refactored
246
- * @since 2.1.0
247
- */
248
- if ( defined( 'WP_FAIL2BAN_BLOCK_USER_ENUMERATION' ) && true === WP_FAIL2BAN_BLOCK_USER_ENUMERATION ) {
249
- require_once __DIR__ . '/feature/user-enum.php';
250
- }
251
- /**
252
- * XML-RPC
253
- *
254
- * @since 4.0.0 Refactored
255
- * @since 3.0.0
256
- */
257
- if ( defined( 'XMLRPC_REQUEST' ) && true === XMLRPC_REQUEST ) {
258
- require_once __DIR__ . '/feature/xmlrpc.php';
259
- }
260
- }
261
-
262
- /**
263
- * Comments
264
- *
265
- * @since 4.0.0 Refactored
266
- * @since 3.5.0
267
- */
268
- if ( defined( 'WP_FAIL2BAN_LOG_COMMENTS' ) && true === WP_FAIL2BAN_LOG_COMMENTS ) {
269
- require_once __DIR__ . '/feature/comments.php';
270
- }
271
- /**
272
- * Password
273
- *
274
- * @since 4.0.0 Refactored
275
- * @since 3.5.0
276
- */
277
- if ( defined( 'WP_FAIL2BAN_LOG_PASSWORD_REQUEST' ) && true === WP_FAIL2BAN_LOG_PASSWORD_REQUEST ) {
278
- require_once __DIR__ . '/feature/password.php';
279
- }
280
- /**
281
- * Spam
282
- *
283
- * @since 4.0.0 Refactored
284
- * @since 3.5.0
285
- */
286
- if ( defined( 'WP_FAIL2BAN_LOG_SPAM' ) && true === WP_FAIL2BAN_LOG_SPAM ) {
287
- require_once __DIR__ . '/feature/spam.php';
288
- }
289
- /**
290
- * Users
291
- *
292
- * @since 4.0.0 Refactored
293
- * @since 2.0.0
294
- */
295
- if ( defined( 'WP_FAIL2BAN_BLOCKED_USERS' ) && '' < WP_FAIL2BAN_BLOCKED_USERS ) {
296
- require_once __DIR__ . '/feature/user.php';
297
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
wp-fail2ban.php CHANGED
@@ -1,20 +1,21 @@
1
  <?php
2
-
3
  /*
4
  * Plugin Name: WP fail2ban
5
  * Plugin URI: https://wp-fail2ban.com/
6
  * Description: Write a myriad of WordPress events to syslog for integration with fail2ban.
7
  * Text Domain: wp-fail2ban
8
- * Version: 4.2.8
9
  * Author: Charles Lecklider
10
  * Author URI: https://charles.lecklider.org/
11
  * License: GPLv2
12
  * SPDX-License-Identifier: GPL-2.0
13
- * Requires PHP: 5.3
 
14
  *
15
- */
 
16
  /*
17
- * Copyright 2012-19 Charles Lecklider (email : wordpress@charles.lecklider.org)
18
  *
19
  * This program is free software; you can redistribute it and/or modify
20
  * it under the terms of the GNU General Public License, version 2, as
@@ -29,97 +30,18 @@
29
  * along with this program; if not, write to the Free Software
30
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31
  */
 
32
  /**
33
  * WP fail2ban
34
  *
35
- * @package wp-fail2ban
36
  */
37
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
38
 
39
- /**
40
- * @since 4.0.5
41
- */
42
- define( 'WP_FAIL2BAN_VER', '4.2.8' );
43
- define( 'WP_FAIL2BAN_FILE', __FILE__ );
 
44
 
45
- if ( defined( 'ABSPATH' ) ) {
46
- /**
47
- * Freemius integration
48
- *
49
- * @since 4.0.0
50
- */
51
-
52
- if ( function_exists( __NAMESPACE__ . '\\wf_fs' ) ) {
53
- // @codeCoverageIgnoreStart
54
- wf_fs()->set_basename( false, __FILE__ );
55
- return;
56
- } else {
57
- /**
58
- * Create a helper function for easy SDK access.
59
- */
60
- function wf_fs()
61
- {
62
- global $wf_fs ;
63
-
64
- if ( !isset( $wf_fs ) ) {
65
- // Include Freemius SDK.
66
- require_once dirname( __FILE__ ) . '/vendor/freemius/wordpress-sdk/start.php';
67
- $wf_fs = fs_dynamic_init( array(
68
- 'id' => '3072',
69
- 'slug' => 'wp-fail2ban',
70
- 'type' => 'plugin',
71
- 'public_key' => 'pk_146d2c2a5bee3b157e43501ef8682',
72
- 'is_premium' => false,
73
- 'has_addons' => true,
74
- 'has_paid_plans' => true,
75
- 'trial' => array(
76
- 'days' => 14,
77
- 'is_require_payment' => false,
78
- ),
79
- 'menu' => array(
80
- 'slug' => 'wp-fail2ban',
81
- 'first-path' => 'admin.php?page=wp-fail2ban',
82
- 'support' => true,
83
- ),
84
- 'is_live' => true,
85
- ) );
86
- }
87
-
88
- return $wf_fs;
89
- }
90
-
91
- // Init Freemius.
92
- wf_fs();
93
- // Set currency to GBP
94
- wf_fs()->add_filter( 'default_currency', function () {
95
- return 'gbp';
96
- } );
97
- // Set forum URL
98
- wf_fs()->add_filter( 'support_forum_url', function () {
99
- if ( wf_fs()->is_trial() ) {
100
- /** Trial forum: Invite-only */
101
- return 'https://forums.invis.net/c/wp-fail2ban-premium/support-trial/';
102
- }
103
- if ( wf_fs()->is_free_plan() ) {
104
- /** Free forum: available to all */
105
- return 'https://forums.invis.net/c/wp-fail2ban/support-free/';
106
- }
107
- if ( wf_fs()->is_paying() ) {
108
- /** Paying forum: Invite-only */
109
- return 'https://forums.invis.net/c/wp-fail2ban-premium/support-premium/';
110
- }
111
- /** Just in case... */
112
- return 'https://forums.invis.net/c/wp-fail2ban/';
113
- } );
114
- // Signal that SDK was initiated.
115
- do_action( 'wf_fs_loaded' );
116
- }
117
-
118
- // @codeCoverageIgnoreEnd
119
- /**
120
- * Freemius insists on mangling the formatting of the main plugin file
121
- *
122
- * @since 4.0.0 Refactored
123
- */
124
- require_once 'wp-fail2ban-main.php';
125
- }
1
  <?php
 
2
  /*
3
  * Plugin Name: WP fail2ban
4
  * Plugin URI: https://wp-fail2ban.com/
5
  * Description: Write a myriad of WordPress events to syslog for integration with fail2ban.
6
  * Text Domain: wp-fail2ban
7
+ * Version: 4.3.0.4
8
  * Author: Charles Lecklider
9
  * Author URI: https://charles.lecklider.org/
10
  * License: GPLv2
11
  * SPDX-License-Identifier: GPL-2.0
12
+ * Requires PHP: 5.6
13
+ * Network: true
14
  *
15
+ */
16
+
17
  /*
18
+ * Copyright 2012-20 Charles Lecklider (email : wordpress@charles.lecklider.org)
19
  *
20
  * This program is free software; you can redistribute it and/or modify
21
  * it under the terms of the GNU General Public License, version 2, as
30
  * along with this program; if not, write to the Free Software
31
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32
  */
33
+
34
  /**
35
  * WP fail2ban
36
  *
37
+ * @package wp-fail2ban
38
  */
39
  namespace org\lecklider\charles\wordpress\wp_fail2ban;
40
 
41
+ // @codeCoverageIgnoreStart
42
+
43
+ defined('ABSPATH') or exit;
44
+
45
+ require_once 'constants.php';
46
+ require_once 'freemius.php';
47