All In One WP Security & Firewall - Version 4.4.11

Version Description

  • 29/March/2022 =

  • FEATURE: Reset all settings by clicking on the "Reset Settings" button on the Settings Page.

  • FEATURE: Verify the Google reCaptcha Site key before rendering and disable it if the Google reCaptcha site key is invalid.

  • FIX: PHP Fatal error: Cannot redeclare wp_install_maybe_enable_pretty_permalinks() in specific server.

  • FIX: throwing database error for creating debug log table in specific MySQL server.

  • FIX: Compatibility issue with WPML plugin for login and logout functionality.

  • FIX: Update email sent in English instead of setting language.

  • FIX: The Simple Math Captcha can't be validated when a third-party plugin clears transients more frequently.

  • FIX: The login lockdown unlock request was not working in a few specific server environments.

  • FIX: The warning headers already sent was displayed in a few specific server environments.

  • FIX: Handle invalid tabs appropriately in setting pages.

  • TWEAK: Add review notice.

  • TWEAK: Improve functionality of fake google bot prevents to access the site.

  • TWEAK: Remove IP address retrieval setting and detect IP address automatically.

  • TWEAK: Verify Google reCaptcha site key before rendering the reCaptcha.

  • TWEAK: Remove force logout checking from REST API Call.

  • TWEAK: Made Admin Dashboard > WP Security > Settings tabs extensible.

  • TWEAK: Add G2 review message in the admin footer.

  • TWEAK: Format failed login date time according to WordPress general settings.

  • TWEAK: Remove unused codes from AIOWPSecurity_Config.

  • TWEAK: Add more specific instructions to change the Display name compared to the username in Admin Dashboard > WP Security > User Accounts > "Display Name" tab > "Modify Accounts With Identical Login Name & Display Name" section.

  • TWEAK: Remove Admin Dashboard > WP Security > Site Info tab (now redundant because of WP's "Site Health" tool)

  • TWEAK: The "Allow Login Lockout Request" checkbox is ticked by default.

  • FIX: Fix login lockout issue with different timezone.

Download this release

Release Info

Developer DavidAnderson
Plugin Icon 128x128 All In One WP Security & Firewall
Version 4.4.11
Comparing to
See all releases

Code changes from version 4.4.10 to 4.4.11

Files changed (69) hide show
  1. admin/wp-security-admin-init.php +111 -6
  2. admin/wp-security-admin-menu.php +19 -0
  3. admin/wp-security-blacklist-menu.php +17 -18
  4. admin/wp-security-brute-force-menu.php +8 -8
  5. admin/wp-security-dashboard-menu.php +8 -153
  6. admin/wp-security-database-menu.php +0 -7
  7. admin/wp-security-filescan-menu.php +0 -7
  8. admin/wp-security-filesystem-menu.php +0 -7
  9. admin/wp-security-firewall-menu.php +15 -16
  10. admin/wp-security-list-login-fails.php +12 -1
  11. admin/wp-security-list-registered-users.php +2 -2
  12. admin/wp-security-maintenance-menu.php +0 -7
  13. admin/wp-security-misc-options-menu.php +0 -7
  14. admin/wp-security-reset-settings.php +81 -0
  15. admin/wp-security-settings-menu.php +270 -287
  16. admin/wp-security-spam-menu.php +1 -8
  17. admin/wp-security-user-accounts-menu.php +2 -9
  18. admin/wp-security-user-login-menu.php +1 -8
  19. admin/wp-security-user-registration-menu.php +0 -7
  20. classes/grade-system/wp-security-feature-item-manager.php +721 -873
  21. classes/grade-system/wp-security-feature-item.php +35 -37
  22. classes/index.php +0 -1
  23. classes/updraft-notices.php +198 -0
  24. classes/wp-security-backup.php +336 -365
  25. classes/wp-security-blocking.php +106 -107
  26. classes/wp-security-bot-protection.php +47 -44
  27. classes/wp-security-captcha.php +244 -225
  28. classes/wp-security-config.php +71 -53
  29. classes/wp-security-configure-settings.php +363 -371
  30. classes/wp-security-cronjob-handler.php +3 -7
  31. classes/wp-security-deactivation-tasks.php +51 -52
  32. classes/wp-security-debug-logger.php +129 -115
  33. classes/wp-security-file-scan.php +337 -363
  34. classes/wp-security-general-init-tasks.php +652 -645
  35. classes/wp-security-installer.php +238 -238
  36. classes/wp-security-notices.php +185 -0
  37. classes/wp-security-process-renamed-login-page.php +230 -227
  38. classes/wp-security-user-login.php +641 -684
  39. classes/wp-security-user-registration.php +72 -73
  40. classes/wp-security-utility-file.php +421 -439
  41. classes/wp-security-utility-htaccess.php +1298 -1303
  42. classes/wp-security-utility-ip-address.php +182 -234
  43. classes/wp-security-utility.php +617 -625
  44. classes/wp-security-wp-footer-content.php +120 -127
  45. classes/wp-security-wp-loaded-tasks.php +53 -52
  46. css/wp-security-notices.css +87 -0
  47. images/notices/aiowps-logo.png +0 -0
  48. images/notices/black_friday.png +0 -0
  49. images/notices/new_year.png +0 -0
  50. images/notices/spring.png +0 -0
  51. images/notices/summer.png +0 -0
  52. images/notices/ud_smile.png +0 -0
  53. images/notices/updraft_logo.png +0 -0
  54. images/notices/wp_optimize_logo.png +0 -0
  55. other-includes/wp-security-rename-login-feature-pre-5-2.php +897 -902
  56. other-includes/wp-security-rename-login-feature-pre-5-7.php +404 -424
  57. other-includes/wp-security-rename-login-feature.php +375 -395
  58. other-includes/wp-security-stop-users-enumeration.php +4 -5
  59. other-includes/wp-security-unlock-request.php +77 -85
  60. other-includes/wp-security-visitor-lockout-page.php +10 -10
  61. readme.txt +30 -1
  62. templates/notices/horizontal-notice.php +92 -0
  63. templates/notices/thanks-for-using-main-dash.php +37 -0
  64. vendor/autoload.php +1 -1
  65. vendor/composer/autoload_real.php +4 -4
  66. vendor/composer/autoload_static.php +2 -2
  67. vendor/composer/installed.php +2 -2
  68. wp-security-core.php +518 -270
  69. wp-security.php +28 -27
admin/wp-security-admin-init.php CHANGED
@@ -3,12 +3,24 @@
3
  * Inits the admin dashboard side of things.
4
  * Main admin file which loads all settings panels and sets up admin menus.
5
  */
6
- if(!defined('ABSPATH')){
7
- exit;//Exit if accessed directly
8
  }
9
 
10
- class AIOWPSecurity_Admin_Init
11
- {
 
 
 
 
 
 
 
 
 
 
 
 
12
  var $main_menu_page;
13
  var $dashboard_menu;
14
  var $settings_menu;
@@ -25,18 +37,29 @@ class AIOWPSecurity_Admin_Init
25
  var $filescan_menu;
26
  var $misc_menu;
27
 
28
- function __construct() {
 
 
 
 
 
29
  //This class is only initialized if is_admin() is true
30
  $this->admin_includes();
31
  add_action('admin_menu', array($this, 'create_admin_menus'));
32
  //handle CSV download
33
  add_action('admin_init', array($this, 'aiowps_csv_download'));
34
 
 
 
35
  //make sure we are on our plugin's menu pages
36
- if (isset($_GET['page']) && strpos($_GET['page'], AIOWPSEC_MENU_SLUG_PREFIX) !== false) {
37
  add_action('admin_print_scripts', array($this, 'admin_menu_page_scripts'));
38
  add_action('admin_print_styles', array($this, 'admin_menu_page_styles'));
39
  add_action('init', array($this, 'init_hook_handler_for_admin_side'));
 
 
 
 
40
  }
41
  }
42
 
@@ -123,6 +146,73 @@ class AIOWPSecurity_Admin_Init
123
  }
124
  }
125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  function admin_includes()
127
  {
128
  include_once('wp-security-admin-menu.php');
@@ -156,6 +246,21 @@ class AIOWPSecurity_Admin_Init
156
  $this->do_other_admin_side_init_tasks();
157
  }
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  function aiowps_media_uploader_modification()
160
  {
161
  //For changing button text inside media uploader (thickbox)
3
  * Inits the admin dashboard side of things.
4
  * Main admin file which loads all settings panels and sets up admin menus.
5
  */
6
+ if (!defined('ABSPATH')) {
7
+ exit;// Exit if accessed directly
8
  }
9
 
10
+ class AIOWPSecurity_Admin_Init {
11
+
12
+ /**
13
+ * Whether the page is admin dashboard page.
14
+ * @var boolean
15
+ */
16
+ private $is_admin_dashboard_page;
17
+
18
+ /**
19
+ * Whether the page is admin AIOWPS page.
20
+ * @var boolean
21
+ */
22
+ private $is_aiowps_admin_page;
23
+
24
  var $main_menu_page;
25
  var $dashboard_menu;
26
  var $settings_menu;
37
  var $filescan_menu;
38
  var $misc_menu;
39
 
40
+ /**
41
+ * Includes admin dependencies and hook admin actions.
42
+ *
43
+ * @return void
44
+ */
45
+ public function __construct() {
46
  //This class is only initialized if is_admin() is true
47
  $this->admin_includes();
48
  add_action('admin_menu', array($this, 'create_admin_menus'));
49
  //handle CSV download
50
  add_action('admin_init', array($this, 'aiowps_csv_download'));
51
 
52
+ add_action('admin_init', array($this, 'hook_admin_notices'));
53
+
54
  //make sure we are on our plugin's menu pages
55
+ if ($this->is_aiowps_admin_page()) {
56
  add_action('admin_print_scripts', array($this, 'admin_menu_page_scripts'));
57
  add_action('admin_print_styles', array($this, 'admin_menu_page_styles'));
58
  add_action('init', array($this, 'init_hook_handler_for_admin_side'));
59
+
60
+ if (class_exists('AIOWPS_PREMIUM')) {
61
+ add_filter('admin_footer_text', array($this, 'display_footer_review_message'));
62
+ }
63
  }
64
  }
65
 
146
  }
147
  }
148
 
149
+ /**
150
+ * Check whether current admin page is All In One WP Security admin page or not.
151
+ *
152
+ * @return boolean True if All In One WP Security admin page, Otherwise false.
153
+ */
154
+ private function is_aiowps_admin_page() {
155
+ if (isset($this->is_aiowps_admin_page)) {
156
+ return $this->is_aiowps_admin_page;
157
+ }
158
+ global $pagenow;
159
+ $this->is_aiowps_admin_page = ('admin.php' == $pagenow && isset($_GET['page']) && false !== strpos($_GET['page'], AIOWPSEC_MENU_SLUG_PREFIX));
160
+ return $this->is_aiowps_admin_page;
161
+ }
162
+
163
+ /**
164
+ * Hook admin notices on admin dashboard page and admin AIOWPS pages.
165
+ *
166
+ * @return void
167
+ */
168
+ public function hook_admin_notices() {
169
+ if (!current_user_can('update_plugins')) {
170
+ return;
171
+ }
172
+
173
+ // If none of the admin dashboard page or the AIOWPS page, Then bail
174
+ if (!$this->is_admin_dashboard_page() && !$this->is_aiowps_admin_page()) {
175
+ return;
176
+ }
177
+
178
+ add_action('all_admin_notices', array($this, 'render_admin_notices'));
179
+ }
180
+
181
+ /**
182
+ * Check whether current admin page is Admin Dashboard page or not.
183
+ *
184
+ * @return boolean True if Admin Dashboard page, Otherwise false.
185
+ */
186
+ private function is_admin_dashboard_page() {
187
+ if (isset($this->is_admin_dashboard_page)) {
188
+ return $this->is_admin_dashboard_page;
189
+ }
190
+ global $pagenow;
191
+ $this->is_admin_dashboard_page = 'index.php' == $pagenow;
192
+ return $this->is_admin_dashboard_page;
193
+ }
194
+
195
+ /**
196
+ * Render admin notices.
197
+ *
198
+ * @return void
199
+ */
200
+ public function render_admin_notices() {
201
+ global $aio_wp_security;
202
+
203
+ $installed_at = $aio_wp_security->notices->get_aiowps_plugin_installed_timestamp();
204
+ $time_now = $aio_wp_security->notices->get_time_now();
205
+ $installed_for = $time_now - $installed_at;
206
+
207
+ $dismissed_dash_notice_until = (int) $aio_wp_security->configs->get_value('dismissdashnotice');
208
+
209
+ if ($this->is_admin_dashboard_page() && ($installed_at && $time_now > $dismissed_dash_notice_until && $installed_for > (14 * 86400) && !defined('AIOWPSECURITY_NOADS_B')) || (defined('AIOWPSECURITY_FORCE_DASHNOTICE') && AIOWPSECURITY_FORCE_DASHNOTICE)) {
210
+ $aio_wp_security->include_template('notices/thanks-for-using-main-dash.php');
211
+ } elseif ($this->is_aiowps_admin_page() && $installed_at && $installed_for > 14*86400) {
212
+ $aio_wp_security->notices->do_notice(false, 'top');
213
+ }
214
+ }
215
+
216
  function admin_includes()
217
  {
218
  include_once('wp-security-admin-menu.php');
246
  $this->do_other_admin_side_init_tasks();
247
  }
248
 
249
+ /**
250
+ * Show footer review message and link.
251
+ *
252
+ * @return string
253
+ */
254
+ public function display_footer_review_message() {
255
+ /* translators: 1: All In One WP Security & Firewall 2: G2 review link */
256
+ $message = sprintf(
257
+ __('Enjoyed %1$s? Please leave us a %2$s rating. We really appreciate your support!', 'all-in-one-wp-security-and-firewall'),
258
+ '<b>All In One WP Security & Firewall</b>',
259
+ '<a href="https://www.g2.com/products/all-in-one-wp-security-firewall/reviews" target="_blank">&starf;&starf;&starf;&starf;&starf;</a>'
260
+ );
261
+ return $message;
262
+ }
263
+
264
  function aiowps_media_uploader_modification()
265
  {
266
  //For changing button text inside media uploader (thickbox)
admin/wp-security-admin-menu.php CHANGED
@@ -8,6 +8,25 @@ if(!defined('ABSPATH')){
8
 
9
  abstract class AIOWPSecurity_Admin_Menu
10
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  /**
12
  * Shows postbox for settings menu
13
  *
8
 
9
  abstract class AIOWPSecurity_Admin_Menu
10
  {
11
+ /**
12
+ * Get valid current tab slug.
13
+ *
14
+ * @return string current valid tab slug or empty string
15
+ */
16
+ protected function get_current_tab() {
17
+ if (is_array($this->menu_tabs) && !empty($this->menu_tabs)) {
18
+ $tab_keys = array_keys($this->menu_tabs);
19
+ if (empty($_GET['tab'])) {
20
+ return $tab_keys[0];
21
+ } else {
22
+ $current_tab = sanitize_text_field($_GET['tab']);
23
+ return in_array($current_tab, $tab_keys) ? $current_tab : $tab_keys[0];
24
+ }
25
+ } else {
26
+ return '';
27
+ }
28
+ }
29
+
30
  /**
31
  * Shows postbox for settings menu
32
  *
admin/wp-security-blacklist-menu.php CHANGED
@@ -26,13 +26,6 @@ class AIOWPSecurity_Blacklist_Menu extends AIOWPSecurity_Admin_Menu
26
  );
27
  }
28
 
29
- function get_current_tab()
30
- {
31
- $tab_keys = array_keys($this->menu_tabs);
32
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
33
- return $tab;
34
- }
35
-
36
  /*
37
  * Renders our tabs of this menu as nav items
38
  */
@@ -153,16 +146,22 @@ class AIOWPSecurity_Blacklist_Menu extends AIOWPSecurity_Admin_Menu
153
  </p>';
154
  ?>
155
  </div>
156
- <div class="aio_grey_box">
157
- <?php
158
- $addon_link = '<strong><a href="http://www.site-scanners.com/country-blocking-addon/" target="_blank">'.__('Country Blocking Addon', 'all-in-one-wp-security-and-firewall').'</a></strong>';
159
- $info_msg = sprintf( __('You may also be interested in our %s.', 'all-in-one-wp-security-and-firewall'), $addon_link);
160
- $info_msg2 = __('This addon allows you to automatically block IP addresses based on their country of origin.', 'all-in-one-wp-security-and-firewall');
 
 
 
161
 
162
- echo '<p>'.$info_msg.
163
- '<br />'.$info_msg2.'</p>';
164
- ?>
165
- </div>
 
 
 
166
 
167
  <div class="postbox">
168
  <h3 class="hndle"><label for="title"><?php _e('IP Hosts and User Agent Blacklist Settings', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
@@ -243,8 +242,8 @@ class AIOWPSecurity_Blacklist_Menu extends AIOWPSecurity_Admin_Menu
243
  //$errors = '';
244
 
245
  $submitted_agents = explode(PHP_EOL, $_POST['aiowps_banned_user_agents']);
246
- $agents = array();
247
- if (!empty($submitted_agents))
248
  {
249
  foreach ($submitted_agents as $agent)
250
  {
26
  );
27
  }
28
 
 
 
 
 
 
 
 
29
  /*
30
  * Renders our tabs of this menu as nav items
31
  */
146
  </p>';
147
  ?>
148
  </div>
149
+ <?php
150
+ /* if (!defined('AIOWPSECURITY_NOADS_B') || !AIOWPSECURITY_NOADS_B) {
151
+ */?><!--
152
+ <div class="aio_grey_box">
153
+ <?php
154
+ /* $premium_plugin_link = '<strong><a href="https://aiowpsecurity.com/landing/aiowpsecurity-premium" target="_blank">'.__('All In One WP Security & Firewall Premium', 'all-in-one-wp-security-and-firewall').'</a></strong>';
155
+ $info_msg = sprintf( __('You may also be interested in %s.', 'all-in-one-wp-security-and-firewall'), $premium_plugin_link);
156
+ $info_msg2 = sprintf(__('This plugin adds a number of extra features including %s and %s.', 'all-in-one-wp-security-and-firewall'), '<strong>'.__('smart 404 blocking', 'all-in-one-wp-security-and-firewall').'</strong>', '<strong>'.__('country IP blocking', 'all-in-one-wp-security-and-firewall').'</strong>');
157
 
158
+ echo '<p>'.$info_msg.
159
+ '<br />'.$info_msg2.'</p>';
160
+ */?>
161
+ </div>
162
+ --><?php
163
+ /* }
164
+ */?>
165
 
166
  <div class="postbox">
167
  <h3 class="hndle"><label for="title"><?php _e('IP Hosts and User Agent Blacklist Settings', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
242
  //$errors = '';
243
 
244
  $submitted_agents = explode(PHP_EOL, $_POST['aiowps_banned_user_agents']);
245
+ $agents = array();
246
+ if (!empty($submitted_agents))
247
  {
248
  foreach ($submitted_agents as $agent)
249
  {
admin/wp-security-brute-force-menu.php CHANGED
@@ -35,13 +35,6 @@ class AIOWPSecurity_Brute_Force_Menu extends AIOWPSecurity_Admin_Menu
35
  );
36
  }
37
 
38
- function get_current_tab()
39
- {
40
- $tab_keys = array_keys($this->menu_tabs);
41
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
42
- return $tab;
43
- }
44
-
45
  /*
46
  * Renders our tabs of this menu as nav items
47
  */
@@ -540,6 +533,10 @@ class AIOWPSecurity_Brute_Force_Menu extends AIOWPSecurity_Admin_Menu
540
  if(strpos($secret_key, '********') === false){
541
  $aio_wp_security->configs->set_value('aiowps_recaptcha_site_key',sanitize_text_field($_POST["aiowps_recaptcha_site_key"]));
542
  $aio_wp_security->configs->set_value('aiowps_recaptcha_secret_key',sanitize_text_field($_POST["aiowps_recaptcha_secret_key"]));
 
 
 
 
543
  }
544
 
545
  $aio_wp_security->configs->set_value('aiowps_default_recaptcha',isset($_POST["aiowps_default_recaptcha"])?'1':'');//Checkbox
@@ -550,6 +547,9 @@ class AIOWPSecurity_Brute_Force_Menu extends AIOWPSecurity_Admin_Menu
550
 
551
  $this->show_msg_settings_updated();
552
  }
 
 
 
553
 
554
  $secret_key_masked = AIOWPSecurity_Utility::mask_string($aio_wp_security->configs->get_value('aiowps_recaptcha_secret_key'));
555
  ?>
@@ -910,4 +910,4 @@ class AIOWPSecurity_Brute_Force_Menu extends AIOWPSecurity_Admin_Menu
910
  }
911
 
912
 
913
- } //end class
35
  );
36
  }
37
 
 
 
 
 
 
 
 
38
  /*
39
  * Renders our tabs of this menu as nav items
40
  */
533
  if(strpos($secret_key, '********') === false){
534
  $aio_wp_security->configs->set_value('aiowps_recaptcha_site_key',sanitize_text_field($_POST["aiowps_recaptcha_site_key"]));
535
  $aio_wp_security->configs->set_value('aiowps_recaptcha_secret_key',sanitize_text_field($_POST["aiowps_recaptcha_secret_key"]));
536
+
537
+ if ($aio_wp_security->google_recaptcha_sitekey_verification(stripslashes($_POST['aiowps_recaptcha_site_key'])) && $aio_wp_security->configs->get_value('aios_is_google_recaptcha_wrong_site_key')) {
538
+ $aio_wp_security->configs->delete_value('aios_is_google_recaptcha_wrong_site_key');
539
+ }
540
  }
541
 
542
  $aio_wp_security->configs->set_value('aiowps_default_recaptcha',isset($_POST["aiowps_default_recaptcha"])?'1':'');//Checkbox
547
 
548
  $this->show_msg_settings_updated();
549
  }
550
+ if (0 === $aio_wp_security->configs->get_value('aios_is_google_recaptcha_wrong_site_key')) {
551
+ echo '<div class="notice notice-warning aio_red_box"><p>'.__('Google reCAPTCHA site key is wrong. Please enter the correct reCAPTCHA keys below to use the reCAPTCHA feature.').'</p></div>';
552
+ }
553
 
554
  $secret_key_masked = AIOWPSecurity_Utility::mask_string($aio_wp_security->configs->get_value('aiowps_recaptcha_secret_key'));
555
  ?>
910
  }
911
 
912
 
913
+ } //end class
admin/wp-security-dashboard-menu.php CHANGED
@@ -13,8 +13,7 @@ class AIOWPSecurity_Dashboard_Menu extends AIOWPSecurity_Admin_Menu
13
  'tab1' => 'render_tab1',
14
  'tab2' => 'render_tab2',
15
  'tab3' => 'render_tab3',
16
- 'tab4' => 'render_tab4',
17
- 'tab5' => 'render_tab5'
18
  );
19
 
20
  public function __construct()
@@ -26,20 +25,12 @@ class AIOWPSecurity_Dashboard_Menu extends AIOWPSecurity_Admin_Menu
26
  {
27
  $this->menu_tabs = array(
28
  'tab1' => __('Dashboard', 'all-in-one-wp-security-and-firewall'),
29
- 'tab2' => __('System Info', 'all-in-one-wp-security-and-firewall'),
30
- 'tab3' => __('Locked IP Addresses', 'all-in-one-wp-security-and-firewall'),
31
- 'tab4' => __('Permanent Block List', 'all-in-one-wp-security-and-firewall'),
32
- 'tab5' => __('Logs', 'all-in-one-wp-security-and-firewall')
33
  );
34
  }
35
 
36
- public function get_current_tab()
37
- {
38
- $tab_keys = array_keys($this->menu_tabs);
39
- $tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
40
- return $tab;
41
- }
42
-
43
  /*
44
  * Renders our tabs of this menu as nav items
45
  */
@@ -93,142 +84,6 @@ class AIOWPSecurity_Dashboard_Menu extends AIOWPSecurity_Admin_Menu
93
  }
94
 
95
  public function render_tab2()
96
- {
97
- global $wpdb;
98
- ?>
99
- <div class="postbox">
100
- <h3 class="hndle"><label for="title"><?php _e('Site Info', 'all-in-one-wp-security-and-firewall');?></label>
101
- </h3>
102
-
103
- <div class="inside">
104
- <strong><?php _e('Plugin Version', 'all-in-one-wp-security-and-firewall');?>
105
- : </strong><code><?php echo AIO_WP_SECURITY_VERSION;?></code><br/>
106
- <strong><?php _e('WP Version', 'all-in-one-wp-security-and-firewall');?>
107
- : </strong><code><?php echo get_bloginfo("version"); ?></code><br/>
108
- <strong>WPMU: </strong><code><?php echo (!defined('MULTISITE') || !MULTISITE) ? "No" : "Yes"; ?></code><br/>
109
- <strong>MySQL <?php _e('Version', 'all-in-one-wp-security-and-firewall');?>
110
- : </strong><code><?php echo $wpdb->db_version();?></code><br/>
111
- <strong>WP <?php _e('Table Prefix', 'all-in-one-wp-security-and-firewall');?>
112
- : </strong><code><?php echo $wpdb->prefix; ?></code><br/>
113
- <strong>PHP <?php _e('Version', 'all-in-one-wp-security-and-firewall');?>
114
- : </strong><code><?php echo phpversion(); ?></code><br/>
115
- <strong><?php _e('Session Save Path', 'all-in-one-wp-security-and-firewall');?>
116
- : </strong><code><?php echo ini_get("session.save_path"); ?></code><br/>
117
- <strong>WP URL: </strong><code><?php echo get_bloginfo('wpurl'); ?></code><br/>
118
- <strong><?php _e('Server Name', 'all-in-one-wp-security-and-firewall');?>
119
- : </strong><code><?php echo $_SERVER['SERVER_NAME']; ?></code><br/>
120
- <strong><?php _e('Cookie Domain', 'all-in-one-wp-security-and-firewall');?>
121
- : </strong><code><?php $cookieDomain = parse_url(strtolower(get_bloginfo('wpurl')));
122
- echo $cookieDomain['host']; ?></code><br/>
123
- <strong>CURL <?php _e('Library Present', 'all-in-one-wp-security-and-firewall');?>
124
- : </strong><code><?php echo (function_exists('curl_init')) ? "Yes" : "No"; ?></code><br/>
125
- <strong><?php _e('Debug File Write Permissions', 'all-in-one-wp-security-and-firewall');?>
126
- : </strong><code><?php echo (is_writable(AIO_WP_SECURITY_PATH)) ? "Writable" : "Not Writable"; ?></code><br/>
127
- </div>
128
- </div><!-- End of Site Info -->
129
-
130
- <div class="postbox">
131
- <h3 class="hndle"><label for="title"><?php _e('PHP Info', 'all-in-one-wp-security-and-firewall');?></label>
132
- </h3>
133
-
134
- <div class="inside">
135
- <strong><?php _e('PHP Version', 'all-in-one-wp-security-and-firewall'); ?>
136
- : </strong><code><?php echo PHP_VERSION; ?></code><br/>
137
- <strong><?php _e('PHP Memory Usage', 'all-in-one-wp-security-and-firewall'); ?>:
138
- </strong><code><?php echo round(memory_get_usage() / 1024 / 1024, 2) . __(' MB', 'all-in-one-wp-security-and-firewall'); ?></code>
139
- <br/>
140
- <?php
141
- if (ini_get('memory_limit')) {
142
- $memory_limit = filter_var(ini_get('memory_limit'), FILTER_SANITIZE_STRING);
143
- } else {
144
- $memory_limit = __('N/A', 'all-in-one-wp-security-and-firewall');
145
- }
146
- ?>
147
- <strong><?php _e('PHP Memory Limit', 'all-in-one-wp-security-and-firewall'); ?>
148
- : </strong><code><?php echo $memory_limit; ?></code><br/>
149
- <?php
150
- if (ini_get('upload_max_filesize')) {
151
- $upload_max = filter_var(ini_get('upload_max_filesize'), FILTER_SANITIZE_STRING);
152
- } else {
153
- $upload_max = __('N/A', 'all-in-one-wp-security-and-firewall');
154
- }
155
- ?>
156
- <strong><?php _e('PHP Max Upload Size', 'all-in-one-wp-security-and-firewall'); ?>
157
- : </strong><code><?php echo $upload_max; ?></code><br/>
158
- <?php
159
- if (ini_get('post_max_size')) {
160
- $post_max = filter_var(ini_get('post_max_size'), FILTER_SANITIZE_STRING);
161
- } else {
162
- $post_max = __('N/A', 'all-in-one-wp-security-and-firewall');
163
- }
164
- ?>
165
- <strong><?php _e('PHP Max Post Size', 'all-in-one-wp-security-and-firewall'); ?>
166
- : </strong><code><?php echo $post_max; ?></code><br/>
167
- <?php
168
- if (ini_get('allow_url_fopen')) {
169
- $allow_url_fopen = __('On', 'all-in-one-wp-security-and-firewall');
170
- } else {
171
- $allow_url_fopen = __('Off', 'all-in-one-wp-security-and-firewall');
172
- }
173
- ?>
174
- <strong><?php _e('PHP Allow URL fopen', 'all-in-one-wp-security-and-firewall'); ?>
175
- : </strong><code><?php echo $allow_url_fopen; ?></code>
176
- <br/>
177
- <?php
178
- if (ini_get('display_errors')) {
179
- $display_errors = __('On', 'all-in-one-wp-security-and-firewall');
180
- } else {
181
- $display_errors = __('Off', 'all-in-one-wp-security-and-firewall');
182
- }
183
- ?>
184
- <strong><?php _e('PHP Display Errors', 'all-in-one-wp-security-and-firewall'); ?>
185
- : </strong><code><?php echo $display_errors; ?></code>
186
- <br/>
187
- <?php
188
- if (ini_get('max_execution_time')) {
189
- $max_execute = filter_var(ini_get('max_execution_time'));
190
- } else {
191
- $max_execute = __('N/A', 'all-in-one-wp-security-and-firewall');
192
- }
193
- ?>
194
- <strong><?php _e('PHP Max Script Execution Time', 'all-in-one-wp-security-and-firewall'); ?>
195
- : </strong><code><?php echo $max_execute; ?> <?php _e('Seconds'); ?></code><br/>
196
- </div>
197
- </div><!-- End of PHP Info -->
198
-
199
- <div class="postbox">
200
- <h3 class="hndle"><label
201
- for="title"><?php _e('Active Plugins', 'all-in-one-wp-security-and-firewall');?></label></h3>
202
-
203
- <div class="inside">
204
- <?php
205
- $all_plugins = get_plugins();
206
- $active_plugins = get_option('active_plugins');
207
- //var_dump($all_plugins);
208
- ?>
209
- <table class="widefat aio_spacer_10_tb">
210
- <thead>
211
- <tr>
212
- <th><?php _e('Name', 'all-in-one-wp-security-and-firewall') ?></th>
213
- <th><?php _e('Version', 'all-in-one-wp-security-and-firewall') ?></th>
214
- <th><?php _e('Plugin URL', 'all-in-one-wp-security-and-firewall') ?></th>
215
- </tr>
216
- </thead>
217
- <tbody>
218
- <?php
219
- foreach ($active_plugins as $plugin_key) {
220
- $plugin_details = $all_plugins[$plugin_key];
221
- echo '<tr><td>' . $plugin_details['Name'] . '</td><td>' . $plugin_details['Version'] . '</td><td>' . $plugin_details['PluginURI'] . '</td></tr>';
222
- }
223
- ?>
224
- </tbody>
225
- </table>
226
- </div>
227
- </div><!-- End of Active Plugins -->
228
- <?php
229
- }
230
-
231
- public function render_tab3()
232
  {
233
  global $wpdb;
234
  include_once 'wp-security-list-locked-ip.php'; //For rendering the AIOWPSecurity_List_Table in tab1
@@ -283,7 +138,7 @@ class AIOWPSecurity_Dashboard_Menu extends AIOWPSecurity_Admin_Menu
283
  <?php
284
  }
285
 
286
- public function render_tab4()
287
  {
288
  global $wpdb;
289
  include_once 'wp-security-list-permanent-blocked-ip.php'; //For rendering the AIOWPSecurity_List_Table
@@ -338,7 +193,7 @@ class AIOWPSecurity_Dashboard_Menu extends AIOWPSecurity_Admin_Menu
338
  *
339
  * @return void
340
  */
341
- public function render_tab5()
342
  {
343
  //Needed for rendering the debug log table
344
  include_once 'wp-security-list-debug.php';
@@ -370,7 +225,7 @@ class AIOWPSecurity_Dashboard_Menu extends AIOWPSecurity_Admin_Menu
370
  ?>
371
  <div class="notice notice-success is-dismissible">
372
  <p><strong><?php _e( 'All In One WP Security & Firewall', 'all-in-one-wp-security-and-firewall' ); ?></strong></p>
373
- <p><?php _e( 'Debug logs have been cleared', 'all-in-one-wp-security-and-firewall' ); ?></p>
374
  </div>
375
  <?php
376
 
@@ -807,7 +662,7 @@ class AIOWPSecurity_Dashboard_Menu extends AIOWPSecurity_Admin_Menu
807
  }
808
 
809
  public function widget_locked_ip_addresses() {
810
- $locked_ips_link = '<a href="admin.php?page=' . AIOWPSEC_MAIN_MENU_SLUG . '&tab=tab3">Locked IP Addresses</a>';
811
 
812
  $locked_ips = AIOWPSecurity_Utility::get_locked_ips();
813
  if ($locked_ips === FALSE) {
13
  'tab1' => 'render_tab1',
14
  'tab2' => 'render_tab2',
15
  'tab3' => 'render_tab3',
16
+ 'tab4' => 'render_tab4'
 
17
  );
18
 
19
  public function __construct()
25
  {
26
  $this->menu_tabs = array(
27
  'tab1' => __('Dashboard', 'all-in-one-wp-security-and-firewall'),
28
+ 'tab2' => __('Locked IP Addresses', 'all-in-one-wp-security-and-firewall'),
29
+ 'tab3' => __('Permanent Block List', 'all-in-one-wp-security-and-firewall'),
30
+ 'tab4' => __('Logs', 'all-in-one-wp-security-and-firewall')
 
31
  );
32
  }
33
 
 
 
 
 
 
 
 
34
  /*
35
  * Renders our tabs of this menu as nav items
36
  */
84
  }
85
 
86
  public function render_tab2()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  {
88
  global $wpdb;
89
  include_once 'wp-security-list-locked-ip.php'; //For rendering the AIOWPSecurity_List_Table in tab1
138
  <?php
139
  }
140
 
141
+ public function render_tab3()
142
  {
143
  global $wpdb;
144
  include_once 'wp-security-list-permanent-blocked-ip.php'; //For rendering the AIOWPSecurity_List_Table
193
  *
194
  * @return void
195
  */
196
+ public function render_tab4()
197
  {
198
  //Needed for rendering the debug log table
199
  include_once 'wp-security-list-debug.php';
225
  ?>
226
  <div class="notice notice-success is-dismissible">
227
  <p><strong><?php _e( 'All In One WP Security & Firewall', 'all-in-one-wp-security-and-firewall' ); ?></strong></p>
228
+ <p><?php _e( 'Debug logs have been cleared.', 'all-in-one-wp-security-and-firewall' ); ?></p>
229
  </div>
230
  <?php
231
 
662
  }
663
 
664
  public function widget_locked_ip_addresses() {
665
+ $locked_ips_link = '<a href="admin.php?page=' . AIOWPSEC_MAIN_MENU_SLUG . '&tab=tab2">Locked IP Addresses</a>';
666
 
667
  $locked_ips = AIOWPSecurity_Utility::get_locked_ips();
668
  if ($locked_ips === FALSE) {
admin/wp-security-database-menu.php CHANGED
@@ -36,13 +36,6 @@ class AIOWPSecurity_Database_Menu extends AIOWPSecurity_Admin_Menu
36
  }
37
 
38
  }
39
-
40
- function get_current_tab()
41
- {
42
- $tab_keys = array_keys($this->menu_tabs);
43
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
44
- return $tab;
45
- }
46
 
47
  /*
48
  * Renders our tabs of this menu as nav items
36
  }
37
 
38
  }
 
 
 
 
 
 
 
39
 
40
  /*
41
  * Renders our tabs of this menu as nav items
admin/wp-security-filescan-menu.php CHANGED
@@ -28,13 +28,6 @@ class AIOWPSecurity_Filescan_Menu extends AIOWPSecurity_Admin_Menu
28
  );
29
  }
30
 
31
- function get_current_tab()
32
- {
33
- $tab_keys = array_keys($this->menu_tabs);
34
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
35
- return $tab;
36
- }
37
-
38
  /*
39
  * Renders our tabs of this menu as nav items
40
  */
28
  );
29
  }
30
 
 
 
 
 
 
 
 
31
  /*
32
  * Renders our tabs of this menu as nav items
33
  */
admin/wp-security-filesystem-menu.php CHANGED
@@ -30,13 +30,6 @@ class AIOWPSecurity_Filesystem_Menu extends AIOWPSecurity_Admin_Menu
30
  );
31
  }
32
 
33
- function get_current_tab()
34
- {
35
- $tab_keys = array_keys($this->menu_tabs);
36
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
37
- return $tab;
38
- }
39
-
40
  /*
41
  * Renders our tabs of this menu as nav items
42
  */
30
  );
31
  }
32
 
 
 
 
 
 
 
 
33
  /*
34
  * Renders our tabs of this menu as nav items
35
  */
admin/wp-security-firewall-menu.php CHANGED
@@ -35,13 +35,6 @@ class AIOWPSecurity_Firewall_Menu extends AIOWPSecurity_Admin_Menu
35
  );
36
  }
37
 
38
- function get_current_tab()
39
- {
40
- $tab_keys = array_keys($this->menu_tabs);
41
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
42
- return $tab;
43
- }
44
-
45
  /*
46
  * Renders our tabs of this menu as nav items
47
  */
@@ -895,16 +888,22 @@ class AIOWPSecurity_Firewall_Menu extends AIOWPSecurity_Admin_Menu
895
  <br />'.__('If you want to temporarily block or blacklist an IP address, simply click the "Temp Block" or "Blacklist IP" link for the applicable IP entry in the "404 Event Logs" table below.', 'all-in-one-wp-security-and-firewall').'</p>';
896
  ?>
897
  </div>
898
- <div class="aio_grey_box">
899
- <?php
900
- $addon_link = '<strong><a href="http://www.site-scanners.com/smart-404-security-blocking-addon/" target="_blank">Smart404 Blocking Addon</a></strong>';
901
- $info_msg = sprintf( __('You may also be interested in our %s.', 'all-in-one-wp-security-and-firewall'), $addon_link);
902
- $info_msg2 = __('This addon allows you to automatically and permanently block IP addresses based on how many 404 errors they produce.', 'all-in-one-wp-security-and-firewall');
 
 
 
903
 
904
- echo '<p>'.$info_msg.
905
- '<br />'.$info_msg2.'</p>';
906
- ?>
907
- </div>
 
 
 
908
 
909
  <div class="postbox">
910
  <h3 class="hndle"><label for="title"><?php _e('404 Detection Options', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
35
  );
36
  }
37
 
 
 
 
 
 
 
 
38
  /*
39
  * Renders our tabs of this menu as nav items
40
  */
888
  <br />'.__('If you want to temporarily block or blacklist an IP address, simply click the "Temp Block" or "Blacklist IP" link for the applicable IP entry in the "404 Event Logs" table below.', 'all-in-one-wp-security-and-firewall').'</p>';
889
  ?>
890
  </div>
891
+ <?php
892
+ /* if (!defined('AIOWPSECURITY_NOADS_B') || !AIOWPSECURITY_NOADS_B) {
893
+ */?><!--
894
+ <div class="aio_grey_box">
895
+ <?php
896
+ /* $premium_plugin_link = '<strong><a href="https://aiowpsecurity.com/landing/aiowpsecurity-premium" target="_blank">'.__('All In One WP Security & Firewall Premium', 'all-in-one-wp-security-and-firewall').'</a></strong>';
897
+ $info_msg = sprintf( __('You may also be interested in %s.', 'all-in-one-wp-security-and-firewall'), $premium_plugin_link);
898
+ $info_msg2 = sprintf(__('This plugin adds a number of extra features including %s and %s.', 'all-in-one-wp-security-and-firewall'), '<strong>'.__('smart 404 blocking', 'all-in-one-wp-security-and-firewall').'</strong>', '<strong>'.__('country IP blocking', 'all-in-one-wp-security-and-firewall').'</strong>');
899
 
900
+ echo '<p>'.$info_msg.
901
+ '<br />'.$info_msg2.'</p>';
902
+ */?>
903
+ </div>
904
+ --><?php
905
+ /* }
906
+ */?>
907
 
908
  <div class="postbox">
909
  <h3 class="hndle"><label for="title"><?php _e('404 Detection Options', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
admin/wp-security-list-login-fails.php CHANGED
@@ -20,7 +20,18 @@ class AIOWPSecurity_List_Login_Failed_Attempts extends AIOWPSecurity_List_Table
20
  function column_default($item, $column_name){
21
  return $item[$column_name];
22
  }
23
-
 
 
 
 
 
 
 
 
 
 
 
24
  function column_login_attempt_ip($item){
25
  $tab = strip_tags($_REQUEST['tab']);
26
  $delete_url = sprintf('admin.php?page=%s&tab=%s&action=%s&failed_login_id=%s', AIOWPSEC_USER_LOGIN_MENU_SLUG, $tab, 'delete_failed_login_rec', $item['id']);
20
  function column_default($item, $column_name){
21
  return $item[$column_name];
22
  }
23
+
24
+ /**
25
+ * This method returns failed login date after being formatted according to the date_format and time_format options.
26
+ *
27
+ * @param Array $item - an array containing data for a single row of the failed logins table
28
+ *
29
+ * @return String returns formatted date-time string
30
+ */
31
+ protected function column_failed_login_date($item) {
32
+ return get_date_from_gmt(mysql2date('Y-m-d H:i:s', $item['failed_login_date']), get_option('date_format').' '.get_option('time_format'));
33
+ }
34
+
35
  function column_login_attempt_ip($item){
36
  $tab = strip_tags($_REQUEST['tab']);
37
  $delete_url = sprintf('admin.php?page=%s&tab=%s&action=%s&failed_login_id=%s', AIOWPSEC_USER_LOGIN_MENU_SLUG, $tab, 'delete_failed_login_rec', $item['id']);
admin/wp-security-list-registered-users.php CHANGED
@@ -266,7 +266,7 @@ class AIOWPSecurity_List_Registered_Users extends AIOWPSecurity_List_Table {
266
  }
267
  }
268
  $msg = __('The selected IP addresses were successfully added to the permanent block list!','all-in-one-wp-security-and-firewall');
269
- $msg .= ' <a href="admin.php?page='.AIOWPSEC_MAIN_MENU_SLUG.'&tab=tab4" target="_blank">'.__('View Blocked IPs','all-in-one-wp-security-and-firewall').'</a>';
270
  AIOWPSecurity_Admin_Menu::show_msg_updated_st($msg);
271
  }
272
  } elseif ($entries != NULL)
@@ -283,7 +283,7 @@ class AIOWPSecurity_List_Registered_Users extends AIOWPSecurity_List_Table {
283
  if($result === true)
284
  {
285
  $msg = __('The selected IP was successfully added to the permanent block list!','all-in-one-wp-security-and-firewall');
286
- $msg .= ' <a href="admin.php?page='.AIOWPSEC_MAIN_MENU_SLUG.'&tab=tab4" target="_blank">'.__('View Blocked IPs','all-in-one-wp-security-and-firewall').'</a>';
287
  AIOWPSecurity_Admin_Menu::show_msg_updated_st($msg);
288
  }
289
  else
266
  }
267
  }
268
  $msg = __('The selected IP addresses were successfully added to the permanent block list!','all-in-one-wp-security-and-firewall');
269
+ $msg .= ' <a href="admin.php?page='.AIOWPSEC_MAIN_MENU_SLUG.'&tab=tab3" target="_blank">'.__('View Blocked IPs','all-in-one-wp-security-and-firewall').'</a>';
270
  AIOWPSecurity_Admin_Menu::show_msg_updated_st($msg);
271
  }
272
  } elseif ($entries != NULL)
283
  if($result === true)
284
  {
285
  $msg = __('The selected IP was successfully added to the permanent block list!','all-in-one-wp-security-and-firewall');
286
+ $msg .= ' <a href="admin.php?page='.AIOWPSEC_MAIN_MENU_SLUG.'&tab=tab3" target="_blank">'.__('View Blocked IPs','all-in-one-wp-security-and-firewall').'</a>';
287
  AIOWPSecurity_Admin_Menu::show_msg_updated_st($msg);
288
  }
289
  else
admin/wp-security-maintenance-menu.php CHANGED
@@ -26,13 +26,6 @@ class AIOWPSecurity_Maintenance_Menu extends AIOWPSecurity_Admin_Menu
26
  );
27
  }
28
 
29
- function get_current_tab()
30
- {
31
- $tab_keys = array_keys($this->menu_tabs);
32
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
33
- return $tab;
34
- }
35
-
36
  /*
37
  * Renders our tabs of this menu as nav items
38
  */
26
  );
27
  }
28
 
 
 
 
 
 
 
 
29
  /*
30
  * Renders our tabs of this menu as nav items
31
  */
admin/wp-security-misc-options-menu.php CHANGED
@@ -32,13 +32,6 @@ class AIOWPSecurity_Misc_Options_Menu extends AIOWPSecurity_Admin_Menu
32
  );
33
  }
34
 
35
- function get_current_tab()
36
- {
37
- $tab_keys = array_keys($this->menu_tabs);
38
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
39
- return $tab;
40
- }
41
-
42
  /*
43
  * Renders our tabs of this menu as nav items
44
  */
32
  );
33
  }
34
 
 
 
 
 
 
 
 
35
  /*
36
  * Renders our tabs of this menu as nav items
37
  */
admin/wp-security-reset-settings.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) die('No direct access.');
3
+
4
+ if (!class_exists('AIOWPSecurity_Reset_Settings')):
5
+
6
+ /**
7
+ * Reset Settings various methods
8
+ */
9
+ class AIOWPSecurity_Reset_Settings {
10
+
11
+ /**
12
+ * Delete config option.
13
+ *
14
+ * @return boolean true if the aio_wp_security_configs option deleted successfully.
15
+ */
16
+ public static function reset_options() {
17
+ $result_delete_option = (false === get_option('aio_wp_security_configs',
18
+ false)) ? true : delete_option('aio_wp_security_configs');
19
+ $result_reset_settings = AIOWPSecurity_Configure_Settings::set_default_settings();
20
+ return $result_delete_option && $result_reset_settings;
21
+ }
22
+
23
+ /**
24
+ * Delete htaccess rules.
25
+ *
26
+ * @return boolean true if the aio_wp_security_configs option deleted successfully.
27
+ */
28
+ public static function delete_htaccess($section = 'All In One WP Security') {
29
+ $htaccess = ABSPATH . '.htaccess';
30
+
31
+ if (!file_exists($htaccess)) {
32
+ return false;
33
+ }
34
+ $ht_contents = preg_split('/\r\n|\r|\n/', file_get_contents($htaccess));
35
+ if ($ht_contents) { // as long as there are lines in the file
36
+ $state = true;
37
+ if (!($f = @fopen($htaccess, 'w+'))) {
38
+ @chmod($htaccess, 0644);
39
+ if (!($f = @fopen($htaccess, 'w+'))) {
40
+ return false;
41
+ }
42
+ }
43
+
44
+ foreach ($ht_contents as $n => $markerline) { // for each line in the file
45
+ if (strpos($markerline, '# BEGIN ' . $section) !== false) { // if we're at the beginning of the section
46
+ $state = false;
47
+ }
48
+ if ($state == true) { // as long as we're not in the section keep writing
49
+ fwrite($f, trim($markerline) . "\n");
50
+ }
51
+ if (strpos($markerline, '# END ' . $section) !== false) { // see if we're at the end of the section
52
+ $state = true;
53
+ }
54
+ }
55
+ @fclose($f);
56
+ return true;
57
+ }
58
+ return true;
59
+ }
60
+
61
+ /**
62
+ * Delete database tables
63
+ *
64
+ * @return boolean true
65
+ */
66
+ public static function reset_db_tables() {
67
+ // Reset (TRUNCATE) all the db tables of the plugin.
68
+ global $wpdb;
69
+
70
+ $wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_login_lockdown');
71
+ $wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_failed_logins');
72
+ $wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_login_activity');
73
+ $wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_global_meta');
74
+ $wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_events');
75
+ $wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_permanent_block');
76
+
77
+ return true;
78
+ }
79
+ }
80
+
81
+ endif;
admin/wp-security-settings-menu.php CHANGED
@@ -5,56 +5,52 @@ if(!defined('ABSPATH')){
5
 
6
  class AIOWPSecurity_Settings_Menu extends AIOWPSecurity_Admin_Menu
7
  {
8
- var $menu_page_slug = AIOWPSEC_SETTINGS_MENU_SLUG;
9
 
10
  /* Specify all the tabs of this menu in the following array */
11
- var $menu_tabs;
12
-
13
- var $menu_tabs_handler = array(
14
- 'tab1' => 'render_tab1',
15
- 'tab2' => 'render_tab2',
16
- 'tab3' => 'render_tab3',
17
- 'tab4' => 'render_tab4',
18
- 'tab5' => 'render_tab5',
19
- 'tab6' => 'render_tab6',
20
- );
21
 
22
- function __construct()
23
- {
24
  $this->render_menu_page();
25
  }
26
 
27
- function set_menu_tabs()
28
- {
29
- $this->menu_tabs = array(
30
- 'tab1' => __('General Settings', 'all-in-one-wp-security-and-firewall'),
31
- 'tab2' => '.htaccess '.__('File', 'all-in-one-wp-security-and-firewall'),
32
- 'tab3' => 'wp-config.php '.__('File', 'all-in-one-wp-security-and-firewall'),
33
- 'tab4' => __('WP Version Info', 'all-in-one-wp-security-and-firewall'),
34
- 'tab5' => __('Import/Export', 'all-in-one-wp-security-and-firewall'),
35
- 'tab6' => __('Advanced Settings', 'all-in-one-wp-security-and-firewall'),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  );
37
  }
38
 
39
- function get_current_tab()
40
- {
41
- $tab_keys = array_keys($this->menu_tabs);
42
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
43
- return $tab;
44
- }
45
-
46
  /*
47
  * Renders our tabs of this menu as nav items
48
  */
49
- function render_menu_tabs()
50
- {
51
  $current_tab = $this->get_current_tab();
52
 
53
  echo '<h2 class="nav-tab-wrapper">';
54
- foreach ( $this->menu_tabs as $tab_key => $tab_caption )
55
- {
56
  $active = $current_tab == $tab_key ? 'nav-tab-active' : '';
57
- echo '<a class="nav-tab ' . $active . '" href="?page=' . $this->menu_page_slug . '&tab=' . $tab_key . '">' . $tab_caption . '</a>';
58
  }
59
  echo '</h2>';
60
  }
@@ -71,11 +67,10 @@ class AIOWPSecurity_Settings_Menu extends AIOWPSecurity_Admin_Menu
71
  $this->render_menu_tabs();
72
  ?>
73
  <div id="poststuff"><div id="post-body">
74
- <?php
75
- //$tab_keys = array_keys($this->menu_tabs);
76
- call_user_func(array($this, $this->menu_tabs_handler[$tab]));
77
- ?>
78
- </div></div>
79
  </div><!-- end of wrap -->
80
  <?php
81
  }
@@ -135,6 +130,30 @@ class AIOWPSecurity_Settings_Menu extends AIOWPSecurity_Admin_Menu
135
  }
136
  }
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  if(isset($_POST['aiowps_save_debug_settings']))//Do form submission tasks
139
  {
140
  $nonce=$_REQUEST['_wpnonce'];
@@ -151,56 +170,93 @@ class AIOWPSecurity_Settings_Menu extends AIOWPSecurity_Admin_Menu
151
 
152
  ?>
153
  <div class="aio_grey_box">
154
- <p><?php _e('For information, updates and documentation, please visit the', 'all-in-one-wp-security-and-firewall'); ?> <a href="https://www.tipsandtricks-hq.com/wordpress-security-and-firewall-plugin" target="_blank">AIO WP Security & Firewall Plugin</a> <?php _e('Page', 'all-in-one-wp-security-and-firewall'); ?>.</p>
155
- <p><a href="https://www.tipsandtricks-hq.com/development-center" target="_blank"><?php _e('Follow us', 'all-in-one-wp-security-and-firewall'); ?></a> <?php _e('on Twitter, Google+ or via Email to stay up to date about the new security features of this plugin.', 'all-in-one-wp-security-and-firewall'); ?></p>
156
  </div>
157
 
158
  <div class="postbox">
159
- <h3 class="hndle"><label for="title"><?php _e('WP Security Plugin', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
160
- <div class="inside">
161
- <p><?php _e('Thank you for using our WordPress security plugin. There are a lot of security features in this plugin.', 'all-in-one-wp-security-and-firewall'); ?></p>
162
- <p><?php _e('Go through each menu items and enable the security options to add more security to your site. Start by activating the basic features first.', 'all-in-one-wp-security-and-firewall'); ?></p>
163
- <p><?php _e('It is a good practice to take a backup of your .htaccess file, database and wp-config.php file before activating the security features. This plugin has options that you can use to backup those resources easily.', 'all-in-one-wp-security-and-firewall'); ?></p>
164
- <p>
165
- <ul class="aiowps_admin_ul_grp1">
166
- <li><a href="admin.php?page=aiowpsec_database&tab=tab2" target="_blank"><?php _e('Backup your database', 'all-in-one-wp-security-and-firewall'); ?></a></li>
167
- <li><a href="admin.php?page=aiowpsec_settings&tab=tab2" target="_blank"><?php _e('Backup .htaccess file', 'all-in-one-wp-security-and-firewall'); ?></a></li>
168
- <li><a href="admin.php?page=aiowpsec_settings&tab=tab3" target="_blank"><?php _e('Backup wp-config.php file', 'all-in-one-wp-security-and-firewall'); ?></a></li>
169
- </ul>
170
- </p>
171
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  </div> <!-- end postbox-->
173
 
174
  <div class="postbox">
175
- <h3 class="hndle"><label for="title"><?php _e('Disable Security Features', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
176
- <div class="inside">
177
- <form method="post" action="">
178
- <?php wp_nonce_field('aiowpsec-disable-all-features'); ?>
179
- <div class="aio_blue_box">
180
- <?php
181
- echo '<p>'.__('If you think that some plugin functionality on your site is broken due to a security feature you enabled in this plugin, then use the following option to turn off all the security features of this plugin.', 'all-in-one-wp-security-and-firewall').'</p>';
182
- ?>
183
- </div>
184
- <div class="submit">
185
- <input type="submit" class="button" name="aiowpsec_disable_all_features" value="<?php _e('Disable All Security Features', 'all-in-one-wp-security-and-firewall'); ?>" />
186
- </div>
187
- </form>
188
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  </div> <!-- end postbox-->
190
 
191
  <div class="postbox">
192
- <h3 class="hndle"><label for="title"><?php _e('Disable All Firewall Rules', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
193
  <div class="inside">
194
  <form method="post" action="">
195
- <?php wp_nonce_field('aiowpsec-disable-all-firewall-rules'); ?>
196
  <div class="aio_blue_box">
197
  <?php
198
- echo '<p>'.__('This feature will disable all firewall rules which are currently active in this plugin and it will also delete these rules from your .htacess file. Use it if you think one of the firewall rules is causing an issue on your site.', 'all-in-one-wp-security-and-firewall').'</p>';
 
 
 
 
199
  ?>
200
  </div>
201
  <div class="submit">
202
- <input type="submit" class="button" name="aiowpsec_disable_all_firewall_rules" value="<?php _e('Disable All Firewall Rules', 'all-in-one-wp-security-and-firewall'); ?>" />
203
  </div>
 
204
  </form>
205
  </div>
206
  </div> <!-- end postbox-->
@@ -329,44 +385,44 @@ class AIOWPSecurity_Settings_Menu extends AIOWPSecurity_Admin_Menu
329
  $blog_id = get_current_blog_id();
330
  if (AIOWPSecurity_Utility::is_multisite_install() && !is_main_site( $blog_id ))
331
  {
332
- //Hide config settings if MS and not main site
333
- AIOWPSecurity_Utility::display_multisite_message();
334
  }
335
  else
336
  {
337
- ?>
338
- <div class="postbox">
339
- <h3 class="hndle"><label for="title"><?php _e('Save the current .htaccess file', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
340
- <div class="inside">
341
- <form action="" method="POST">
342
- <?php wp_nonce_field('aiowpsec-save-htaccess-nonce'); ?>
343
- <p class="description"><?php _e('Click the button below to backup and save the currently active .htaccess file.', 'all-in-one-wp-security-and-firewall'); ?></p>
344
- <input type="submit" name="aiowps_save_htaccess" value="<?php _e('Backup .htaccess File', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
345
- </form>
346
- </div></div>
347
- <div class="postbox">
348
- <h3 class="hndle"><label for="title"><?php _e('Restore from a backed up .htaccess file', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
349
- <div class="inside">
350
- <form action="" method="POST">
351
- <?php wp_nonce_field('aiowpsec-restore-htaccess-nonce'); ?>
352
- <table class="form-table">
353
- <tr valign="top">
354
- <th scope="row"><?php _e('.htaccess file to restore from', 'all-in-one-wp-security-and-firewall')?>:</th>
355
- <td>
356
- <input type="button" id="aiowps_htaccess_file_button" name="aiowps_htaccess_file_button" class="button rbutton" value="<?php _e('Select Your htaccess File', 'all-in-one-wp-security-and-firewall'); ?>" />
357
- <input name="aiowps_htaccess_file" type="text" id="aiowps_htaccess_file" value="" size="80" />
358
- <p class="description">
359
- <?php
360
- _e('After selecting your file, click the button below to restore your site using the backed up htaccess file (htaccess_backup.txt).', 'all-in-one-wp-security-and-firewall');
361
- ?>
362
- </p>
363
- </td>
364
- </tr>
365
- </table>
366
- <input type="submit" name="aiowps_restore_htaccess_button" value="<?php _e('Restore .htaccess File', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
367
- </form>
368
- </div></div>
369
- <?php
370
  } // End if statement
371
  }
372
 
@@ -430,55 +486,55 @@ class AIOWPSecurity_Settings_Menu extends AIOWPSecurity_Admin_Menu
430
  $blog_id = get_current_blog_id();
431
  if (AIOWPSecurity_Utility::is_multisite_install() && !is_main_site( $blog_id ))
432
  {
433
- //Hide config settings if MS and not main site
434
- AIOWPSecurity_Utility::display_multisite_message();
435
  }
436
  else
437
  {
438
- ?>
439
- <div class="postbox">
440
- <h3 class="hndle"><label for="title"><?php _e('Save the current wp-config.php file', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
441
- <div class="inside">
442
- <form action="" method="POST">
443
- <?php wp_nonce_field('aiowpsec-save-wp-config-nonce'); ?>
444
- <p class="description"><?php _e('Click the button below to backup and download the contents of the currently active wp-config.php file.', 'all-in-one-wp-security-and-firewall'); ?></p>
445
- <input type="submit" name="aiowps_save_wp_config" value="<?php _e('Backup wp-config.php File', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
446
-
447
- </form>
448
- </div></div>
449
- <div class="postbox">
450
- <h3 class="hndle"><label for="title"><?php _e('Restore from a backed up wp-config file', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
451
- <div class="inside">
452
- <form action="" method="POST">
453
- <?php wp_nonce_field('aiowpsec-restore-wp-config-nonce'); ?>
454
- <table class="form-table">
455
- <tr valign="top">
456
- <th scope="row"><?php _e('wp-config file to restore from', 'all-in-one-wp-security-and-firewall')?>:</th>
457
- <td>
458
- <input type="button" id="aiowps_wp_config_file_button" name="aiowps_wp_config_file_button" class="button rbutton" value="<?php _e('Select Your wp-config File', 'all-in-one-wp-security-and-firewall'); ?>" />
459
- <input name="aiowps_wp_config_file" type="text" id="aiowps_wp_config_file" value="" size="80" />
460
- <p class="description">
461
- <?php
462
- _e('After selecting your file click the button below to restore your site using the backed up wp-config file (wp-config.php.backup.txt).', 'all-in-one-wp-security-and-firewall');
463
- ?>
464
- </p>
465
- </td>
466
- </tr>
467
- </table>
468
- <input type="submit" name="aiowps_restore_wp_config_button" value="<?php _e('Restore wp-config File', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
469
- </form>
470
- </div></div>
471
- <!-- <div class="postbox">-->
472
- <!-- <h3 class="hndle"><label for="title">--><?php //_e('View Contents of the currently active wp-config.php file', 'all-in-one-wp-security-and-firewall'); ?><!--</label></h3>-->
473
- <!-- <div class="inside">-->
474
- <!-- --><?php
475
  // $wp_config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
476
  // $wp_config_contents = AIOWPSecurity_Utility_File::get_file_contents($wp_config_file);
477
  // ?>
478
- <!-- <textarea class="aio_text_area_file_output aio_width_80 aio_spacer_10_tb" rows="20" readonly>--><?php //echo $wp_config_contents; ?><!--</textarea>-->
479
- <!-- </div></div>-->
480
 
481
- <?php
482
  } //End if statement
483
  }
484
 
@@ -502,7 +558,7 @@ class AIOWPSecurity_Settings_Menu extends AIOWPSecurity_Admin_Menu
502
  $aiowps_feature_mgr->check_feature_status_and_recalculate_points();
503
 
504
  $this->show_msg_settings_updated();
505
- }
506
  ?>
507
  <h2><?php _e('WP Generator Meta Tag & Version Info', 'all-in-one-wp-security-and-firewall')?></h2>
508
  <div class="aio_blue_box">
@@ -518,34 +574,33 @@ class AIOWPSecurity_Settings_Menu extends AIOWPSecurity_Admin_Menu
518
  </div>
519
 
520
  <div class="postbox">
521
- <h3 class="hndle"><label for="title"><?php _e('WP Generator Meta Info', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
522
- <div class="inside">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
523
  <?php
524
- //Display security info badge
525
- global $aiowps_feature_mgr;
526
- $aiowps_feature_mgr->output_feature_details_badge("wp-generator-meta-tag");
527
- ?>
528
-
529
- <form action="" method="POST">
530
- <?php wp_nonce_field('aiowpsec-remove-wp-meta-info-nonce'); ?>
531
- <table class="form-table">
532
- <tr valign="top">
533
- <th scope="row"><?php _e('Remove WP Generator Meta Info', 'all-in-one-wp-security-and-firewall')?>:</th>
534
- <td>
535
- <input name="aiowps_remove_wp_generator_meta_info" type="checkbox"<?php if($aio_wp_security->configs->get_value('aiowps_remove_wp_generator_meta_info')=='1') echo ' checked="checked"'; ?> value="1"/>
536
- <span class="description"><?php _e('Check this if you want to remove the version and meta info produced by WP from all pages', 'all-in-one-wp-security-and-firewall'); ?></span>
537
- </td>
538
- </tr>
539
- </table>
540
- <input type="submit" name="aiowps_save_remove_wp_meta_info" value="<?php _e('Save Settings', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
541
- </form>
542
- </div></div>
543
- <?php
544
  }
545
 
546
 
547
- function render_tab5()
548
- {
549
  global $aio_wp_security;
550
 
551
  global $wpdb;
@@ -668,120 +723,48 @@ function render_tab5()
668
  </div>
669
 
670
  <div class="postbox">
671
- <h3 class="hndle"><label for="title"><?php _e('Export AIOWPS Settings', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
672
- <div class="inside">
673
- <form action="" method="POST">
674
- <?php wp_nonce_field('aiowpsec-export-settings-nonce'); ?>
675
- <table class="form-table">
676
- <tr valign="top">
677
- <span class="description"><?php _e('To export your All In One WP Security & Firewall settings click the button below.', 'all-in-one-wp-security-and-firewall'); ?></span>
678
- </tr>
679
- </table>
680
- <input type="submit" name="aiowps_export_settings" value="<?php _e('Export AIOWPS Settings', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
681
- </form>
682
- </div></div>
683
- <div class="postbox">
684
- <h3 class="hndle"><label for="title"><?php _e('Import AIOWPS Settings', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
685
- <div class="inside">
686
- <form action="" method="POST">
687
- <?php wp_nonce_field('aiowpsec-import-settings-nonce'); ?>
688
- <table class="form-table">
689
- <tr valign="top">
690
- <span class="description"><?php _e('Use this section to import your All In One WP Security & Firewall settings from a file. Alternatively, copy/paste the contents of your import file into the textarea below.', 'all-in-one-wp-security-and-firewall'); ?></span>
691
- <th scope="row"><?php _e('Import File', 'all-in-one-wp-security-and-firewall')?>:</th>
692
- <td>
693
- <input type="button" id="aiowps_import_settings_file_button" name="aiowps_import_settings_file_button" class="button rbutton" value="<?php _e('Select Your Import Settings File', 'all-in-one-wp-security-and-firewall'); ?>" />
694
- <input name="aiowps_import_settings_file" type="text" id="aiowps_import_settings_file" value="" size="80" />
695
- <p class="description">
696
- <?php
697
- _e('After selecting your file, click the button below to apply the settings to your site.', 'all-in-one-wp-security-and-firewall');
698
- ?>
699
- </p>
700
- </td>
701
- </tr>
702
- <tr valign="top">
703
- <th scope="row"><?php _e('Copy/Paste Import Data', 'all-in-one-wp-security-and-firewall')?>:</th>
704
- <td>
705
- <textarea name="aiowps_import_settings_text" id="aiowps_import_settings_text" style="width:80%;height:140px;"></textarea>
706
- </td>
707
- </tr>
708
- </table>
709
- <input type="submit" name="aiowps_import_settings" value="<?php _e('Import AIOWPS Settings', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
710
- </form>
711
- </div></div>
712
- <?php
713
- }
714
-
715
- function render_tab6()
716
- {
717
- global $aio_wp_security;
718
-
719
- $result = 1;
720
- if (isset($_POST['aiowps_save_advanced_settings']))
721
- {
722
- $nonce=$_REQUEST['_wpnonce'];
723
- if (!wp_verify_nonce($nonce, 'aiowpsec-ip-settings-nonce'))
724
- {
725
- $aio_wp_security->debug_logger->log_debug("Nonce check failed for save advanced settings!",4);
726
- die(__('Nonce check failed for save advanced settings!','aiowpsecurity'));
727
- }
728
-
729
- $aio_wp_security->configs->set_value('aiowps_ip_retrieve_method', sanitize_text_field($_POST["aiowps_ip_retrieve_method"]));
730
- $aio_wp_security->configs->save_config(); //Save the configuration
731
-
732
- //Clear logged in list because it might be showing wrong addresses
733
- if (AIOWPSecurity_Utility::is_multisite_install()){
734
- delete_site_transient('users_online');
735
- }
736
- else{
737
- delete_transient('users_online');
738
- }
739
-
740
- $this->show_msg_settings_updated();
741
- }
742
- ?>
743
  <div class="postbox">
744
- <h3 class="hndle"><label for="title"><?php _e('IP Retrieval Settings', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
745
- <div class="inside">
746
- <div class="aio_blue_box">
747
- <?php
748
- echo '<p>'.__('The IP Retrieval Settings allow you to specify which $_SERVER global variable you want this plugin to use to retrieve the visitor IP address.', 'all-in-one-wp-security-and-firewall').
749
- '<br />'.__('By default this plugin uses the $_SERVER[\'REMOTE_ADDR\'] variable to retrieve the visitor IP address. This should normally be the most accurate safest way to get the IP.', 'all-in-one-wp-security-and-firewall').
750
- '<br />'.__('However in some setups such as those using proxies, load-balancers and CloudFlare, it may be necessary to use a different $_SERVER variable.', 'all-in-one-wp-security-and-firewall').
751
- '<br />'.__('You can use the settings below to configure which $_SERVER global you would like to use for retrieving the IP address.', 'all-in-one-wp-security-and-firewall').'</p>';
752
- ?>
753
- </div>
754
-
755
- <form action="" method="POST">
756
- <?php wp_nonce_field('aiowpsec-ip-settings-nonce'); ?>
757
- <table class="form-table">
758
- <tr valign="top">
759
- <td>
760
- <select id="aiowps_ip_retrieve_method" name="aiowps_ip_retrieve_method">
761
- <option value="0" <?php selected( $aio_wp_security->configs->get_value('aiowps_ip_retrieve_method'), '0' ); ?>><?php echo 'REMOTE_ADDR' .' ('.__('Default','all-in-one-wp-security-and-firewall').')'; ?></option>
762
- <option value="1" <?php selected( $aio_wp_security->configs->get_value('aiowps_ip_retrieve_method'), '1' ); ?>><?php echo 'HTTP_CF_CONNECTING_IP'; ?></option>
763
- <option value="2" <?php selected( $aio_wp_security->configs->get_value('aiowps_ip_retrieve_method'), '2' ); ?>><?php echo 'HTTP_X_FORWARDED_FOR'; ?></option>
764
- <option value="3" <?php selected( $aio_wp_security->configs->get_value('aiowps_ip_retrieve_method'), '3' ); ?>><?php echo 'HTTP_X_FORWARDED'; ?></option>
765
- <option value="4" <?php selected( $aio_wp_security->configs->get_value('aiowps_ip_retrieve_method'), '4' ); ?>><?php echo 'HTTP_CLIENT_IP'; ?></option>
766
- </select>
767
- <span class="description"><?php _e('Choose a $_SERVER variable you would like to retrieve the visitor IP address from.', 'all-in-one-wp-security-and-firewall'); ?>
768
- </span>
769
- <span class="aiowps_more_info_anchor"><span class="aiowps_more_info_toggle_char">+</span><span class="aiowps_more_info_toggle_text"><?php _e('More Info', 'all-in-one-wp-security-and-firewall'); ?></span></span>
770
- <div class="aiowps_more_info_body">
771
- <p class="description">
772
- <?php
773
- _e('If your chosen server variable fails the plugin will automatically fall back to retrieving the IP address from $_SERVER["REMOTE_ADDR"]', 'all-in-one-wp-security-and-firewall');
774
- ?>
775
- </p>
776
- </div>
777
- </td>
778
- </tr>
779
- </table>
780
- <input type="submit" name="aiowps_save_advanced_settings" value="<?php _e('Save Settings', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
781
- </form>
782
- </div></div>
783
  <?php
784
-
785
  }
786
 
787
  function check_if_wp_config_contents($wp_file)
@@ -860,4 +843,4 @@ function render_tab5()
860
 
861
  }
862
 
863
- } //end class
5
 
6
  class AIOWPSecurity_Settings_Menu extends AIOWPSecurity_Admin_Menu
7
  {
8
+ private $menu_page_slug = AIOWPSEC_SETTINGS_MENU_SLUG;
9
 
10
  /* Specify all the tabs of this menu in the following array */
11
+ public $menu_tabs;
 
 
 
 
 
 
 
 
 
12
 
13
+ public function __construct() {
 
14
  $this->render_menu_page();
15
  }
16
 
17
+ public function set_menu_tabs() {
18
+ $this->menu_tabs = apply_filters('aiowpsecurity_setting_tabs',
19
+ array(
20
+ 'tab1' => array(
21
+ 'title' => __('General Settings', 'all-in-one-wp-security-and-firewall'),
22
+ 'render_callback' => array($this, 'render_tab1'),
23
+ ),
24
+ 'tab2' => array(
25
+ 'title' => '.htaccess '.__('File', 'all-in-one-wp-security-and-firewall'),
26
+ 'render_callback' => array($this, 'render_tab2'),
27
+ ),
28
+ 'tab3' => array(
29
+ 'title' => 'wp-config.php '.__('File', 'all-in-one-wp-security-and-firewall'),
30
+ 'render_callback' => array($this, 'render_tab3'),
31
+ ),
32
+ 'tab4' => array(
33
+ 'title' => __('WP Version Info', 'all-in-one-wp-security-and-firewall'),
34
+ 'render_callback' => array($this, 'render_tab4'),
35
+ ),
36
+ 'tab5' => array(
37
+ 'title' => __('Import/Export', 'all-in-one-wp-security-and-firewall'),
38
+ 'render_callback' => array($this, 'render_tab5'),
39
+ ),
40
+ )
41
  );
42
  }
43
 
 
 
 
 
 
 
 
44
  /*
45
  * Renders our tabs of this menu as nav items
46
  */
47
+ public function render_menu_tabs() {
 
48
  $current_tab = $this->get_current_tab();
49
 
50
  echo '<h2 class="nav-tab-wrapper">';
51
+ foreach ($this->menu_tabs as $tab_key => $tab_info) {
 
52
  $active = $current_tab == $tab_key ? 'nav-tab-active' : '';
53
+ echo '<a class="nav-tab ' . $active . '" href="?page=' . $this->menu_page_slug . '&tab=' . $tab_key . '">' . esc_html($tab_info['title']) . '</a>';
54
  }
55
  echo '</h2>';
56
  }
67
  $this->render_menu_tabs();
68
  ?>
69
  <div id="poststuff"><div id="post-body">
70
+ <?php
71
+ call_user_func($this->menu_tabs[$tab]['render_callback']);
72
+ ?>
73
+ </div></div>
 
74
  </div><!-- end of wrap -->
75
  <?php
76
  }
130
  }
131
  }
132
 
133
+ if (isset($_POST['aiowps_reset_settings'])) { // Do form submission tasks
134
+ if (!wp_verify_nonce($_POST['_wpnonce'], 'aiowps-reset-settings-nonce')) {
135
+ $aio_wp_security->debug_logger->log_debug("Nonce check failed for reset settings.", 4);
136
+ die("Nonce check failed for reset settings.");
137
+ }
138
+
139
+ if (!class_exists('AIOWPSecurity_Reset_Settings')) {
140
+ require(AIO_WP_SECURITY_PATH . '/admin/wp-security-reset-settings.php' );
141
+ }
142
+ $reset_option_res = AIOWPSecurity_Reset_Settings::reset_options();
143
+ $delete_htaccess = AIOWPSecurity_Reset_Settings::delete_htaccess();
144
+ $truncate_db_tables = AIOWPSecurity_Reset_Settings::reset_db_tables();
145
+
146
+ if (false === $reset_option_res && false === $delete_htaccess) {
147
+ $this->show_msg_error(__('Deletion of aio_wp_security_configs option and .htaccess directives failed.', 'all-in-one-wp-security-and-firewall'));
148
+ } elseif (false === $reset_option_res) {
149
+ $this->show_msg_error(__('Reset of aio_wp_security_configs option failed.', 'all-in-one-wp-security-and-firewall'));
150
+ } elseif (false === $delete_htaccess) {
151
+ $this->show_msg_error(__('Deletion of .htaccess directives failed.', 'all-in-one-wp-security-and-firewall'));
152
+ } else {
153
+ $this->show_msg_updated(__('All settings have been successfully reset.', 'all-in-one-wp-security-and-firewall'));
154
+ }
155
+ }
156
+
157
  if(isset($_POST['aiowps_save_debug_settings']))//Do form submission tasks
158
  {
159
  $nonce=$_REQUEST['_wpnonce'];
170
 
171
  ?>
172
  <div class="aio_grey_box">
173
+ <p><?php _e('For information, updates and documentation, please visit the', 'all-in-one-wp-security-and-firewall'); ?> <a href="https://www.tipsandtricks-hq.com/wordpress-security-and-firewall-plugin" target="_blank">AIO WP Security & Firewall Plugin</a> <?php _e('Page', 'all-in-one-wp-security-and-firewall'); ?>.</p>
174
+ <p><a href="https://www.tipsandtricks-hq.com/development-center" target="_blank"><?php _e('Follow us', 'all-in-one-wp-security-and-firewall'); ?></a> <?php _e('on Twitter, Google+ or via Email to stay up to date about the new security features of this plugin.', 'all-in-one-wp-security-and-firewall'); ?></p>
175
  </div>
176
 
177
  <div class="postbox">
178
+ <h3 class="hndle"><label for="title"><?php _e('WP Security Plugin', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
179
+ <div class="inside">
180
+ <p>
181
+ <?php
182
+ _e('Thank you for using the AIOWPS security plugin.', 'all-in-one-wp-security-and-firewall');
183
+ ?>
184
+ &nbsp;
185
+ <?php
186
+ _e('There are a lot of security features in this plugin.', 'all-in-one-wp-security-and-firewall');
187
+ ?>
188
+ </p>
189
+ <p>
190
+ <?php
191
+ _e('To start, go through each security option and enable the "basic" options.', 'all-in-one-wp-security-and-firewall');
192
+ ?>
193
+ &nbsp;
194
+ <?php
195
+ _e('The more features you enable, the more security points you will achieve.', 'all-in-one-wp-security-and-firewall');
196
+ ?>
197
+ </p>
198
+ <p><?php _e('Before doing anything we advise taking a backup of your .htaccess file, database and wp-config.php.', 'all-in-one-wp-security-and-firewall'); ?></p>
199
+ <p>
200
+ <ul class="aiowps_admin_ul_grp1">
201
+ <li><a href="admin.php?page=aiowpsec_database&tab=tab2" target="_blank"><?php _e('Backup your database', 'all-in-one-wp-security-and-firewall'); ?></a></li>
202
+ <li><a href="admin.php?page=aiowpsec_settings&tab=tab2" target="_blank"><?php _e('Backup .htaccess file', 'all-in-one-wp-security-and-firewall'); ?></a></li>
203
+ <li><a href="admin.php?page=aiowpsec_settings&tab=tab3" target="_blank"><?php _e('Backup wp-config.php file', 'all-in-one-wp-security-and-firewall'); ?></a></li>
204
+ </ul>
205
+ </p>
206
+ </div>
207
  </div> <!-- end postbox-->
208
 
209
  <div class="postbox">
210
+ <h3 class="hndle"><label for="title"><?php _e('Disable Security Features', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
211
+ <div class="inside">
212
+ <form method="post" action="">
213
+ <?php wp_nonce_field('aiowpsec-disable-all-features'); ?>
214
+ <div class="aio_blue_box">
215
+ <?php
216
+ echo '<p>'.__('If you think that some plugin functionality on your site is broken due to a security feature you enabled in this plugin, then use the following option to turn off all the security features of this plugin.', 'all-in-one-wp-security-and-firewall').'</p>';
217
+ ?>
218
+ </div>
219
+ <div class="submit">
220
+ <input type="submit" class="button" name="aiowpsec_disable_all_features" value="<?php _e('Disable All Security Features', 'all-in-one-wp-security-and-firewall'); ?>" />
221
+ </div>
222
+ </form>
223
+ </div>
224
+ </div> <!-- end postbox-->
225
+
226
+ <div class="postbox">
227
+ <h3 class="hndle"><label for="title"><?php _e('Disable All Firewall Rules', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
228
+ <div class="inside">
229
+ <form method="post" action="">
230
+ <?php wp_nonce_field('aiowpsec-disable-all-firewall-rules'); ?>
231
+ <div class="aio_blue_box">
232
+ <?php
233
+ echo '<p>'.__('This feature will disable all firewall rules which are currently active in this plugin and it will also delete these rules from your .htacess file. Use it if you think one of the firewall rules is causing an issue on your site.', 'all-in-one-wp-security-and-firewall').'</p>';
234
+ ?>
235
+ </div>
236
+ <div class="submit">
237
+ <input type="submit" class="button" name="aiowpsec_disable_all_firewall_rules" value="<?php _e('Disable All Firewall Rules', 'all-in-one-wp-security-and-firewall'); ?>" />
238
+ </div>
239
+ </form>
240
+ </div>
241
  </div> <!-- end postbox-->
242
 
243
  <div class="postbox">
244
+ <h3 class="hndle"><label for="title"><?php _e('Reset Settings', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
245
  <div class="inside">
246
  <form method="post" action="">
 
247
  <div class="aio_blue_box">
248
  <?php
249
+ echo '<p>'.htmlspecialchars(__('This button click will delete all of your settings related to the All In One WP Security & Firewall Plugin.', 'all-in-one-wp-security-and-firewall')).'</p>';
250
+ echo '<p'.__('This button click will reset/empty all the database tables of the security plugin also.', 'all-in-one-wp-security-and-firewall').'</p>';
251
+ echo '<p>'.htmlspecialchars(__('Use this plugin if you were locked out by the All In One WP Security & Firewall Plugin and/or you are having issues logging in when that plugin is activated.', 'all-in-one-wp-security-and-firewall')).'</p>';
252
+ echo '<p>'.__('In addition to the settings it will also delete any directives which were added to the .htaccess file by the All In One WP Security & Firewall Plugin.', 'all-in-one-wp-security-and-firewall').'</p>';
253
+ echo '<p>'.sprintf(__('%1$sNOTE: %2$sAfter deleting the settings you will need to re-configure the All In One WP Security & Firewall plugin.', 'all-in-one-wp-security-and-firewall'), '<strong>', '</strong>').'</p>';
254
  ?>
255
  </div>
256
  <div class="submit">
257
+ <input type="submit" name="aiowps_reset_settings" value="<?php _e('Reset Settings', 'all-in-one-wp-security-and-firewall') ?>" class="button" />
258
  </div>
259
+ <?php wp_nonce_field('aiowps-reset-settings-nonce'); ?>
260
  </form>
261
  </div>
262
  </div> <!-- end postbox-->
385
  $blog_id = get_current_blog_id();
386
  if (AIOWPSecurity_Utility::is_multisite_install() && !is_main_site( $blog_id ))
387
  {
388
+ //Hide config settings if MS and not main site
389
+ AIOWPSecurity_Utility::display_multisite_message();
390
  }
391
  else
392
  {
393
+ ?>
394
+ <div class="postbox">
395
+ <h3 class="hndle"><label for="title"><?php _e('Save the current .htaccess file', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
396
+ <div class="inside">
397
+ <form action="" method="POST">
398
+ <?php wp_nonce_field('aiowpsec-save-htaccess-nonce'); ?>
399
+ <p class="description"><?php _e('Click the button below to backup and save the currently active .htaccess file.', 'all-in-one-wp-security-and-firewall'); ?></p>
400
+ <input type="submit" name="aiowps_save_htaccess" value="<?php _e('Backup .htaccess File', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
401
+ </form>
402
+ </div></div>
403
+ <div class="postbox">
404
+ <h3 class="hndle"><label for="title"><?php _e('Restore from a backed up .htaccess file', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
405
+ <div class="inside">
406
+ <form action="" method="POST">
407
+ <?php wp_nonce_field('aiowpsec-restore-htaccess-nonce'); ?>
408
+ <table class="form-table">
409
+ <tr valign="top">
410
+ <th scope="row"><?php _e('.htaccess file to restore from', 'all-in-one-wp-security-and-firewall')?>:</th>
411
+ <td>
412
+ <input type="button" id="aiowps_htaccess_file_button" name="aiowps_htaccess_file_button" class="button rbutton" value="<?php _e('Select Your htaccess File', 'all-in-one-wp-security-and-firewall'); ?>" />
413
+ <input name="aiowps_htaccess_file" type="text" id="aiowps_htaccess_file" value="" size="80" />
414
+ <p class="description">
415
+ <?php
416
+ _e('After selecting your file, click the button below to restore your site using the backed up htaccess file (htaccess_backup.txt).', 'all-in-one-wp-security-and-firewall');
417
+ ?>
418
+ </p>
419
+ </td>
420
+ </tr>
421
+ </table>
422
+ <input type="submit" name="aiowps_restore_htaccess_button" value="<?php _e('Restore .htaccess File', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
423
+ </form>
424
+ </div></div>
425
+ <?php
426
  } // End if statement
427
  }
428
 
486
  $blog_id = get_current_blog_id();
487
  if (AIOWPSecurity_Utility::is_multisite_install() && !is_main_site( $blog_id ))
488
  {
489
+ //Hide config settings if MS and not main site
490
+ AIOWPSecurity_Utility::display_multisite_message();
491
  }
492
  else
493
  {
494
+ ?>
495
+ <div class="postbox">
496
+ <h3 class="hndle"><label for="title"><?php _e('Save the current wp-config.php file', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
497
+ <div class="inside">
498
+ <form action="" method="POST">
499
+ <?php wp_nonce_field('aiowpsec-save-wp-config-nonce'); ?>
500
+ <p class="description"><?php _e('Click the button below to backup and download the contents of the currently active wp-config.php file.', 'all-in-one-wp-security-and-firewall'); ?></p>
501
+ <input type="submit" name="aiowps_save_wp_config" value="<?php _e('Backup wp-config.php File', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
502
+
503
+ </form>
504
+ </div></div>
505
+ <div class="postbox">
506
+ <h3 class="hndle"><label for="title"><?php _e('Restore from a backed up wp-config file', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
507
+ <div class="inside">
508
+ <form action="" method="POST">
509
+ <?php wp_nonce_field('aiowpsec-restore-wp-config-nonce'); ?>
510
+ <table class="form-table">
511
+ <tr valign="top">
512
+ <th scope="row"><?php _e('wp-config file to restore from', 'all-in-one-wp-security-and-firewall')?>:</th>
513
+ <td>
514
+ <input type="button" id="aiowps_wp_config_file_button" name="aiowps_wp_config_file_button" class="button rbutton" value="<?php _e('Select Your wp-config File', 'all-in-one-wp-security-and-firewall'); ?>" />
515
+ <input name="aiowps_wp_config_file" type="text" id="aiowps_wp_config_file" value="" size="80" />
516
+ <p class="description">
517
+ <?php
518
+ _e('After selecting your file click the button below to restore your site using the backed up wp-config file (wp-config.php.backup.txt).', 'all-in-one-wp-security-and-firewall');
519
+ ?>
520
+ </p>
521
+ </td>
522
+ </tr>
523
+ </table>
524
+ <input type="submit" name="aiowps_restore_wp_config_button" value="<?php _e('Restore wp-config File', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
525
+ </form>
526
+ </div></div>
527
+ <!-- <div class="postbox">-->
528
+ <!-- <h3 class="hndle"><label for="title">--><?php //_e('View Contents of the currently active wp-config.php file', 'all-in-one-wp-security-and-firewall'); ?><!--</label></h3>-->
529
+ <!-- <div class="inside">-->
530
+ <!-- --><?php
531
  // $wp_config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
532
  // $wp_config_contents = AIOWPSecurity_Utility_File::get_file_contents($wp_config_file);
533
  // ?>
534
+ <!-- <textarea class="aio_text_area_file_output aio_width_80 aio_spacer_10_tb" rows="20" readonly>--><?php //echo $wp_config_contents; ?><!--</textarea>-->
535
+ <!-- </div></div>-->
536
 
537
+ <?php
538
  } //End if statement
539
  }
540
 
558
  $aiowps_feature_mgr->check_feature_status_and_recalculate_points();
559
 
560
  $this->show_msg_settings_updated();
561
+ }
562
  ?>
563
  <h2><?php _e('WP Generator Meta Tag & Version Info', 'all-in-one-wp-security-and-firewall')?></h2>
564
  <div class="aio_blue_box">
574
  </div>
575
 
576
  <div class="postbox">
577
+ <h3 class="hndle"><label for="title"><?php _e('WP Generator Meta Info', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
578
+ <div class="inside">
579
+ <?php
580
+ //Display security info badge
581
+ global $aiowps_feature_mgr;
582
+ $aiowps_feature_mgr->output_feature_details_badge("wp-generator-meta-tag");
583
+ ?>
584
+
585
+ <form action="" method="POST">
586
+ <?php wp_nonce_field('aiowpsec-remove-wp-meta-info-nonce'); ?>
587
+ <table class="form-table">
588
+ <tr valign="top">
589
+ <th scope="row"><?php _e('Remove WP Generator Meta Info', 'all-in-one-wp-security-and-firewall')?>:</th>
590
+ <td>
591
+ <input name="aiowps_remove_wp_generator_meta_info" type="checkbox"<?php if($aio_wp_security->configs->get_value('aiowps_remove_wp_generator_meta_info')=='1') echo ' checked="checked"'; ?> value="1"/>
592
+ <span class="description"><?php _e('Check this if you want to remove the version and meta info produced by WP from all pages', 'all-in-one-wp-security-and-firewall'); ?></span>
593
+ </td>
594
+ </tr>
595
+ </table>
596
+ <input type="submit" name="aiowps_save_remove_wp_meta_info" value="<?php _e('Save Settings', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
597
+ </form>
598
+ </div></div>
599
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  }
601
 
602
 
603
+ public function render_tab5() {
 
604
  global $aio_wp_security;
605
 
606
  global $wpdb;
723
  </div>
724
 
725
  <div class="postbox">
726
+ <h3 class="hndle"><label for="title"><?php _e('Export AIOWPS Settings', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
727
+ <div class="inside">
728
+ <form action="" method="POST">
729
+ <?php wp_nonce_field('aiowpsec-export-settings-nonce'); ?>
730
+ <table class="form-table">
731
+ <tr valign="top">
732
+ <span class="description"><?php _e('To export your All In One WP Security & Firewall settings click the button below.', 'all-in-one-wp-security-and-firewall'); ?></span>
733
+ </tr>
734
+ </table>
735
+ <input type="submit" name="aiowps_export_settings" value="<?php _e('Export AIOWPS Settings', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
736
+ </form>
737
+ </div></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
738
  <div class="postbox">
739
+ <h3 class="hndle"><label for="title"><?php _e('Import AIOWPS Settings', 'all-in-one-wp-security-and-firewall'); ?></label></h3>
740
+ <div class="inside">
741
+ <form action="" method="POST">
742
+ <?php wp_nonce_field('aiowpsec-import-settings-nonce'); ?>
743
+ <table class="form-table">
744
+ <tr valign="top">
745
+ <span class="description"><?php _e('Use this section to import your All In One WP Security & Firewall settings from a file. Alternatively, copy/paste the contents of your import file into the textarea below.', 'all-in-one-wp-security-and-firewall'); ?></span>
746
+ <th scope="row"><?php _e('Import File', 'all-in-one-wp-security-and-firewall')?>:</th>
747
+ <td>
748
+ <input type="button" id="aiowps_import_settings_file_button" name="aiowps_import_settings_file_button" class="button rbutton" value="<?php _e('Select Your Import Settings File', 'all-in-one-wp-security-and-firewall'); ?>" />
749
+ <input name="aiowps_import_settings_file" type="text" id="aiowps_import_settings_file" value="" size="80" />
750
+ <p class="description">
751
+ <?php
752
+ _e('After selecting your file, click the button below to apply the settings to your site.', 'all-in-one-wp-security-and-firewall');
753
+ ?>
754
+ </p>
755
+ </td>
756
+ </tr>
757
+ <tr valign="top">
758
+ <th scope="row"><?php _e('Copy/Paste Import Data', 'all-in-one-wp-security-and-firewall')?>:</th>
759
+ <td>
760
+ <textarea name="aiowps_import_settings_text" id="aiowps_import_settings_text" style="width:80%;height:140px;"></textarea>
761
+ </td>
762
+ </tr>
763
+ </table>
764
+ <input type="submit" name="aiowps_import_settings" value="<?php _e('Import AIOWPS Settings', 'all-in-one-wp-security-and-firewall')?>" class="button-primary" />
765
+ </form>
766
+ </div></div>
 
 
 
 
 
 
 
 
 
 
 
767
  <?php
 
768
  }
769
 
770
  function check_if_wp_config_contents($wp_file)
843
 
844
  }
845
 
846
+ } //end class
admin/wp-security-spam-menu.php CHANGED
@@ -32,13 +32,6 @@ class AIOWPSecurity_Spam_Menu extends AIOWPSecurity_Admin_Menu
32
  );
33
  }
34
 
35
- function get_current_tab()
36
- {
37
- $tab_keys = array_keys($this->menu_tabs);
38
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
39
- return $tab;
40
- }
41
-
42
  /*
43
  * Renders our tabs of this menu as nav items
44
  */
@@ -322,7 +315,7 @@ class AIOWPSecurity_Spam_Menu extends AIOWPSecurity_Admin_Menu
322
  }
323
  echo '<p><strong>'.__('Spammer IPs Added To Permanent Block List Today: ', 'all-in-one-wp-security-and-firewall').$todays_blocked_count.'</strong></p>'.
324
  '<hr><p><strong>'.__('All Time Total: ', 'all-in-one-wp-security-and-firewall').$total_count.'</strong></p>'.
325
- '<p><a class="button" href="admin.php?page='.AIOWPSEC_MAIN_MENU_SLUG.'&tab=tab4" target="_blank">'.__('View Blocked IPs','all-in-one-wp-security-and-firewall').'</a></p>';
326
  }
327
  ?>
328
  </div>
32
  );
33
  }
34
 
 
 
 
 
 
 
 
35
  /*
36
  * Renders our tabs of this menu as nav items
37
  */
315
  }
316
  echo '<p><strong>'.__('Spammer IPs Added To Permanent Block List Today: ', 'all-in-one-wp-security-and-firewall').$todays_blocked_count.'</strong></p>'.
317
  '<hr><p><strong>'.__('All Time Total: ', 'all-in-one-wp-security-and-firewall').$total_count.'</strong></p>'.
318
+ '<p><a class="button" href="admin.php?page='.AIOWPSEC_MAIN_MENU_SLUG.'&tab=tab3" target="_blank">'.__('View Blocked IPs','all-in-one-wp-security-and-firewall').'</a></p>';
319
  }
320
  ?>
321
  </div>
admin/wp-security-user-accounts-menu.php CHANGED
@@ -35,13 +35,6 @@ class AIOWPSecurity_User_Accounts_Menu extends AIOWPSecurity_Admin_Menu
35
  );
36
  }
37
 
38
- function get_current_tab()
39
- {
40
- $tab_keys = array_keys($this->menu_tabs);
41
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
42
- return $tab;
43
- }
44
-
45
  /*
46
  * Renders our tabs of this menu as nav items
47
  */
@@ -174,7 +167,7 @@ class AIOWPSecurity_User_Accounts_Menu extends AIOWPSecurity_Admin_Menu
174
  $login_nick_name_accounts = AIOWPSecurity_Utility::check_identical_login_and_nick_names();
175
  if ($login_nick_name_accounts) {
176
  echo '<div class="aio_red_box"><p>'.__('Your site currently has the following accounts which have an identical login name and display name.', 'all-in-one-wp-security-and-firewall').'
177
- <span class="description">('.__('Click on the link to edit the settings of that particular user account', 'all-in-one-wp-security-and-firewall').'</span></p></div>';
178
  ?>
179
  <table class="form-table">
180
  <?php
@@ -342,4 +335,4 @@ class AIOWPSecurity_User_Accounts_Menu extends AIOWPSecurity_Admin_Menu
342
  }
343
  return $account_output;
344
  }
345
- } //end class
35
  );
36
  }
37
 
 
 
 
 
 
 
 
38
  /*
39
  * Renders our tabs of this menu as nav items
40
  */
167
  $login_nick_name_accounts = AIOWPSecurity_Utility::check_identical_login_and_nick_names();
168
  if ($login_nick_name_accounts) {
169
  echo '<div class="aio_red_box"><p>'.__('Your site currently has the following accounts which have an identical login name and display name.', 'all-in-one-wp-security-and-firewall').'
170
+ <span class="description">('.__('Follow the link to edit the user profile of that particular user account, change Nickname, choose a different Display name compared to Username, and press the "Update User" button.)', 'all-in-one-wp-security-and-firewall').'</span></p></div>';
171
  ?>
172
  <table class="form-table">
173
  <?php
335
  }
336
  return $account_output;
337
  }
338
+ } //end class
admin/wp-security-user-login-menu.php CHANGED
@@ -33,13 +33,6 @@ class AIOWPSecurity_User_Login_Menu extends AIOWPSecurity_Admin_Menu
33
  );
34
  }
35
 
36
- function get_current_tab()
37
- {
38
- $tab_keys = array_keys($this->menu_tabs);
39
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
40
- return $tab;
41
- }
42
-
43
  /*
44
  * Renders our tabs of this menu as nav items
45
  */
@@ -325,7 +318,7 @@ class AIOWPSecurity_User_Login_Menu extends AIOWPSecurity_Admin_Menu
325
  <div class="inside">
326
  <div class="aio_blue_box aio_width_80">
327
  <?php
328
- $locked_ips_link = '<a href="admin.php?page='.AIOWPSEC_MAIN_MENU_SLUG.'&tab=tab3">Locked IP Addresses</a>';
329
  echo '<p>'.sprintf( __('To see a list of all locked IP addresses and ranges go to the %s tab in the dashboard menu.', 'all-in-one-wp-security-and-firewall'), $locked_ips_link).'</p>';
330
  ?>
331
  </div>
33
  );
34
  }
35
 
 
 
 
 
 
 
 
36
  /*
37
  * Renders our tabs of this menu as nav items
38
  */
318
  <div class="inside">
319
  <div class="aio_blue_box aio_width_80">
320
  <?php
321
+ $locked_ips_link = '<a href="admin.php?page='.AIOWPSEC_MAIN_MENU_SLUG.'&tab=tab2">Locked IP Addresses</a>';
322
  echo '<p>'.sprintf( __('To see a list of all locked IP addresses and ranges go to the %s tab in the dashboard menu.', 'all-in-one-wp-security-and-firewall'), $locked_ips_link).'</p>';
323
  ?>
324
  </div>
admin/wp-security-user-registration-menu.php CHANGED
@@ -30,13 +30,6 @@ class AIOWPSecurity_User_Registration_Menu extends AIOWPSecurity_Admin_Menu
30
  );
31
  }
32
 
33
- function get_current_tab()
34
- {
35
- $tab_keys = array_keys($this->menu_tabs);
36
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : $tab_keys[0];
37
- return $tab;
38
- }
39
-
40
  /*
41
  * Renders our tabs of this menu as nav items
42
  */
30
  );
31
  }
32
 
 
 
 
 
 
 
 
33
  /*
34
  * Renders our tabs of this menu as nav items
35
  */
classes/grade-system/wp-security-feature-item-manager.php CHANGED
@@ -1,876 +1,724 @@
1
  <?php
2
 
3
- class AIOWPSecurity_Feature_Item_Manager
4
- {
5
- var $feature_items;
6
- var $total_points = 0;
7
- var $total_achievable_points = 0;
8
-
9
- var $feature_point_1 = "5";
10
- var $feature_point_2 = "10";
11
- var $feature_point_3 = "15";
12
- var $feature_point_4 = "20";
13
- var $sec_level_basic = "1";
14
- var $sec_level_inter = "2";
15
- var $sec_level_advanced = "3";
16
- var $feature_active = "active";
17
- var $feature_inactive = "inactive";
18
- var $feature_partial = "partial";
19
-
20
- function __construct(){
21
-
22
- }
23
-
24
- function initialize_features()
25
- {
26
- $this->feature_items = array();
27
- //Settings Menu Features
28
- //WP Generator Meta
29
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("wp-generator-meta-tag", __("Remove WP Generator Meta Tag", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_basic);
30
-
31
- //Prevent Image Hotlinks
32
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("prevent-hotlinking", __("Prevent Image Hotlinking", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
33
-
34
- //User Accounts Menu Features
35
- //Change Admin Username
36
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-accounts-change-admin-user", __("Change Admin Username", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_basic);
37
- //Change Display Name
38
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-accounts-display-name", __("Change Display Name", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_basic);
39
-
40
- //User Login Menu Features
41
- //Locking Lockdown
42
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-login-login-lockdown", __("Login Lockdown", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
43
- //Login Captcha
44
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-login-captcha", __("Login Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
45
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("custom-login-captcha", __("Custom Login Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
46
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("woo-login-captcha", __("Woo Login Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
47
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("woo-lostpassword-captcha", __("Woo Lost Password Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
48
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("woo-register-captcha", __("Woo Register Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
49
- //Lost Password Captcha
50
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("lost-password-captcha", __("Lost Password Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
51
- //Login whitelisting
52
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("whitelist-manager-ip-login-whitelisting", __("Login IP Whitelisting", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_inter);
53
- //Force Logout
54
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-login-force-logout", __("Force Logout", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_basic);
55
-
56
- //User Registration
57
- //Manually approve registrations
58
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("manually-approve-registrations", __("Registration Approval", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
59
- //Registration Captcha
60
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-registration-captcha", __("Registration Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
61
- //Registration Honeypot
62
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("registration-honeypot", __("Enable Registration Honeypot", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_inter);
63
-
64
- //Database Security Menu Features
65
- //DB Prefix
66
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("db-security-db-prefix", __("DB Prefix", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_inter);
67
- //DB Backup
68
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("db-security-db-backup", __("DB Backup", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
69
-
70
- //File System Security Menu Features
71
- //File Permissions
72
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("filesystem-file-permissions", __("File Permissions", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
73
- //PHP File Editing
74
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("filesystem-file-editing", __("File Editing", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
75
- //Prevent Access WP Install Files
76
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("block-wp-files-access", __("WordPress Files Access", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
77
-
78
- //Blacklist Manager Menu Features
79
- //IP and user agent blacklisting
80
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("blacklist-manager-ip-user-agent-blacklisting", __("IP and User Agent Blacklisting", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_advanced);
81
-
82
- //Firewall Menu Features
83
- //Basic firewall
84
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-basic-rules", __("Enable Basic Firewall", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_basic);
85
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-pingback-rules", __("Enable Pingback Vulnerability Protection", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_basic);
86
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-block-debug-file-access", __("Block Accesss to Debug Log File", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_inter);
87
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-enable-404-blocking", __("Enable IP blocking for 404 detection", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_inter);
88
-
89
- //Brute Force Menu Features
90
- //Rename Login page
91
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("bf-rename-login-page", __("Enable Rename Login Page", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_inter);
92
- //Login Honeypot
93
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("login-honeypot", __("Enable Login Honeypot", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_inter);
94
-
95
- //Additional and Advanced firewall
96
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-enable-brute-force-attack-prevention", __("Enable Brute Force Attack Prevention", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_advanced);
97
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-disable-index-views", __("Disable Index Views", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_inter);
98
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-disable-trace-track", __("Disable Trace and Track", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_advanced);
99
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-forbid-proxy-comments", __("Forbid Proxy Comments", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_advanced);
100
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-deny-bad-queries", __("Deny Bad Queries", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_advanced);
101
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-advanced-character-string-filter", __("Advanced Character String Filter", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_advanced);
102
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-enable-5g-6g-blacklist", __("5G/6G Blacklist", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_advanced);
103
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-block-fake-googlebots", __("Block Fake Googlebots", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_advanced);
104
- //SPAM Prevention
105
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("block-spambots", __("Block Spambots", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
106
- //Comment Captcha
107
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("comment-form-captcha", __("Comment Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
108
- //BuddyPress Registration Captcha
109
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("bp-register-captcha", __("BuddyPress Registration Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_basic);
110
- //BBPress new topic Captcha
111
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("bbp-new-topic-captcha", __("BBPress New Topic Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_basic);
112
-
113
- //Filescan
114
- //File change detection
115
- $this->feature_items[] = new AIOWPSecurity_Feature_Item("scan-file-change-detection", __("File Change Detection", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_inter);
116
-
117
- }
118
-
119
- function get_feature_item_by_id($feature_id)
120
- {
121
- foreach($this->feature_items as $item)
122
- {
123
- if($item->feature_id == $feature_id)
124
- {
125
- return $item;
126
- }
127
- }
128
- return "";
129
- }
130
-
131
- function output_feature_details_badge($feature_id)
132
- {
133
- $cau_feature_item = $this->get_feature_item_by_id($feature_id);
134
- $cau_security_level = $cau_feature_item->security_level;
135
- $cau_security_points = $cau_feature_item->item_points;
136
- $cau_your_points = 0;
137
- if($cau_feature_item->feature_status == $this->feature_active){
138
- $cau_your_points = $cau_security_points;
139
- }
140
- $level_str = $cau_feature_item->get_security_level_string($cau_security_level);
141
- ?>
142
- <div class="aiowps_feature_details_badge">
143
- <div class="aiowps_feature_details_badge_difficulty" title="Feature Difficulty">
144
- <span class="aiowps_feature_details_badge_difficulty_text"><?php _e($level_str, 'all-in-one-wp-security-and-firewall'); ?></span>
145
- </div>
146
- <div class="aiowps_feature_details_badge_points" title="Security Points">
147
- <span class="aiowps_feature_details_badge_points_text"><?php echo $cau_your_points .'/'. $cau_security_points; ?></span>
148
- </div>
149
- </div>
150
- <?php
151
- }
152
-
153
- function check_feature_status_and_recalculate_points()
154
- {
155
- $this->check_and_set_feature_status();
156
- $this->calculate_total_points();
157
- }
158
-
159
- function check_and_set_feature_status()
160
- {
161
- foreach($this->feature_items as $item)
162
- {
163
- if($item->feature_id == "wp-generator-meta-tag")
164
- {
165
- $this->check_remove_wp_generator_meta_feature($item);
166
- }
167
-
168
- if($item->feature_id == "prevent-hotlinking")
169
- {
170
- $this->check_prevent_hotlinking_feature($item);
171
- }
172
-
173
- if($item->feature_id == "user-accounts-change-admin-user")
174
- {
175
- $this->check_user_accounts_change_admin_user_feature($item);
176
- }
177
- if($item->feature_id == "user-accounts-display-name")
178
- {
179
- $this->check_user_accounts_display_name_feature($item);
180
- }
181
-
182
- if($item->feature_id == "db-security-db-prefix")
183
- {
184
- $this->check_db_security_db_prefix_feature($item);
185
- }
186
- if($item->feature_id == "db-security-db-backup")
187
- {
188
- $this->check_db_security_db_backup_feature($item);
189
- }
190
-
191
- if($item->feature_id == "user-login-login-lockdown")
192
- {
193
- $this->check_login_lockdown_feature($item);
194
- }
195
- if($item->feature_id == "user-login-captcha")
196
- {
197
- $this->check_login_captcha_feature($item);
198
- }
199
- if($item->feature_id == "custom-login-captcha")
200
- {
201
- $this->check_custom_login_captcha_feature($item);
202
- }
203
- if($item->feature_id == "woo-login-captcha")
204
- {
205
- $this->check_woo_login_captcha_feature($item);
206
- }
207
- if($item->feature_id == "woo-lostpassword-captcha")
208
- {
209
- $this->check_woo_lostpassword_captcha_feature($item);
210
- }
211
- if($item->feature_id == "woo-register-captcha")
212
- {
213
- $this->check_woo_register_captcha_feature($item);
214
- }
215
- if($item->feature_id == "lost-password-captcha")
216
- {
217
- $this->check_lost_password_captcha_feature($item);
218
- }
219
- if($item->feature_id == "comment-form-captcha")
220
- {
221
- $this->check_comment_captcha_feature($item);
222
- }
223
- if($item->feature_id == "bp-register-captcha")
224
- {
225
- $this->check_bp_register_captcha_feature($item);
226
- }
227
- if($item->feature_id == "bbp-new-topic-captcha")
228
- {
229
- $this->check_bbp_new_topic_captcha_feature($item);
230
- }
231
- if($item->feature_id == "whitelist-manager-ip-login-whitelisting")
232
- {
233
- $this->check_login_whitelist_feature($item);
234
- }
235
- if($item->feature_id == "user-login-force-logout")
236
- {
237
- $this->check_force_logout_feature($item);
238
- }
239
-
240
- if($item->feature_id == "manually-approve-registrations")
241
- {
242
- $this->check_registration_approval_feature($item);
243
- }
244
- if($item->feature_id == "user-registration-captcha")
245
- {
246
- $this->check_registration_captcha_feature($item);
247
- }
248
- if($item->feature_id == "registration-honeypot")
249
- {
250
- $this->check_enable_registration_honeypot_feature($item);
251
- }
252
-
253
- if($item->feature_id == "filesystem-file-permissions")
254
- {
255
- $this->check_filesystem_permissions_feature($item);
256
- }
257
- if($item->feature_id == "filesystem-file-editing")
258
- {
259
- $this->check_filesystem_file_editing_feature($item);
260
- }
261
- if($item->feature_id == "block-wp-files-access")
262
- {
263
- $this->check_block_wp_files_access_feature($item);
264
- }
265
-
266
- if($item->feature_id == "blacklist-manager-ip-user-agent-blacklisting")
267
- {
268
- $this->check_enable_ip_useragent_blacklist_feature($item);
269
- }
270
-
271
- if($item->feature_id == "firewall-basic-rules")
272
- {
273
- $this->check_enable_basic_firewall_feature($item);
274
- }
275
-
276
- if($item->feature_id == "firewall-pingback-rules")
277
- {
278
- $this->check_enable_pingback_firewall_feature($item);
279
- }
280
-
281
- if($item->feature_id == "firewall-block-debug-file-access")
282
- {
283
- $this->check_debug_file_access_block_firewall_feature($item);
284
- }
285
-
286
- if($item->feature_id == "firewall-enable-404-blocking")
287
- {
288
- $this->check_enable_404_blocking_feature($item);
289
- }
290
-
291
- if($item->feature_id == "firewall-enable-brute-force-attack-prevention")
292
- {
293
- $this->check_enable_bfap_firewall_feature($item);
294
- }
295
- if($item->feature_id == "firewall-disable-index-views")
296
- {
297
- $this->check_disable_index_views_firewall_feature($item);
298
- }
299
- if($item->feature_id == "firewall-disable-trace-track")
300
- {
301
- $this->check_disable_trace_track_firewall_feature($item);
302
- }
303
- if($item->feature_id == "firewall-forbid-proxy-comments")
304
- {
305
- $this->check_forbid_proxy_comments_firewall_feature($item);
306
- }
307
- if($item->feature_id == "firewall-deny-bad-queries")
308
- {
309
- $this->check_deny_bad_queries_firewall_feature($item);
310
- }
311
- if($item->feature_id == "firewall-advanced-character-string-filter")
312
- {
313
- $this->check_advanced_char_string_filter_firewall_feature($item);
314
- }
315
- if($item->feature_id == "firewall-enable-5g-6g-blacklist")
316
- {
317
- $this->check_enable_5G_6G_blacklist_firewall_feature($item);
318
- }
319
- if($item->feature_id == "firewall-block-fake-googlebots")
320
- {
321
- $this->check_block_fake_googlebots_firewall_feature($item);
322
- }
323
-
324
- if($item->feature_id == "bf-rename-login-page")
325
- {
326
- $this->check_enable_rename_login_page_feature($item);
327
- }
328
-
329
- if($item->feature_id == "login-honeypot")
330
- {
331
- $this->check_enable_login_honeypot_feature($item);
332
- }
333
-
334
- if($item->feature_id == "block-spambots")
335
- {
336
- $this->check_enable_block_spambots_feature($item);
337
- }
338
-
339
- if($item->feature_id == "scan-file-change-detection")
340
- {
341
- $this->check_enable_fcd_scan_feature($item);
342
- }
343
-
344
- }
345
- }
346
-
347
- function calculate_total_points()
348
- {
349
- foreach($this->feature_items as $item)
350
- {
351
- if($item->feature_status == "active")
352
- {
353
- $this->total_points = $this->total_points + intval($item->item_points);
354
- }
355
- }
356
- }
357
-
358
- function get_total_site_points()
359
- {
360
- return $this->total_points;
361
- }
362
-
363
- function get_total_achievable_points()
364
- {
365
- foreach($this->feature_items as $item)
366
- {
367
- $this->total_achievable_points = $this->total_achievable_points + intval($item->item_points);
368
- }
369
- return $this->total_achievable_points;
370
- }
371
-
372
- function check_remove_wp_generator_meta_feature($item)
373
- {
374
- global $aio_wp_security;
375
- if ($aio_wp_security->configs->get_value('aiowps_remove_wp_generator_meta_info') == '1') {
376
- $item->set_feature_status($this->feature_active);
377
- }
378
- else
379
- {
380
- $item->set_feature_status($this->feature_inactive);
381
- }
382
- }
383
-
384
- function check_prevent_hotlinking_feature($item)
385
- {
386
- global $aio_wp_security;
387
- if ($aio_wp_security->configs->get_value('aiowps_prevent_hotlinking') == '1') {
388
- $item->set_feature_status($this->feature_active);
389
- }
390
- else
391
- {
392
- $item->set_feature_status($this->feature_inactive);
393
- }
394
- }
395
-
396
- function check_user_accounts_change_admin_user_feature($item)
397
- {
398
- if (AIOWPSecurity_Utility::check_user_exists('admin')) {
399
- $item->set_feature_status($this->feature_inactive);
400
- }
401
- else
402
- {
403
- $item->set_feature_status($this->feature_active);
404
- }
405
- }
406
 
407
- function check_user_accounts_display_name_feature($item)
408
- {
409
- if (AIOWPSecurity_Utility::check_identical_login_and_nick_names()) {
410
- $item->set_feature_status($this->feature_inactive);
411
- }
412
- else
413
- {
414
- $item->set_feature_status($this->feature_active);
415
- }
416
- }
417
-
418
- function check_login_lockdown_feature($item)
419
- {
420
- global $aio_wp_security;
421
- if ($aio_wp_security->configs->get_value('aiowps_enable_login_lockdown') == '1') {
422
- $item->set_feature_status($this->feature_active);
423
- }
424
- else
425
- {
426
- $item->set_feature_status($this->feature_inactive);
427
- }
428
- }
429
-
430
- function check_login_captcha_feature($item)
431
- {
432
- global $aio_wp_security;
433
- if ($aio_wp_security->configs->get_value('aiowps_enable_login_captcha') == '1') {
434
- $item->set_feature_status($this->feature_active);
435
- }
436
- else
437
- {
438
- $item->set_feature_status($this->feature_inactive);
439
- }
440
- }
441
-
442
- function check_custom_login_captcha_feature($item)
443
- {
444
- global $aio_wp_security;
445
- if ($aio_wp_security->configs->get_value('aiowps_enable_custom_login_captcha') == '1') {
446
- $item->set_feature_status($this->feature_active);
447
- }
448
- else
449
- {
450
- $item->set_feature_status($this->feature_inactive);
451
- }
452
- }
453
-
454
- function check_woo_login_captcha_feature($item)
455
- {
456
- global $aio_wp_security;
457
- if ($aio_wp_security->configs->get_value('aiowps_enable_woo_login_captcha') == '1') {
458
- $item->set_feature_status($this->feature_active);
459
- }
460
- else
461
- {
462
- $item->set_feature_status($this->feature_inactive);
463
- }
464
- }
465
-
466
- function check_woo_lostpassword_captcha_feature($item)
467
- {
468
- global $aio_wp_security;
469
- if ($aio_wp_security->configs->get_value('aiowps_enable_woo_lostpassword_captcha') == '1') {
470
- $item->set_feature_status($this->feature_active);
471
- }
472
- else
473
- {
474
- $item->set_feature_status($this->feature_inactive);
475
- }
476
- }
477
-
478
- function check_woo_register_captcha_feature($item)
479
- {
480
- global $aio_wp_security;
481
- if ($aio_wp_security->configs->get_value('aiowps_enable_woo_register_captcha') == '1') {
482
- $item->set_feature_status($this->feature_active);
483
- }
484
- else
485
- {
486
- $item->set_feature_status($this->feature_inactive);
487
- }
488
- }
489
-
490
- function check_lost_password_captcha_feature($item)
491
- {
492
- global $aio_wp_security;
493
- if ($aio_wp_security->configs->get_value('aiowps_enable_lost_password_captcha') == '1') {
494
- $item->set_feature_status($this->feature_active);
495
- }
496
- else
497
- {
498
- $item->set_feature_status($this->feature_inactive);
499
- }
500
- }
501
-
502
- function check_comment_captcha_feature($item)
503
- {
504
- global $aio_wp_security;
505
- if ($aio_wp_security->configs->get_value('aiowps_enable_comment_captcha') == '1') {
506
- $item->set_feature_status($this->feature_active);
507
- }
508
- else
509
- {
510
- $item->set_feature_status($this->feature_inactive);
511
- }
512
- }
513
-
514
- function check_bp_register_captcha_feature($item)
515
- {
516
- global $aio_wp_security;
517
- if ($aio_wp_security->configs->get_value('aiowps_enable_bp_register_captcha') == '1') {
518
- $item->set_feature_status($this->feature_active);
519
- }
520
- else
521
- {
522
- $item->set_feature_status($this->feature_inactive);
523
- }
524
- }
525
-
526
- function check_bbp_new_topic_captcha_feature($item)
527
- {
528
- global $aio_wp_security;
529
- if ($aio_wp_security->configs->get_value('aiowps_enable_bbp_new_topic_captcha') == '1') {
530
- $item->set_feature_status($this->feature_active);
531
- }
532
- else
533
- {
534
- $item->set_feature_status($this->feature_inactive);
535
- }
536
- }
537
-
538
- function check_login_whitelist_feature($item)
539
- {
540
- global $aio_wp_security;
541
- if ($aio_wp_security->configs->get_value('aiowps_enable_whitelisting') == '1') {
542
- $item->set_feature_status($this->feature_active);
543
- }
544
- else
545
- {
546
- $item->set_feature_status($this->feature_inactive);
547
- }
548
- }
549
-
550
- function check_force_logout_feature($item)
551
- {
552
- global $aio_wp_security;
553
- if ($aio_wp_security->configs->get_value('aiowps_enable_forced_logout') == '1') {
554
- $item->set_feature_status($this->feature_active);
555
- }
556
- else
557
- {
558
- $item->set_feature_status($this->feature_inactive);
559
- }
560
- }
561
-
562
- function check_registration_approval_feature($item)
563
- {
564
- global $aio_wp_security;
565
- if ($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1') {
566
- $item->set_feature_status($this->feature_active);
567
- }
568
- else
569
- {
570
- $item->set_feature_status($this->feature_inactive);
571
- }
572
- }
573
-
574
- function check_registration_captcha_feature($item)
575
- {
576
- global $aio_wp_security;
577
- if ($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') {
578
- $item->set_feature_status($this->feature_active);
579
- }
580
- else
581
- {
582
- $item->set_feature_status($this->feature_inactive);
583
- }
584
- }
585
-
586
- function check_enable_registration_honeypot_feature($item)
587
- {
588
- global $aio_wp_security;
589
- if ($aio_wp_security->configs->get_value('aiowps_enable_registration_honeypot') == '1') {
590
- $item->set_feature_status($this->feature_active);
591
- }
592
- else
593
- {
594
- $item->set_feature_status($this->feature_inactive);
595
- }
596
- }
597
-
598
- function check_db_security_db_prefix_feature($item)
599
- {
600
- global $wpdb;
601
- if ($wpdb->prefix == 'wp_') {
602
- $item->set_feature_status($this->feature_inactive);
603
- }
604
- else
605
- {
606
- $item->set_feature_status($this->feature_active);
607
- }
608
- }
609
-
610
- function check_db_security_db_backup_feature($item)
611
- {
612
- global $aio_wp_security;
613
- if ($aio_wp_security->configs->get_value('aiowps_enable_automated_backups') == '1') {
614
- $item->set_feature_status($this->feature_active);
615
- }
616
- else
617
- {
618
- $item->set_feature_status($this->feature_inactive);
619
- }
620
- }
621
-
622
- function check_filesystem_permissions_feature($item)
623
- {
624
- //TODO
625
- $is_secure = 1;
626
- $util = new AIOWPSecurity_Utility_File;
627
- $files_dirs_to_check = $util->files_and_dirs_to_check;
628
- foreach ($files_dirs_to_check as $file_or_dir)
629
- {
630
- $actual_perm = AIOWPSecurity_Utility_File::get_file_permission($file_or_dir['path']);
631
- $is_secure = $is_secure*AIOWPSecurity_Utility_File::is_file_permission_secure($file_or_dir['permissions'], $actual_perm);
632
- }
633
-
634
- //Only if all of the files' permissions are deemed secure give this a thumbs up
635
- if ($is_secure == 1)
636
- {
637
- $item->set_feature_status($this->feature_active);
638
- }
639
- else
640
- {
641
- $item->set_feature_status($this->feature_inactive);
642
- }
643
- }
644
-
645
- function check_filesystem_file_editing_feature($item)
646
- {
647
- global $aio_wp_security;
648
- if ($aio_wp_security->configs->get_value('aiowps_disable_file_editing') == '1') {
649
- $item->set_feature_status($this->feature_active);
650
- }
651
- else
652
- {
653
- $item->set_feature_status($this->feature_inactive);
654
- }
655
- }
656
-
657
- function check_block_wp_files_access_feature($item)
658
- {
659
- global $aio_wp_security;
660
- if ($aio_wp_security->configs->get_value('aiowps_prevent_default_wp_file_access') == '1') {
661
- $item->set_feature_status($this->feature_active);
662
- }
663
- else
664
- {
665
- $item->set_feature_status($this->feature_inactive);
666
- }
667
- }
668
-
669
- function check_enable_ip_useragent_blacklist_feature($item)
670
- {
671
- global $aio_wp_security;
672
- if ($aio_wp_security->configs->get_value('aiowps_enable_blacklisting') == '1') {
673
- $item->set_feature_status($this->feature_active);
674
- }
675
- else
676
- {
677
- $item->set_feature_status($this->feature_inactive);
678
- }
679
- }
680
-
681
- function check_enable_basic_firewall_feature($item)
682
- {
683
- global $aio_wp_security;
684
- if ($aio_wp_security->configs->get_value('aiowps_enable_basic_firewall') == '1') {
685
- $item->set_feature_status($this->feature_active);
686
- }
687
- else
688
- {
689
- $item->set_feature_status($this->feature_inactive);
690
- }
691
- }
692
-
693
- function check_enable_pingback_firewall_feature($item)
694
- {
695
- global $aio_wp_security;
696
- if ($aio_wp_security->configs->get_value('aiowps_enable_pingback_firewall') == '1') {
697
- $item->set_feature_status($this->feature_active);
698
- }
699
- else
700
- {
701
- $item->set_feature_status($this->feature_inactive);
702
- }
703
- }
704
-
705
- function check_debug_file_access_block_firewall_feature($item)
706
- {
707
- global $aio_wp_security;
708
- if ($aio_wp_security->configs->get_value('aiowps_block_debug_log_file_access') == '1') {
709
- $item->set_feature_status($this->feature_active);
710
- }
711
- else
712
- {
713
- $item->set_feature_status($this->feature_inactive);
714
- }
715
- }
716
-
717
- function check_disable_trace_track_firewall_feature($item)
718
- {
719
- global $aio_wp_security;
720
- if ($aio_wp_security->configs->get_value('aiowps_disable_trace_and_track') == '1') {
721
- $item->set_feature_status($this->feature_active);
722
- }
723
- else
724
- {
725
- $item->set_feature_status($this->feature_inactive);
726
- }
727
- }
728
-
729
- function check_disable_index_views_firewall_feature($item)
730
- {
731
- global $aio_wp_security;
732
- if ($aio_wp_security->configs->get_value('aiowps_disable_index_views') == '1') {
733
- $item->set_feature_status($this->feature_active);
734
- }
735
- else
736
- {
737
- $item->set_feature_status($this->feature_inactive);
738
- }
739
- }
740
-
741
- function check_enable_bfap_firewall_feature($item)
742
- {
743
- global $aio_wp_security;
744
- if ($aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention') == '1') {
745
- $item->set_feature_status($this->feature_active);
746
- }
747
- else
748
- {
749
- $item->set_feature_status($this->feature_inactive);
750
- }
751
- }
752
-
753
- function check_forbid_proxy_comments_firewall_feature($item)
754
- {
755
- global $aio_wp_security;
756
- if ($aio_wp_security->configs->get_value('aiowps_forbid_proxy_comments') == '1') {
757
- $item->set_feature_status($this->feature_active);
758
- }
759
- else
760
- {
761
- $item->set_feature_status($this->feature_inactive);
762
- }
763
- }
764
-
765
- function check_deny_bad_queries_firewall_feature($item)
766
- {
767
- global $aio_wp_security;
768
- if ($aio_wp_security->configs->get_value('aiowps_deny_bad_query_strings') == '1') {
769
- $item->set_feature_status($this->feature_active);
770
- }
771
- else
772
- {
773
- $item->set_feature_status($this->feature_inactive);
774
- }
775
- }
776
-
777
- function check_advanced_char_string_filter_firewall_feature($item)
778
- {
779
- global $aio_wp_security;
780
- if ($aio_wp_security->configs->get_value('aiowps_advanced_char_string_filter') == '1') {
781
- $item->set_feature_status($this->feature_active);
782
- }
783
- else
784
- {
785
- $item->set_feature_status($this->feature_inactive);
786
- }
787
- }
788
-
789
- function check_enable_5G_6G_blacklist_firewall_feature($item)
790
- {
791
- global $aio_wp_security;
792
- if ($aio_wp_security->configs->get_value('aiowps_enable_5g_firewall') == '1') {
793
- $item->set_feature_status($this->feature_active);
794
- }
795
- else if ($aio_wp_security->configs->get_value('aiowps_enable_6g_firewall') == '1') {
796
- $item->set_feature_status($this->feature_active);
797
- }
798
- else
799
- {
800
- $item->set_feature_status($this->feature_inactive);
801
- }
802
- }
803
-
804
- function check_block_fake_googlebots_firewall_feature($item)
805
- {
806
- global $aio_wp_security;
807
- if ($aio_wp_security->configs->get_value('aiowps_block_fake_googlebots') == '1') {
808
- $item->set_feature_status($this->feature_active);
809
- }
810
- else
811
- {
812
- $item->set_feature_status($this->feature_inactive);
813
- }
814
- }
815
-
816
- function check_enable_404_blocking_feature($item)
817
- {
818
- global $aio_wp_security;
819
- if ($aio_wp_security->configs->get_value('aiowps_enable_404_IP_lockout') == '1') {
820
- $item->set_feature_status($this->feature_active);
821
- }
822
- else
823
- {
824
- $item->set_feature_status($this->feature_inactive);
825
- }
826
- }
827
-
828
- function check_enable_rename_login_page_feature($item)
829
- {
830
- global $aio_wp_security;
831
- if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
832
- $item->set_feature_status($this->feature_active);
833
- }
834
- else
835
- {
836
- $item->set_feature_status($this->feature_inactive);
837
- }
838
- }
839
-
840
- function check_enable_login_honeypot_feature($item)
841
- {
842
- global $aio_wp_security;
843
- if ($aio_wp_security->configs->get_value('aiowps_enable_login_honeypot') == '1') {
844
- $item->set_feature_status($this->feature_active);
845
- }
846
- else
847
- {
848
- $item->set_feature_status($this->feature_inactive);
849
- }
850
- }
851
-
852
- function check_enable_block_spambots_feature($item)
853
- {
854
- global $aio_wp_security;
855
- if ($aio_wp_security->configs->get_value('aiowps_enable_spambot_blocking') == '1') {
856
- $item->set_feature_status($this->feature_active);
857
- }
858
- else
859
- {
860
- $item->set_feature_status($this->feature_inactive);
861
- }
862
- }
863
-
864
- function check_enable_fcd_scan_feature($item)
865
- {
866
- global $aio_wp_security;
867
- if ($aio_wp_security->configs->get_value('aiowps_enable_automated_fcd_scan') == '1') {
868
- $item->set_feature_status($this->feature_active);
869
- }
870
- else
871
- {
872
- $item->set_feature_status($this->feature_inactive);
873
- }
874
- }
875
-
876
- }
1
  <?php
2
 
3
+ class AIOWPSecurity_Feature_Item_Manager {
4
+
5
+ public $feature_items;
6
+
7
+ public $total_points = 0;
8
+
9
+ public $total_achievable_points = 0;
10
+
11
+ public $feature_point_1 = "5";
12
+
13
+ public $feature_point_2 = "10";
14
+
15
+ public $feature_point_3 = "15";
16
+
17
+ public $feature_point_4 = "20";
18
+
19
+ public $sec_level_basic = "1";
20
+
21
+ public $sec_level_inter = "2";
22
+
23
+ public $sec_level_advanced = "3";
24
+
25
+ public $feature_active = "active";
26
+
27
+ public $feature_inactive = "inactive";
28
+
29
+ public $feature_partial = "partial";
30
+
31
+ public function __construct() {
32
+
33
+ }
34
+
35
+ public function initialize_features() {
36
+ $this->feature_items = array();
37
+ //Settings Menu Features
38
+ //WP Generator Meta
39
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("wp-generator-meta-tag", __("Remove WP Generator Meta Tag", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_basic);
40
+
41
+ //Prevent Image Hotlinks
42
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("prevent-hotlinking", __("Prevent Image Hotlinking", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
43
+
44
+ //User Accounts Menu Features
45
+ //Change Admin Username
46
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-accounts-change-admin-user", __("Change Admin Username", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_basic);
47
+ //Change Display Name
48
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-accounts-display-name", __("Change Display Name", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_basic);
49
+
50
+ //User Login Menu Features
51
+ //Locking Lockdown
52
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-login-login-lockdown", __("Login Lockdown", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
53
+ //Login Captcha
54
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-login-captcha", __("Login Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
55
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("custom-login-captcha", __("Custom Login Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
56
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("woo-login-captcha", __("Woo Login Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
57
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("woo-lostpassword-captcha", __("Woo Lost Password Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
58
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("woo-register-captcha", __("Woo Register Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
59
+ //Lost Password Captcha
60
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("lost-password-captcha", __("Lost Password Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
61
+ //Login whitelisting
62
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("whitelist-manager-ip-login-whitelisting", __("Login IP Whitelisting", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_inter);
63
+ //Force Logout
64
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-login-force-logout", __("Force Logout", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_basic);
65
+
66
+ //User Registration
67
+ //Manually approve registrations
68
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("manually-approve-registrations", __("Registration Approval", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
69
+ //Registration Captcha
70
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("user-registration-captcha", __("Registration Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
71
+ //Registration Honeypot
72
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("registration-honeypot", __("Enable Registration Honeypot", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_inter);
73
+
74
+ //Database Security Menu Features
75
+ //DB Prefix
76
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("db-security-db-prefix", __("DB Prefix", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_inter);
77
+ //DB Backup
78
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("db-security-db-backup", __("DB Backup", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
79
+
80
+ //File System Security Menu Features
81
+ //File Permissions
82
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("filesystem-file-permissions", __("File Permissions", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
83
+ //PHP File Editing
84
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("filesystem-file-editing", __("File Editing", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
85
+ //Prevent Access WP Install Files
86
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("block-wp-files-access", __("WordPress Files Access", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
87
+
88
+ //Blacklist Manager Menu Features
89
+ //IP and user agent blacklisting
90
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("blacklist-manager-ip-user-agent-blacklisting", __("IP and User Agent Blacklisting", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_advanced);
91
+
92
+ //Firewall Menu Features
93
+ //Basic firewall
94
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-basic-rules", __("Enable Basic Firewall", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_basic);
95
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-pingback-rules", __("Enable Pingback Vulnerability Protection", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_basic);
96
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-block-debug-file-access", __("Block Accesss to Debug Log File", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_inter);
97
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-enable-404-blocking", __("Enable IP blocking for 404 detection", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_inter);
98
+
99
+ //Brute Force Menu Features
100
+ //Rename Login page
101
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("bf-rename-login-page", __("Enable Rename Login Page", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_inter);
102
+ //Login Honeypot
103
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("login-honeypot", __("Enable Login Honeypot", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_inter);
104
+
105
+ //Additional and Advanced firewall
106
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-enable-brute-force-attack-prevention", __("Enable Brute Force Attack Prevention", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_advanced);
107
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-disable-index-views", __("Disable Index Views", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_inter);
108
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-disable-trace-track", __("Disable Trace and Track", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_advanced);
109
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-forbid-proxy-comments", __("Forbid Proxy Comments", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_advanced);
110
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-deny-bad-queries", __("Deny Bad Queries", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_advanced);
111
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-advanced-character-string-filter", __("Advanced Character String Filter", "all-in-one-wp-security-and-firewall"), $this->feature_point_3, $this->sec_level_advanced);
112
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-enable-5g-6g-blacklist", __("5G/6G Blacklist", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_advanced);
113
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("firewall-block-fake-googlebots", __("Block Fake Googlebots", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_advanced);
114
+ //SPAM Prevention
115
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("block-spambots", __("Block Spambots", "all-in-one-wp-security-and-firewall"), $this->feature_point_2, $this->sec_level_basic);
116
+ //Comment Captcha
117
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("comment-form-captcha", __("Comment Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_basic);
118
+ //BuddyPress Registration Captcha
119
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("bp-register-captcha", __("BuddyPress Registration Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_basic);
120
+ //BBPress new topic Captcha
121
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("bbp-new-topic-captcha", __("BBPress New Topic Captcha", "all-in-one-wp-security-and-firewall"), $this->feature_point_1, $this->sec_level_basic);
122
+
123
+ //Filescan
124
+ //File change detection
125
+ $this->feature_items[] = new AIOWPSecurity_Feature_Item("scan-file-change-detection", __("File Change Detection", "all-in-one-wp-security-and-firewall"), $this->feature_point_4, $this->sec_level_inter);
126
+
127
+ }
128
+
129
+ public function get_feature_item_by_id($feature_id) {
130
+ foreach ($this->feature_items as $item) {
131
+ if ($feature_id) {
132
+ return $item;
133
+ }
134
+ }
135
+ return "";
136
+ }
137
+
138
+ public function output_feature_details_badge($feature_id) {
139
+ $cau_feature_item = $this->get_feature_item_by_id($feature_id);
140
+ $cau_security_level = $cau_feature_item->security_level;
141
+ $cau_security_points = $cau_feature_item->item_points;
142
+ $cau_your_points = 0;
143
+ if ($cau_feature_item->feature_status == $this->feature_active) {
144
+ $cau_your_points = $cau_security_points;
145
+ }
146
+ $level_str = $cau_feature_item->get_security_level_string($cau_security_level);
147
+ ?>
148
+ <div class="aiowps_feature_details_badge">
149
+ <div class="aiowps_feature_details_badge_difficulty" title="Feature Difficulty">
150
+ <span class="aiowps_feature_details_badge_difficulty_text"><?php _e($level_str, 'all-in-one-wp-security-and-firewall'); ?></span>
151
+ </div>
152
+ <div class="aiowps_feature_details_badge_points" title="Security Points">
153
+ <span class="aiowps_feature_details_badge_points_text"><?php echo $cau_your_points .'/'. $cau_security_points; ?></span>
154
+ </div>
155
+ </div>
156
+ <?php
157
+ }
158
+
159
+ public function check_feature_status_and_recalculate_points() {
160
+ $this->check_and_set_feature_status();
161
+ $this->calculate_total_points();
162
+ }
163
+
164
+ public function check_and_set_feature_status() {
165
+ foreach ($this->feature_items as $item) {
166
+ if ("wp-generator-meta-tag" == $item->feature_id) {
167
+ $this->check_remove_wp_generator_meta_feature($item);
168
+ }
169
+
170
+ if ("prevent-hotlinking" == $item->feature_id) {
171
+ $this->check_prevent_hotlinking_feature($item);
172
+ }
173
+
174
+ if ("user-accounts-change-admin-user" == $item->feature_id) {
175
+ $this->check_user_accounts_change_admin_user_feature($item);
176
+ }
177
+
178
+ if ("user-accounts-display-name" == $item->feature_id) {
179
+ $this->check_user_accounts_display_name_feature($item);
180
+ }
181
+
182
+ if ("db-security-db-prefix" == $item->feature_id) {
183
+ $this->check_db_security_db_prefix_feature($item);
184
+ }
185
+
186
+ if ("db-security-db-backup" == $item->feature_id) {
187
+ $this->check_db_security_db_backup_feature($item);
188
+ }
189
+
190
+ if ("user-login-login-lockdown" == $item->feature_id) {
191
+ $this->check_login_lockdown_feature($item);
192
+ }
193
+
194
+ if ("user-login-captcha" == $item->feature_id) {
195
+ $this->check_login_captcha_feature($item);
196
+ }
197
+
198
+ if ("custom-login-captcha" == $item->feature_id) {
199
+ $this->check_custom_login_captcha_feature($item);
200
+ }
201
+
202
+ if ("woo-login-captcha" == $item->feature_id) {
203
+ $this->check_woo_login_captcha_feature($item);
204
+ }
205
+
206
+ if ("woo-lostpassword-captcha" == $item->feature_id) {
207
+ $this->check_woo_lostpassword_captcha_feature($item);
208
+ }
209
+
210
+ if ("woo-register-captcha" == $item->feature_id) {
211
+ $this->check_woo_register_captcha_feature($item);
212
+ }
213
+
214
+ if ("lost-password-captcha" == $item->feature_id) {
215
+ $this->check_lost_password_captcha_feature($item);
216
+ }
217
+
218
+ if ("comment-form-captcha" == $item->feature_id) {
219
+ $this->check_comment_captcha_feature($item);
220
+ }
221
+
222
+ if ("bp-register-captcha" == $item->feature_id) {
223
+ $this->check_bp_register_captcha_feature($item);
224
+ }
225
+
226
+ if ("bbp-new-topic-captcha" == $item->feature_id) {
227
+ $this->check_bbp_new_topic_captcha_feature($item);
228
+ }
229
+
230
+ if ("whitelist-manager-ip-login-whitelisting" == $item->feature_id) {
231
+ $this->check_login_whitelist_feature($item);
232
+ }
233
+
234
+ if ("user-login-force-logout" == $item->feature_id) {
235
+ $this->check_force_logout_feature($item);
236
+ }
237
+
238
+ if ("manually-approve-registrations" == $item->feature_id) {
239
+ $this->check_registration_approval_feature($item);
240
+ }
241
+
242
+ if ("user-registration-captcha" == $item->feature_id) {
243
+ $this->check_registration_captcha_feature($item);
244
+ }
245
+
246
+ if ("registration-honeypot" == $item->feature_id) {
247
+ $this->check_enable_registration_honeypot_feature($item);
248
+ }
249
+
250
+ if ("filesystem-file-permissions" == $item->feature_id) {
251
+ $this->check_filesystem_permissions_feature($item);
252
+ }
253
+
254
+ if ("filesystem-file-editing" == $item->feature_id) {
255
+ $this->check_filesystem_file_editing_feature($item);
256
+ }
257
+
258
+ if ("block-wp-files-access" == $item->feature_id) {
259
+ $this->check_block_wp_files_access_feature($item);
260
+ }
261
+
262
+ if ("blacklist-manager-ip-user-agent-blacklisting" == $item->feature_id) {
263
+ $this->check_enable_ip_useragent_blacklist_feature($item);
264
+ }
265
+
266
+ if ("firewall-basic-rules" == $item->feature_id) {
267
+ $this->check_enable_basic_firewall_feature($item);
268
+ }
269
+
270
+ if ("firewall-pingback-rules" == $item->feature_id) {
271
+ $this->check_enable_pingback_firewall_feature($item);
272
+ }
273
+
274
+ if ("firewall-block-debug-file-access" == $item->feature_id) {
275
+ $this->check_debug_file_access_block_firewall_feature($item);
276
+ }
277
+
278
+ if ("firewall-enable-404-blocking" == $item->feature_id) {
279
+ $this->check_enable_404_blocking_feature($item);
280
+ }
281
+
282
+ if ("firewall-enable-brute-force-attack-prevention" == $item->feature_id) {
283
+ $this->check_enable_bfap_firewall_feature($item);
284
+ }
285
+ if ("firewall-disable-index-views" == $item->feature_id) {
286
+ $this->check_disable_index_views_firewall_feature($item);
287
+ }
288
+ if ("firewall-disable-trace-track" == $item->feature_id) {
289
+ $this->check_disable_trace_track_firewall_feature($item);
290
+ }
291
+ if ("firewall-forbid-proxy-comments" == $item->feature_id) {
292
+ $this->check_forbid_proxy_comments_firewall_feature($item);
293
+ }
294
+ if ("firewall-deny-bad-queries" == $item->feature_id) {
295
+ $this->check_deny_bad_queries_firewall_feature($item);
296
+ }
297
+ if ("firewall-advanced-character-string-filter" == $item->feature_id) {
298
+ $this->check_advanced_char_string_filter_firewall_feature($item);
299
+ }
300
+ if ("firewall-enable-5g-6g-blacklist" == $item->feature_id) {
301
+ $this->check_enable_5G_6G_blacklist_firewall_feature($item);
302
+ }
303
+ if ("firewall-block-fake-googlebots" == $item->feature_id) {
304
+ $this->check_block_fake_googlebots_firewall_feature($item);
305
+ }
306
+
307
+ if ("bf-rename-login-page" == $item->feature_id) {
308
+ $this->check_enable_rename_login_page_feature($item);
309
+ }
310
+
311
+ if ("login-honeypot" == $item->feature_id) {
312
+ $this->check_enable_login_honeypot_feature($item);
313
+ }
314
+
315
+ if ("block-spambots" == $item->feature_id) {
316
+ $this->check_enable_block_spambots_feature($item);
317
+ }
318
+
319
+ if ("scan-file-change-detection" == $item->feature_id) {
320
+ $this->check_enable_fcd_scan_feature($item);
321
+ }
322
+
323
+ }
324
+ }
325
+
326
+ public function calculate_total_points() {
327
+ foreach ($this->feature_items as $item) {
328
+ if ("active" == $item->feature_status) {
329
+ $this->total_points = $this->total_points + intval($item->item_points);
330
+ }
331
+ }
332
+ }
333
+
334
+ public function get_total_site_points() {
335
+ return $this->total_points;
336
+ }
337
+
338
+ public function get_total_achievable_points() {
339
+ foreach ($this->feature_items as $item) {
340
+ $this->total_achievable_points = $this->total_achievable_points + intval($item->item_points);
341
+ }
342
+ return $this->total_achievable_points;
343
+ }
344
+
345
+ public function check_remove_wp_generator_meta_feature($item) {
346
+ global $aio_wp_security;
347
+ if ($aio_wp_security->configs->get_value('aiowps_remove_wp_generator_meta_info') == '1') {
348
+ $item->set_feature_status($this->feature_active);
349
+ } else {
350
+ $item->set_feature_status($this->feature_inactive);
351
+ }
352
+ }
353
+
354
+ public function check_prevent_hotlinking_feature($item) {
355
+ global $aio_wp_security;
356
+ if ($aio_wp_security->configs->get_value('aiowps_prevent_hotlinking') == '1') {
357
+ $item->set_feature_status($this->feature_active);
358
+ } else {
359
+ $item->set_feature_status($this->feature_inactive);
360
+ }
361
+ }
362
+
363
+ public function check_user_accounts_change_admin_user_feature($item) {
364
+ if (AIOWPSecurity_Utility::check_user_exists('admin')) {
365
+ $item->set_feature_status($this->feature_inactive);
366
+ } else {
367
+ $item->set_feature_status($this->feature_active);
368
+ }
369
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
 
371
+ public function check_user_accounts_display_name_feature($item) {
372
+ if (AIOWPSecurity_Utility::check_identical_login_and_nick_names()) {
373
+ $item->set_feature_status($this->feature_inactive);
374
+ } else {
375
+ $item->set_feature_status($this->feature_active);
376
+ }
377
+ }
378
+
379
+ public function check_login_lockdown_feature($item) {
380
+ global $aio_wp_security;
381
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_lockdown') == '1') {
382
+ $item->set_feature_status($this->feature_active);
383
+ } else {
384
+ $item->set_feature_status($this->feature_inactive);
385
+ }
386
+ }
387
+
388
+ public function check_login_captcha_feature($item) {
389
+ global $aio_wp_security;
390
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_captcha') == '1') {
391
+ $item->set_feature_status($this->feature_active);
392
+ } else {
393
+ $item->set_feature_status($this->feature_inactive);
394
+ }
395
+ }
396
+
397
+ public function check_custom_login_captcha_feature($item) {
398
+ global $aio_wp_security;
399
+ if ($aio_wp_security->configs->get_value('aiowps_enable_custom_login_captcha') == '1') {
400
+ $item->set_feature_status($this->feature_active);
401
+ } else {
402
+ $item->set_feature_status($this->feature_inactive);
403
+ }
404
+ }
405
+
406
+ public function check_woo_login_captcha_feature($item) {
407
+ global $aio_wp_security;
408
+ if ($aio_wp_security->configs->get_value('aiowps_enable_woo_login_captcha') == '1') {
409
+ $item->set_feature_status($this->feature_active);
410
+ } else {
411
+ $item->set_feature_status($this->feature_inactive);
412
+ }
413
+ }
414
+
415
+ public function check_woo_lostpassword_captcha_feature($item) {
416
+ global $aio_wp_security;
417
+ if ($aio_wp_security->configs->get_value('aiowps_enable_woo_lostpassword_captcha') == '1') {
418
+ $item->set_feature_status($this->feature_active);
419
+ } else {
420
+ $item->set_feature_status($this->feature_inactive);
421
+ }
422
+ }
423
+
424
+ public function check_woo_register_captcha_feature($item) {
425
+ global $aio_wp_security;
426
+ if ($aio_wp_security->configs->get_value('aiowps_enable_woo_register_captcha') == '1') {
427
+ $item->set_feature_status($this->feature_active);
428
+ } else {
429
+ $item->set_feature_status($this->feature_inactive);
430
+ }
431
+ }
432
+
433
+ public function check_lost_password_captcha_feature($item) {
434
+ global $aio_wp_security;
435
+ if ($aio_wp_security->configs->get_value('aiowps_enable_lost_password_captcha') == '1') {
436
+ $item->set_feature_status($this->feature_active);
437
+ } else {
438
+ $item->set_feature_status($this->feature_inactive);
439
+ }
440
+ }
441
+
442
+ public function check_comment_captcha_feature($item) {
443
+ global $aio_wp_security;
444
+ if ($aio_wp_security->configs->get_value('aiowps_enable_comment_captcha') == '1') {
445
+ $item->set_feature_status($this->feature_active);
446
+ } else {
447
+ $item->set_feature_status($this->feature_inactive);
448
+ }
449
+ }
450
+
451
+ public function check_bp_register_captcha_feature($item) {
452
+ global $aio_wp_security;
453
+ if ($aio_wp_security->configs->get_value('aiowps_enable_bp_register_captcha') == '1') {
454
+ $item->set_feature_status($this->feature_active);
455
+ } else {
456
+ $item->set_feature_status($this->feature_inactive);
457
+ }
458
+ }
459
+
460
+ public function check_bbp_new_topic_captcha_feature($item) {
461
+ global $aio_wp_security;
462
+ if ($aio_wp_security->configs->get_value('aiowps_enable_bbp_new_topic_captcha') == '1') {
463
+ $item->set_feature_status($this->feature_active);
464
+ } else {
465
+ $item->set_feature_status($this->feature_inactive);
466
+ }
467
+ }
468
+
469
+ public function check_login_whitelist_feature($item) {
470
+ global $aio_wp_security;
471
+ if ($aio_wp_security->configs->get_value('aiowps_enable_whitelisting') == '1') {
472
+ $item->set_feature_status($this->feature_active);
473
+ } else {
474
+ $item->set_feature_status($this->feature_inactive);
475
+ }
476
+ }
477
+
478
+ public function check_force_logout_feature($item) {
479
+ global $aio_wp_security;
480
+ if ($aio_wp_security->configs->get_value('aiowps_enable_forced_logout') == '1') {
481
+ $item->set_feature_status($this->feature_active);
482
+ } else {
483
+ $item->set_feature_status($this->feature_inactive);
484
+ }
485
+ }
486
+
487
+ public function check_registration_approval_feature($item) {
488
+ global $aio_wp_security;
489
+ if ($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1') {
490
+ $item->set_feature_status($this->feature_active);
491
+ } else {
492
+ $item->set_feature_status($this->feature_inactive);
493
+ }
494
+ }
495
+
496
+ public function check_registration_captcha_feature($item) {
497
+ global $aio_wp_security;
498
+ if ($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') {
499
+ $item->set_feature_status($this->feature_active);
500
+ } else {
501
+ $item->set_feature_status($this->feature_inactive);
502
+ }
503
+ }
504
+
505
+ public function check_enable_registration_honeypot_feature($item) {
506
+ global $aio_wp_security;
507
+ if ($aio_wp_security->configs->get_value('aiowps_enable_registration_honeypot') == '1') {
508
+ $item->set_feature_status($this->feature_active);
509
+ } else {
510
+ $item->set_feature_status($this->feature_inactive);
511
+ }
512
+ }
513
+
514
+ public function check_db_security_db_prefix_feature($item) {
515
+ global $wpdb;
516
+ if ('wp_' == $wpdb->prefix) {
517
+ $item->set_feature_status($this->feature_inactive);
518
+ } else {
519
+ $item->set_feature_status($this->feature_active);
520
+ }
521
+ }
522
+
523
+ public function check_db_security_db_backup_feature($item) {
524
+ global $aio_wp_security;
525
+ if ($aio_wp_security->configs->get_value('aiowps_enable_automated_backups') == '1') {
526
+ $item->set_feature_status($this->feature_active);
527
+ } else {
528
+ $item->set_feature_status($this->feature_inactive);
529
+ }
530
+ }
531
+
532
+ public function check_filesystem_permissions_feature($item) {
533
+ //TODO
534
+ $is_secure = 1;
535
+ $util = new AIOWPSecurity_Utility_File;
536
+ $files_dirs_to_check = $util->files_and_dirs_to_check;
537
+
538
+ foreach ($files_dirs_to_check as $file_or_dir) {
539
+ $actual_perm = AIOWPSecurity_Utility_File::get_file_permission($file_or_dir['path']);
540
+ $is_secure = $is_secure*AIOWPSecurity_Utility_File::is_file_permission_secure($file_or_dir['permissions'], $actual_perm);
541
+ }
542
+
543
+ //Only if all of the files' permissions are deemed secure give this a thumbs up
544
+ if (1 == $is_secure) {
545
+ $item->set_feature_status($this->feature_active);
546
+ } else {
547
+ $item->set_feature_status($this->feature_inactive);
548
+ }
549
+ }
550
+
551
+ public function check_filesystem_file_editing_feature($item) {
552
+ global $aio_wp_security;
553
+ if ($aio_wp_security->configs->get_value('aiowps_disable_file_editing') == '1') {
554
+ $item->set_feature_status($this->feature_active);
555
+ } else {
556
+ $item->set_feature_status($this->feature_inactive);
557
+ }
558
+ }
559
+
560
+ public function check_block_wp_files_access_feature($item) {
561
+ global $aio_wp_security;
562
+ if ($aio_wp_security->configs->get_value('aiowps_prevent_default_wp_file_access') == '1') {
563
+ $item->set_feature_status($this->feature_active);
564
+ } else {
565
+ $item->set_feature_status($this->feature_inactive);
566
+ }
567
+ }
568
+
569
+ public function check_enable_ip_useragent_blacklist_feature($item) {
570
+ global $aio_wp_security;
571
+ if ($aio_wp_security->configs->get_value('aiowps_enable_blacklisting') == '1') {
572
+ $item->set_feature_status($this->feature_active);
573
+ } else {
574
+ $item->set_feature_status($this->feature_inactive);
575
+ }
576
+ }
577
+
578
+ public function check_enable_basic_firewall_feature($item) {
579
+ global $aio_wp_security;
580
+ if ($aio_wp_security->configs->get_value('aiowps_enable_basic_firewall') == '1') {
581
+ $item->set_feature_status($this->feature_active);
582
+ } else {
583
+ $item->set_feature_status($this->feature_inactive);
584
+ }
585
+ }
586
+
587
+ public function check_enable_pingback_firewall_feature($item) {
588
+ global $aio_wp_security;
589
+ if ($aio_wp_security->configs->get_value('aiowps_enable_pingback_firewall') == '1') {
590
+ $item->set_feature_status($this->feature_active);
591
+ } else {
592
+ $item->set_feature_status($this->feature_inactive);
593
+ }
594
+ }
595
+
596
+ public function check_debug_file_access_block_firewall_feature($item) {
597
+ global $aio_wp_security;
598
+ if ($aio_wp_security->configs->get_value('aiowps_block_debug_log_file_access') == '1') {
599
+ $item->set_feature_status($this->feature_active);
600
+ } else {
601
+ $item->set_feature_status($this->feature_inactive);
602
+ }
603
+ }
604
+
605
+ public function check_disable_trace_track_firewall_feature($item) {
606
+ global $aio_wp_security;
607
+ if ($aio_wp_security->configs->get_value('aiowps_disable_trace_and_track') == '1') {
608
+ $item->set_feature_status($this->feature_active);
609
+ } else {
610
+ $item->set_feature_status($this->feature_inactive);
611
+ }
612
+ }
613
+
614
+ public function check_disable_index_views_firewall_feature($item) {
615
+ global $aio_wp_security;
616
+ if ($aio_wp_security->configs->get_value('aiowps_disable_index_views') == '1') {
617
+ $item->set_feature_status($this->feature_active);
618
+ } else {
619
+ $item->set_feature_status($this->feature_inactive);
620
+ }
621
+ }
622
+
623
+ public function check_enable_bfap_firewall_feature($item) {
624
+ global $aio_wp_security;
625
+ if ($aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention') == '1') {
626
+ $item->set_feature_status($this->feature_active);
627
+ } else {
628
+ $item->set_feature_status($this->feature_inactive);
629
+ }
630
+ }
631
+
632
+ public function check_forbid_proxy_comments_firewall_feature($item) {
633
+ global $aio_wp_security;
634
+ if ($aio_wp_security->configs->get_value('aiowps_forbid_proxy_comments') == '1') {
635
+ $item->set_feature_status($this->feature_active);
636
+ } else {
637
+ $item->set_feature_status($this->feature_inactive);
638
+ }
639
+ }
640
+
641
+ public function check_deny_bad_queries_firewall_feature($item) {
642
+ global $aio_wp_security;
643
+ if ($aio_wp_security->configs->get_value('aiowps_deny_bad_query_strings') == '1') {
644
+ $item->set_feature_status($this->feature_active);
645
+ } else {
646
+ $item->set_feature_status($this->feature_inactive);
647
+ }
648
+ }
649
+
650
+ public function check_advanced_char_string_filter_firewall_feature($item) {
651
+ global $aio_wp_security;
652
+ if ($aio_wp_security->configs->get_value('aiowps_advanced_char_string_filter') == '1') {
653
+ $item->set_feature_status($this->feature_active);
654
+ } else {
655
+ $item->set_feature_status($this->feature_inactive);
656
+ }
657
+ }
658
+
659
+ public function check_enable_5G_6G_blacklist_firewall_feature($item) {
660
+ global $aio_wp_security;
661
+ if ($aio_wp_security->configs->get_value('aiowps_enable_5g_firewall') == '1') {
662
+ $item->set_feature_status($this->feature_active);
663
+ } elseif ($aio_wp_security->configs->get_value('aiowps_enable_6g_firewall') == '1') {
664
+ $item->set_feature_status($this->feature_active);
665
+ } else {
666
+ $item->set_feature_status($this->feature_inactive);
667
+ }
668
+ }
669
+
670
+ public function check_block_fake_googlebots_firewall_feature($item) {
671
+ global $aio_wp_security;
672
+ if ($aio_wp_security->configs->get_value('aiowps_block_fake_googlebots') == '1') {
673
+ $item->set_feature_status($this->feature_active);
674
+ } else {
675
+ $item->set_feature_status($this->feature_inactive);
676
+ }
677
+ }
678
+
679
+ public function check_enable_404_blocking_feature($item) {
680
+ global $aio_wp_security;
681
+ if ($aio_wp_security->configs->get_value('aiowps_enable_404_IP_lockout') == '1') {
682
+ $item->set_feature_status($this->feature_active);
683
+ } else {
684
+ $item->set_feature_status($this->feature_inactive);
685
+ }
686
+ }
687
+
688
+ public function check_enable_rename_login_page_feature($item) {
689
+ global $aio_wp_security;
690
+ if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
691
+ $item->set_feature_status($this->feature_active);
692
+ } else {
693
+ $item->set_feature_status($this->feature_inactive);
694
+ }
695
+ }
696
+
697
+ public function check_enable_login_honeypot_feature($item) {
698
+ global $aio_wp_security;
699
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_honeypot') == '1') {
700
+ $item->set_feature_status($this->feature_active);
701
+ } else {
702
+ $item->set_feature_status($this->feature_inactive);
703
+ }
704
+ }
705
+
706
+ public function check_enable_block_spambots_feature($item) {
707
+ global $aio_wp_security;
708
+ if ($aio_wp_security->configs->get_value('aiowps_enable_spambot_blocking') == '1') {
709
+ $item->set_feature_status($this->feature_active);
710
+ } else {
711
+ $item->set_feature_status($this->feature_inactive);
712
+ }
713
+ }
714
+
715
+ public function check_enable_fcd_scan_feature($item) {
716
+ global $aio_wp_security;
717
+ if ($aio_wp_security->configs->get_value('aiowps_enable_automated_fcd_scan') == '1') {
718
+ $item->set_feature_status($this->feature_active);
719
+ } else {
720
+ $item->set_feature_status($this->feature_inactive);
721
+ }
722
+ }
723
+
724
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/grade-system/wp-security-feature-item.php CHANGED
@@ -1,40 +1,38 @@
1
  <?php
2
 
3
- class AIOWPSecurity_Feature_Item
4
- {
5
- var $feature_id;//Example "user-accounts-tab1-change-admin-user"
6
- var $feature_name;
7
- var $item_points;
8
- var $security_level;//1, 2 or 3
9
-
10
- var $feature_status;//active, inactive, partial
11
-
12
- function __construct($feature_id,$feature_name,$item_points,$security_level){
13
- $this->feature_id = $feature_id;
14
- $this->feature_name = $feature_name;
15
- $this->item_points = $item_points;
16
- $this->security_level = $security_level;
17
- }
18
-
19
- function set_feature_status($status)
20
- {
21
- $this->feature_status = $status;
22
- }
23
-
24
- function get_security_level_string($level)
25
- {
26
- $level_string = "";
27
- if($level == "1"){
28
- $level_string = __('Basic', 'all-in-one-wp-security-and-firewall');
29
- }
30
- else if($level == "2"){
31
- $level_string = __('Intermediate', 'all-in-one-wp-security-and-firewall');
32
- }
33
- else if($level == "3"){
34
- $level_string = __('Advanced', 'all-in-one-wp-security-and-firewall');
35
- }
36
- return $level_string;
37
- }
38
-
39
- }
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
 
3
+ class AIOWPSecurity_Feature_Item {
4
+
5
+ public $feature_id;//Example "user-accounts-tab1-change-admin-user"
6
+
7
+ public $feature_name;
8
+
9
+ public $item_points;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
+ public $security_level;//1, 2 or 3
12
+
13
+ public $feature_status;//active, inactive, partial
14
+
15
+ public function __construct($feature_id, $feature_name, $item_points, $security_level) {
16
+ $this->feature_id = $feature_id;
17
+ $this->feature_name = $feature_name;
18
+ $this->item_points = $item_points;
19
+ $this->security_level = $security_level;
20
+ }
21
+
22
+ public function set_feature_status($status) {
23
+ $this->feature_status = $status;
24
+ }
25
+
26
+ public function get_security_level_string($level) {
27
+ $level_string = "";
28
+ if ("1" == $level) {
29
+ $level_string = __('Basic', 'all-in-one-wp-security-and-firewall');
30
+ } elseif ("2" == $level) {
31
+ $level_string = __('Intermediate', 'all-in-one-wp-security-and-firewall');
32
+ } elseif ("3" == $level) {
33
+ $level_string = __('Advanced', 'all-in-one-wp-security-and-firewall');
34
+ }
35
+ return $level_string;
36
+ }
37
+
38
+ }
classes/index.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  /**
4
  * Do not modify the files in this folder.
5
  */
1
  <?php
 
2
  /**
3
  * Do not modify the files in this folder.
4
  */
classes/updraft-notices.php ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('ABSPATH')) die('No direct access allowed');
4
+
5
+ /**
6
+ * If we ever change the API of the Updraft_Notices class, then we'll need to rename and version it, e.g. Updraft_Notices_1_0, because otherwise a plugin may find that it's loaded an older instance than it wanted from another plugin.
7
+ */
8
+ abstract class Updraft_Notices {
9
+
10
+ protected $notices_content;
11
+
12
+ // These variables are just short-hands to be used in advert content.
13
+ protected $dashboard_top = array('top');
14
+
15
+ protected $dashboard_top_or_report = array('top', 'report', 'report-plain');
16
+
17
+ protected $dashboard_bottom_or_report = array('bottom', 'report', 'report-plain');
18
+
19
+ protected $anywhere = array('top', 'bottom', 'report', 'report-plain');
20
+
21
+ protected $autobackup = array('autobackup');
22
+
23
+ protected $autobackup_bottom_or_report = array('autobackup', 'bottom', 'report', 'report-plain');
24
+
25
+ /**
26
+ * Global adverts that appear in all products will be returned to the child to display.
27
+ *
28
+ * @return Array - a 2d array of notices with all the data for each notice
29
+ */
30
+ protected function populate_notices_content() {
31
+ return array();
32
+ }
33
+
34
+ /**
35
+ * Call this method to setup the notices
36
+ */
37
+ abstract protected function notices_init();
38
+
39
+ /**
40
+ * Returns false if a translation is present for the current locale and true otherwise.
41
+ *
42
+ * @param String $plugin_base_dir
43
+ * @param String $product_name
44
+ *
45
+ * @return Boolean
46
+ */
47
+ protected function translation_needed($plugin_base_dir, $product_name) {
48
+ $wplang = get_locale();
49
+ if (strlen($wplang) < 1 || 'en_US' == $wplang || 'en_GB' == $wplang) return false;
50
+ if (defined('WP_LANG_DIR') && is_file(WP_LANG_DIR.'/plugins/'.$product_name.'-'.$wplang.'.mo')) return false;
51
+ if (is_file($plugin_base_dir.'/languages/'.$product_name.'-'.$wplang.'.mo')) return false;
52
+ return true;
53
+ }
54
+
55
+ /**
56
+ * This method is used to generate the correct URL output for the start of the URL.
57
+ *
58
+ * @param Boolean $html_allowed - a boolean value to indicate if HTML can be used or not
59
+ * @param String $url - the url to use
60
+ * @param Boolean $https - a boolean value to indicate if https should be used or not
61
+ * @param String $website_home - a string to be displayed
62
+ *
63
+ * @return String returns a string of the completed url
64
+ */
65
+ protected function url_start($html_allowed, $url, $https = false, $website_home = null) {
66
+ $proto = ($https) ? 'https' : 'http';
67
+ if (strpos($url, $website_home) !== false) {
68
+ return $html_allowed ? "<a href=".apply_filters(str_replace('.', '_', $website_home).'_link', $proto.'://'.$url).">" : "";
69
+ } else {
70
+ return $html_allowed ? "<a href=\"$proto://$url\">" : "";
71
+ }
72
+ }
73
+
74
+ /**
75
+ * This method is used to generate the correct URL output for the end of the URL.
76
+ *
77
+ * @param Boolean $html_allowed - a boolean value to indicate if HTML can be used or not
78
+ * @param String $url - the url to use
79
+ * @param Boolean $https - a boolean value to indicate if https should be used or not
80
+ *
81
+ * @return String returns a string of the completed url
82
+ */
83
+ protected function url_end($html_allowed, $url, $https = false) {
84
+ $proto = ($https) ? 'https' : 'http';
85
+ return $html_allowed ? '</a>' : " ($proto://$url)";
86
+ }
87
+
88
+ /**
89
+ * Prepares and then renders or returns a notice.
90
+ *
91
+ * @param Boolean|String $notice - id of notice or false for 'get_notice_data' to decide
92
+ * @param String $position - notice position
93
+ * @param Boolean $return_instead_of_echo - whether to return the notice(true) or render it to the page(false)
94
+ *
95
+ * @return Void|String
96
+ */
97
+ public function do_notice($notice = false, $position = 'top', $return_instead_of_echo = false) {
98
+
99
+ $this->notices_init();
100
+
101
+ if (false === $notice) $notice = apply_filters('updraft_notices_force_id', false, $this);
102
+
103
+ $notice_content = $this->get_notice_data($notice, $position);
104
+
105
+ if (false != $notice_content) {
106
+ return $this->render_specified_notice($notice_content, $return_instead_of_echo, $position);
107
+ }
108
+ }
109
+
110
+ /**
111
+ * This method will return a notice ready for display.
112
+ *
113
+ * @param Boolean $notice - the notice to grab the data
114
+ * @param String $position - position of notice
115
+ *
116
+ * @return Array
117
+ */
118
+ protected function get_notice_data($notice = false, $position = 'top') {
119
+
120
+ // If a specific notice has been passed to this method then return that notice.
121
+ if ($notice) {
122
+ if (!isset($this->notices_content[$notice])) return false;
123
+
124
+ // Does the notice support the position specified?
125
+ if (isset($this->notices_content[$notice]['supported_positions']) && !in_array($position, $this->notices_content[$notice]['supported_positions'])) return false;
126
+
127
+ /*
128
+ First check if the advert passed can be displayed and hasn't been dismissed, we do this by checking what dismissed value we should be checking.
129
+ */
130
+ $dismiss_time = $this->notices_content[$notice]['dismiss_time'];
131
+
132
+ $dismiss = $this->check_notice_dismissed($dismiss_time);
133
+
134
+ if ($dismiss) return false;
135
+
136
+ // If the advert has a validity function, then require the advert to be valid
137
+ if (!empty($this->notices_content[$notice]['validity_function']) && !call_user_func(array($this, $this->notices_content[$notice]['validity_function']))) return false;
138
+
139
+ return $this->notices_content[$notice];
140
+ }
141
+
142
+ // create an array to add non-seasonal adverts to so that if a seasonal advert can't be returned we can choose a random advert from this array.
143
+ $available_notices = array();
144
+
145
+ // If Advert wasn't passed then next we should check to see if a seasonal advert can be returned.
146
+ foreach ($this->notices_content as $notice_id => $notice_data) {
147
+ // Does the notice support the position specified?
148
+ if (isset($this->notices_content[$notice_id]['supported_positions']) && !in_array($position, $this->notices_content[$notice_id]['supported_positions'])) continue;
149
+
150
+ // If the advert has a validity function, then require the advert to be valid
151
+ if (!empty($notice_data['validity_function']) && !call_user_func(array($this, $notice_data['validity_function']))) continue;
152
+
153
+ if (isset($notice_data['valid_from']) && isset($notice_data['valid_to'])) {
154
+
155
+ if ($this->skip_seasonal_notices($notice_data)) return $notice_data;
156
+
157
+ } else {
158
+
159
+ $dismiss_time = $this->notices_content[$notice_id]['dismiss_time'];
160
+ $dismiss = $this->check_notice_dismissed($dismiss_time);
161
+
162
+ if (!$dismiss) $available_notices[$notice_id] = $notice_data;
163
+ }
164
+ }
165
+
166
+ if (empty($available_notices)) return false;
167
+
168
+ // If a seasonal advert can't be returned then we will return a random advert
169
+
170
+ // Here we give a 25% chance for the rate advert to be returned before selecting a random advert from the entire collection which also includes the rate advert
171
+ if (0 == rand(0, 3) && isset($available_notices['rate'])) return $available_notices['rate'];
172
+
173
+ /*
174
+ Using shuffle here as something like rand which produces a random number and uses that as the array index fails, this is because in future an advert may not be numbered and could have a string as its key which will then cause errors.
175
+ */
176
+
177
+ shuffle($available_notices);
178
+ return $available_notices[0];
179
+ }
180
+
181
+ /**
182
+ * This method returns false although it's usually overridden to determine whether to prepare a seasonal notice(returns true) or not(returns false).
183
+ *
184
+ * @param Array $notice_data - all data for the notice
185
+ *
186
+ * @return Boolean
187
+ */
188
+ protected function skip_seasonal_notices($notice_data) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
189
+ return false;
190
+ }
191
+
192
+ /**
193
+ * When overridden this method should check whether a notice is dismissed(returns true) or not(returns false).
194
+ *
195
+ * @param String $dismiss_time - dismiss time id for the notice
196
+ */
197
+ abstract protected function check_notice_dismissed($dismiss_time);
198
+ }
classes/wp-security-backup.php CHANGED
@@ -1,368 +1,339 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Backup
7
- {
8
- var $last_backup_file_name;//Stores the name of the last backup file when execute_backup function is called
9
- var $last_backup_file_path;
10
- var $last_backup_file_dir_multisite;
11
-
12
- function __construct()
13
- {
14
- add_action('aiowps_perform_scheduled_backup_tasks', array($this, 'aiowps_scheduled_backup_handler'));
15
- add_action('aiowps_perform_db_cleanup_tasks', array($this, 'aiowps_scheduled_db_cleanup_handler'));
16
- }
17
-
18
- /**
19
- * Add slashes, sanitize end-of-line characters (?), wrap $value in quotation marks.
20
- * @param string $value
21
- * @return string
22
- */
23
- function sanitize_db_field($value) {
24
- return '"' . preg_replace( "/".PHP_EOL."/", "\n", addslashes($value) ) . '"';
25
- }
26
-
27
- /**
28
- * Write sql dump of $tables to backup file identified by $handle.
29
- * @global wpdb $wpdb WordPress database abstraction object.
30
- * @global AIO_WP_Security $aio_wp_security
31
- * @param resource $handle
32
- * @param array $tables
33
- * @return boolean True, if database tables dump have been successfully written to the backup file, false otherwise.
34
- */
35
- function write_db_backup_file($handle, $tables)
36
- {
37
- global $wpdb, $aio_wp_security;
38
-
39
- $preamble
40
- = "-- All In One WP Security & Firewall {$aio_wp_security->version}" . PHP_EOL
41
- . '-- MySQL dump' . PHP_EOL
42
- . '-- ' . date('Y-m-d H:i:s') . PHP_EOL . PHP_EOL
43
- // When importing the backup, tell database server that our data is in UTF-8...
44
- . "SET NAMES utf8;" . PHP_EOL
45
- // ...and that foreign key checks should be ignored.
46
- . "SET foreign_key_checks = 0;" . PHP_EOL . PHP_EOL
47
- ;
48
- if ( !@fwrite( $handle, $preamble ) ) { return false; }
49
-
50
- // Loop through each table
51
- foreach ( $tables as $table )
52
- {
53
- $table_name = $table[0];
54
-
55
- $result_create_table = $wpdb->get_row( 'SHOW CREATE TABLE `' . $table_name . '`;', ARRAY_N );
56
- if ( empty($result_create_table) ) {
57
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - get_row returned NULL for table: ".$table_name, 4);
58
- return false; // Avoid incomplete backups
59
- }
60
-
61
- // Drop/create table preamble
62
- $drop_and_create = 'DROP TABLE IF EXISTS `' . $table_name . '`;' . PHP_EOL . PHP_EOL
63
- . $result_create_table[1] . ";" . PHP_EOL . PHP_EOL
64
- ;
65
- if ( !@fwrite( $handle, $drop_and_create ) ) { return false; }
66
-
67
- // Dump table contents
68
- // Fetch results as row of objects to spare memory.
69
- $result = $wpdb->get_results( 'SELECT * FROM `' . $table_name . '`;', OBJECT );
70
- foreach ( $result as $object_row )
71
- {
72
- // Convert object row to array row: this is what $wpdb->get_results()
73
- // internally does when invoked with ARRAY_N param, but in the process
74
- // it creates new copy of entire results array that eats a lot of memory.
75
- $row = array_values(get_object_vars($object_row));
76
- // Start INSERT statement
77
- if ( !@fwrite( $handle, 'INSERT INTO `' . $table_name . '` VALUES(' ) ) { return false; }
78
- // Loop through all fields and echo them out
79
- foreach ( $row as $idx => $field ) {
80
- // Echo fields separator (except for first loop)
81
- if ( ($idx > 0) && !@fwrite( $handle, ',' ) ) { return false; }
82
- // Echo field content (sanitized)
83
- if ( !@fwrite( $handle, $this->sanitize_db_field($field) ) ) { return false; }
84
- }
85
- // Finish INSERT statement
86
- if ( !@fwrite( $handle, ");" . PHP_EOL ) ) { return false; }
87
- }
88
- // Place two-empty lines after table data
89
- if ( !@fwrite( $handle, PHP_EOL . PHP_EOL ) ) { return false; }
90
- }
91
-
92
- return true;
93
- }
94
-
95
- /**
96
- * This function will perform a database backup
97
- */
98
- function execute_backup()
99
- {
100
- global $wpdb, $aio_wp_security;
101
- $is_multi_site = function_exists('is_multisite') && is_multisite();
102
-
103
- @ini_set( 'auto_detect_line_endings', true );
104
- $execute_backup_memory_limit = apply_filters( 'aiowps_execute_backup_set_memory_limit', '512M' );
105
- @ini_set( 'memory_limit', $execute_backup_memory_limit );
106
-
107
- if ( $is_multi_site )
108
- {
109
- //Let's get the current site's table prefix
110
- $site_pref = esc_sql($wpdb->prefix);
111
- $db_query = "SHOW TABLES LIKE '".$site_pref."%'";
112
- $tables = $wpdb->get_results( $db_query, ARRAY_N );
113
- }
114
- else
115
- {
116
- //get all of the tables
117
- $tables = $wpdb->get_results( 'SHOW TABLES', ARRAY_N );
118
- }
119
-
120
- if ( empty($tables) ) {
121
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - no tables found!",4);
122
- return false;
123
- }
124
-
125
- //Check to see if the main "backups" directory exists - create it otherwise
126
-
127
- $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
128
- if (!AIOWPSecurity_Utility_File::create_dir($aiowps_backup_dir))
129
- {
130
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Creation of DB backup directory failed!",4);
131
- return false;
132
- }
133
-
134
- //Generate a random prefix for more secure filenames
135
- $random_suffix = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10);
136
-
137
- if ($is_multi_site)
138
- {
139
- global $current_blog;
140
- $blog_id = $current_blog->blog_id;
141
- //Get the current site name string for use later
142
- $site_name = get_bloginfo('name');
143
-
144
- $site_name = strtolower($site_name);
145
-
146
- //make alphanumeric
147
- $site_name = preg_replace("/[^a-z0-9_\s-]/", "", $site_name);
148
-
149
- //Cleanup multiple instances of dashes or whitespaces
150
- $site_name = preg_replace("/[\s-]+/", " ", $site_name);
151
-
152
- //Convert whitespaces and underscore to dash
153
- $site_name = preg_replace("/[\s_]/", "-", $site_name);
154
-
155
- $file = 'database-backup-site-name-' . $site_name . '-' . current_time( 'Ymd-His' ) . '-' . $random_suffix;
156
-
157
- //We will create a sub dir for the blog using its blog id
158
- $dirpath = $aiowps_backup_dir . '/blogid_' . $blog_id;
159
-
160
- //Create a subdirectory for this blog_id
161
- if (!AIOWPSecurity_Utility_File::create_dir($dirpath))
162
- {
163
- $aio_wp_security->debug_logger->log_debug("Creation failed of DB backup directory for the following multisite blog ID: ".$blog_id,4);
164
- return false;
165
- }
166
- }
167
- else
168
- {
169
- $dirpath = $aiowps_backup_dir;
170
- $file = 'database-backup-' . current_time( 'Ymd-His' ) . '-' . $random_suffix;
171
- }
172
-
173
- $handle = @fopen( $dirpath . '/' . $file . '.sql', 'w+' );
174
-
175
- if ( $handle === false ) {
176
- $aio_wp_security->debug_logger->log_debug("Cannot create DB backup file: {$dirpath}/{$file}.sql", 4);
177
- return false;
178
- }
179
-
180
- // Delete old backup files now to avoid polluting backups directory
181
- // with incomplete backups on websites where max execution time is too
182
- // low for database content to be written to a file:
183
- // https://github.com/Arsenal21/all-in-one-wordpress-security/issues/62
184
- $this->aiowps_delete_backup_files($dirpath);
185
-
186
- $fw_res = $this->write_db_backup_file($handle, $tables);
187
- @fclose( $handle );
188
-
189
- if (!$fw_res)
190
- {
191
- @unlink( $dirpath . '/' . $file . '.sql' );
192
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Write to DB backup file failed",4);
193
- return false;
194
- }
195
-
196
- //zip the file
197
- if ( class_exists( 'ZipArchive' ) )
198
- {
199
- $zip = new ZipArchive();
200
- $archive = $zip->open($dirpath . '/' . $file . '.zip', ZipArchive::CREATE);
201
- $zip->addFile($dirpath . '/' . $file . '.sql', $file . '.sql' );
202
- $zip->close();
203
-
204
- //delete .sql and keep zip
205
- @unlink( $dirpath . '/' . $file . '.sql' );
206
- $fileext = '.zip';
207
- } else
208
- {
209
- $fileext = '.sql';
210
- }
211
- $this->last_backup_file_name = $file . $fileext;//database-backup-YYYYMMDD-HHIISS-<random-string>.zip or database-backup-YYYYMMDD-HHIISS-<random-string>.sql
212
- $this->last_backup_file_path = $dirpath . '/' . $file . $fileext;
213
- if ($is_multi_site)
214
- {
215
- $this->last_backup_file_dir_multisite = $aiowps_backup_dir . '/blogid_' . $blog_id;
216
- }
217
-
218
- $this->aiowps_send_backup_email(); //Send backup file via email if applicable
219
- return true;
220
- }
221
-
222
- function aiowps_send_backup_email()
223
- {
224
- global $aio_wp_security;
225
- if ( $aio_wp_security->configs->get_value('aiowps_send_backup_email_address') == '1' )
226
- {
227
- //Get the right email address.
228
- if ( is_email( $aio_wp_security->configs->get_value('aiowps_backup_email_address') ) )
229
- {
230
- $toaddress = $aio_wp_security->configs->get_value('aiowps_backup_email_address');
231
- } else
232
- {
233
- $toaddress = get_site_option( 'admin_email' );
234
- }
235
-
236
- $to = $toaddress;
237
- $site_title = get_bloginfo( 'name' );
238
- $from_name = empty($site_title)?'WordPress':$site_title;
239
-
240
- $headers = 'From: ' . $from_name . ' <' . get_option('admin_email') . '>' . PHP_EOL;
241
- $subject = __( 'All In One WP Security - Site Database Backup', 'all-in-one-wp-security-and-firewall' ) . ' ' . date( 'l, F jS, Y \a\\t g:i a', current_time( 'timestamp' ) );
242
- $attachment = array( $this->last_backup_file_path );
243
- $message = __( 'Attached is your latest DB backup file for site URL', 'all-in-one-wp-security-and-firewall' ) . ' ' . get_option( 'siteurl' ) . __( ' generated on', 'all-in-one-wp-security-and-firewall' ) . ' ' . date( 'l, F jS, Y \a\\t g:i a', current_time( 'timestamp' ) );
244
-
245
- $sendMail = wp_mail( $to, $subject, $message, $headers, $attachment );
246
- if(FALSE === $sendMail){
247
- $aio_wp_security->debug_logger->log_debug("Backup notification email failed to send to ".$to,4);
248
- }
249
- }
250
- }
251
-
252
- function aiowps_delete_backup_files($backups_dir)
253
- {
254
- global $aio_wp_security;
255
- $files_to_keep = absint($aio_wp_security->configs->get_value('aiowps_backup_files_stored'));
256
- if ( $files_to_keep > 0 )
257
- {
258
- $aio_wp_security->debug_logger->log_debug(sprintf('DB Backup - Deleting all but %d latest backup file(s) in %s directory.', $files_to_keep, $backups_dir));
259
- $files = AIOWPSecurity_Utility_File::scan_dir_sort_date( $backups_dir );
260
- $count = 0;
261
-
262
- foreach ( $files as $file )
263
- {
264
- if ( strpos( $file, 'database-backup' ) !== false )
265
- {
266
- if ( $count >= $files_to_keep )
267
- {
268
- @unlink( $backups_dir . '/' . $file );
269
- }
270
- $count++;
271
- }
272
- }
273
- }
274
- else
275
- {
276
- $aio_wp_security->debug_logger->log_debug('DB Backup - Backup configuration prevents removal of old backup files!', 3);
277
- }
278
- }
279
-
280
- function aiowps_scheduled_backup_handler()
281
- {
282
- global $aio_wp_security;
283
- if($aio_wp_security->configs->get_value('aiowps_enable_automated_backups')=='1')
284
- {
285
- $aio_wp_security->debug_logger->log_debug_cron("DB Backup - Scheduled backup is enabled. Checking if a backup needs to be done now...");
286
- $time_now = current_time( 'mysql' );
287
- $current_time = strtotime($time_now);
288
- $backup_frequency = $aio_wp_security->configs->get_value('aiowps_db_backup_frequency'); //Number of hours or days or months interval per backup
289
- $interval_setting = $aio_wp_security->configs->get_value('aiowps_db_backup_interval'); //Hours/Days/Months
290
- switch($interval_setting)
291
- {
292
- case '0':
293
- $interval = 'hours';
294
- break;
295
- case '1':
296
- $interval = 'days';
297
- break;
298
- case '2':
299
- $interval = 'weeks';
300
- break;
301
- default:
302
- // Fall back to default value, if config is corrupted for some reason.
303
- $interval = 'weeks';
304
- break;
305
- }
306
- $last_backup_time = $aio_wp_security->configs->get_value('aiowps_last_backup_time');
307
- if ($last_backup_time != NULL)
308
- {
309
- $last_backup_time = strtotime($aio_wp_security->configs->get_value('aiowps_last_backup_time'));
310
- $next_backup_time = strtotime("+".abs($backup_frequency).$interval, $last_backup_time);
311
- if ($next_backup_time <= $current_time)
312
- {
313
- //It's time to do a backup
314
- $result = $this->execute_backup();
315
- if ($result)
316
- {
317
- $aio_wp_security->configs->set_value('aiowps_last_backup_time', $time_now);
318
- $aio_wp_security->configs->save_config();
319
- $aio_wp_security->debug_logger->log_debug_cron("DB Backup - Scheduled backup was successfully completed.");
320
- }
321
- else
322
- {
323
- $aio_wp_security->debug_logger->log_debug_cron("DB Backup - Scheduled backup operation failed!",4);
324
- }
325
- }
326
- }
327
- else
328
- {
329
- //Set the last backup time to now so it can trigger for the next scheduled period
330
- $aio_wp_security->configs->set_value('aiowps_last_backup_time', $time_now);
331
- $aio_wp_security->configs->save_config();
332
- }
333
- }
334
- }
335
-
336
-
337
- function aiowps_scheduled_db_cleanup_handler()
338
- {
339
- //Check the events table because this can grow quite large especially when 404 events are being logged
340
- $events_table_name = AIOWPSEC_TBL_EVENTS;
341
- $max_rows_event_table = '5000'; //Keep a max of 5000 rows in the events table
342
- $max_rows_event_table = apply_filters( 'aiowps_max_rows_event_table', $max_rows_event_table );
343
- AIOWPSecurity_Utility::cleanup_table($events_table_name, $max_rows_event_table);
344
-
345
- //Check the failed logins table
346
- $failed_logins_table_name = AIOWPSEC_TBL_FAILED_LOGINS;
347
- $max_rows_failed_logins_table = '5000'; //Keep a max of 5000 rows in the events table
348
- $max_rows_failed_logins_table = apply_filters( 'aiowps_max_rows_failed_logins_table', $max_rows_failed_logins_table );
349
- AIOWPSecurity_Utility::cleanup_table($failed_logins_table_name, $max_rows_failed_logins_table);
350
-
351
- //Check the login activity table
352
- $login_activity_table_name = AIOWPSEC_TBL_USER_LOGIN_ACTIVITY;
353
- $max_rows_login_activity_table = '5000'; //Keep a max of 5000 rows in the events table
354
- $max_rows_login_activity_table = apply_filters( 'aiowps_max_rows_login_attempts_table', $max_rows_login_activity_table );
355
- AIOWPSecurity_Utility::cleanup_table($login_activity_table_name, $max_rows_login_activity_table);
356
-
357
- //Check the global meta table
358
- $global_meta_table_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
359
- $max_rows_global_meta_table = '5000'; //Keep a max of 5000 rows in this table
360
- $max_rows_global_meta_table = apply_filters( 'aiowps_max_rows_global_meta_table', $max_rows_global_meta_table );
361
- AIOWPSecurity_Utility::cleanup_table($global_meta_table_name, $max_rows_global_meta_table);
362
-
363
- //Delete any expired _aiowps_captcha_string_info_xxxx transients
364
- AIOWPSecurity_Utility::delete_expired_captcha_transients();
365
-
366
- //Keep adding other DB cleanup tasks as they arise...
367
- }
368
- }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Backup {
7
+
8
+ public $last_backup_file_name;//Stores the name of the last backup file when execute_backup function is called
9
+
10
+ public $last_backup_file_path;
11
+
12
+ public $last_backup_file_dir_multisite;
13
+
14
+ public function __construct() {
15
+ add_action('aiowps_perform_scheduled_backup_tasks', array($this, 'aiowps_scheduled_backup_handler'));
16
+ add_action('aiowps_perform_db_cleanup_tasks', array($this, 'aiowps_scheduled_db_cleanup_handler'));
17
+ }
18
+
19
+ /**
20
+ * Add slashes, sanitize end-of-line characters (?), wrap $value in quotation marks.
21
+ *
22
+ * @param string $value
23
+ * @return string
24
+ */
25
+ public function sanitize_db_field($value) {
26
+ return '"' . preg_replace("/".PHP_EOL."/", "\n", addslashes($value)) . '"';
27
+ }
28
+
29
+ /**
30
+ * Write sql dump of $tables to backup file identified by $handle.
31
+ *
32
+ * @global wpdb $wpdb WordPress database abstraction object.
33
+ * @global AIO_WP_Security $aio_wp_security
34
+ * @param resource $handle
35
+ * @param array $tables
36
+ * @return boolean True, if database tables dump have been successfully written to the backup file, false otherwise.
37
+ */
38
+ public function write_db_backup_file($handle, $tables) {
39
+ global $wpdb, $aio_wp_security;
40
+
41
+ // When importing the backup, tell database server that our data is in UTF-8...
42
+ // ...and that foreign key checks should be ignored.
43
+ $preamble
44
+ = "-- All In One WP Security & Firewall {$aio_wp_security->version}" . PHP_EOL . '-- MySQL dump' . PHP_EOL . '-- ' . date('Y-m-d H:i:s') . PHP_EOL . PHP_EOL . "SET NAMES utf8;" . PHP_EOL . "SET foreign_key_checks = 0;" . PHP_EOL . PHP_EOL;
45
+ if (!@fwrite($handle, $preamble)) {
46
+ return false;
47
+ }
48
+
49
+ // Loop through each table
50
+ foreach ($tables as $table) {
51
+ $table_name = $table[0];
52
+
53
+ $result_create_table = $wpdb->get_row('SHOW CREATE TABLE `' . $table_name . '`;', ARRAY_N);
54
+ if (empty($result_create_table)) {
55
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - get_row returned null for table: ".$table_name, 4);
56
+ return false; // Avoid incomplete backups
57
+ }
58
+
59
+ // Drop/create table preamble
60
+ $drop_and_create = 'DROP TABLE IF EXISTS `' . $table_name . '`;' . PHP_EOL . PHP_EOL . $result_create_table[1] . ";" . PHP_EOL . PHP_EOL;
61
+ if (!@fwrite($handle, $drop_and_create)) {
62
+ return false;
63
+ }
64
+
65
+ // Dump table contents
66
+ // Fetch results as row of objects to spare memory.
67
+ $result = $wpdb->get_results('SELECT * FROM `' . $table_name . '`;', OBJECT);
68
+ foreach ($result as $object_row) {
69
+ // Convert object row to array row: this is what $wpdb->get_results()
70
+ // internally does when invoked with ARRAY_N param, but in the process
71
+ // it creates new copy of entire results array that eats a lot of memory.
72
+ $row = array_values(get_object_vars($object_row));
73
+ // Start INSERT statement
74
+ if (!@fwrite($handle, 'INSERT INTO `' . $table_name . '` VALUES(')) {
75
+ return false;
76
+ }
77
+ // Loop through all fields and echo them out
78
+ foreach ($row as $idx => $field) {
79
+ // Echo fields separator (except for first loop)
80
+ if (($idx > 0) && !@fwrite($handle, ',')) {
81
+ return false;
82
+ }
83
+ // Echo field content (sanitized)
84
+ if (!@fwrite($handle, $this->sanitize_db_field($field))) {
85
+ return false;
86
+ }
87
+ }
88
+ // Finish INSERT statement
89
+ if (!@fwrite($handle, ");" . PHP_EOL)) {
90
+ return false;
91
+ }
92
+ }
93
+ // Place two-empty lines after table data
94
+ if (!@fwrite($handle, PHP_EOL . PHP_EOL)) {
95
+ return false;
96
+ }
97
+ }
98
+
99
+ return true;
100
+ }
101
+
102
+ /**
103
+ * This function will perform a database backup
104
+ */
105
+ public function execute_backup() {
106
+ global $wpdb, $aio_wp_security;
107
+ $is_multi_site = function_exists('is_multisite') && is_multisite();
108
+
109
+ $execute_backup_memory_limit = apply_filters('aiowps_execute_backup_set_memory_limit', '512M');
110
+ @ini_set('memory_limit', $execute_backup_memory_limit);
111
+
112
+ if ($is_multi_site) {
113
+ //Let's get the current site's table prefix
114
+ $site_pref = esc_sql($wpdb->prefix);
115
+ $db_query = "SHOW TABLES LIKE '".$site_pref."%'";
116
+ $tables = $wpdb->get_results($db_query, ARRAY_N);
117
+ } else {
118
+ //get all of the tables
119
+ $tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
120
+ }
121
+
122
+ if (empty($tables)) {
123
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - no tables found!", 4);
124
+ return false;
125
+ }
126
+
127
+ //Check to see if the main "backups" directory exists - create it otherwise
128
+
129
+ $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
130
+ if (!AIOWPSecurity_Utility_File::create_dir($aiowps_backup_dir)) {
131
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Creation of DB backup directory failed!", 4);
132
+ return false;
133
+ }
134
+
135
+ //Generate a random prefix for more secure filenames
136
+ $random_suffix = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10);
137
+
138
+ if ($is_multi_site) {
139
+ global $current_blog;
140
+ $blog_id = $current_blog->blog_id;
141
+ //Get the current site name string for use later
142
+ $site_name = get_bloginfo('name');
143
+
144
+ $site_name = strtolower($site_name);
145
+
146
+ //make alphanumeric
147
+ $site_name = preg_replace("/[^a-z0-9_\s-]/", "", $site_name);
148
+
149
+ //Cleanup multiple instances of dashes or whitespaces
150
+ $site_name = preg_replace("/[\s-]+/", " ", $site_name);
151
+
152
+ //Convert whitespaces and underscore to dash
153
+ $site_name = preg_replace("/[\s_]/", "-", $site_name);
154
+
155
+ $file = 'database-backup-site-name-' . $site_name . '-' . current_time('Ymd-His') . '-' . $random_suffix;
156
+
157
+ //We will create a sub dir for the blog using its blog id
158
+ $dirpath = $aiowps_backup_dir . '/blogid_' . $blog_id;
159
+
160
+ //Create a subdirectory for this blog_id
161
+ if (!AIOWPSecurity_Utility_File::create_dir($dirpath)) {
162
+ $aio_wp_security->debug_logger->log_debug("Creation failed of DB backup directory for the following multisite blog ID: ".$blog_id, 4);
163
+ return false;
164
+ }
165
+ } else {
166
+ $dirpath = $aiowps_backup_dir;
167
+ $file = 'database-backup-' . current_time('Ymd-His') . '-' . $random_suffix;
168
+ }
169
+
170
+ $handle = @fopen($dirpath . '/' . $file . '.sql', 'w+');
171
+
172
+ if (false === $handle) {
173
+ $aio_wp_security->debug_logger->log_debug("Cannot create DB backup file: {$dirpath}/{$file}.sql", 4);
174
+ return false;
175
+ }
176
+
177
+ // Delete old backup files now to avoid polluting backups directory
178
+ // with incomplete backups on websites where max execution time is too
179
+ // low for database content to be written to a file:
180
+ // https://github.com/Arsenal21/all-in-one-wordpress-security/issues/62
181
+ $this->aiowps_delete_backup_files($dirpath);
182
+
183
+ $fw_res = $this->write_db_backup_file($handle, $tables);
184
+ @fclose($handle);
185
+
186
+ if (!$fw_res) {
187
+ @unlink($dirpath . '/' . $file . '.sql');
188
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Write to DB backup file failed", 4);
189
+ return false;
190
+ }
191
+
192
+ //zip the file
193
+ if (class_exists('ZipArchive')) {
194
+ $zip = new ZipArchive();
195
+ $archive = $zip->open($dirpath . '/' . $file . '.zip', ZipArchive::CREATE);// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
196
+ $zip->addFile($dirpath . '/' . $file . '.sql', $file . '.sql');
197
+ $zip->close();
198
+
199
+ //delete .sql and keep zip
200
+ @unlink($dirpath . '/' . $file . '.sql');
201
+ $fileext = '.zip';
202
+ } else {
203
+ $fileext = '.sql';
204
+ }
205
+ $this->last_backup_file_name = $file . $fileext;//database-backup-YYYYMMDD-HHIISS-<random-string>.zip or database-backup-YYYYMMDD-HHIISS-<random-string>.sql
206
+ $this->last_backup_file_path = $dirpath . '/' . $file . $fileext;
207
+ if ($is_multi_site) {
208
+ $this->last_backup_file_dir_multisite = $aiowps_backup_dir . '/blogid_' . $blog_id;
209
+ }
210
+
211
+ $this->aiowps_send_backup_email(); //Send backup file via email if applicable
212
+ return true;
213
+ }
214
+
215
+ public function aiowps_send_backup_email() {
216
+ global $aio_wp_security;
217
+ if ($aio_wp_security->configs->get_value('aiowps_send_backup_email_address') == '1') {
218
+ //Get the right email address.
219
+ if (is_email($aio_wp_security->configs->get_value('aiowps_backup_email_address'))) {
220
+ $toaddress = $aio_wp_security->configs->get_value('aiowps_backup_email_address');
221
+ } else {
222
+ $toaddress = get_site_option('admin_email');
223
+ }
224
+
225
+ $to = $toaddress;
226
+ $site_title = get_bloginfo('name');
227
+ $from_name = empty($site_title) ? 'WordPress' : $site_title;
228
+
229
+ $headers = 'From: ' . $from_name . ' <' . get_option('admin_email') . '>' . PHP_EOL;
230
+ $subject = __('All In One WP Security - Site Database Backup', 'all-in-one-wp-security-and-firewall') . ' ' . date('l, F jS, Y \a\\t g:i a', current_time('timestamp'));
231
+ $attachment = array($this->last_backup_file_path);
232
+ $message = __('Attached is your latest DB backup file for site URL', 'all-in-one-wp-security-and-firewall') . ' ' . get_option('siteurl') . __(' generated on', 'all-in-one-wp-security-and-firewall') . ' ' . date('l, F jS, Y \a\\t g:i a', current_time('timestamp'));
233
+
234
+ $sendMail = wp_mail($to, $subject, $message, $headers, $attachment);
235
+ if (false === $sendMail) {
236
+ $aio_wp_security->debug_logger->log_debug("Backup notification email failed to send to ".$to, 4);
237
+ }
238
+ }
239
+ }
240
+
241
+ public function aiowps_delete_backup_files($backups_dir) {
242
+ global $aio_wp_security;
243
+ $files_to_keep = absint($aio_wp_security->configs->get_value('aiowps_backup_files_stored'));
244
+ if ($files_to_keep > 0) {
245
+ $aio_wp_security->debug_logger->log_debug(sprintf('DB Backup - Deleting all but %d latest backup file(s) in %s directory.', $files_to_keep, $backups_dir));
246
+ $files = AIOWPSecurity_Utility_File::scan_dir_sort_date($backups_dir);
247
+ $count = 0;
248
+
249
+ foreach ($files as $file) {
250
+ if (strpos($file, 'database-backup') !== false) {
251
+ if ($count >= $files_to_keep) {
252
+ @unlink($backups_dir . '/' . $file);
253
+ }
254
+ $count++;
255
+ }
256
+ }
257
+ } else {
258
+ $aio_wp_security->debug_logger->log_debug('DB Backup - Backup configuration prevents removal of old backup files!', 3);
259
+ }
260
+ }
261
+
262
+ public function aiowps_scheduled_backup_handler() {
263
+ global $aio_wp_security;
264
+ if ($aio_wp_security->configs->get_value('aiowps_enable_automated_backups')=='1') {
265
+ $aio_wp_security->debug_logger->log_debug_cron("DB Backup - Scheduled backup is enabled. Checking if a backup needs to be done now...");
266
+ $time_now = current_time('mysql');
267
+ $current_time = strtotime($time_now);
268
+ $backup_frequency = $aio_wp_security->configs->get_value('aiowps_db_backup_frequency'); //Number of hours or days or months interval per backup
269
+ $interval_setting = $aio_wp_security->configs->get_value('aiowps_db_backup_interval'); //Hours/Days/Months
270
+ switch ($interval_setting) {
271
+ case '0':
272
+ $interval = 'hours';
273
+ break;
274
+ case '1':
275
+ $interval = 'days';
276
+ break;
277
+ case '2':
278
+ $interval = 'weeks';
279
+ break;
280
+ default:
281
+ // Fall back to default value, if config is corrupted for some reason.
282
+ $interval = 'weeks';
283
+ break;
284
+ }
285
+ $last_backup_time = $aio_wp_security->configs->get_value('aiowps_last_backup_time');
286
+ if (null != $last_backup_time) {
287
+ $last_backup_time = strtotime($aio_wp_security->configs->get_value('aiowps_last_backup_time'));
288
+ $next_backup_time = strtotime("+".abs($backup_frequency).$interval, $last_backup_time);
289
+ if ($next_backup_time <= $current_time) {
290
+ //It's time to do a backup
291
+ $result = $this->execute_backup();
292
+ if ($result) {
293
+ $aio_wp_security->configs->set_value('aiowps_last_backup_time', $time_now);
294
+ $aio_wp_security->configs->save_config();
295
+ $aio_wp_security->debug_logger->log_debug_cron("DB Backup - Scheduled backup was successfully completed.");
296
+ } else {
297
+ $aio_wp_security->debug_logger->log_debug_cron("DB Backup - Scheduled backup operation failed!", 4);
298
+ }
299
+ }
300
+ } else {
301
+ //Set the last backup time to now so it can trigger for the next scheduled period
302
+ $aio_wp_security->configs->set_value('aiowps_last_backup_time', $time_now);
303
+ $aio_wp_security->configs->save_config();
304
+ }
305
+ }
306
+ }
307
+
308
+
309
+ public function aiowps_scheduled_db_cleanup_handler() {
310
+ //Check the events table because this can grow quite large especially when 404 events are being logged
311
+ $events_table_name = AIOWPSEC_TBL_EVENTS;
312
+ $max_rows_event_table = '5000'; //Keep a max of 5000 rows in the events table
313
+ $max_rows_event_table = apply_filters('aiowps_max_rows_event_table', $max_rows_event_table);
314
+ AIOWPSecurity_Utility::cleanup_table($events_table_name, $max_rows_event_table);
315
+
316
+ //Check the failed logins table
317
+ $failed_logins_table_name = AIOWPSEC_TBL_FAILED_LOGINS;
318
+ $max_rows_failed_logins_table = '5000'; //Keep a max of 5000 rows in the events table
319
+ $max_rows_failed_logins_table = apply_filters('aiowps_max_rows_failed_logins_table', $max_rows_failed_logins_table);
320
+ AIOWPSecurity_Utility::cleanup_table($failed_logins_table_name, $max_rows_failed_logins_table);
321
+
322
+ //Check the login activity table
323
+ $login_activity_table_name = AIOWPSEC_TBL_USER_LOGIN_ACTIVITY;
324
+ $max_rows_login_activity_table = '5000'; //Keep a max of 5000 rows in the events table
325
+ $max_rows_login_activity_table = apply_filters('aiowps_max_rows_login_attempts_table', $max_rows_login_activity_table);
326
+ AIOWPSecurity_Utility::cleanup_table($login_activity_table_name, $max_rows_login_activity_table);
327
+
328
+ //Check the global meta table
329
+ $global_meta_table_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
330
+ $max_rows_global_meta_table = '5000'; //Keep a max of 5000 rows in this table
331
+ $max_rows_global_meta_table = apply_filters('aiowps_max_rows_global_meta_table', $max_rows_global_meta_table);
332
+ AIOWPSecurity_Utility::cleanup_table($global_meta_table_name, $max_rows_global_meta_table);
333
+
334
+ //Delete any expired _aiowps_captcha_string_info_xxxx option
335
+ AIOWPSecurity_Utility::delete_expired_captcha_options();
336
+
337
+ //Keep adding other DB cleanup tasks as they arise...
338
+ }
339
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/wp-security-blocking.php CHANGED
@@ -1,120 +1,119 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Blocking
7
- {
8
- function __construct(){
9
- //NOP
10
- }
11
 
12
- /**
13
- * Will return an array of blocked IPs in the AIOWPSEC_TBL_PERM_BLOCK table
14
- * @param string $block_reason - spam, etc
15
- * @param string $output_type
16
- * @return single dimensional array
17
- */
18
- static function get_list_blocked_ips($block_reason='', $output_type='ARRAY_A')
19
- {
20
- global $wpdb;
21
- $blocked_ip_array = array();
22
- if(empty($block_reason)){
23
- $sql = 'SELECT blocked_ip FROM '.AIOWPSEC_TBL_PERM_BLOCK;
24
- }else{
25
- $sql = $wpdb->prepare('SELECT blocked_ip FROM '.AIOWPSEC_TBL_PERM_BLOCK.' WHERE block_reason=%s',$block_reason);
26
- }
27
 
28
- $result = $wpdb->get_results($sql,$output_type);
29
- //The result returned by wp function is multi-dim array. Let's return a simple single dimensional array of ip addresses
30
- if(!empty($result)){
31
- foreach($result as $item){
32
- $blocked_ip_array[] = $item['blocked_ip'];
33
- }
34
- }
35
- return $blocked_ip_array;
36
- }
 
 
 
 
 
 
 
37
 
38
- /**
39
- * Checks if an IP address is blocked permanently
40
- * @param $ip_address
41
- * @return bool
42
- */
43
- static function is_ip_blocked($ip_address)
44
- {
45
- global $wpdb;
46
- $blocked_record = $wpdb->get_row($wpdb->prepare('SELECT * FROM '.AIOWPSEC_TBL_PERM_BLOCK.' WHERE blocked_ip=%s', $ip_address));
47
- if(empty($blocked_record)){
48
- return false;
49
- }else{
50
- return true;
51
- }
52
- }
53
 
54
- /**
55
- * Will add an IP address to the permament block list
56
- * @param $ip_address
57
- * @param string $reason
58
- * @return bool - TRUE or FALSE on error
59
- */
60
- static function add_ip_to_block_list($ip_address, $reason='')
61
- {
62
- global $wpdb, $aio_wp_security;
63
- //Check if this IP address is already in the block list
64
- $blocked = AIOWPSecurity_Blocking::is_ip_blocked($ip_address);
65
- $time_now = current_time( 'mysql' );
66
- if(empty($blocked)){
67
- //Add this IP to the blocked table
68
- $data = array(
69
- 'blocked_ip'=>$ip_address,
70
- 'block_reason'=>$reason,
71
- 'blocked_date'=>$time_now
72
- );
73
- $data = apply_filters('pre_add_to_permanent_block', $data);
74
- $res = $wpdb->insert(AIOWPSEC_TBL_PERM_BLOCK, $data);
75
- if($res === false){
76
- $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Blocking::add_ip_to_block_list - Error inserting record into AIOWPSEC_TBL_PERM_BLOCK table for IP ".$ip_address);
77
- return false;
78
- }
79
- return true;
80
- }
81
- return true;
82
- }
83
 
84
- static function unblock_ip($ip_address)
85
- {
86
- global $wpdb;
87
- $where = array('blocked_ip'=>$ip_address);
88
- $result = $wpdb->delete(AIOWPSEC_TBL_PERM_BLOCK,$where);
89
- return $result;
90
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
- /**
93
- * Will check the current visitor IP against the blocked table
94
- * If IP present will block the visitor from viewing the site
95
- */
96
- static function check_visitor_ip_and_perform_blocking()
97
- {
98
- global $aio_wp_security, $wpdb;
99
- $visitor_ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
100
- $ip_type = WP_Http::is_ip_address($visitor_ip);
101
- if(empty($ip_type)){
102
- $aio_wp_security->debug_logger->log_debug("do_general_ip_blocking_tasks: ".$visitor_ip." is not a valid IP!",4);
103
- return;
104
- }
105
 
106
- //Check if this IP address is in the block list
107
- $blocked = AIOWPSecurity_Blocking::is_ip_blocked($visitor_ip);
108
- //TODO - future feature: add blocking whitelist and check
 
 
 
 
 
 
 
 
 
109
 
110
- if(empty($blocked)){
111
- return; //Visitor IP is not blocked - allow page to load
112
- }else{
113
- //block this visitor!!
114
- AIOWPSecurity_Utility::redirect_to_url('http://127.0.0.1');
115
- }
116
- return;
117
 
118
- }
 
 
 
 
 
 
119
 
120
- }
 
 
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Blocking {
 
 
 
 
7
 
8
+ /**
9
+ * Class constructor
10
+ **/
11
+ public function __construct() {
12
+ //NOP
13
+ }
 
 
 
 
 
 
 
 
 
14
 
15
+ /**
16
+ * Will return an array of blocked IPs in the AIOWPSEC_TBL_PERM_BLOCK table
17
+ *
18
+ * @param string $block_reason - spam, etc
19
+ * @param string $output_type
20
+ *
21
+ * @return single dimensional array
22
+ */
23
+ public static function get_list_blocked_ips($block_reason = '', $output_type = 'ARRAY_A') {
24
+ global $wpdb;
25
+ $blocked_ip_array = array();
26
+ if (empty($block_reason)) {
27
+ $sql = 'SELECT blocked_ip FROM '.AIOWPSEC_TBL_PERM_BLOCK;
28
+ } else {
29
+ $sql = $wpdb->prepare('SELECT blocked_ip FROM '.AIOWPSEC_TBL_PERM_BLOCK.' WHERE block_reason=%s', $block_reason);
30
+ }
31
 
32
+ $result = $wpdb->get_results($sql, $output_type);
33
+ //The result returned by wp function is multi-dim array. Let's return a simple single dimensional array of ip addresses
34
+ if (!empty($result)) {
35
+ foreach ($result as $item) {
36
+ $blocked_ip_array[] = $item['blocked_ip'];
37
+ }
38
+ }
39
+ return $blocked_ip_array;
40
+ }
 
 
 
 
 
 
41
 
42
+ /**
43
+ * Checks if an IP address is blocked permanently according to the database
44
+ *
45
+ * @param int $ip_address
46
+ *
47
+ * @return bool
48
+ */
49
+ public static function is_ip_blocked($ip_address) {
50
+ global $wpdb;
51
+ $blocked_record = $wpdb->get_row($wpdb->prepare('SELECT * FROM '.AIOWPSEC_TBL_PERM_BLOCK.' WHERE blocked_ip=%s', $ip_address));
52
+ return !empty($blocked_record);
53
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
+ /**
56
+ * Will add an IP address to the permament block list
57
+ *
58
+ * @param int $ip_address
59
+ * @param string $reason
60
+ * @return bool - TRUE or FALSE on error
61
+ */
62
+ public static function add_ip_to_block_list($ip_address, $reason = '') {
63
+ global $wpdb, $aio_wp_security;
64
+ //Check if this IP address is already in the block list
65
+ $blocked = AIOWPSecurity_Blocking::is_ip_blocked($ip_address);
66
+ $time_now = current_time('mysql');
67
+ if (empty($blocked)) {
68
+ //Add this IP to the blocked table
69
+ $data = array(
70
+ 'blocked_ip'=>$ip_address,
71
+ 'block_reason'=>$reason,
72
+ 'blocked_date'=>$time_now
73
+ );
74
+ $data = apply_filters('pre_add_to_permanent_block', $data);
75
+ $res = $wpdb->insert(AIOWPSEC_TBL_PERM_BLOCK, $data);
76
+ if (false === $res) {
77
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Blocking::add_ip_to_block_list - Error inserting record into AIOWPSEC_TBL_PERM_BLOCK table for IP ".$ip_address);
78
+ return false;
79
+ }
80
+ return true;
81
+ }
82
+ return true;
83
+ }
84
 
85
+ public static function unblock_ip($ip_address) {
86
+ global $wpdb;
87
+ $where = array('blocked_ip' => $ip_address);
88
+ $result = $wpdb->delete(AIOWPSEC_TBL_PERM_BLOCK, $where);
89
+ return $result;
90
+ }
 
 
 
 
 
 
 
91
 
92
+ /**
93
+ * Will check the current visitor IP against the blocked table
94
+ * If IP present will block the visitor from viewing the site
95
+ */
96
+ public static function check_visitor_ip_and_perform_blocking() {
97
+ global $aio_wp_security;
98
+ $visitor_ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
99
+ $ip_type = WP_Http::is_ip_address($visitor_ip);
100
+ if (empty($ip_type)) {
101
+ $aio_wp_security->debug_logger->log_debug("do_general_ip_blocking_tasks: ".$visitor_ip." is not a valid IP!", 4);
102
+ return;
103
+ }
104
 
105
+ //Check if this IP address is in the block list
106
+ $blocked = AIOWPSecurity_Blocking::is_ip_blocked($visitor_ip);
107
+ //TODO - future feature: add blocking whitelist and check
 
 
 
 
108
 
109
+ if (empty($blocked)) {
110
+ return; //Visitor IP is not blocked - allow page to load
111
+ } else {
112
+ //block this visitor!!
113
+ AIOWPSecurity_Utility::redirect_to_url('http://127.0.0.1');
114
+ }
115
+ return;
116
 
117
+ }
118
+
119
+ }
classes/wp-security-bot-protection.php CHANGED
@@ -1,51 +1,54 @@
1
  <?php
2
-
3
- /*
4
  * This class handles all bot related tasks and protection mechanisms.
5
- *
6
  */
7
- if(!defined('ABSPATH')){
8
- exit;//Exit if accessed directly
9
  }
10
 
11
- class AIOWPSecurity_Fake_Bot_Protection
12
- {
13
- function __construct()
14
- {
15
- //NOP
16
- }
 
17
 
18
- static function block_fake_googlebots()
19
- {
20
- global $aio_wp_security;
 
 
 
 
 
21
 
22
- $user_agent = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
23
- if (preg_match('/Googlebot/i', $user_agent, $matches)){
24
- //If user agent says it is googlebot start doing checks
25
- $ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
26
- $aio_wp_security->debug_logger->log_debug("block_fake_googlebots(): IP address = ".$ip,2);
27
- if(empty($ip)){
28
- $aio_wp_security->debug_logger->log_debug("block_fake_googlebots(): Empty IP address detected!",2);
29
- $aio_wp_security->debug_logger->log_debug("block_fake_googlebots(): User Agent = ".$user_agent,2);
30
- return;
31
- }
32
- $name = gethostbyaddr($ip); //let's get the internet hostname using the given IP address
33
- //TODO - maybe add check if gethostbyaddr() fails
34
- $host_ip = gethostbyname($name); //Reverse lookup - let's get the IP using the name
35
- if(preg_match('/Googlebot/i', $name, $matches)){
36
- if ($host_ip == $ip){
37
- //Genuine googlebot allow it through....
38
- }else{
39
- //fake googlebot - block it!
40
- $aio_wp_security->debug_logger->log_debug("Fake googlebot detected: IP = ".$ip." hostname = ".$name." reverse IP = ".$host_ip,2);
41
- exit();
42
- }
43
- }else{
44
- //fake googlebot - block it!
45
- $aio_wp_security->debug_logger->log_debug("Fake googlebot detected: IP = ".$ip." hostname = ".$name." reverse IP = ".$host_ip,2);
46
- exit();
47
- }
48
- }
49
- }
50
-
51
- }
1
  <?php
2
+ /**
 
3
  * This class handles all bot related tasks and protection mechanisms.
 
4
  */
5
+ if (!defined('ABSPATH')) {
6
+ exit;//Exit if accessed directly
7
  }
8
 
9
+ class AIOWPSecurity_Fake_Bot_Protection {
10
+ public function __construct() {
11
+ //NOP
12
+ }
13
+
14
+ public static function block_fake_googlebots() {
15
+ global $aio_wp_security;
16
 
17
+ $user_agent = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
18
+ if (preg_match('/Googlebot/i', $user_agent, $matches)) {
19
+ // If user agent says it is googlebot start doing checks
20
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
21
+ if (empty($ip)) {
22
+ $aio_wp_security->debug_logger->log_debug('block_fake_googlebots(): Empty IP address detected! User Agent = ' . $user_agent, 2);
23
+ return;
24
+ }
25
 
26
+ try {
27
+ $name = gethostbyaddr($ip); // let's get the internet hostname using the given IP address
28
+ if ($name == $ip || false === $name) return;
29
+ $host_ip = gethostbyname($name); // Reverse lookup - let's get the IP using the name
30
+ } catch (Exception $e) {
31
+ $log_message = 'block_fake_googlebots(): PHP Fatal Exception error ('.get_class($e).') has occurred during processing gethostbyaddr()/gethostbyname() function. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
32
+ $aio_wp_security->debug_logger->log_debug($log_message, 4); // $level_code = 4 for failure
33
+ return;
34
+ } catch (Error $e) {
35
+ $log_message = 'block_fake_googlebots(): PHP Fatal error ('.get_class($e).') has occurred during processing gethostbyaddr()/gethostbyname() function. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
36
+ $aio_wp_security->debug_logger->log_debug($log_message, 4); // $level_code = 4 for failure
37
+ return;
38
+ }
39
+ if (preg_match('/Google/i', $name, $matches)) {
40
+ if ($host_ip == $ip) {
41
+ // Genuine googlebot allow it through....
42
+ } else {
43
+ // fake googlebot - block it!
44
+ $aio_wp_security->debug_logger->log_debug('Fake googlebot detected: IP = '.$ip.' hostname = '.$name.' reverse IP = '. $host_ip, 2);
45
+ exit();
46
+ }
47
+ } else {
48
+ // fake googlebot - block it!
49
+ $aio_wp_security->debug_logger->log_debug('Fake googlebot detected: IP = '.$ip.' hostname = '.$name.' reverse IP = '.$host_ip, 2);
50
+ exit();
51
+ }
52
+ }
53
+ }
54
+ }
 
classes/wp-security-captcha.php CHANGED
@@ -1,238 +1,257 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Captcha
7
- {
8
- private $google_verify_recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
9
 
10
- function __construct()
11
- {
12
- //NOP
13
- }
14
-
15
- /**
16
- * Displays Google reCaptcha form v2
17
- * @global type $aio_wp_security
18
- */
19
- function display_recaptcha_form()
20
- {
21
- global $aio_wp_security;
22
- if($aio_wp_security->configs->get_value('aiowps_enable_bp_register_captcha') == '1' && defined('BP_VERSION')){
23
- //if buddy press feature active add action hook so buddy press can display our errors properly on bp registration form
24
- do_action( 'bp_aiowps-captcha-answer_errors' );
25
- }
26
- $site_key = esc_html( $aio_wp_security->configs->get_value('aiowps_recaptcha_site_key') );
27
- $cap_form = '<div class="g-recaptcha-wrap" style="padding:10px 0 10px 0"><div class="g-recaptcha" data-sitekey="'.$site_key.'"></div></div>';
28
- echo $cap_form;
29
- }
 
30
 
31
- /**
32
- * Displays simple maths captcha form
33
- * @global type $aio_wp_security
34
- */
35
- function display_captcha_form()
36
- {
37
- global $aio_wp_security;
38
- if($aio_wp_security->configs->get_value('aiowps_enable_bp_register_captcha') == '1' && defined('BP_VERSION')){
39
- //if buddy press feature active add action hook so buddy press can display our errors properly on bp registration form
40
- do_action( 'bp_aiowps-captcha-answer_errors' );
41
- }
42
- $cap_form = '<p class="aiowps-captcha"><label for="aiowps-captcha-answer">'.__('Please enter an answer in digits:','all-in-one-wp-security-and-firewall').'</label>';
43
- $cap_form .= '<div class="aiowps-captcha-equation"><strong>';
44
- $maths_question_output = $this->generate_maths_question();
45
- $cap_form .= $maths_question_output . '</strong></div></p>';
46
- echo $cap_form;
47
- }
48
-
49
- function generate_maths_question()
50
- {
51
- global $aio_wp_security;
52
- //For now we will only do plus, minus, multiplication
53
- $equation_string = '';
54
- $operator_type = array('&#43;', '&#8722;', '&#215;');
55
-
56
- $operand_display = array('word', 'number');
57
-
58
- //let's now generate an equation
59
- $operator = $operator_type[rand(0,2)];
60
 
61
- if($operator === '&#215;'){
62
- //Don't make the question too hard if multiplication
63
- $first_digit = rand(1,5);
64
- $second_digit = rand(1,5);
65
- }else{
66
- $first_digit = rand(1,20);
67
- $second_digit = rand(1,20);
68
- }
69
-
70
- if($operand_display[rand(0,1)] == 'word'){
71
- $first_operand = $this->number_word_mapping($first_digit);
72
- }else{
73
- $first_operand = $first_digit;
74
- }
75
-
76
- if($operand_display[rand(0,1)] == 'word'){
77
- $second_operand = $this->number_word_mapping($second_digit);
78
- }else{
79
- $second_operand = $second_digit;
80
- }
 
 
 
 
 
 
 
 
81
 
82
- //Let's caluclate the result and construct the equation string
83
- if($operator === '&#43;')
84
- {
85
- //Addition
86
- $result = $first_digit+$second_digit;
87
- $equation_string .= $first_operand . ' ' . $operator . ' ' . $second_operand . ' = ';
88
- }
89
- else if($operator === '&#8722;')
90
- {
91
- //Subtraction
92
- //If we are going to be negative let's swap operands around
93
- if($first_digit < $second_digit){
94
- $equation_string .= $second_operand . ' ' . $operator . ' ' . $first_operand . ' = ';
95
- $result = $second_digit-$first_digit;
96
- }else{
97
- $equation_string .= $first_operand . ' ' . $operator . ' ' . $second_operand . ' = ';
98
- $result = $first_digit-$second_digit;
99
- }
100
- }
101
- elseif($operator === '&#215;')
102
- {
103
- //Multiplication
104
- $equation_string .= $first_operand . ' ' . $operator . ' ' . $second_operand . ' = ';
105
- $result = $first_digit*$second_digit;
106
- }
107
-
108
- //Let's encode correct answer
109
- $captcha_secret_string = $aio_wp_security->configs->get_value('aiowps_captcha_secret_key');
110
- $current_time = time();
111
- $enc_result = base64_encode($current_time.$captcha_secret_string.$result);
112
- $random_str = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10);
113
- AIOWPSecurity_Utility::is_multisite_install() ? set_site_transient('aiowps_captcha_string_info_'.$random_str, $enc_result, 30 * 60) : set_transient('aiowps_captcha_string_info_'.$random_str, $enc_result, 30 * 60);
114
- $equation_string .= '<input type="hidden" name="aiowps-captcha-string-info" id="aiowps-captcha-string-info" value="'.$random_str.'" />';
115
- $equation_string .= '<input type="hidden" name="aiowps-captcha-temp-string" id="aiowps-captcha-temp-string" value="'.$current_time.'" />';
116
- $equation_string .= '<input type="text" size="2" id="aiowps-captcha-answer" name="aiowps-captcha-answer" value="" autocomplete="off" />';
117
- return $equation_string;
118
- }
119
-
120
- function number_word_mapping($num)
121
- {
122
- $number_map = array(
123
- 1 => __('one', 'all-in-one-wp-security-and-firewall'),
124
- 2 => __('two', 'all-in-one-wp-security-and-firewall'),
125
- 3 => __('three', 'all-in-one-wp-security-and-firewall'),
126
- 4 => __('four', 'all-in-one-wp-security-and-firewall'),
127
- 5 => __('five', 'all-in-one-wp-security-and-firewall'),
128
- 6 => __('six', 'all-in-one-wp-security-and-firewall'),
129
- 7 => __('seven', 'all-in-one-wp-security-and-firewall'),
130
- 8 => __('eight', 'all-in-one-wp-security-and-firewall'),
131
- 9 => __('nine', 'all-in-one-wp-security-and-firewall'),
132
- 10 => __('ten', 'all-in-one-wp-security-and-firewall'),
133
- 11 => __('eleven', 'all-in-one-wp-security-and-firewall'),
134
- 12 => __('twelve', 'all-in-one-wp-security-and-firewall'),
135
- 13 => __('thirteen', 'all-in-one-wp-security-and-firewall'),
136
- 14 => __('fourteen', 'all-in-one-wp-security-and-firewall'),
137
- 15 => __('fifteen', 'all-in-one-wp-security-and-firewall'),
138
- 16 => __('sixteen', 'all-in-one-wp-security-and-firewall'),
139
- 17 => __('seventeen', 'all-in-one-wp-security-and-firewall'),
140
- 18 => __('eighteen', 'all-in-one-wp-security-and-firewall'),
141
- 19 => __('nineteen', 'all-in-one-wp-security-and-firewall'),
142
- 20 => __('twenty', 'all-in-one-wp-security-and-firewall'),
143
- );
144
- return $number_map[$num];
145
- }
146
-
147
-
148
- /**
149
- * Verifies the math or Google recaptcha v2 forms
150
- * Returns TRUE if correct answer.
151
- * Returns FALSE on wrong captcha result or missing data.
152
- * @global type $aio_wp_security
153
- * @return boolean
154
- */
155
- function verify_captcha_submit () {
156
- global $aio_wp_security;
157
- if($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
158
- //Google reCaptcha enabled
159
- if (array_key_exists('g-recaptcha-response', $_POST)) {
160
- $g_recaptcha_response = isset($_POST['g-recaptcha-response'])?sanitize_text_field($_POST['g-recaptcha-response']):'';
161
- $verify_captcha = $this->verify_google_recaptcha($g_recaptcha_response);
162
- return $verify_captcha;
163
- }else {
164
- // Expected captcha field in $_POST but got none!
165
- return false;
166
- }
167
- } else {
168
- // math captcha is enabled
169
- if (array_key_exists('aiowps-captcha-answer', $_POST)) {
170
- $captcha_answer = isset($_POST['aiowps-captcha-answer'])?sanitize_text_field($_POST['aiowps-captcha-answer']):'';
171
 
172
- $verify_captcha = $this->verify_math_captcha_answer($captcha_answer);
173
- return $verify_captcha;
174
- } else {
175
- // Expected captcha field in $_POST but got none!
176
- return false;
177
- }
178
- }
179
- }
180
-
181
- /**
182
- * Verifies the math captcha answer entered by the user
183
- * @param type $captcha_answer
184
- * @return boolean
185
- */
186
- function verify_math_captcha_answer($captcha_answer='') {
187
- global $aio_wp_security;
188
- $captcha_secret_string = $aio_wp_security->configs->get_value('aiowps_captcha_secret_key');
189
- $captcha_temp_string = sanitize_text_field($_POST['aiowps-captcha-temp-string']);
190
- $submitted_encoded_string = base64_encode($captcha_temp_string.$captcha_secret_string.$captcha_answer);
191
- $trans_handle = sanitize_text_field($_POST['aiowps-captcha-string-info']);
192
- $captcha_string_info_trans = (AIOWPSecurity_Utility::is_multisite_install() ? get_site_transient('aiowps_captcha_string_info_'.$trans_handle) : get_transient('aiowps_captcha_string_info_'.$trans_handle));
193
- if($submitted_encoded_string === $captcha_string_info_trans) {
194
- return true;
195
- }else{
196
- return false; // wrong answer was entered
197
- }
198
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
- /**
201
- * Send a query to Google api to verify reCaptcha submission
202
- * @global type $aio_wp_security
203
- * @param type $resp_token
204
- * @return boolean
205
- */
206
- function verify_google_recaptcha($resp_token='') {
207
- global $aio_wp_security;
208
- $is_humanoid = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
 
210
- if ( empty( $resp_token ) ) {
211
- return $is_humanoid;
212
- }
 
 
 
 
 
 
 
213
 
214
- $url = $this->google_verify_recaptcha_url;
215
-
216
- $sitekey = $aio_wp_security->configs->get_value('aiowps_recaptcha_site_key');
217
- $secret = $aio_wp_security->configs->get_value('aiowps_recaptcha_secret_key');
218
- $ip_address = AIOWPSecurity_Utility_IP::get_user_ip_address();
219
- $response = wp_safe_remote_post( $url, array(
220
- 'body' => array(
221
- 'secret' => $secret,
222
- 'response' => $resp_token,
223
- 'remoteip' => $ip_address,
224
- ),
225
- ) );
226
 
227
- if ( wp_remote_retrieve_response_code( $response ) != 200 ) {
228
- return $is_humanoid;
229
- }
230
- $response = wp_remote_retrieve_body( $response );
231
- $response = json_decode( $response, true );
232
- if(isset( $response['success'] ) && $response['success'] == true) {
233
- $is_humanoid = true;
234
- }
235
- return $is_humanoid;
236
- }
 
 
237
 
238
- }
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Captcha {
7
+
8
+ private $google_verify_recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
9
 
10
+ public function __construct() {
11
+ //NOP
12
+ }
13
+
14
+ /**
15
+ * Displays Google reCaptcha form v2
16
+ *
17
+ * @global type $aio_wp_security
18
+ */
19
+ public function display_recaptcha_form() {
20
+ global $aio_wp_security;
21
+ if ($aio_wp_security->configs->get_value('aiowps_enable_bp_register_captcha') == '1' && defined('BP_VERSION')) {
22
+ //if buddy press feature active add action hook so buddy press can display our errors properly on bp registration form
23
+ do_action('bp_aiowps-captcha-answer_errors');
24
+ }
25
+ $site_key = $aio_wp_security->configs->get_value('aiowps_recaptcha_site_key');
26
+ if (false === $aio_wp_security->google_recaptcha_sitekey_verification($site_key)) {
27
+ $aio_wp_security->configs->set_value('aios_is_google_recaptcha_wrong_site_key', 1);
28
+ $aio_wp_security->configs->save_config();
29
+ return;
30
+ }
31
 
32
+ $cap_form = '<div class="g-recaptcha-wrap" style="padding:10px 0 10px 0"><div class="g-recaptcha" data-sitekey="'.esc_attr($site_key).'"></div></div>';
33
+ echo $cap_form;
34
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ /**
37
+ * Displays simple maths captcha form
38
+ *
39
+ * @global type $aio_wp_security
40
+ */
41
+ public function display_captcha_form() {
42
+ global $aio_wp_security;
43
+ if ($aio_wp_security->configs->get_value('aiowps_enable_bp_register_captcha') == '1' && defined('BP_VERSION')) {
44
+ //if buddy press feature active add action hook so buddy press can display our errors properly on bp registration form
45
+ do_action('bp_aiowps-captcha-answer_errors');
46
+ }
47
+ $cap_form = '<p class="aiowps-captcha"><label for="aiowps-captcha-answer">'.__('Please enter an answer in digits:', 'all-in-one-wp-security-and-firewall').'</label>';
48
+ $cap_form .= '<div class="aiowps-captcha-equation"><strong>';
49
+ $maths_question_output = $this->generate_maths_question();
50
+ $cap_form .= $maths_question_output . '</strong></div></p>';
51
+ echo $cap_form;
52
+ }
53
+
54
+ public function generate_maths_question() {
55
+ global $aio_wp_security;
56
+ //For now we will only do plus, minus, multiplication
57
+ $equation_string = '';
58
+ $operator_type = array('&#43;', '&#8722;', '&#215;');
59
+
60
+ $operand_display = array('word', 'number');
61
+
62
+ //let's now generate an equation
63
+ $operator = $operator_type[rand(0, 2)];
64
 
65
+ if ('&#215;' === $operator) {
66
+ //Don't make the question too hard if multiplication
67
+ $first_digit = rand(1, 5);
68
+ $second_digit = rand(1, 5);
69
+ } else {
70
+ $first_digit = rand(1, 20);
71
+ $second_digit = rand(1, 20);
72
+ }
73
+
74
+ if ('word' == $operand_display[rand(0, 1)]) {
75
+ $first_operand = $this->number_word_mapping($first_digit);
76
+ } else {
77
+ $first_operand = $first_digit;
78
+ }
79
+
80
+ if ('word' == $operand_display[rand(0, 1)]) {
81
+ $second_operand = $this->number_word_mapping($second_digit);
82
+ } else {
83
+ $second_operand = $second_digit;
84
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
+ //Let's caluclate the result and construct the equation string
87
+ if ('&#43;' === $operator) {
88
+ //Addition
89
+ $result = $first_digit+$second_digit;
90
+ $equation_string .= $first_operand . ' ' . $operator . ' ' . $second_operand . ' = ';
91
+ } elseif ('&#8722;' === $operator) {
92
+ //Subtraction
93
+ //If we are going to be negative let's swap operands around
94
+ if ($first_digit < $second_digit) {
95
+ $equation_string .= $second_operand . ' ' . $operator . ' ' . $first_operand . ' = ';
96
+ $result = $second_digit-$first_digit;
97
+ } else {
98
+ $equation_string .= $first_operand . ' ' . $operator . ' ' . $second_operand . ' = ';
99
+ $result = $first_digit-$second_digit;
100
+ }
101
+ } elseif ('&#215;' === $operator) {
102
+ //Multiplication
103
+ $equation_string .= $first_operand . ' ' . $operator . ' ' . $second_operand . ' = ';
104
+ $result = $first_digit*$second_digit;
105
+ }
106
+
107
+ //Let's encode correct answer
108
+ $captcha_secret_string = $aio_wp_security->configs->get_value('aiowps_captcha_secret_key');
109
+ $current_time = time();
110
+ $enc_result = base64_encode($current_time.$captcha_secret_string.$result);
111
+ $random_str = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10);
112
+ if (AIOWPSecurity_Utility::is_multisite_install()) {
113
+ update_site_option('aiowps_captcha_string_info_'.$random_str, $enc_result);
114
+ update_site_option('aiowps_captcha_string_info_time_'.$random_str, $current_time);
115
+ } else {
116
+ update_option('aiowps_captcha_string_info_'.$random_str, $enc_result);
117
+ update_option('aiowps_captcha_string_info_time_'.$random_str, $current_time);
118
+ }
119
+ $equation_string .= '<input type="hidden" name="aiowps-captcha-string-info" id="aiowps-captcha-string-info" value="'.$random_str.'" />';
120
+ $equation_string .= '<input type="hidden" name="aiowps-captcha-temp-string" id="aiowps-captcha-temp-string" value="'.$current_time.'" />';
121
+ $equation_string .= '<input type="text" size="2" id="aiowps-captcha-answer" name="aiowps-captcha-answer" value="" autocomplete="off" />';
122
+ return $equation_string;
123
+ }
124
+
125
+ public function number_word_mapping($num) {
126
+ $number_map = array(
127
+ 1 => __('one', 'all-in-one-wp-security-and-firewall'),
128
+ 2 => __('two', 'all-in-one-wp-security-and-firewall'),
129
+ 3 => __('three', 'all-in-one-wp-security-and-firewall'),
130
+ 4 => __('four', 'all-in-one-wp-security-and-firewall'),
131
+ 5 => __('five', 'all-in-one-wp-security-and-firewall'),
132
+ 6 => __('six', 'all-in-one-wp-security-and-firewall'),
133
+ 7 => __('seven', 'all-in-one-wp-security-and-firewall'),
134
+ 8 => __('eight', 'all-in-one-wp-security-and-firewall'),
135
+ 9 => __('nine', 'all-in-one-wp-security-and-firewall'),
136
+ 10 => __('ten', 'all-in-one-wp-security-and-firewall'),
137
+ 11 => __('eleven', 'all-in-one-wp-security-and-firewall'),
138
+ 12 => __('twelve', 'all-in-one-wp-security-and-firewall'),
139
+ 13 => __('thirteen', 'all-in-one-wp-security-and-firewall'),
140
+ 14 => __('fourteen', 'all-in-one-wp-security-and-firewall'),
141
+ 15 => __('fifteen', 'all-in-one-wp-security-and-firewall'),
142
+ 16 => __('sixteen', 'all-in-one-wp-security-and-firewall'),
143
+ 17 => __('seventeen', 'all-in-one-wp-security-and-firewall'),
144
+ 18 => __('eighteen', 'all-in-one-wp-security-and-firewall'),
145
+ 19 => __('nineteen', 'all-in-one-wp-security-and-firewall'),
146
+ 20 => __('twenty', 'all-in-one-wp-security-and-firewall'),
147
+ );
148
+ return $number_map[$num];
149
+ }
150
+
151
+
152
+ /**
153
+ * Verifies the math or Google recaptcha v2 forms
154
+ * Returns TRUE if correct answer.
155
+ * Returns FALSE on wrong captcha result or missing data.
156
+ *
157
+ * @global type $aio_wp_security
158
+ * @return boolean
159
+ */
160
+ public function verify_captcha_submit() {
161
+ global $aio_wp_security;
162
+ if ($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
163
+ //Google reCaptcha enabled
164
+ if (1 == $aio_wp_security->configs->get_value('aios_is_google_recaptcha_wrong_site_key')) {
165
+ return true;
166
+ }
167
+ $site_key = esc_html($aio_wp_security->configs->get_value('aiowps_recaptcha_site_key'));// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
168
+ if (array_key_exists('g-recaptcha-response', $_POST)) {
169
+ $g_recaptcha_response = isset($_POST['g-recaptcha-response']) ? sanitize_text_field($_POST['g-recaptcha-response']) : '';
170
+ $verify_captcha = $this->verify_google_recaptcha($g_recaptcha_response);
171
+ return $verify_captcha;
172
+ } else {
173
+ // Expected captcha field in $_POST but got none!
174
+ return false;
175
+ }
176
+ } else {
177
+ // math captcha is enabled
178
+ if (array_key_exists('aiowps-captcha-answer', $_POST)) {
179
+ $captcha_answer = isset($_POST['aiowps-captcha-answer']) ? sanitize_text_field($_POST['aiowps-captcha-answer']) : '';
180
 
181
+ $verify_captcha = $this->verify_math_captcha_answer($captcha_answer);
182
+ return $verify_captcha;
183
+ } else {
184
+ // Expected captcha field in $_POST but got none!
185
+ return false;
186
+ }
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Verifies the math captcha answer entered by the user
192
+ *
193
+ * @param type $captcha_answer
194
+ * @return boolean
195
+ */
196
+ public function verify_math_captcha_answer($captcha_answer = '') {
197
+ global $aio_wp_security;
198
+ $captcha_secret_string = $aio_wp_security->configs->get_value('aiowps_captcha_secret_key');
199
+ $captcha_temp_string = sanitize_text_field($_POST['aiowps-captcha-temp-string']);
200
+ $submitted_encoded_string = base64_encode($captcha_temp_string.$captcha_secret_string.$captcha_answer);
201
+ $trans_handle = sanitize_text_field($_POST['aiowps-captcha-string-info']);
202
+ if (AIOWPSecurity_Utility::is_multisite_install()) {
203
+ $captcha_string_info_option = get_site_option('aiowps_captcha_string_info_'.$trans_handle);
204
+ delete_site_option('aiowps_captcha_string_info_'.$trans_handle);
205
+ delete_site_option('aiowps_captcha_string_info_time_'.$trans_handle);
206
+ } else {
207
+ $captcha_string_info_option = get_option('aiowps_captcha_string_info_'.$trans_handle);
208
+ delete_option('aiowps_captcha_string_info_'.$trans_handle);
209
+ delete_option('aiowps_captcha_string_info_time_'.$trans_handle);
210
+ }
211
+ if ($submitted_encoded_string === $captcha_string_info_option) {
212
+ return true;
213
+ } else {
214
+ return false; // wrong answer was entered
215
+ }
216
+ }
217
 
218
+ /**
219
+ * Send a query to Google api to verify reCaptcha submission
220
+ *
221
+ * @global type $aio_wp_security
222
+ * @param type $resp_token
223
+ * @return boolean
224
+ */
225
+ public function verify_google_recaptcha($resp_token = '') {
226
+ global $aio_wp_security;
227
+ $is_humanoid = false;
228
 
229
+ if (empty($resp_token)) {
230
+ return $is_humanoid;
231
+ }
 
 
 
 
 
 
 
 
 
232
 
233
+ $url = $this->google_verify_recaptcha_url;
234
+
235
+ $sitekey = $aio_wp_security->configs->get_value('aiowps_recaptcha_site_key');// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
236
+ $secret = $aio_wp_security->configs->get_value('aiowps_recaptcha_secret_key');
237
+ $ip_address = AIOWPSecurity_Utility_IP::get_user_ip_address();
238
+ $response = wp_safe_remote_post($url, array(
239
+ 'body' => array(
240
+ 'secret' => $secret,
241
+ 'response' => $resp_token,
242
+ 'remoteip' => $ip_address,
243
+ ),
244
+ ));
245
 
246
+ if (wp_remote_retrieve_response_code($response) != 200) {
247
+ return $is_humanoid;
248
+ }
249
+ $response = wp_remote_retrieve_body($response);
250
+ $response = json_decode($response, true);
251
+ if (isset($response['success']) && true == $response['success']) {
252
+ $is_humanoid = true;
253
+ }
254
+ return $is_humanoid;
255
+ }
256
+
257
+ }
classes/wp-security-config.php CHANGED
@@ -1,60 +1,78 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Config{
7
- var $configs;
8
- var $message_stack;
9
- static $_this;
10
-
11
- function __construct(){
12
- $this->message_stack = new stdClass();
13
- }
14
 
15
- function load_config(){
 
 
 
 
 
 
 
16
  $this->configs = get_option('aio_wp_security_configs');
17
- }
18
 
19
- function get_value($key){
20
- return isset($this->configs[$key])?$this->configs[$key] : '';
21
- }
22
-
23
- function set_value($key, $value){
24
- $this->configs[$key] = $value;
25
- }
26
-
27
- function add_value($key, $value){
28
- if(!is_array($this->configs)){$this->configs = array();}
29
-
30
- if (array_key_exists($key, $this->configs)){
31
- //Don't update the value for this key
32
- }
33
- else{//It is safe to update the value for this key
34
- $this->configs[$key] = $value;
35
- }
36
- }
37
-
38
- function save_config(){
39
- update_option('aio_wp_security_configs', $this->configs);
40
- }
41
-
42
- function get_stacked_message($key){
43
- if(isset($this->message_stack->{$key}))
44
- return $this->message_stack->{$key};
45
- return "";
46
- }
47
-
48
- function set_stacked_message($key,$value){
49
- $this->message_stack->{$key} = $value;
50
- }
51
-
52
- static function get_instance(){
53
- if(empty(self::$_this)){
54
- self::$_this = new AIOWPSecurity_Config();
55
- self::$_this->load_config();
56
- return self::$_this;
57
- }
58
- return self::$_this;
59
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Config {
 
 
 
 
 
 
 
7
 
8
+ public $configs;
9
+
10
+ public static $_this;
11
+
12
+ public function __construct() {
13
+ }
14
+
15
+ public function load_config() {
16
  $this->configs = get_option('aio_wp_security_configs');
17
+ }
18
 
19
+ public function get_value($key) {
20
+ return isset($this->configs[$key]) ? $this->configs[$key] : '';
21
+ }
22
+
23
+ public function set_value($key, $value) {
24
+ $this->configs[$key] = $value;
25
+ }
26
+
27
+ public function add_value($key, $value) {
28
+ if (!is_array($this->configs)) {
29
+ $this->configs = array();
30
+ }
31
+
32
+ if (array_key_exists($key, $this->configs)) {
33
+ //Don't update the value for this key
34
+ } else {//It is safe to update the value for this key
35
+ $this->configs[$key] = $value;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Save configuaration that are set.
41
+ *
42
+ * @return boolean True on save config, Otherwise false.
43
+ */
44
+ public function save_config() {
45
+ return update_option('aio_wp_security_configs', $this->configs);
46
+ }
47
+
48
+ /**
49
+ * Remove key element from config.
50
+ *
51
+ * @param String $key config key
52
+ *
53
+ * @return boolean True if removed, otherwise false.
54
+ */
55
+ public function delete_value($key) {
56
+ if (!is_array($this->configs)) {
57
+ $this->configs = array();
58
+ }
59
+
60
+ if (array_key_exists($key, $this->configs)) {
61
+ unset($this->configs[$key]);
62
+ if (!isset($this->configs[$key])) {
63
+ return true;
64
+ }
65
+ }
66
+
67
+ return false;
68
+ }
69
+
70
+ public static function get_instance() {
71
+ if (empty(self::$_this)) {
72
+ self::$_this = new AIOWPSecurity_Config();
73
+ self::$_this->load_config();
74
+ return self::$_this;
75
+ }
76
+ return self::$_this;
77
+ }
78
  }
classes/wp-security-configure-settings.php CHANGED
@@ -1,376 +1,368 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Configure_Settings
7
- {
8
- function __construct(){
9
-
10
- }
11
-
12
- static function set_default_settings()
13
- {
14
- global $aio_wp_security;
15
- $blog_email_address = get_bloginfo('admin_email'); //Get the blog admin email address - we will use as the default value
16
-
17
- //Debug
18
- $aio_wp_security->configs->set_value('aiowps_enable_debug','');//Checkbox
19
-
20
- //WP Generator Meta Tag feature
21
- $aio_wp_security->configs->set_value('aiowps_remove_wp_generator_meta_info','');//Checkbox
22
-
23
- //Prevent Image Hotlinks
24
- $aio_wp_security->configs->set_value('aiowps_prevent_hotlinking','');//Checkbox
25
- //General Settings Page
26
-
27
- //User password feature
28
-
29
- //Lockdown feature
30
- $aio_wp_security->configs->set_value('aiowps_enable_login_lockdown','');//Checkbox
31
- $aio_wp_security->configs->set_value('aiowps_allow_unlock_requests','');//Checkbox
32
- $aio_wp_security->configs->set_value('aiowps_max_login_attempts','3');
33
- $aio_wp_security->configs->set_value('aiowps_retry_time_period','5');
34
- $aio_wp_security->configs->set_value('aiowps_lockout_time_length','60');
35
- $aio_wp_security->configs->set_value('aiowps_set_generic_login_msg','');//Checkbox
36
- $aio_wp_security->configs->set_value('aiowps_enable_email_notify','');//Checkbox
37
- $aio_wp_security->configs->set_value('aiowps_email_address',$blog_email_address);//text field
38
- $aio_wp_security->configs->set_value('aiowps_enable_forced_logout','');//Checkbox
39
- $aio_wp_security->configs->set_value('aiowps_logout_time_period','60');
40
- $aio_wp_security->configs->set_value('aiowps_enable_invalid_username_lockdown','');//Checkbox
41
- $aio_wp_security->configs->set_value('aiowps_instantly_lockout_specific_usernames', array()); // Textarea (list of strings)
42
- $aio_wp_security->configs->set_value('aiowps_unlock_request_secret_key',AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20));//Hidden secret value which will be used to do some unlock request processing. This will be assigned a random string generated when lockdown settings saved
43
- $aio_wp_security->configs->set_value('aiowps_lockdown_enable_whitelisting','');//Checkbox
44
- $aio_wp_security->configs->set_value('aiowps_lockdown_allowed_ip_addresses','');
45
-
46
- //Captcha feature
47
- $aio_wp_security->configs->set_value('aiowps_enable_login_captcha','');//Checkbox
48
- $aio_wp_security->configs->set_value('aiowps_enable_custom_login_captcha','');//Checkbox
49
- $aio_wp_security->configs->set_value('aiowps_enable_woo_login_captcha','');//Checkbox
50
- $aio_wp_security->configs->set_value('aiowps_enable_woo_lostpassword_captcha','');//Checkbox
51
- $aio_wp_security->configs->set_value('aiowps_enable_woo_register_captcha','');//Checkbox
52
- $aio_wp_security->configs->set_value('aiowps_enable_lost_password_captcha','');//Checkbox
53
- $aio_wp_security->configs->set_value('aiowps_captcha_secret_key',AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20));//Hidden secret value which will be used to do some captcha processing. This will be assigned a random string generated when captcha settings saved
54
-
55
- //Login Whitelist feature
56
- $aio_wp_security->configs->set_value('aiowps_enable_whitelisting','');//Checkbox
57
- $aio_wp_security->configs->set_value('aiowps_allowed_ip_addresses','');
58
-
59
- //User registration
60
- $aio_wp_security->configs->set_value('aiowps_enable_manual_registration_approval','');//Checkbox
61
- $aio_wp_security->configs->set_value('aiowps_enable_registration_page_captcha','');//Checkbox
62
- $aio_wp_security->configs->set_value('aiowps_enable_registration_honeypot','');//Checkbox
63
-
64
- //DB Security feature
65
- //$aio_wp_security->configs->set_value('aiowps_new_manual_db_pefix',''); //text field
66
- $aio_wp_security->configs->set_value('aiowps_enable_random_prefix','');//Checkbox
67
- $aio_wp_security->configs->set_value('aiowps_enable_automated_backups','');//Checkbox
68
- $aio_wp_security->configs->set_value('aiowps_db_backup_frequency','4');
69
- $aio_wp_security->configs->set_value('aiowps_db_backup_interval','2'); //Dropdown box where (0,1,2) => (hours,days,weeks)
70
- $aio_wp_security->configs->set_value('aiowps_backup_files_stored','2');
71
- $aio_wp_security->configs->set_value('aiowps_send_backup_email_address','');//Checkbox
72
- $aio_wp_security->configs->set_value('aiowps_backup_email_address',$blog_email_address);
73
-
74
- //Filesystem Security feature
75
- $aio_wp_security->configs->set_value('aiowps_disable_file_editing','');//Checkbox
76
- $aio_wp_security->configs->set_value('aiowps_prevent_default_wp_file_access','');//Checkbox
77
- $aio_wp_security->configs->set_value('aiowps_system_log_file','error_log');
78
-
79
- //Blacklist feature
80
- $aio_wp_security->configs->set_value('aiowps_enable_blacklisting','');//Checkbox
81
- $aio_wp_security->configs->set_value('aiowps_banned_ip_addresses','');
82
-
83
- //Firewall features
84
- $aio_wp_security->configs->set_value('aiowps_enable_basic_firewall','');//Checkbox
85
- $aio_wp_security->configs->set_value('aiowps_max_file_upload_size','10'); //Default 10MB
86
- $aio_wp_security->configs->set_value('aiowps_enable_pingback_firewall','');//Checkbox - blocks all access to XMLRPC
87
- $aio_wp_security->configs->set_value('aiowps_disable_xmlrpc_pingback_methods','');//Checkbox - Disables only pingback methods in XMLRPC functionality
88
- $aio_wp_security->configs->set_value('aiowps_block_debug_log_file_access','');//Checkbox
89
- $aio_wp_security->configs->set_value('aiowps_disable_index_views','');//Checkbox
90
- $aio_wp_security->configs->set_value('aiowps_disable_trace_and_track','');//Checkbox
91
- $aio_wp_security->configs->set_value('aiowps_forbid_proxy_comments','');//Checkbox
92
- $aio_wp_security->configs->set_value('aiowps_deny_bad_query_strings','');//Checkbox
93
- $aio_wp_security->configs->set_value('aiowps_advanced_char_string_filter','');//Checkbox
94
- $aio_wp_security->configs->set_value('aiowps_enable_5g_firewall','');//Checkbox
95
- $aio_wp_security->configs->set_value('aiowps_enable_6g_firewall','');//Checkbox
96
- $aio_wp_security->configs->set_value('aiowps_enable_custom_rules','');//Checkbox
97
- $aio_wp_security->configs->set_value('aiowps_place_custom_rules_at_top','');//Checkbox
98
- $aio_wp_security->configs->set_value('aiowps_custom_rules','');
99
-
100
- //404 detection
101
- $aio_wp_security->configs->set_value('aiowps_enable_404_logging','');//Checkbox
102
- $aio_wp_security->configs->set_value('aiowps_enable_404_IP_lockout','');//Checkbox
103
- $aio_wp_security->configs->set_value('aiowps_404_lockout_time_length','60');
104
- $aio_wp_security->configs->set_value('aiowps_404_lock_redirect_url','http://127.0.0.1');
105
-
106
- //Brute Force features
107
- $aio_wp_security->configs->set_value('aiowps_enable_rename_login_page','');//Checkbox
108
- $aio_wp_security->configs->set_value('aiowps_enable_login_honeypot','');//Checkbox
109
-
110
- $aio_wp_security->configs->set_value('aiowps_enable_brute_force_attack_prevention','');//Checkbox
111
- $aio_wp_security->configs->set_value('aiowps_brute_force_secret_word','');
112
- $aio_wp_security->configs->set_value('aiowps_cookie_brute_test','');
113
- $aio_wp_security->configs->set_value('aiowps_cookie_based_brute_force_redirect_url','http://127.0.0.1');
114
- $aio_wp_security->configs->set_value('aiowps_brute_force_attack_prevention_pw_protected_exception','');//Checkbox
115
- $aio_wp_security->configs->set_value('aiowps_brute_force_attack_prevention_ajax_exception','');//Checkbox
116
-
117
- //Maintenance menu - Visitor lockout feature
118
- $aio_wp_security->configs->set_value('aiowps_site_lockout','');//Checkbox
119
- $aio_wp_security->configs->set_value('aiowps_site_lockout_msg','');//Text area/msg box
120
-
121
- //SPAM Prevention menu
122
- $aio_wp_security->configs->set_value('aiowps_enable_spambot_blocking','');//Checkbox
123
- $aio_wp_security->configs->set_value('aiowps_enable_comment_captcha','');//Checkbox
124
- $aio_wp_security->configs->set_value('aiowps_enable_autoblock_spam_ip','');//Checkbox
125
- $aio_wp_security->configs->set_value('aiowps_spam_ip_min_comments_block','');
126
- $aio_wp_security->configs->set_value('aiowps_enable_bp_register_captcha','');
127
- $aio_wp_security->configs->set_value('aiowps_enable_bbp_new_topic_captcha','');//Checkbox
128
-
129
- //Filescan features
130
- //File change detection feature
131
- $aio_wp_security->configs->set_value('aiowps_enable_automated_fcd_scan','');//Checkbox
132
- $aio_wp_security->configs->set_value('aiowps_fcd_scan_frequency','4');
133
- $aio_wp_security->configs->set_value('aiowps_fcd_scan_interval','2'); //Dropdown box where (0,1,2) => (hours,days,weeks)
134
- $aio_wp_security->configs->set_value('aiowps_fcd_exclude_filetypes','');
135
- $aio_wp_security->configs->set_value('aiowps_fcd_exclude_files','');
136
- $aio_wp_security->configs->set_value('aiowps_send_fcd_scan_email','');//Checkbox
137
- $aio_wp_security->configs->set_value('aiowps_fcd_scan_email_address',$blog_email_address);
138
- $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', FALSE); //used to display a global alert on site when file change detected
139
-
140
- //Misc Options
141
- //Copy protection feature
142
- $aio_wp_security->configs->set_value('aiowps_copy_protection','');//Checkbox
143
- //Prevent others from dislaying your site in iframe
144
- $aio_wp_security->configs->set_value('aiowps_prevent_site_display_inside_frame','');//Checkbox
145
- //Prevent users enumeration
146
- $aio_wp_security->configs->set_value('aiowps_prevent_users_enumeration','');//Checkbox
147
-
148
- //REST API Security
149
- $aio_wp_security->configs->set_value('aiowps_disallow_unauthorized_rest_requests','');//Checkbox
150
-
151
- //IP retrieval setting
152
- $aio_wp_security->configs->set_value('aiowps_ip_retrieve_method','0');//default is $_SERVER['REMOTE_ADDR']
153
-
154
- // Google reCaptcha
155
- $aio_wp_security->configs->set_value('aiowps_recaptcha_site_key','');
156
- $aio_wp_security->configs->set_value('aiowps_recaptcha_secret_key','');
157
- $aio_wp_security->configs->set_value('aiowps_default_recaptcha','');//Checkbox
158
-
159
- //TODO - keep adding default options for any fields that require it
160
-
161
- //Save it
162
- $aio_wp_security->configs->save_config();
163
- }
164
-
165
- static function add_option_values()
166
- {
167
- global $aio_wp_security;
168
- $blog_email_address = get_bloginfo('admin_email'); //Get the blog admin email address - we will use as the default value
169
-
170
- //Debug
171
- $aio_wp_security->configs->add_value('aiowps_enable_debug','');//Checkbox
172
-
173
- //WP Generator Meta Tag feature
174
- $aio_wp_security->configs->add_value('aiowps_remove_wp_generator_meta_info','');//Checkbox
175
-
176
- //Prevent Image Hotlinks
177
- $aio_wp_security->configs->add_value('aiowps_prevent_hotlinking','');//Checkbox
178
-
179
- //General Settings Page
180
-
181
- //User password feature
182
-
183
- //Lockdown feature
184
- $aio_wp_security->configs->add_value('aiowps_enable_login_lockdown','');//Checkbox
185
- $aio_wp_security->configs->add_value('aiowps_allow_unlock_requests','');//Checkbox
186
- $aio_wp_security->configs->add_value('aiowps_max_login_attempts','3');
187
- $aio_wp_security->configs->add_value('aiowps_retry_time_period','5');
188
- $aio_wp_security->configs->add_value('aiowps_lockout_time_length','60');
189
- $aio_wp_security->configs->add_value('aiowps_set_generic_login_msg','');//Checkbox
190
- $aio_wp_security->configs->add_value('aiowps_enable_email_notify','');//Checkbox
191
- $aio_wp_security->configs->add_value('aiowps_email_address',$blog_email_address);//text field
192
- $aio_wp_security->configs->add_value('aiowps_enable_forced_logout','');//Checkbox
193
- $aio_wp_security->configs->add_value('aiowps_logout_time_period','60');
194
- $aio_wp_security->configs->add_value('aiowps_enable_invalid_username_lockdown','');//Checkbox
195
- $aio_wp_security->configs->add_value('aiowps_instantly_lockout_specific_usernames', array()); // Textarea (list of strings)
196
- $aio_wp_security->configs->add_value('aiowps_unlock_request_secret_key',AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20));//Hidden secret value which will be used to do some unlock request processing. This will be assigned a random string generated when lockdown settings saved
197
- $aio_wp_security->configs->add_value('aiowps_lockdown_enable_whitelisting','');//Checkbox
198
- $aio_wp_security->configs->add_value('aiowps_lockdown_allowed_ip_addresses','');
199
-
200
- //Login Whitelist feature
201
- $aio_wp_security->configs->add_value('aiowps_enable_whitelisting','');//Checkbox
202
- $aio_wp_security->configs->add_value('aiowps_allowed_ip_addresses','');
203
- //Captcha feature
204
- $aio_wp_security->configs->add_value('aiowps_enable_login_captcha','');//Checkbox
205
- $aio_wp_security->configs->add_value('aiowps_enable_custom_login_captcha','');//Checkbox
206
- $aio_wp_security->configs->add_value('aiowps_enable_woo_login_captcha','');//Checkbox
207
- $aio_wp_security->configs->add_value('aiowps_enable_woo_register_captcha','');//Checkbox
208
- $aio_wp_security->configs->add_value('aiowps_enable_woo_lostpassword_captcha','');//Checkbox
209
- $aio_wp_security->configs->add_value('aiowps_captcha_secret_key',AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20));//Hidden secret value which will be used to do some captcha processing. This will be assigned a random string generated when captcha settings saved
210
-
211
- //User registration
212
- $aio_wp_security->configs->add_value('aiowps_enable_manual_registration_approval','');//Checkbox
213
- $aio_wp_security->configs->add_value('aiowps_enable_registration_page_captcha','');//Checkbox
214
- $aio_wp_security->configs->set_value('aiowps_enable_registration_honeypot','');//Checkbox
215
-
216
- //DB Security feature
217
- //$aio_wp_security->configs->add_value('aiowps_new_manual_db_pefix',''); //text field
218
- $aio_wp_security->configs->add_value('aiowps_enable_random_prefix','');//Checkbox
219
- $aio_wp_security->configs->add_value('aiowps_enable_automated_backups','');//Checkbox
220
- $aio_wp_security->configs->add_value('aiowps_db_backup_frequency','4');
221
- $aio_wp_security->configs->add_value('aiowps_db_backup_interval','2'); //Dropdown box where (0,1,2) => (hours,days,weeks)
222
- $aio_wp_security->configs->add_value('aiowps_backup_files_stored','2');
223
- $aio_wp_security->configs->add_value('aiowps_send_backup_email_address','');//Checkbox
224
- $aio_wp_security->configs->add_value('aiowps_backup_email_address',$blog_email_address);
225
-
226
- //Filesystem Security feature
227
- $aio_wp_security->configs->add_value('aiowps_disable_file_editing','');//Checkbox
228
- $aio_wp_security->configs->add_value('aiowps_prevent_default_wp_file_access','');//Checkbox
229
- $aio_wp_security->configs->add_value('aiowps_system_log_file','error_log');
230
-
231
-
232
- //Blacklist feature
233
- $aio_wp_security->configs->add_value('aiowps_enable_blacklisting','');//Checkbox
234
- $aio_wp_security->configs->add_value('aiowps_banned_ip_addresses','');
235
-
236
- //Firewall features
237
- $aio_wp_security->configs->add_value('aiowps_enable_basic_firewall','');//Checkbox
238
- $aio_wp_security->configs->add_value('aiowps_max_file_upload_size','10');
239
- $aio_wp_security->configs->add_value('aiowps_enable_pingback_firewall','');//Checkbox - blocks all access to XMLRPC
240
- $aio_wp_security->configs->add_value('aiowps_disable_xmlrpc_pingback_methods','');//Checkbox - Disables only pingback methods in XMLRPC functionality
241
- $aio_wp_security->configs->add_value('aiowps_block_debug_log_file_access','');//Checkbox
242
- $aio_wp_security->configs->add_value('aiowps_disable_index_views','');//Checkbox
243
- $aio_wp_security->configs->add_value('aiowps_disable_trace_and_track','');//Checkbox
244
- $aio_wp_security->configs->add_value('aiowps_forbid_proxy_comments','');//Checkbox
245
- $aio_wp_security->configs->add_value('aiowps_deny_bad_query_strings','');//Checkbox
246
- $aio_wp_security->configs->add_value('aiowps_advanced_char_string_filter','');//Checkbox
247
- $aio_wp_security->configs->add_value('aiowps_enable_5g_firewall','');//Checkbox
248
- $aio_wp_security->configs->add_value('aiowps_enable_6g_firewall','');//Checkbox
249
- $aio_wp_security->configs->add_value('aiowps_enable_custom_rules','');//Checkbox
250
- $aio_wp_security->configs->add_value('aiowps_place_custom_rules_at_top','');//Checkbox
251
- $aio_wp_security->configs->add_value('aiowps_custom_rules','');
252
-
253
- //404 detection
254
- $aio_wp_security->configs->add_value('aiowps_enable_404_logging','');//Checkbox
255
- $aio_wp_security->configs->add_value('aiowps_enable_404_IP_lockout','');//Checkbox
256
- $aio_wp_security->configs->add_value('aiowps_404_lockout_time_length','60');
257
- $aio_wp_security->configs->add_value('aiowps_404_lock_redirect_url','http://127.0.0.1');
258
-
259
- //Brute Force features
260
- $aio_wp_security->configs->add_value('aiowps_enable_rename_login_page','');//Checkbox
261
- $aio_wp_security->configs->add_value('aiowps_enable_login_honeypot','');//Checkbox
262
-
263
- $aio_wp_security->configs->add_value('aiowps_enable_brute_force_attack_prevention','');//Checkbox
264
- $aio_wp_security->configs->add_value('aiowps_brute_force_secret_word','');
265
- $aio_wp_security->configs->add_value('aiowps_cookie_brute_test','');
266
- $aio_wp_security->configs->add_value('aiowps_cookie_based_brute_force_redirect_url','http://127.0.0.1');
267
- $aio_wp_security->configs->add_value('aiowps_brute_force_attack_prevention_pw_protected_exception','');//Checkbox
268
- $aio_wp_security->configs->add_value('aiowps_brute_force_attack_prevention_ajax_exception','');//Checkbox
269
-
270
- //Maintenance menu - Visitor lockout feature
271
- $aio_wp_security->configs->add_value('aiowps_site_lockout','');//Checkbox
272
- $aio_wp_security->configs->add_value('aiowps_site_lockout_msg','');//Text area/msg box
273
-
274
- //SPAM Prevention menu
275
- $aio_wp_security->configs->add_value('aiowps_enable_spambot_blocking','');//Checkbox
276
- $aio_wp_security->configs->add_value('aiowps_enable_comment_captcha','');//Checkbox
277
- $aio_wp_security->configs->add_value('aiowps_enable_autoblock_spam_ip','');//Checkbox
278
- $aio_wp_security->configs->add_value('aiowps_spam_ip_min_comments_block','');
279
- $aio_wp_security->configs->add_value('aiowps_enable_bp_register_captcha','');
280
- $aio_wp_security->configs->add_value('aiowps_enable_bbp_new_topic_captcha','');//Checkbox
281
-
282
-
283
- //Filescan features
284
- //File change detection feature
285
- $aio_wp_security->configs->add_value('aiowps_enable_automated_fcd_scan','');//Checkbox
286
- $aio_wp_security->configs->add_value('aiowps_fcd_scan_frequency','4');
287
- $aio_wp_security->configs->add_value('aiowps_fcd_scan_interval','2'); //Dropdown box where (0,1,2) => (hours,days,weeks)
288
- $aio_wp_security->configs->add_value('aiowps_fcd_exclude_filetypes','');
289
- $aio_wp_security->configs->add_value('aiowps_fcd_exclude_files','');
290
- $aio_wp_security->configs->add_value('aiowps_send_fcd_scan_email','');//Checkbox
291
- $aio_wp_security->configs->add_value('aiowps_fcd_scan_email_address',$blog_email_address);
292
- $aio_wp_security->configs->add_value('aiowps_fcds_change_detected',FALSE); //used to display a global alert on site when file change detected
293
-
294
- //Misc Options
295
- //Copy protection feature
296
- $aio_wp_security->configs->add_value('aiowps_copy_protection','');//Checkbox
297
- //Prevent others from dislaying your site in iframe
298
- $aio_wp_security->configs->add_value('aiowps_prevent_site_display_inside_frame','');//Checkbox
299
- //Prevent users enumeration
300
- $aio_wp_security->configs->add_value('aiowps_prevent_users_enumeration','');//Checkbox
301
-
302
- //REST API Security
303
- $aio_wp_security->configs->add_value('aiowps_disallow_unauthorized_rest_requests','');//Checkbox
304
-
305
- //IP retrieval setting
306
- $aio_wp_security->configs->add_value('aiowps_ip_retrieve_method','0');//default is $_SERVER['REMOTE_ADDR']
307
-
308
- // Google reCaptcha
309
- $aio_wp_security->configs->add_value('aiowps_recaptcha_site_key','');
310
- $aio_wp_security->configs->add_value('aiowps_recaptcha_secret_key','');
311
- $aio_wp_security->configs->add_value('aiowps_default_recaptcha','');//Checkbox
312
-
313
- //TODO - keep adding default options for any fields that require it
314
-
315
- //Save it
316
- $aio_wp_security->configs->save_config();
317
- }
318
-
319
- static function turn_off_all_security_features()
320
- {
321
- global $aio_wp_security;
322
- AIOWPSecurity_Configure_Settings::set_default_settings();
323
-
324
- //Refresh the .htaccess file based on the new settings
325
- $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
326
- if( !$res )
327
- {
328
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Could not write to the .htaccess file. Please check the file permissions.",4);
329
- }
330
- }
331
-
332
- static function turn_off_all_firewall_rules()
333
- {
334
- global $aio_wp_security;
335
- $aio_wp_security->configs->set_value('aiowps_enable_blacklisting','');//Checkbox
336
- $aio_wp_security->configs->set_value('aiowps_enable_whitelisting','');//Checkbox
337
-
338
- $aio_wp_security->configs->set_value('aiowps_enable_basic_firewall','');//Checkbox
339
- $aio_wp_security->configs->set_value('aiowps_enable_pingback_firewall','');//Checkbox - blocks all access to XMLRPC
340
- $aio_wp_security->configs->set_value('aiowps_disable_xmlrpc_pingback_methods','');//Checkbox - Disables only pingback methods in XMLRPC functionality
341
- $aio_wp_security->configs->set_value('aiowps_block_debug_log_file_access','');//Checkbox
342
- $aio_wp_security->configs->set_value('aiowps_disable_index_views','');//Checkbox
343
- $aio_wp_security->configs->set_value('aiowps_disable_trace_and_track','');//Checkbox
344
- $aio_wp_security->configs->set_value('aiowps_forbid_proxy_comments','');//Checkbox
345
- $aio_wp_security->configs->set_value('aiowps_deny_bad_query_strings','');//Checkbox
346
- $aio_wp_security->configs->set_value('aiowps_advanced_char_string_filter','');//Checkbox
347
- $aio_wp_security->configs->set_value('aiowps_enable_5g_firewall','');//Checkbox
348
- $aio_wp_security->configs->set_value('aiowps_enable_6g_firewall','');//Checkbox
349
- $aio_wp_security->configs->set_value('aiowps_enable_brute_force_attack_prevention','');//Checkbox
350
- $aio_wp_security->configs->set_value('aiowps_enable_custom_rules','');//Checkbox
351
- $aio_wp_security->configs->set_value('aiowps_place_custom_rules_at_top','');//Checkbox
352
- $aio_wp_security->configs->set_value('aiowps_custom_rules','');
353
-
354
- $aio_wp_security->configs->set_value('aiowps_prevent_default_wp_file_access','');//Checkbox
355
-
356
- $aio_wp_security->configs->set_value('aiowps_enable_spambot_blocking','');//Checkbox
357
-
358
- //404 detection
359
- $aio_wp_security->configs->set_value('aiowps_enable_404_logging','');//Checkbox
360
- $aio_wp_security->configs->set_value('aiowps_enable_404_IP_lockout','');//Checkbox
361
-
362
- //Prevent Image Hotlinks
363
- $aio_wp_security->configs->set_value('aiowps_prevent_hotlinking','');//Checkbox
364
-
365
- $aio_wp_security->configs->save_config();
366
-
367
- //Refresh the .htaccess file based on the new settings
368
- $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
369
-
370
- if( !$res )
371
- {
372
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Could not write to the .htaccess file. Please check the file permissions.",4);
373
- }
374
- }
375
 
376
  }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Configure_Settings {
7
+
8
+ /**
9
+ * Set default settings.
10
+ *
11
+ * @return boolean True if the settings options was updated, false otherwise.
12
+ */
13
+ public static function set_default_settings() {
14
+ global $aio_wp_security;
15
+ $blog_email_address = get_bloginfo('admin_email'); //Get the blog admin email address - we will use as the default value
16
+
17
+ //Debug
18
+ $aio_wp_security->configs->set_value('aiowps_enable_debug', '');//Checkbox
19
+
20
+ //WP Generator Meta Tag feature
21
+ $aio_wp_security->configs->set_value('aiowps_remove_wp_generator_meta_info', '');//Checkbox
22
+
23
+ //Prevent Image Hotlinks
24
+ $aio_wp_security->configs->set_value('aiowps_prevent_hotlinking', '');//Checkbox
25
+ //General Settings Page
26
+
27
+ //User password feature
28
+
29
+ //Lockdown feature
30
+ $aio_wp_security->configs->set_value('aiowps_enable_login_lockdown', '');//Checkbox
31
+ $aio_wp_security->configs->set_value('aiowps_allow_unlock_requests', '1'); // Checkbox
32
+ $aio_wp_security->configs->set_value('aiowps_max_login_attempts', '3');
33
+ $aio_wp_security->configs->set_value('aiowps_retry_time_period', '5');
34
+ $aio_wp_security->configs->set_value('aiowps_lockout_time_length', '60');
35
+ $aio_wp_security->configs->set_value('aiowps_set_generic_login_msg', '');//Checkbox
36
+ $aio_wp_security->configs->set_value('aiowps_enable_email_notify', '');//Checkbox
37
+ $aio_wp_security->configs->set_value('aiowps_email_address', $blog_email_address);//text field
38
+ $aio_wp_security->configs->set_value('aiowps_enable_forced_logout', '');//Checkbox
39
+ $aio_wp_security->configs->set_value('aiowps_logout_time_period', '60');
40
+ $aio_wp_security->configs->set_value('aiowps_enable_invalid_username_lockdown', '');//Checkbox
41
+ $aio_wp_security->configs->set_value('aiowps_instantly_lockout_specific_usernames', array()); // Textarea (list of strings)
42
+ $aio_wp_security->configs->set_value('aiowps_unlock_request_secret_key', AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20));//Hidden secret value which will be used to do some unlock request processing. This will be assigned a random string generated when lockdown settings saved
43
+ $aio_wp_security->configs->set_value('aiowps_lockdown_enable_whitelisting', '');//Checkbox
44
+ $aio_wp_security->configs->set_value('aiowps_lockdown_allowed_ip_addresses', '');
45
+
46
+ //Captcha feature
47
+ $aio_wp_security->configs->set_value('aiowps_enable_login_captcha', '');//Checkbox
48
+ $aio_wp_security->configs->set_value('aiowps_enable_custom_login_captcha', '');//Checkbox
49
+ $aio_wp_security->configs->set_value('aiowps_enable_woo_login_captcha', '');//Checkbox
50
+ $aio_wp_security->configs->set_value('aiowps_enable_woo_lostpassword_captcha', '');//Checkbox
51
+ $aio_wp_security->configs->set_value('aiowps_enable_woo_register_captcha', '');//Checkbox
52
+ $aio_wp_security->configs->set_value('aiowps_enable_lost_password_captcha', '');//Checkbox
53
+ $aio_wp_security->configs->set_value('aiowps_captcha_secret_key', AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20));//Hidden secret value which will be used to do some captcha processing. This will be assigned a random string generated when captcha settings saved
54
+
55
+ //Login Whitelist feature
56
+ $aio_wp_security->configs->set_value('aiowps_enable_whitelisting', '');//Checkbox
57
+ $aio_wp_security->configs->set_value('aiowps_allowed_ip_addresses', '');
58
+
59
+ //User registration
60
+ $aio_wp_security->configs->set_value('aiowps_enable_manual_registration_approval', '');//Checkbox
61
+ $aio_wp_security->configs->set_value('aiowps_enable_registration_page_captcha', '');//Checkbox
62
+ $aio_wp_security->configs->set_value('aiowps_enable_registration_honeypot', '');//Checkbox
63
+
64
+ //DB Security feature
65
+ //$aio_wp_security->configs->set_value('aiowps_new_manual_db_pefix', ''); //text field
66
+ $aio_wp_security->configs->set_value('aiowps_enable_random_prefix', '');//Checkbox
67
+ $aio_wp_security->configs->set_value('aiowps_enable_automated_backups', '');//Checkbox
68
+ $aio_wp_security->configs->set_value('aiowps_db_backup_frequency', '4');
69
+ $aio_wp_security->configs->set_value('aiowps_db_backup_interval', '2'); //Dropdown box where (0,1,2) => (hours,days,weeks)
70
+ $aio_wp_security->configs->set_value('aiowps_backup_files_stored', '2');
71
+ $aio_wp_security->configs->set_value('aiowps_send_backup_email_address', '');//Checkbox
72
+ $aio_wp_security->configs->set_value('aiowps_backup_email_address', $blog_email_address);
73
+
74
+ //Filesystem Security feature
75
+ AIOWPSecurity_Utility::enable_file_edits();
76
+ $aio_wp_security->configs->set_value('aiowps_disable_file_editing', '');//Checkbox
77
+ $aio_wp_security->configs->set_value('aiowps_prevent_default_wp_file_access', '');//Checkbox
78
+ $aio_wp_security->configs->set_value('aiowps_system_log_file', 'error_log');
79
+
80
+ //Blacklist feature
81
+ $aio_wp_security->configs->set_value('aiowps_enable_blacklisting', '');//Checkbox
82
+ $aio_wp_security->configs->set_value('aiowps_banned_ip_addresses', '');
83
+ $aio_wp_security->configs->set_value('aiowps_banned_user_agents', '');
84
+
85
+ //Firewall features
86
+ $aio_wp_security->configs->set_value('aiowps_enable_basic_firewall', '');//Checkbox
87
+ $aio_wp_security->configs->set_value('aiowps_max_file_upload_size', '10'); //Default 10MB
88
+ $aio_wp_security->configs->set_value('aiowps_enable_pingback_firewall', '');//Checkbox - blocks all access to XMLRPC
89
+ $aio_wp_security->configs->set_value('aiowps_disable_xmlrpc_pingback_methods', '');//Checkbox - Disables only pingback methods in XMLRPC functionality
90
+ $aio_wp_security->configs->set_value('aiowps_block_debug_log_file_access', '');//Checkbox
91
+ $aio_wp_security->configs->set_value('aiowps_disable_index_views', '');//Checkbox
92
+ $aio_wp_security->configs->set_value('aiowps_disable_trace_and_track', '');//Checkbox
93
+ $aio_wp_security->configs->set_value('aiowps_forbid_proxy_comments', '');//Checkbox
94
+ $aio_wp_security->configs->set_value('aiowps_deny_bad_query_strings', '');//Checkbox
95
+ $aio_wp_security->configs->set_value('aiowps_advanced_char_string_filter', '');//Checkbox
96
+ $aio_wp_security->configs->set_value('aiowps_enable_5g_firewall', '');//Checkbox
97
+ $aio_wp_security->configs->set_value('aiowps_enable_6g_firewall', '');//Checkbox
98
+ $aio_wp_security->configs->set_value('aiowps_block_fake_googlebots', ''); // Checkbox
99
+ $aio_wp_security->configs->set_value('aiowps_enable_custom_rules', '');//Checkbox
100
+ $aio_wp_security->configs->set_value('aiowps_place_custom_rules_at_top', '');//Checkbox
101
+ $aio_wp_security->configs->set_value('aiowps_custom_rules', '');
102
+
103
+ //404 detection
104
+ $aio_wp_security->configs->set_value('aiowps_enable_404_logging', '');//Checkbox
105
+ $aio_wp_security->configs->set_value('aiowps_enable_404_IP_lockout', '');//Checkbox
106
+ $aio_wp_security->configs->set_value('aiowps_404_lockout_time_length', '60');
107
+ $aio_wp_security->configs->set_value('aiowps_404_lock_redirect_url', 'http://127.0.0.1');
108
+
109
+ //Brute Force features
110
+ $aio_wp_security->configs->set_value('aiowps_enable_rename_login_page', '');//Checkbox
111
+ $aio_wp_security->configs->set_value('aiowps_enable_login_honeypot', '');//Checkbox
112
+
113
+ $aio_wp_security->configs->set_value('aiowps_enable_brute_force_attack_prevention', '');//Checkbox
114
+ $aio_wp_security->configs->set_value('aiowps_brute_force_secret_word', '');
115
+ $aio_wp_security->configs->set_value('aiowps_cookie_brute_test', '');
116
+ $aio_wp_security->configs->set_value('aiowps_cookie_based_brute_force_redirect_url', 'http://127.0.0.1');
117
+ $aio_wp_security->configs->set_value('aiowps_brute_force_attack_prevention_pw_protected_exception', '');//Checkbox
118
+ $aio_wp_security->configs->set_value('aiowps_brute_force_attack_prevention_ajax_exception', '');//Checkbox
119
+
120
+ //Maintenance menu - Visitor lockout feature
121
+ $aio_wp_security->configs->set_value('aiowps_site_lockout', '');//Checkbox
122
+ $aio_wp_security->configs->set_value('aiowps_site_lockout_msg', '');//Text area/msg box
123
+
124
+ //SPAM Prevention menu
125
+ $aio_wp_security->configs->set_value('aiowps_enable_spambot_blocking', '');//Checkbox
126
+ $aio_wp_security->configs->set_value('aiowps_enable_comment_captcha', '');//Checkbox
127
+ $aio_wp_security->configs->set_value('aiowps_enable_autoblock_spam_ip', '');//Checkbox
128
+ $aio_wp_security->configs->set_value('aiowps_spam_ip_min_comments_block', '');
129
+ $aio_wp_security->configs->set_value('aiowps_enable_bp_register_captcha', '');
130
+ $aio_wp_security->configs->set_value('aiowps_enable_bbp_new_topic_captcha', '');//Checkbox
131
+
132
+ //Filescan features
133
+ //File change detection feature
134
+ $aio_wp_security->configs->set_value('aiowps_enable_automated_fcd_scan', '');//Checkbox
135
+ $aio_wp_security->configs->set_value('aiowps_fcd_scan_frequency', '4');
136
+ $aio_wp_security->configs->set_value('aiowps_fcd_scan_interval', '2'); //Dropdown box where (0,1,2) => (hours,days,weeks)
137
+ $aio_wp_security->configs->set_value('aiowps_fcd_exclude_filetypes', '');
138
+ $aio_wp_security->configs->set_value('aiowps_fcd_exclude_files', '');
139
+ $aio_wp_security->configs->set_value('aiowps_send_fcd_scan_email', '');//Checkbox
140
+ $aio_wp_security->configs->set_value('aiowps_fcd_scan_email_address', $blog_email_address);
141
+ $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', false); //used to display a global alert on site when file change detected
142
+
143
+ //Misc Options
144
+ //Copy protection feature
145
+ $aio_wp_security->configs->set_value('aiowps_copy_protection', '');//Checkbox
146
+ //Prevent others from dislaying your site in iframe
147
+ $aio_wp_security->configs->set_value('aiowps_prevent_site_display_inside_frame', '');//Checkbox
148
+ //Prevent users enumeration
149
+ $aio_wp_security->configs->set_value('aiowps_prevent_users_enumeration', '');//Checkbox
150
+
151
+ //REST API Security
152
+ $aio_wp_security->configs->set_value('aiowps_disallow_unauthorized_rest_requests', '');//Checkbox
153
+
154
+ // Google reCaptcha
155
+ $aio_wp_security->configs->set_value('aiowps_recaptcha_site_key', '');
156
+ $aio_wp_security->configs->set_value('aiowps_recaptcha_secret_key', '');
157
+ $aio_wp_security->configs->set_value('aiowps_default_recaptcha', '');//Checkbox
158
+
159
+ //TODO - keep adding default options for any fields that require it
160
+
161
+ //Save it
162
+ return $aio_wp_security->configs->save_config();
163
+ }
164
+
165
+ public static function add_option_values() {
166
+ global $aio_wp_security;
167
+ $blog_email_address = get_bloginfo('admin_email'); //Get the blog admin email address - we will use as the default value
168
+
169
+ //Debug
170
+ $aio_wp_security->configs->add_value('aiowps_enable_debug', '');//Checkbox
171
+
172
+ //WP Generator Meta Tag feature
173
+ $aio_wp_security->configs->add_value('aiowps_remove_wp_generator_meta_info', '');//Checkbox
174
+
175
+ //Prevent Image Hotlinks
176
+ $aio_wp_security->configs->add_value('aiowps_prevent_hotlinking', '');//Checkbox
177
+
178
+ //General Settings Page
179
+
180
+ //User password feature
181
+
182
+ //Lockdown feature
183
+ $aio_wp_security->configs->add_value('aiowps_enable_login_lockdown', '');//Checkbox
184
+ $aio_wp_security->configs->add_value('aiowps_allow_unlock_requests', '1'); // Checkbox
185
+ $aio_wp_security->configs->add_value('aiowps_max_login_attempts', '3');
186
+ $aio_wp_security->configs->add_value('aiowps_retry_time_period', '5');
187
+ $aio_wp_security->configs->add_value('aiowps_lockout_time_length', '60');
188
+ $aio_wp_security->configs->add_value('aiowps_set_generic_login_msg', '');//Checkbox
189
+ $aio_wp_security->configs->add_value('aiowps_enable_email_notify', '');//Checkbox
190
+ $aio_wp_security->configs->add_value('aiowps_email_address', $blog_email_address);//text field
191
+ $aio_wp_security->configs->add_value('aiowps_enable_forced_logout', '');//Checkbox
192
+ $aio_wp_security->configs->add_value('aiowps_logout_time_period', '60');
193
+ $aio_wp_security->configs->add_value('aiowps_enable_invalid_username_lockdown', '');//Checkbox
194
+ $aio_wp_security->configs->add_value('aiowps_instantly_lockout_specific_usernames', array()); // Textarea (list of strings)
195
+ $aio_wp_security->configs->add_value('aiowps_unlock_request_secret_key', AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20));//Hidden secret value which will be used to do some unlock request processing. This will be assigned a random string generated when lockdown settings saved
196
+ $aio_wp_security->configs->add_value('aiowps_lockdown_enable_whitelisting', '');//Checkbox
197
+ $aio_wp_security->configs->add_value('aiowps_lockdown_allowed_ip_addresses', '');
198
+
199
+ //Login Whitelist feature
200
+ $aio_wp_security->configs->add_value('aiowps_enable_whitelisting', '');//Checkbox
201
+ $aio_wp_security->configs->add_value('aiowps_allowed_ip_addresses', '');
202
+ //Captcha feature
203
+ $aio_wp_security->configs->add_value('aiowps_enable_login_captcha', '');//Checkbox
204
+ $aio_wp_security->configs->add_value('aiowps_enable_custom_login_captcha', '');//Checkbox
205
+ $aio_wp_security->configs->add_value('aiowps_enable_woo_login_captcha', '');//Checkbox
206
+ $aio_wp_security->configs->add_value('aiowps_enable_woo_register_captcha', '');//Checkbox
207
+ $aio_wp_security->configs->add_value('aiowps_enable_woo_lostpassword_captcha', '');//Checkbox
208
+ $aio_wp_security->configs->add_value('aiowps_captcha_secret_key', AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20));//Hidden secret value which will be used to do some captcha processing. This will be assigned a random string generated when captcha settings saved
209
+
210
+ //User registration
211
+ $aio_wp_security->configs->add_value('aiowps_enable_manual_registration_approval', '');//Checkbox
212
+ $aio_wp_security->configs->add_value('aiowps_enable_registration_page_captcha', '');//Checkbox
213
+ $aio_wp_security->configs->set_value('aiowps_enable_registration_honeypot', '');//Checkbox
214
+
215
+ //DB Security feature
216
+ //$aio_wp_security->configs->add_value('aiowps_new_manual_db_pefix', ''); //text field
217
+ $aio_wp_security->configs->add_value('aiowps_enable_random_prefix', '');//Checkbox
218
+ $aio_wp_security->configs->add_value('aiowps_enable_automated_backups', '');//Checkbox
219
+ $aio_wp_security->configs->add_value('aiowps_db_backup_frequency', '4');
220
+ $aio_wp_security->configs->add_value('aiowps_db_backup_interval', '2'); //Dropdown box where (0,1,2) => (hours,days,weeks)
221
+ $aio_wp_security->configs->add_value('aiowps_backup_files_stored', '2');
222
+ $aio_wp_security->configs->add_value('aiowps_send_backup_email_address', '');//Checkbox
223
+ $aio_wp_security->configs->add_value('aiowps_backup_email_address', $blog_email_address);
224
+
225
+ //Filesystem Security feature
226
+ $aio_wp_security->configs->add_value('aiowps_disable_file_editing', '');//Checkbox
227
+ $aio_wp_security->configs->add_value('aiowps_prevent_default_wp_file_access', '');//Checkbox
228
+ $aio_wp_security->configs->add_value('aiowps_system_log_file', 'error_log');
229
+
230
+
231
+ //Blacklist feature
232
+ $aio_wp_security->configs->add_value('aiowps_enable_blacklisting', '');//Checkbox
233
+ $aio_wp_security->configs->add_value('aiowps_banned_ip_addresses', '');
234
+
235
+ //Firewall features
236
+ $aio_wp_security->configs->add_value('aiowps_enable_basic_firewall', '');//Checkbox
237
+ $aio_wp_security->configs->add_value('aiowps_max_file_upload_size', '10');
238
+ $aio_wp_security->configs->add_value('aiowps_enable_pingback_firewall', '');//Checkbox - blocks all access to XMLRPC
239
+ $aio_wp_security->configs->add_value('aiowps_disable_xmlrpc_pingback_methods', '');//Checkbox - Disables only pingback methods in XMLRPC functionality
240
+ $aio_wp_security->configs->add_value('aiowps_block_debug_log_file_access', '');//Checkbox
241
+ $aio_wp_security->configs->add_value('aiowps_disable_index_views', '');//Checkbox
242
+ $aio_wp_security->configs->add_value('aiowps_disable_trace_and_track', '');//Checkbox
243
+ $aio_wp_security->configs->add_value('aiowps_forbid_proxy_comments', '');//Checkbox
244
+ $aio_wp_security->configs->add_value('aiowps_deny_bad_query_strings', '');//Checkbox
245
+ $aio_wp_security->configs->add_value('aiowps_advanced_char_string_filter', '');//Checkbox
246
+ $aio_wp_security->configs->add_value('aiowps_enable_5g_firewall', '');//Checkbox
247
+ $aio_wp_security->configs->add_value('aiowps_enable_6g_firewall', '');//Checkbox
248
+ $aio_wp_security->configs->add_value('aiowps_enable_custom_rules', '');//Checkbox
249
+ $aio_wp_security->configs->add_value('aiowps_place_custom_rules_at_top', '');//Checkbox
250
+ $aio_wp_security->configs->add_value('aiowps_custom_rules', '');
251
+
252
+ //404 detection
253
+ $aio_wp_security->configs->add_value('aiowps_enable_404_logging', '');//Checkbox
254
+ $aio_wp_security->configs->add_value('aiowps_enable_404_IP_lockout', '');//Checkbox
255
+ $aio_wp_security->configs->add_value('aiowps_404_lockout_time_length', '60');
256
+ $aio_wp_security->configs->add_value('aiowps_404_lock_redirect_url', 'http://127.0.0.1');
257
+
258
+ //Brute Force features
259
+ $aio_wp_security->configs->add_value('aiowps_enable_rename_login_page', '');//Checkbox
260
+ $aio_wp_security->configs->add_value('aiowps_enable_login_honeypot', '');//Checkbox
261
+
262
+ $aio_wp_security->configs->add_value('aiowps_enable_brute_force_attack_prevention', '');//Checkbox
263
+ $aio_wp_security->configs->add_value('aiowps_brute_force_secret_word', '');
264
+ $aio_wp_security->configs->add_value('aiowps_cookie_brute_test', '');
265
+ $aio_wp_security->configs->add_value('aiowps_cookie_based_brute_force_redirect_url', 'http://127.0.0.1');
266
+ $aio_wp_security->configs->add_value('aiowps_brute_force_attack_prevention_pw_protected_exception', '');//Checkbox
267
+ $aio_wp_security->configs->add_value('aiowps_brute_force_attack_prevention_ajax_exception', '');//Checkbox
268
+
269
+ //Maintenance menu - Visitor lockout feature
270
+ $aio_wp_security->configs->add_value('aiowps_site_lockout', '');//Checkbox
271
+ $aio_wp_security->configs->add_value('aiowps_site_lockout_msg', '');//Text area/msg box
272
+
273
+ //SPAM Prevention menu
274
+ $aio_wp_security->configs->add_value('aiowps_enable_spambot_blocking', '');//Checkbox
275
+ $aio_wp_security->configs->add_value('aiowps_enable_comment_captcha', '');//Checkbox
276
+ $aio_wp_security->configs->add_value('aiowps_enable_autoblock_spam_ip', '');//Checkbox
277
+ $aio_wp_security->configs->add_value('aiowps_spam_ip_min_comments_block', '');
278
+ $aio_wp_security->configs->add_value('aiowps_enable_bp_register_captcha', '');
279
+ $aio_wp_security->configs->add_value('aiowps_enable_bbp_new_topic_captcha', '');//Checkbox
280
+
281
+
282
+ //Filescan features
283
+ //File change detection feature
284
+ $aio_wp_security->configs->add_value('aiowps_enable_automated_fcd_scan', '');//Checkbox
285
+ $aio_wp_security->configs->add_value('aiowps_fcd_scan_frequency', '4');
286
+ $aio_wp_security->configs->add_value('aiowps_fcd_scan_interval', '2'); //Dropdown box where (0,1,2) => (hours,days,weeks)
287
+ $aio_wp_security->configs->add_value('aiowps_fcd_exclude_filetypes', '');
288
+ $aio_wp_security->configs->add_value('aiowps_fcd_exclude_files', '');
289
+ $aio_wp_security->configs->add_value('aiowps_send_fcd_scan_email', '');//Checkbox
290
+ $aio_wp_security->configs->add_value('aiowps_fcd_scan_email_address', $blog_email_address);
291
+ $aio_wp_security->configs->add_value('aiowps_fcds_change_detected', false); //used to display a global alert on site when file change detected
292
+
293
+ //Misc Options
294
+ //Copy protection feature
295
+ $aio_wp_security->configs->add_value('aiowps_copy_protection', '');//Checkbox
296
+ //Prevent others from dislaying your site in iframe
297
+ $aio_wp_security->configs->add_value('aiowps_prevent_site_display_inside_frame', '');//Checkbox
298
+ //Prevent users enumeration
299
+ $aio_wp_security->configs->add_value('aiowps_prevent_users_enumeration', '');//Checkbox
300
+
301
+ //REST API Security
302
+ $aio_wp_security->configs->add_value('aiowps_disallow_unauthorized_rest_requests', '');//Checkbox
303
+
304
+ // Google reCaptcha
305
+ $aio_wp_security->configs->add_value('aiowps_recaptcha_site_key', '');
306
+ $aio_wp_security->configs->add_value('aiowps_recaptcha_secret_key', '');
307
+ $aio_wp_security->configs->add_value('aiowps_default_recaptcha', '');//Checkbox
308
+
309
+ //TODO - keep adding default options for any fields that require it
310
+
311
+ //Save it
312
+ $aio_wp_security->configs->save_config();
313
+ }
314
+
315
+ public static function turn_off_all_security_features() {
316
+ global $aio_wp_security;
317
+ AIOWPSecurity_Configure_Settings::set_default_settings();
318
+
319
+ //Refresh the .htaccess file based on the new settings
320
+ $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
321
+ if (!$res) {
322
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Could not write to the .htaccess file. Please check the file permissions.", 4);
323
+ }
324
+ }
325
+
326
+ public static function turn_off_all_firewall_rules() {
327
+ global $aio_wp_security;
328
+ $aio_wp_security->configs->set_value('aiowps_enable_blacklisting', '');//Checkbox
329
+ $aio_wp_security->configs->set_value('aiowps_enable_whitelisting', '');//Checkbox
330
+
331
+ $aio_wp_security->configs->set_value('aiowps_enable_basic_firewall', '');//Checkbox
332
+ $aio_wp_security->configs->set_value('aiowps_enable_pingback_firewall', '');//Checkbox - blocks all access to XMLRPC
333
+ $aio_wp_security->configs->set_value('aiowps_disable_xmlrpc_pingback_methods', '');//Checkbox - Disables only pingback methods in XMLRPC functionality
334
+ $aio_wp_security->configs->set_value('aiowps_block_debug_log_file_access', '');//Checkbox
335
+ $aio_wp_security->configs->set_value('aiowps_disable_index_views', '');//Checkbox
336
+ $aio_wp_security->configs->set_value('aiowps_disable_trace_and_track', '');//Checkbox
337
+ $aio_wp_security->configs->set_value('aiowps_forbid_proxy_comments', '');//Checkbox
338
+ $aio_wp_security->configs->set_value('aiowps_deny_bad_query_strings', '');//Checkbox
339
+ $aio_wp_security->configs->set_value('aiowps_advanced_char_string_filter', '');//Checkbox
340
+ $aio_wp_security->configs->set_value('aiowps_enable_5g_firewall', '');//Checkbox
341
+ $aio_wp_security->configs->set_value('aiowps_enable_6g_firewall', '');//Checkbox
342
+ $aio_wp_security->configs->set_value('aiowps_enable_brute_force_attack_prevention', '');//Checkbox
343
+ $aio_wp_security->configs->set_value('aiowps_enable_custom_rules', '');//Checkbox
344
+ $aio_wp_security->configs->set_value('aiowps_place_custom_rules_at_top', '');//Checkbox
345
+ $aio_wp_security->configs->set_value('aiowps_custom_rules', '');
346
+
347
+ $aio_wp_security->configs->set_value('aiowps_prevent_default_wp_file_access', '');//Checkbox
348
+
349
+ $aio_wp_security->configs->set_value('aiowps_enable_spambot_blocking', '');//Checkbox
350
+
351
+ //404 detection
352
+ $aio_wp_security->configs->set_value('aiowps_enable_404_logging', '');//Checkbox
353
+ $aio_wp_security->configs->set_value('aiowps_enable_404_IP_lockout', '');//Checkbox
354
+
355
+ //Prevent Image Hotlinks
356
+ $aio_wp_security->configs->set_value('aiowps_prevent_hotlinking', '');//Checkbox
357
+
358
+ $aio_wp_security->configs->save_config();
359
+
360
+ //Refresh the .htaccess file based on the new settings
361
+ $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
362
+
363
+ if (!$res) {
364
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Could not write to the .htaccess file. Please check the file permissions.", 4);
365
+ }
366
+ }
 
 
 
 
 
 
 
 
367
 
368
  }
classes/wp-security-cronjob-handler.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
  exit;//Exit if accessed directly
4
  }
5
 
@@ -18,8 +18,7 @@ class AIOWPSecurity_Cronjob_Handler {
18
  add_action('aiowps_purge_old_debug_logs', array($this, 'purge_old_debug_logs'));
19
  }
20
 
21
- function aiowps_hourly_cron_event_handler()
22
- {
23
  //Do stuff that needs checking hourly
24
  do_action('aiowps_perform_scheduled_backup_tasks');
25
  do_action('aiowps_perform_fcd_scan_tasks');
@@ -45,7 +44,7 @@ class AIOWPSecurity_Cronjob_Handler {
45
  global $wpdb, $aio_wp_security;
46
 
47
  $purge_records_after_days = apply_filters('aiowps_purge_failed_login_records_after_days', AIOWPSEC_PURGE_FAILED_LOGIN_RECORDS_AFTER_DAYS);
48
- $older_than_date_time = date('Y-m-d H:m:s', strtotime('-' . $purge_records_after_days . ' days', strtotime(current_time('mysql', false))));
49
  $sql = $wpdb->prepare('DELETE FROM ' . AIOWPSEC_TBL_FAILED_LOGINS . ' WHERE failed_login_date<%s', $older_than_date_time);
50
  $ret_deleted = $wpdb->query($sql);
51
  if (false === $ret_deleted) {
@@ -59,7 +58,6 @@ class AIOWPSecurity_Cronjob_Handler {
59
 
60
  /**
61
  * Purges debug logs older than 90 days
62
- *
63
  * The 90 days can be modified using the constant AIOWPSEC_PURGE_DEBUG_LOGS_AFTER_DAYS
64
  *
65
  * @return void
@@ -85,6 +83,4 @@ class AIOWPSecurity_Cronjob_Handler {
85
  $aio_wp_security->debug_logger->log_debug_cron("Failed to purge older debug logs : {$error_msg}", 4);
86
  }
87
  }
88
-
89
  }
90
-
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
  exit;//Exit if accessed directly
4
  }
5
 
18
  add_action('aiowps_purge_old_debug_logs', array($this, 'purge_old_debug_logs'));
19
  }
20
 
21
+ public function aiowps_hourly_cron_event_handler() {
 
22
  //Do stuff that needs checking hourly
23
  do_action('aiowps_perform_scheduled_backup_tasks');
24
  do_action('aiowps_perform_fcd_scan_tasks');
44
  global $wpdb, $aio_wp_security;
45
 
46
  $purge_records_after_days = apply_filters('aiowps_purge_failed_login_records_after_days', AIOWPSEC_PURGE_FAILED_LOGIN_RECORDS_AFTER_DAYS);
47
+ $older_than_date_time = date('Y-m-d H:m:s', strtotime('-' . $purge_records_after_days . ' days', strtotime(current_time('mysql', true))));
48
  $sql = $wpdb->prepare('DELETE FROM ' . AIOWPSEC_TBL_FAILED_LOGINS . ' WHERE failed_login_date<%s', $older_than_date_time);
49
  $ret_deleted = $wpdb->query($sql);
50
  if (false === $ret_deleted) {
58
 
59
  /**
60
  * Purges debug logs older than 90 days
 
61
  * The 90 days can be modified using the constant AIOWPSEC_PURGE_DEBUG_LOGS_AFTER_DAYS
62
  *
63
  * @return void
83
  $aio_wp_security->debug_logger->log_debug_cron("Failed to purge older debug logs : {$error_msg}", 4);
84
  }
85
  }
 
86
  }
 
classes/wp-security-deactivation-tasks.php CHANGED
@@ -1,57 +1,56 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- include_once(dirname(__FILE__) . '/wp-security-configure-settings.php');//Allows activating via wp-cli
 
7
 
8
- class AIOWPSecurity_Deactivation
9
- {
10
- /**
11
- * Runs various deactivation tasks
12
- * Handles single and multi-site (NW activation) cases
13
- * @global type $wpdb
14
- * @global type $aio_wp_security
15
- * @param type $networkwide
16
- */
17
- static function run_deactivation_tasks($networkwide)
18
- {
19
- global $wpdb;
20
- global $aio_wp_security;
21
-
22
- if (AIOWPSecurity_Utility::is_multisite_install()){
23
- delete_site_transient('users_online');
24
- }
25
- else{
26
- delete_transient('users_online');
27
- }
28
-
29
- if (AIOWPSecurity_Utility::is_multisite_install() && $networkwide) {
30
- // check if it is a network activation
31
- $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
32
- foreach ($blogids as $blog_id) {
33
- switch_to_blog($blog_id);
34
- //Let's first save the current aio_wp_security_configs options in a temp option
35
- update_option('aiowps_temp_configs', $aio_wp_security->configs->configs);
36
-
37
- AIOWPSecurity_Deactivation::clear_cron_events();
38
- restore_current_blog();
39
- }
40
- } else {
41
- //Let's first save the current aio_wp_security_configs options in a temp option
42
- update_option('aiowps_temp_configs', $aio_wp_security->configs->configs);
43
-
44
- AIOWPSecurity_Deactivation::clear_cron_events();
45
- }
46
- //Deactivate all firewall and other .htaccess rules
47
- AIOWPSecurity_Configure_Settings::turn_off_all_firewall_rules();
48
- }
49
-
50
- /**
51
- * Helper function which clears aiowps cron events
52
- */
53
- static function clear_cron_events() {
54
- wp_clear_scheduled_hook('aiowps_hourly_cron_event');
55
- wp_clear_scheduled_hook('aiowps_daily_cron_event');
56
- }
57
  }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ //Allows activating via wp-cli
7
+ require_once(dirname(__FILE__) . '/wp-security-configure-settings.php');
8
 
9
+ class AIOWPSecurity_Deactivation {
10
+ /**
11
+ * Runs various deactivation tasks
12
+ * Handles single and multi-site (NW activation) cases
13
+ *
14
+ * @global type $wpdb
15
+ * @global type $aio_wp_security
16
+ * @param type $networkwide
17
+ */
18
+ public static function run_deactivation_tasks($networkwide) {
19
+ global $wpdb;
20
+ global $aio_wp_security;
21
+
22
+ if (AIOWPSecurity_Utility::is_multisite_install()) {
23
+ delete_site_transient('users_online');
24
+ } else {
25
+ delete_transient('users_online');
26
+ }
27
+
28
+ if (AIOWPSecurity_Utility::is_multisite_install() && $networkwide) {
29
+ // check if it is a network activation
30
+ $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
31
+ foreach ($blogids as $blog_id) {
32
+ switch_to_blog($blog_id);
33
+ //Let's first save the current aio_wp_security_configs options in a temp option
34
+ update_option('aiowps_temp_configs', $aio_wp_security->configs->configs);
35
+
36
+ AIOWPSecurity_Deactivation::clear_cron_events();
37
+ restore_current_blog();
38
+ }
39
+ } else {
40
+ //Let's first save the current aio_wp_security_configs options in a temp option
41
+ update_option('aiowps_temp_configs', $aio_wp_security->configs->configs);
42
+
43
+ AIOWPSecurity_Deactivation::clear_cron_events();
44
+ }
45
+ //Deactivate all firewall and other .htaccess rules
46
+ AIOWPSecurity_Configure_Settings::turn_off_all_firewall_rules();
47
+ }
48
+
49
+ /**
50
+ * Helper function which clears aiowps cron events
51
+ */
52
+ public static function clear_cron_events() {
53
+ wp_clear_scheduled_hook('aiowps_hourly_cron_event');
54
+ wp_clear_scheduled_hook('aiowps_daily_cron_event');
55
+ }
 
 
56
  }
classes/wp-security-debug-logger.php CHANGED
@@ -1,124 +1,138 @@
1
  <?php
2
- /*
3
  * Logs debug data to a file. Here is an example usage
4
  * global $aio_wp_security;
5
  * $aio_wp_security->debug_logger->log_debug("Log messaged goes here");
6
  */
7
- if(!defined('ABSPATH')){
8
- exit;//Exit if accessed directly
9
  }
10
 
11
- class AIOWPSecurity_Logger
12
- {
13
- private $debug_enabled = false;
14
- private $debug_readable_level = array('SUCCESS','STATUS','NOTICE','WARNING','FAILURE','CRITICAL');
 
15
 
16
- public function __construct($debug_enabled)
17
- {
18
- $this->debug_enabled = $debug_enabled;
19
- $this->maybe_create_debug_log_table();
20
- }
21
-
22
- /**
23
- * Translates the level code to its readable form
24
- *
25
- * @param integer $level - The level code to translate (e.g: 2)
26
- * @return string - The level as its readable value (e.g: NOTICE)
27
- */
28
- private function get_readable_level_from_code($level_code)
29
- {
30
- return isset($this->debug_readable_level[$level_code]) ? $this->debug_readable_level[$level_code] : 'UNKNOWN';
31
- }
32
-
33
- /**
34
- * Creates the debug log table if it doesn't already exist
35
- *
36
- * @return void
37
- */
38
- private function maybe_create_debug_log_table() {
39
-
40
- global $wpdb;
41
-
42
- //needed for the maybe_create_table function
43
- require_once ABSPATH . 'wp-admin/includes/upgrade.php';
44
-
45
- //This exists as a constant, but multisite will need to refresh $wpdb->prefix
46
- $debug_log_tbl_name = $wpdb->prefix.'aiowps_debug_log';
47
-
48
- $debug_log_tbl_sql = "CREATE TABLE " . $debug_log_tbl_name . " (
49
- id bigint(20) NOT NULL AUTO_INCREMENT,
50
- level varchar(25) NOT NULL DEFAULT '',
51
- message text NOT NULL DEFAULT '',
52
- type varchar(25) NOT NULL DEFAULT '',
53
- created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
54
- PRIMARY KEY (id)
55
- )" . $charset_collate . ";";
56
-
57
- maybe_create_table($debug_log_tbl_name, $debug_log_tbl_sql);
58
-
59
- }
60
-
61
- /**
62
- * Clears the debug logs
63
- *
64
- * @return int|WP_Error the amount of records deleted or WP_Error if query failed
65
- */
66
- public function clear_logs() {
67
- global $wpdb;
68
-
69
- $debug_log_tbl = $wpdb->prefix . 'aiowps_debug_log';
70
-
71
- $query = "DELETE FROM $debug_log_tbl";
72
-
73
- $ret = $wpdb->query($query);
74
-
75
- if (false === $ret) {
76
- $error_msg = empty($wpdb->last_error) ? __('Unable to get the reason why', 'all-in-one-wp-security-and-firewall') : $wpdb->last_error;
77
- $ret = new WP_Error('db_unable_delete', __('Unable to clear the logs', 'all-in-one-wp-security-and-firewall'), $error_msg);
78
- }
79
-
80
- return $ret;
81
- }
82
-
83
- /**
84
- * Logs the debug messages to the database
85
- *
86
- * @param string $message - The main debug message
87
- * @param integer $level_code - The level code which indicates the severity of the message
88
- * @param string $type - The type of debug message. Seperates general debug messages from those generated by the cron, for example.
89
- * @return void
90
- */
91
- public function log_debug($message, $level_code = 0, $type = 'debug') {
92
-
93
- if (!$this->debug_enabled) { return; }
94
-
95
- global $wpdb;
96
- $debug_tbl_name = AIOWPSEC_TBL_DEBUG_LOG;
97
-
98
- $data = array(
99
- 'level' => $this->get_readable_level_from_code($level_code),
100
- 'message' => $message,
101
- 'type' => $type
102
- );
103
-
104
- $ret = $wpdb->insert($debug_tbl_name, $data);
105
- if(false === $ret) {
106
- $error_msg = empty($wpdb->last_error) ? 'Could not write to the debug log' : $wpdb->last_error;
107
- error_log("All In One WP Security : {$error_msg}");
108
- }
109
-
110
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
- /**
113
- * Logs the debug messages that relate to the cron
114
- *
115
- * @param string $message - The main debug message
116
- * @param integer $level_code - The level code which indicates the severity of the message
117
- * @return void
118
- */
119
- public function log_debug_cron($message, $level_code = 0) {
120
- $this->log_debug($message, $level_code, 'cron_debug');
121
- }
122
-
123
-
124
- }
1
  <?php
2
+ /**
3
  * Logs debug data to a file. Here is an example usage
4
  * global $aio_wp_security;
5
  * $aio_wp_security->debug_logger->log_debug("Log messaged goes here");
6
  */
7
+ if (!defined('ABSPATH')) {
8
+ exit;//Exit if accessed directly
9
  }
10
 
11
+ class AIOWPSecurity_Logger {
12
+
13
+ private $debug_enabled = false;
14
+
15
+ private $debug_readable_level = array('SUCCESS','STATUS','NOTICE','WARNING','FAILURE','CRITICAL');
16
 
17
+ public function __construct($debug_enabled) {
18
+ $this->debug_enabled = $debug_enabled;
19
+ $this->maybe_create_debug_log_table();
20
+ }
21
+
22
+ /**
23
+ * Translates the level code to its readable form
24
+ *
25
+ * @param integer $level_code - The level code to translate (e.g: 2)
26
+ * @return string - The level as its readable value (e.g: NOTICE)
27
+ */
28
+ private function get_readable_level_from_code($level_code) {
29
+ return isset($this->debug_readable_level[$level_code]) ? $this->debug_readable_level[$level_code] : 'UNKNOWN';
30
+ }
31
+
32
+ /**
33
+ * Creates the debug log table if it doesn't already exist
34
+ *
35
+ * @return void
36
+ */
37
+ private function maybe_create_debug_log_table() {
38
+
39
+ global $wpdb;
40
+
41
+ if (!function_exists('maybe_create_table')) {
42
+ //needed for the maybe_create_table function
43
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
44
+ }
45
+
46
+ $charset_collate = '';
47
+ if (!empty($wpdb->charset)) {
48
+ $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
49
+ } else {
50
+ $charset_collate = "DEFAULT CHARSET=utf8";
51
+ }
52
+ if (!empty($wpdb->collate)) {
53
+ $charset_collate .= " COLLATE $wpdb->collate";
54
+ }
55
+
56
+ //This exists as a constant, but multisite will need to refresh $wpdb->prefix
57
+ $debug_log_tbl_name = $wpdb->prefix.'aiowps_debug_log';
58
+
59
+ $debug_log_tbl_sql = "CREATE TABLE " . $debug_log_tbl_name . " (
60
+ id bigint(20) NOT NULL AUTO_INCREMENT,
61
+ level varchar(25) NOT NULL DEFAULT '',
62
+ message text NOT NULL DEFAULT '',
63
+ type varchar(25) NOT NULL DEFAULT '',
64
+ created datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
65
+ PRIMARY KEY (id)
66
+ )" . $charset_collate . ";";
67
+
68
+ maybe_create_table($debug_log_tbl_name, $debug_log_tbl_sql);
69
+
70
+ }
71
+
72
+ /**
73
+ * Clears the debug logs
74
+ *
75
+ * @return int|WP_Error the amount of records deleted or WP_Error if query failed
76
+ */
77
+ public function clear_logs() {
78
+ global $wpdb;
79
+
80
+ $debug_log_tbl = $wpdb->prefix . 'aiowps_debug_log';
81
+
82
+ $query = "DELETE FROM $debug_log_tbl";
83
+
84
+ $ret = $wpdb->query($query);
85
+
86
+ if (false === $ret) {
87
+ $error_msg = empty($wpdb->last_error) ? __('Unable to get the reason why', 'all-in-one-wp-security-and-firewall') : $wpdb->last_error;
88
+ $ret = new WP_Error('db_unable_delete', __('Unable to clear the logs', 'all-in-one-wp-security-and-firewall'), $error_msg);
89
+ }
90
+
91
+ return $ret;
92
+ }
93
+
94
+ /**
95
+ * Logs the debug messages to the database
96
+ *
97
+ * @param string $message - The main debug message
98
+ * @param integer $level_code - The level code which indicates the severity of the message
99
+ * @param string $type - The type of debug message. Seperates general debug messages from those generated by the cron, for example.
100
+ * @return void
101
+ */
102
+ public function log_debug($message, $level_code = 0, $type = 'debug') {
103
+
104
+ if (!$this->debug_enabled) {
105
+ return;
106
+ }
107
+
108
+ global $wpdb;
109
+ $debug_tbl_name = AIOWPSEC_TBL_DEBUG_LOG;
110
+
111
+ $data = array(
112
+ 'level' => $this->get_readable_level_from_code($level_code),
113
+ 'message' => $message,
114
+ 'type' => $type,
115
+ 'created' => current_time('mysql'),
116
+ );
117
+
118
+ $ret = $wpdb->insert($debug_tbl_name, $data);
119
+ if (false === $ret) {
120
+ $error_msg = empty($wpdb->last_error) ? 'Could not write to the debug log' : $wpdb->last_error;
121
+ error_log("All In One WP Security : {$error_msg}");
122
+ }
123
+
124
+ }
125
 
126
+ /**
127
+ * Logs the debug messages that relate to the cron
128
+ *
129
+ * @param string $message - The main debug message
130
+ * @param integer $level_code - The level code which indicates the severity of the message
131
+ * @return void
132
+ */
133
+ public function log_debug_cron($message, $level_code = 0) {
134
+ $this->log_debug($message, $level_code, 'cron_debug');
135
+ }
136
+
137
+
138
+ }
classes/wp-security-file-scan.php CHANGED
@@ -1,393 +1,367 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Scan
7
- {
8
 
9
- function __construct()
10
- {
11
- add_action('aiowps_perform_fcd_scan_tasks', array($this, 'aiowps_scheduled_fcd_scan_handler'));
12
- }
13
-
14
- /**
15
- * This function will recursively scan through all directories starting from the specified location
16
- * It will store the path/filename, last_modified and filesize values in a multi-dimensional associative array
17
- */
18
-
19
- /**
20
- * Will recursively scan through all directories starting from ABSPATH.
21
- * Will return array with the path/filename, last_modified and filesize values
22
- * @global AIO_WP_Security $aio_wp_security
23
- * @return boolean|array
24
- */
25
- function execute_file_change_detection_scan()
26
- {
27
- global $aio_wp_security;
28
- $scan_result = array();
29
- $fcd_filename = $aio_wp_security->configs->get_value('aiowps_fcd_filename');
30
- if (empty($fcd_filename)) {
31
- // means that we haven't done a scan before, or,
32
- // the fcd file containing the results doesn't exist
33
- $random_suffix = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10);
34
- $fcd_filename = 'aiowps_fcd_data_' . $random_suffix;
35
- $aio_wp_security->configs->set_value('aiowps_fcd_filename', $fcd_filename);
36
- $aio_wp_security->configs->save_config();
37
- }
38
-
39
- $fcd_data = self::get_fcd_data(); // get previous scan data if any
40
 
41
- if ($fcd_data === false) {
42
- // an error occurred so return
43
- return false;
44
- }
45
-
46
- $scanned_data = $this->do_file_change_scan();
47
-
48
- if(empty($fcd_data)){
49
- $this->save_fcd_data($scanned_data);
50
- $scan_result['initial_scan'] = '1';
51
- return $scan_result;
52
- } else {
53
-
54
- $scan_result = $this->compare_scan_data($fcd_data['file_scan_data'], $scanned_data);
55
-
56
- $scan_result['initial_scan'] = '';
57
- $this->save_fcd_data($scanned_data, $scan_result);
58
- if (!empty($scan_result['files_added']) || !empty($scan_result['files_removed']) || !empty($scan_result['files_changed'])){
59
- //This means there was a change detected
60
- $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', TRUE);
61
- $aio_wp_security->configs->save_config();
62
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - change to filesystem detected!");
63
 
64
- $this->aiowps_send_file_change_alert_email($scan_result); //Send file change scan results via email if applicable
65
- } else {
66
- //Reset the change flag
67
- $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', FALSE);
68
- $aio_wp_security->configs->save_config();
69
- }
70
- return $scan_result;
71
- }
72
- }
73
 
74
- /**
75
- * Send email with notification about file changes detected by last scan.
76
- * @global AIO_WP_Security $aio_wp_security
77
- * @param array $scan_result Array with scan result returned by compare_scan_data() method.
78
- */
79
- function aiowps_send_file_change_alert_email($scan_result)
80
- {
81
- global $aio_wp_security;
82
- if ( $aio_wp_security->configs->get_value('aiowps_send_fcd_scan_email') == '1' )
83
- {
84
- $site_title = get_bloginfo( 'name' );
85
- $from_name = empty($site_title)?'WordPress':$site_title;
86
-
87
- $headers = 'From: ' . $from_name . ' <' . get_option('admin_email') . '>' . PHP_EOL;
88
- $subject = __( 'All In One WP Security - File change detected!', 'all-in-one-wp-security-and-firewall' ) . ' ' . date( 'l, F jS, Y \a\\t g:i a', current_time( 'timestamp' ) );
89
- //$attachment = array();
90
- $message = __( 'A file change was detected on your system for site URL', 'all-in-one-wp-security-and-firewall' ) . ' ' . get_option( 'siteurl' ) . __( '. Scan was generated on', 'all-in-one-wp-security-and-firewall' ) . ' ' . date( 'l, F jS, Y \a\\t g:i a', current_time( 'timestamp' ) );
91
- $message .= "\r\n\r\n".__( 'A summary of the scan results is shown below:', 'all-in-one-wp-security-and-firewall' );
92
- $message .= "\r\n\r\n";
93
- $message .= self::get_file_change_summary($scan_result);
94
- $message .= "\r\n".__( 'Login to your site to view the scan details.', 'all-in-one-wp-security-and-firewall' );
95
 
96
- // Get the email address(es).
97
- $addresses = $aio_wp_security->configs->get_value('aiowps_fcd_scan_email_address');
98
- // If no explicit email address(es) are given, send email to site admin.
99
- $to = empty( $addresses ) ? array( get_site_option('admin_email') ) : explode(PHP_EOL, $addresses);
100
- if ( !wp_mail( $to, $subject, $message, $headers ) ) {
101
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - File change notification email failed to send.",4);
102
- }
103
 
104
- }
105
- }
106
-
107
- function aiowps_scheduled_fcd_scan_handler()
108
- {
109
- global $aio_wp_security;
110
- if($aio_wp_security->configs->get_value('aiowps_enable_automated_fcd_scan')=='1')
111
- {
112
- $aio_wp_security->debug_logger->log_debug_cron(__METHOD__ . " - Scheduled fcd_scan is enabled. Checking now to see if scan needs to be done...");
113
- $time_now = current_time( 'mysql' );
114
- $current_time = strtotime($time_now);
115
- $fcd_scan_frequency = $aio_wp_security->configs->get_value('aiowps_fcd_scan_frequency'); //Number of hours or days or months interval
116
- $interval_setting = $aio_wp_security->configs->get_value('aiowps_fcd_scan_interval'); //Hours/Days/Months
117
- switch($interval_setting)
118
- {
119
- case '0':
120
- $interval = 'hours';
121
- break;
122
- case '1':
123
- $interval = 'days';
124
- break;
125
- case '2':
126
- $interval = 'weeks';
127
- break;
128
- }
129
- $last_fcd_scan_time_string = $aio_wp_security->configs->get_value('aiowps_last_fcd_scan_time');
130
- if ($last_fcd_scan_time_string != NULL)
131
- {
132
- $last_fcd_scan_time = strtotime($last_fcd_scan_time_string);
133
- $next_fcd_scan_time = strtotime("+".abs($fcd_scan_frequency).$interval, $last_fcd_scan_time);
134
- if ($next_fcd_scan_time <= $current_time)
135
- {
136
- //It's time to do a filescan
137
- $result = $this->execute_file_change_detection_scan();
138
- if ($result === false)
139
- {
140
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Scheduled filescan operation failed!",4);
141
- }
142
- else
143
- {
144
- $aio_wp_security->configs->set_value('aiowps_last_fcd_scan_time', $time_now);
145
- $aio_wp_security->configs->save_config();
146
- }
147
- }
148
- }
149
- else
150
- {
151
- //Set the last scan time to now so it can trigger for the next scheduled period
152
- $aio_wp_security->configs->set_value('aiowps_last_fcd_scan_time', $time_now);
153
- $aio_wp_security->configs->save_config();
154
- }
155
- }
156
- }
157
-
158
- /**
159
- * Get the last filechange detection data which is stored in the special file.
160
- * @global AIO_WP_Security $aio_wp_security
161
- * @return bool|array - false on failure, array on success
162
- */
163
- static function get_fcd_data()
164
- {
165
- global $aio_wp_security;
166
- $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
167
-
168
- $fcd_filename = $aio_wp_security->configs->get_value('aiowps_fcd_filename');
169
- $results_file = $aiowps_backup_dir. '/'. $fcd_filename;
170
-
171
- if(!file_exists($results_file)) {
172
- $fp = @fopen($results_file, 'w'); //open for write - will create file if doesn't exist
173
- return array();
174
- }
175
-
176
- if(empty(filesize($results_file))) {
177
- return array(); // if newly created file return empty array
178
- }
179
-
180
- $fp = @fopen($results_file, 'r'); //open for read and write - will create file if doesn't exist
181
- if($fp === false) {
182
- // Error
183
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - fopen returned false when opening fcd data file");
184
- return false;
185
- }
186
-
187
- $contents = fread($fp, filesize($results_file));
188
- fclose($fp);
189
- if($contents === false){
190
- // Error
191
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - fread returned false when reading fcd data file");
192
- return false;
193
- } else {
194
-
195
- $fcd_file_contents = json_decode($contents, TRUE);
196
- if(isset($fcd_file_contents['file_scan_data'])) {
197
- return $fcd_file_contents;
198
- } else {
199
- return array();
200
- }
201
-
202
- }
203
- }
204
-
205
- /**
206
- * Recursively scan the entire $start_dir directory and return file size
207
- * and last modified date of every regular file. Ignore files and file
208
- * types specified in file scanner settings.
209
- * @global AIO_WP_Security $aio_wp_security
210
- * @param string $start_dir
211
- * @return array
212
- */
213
- function do_file_change_scan($start_dir=ABSPATH)
214
- {
215
- global $aio_wp_security;
216
- $filescan_data = array();
217
- // Iterator key is absolute file path, iterator value is SplFileInfo object,
218
- // iteration skips '..' and '.' records, because we're not interested in directories.
219
- $dit = new RecursiveDirectoryIterator(
220
- $start_dir, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS
221
- );
222
- $rit = new RecursiveIteratorIterator(
223
- $dit, RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD
224
- );
225
 
226
- // Grab files/directories to skip
227
- $files_to_skip = AIOWPSecurity_Utility::explode_trim_filter_empty($aio_wp_security->configs->get_value('aiowps_fcd_exclude_files'));
228
- // Grab (lowercased) file types to skip
229
- $file_types_to_skip = AIOWPSecurity_Utility::explode_trim_filter_empty(strtolower($aio_wp_security->configs->get_value('aiowps_fcd_exclude_filetypes')));
230
 
231
- $start_dir_length = strlen($start_dir);
232
 
233
- foreach ($rit as $filename => $fileinfo) {
234
 
235
- if ( !file_exists($filename) || is_dir($filename) ) {
236
- continue; // if file doesn't exist or is a directory move on to next iteration
237
- }
238
 
239
- if ( $fileinfo->getFilename() == 'wp-security-log-cron-job.txt' || $fileinfo->getFilename() == 'wp-security-log.txt' ) {
240
- continue; // skip aiowps log files
241
- }
242
 
243
- // Let's omit any file types from the scan which were specified in the settings if necessary
244
- if ( !empty($file_types_to_skip) ) {
245
- //$current_file_ext = strtolower($fileinfo->getExtension()); //getExtension() only available on PHP 5.3.6 or higher
246
- $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
247
- if (in_array($ext, $file_types_to_skip) ) { continue; }
248
- }
 
 
249
 
250
- // Let's omit specific files or directories from the scan which were specified in the settings
251
- if ( !empty($files_to_skip) ) {
252
 
253
- $skip_this = false;
254
- foreach ($files_to_skip as $f_or_dir) {
255
- // Expect files/dirs to be specified relatively to $start_dir,
256
- // so start searching at $start_dir_length offset.
257
- if (strpos($filename, $f_or_dir, $start_dir_length) !== false) {
258
- $skip_this = true;
259
- break; // !
260
- }
261
- }
262
- if ($skip_this) { continue; }
263
- }
 
 
264
 
265
- $filescan_data[$filename] = array(
266
- 'last_modified' => $fileinfo->getMTime(),
267
- 'filesize' => $fileinfo->getSize(),
268
- );
269
 
270
- }
271
- return $filescan_data;
272
- }
273
-
274
- function compare_scan_data($last_scan_data, $new_scanned_data)
275
- {
276
- // Identify new files added: get all files which are in the new scan but not present in the old scan
277
- $files_added = @array_diff_key( $new_scanned_data, $last_scan_data );
278
- // Identify files deleted: get all files which are in the old scan but not present in the new scan
279
- $files_removed = @array_diff_key( $last_scan_data, $new_scanned_data );
280
- // Identify existing files: get all files which are in new scan, but were not added
281
- $files_kept = @array_diff_key( $new_scanned_data, $files_added );
282
 
283
- $files_changed = array();
284
 
285
- // Loop through existing files and determine, if they have been changed
286
- foreach ( $files_kept as $filename => $new_scan_meta ) {
287
- $last_scan_meta = $last_scan_data[$filename];
288
- // Check filesize and last_modified values
289
- if ( ($new_scan_meta['last_modified'] !== $last_scan_meta['last_modified'])
290
- || ($new_scan_meta['filesize'] !== $last_scan_meta['filesize']) )
291
- {
292
- $files_changed[$filename] = $new_scan_meta;
293
- }
294
- }
295
 
296
- // Create single array of all changes
297
- return array(
298
- 'files_added' => $files_added,
299
- 'files_removed' => $files_removed,
300
- 'files_changed' => $files_changed,
301
- );
302
- }
303
 
304
- static function get_file_change_data()
305
- {
306
- global $wpdb, $aio_wp_security;
307
- //Let's get the results array from the DB
308
- $tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
309
- $key = 'file_change_detection';
310
- $sql_prep = $wpdb->prepare("SELECT * FROM $tbl_name WHERE meta_key1 = %s", $key);
311
- $scan_db_data = $wpdb->get_row($sql_prep, ARRAY_A);
312
- if ($scan_db_data === NULL)
313
- {
314
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - DB query for scan results data from global meta table returned NULL!",4);
315
- return FALSE;
316
- }
317
- $date_last_scan = $scan_db_data['date_time'];
318
- $scan_results_unserialized = maybe_unserialize($scan_db_data['meta_value5']);
319
- if (empty($scan_results_unserialized['files_added']) && empty($scan_results_unserialized['files_removed']) && empty($scan_results_unserialized['files_changed'])){
320
- //No file change detected
321
- return FALSE;
322
- }else{
323
- return $scan_results_unserialized;
324
- }
325
 
326
- }
327
 
328
- static function get_file_change_summary($scan_result)
329
- {
330
- $scan_summary = "";
331
- if (!empty($scan_result['files_added']))
332
- {
333
- //Output of files added
334
- $scan_summary .= "\r\n".__('The following files were added to your host', 'all-in-one-wp-security-and-firewall').":\r\n";
335
- foreach ($scan_result['files_added'] as $key=>$value) {
336
- $scan_summary .= "\r\n".$key.' ('.__('modified on: ', 'all-in-one-wp-security-and-firewall').date('Y-m-d H:i:s',$value['last_modified']).')';
337
- }
338
- $scan_summary .= "\r\n======================================\r\n";
339
- }
340
- if (!empty($scan_result['files_removed']))
341
- {
342
- //Output of files removed
343
- $scan_summary .= "\r\n".__('The following files were removed from your host', 'all-in-one-wp-security-and-firewall').":\r\n";
344
- foreach ($scan_result['files_removed'] as $key=>$value) {
345
- $scan_summary .= "\r\n".$key.' ('.__('modified on: ', 'all-in-one-wp-security-and-firewall').date('Y-m-d H:i:s',$value['last_modified']).')';
346
- }
347
- $scan_summary .= "\r\n======================================\r\n";
348
- }
349
 
350
- if (!empty($scan_result['files_changed']))
351
- {
352
- //Output of files changed
353
- $scan_summary .= "\r\n".__('The following files were changed on your host', 'all-in-one-wp-security-and-firewall').":\r\n";
354
- foreach ($scan_result['files_changed'] as $key=>$value) {
355
- $scan_summary .= "\r\n".$key.' ('.__('modified on: ', 'all-in-one-wp-security-and-firewall').date('Y-m-d H:i:s',$value['last_modified']).')';
356
- }
357
- $scan_summary .= "\r\n======================================\r\n";
358
- }
359
 
360
- return $scan_summary;
361
- }
362
 
363
- /**
364
- * Saves file change detection data into a special file
365
- * @global AIO_WP_Security $aio_wp_security
366
- * @param type $scanned_data
367
- * @param type $scan_result
368
- * @return boolean
369
- */
370
- function save_fcd_data($scanned_data, $scan_result = array())
371
- {
372
- global $aio_wp_security;
373
 
374
- $date_time = current_time( 'mysql' );
375
- $data = array('date_time' => $date_time, 'file_scan_data' => $scanned_data, 'last_scan_result' => $scan_result);
376
-
377
- $fcd_filename = $aio_wp_security->configs->get_value('aiowps_fcd_filename');
378
- $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
379
-
380
- if (!AIOWPSecurity_Utility_File::create_dir($aiowps_backup_dir))
381
- {
382
- $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Creation of DB backup directory failed!",4);
383
- return false;
384
- }
385
- $results_file = $aiowps_backup_dir. '/'. $fcd_filename;
386
- $fp=fopen($results_file,'w');
387
- fwrite($fp, json_encode($data));
388
- fclose($fp);
389
-
390
- }
391
-
392
  }
393
-
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Scan {
 
7
 
8
+ public function __construct() {
9
+ add_action('aiowps_perform_fcd_scan_tasks', array($this, 'aiowps_scheduled_fcd_scan_handler'));
10
+ }
11
+
12
+ /**
13
+ * This function will recursively scan through all directories starting from the specified location
14
+ * It will store the path/filename, last_modified and filesize values in a multi-dimensional associative array
15
+ */
16
+
17
+ /**
18
+ * Will recursively scan through all directories starting from ABSPATH.
19
+ * Will return array with the path/filename, last_modified and filesize values
20
+ *
21
+ * @global AIO_WP_Security $aio_wp_security
22
+ * @return boolean|array
23
+ */
24
+ public function execute_file_change_detection_scan() {
25
+ global $aio_wp_security;
26
+ $scan_result = array();
27
+ $fcd_filename = $aio_wp_security->configs->get_value('aiowps_fcd_filename');
28
+ if (empty($fcd_filename)) {
29
+ // means that we haven't done a scan before, or,
30
+ // the fcd file containing the results doesn't exist
31
+ $random_suffix = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10);
32
+ $fcd_filename = 'aiowps_fcd_data_' . $random_suffix;
33
+ $aio_wp_security->configs->set_value('aiowps_fcd_filename', $fcd_filename);
34
+ $aio_wp_security->configs->save_config();
35
+ }
36
+
37
+ $fcd_data = self::get_fcd_data(); // get previous scan data if any
 
38
 
39
+ if (false === $fcd_data) {
40
+ // an error occurred so return
41
+ return false;
42
+ }
43
+
44
+ $scanned_data = $this->do_file_change_scan();
45
+
46
+ if (empty($fcd_data)) {
47
+ $this->save_fcd_data($scanned_data);
48
+ $scan_result['initial_scan'] = '1';
49
+ return $scan_result;
50
+ } else {
51
+
52
+ $scan_result = $this->compare_scan_data($fcd_data['file_scan_data'], $scanned_data);
53
+
54
+ $scan_result['initial_scan'] = '';
55
+ $this->save_fcd_data($scanned_data, $scan_result);
56
+ if (!empty($scan_result['files_added']) || !empty($scan_result['files_removed']) || !empty($scan_result['files_changed'])) {
57
+ //This means there was a change detected
58
+ $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', true);
59
+ $aio_wp_security->configs->save_config();
60
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - change to filesystem detected!");
61
 
62
+ $this->aiowps_send_file_change_alert_email($scan_result); //Send file change scan results via email if applicable
63
+ } else {
64
+ //Reset the change flag
65
+ $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', false);
66
+ $aio_wp_security->configs->save_config();
67
+ }
68
+ return $scan_result;
69
+ }
70
+ }
71
 
72
+ /**
73
+ * Send email with notification about file changes detected by last scan.
74
+ *
75
+ * @global AIO_WP_Security $aio_wp_security
76
+ * @param array $scan_result Array with scan result returned by compare_scan_data() method.
77
+ */
78
+ public function aiowps_send_file_change_alert_email($scan_result) {
79
+ global $aio_wp_security;
80
+ if ($aio_wp_security->configs->get_value('aiowps_send_fcd_scan_email') == '1') {
81
+ $site_title = get_bloginfo('name');
82
+ $from_name = empty($site_title) ? 'WordPress' : $site_title;
83
+
84
+ $headers = 'From: ' . $from_name . ' <' . get_option('admin_email') . '>' . PHP_EOL;
85
+ $subject = __('All In One WP Security - File change detected!', 'all-in-one-wp-security-and-firewall') . ' ' . date('l, F jS, Y \a\\t g:i a', current_time('timestamp'));
86
+ //$attachment = array();
87
+ $message = __('A file change was detected on your system for site URL', 'all-in-one-wp-security-and-firewall') . ' ' . get_option('siteurl') . __('. Scan was generated on', 'all-in-one-wp-security-and-firewall') . ' ' . date('l, F jS, Y \a\\t g:i a', current_time('timestamp'));
88
+ $message .= "\r\n\r\n".__('A summary of the scan results is shown below:', 'all-in-one-wp-security-and-firewall');
89
+ $message .= "\r\n\r\n";
90
+ $message .= self::get_file_change_summary($scan_result);
91
+ $message .= "\r\n".__('Login to your site to view the scan details.', 'all-in-one-wp-security-and-firewall');
 
92
 
93
+ // Get the email address(es).
94
+ $addresses = $aio_wp_security->configs->get_value('aiowps_fcd_scan_email_address');
95
+ // If no explicit email address(es) are given, send email to site admin.
96
+ $to = empty($addresses) ? array(get_site_option('admin_email')) : explode(PHP_EOL, $addresses);
97
+ if (!wp_mail($to, $subject, $message, $headers)) {
98
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - File change notification email failed to send.", 4);
99
+ }
100
 
101
+ }
102
+ }
103
+
104
+ public function aiowps_scheduled_fcd_scan_handler() {
105
+ global $aio_wp_security;
106
+ if ($aio_wp_security->configs->get_value('aiowps_enable_automated_fcd_scan')=='1') {
107
+ $aio_wp_security->debug_logger->log_debug_cron(__METHOD__ . " - Scheduled fcd_scan is enabled. Checking now to see if scan needs to be done...");
108
+ $time_now = current_time('mysql');
109
+ $current_time = strtotime($time_now);
110
+ $fcd_scan_frequency = $aio_wp_security->configs->get_value('aiowps_fcd_scan_frequency'); //Number of hours or days or months interval
111
+ $interval_setting = $aio_wp_security->configs->get_value('aiowps_fcd_scan_interval'); //Hours/Days/Months
112
+ switch ($interval_setting) {
113
+ case '0':
114
+ $interval = 'hours';
115
+ break;
116
+ case '1':
117
+ $interval = 'days';
118
+ break;
119
+ case '2':
120
+ $interval = 'weeks';
121
+ break;
122
+ }
123
+ $last_fcd_scan_time_string = $aio_wp_security->configs->get_value('aiowps_last_fcd_scan_time');
124
+ if (null != $last_fcd_scan_time_string) {
125
+ $last_fcd_scan_time = strtotime($last_fcd_scan_time_string);
126
+ $next_fcd_scan_time = strtotime("+".abs($fcd_scan_frequency).$interval, $last_fcd_scan_time);
127
+ if ($next_fcd_scan_time <= $current_time) {
128
+ //It's time to do a filescan
129
+ $result = $this->execute_file_change_detection_scan();
130
+ if (false === $result) {
131
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Scheduled filescan operation failed!", 4);
132
+ } else {
133
+ $aio_wp_security->configs->set_value('aiowps_last_fcd_scan_time', $time_now);
134
+ $aio_wp_security->configs->save_config();
135
+ }
136
+ }
137
+ } else {
138
+ //Set the last scan time to now so it can trigger for the next scheduled period
139
+ $aio_wp_security->configs->set_value('aiowps_last_fcd_scan_time', $time_now);
140
+ $aio_wp_security->configs->save_config();
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Get the last filechange detection data which is stored in the special file.
147
+ *
148
+ * @global AIO_WP_Security $aio_wp_security
149
+ * @return bool|array - false on failure, array on success
150
+ */
151
+ public static function get_fcd_data() {
152
+ global $aio_wp_security;
153
+ $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
154
+
155
+ $fcd_filename = $aio_wp_security->configs->get_value('aiowps_fcd_filename');
156
+ $results_file = $aiowps_backup_dir. '/'. $fcd_filename;
157
+
158
+ if (!file_exists($results_file)) {
159
+ $fp = @fopen($results_file, 'w'); //open for write - will create file if doesn't exist
160
+ return array();
161
+ }
162
+
163
+ if (empty(filesize($results_file))) {
164
+ return array(); // if newly created file return empty array
165
+ }
166
+
167
+ $fp = @fopen($results_file, 'r'); //open for read and write - will create file if doesn't exist
168
+ if (false === $fp) {
169
+ // Error
170
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - fopen returned false when opening fcd data file");
171
+ return false;
172
+ }
173
+
174
+ $contents = fread($fp, filesize($results_file));
175
+ fclose($fp);
176
+ if (false === $contents) {
177
+ // Error
178
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - fread returned false when reading fcd data file");
179
+ return false;
180
+ } else {
181
+
182
+ $fcd_file_contents = json_decode($contents, true);
183
+ if (isset($fcd_file_contents['file_scan_data'])) {
184
+ return $fcd_file_contents;
185
+ } else {
186
+ return array();
187
+ }
188
+
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Recursively scan the entire $start_dir directory and return file size
194
+ * and last modified date of every regular file. Ignore files and file
195
+ * types specified in file scanner settings.
196
+ *
197
+ * @global AIO_WP_Security $aio_wp_security
198
+ * @param string $start_dir
199
+ * @return array
200
+ */
201
+ public function do_file_change_scan($start_dir = ABSPATH) {
202
+ global $aio_wp_security;
203
+ $filescan_data = array();
204
+ // Iterator key is absolute file path, iterator value is SplFileInfo object,
205
+ // iteration skips '..' and '.' records, because we're not interested in directories.
206
+ $dit = new RecursiveDirectoryIterator($start_dir, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS);
207
+ $rit = new RecursiveIteratorIterator($dit, RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
 
209
+ // Grab files/directories to skip
210
+ $files_to_skip = AIOWPSecurity_Utility::explode_trim_filter_empty($aio_wp_security->configs->get_value('aiowps_fcd_exclude_files'));
211
+ // Grab (lowercased) file types to skip
212
+ $file_types_to_skip = AIOWPSecurity_Utility::explode_trim_filter_empty(strtolower($aio_wp_security->configs->get_value('aiowps_fcd_exclude_filetypes')));
213
 
214
+ $start_dir_length = strlen($start_dir);
215
 
216
+ foreach ($rit as $filename => $fileinfo) {
217
 
218
+ if (!file_exists($filename) || is_dir($filename)) {
219
+ continue; // if file doesn't exist or is a directory move on to next iteration
220
+ }
221
 
222
+ if ($fileinfo->getFilename() == 'wp-security-log-cron-job.txt' || $fileinfo->getFilename() == 'wp-security-log.txt') {
223
+ continue; // skip aiowps log files
224
+ }
225
 
226
+ // Let's omit any file types from the scan which were specified in the settings if necessary
227
+ if (!empty($file_types_to_skip)) {
228
+ //$current_file_ext = strtolower($fileinfo->getExtension()); //getExtension() only available on PHP 5.3.6 or higher
229
+ $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
230
+ if (in_array($ext, $file_types_to_skip)) {
231
+ continue;
232
+ }
233
+ }
234
 
235
+ // Let's omit specific files or directories from the scan which were specified in the settings
236
+ if (!empty($files_to_skip)) {
237
 
238
+ $skip_this = false;
239
+ foreach ($files_to_skip as $f_or_dir) {
240
+ // Expect files/dirs to be specified relatively to $start_dir,
241
+ // so start searching at $start_dir_length offset.
242
+ if (strpos($filename, $f_or_dir, $start_dir_length) !== false) {
243
+ $skip_this = true;
244
+ break; // !
245
+ }
246
+ }
247
+ if ($skip_this) {
248
+ continue;
249
+ }
250
+ }
251
 
252
+ $filescan_data[$filename] = array(
253
+ 'last_modified' => $fileinfo->getMTime(),
254
+ 'filesize' => $fileinfo->getSize(),
255
+ );
256
 
257
+ }
258
+ return $filescan_data;
259
+ }
260
+
261
+ public function compare_scan_data($last_scan_data, $new_scanned_data) {
262
+ // Identify new files added: get all files which are in the new scan but not present in the old scan
263
+ $files_added = @array_diff_key($new_scanned_data, $last_scan_data);
264
+ // Identify files deleted: get all files which are in the old scan but not present in the new scan
265
+ $files_removed = @array_diff_key($last_scan_data, $new_scanned_data);
266
+ // Identify existing files: get all files which are in new scan, but were not added
267
+ $files_kept = @array_diff_key($new_scanned_data, $files_added);
 
268
 
269
+ $files_changed = array();
270
 
271
+ // Loop through existing files and determine, if they have been changed
272
+ foreach ($files_kept as $filename => $new_scan_meta) {
273
+ $last_scan_meta = $last_scan_data[$filename];
274
+ // Check filesize and last_modified values
275
+ if (($new_scan_meta['last_modified'] !== $last_scan_meta['last_modified']) || ($new_scan_meta['filesize'] !== $last_scan_meta['filesize'])) {
276
+ $files_changed[$filename] = $new_scan_meta;
277
+ }
278
+ }
 
 
279
 
280
+ // Create single array of all changes
281
+ return array(
282
+ 'files_added' => $files_added,
283
+ 'files_removed' => $files_removed,
284
+ 'files_changed' => $files_changed,
285
+ );
286
+ }
287
 
288
+ public static function get_file_change_data() {
289
+ global $wpdb, $aio_wp_security;
290
+ //Let's get the results array from the DB
291
+ $tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
292
+ $key = 'file_change_detection';
293
+ $sql_prep = $wpdb->prepare("SELECT * FROM $tbl_name WHERE meta_key1 = %s", $key);
294
+ $scan_db_data = $wpdb->get_row($sql_prep, ARRAY_A);
295
+ if (null === $scan_db_data) {
296
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - DB query for scan results data from global meta table returned null!", 4);
297
+ return false;
298
+ }
299
+ $scan_results_unserialized = maybe_unserialize($scan_db_data['meta_value5']);
300
+ if (empty($scan_results_unserialized['files_added']) && empty($scan_results_unserialized['files_removed']) && empty($scan_results_unserialized['files_changed'])) {
301
+ //No file change detected
302
+ return false;
303
+ } else {
304
+ return $scan_results_unserialized;
305
+ }
 
 
 
306
 
307
+ }
308
 
309
+ public static function get_file_change_summary($scan_result) {
310
+ $scan_summary = "";
311
+ if (!empty($scan_result['files_added'])) {
312
+ //Output of files added
313
+ $scan_summary .= "\r\n".__('The following files were added to your host', 'all-in-one-wp-security-and-firewall').":\r\n";
314
+ foreach ($scan_result['files_added'] as $key => $value) {
315
+ $scan_summary .= "\r\n".$key.' ('.__('modified on: ', 'all-in-one-wp-security-and-firewall').date('Y-m-d H:i:s', $value['last_modified']).')';
316
+ }
317
+ $scan_summary .= "\r\n======================================\r\n";
318
+ }
319
+ if (!empty($scan_result['files_removed'])) {
320
+ //Output of files removed
321
+ $scan_summary .= "\r\n".__('The following files were removed from your host', 'all-in-one-wp-security-and-firewall').":\r\n";
322
+ foreach ($scan_result['files_removed'] as $key => $value) {
323
+ $scan_summary .= "\r\n".$key.' ('.__('modified on: ', 'all-in-one-wp-security-and-firewall').date('Y-m-d H:i:s', $value['last_modified']).')';
324
+ }
325
+ $scan_summary .= "\r\n======================================\r\n";
326
+ }
 
 
 
327
 
328
+ if (!empty($scan_result['files_changed'])) {
329
+ //Output of files changed
330
+ $scan_summary .= "\r\n".__('The following files were changed on your host', 'all-in-one-wp-security-and-firewall').":\r\n";
331
+ foreach ($scan_result['files_changed'] as $key => $value) {
332
+ $scan_summary .= "\r\n".$key.' ('.__('modified on: ', 'all-in-one-wp-security-and-firewall').date('Y-m-d H:i:s', $value['last_modified']).')';
333
+ }
334
+ $scan_summary .= "\r\n======================================\r\n";
335
+ }
 
336
 
337
+ return $scan_summary;
338
+ }
339
 
340
+ /**
341
+ * Saves file change detection data into a special file
342
+ *
343
+ * @global AIO_WP_Security $aio_wp_security
344
+ * @param type $scanned_data
345
+ * @param type $scan_result
346
+ * @return boolean
347
+ */
348
+ public function save_fcd_data($scanned_data, $scan_result = array()) {
349
+ global $aio_wp_security;
350
 
351
+ $date_time = current_time('mysql');
352
+ $data = array('date_time' => $date_time, 'file_scan_data' => $scanned_data, 'last_scan_result' => $scan_result);
353
+
354
+ $fcd_filename = $aio_wp_security->configs->get_value('aiowps_fcd_filename');
355
+ $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
356
+
357
+ if (!AIOWPSecurity_Utility_File::create_dir($aiowps_backup_dir)) {
358
+ $aio_wp_security->debug_logger->log_debug(__METHOD__ . " - Creation of DB backup directory failed!", 4);
359
+ return false;
360
+ }
361
+ $results_file = $aiowps_backup_dir. '/'. $fcd_filename;
362
+ $fp = fopen($results_file, 'w');
363
+ fwrite($fp, json_encode($data));
364
+ fclose($fp);
365
+
366
+ }
 
 
367
  }
 
classes/wp-security-general-init-tasks.php CHANGED
@@ -1,649 +1,656 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_General_Init_Tasks
7
- {
8
- function __construct(){
9
- // Do init time tasks
10
- global $aio_wp_security;
11
-
12
- if ($aio_wp_security->configs->get_value('aiowps_disable_xmlrpc_pingback_methods') == '1') {
13
- add_filter( 'xmlrpc_methods', array($this, 'aiowps_disable_xmlrpc_pingback_methods') );
14
- add_filter( 'wp_headers', array($this, 'aiowps_remove_x_pingback_header') );
15
- }
16
-
17
- add_action( 'permalink_structure_changed', array($this, 'refresh_firewall_rules' ), 10, 2);
18
-
19
- // Check permanent block list and block if applicable (ie, do PHP blocking)
20
- AIOWPSecurity_Blocking::check_visitor_ip_and_perform_blocking();
21
-
22
- if ($aio_wp_security->configs->get_value('aiowps_enable_autoblock_spam_ip') == '1') {
23
- add_action( 'comment_post', array($this, 'spam_detect_process_comment_post' ), 10, 2); //this hook gets fired just after comment is saved to DB
24
- add_action( 'transition_comment_status', array($this, 'process_transition_comment_status' ), 10, 3); //this hook gets fired when a comment's status changes
25
- }
26
-
27
- if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
28
- add_action( 'widgets_init', array($this, 'remove_standard_wp_meta_widget' ));
29
- add_filter( 'retrieve_password_message', array($this, 'decode_reset_pw_msg'), 10, 4); //Fix for non decoded html entities in password reset link
30
- }
31
-
32
- if (current_user_can(AIOWPSEC_MANAGEMENT_PERMISSION)) {
33
- $this->reapply_htaccess_rules();
34
- add_action('admin_notices', array($this,'reapply_htaccess_rules_notice'));
35
- }
36
-
37
- if($aio_wp_security->configs->get_value('aiowps_prevent_site_display_inside_frame') == '1'){
38
- send_frame_options_header(); //send X-Frame-Options: SAMEORIGIN in HTTP header
39
- }
40
-
41
- if($aio_wp_security->configs->get_value('aiowps_remove_wp_generator_meta_info') == '1'){
42
- add_filter('the_generator', array($this,'remove_wp_generator_meta_info'));
43
- add_filter('style_loader_src', array($this,'remove_wp_css_js_meta_info'));
44
- add_filter('script_loader_src', array($this,'remove_wp_css_js_meta_info'));
45
- }
46
-
47
- // For the cookie based brute force prevention feature
48
- if($aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention') == 1){
49
- $bfcf_secret_word = $aio_wp_security->configs->get_value('aiowps_brute_force_secret_word');
50
- if(isset($_GET[$bfcf_secret_word])){
51
- // If URL contains secret word in query param then set cookie and then redirect to the login page
52
- AIOWPSecurity_Utility::set_cookie_value($bfcf_secret_word, "1");
53
- AIOWPSecurity_Utility::redirect_to_url(AIOWPSEC_WP_URL."/wp-admin");
54
- }
55
- }
56
-
57
- // Stop users enumeration feature
58
- if( $aio_wp_security->configs->get_value('aiowps_prevent_users_enumeration') == 1) {
59
- include_once(AIO_WP_SECURITY_PATH.'/other-includes/wp-security-stop-users-enumeration.php');
60
- }
61
-
62
- // REST API security
63
- if( $aio_wp_security->configs->get_value('aiowps_disallow_unauthorized_rest_requests') == 1) {
64
- add_action('rest_api_init', array($this, 'check_rest_api_requests'), 10 ,1);
65
- }
66
-
67
- // For user unlock request feature
68
- if(isset($_POST['aiowps_unlock_request']) || isset($_POST['aiowps_wp_submit_unlock_request'])){
69
- nocache_headers();
70
- remove_action('wp_head','head_addons',7);
71
- include_once(AIO_WP_SECURITY_PATH.'/other-includes/wp-security-unlock-request.php');
72
- exit();
73
- }
74
-
75
- if(isset($_GET['aiowps_auth_key'])){
76
- //If URL contains unlock key in query param then process the request
77
- $unlock_key = sanitize_text_field($_GET['aiowps_auth_key']);
78
- AIOWPSecurity_User_Login::process_unlock_request($unlock_key);
79
- }
80
-
81
- // For honeypot feature
82
- if(isset($_POST['aio_special_field'])){
83
- $special_field_value = sanitize_text_field($_POST['aio_special_field']);
84
- if(!empty($special_field_value)){
85
- //This means a robot has submitted the login form!
86
- //Redirect back to its localhost
87
- AIOWPSecurity_Utility::redirect_to_url('http://127.0.0.1');
88
- }
89
- }
90
-
91
- // For 404 IP lockout feature
92
- if($aio_wp_security->configs->get_value('aiowps_enable_404_IP_lockout') == '1'){
93
- if (!is_user_logged_in() || !current_user_can('administrator')) {
94
- $this->do_404_lockout_tasks();
95
- }
96
- }
97
-
98
-
99
- // For login captcha feature
100
- if($aio_wp_security->configs->get_value('aiowps_enable_login_captcha') == '1'){
101
- if (!is_user_logged_in()) {
102
- add_action('login_form', array($this, 'insert_captcha_question_form'));
103
- }
104
- }
105
-
106
- // For woo form captcha features
107
- if($aio_wp_security->configs->get_value('aiowps_enable_woo_login_captcha') == '1') {
108
- if (!is_user_logged_in()) {
109
- add_action('woocommerce_login_form', array($this, 'insert_captcha_question_form'));
110
- }
111
- if(isset($_POST['woocommerce-login-nonce'])) {
112
- add_filter('woocommerce_process_login_errors', array($this, 'aiowps_validate_woo_login_or_reg_captcha'), 10, 3);
113
- }
114
- }
115
-
116
- if($aio_wp_security->configs->get_value('aiowps_enable_woo_register_captcha') == '1') {
117
- if(!is_user_logged_in()) {
118
- add_action('woocommerce_register_form', array($this, 'insert_captcha_question_form'));
119
- }
120
-
121
- if(isset($_POST['woocommerce-register-nonce'])) {
122
- add_filter('woocommerce_process_registration_errors', array($this, 'aiowps_validate_woo_login_or_reg_captcha'), 10, 3);
123
- }
124
- }
125
-
126
- if($aio_wp_security->configs->get_value('aiowps_enable_woo_lostpassword_captcha') == '1') {
127
- if(!is_user_logged_in()) {
128
- add_action('woocommerce_lostpassword_form', array($this, 'insert_captcha_question_form'));
129
- }
130
- if(isset($_POST['woocommerce-lost-password-nonce'])) {
131
- add_action('lostpassword_post', array($this, 'process_woo_lost_password_form_post'));
132
- }
133
- }
134
-
135
- // For bbpress new topic form captcha
136
- if($aio_wp_security->configs->get_value('aiowps_enable_bbp_new_topic_captcha') == '1'){
137
- if (!is_user_logged_in()) {
138
- add_action('bbp_theme_before_topic_form_submit_wrapper', array($this, 'insert_captcha_question_form'));
139
- }
140
- }
141
-
142
- // For custom login form captcha feature, ie, when wp_login_form() function is used to generate login form
143
- if($aio_wp_security->configs->get_value('aiowps_enable_custom_login_captcha') == '1'){
144
- if (!is_user_logged_in()) {
145
- add_filter( 'login_form_middle', array($this, 'insert_captcha_custom_login'), 10, 2); //For cases where the WP wp_login_form() function is used
146
- }
147
- }
148
-
149
- // For honeypot feature
150
- if($aio_wp_security->configs->get_value('aiowps_enable_login_honeypot') == '1'){
151
- if (!is_user_logged_in()) {
152
- add_action('login_form', array($this, 'insert_honeypot_hidden_field'));
153
- }
154
- }
 
 
 
 
 
 
 
155
 
156
- // For registration honeypot feature
157
- if($aio_wp_security->configs->get_value('aiowps_enable_registration_honeypot') == '1'){
158
- if (!is_user_logged_in()) {
159
- add_action('register_form', array($this, 'insert_honeypot_hidden_field'));
160
- }
161
- }
162
-
163
- // For lost password captcha feature
164
- if($aio_wp_security->configs->get_value('aiowps_enable_lost_password_captcha') == '1'){
165
- if (!is_user_logged_in()) {
166
- add_action('lostpassword_form', array($this, 'insert_captcha_question_form'));
167
- add_action('lostpassword_post', array($this, 'process_lost_password_form_post'));
168
- }
169
- }
170
-
171
- // For registration manual approval feature
172
- if($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1'){
173
- add_filter('wp_login_errors', array($this, 'modify_registration_page_messages'),10, 2);
174
- }
175
-
176
- // For registration page captcha feature
177
- if (AIOWPSecurity_Utility::is_multisite_install()){
178
- $blog_id = get_current_blog_id();
179
- switch_to_blog($blog_id);
180
- if($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1'){
181
- if (!is_user_logged_in()) {
182
- add_action('signup_extra_fields', array($this, 'insert_captcha_question_form_multi'));
183
- //add_action('preprocess_signup_form', array($this, 'process_signup_form_multi'));
184
- add_filter( 'wpmu_validate_user_signup', array($this, 'process_signup_form_multi') );
185
- }
186
- }
187
- restore_current_blog();
188
- }else{
189
- if($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1'){
190
- if (!is_user_logged_in()) {
191
- add_action('register_form', array($this, 'insert_captcha_question_form'));
192
- }
193
- }
194
- }
195
-
196
- // For comment captcha feature or custom login form captcha
197
- if (AIOWPSecurity_Utility::is_multisite_install()){
198
- $blog_id = get_current_blog_id();
199
- switch_to_blog($blog_id);
200
- if($aio_wp_security->configs->get_value('aiowps_enable_comment_captcha') == '1'){
201
- if (!is_user_logged_in()) {
202
- if($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
203
- add_action('wp_head', array($this, 'add_recaptcha_script'));
204
- }
205
- add_action( 'comment_form_after_fields', array($this, 'insert_captcha_question_form'), 1 );
206
- add_action( 'comment_form_logged_in_after', array($this, 'insert_captcha_question_form'), 1 );
207
- add_filter( 'preprocess_comment', array($this, 'process_comment_post') );
208
- }
209
- }
210
- restore_current_blog();
211
- }else{
212
- if($aio_wp_security->configs->get_value('aiowps_enable_comment_captcha') == '1'){
213
- if (!is_user_logged_in()) {
214
- if($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
215
- add_action('wp_head', array($this, 'add_recaptcha_script'));
216
- }
217
- add_action( 'comment_form_after_fields', array($this, 'insert_captcha_question_form'), 1 );
218
- add_action( 'comment_form_logged_in_after', array($this, 'insert_captcha_question_form'), 1 );
219
- add_filter( 'preprocess_comment', array($this, 'process_comment_post') );
220
- }
221
- }
222
- }
223
-
224
- // For buddypress registration captcha feature
225
- if($aio_wp_security->configs->get_value('aiowps_enable_bp_register_captcha') == '1'){
226
- add_action('bp_account_details_fields', array($this, 'insert_captcha_question_form'));
227
- add_action('bp_signup_validate', array($this, 'buddy_press_signup_validate_captcha'));
228
- }
229
-
230
-
231
- // For feature which displays logged in users
232
- $aio_wp_security->user_login_obj->update_users_online_transient();
233
-
234
- // For block fake googlebots feature
235
- if($aio_wp_security->configs->get_value('aiowps_block_fake_googlebots') == '1'){
236
- include_once(AIO_WP_SECURITY_PATH.'/classes/wp-security-bot-protection.php');
237
- AIOWPSecurity_Fake_Bot_Protection::block_fake_googlebots();
238
- }
239
-
240
- // For 404 event logging
241
- if($aio_wp_security->configs->get_value('aiowps_enable_404_logging') == '1'){
242
- add_action('wp_head', array($this, 'check_404_event'));
243
- }
244
-
245
- // Add more tasks that need to be executed at init time
246
-
247
- } // end _construct()
248
-
249
- function aiowps_disable_xmlrpc_pingback_methods( $methods ) {
250
- unset( $methods['pingback.ping'] );
251
- unset( $methods['pingback.extensions.getPingbacks'] );
252
- return $methods;
253
- }
254
-
255
- function aiowps_remove_x_pingback_header( $headers ) {
256
- unset( $headers['X-Pingback'] );
257
- return $headers;
258
- }
259
-
260
- /**
261
- * Refreshes the firewall rules in .htaccess file
262
- * eg: if permalink settings changed and white list enabled
263
- * @param $old_permalink_structure
264
- * @param $permalink_structure
265
- */
266
- function refresh_firewall_rules($old_permalink_structure, $permalink_structure){
267
- global $aio_wp_security;
268
- //If white list enabled need to re-adjust the .htaccess rules
269
- if ($aio_wp_security->configs->get_value('aiowps_enable_whitelisting') == '1') {
270
- $write_result = AIOWPSecurity_Utility_Htaccess::write_to_htaccess(); //now let's write to the .htaccess file
271
- if ( !$write_result )
272
- {
273
- $this->show_msg_error(__('The plugin was unable to write to the .htaccess file. Please edit file manually.','all-in-one-wp-security-and-firewall'));
274
- $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_whitelist_Menu - The plugin was unable to write to the .htaccess file.");
275
- }
276
- }
277
- }
278
-
279
- function spam_detect_process_comment_post($comment_id, $comment_approved)
280
- {
281
- if($comment_approved === "spam"){
282
- $this->block_comment_ip($comment_id);
283
- }
284
-
285
- }
286
-
287
- function process_transition_comment_status($new_status, $old_status, $comment)
288
- {
289
- if($new_status == 'spam'){
290
- $this->block_comment_ip($comment->comment_ID);
291
- }
292
-
293
- }
294
-
295
- /**
296
- * Will check auto-spam blocking settings and will add IP to blocked table accordingly
297
- * @param $comment_id
298
- */
299
- function block_comment_ip($comment_id)
300
- {
301
- global $aio_wp_security, $wpdb;
302
- $comment_obj = get_comment( $comment_id );
303
- $comment_ip = $comment_obj->comment_author_IP;
304
- //Get number of spam comments from this IP
305
- $sql = $wpdb->prepare("SELECT * FROM $wpdb->comments
306
- WHERE comment_approved = 'spam'
307
- AND comment_author_IP = %s
308
- ", $comment_ip);
309
- $comment_data = $wpdb->get_results($sql, ARRAY_A);
310
- $spam_count = count($comment_data);
311
- $min_comment_before_block = $aio_wp_security->configs->get_value('aiowps_spam_ip_min_comments_block');
312
- if(!empty($min_comment_before_block) && $spam_count >= ($min_comment_before_block - 1)){
313
- AIOWPSecurity_Blocking::add_ip_to_block_list($comment_ip, 'spam');
314
- }
315
- }
316
-
317
- function remove_standard_wp_meta_widget()
318
- {
319
- unregister_widget('WP_Widget_Meta');
320
- }
321
-
322
- function remove_wp_generator_meta_info()
323
- {
324
- return '';
325
- }
326
-
327
- function remove_wp_css_js_meta_info($src) {
328
- global $wp_version;
329
- static $wp_version_hash = null; // Cache hash value for all function calls
330
-
331
- // Replace only version number of assets with WP version
332
- if ( strpos($src, 'ver=' . $wp_version) !== false ) {
333
- if ( !$wp_version_hash ) {
334
- $wp_version_hash = wp_hash($wp_version);
335
- }
336
- // Replace version number with computed hash
337
- $src = add_query_arg('ver', $wp_version_hash, $src);
338
- }
339
- return $src;
340
- }
341
-
342
- function do_404_lockout_tasks(){
343
- global $aio_wp_security;
344
- $redirect_url = $aio_wp_security->configs->get_value('aiowps_404_lock_redirect_url'); //This is the redirect URL for blocked users
345
-
346
- $visitor_ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
347
-
348
- $is_locked = AIOWPSecurity_Utility::check_locked_ip($visitor_ip);
349
-
350
- if($is_locked){
351
- //redirect blocked user to configured URL
352
- AIOWPSecurity_Utility::redirect_to_url($redirect_url);
353
- }else{
354
- //allow through
355
- }
356
- }
357
-
358
- /**
359
- * Renders captcha on form produced by the wp_login_form() function, ie, custom wp login form
360
- * @global type $aio_wp_security
361
- * @param type $cust_html_code
362
- * @param type $args
363
- * @return string
364
- */
365
- function insert_captcha_custom_login($cust_html_code, $args)
366
- {
367
- global $aio_wp_security;
368
- if($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
369
- $site_key = esc_html( $aio_wp_security->configs->get_value('aiowps_recaptcha_site_key') );
370
- $cap_form = '<div class="g-recaptcha-wrap" style="padding:10px 0 10px 0"><div class="g-recaptcha" data-sitekey="'.$site_key.'"></div></div>';
371
- $cust_html_code .= $cap_form;
372
- return $cust_html_code;
373
- } else {
374
- $cap_form = '<p class="aiowps-captcha"><label>'.__('Please enter an answer in digits:','all-in-one-wp-security-and-firewall').'</label>';
375
- $cap_form .= '<div class="aiowps-captcha-equation"><strong>';
376
- $maths_question_output = $aio_wp_security->captcha_obj->generate_maths_question();
377
- $cap_form .= $maths_question_output . '</strong></div></p>';
378
-
379
- $cust_html_code .= $cap_form;
380
- return $cust_html_code;
381
- }
382
- }
383
-
384
- function insert_captcha_question_form_multi($error)
385
- {
386
- global $aio_wp_security;
387
- $aio_wp_security->captcha_obj->display_captcha_form();
388
- }
389
-
390
- function process_signup_form_multi($result)
391
- {
392
- global $aio_wp_security;
393
- //Check if captcha enabled
394
- $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
395
- if ( $verify_captcha === false ) {
396
- // wrong answer was entered
397
- $result['errors']->add('generic', __('<strong>ERROR</strong>: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
398
- }
399
- return $result;
400
- }
401
-
402
- function insert_captcha_question_form(){
403
- global $aio_wp_security;
404
-
405
- if($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
406
-
407
- // Woocommerce "my account" page needs special consideration, ie,
408
- // need to display two Google reCaptcha forms on same page (for login and register forms)
409
- // For this case we use the "explicit" recaptcha display
410
- $calling_hook = current_filter();
411
- $site_key = esc_html( $aio_wp_security->configs->get_value('aiowps_recaptcha_site_key') );
412
- if ( $calling_hook == 'woocommerce_login_form' || $calling_hook == 'woocommerce_lostpassword_form') {
413
- echo '<div class="g-recaptcha-wrap" style="padding:10px 0 10px 0"><div id="woo_recaptcha_1" class="g-recaptcha" data-sitekey="'.$site_key.'"></div></div>';
414
- return;
415
- }
416
-
417
- if ( $calling_hook == 'woocommerce_register_form' ) {
418
- echo '<div class="g-recaptcha-wrap" style="padding:10px 0 10px 0"><div id="woo_recaptcha_2" class="g-recaptcha" data-sitekey="'.$site_key.'"></div></div>';
419
- return;
420
- }
421
-
422
- // For all other forms simply display google recaptcha as per normal
423
- $aio_wp_security->captcha_obj->display_recaptcha_form();
424
- } else {
425
- // display plain maths captcha form
426
- $aio_wp_security->captcha_obj->display_captcha_form();
427
- }
428
-
429
- }
430
-
431
- function insert_honeypot_hidden_field(){
432
- $honey_input = '<p style="display: none;"><label>'.__('Enter something special:','all-in-one-wp-security-and-firewall').'</label>';
433
- $honey_input .= '<input name="aio_special_field" type="text" id="aio_special_field" class="aio_special_field" value="" /></p>';
434
- echo $honey_input;
435
- }
436
-
437
- function process_comment_post( $comment )
438
- {
439
- global $aio_wp_security;
440
- if (is_user_logged_in()) {
441
- return $comment;
442
- }
443
-
444
- //Don't process captcha for comment replies inside admin menu
445
- if (isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'replyto-comment' &&
446
- (check_ajax_referer('replyto-comment', '_ajax_nonce', false) || check_ajax_referer('replyto-comment', '_ajax_nonce-replyto-comment', false))) {
447
- return $comment;
448
- }
449
-
450
- //Don't do captcha for pingback/trackback
451
- if ($comment['comment_type'] != '' && $comment['comment_type'] != 'comment' && $comment['comment_type'] != 'review') {
452
- return $comment;
453
- }
454
-
455
- $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
456
- if($verify_captcha === false) {
457
- //Wrong answer
458
- wp_die( __('Error: You entered an incorrect CAPTCHA answer. Please go back and try again.', 'all-in-one-wp-security-and-firewall'));
459
- } else {
460
- return($comment);
461
- }
462
- }
463
-
464
- /**
465
- * Process the main Wordpress account lost password login form post
466
- * Called by wp hook "lostpassword_post"
467
- */
468
- function process_lost_password_form_post()
469
- {
470
- global $aio_wp_security;
471
-
472
- // Workaround - the woocommerce lost password form also uses the same "lostpassword_post" hook.
473
- // We don't want to process woo forms here so ignore if this is a woo lost password $_POST
474
- if (!array_key_exists('woocommerce-lost-password-nonce', $_POST)) {
475
- $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
476
- if ( $verify_captcha === false ) {
477
- add_filter('allow_password_reset', array($this, 'add_lostpassword_captcha_error_msg'));
478
- }
479
- }
480
- }
481
-
482
- function add_lostpassword_captcha_error_msg()
483
- {
484
- //Insert an error just before the password reset process kicks in
485
- return new WP_Error('aiowps_captcha_error',__('<strong>ERROR</strong>: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
486
- }
487
-
488
- function check_404_event()
489
- {
490
- if(is_404()){
491
- //This means a 404 event has occurred - let's log it!
492
- AIOWPSecurity_Utility::event_logger('404');
493
- }
494
-
495
- }
496
-
497
- function buddy_press_signup_validate_captcha($errors)
498
- {
499
- global $bp, $aio_wp_security;
500
- //Check captcha if required
501
- $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
502
- if($verify_captcha === false) {
503
- // wrong answer was entered
504
- $bp->signup->errors['aiowps-captcha-answer'] = __('Your CAPTCHA answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall');
505
- }
506
- return;
507
- }
508
-
509
- function aiowps_validate_woo_login_or_reg_captcha( $errors, $username, $password ) {
510
- global $aio_wp_security;
511
- $locked = $aio_wp_security->user_login_obj->check_locked_user();
512
- if(!empty($locked)){
513
- $errors->add('authentication_failed', __('<strong>ERROR</strong>: Your IP address is currently locked please contact the administrator!', 'all-in-one-wp-security-and-firewall'));
514
- return $errors;
515
- }
516
-
517
- $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
518
- if($verify_captcha === false) {
519
- // wrong answer was entered
520
- $errors->add('authentication_failed', __('<strong>ERROR</strong>: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
521
- }
522
- return $errors;
523
-
524
- }
525
-
526
- /**
527
- * Process the woocommerce lost password login form post
528
- * Called by wp hook "lostpassword_post"
529
- */
530
- function process_woo_lost_password_form_post()
531
- {
532
- global $aio_wp_security;
533
-
534
- if(isset($_POST['woocommerce-lost-password-nonce'])) {
535
- $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
536
- if ( $verify_captcha === false ) {
537
- add_filter('allow_password_reset', array($this, 'add_lostpassword_captcha_error_msg'));
538
- }
539
- }
540
- }
541
-
542
- /**
543
- * Reapply htaccess rule or dismiss the related notice.
544
- *
545
- * @return void
546
- */
547
- public function reapply_htaccess_rules() {
548
- if (isset($_REQUEST['aiowps_reapply_htaccess'])) {
549
- global $aio_wp_security;
550
-
551
- if (strip_tags($_REQUEST['aiowps_reapply_htaccess']) == 1) {
552
- if (!wp_verify_nonce($_GET['_wpnonce'], 'aiowps-reapply-htaccess-yes')) {
553
- $aio_wp_security->debug_logger->log_debug("Nonce check failed on reapply .htaccess rule!", 4);
554
- // Temp
555
- die('nonce issue');
556
- return;
557
- }
558
- include_once ('wp-security-installer.php');
559
- if (AIOWPSecurity_Installer::reactivation_tasks()) {
560
- $aio_wp_security->debug_logger->log_debug("The AIOWPS .htaccess rules were successfully re-inserted!");
561
- $_SESSION['reapply_htaccess_rules_action_result'] = '1';//Success indicator.
562
- // Can't echo to the screen here. It will create an header already sent error.
563
- } else {
564
- $aio_wp_security->debug_logger->log_debug("AIOWPS encountered an error when trying to write to your .htaccess file. Please check the logs.", 5);
565
- $_SESSION['reapply_htaccess_rules_action_result'] = '2';//fail indicator.
566
- // Can't echo to the screen here. It will create an header already sent error.
567
- }
568
- } elseif (strip_tags($_REQUEST['aiowps_reapply_htaccess']) == 2) {
569
- if (!wp_verify_nonce($_GET['_wpnonce'], 'aiowps-reapply-htaccess-no')) {
570
- $aio_wp_security->debug_logger->log_debug("Nonce check failed on dismissing reapply .htaccess rule notice!", 4);
571
- return;
572
- }
573
- // Don't re-write the rules and just delete the temp config item
574
- delete_option('aiowps_temp_configs');
575
- }
576
- }
577
- }
578
-
579
- /**
580
- * Displays a notice message if the plugin was reactivated after being initially deactivated
581
- * Gives users option of re-applying the aiowps rules which were deleted from the .htaccess after deactivation.
582
- */
583
- public function reapply_htaccess_rules_notice() {
584
- if (get_option('aiowps_temp_configs') !== FALSE){
585
- $reapply_htaccess_yes_url = wp_nonce_url('admin.php?page='.AIOWPSEC_MENU_SLUG_PREFIX.'&aiowps_reapply_htaccess=1', 'aiowps-reapply-htaccess-yes');
586
- $reapply_htaccess_no_url = wp_nonce_url('admin.php?page='.AIOWPSEC_MENU_SLUG_PREFIX.'&aiowps_reapply_htaccess=2', 'aiowps-reapply-htaccess-no');
587
- echo '<div class="updated"><p>'.__('Would you like All In One WP Security & Firewall to re-insert the security rules in your .htaccess file which were cleared when you deactivated the plugin?', 'all-in-one-wp-security-and-firewall').'&nbsp;&nbsp;<a href="'.esc_url($reapply_htaccess_yes_url).'" class="button-primary">'.__('Yes', 'all-in-one-wp-security-and-firewall').'</a>&nbsp;&nbsp;<a href="'.esc_url($reapply_htaccess_no_url).'" class="button-primary">'.__('No', 'all-in-one-wp-security-and-firewall').'</a></p></div>';
588
- }
589
- }
590
-
591
- //This is a fix for cases when the password reset URL in the email was not decoding all html entities properly
592
- function decode_reset_pw_msg($message, $key, $user_login, $user_data)
593
- {
594
- global $aio_wp_security;
595
- $message = html_entity_decode($message);
596
- return $message;
597
- }
598
-
599
- function modify_registration_page_messages($errors, $redirect_to)
600
- {
601
- if( isset($_GET['checkemail']) && 'registered' == $_GET['checkemail'] ){
602
- if(is_wp_error($errors)){
603
- $errors->remove('registered');
604
- $pending_approval_msg = __('Your registration is pending approval.', 'all-in-one-wp-security-and-firewall');
605
- $pending_approval_msg = apply_filters('aiowps_pending_registration_message', $pending_approval_msg);
606
- $errors->add('registered', $pending_approval_msg, array('registered'=>'message'));
607
- }
608
- }
609
- return $errors;
610
- }
611
-
612
- /*
613
- * Re-wrote code which checks for REST API requests
614
- * Below uses the "rest_api_init" action hook to check for REST requests.
615
- * The code will block "unauthorized" requests whilst allowing genuine requests.
616
- * (P. Petreski June 2018)
617
- */
618
- function check_rest_api_requests($rest_server_object){
619
- $rest_user = wp_get_current_user();
620
- if(empty($rest_user->ID)){
621
- $error_message = apply_filters('aiowps_rest_api_error_message', __('You are not authorized to perform this action.', 'disable-wp-rest-api'));
622
- wp_die($error_message);
623
- }
624
- }
625
-
626
- /**
627
- * Enqueues the Google recaptcha api URL in the wp_head for general pages
628
- * Caters for scenarios when recaptcha used on wp comments or custom wp login form
629
- *
630
- */
631
- function add_recaptcha_script()
632
- {
633
- // Enqueue the recaptcha api url
634
-
635
- // Do NOT enqueue if this is the main woocommerce account login page because for woocommerce page we "explicitly" render the recaptcha widget
636
- $is_woo = false;
637
-
638
- // We don't want to load for woo account page because we have a special function for this
639
- if ( function_exists('is_account_page') ) {
640
- // Check if this a woocommerce account page
641
- $is_woo = is_account_page();
642
- }
643
-
644
- if ( empty( $is_woo ) ) {
645
- //only enqueue when not a woocommerce page
646
- wp_enqueue_script( 'google-recaptcha', 'https://www.google.com/recaptcha/api.js', false );
647
- }
648
- }
649
- }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_General_Init_Tasks {
7
+ public function __construct() {
8
+ // Do init time tasks
9
+ global $aio_wp_security;
10
+
11
+ if ($aio_wp_security->configs->get_value('aiowps_disable_xmlrpc_pingback_methods') == '1') {
12
+ add_filter('xmlrpc_methods', array($this, 'aiowps_disable_xmlrpc_pingback_methods'));
13
+ add_filter('wp_headers', array($this, 'aiowps_remove_x_pingback_header'));
14
+ }
15
+
16
+ add_action('permalink_structure_changed', array($this, 'refresh_firewall_rules'), 10, 2);
17
+
18
+ // Check permanent block list and block if applicable (ie, do PHP blocking)
19
+ AIOWPSecurity_Blocking::check_visitor_ip_and_perform_blocking();
20
+
21
+ if ($aio_wp_security->configs->get_value('aiowps_enable_autoblock_spam_ip') == '1') {
22
+ add_action('comment_post', array($this, 'spam_detect_process_comment_post'), 10, 2); //this hook gets fired just after comment is saved to DB
23
+ add_action('transition_comment_status', array($this, 'process_transition_comment_status'), 10, 3); //this hook gets fired when a comment's status changes
24
+ }
25
+
26
+ if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
27
+ add_action('widgets_init', array($this, 'remove_standard_wp_meta_widget'));
28
+ add_filter('retrieve_password_message', array($this, 'decode_reset_pw_msg'), 10, 4); //Fix for non decoded html entities in password reset link
29
+ }
30
+
31
+ if (current_user_can(AIOWPSEC_MANAGEMENT_PERMISSION) && $aio_wp_security->configs->get_value('aios_is_google_recaptcha_wrong_site_key')) {
32
+ add_action('all_admin_notices', array($this, 'google_recaptcha_notice'));
33
+ }
34
+
35
+ if (current_user_can(AIOWPSEC_MANAGEMENT_PERMISSION)) {
36
+ $this->reapply_htaccess_rules();
37
+ add_action('admin_notices', array($this,'reapply_htaccess_rules_notice'));
38
+ }
39
+
40
+
41
+ /**
42
+ * Send X-Frame-Options: SAMEORIGIN in HTTP header
43
+ */
44
+ if ($aio_wp_security->configs->get_value('aiowps_prevent_site_display_inside_frame') == '1') {
45
+ add_action('template_redirect', 'send_frame_options_header');
46
+ }
47
+
48
+ if ($aio_wp_security->configs->get_value('aiowps_remove_wp_generator_meta_info') == '1') {
49
+ add_filter('the_generator', array($this,'remove_wp_generator_meta_info'));
50
+ add_filter('style_loader_src', array($this,'remove_wp_css_js_meta_info'));
51
+ add_filter('script_loader_src', array($this,'remove_wp_css_js_meta_info'));
52
+ }
53
+
54
+ // For the cookie based brute force prevention feature
55
+ if ($aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention') == 1) {
56
+ $bfcf_secret_word = $aio_wp_security->configs->get_value('aiowps_brute_force_secret_word');
57
+ if (isset($_GET[$bfcf_secret_word])) {
58
+ // If URL contains secret word in query param then set cookie and then redirect to the login page
59
+ AIOWPSecurity_Utility::set_cookie_value($bfcf_secret_word, "1");
60
+ AIOWPSecurity_Utility::redirect_to_url(AIOWPSEC_WP_URL."/wp-admin");
61
+ }
62
+ }
63
+
64
+ // Stop users enumeration feature
65
+ if ($aio_wp_security->configs->get_value('aiowps_prevent_users_enumeration') == 1) {
66
+ include_once(AIO_WP_SECURITY_PATH.'/other-includes/wp-security-stop-users-enumeration.php');
67
+ }
68
+
69
+ // REST API security
70
+ if ($aio_wp_security->configs->get_value('aiowps_disallow_unauthorized_rest_requests') == 1) {
71
+ add_action('rest_api_init', array($this, 'check_rest_api_requests'), 10, 1);
72
+ }
73
+
74
+ // For user unlock request feature
75
+ if (isset($_POST['aiowps_unlock_request']) || isset($_POST['aiowps_wp_submit_unlock_request'])) {
76
+ nocache_headers();
77
+ remove_action('wp_head', 'head_addons', 7);
78
+ include_once(AIO_WP_SECURITY_PATH.'/other-includes/wp-security-unlock-request.php');
79
+ exit();
80
+ }
81
+
82
+ if (isset($_GET['aiowps_auth_key'])) {
83
+ //If URL contains unlock key in query param then process the request
84
+ $unlock_key = sanitize_text_field($_GET['aiowps_auth_key']);
85
+ AIOWPSecurity_User_Login::process_unlock_request($unlock_key);
86
+ }
87
+
88
+ // For honeypot feature
89
+ if (isset($_POST['aio_special_field'])) {
90
+ $special_field_value = sanitize_text_field($_POST['aio_special_field']);
91
+ if (!empty($special_field_value)) {
92
+ //This means a robot has submitted the login form!
93
+ //Redirect back to its localhost
94
+ AIOWPSecurity_Utility::redirect_to_url('http://127.0.0.1');
95
+ }
96
+ }
97
+
98
+ // For 404 IP lockout feature
99
+ if ($aio_wp_security->configs->get_value('aiowps_enable_404_IP_lockout') == '1') {
100
+ if (!is_user_logged_in() || !current_user_can('administrator')) {
101
+ $this->do_404_lockout_tasks();
102
+ }
103
+ }
104
+
105
+
106
+ // For login captcha feature
107
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_captcha') == '1') {
108
+ if (!is_user_logged_in()) {
109
+ add_action('login_form', array($this, 'insert_captcha_question_form'));
110
+ }
111
+ }
112
+
113
+ // For woo form captcha features
114
+ if ($aio_wp_security->configs->get_value('aiowps_enable_woo_login_captcha') == '1') {
115
+ if (!is_user_logged_in()) {
116
+ add_action('woocommerce_login_form', array($this, 'insert_captcha_question_form'));
117
+ }
118
+ if (isset($_POST['woocommerce-login-nonce'])) {
119
+ add_filter('woocommerce_process_login_errors', array($this, 'aiowps_validate_woo_login_or_reg_captcha'), 10, 3);
120
+ }
121
+ }
122
+
123
+ if ($aio_wp_security->configs->get_value('aiowps_enable_woo_register_captcha') == '1') {
124
+ if (!is_user_logged_in()) {
125
+ add_action('woocommerce_register_form', array($this, 'insert_captcha_question_form'));
126
+ }
127
+
128
+ if (isset($_POST['woocommerce-register-nonce'])) {
129
+ add_filter('woocommerce_process_registration_errors', array($this, 'aiowps_validate_woo_login_or_reg_captcha'), 10, 3);
130
+ }
131
+ }
132
+
133
+ if ($aio_wp_security->configs->get_value('aiowps_enable_woo_lostpassword_captcha') == '1') {
134
+ if (!is_user_logged_in()) {
135
+ add_action('woocommerce_lostpassword_form', array($this, 'insert_captcha_question_form'));
136
+ }
137
+ if (isset($_POST['woocommerce-lost-password-nonce'])) {
138
+ add_action('lostpassword_post', array($this, 'process_woo_lost_password_form_post'));
139
+ }
140
+ }
141
+
142
+ // For bbpress new topic form captcha
143
+ if ($aio_wp_security->configs->get_value('aiowps_enable_bbp_new_topic_captcha') == '1') {
144
+ if (!is_user_logged_in()) {
145
+ add_action('bbp_theme_before_topic_form_submit_wrapper', array($this, 'insert_captcha_question_form'));
146
+ }
147
+ }
148
+
149
+ // For custom login form captcha feature, ie, when wp_login_form() function is used to generate login form
150
+ if ($aio_wp_security->configs->get_value('aiowps_enable_custom_login_captcha') == '1') {
151
+ if (!is_user_logged_in()) {
152
+ add_filter('login_form_middle', array($this, 'insert_captcha_custom_login'), 10, 2); //For cases where the WP wp_login_form() function is used
153
+ }
154
+ }
155
+
156
+ // For honeypot feature
157
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_honeypot') == '1') {
158
+ if (!is_user_logged_in()) {
159
+ add_action('login_form', array($this, 'insert_honeypot_hidden_field'));
160
+ }
161
+ }
162
 
163
+ // For registration honeypot feature
164
+ if ($aio_wp_security->configs->get_value('aiowps_enable_registration_honeypot') == '1') {
165
+ if (!is_user_logged_in()) {
166
+ add_action('register_form', array($this, 'insert_honeypot_hidden_field'));
167
+ }
168
+ }
169
+
170
+ // For lost password captcha feature
171
+ if ($aio_wp_security->configs->get_value('aiowps_enable_lost_password_captcha') == '1') {
172
+ if (!is_user_logged_in()) {
173
+ add_action('lostpassword_form', array($this, 'insert_captcha_question_form'));
174
+ add_action('lostpassword_post', array($this, 'process_lost_password_form_post'));
175
+ }
176
+ }
177
+
178
+ // For registration manual approval feature
179
+ if ($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1') {
180
+ add_filter('wp_login_errors', array($this, 'modify_registration_page_messages'), 10, 2);
181
+ }
182
+
183
+ // For registration page captcha feature
184
+ if (AIOWPSecurity_Utility::is_multisite_install()) {
185
+ $blog_id = get_current_blog_id();
186
+ switch_to_blog($blog_id);
187
+ if ($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') {
188
+ if (!is_user_logged_in()) {
189
+ add_action('signup_extra_fields', array($this, 'insert_captcha_question_form_multi'));
190
+ //add_action('preprocess_signup_form', array($this, 'process_signup_form_multi'));
191
+ add_filter('wpmu_validate_user_signup', array($this, 'process_signup_form_multi'));
192
+ }
193
+ }
194
+ restore_current_blog();
195
+ } else {
196
+ if ($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') {
197
+ if (!is_user_logged_in()) {
198
+ add_action('register_form', array($this, 'insert_captcha_question_form'));
199
+ }
200
+ }
201
+ }
202
+
203
+ // For comment captcha feature or custom login form captcha
204
+ if (AIOWPSecurity_Utility::is_multisite_install()) {
205
+ $blog_id = get_current_blog_id();
206
+ switch_to_blog($blog_id);
207
+ if ($aio_wp_security->configs->get_value('aiowps_enable_comment_captcha') == '1') {
208
+ if (!is_user_logged_in()) {
209
+ if ($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
210
+ add_action('wp_head', array($this, 'add_recaptcha_script'));
211
+ }
212
+ add_action('comment_form_after_fields', array($this, 'insert_captcha_question_form'), 1);
213
+ add_action('comment_form_logged_in_after', array($this, 'insert_captcha_question_form'), 1);
214
+ add_filter('preprocess_comment', array($this, 'process_comment_post'));
215
+ }
216
+ }
217
+ restore_current_blog();
218
+ } else {
219
+ if ($aio_wp_security->configs->get_value('aiowps_enable_comment_captcha') == '1') {
220
+ if (!is_user_logged_in()) {
221
+ if ($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
222
+ add_action('wp_head', array($this, 'add_recaptcha_script'));
223
+ }
224
+ add_action('comment_form_after_fields', array($this, 'insert_captcha_question_form'), 1);
225
+ add_action('comment_form_logged_in_after', array($this, 'insert_captcha_question_form'), 1);
226
+ add_filter('preprocess_comment', array($this, 'process_comment_post'));
227
+ }
228
+ }
229
+ }
230
+
231
+ // For buddypress registration captcha feature
232
+ if ($aio_wp_security->configs->get_value('aiowps_enable_bp_register_captcha') == '1') {
233
+ add_action('bp_account_details_fields', array($this, 'insert_captcha_question_form'));
234
+ add_action('bp_signup_validate', array($this, 'buddy_press_signup_validate_captcha'));
235
+ }
236
+
237
+
238
+ // For feature which displays logged in users
239
+ $aio_wp_security->user_login_obj->update_users_online_transient();
240
+
241
+ // For block fake googlebots feature
242
+ if ($aio_wp_security->configs->get_value('aiowps_block_fake_googlebots') == '1') {
243
+ include_once(AIO_WP_SECURITY_PATH.'/classes/wp-security-bot-protection.php');
244
+ AIOWPSecurity_Fake_Bot_Protection::block_fake_googlebots();
245
+ }
246
+
247
+ // For 404 event logging
248
+ if ($aio_wp_security->configs->get_value('aiowps_enable_404_logging') == '1') {
249
+ add_action('wp_head', array($this, 'check_404_event'));
250
+ }
251
+
252
+ // Add more tasks that need to be executed at init time
253
+
254
+ } // end _construct()
255
+
256
+ public function aiowps_disable_xmlrpc_pingback_methods($methods) {
257
+ unset($methods['pingback.ping']);
258
+ unset($methods['pingback.extensions.getPingbacks']);
259
+ return $methods;
260
+ }
261
+
262
+ public function aiowps_remove_x_pingback_header($headers) {
263
+ unset($headers['X-Pingback']);
264
+ return $headers;
265
+ }
266
+
267
+ /**
268
+ * Refreshes the firewall rules in .htaccess file
269
+ * eg: if permalink settings changed and white list enabled
270
+ */
271
+ public function refresh_firewall_rules() {
272
+ global $aio_wp_security;
273
+ //If white list enabled need to re-adjust the .htaccess rules
274
+ if ($aio_wp_security->configs->get_value('aiowps_enable_whitelisting') == '1') {
275
+ $write_result = AIOWPSecurity_Utility_Htaccess::write_to_htaccess(); //now let's write to the .htaccess file
276
+ if (!$write_result) {
277
+ $this->show_msg_error(__('The plugin was unable to write to the .htaccess file. Please edit file manually.', 'all-in-one-wp-security-and-firewall'));
278
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_whitelist_Menu - The plugin was unable to write to the .htaccess file.");
279
+ }
280
+ }
281
+ }
282
+
283
+ public function spam_detect_process_comment_post($comment_id, $comment_approved) {
284
+ if ("spam" === $comment_approved) {
285
+ $this->block_comment_ip($comment_id);
286
+ }
287
+
288
+ }
289
+
290
+ public function process_transition_comment_status($new_status, $old_status, $comment) {
291
+ if ('spam' == $new_status) {
292
+ $this->block_comment_ip($comment->comment_ID);
293
+ }
294
+
295
+ }
296
+
297
+ /**
298
+ * Will check auto-spam blocking settings and will add IP to blocked table accordingly
299
+ *
300
+ * @param int $comment_id
301
+ */
302
+ public function block_comment_ip($comment_id) {
303
+ global $aio_wp_security, $wpdb;
304
+ $comment_obj = get_comment($comment_id);
305
+ $comment_ip = $comment_obj->comment_author_IP;
306
+ //Get number of spam comments from this IP
307
+ $sql = $wpdb->prepare("SELECT * FROM $wpdb->comments
308
+ WHERE comment_approved = 'spam'
309
+ AND comment_author_IP = %s
310
+ ", $comment_ip);
311
+ $comment_data = $wpdb->get_results($sql, ARRAY_A);
312
+ $spam_count = count($comment_data);
313
+ $min_comment_before_block = $aio_wp_security->configs->get_value('aiowps_spam_ip_min_comments_block');
314
+ if (!empty($min_comment_before_block) && $spam_count >= ($min_comment_before_block - 1)) {
315
+ AIOWPSecurity_Blocking::add_ip_to_block_list($comment_ip, 'spam');
316
+ }
317
+ }
318
+
319
+ public function remove_standard_wp_meta_widget() {
320
+ unregister_widget('WP_Widget_Meta');
321
+ }
322
+
323
+ public function remove_wp_generator_meta_info() {
324
+ return '';
325
+ }
326
+
327
+ public function remove_wp_css_js_meta_info($src) {
328
+ global $wp_version;
329
+ static $wp_version_hash = null; // Cache hash value for all function calls
330
+
331
+ // Replace only version number of assets with WP version
332
+ if (strpos($src, 'ver=' . $wp_version) !== false) {
333
+ if (!$wp_version_hash) {
334
+ $wp_version_hash = wp_hash($wp_version);
335
+ }
336
+ // Replace version number with computed hash
337
+ $src = add_query_arg('ver', $wp_version_hash, $src);
338
+ }
339
+ return $src;
340
+ }
341
+
342
+ public function do_404_lockout_tasks() {
343
+ global $aio_wp_security;
344
+ $redirect_url = $aio_wp_security->configs->get_value('aiowps_404_lock_redirect_url'); //This is the redirect URL for blocked users
345
+
346
+ $visitor_ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
347
+
348
+ $is_locked = AIOWPSecurity_Utility::check_locked_ip($visitor_ip);
349
+
350
+ if ($is_locked) {
351
+ //redirect blocked user to configured URL
352
+ AIOWPSecurity_Utility::redirect_to_url($redirect_url);
353
+ } else {
354
+ //allow through
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Renders captcha on form produced by the wp_login_form() function, ie, custom wp login form
360
+ *
361
+ * @global type $aio_wp_security
362
+ * @param type $cust_html_code
363
+ * @return string
364
+ */
365
+ public function insert_captcha_custom_login($cust_html_code) {
366
+ global $aio_wp_security;
367
+ if ($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
368
+ $site_key = esc_html($aio_wp_security->configs->get_value('aiowps_recaptcha_site_key'));
369
+ $cap_form = '<div class="g-recaptcha-wrap" style="padding:10px 0 10px 0"><div class="g-recaptcha" data-sitekey="'.$site_key.'"></div></div>';
370
+ $cust_html_code .= $cap_form;
371
+ return $cust_html_code;
372
+ } else {
373
+ $cap_form = '<p class="aiowps-captcha"><label>'.__('Please enter an answer in digits:', 'all-in-one-wp-security-and-firewall').'</label>';
374
+ $cap_form .= '<div class="aiowps-captcha-equation"><strong>';
375
+ $maths_question_output = $aio_wp_security->captcha_obj->generate_maths_question();
376
+ $cap_form .= $maths_question_output . '</strong></div></p>';
377
+
378
+ $cust_html_code .= $cap_form;
379
+ return $cust_html_code;
380
+ }
381
+ }
382
+
383
+ public function insert_captcha_question_form_multi() {
384
+ global $aio_wp_security;
385
+ $aio_wp_security->captcha_obj->display_captcha_form();
386
+ }
387
+
388
+ public function process_signup_form_multi($result) {
389
+ global $aio_wp_security;
390
+ //Check if captcha enabled
391
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
392
+ if (false === $verify_captcha) {
393
+ // wrong answer was entered
394
+ $result['errors']->add('generic', __('<strong>ERROR</strong>: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
395
+ }
396
+ return $result;
397
+ }
398
+
399
+ public function insert_captcha_question_form() {
400
+ global $aio_wp_security;
401
+
402
+ if ($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
403
+
404
+ // Woocommerce "my account" page needs special consideration, ie,
405
+ // need to display two Google reCaptcha forms on same page (for login and register forms)
406
+ // For this case we use the "explicit" recaptcha display
407
+ $calling_hook = current_filter();
408
+ $site_key = esc_html($aio_wp_security->configs->get_value('aiowps_recaptcha_site_key'));
409
+ if ('woocommerce_login_form' == $calling_hook || 'woocommerce_lostpassword_form' == $calling_hook) {
410
+ echo '<div class="g-recaptcha-wrap" style="padding:10px 0 10px 0"><div id="woo_recaptcha_1" class="g-recaptcha" data-sitekey="'.$site_key.'"></div></div>';
411
+ return;
412
+ }
413
+
414
+ if ('woocommerce_register_form' == $calling_hook) {
415
+ echo '<div class="g-recaptcha-wrap" style="padding:10px 0 10px 0"><div id="woo_recaptcha_2" class="g-recaptcha" data-sitekey="'.$site_key.'"></div></div>';
416
+ return;
417
+ }
418
+
419
+ // For all other forms simply display google recaptcha as per normal
420
+ $aio_wp_security->captcha_obj->display_recaptcha_form();
421
+ } else {
422
+ // display plain maths captcha form
423
+ $aio_wp_security->captcha_obj->display_captcha_form();
424
+ }
425
+
426
+ }
427
+
428
+ public function insert_honeypot_hidden_field() {
429
+ $honey_input = '<p style="display: none;"><label>'.__('Enter something special:', 'all-in-one-wp-security-and-firewall').'</label>';
430
+ $honey_input .= '<input name="aio_special_field" type="text" id="aio_special_field" class="aio_special_field" value="" /></p>';
431
+ echo $honey_input;
432
+ }
433
+
434
+ public function process_comment_post($comment) {
435
+ global $aio_wp_security;
436
+ if (is_user_logged_in()) {
437
+ return $comment;
438
+ }
439
+
440
+ //Don't process captcha for comment replies inside admin menu
441
+ if (isset($_REQUEST['action']) && 'replyto-comment' == $_REQUEST['action'] && (check_ajax_referer('replyto-comment', '_ajax_nonce', false) || check_ajax_referer('replyto-comment', '_ajax_nonce-replyto-comment', false))) {
442
+ return $comment;
443
+ }
444
+
445
+ //Don't do captcha for pingback/trackback
446
+ if ('' != $comment['comment_type'] && 'comment' != $comment['comment_type'] && 'review' != $comment['comment_type']) {
447
+ return $comment;
448
+ }
449
+
450
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
451
+ if (false === $verify_captcha) {
452
+ //Wrong answer
453
+ wp_die(__('Error: You entered an incorrect CAPTCHA answer. Please go back and try again.', 'all-in-one-wp-security-and-firewall'));
454
+ } else {
455
+ return($comment);
456
+ }
457
+ }
458
+
459
+ /**
460
+ * Process the main Wordpress account lost password login form post
461
+ * Called by wp hook "lostpassword_post"
462
+ */
463
+ public function process_lost_password_form_post() {
464
+ global $aio_wp_security;
465
+
466
+ // Workaround - the woocommerce lost password form also uses the same "lostpassword_post" hook.
467
+ // We don't want to process woo forms here so ignore if this is a woo lost password $_POST
468
+ if (!array_key_exists('woocommerce-lost-password-nonce', $_POST)) {
469
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
470
+ if (false === $verify_captcha) {
471
+ add_filter('allow_password_reset', array($this, 'add_lostpassword_captcha_error_msg'));
472
+ }
473
+ }
474
+ }
475
+
476
+ public function add_lostpassword_captcha_error_msg() {
477
+ //Insert an error just before the password reset process kicks in
478
+ return new WP_Error('aiowps_captcha_error', __('<strong>ERROR</strong>: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
479
+ }
480
+
481
+ public function check_404_event() {
482
+ if (is_404()) {
483
+ //This means a 404 event has occurred - let's log it!
484
+ AIOWPSecurity_Utility::event_logger('404');
485
+ }
486
+
487
+ }
488
+
489
+ public function buddy_press_signup_validate_captcha() {
490
+ global $bp, $aio_wp_security;
491
+ //Check captcha if required
492
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
493
+ if (false === $verify_captcha) {
494
+ // wrong answer was entered
495
+ $bp->signup->errors['aiowps-captcha-answer'] = __('Your CAPTCHA answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall');
496
+ }
497
+ return;
498
+ }
499
+
500
+ public function aiowps_validate_woo_login_or_reg_captcha($errors) {
501
+ global $aio_wp_security;
502
+ $locked = $aio_wp_security->user_login_obj->check_locked_user();
503
+ if (!empty($locked)) {
504
+ $errors->add('authentication_failed', __('<strong>ERROR</strong>: Your IP address is currently locked please contact the administrator!', 'all-in-one-wp-security-and-firewall'));
505
+ return $errors;
506
+ }
507
+
508
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
509
+ if (false === $verify_captcha) {
510
+ // wrong answer was entered
511
+ $errors->add('authentication_failed', __('<strong>ERROR</strong>: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
512
+ }
513
+ return $errors;
514
+
515
+ }
516
+
517
+ /**
518
+ * Process the woocommerce lost password login form post
519
+ * Called by wp hook "lostpassword_post"
520
+ */
521
+ public function process_woo_lost_password_form_post() {
522
+ global $aio_wp_security;
523
+
524
+ if (isset($_POST['woocommerce-lost-password-nonce'])) {
525
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
526
+ if (false === $verify_captcha) {
527
+ add_filter('allow_password_reset', array($this, 'add_lostpassword_captcha_error_msg'));
528
+ }
529
+ }
530
+ }
531
+
532
+ /**
533
+ * Reapply htaccess rule or dismiss the related notice.
534
+ *
535
+ * @return void
536
+ */
537
+ public function reapply_htaccess_rules() {
538
+ if (isset($_REQUEST['aiowps_reapply_htaccess'])) {
539
+ global $aio_wp_security;
540
+
541
+ if (strip_tags($_REQUEST['aiowps_reapply_htaccess']) == 1) {
542
+ if (!wp_verify_nonce($_GET['_wpnonce'], 'aiowps-reapply-htaccess-yes')) {
543
+ $aio_wp_security->debug_logger->log_debug("Nonce check failed on reapply .htaccess rule!", 4);
544
+ // Temp
545
+ die('nonce issue');
546
+ return;
547
+ }
548
+ include_once('wp-security-installer.php');
549
+ if (AIOWPSecurity_Installer::reactivation_tasks()) {
550
+ $aio_wp_security->debug_logger->log_debug("The AIOWPS .htaccess rules were successfully re-inserted!");
551
+ $_SESSION['reapply_htaccess_rules_action_result'] = '1';//Success indicator.
552
+ // Can't echo to the screen here. It will create an header already sent error.
553
+ } else {
554
+ $aio_wp_security->debug_logger->log_debug("AIOWPS encountered an error when trying to write to your .htaccess file. Please check the logs.", 5);
555
+ $_SESSION['reapply_htaccess_rules_action_result'] = '2';//fail indicator.
556
+ // Can't echo to the screen here. It will create an header already sent error.
557
+ }
558
+ } elseif (strip_tags($_REQUEST['aiowps_reapply_htaccess']) == 2) {
559
+ if (!wp_verify_nonce($_GET['_wpnonce'], 'aiowps-reapply-htaccess-no')) {
560
+ $aio_wp_security->debug_logger->log_debug("Nonce check failed on dismissing reapply .htaccess rule notice!", 4);
561
+ return;
562
+ }
563
+ // Don't re-write the rules and just delete the temp config item
564
+ delete_option('aiowps_temp_configs');
565
+ }
566
+ }
567
+ }
568
+
569
+ /**
570
+ * Displays a notice message if the entered recatcha site key is wrong.
571
+ */
572
+ public function google_recaptcha_notice() {
573
+ global $aio_wp_security;
574
+
575
+ if (($aio_wp_security->is_admin_dashboard_page() || $aio_wp_security->is_plugin_admin_page() || $aio_wp_security->is_aiowps_admin_page()) && !$aio_wp_security->is_aiowps_google_recaptcha_tab_page()) {
576
+ $recaptcha_tab_url = 'admin.php?page='.AIOWPSEC_BRUTE_FORCE_MENU_SLUG.'&tab=tab3';
577
+ echo '<div class="notice notice-warning"><p>';
578
+ /* translators: %s: Admin Dashboard > WP Security > Brute Force > Login Captcha Tab Link */
579
+ printf(__('Your Google reCAPTCHA site key is wrong. Please fill the correct reCAPTCHA keys %s to use the Google reCAPTCHA feature.', 'all-in-one-wp-security-and-firewall'), '<a href="'.esc_url($recaptcha_tab_url).'">'.__('here', 'all-in-one-wp-security-and-firewall').'</a>');
580
+ echo '</p></div>';
581
+ }
582
+ }
583
+
584
+ /**
585
+ * Displays a notice message if the plugin was reactivated after being initially deactivated
586
+ * Gives users option of re-applying the aiowps rules which were deleted from the .htaccess after deactivation.
587
+ */
588
+ public function reapply_htaccess_rules_notice() {
589
+ if (get_option('aiowps_temp_configs') !== false) {
590
+ $reapply_htaccess_yes_url = wp_nonce_url('admin.php?page='.AIOWPSEC_MENU_SLUG_PREFIX.'&aiowps_reapply_htaccess=1', 'aiowps-reapply-htaccess-yes');
591
+ $reapply_htaccess_no_url = wp_nonce_url('admin.php?page='.AIOWPSEC_MENU_SLUG_PREFIX.'&aiowps_reapply_htaccess=2', 'aiowps-reapply-htaccess-no');
592
+ echo '<div class="updated"><p>'.__('Would you like All In One WP Security & Firewall to re-insert the security rules in your .htaccess file which were cleared when you deactivated the plugin?', 'all-in-one-wp-security-and-firewall').'&nbsp;&nbsp;<a href="'.esc_url($reapply_htaccess_yes_url).'" class="button-primary">'.__('Yes', 'all-in-one-wp-security-and-firewall').'</a>&nbsp;&nbsp;<a href="'.esc_url($reapply_htaccess_no_url).'" class="button-primary">'.__('No', 'all-in-one-wp-security-and-firewall').'</a></p></div>';
593
+ }
594
+ }
595
+
596
+ /**
597
+ * This is a fix for cases when the password reset URL in the email was not decoding all html entities properly
598
+ *
599
+ * @param string $message
600
+ * @return string
601
+ */
602
+ public function decode_reset_pw_msg($message) {
603
+ $message = html_entity_decode($message);
604
+ return $message;
605
+ }
606
+
607
+ public function modify_registration_page_messages($errors) {
608
+ if (isset($_GET['checkemail']) && 'registered' == $_GET['checkemail']) {
609
+ if (is_wp_error($errors)) {
610
+ $errors->remove('registered');
611
+ $pending_approval_msg = __('Your registration is pending approval.', 'all-in-one-wp-security-and-firewall');
612
+ $pending_approval_msg = apply_filters('aiowps_pending_registration_message', $pending_approval_msg);
613
+ $errors->add('registered', $pending_approval_msg, array('registered' => 'message'));
614
+ }
615
+ }
616
+ return $errors;
617
+ }
618
+
619
+ /**
620
+ * Re-wrote code which checks for REST API requests
621
+ * Below uses the "rest_api_init" action hook to check for REST requests.
622
+ * The code will block "unauthorized" requests whilst allowing genuine requests.
623
+ * (P. Petreski June 2018)
624
+ *
625
+ * @return void
626
+ */
627
+ public function check_rest_api_requests() {
628
+ $rest_user = wp_get_current_user();
629
+ if (empty($rest_user->ID)) {
630
+ $error_message = apply_filters('aiowps_rest_api_error_message', __('You are not authorized to perform this action.', 'disable-wp-rest-api'));
631
+ wp_die($error_message);
632
+ }
633
+ }
634
+
635
+ /**
636
+ * Enqueues the Google recaptcha api URL in the wp_head for general pages
637
+ * Caters for scenarios when recaptcha used on wp comments or custom wp login form
638
+ */
639
+ public function add_recaptcha_script() {
640
+ // Enqueue the recaptcha api url
641
+
642
+ // Do NOT enqueue if this is the main woocommerce account login page because for woocommerce page we "explicitly" render the recaptcha widget
643
+ $is_woo = false;
644
+
645
+ // We don't want to load for woo account page because we have a special function for this
646
+ if (function_exists('is_account_page')) {
647
+ // Check if this a woocommerce account page
648
+ $is_woo = is_account_page();
649
+ }
650
+
651
+ if (empty($is_woo)) {
652
+ //only enqueue when not a woocommerce page
653
+ wp_enqueue_script('google-recaptcha', 'https://www.google.com/recaptcha/api.js', false);
654
+ }
655
+ }
656
+ }
classes/wp-security-installer.php CHANGED
@@ -1,242 +1,242 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- include_once(dirname(__FILE__) . '/wp-security-configure-settings.php');//Allows activating via wp-cli
7
-
8
- class AIOWPSecurity_Installer
9
- {
10
- static function run_installer($networkwide='')
11
- {
12
- global $wpdb;
13
- if (function_exists('is_multisite') && is_multisite() && $networkwide) {
14
- // check if it is a network activation - if so, run the activation function for each blog id
15
- $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
16
- foreach ($blogids as $blog_id) {
17
- switch_to_blog($blog_id);
18
- AIOWPSecurity_Installer::create_db_tables();
19
- AIOWPSecurity_Configure_Settings::add_option_values();
20
- restore_current_blog();
21
- }
22
- AIOWPSecurity_Installer::create_db_backup_dir(); //Create a backup dir in the WP uploads directory
23
- } else {
24
- AIOWPSecurity_Installer::create_db_tables();
25
- AIOWPSecurity_Configure_Settings::add_option_values();
26
- AIOWPSecurity_Installer::create_db_backup_dir(); //Create a backup dir in the WP uploads directory
27
- }
28
- }
29
-
30
- static function create_db_tables()
31
- {
32
- global $wpdb;
33
- require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
34
-
35
- if (function_exists('is_multisite') && is_multisite()) {
36
- /*
37
- * FIX for multisite table creation case:
38
- * Although each table name is defined in a constant inside the wp-security-core.php,
39
- * we need to do this step for multisite case because we need to refresh the $wpdb->prefix value
40
- * otherwise it will contain the original blog id and not the current id we need.
41
- *
42
- */
43
- $lockdown_tbl_name = $wpdb->prefix.'aiowps_login_lockdown';
44
- $failed_login_tbl_name = $wpdb->prefix.'aiowps_failed_logins';
45
- $user_login_activity_tbl_name = $wpdb->prefix.'aiowps_login_activity';
46
- $aiowps_global_meta_tbl_name = $wpdb->prefix.'aiowps_global_meta';
47
- $aiowps_event_tbl_name = $wpdb->prefix.'aiowps_events';
48
- $perm_block_tbl_name = $wpdb->prefix.'aiowps_permanent_block';
49
-
50
- } else {
51
- $lockdown_tbl_name = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
52
- $failed_login_tbl_name = AIOWPSEC_TBL_FAILED_LOGINS;
53
- $user_login_activity_tbl_name = AIOWPSEC_TBL_USER_LOGIN_ACTIVITY;
54
- $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
55
- $aiowps_event_tbl_name = AIOWPSEC_TBL_EVENTS;
56
- $perm_block_tbl_name = AIOWPSEC_TBL_PERM_BLOCK;
57
- }
58
-
59
- $charset_collate = '';
60
- if (!empty($wpdb->charset)) {
61
- $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
62
- } else {
63
- $charset_collate = "DEFAULT CHARSET=utf8";
64
- }
65
- if (!empty($wpdb->collate)) {
66
- $charset_collate .= " COLLATE $wpdb->collate";
67
- }
68
-
69
- $ld_tbl_sql = "CREATE TABLE " . $lockdown_tbl_name . " (
70
- id bigint(20) NOT NULL AUTO_INCREMENT,
71
- user_id bigint(20) NOT NULL,
72
- user_login VARCHAR(150) NOT NULL,
73
- lockdown_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
74
- release_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
75
- failed_login_ip varchar(100) NOT NULL DEFAULT '',
76
- lock_reason varchar(128) NOT NULL DEFAULT '',
77
- unlock_key varchar(128) NOT NULL DEFAULT '',
78
- PRIMARY KEY (id)
79
- )" . $charset_collate . ";";
80
- dbDelta($ld_tbl_sql);
81
-
82
- $fl_tbl_sql = "CREATE TABLE " . $failed_login_tbl_name . " (
83
- id bigint(20) NOT NULL AUTO_INCREMENT,
84
- user_id bigint(20) NOT NULL,
85
- user_login VARCHAR(150) NOT NULL,
86
- failed_login_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
87
- login_attempt_ip varchar(100) NOT NULL DEFAULT '',
88
- PRIMARY KEY (id)
89
- )" . $charset_collate . ";";
90
- dbDelta($fl_tbl_sql);
91
-
92
- $ula_tbl_sql = "CREATE TABLE " . $user_login_activity_tbl_name . " (
93
- id bigint(20) NOT NULL AUTO_INCREMENT,
94
- user_id bigint(20) NOT NULL,
95
- user_login VARCHAR(150) NOT NULL,
96
- login_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
97
- logout_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
98
- login_ip varchar(100) NOT NULL DEFAULT '',
99
- login_country varchar(150) NOT NULL DEFAULT '',
100
- browser_type varchar(150) NOT NULL DEFAULT '',
101
- PRIMARY KEY (id)
102
- )" . $charset_collate . ";";
103
- dbDelta($ula_tbl_sql);
104
-
105
- $gm_tbl_sql = "CREATE TABLE " . $aiowps_global_meta_tbl_name . " (
106
- meta_id bigint(20) NOT NULL auto_increment,
107
- date_time datetime NOT NULL default '1000-10-10 10:00:00',
108
- meta_key1 varchar(255) NOT NULL,
109
- meta_key2 varchar(255) NOT NULL,
110
- meta_key3 varchar(255) NOT NULL,
111
- meta_key4 varchar(255) NOT NULL,
112
- meta_key5 varchar(255) NOT NULL,
113
- meta_value1 varchar(255) NOT NULL,
114
- meta_value2 text NOT NULL,
115
- meta_value3 text NOT NULL,
116
- meta_value4 longtext NOT NULL,
117
- meta_value5 longtext NOT NULL,
118
- PRIMARY KEY (meta_id)
119
- )" . $charset_collate . ";";
120
- dbDelta($gm_tbl_sql);
121
-
122
- $evt_tbl_sql = "CREATE TABLE " . $aiowps_event_tbl_name . " (
123
- id bigint(20) NOT NULL AUTO_INCREMENT,
124
- event_type VARCHAR(150) NOT NULL DEFAULT '',
125
- username VARCHAR(150),
126
- user_id bigint(20),
127
- event_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
128
- ip_or_host varchar(100),
129
- referer_info varchar(255),
130
- url varchar(255),
131
- country_code varchar(50),
132
- event_data longtext,
133
- PRIMARY KEY (id)
134
- )" . $charset_collate . ";";
135
- dbDelta($evt_tbl_sql);
136
-
137
- $pb_tbl_sql = "CREATE TABLE " . $perm_block_tbl_name . " (
138
- id bigint(20) NOT NULL AUTO_INCREMENT,
139
- blocked_ip varchar(100) NOT NULL DEFAULT '',
140
- block_reason varchar(128) NOT NULL DEFAULT '',
141
- country_origin varchar(50) NOT NULL DEFAULT '',
142
- blocked_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
143
- unblock tinyint(1) NOT NULL DEFAULT '0',
144
- PRIMARY KEY (id)
145
- )" . $charset_collate . ";";
146
- dbDelta($pb_tbl_sql);
147
-
148
- update_option("aiowpsec_db_version", AIO_WP_SECURITY_DB_VERSION);
149
- }
150
-
151
- static function create_db_backup_dir()
152
- {
153
- global $aio_wp_security;
154
- //Create our folder in the "wp-content" directory
155
- $aiowps_dir = WP_CONTENT_DIR . '/' . AIO_WP_SECURITY_BACKUPS_DIR_NAME;
156
- if (!is_dir($aiowps_dir)) {
157
- mkdir($aiowps_dir, 0755, true);
158
- //Let's also create an empty index.html file in this folder
159
- $index_file = $aiowps_dir . '/index.html';
160
- $handle = fopen($index_file, 'w'); //or die('Cannot open file: '.$index_file);
161
- fclose($handle);
162
- }
163
- $server_type = AIOWPSecurity_Utility::get_server_type();
164
- //Only create .htaccess if server is the right type
165
- if ($server_type == 'apache' || $server_type == 'litespeed') {
166
- $file = $aiowps_dir . '/.htaccess';
167
- if (!file_exists($file)) {
168
- //Create an .htacces file
169
- //Write some rules which will only allow people originating from wp admin page to download the DB backup
170
- $rules = '';
171
- $rules .= 'order deny,allow' . PHP_EOL;
172
- $rules .= 'deny from all' . PHP_EOL;
173
- $write_result = file_put_contents($file, $rules);
174
- if ($write_result === false) {
175
- $aio_wp_security->debug_logger->log_debug("Creation of .htaccess file in " . AIO_WP_SECURITY_BACKUPS_DIR_NAME . " directory failed!", 4);
176
- }
177
- }
178
- }
179
- }
180
-
181
- static function reactivation_tasks()
182
- {
183
- global $aio_wp_security;
184
- $temp_cfgs = get_option('aiowps_temp_configs');
185
- if ($temp_cfgs !== FALSE) {
186
- //Case where previously installed plugin was reactivated
187
- //Let's copy the original configs back to the options table
188
- $updated = update_option('aio_wp_security_configs', $temp_cfgs);
189
- if (!$updated) {
190
- $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Installer::reactivation_tasks() - Update of option settings failed upon plugin activation!", 4);
191
- }
192
- $aio_wp_security->configs->configs = $temp_cfgs; //copy the original configs to memory
193
- //Now let's write any rules to the .htaccess file if necessary
194
- $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
195
-
196
- if ( !$res ) {
197
- $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Installer::reactivation_tasks() - Could not write to the .htaccess file. Please check the file permissions.", 4);
198
- return false;
199
- }
200
- delete_option('aiowps_temp_configs');
201
- return true;
202
- } else {
203
- $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Deactivation::run_deactivation_tasks() - Original config settings not found!", 4);
204
- return false;
205
- }
206
- }
207
-
208
- /**
209
- * Setup aiowps cron tasks
210
- * Handles both single and multi-site (NW activation) cases
211
- * @global type $wpdb
212
- * @param type $networkwide
213
- */
214
- static function set_cron_tasks_upon_activation($networkwide) {
215
- global $wpdb;
216
- if (AIOWPSecurity_Utility::is_multisite_install() && $networkwide) {
217
- // check if it is a network activation
218
- $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
219
- foreach ($blogids as $blog_id) {
220
- switch_to_blog($blog_id);
221
- AIOWPSecurity_Installer::schedule_cron_events();
222
- do_action('aiowps_activation_complete');
223
- restore_current_blog();
224
- }
225
- } else {
226
- AIOWPSecurity_Installer::schedule_cron_events();
227
- do_action('aiowps_activation_complete');
228
- }
229
- }
230
-
231
- /**
232
- * Helper function for scheduling aiowps cron events
233
- */
234
- static function schedule_cron_events() {
235
- if ( !wp_next_scheduled('aiowps_hourly_cron_event') ) {
236
- wp_schedule_event(time(), 'hourly', 'aiowps_hourly_cron_event'); //schedule an hourly cron event
237
- }
238
- if ( !wp_next_scheduled('aiowps_daily_cron_event') ) {
239
- wp_schedule_event(time(), 'daily', 'aiowps_daily_cron_event'); //schedule an daily cron event
240
- }
241
- }
242
  }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ //Allows activating via wp-cli
7
+ require_once(dirname(__FILE__) . '/wp-security-configure-settings.php');
8
+
9
+ class AIOWPSecurity_Installer {
10
+ public static function run_installer($networkwide = '') {
11
+ global $wpdb;
12
+ if (function_exists('is_multisite') && is_multisite() && $networkwide) {
13
+ // check if it is a network activation - if so, run the activation function for each blog id
14
+ $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
15
+ foreach ($blogids as $blog_id) {
16
+ switch_to_blog($blog_id);
17
+ AIOWPSecurity_Installer::create_db_tables();
18
+ AIOWPSecurity_Configure_Settings::add_option_values();
19
+ restore_current_blog();
20
+ }
21
+ AIOWPSecurity_Installer::create_db_backup_dir(); //Create a backup dir in the WP uploads directory
22
+ } else {
23
+ AIOWPSecurity_Installer::create_db_tables();
24
+ AIOWPSecurity_Configure_Settings::add_option_values();
25
+ AIOWPSecurity_Installer::create_db_backup_dir(); //Create a backup dir in the WP uploads directory
26
+ }
27
+ }
28
+
29
+ public static function create_db_tables() {
30
+ global $wpdb;
31
+
32
+ if (!function_exists('dbDelta')) {
33
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
34
+ }
35
+
36
+ if (function_exists('is_multisite') && is_multisite()) {
37
+ /*
38
+ * FIX for multisite table creation case:
39
+ * Although each table name is defined in a constant inside the wp-security-core.php,
40
+ * we need to do this step for multisite case because we need to refresh the $wpdb->prefix value
41
+ * otherwise it will contain the original blog id and not the current id we need.
42
+ *
43
+ */
44
+ $lockdown_tbl_name = $wpdb->prefix.'aiowps_login_lockdown';
45
+ $failed_login_tbl_name = $wpdb->prefix.'aiowps_failed_logins';
46
+ $user_login_activity_tbl_name = $wpdb->prefix.'aiowps_login_activity';
47
+ $aiowps_global_meta_tbl_name = $wpdb->prefix.'aiowps_global_meta';
48
+ $aiowps_event_tbl_name = $wpdb->prefix.'aiowps_events';
49
+ $perm_block_tbl_name = $wpdb->prefix.'aiowps_permanent_block';
50
+
51
+ } else {
52
+ $lockdown_tbl_name = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
53
+ $failed_login_tbl_name = AIOWPSEC_TBL_FAILED_LOGINS;
54
+ $user_login_activity_tbl_name = AIOWPSEC_TBL_USER_LOGIN_ACTIVITY;
55
+ $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
56
+ $aiowps_event_tbl_name = AIOWPSEC_TBL_EVENTS;
57
+ $perm_block_tbl_name = AIOWPSEC_TBL_PERM_BLOCK;
58
+ }
59
+
60
+ $charset_collate = '';
61
+ if (!empty($wpdb->charset)) {
62
+ $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
63
+ } else {
64
+ $charset_collate = "DEFAULT CHARSET=utf8";
65
+ }
66
+ if (!empty($wpdb->collate)) {
67
+ $charset_collate .= " COLLATE $wpdb->collate";
68
+ }
69
+
70
+ $ld_tbl_sql = "CREATE TABLE " . $lockdown_tbl_name . " (
71
+ id bigint(20) NOT NULL AUTO_INCREMENT,
72
+ user_id bigint(20) NOT NULL,
73
+ user_login VARCHAR(150) NOT NULL,
74
+ lockdown_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
75
+ release_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
76
+ failed_login_ip varchar(100) NOT NULL DEFAULT '',
77
+ lock_reason varchar(128) NOT NULL DEFAULT '',
78
+ unlock_key varchar(128) NOT NULL DEFAULT '',
79
+ PRIMARY KEY (id)
80
+ )" . $charset_collate . ";";
81
+ dbDelta($ld_tbl_sql);
82
+
83
+ $fl_tbl_sql = "CREATE TABLE " . $failed_login_tbl_name . " (
84
+ id bigint(20) NOT NULL AUTO_INCREMENT,
85
+ user_id bigint(20) NOT NULL,
86
+ user_login VARCHAR(150) NOT NULL,
87
+ failed_login_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
88
+ login_attempt_ip varchar(100) NOT NULL DEFAULT '',
89
+ PRIMARY KEY (id)
90
+ )" . $charset_collate . ";";
91
+ dbDelta($fl_tbl_sql);
92
+
93
+ $ula_tbl_sql = "CREATE TABLE " . $user_login_activity_tbl_name . " (
94
+ id bigint(20) NOT NULL AUTO_INCREMENT,
95
+ user_id bigint(20) NOT NULL,
96
+ user_login VARCHAR(150) NOT NULL,
97
+ login_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
98
+ logout_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
99
+ login_ip varchar(100) NOT NULL DEFAULT '',
100
+ login_country varchar(150) NOT NULL DEFAULT '',
101
+ browser_type varchar(150) NOT NULL DEFAULT '',
102
+ PRIMARY KEY (id)
103
+ )" . $charset_collate . ";";
104
+ dbDelta($ula_tbl_sql);
105
+
106
+ $gm_tbl_sql = "CREATE TABLE " . $aiowps_global_meta_tbl_name . " (
107
+ meta_id bigint(20) NOT NULL auto_increment,
108
+ date_time datetime NOT NULL default '1000-10-10 10:00:00',
109
+ meta_key1 varchar(255) NOT NULL,
110
+ meta_key2 varchar(255) NOT NULL,
111
+ meta_key3 varchar(255) NOT NULL,
112
+ meta_key4 varchar(255) NOT NULL,
113
+ meta_key5 varchar(255) NOT NULL,
114
+ meta_value1 varchar(255) NOT NULL,
115
+ meta_value2 text NOT NULL,
116
+ meta_value3 text NOT NULL,
117
+ meta_value4 longtext NOT NULL,
118
+ meta_value5 longtext NOT NULL,
119
+ PRIMARY KEY (meta_id)
120
+ )" . $charset_collate . ";";
121
+ dbDelta($gm_tbl_sql);
122
+
123
+ $evt_tbl_sql = "CREATE TABLE " . $aiowps_event_tbl_name . " (
124
+ id bigint(20) NOT NULL AUTO_INCREMENT,
125
+ event_type VARCHAR(150) NOT NULL DEFAULT '',
126
+ username VARCHAR(150),
127
+ user_id bigint(20),
128
+ event_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
129
+ ip_or_host varchar(100),
130
+ referer_info varchar(255),
131
+ url varchar(255),
132
+ country_code varchar(50),
133
+ event_data longtext,
134
+ PRIMARY KEY (id)
135
+ )" . $charset_collate . ";";
136
+ dbDelta($evt_tbl_sql);
137
+
138
+ $pb_tbl_sql = "CREATE TABLE " . $perm_block_tbl_name . " (
139
+ id bigint(20) NOT NULL AUTO_INCREMENT,
140
+ blocked_ip varchar(100) NOT NULL DEFAULT '',
141
+ block_reason varchar(128) NOT NULL DEFAULT '',
142
+ country_origin varchar(50) NOT NULL DEFAULT '',
143
+ blocked_date datetime NOT NULL DEFAULT '1000-10-10 10:00:00',
144
+ unblock tinyint(1) NOT NULL DEFAULT '0',
145
+ PRIMARY KEY (id)
146
+ )" . $charset_collate . ";";
147
+ dbDelta($pb_tbl_sql);
148
+
149
+ update_option("aiowpsec_db_version", AIO_WP_SECURITY_DB_VERSION);
150
+ }
151
+
152
+ public static function create_db_backup_dir() {
153
+ global $aio_wp_security;
154
+ //Create our folder in the "wp-content" directory
155
+ $aiowps_dir = WP_CONTENT_DIR . '/' . AIO_WP_SECURITY_BACKUPS_DIR_NAME;
156
+ if (!is_dir($aiowps_dir)) {
157
+ mkdir($aiowps_dir, 0755, true);
158
+ //Let's also create an empty index.html file in this folder
159
+ $index_file = $aiowps_dir . '/index.html';
160
+ $handle = fopen($index_file, 'w'); //or die('Cannot open file: '.$index_file);
161
+ fclose($handle);
162
+ }
163
+ $server_type = AIOWPSecurity_Utility::get_server_type();
164
+ //Only create .htaccess if server is the right type
165
+ if ('apache' == $server_type || 'litespeed' == $server_type) {
166
+ $file = $aiowps_dir . '/.htaccess';
167
+ if (!file_exists($file)) {
168
+ //Create an .htacces file
169
+ //Write some rules which will only allow people originating from wp admin page to download the DB backup
170
+ $rules = '';
171
+ $rules .= 'order deny,allow' . PHP_EOL;
172
+ $rules .= 'deny from all' . PHP_EOL;
173
+ $write_result = file_put_contents($file, $rules);
174
+ if (false === $write_result) {
175
+ $aio_wp_security->debug_logger->log_debug("Creation of .htaccess file in " . AIO_WP_SECURITY_BACKUPS_DIR_NAME . " directory failed!", 4);
176
+ }
177
+ }
178
+ }
179
+ }
180
+
181
+ public static function reactivation_tasks() {
182
+ global $aio_wp_security;
183
+ $temp_cfgs = get_option('aiowps_temp_configs');
184
+ if (false !== $temp_cfgs) {
185
+ //Case where previously installed plugin was reactivated
186
+ //Let's copy the original configs back to the options table
187
+ $updated = update_option('aio_wp_security_configs', $temp_cfgs);
188
+ if (!$updated) {
189
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Installer::reactivation_tasks() - Update of option settings failed upon plugin activation!", 4);
190
+ }
191
+ $aio_wp_security->configs->configs = $temp_cfgs; //copy the original configs to memory
192
+ //Now let's write any rules to the .htaccess file if necessary
193
+ $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
194
+
195
+ if (!$res) {
196
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Installer::reactivation_tasks() - Could not write to the .htaccess file. Please check the file permissions.", 4);
197
+ return false;
198
+ }
199
+ delete_option('aiowps_temp_configs');
200
+ return true;
201
+ } else {
202
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Deactivation::run_deactivation_tasks() - Original config settings not found!", 4);
203
+ return false;
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Setup aiowps cron tasks
209
+ * Handles both single and multi-site (NW activation) cases
210
+ *
211
+ * @global type $wpdb
212
+ * @param type $networkwide
213
+ */
214
+ public static function set_cron_tasks_upon_activation($networkwide) {
215
+ global $wpdb;
216
+ if (AIOWPSecurity_Utility::is_multisite_install() && $networkwide) {
217
+ // check if it is a network activation
218
+ $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
219
+ foreach ($blogids as $blog_id) {
220
+ switch_to_blog($blog_id);
221
+ AIOWPSecurity_Installer::schedule_cron_events();
222
+ do_action('aiowps_activation_complete');
223
+ restore_current_blog();
224
+ }
225
+ } else {
226
+ AIOWPSecurity_Installer::schedule_cron_events();
227
+ do_action('aiowps_activation_complete');
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Helper function for scheduling aiowps cron events
233
+ */
234
+ public static function schedule_cron_events() {
235
+ if (!wp_next_scheduled('aiowps_hourly_cron_event')) {
236
+ wp_schedule_event(time(), 'hourly', 'aiowps_hourly_cron_event'); //schedule an hourly cron event
237
+ }
238
+ if (!wp_next_scheduled('aiowps_daily_cron_event')) {
239
+ wp_schedule_event(time(), 'daily', 'aiowps_daily_cron_event'); //schedule an daily cron event
240
+ }
241
+ }
242
  }
classes/wp-security-notices.php ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('AIO_WP_SECURITY_PATH')) die('No direct access allowed');
4
+
5
+ if (!class_exists('Updraft_Notices')) require_once(AIO_WP_SECURITY_PATH.'/classes/updraft-notices.php');
6
+
7
+ class AIOWPSecurity_Notices extends Updraft_Notices {
8
+
9
+ private $initialized = false;
10
+
11
+ protected $notices_content = array();
12
+
13
+ // protected $self_affiliate_id = null;
14
+
15
+ /**
16
+ * Returns array_merge of notices from parent and notices in $child_notice_content.
17
+ *
18
+ * @return Array
19
+ */
20
+ protected function populate_notices_content() {
21
+
22
+ $parent_notice_content = parent::populate_notices_content();
23
+
24
+ $child_notice_content = array(
25
+ 'rate_plugin' => array(
26
+ 'text' => sprintf(htmlspecialchars(__('Hey - We noticed All In One WP Security & Firewall has kept your site safe for a while. If you like us, please consider leaving a positive review to spread the word. Or if you have any issues or questions please leave us a support message %s.', 'all-in-one-wp-security-and-firewall')), '<a href="https://wordpress.org/support/plugin/all-in-one-wp-security-and-firewall/" target="_blank">'.__('here', 'all-in-one-wp-security-and-firewall').'</a>').'<br>'.__('Thank you so much!', 'all-in-one-wp-security-and-firewall').'<br><br>- <b>'.__('Team All In One WP Security & Firewall', 'all-in-one-wp-security-and-firewall').'</b>',
27
+ 'image' => 'notices/aiowps-logo.png',
28
+ 'button_link' => 'https://wordpress.org/support/plugin/all-in-one-wp-security-and-firewall/reviews/?rate=5#new-post',
29
+ 'button_meta' => 'review',
30
+ 'dismiss_time' => 'dismiss_review_notice',
31
+ 'supported_positions' => $this->dashboard_top,
32
+ 'validity_function' => 'show_rate_notice'
33
+ ),
34
+ );
35
+
36
+ return array_merge($parent_notice_content, $child_notice_content);
37
+ }
38
+
39
+ /**
40
+ * Call this method to setup the notices
41
+ */
42
+ public function notices_init() {
43
+ if ($this->initialized) return;
44
+ $this->initialized = true;
45
+ $this->notices_content = (defined('AIOWPSECURITY_NOADS_B') && AIOWPSECURITY_NOADS_B) ? array() : $this->populate_notices_content();
46
+
47
+ $enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? AIO_WP_SECURITY_VERSION.'.'.time() : AIO_WP_SECURITY_VERSION;
48
+ wp_enqueue_style('aiowpsec-admin-notices-css', AIO_WP_SECURITY_URL.'/css/wp-security-notices.css', array(), $enqueue_version);
49
+ }
50
+
51
+ /**
52
+ * Get AIOWPS Plugin installation timestamp.
53
+ *
54
+ * @return integer AIOWPS Plugin installation timestamp.
55
+ */
56
+ public function get_aiowps_plugin_installed_timestamp() {
57
+ $installed_at = @filemtime(AIO_WP_SECURITY_PATH.'/index.html'); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
58
+ if (false === $installed_at) {
59
+ global $aio_wp_security;
60
+ $installed_at = (int) $aio_wp_security->configs->get_value('installed-at');
61
+ }
62
+ $installed_at = apply_filters('aiowps_plugin_installed_timestamp', $installed_at);
63
+ return $installed_at;
64
+ }
65
+
66
+ /**
67
+ * This function will check if we should display the rate notice or not
68
+ *
69
+ * @return boolean - to indicate if we should show the notice or not
70
+ */
71
+ protected function show_rate_notice() {
72
+ $installed_at = $this->get_aiowps_plugin_installed_timestamp();
73
+ $time_now = $this->get_time_now();
74
+ $installed_for = $time_now - $installed_at;
75
+
76
+ if ($installed_at && $installed_for > 28*86400) {
77
+ return true;
78
+ }
79
+
80
+ return false;
81
+ }
82
+
83
+ /**
84
+ * Checks if UpdraftPlus is installed(returns false) or not(returns true).
85
+ *
86
+ * @return Boolean
87
+ */
88
+ protected function updraftplus_not_installed() {
89
+ if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
90
+ $plugins = get_plugins();
91
+
92
+ foreach ($plugins as $value) {
93
+ if ('updraftplus' == $value['TextDomain']) {
94
+ return false;
95
+ }
96
+ }
97
+ return true;
98
+ }
99
+
100
+ /**
101
+ * Checks if WP-Optimize is installed(returns false) or not(returns true).
102
+ *
103
+ * @return Boolean
104
+ */
105
+ protected function wp_optimize_not_installed() {
106
+ if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
107
+ $plugins = get_plugins();
108
+
109
+ foreach ($plugins as $value) {
110
+ if ('wp-optimize' == $value['TextDomain']) {
111
+ return false;
112
+ }
113
+ }
114
+ return true;
115
+ }
116
+
117
+ /**
118
+ * Determines whether to prepare a seasonal notice(returns true) or not(returns false).
119
+ *
120
+ * @param Array $notice_data - all data for the notice
121
+ *
122
+ * @return Boolean
123
+ */
124
+ protected function skip_seasonal_notices($notice_data) {
125
+ $time_now = $this->get_time_now();
126
+ $valid_from = strtotime($notice_data['valid_from']);
127
+ $valid_to = strtotime($notice_data['valid_to']);
128
+ $dismiss = $this->check_notice_dismissed($notice_data['dismiss_time']);
129
+ if (($time_now >= $valid_from && $time_now <= $valid_to) && !$dismiss) {
130
+ // return true so that we return this notice to be displayed
131
+ return true;
132
+ }
133
+
134
+ return false;
135
+ }
136
+
137
+ /**
138
+ * Get timestamp that is considered as current timestamp for notice.
139
+ *
140
+ * @return integer timestamp that should be consider as a current time.
141
+ */
142
+ public function get_time_now() {
143
+ $time_now = defined('AIOWPSECURITY_NOTICES_FORCE_TIME') ? AIOWPSECURITY_NOTICES_FORCE_TIME : time();
144
+ return $time_now;
145
+ }
146
+
147
+ /**
148
+ * Checks whether a notice is dismissed(returns true) or not(returns false).
149
+ *
150
+ * @param String $dismiss_time - dismiss time id for the notice
151
+ */
152
+ protected function check_notice_dismissed($dismiss_time) {
153
+ $time_now = $this->get_time_now();
154
+
155
+ global $aio_wp_security;
156
+ $dismiss = ($time_now < (int) $aio_wp_security->configs->get_value($dismiss_time));
157
+
158
+ return $dismiss;
159
+ }
160
+
161
+ /**
162
+ * Renders or returns a notice.
163
+ *
164
+ * @param Boolean|String $advert_information - all data for the notice
165
+ * @param Boolean $return_instead_of_echo - whether to return the notice(true) or render it to the page(false)
166
+ * @param String $position - notice position
167
+ *
168
+ * @return Void|String
169
+ */
170
+ protected function render_specified_notice($advert_information, $return_instead_of_echo = false, $position = 'top') {
171
+
172
+ if ('bottom' == $position) {
173
+ $template_file = 'bottom-notice.php';
174
+ } elseif ('report' == $position) {
175
+ $template_file = 'report.php';
176
+ } elseif ('report-plain' == $position) {
177
+ $template_file = 'report-plain.php';
178
+ } else {
179
+ $template_file = 'horizontal-notice.php';
180
+ }
181
+
182
+ global $aio_wp_security;
183
+ return $aio_wp_security->include_template('notices/'.$template_file, $return_instead_of_echo, $advert_information);
184
+ }
185
+ }
classes/wp-security-process-renamed-login-page.php CHANGED
@@ -1,261 +1,264 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Process_Renamed_Login_Page
7
- {
8
 
9
- function __construct()
10
- {
11
- add_action('login_init', array($this, 'aiowps_login_init'));
12
- add_filter('site_url', array($this, 'aiowps_site_url'), 10, 2);
13
- add_filter('network_site_url', array($this, 'aiowps_site_url'), 10, 2);
14
- add_filter('wp_redirect', array($this, 'aiowps_wp_redirect'), 10, 2);
15
- add_filter('register', array($this, 'register_link'));
16
- add_filter('user_request_action_email_content', array($this, 'aiowps_user_request_email_content'), 10, 2);
17
- remove_action('template_redirect', 'wp_redirect_admin_locations', 1000); //To prevent redirect to login page when people type "login" at end of home URL
18
 
19
- }
20
 
21
- function aiowps_login_init()
22
- {
23
- if (strpos($_SERVER['REQUEST_URI'], 'wp-login') !== false){
24
- $referer = wp_get_referer();
25
- if($referer && strpos($referer, 'wp-activate.php') !== false){
26
- $parsed_referer = parse_url($referer);
27
- if($parsed_referer && !empty($parsed_referer['query'])){
28
- parse_str($parsed_referer['query'], $referer);
29
- if (!empty($parsed_referer['key'])){
30
- $result = wpmu_activate_signup($parsed_referer['key']); //MS site creation
31
- if($result && is_wp_error($result) && ($result->get_error_code() === 'already_active' || $result->get_error_code() === 'blog_taken')){
32
- $aiowps_new_login_url = AIOWPSecurity_Process_Renamed_Login_Page::new_login_url();
33
- wp_safe_redirect($aiowps_new_login_url . (!empty($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : ''));
34
- die;
35
- }
36
- }
37
- }
38
- }
39
- AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404();
40
- }
41
 
42
- }
43
 
44
- function aiowps_site_url($url, $path)
45
- {
46
- return $this->aiowps_filter_wp_login_file($url);
47
- }
48
 
49
- function aiowps_wp_redirect($location, $status)
50
- {
51
- return $this->aiowps_filter_wp_login_file($location);
52
- }
53
 
54
- //Filter register link on the login page
55
- function register_link($registration_url)
56
- {
57
- return $this->aiowps_filter_wp_login_file($registration_url);
58
- }
 
 
 
 
59
 
60
- // Filter confirm link so we hide the secret login slug in the export_personal_data email
61
- function aiowps_user_request_email_content($email_text, $email_data)
62
- {
63
- global $aio_wp_security;
64
- if(isset($email_data['request']) && isset($email_data['request']->action_name)) {
65
- if($email_data['request']->action_name == 'export_personal_data') {
66
- $confirm_url = $email_data['confirm_url'];
67
- $login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
68
- if(get_option('permalink_structure')) {
69
- $new_confirm_url = str_replace( $login_slug, 'wp-login.php', $confirm_url );
70
- } else {
71
- $search_pattern = '?'.$login_slug.'&action';
72
- $new_confirm_url = str_replace( $search_pattern, '/wp-login.php/?action', $confirm_url );
73
- }
 
 
 
 
 
74
 
75
- $email_text_modified = str_replace( '###CONFIRM_URL###', esc_url_raw( $new_confirm_url ), $email_text );
76
- return $email_text_modified;
77
- }
78
- }
79
- return $email_text;
80
- }
81
 
82
- //Filter all login url strings on the login page
83
- function aiowps_filter_wp_login_file($url)
84
- {
85
- if (strpos($url, 'wp-login.php') !== false){
86
- $args = explode( '?', $url );
87
- if (isset($args[1])){
88
- if (strpos($args[1], 'action=postpass') !== FALSE){
89
- return $url; //Don't reveal the secret URL in the post password action url
90
- }
91
- parse_str($args[1], $args);
92
- $url = esc_url(add_query_arg($args, AIOWPSecurity_Process_Renamed_Login_Page::new_login_url()));
93
- $url = html_entity_decode($url);
94
- }else{
95
- $url = AIOWPSecurity_Process_Renamed_Login_Page::new_login_url();
96
- }
97
- }
98
- return $url;
99
- }
 
 
 
 
100
 
101
- static function renamed_login_init_tasks()
102
- {
103
- global $aio_wp_security;
104
 
105
- //The following will process the native wordpress post password protection form
106
- //Normally this is done by wp-login.php file but we cannot use that since the login page has been renamed
107
- $action = isset($_GET['action'])?strip_tags($_GET['action']):'';
108
- if(isset($_POST['post_password']) && $action == 'postpass'){
109
- require_once ABSPATH . 'wp-includes/class-phpass.php';
110
- $hasher = new PasswordHash( 8, true );
111
 
112
- /**
113
- * Filter the life span of the post password cookie.
114
- *
115
- * By default, the cookie expires 10 days from creation. To turn this
116
- * into a session cookie, return 0.
117
- *
118
- * @since 3.7.0
119
- *
120
- * @param int $expires The expiry time, as passed to setcookie().
121
- */
122
- $expire = apply_filters( 'post_password_expires', time() + 10 * DAY_IN_SECONDS );
123
- setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH );
124
 
125
- wp_safe_redirect( wp_get_referer() );
126
- exit();
127
- }
128
 
129
- //case where someone attempting to reach wp-admin
130
- if (is_admin() && !is_user_logged_in() && !defined('DOING_AJAX') && basename( $_SERVER["SCRIPT_FILENAME"] ) !== 'admin-post.php'){
131
- //Fix to prevent fatal error caused by some themes and Yoast SEO
132
- do_action('aiowps_before_wp_die_renamed_login');
133
- wp_die( __( 'Not available.', 'all-in-one-wp-security-and-firewall' ), 403 );
134
- }
135
 
136
- //case where someone attempting to reach wp-login
137
- if(isset($_SERVER['REQUEST_URI']) && strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) && !is_user_logged_in()){
138
 
139
- // Handle export personal data request for rename login case
140
- if(isset($_GET['request_id'])) {
141
- $request_id = (int) $_GET['request_id'];
142
- $result = '';
143
- if ( isset( $_GET['confirm_key'] ) ) {
144
- $key = sanitize_text_field( wp_unslash( $_GET['confirm_key'] ) );
145
- $result = wp_validate_user_request_key( $request_id, $key );
146
- } else {
147
- $result = new WP_Error( 'invalid_key', __( 'Invalid key' ) );
148
- }
149
 
150
- if ( is_wp_error( $result ) ) {
151
- wp_die( $result );
152
- }else if(!empty($result)) {
153
- _wp_privacy_account_request_confirmed($request_id);
154
- $message = _wp_privacy_account_request_confirmed_message( $request_id );
155
- login_header( __( 'User action confirmed.' ), $message );
156
- login_footer();
157
- exit;
158
- }
159
- }
160
 
161
- //Check if the maintenance (lockout) mode is active - if so prevent access to site by not displaying 404 page!
162
- if($aio_wp_security->configs->get_value('aiowps_site_lockout') == '1'){
163
- AIOWPSecurity_WP_Loaded_Tasks::site_lockout_tasks();
164
- }else{
165
- AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404();
166
- }
167
- }
168
 
169
- //case where someone attempting to reach the standard register or signup pages
170
- if(isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], 'wp-register.php' ) ||
171
- isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], 'wp-signup.php' )){
172
- //Check if the maintenance (lockout) mode is active - if so prevent access to site by not displaying 404 page!
173
- if($aio_wp_security->configs->get_value('aiowps_site_lockout') == '1'){
174
- AIOWPSecurity_WP_Loaded_Tasks::site_lockout_tasks();
175
- }else{
176
- AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404();
177
- }
178
- }
179
 
180
- $parsed_url = parse_url($_SERVER['REQUEST_URI']);
181
 
182
- $login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
183
- $home_url_with_slug = home_url($login_slug, 'relative');
184
 
185
- /*
186
- * Compatibility fix for WPML plugin
187
- */
188
- if (function_exists('icl_object_id') && strpos($home_url_with_slug,$login_slug)){
189
- $home_url_with_slug = home_url($login_slug);
190
- function qtranxf_init_language() {}
191
- }
192
 
193
- /*
194
- * *** Compatibility fix for qTranslate-X plugin ***
195
- * qTranslate-X plugin modifies the result for the following command by adding the protocol and host to the url path:
196
- * home_url($login_slug, 'relative');
197
- * Therefore we will remove the protocol and host for the following cases:
198
- * qTranslate-X is active AND the URL being accessed contains the secret slug
199
- */
200
- if (function_exists('qtranxf_init_language') && strpos($home_url_with_slug,$login_slug)){
201
- $parsed_home_url_with_slug = parse_url($home_url_with_slug);
202
- $home_url_with_slug = $parsed_home_url_with_slug['path']; //this will return just the path minus the protocol and host
203
- }
204
 
205
- if(untrailingslashit($parsed_url['path']) === $home_url_with_slug
206
- || (!get_option('permalink_structure') && isset($_GET[$login_slug]))){
207
- if(empty($action) && is_user_logged_in()){
208
- //if user is already logged in but tries to access the renamed login page, send them to the dashboard
209
- // or to requested redirect-page, filterd in 'login_redirect'.
210
- if (isset($_REQUEST['redirect_to'])) {
211
- $redirect_to = $_REQUEST['redirect_to'];
212
- $requested_redirect_to = $redirect_to;
213
- } else {
214
- $redirect_to = admin_url();
215
- $requested_redirect_to = '';
216
- }
217
- $redirect_to = apply_filters('login_redirect', $redirect_to, $requested_redirect_to, wp_get_current_user());
218
- AIOWPSecurity_Utility::redirect_to_url($redirect_to);
219
- }else{
220
- global $wp_version;
221
- do_action('aiowps_rename_login_load');
222
- status_header( 200 );
223
- if ( version_compare( $wp_version, '5.7', '>=' ) ) {
224
- require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature.php' );
225
- } else if ( version_compare( $wp_version, '5.2', '>=' ) ) {
226
- require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature-pre-5-7.php' );
227
- } else {
228
- require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature-pre-5-2.php' );
229
- }
230
 
231
- die;
232
- }
233
- }
234
- }
235
 
236
- static function new_login_url()
237
- {
238
- global $aio_wp_security;
239
- $login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
240
- if(get_option('permalink_structure')){
241
- return trailingslashit(trailingslashit(home_url()) . $login_slug);
242
- }else{
243
- return trailingslashit(home_url()) . '?' . $login_slug;
244
- }
245
- }
246
 
247
- static function aiowps_set_404()
248
- {
249
- global $wp_query;
250
- do_action('aiopws_before_set_404'); //This hook is for themes which produce a fatal error when the rename login feature is enabled and someone visits "wp-admin" slug directly
251
 
252
- status_header(404);
253
- $wp_query->set_404();
254
- if ((($template = get_404_template()) || ($template = get_index_template()))
255
- && ($template = apply_filters('template_include', $template))){
256
- include($template);
257
- }
258
- die;
259
- }
260
 
261
  }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Process_Renamed_Login_Page {
 
7
 
8
+ public function __construct() {
9
+ add_action('login_init', array($this, 'aiowps_login_init'));
10
+ add_filter('site_url', array($this, 'aiowps_site_url'), 10, 2);
11
+ add_filter('network_site_url', array($this, 'aiowps_site_url'), 10, 2);
12
+ add_filter('wp_redirect', array($this, 'aiowps_wp_redirect'), 10, 2);
13
+ add_filter('register', array($this, 'register_link'));
14
+ add_filter('user_request_action_email_content', array($this, 'aiowps_user_request_email_content'), 10, 2);
15
+ remove_action('template_redirect', 'wp_redirect_admin_locations', 1000); //To prevent redirect to login page when people type "login" at end of home URL
 
16
 
17
+ }
18
 
19
+ public function aiowps_login_init() {
20
+ if (strpos($_SERVER['REQUEST_URI'], 'wp-login') !== false) {
21
+ $referer = wp_get_referer();
22
+ if ($referer && strpos($referer, 'wp-activate.php') !== false) {
23
+ $parsed_referer = parse_url($referer);
24
+ if ($parsed_referer && !empty($parsed_referer['query'])) {
25
+ parse_str($parsed_referer['query'], $referer);
26
+ if (!empty($parsed_referer['key'])) {
27
+ $result = wpmu_activate_signup($parsed_referer['key']); //MS site creation
28
+ if ($result && is_wp_error($result) && ($result->get_error_code() === 'already_active' || $result->get_error_code() === 'blog_taken')) {
29
+ $aiowps_new_login_url = AIOWPSecurity_Process_Renamed_Login_Page::new_login_url();
30
+ wp_safe_redirect($aiowps_new_login_url . (!empty($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : ''));
31
+ die;
32
+ }
33
+ }
34
+ }
35
+ }
36
+ AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404();
37
+ }
 
38
 
39
+ }
40
 
41
+ public function aiowps_site_url($url) {
42
+ return $this->aiowps_filter_wp_login_file($url);
43
+ }
 
44
 
45
+ public function aiowps_wp_redirect($location) {
46
+ return $this->aiowps_filter_wp_login_file($location);
47
+ }
 
48
 
49
+ /**
50
+ * Filter register link on the login page
51
+ *
52
+ * @param string $registration_url
53
+ * @return string
54
+ */
55
+ public function register_link($registration_url) {
56
+ return $this->aiowps_filter_wp_login_file($registration_url);
57
+ }
58
 
59
+ /**
60
+ * Filter confirm link so we hide the secret login slug in the export_personal_data email
61
+ *
62
+ * @param string $email_text
63
+ * @param string $email_data
64
+ * @return string
65
+ */
66
+ public function aiowps_user_request_email_content($email_text, $email_data) {
67
+ global $aio_wp_security;
68
+ if (isset($email_data['request']) && isset($email_data['request']->action_name)) {
69
+ if ('export_personal_data' == $email_data['request']->action_name) {
70
+ $confirm_url = $email_data['confirm_url'];
71
+ $login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
72
+ if (get_option('permalink_structure')) {
73
+ $new_confirm_url = str_replace($login_slug, 'wp-login.php', $confirm_url);
74
+ } else {
75
+ $search_pattern = '?'.$login_slug.'&action';
76
+ $new_confirm_url = str_replace($search_pattern, '/wp-login.php/?action', $confirm_url);
77
+ }
78
 
79
+ $email_text_modified = str_replace('###CONFIRM_URL###', esc_url_raw($new_confirm_url), $email_text);
80
+ return $email_text_modified;
81
+ }
82
+ }
83
+ return $email_text;
84
+ }
85
 
86
+ /**
87
+ * Filter all login url strings on the login page
88
+ *
89
+ * @param string $url
90
+ * @return string
91
+ */
92
+ public function aiowps_filter_wp_login_file($url) {
93
+ if (strpos($url, 'wp-login.php') !== false) {
94
+ $args = explode('?', $url);
95
+ if (isset($args[1])) {
96
+ if (strpos($args[1], 'action=postpass') !== false) {
97
+ return $url; //Don't reveal the secret URL in the post password action url
98
+ }
99
+ parse_str($args[1], $args);
100
+ $url = esc_url(add_query_arg($args, AIOWPSecurity_Process_Renamed_Login_Page::new_login_url()));
101
+ $url = html_entity_decode($url);
102
+ } else {
103
+ $url = AIOWPSecurity_Process_Renamed_Login_Page::new_login_url();
104
+ }
105
+ }
106
+ return $url;
107
+ }
108
 
109
+ public static function renamed_login_init_tasks() {
110
+ global $aio_wp_security;
 
111
 
112
+ //The following will process the native wordpress post password protection form
113
+ //Normally this is done by wp-login.php file but we cannot use that since the login page has been renamed
114
+ $action = isset($_GET['action']) ? strip_tags($_GET['action']) : '';
115
+ if (isset($_POST['post_password']) && 'postpass' == $action) {
116
+ require_once ABSPATH . 'wp-includes/class-phpass.php';
117
+ $hasher = new PasswordHash(8, true);
118
 
119
+ /**
120
+ * Filter the life span of the post password cookie.
121
+ *
122
+ * By default, the cookie expires 10 days from creation. To turn this
123
+ * into a session cookie, return 0.
124
+ *
125
+ * @since 3.7.0
126
+ *
127
+ * @param int $expires The expiry time, as passed to setcookie().
128
+ */
129
+ $expire = apply_filters('post_password_expires', time() + 10 * DAY_IN_SECONDS);
130
+ setcookie('wp-postpass_' . COOKIEHASH, $hasher->HashPassword(wp_unslash($_POST['post_password'])), $expire, COOKIEPATH);
131
 
132
+ wp_safe_redirect(wp_get_referer());
133
+ exit();
134
+ }
135
 
136
+ //case where someone attempting to reach wp-admin
137
+ if (is_admin() && !is_user_logged_in() && !defined('DOING_AJAX') && basename($_SERVER["SCRIPT_FILENAME"]) !== 'admin-post.php') {
138
+ //Fix to prevent fatal error caused by some themes and Yoast SEO
139
+ do_action('aiowps_before_wp_die_renamed_login');
140
+ wp_die(__('Not available.', 'all-in-one-wp-security-and-firewall'), 403);
141
+ }
142
 
143
+ //case where someone attempting to reach wp-login
144
+ if (isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], 'wp-login.php') && !is_user_logged_in()) {
145
 
146
+ // Handle export personal data request for rename login case
147
+ if (isset($_GET['request_id'])) {
148
+ $request_id = (int) $_GET['request_id'];
149
+ $result = '';
150
+ if (isset($_GET['confirm_key'])) {
151
+ $key = sanitize_text_field(wp_unslash($_GET['confirm_key']));
152
+ $result = wp_validate_user_request_key($request_id, $key);
153
+ } else {
154
+ $result = new WP_Error('invalid_key', __('Invalid key'));
155
+ }
156
 
157
+ if (is_wp_error($result)) {
158
+ wp_die($result);
159
+ } elseif (!empty($result)) {
160
+ _wp_privacy_account_request_confirmed($request_id);
161
+ $message = _wp_privacy_account_request_confirmed_message($request_id);
162
+ login_header(__('User action confirmed.'), $message);
163
+ login_footer();
164
+ exit;
165
+ }
166
+ }
167
 
168
+ //Check if the maintenance (lockout) mode is active - if so prevent access to site by not displaying 404 page!
169
+ if ($aio_wp_security->configs->get_value('aiowps_site_lockout') == '1') {
170
+ AIOWPSecurity_WP_Loaded_Tasks::site_lockout_tasks();
171
+ } else {
172
+ AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404();
173
+ }
174
+ }
175
 
176
+ //case where someone attempting to reach the standard register or signup pages
177
+ if (isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], 'wp-register.php') || isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], 'wp-signup.php')) {
178
+ //Check if the maintenance (lockout) mode is active - if so prevent access to site by not displaying 404 page!
179
+ if ($aio_wp_security->configs->get_value('aiowps_site_lockout') == '1') {
180
+ AIOWPSecurity_WP_Loaded_Tasks::site_lockout_tasks();
181
+ } else {
182
+ AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404();
183
+ }
184
+ }
 
185
 
186
+ $parsed_url = parse_url($_SERVER['REQUEST_URI']);
187
 
188
+ $login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
189
+ $home_url_with_slug = home_url($login_slug, 'relative');
190
 
191
+ /*
192
+ * Compatibility fix for WPML plugin
193
+ */
194
+ if (function_exists('wpml_object_id') && strpos($home_url_with_slug, $login_slug)) {
195
+ $home_url_with_slug = home_url($login_slug);
196
+ function qtranxf_init_language() {}// phpcs:ignore Squiz.WhiteSpace.ScopeClosingBrace.ContentBefore,PEAR.WhiteSpace.ScopeClosingBrace.Line,Squiz.PHP.InnerFunctions.NotAllowed
197
+ }
198
 
199
+ /*
200
+ * *** Compatibility fix for qTranslate-X plugin ***
201
+ * qTranslate-X plugin modifies the result for the following command by adding the protocol and host to the url path:
202
+ * home_url($login_slug, 'relative');
203
+ * Therefore we will remove the protocol and host for the following cases:
204
+ * qTranslate-X is active AND the URL being accessed contains the secret slug
205
+ */
206
+ if (function_exists('qtranxf_init_language') && strpos($home_url_with_slug, $login_slug)) {
207
+ $parsed_home_url_with_slug = parse_url($home_url_with_slug);
208
+ $home_url_with_slug = $parsed_home_url_with_slug['path']; //this will return just the path minus the protocol and host
209
+ }
210
 
211
+ if (untrailingslashit($parsed_url['path']) === $home_url_with_slug || (!get_option('permalink_structure') && isset($_GET[$login_slug]))) {
212
+ if (empty($action) && is_user_logged_in()) {
213
+ //if user is already logged in but tries to access the renamed login page, send them to the dashboard
214
+ // or to requested redirect-page, filterd in 'login_redirect'.
215
+ if (isset($_REQUEST['redirect_to'])) {
216
+ $redirect_to = wp_sanitize_redirect($_REQUEST['redirect_to']);
217
+ $redirect_to = wp_validate_redirect($redirect_to, apply_filters('wp_safe_redirect_fallback', admin_url(), 302));
218
+ $requested_redirect_to = $redirect_to;
219
+ } else {
220
+ $redirect_to = admin_url();
221
+ $requested_redirect_to = '';
222
+ }
223
+ $redirect_to = apply_filters('login_redirect', $redirect_to, $requested_redirect_to, wp_get_current_user());
224
+ AIOWPSecurity_Utility::redirect_to_url($redirect_to);
225
+ } else {
226
+ global $wp_version;
227
+ do_action('aiowps_rename_login_load');
228
+ status_header(200);
229
+ if (version_compare($wp_version, '5.7', '>=')) {
230
+ require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature.php');
231
+ } elseif (version_compare($wp_version, '5.2', '>=')) {
232
+ require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature-pre-5-7.php');
233
+ } else {
234
+ require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature-pre-5-2.php');
235
+ }
236
 
237
+ die;
238
+ }
239
+ }
240
+ }
241
 
242
+ public static function new_login_url() {
243
+ global $aio_wp_security;
244
+ $login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
245
+ if (get_option('permalink_structure')) {
246
+ return trailingslashit(trailingslashit(home_url()) . $login_slug);
247
+ } else {
248
+ return trailingslashit(home_url()) . '?' . $login_slug;
249
+ }
250
+ }
 
251
 
252
+ public static function aiowps_set_404() {
253
+ global $wp_query;
254
+ do_action('aiopws_before_set_404'); //This hook is for themes which produce a fatal error when the rename login feature is enabled and someone visits "wp-admin" slug directly
 
255
 
256
+ status_header(404);
257
+ $wp_query->set_404();
258
+ if ((($template = get_404_template()) || ($template = get_index_template())) && ($template = apply_filters('template_include', $template))) {// phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
259
+ include($template);
260
+ }
261
+ die;
262
+ }
 
263
 
264
  }
classes/wp-security-user-login.php CHANGED
@@ -1,718 +1,675 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_User_Login
7
- {
8
- /**
9
- * This will store a URI query string key for passing messages to the login form
10
- * @var string
11
- */
12
- var $key_login_msg;
13
- function __construct()
14
- {
15
- global $aio_wp_security;
16
- $this->key_login_msg = 'aiowps_login_msg_id';
17
- // As a first authentication step, check if user's IP is locked.
18
- add_filter('authenticate', array($this, 'block_ip_if_locked'), 1, 1);
19
- // Check whether user needs to be manually approved after default WordPress authenticate hooks (with priority 20).
20
- add_filter('authenticate', array($this, 'check_manual_registration_approval'), 30, 1);
21
- // Check login captcha
22
- if($aio_wp_security->configs->get_value('aiowps_enable_login_captcha')) {
23
- add_filter('authenticate', array($this, 'check_captcha'), 20, 1);
24
- }
25
- // As a last authentication step, perform post authentication steps
26
- add_filter('authenticate', array($this, 'post_authenticate'), 100, 3);
27
- add_action('aiowps_force_logout_check', array($this, 'aiowps_force_logout_action_handler'));
28
- add_action('clear_auth_cookie', array($this, 'wp_logout_action_handler'));
29
- add_filter('login_message', array($this, 'aiowps_login_message')); //WP filter to add or modify messages on the login page
30
- }
31
- /**
32
- * Terminate the execution via wp_die with 503 status code, if current
33
- * user's IP is currently locked.
34
- *
35
- * @global AIO_WP_Security $aio_wp_security
36
- * @param WP_Error|WP_User $user
37
- * @return WP_User
38
- */
39
- function block_ip_if_locked($user)
40
- {
41
- global $aio_wp_security;
42
- $user_locked = $this->check_locked_user();
43
- if ( $user_locked != NULL ) {
44
- $aio_wp_security->debug_logger->log_debug("Login attempt from blocked IP range - ".$user_locked['failed_login_ip'],2);
45
- // Allow the error message to be filtered.
46
- $error_msg = apply_filters( 'aiowps_ip_blocked_error_msg', __('<strong>ERROR</strong>: Access from your IP address has been blocked for security reasons. Please contact the administrator.', 'all-in-one-wp-security-and-firewall') );
47
- // If unlock requests are allowed, add the "Request Unlock" button to the message.
48
- $unlock_form = '';
49
- if( $aio_wp_security->configs->get_value('aiowps_allow_unlock_requests') == '1' )
50
- {
51
- $unlock_form = $this->get_unlock_request_form();
52
- $error_msg .= $unlock_form;
53
- }
54
- $error_msg = apply_filters('aiowps_ip_blocked_output_page', $error_msg, $unlock_form); //filter the complete output of the locked page
55
- wp_die($error_msg, __('Service Temporarily Unavailable', 'all-in-one-wp-security-and-firewall'), 503);
56
- } else {
57
- return $user;
58
  }
59
- }
60
 
61
- /**
62
- * Check login captcha (if enabled).
63
- * @global AIO_WP_Security $aio_wp_security
64
- * @param WP_Error|WP_User $user
65
- * @return WP_Error|WP_User
66
- */
67
- function check_captcha($user)
68
- {
69
- global $aio_wp_security;
70
- if ( is_wp_error($user) ) {
71
- // Authentication has failed already at some earlier step.
72
- return $user;
73
- }
74
 
75
- if ( ! (isset($_POST['log']) && isset($_POST['pwd'])) ) {
76
- // XML-RPC authentication (not via wp-login.php), nothing to do here.
77
- return $user;
78
- }
79
 
80
- if ( $aio_wp_security->configs->get_value('aiowps_enable_login_captcha') != '1' ) {
81
- // Captcha not enabled, nothing to do here.
82
- return $user;
83
- }
84
- $captcha_error = new WP_Error('authentication_failed', __('<strong>ERROR</strong>: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
85
- $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
86
- if ( $verify_captcha === false ) {
87
- return $captcha_error;
88
- }
89
- return $user;
90
- }
91
- /**
92
- * Check, whether $user needs to be manually approved by site admin yet.
93
- * @global AIO_WP_Security $aio_wp_security
94
- * @param WP_Error|WP_User $user
95
- * @return WP_Error|WP_User
96
- */
97
- function check_manual_registration_approval($user)
98
- {
99
- global $aio_wp_security;
100
- if ( !($user instanceof WP_User) ) {
101
- // Not a WP_User - nothing to do here.
102
- return $user;
103
- }
104
- //Check if auto pending new account status feature is enabled
105
- if ($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1')
106
- {
107
- $aiowps_account_status = get_user_meta($user->ID, 'aiowps_account_status', TRUE);
108
- if ($aiowps_account_status == 'pending') {
109
- // Account needs to be activated yet
110
- return new WP_Error('account_pending', __('<strong>ACCOUNT PENDING</strong>: Your account is currently not active. An administrator needs to activate your account before you can login.', 'all-in-one-wp-security-and-firewall'));
111
- }
112
- }
113
- return $user;
114
- }
115
- /**
116
- * Handle post authentication steps (in case of failed login):
117
- * - increment number of failed logins for $username
118
- * - (optionally) lock the user
119
- * - (optionally) display a generic error message
120
- * @global AIO_WP_Security $aio_wp_security
121
- * @param WP_Error|WP_User $user
122
- * @param string $username
123
- * @param string $password
124
- * @return WP_Error|WP_User
125
- */
126
- function post_authenticate($user, $username, $password)
127
- {
128
- global $aio_wp_security;
129
- if ( !is_wp_error($user) ) {
130
- // Authentication has been successful, there's nothing to do here.
131
- return $user;
132
- }
133
- if ( empty($username) || empty($password) ) {
134
- // Neither log nor block login attempts with empty username or password.
135
- return $user;
136
- }
137
- if ( $user->get_error_code() === 'account_pending' ) {
138
- // Neither log nor block users attempting to log in before their registration is approved.
139
- return $user;
140
- }
141
- // Login failed for non-trivial reason
142
- $this->increment_failed_logins($username);
143
- if ( $aio_wp_security->configs->get_value('aiowps_enable_login_lockdown') == '1' )
144
- {
145
- $is_whitelisted = false;
146
- //check if lockdown whitelist enabled
147
- if ( $aio_wp_security->configs->get_value('aiowps_lockdown_enable_whitelisting') == '1' ){
148
- $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
149
- $whitelisted_ips = $aio_wp_security->configs->get_value('aiowps_lockdown_allowed_ip_addresses');
150
- $is_whitelisted = AIOWPSecurity_Utility_IP::is_ip_whitelisted($ip, $whitelisted_ips);
151
- }
152
 
153
- if($is_whitelisted === false){
154
- // Too many failed logins from user's IP?
155
- $login_attempts_permitted = absint($aio_wp_security->configs->get_value('aiowps_max_login_attempts'));
156
- $too_many_failed_logins = $login_attempts_permitted <= $this->get_login_fail_count();
157
- // Is an invalid username or email the reason for login error?
158
- $invalid_username = ($user->get_error_code() === 'invalid_username' || $user->get_error_code() == 'invalid_email');
159
- // Should an invalid username be immediately locked?
160
- $invalid_username_lockdown = $aio_wp_security->configs->get_value('aiowps_enable_invalid_username_lockdown') == '1';
161
- $lock_invalid_username = $invalid_username && $invalid_username_lockdown;
162
- // Should an invalid username be blocked as per blacklist?
163
- $instant_lockout_users_list = $aio_wp_security->configs->get_value('aiowps_instantly_lockout_specific_usernames');
164
- if ( !is_array($instant_lockout_users_list) ) {
165
- $instant_lockout_users_list = array();
166
- }
167
- $username_blacklisted = $invalid_username && in_array($username, $instant_lockout_users_list);
168
- if ( $too_many_failed_logins || $lock_invalid_username || $username_blacklisted )
169
- {
170
- $this->lock_the_user($username, 'login_fail');
171
- }
172
- }
173
- }
174
 
175
- if ( $aio_wp_security->configs->get_value('aiowps_set_generic_login_msg') == '1' )
176
- {
177
- // Return generic error message if configured
178
- return new WP_Error('authentication_failed', __('<strong>ERROR</strong>: Invalid login credentials.', 'all-in-one-wp-security-and-firewall'));
179
- }
180
- return $user;
181
- }
182
- /*
183
- * This function queries the aiowps_login_lockdown table.
184
- * If the release_date has not expired AND the current visitor IP addr matches
185
- * it will return a record
186
- */
187
- function check_locked_user()
188
- {
189
- global $wpdb;
190
- $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
191
- $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
192
- if(empty($ip)) return false;
193
- $now = current_time( 'mysql' );
194
- $locked_user = $wpdb->get_row("SELECT * FROM $login_lockdown_table " .
195
- "WHERE release_date > '".$now."' AND " .
196
- "failed_login_ip = '" . esc_sql($ip) . "'", ARRAY_A);
197
- return $locked_user;
198
- }
199
- /*
200
- * This function queries the aiowps_failed_logins table and returns the number of failures for current IP range within allowed failure period
201
- */
202
- function get_login_fail_count()
203
- {
204
- global $wpdb, $aio_wp_security;
205
- $failed_logins_table = AIOWPSEC_TBL_FAILED_LOGINS;
206
- $login_retry_interval = $aio_wp_security->configs->get_value('aiowps_retry_time_period');
207
- $now = current_time( 'mysql' );
208
- $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
209
- if(empty($ip)) return false;
210
- $login_failures = $wpdb->get_var("SELECT COUNT(ID) FROM $failed_logins_table " .
211
- "WHERE failed_login_date + INTERVAL " .
212
- esc_sql($login_retry_interval) . " MINUTE > '" . esc_sql($now) . "' AND " .
213
- "login_attempt_ip = '" . esc_sql($ip) . "'");
214
- return $login_failures;
215
- }
216
- /**
217
- * Adds an entry to the `aiowps_login_lockdown` table.
218
- * @param string $username User's username or email
219
- * @param string $lock_reason
220
- */
221
- function lock_the_user($username, $lock_reason='login_fail')
222
- {
223
- global $wpdb, $aio_wp_security;
224
- $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
225
- $lock_minutes = $aio_wp_security->configs->get_value('aiowps_lockout_time_length');
226
- $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
227
- if(empty($ip)) return;
228
- $ip_range = AIOWPSecurity_Utility_IP::get_sanitized_ip_range($ip); //Get the IP range of the current user
229
- $user = is_email($username) ? get_user_by('email', $username) : get_user_by('login', $username); //Returns WP_User object if exists
230
- $ip_range = apply_filters('aiowps_before_lockdown', $ip_range);
231
- if ($user)
232
- {
233
- //If the login attempt was made using a valid user set variables for DB storage later on
234
- $user_id = $user->ID;
235
- } else {
236
- //If the login attempt was made using a non-existent user then let's set user_id to blank and record the attempted user login name for DB storage later on
237
- $user_id = 0;
238
- }
239
- $ip_range_str = esc_sql($ip_range).'.*';
240
 
241
- $lock_time = current_time( 'mysql' );
242
- $date = new DateTime($lock_time);
243
- $add_interval = 'PT'.absint($lock_minutes).'M';
244
- $date->add(new DateInterval($add_interval));
245
- $release_time = $date->format('Y-m-d H:i:s');
246
 
247
- $data = array('user_id' => $user_id, 'user_login' => $username, 'lockdown_date' => $lock_time, 'release_date' => $release_time, 'failed_login_IP' => $ip, 'lock_reason' => $lock_reason);
248
- $format = array('%d', '%s', '%s', '%s', '%s', '%s');
249
- $result = $wpdb->insert($login_lockdown_table, $data, $format);
250
 
251
- if ($result === FALSE)
252
- {
253
- $aio_wp_security->debug_logger->log_debug("Error inserting record into ".$login_lockdown_table,4);//Log the highly unlikely event of DB error
254
- }
255
- else
256
- {
257
- do_action('aiowps_lockdown_event', $ip_range, $username);
258
- $this->send_ip_lock_notification_email($username, $ip_range, $ip);
259
- $aio_wp_security->debug_logger->log_debug("The following IP address range has been locked out for exceeding the maximum login attempts: ".$ip_range,2);//Log the lockdown event
260
- }
261
- }
262
- /**
263
- * Adds an entry to the `aiowps_failed_logins` table.
264
- * @param string $username User's username or email
265
- */
266
- function increment_failed_logins($username)
267
- {
268
- global $wpdb, $aio_wp_security;
269
- $login_fails_table = AIOWPSEC_TBL_FAILED_LOGINS;
270
- $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
271
- if(empty($ip)) return;
272
- $user = is_email($username) ? get_user_by('email', $username) : get_user_by('login', $username); //Returns WP_User object if it exists
273
- if ($user)
274
- {
275
- //If the login attempt was made using a valid user set variables for DB storage later on
276
- $user_id = $user->ID;
277
- } else {
278
- //If the login attempt was made using a non-existent user then let's set user_id to blank and record the attempted user login name for DB storage later on
279
- $user_id = 0;
280
- }
281
- $ip_str = esc_sql($ip);
282
- $now = current_time( 'mysql' );
283
- $data = array('user_id' => $user_id, 'user_login' => $username, 'failed_login_date' => $now, 'login_attempt_ip' => $ip_str);
284
- $format = array('%d', '%s', '%s', '%s');
285
- $result = $wpdb->insert($login_fails_table, $data, $format);
286
- if ($result === FALSE)
287
- {
288
- $aio_wp_security->debug_logger->log_debug("Error inserting record into ".$login_fails_table,4);//Log the highly unlikely event of DB error
289
- }
290
- }
291
- /**
292
- * @param string $username User's username or email
293
- */
294
- function send_ip_lock_notification_email($username, $ip_range, $ip)
295
- {
296
- global $aio_wp_security;
297
- $email_notification_enabled = $aio_wp_security->configs->get_value('aiowps_enable_email_notify');
298
- if ($email_notification_enabled == 1)
299
- {
300
- $to_email_address = $aio_wp_security->configs->get_value('aiowps_email_address');
301
- $subject = '['.get_option('home').'] '. __('Site Lockout Notification','all-in-one-wp-security-and-firewall');
302
- $email_msg = __('A lockdown event has occurred due to too many failed login attempts or invalid username:','all-in-one-wp-security-and-firewall')."\n";
303
- $email_msg .= __('Username:', 'all-in-one-wp-security-and-firewall') . ' ' . $username . "\n";
304
- $email_msg .= __('IP Address:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip . "\n\n";
305
- $email_msg .= __('IP Range:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip_range . '.*' . "\n\n";
306
- $email_msg .= __("Log into your site's WordPress administration panel to see the duration of the lockout or to unlock the user.",'all-in-one-wp-security-and-firewall') . "\n";
307
- $site_title = get_bloginfo( 'name' );
308
- $from_name = empty($site_title)?'WordPress':$site_title;
309
- $email_header = 'From: '.$from_name.' <'.get_bloginfo('admin_email').'>' . "\r\n\\";
310
- $sendMail = wp_mail($to_email_address, $subject, $email_msg, $email_header);
311
- if(FALSE === $sendMail){
312
- $aio_wp_security->debug_logger->log_debug("Lockout notification email failed to send to ".$to_email_address." for IP ".$ip,4);
313
- }
314
- }
315
- }
316
 
317
- /**
318
- * Generates and returns an unlock request link which will be used to send to the user.
319
- *
320
- * @global type $wpdb
321
- * @global AIO_WP_Security $aio_wp_security
322
- * @param type $ip_range
323
- * @return string or FALSE on failure
324
- */
325
- static function generate_unlock_request_link($ip_range)
326
- {
327
- //Get the locked user row from lockdown table
328
- global $wpdb, $aio_wp_security;
329
- $unlock_link = '';
330
- $lockdown_table_name = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
331
- $secret_rand_key = (md5(uniqid(rand(), true)));
332
- $res = $wpdb->query( $wpdb->prepare("UPDATE $lockdown_table_name SET unlock_key = '$secret_rand_key' WHERE release_date > now() AND failed_login_ip LIKE %s","%".esc_sql($ip_range)."%") );
333
- if($res == NULL){
334
- $aio_wp_security->debug_logger->log_debug("No locked user found with IP range ".$ip_range,4);
335
- return false;
336
- }else{
337
- //Check if unlock requestor submitted from a woocommerce account login page
338
- if(isset($_POST['aiowps-woo-login'])){
339
- $date_time = current_time( 'mysql' );
340
- $data = array('date_time' => $date_time, 'meta_key1' => 'woo_unlock_request_key', 'meta_value1' => $secret_rand_key);
341
- $result = $wpdb->insert(AIOWPSEC_TBL_GLOBAL_META_DATA, $data);
342
- if ($result === false){
343
- $aio_wp_security->debug_logger->log_debug("generate_unlock_request_link() - Error inserting woo_unlock_request_key to AIOWPSEC_TBL_GLOBAL_META_DATA table for secret key ".$secret_rand_key,4);
344
- }
345
- }
346
- $query_param = array('aiowps_auth_key'=>$secret_rand_key);
347
- $wp_site_url = AIOWPSEC_WP_URL;
348
- $unlock_link = esc_url(add_query_arg($query_param, $wp_site_url));
349
- }
350
- return $unlock_link;
351
- }
352
- /*
353
- * This function will process an unlock request when someone clicks on the special URL
354
- * It will check if the special random code matches that in lockdown table for the relevant user
355
- * If so, it will unlock the user
356
- */
357
- static function process_unlock_request($unlock_key)
358
- {
359
- global $wpdb, $aio_wp_security;
360
- $lockdown_table_name = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
361
 
362
- $unlock_command = $wpdb->prepare( "UPDATE ".$lockdown_table_name." SET release_date = now() WHERE unlock_key = %s", $unlock_key );
363
- $result = $wpdb->query($unlock_command);
364
- if($result === false)
365
- {
366
- $aio_wp_security->debug_logger->log_debug("Error unlocking user with unlock_key ".$unlock_key,4);
367
- }
368
- else
369
- {
370
- //Now check if this unlock operation is for a woocommerce login
371
- $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
372
- $sql = $wpdb->prepare("SELECT * FROM $aiowps_global_meta_tbl_name WHERE meta_key1=%s AND meta_value1=%s", 'woo_unlock_request_key', $unlock_key);
373
- $woo_result = $wpdb->get_row($sql, OBJECT);
374
- if(empty($woo_result)){
375
- $woo_unlock = false;
376
- }else{
377
- $woo_unlock = true;
378
- }
379
- if($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page')=='1'){
380
- if (get_option('permalink_structure')){
381
- $home_url = trailingslashit(home_url());
382
- }else{
383
- $home_url = trailingslashit(home_url()) . '?';
384
- }
385
- if ( $woo_unlock ){
386
- $login_url = wc_get_page_permalink( 'myaccount' ); //redirect to woo login page if applicable
387
- //Now let's cleanup after ourselves and delete the woo-related row in the AIOWPSEC_TBL_GLOBAL_META_DATA table
388
- $delete = $wpdb->delete( $aiowps_global_meta_tbl_name, array( 'meta_key1' => 'woo_unlock_request_key', 'meta_value1' => $unlock_key ) );
389
- if($delete === false){
390
- $aio_wp_security->debug_logger->log_debug("process_unlock_request(): Error deleting row from AIOWPSEC_TBL_GLOBAL_META_DATA for meta_key1=woo_unlock_request_key and meta_value1=".$unlock_key,4);
391
- }
392
- }else{
393
- $login_url = $home_url.$aio_wp_security->configs->get_value('aiowps_login_page_slug');
394
- }
 
 
395
 
396
- AIOWPSecurity_Utility::redirect_to_url($login_url);
397
- }else{
398
- AIOWPSecurity_Utility::redirect_to_url(wp_login_url());
399
- }
400
- }
401
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
 
403
- /*
404
- * This function sends an unlock request email to a locked out user
405
- */
406
- static function send_unlock_request_email($email, $unlock_link)
407
- {
408
- global $aio_wp_security;
409
- $subject = '['.get_option('siteurl').'] '. __('Unlock Request Notification','all-in-one-wp-security-and-firewall');
410
- $email_msg
411
- = sprintf(__('You have requested for the account with email address %s to be unlocked. Please click the link below to unlock your account:','all-in-one-wp-security-and-firewall'), $email) . "\n"
412
- . sprintf(__('Unlock link: %s', 'all-in-one-wp-security-and-firewall'), $unlock_link) . "\n\n"
413
- . __('After clicking the above link you will be able to login to the WordPress administration panel.', 'all-in-one-wp-security-and-firewall') . "\n"
414
- ;
415
- $site_title = get_bloginfo( 'name' );
416
- $from_name = empty($site_title)?'WordPress':$site_title;
417
- $email_header = 'From: '.$from_name.' <'.get_bloginfo('admin_email').'>' . "\r\n\\";
418
- $sendMail = wp_mail($email, $subject, $email_msg, $email_header);
419
- if ( false === $sendMail ) {
420
- $aio_wp_security->debug_logger->log_debug("Unlock Request Notification email failed to send to " . $email, 4);
421
- }
422
- }
423
 
424
- /*
425
- * This function will check the settings and log the user after the configured time period
426
- */
427
- function aiowps_force_logout_action_handler()
428
- {
429
- global $aio_wp_security;
430
- //$aio_wp_security->debug_logger->log_debug("Force Logout - Checking if any user need to be logged out...");
431
- if($aio_wp_security->configs->get_value('aiowps_enable_forced_logout')=='1') //if this feature is enabled then do something
432
- {
433
- if(is_user_logged_in())
434
- {
435
- $current_user = wp_get_current_user();
436
- $user_id = $current_user->ID;
437
- $current_time = current_time( 'mysql' );
438
- $login_time = $this->get_wp_user_last_login_time($user_id);
439
- $diff = strtotime($current_time) - strtotime($login_time);
440
- $logout_time_interval_value = $aio_wp_security->configs->get_value('aiowps_logout_time_period');
441
- $logout_time_interval_val_seconds = $logout_time_interval_value * 60;
442
- if($diff > $logout_time_interval_val_seconds)
443
- {
444
- $aio_wp_security->debug_logger->log_debug("Force Logout - This user logged in more than (".$logout_time_interval_value.") minutes ago. Doing a force log out for the user with username: ".$current_user->user_login);
445
- $this->wp_logout_action_handler(); //this will register the logout time/date in the logout_date column
446
 
447
- $curr_page_url = AIOWPSecurity_Utility::get_current_page_url();
448
- $after_logout_payload = array('redirect_to'=>$curr_page_url, 'msg'=>$this->key_login_msg.'=session_expired');
449
- //Save some of the logout redirect data to a transient
450
- AIOWPSecurity_Utility::is_multisite_install() ? set_site_transient('aiowps_logout_payload', $after_logout_payload, 30 * 60) : set_transient('aiowps_logout_payload', $after_logout_payload, 30 * 60);
451
- $logout_url = AIOWPSEC_WP_URL.'?aiowpsec_do_log_out=1';
452
- $logout_url = AIOWPSecurity_Utility::add_query_data_to_url($logout_url, 'al_additional_data', '1');
453
- $logout_url_with_nonce = html_entity_decode(wp_nonce_url($logout_url, 'aio_logout'));
454
- AIOWPSecurity_Utility::redirect_to_url($logout_url_with_nonce);
455
- }
456
- }
457
- }
458
- }
 
 
 
 
 
 
 
 
 
459
 
460
- function get_wp_user_last_login_time($user_id)
461
- {
462
- $last_login = get_user_meta($user_id, 'last_login_time', true);
463
- return $last_login;
464
- }
465
- static function wp_login_action_handler($user_login, $user='')
466
- {
467
- global $wpdb, $aio_wp_security;
468
- $login_activity_table = AIOWPSEC_TBL_USER_LOGIN_ACTIVITY;
 
 
 
469
 
470
- if ($user == ''){
471
- //Try and get user object
472
- $user = get_user_by('login', $user_login); //This should return WP_User obj
473
- if (!$user){
474
- $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_User_Login::wp_login_action_handler: Unable to get WP_User object for login ".$user_login,4);
475
- return;
476
- }
477
- }
478
- $login_date_time = current_time( 'mysql' );
479
- update_user_meta($user->ID, 'last_login_time', $login_date_time); //store last login time in meta table
480
- $curr_ip_address = AIOWPSecurity_Utility_IP::get_user_ip_address();
481
- $data = array('user_id' => $user->ID, 'user_login' => $user_login, 'login_date' => $login_date_time, 'login_ip' => $curr_ip_address);
482
- $format = array('%d', '%s', '%s', '%s');
483
- $result = $wpdb->insert($login_activity_table, $data, $format);
484
- if ($result === FALSE)
485
- {
486
- $aio_wp_security->debug_logger->log_debug("Error inserting record into ".$login_activity_table,4);//Log the highly unlikely event of DB error
487
- }
488
 
489
- }
490
- /**
491
- * The handler for logout events, ie, uses the WP "clear_auth_cookies" action.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
492
 
493
- * Modifies the login activity record for the current user by registering the logout time/date in the logout_date column.
494
- * (NOTE: Because of the way we are doing a force logout, the "clear_auth_cookies" hook does not fire.
495
- * upon auto logout. The current workaround is to call this function directly from the aiowps_force_logout_action_handler() when
496
- * an auto logout occurs due to the "force logout" feature).
497
- *
498
- */
499
- function wp_logout_action_handler()
500
- {
501
- global $wpdb, $aio_wp_security;
502
- $current_user = wp_get_current_user();
503
- $ip_addr = AIOWPSecurity_Utility_IP::get_user_ip_address();
504
- $user_id = $current_user->ID;
505
- //Clean up transients table
506
- $this->cleanup_users_online_transient($user_id, $ip_addr);
507
- $login_activity_table = AIOWPSEC_TBL_USER_LOGIN_ACTIVITY;
508
- $logout_date_time = current_time( 'mysql' );
509
- $data = array('logout_date' => $logout_date_time);
510
- $where = array('user_id' => $user_id,
511
- 'login_ip' => $ip_addr,
512
- 'logout_date' => '1000-10-10 10:00:00');
513
- $result = $wpdb->update($login_activity_table, $data, $where);
514
- if ($result === FALSE)
515
- {
516
- $aio_wp_security->debug_logger->log_debug("Error inserting record into ".$login_activity_table,4);//Log the highly unlikely event of DB error
517
- }
518
- }
519
 
520
- /**
521
- * Update the 'users_online' transient
522
- * @return void
523
- */
524
- function update_users_online_transient()
525
- {
526
- if(is_user_logged_in()){
527
- $is_multi_site = AIOWPSecurity_Utility::is_multisite_install();
528
- $current_user_ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
529
- // get the logged in users list from transients entry
530
- $logged_in_users = ($is_multi_site ? get_site_transient('users_online') : get_transient('users_online'));
531
- $current_user = wp_get_current_user();
532
- $current_user = $current_user->ID;
533
- $current_time = current_time('timestamp');
534
- $current_user_info = array();
535
 
536
- // Store last activity time and ip address in transient entry
537
- if($is_multi_site) {
538
- $current_blog_id = get_current_blog_id();
539
- // For multi-sites also store blog_id
540
- $current_user_info = array("user_id" => $current_user, "last_activity" => $current_time, "ip_address" => $current_user_ip, "blog_id" => $current_blog_id);
541
- } else {
542
- $current_user_info = array("user_id" => $current_user, "last_activity" => $current_time, "ip_address" => $current_user_ip, "blog_id" => false);
543
- }
544
 
545
- if(empty($logged_in_users))
546
- {
547
- // case when "users_online" transient has been deleted after expiry or is empty
548
- $logged_in_users = array();
549
- $logged_in_users[] = $current_user_info;
550
- $is_multi_site ? set_site_transient('users_online', $logged_in_users, 30 * 60) : set_transient('users_online', $logged_in_users, 30 * 60);
551
- }
552
- else
553
- {
554
- $key = 0;
555
- $update_existing = false;
556
- $item_index = 0;
557
- foreach ($logged_in_users as $value)
558
- {
559
- $value_minus_activity = $value;
560
- unset($value_minus_activity['last_activity']);
561
- $current_user_minus_activity = $current_user_info;
562
- unset($current_user_minus_activity['last_activity']);
563
- // Check if current user we're looking at has an entry in the 'users_online' transient
564
- if(empty(array_diff($current_user_minus_activity, $value_minus_activity)))
565
- {
566
- if ($value['last_activity'] < ($current_time - (15 * 60)))
567
- {
568
- $update_existing = true;
569
- $item_index = $key;
570
- break;
571
- }else{
572
- return; // do nothing and just return
573
- }
574
- }
575
- $key++;
576
- }
577
 
578
- if($update_existing) {
579
- // Update transient if the last activity was over 15 min ago for this user
580
- $logged_in_users[$item_index] = $current_user_info;
581
- AIOWPSecurity_Utility::is_multisite_install() ? set_site_transient('users_online', $logged_in_users, 30 * 60) : set_transient('users_online', $logged_in_users, 30 * 60);
582
- } else {
583
- $logged_in_users[] = $current_user_info;
584
- AIOWPSecurity_Utility::is_multisite_install() ? set_site_transient('users_online', $logged_in_users, 30 * 60) : set_transient('users_online', $logged_in_users, 30 * 60);
585
- }
586
- }
587
- }
588
- }
589
 
590
- /**
591
- * This will clean up the "users_online" transient entry for the current user when a logout occurs
592
- * @return void
593
- */
594
- function cleanup_users_online_transient($user_id, $ip_addr)
595
- {
596
- global $aio_wp_security;
597
- $is_multi_site = AIOWPSecurity_Utility::is_multisite_install();
598
- if ($is_multi_site) {
599
- $current_blog_id = get_current_blog_id();
600
- $logged_in_users = AIOWPSecurity_User_Login::get_subsite_logged_in_users($current_blog_id);
601
- } else {
602
- $logged_in_users = get_transient('users_online');
603
- }
 
604
 
605
- if (empty($logged_in_users))
606
- {
607
- return;
608
- }
609
- $j = 0;
610
- foreach ($logged_in_users as $value)
611
- {
612
- if ($value['user_id'] == $user_id && strcmp($value['ip_address'], $ip_addr) == 0)
613
- {
614
- unset($logged_in_users[$j]);
615
- break;
616
- }
617
- $j++;
618
- }
619
 
620
- // Save the transient
621
- if ($is_multi_site) {
622
- set_site_transient('users_online', $logged_in_users, 30 * 60);
623
- } else {
624
- set_transient('users_online', $logged_in_users, 30 * 60);
625
- }
626
- return;
627
- }
628
 
629
- /**
630
- * The handler for the WP "login_message" filter
631
- * Adds custom messages to the other messages that appear above the login form.
632
- *
633
- * NOTE: This method is automatically called by WordPress for displaying
634
- * text above the login form.
635
- *
636
- * @param string $message the output from earlier login_message filters
637
- * @return string
638
- *
639
- */
640
- function aiowps_login_message($message = '')
641
- {
642
- global $aio_wp_security;
643
- $msg = '';
644
- if(isset($_GET[$this->key_login_msg]) && !empty($_GET[$this->key_login_msg]))
645
- {
646
- $logout_msg = strip_tags($_GET[$this->key_login_msg]);
647
- }
648
- if (!empty($logout_msg))
649
- {
650
- switch ($logout_msg) {
651
- case 'session_expired':
652
- $msg = sprintf(__('Your session has expired because it has been over %d minutes since your last login.', 'all-in-one-wp-security-and-firewall'), $aio_wp_security->configs->get_value('aiowps_logout_time_period'));
653
- $msg .= ' ' . __('Please log back in to continue.', 'all-in-one-wp-security-and-firewall');
654
- break;
655
- case 'admin_user_changed':
656
- $msg = __('You were logged out because you just changed the "admin" username.', 'all-in-one-wp-security-and-firewall');
657
- $msg .= ' ' . __('Please log back in to continue.', 'all-in-one-wp-security-and-firewall');
658
- break;
659
- default:
660
- }
661
- }
662
- if (!empty($msg))
663
- {
664
- $msg = htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');
665
- $message .= '<p class="login message">'. $msg . '</p>';
666
- }
667
- return $message;
668
- }
669
- /**
670
- * This function will generate an unlock request form to be inserted inside
671
- * error message when user gets locked out.
672
- *
673
- * @return string
674
- */
675
- function get_unlock_request_form()
676
- {
677
- global $aio_wp_security;
678
- $unlock_request_form = '';
679
- //Let's encode some hidden data and make a form
680
- $unlock_secret_string = $aio_wp_security->configs->get_value('aiowps_unlock_request_secret_key');
681
- $current_time = time();
682
- $enc_result = base64_encode($current_time.$unlock_secret_string);
683
- $unlock_request_form .= '<form method="post" action=""><div style="padding-bottom:10px;"><input type="hidden" name="aiowps-unlock-string-info" id="aiowps-unlock-string-info" value="'.$enc_result.'" />';
684
- $unlock_request_form .= '<input type="hidden" name="aiowps-unlock-temp-string" id="aiowps-unlock-temp-string" value="'.$current_time.'" />';
685
- if(isset($_POST['woocommerce-login-nonce'])){
686
- $unlock_request_form .= '<input type="hidden" name="aiowps-woo-login" id="aiowps-woo-login" value="1" />';
687
- }
688
- $unlock_request_form .= '<button type="submit" name="aiowps_unlock_request" id="aiowps_unlock_request" class="button">'.__('Request Unlock', 'all-in-one-wp-security-and-firewall').'</button></div></form>';
689
- return $unlock_request_form;
690
- }
691
 
692
- /**
693
- * Returns all logged in users for specific subsite of multisite installation
694
- * Checks the aiowps transient 'users_online'
695
- * @param type $blog_id
696
- * @return array|bool
697
- */
698
- static function get_subsite_logged_in_users($blog_id=0) {
699
- if(empty($blog_id)) return false;
 
700
 
701
- $subsite_logged_in_users = array();
702
- if (AIOWPSecurity_Utility::is_multisite_install()) {
703
- // this contains all logged in users sitewide across subsites
704
- $users_online = get_site_transient('users_online');
705
- if(empty($users_online)) {
706
- return array();
707
- }
708
- // Extract only logged in users for current subsite
709
- foreach($users_online as $user) {
710
- if (isset($user['blog_id']) && $user['blog_id'] == $blog_id) {
711
- $subsite_logged_in_users[] = $user;
712
- }
713
- }
714
- }
715
- return $subsite_logged_in_users;
716
- }
717
 
718
  }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_User_Login {
7
+
8
+ public $key_login_msg;// This will store a URI query string key for passing messages to the login form
9
+
10
+ public function __construct() {
11
+ global $aio_wp_security;
12
+ $this->key_login_msg = 'aiowps_login_msg_id';
13
+ // As a first authentication step, check if user's IP is locked.
14
+ add_filter('authenticate', array($this, 'block_ip_if_locked'), 1, 1);
15
+ // Check whether user needs to be manually approved after default WordPress authenticate hooks (with priority 20).
16
+ add_filter('authenticate', array($this, 'check_manual_registration_approval'), 30, 1);
17
+ // Check login captcha
18
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_captcha')) {
19
+ add_filter('authenticate', array($this, 'check_captcha'), 20, 1);
20
+ }
21
+ // As a last authentication step, perform post authentication steps
22
+ add_filter('authenticate', array($this, 'post_authenticate'), 100, 3);
23
+ add_action('aiowps_force_logout_check', array($this, 'aiowps_force_logout_action_handler'));
24
+ add_action('clear_auth_cookie', array($this, 'wp_logout_action_handler'));
25
+ add_filter('login_message', array($this, 'aiowps_login_message')); //WP filter to add or modify messages on the login page
26
+ }
27
+ /**
28
+ * Terminate the execution via wp_die with 503 status code, if current
29
+ * user's IP is currently locked.
30
+ *
31
+ * @global AIO_WP_Security $aio_wp_security
32
+ * @param WP_Error|WP_User $user
33
+ * @return WP_User
34
+ */
35
+ public function block_ip_if_locked($user) {
36
+ global $aio_wp_security;
37
+ $user_locked = $this->check_locked_user();
38
+ if (null != $user_locked) {
39
+ $aio_wp_security->debug_logger->log_debug("Login attempt from blocked IP range - ".$user_locked['failed_login_ip'], 2);
40
+ // Allow the error message to be filtered.
41
+ $error_msg = apply_filters('aiowps_ip_blocked_error_msg', __('<strong>ERROR</strong>: Access from your IP address has been blocked for security reasons. Please contact the administrator.', 'all-in-one-wp-security-and-firewall'));
42
+ // If unlock requests are allowed, add the "Request Unlock" button to the message.
43
+ $unlock_form = '';
44
+ if ($aio_wp_security->configs->get_value('aiowps_allow_unlock_requests') == '1') {
45
+ $unlock_form = $this->get_unlock_request_form();
46
+ $error_msg .= $unlock_form;
47
+ }
48
+ $error_msg = apply_filters('aiowps_ip_blocked_output_page', $error_msg, $unlock_form); //filter the complete output of the locked page
49
+ wp_die($error_msg, __('Service Temporarily Unavailable', 'all-in-one-wp-security-and-firewall'), 503);
50
+ } else {
51
+ return $user;
52
+ }
 
 
 
 
 
53
  }
 
54
 
55
+ /**
56
+ * Check login captcha (if enabled).
57
+ *
58
+ * @global AIO_WP_Security $aio_wp_security
59
+ * @param WP_Error|WP_User $user
60
+ * @return WP_Error|WP_User
61
+ */
62
+ public function check_captcha($user) {
63
+ global $aio_wp_security;
64
+ if (is_wp_error($user)) {
65
+ // Authentication has failed already at some earlier step.
66
+ return $user;
67
+ }
68
 
69
+ if (! (isset($_POST['log']) && isset($_POST['pwd']))) {
70
+ // XML-RPC authentication (not via wp-login.php), nothing to do here.
71
+ return $user;
72
+ }
73
 
74
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_captcha') != '1') {
75
+ // Captcha not enabled, nothing to do here.
76
+ return $user;
77
+ }
78
+ $captcha_error = new WP_Error('authentication_failed', __('<strong>ERROR</strong>: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
79
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
80
+ if (false === $verify_captcha) {
81
+ return $captcha_error;
82
+ }
83
+ return $user;
84
+ }
85
+ /**
86
+ * Check, whether $user needs to be manually approved by site admin yet.
87
+ *
88
+ * @global AIO_WP_Security $aio_wp_security
89
+ * @param WP_Error|WP_User $user
90
+ * @return WP_Error|WP_User
91
+ */
92
+ public function check_manual_registration_approval($user) {
93
+ global $aio_wp_security;
94
+ if (!($user instanceof WP_User)) {
95
+ // Not a WP_User - nothing to do here.
96
+ return $user;
97
+ }
98
+ //Check if auto pending new account status feature is enabled
99
+ if ($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1') {
100
+ $aiowps_account_status = get_user_meta($user->ID, 'aiowps_account_status', true);
101
+ if ('pending' == $aiowps_account_status) {
102
+ // Account needs to be activated yet
103
+ return new WP_Error('account_pending', __('<strong>ACCOUNT PENDING</strong>: Your account is currently not active. An administrator needs to activate your account before you can login.', 'all-in-one-wp-security-and-firewall'));
104
+ }
105
+ }
106
+ return $user;
107
+ }
108
+ /**
109
+ * Handle post authentication steps (in case of failed login):
110
+ * - increment number of failed logins for $username
111
+ * - (optionally) lock the user
112
+ * - (optionally) display a generic error message
113
+ *
114
+ * @global AIO_WP_Security $aio_wp_security
115
+ * @param WP_Error|WP_User $user
116
+ * @param string $username
117
+ * @param string $password
118
+ * @return WP_Error|WP_User
119
+ */
120
+ public function post_authenticate($user, $username, $password) {
121
+ global $aio_wp_security;
122
+ if (!is_wp_error($user)) {
123
+ // Authentication has been successful, there's nothing to do here.
124
+ return $user;
125
+ }
126
+ if (empty($username) || empty($password)) {
127
+ // Neither log nor block login attempts with empty username or password.
128
+ return $user;
129
+ }
130
+ if ($user->get_error_code() === 'account_pending') {
131
+ // Neither log nor block users attempting to log in before their registration is approved.
132
+ return $user;
133
+ }
134
+ // Login failed for non-trivial reason
135
+ $this->increment_failed_logins($username);
136
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_lockdown') == '1') {
137
+ $is_whitelisted = false;
138
+ //check if lockdown whitelist enabled
139
+ if ($aio_wp_security->configs->get_value('aiowps_lockdown_enable_whitelisting') == '1') {
140
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
141
+ $whitelisted_ips = $aio_wp_security->configs->get_value('aiowps_lockdown_allowed_ip_addresses');
142
+ $is_whitelisted = AIOWPSecurity_Utility_IP::is_ip_whitelisted($ip, $whitelisted_ips);
143
+ }
 
 
144
 
145
+ if (false === $is_whitelisted) {
146
+ // Too many failed logins from user's IP?
147
+ $login_attempts_permitted = absint($aio_wp_security->configs->get_value('aiowps_max_login_attempts'));
148
+ $too_many_failed_logins = $login_attempts_permitted <= $this->get_login_fail_count();
149
+ // Is an invalid username or email the reason for login error?
150
+ $invalid_username = ($user->get_error_code() === 'invalid_username' || $user->get_error_code() == 'invalid_email');
151
+ // Should an invalid username be immediately locked?
152
+ $invalid_username_lockdown = $aio_wp_security->configs->get_value('aiowps_enable_invalid_username_lockdown') == '1';
153
+ $lock_invalid_username = $invalid_username && $invalid_username_lockdown;
154
+ // Should an invalid username be blocked as per blacklist?
155
+ $instant_lockout_users_list = $aio_wp_security->configs->get_value('aiowps_instantly_lockout_specific_usernames');
156
+ if (!is_array($instant_lockout_users_list)) {
157
+ $instant_lockout_users_list = array();
158
+ }
159
+ $username_blacklisted = $invalid_username && in_array($username, $instant_lockout_users_list);
160
+ if ($too_many_failed_logins || $lock_invalid_username || $username_blacklisted) {
161
+ $this->lock_the_user($username, 'login_fail');
162
+ }
163
+ }
164
+ }
 
165
 
166
+ if ($aio_wp_security->configs->get_value('aiowps_set_generic_login_msg') == '1') {
167
+ // Return generic error message if configured
168
+ return new WP_Error('authentication_failed', __('<strong>ERROR</strong>: Invalid login credentials.', 'all-in-one-wp-security-and-firewall'));
169
+ }
170
+ return $user;
171
+ }
172
+ /**
173
+ * This function queries the aiowps_login_lockdown table.
174
+ * If the release_date has not expired AND the current visitor IP addr matches
175
+ * it will return a record
176
+ */
177
+ public function check_locked_user() {
178
+ global $wpdb;
179
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
180
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
181
+ if (empty($ip)) return false;
182
+ $now = current_time('mysql');
183
+ $locked_user = $wpdb->get_row("SELECT * FROM $login_lockdown_table " . "WHERE release_date > '".$now."' AND " . "failed_login_ip = '" . esc_sql($ip) . "'", ARRAY_A);
184
+ return $locked_user;
185
+ }
186
+ /**
187
+ * This function queries the aiowps_failed_logins table and returns the number of failures for current IP range within allowed failure period
188
+ */
189
+ public function get_login_fail_count() {
190
+ global $wpdb, $aio_wp_security;
191
+ $failed_logins_table = AIOWPSEC_TBL_FAILED_LOGINS;
192
+ $login_retry_interval = $aio_wp_security->configs->get_value('aiowps_retry_time_period');
193
+ $now = current_time('mysql', true);
194
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
195
+ if (empty($ip)) return false;
196
+ $login_failures = $wpdb->get_var("SELECT COUNT(ID) FROM $failed_logins_table " . "WHERE failed_login_date + INTERVAL " . esc_sql($login_retry_interval) . " MINUTE > '" . esc_sql($now) . "' AND " . "login_attempt_ip = '" . esc_sql($ip) . "'");
197
+ return $login_failures;
198
+ }
199
+ /**
200
+ * Adds an entry to the `aiowps_login_lockdown` table.
201
+ *
202
+ * @param string $username User's username or email
203
+ * @param string $lock_reason
204
+ */
205
+ public function lock_the_user($username, $lock_reason = 'login_fail') {
206
+ global $wpdb, $aio_wp_security;
207
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
208
+ $lock_minutes = $aio_wp_security->configs->get_value('aiowps_lockout_time_length');
209
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
210
+ if (empty($ip)) return;
211
+ $ip_range = AIOWPSecurity_Utility_IP::get_sanitized_ip_range($ip); //Get the IP range of the current user
212
+ $user = is_email($username) ? get_user_by('email', $username) : get_user_by('login', $username); //Returns WP_User object if exists
213
+ $ip_range = apply_filters('aiowps_before_lockdown', $ip_range);
214
+ if ($user) {
215
+ //If the login attempt was made using a valid user set variables for DB storage later on
216
+ $user_id = $user->ID;
217
+ } else {
218
+ //If the login attempt was made using a non-existent user then let's set user_id to blank and record the attempted user login name for DB storage later on
219
+ $user_id = 0;
220
+ }
221
+ $ip_range_str = esc_sql($ip_range).'.*';// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
 
 
 
 
 
 
 
 
 
222
 
223
+ $lock_time = current_time('mysql');
224
+ $date = new DateTime($lock_time);
225
+ $add_interval = 'PT'.absint($lock_minutes).'M';
226
+ $date->add(new DateInterval($add_interval));
227
+ $release_time = $date->format('Y-m-d H:i:s');
228
 
229
+ $data = array('user_id' => $user_id, 'user_login' => $username, 'lockdown_date' => $lock_time, 'release_date' => $release_time, 'failed_login_IP' => $ip, 'lock_reason' => $lock_reason);
230
+ $format = array('%d', '%s', '%s', '%s', '%s', '%s');
231
+ $result = $wpdb->insert($login_lockdown_table, $data, $format);
232
 
233
+ if (false === $result) {
234
+ $aio_wp_security->debug_logger->log_debug("Error inserting record into ".$login_lockdown_table, 4);//Log the highly unlikely event of DB error
235
+ } else {
236
+ do_action('aiowps_lockdown_event', $ip_range, $username);
237
+ $this->send_ip_lock_notification_email($username, $ip_range, $ip);
238
+ $aio_wp_security->debug_logger->log_debug("The following IP address range has been locked out for exceeding the maximum login attempts: ".$ip_range, 2);//Log the lockdown event
239
+ }
240
+ }
241
+ /**
242
+ * Adds an entry to the `aiowps_failed_logins` table.
243
+ *
244
+ * @param string $username User's username or email
245
+ */
246
+ public function increment_failed_logins($username) {
247
+ global $wpdb, $aio_wp_security;
248
+ $login_fails_table = AIOWPSEC_TBL_FAILED_LOGINS;
249
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
250
+ if (empty($ip)) return;
251
+ $user = is_email($username) ? get_user_by('email', $username) : get_user_by('login', $username); //Returns WP_User object if it exists
252
+ if ($user) {
253
+ //If the login attempt was made using a valid user set variables for DB storage later on
254
+ $user_id = $user->ID;
255
+ } else {
256
+ //If the login attempt was made using a non-existent user then let's set user_id to blank and record the attempted user login name for DB storage later on
257
+ $user_id = 0;
258
+ }
259
+ $ip_str = esc_sql($ip);
260
+ $now = current_time('mysql', true);
261
+ $data = array('user_id' => $user_id, 'user_login' => $username, 'failed_login_date' => $now, 'login_attempt_ip' => $ip_str);
262
+ $format = array('%d', '%s', '%s', '%s');
263
+ $result = $wpdb->insert($login_fails_table, $data, $format);
264
+ if (false === $result) {
265
+ $aio_wp_security->debug_logger->log_debug("Error inserting record into ".$login_fails_table, 4);//Log the highly unlikely event of DB error
266
+ }
267
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
 
269
+ /**
270
+ * Send IP Lock notification
271
+ *
272
+ * @param string $username User's username or email
273
+ * @param int $ip_range
274
+ * @param int $ip
275
+ * @return void
276
+ */
277
+ public function send_ip_lock_notification_email($username, $ip_range, $ip) {
278
+ global $aio_wp_security;
279
+ $email_notification_enabled = $aio_wp_security->configs->get_value('aiowps_enable_email_notify');
280
+ if (1 == $email_notification_enabled) {
281
+ $to_email_address = $aio_wp_security->configs->get_value('aiowps_email_address');
282
+ $subject = '['.get_option('home').'] '. __('Site Lockout Notification', 'all-in-one-wp-security-and-firewall');
283
+ $email_msg = __('A lockdown event has occurred due to too many failed login attempts or invalid username:', 'all-in-one-wp-security-and-firewall')."\n";
284
+ $email_msg .= __('Username:', 'all-in-one-wp-security-and-firewall') . ' ' . $username . "\n";
285
+ $email_msg .= __('IP Address:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip . "\n\n";
286
+ $email_msg .= __('IP Range:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip_range . '.*' . "\n\n";
287
+ $email_msg .= __("Log into your site's WordPress administration panel to see the duration of the lockout or to unlock the user.", 'all-in-one-wp-security-and-firewall') . "\n";
288
+ $site_title = get_bloginfo('name');
289
+ $from_name = empty($site_title) ? 'WordPress' : $site_title;
290
+ $email_header = 'From: '.$from_name.' <'.get_bloginfo('admin_email').'>' . "\r\n\\";
291
+ $sendMail = wp_mail($to_email_address, $subject, $email_msg, $email_header);
292
+ if (false === $sendMail) {
293
+ $aio_wp_security->debug_logger->log_debug("Lockout notification email failed to send to ".$to_email_address." for IP ".$ip, 4);
294
+ }
295
+ }
296
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
 
298
+ /**
299
+ * Generates and returns an unlock request link which will be used to send to the user.
300
+ *
301
+ * @global type $wpdb
302
+ * @global AIO_WP_Security $aio_wp_security
303
+ * @param type $ip_range
304
+ * @return string or false on failure
305
+ */
306
+ public static function generate_unlock_request_link($ip_range) {
307
+ //Get the locked user row from lockdown table
308
+ global $wpdb, $aio_wp_security;
309
+ $unlock_link = '';
310
+ $lockdown_table_name = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
311
+ $secret_rand_key = (md5(uniqid(rand(), true)));
312
+ $unlock_request_date_time = date("Y-m-d H:i:s");
313
+ $res = $wpdb->query($wpdb->prepare("UPDATE $lockdown_table_name SET unlock_key = %s WHERE release_date > %s AND failed_login_ip LIKE %s", $secret_rand_key, $unlock_request_date_time, "%" . esc_sql($ip_range) . "%"));
314
+ if (null == $res) {
315
+ $aio_wp_security->debug_logger->log_debug("No locked user found with IP range ".$ip_range, 4);
316
+ return false;
317
+ } else {
318
+ //Check if unlock requestor submitted from a woocommerce account login page
319
+ if (isset($_POST['aiowps-woo-login'])) {
320
+ $date_time = current_time('mysql');
321
+ $data = array('date_time' => $date_time, 'meta_key1' => 'woo_unlock_request_key', 'meta_value1' => $secret_rand_key);
322
+ $result = $wpdb->insert(AIOWPSEC_TBL_GLOBAL_META_DATA, $data);
323
+ if (false === $result) {
324
+ $aio_wp_security->debug_logger->log_debug("generate_unlock_request_link() - Error inserting woo_unlock_request_key to AIOWPSEC_TBL_GLOBAL_META_DATA table for secret key ".$secret_rand_key, 4);
325
+ }
326
+ }
327
+ $query_param = array('aiowps_auth_key' => $secret_rand_key);
328
+ $wp_site_url = AIOWPSEC_WP_URL;
329
+ $unlock_link = esc_url(add_query_arg($query_param, $wp_site_url));
330
+ }
331
+ return $unlock_link;
332
+ }
333
 
334
+ /**
335
+ * This function will process an unlock request when someone clicks on the special URL
336
+ * It will check if the special random code matches that in lockdown table for the relevant user
337
+ * If so, it will unlock the user
338
+ *
339
+ * @param string $unlock_key
340
+ * @return void
341
+ */
342
+ public static function process_unlock_request($unlock_key) {
343
+ global $wpdb, $aio_wp_security;
344
+ $lockdown_table_name = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
345
+ $unlock_request_date_time = date("Y-m-d H:i:s");
346
+ $unlock_command = $wpdb->prepare("UPDATE ".$lockdown_table_name." SET release_date = %s WHERE unlock_key = %s", $unlock_request_date_time, $unlock_key);
347
+ $result = $wpdb->query($unlock_command);
348
+ if (false === $result) {
349
+ $aio_wp_security->debug_logger->log_debug("Error unlocking user with unlock_key ".$unlock_key, 4);
350
+ } else {
351
+ //Now check if this unlock operation is for a woocommerce login
352
+ $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
353
+ $sql = $wpdb->prepare("SELECT * FROM $aiowps_global_meta_tbl_name WHERE meta_key1=%s AND meta_value1=%s", 'woo_unlock_request_key', $unlock_key);
354
+ $woo_result = $wpdb->get_row($sql, OBJECT);
355
+ if (empty($woo_result)) {
356
+ $woo_unlock = false;
357
+ } else {
358
+ $woo_unlock = true;
359
+ }
360
+ if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page')=='1') {
361
+ if (get_option('permalink_structure')) {
362
+ $home_url = trailingslashit(home_url());
363
+ } else {
364
+ $home_url = trailingslashit(home_url()) . '?';
365
+ }
366
+ if ($woo_unlock) {
367
+ $login_url = wc_get_page_permalink('myaccount'); //redirect to woo login page if applicable
368
+ //Now let's cleanup after ourselves and delete the woo-related row in the AIOWPSEC_TBL_GLOBAL_META_DATA table
369
+ $delete = $wpdb->delete($aiowps_global_meta_tbl_name, array('meta_key1' => 'woo_unlock_request_key', 'meta_value1' => $unlock_key));
370
+ if (false === $delete) {
371
+ $aio_wp_security->debug_logger->log_debug("process_unlock_request(): Error deleting row from AIOWPSEC_TBL_GLOBAL_META_DATA for meta_key1=woo_unlock_request_key and meta_value1=".$unlock_key, 4);
372
+ }
373
+ } else {
374
+ $login_url = $home_url.$aio_wp_security->configs->get_value('aiowps_login_page_slug');
375
+ }
376
 
377
+ AIOWPSecurity_Utility::redirect_to_url($login_url);
378
+ } else {
379
+ AIOWPSecurity_Utility::redirect_to_url(wp_login_url());
380
+ }
381
+ }
382
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
 
384
+ /**
385
+ * This function sends an unlock request email to a locked out user
386
+ *
387
+ * @param string $email
388
+ * @param string $unlock_link
389
+ * @return void
390
+ */
391
+ public static function send_unlock_request_email($email, $unlock_link) {
392
+ global $aio_wp_security;
393
+ $subject = '['.get_option('siteurl').'] '. __('Unlock Request Notification', 'all-in-one-wp-security-and-firewall');
394
+ $email_msg = sprintf(__('You have requested for the account with email address %s to be unlocked. Please click the link below to unlock your account:', 'all-in-one-wp-security-and-firewall'), $email) . "\n" . sprintf(__('Unlock link: %s', 'all-in-one-wp-security-and-firewall'), $unlock_link) . "\n\n" . __('After clicking the above link you will be able to login to the WordPress administration panel.', 'all-in-one-wp-security-and-firewall') . "\n";
395
+ $site_title = get_bloginfo('name');
396
+ $from_name = empty($site_title) ? 'WordPress' : $site_title;
397
+ $email_header = 'From: '.$from_name.' <'.get_bloginfo('admin_email').'>' . "\r\n\\";
398
+ $sendMail = wp_mail($email, $subject, $email_msg, $email_header);
399
+ if (false === $sendMail) {
400
+ $aio_wp_security->debug_logger->log_debug("Unlock Request Notification email failed to send to " . $email, 4);
401
+ }
402
+ }
 
 
 
403
 
404
+ /**
405
+ * Check the settings and log the user after the configured time period
406
+ *
407
+ * @return void
408
+ */
409
+ public function aiowps_force_logout_action_handler() {
410
+ global $aio_wp_security;
411
+ //$aio_wp_security->debug_logger->log_debug("Force Logout - Checking if any user need to be logged out...");
412
+ //if this feature is enabled then do something
413
+ if ($aio_wp_security->configs->get_value('aiowps_enable_forced_logout')=='1') {
414
+ if (is_user_logged_in()) {
415
+ $current_user = wp_get_current_user();
416
+ $user_id = $current_user->ID;
417
+ $current_time = current_time('mysql');
418
+ $login_time = $this->get_wp_user_last_login_time($user_id);
419
+ $diff = strtotime($current_time) - strtotime($login_time);
420
+ $logout_time_interval_value = $aio_wp_security->configs->get_value('aiowps_logout_time_period');
421
+ $logout_time_interval_val_seconds = $logout_time_interval_value * 60;
422
+ if ($diff > $logout_time_interval_val_seconds) {
423
+ $aio_wp_security->debug_logger->log_debug("Force Logout - This user logged in more than (".$logout_time_interval_value.") minutes ago. Doing a force log out for the user with username: ".$current_user->user_login);
424
+ $this->wp_logout_action_handler(); //this will register the logout time/date in the logout_date column
425
 
426
+ $curr_page_url = AIOWPSecurity_Utility::get_current_page_url();
427
+ $after_logout_payload = array('redirect_to' => $curr_page_url, 'msg' => $this->key_login_msg.'=session_expired');
428
+ //Save some of the logout redirect data to a transient
429
+ AIOWPSecurity_Utility::is_multisite_install() ? set_site_transient('aiowps_logout_payload', $after_logout_payload, 30 * 60) : set_transient('aiowps_logout_payload', $after_logout_payload, 30 * 60);
430
+ $logout_url = AIOWPSEC_WP_URL.'?aiowpsec_do_log_out=1';
431
+ $logout_url = AIOWPSecurity_Utility::add_query_data_to_url($logout_url, 'al_additional_data', '1');
432
+ $logout_url_with_nonce = html_entity_decode(wp_nonce_url($logout_url, 'aio_logout'));
433
+ AIOWPSecurity_Utility::redirect_to_url($logout_url_with_nonce);
434
+ }
435
+ }
436
+ }
437
+ }
438
 
439
+ public function get_wp_user_last_login_time($user_id) {
440
+ $last_login = get_user_meta($user_id, 'last_login_time', true);
441
+ return $last_login;
442
+ }
443
+ public static function wp_login_action_handler($user_login, $user = '') {
444
+ global $wpdb, $aio_wp_security;
445
+ $login_activity_table = AIOWPSEC_TBL_USER_LOGIN_ACTIVITY;
 
 
 
 
 
 
 
 
 
 
 
446
 
447
+ if ('' == $user) {
448
+ //Try and get user object
449
+ $user = get_user_by('login', $user_login); //This should return WP_User obj
450
+ if (!$user) {
451
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_User_Login::wp_login_action_handler: Unable to get WP_User object for login ".$user_login, 4);
452
+ return;
453
+ }
454
+ }
455
+ $login_date_time = current_time('mysql');
456
+ update_user_meta($user->ID, 'last_login_time', $login_date_time); //store last login time in meta table
457
+ $curr_ip_address = AIOWPSecurity_Utility_IP::get_user_ip_address();
458
+ $data = array('user_id' => $user->ID, 'user_login' => $user_login, 'login_date' => $login_date_time, 'login_ip' => $curr_ip_address);
459
+ $format = array('%d', '%s', '%s', '%s');
460
+ $result = $wpdb->insert($login_activity_table, $data, $format);
461
+ if (false === $result) {
462
+ $aio_wp_security->debug_logger->log_debug("Error inserting record into ".$login_activity_table, 4);//Log the highly unlikely event of DB error
463
+ }
464
 
465
+ }
466
+ /**
467
+ * The handler for logout events, ie, uses the WP "clear_auth_cookies" action.
468
+ * Modifies the login activity record for the current user by registering the logout time/date in the logout_date column.
469
+ * (NOTE: Because of the way we are doing a force logout, the "clear_auth_cookies" hook does not fire.
470
+ * upon auto logout. The current workaround is to call this function directly from the aiowps_force_logout_action_handler() when
471
+ * an auto logout occurs due to the "force logout" feature).
472
+ */
473
+ public function wp_logout_action_handler() {
474
+ global $wpdb, $aio_wp_security;
475
+ $current_user = wp_get_current_user();
476
+ $ip_addr = AIOWPSecurity_Utility_IP::get_user_ip_address();
477
+ $user_id = $current_user->ID;
478
+ //Clean up transients table
479
+ $this->cleanup_users_online_transient($user_id, $ip_addr);
480
+ $login_activity_table = AIOWPSEC_TBL_USER_LOGIN_ACTIVITY;
481
+ $logout_date_time = current_time('mysql');
482
+ $data = array('logout_date' => $logout_date_time);
483
+ $where = array('user_id' => $user_id, 'login_ip' => $ip_addr, 'logout_date' => '1000-10-10 10:00:00');
484
+ $result = $wpdb->update($login_activity_table, $data, $where);
485
+ if (false === $result) {
486
+ $aio_wp_security->debug_logger->log_debug("Error inserting record into ".$login_activity_table, 4);//Log the highly unlikely event of DB error
487
+ }
488
+ }
 
 
489
 
490
+ /**
491
+ * Update the 'users_online' transient
492
+ *
493
+ * @return void
494
+ */
495
+ public function update_users_online_transient() {
496
+ if (is_user_logged_in()) {
497
+ $is_multi_site = AIOWPSecurity_Utility::is_multisite_install();
498
+ $current_user_ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
499
+ // get the logged in users list from transients entry
500
+ $logged_in_users = ($is_multi_site ? get_site_transient('users_online') : get_transient('users_online'));
501
+ $current_user = wp_get_current_user();
502
+ $current_user = $current_user->ID;
503
+ $current_time = current_time('timestamp');
504
+ $current_user_info = array();
505
 
506
+ // Store last activity time and ip address in transient entry
507
+ if ($is_multi_site) {
508
+ $current_blog_id = get_current_blog_id();
509
+ // For multi-sites also store blog_id
510
+ $current_user_info = array("user_id" => $current_user, "last_activity" => $current_time, "ip_address" => $current_user_ip, "blog_id" => $current_blog_id);
511
+ } else {
512
+ $current_user_info = array("user_id" => $current_user, "last_activity" => $current_time, "ip_address" => $current_user_ip, "blog_id" => false);
513
+ }
514
 
515
+ if (empty($logged_in_users)) {
516
+ // case when "users_online" transient has been deleted after expiry or is empty
517
+ $logged_in_users = array();
518
+ $logged_in_users[] = $current_user_info;
519
+ $is_multi_site ? set_site_transient('users_online', $logged_in_users, 30 * 60) : set_transient('users_online', $logged_in_users, 30 * 60);
520
+ } else {
521
+ $key = 0;
522
+ $update_existing = false;
523
+ $item_index = 0;
524
+ foreach ($logged_in_users as $value) {
525
+ $value_minus_activity = $value;
526
+ unset($value_minus_activity['last_activity']);
527
+ $current_user_minus_activity = $current_user_info;
528
+ unset($current_user_minus_activity['last_activity']);
529
+ // Check if current user we're looking at has an entry in the 'users_online' transient
530
+ if (empty(array_diff($current_user_minus_activity, $value_minus_activity))) {
531
+ if ($value['last_activity'] < ($current_time - (15 * 60))) {
532
+ $update_existing = true;
533
+ $item_index = $key;
534
+ break;
535
+ } else {
536
+ return; // do nothing and just return
537
+ }
538
+ }
539
+ $key++;
540
+ }
 
 
 
 
 
 
541
 
542
+ if ($update_existing) {
543
+ // Update transient if the last activity was over 15 min ago for this user
544
+ $logged_in_users[$item_index] = $current_user_info;
545
+ AIOWPSecurity_Utility::is_multisite_install() ? set_site_transient('users_online', $logged_in_users, 30 * 60) : set_transient('users_online', $logged_in_users, 30 * 60);
546
+ } else {
547
+ $logged_in_users[] = $current_user_info;
548
+ AIOWPSecurity_Utility::is_multisite_install() ? set_site_transient('users_online', $logged_in_users, 30 * 60) : set_transient('users_online', $logged_in_users, 30 * 60);
549
+ }
550
+ }
551
+ }
552
+ }
553
 
554
+ /**
555
+ * This will clean up the "users_online" transient entry for the current user when a logout occurs
556
+ *
557
+ * @param int $user_id
558
+ * @param int $ip_addr
559
+ * @return void
560
+ */
561
+ public function cleanup_users_online_transient($user_id, $ip_addr) {
562
+ $is_multi_site = AIOWPSecurity_Utility::is_multisite_install();
563
+ if ($is_multi_site) {
564
+ $current_blog_id = get_current_blog_id();
565
+ $logged_in_users = AIOWPSecurity_User_Login::get_subsite_logged_in_users($current_blog_id);
566
+ } else {
567
+ $logged_in_users = get_transient('users_online');
568
+ }
569
 
570
+ if (empty($logged_in_users)) {
571
+ return;
572
+ }
573
+ $j = 0;
574
+ foreach ($logged_in_users as $value) {
575
+ if ($value['user_id'] == $user_id && strcmp($value['ip_address'], $ip_addr) == 0) {
576
+ unset($logged_in_users[$j]);
577
+ break;
578
+ }
579
+ $j++;
580
+ }
 
 
 
581
 
582
+ // Save the transient
583
+ if ($is_multi_site) {
584
+ set_site_transient('users_online', $logged_in_users, 30 * 60);
585
+ } else {
586
+ set_transient('users_online', $logged_in_users, 30 * 60);
587
+ }
588
+ return;
589
+ }
590
 
591
+ /**
592
+ * The handler for the WP "login_message" filter
593
+ * Adds custom messages to the other messages that appear above the login form.
594
+ *
595
+ * NOTE: This method is automatically called by WordPress for displaying
596
+ * text above the login form.
597
+ *
598
+ * @param string $message the output from earlier login_message filters
599
+ * @return string
600
+ */
601
+ public function aiowps_login_message($message = '') {
602
+ global $aio_wp_security;
603
+ $msg = '';
604
+ if (isset($_GET[$this->key_login_msg]) && !empty($_GET[$this->key_login_msg])) {
605
+ $logout_msg = strip_tags($_GET[$this->key_login_msg]);
606
+ }
607
+ if (!empty($logout_msg)) {
608
+ switch ($logout_msg) {
609
+ case 'session_expired':
610
+ $msg = sprintf(__('Your session has expired because it has been over %d minutes since your last login.', 'all-in-one-wp-security-and-firewall'), $aio_wp_security->configs->get_value('aiowps_logout_time_period'));
611
+ $msg .= ' ' . __('Please log back in to continue.', 'all-in-one-wp-security-and-firewall');
612
+ break;
613
+ case 'admin_user_changed':
614
+ $msg = __('You were logged out because you just changed the "admin" username.', 'all-in-one-wp-security-and-firewall');
615
+ $msg .= ' ' . __('Please log back in to continue.', 'all-in-one-wp-security-and-firewall');
616
+ break;
617
+ default:
618
+ }
619
+ }
620
+ if (!empty($msg)) {
621
+ $msg = htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');
622
+ $message .= '<p class="login message">'. $msg . '</p>';
623
+ }
624
+ return $message;
625
+ }
626
+ /**
627
+ * This function will generate an unlock request form to be inserted inside
628
+ * error message when user gets locked out.
629
+ *
630
+ * @return string
631
+ */
632
+ public function get_unlock_request_form() {
633
+ global $aio_wp_security;
634
+ $unlock_request_form = '';
635
+ //Let's encode some hidden data and make a form
636
+ $unlock_secret_string = $aio_wp_security->configs->get_value('aiowps_unlock_request_secret_key');
637
+ $current_time = time();
638
+ $enc_result = base64_encode($current_time.$unlock_secret_string);
639
+ $unlock_request_form .= '<form method="post" action=""><div style="padding-bottom:10px;"><input type="hidden" name="aiowps-unlock-string-info" id="aiowps-unlock-string-info" value="'.$enc_result.'" />';
640
+ $unlock_request_form .= '<input type="hidden" name="aiowps-unlock-temp-string" id="aiowps-unlock-temp-string" value="'.$current_time.'" />';
641
+ if (isset($_POST['woocommerce-login-nonce'])) {
642
+ $unlock_request_form .= '<input type="hidden" name="aiowps-woo-login" id="aiowps-woo-login" value="1" />';
643
+ }
644
+ $unlock_request_form .= '<button type="submit" name="aiowps_unlock_request" id="aiowps_unlock_request" class="button">'.__('Request Unlock', 'all-in-one-wp-security-and-firewall').'</button></div></form>';
645
+ return $unlock_request_form;
646
+ }
 
 
 
 
 
 
647
 
648
+ /**
649
+ * Returns all logged in users for specific subsite of multisite installation
650
+ * Checks the aiowps transient 'users_online'
651
+ *
652
+ * @param type $blog_id
653
+ * @return array|bool
654
+ */
655
+ public static function get_subsite_logged_in_users($blog_id = 0) {
656
+ if (empty($blog_id)) return false;
657
 
658
+ $subsite_logged_in_users = array();
659
+ if (AIOWPSecurity_Utility::is_multisite_install()) {
660
+ // this contains all logged in users sitewide across subsites
661
+ $users_online = get_site_transient('users_online');
662
+ if (empty($users_online)) {
663
+ return array();
664
+ }
665
+ // Extract only logged in users for current subsite
666
+ foreach ($users_online as $user) {
667
+ if (isset($user['blog_id']) && $user['blog_id'] == $blog_id) {
668
+ $subsite_logged_in_users[] = $user;
669
+ }
670
+ }
671
+ }
672
+ return $subsite_logged_in_users;
673
+ }
674
 
675
  }
classes/wp-security-user-registration.php CHANGED
@@ -1,80 +1,79 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_User_Registration
7
- {
8
 
9
- function __construct()
10
- {
11
- global $aio_wp_security;
12
- add_action('user_register', array($this, 'aiowps_user_registration_action_handler'));
13
- if($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1'){
14
- add_filter('registration_errors', array($this, 'aiowps_validate_registration_with_captcha'), 10, 3);
15
- }
16
- }
17
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
- /*
20
- * This function will add a special meta string in the users table
21
- * Meta field name: 'aiowps_account_status'
22
- * Meta field value: 'pending'
23
- */
24
- function aiowps_user_registration_action_handler($user_id)
25
- {
26
- global $wpdb, $aio_wp_security;
27
- //Check if auto pending new account status feature is enabled
28
- if ($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1')
29
- {
30
- if ( isset($_REQUEST['action']) && 'createuser' == $_REQUEST['action'] ) {
31
- return; //if the user has been added from admin side don't put in pending state
32
- }
33
- $res = add_user_meta($user_id, 'aiowps_account_status', 'pending');
34
- if (!$res){
35
- $aio_wp_security->debug_logger->log_debug("aiowps_user_registration_action_handler: Error adding user meta data: aiowps_account_status",4);
36
- }
37
- $user_ip_address = AIOWPSecurity_Utility_IP::get_user_ip_address();
38
- $res = add_user_meta($user_id, 'aiowps_registrant_ip', $user_ip_address);
39
- if (!$res){
40
- $aio_wp_security->debug_logger->log_debug("aiowps_user_registration_action_handler: Error adding user meta data: aiowps_registrant_ip",4);
41
- }
42
 
43
- }
44
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
- /*
47
- * This function will set the special meta string in the usermeta table so that the account becomes active
48
- * Meta field name: 'aiowps_account_status'
49
- * Meta field values: 'active', 'pending', etc
50
- */
51
- function aiowps_set_user_account_status($user_id, $status)
52
- {
53
- global $wpdb, $aio_wp_security;
54
- $res = update_user_meta($user_id, 'aiowps_account_status', $status);
55
- if (!$res){
56
- $aio_wp_security->debug_logger->log_debug("aiowps_set_user_account_status: Error updating user meta data: aiowps_account_status",4);
57
- }
58
- }
59
-
60
- function aiowps_validate_registration_with_captcha($errors, $sanitized_user_login, $user_email)
61
- {
62
- global $aio_wp_security;
63
-
64
- $locked = $aio_wp_security->user_login_obj->check_locked_user();
65
- if($locked == null){
66
- //user is not locked continue
67
- }else{
68
- $errors->add('authentication_failed', __('<strong>ERROR</strong>: You are not allowed to register because your IP address is currently locked!', 'all-in-one-wp-security-and-firewall'));
69
- return $errors;
70
- }
71
- $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
72
- if($verify_captcha === false)
73
- {
74
- // wrong answer was entered
75
- $errors->add('authentication_failed', __('<strong>ERROR</strong>: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
76
- return $errors;
77
- }
78
- return $errors;
79
- }
80
- }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_User_Registration {
 
7
 
8
+ public function __construct() {
9
+ global $aio_wp_security;
10
+ add_action('user_register', array($this, 'aiowps_user_registration_action_handler'));
11
+ if ($aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') {
12
+ add_filter('registration_errors', array($this, 'aiowps_validate_registration_with_captcha'), 10, 3);
13
+ }
14
+ }
15
+
16
+ /**
17
+ * This public function will add a special meta string in the users table
18
+ * Meta field name: 'aiowps_account_status'
19
+ * Meta field value: 'pending'
20
+ *
21
+ * @param int $user_id
22
+ * @return void
23
+ */
24
+ public function aiowps_user_registration_action_handler($user_id) {
25
+ global $aio_wp_security;
26
+ //Check if auto pending new account status feature is enabled
27
+ if ($aio_wp_security->configs->get_value('aiowps_enable_manual_registration_approval') == '1') {
28
+ if (isset($_REQUEST['action']) && 'createuser' == $_REQUEST['action']) {
29
+ return; //if the user has been added from admin side don't put in pending state
30
+ }
31
+ $res = add_user_meta($user_id, 'aiowps_account_status', 'pending');
32
+ if (!$res) {
33
+ $aio_wp_security->debug_logger->log_debug("aiowps_user_registration_action_handler: Error adding user meta data: aiowps_account_status", 4);
34
+ }
35
+ $user_ip_address = AIOWPSecurity_Utility_IP::get_user_ip_address();
36
+ $res = add_user_meta($user_id, 'aiowps_registrant_ip', $user_ip_address);
37
+ if (!$res) {
38
+ $aio_wp_security->debug_logger->log_debug("aiowps_user_registration_action_handler: Error adding user meta data: aiowps_registrant_ip", 4);
39
+ }
40
 
41
+ }
42
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ /**
45
+ * This public function will set the special meta string in the usermeta table so that the account becomes active
46
+ * Meta field name: 'aiowps_account_status'
47
+ * Meta field values: 'active', 'pending', etc
48
+ *
49
+ * @param int $user_id
50
+ * @param string $status
51
+ * @return void
52
+ */
53
+ public function aiowps_set_user_account_status($user_id, $status) {
54
+ global $aio_wp_security;
55
+ $res = update_user_meta($user_id, 'aiowps_account_status', $status);
56
+ if (!$res) {
57
+ $aio_wp_security->debug_logger->log_debug("aiowps_set_user_account_status: Error updating user meta data: aiowps_account_status", 4);
58
+ }
59
+ }
60
+
61
+ public function aiowps_validate_registration_with_captcha($errors) {
62
+ global $aio_wp_security;
63
 
64
+ $locked = $aio_wp_security->user_login_obj->check_locked_user();
65
+ if (null == $locked) {
66
+ //user is not locked continue
67
+ } else {
68
+ $errors->add('authentication_failed', __('<strong>ERROR</strong>: You are not allowed to register because your IP address is currently locked!', 'all-in-one-wp-security-and-firewall'));
69
+ return $errors;
70
+ }
71
+ $verify_captcha = $aio_wp_security->captcha_obj->verify_captcha_submit();
72
+ if (false === $verify_captcha) {
73
+ // wrong answer was entered
74
+ $errors->add('authentication_failed', __('<strong>ERROR</strong>: Your answer was incorrect - please try again.', 'all-in-one-wp-security-and-firewall'));
75
+ return $errors;
76
+ }
77
+ return $errors;
78
+ }
79
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/wp-security-utility-file.php CHANGED
@@ -1,445 +1,427 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Utility_File
7
- {
8
-
9
- /* This variable will be an array which will contain all of the files and/or directories we wish to check permissions for */
10
- public $files_and_dirs_to_check;
11
-
12
- function __construct(){
13
- /* Let's initiliaze our class variable array with all of the files and/or directories we wish to check permissions for.
14
- * NOTE: we can add to this list in future if we wish
15
- */
16
-
17
- //Get wp-config.php file path
18
- if ( !function_exists( 'get_home_path' ) ) require_once( ABSPATH. '/wp-admin/includes/file.php' );
19
- $wp_config_path = AIOWPSecurity_Utility_File::get_wp_config_file_path();
20
- $home_path = get_home_path();
21
-
22
- $this->files_and_dirs_to_check = array(
23
- array('name'=>'root directory','path'=>ABSPATH,'permissions'=>'0755'),
24
- array('name'=>'wp-includes/','path'=>ABSPATH."wp-includes",'permissions'=>'0755'),
25
- array('name'=>'.htaccess','path'=>$home_path.".htaccess",'permissions'=>'0644'),
26
- array('name'=>'wp-admin/index.php','path'=>ABSPATH."wp-admin/index.php",'permissions'=>'0644'),
27
- array('name'=>'wp-admin/js/','path'=>ABSPATH."wp-admin/js/",'permissions'=>'0755'),
28
- array('name'=>'wp-content/themes/','path'=>ABSPATH."wp-content/themes",'permissions'=>'0755'),
29
- array('name'=>'wp-content/plugins/','path'=>ABSPATH."wp-content/plugins",'permissions'=>'0755'),
30
- array('name'=>'wp-admin/','path'=>ABSPATH."wp-admin",'permissions'=>'0755'),
31
- array('name'=>'wp-content/','path'=>ABSPATH."wp-content",'permissions'=>'0755'),
32
- array('name'=>'wp-config.php','path'=>$wp_config_path,'permissions'=>'0640')
33
- //Add as many files or dirs as needed by following the convention above
34
- );
35
-
36
- }
37
-
38
- static function get_wp_config_file_path()
39
- {
40
- $wp_config_file = ABSPATH . 'wp-config.php';
41
- if(file_exists($wp_config_file)){
42
- return $wp_config_file;
43
- }
44
- else if (file_exists(dirname( ABSPATH ) . '/wp-config.php')){
45
- return dirname( ABSPATH ) . '/wp-config.php';
46
- }
47
- return $wp_config_file;
48
- }
49
-
50
- static function write_content_to_file($file_path, $new_contents)
51
- {
52
- @chmod($file_path, 0777);
53
- if (is_writeable($file_path))
54
- {
55
- $handle = fopen($file_path, 'w');
56
- foreach( $new_contents as $line ) {
57
- fwrite($handle, $line);
58
- }
59
- fclose($handle);
60
- @chmod($file_path, 0644); //Let's change the file back to a secure permission setting
61
- return true;
62
- } else {
63
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
- }
66
-
67
- static function backup_a_file($src_file_path, $suffix = 'backup')
68
- {
69
- $backup_file_path = $src_file_path . '.' . $suffix;
70
- if (!copy($src_file_path, $backup_file_path)) {
71
- //Failed to make a backup copy
72
- return false;
73
- }
74
- return true;
75
- }
76
-
77
- static function backup_and_rename_wp_config($src_file_path, $prefix = 'backup')
78
- {
79
- global $aio_wp_security;
80
-
81
- //Check to see if the main "backups" directory exists - create it otherwise
82
- $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
83
- if (!AIOWPSecurity_Utility_File::create_dir($aiowps_backup_dir))
84
- {
85
- $aio_wp_security->debug_logger->log_debug("backup_and_rename_wp_config - Creation of backup directory failed!",4);
86
- return false;
87
- }
88
-
89
- $src_parts = pathinfo($src_file_path);
90
- $backup_file_name = $prefix . '.' . $src_parts['basename'];
91
-
92
- $backup_file_path = $aiowps_backup_dir . '/' . $backup_file_name;
93
- if (!copy($src_file_path, $backup_file_path)) {
94
- //Failed to make a backup copy
95
- return false;
96
- }
97
- return true;
98
- }
99
-
100
- static function backup_and_rename_htaccess($src_file_path, $suffix = 'backup')
101
- {
102
- global $aio_wp_security;
103
-
104
- //Check to see if the main "backups" directory exists - create it otherwise
105
- $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
106
- if (!AIOWPSecurity_Utility_File::create_dir($aiowps_backup_dir))
107
- {
108
- $aio_wp_security->debug_logger->log_debug("backup_and_rename_htaccess - Creation of backup directory failed!",4);
109
- return false;
110
- }
111
-
112
- $src_parts = pathinfo($src_file_path);
113
- $backup_file_name = $src_parts['basename'] . '.' . $suffix;
114
-
115
- $backup_file_path = $aiowps_backup_dir . '/' . $backup_file_name;
116
- if (!copy($src_file_path, $backup_file_path)) {
117
- //Failed to make a backup copy
118
- return false;
119
- }
120
- return true;
121
- }
122
-
123
- //Function which reads entire contents of a file and stores serialized contents into our global_meta table
124
- static function backup_file_contents_to_db($src_file_path, $key_description)
125
- {
126
- global $wpdb, $aio_wp_security;
127
- $file_contents = AIOWPSecurity_Utility_File::get_file_contents($src_file_path);
128
-
129
- $payload = serialize($file_contents);
130
- $date_time = current_time( 'mysql' );
131
- $data = array('date_time' => $date_time, 'meta_key1' => $key_description, 'meta_value2' => $payload);
132
-
133
- //First check if a backup entry already exists in the global_meta table
134
- $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
135
- $resultset = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $aiowps_global_meta_tbl_name WHERE meta_key1 = '%s'", $key_description) );
136
- if($resultset){
137
- $where = array('meta_key1' => $key_description);
138
- $res = $wpdb->update($aiowps_global_meta_tbl_name, $data, $where);
139
- }else{
140
- $res = $wpdb->insert($aiowps_global_meta_tbl_name, $data);
141
- }
142
-
143
- if($res === false)
144
- {
145
- $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility_File::backup_file_contents_to_db() - Unable to write entry to DB",4);
146
- }
147
- return;
148
- }
149
-
150
-
151
- static function recursive_file_search($pattern='*', $flags = 0, $path='')
152
- {
153
- $paths=glob($path.'*', GLOB_MARK|GLOB_ONLYDIR|GLOB_NOSORT);
154
- if ($paths === FALSE){
155
- return FALSE;
156
- }
157
- $files=glob($path.$pattern, $flags);
158
- if ($files === FALSE){
159
- return FALSE;
160
- }
161
- foreach ($paths as $path) { $files=array_merge($files,AIOWPSecurity_Utility_File::recursive_file_search($pattern, $flags, $path)); }
162
- return $files;
163
- }
164
-
165
- /*
166
- * Useful when wanting to echo file contents to screen with <br /> tags
167
- */
168
- static function get_file_contents_with_br($src_file)
169
- {
170
- $file_contents = file_get_contents($src_file);
171
- return nl2br($file_contents);
172
- }
173
-
174
- /*
175
- * Useful when wanting to echo file contents inside textarea
176
- */
177
- static function get_file_contents($src_file)
178
- {
179
- $file_contents = file_get_contents($src_file);
180
- return $file_contents;
181
- }
182
-
183
- /*
184
- * Returns the file's permission value eg, "0755"
185
- */
186
- static function get_file_permission($filepath)
187
- {
188
- if (!function_exists('fileperms'))
189
- {
190
- $perms = '-1';
191
- }
192
- else
193
- {
194
- clearstatcache();
195
- $perms = substr(sprintf("%o", @fileperms($filepath)), -4);
196
- }
197
- return $perms;
198
- }
199
-
200
- /*
201
- * Checks if a write operation is possible for the file in question
202
- */
203
- static function is_file_writable($filepath)
204
- {
205
- $test_string = ""; //We will attempt to append an empty string at the end of the file for the test
206
- $write_result = @file_put_contents($filepath, $test_string, FILE_APPEND | LOCK_EX);
207
- if ($write_result === false)
208
- {
209
- return false;
210
- }
211
- else
212
- {
213
- return true;
214
- }
215
- }
216
-
217
- static function download_a_file_option1($file_path, $file_name = '')
218
- {
219
- $file = $file_path;//Full ABS path to the file
220
- if(empty($file_name)){$file_name = basename($file);}
221
-
222
- header('Content-Description: File Transfer');
223
- header('Content-Type: application/octet-stream');
224
- header('Content-Disposition: attachment; filename='.$file_name);
225
- header('Content-Transfer-Encoding: binary');
226
- header('Expires: 0');
227
- header('Cache-Control: must-revalidate');
228
- header('Pragma: public');
229
- header('Content-Length: ' . filesize($file));
230
- //ob_clean();
231
- //flush();
232
- readfile($file);
233
- exit;
234
- }
235
-
236
- static function download_content_to_a_file($output, $file_name = '')
237
- {
238
- if(empty($file_name)){$file_name = "aiowps_" . date("Y-m-d_H-i", time()).".txt";}
239
-
240
- header("Content-Encoding: UTF-8");
241
- header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
242
- header("Content-Description: File Transfer");
243
- header("Content-type: application/octet-stream");
244
- header("Content-disposition: attachment; filename=" . $file_name);
245
- header("Content-Transfer-Encoding: binary");
246
- header("Content-Length: " . strlen($output));
247
- echo $output;
248
- exit;
249
- }
250
-
251
- /*
252
- * This function will compare the current permission value for a file or dir with the recommended value.
253
- * It will compare the individual "execute", "write" and "read" bits for the "public", "group" and "owner" permissions.
254
- * If the permissions for an actual bit value are greater than the recommended value it returns '0' (=less secure)
255
- * Otherwise it returns '1' which means it is secure
256
- * Accepts permission value parameters in octal, ie, "0777" or "777"
257
- */
258
- static function is_file_permission_secure($recommended, $actual)
259
- {
260
- $result = 1; //initialize return result
261
-
262
- //Check "public" permissions
263
- $public_value_actual = substr($actual,-1,1); //get dec value for actual public permission
264
- $public_value_rec = substr($recommended,-1,1); //get dec value for recommended public permission
265
-
266
- $pva_bin = sprintf('%04b', $public_value_actual); //Convert value to binary
267
- $pvr_bin = sprintf('%04b', $public_value_rec); //Convert value to binary
268
- //Compare the "executable" bit values for the public actual versus the recommended
269
- if (substr($pva_bin,-1,1)<=substr($pvr_bin,-1,1))
270
- {
271
- //The "execute" bit is the same or less as the recommended value
272
- $result = 1*$result;
273
- }else
274
- {
275
- //The "execute" bit is switched on for the actual value - meaning it is less secure
276
- $result = 0*$result;
277
- }
278
-
279
- //Compare the "write" bit values for the public actual versus the recommended
280
- if (substr($pva_bin,-2,1)<=substr($pvr_bin,-2,1))
281
- {
282
- //The "write" bit is the same or less as the recommended value
283
- $result = 1*$result;
284
- }else
285
- {
286
- //The "write" bit is switched on for the actual value - meaning it is less secure
287
- $result = 0*$result;
288
- }
289
-
290
- //Compare the "read" bit values for the public actual versus the recommended
291
- if (substr($pva_bin,-3,1)<=substr($pvr_bin,-3,1))
292
- {
293
- //The "read" bit is the same or less as the recommended value
294
- $result = 1*$result;
295
- }else
296
- {
297
- //The "read" bit is switched on for the actual value - meaning it is less secure
298
- $result = 0*$result;
299
- }
300
-
301
- //Check "group" permissions
302
- $group_value_actual = substr($actual,-2,1);
303
- $group_value_rec = substr($recommended,-2,1);
304
- $gva_bin = sprintf('%04b', $group_value_actual); //Convert value to binary
305
- $gvr_bin = sprintf('%04b', $group_value_rec); //Convert value to binary
306
-
307
- //Compare the "executable" bit values for the group actual versus the recommended
308
- if (substr($gva_bin,-1,1)<=substr($gvr_bin,-1,1))
309
- {
310
- //The "execute" bit is the same or less as the recommended value
311
- $result = 1*$result;
312
- }else
313
- {
314
- //The "execute" bit is switched on for the actual value - meaning it is less secure
315
- $result = 0*$result;
316
- }
317
-
318
- //Compare the "write" bit values for the public actual versus the recommended
319
- if (substr($gva_bin,-2,1)<=substr($gvr_bin,-2,1))
320
- {
321
- //The "write" bit is the same or less as the recommended value
322
- $result = 1*$result;
323
- }else
324
- {
325
- //The "write" bit is switched on for the actual value - meaning it is less secure
326
- $result = 0*$result;
327
- }
328
-
329
- //Compare the "read" bit values for the public actual versus the recommended
330
- if (substr($gva_bin,-3,1)<=substr($gvr_bin,-3,1))
331
- {
332
- //The "read" bit is the same or less as the recommended value
333
- $result = 1*$result;
334
- }else
335
- {
336
- //The "read" bit is switched on for the actual value - meaning it is less secure
337
- $result = 0*$result;
338
- }
339
-
340
- //Check "owner" permissions
341
- $owner_value_actual = substr($actual,-3,1);
342
- $owner_value_rec = substr($recommended,-3,1);
343
- $ova_bin = sprintf('%04b', $owner_value_actual); //Convert value to binary
344
- $ovr_bin = sprintf('%04b', $owner_value_rec); //Convert value to binary
345
-
346
- //Compare the "executable" bit values for the group actual versus the recommended
347
- if (substr($ova_bin,-1,1)<=substr($ovr_bin,-1,1))
348
- {
349
- //The "execute" bit is the same or less as the recommended value
350
- $result = 1*$result;
351
- }else
352
- {
353
- //The "execute" bit is switched on for the actual value - meaning it is less secure
354
- $result = 0*$result;
355
- }
356
-
357
- //Compare the "write" bit values for the public actual versus the recommended
358
- if (substr($ova_bin,-2,1)<=substr($ovr_bin,-2,1))
359
- {
360
- //The "write" bit is the same or less as the recommended value
361
- $result = 1*$result;
362
- }else
363
- {
364
- //The "write" bit is switched on for the actual value - meaning it is less secure
365
- $result = 0*$result;
366
- }
367
-
368
- //Compare the "read" bit values for the public actual versus the recommended
369
- if (substr($ova_bin,-3,1)<=substr($ovr_bin,-3,1))
370
- {
371
- //The "read" bit is the same or less as the recommended value
372
- $result = 1*$result;
373
- }else
374
- {
375
- //The "read" bit is switched on for the actual value - meaning it is less secure
376
- $result = 0*$result;
377
- }
378
-
379
- return $result;
380
- }
381
-
382
- /*
383
- * Checks if a directory exists and creates one if it does not
384
- */
385
- static function create_dir($dirpath='')
386
- {
387
- $res = true;
388
- if ($dirpath != '')
389
- {
390
- //TODO - maybe add some checks to make sure someone is not passing a path with a filename, ie, something which has ".<extenstion>" at the end
391
- //$path_parts = pathinfo($dirpath);
392
- //$dirpath = $path_parts['dirname'] . '/' . $path_parts['basename'];
393
- if (!file_exists($dirpath))
394
- {
395
- $res = mkdir($dirpath, 0755);
396
- }
397
- }
398
- return $res;
399
- }
400
-
401
- static function get_attachment_id_from_url($attachment_url = '')
402
- {
403
- global $wpdb;
404
- $attachment_id = false;
405
-
406
- // If there is no url, return.
407
- if ('' == $attachment_url)return;
408
-
409
- // Get the upload directory paths
410
- $upload_dir_paths = wp_upload_dir();
411
-
412
- // Make sure the upload path base directory exists in the attachment URL, to verify that we're working with a media library image
413
- if (false !== strpos($attachment_url, $upload_dir_paths['baseurl'])) {
414
- // Remove the upload path base directory from the attachment URL
415
- $attachment_url = str_replace( $upload_dir_paths['baseurl'] . '/', '', $attachment_url );
416
- // Now run custom database query to get attachment ID from attachment URL
417
- $attachment_id = $wpdb->get_var( $wpdb->prepare( "SELECT wposts.ID FROM $wpdb->posts wposts, $wpdb->postmeta wpostmeta WHERE wposts.ID = wpostmeta.post_id AND wpostmeta.meta_key = '_wp_attached_file' AND wpostmeta.meta_value = '%s' AND wposts.post_type = 'attachment'", $attachment_url ) );
418
- }
419
- return $attachment_id;
420
- }
421
-
422
-
423
- /**
424
- * Will return an indexed array of files sorted by last modified timestamp
425
- * @param string $dir
426
- * @param string $sort (ASC, DESC)
427
- * @return array
428
- */
429
- static function scan_dir_sort_date($dir, $sort='DESC') {
430
- $files = array();
431
- foreach (scandir($dir) as $file) {
432
- $files[$file] = filemtime($dir . '/' . $file);
433
- }
434
-
435
- if ($sort === 'ASC') {
436
- asort($files);
437
- }
438
- else {
439
- arsort($files);
440
- }
441
-
442
- return array_keys($files);
443
- }
444
 
445
  }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Utility_File {
7
+
8
+ // This variable will be an array which will contain all of the files and/or directories we wish to check permissions for
9
+ public $files_and_dirs_to_check;
10
+
11
+ public function __construct() {
12
+ // Let's initiliaze our class variable array with all of the files and/or directories we wish to check permissions for.
13
+ // NOTE: we can add to this list in future if we wish
14
+
15
+ //Get wp-config.php file path
16
+ if (!function_exists('get_home_path')) require_once(ABSPATH. '/wp-admin/includes/file.php');
17
+ $wp_config_path = AIOWPSecurity_Utility_File::get_wp_config_file_path();
18
+ $home_path = get_home_path();
19
+
20
+ $this->files_and_dirs_to_check = array(
21
+ array('name' => 'root directory', 'path' => ABSPATH, 'permissions' => '0755'),
22
+ array('name' => 'wp-includes/', 'path' => ABSPATH."wp-includes", 'permissions' => '0755'),
23
+ array('name' => '.htaccess', 'path' => $home_path.".htaccess", 'permissions' => '0644'),
24
+ array('name' => 'wp-admin/index.php', 'path' => ABSPATH."wp-admin/index.php", 'permissions' => '0644'),
25
+ array('name' => 'wp-admin/js/', 'path' => ABSPATH."wp-admin/js/", 'permissions' => '0755'),
26
+ array('name' => 'wp-content/themes/', 'path' => ABSPATH."wp-content/themes", 'permissions' => '0755'),
27
+ array('name' => 'wp-content/plugins/', 'path' => ABSPATH."wp-content/plugins", 'permissions' => '0755'),
28
+ array('name' => 'wp-admin/', 'path' => ABSPATH."wp-admin", 'permissions' => '0755'),
29
+ array('name' => 'wp-content/', 'path' => ABSPATH."wp-content", 'permissions' => '0755'),
30
+ array('name' => 'wp-config.php', 'path' => $wp_config_path, 'permissions' => '0640'),
31
+ //Add as many files or dirs as needed by following the convention above
32
+ );
33
+
34
+ }
35
+
36
+ public static function get_wp_config_file_path() {
37
+ $wp_config_file = ABSPATH . 'wp-config.php';
38
+ if (file_exists($wp_config_file)) {
39
+ return $wp_config_file;
40
+ } elseif (file_exists(dirname(ABSPATH) . '/wp-config.php')) {
41
+ return dirname(ABSPATH) . '/wp-config.php';
42
+ }
43
+ return $wp_config_file;
44
+ }
45
+
46
+ public static function write_content_to_file($file_path, $new_contents) {
47
+ @chmod($file_path, 0777);
48
+ if (is_writeable($file_path)) {
49
+ $handle = fopen($file_path, 'w');
50
+ foreach ($new_contents as $line) {
51
+ fwrite($handle, $line);
52
+ }
53
+ fclose($handle);
54
+ @chmod($file_path, 0644); //Let's change the file back to a secure permission setting
55
+ return true;
56
+ } else {
57
+ return false;
58
+ }
59
+ }
60
+
61
+ public static function backup_a_file($src_file_path, $suffix = 'backup') {
62
+ $backup_file_path = $src_file_path . '.' . $suffix;
63
+ if (!copy($src_file_path, $backup_file_path)) {
64
+ //Failed to make a backup copy
65
+ return false;
66
+ }
67
+ return true;
68
+ }
69
+
70
+ public static function backup_and_rename_wp_config($src_file_path, $prefix = 'backup') {
71
+ global $aio_wp_security;
72
+
73
+ //Check to see if the main "backups" directory exists - create it otherwise
74
+ $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
75
+ if (!AIOWPSecurity_Utility_File::create_dir($aiowps_backup_dir)) {
76
+ $aio_wp_security->debug_logger->log_debug("backup_and_rename_wp_config - Creation of backup directory failed!", 4);
77
+ return false;
78
+ }
79
+
80
+ $src_parts = pathinfo($src_file_path);
81
+ $backup_file_name = $prefix . '.' . $src_parts['basename'];
82
+
83
+ $backup_file_path = $aiowps_backup_dir . '/' . $backup_file_name;
84
+ if (!copy($src_file_path, $backup_file_path)) {
85
+ //Failed to make a backup copy
86
+ return false;
87
+ }
88
+ return true;
89
+ }
90
+
91
+ public static function backup_and_rename_htaccess($src_file_path, $suffix = 'backup') {
92
+ global $aio_wp_security;
93
+
94
+ //Check to see if the main "backups" directory exists - create it otherwise
95
+ $aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
96
+ if (!AIOWPSecurity_Utility_File::create_dir($aiowps_backup_dir)) {
97
+ $aio_wp_security->debug_logger->log_debug("backup_and_rename_htaccess - Creation of backup directory failed!", 4);
98
+ return false;
99
+ }
100
+
101
+ $src_parts = pathinfo($src_file_path);
102
+ $backup_file_name = $src_parts['basename'] . '.' . $suffix;
103
+
104
+ $backup_file_path = $aiowps_backup_dir . '/' . $backup_file_name;
105
+ if (!copy($src_file_path, $backup_file_path)) {
106
+ //Failed to make a backup copy
107
+ return false;
108
+ }
109
+ return true;
110
+ }
111
+
112
+ /**
113
+ * Function which reads entire contents of a file and stores serialized contents into our global_meta table
114
+ *
115
+ * @param string $src_file_path
116
+ * @param string $key_description
117
+ * @return void
118
+ */
119
+ public static function backup_file_contents_to_db($src_file_path, $key_description) {
120
+ global $wpdb, $aio_wp_security;
121
+ $file_contents = AIOWPSecurity_Utility_File::get_file_contents($src_file_path);
122
+
123
+ $payload = serialize($file_contents);
124
+ $date_time = current_time('mysql');
125
+ $data = array('date_time' => $date_time, 'meta_key1' => $key_description, 'meta_value2' => $payload);
126
+
127
+ //First check if a backup entry already exists in the global_meta table
128
+ $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA;
129
+ $resultset = $wpdb->get_row($wpdb->prepare("SELECT * FROM $aiowps_global_meta_tbl_name WHERE meta_key1 = '%s'", $key_description));
130
+ if ($resultset) {
131
+ $where = array('meta_key1' => $key_description);
132
+ $res = $wpdb->update($aiowps_global_meta_tbl_name, $data, $where);
133
+ } else {
134
+ $res = $wpdb->insert($aiowps_global_meta_tbl_name, $data);
135
+ }
136
+
137
+ if (false === $res) {
138
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility_File::backup_file_contents_to_db() - Unable to write entry to DB", 4);
139
+ }
140
+ return;// phpcs:ignore Squiz.PHP.NonExecutableCode.ReturnNotRequired
141
+ }
142
+
143
+
144
+ public static function recursive_file_search($pattern = '*', $flags = 0, $path = '') {
145
+ $paths = glob($path.'*', GLOB_MARK|GLOB_ONLYDIR|GLOB_NOSORT);
146
+ if (false === $paths) {
147
+ return false;
148
+ }
149
+ $files = glob($path.$pattern, $flags);
150
+ if (false === $files) {
151
+ return false;
152
+ }
153
+ foreach ($paths as $path) {
154
+ $files = array_merge($files, AIOWPSecurity_Utility_File::recursive_file_search($pattern, $flags, $path));
155
+ }
156
+ return $files;
157
+ }
158
+
159
+ /**
160
+ * Useful when wanting to echo file contents to screen with <br /> tags
161
+ *
162
+ * @param string $src_file
163
+ * @return string
164
+ */
165
+ public static function get_file_contents_with_br($src_file) {
166
+ $file_contents = file_get_contents($src_file);
167
+ return nl2br($file_contents);
168
+ }
169
+
170
+ /**
171
+ * Useful when wanting to echo file contents inside textarea
172
+ *
173
+ * @param string $src_file
174
+ * @return string
175
+ */
176
+ public static function get_file_contents($src_file) {
177
+ $file_contents = file_get_contents($src_file);
178
+ return $file_contents;
179
+ }
180
+
181
+ /**
182
+ * Returns the file's permission value eg, "0755"
183
+ *
184
+ * @param string $filepath
185
+ * @return string
186
+ */
187
+ public static function get_file_permission($filepath) {
188
+ if (!function_exists('fileperms')) {
189
+ $perms = '-1';
190
+ } else {
191
+ clearstatcache();
192
+ $perms = substr(sprintf("%o", @fileperms($filepath)), -4);
193
+ }
194
+ return $perms;
195
+ }
196
+
197
+ /**
198
+ * Checks if a write operation is possible for the file in question
199
+ *
200
+ * @param string $filepath
201
+ * @return boolean
202
+ */
203
+ public static function is_file_writable($filepath) {
204
+ $test_string = ""; //We will attempt to append an empty string at the end of the file for the test
205
+ $write_result = @file_put_contents($filepath, $test_string, FILE_APPEND | LOCK_EX);
206
+ if (false === $write_result) {
207
+ return false;
208
+ } else {
209
+ return true;
210
+ }
211
+ }
212
+
213
+ public static function download_a_file_option1($file_path, $file_name = '') {
214
+ $file = $file_path;//Full ABS path to the file
215
+ if (empty($file_name)) {
216
+ $file_name = basename($file);
217
+ }
218
+
219
+ header('Content-Description: File Transfer');
220
+ header('Content-Type: application/octet-stream');
221
+ header('Content-Disposition: attachment; filename='.$file_name);
222
+ header('Content-Transfer-Encoding: binary');
223
+ header('Expires: 0');
224
+ header('Cache-Control: must-revalidate');
225
+ header('Pragma: public');
226
+ header('Content-Length: ' . filesize($file));
227
+ //ob_clean();
228
+ //flush();
229
+ readfile($file);
230
+ exit;
231
+ }
232
+
233
+ public static function download_content_to_a_file($output, $file_name = '') {
234
+ if (empty($file_name)) {
235
+ $file_name = "aiowps_" . date("Y-m-d_H-i", time()).".txt";
236
+ }
237
+
238
+ header("Content-Encoding: UTF-8");
239
+ header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
240
+ header("Content-Description: File Transfer");
241
+ header("Content-type: application/octet-stream");
242
+ header("Content-disposition: attachment; filename=" . $file_name);
243
+ header("Content-Transfer-Encoding: binary");
244
+ header("Content-Length: " . strlen($output));
245
+ echo $output;
246
+ exit;
247
+ }
248
+
249
+ /**
250
+ * This function will compare the current permission value for a file or dir with the recommended value.
251
+ * It will compare the individual "execute", "write" and "read" bits for the "public", "group" and "owner" permissions.
252
+ * If the permissions for an actual bit value are greater than the recommended value it returns '0' (=less secure)
253
+ * Otherwise it returns '1' which means it is secure
254
+ * Accepts permission value parameters in octal, ie, "0777" or "777"
255
+ *
256
+ * @param string $recommended
257
+ * @param string $actual
258
+ * @return boolean
259
+ */
260
+ public static function is_file_permission_secure($recommended, $actual) {
261
+ $result = 1; //initialize return result
262
+
263
+ //Check "public" permissions
264
+ $public_value_actual = substr($actual, -1, 1); //get dec value for actual public permission
265
+ $public_value_rec = substr($recommended, -1, 1); //get dec value for recommended public permission
266
+
267
+ $pva_bin = sprintf('%04b', $public_value_actual); //Convert value to binary
268
+ $pvr_bin = sprintf('%04b', $public_value_rec); //Convert value to binary
269
+ //Compare the "executable" bit values for the public actual versus the recommended
270
+ if (substr($pva_bin, -1, 1)<=substr($pvr_bin, -1, 1)) {
271
+ //The "execute" bit is the same or less as the recommended value
272
+ $result = 1*$result;
273
+ } else {
274
+ //The "execute" bit is switched on for the actual value - meaning it is less secure
275
+ $result = 0*$result;
276
+ }
277
+
278
+ //Compare the "write" bit values for the public actual versus the recommended
279
+ if (substr($pva_bin, -2, 1)<=substr($pvr_bin, -2, 1)) {
280
+ //The "write" bit is the same or less as the recommended value
281
+ $result = 1*$result;
282
+ } else {
283
+ //The "write" bit is switched on for the actual value - meaning it is less secure
284
+ $result = 0*$result;
285
+ }
286
+
287
+ //Compare the "read" bit values for the public actual versus the recommended
288
+ if (substr($pva_bin, -3, 1)<=substr($pvr_bin, -3, 1)) {
289
+ //The "read" bit is the same or less as the recommended value
290
+ $result = 1*$result;
291
+ } else {
292
+ //The "read" bit is switched on for the actual value - meaning it is less secure
293
+ $result = 0*$result;
294
+ }
295
+
296
+ //Check "group" permissions
297
+ $group_value_actual = substr($actual, -2, 1);
298
+ $group_value_rec = substr($recommended, -2, 1);
299
+ $gva_bin = sprintf('%04b', $group_value_actual); //Convert value to binary
300
+ $gvr_bin = sprintf('%04b', $group_value_rec); //Convert value to binary
301
+
302
+ //Compare the "executable" bit values for the group actual versus the recommended
303
+ if (substr($gva_bin, -1, 1)<=substr($gvr_bin, -1, 1)) {
304
+ //The "execute" bit is the same or less as the recommended value
305
+ $result = 1*$result;
306
+ } else {
307
+ //The "execute" bit is switched on for the actual value - meaning it is less secure
308
+ $result = 0*$result;
309
+ }
310
+
311
+ //Compare the "write" bit values for the public actual versus the recommended
312
+ if (substr($gva_bin, -2, 1)<=substr($gvr_bin, -2, 1)) {
313
+ //The "write" bit is the same or less as the recommended value
314
+ $result = 1*$result;
315
+ } else {
316
+ //The "write" bit is switched on for the actual value - meaning it is less secure
317
+ $result = 0*$result;
318
+ }
319
+
320
+ //Compare the "read" bit values for the public actual versus the recommended
321
+ if (substr($gva_bin, -3, 1)<=substr($gvr_bin, -3, 1)) {
322
+ //The "read" bit is the same or less as the recommended value
323
+ $result = 1*$result;
324
+ } else {
325
+ //The "read" bit is switched on for the actual value - meaning it is less secure
326
+ $result = 0*$result;
327
+ }
328
+
329
+ //Check "owner" permissions
330
+ $owner_value_actual = substr($actual, -3, 1);
331
+ $owner_value_rec = substr($recommended, -3, 1);
332
+ $ova_bin = sprintf('%04b', $owner_value_actual); //Convert value to binary
333
+ $ovr_bin = sprintf('%04b', $owner_value_rec); //Convert value to binary
334
+
335
+ //Compare the "executable" bit values for the group actual versus the recommended
336
+ if (substr($ova_bin, -1, 1)<=substr($ovr_bin, -1, 1)) {
337
+ //The "execute" bit is the same or less as the recommended value
338
+ $result = 1*$result;
339
+ } else {
340
+ //The "execute" bit is switched on for the actual value - meaning it is less secure
341
+ $result = 0*$result;
342
+ }
343
+
344
+ //Compare the "write" bit values for the public actual versus the recommended
345
+ if (substr($ova_bin, -2, 1)<=substr($ovr_bin, -2, 1)) {
346
+ //The "write" bit is the same or less as the recommended value
347
+ $result = 1*$result;
348
+ } else {
349
+ //The "write" bit is switched on for the actual value - meaning it is less secure
350
+ $result = 0*$result;
351
+ }
352
+
353
+ //Compare the "read" bit values for the public actual versus the recommended
354
+ if (substr($ova_bin, -3, 1)<=substr($ovr_bin, -3, 1)) {
355
+ //The "read" bit is the same or less as the recommended value
356
+ $result = 1*$result;
357
+ } else {
358
+ //The "read" bit is switched on for the actual value - meaning it is less secure
359
+ $result = 0*$result;
360
+ }
361
+
362
+ return $result;
363
+ }
364
+
365
+ /**
366
+ * Checks if a directory exists and creates one if it does not
367
+ *
368
+ * @param string $dirpath
369
+ * @return boolean
370
+ */
371
+ public static function create_dir($dirpath = '') {
372
+ $res = true;
373
+ if ('' != $dirpath) {
374
+ //TODO - maybe add some checks to make sure someone is not passing a path with a filename, ie, something which has ".<extenstion>" at the end
375
+ //$path_parts = pathinfo($dirpath);
376
+ //$dirpath = $path_parts['dirname'] . '/' . $path_parts['basename'];
377
+ if (!file_exists($dirpath)) {
378
+ $res = mkdir($dirpath, 0755);
379
+ }
380
+ }
381
+ return $res;
382
+ }
383
+
384
+ public static function get_attachment_id_from_url($attachment_url = '') {
385
+ global $wpdb;
386
+ $attachment_id = false;
387
+
388
+ // If there is no url, return.
389
+ if ('' == $attachment_url)return;
390
+
391
+ // Get the upload directory paths
392
+ $upload_dir_paths = wp_upload_dir();
393
+
394
+ // Make sure the upload path base directory exists in the attachment URL, to verify that we're working with a media library image
395
+ if (false !== strpos($attachment_url, $upload_dir_paths['baseurl'])) {
396
+ // Remove the upload path base directory from the attachment URL
397
+ $attachment_url = str_replace($upload_dir_paths['baseurl'] . '/', '', $attachment_url);
398
+ // Now run custom database query to get attachment ID from attachment URL
399
+ $attachment_id = $wpdb->get_var($wpdb->prepare("SELECT wposts.ID FROM $wpdb->posts wposts, $wpdb->postmeta wpostmeta WHERE wposts.ID = wpostmeta.post_id AND wpostmeta.meta_key = '_wp_attached_file' AND wpostmeta.meta_value = '%s' AND wposts.post_type = 'attachment'", $attachment_url));
400
+ }
401
+ return $attachment_id;
402
+ }
403
+
404
+
405
+ /**
406
+ * Will return an indexed array of files sorted by last modified timestamp
407
+ *
408
+ * @param string $dir
409
+ * @param string $sort (ASC, DESC)
410
+ * @return array
411
+ */
412
+ public static function scan_dir_sort_date($dir, $sort = 'DESC') {
413
+ $files = array();
414
+ foreach (scandir($dir) as $file) {
415
+ $files[$file] = filemtime($dir . '/' . $file);
416
+ }
417
+
418
+ if ('ASC' === $sort) {
419
+ asort($files);
420
+ } else {
421
+ arsort($files);
422
+ }
423
+
424
+ return array_keys($files);
425
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
426
 
427
  }
classes/wp-security-utility-htaccess.php CHANGED
@@ -1,1321 +1,1316 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Utility_Htaccess
7
- {
8
- //The following variables will store the comment markers for each of features added to the .htacces file
9
- //This will make it easy to locate the blocks of code for deletion if someone disables a feature
10
- public static $ip_blacklist_marker_start = '#AIOWPS_IP_BLACKLIST_START';
11
- public static $ip_blacklist_marker_end = '#AIOWPS_IP_BLACKLIST_END';
12
 
13
- public static $prevent_wp_file_access_marker_start = '#AIOWPS_BLOCK_WP_FILE_ACCESS_START';
14
- public static $prevent_wp_file_access_marker_end = '#AIOWPS_BLOCK_WP_FILE_ACCESS_END';
 
15
 
16
- public static $basic_htaccess_rules_marker_start = '#AIOWPS_BASIC_HTACCESS_RULES_START';
17
- public static $basic_htaccess_rules_marker_end = '#AIOWPS_BASIC_HTACCESS_RULES_END';
18
 
19
- public static $pingback_htaccess_rules_marker_start = '#AIOWPS_PINGBACK_HTACCESS_RULES_START';
20
- public static $pingback_htaccess_rules_marker_end = '#AIOWPS_PINGBACK_HTACCESS_RULES_END';
21
 
22
- public static $debug_log_block_htaccess_rules_marker_start = '#AIOWPS_DEBUG_LOG_BLOCK_HTACCESS_RULES_START';
23
- public static $debug_log_block_htaccess_rules_marker_end = '#AIOWPS_DEBUG_LOG_BLOCK_HTACCESS_RULES_END';
24
 
25
- public static $user_agent_blacklist_marker_start = '#AIOWPS_USER_AGENT_BLACKLIST_START';
26
- public static $user_agent_blacklist_marker_end = '#AIOWPS_USER_AGENT_BLACKLIST_END';
27
 
28
- public static $enable_brute_force_attack_prevention_marker_start = '#AIOWPS_ENABLE_BRUTE_FORCE_PREVENTION_START';
29
- public static $enable_brute_force_attack_prevention_marker_end = '#AIOWPS_ENABLE_BRUTE_FORCE_PREVENTION_END';
30
-
31
- public static $disable_index_views_marker_start = '#AIOWPS_DISABLE_INDEX_VIEWS_START';
32
- public static $disable_index_views_marker_end = '#AIOWPS_DISABLE_INDEX_VIEWS_END';
33
-
34
- public static $disable_trace_track_marker_start = '#AIOWPS_DISABLE_TRACE_TRACK_START';
35
- public static $disable_trace_track_marker_end = '#AIOWPS_DISABLE_TRACE_TRACK_END';
36
-
37
- public static $forbid_proxy_comments_marker_start = '#AIOWPS_FORBID_PROXY_COMMENTS_START';
38
- public static $forbid_proxy_comments_marker_end = '#AIOWPS_FORBID_PROXY_COMMENTS_END';
39
-
40
- public static $deny_bad_query_strings_marker_start = '#AIOWPS_DENY_BAD_QUERY_STRINGS_START';
41
- public static $deny_bad_query_strings_marker_end = '#AIOWPS_DENY_BAD_QUERY_STRINGS_END';
42
-
43
- public static $advanced_char_string_filter_marker_start = '#AIOWPS_ADVANCED_CHAR_STRING_FILTER_START';
44
- public static $advanced_char_string_filter_marker_end = '#AIOWPS_ADVANCED_CHAR_STRING_FILTER_END';
45
-
46
- public static $five_g_blacklist_marker_start = '#AIOWPS_FIVE_G_BLACKLIST_START';
47
- public static $five_g_blacklist_marker_end = '#AIOWPS_FIVE_G_BLACKLIST_END';
48
-
49
- public static $six_g_blacklist_marker_start = '#AIOWPS_SIX_G_BLACKLIST_START';
50
- public static $six_g_blacklist_marker_end = '#AIOWPS_SIX_G_BLACKLIST_END';
51
-
52
- public static $block_spambots_marker_start = '#AIOWPS_BLOCK_SPAMBOTS_START';
53
- public static $block_spambots_marker_end = '#AIOWPS_BLOCK_SPAMBOTS_END';
54
-
55
- public static $enable_login_whitelist_marker_start = '#AIOWPS_LOGIN_WHITELIST_START';
56
- public static $enable_login_whitelist_marker_end = '#AIOWPS_LOGIN_WHITELIST_END';
57
-
58
- public static $prevent_image_hotlinks_marker_start = '#AIOWPS_PREVENT_IMAGE_HOTLINKS_START';
59
- public static $prevent_image_hotlinks_marker_end = '#AIOWPS_PREVENT_IMAGE_HOTLINKS_END';
60
-
61
- public static $custom_rules_marker_start = '#AIOWPS_CUSTOM_RULES_START';
62
- public static $custom_rules_marker_end = '#AIOWPS_CUSTOM_RULES_END';
63
-
64
- // TODO - enter more markers as new .htaccess features are added
65
-
66
- function __construct()
67
- {
68
- //NOP
69
- }
70
-
71
-
72
- /**
73
- * Write all active rules to .htaccess file.
74
- *
75
- * @return boolean True on success, false on failure.
76
- */
77
- static function write_to_htaccess()
78
- {
79
- global $aio_wp_security;
80
- //figure out what server is being used
81
- if (AIOWPSecurity_Utility::get_server_type() == -1) {
82
- $aio_wp_security->debug_logger->log_debug("Unable to write to .htaccess - server type not supported!", 4);
83
- return false; //unable to write to the file
84
- }
85
-
86
- //clean up old rules first
87
- if (AIOWPSecurity_Utility_Htaccess::delete_from_htaccess() == -1) {
88
- $aio_wp_security->debug_logger->log_debug("Delete operation of .htaccess file failed!", 4);
89
- return false; //unable to write to the file
90
- }
91
-
92
- if ( !function_exists( 'get_home_path' ) ) require_once( ABSPATH. '/wp-admin/includes/file.php' );
93
- $home_path = get_home_path();
94
- $htaccess = $home_path . '.htaccess';
95
-
96
- if (!$f = @fopen($htaccess, 'a+')) {
97
- @chmod($htaccess, 0644);
98
- if (!$f = @fopen($htaccess, 'a+')) {
99
- $aio_wp_security->debug_logger->log_debug("chmod operation on .htaccess failed!", 4);
100
- return false;
101
- }
102
- }
103
- AIOWPSecurity_Utility_File::backup_and_rename_htaccess($htaccess); //TODO - we dont want to continually be backing up the htaccess file
104
- @ini_set('auto_detect_line_endings', true);
105
- $ht = explode(PHP_EOL, implode('', file($htaccess))); //parse each line of file into array
106
-
107
- $rules = AIOWPSecurity_Utility_Htaccess::getrules();
108
-
109
- $rulesarray = explode(PHP_EOL, $rules);
110
- $rulesarray = apply_filters('aiowps_htaccess_rules_before_writing', $rulesarray);
111
- $contents = array_merge($rulesarray, $ht);
112
-
113
- if (!$f = @fopen($htaccess, 'w+')) {
114
- $aio_wp_security->debug_logger->log_debug("Write operation on .htaccess failed!", 4);
115
- return false; //we can't write to the file
116
- }
117
-
118
- $blank = false;
119
-
120
- //write each line to file
121
- foreach ($contents as $insertline) {
122
- if (trim($insertline) == '') {
123
- if ($blank == false) {
124
- fwrite($f, PHP_EOL . trim($insertline));
125
- }
126
- $blank = true;
127
- } else {
128
- $blank = false;
129
- fwrite($f, PHP_EOL . trim($insertline));
130
- }
131
- }
132
- @fclose($f);
133
- return true; //success
134
- }
135
-
136
- /*
137
- * This function will delete the code which has been added to the .htaccess file by this plugin
138
- * It will try to find the comment markers "# BEGIN All In One WP Security" and "# END All In One WP Security" and delete contents in between
139
- */
140
- static function delete_from_htaccess($section = 'All In One WP Security')
141
- {
142
- if ( !function_exists( 'get_home_path' ) ) require_once( ABSPATH. '/wp-admin/includes/file.php' );
143
- $home_path = get_home_path();
144
- $htaccess = $home_path . '.htaccess';
145
-
146
- @ini_set('auto_detect_line_endings', true);
147
- if (!file_exists($htaccess)) {
148
- $ht = @fopen($htaccess, 'a+');
149
- @fclose($ht);
150
- }
151
- /*
152
- *
153
- Bug Fix: On some environments such as windows (xampp) this function was clobbering the non-aiowps-related .htaccess contents for certain cases.
154
- In some cases when WordPress saves the .htaccess file (eg, when saving permalink settings),
155
- the line endings differ from the expected PHP_EOL endings. (WordPress saves with "\n" (UNIX style) but PHP_EOL may be set as "\r\n" (WIN/DOS))
156
- In this case exploding via PHP_EOL may not yield the result we expect.
157
- Therefore we need to do the following extra checks.
158
- */
159
- $ht_contents_imploded = implode('', file($htaccess));
160
- if(empty($ht_contents_imploded)){
161
- return 1;
162
- }else if(strstr($ht_contents_imploded, PHP_EOL)) {
163
- $ht_contents = explode(PHP_EOL, $ht_contents_imploded); //parse each line of file into array
164
- }else if(strstr($ht_contents_imploded, "\n")){
165
- $ht_contents = explode("\n", $ht_contents_imploded); //parse each line of file into array
166
- }else if(strstr($ht_contents_imploded, "\r")){
167
- $ht_contents = explode("\r", $ht_contents_imploded); //parse each line of file into array
168
- }else if(strstr($ht_contents_imploded, "\r\n")){
169
- $ht_contents = explode("\r\n", $ht_contents_imploded); //parse each line of file into array
170
- }
171
-
172
- if ($ht_contents) { //as long as there are lines in the file
173
- $state = true;
174
- if (!$f = @fopen($htaccess, 'w+')) {
175
- @chmod($htaccess, 0644);
176
- if (!$f = @fopen($htaccess, 'w+')) {
177
- return -1;
178
- }
179
- }
180
-
181
- foreach ($ht_contents as $n => $markerline) { //for each line in the file
182
- if (strpos($markerline, '# BEGIN ' . $section) !== false) { //if we're at the beginning of the section
183
- $state = false;
184
- }
185
- if ($state == true) { //as long as we're not in the section keep writing
186
- fwrite($f, trim($markerline) . PHP_EOL);
187
- }
188
- if (strpos($markerline, '# END ' . $section) !== false) { //see if we're at the end of the section
189
- $state = true;
190
- }
191
- }
192
- @fclose($f);
193
- return 1;
194
- }
195
- return 1;
196
- }
197
-
198
- static function getrules()
199
- {
200
- global $aio_wp_security;
201
- $rules = "";
202
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_block_wp_file_access();
203
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_basic_htaccess();
204
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_pingback_htaccess();
205
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_block_debug_log_access_htaccess();
206
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_disable_index_views();
207
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_blacklist();
208
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_disable_trace_and_track();
209
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_forbid_proxy_comment_posting();
210
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_deny_bad_query_strings();
211
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_advanced_character_string_filter();
212
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_6g_blacklist();
213
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_5g_blacklist();
214
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_enable_brute_force_prevention();
215
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_block_spambots();
216
- $rules .= AIOWPSecurity_Utility_Htaccess::getrules_enable_login_whitelist_v2();
217
- $rules .= AIOWPSecurity_Utility_Htaccess::prevent_image_hotlinks();
218
- $custom_rules = AIOWPSecurity_Utility_Htaccess::getrules_custom_rules();
219
- if($aio_wp_security->configs->get_value('aiowps_place_custom_rules_at_top')=='1'){
220
- $rules = $custom_rules . $rules;
221
- }else{
222
- $rules .= $custom_rules;
223
- }
224
-
225
- //TODO: The following utility functions are ready to use when we write the menu pages for these features
226
-
227
- //Add more functions for features as needed
228
- //$rules .= AIOWPSecurity_Utility_Htaccess::getrules_somefeature();
229
-
230
- //Add outer markers if we have rules
231
- if ($rules != '') {
232
- $rules = "# BEGIN All In One WP Security" . PHP_EOL . $rules . "# END All In One WP Security" . PHP_EOL;
233
- }
234
-
235
- return $rules;
236
- }
237
-
238
- /*
239
- * This function will write rules to prevent people from accessing the following files:
240
- * readme.html, license.txt and wp-config-sample.php.
241
- */
242
- static function getrules_block_wp_file_access()
243
- {
244
- global $aio_wp_security;
245
- $rules = '';
246
- if ($aio_wp_security->configs->get_value('aiowps_prevent_default_wp_file_access') == '1') {
247
- $rules .= AIOWPSecurity_Utility_Htaccess::$prevent_wp_file_access_marker_start . PHP_EOL; //Add feature marker start
248
- $rules .= self::create_apache2_access_denied_rule('license.txt');
249
- $rules .= self::create_apache2_access_denied_rule('wp-config-sample.php');
250
- $rules .= self::create_apache2_access_denied_rule('readme.html');
251
- $rules .= AIOWPSecurity_Utility_Htaccess::$prevent_wp_file_access_marker_end . PHP_EOL; //Add feature marker end
252
- }
253
-
254
- return $rules;
255
- }
256
-
257
- static function getrules_blacklist()
258
- {
259
- global $aio_wp_security;
260
- // Are we on Apache or LiteSpeed webserver?
261
- $aiowps_server = AIOWPSecurity_Utility::get_server_type();
262
- $apache_or_litespeed = $aiowps_server == 'apache' || $aiowps_server == 'litespeed';
263
- $rules = '';
264
- if ($aio_wp_security->configs->get_value('aiowps_enable_blacklisting') == '1') {
265
- // Let's do the list of blacklisted IPs first
266
- $hosts = AIOWPSecurity_Utility::explode_trim_filter_empty($aio_wp_security->configs->get_value('aiowps_banned_ip_addresses'));
267
- // Filter out duplicate lines, add netmask to IP addresses
268
- $ips_with_netmask = self::add_netmask(array_unique($hosts));
269
- if ( !empty($ips_with_netmask) && ($aio_wp_security->configs->get_value('aiowps_enable_6g_firewall') != '1') ) {
270
- $rules .= AIOWPSecurity_Utility_Htaccess::$ip_blacklist_marker_start . PHP_EOL; //Add feature marker start
271
-
272
- if ( $apache_or_litespeed ) {
273
- // Apache or LiteSpeed webserver
274
- // Apache 2.2 and older
275
- $rules .= "<IfModule !mod_authz_core.c>" . PHP_EOL;
276
- $rules .= "Order allow,deny" . PHP_EOL;
277
- $rules .= "Allow from all" . PHP_EOL;
278
- foreach ($ips_with_netmask as $ip_with_netmask) {
279
- $rules .= "Deny from " . $ip_with_netmask . PHP_EOL;
280
- }
281
- $rules .= "</IfModule>" . PHP_EOL;
282
- // Apache 2.3 and newer
283
- $rules .= "<IfModule mod_authz_core.c>" . PHP_EOL;
284
- $rules .= "<RequireAll>" . PHP_EOL;
285
- $rules .= "Require all granted" . PHP_EOL;
286
- foreach ($ips_with_netmask as $ip_with_netmask) {
287
- $rules .= "Require not ip " . $ip_with_netmask . PHP_EOL;
288
- }
289
- $rules .= "</RequireAll>" . PHP_EOL;
290
- $rules .= "</IfModule>" . PHP_EOL;
291
- }
292
- else {
293
- // Nginx webserver
294
- foreach ($ips_with_netmask as $ip_with_netmask) {
295
- $rules .= "\tdeny " . $ip_with_netmask . ";" . PHP_EOL;
296
- }
297
- }
298
-
299
- $rules .= AIOWPSecurity_Utility_Htaccess::$ip_blacklist_marker_end . PHP_EOL; //Add feature marker end
300
- }
301
-
302
- //Now let's do the user agent list
303
- $user_agents = explode(PHP_EOL, $aio_wp_security->configs->get_value('aiowps_banned_user_agents'));
304
- if (!empty($user_agents) && !(sizeof($user_agents) == 1 && trim($user_agents[0]) == '')) {
305
- if ( $apache_or_litespeed ) {
306
- $rules .= AIOWPSecurity_Utility_Htaccess::$user_agent_blacklist_marker_start . PHP_EOL; //Add feature marker start
307
- //Start mod_rewrite rules
308
- $rules .= "<IfModule mod_rewrite.c>" . PHP_EOL . "RewriteEngine On" . PHP_EOL . PHP_EOL;
309
- $count = 1;
310
- foreach ($user_agents as $agent) {
311
- $agent_escaped = quotemeta($agent);
312
- $pattern = '/\s/'; //Find spaces in the string
313
- $replacement = '\s'; //Replace spaces with \s so apache can understand
314
- $agent_sanitized = preg_replace($pattern, $replacement, $agent_escaped);
315
-
316
- $rules .= "RewriteCond %{HTTP_USER_AGENT} ^" . trim($agent_sanitized);
317
- if ($count < sizeof($user_agents)) {
318
- $rules .= " [NC,OR]" . PHP_EOL;
319
- $count++;
320
- } else {
321
- $rules .= " [NC]" . PHP_EOL;
322
- }
323
-
324
- }
325
- $rules .= "RewriteRule ^(.*)$ - [F,L]" . PHP_EOL . PHP_EOL;
326
- // End mod_rewrite rules
327
- $rules .= "</IfModule>" . PHP_EOL;
328
- $rules .= AIOWPSecurity_Utility_Htaccess::$user_agent_blacklist_marker_end . PHP_EOL; //Add feature marker end
329
- } else {
330
- $count = 1;
331
- $alist = '';
332
- foreach ($user_agents as $agent) {
333
- $alist .= trim($agent);
334
- if ($count < sizeof($user_agents)) {
335
- $alist .= '|';
336
- $count++;
337
- }
338
- }
339
- $rules .= "\tif (\$http_user_agent ~* " . $alist . ") { return 403; }" . PHP_EOL;
340
- }
341
- }
342
- }
343
-
344
- return implode(PHP_EOL, array_diff(explode(PHP_EOL, $rules), array('Deny from ', 'Deny from')));
345
- }
346
-
347
- /*
348
- * TODO - info
349
- */
350
- static function getrules_basic_htaccess()
351
- {
352
- global $aio_wp_security;
353
-
354
- $rules = '';
355
- if ($aio_wp_security->configs->get_value('aiowps_enable_basic_firewall') == '1') {
356
- $rules .= AIOWPSecurity_Utility_Htaccess::$basic_htaccess_rules_marker_start . PHP_EOL; //Add feature marker start
357
- //protect the htaccess file - this is done by default with apache config file but we are including it here for good measure
358
- $rules .= self::create_apache2_access_denied_rule('.htaccess');
359
-
360
- //disable the server signature
361
- $rules .= 'ServerSignature Off' . PHP_EOL;
362
-
363
- //limit file upload size
364
- $upload_limit = $aio_wp_security->configs->get_value('aiowps_max_file_upload_size');
365
- //Shouldn't be empty but just in case
366
- $upload_limit = empty($upload_limit)?10:$upload_limit;
367
- $upload_limit = $upload_limit * 1024 * 1024; // Convert from MB to Bytes - approx but close enough
368
-
369
- $rules .= 'LimitRequestBody '.$upload_limit . PHP_EOL;
370
-
371
- // protect wpconfig.php.
372
- $rules .= self::create_apache2_access_denied_rule('wp-config.php');
373
-
374
- $rules .= AIOWPSecurity_Utility_Htaccess::$basic_htaccess_rules_marker_end . PHP_EOL; //Add feature marker end
375
- }
376
- return $rules;
377
- }
378
-
379
- static function getrules_pingback_htaccess()
380
- {
381
- global $aio_wp_security;
382
-
383
- $rules = '';
384
- if ($aio_wp_security->configs->get_value('aiowps_enable_pingback_firewall') == '1') {
385
- $rules .= AIOWPSecurity_Utility_Htaccess::$pingback_htaccess_rules_marker_start . PHP_EOL; //Add feature marker start
386
- $rules .= self::create_apache2_access_denied_rule('xmlrpc.php');
387
- $rules .= AIOWPSecurity_Utility_Htaccess::$pingback_htaccess_rules_marker_end . PHP_EOL; //Add feature marker end
388
- }
389
- return $rules;
390
- }
391
-
392
- static function getrules_block_debug_log_access_htaccess()
393
- {
394
- global $aio_wp_security;
395
-
396
- $rules = '';
397
- if ($aio_wp_security->configs->get_value('aiowps_block_debug_log_file_access') == '1') {
398
- $rules .= AIOWPSecurity_Utility_Htaccess::$debug_log_block_htaccess_rules_marker_start . PHP_EOL; //Add feature marker start
399
- $rules .= self::create_apache2_access_denied_rule('debug.log');
400
- $rules .= AIOWPSecurity_Utility_Htaccess::$debug_log_block_htaccess_rules_marker_end . PHP_EOL; //Add feature marker end
401
- }
402
- return $rules;
403
- }
404
-
405
- /*
406
- * This function will write some drectives to block all people who do not have a cookie
407
- * when trying to access the WP login page
408
- */
409
- static function getrules_enable_brute_force_prevention()
410
- {
411
- global $aio_wp_security;
412
- $rules = '';
413
- if ($aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention') == '1') {
414
- $cookie_name = $aio_wp_security->configs->get_value('aiowps_brute_force_secret_word');
415
- $test_cookie_name = $aio_wp_security->configs->get_value('aiowps_cookie_brute_test');
416
- $redirect_url = $aio_wp_security->configs->get_value('aiowps_cookie_based_brute_force_redirect_url');
417
- $rules .= AIOWPSecurity_Utility_Htaccess::$enable_brute_force_attack_prevention_marker_start . PHP_EOL; //Add feature marker start
418
- $rules .= 'RewriteEngine On' . PHP_EOL;
419
- $rules .= 'RewriteCond %{REQUEST_URI} (wp-admin|wp-login)' . PHP_EOL;// If URI contains wp-admin or wp-login
420
- if ($aio_wp_security->configs->get_value('aiowps_brute_force_attack_prevention_ajax_exception') == '1') {
421
- $rules .= 'RewriteCond %{REQUEST_URI} !(wp-admin/admin-ajax.php)' . PHP_EOL; // To allow ajax requests through
422
- }
423
- if ($aio_wp_security->configs->get_value('aiowps_brute_force_attack_prevention_pw_protected_exception') == '1') {
424
- $rules .= 'RewriteCond %{QUERY_STRING} !(action\=postpass)' . PHP_EOL; // Possible workaround for people usign the password protected page/post feature
425
- }
426
- $rules .= 'RewriteCond %{HTTP_COOKIE} !' . $cookie_name . '= [NC]' . PHP_EOL;
427
- $rules .= 'RewriteCond %{HTTP_COOKIE} !' . $test_cookie_name . '= [NC]' . PHP_EOL;
428
- $rules .= 'RewriteRule .* ' . $redirect_url . ' [L]' . PHP_EOL;
429
- $rules .= AIOWPSecurity_Utility_Htaccess::$enable_brute_force_attack_prevention_marker_end . PHP_EOL; //Add feature marker end
430
- }
431
-
432
- return $rules;
433
- }
434
-
435
-
436
- /*
437
- * This function will write some directives to allow IPs in the whitelist to access wp-login.php or wp-admin
438
- * The function also handles the following special cases:
439
- * 1) If the rename login feature is being used: for this scenario instead of protecting wp-login.php we must protect the special page slug
440
- * 2) If the rename login feature is being used AND non permalink URL structure: for this case need to use mod_rewrite because we must check QUERY_STRING
441
- */
442
- static function getrules_enable_login_whitelist()
443
- {
444
- global $aio_wp_security;
445
- $rules = '';
446
-
447
- if ($aio_wp_security->configs->get_value('aiowps_enable_whitelisting') == '1') {
448
- $site_url = AIOWPSEC_WP_URL;
449
- $parse_url = parse_url($site_url);
450
- $hostname = $parse_url['host'];
451
- $host_ip = gethostbyname($hostname);
452
- $special_case = false;
453
- $rules .= AIOWPSecurity_Utility_Htaccess::$enable_login_whitelist_marker_start . PHP_EOL; //Add feature marker start
454
- //If the rename login page feature is active, we will need to adjust the directives
455
- if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
456
- $secret_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
457
- if (!get_option('permalink_structure')) {
458
- //standard url structure is being used - ie, non permalinks
459
- $special_case = true;
460
- $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
461
- $rules .= 'RewriteEngine on' . PHP_EOL;
462
- $rules .= 'RewriteCond %{QUERY_STRING} ^' . $secret_slug . '=1.*$' . PHP_EOL;
463
- $rules .= 'RewriteCond %{REMOTE_ADDR} !^' . preg_quote($host_ip) . '[OR]' . PHP_EOL;
464
- } else {
465
- $slug = preg_quote($secret_slug); //escape any applicable chars
466
- $rules .= '<FilesMatch "^(' . $slug . ')">' . PHP_EOL;
467
- }
468
- } else {
469
- $rules .= '<FilesMatch "^(wp-login\.php)">' . PHP_EOL;
470
- }
471
- if (!$special_case) {
472
- $rules .= 'Order Allow,Deny' . PHP_EOL;
473
- $rules .= 'Allow from ' . $hostname . PHP_EOL;
474
- $rules .= 'Allow from ' . $host_ip . PHP_EOL;
475
- }
476
-
477
- //Let's get list of whitelisted IPs
478
- $hosts = explode(PHP_EOL, $aio_wp_security->configs->get_value('aiowps_allowed_ip_addresses'));
479
- if (!empty($hosts) && !(sizeof($hosts) == 1 && trim($hosts[0]) == '')) {
480
- $phosts = array();
481
- $num_hosts = count($hosts);
482
- $i = 0;
483
- foreach ($hosts as $host) {
484
- $host = trim($host);
485
- $or_string = ($i == $num_hosts - 1) ? '' : '[OR]'; //Add an [OR] clause for all except the last condition
486
-
487
- if (!in_array($host, $phosts)) {
488
- if (strstr($host, '*')) {
489
- $parts = array_reverse(explode('.', $host));
490
- $netmask = 32;
491
- foreach ($parts as $part) {
492
- if (strstr(trim($part), '*')) {
493
- $netmask = $netmask - 8;
494
-
495
- }
496
- }
497
- //*****Bug Fix ******
498
- //Seems that netmask does not work when using the following type of directive, ie,
499
- //RewriteCond %{REMOTE_ADDR} !^203\.87\.121\.0/24
500
-
501
- //The following works:
502
- //RewriteCond %{REMOTE_ADDR} !^203\.87\.121\.
503
-
504
- if($special_case){
505
- $dhost = trim(str_replace('*', '', implode('.', array_reverse($parts)),$count));
506
- if($count > 1){
507
- //means that we will have consecutive periods in the string and we must remove all except one - eg: 45.12..
508
- $dhost = rtrim($dhost, '.');
509
- $dhost = $dhost . '.';
510
- }
511
- }else{
512
- $dhost = trim( str_replace('*', '0', implode( '.', array_reverse( $parts ) ) ) . '/' . $netmask );
513
- }
514
- if (strlen($dhost) > 4) {
515
- if ($special_case) {
516
- $dhost = preg_quote($dhost); //escape any applicable chars
517
- $trule = 'RewriteCond %{REMOTE_ADDR} !^' . $dhost . $or_string . PHP_EOL;
518
- if (trim($trule) != 'RewriteCond %{REMOTE_ADDR}!=') {
519
- $rules .= $trule;
520
- }
521
- } else {
522
- $trule = 'Allow from ' . $dhost . PHP_EOL;
523
- if (trim($trule) != 'Allow from') {
524
- $rules .= $trule;
525
- }
526
- }
527
- }
528
- } else {
529
- $dhost = trim($host);
530
- //ipv6 - for now we will support only whole ipv6 addresses, NOT ranges
531
- if (strpos($dhost, ':') !== false) {
532
- //possible ipv6 addr
533
- $res = WP_Http::is_ip_address($dhost);
534
- if (FALSE === $res) {
535
- continue;
536
- }
537
- }
538
- if (strlen($dhost) > 4 || $res == '6') {
539
- if ($special_case) {
540
- $dhost = preg_quote($dhost); //escape any applicable chars
541
- $rules .= 'RewriteCond %{REMOTE_ADDR} !^' . $dhost . $or_string . PHP_EOL;
542
- } else {
543
- $rules .= 'Allow from ' . $dhost . PHP_EOL;
544
- }
545
-
546
- }
547
- }
548
- }
549
- $phosts[] = $host;
550
- $i++;
551
- }
552
- }
553
-
554
- if ($special_case) {
555
- $rules .= 'RewriteRule .* http://127.0.0.1 [L]' . PHP_EOL;
556
- $rules .= '</IfModule>' . PHP_EOL;
557
- } else {
558
- $rules .= '</FilesMatch>' . PHP_EOL;
559
- }
560
- $rules .= AIOWPSecurity_Utility_Htaccess::$enable_login_whitelist_marker_end . PHP_EOL; //Add feature marker end
561
- }
562
-
563
- return $rules;
564
- }
565
-
566
- /*
567
- * (This is an updated and improved version of getrules_enable_login_whitelist())
568
- * This function will write some directives to allow IPs in the whitelist to access wp-login.php or wp-admin
569
- * The function also handles the following special cases:
570
- * 1) If the rename login feature is being used: for this scenario instead of protecting wp-login.php we must protect the special page slug
571
- * 2) If the rename login feature is being used AND non permalink URL structure: for this case need to use mod_rewrite because we must check QUERY_STRING
572
- */
573
- static function getrules_enable_login_whitelist_v2()
574
- {
575
- global $aio_wp_security;
576
- $rules = '';
577
-
578
- if ($aio_wp_security->configs->get_value('aiowps_enable_whitelisting') == '1') {
579
- $site_url = AIOWPSEC_WP_URL;
580
- $parse_url = parse_url($site_url);
581
- $hostname = $parse_url['host'];
582
- $host_ip = gethostbyname($hostname);
583
- $hidden_login_pretty_perms = false;
584
- $rules .= AIOWPSecurity_Utility_Htaccess::$enable_login_whitelist_marker_start . PHP_EOL; //Add feature marker start
585
- //If the rename login page feature is active, we will need to adjust the directives
586
- if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
587
- $secret_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
588
- if (get_option('permalink_structure')) {
589
- $slug = preg_quote($secret_slug); //escape any applicable chars
590
- $rules .= '<FilesMatch "^(' . $slug . ')">' . PHP_EOL;
591
- } else {
592
- //standard url structure is being used - ie, non permalinks
593
- $hidden_login_pretty_perms = true;
594
- $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
595
- $rules .= 'RewriteEngine on' . PHP_EOL;
596
- $rules .= 'RewriteCond %{QUERY_STRING} ^' . $secret_slug . '=1.*$' . PHP_EOL;
597
- $rules .= 'RewriteCond %{REMOTE_ADDR} !^' . preg_quote($host_ip) . PHP_EOL;
598
- }
599
- } else {
600
- $rules .= '<FilesMatch "^(wp-login\.php)">' . PHP_EOL;
601
- }
602
- $rules_apache_pre_24 = '';
603
- $rules_apache_24 = '';
604
- if (!$hidden_login_pretty_perms) {
605
- //start writing rules for versions of apache < 2.4
606
- $rules_apache_pre_24 .= '<IfModule !mod_authz_core.c>' . PHP_EOL;
607
- $rules_apache_pre_24 .= 'Order Allow,Deny' . PHP_EOL;
608
- $rules_apache_pre_24 .= 'Allow from ' . $hostname . PHP_EOL;
609
- $rules_apache_pre_24 .= 'Allow from ' . $host_ip . PHP_EOL;
610
-
611
- //start writing rules for versions of apache >=2.4
612
- $rules_apache_24 .= '<IfModule mod_authz_core.c>' . PHP_EOL;
613
- $rules_apache_24 .= 'Require all denied' . PHP_EOL;
614
- $rules_apache_24 .= 'Require local' . PHP_EOL;
615
- $rules_apache_24 .= 'Require ip 127.0.0.1' . PHP_EOL;
616
- $rules_apache_24 .= 'Require host ' . $hostname . PHP_EOL;
617
- }
618
-
619
- //Let's get list of whitelisted IPs
620
- $hosts = AIOWPSecurity_Utility::explode_trim_filter_empty($aio_wp_security->configs->get_value('aiowps_allowed_ip_addresses'));
621
- // Filter out duplicate lines, add netmask to IP addresses
622
- $ips_with_netmask = self::add_netmask(array_unique($hosts));
623
- if(!empty($ips_with_netmask)){
624
- foreach($ips_with_netmask as $xhost){
625
- $ipv6 = false;
626
- if (strpos($xhost, ':') !== false) {
627
- //possible ipv6 addr
628
- //ipv6 - for now we will support only whole ipv6 addresses, NOT ranges
629
- $ipv6 = WP_Http::is_ip_address($xhost);
630
- if (FALSE === $ipv6) {
631
- continue;
632
- }
633
- }
634
- $ip_range = substr($xhost, 0, strpos($xhost, "/")); //check if address range
635
- if($hidden_login_pretty_perms){
636
- if(!empty($ip_range)){
637
- $xhost = $ip_range; //get the IP minus the slash with netmask bits
638
- }
639
- if(!$ipv6){
640
- $xhost = preg_replace("/[\.0]+$/", ".", $xhost);
641
- $xhost = preg_quote($xhost);
642
- }
643
- $rules .= 'RewriteCond %{REMOTE_ADDR} !^' . $xhost . PHP_EOL;
644
- }else{
645
- //write rules for both apache 2.2 and 2.4+
646
- $rules_apache_pre_24 .= 'Allow from ' . $xhost . PHP_EOL;
647
- $rules_apache_24 .= 'Require ip '. $xhost . PHP_EOL;
648
- }
649
- }
650
-
651
- }
652
- if(!empty($rules_apache_pre_24)){
653
- $rules_apache_pre_24 .= '</IfModule>' . PHP_EOL;
654
- }
655
- if(!empty($rules_apache_24)){
656
- $rules_apache_24 .= '</IfModule>' . PHP_EOL;
657
- }
658
- $rules .= $rules_apache_pre_24 . $rules_apache_24;
659
- if ($hidden_login_pretty_perms) {
660
- $rules .= 'RewriteRule .* http://127.0.0.1 [L]' . PHP_EOL;
661
- $rules .= '</IfModule>' . PHP_EOL;
662
- } else {
663
- $rules .= '</FilesMatch>' . PHP_EOL;
664
- }
665
- $rules .= AIOWPSecurity_Utility_Htaccess::$enable_login_whitelist_marker_end . PHP_EOL; //Add feature marker end
666
- }
667
-
668
- return $rules;
669
- }
670
-
671
- /*
672
- * This function will disable directory listings for all directories, add this line to the
673
- * site’s root .htaccess file.
674
- * NOTE: AllowOverride must be enabled in the httpd.conf file for this to work!
675
- */
676
- static function getrules_disable_index_views()
677
- {
678
- global $aio_wp_security;
679
- $rules = '';
680
- if ($aio_wp_security->configs->get_value('aiowps_disable_index_views') == '1') {
681
- $rules .= AIOWPSecurity_Utility_Htaccess::$disable_index_views_marker_start . PHP_EOL; //Add feature marker start
682
- $rules .= 'Options -Indexes' . PHP_EOL;
683
- $rules .= AIOWPSecurity_Utility_Htaccess::$disable_index_views_marker_end . PHP_EOL; //Add feature marker end
684
- }
685
-
686
- return $rules;
687
- }
688
-
689
- /*
690
- * This function will write rules to disable trace and track.
691
- * HTTP Trace attack (XST) can be used to return header requests
692
- * and grab cookies and other information and is used along with
693
- * a cross site scripting attacks (XSS)
694
- */
695
- static function getrules_disable_trace_and_track()
696
- {
697
- global $aio_wp_security;
698
- $rules = '';
699
- if ($aio_wp_security->configs->get_value('aiowps_disable_trace_and_track') == '1') {
700
- $rules .= AIOWPSecurity_Utility_Htaccess::$disable_trace_track_marker_start . PHP_EOL; //Add feature marker start
701
- $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
702
- $rules .= 'RewriteEngine On' . PHP_EOL;
703
- $rules .= 'RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)' . PHP_EOL;
704
- $rules .= 'RewriteRule .* - [F]' . PHP_EOL;
705
- $rules .= '</IfModule>' . PHP_EOL;
706
- $rules .= AIOWPSecurity_Utility_Htaccess::$disable_trace_track_marker_end . PHP_EOL; //Add feature marker end
707
- }
708
-
709
- return $rules;
710
- }
711
-
712
- /*
713
- * This function will write rules to prevent proxy comment posting.
714
- * This will deny any requests that use a proxy server when posting
715
- * to comments eliminating some spam and proxy requests.
716
- * Thanks go to the helpful info and suggestions from perishablepress.com and Thomas O. (https://wordpress.org/support/topic/high-server-cpu-with-proxy-login)
717
- */
718
- static function getrules_forbid_proxy_comment_posting()
719
- {
720
- global $aio_wp_security;
721
- $rules = '';
722
- if ($aio_wp_security->configs->get_value('aiowps_forbid_proxy_comments') == '1') {
723
- $rules .= AIOWPSecurity_Utility_Htaccess::$forbid_proxy_comments_marker_start . PHP_EOL; //Add feature marker start
724
- $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
725
- $rules .= 'RewriteEngine On' . PHP_EOL;
726
- $rules .= 'RewriteCond %{REQUEST_METHOD} ^POST' . PHP_EOL;
727
- $rules .= 'RewriteCond %{HTTP:VIA} !^$ [OR]' . PHP_EOL;
728
- $rules .= 'RewriteCond %{HTTP:FORWARDED} !^$ [OR]' . PHP_EOL;
729
- $rules .= 'RewriteCond %{HTTP:USERAGENT_VIA} !^$ [OR]' . PHP_EOL;
730
- $rules .= 'RewriteCond %{HTTP:X_FORWARDED_FOR} !^$ [OR]' . PHP_EOL;
731
- $rules .= 'RewriteCond %{HTTP:X_FORWARDED_HOST} !^$ [OR]' . PHP_EOL;
732
- $rules .= 'RewriteCond %{HTTP:PROXY_CONNECTION} !^$ [OR]' . PHP_EOL;
733
- $rules .= 'RewriteCond %{HTTP:XPROXY_CONNECTION} !^$ [OR]' . PHP_EOL;
734
- $rules .= 'RewriteCond %{HTTP:HTTP_PC_REMOTE_ADDR} !^$ [OR]' . PHP_EOL;
735
- $rules .= 'RewriteCond %{HTTP:HTTP_CLIENT_IP} !^$' . PHP_EOL;
736
- $rules .= 'RewriteRule wp-comments-post\.php - [F]' . PHP_EOL;
737
- $rules .= '</IfModule>' . PHP_EOL;
738
- $rules .= AIOWPSecurity_Utility_Htaccess::$forbid_proxy_comments_marker_end . PHP_EOL; //Add feature marker end
739
- }
740
-
741
- return $rules;
742
- }
743
-
744
- /*
745
- * This function will write rules to prevent malicious string attacks on your site using XSS.
746
- * NOTE: Some of these strings might be used for plugins or themes and doing so will disable the functionality.
747
- * This script is from perishablepress and is fairly safe to use and should not break anything important
748
- */
749
- //TODO - the currently commented out rules (see function below) break the site - need to investigate why or if we can tweak the rules a bit
750
- static function getrules_deny_bad_query_strings()
751
- {
752
- global $aio_wp_security;
753
- $rules = '';
754
- if ($aio_wp_security->configs->get_value('aiowps_deny_bad_query_strings') == '1') {
755
- $rules .= AIOWPSecurity_Utility_Htaccess::$deny_bad_query_strings_marker_start . PHP_EOL; //Add feature marker start
756
- $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
757
- $rules .= 'RewriteEngine On' . PHP_EOL;
758
- //$rules .= 'RewriteCond %{QUERY_STRING} ../ [NC,OR]' . PHP_EOL;
759
- //$rules .= 'RewriteCond %{QUERY_STRING} boot.ini [NC,OR]' . PHP_EOL;
760
- //$rules .= 'RewriteCond %{QUERY_STRING} tag= [NC,OR]' . PHP_EOL;
761
- $rules .= 'RewriteCond %{QUERY_STRING} ftp: [NC,OR]' . PHP_EOL;
762
- $rules .= 'RewriteCond %{QUERY_STRING} http: [NC,OR]' . PHP_EOL;
763
- $rules .= 'RewriteCond %{QUERY_STRING} https: [NC,OR]' . PHP_EOL;
764
- $rules .= 'RewriteCond %{QUERY_STRING} mosConfig [NC,OR]' . PHP_EOL;
765
- //$rules .= 'RewriteCond %{QUERY_STRING} ^.*([|]|(|)||\'|"|;|?|*).* [NC,OR]' . PHP_EOL;
766
- //$rules .= 'RewriteCond %{QUERY_STRING} ^.*(%22|%27|%3C|%3E|%5C|%7B|%7C).* [NC,OR]' . PHP_EOL;
767
- //$rules .= 'RewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F|127.0).* [NC,OR]' . PHP_EOL;
768
- $rules .= 'RewriteCond %{QUERY_STRING} ^.*(globals|encode|localhost|loopback).* [NC,OR]' . PHP_EOL;
769
- $rules .= 'RewriteCond %{QUERY_STRING} (\;|\'|\"|%22).*(request|insert|union|declare|drop) [NC]' . PHP_EOL;
770
- $rules .= 'RewriteRule ^(.*)$ - [F,L]' . PHP_EOL;
771
- $rules .= '</IfModule>' . PHP_EOL;
772
- $rules .= AIOWPSecurity_Utility_Htaccess::$deny_bad_query_strings_marker_end . PHP_EOL; //Add feature marker end
773
- }
774
-
775
- return $rules;
776
- }
777
-
778
- /*
779
- * This function will write rules to produce an advanced character string filter to prevent malicious string attacks from Cross Site Scripting (XSS)
780
- * NOTE: Some of these strings might be used for plugins or themes and doing so will disable the functionality.
781
- * This script is from perishablepress and is fairly safe to use and should not break anything important
782
- */
783
- //TODO - the rules below break the site - need to investigate why or if we can tweak the rules a bit
784
- //RedirectMatch 403 ^
785
- //RedirectMatch 403 $
786
- //RedirectMatch 403 |
787
- //RedirectMatch 403 ..
788
- //Redirectmatch 403 select(
789
- //Redirectmatch 403 convert(
790
- //RedirectMatch 403 .inc
791
- //RedirectMatch 403 include.
792
- //
793
- // The "@" sign is often used in filenames of retina-ready images like
794
- // "logo@2x.jpg", therefore it has been removed from the list.
795
- //RedirectMatch 403 \@
796
-
797
- static function getrules_advanced_character_string_filter()
798
- {
799
- global $aio_wp_security;
800
- $rules = '';
801
- if ($aio_wp_security->configs->get_value('aiowps_advanced_char_string_filter') == '1') {
802
- $rules .= AIOWPSecurity_Utility_Htaccess::$advanced_char_string_filter_marker_start . PHP_EOL; //Add feature marker start
803
-
804
- $rules .= '<IfModule mod_alias.c>
805
- RedirectMatch 403 \,
806
- RedirectMatch 403 \:
807
- RedirectMatch 403 \;
808
- RedirectMatch 403 \=
809
- RedirectMatch 403 \[
810
- RedirectMatch 403 \]
811
- RedirectMatch 403 \^
812
- RedirectMatch 403 \`
813
- RedirectMatch 403 \{
814
- RedirectMatch 403 \}
815
- RedirectMatch 403 \~
816
- RedirectMatch 403 \"
817
- RedirectMatch 403 \$
818
- RedirectMatch 403 \<
819
- RedirectMatch 403 \>
820
- RedirectMatch 403 \|
821
- RedirectMatch 403 \.\.
822
- RedirectMatch 403 \%0
823
- RedirectMatch 403 \%A
824
- RedirectMatch 403 \%B
825
- RedirectMatch 403 \%C
826
- RedirectMatch 403 \%D
827
- RedirectMatch 403 \%E
828
- RedirectMatch 403 \%F
829
- RedirectMatch 403 \%22
830
- RedirectMatch 403 \%27
831
- RedirectMatch 403 \%28
832
- RedirectMatch 403 \%29
833
- RedirectMatch 403 \%3C
834
- RedirectMatch 403 \%3E
835
- RedirectMatch 403 \%3F
836
- RedirectMatch 403 \%5B
837
- RedirectMatch 403 \%5C
838
- RedirectMatch 403 \%5D
839
- RedirectMatch 403 \%7B
840
- RedirectMatch 403 \%7C
841
- RedirectMatch 403 \%7D
842
- # COMMON PATTERNS
843
- Redirectmatch 403 \_vpi
844
- RedirectMatch 403 \.inc
845
- Redirectmatch 403 xAou6
846
- Redirectmatch 403 db\_name
847
- Redirectmatch 403 select\(
848
- Redirectmatch 403 convert\(
849
- Redirectmatch 403 \/query\/
850
- RedirectMatch 403 ImpEvData
851
- Redirectmatch 403 \.XMLHTTP
852
- Redirectmatch 403 proxydeny
853
- RedirectMatch 403 function\.
854
- Redirectmatch 403 remoteFile
855
- Redirectmatch 403 servername
856
- Redirectmatch 403 \&rptmode\=
857
- Redirectmatch 403 sys\_cpanel
858
- RedirectMatch 403 db\_connect
859
- RedirectMatch 403 doeditconfig
860
- RedirectMatch 403 check\_proxy
861
- Redirectmatch 403 system\_user
862
- Redirectmatch 403 \/\(null\)\/
863
- Redirectmatch 403 clientrequest
864
- Redirectmatch 403 option\_value
865
- RedirectMatch 403 ref\.outcontrol
866
- # SPECIFIC EXPLOITS
867
- RedirectMatch 403 errors\.
868
- RedirectMatch 403 config\.
869
- RedirectMatch 403 include\.
870
- RedirectMatch 403 display\.
871
- RedirectMatch 403 register\.
872
- Redirectmatch 403 password\.
873
- RedirectMatch 403 maincore\.
874
- RedirectMatch 403 authorize\.
875
- Redirectmatch 403 macromates\.
876
- RedirectMatch 403 head\_auth\.
877
- RedirectMatch 403 submit\_links\.
878
- RedirectMatch 403 change\_action\.
879
- Redirectmatch 403 com\_facileforms\/
880
- RedirectMatch 403 admin\_db\_utilities\.
881
- RedirectMatch 403 admin\.webring\.docs\.
882
- Redirectmatch 403 Table\/Latest\/index\.
883
- </IfModule>' . PHP_EOL;
884
- $rules .= AIOWPSecurity_Utility_Htaccess::$advanced_char_string_filter_marker_end . PHP_EOL; //Add feature marker end
885
- }
886
-
887
- return $rules;
888
- }
889
-
890
- /*
891
- * This function contains the rules for the 5G blacklist produced by Jeff Starr from perishablepress.com
892
- * NOTE: Since Jeff regularly updates and evolves his blacklist rules, ie, 5G->6G->7G.... we will update this function to reflect the latest blacklist release
893
- */
894
-
895
-
896
- static function getrules_5g_blacklist()
897
- {
898
- global $aio_wp_security;
899
- $rules = '';
900
- if ($aio_wp_security->configs->get_value('aiowps_enable_5g_firewall') == '1') {
901
- $rules .= AIOWPSecurity_Utility_Htaccess::$five_g_blacklist_marker_start . PHP_EOL; //Add feature marker start
902
-
903
- $rules .= '# 5G BLACKLIST/FIREWALL (2013)
904
- # @ http://perishablepress.com/5g-blacklist-2013/
905
-
906
- # 5G:[QUERY STRINGS]
907
- <IfModule mod_rewrite.c>
908
- RewriteEngine On
909
- RewriteBase /
910
- RewriteCond %{QUERY_STRING} (\"|%22).*(<|>|%3) [NC,OR]
911
- RewriteCond %{QUERY_STRING} (javascript:).*(\;) [NC,OR]
912
- RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3) [NC,OR]
913
- RewriteCond %{QUERY_STRING} (\\\|\.\./|`|=\'$|=%27$) [NC,OR]
914
- RewriteCond %{QUERY_STRING} (\;|\'|\"|%22).*(union|select|insert|drop|update|md5|benchmark|or|and|if) [NC,OR]
915
- RewriteCond %{QUERY_STRING} (base64_encode|localhost|mosconfig) [NC,OR]
916
- RewriteCond %{QUERY_STRING} (boot\.ini|echo.*kae|etc/passwd) [NC,OR]
917
- RewriteCond %{QUERY_STRING} (GLOBALS|REQUEST)(=|\[|%) [NC]
918
- RewriteRule .* - [F]
919
- </IfModule>
920
-
921
- # 5G:[USER AGENTS]
922
- <IfModule mod_setenvif.c>
923
- # SetEnvIfNoCase User-Agent ^$ keep_out
924
- SetEnvIfNoCase User-Agent (binlar|casper|cmsworldmap|comodo|diavol|dotbot|feedfinder|flicky|ia_archiver|jakarta|kmccrew|nutch|planetwork|purebot|pycurl|skygrid|sucker|turnit|vikspider|zmeu) keep_out
925
- <limit GET POST PUT>
926
- Order Allow,Deny
927
- Allow from all
928
- Deny from env=keep_out
929
- </limit>
930
- </IfModule>
931
-
932
- # 5G:[REQUEST STRINGS]
933
- <IfModule mod_alias.c>
934
- RedirectMatch 403 (https?|ftp|php)\://
935
- RedirectMatch 403 /(https?|ima|ucp)/
936
- RedirectMatch 403 /(Permanent|Better)$
937
- RedirectMatch 403 (\=\\\\\\\'|\=\\\%27|/\\\\\\\'/?|\)\.css\()$
938
- RedirectMatch 403 (\,|\)\+|/\,/|\{0\}|\(/\(|\.\.\.|\+\+\+|\||\\\\\"\\\\\")
939
- RedirectMatch 403 \.(cgi|asp|aspx|cfg|dll|exe|jsp|mdb|sql|ini|rar)$
940
- RedirectMatch 403 /(contac|fpw|install|pingserver|register)\.php$
941
- RedirectMatch 403 (base64|crossdomain|localhost|wwwroot|e107\_)
942
- RedirectMatch 403 (eval\(|\_vti\_|\(null\)|echo.*kae|config\.xml)
943
- RedirectMatch 403 \.well\-known/host\-meta
944
- RedirectMatch 403 /function\.array\-rand
945
- RedirectMatch 403 \)\;\$\(this\)\.html\(
946
- RedirectMatch 403 proc/self/environ
947
- RedirectMatch 403 msnbot\.htm\)\.\_
948
- RedirectMatch 403 /ref\.outcontrol
949
- RedirectMatch 403 com\_cropimage
950
- RedirectMatch 403 indonesia\.htm
951
- RedirectMatch 403 \{\$itemURL\}
952
- RedirectMatch 403 function\(\)
953
- RedirectMatch 403 labels\.rdf
954
- RedirectMatch 403 /playing.php
955
- RedirectMatch 403 muieblackcat
956
- </IfModule>
957
-
958
- # 5G:[REQUEST METHOD]
959
- <ifModule mod_rewrite.c>
960
- RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
961
- RewriteRule .* - [F]
962
- </IfModule>' . PHP_EOL;
963
- $rules .= AIOWPSecurity_Utility_Htaccess::$five_g_blacklist_marker_end . PHP_EOL; //Add feature marker end
964
- }
965
-
966
- return $rules;
967
- }
968
-
969
- /*
970
- * This function contains the rules for the 6G blacklist produced by Jeff Starr:
 
 
 
 
 
 
971
  * https://perishablepress.com/6g/
972
- */
973
- static function getrules_6g_blacklist()
974
- {
975
- global $aio_wp_security;
976
- $rules = '';
977
- $ip_blacklist_23 = '';
978
- $ip_blacklist_24 = '';
979
- if ($aio_wp_security->configs->get_value('aiowps_enable_6g_firewall') == '1') {
980
- //if ip blacklist is enabled we will merge that code with the 6G rules to prevent clashes
981
- if ($aio_wp_security->configs->get_value('aiowps_enable_blacklisting') == '1') {
982
- // Let's do the list of blacklisted IPs first
983
- $hosts = AIOWPSecurity_Utility::explode_trim_filter_empty($aio_wp_security->configs->get_value('aiowps_banned_ip_addresses'));
984
- // Filter out duplicate lines, add netmask to IP addresses
985
- $ips_with_netmask = self::add_netmask(array_unique($hosts));
986
-
987
- if ( !empty($ips_with_netmask) ) {
988
- // Apache or LiteSpeed webserver
989
- // Apache 2.2 and older
990
- $ip_blacklist_23 .= '#AIOWPS_IP_BLACKLIST_2_3_START' . PHP_EOL;
991
- $ip_blacklist_24 .= '#AIOWPS_IP_BLACKLIST_2_4_START' . PHP_EOL;
992
- foreach ($ips_with_netmask as $ip_with_netmask) {
993
- $ip_blacklist_23 .= "Deny from " . $ip_with_netmask . PHP_EOL;
994
- $ip_blacklist_24 .= "Require not ip " . $ip_with_netmask . PHP_EOL;
995
- }
996
- $ip_blacklist_23 .= '#AIOWPS_IP_BLACKLIST_2_3_END' . PHP_EOL;
997
- $ip_blacklist_24 .= '#AIOWPS_IP_BLACKLIST_2_4_END' . PHP_EOL;
998
- }
999
- }
1000
-
1001
- $rules .= AIOWPSecurity_Utility_Htaccess::$six_g_blacklist_marker_start . PHP_EOL; //Add feature marker start
1002
-
1003
- $rules .= '# 6G FIREWALL/BLACKLIST
1004
- # @ https://perishablepress.com/6g/
1005
-
1006
- # 6G:[QUERY STRINGS]
1007
- <IfModule mod_rewrite.c>
1008
- RewriteEngine On
1009
- RewriteCond %{QUERY_STRING} (eval\() [NC,OR]
1010
- RewriteCond %{QUERY_STRING} (127\.0\.0\.1) [NC,OR]
1011
- RewriteCond %{QUERY_STRING} ([a-z0-9]{2000,}) [NC,OR]
1012
- RewriteCond %{QUERY_STRING} (javascript:)(.*)(;) [NC,OR]
1013
- RewriteCond %{QUERY_STRING} (base64_encode)(.*)(\() [NC,OR]
1014
- RewriteCond %{QUERY_STRING} (GLOBALS|REQUEST)(=|\[|%) [NC,OR]
1015
- RewriteCond %{QUERY_STRING} (<|%3C)(.*)script(.*)(>|%3) [NC,OR]
1016
- RewriteCond %{QUERY_STRING} (\\|\.\.\.|\.\./|~|`|<|>|\|) [NC,OR]
1017
- RewriteCond %{QUERY_STRING} (boot\.ini|etc/passwd|self/environ) [NC,OR]
1018
- RewriteCond %{QUERY_STRING} (thumbs?(_editor|open)?|tim(thumb)?)\.php [NC,OR]
1019
- RewriteCond %{QUERY_STRING} (\'|\")(.*)(drop|insert|md5|select|union) [NC]
1020
- RewriteRule .* - [F]
1021
- </IfModule>
1022
-
1023
- # 6G:[REQUEST METHOD]
1024
- <IfModule mod_rewrite.c>
1025
- RewriteCond %{REQUEST_METHOD} ^(connect|debug|move|put|trace|track) [NC]
1026
- RewriteRule .* - [F]
1027
- </IfModule>
1028
-
1029
- # 6G:[REFERRERS]
1030
- <IfModule mod_rewrite.c>
1031
- RewriteCond %{HTTP_REFERER} ([a-z0-9]{2000,}) [NC,OR]
1032
- RewriteCond %{HTTP_REFERER} (semalt.com|todaperfeita) [NC]
1033
- RewriteRule .* - [F]
1034
- </IfModule>
1035
-
1036
- # 6G:[REQUEST STRINGS]
1037
- <IfModule mod_alias.c>
1038
- RedirectMatch 403 (?i)([a-z0-9]{2000,})
1039
- RedirectMatch 403 (?i)(https?|ftp|php):/
1040
- RedirectMatch 403 (?i)(base64_encode)(.*)(\()
1041
- RedirectMatch 403 (?i)(=\\\'|=\\%27|/\\\'/?)\.
1042
- RedirectMatch 403 (?i)/(\$(\&)?|\*|\"|\.|,|&|&amp;?)/?$
1043
- RedirectMatch 403 (?i)(\{0\}|\(/\(|\.\.\.|\+\+\+|\\\"\\\")
1044
- RedirectMatch 403 (?i)(~|`|<|>|:|;|,|%|\\|\s|\{|\}|\[|\]|\|)
1045
- RedirectMatch 403 (?i)/(=|\$&|_mm|cgi-|etc/passwd|muieblack)
1046
- RedirectMatch 403 (?i)(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ)
1047
- RedirectMatch 403 (?i)\.(aspx?|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf)$
1048
- RedirectMatch 403 (?i)/(^$|(wp-)?config|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell)\.php
1049
- </IfModule>
1050
-
1051
- # 6G:[USER AGENTS]
1052
- <IfModule mod_setenvif.c>
1053
- SetEnvIfNoCase User-Agent ([a-z0-9]{2000,}) bad_bot
1054
- SetEnvIfNoCase User-Agent (archive.org|binlar|casper|checkpriv|choppy|clshttp|cmsworld|diavol|dotbot|extract|feedfinder|flicky|g00g1e|harvest|heritrix|httrack|kmccrew|loader|miner|nikto|nutch|planetwork|postrank|purebot|pycurl|python|seekerspider|siclab|skygrid|sqlmap|sucker|turnit|vikspider|winhttp|xxxyy|youda|zmeu|zune) bad_bot
1055
-
1056
- # Apache < 2.3
1057
- <IfModule !mod_authz_core.c>
1058
- Order Allow,Deny
1059
- Allow from all
1060
- Deny from env=bad_bot';
1061
- if(!empty($ip_blacklist_23))
1062
- $rules .= PHP_EOL.$ip_blacklist_23; //add ip blacklist if applicable
1063
- $rules .= '
1064
- </IfModule>
1065
-
1066
- # Apache >= 2.3
1067
- <IfModule mod_authz_core.c>
1068
- <RequireAll>
1069
- Require all Granted
1070
- Require not env bad_bot';
1071
- if(!empty($ip_blacklist_24))
1072
- $rules .= PHP_EOL.$ip_blacklist_24; //add ip blacklist if applicable
1073
- $rules .= '
1074
- </RequireAll>
1075
- </IfModule>
1076
- </IfModule>' . PHP_EOL;
1077
- $rules .= AIOWPSecurity_Utility_Htaccess::$six_g_blacklist_marker_end . PHP_EOL; //Add feature marker end
1078
- }
1079
-
1080
- return $rules;
1081
- }
1082
-
1083
- /*
1084
- * This function will write some directives to block all comments which do not originate from the blog's domain
1085
- * OR if the user agent is empty. All blocked requests will be redirected to 127.0.0.1
1086
- */
1087
- static function getrules_block_spambots()
1088
- {
1089
- global $aio_wp_security;
1090
- $rules = '';
1091
- if ($aio_wp_security->configs->get_value('aiowps_enable_spambot_blocking') == '1') {
1092
- $url_string = AIOWPSecurity_Utility_Htaccess::return_regularized_url(AIOWPSEC_WP_HOME_URL);
1093
- if ($url_string == FALSE) {
1094
- $url_string = AIOWPSEC_WP_HOME_URL;
1095
- }
1096
- $rules .= AIOWPSecurity_Utility_Htaccess::$block_spambots_marker_start . PHP_EOL; //Add feature marker start
1097
- $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
1098
- $rules .= 'RewriteEngine On' . PHP_EOL;
1099
- $rules .= 'RewriteCond %{REQUEST_METHOD} POST' . PHP_EOL;
1100
- $rules .= 'RewriteCond %{REQUEST_URI} ^(.*)?wp-comments-post\.php(.*)$' . PHP_EOL;
1101
- $rules .= 'RewriteCond %{HTTP_REFERER} !^' . $url_string . ' [NC,OR]' . PHP_EOL;
1102
- $rules .= 'RewriteCond %{HTTP_USER_AGENT} ^$' . PHP_EOL;
1103
- $rules .= 'RewriteRule .* http://127.0.0.1 [L]' . PHP_EOL;
1104
- $rules .= '</IfModule>' . PHP_EOL;
1105
- $rules .= AIOWPSecurity_Utility_Htaccess::$block_spambots_marker_end . PHP_EOL; //Add feature marker end
1106
- }
1107
-
1108
- return $rules;
1109
- }
1110
-
1111
- /*
1112
- * This function will write some directives to prevent image hotlinking
1113
- */
1114
- static function prevent_image_hotlinks()
1115
- {
1116
- global $aio_wp_security;
1117
- $rules = '';
1118
- if ($aio_wp_security->configs->get_value('aiowps_prevent_hotlinking') == '1') {
1119
- $url_string = AIOWPSecurity_Utility_Htaccess::return_regularized_url(AIOWPSEC_WP_HOME_URL);
1120
- if ($url_string == FALSE) {
1121
- $url_string = AIOWPSEC_WP_HOME_URL;
1122
- }
1123
- $rules .= AIOWPSecurity_Utility_Htaccess::$prevent_image_hotlinks_marker_start . PHP_EOL; //Add feature marker start
1124
- $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
1125
- $rules .= 'RewriteEngine On' . PHP_EOL;
1126
- $rules .= 'RewriteCond %{HTTP_REFERER} !^$' . PHP_EOL;
1127
- $rules .= 'RewriteCond %{REQUEST_FILENAME} -f' . PHP_EOL;
1128
- $rules .= 'RewriteCond %{REQUEST_FILENAME} \.(gif|jpe?g?|png)$ [NC]' . PHP_EOL;
1129
- $rules .= 'RewriteCond %{HTTP_REFERER} !^' . $url_string . ' [NC]' . PHP_EOL;
1130
- $rules .= 'RewriteRule \.(gif|jpe?g?|png)$ - [F,NC,L]' . PHP_EOL;
1131
- $rules .= '</IfModule>' . PHP_EOL;
1132
- $rules .= AIOWPSecurity_Utility_Htaccess::$prevent_image_hotlinks_marker_end . PHP_EOL; //Add feature marker end
1133
- }
1134
-
1135
- return $rules;
1136
- }
1137
-
1138
- /**
1139
- * This function will write any custom htaccess rules into the server's .htaccess file
1140
- * @return string
1141
- */
1142
- static function getrules_custom_rules()
1143
- {
1144
- global $aio_wp_security;
1145
- $rules = '';
1146
- if ($aio_wp_security->configs->get_value('aiowps_enable_custom_rules') == '1') {
1147
- $custom_rules = $aio_wp_security->configs->get_value('aiowps_custom_rules');
1148
- $rules .= AIOWPSecurity_Utility_Htaccess::$custom_rules_marker_start . PHP_EOL; //Add feature marker start
1149
- $rules .= $custom_rules . PHP_EOL;
1150
- $rules .= AIOWPSecurity_Utility_Htaccess::$custom_rules_marker_end . PHP_EOL; //Add feature marker end
1151
- }
1152
-
1153
- return $rules;
1154
- }
1155
-
1156
-
1157
- /*
1158
- * This function will do a quick check to see if a file's contents are actually .htaccess specific.
1159
- * At the moment it will look for the following tag somewhere in the file - "# BEGIN WordPress"
1160
- * If it finds the tag it will deem the file as being .htaccess specific.
1161
- * This was written to supplement the .htaccess restore functionality
1162
- */
1163
-
1164
- static function check_if_htaccess_contents($file)
1165
- {
1166
- $is_htaccess = false;
1167
- $file_contents = file_get_contents($file);
1168
- if ($file_contents === FALSE || strlen($file_contents) == 0) {
1169
- return -1;
1170
- }
1171
-
1172
- if ((strpos($file_contents, '# BEGIN WordPress') !== false) || (strpos($file_contents, '# BEGIN') !== false)) {
1173
- $is_htaccess = true; //It appears that we have some sort of .htacces file
1174
- } else {
1175
- //see if we're at the end of the section
1176
- $is_htaccess = false;
1177
- }
1178
-
1179
- if ($is_htaccess) {
1180
- return 1;
1181
- } else {
1182
- return -1;
1183
- }
1184
- }
1185
-
1186
- /*
1187
- * This function will take a URL string and convert it to a form useful for using in htaccess rules.
1188
- * Example: If URL passed to function = "http://www.mysite.com"
1189
- * Result = "http(s)?://(.*)?mysite\.com"
1190
- */
1191
- static function return_regularized_url($url)
1192
- {
1193
- if (filter_var($url, FILTER_VALIDATE_URL)) {
1194
- $xyz = explode('.', $url);
1195
- $y = '';
1196
- if (count($xyz) > 1) {
1197
- $j = 1;
1198
- foreach ($xyz as $x) {
1199
- if (strpos($x, 'www') !== false) {
1200
- $y .= str_replace('www', '(.*)?', $x);
1201
- } else if ($j == 1) {
1202
- $y .= $x;
1203
- } else if ($j > 1) {
1204
- $y .= '\.' . $x;
1205
- }
1206
- $j++;
1207
- }
1208
- //Now replace the "http" with "http(s)?" to cover both secure and non-secure
1209
- if (strpos($y, 'https') !== false) {
1210
- $y = str_replace('https', 'http(s)?', $y);
1211
- }else if (strpos($y, 'http') !== false) {
1212
- $y = str_replace('http', 'http(s)?', $y);
1213
- }
1214
- return $y;
1215
- } else {
1216
- return $url;
1217
- }
1218
- } else {
1219
- return FALSE;
1220
- }
1221
- }
1222
-
1223
- /**
1224
- * Returns a string with <Files $filename> directive that contains rules
1225
- * to effectively block access to any file that has basename matching
1226
- * $filename under Apache webserver.
1227
- *
1228
- * @link http://httpd.apache.org/docs/current/mod/core.html#files
1229
- *
1230
- * @param string $filename
1231
- * @return string
1232
- */
1233
- protected static function create_apache2_access_denied_rule($filename) {
1234
- return <<<END
1235
  <Files $filename>
1236
  <IfModule mod_authz_core.c>
1237
- Require all denied
1238
  </IfModule>
1239
  <IfModule !mod_authz_core.c>
1240
- Order deny,allow
1241
- Deny from all
1242
  </IfModule>
1243
  </Files>
1244
 
1245
  END;
1246
- // Keep the empty line at the end of heredoc string,
1247
- // otherwise the string will not end with end-of-line character!
1248
- }
1249
-
1250
-
1251
- /**
1252
- * Convert an array of optionally asterisk-masked or partial IPv4 addresses
1253
- * into network/netmask notation. Netmask value for a "full" IP is not
1254
- * added (see example below)
1255
- *
1256
- * Example:
1257
- * In: array('1.2.3.4', '5.6', '7.8.9.*')
1258
- * Out: array('1.2.3.4', '5.6.0.0/16', '7.8.9.0/24')
1259
- *
1260
- * Simple validation is performed:
1261
- * In: array('1.2.3.4.5', 'abc', '1.2.xyz.4')
1262
- * Out: array()
1263
- *
1264
- * Simple sanitization is performed:
1265
- * In: array('6.7.*.9')
1266
- * Out: array('6.7.0.0/16')
1267
- *
1268
- * @param array $ips
1269
- * @return array
1270
- */
1271
- protected static function add_netmask($ips=array()) {
1272
-
1273
- $output = array();
1274
- if(empty($ips)) return array();
1275
- foreach ( $ips as $ip ) {
1276
- //Check if ipv6
1277
- if (strpos($ip, ':') !== false) {
1278
- //for now we'll only support whole ipv6 (not address ranges)
1279
- $ipv6 = WP_Http::is_ip_address($ip);
1280
- if (FALSE === $ipv6) {
1281
- continue;
1282
- }
1283
- $output[] = $ip;
1284
- }
1285
-
1286
-
1287
- $parts = explode('.', $ip);
1288
-
1289
- // Skip any IP that is empty, has more parts than expected or has
1290
- // a non-numeric first part.
1291
- if ( empty($parts) || (count($parts) > 4) || !is_numeric($parts[0]) ) {
1292
- continue;
1293
- }
1294
-
1295
- $ip_out = array( $parts[0] );
1296
- $netmask = 8;
1297
-
1298
- for ( $i = 1, $force_zero = false; ($i < 4) && $ip_out; $i++ ) {
1299
- if ( $force_zero || !isset($parts[$i]) || ($parts[$i] === '') || ($parts[$i] === '*') ) {
1300
- $ip_out[$i] = '0';
1301
- $force_zero = true; // Forces all subsequent parts to be a zero
1302
- }
1303
- else if ( is_numeric($parts[$i]) ) {
1304
- $ip_out[$i] = $parts[$i];
1305
- $netmask += 8;
1306
- }
1307
- else {
1308
- // Invalid IP part detected, invalidate entire IP
1309
- $ip_out = false;
1310
- }
1311
- }
1312
-
1313
- if ( $ip_out ) {
1314
- // Glue IP back together, add netmask if IP denotes a subnet, store for output.
1315
- $output[] = implode('.', $ip_out) . (($netmask < 32) ? ('/' . $netmask) : '');
1316
- }
1317
- }
1318
-
1319
- return $output;
1320
- }
1321
- }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Utility_Htaccess {
 
 
 
 
 
7
 
8
+ // The following variables will store the comment markers for each of features added to the .htacces file
9
+ // This will make it easy to locate the blocks of code for deletion if someone disables a feature
10
+ public static $ip_blacklist_marker_start = '#AIOWPS_IP_BLACKLIST_START';
11
 
12
+ public static $ip_blacklist_marker_end = '#AIOWPS_IP_BLACKLIST_END';
 
13
 
14
+ public static $prevent_wp_file_access_marker_start = '#AIOWPS_BLOCK_WP_FILE_ACCESS_START';
 
15
 
16
+ public static $prevent_wp_file_access_marker_end = '#AIOWPS_BLOCK_WP_FILE_ACCESS_END';
 
17
 
18
+ public static $basic_htaccess_rules_marker_start = '#AIOWPS_BASIC_HTACCESS_RULES_START';
 
19
 
20
+ public static $basic_htaccess_rules_marker_end = '#AIOWPS_BASIC_HTACCESS_RULES_END';
21
+
22
+ public static $pingback_htaccess_rules_marker_start = '#AIOWPS_PINGBACK_HTACCESS_RULES_START';
23
+
24
+ public static $pingback_htaccess_rules_marker_end = '#AIOWPS_PINGBACK_HTACCESS_RULES_END';
25
+
26
+ public static $debug_log_block_htaccess_rules_marker_start = '#AIOWPS_DEBUG_LOG_BLOCK_HTACCESS_RULES_START';
27
+
28
+ public static $debug_log_block_htaccess_rules_marker_end = '#AIOWPS_DEBUG_LOG_BLOCK_HTACCESS_RULES_END';
29
+
30
+ public static $user_agent_blacklist_marker_start = '#AIOWPS_USER_AGENT_BLACKLIST_START';
31
+
32
+ public static $user_agent_blacklist_marker_end = '#AIOWPS_USER_AGENT_BLACKLIST_END';
33
+
34
+ public static $enable_brute_force_attack_prevention_marker_start = '#AIOWPS_ENABLE_BRUTE_FORCE_PREVENTION_START';
35
+
36
+ public static $enable_brute_force_attack_prevention_marker_end = '#AIOWPS_ENABLE_BRUTE_FORCE_PREVENTION_END';
37
+
38
+ public static $disable_index_views_marker_start = '#AIOWPS_DISABLE_INDEX_VIEWS_START';
39
+
40
+ public static $disable_index_views_marker_end = '#AIOWPS_DISABLE_INDEX_VIEWS_END';
41
+
42
+ public static $disable_trace_track_marker_start = '#AIOWPS_DISABLE_TRACE_TRACK_START';
43
+
44
+ public static $disable_trace_track_marker_end = '#AIOWPS_DISABLE_TRACE_TRACK_END';
45
+
46
+ public static $forbid_proxy_comments_marker_start = '#AIOWPS_FORBID_PROXY_COMMENTS_START';
47
+
48
+ public static $forbid_proxy_comments_marker_end = '#AIOWPS_FORBID_PROXY_COMMENTS_END';
49
+
50
+ public static $deny_bad_query_strings_marker_start = '#AIOWPS_DENY_BAD_QUERY_STRINGS_START';
51
+
52
+ public static $deny_bad_query_strings_marker_end = '#AIOWPS_DENY_BAD_QUERY_STRINGS_END';
53
+
54
+ public static $advanced_char_string_filter_marker_start = '#AIOWPS_ADVANCED_CHAR_STRING_FILTER_START';
55
+
56
+ public static $advanced_char_string_filter_marker_end = '#AIOWPS_ADVANCED_CHAR_STRING_FILTER_END';
57
+
58
+ public static $five_g_blacklist_marker_start = '#AIOWPS_FIVE_G_BLACKLIST_START';
59
+
60
+ public static $five_g_blacklist_marker_end = '#AIOWPS_FIVE_G_BLACKLIST_END';
61
+
62
+ public static $six_g_blacklist_marker_start = '#AIOWPS_SIX_G_BLACKLIST_START';
63
+
64
+ public static $six_g_blacklist_marker_end = '#AIOWPS_SIX_G_BLACKLIST_END';
65
+
66
+ public static $block_spambots_marker_start = '#AIOWPS_BLOCK_SPAMBOTS_START';
67
+
68
+ public static $block_spambots_marker_end = '#AIOWPS_BLOCK_SPAMBOTS_END';
69
+
70
+ public static $enable_login_whitelist_marker_start = '#AIOWPS_LOGIN_WHITELIST_START';
71
+
72
+ public static $enable_login_whitelist_marker_end = '#AIOWPS_LOGIN_WHITELIST_END';
73
+
74
+ public static $prevent_image_hotlinks_marker_start = '#AIOWPS_PREVENT_IMAGE_HOTLINKS_START';
75
+
76
+ public static $prevent_image_hotlinks_marker_end = '#AIOWPS_PREVENT_IMAGE_HOTLINKS_END';
77
+
78
+ public static $custom_rules_marker_start = '#AIOWPS_CUSTOM_RULES_START';
79
+
80
+ public static $custom_rules_marker_end = '#AIOWPS_CUSTOM_RULES_END';
81
+
82
+ /**
83
+ * TODO - enter more markers as new .htaccess features are added
84
+ */
85
+ public function __construct() {
86
+ //NOP
87
+ }
88
+
89
+
90
+ /**
91
+ * Write all active rules to .htaccess file.
92
+ *
93
+ * @return boolean True on success, false on failure.
94
+ */
95
+ public static function write_to_htaccess() {
96
+ global $aio_wp_security;
97
+ //figure out what server is being used
98
+ if (AIOWPSecurity_Utility::get_server_type() == -1) {
99
+ $aio_wp_security->debug_logger->log_debug("Unable to write to .htaccess - server type not supported!", 4);
100
+ return false; //unable to write to the file
101
+ }
102
+
103
+ //clean up old rules first
104
+ if (AIOWPSecurity_Utility_Htaccess::delete_from_htaccess() == -1) {
105
+ $aio_wp_security->debug_logger->log_debug("Delete operation of .htaccess file failed!", 4);
106
+ return false; //unable to write to the file
107
+ }
108
+
109
+ if (!function_exists('get_home_path')) require_once(ABSPATH. '/wp-admin/includes/file.php');
110
+ $home_path = get_home_path();
111
+ $htaccess = $home_path . '.htaccess';
112
+
113
+ if (!$f = @fopen($htaccess, 'a+')) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged,Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
114
+ @chmod($htaccess, 0644);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
115
+ if (!$f = @fopen($htaccess, 'a+')) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged,Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
116
+ $aio_wp_security->debug_logger->log_debug("chmod operation on .htaccess failed!", 4);
117
+ return false;
118
+ }
119
+ }
120
+ AIOWPSecurity_Utility_File::backup_and_rename_htaccess($htaccess); //TODO - we dont want to continually be backing up the htaccess file
121
+ $ht = explode(PHP_EOL, implode('', file($htaccess))); //parse each line of file into array
122
+
123
+ $rules = AIOWPSecurity_Utility_Htaccess::getrules();
124
+
125
+ $rulesarray = explode(PHP_EOL, $rules);
126
+ $rulesarray = apply_filters('aiowps_htaccess_rules_before_writing', $rulesarray);
127
+ $contents = array_merge($rulesarray, $ht);
128
+
129
+ if (!$f = @fopen($htaccess, 'w+')) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged,Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
130
+ $aio_wp_security->debug_logger->log_debug("Write operation on .htaccess failed!", 4);
131
+ return false; //we can't write to the file
132
+ }
133
+
134
+ $blank = false;
135
+
136
+ //write each line to file
137
+ foreach ($contents as $insertline) {
138
+ if (trim($insertline) == '') {
139
+ if (false == $blank) {
140
+ fwrite($f, PHP_EOL . trim($insertline));
141
+ }
142
+ $blank = true;
143
+ } else {
144
+ $blank = false;
145
+ fwrite($f, PHP_EOL . trim($insertline));
146
+ }
147
+ }
148
+ @fclose($f);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
149
+ return true; //success
150
+ }
151
+
152
+ /**
153
+ * This function will delete the code which has been added to the .htaccess file by this plugin
154
+ * It will try to find the comment markers "# BEGIN All In One WP Security" and "# END All In One WP Security" and delete contents in between
155
+ *
156
+ * @param string $section
157
+ * @return boolean
158
+ */
159
+ public static function delete_from_htaccess($section = 'All In One WP Security') {
160
+ if (!function_exists('get_home_path')) require_once(ABSPATH. '/wp-admin/includes/file.php');
161
+ $home_path = get_home_path();
162
+ $htaccess = $home_path . '.htaccess';
163
+
164
+ if (!file_exists($htaccess)) {
165
+ $ht = @fopen($htaccess, 'a+');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
166
+ @fclose($ht);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
167
+ }
168
+
169
+ // Bug Fix: On some environments such as windows (xampp) this function was clobbering the non-aiowps-related .htaccess contents for certain cases.
170
+ // In some cases when WordPress saves the .htaccess file (eg, when saving permalink settings),
171
+ // the line endings differ from the expected PHP_EOL endings. (WordPress saves with "\n" (UNIX style) but PHP_EOL may be set as "\r\n" (WIN/DOS))
172
+ // In this case exploding via PHP_EOL may not yield the result we expect.
173
+ // Therefore we need to do the following extra checks.
174
+ $ht_contents_imploded = implode('', file($htaccess));
175
+ if (empty($ht_contents_imploded)) {
176
+ return 1;
177
+ } elseif (strstr($ht_contents_imploded, PHP_EOL)) {
178
+ $ht_contents = explode(PHP_EOL, $ht_contents_imploded); //parse each line of file into array
179
+ } elseif (strstr($ht_contents_imploded, "\n")) {
180
+ $ht_contents = explode("\n", $ht_contents_imploded); //parse each line of file into array
181
+ } elseif (strstr($ht_contents_imploded, "\r")) {
182
+ $ht_contents = explode("\r", $ht_contents_imploded); //parse each line of file into array
183
+ } elseif (strstr($ht_contents_imploded, "\r\n")) {
184
+ $ht_contents = explode("\r\n", $ht_contents_imploded); //parse each line of file into array
185
+ }
186
+
187
+ if ($ht_contents) { //as long as there are lines in the file
188
+ $state = true;
189
+ if (!$f = @fopen($htaccess, 'w+')) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged,Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
190
+ @chmod($htaccess, 0644);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
191
+ if (!$f = @fopen($htaccess, 'w+')) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged,Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
192
+ return -1;
193
+ }
194
+ }
195
+
196
+ foreach ($ht_contents as $markerline) { //for each line in the file
197
+ if (strpos($markerline, '# BEGIN ' . $section) !== false) { //if we're at the beginning of the section
198
+ $state = false;
199
+ }
200
+ if (true == $state) { //as long as we're not in the section keep writing
201
+ fwrite($f, trim($markerline) . PHP_EOL);
202
+ }
203
+ if (strpos($markerline, '# END ' . $section) !== false) { //see if we're at the end of the section
204
+ $state = true;
205
+ }
206
+ }
207
+ @fclose($f);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
208
+ return 1;
209
+ }
210
+ return 1;
211
+ }
212
+
213
+ public static function getrules() {
214
+ global $aio_wp_security;
215
+ $rules = "";
216
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_block_wp_file_access();
217
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_basic_htaccess();
218
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_pingback_htaccess();
219
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_block_debug_log_access_htaccess();
220
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_disable_index_views();
221
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_blacklist();
222
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_disable_trace_and_track();
223
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_forbid_proxy_comment_posting();
224
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_deny_bad_query_strings();
225
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_advanced_character_string_filter();
226
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_6g_blacklist();
227
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_5g_blacklist();
228
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_enable_brute_force_prevention();
229
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_block_spambots();
230
+ $rules .= AIOWPSecurity_Utility_Htaccess::getrules_enable_login_whitelist_v2();
231
+ $rules .= AIOWPSecurity_Utility_Htaccess::prevent_image_hotlinks();
232
+ $custom_rules = AIOWPSecurity_Utility_Htaccess::getrules_custom_rules();
233
+ if ($aio_wp_security->configs->get_value('aiowps_place_custom_rules_at_top')=='1') {
234
+ $rules = $custom_rules . $rules;
235
+ } else {
236
+ $rules .= $custom_rules;
237
+ }
238
+
239
+ //TODO: The following utility functions are ready to use when we write the menu pages for these features
240
+
241
+ //Add more functions for features as needed
242
+ //$rules .= AIOWPSecurity_Utility_Htaccess::getrules_somefeature();
243
+
244
+ //Add outer markers if we have rules
245
+ if ('' != $rules) {
246
+ $rules = "# BEGIN All In One WP Security" . PHP_EOL . $rules . "# END All In One WP Security" . PHP_EOL;
247
+ }
248
+
249
+ return $rules;
250
+ }
251
+
252
+ /**
253
+ * This function will write rules to prevent people from accessing the following files:
254
+ * readme.html, license.txt and wp-config-sample.php.
255
+ */
256
+ public static function getrules_block_wp_file_access() {
257
+ global $aio_wp_security;
258
+ $rules = '';
259
+ if ($aio_wp_security->configs->get_value('aiowps_prevent_default_wp_file_access') == '1') {
260
+ $rules .= AIOWPSecurity_Utility_Htaccess::$prevent_wp_file_access_marker_start . PHP_EOL; //Add feature marker start
261
+ $rules .= self::create_apache2_access_denied_rule('license.txt');
262
+ $rules .= self::create_apache2_access_denied_rule('wp-config-sample.php');
263
+ $rules .= self::create_apache2_access_denied_rule('readme.html');
264
+ $rules .= AIOWPSecurity_Utility_Htaccess::$prevent_wp_file_access_marker_end . PHP_EOL; //Add feature marker end
265
+ }
266
+
267
+ return $rules;
268
+ }
269
+
270
+ public static function getrules_blacklist() {
271
+ global $aio_wp_security;
272
+ // Are we on Apache or LiteSpeed webserver?
273
+ $aiowps_server = AIOWPSecurity_Utility::get_server_type();
274
+ $apache_or_litespeed = 'apache' == $aiowps_server || 'litespeed' == $aiowps_server;
275
+ $rules = '';
276
+ if ($aio_wp_security->configs->get_value('aiowps_enable_blacklisting') == '1') {
277
+ // Let's do the list of blacklisted IPs first
278
+ $hosts = AIOWPSecurity_Utility::explode_trim_filter_empty($aio_wp_security->configs->get_value('aiowps_banned_ip_addresses'));
279
+ // Filter out duplicate lines, add netmask to IP addresses
280
+ $ips_with_netmask = self::add_netmask(array_unique($hosts));
281
+ if (!empty($ips_with_netmask) && ($aio_wp_security->configs->get_value('aiowps_enable_6g_firewall') != '1')) {
282
+ $rules .= AIOWPSecurity_Utility_Htaccess::$ip_blacklist_marker_start . PHP_EOL; //Add feature marker start
283
+
284
+ if ($apache_or_litespeed) {
285
+ // Apache or LiteSpeed webserver
286
+ // Apache 2.2 and older
287
+ $rules .= "<IfModule !mod_authz_core.c>" . PHP_EOL;
288
+ $rules .= "Order allow,deny" . PHP_EOL;
289
+ $rules .= "Allow from all" . PHP_EOL;
290
+ foreach ($ips_with_netmask as $ip_with_netmask) {
291
+ $rules .= "Deny from " . $ip_with_netmask . PHP_EOL;
292
+ }
293
+ $rules .= "</IfModule>" . PHP_EOL;
294
+ // Apache 2.3 and newer
295
+ $rules .= "<IfModule mod_authz_core.c>" . PHP_EOL;
296
+ $rules .= "<RequireAll>" . PHP_EOL;
297
+ $rules .= "Require all granted" . PHP_EOL;
298
+ foreach ($ips_with_netmask as $ip_with_netmask) {
299
+ $rules .= "Require not ip " . $ip_with_netmask . PHP_EOL;
300
+ }
301
+ $rules .= "</RequireAll>" . PHP_EOL;
302
+ $rules .= "</IfModule>" . PHP_EOL;
303
+ } else {
304
+ // Nginx webserver
305
+ foreach ($ips_with_netmask as $ip_with_netmask) {
306
+ $rules .= "\tdeny " . $ip_with_netmask . ";" . PHP_EOL;
307
+ }
308
+ }
309
+
310
+ $rules .= AIOWPSecurity_Utility_Htaccess::$ip_blacklist_marker_end . PHP_EOL; //Add feature marker end
311
+ }
312
+
313
+ //Now let's do the user agent list
314
+ $user_agents = explode(PHP_EOL, $aio_wp_security->configs->get_value('aiowps_banned_user_agents'));
315
+ if (!empty($user_agents) && !(sizeof($user_agents) == 1 && trim($user_agents[0]) == '')) {
316
+ if ($apache_or_litespeed) {
317
+ $rules .= AIOWPSecurity_Utility_Htaccess::$user_agent_blacklist_marker_start . PHP_EOL; //Add feature marker start
318
+ //Start mod_rewrite rules
319
+ $rules .= "<IfModule mod_rewrite.c>" . PHP_EOL . "RewriteEngine On" . PHP_EOL . PHP_EOL;
320
+ $count = 1;
321
+ foreach ($user_agents as $agent) {
322
+ $agent_escaped = quotemeta($agent);
323
+ $pattern = '/\s/'; //Find spaces in the string
324
+ $replacement = '\s'; //Replace spaces with \s so apache can understand
325
+ $agent_sanitized = preg_replace($pattern, $replacement, $agent_escaped);
326
+
327
+ $rules .= "RewriteCond %{HTTP_USER_AGENT} ^" . trim($agent_sanitized);
328
+ if ($count < sizeof($user_agents)) {
329
+ $rules .= " [NC,OR]" . PHP_EOL;
330
+ $count++;
331
+ } else {
332
+ $rules .= " [NC]" . PHP_EOL;
333
+ }
334
+
335
+ }
336
+ $rules .= "RewriteRule ^(.*)$ - [F,L]" . PHP_EOL . PHP_EOL;
337
+ // End mod_rewrite rules
338
+ $rules .= "</IfModule>" . PHP_EOL;
339
+ $rules .= AIOWPSecurity_Utility_Htaccess::$user_agent_blacklist_marker_end . PHP_EOL; //Add feature marker end
340
+ } else {
341
+ $count = 1;
342
+ $alist = '';
343
+ foreach ($user_agents as $agent) {
344
+ $alist .= trim($agent);
345
+ if ($count < sizeof($user_agents)) {
346
+ $alist .= '|';
347
+ $count++;
348
+ }
349
+ }
350
+ $rules .= "\tif (\$http_user_agent ~* " . $alist . ") { return 403; }" . PHP_EOL;
351
+ }
352
+ }
353
+ }
354
+
355
+ return implode(PHP_EOL, array_diff(explode(PHP_EOL, $rules), array('Deny from ', 'Deny from')));
356
+ }
357
+
358
+ /**
359
+ * TODO - info
360
+ */
361
+ public static function getrules_basic_htaccess() {
362
+ global $aio_wp_security;
363
+
364
+ $rules = '';
365
+ if ($aio_wp_security->configs->get_value('aiowps_enable_basic_firewall') == '1') {
366
+ $rules .= AIOWPSecurity_Utility_Htaccess::$basic_htaccess_rules_marker_start . PHP_EOL; //Add feature marker start
367
+ //protect the htaccess file - this is done by default with apache config file but we are including it here for good measure
368
+ $rules .= self::create_apache2_access_denied_rule('.htaccess');
369
+
370
+ //disable the server signature
371
+ $rules .= 'ServerSignature Off' . PHP_EOL;
372
+
373
+ //limit file upload size
374
+ $upload_limit = $aio_wp_security->configs->get_value('aiowps_max_file_upload_size');
375
+ //Shouldn't be empty but just in case
376
+ $upload_limit = empty($upload_limit) ? 10 : $upload_limit;
377
+ $upload_limit = $upload_limit * 1024 * 1024; // Convert from MB to Bytes - approx but close enough
378
+
379
+ $rules .= 'LimitRequestBody '.$upload_limit . PHP_EOL;
380
+
381
+ // protect wpconfig.php.
382
+ $rules .= self::create_apache2_access_denied_rule('wp-config.php');
383
+
384
+ $rules .= AIOWPSecurity_Utility_Htaccess::$basic_htaccess_rules_marker_end . PHP_EOL; //Add feature marker end
385
+ }
386
+ return $rules;
387
+ }
388
+
389
+ public static function getrules_pingback_htaccess() {
390
+ global $aio_wp_security;
391
+
392
+ $rules = '';
393
+ if ($aio_wp_security->configs->get_value('aiowps_enable_pingback_firewall') == '1') {
394
+ $rules .= AIOWPSecurity_Utility_Htaccess::$pingback_htaccess_rules_marker_start . PHP_EOL; //Add feature marker start
395
+ $rules .= self::create_apache2_access_denied_rule('xmlrpc.php');
396
+ $rules .= AIOWPSecurity_Utility_Htaccess::$pingback_htaccess_rules_marker_end . PHP_EOL; //Add feature marker end
397
+ }
398
+ return $rules;
399
+ }
400
+
401
+ public static function getrules_block_debug_log_access_htaccess() {
402
+ global $aio_wp_security;
403
+
404
+ $rules = '';
405
+ if ($aio_wp_security->configs->get_value('aiowps_block_debug_log_file_access') == '1') {
406
+ $rules .= AIOWPSecurity_Utility_Htaccess::$debug_log_block_htaccess_rules_marker_start . PHP_EOL; //Add feature marker start
407
+ $rules .= self::create_apache2_access_denied_rule('debug.log');
408
+ $rules .= AIOWPSecurity_Utility_Htaccess::$debug_log_block_htaccess_rules_marker_end . PHP_EOL; //Add feature marker end
409
+ }
410
+ return $rules;
411
+ }
412
+
413
+ /**
414
+ * This function will write some drectives to block all people who do not have a cookie
415
+ * when trying to access the WP login page
416
+ */
417
+ public static function getrules_enable_brute_force_prevention() {
418
+ global $aio_wp_security;
419
+ $rules = '';
420
+ if ($aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention') == '1') {
421
+ $cookie_name = $aio_wp_security->configs->get_value('aiowps_brute_force_secret_word');
422
+ $test_cookie_name = $aio_wp_security->configs->get_value('aiowps_cookie_brute_test');
423
+ $redirect_url = $aio_wp_security->configs->get_value('aiowps_cookie_based_brute_force_redirect_url');
424
+ $rules .= AIOWPSecurity_Utility_Htaccess::$enable_brute_force_attack_prevention_marker_start . PHP_EOL; //Add feature marker start
425
+ $rules .= 'RewriteEngine On' . PHP_EOL;
426
+ $rules .= 'RewriteCond %{REQUEST_URI} (wp-admin|wp-login)' . PHP_EOL;// If URI contains wp-admin or wp-login
427
+ if ($aio_wp_security->configs->get_value('aiowps_brute_force_attack_prevention_ajax_exception') == '1') {
428
+ $rules .= 'RewriteCond %{REQUEST_URI} !(wp-admin/admin-ajax.php)' . PHP_EOL; // To allow ajax requests through
429
+ }
430
+ if ($aio_wp_security->configs->get_value('aiowps_brute_force_attack_prevention_pw_protected_exception') == '1') {
431
+ $rules .= 'RewriteCond %{QUERY_STRING} !(action\=postpass)' . PHP_EOL; // Possible workaround for people usign the password protected page/post feature
432
+ }
433
+ $rules .= 'RewriteCond %{HTTP_COOKIE} !' . $cookie_name . '= [NC]' . PHP_EOL;
434
+ $rules .= 'RewriteCond %{HTTP_COOKIE} !' . $test_cookie_name . '= [NC]' . PHP_EOL;
435
+ $rules .= 'RewriteRule .* ' . $redirect_url . ' [L]' . PHP_EOL;
436
+ $rules .= AIOWPSecurity_Utility_Htaccess::$enable_brute_force_attack_prevention_marker_end . PHP_EOL; //Add feature marker end
437
+ }
438
+
439
+ return $rules;
440
+ }
441
+
442
+
443
+ /**
444
+ * This function will write some directives to allow IPs in the whitelist to access wp-login.php or wp-admin
445
+ * The function also handles the following special cases:
446
+ * 1) If the rename login feature is being used: for this scenario instead of protecting wp-login.php we must protect the special page slug
447
+ * 2) If the rename login feature is being used AND non permalink URL structure: for this case need to use mod_rewrite because we must check QUERY_STRING
448
+ */
449
+ public static function getrules_enable_login_whitelist() {
450
+ global $aio_wp_security;
451
+ $rules = '';
452
+
453
+ if ($aio_wp_security->configs->get_value('aiowps_enable_whitelisting') == '1') {
454
+ $site_url = AIOWPSEC_WP_URL;
455
+ $parse_url = parse_url($site_url);
456
+ $hostname = $parse_url['host'];
457
+ $host_ip = gethostbyname($hostname);
458
+ $special_case = false;
459
+ $rules .= AIOWPSecurity_Utility_Htaccess::$enable_login_whitelist_marker_start . PHP_EOL; //Add feature marker start
460
+ //If the rename login page feature is active, we will need to adjust the directives
461
+ if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
462
+ $secret_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
463
+ if (!get_option('permalink_structure')) {
464
+ //standard url structure is being used - ie, non permalinks
465
+ $special_case = true;
466
+ $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
467
+ $rules .= 'RewriteEngine on' . PHP_EOL;
468
+ $rules .= 'RewriteCond %{QUERY_STRING} ^' . $secret_slug . '=1.*$' . PHP_EOL;
469
+ $rules .= 'RewriteCond %{REMOTE_ADDR} !^' . preg_quote($host_ip) . '[OR]' . PHP_EOL;
470
+ } else {
471
+ $slug = preg_quote($secret_slug); //escape any applicable chars
472
+ $rules .= '<FilesMatch "^(' . $slug . ')">' . PHP_EOL;
473
+ }
474
+ } else {
475
+ $rules .= '<FilesMatch "^(wp-login\.php)">' . PHP_EOL;
476
+ }
477
+ if (!$special_case) {
478
+ $rules .= 'Order Allow,Deny' . PHP_EOL;
479
+ $rules .= 'Allow from ' . $hostname . PHP_EOL;
480
+ $rules .= 'Allow from ' . $host_ip . PHP_EOL;
481
+ }
482
+
483
+ //Let's get list of whitelisted IPs
484
+ $hosts = explode(PHP_EOL, $aio_wp_security->configs->get_value('aiowps_allowed_ip_addresses'));
485
+ if (!empty($hosts) && !(sizeof($hosts) == 1 && trim($hosts[0]) == '')) {
486
+ $phosts = array();
487
+ $num_hosts = count($hosts);
488
+ $i = 0;
489
+ foreach ($hosts as $host) {
490
+ $host = trim($host);
491
+ $or_string = ($i == $num_hosts - 1) ? '' : '[OR]'; //Add an [OR] clause for all except the last condition
492
+
493
+ if (!in_array($host, $phosts)) {
494
+ if (strstr($host, '*')) {
495
+ $parts = array_reverse(explode('.', $host));
496
+ $netmask = 32;
497
+ foreach ($parts as $part) {
498
+ if (strstr(trim($part), '*')) {
499
+ $netmask = $netmask - 8;
500
+
501
+ }
502
+ }
503
+ //*****Bug Fix ******
504
+ //Seems that netmask does not work when using the following type of directive, ie,
505
+ //RewriteCond %{REMOTE_ADDR} !^203\.87\.121\.0/24
506
+
507
+ //The following works:
508
+ //RewriteCond %{REMOTE_ADDR} !^203\.87\.121\.
509
+
510
+ if ($special_case) {
511
+ $dhost = trim(str_replace('*', '', implode('.', array_reverse($parts)), $count));
512
+ if ($count > 1) {
513
+ //means that we will have consecutive periods in the string and we must remove all except one - eg: 45.12..
514
+ $dhost = rtrim($dhost, '.');
515
+ $dhost = $dhost . '.';
516
+ }
517
+ } else {
518
+ $dhost = trim(str_replace('*', '0', implode('.', array_reverse($parts))) . '/' . $netmask);
519
+ }
520
+ if (strlen($dhost) > 4) {
521
+ if ($special_case) {
522
+ $dhost = preg_quote($dhost); //escape any applicable chars
523
+ $trule = 'RewriteCond %{REMOTE_ADDR} !^' . $dhost . $or_string . PHP_EOL;
524
+ if (trim($trule) != 'RewriteCond %{REMOTE_ADDR}!=') {
525
+ $rules .= $trule;
526
+ }
527
+ } else {
528
+ $trule = 'Allow from ' . $dhost . PHP_EOL;
529
+ if (trim($trule) != 'Allow from') {
530
+ $rules .= $trule;
531
+ }
532
+ }
533
+ }
534
+ } else {
535
+ $dhost = trim($host);
536
+ //ipv6 - for now we will support only whole ipv6 addresses, NOT ranges
537
+ if (strpos($dhost, ':') !== false) {
538
+ //possible ipv6 addr
539
+ $res = WP_Http::is_ip_address($dhost);
540
+ if (false === $res) {
541
+ continue;
542
+ }
543
+ }
544
+ if (strlen($dhost) > 4 || '6' == $res) {
545
+ if ($special_case) {
546
+ $dhost = preg_quote($dhost); //escape any applicable chars
547
+ $rules .= 'RewriteCond %{REMOTE_ADDR} !^' . $dhost . $or_string . PHP_EOL;
548
+ } else {
549
+ $rules .= 'Allow from ' . $dhost . PHP_EOL;
550
+ }
551
+
552
+ }
553
+ }
554
+ }
555
+ $phosts[] = $host;
556
+ $i++;
557
+ }
558
+ }
559
+
560
+ if ($special_case) {
561
+ $rules .= 'RewriteRule .* http://127.0.0.1 [L]' . PHP_EOL;
562
+ $rules .= '</IfModule>' . PHP_EOL;
563
+ } else {
564
+ $rules .= '</FilesMatch>' . PHP_EOL;
565
+ }
566
+ $rules .= AIOWPSecurity_Utility_Htaccess::$enable_login_whitelist_marker_end . PHP_EOL; //Add feature marker end
567
+ }
568
+
569
+ return $rules;
570
+ }
571
+
572
+ /**
573
+ * (This is an updated and improved version of getrules_enable_login_whitelist())
574
+ * This function will write some directives to allow IPs in the whitelist to access wp-login.php or wp-admin
575
+ * The function also handles the following special cases:
576
+ * 1) If the rename login feature is being used: for this scenario instead of protecting wp-login.php we must protect the special page slug
577
+ * 2) If the rename login feature is being used AND non permalink URL structure: for this case need to use mod_rewrite because we must check QUERY_STRING
578
+ */
579
+ public static function getrules_enable_login_whitelist_v2() {
580
+ global $aio_wp_security;
581
+ $rules = '';
582
+
583
+ if ($aio_wp_security->configs->get_value('aiowps_enable_whitelisting') == '1') {
584
+ $site_url = AIOWPSEC_WP_URL;
585
+ $parse_url = parse_url($site_url);
586
+ $hostname = $parse_url['host'];
587
+ $host_ip = gethostbyname($hostname);
588
+ $hidden_login_pretty_perms = false;
589
+ $rules .= AIOWPSecurity_Utility_Htaccess::$enable_login_whitelist_marker_start . PHP_EOL; //Add feature marker start
590
+ //If the rename login page feature is active, we will need to adjust the directives
591
+ if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
592
+ $secret_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
593
+ if (get_option('permalink_structure')) {
594
+ $slug = preg_quote($secret_slug); //escape any applicable chars
595
+ $rules .= '<FilesMatch "^(' . $slug . ')">' . PHP_EOL;
596
+ } else {
597
+ //standard url structure is being used - ie, non permalinks
598
+ $hidden_login_pretty_perms = true;
599
+ $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
600
+ $rules .= 'RewriteEngine on' . PHP_EOL;
601
+ $rules .= 'RewriteCond %{QUERY_STRING} ^' . $secret_slug . '=1.*$' . PHP_EOL;
602
+ $rules .= 'RewriteCond %{REMOTE_ADDR} !^' . preg_quote($host_ip) . PHP_EOL;
603
+ }
604
+ } else {
605
+ $rules .= '<FilesMatch "^(wp-login\.php)">' . PHP_EOL;
606
+ }
607
+ $rules_apache_pre_24 = '';
608
+ $rules_apache_24 = '';
609
+ if (!$hidden_login_pretty_perms) {
610
+ //start writing rules for versions of apache < 2.4
611
+ $rules_apache_pre_24 .= '<IfModule !mod_authz_core.c>' . PHP_EOL;
612
+ $rules_apache_pre_24 .= 'Order Allow,Deny' . PHP_EOL;
613
+ $rules_apache_pre_24 .= 'Allow from ' . $hostname . PHP_EOL;
614
+ $rules_apache_pre_24 .= 'Allow from ' . $host_ip . PHP_EOL;
615
+
616
+ //start writing rules for versions of apache >=2.4
617
+ $rules_apache_24 .= '<IfModule mod_authz_core.c>' . PHP_EOL;
618
+ $rules_apache_24 .= 'Require all denied' . PHP_EOL;
619
+ $rules_apache_24 .= 'Require local' . PHP_EOL;
620
+ $rules_apache_24 .= 'Require ip 127.0.0.1' . PHP_EOL;
621
+ $rules_apache_24 .= 'Require host ' . $hostname . PHP_EOL;
622
+ }
623
+
624
+ //Let's get list of whitelisted IPs
625
+ $hosts = AIOWPSecurity_Utility::explode_trim_filter_empty($aio_wp_security->configs->get_value('aiowps_allowed_ip_addresses'));
626
+ // Filter out duplicate lines, add netmask to IP addresses
627
+ $ips_with_netmask = self::add_netmask(array_unique($hosts));
628
+ if (!empty($ips_with_netmask)) {
629
+ foreach ($ips_with_netmask as $xhost) {
630
+ $ipv6 = false;
631
+ if (strpos($xhost, ':') !== false) {
632
+ //possible ipv6 addr
633
+ //ipv6 - for now we will support only whole ipv6 addresses, NOT ranges
634
+ $ipv6 = WP_Http::is_ip_address($xhost);
635
+ if (false === $ipv6) {
636
+ continue;
637
+ }
638
+ }
639
+ $ip_range = substr($xhost, 0, strpos($xhost, "/")); //check if address range
640
+ if ($hidden_login_pretty_perms) {
641
+ if (!empty($ip_range)) {
642
+ $xhost = $ip_range; //get the IP minus the slash with netmask bits
643
+ }
644
+ if (!$ipv6) {
645
+ $xhost = preg_replace("/[\.0]+$/", ".", $xhost);
646
+ $xhost = preg_quote($xhost);
647
+ }
648
+ $rules .= 'RewriteCond %{REMOTE_ADDR} !^' . $xhost . PHP_EOL;
649
+ } else {
650
+ //write rules for both apache 2.2 and 2.4+
651
+ $rules_apache_pre_24 .= 'Allow from ' . $xhost . PHP_EOL;
652
+ $rules_apache_24 .= 'Require ip '. $xhost . PHP_EOL;
653
+ }
654
+ }
655
+
656
+ }
657
+ if (!empty($rules_apache_pre_24)) {
658
+ $rules_apache_pre_24 .= '</IfModule>' . PHP_EOL;
659
+ }
660
+ if (!empty($rules_apache_24)) {
661
+ $rules_apache_24 .= '</IfModule>' . PHP_EOL;
662
+ }
663
+ $rules .= $rules_apache_pre_24 . $rules_apache_24;
664
+ if ($hidden_login_pretty_perms) {
665
+ $rules .= 'RewriteRule .* http://127.0.0.1 [L]' . PHP_EOL;
666
+ $rules .= '</IfModule>' . PHP_EOL;
667
+ } else {
668
+ $rules .= '</FilesMatch>' . PHP_EOL;
669
+ }
670
+ $rules .= AIOWPSecurity_Utility_Htaccess::$enable_login_whitelist_marker_end . PHP_EOL; //Add feature marker end
671
+ }
672
+
673
+ return $rules;
674
+ }
675
+
676
+ /**
677
+ * This function will disable directory listings for all directories, add this line to the
678
+ * site’s root .htaccess file.
679
+ * NOTE: AllowOverride must be enabled in the httpd.conf file for this to work!
680
+ */
681
+ public static function getrules_disable_index_views() {
682
+ global $aio_wp_security;
683
+ $rules = '';
684
+ if ($aio_wp_security->configs->get_value('aiowps_disable_index_views') == '1') {
685
+ $rules .= AIOWPSecurity_Utility_Htaccess::$disable_index_views_marker_start . PHP_EOL; //Add feature marker start
686
+ $rules .= 'Options -Indexes' . PHP_EOL;
687
+ $rules .= AIOWPSecurity_Utility_Htaccess::$disable_index_views_marker_end . PHP_EOL; //Add feature marker end
688
+ }
689
+
690
+ return $rules;
691
+ }
692
+
693
+ /**
694
+ * This function will write rules to disable trace and track.
695
+ * HTTP Trace attack (XST) can be used to return header requests
696
+ * and grab cookies and other information and is used along with
697
+ * a cross site scripting attacks (XSS)
698
+ */
699
+ public static function getrules_disable_trace_and_track() {
700
+ global $aio_wp_security;
701
+ $rules = '';
702
+ if ($aio_wp_security->configs->get_value('aiowps_disable_trace_and_track') == '1') {
703
+ $rules .= AIOWPSecurity_Utility_Htaccess::$disable_trace_track_marker_start . PHP_EOL; //Add feature marker start
704
+ $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
705
+ $rules .= 'RewriteEngine On' . PHP_EOL;
706
+ $rules .= 'RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)' . PHP_EOL;
707
+ $rules .= 'RewriteRule .* - [F]' . PHP_EOL;
708
+ $rules .= '</IfModule>' . PHP_EOL;
709
+ $rules .= AIOWPSecurity_Utility_Htaccess::$disable_trace_track_marker_end . PHP_EOL; //Add feature marker end
710
+ }
711
+
712
+ return $rules;
713
+ }
714
+
715
+ /**
716
+ * This function will write rules to prevent proxy comment posting.
717
+ * This will deny any requests that use a proxy server when posting
718
+ * to comments eliminating some spam and proxy requests.
719
+ * Thanks go to the helpful info and suggestions from perishablepress.com and Thomas O. (https://wordpress.org/support/topic/high-server-cpu-with-proxy-login)
720
+ */
721
+ public static function getrules_forbid_proxy_comment_posting() {
722
+ global $aio_wp_security;
723
+ $rules = '';
724
+ if ($aio_wp_security->configs->get_value('aiowps_forbid_proxy_comments') == '1') {
725
+ $rules .= AIOWPSecurity_Utility_Htaccess::$forbid_proxy_comments_marker_start . PHP_EOL; //Add feature marker start
726
+ $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
727
+ $rules .= 'RewriteEngine On' . PHP_EOL;
728
+ $rules .= 'RewriteCond %{REQUEST_METHOD} ^POST' . PHP_EOL;
729
+ $rules .= 'RewriteCond %{HTTP:VIA} !^$ [OR]' . PHP_EOL;
730
+ $rules .= 'RewriteCond %{HTTP:FORWARDED} !^$ [OR]' . PHP_EOL;
731
+ $rules .= 'RewriteCond %{HTTP:USERAGENT_VIA} !^$ [OR]' . PHP_EOL;
732
+ $rules .= 'RewriteCond %{HTTP:X_FORWARDED_FOR} !^$ [OR]' . PHP_EOL;
733
+ $rules .= 'RewriteCond %{HTTP:X_FORWARDED_HOST} !^$ [OR]' . PHP_EOL;
734
+ $rules .= 'RewriteCond %{HTTP:PROXY_CONNECTION} !^$ [OR]' . PHP_EOL;
735
+ $rules .= 'RewriteCond %{HTTP:XPROXY_CONNECTION} !^$ [OR]' . PHP_EOL;
736
+ $rules .= 'RewriteCond %{HTTP:HTTP_PC_REMOTE_ADDR} !^$ [OR]' . PHP_EOL;
737
+ $rules .= 'RewriteCond %{HTTP:HTTP_CLIENT_IP} !^$' . PHP_EOL;
738
+ $rules .= 'RewriteRule wp-comments-post\.php - [F]' . PHP_EOL;
739
+ $rules .= '</IfModule>' . PHP_EOL;
740
+ $rules .= AIOWPSecurity_Utility_Htaccess::$forbid_proxy_comments_marker_end . PHP_EOL; //Add feature marker end
741
+ }
742
+
743
+ return $rules;
744
+ }
745
+
746
+ /**
747
+ * This function will write rules to prevent malicious string attacks on your site using XSS.
748
+ * NOTE: Some of these strings might be used for plugins or themes and doing so will disable the functionality.
749
+ * This script is from perishablepress and is fairly safe to use and should not break anything important
750
+ * TODO - the currently commented out rules (see function below) break the site - need to investigate why or if we can tweak the rules a bit
751
+ */
752
+ public static function getrules_deny_bad_query_strings() {
753
+ global $aio_wp_security;
754
+ $rules = '';
755
+ if ($aio_wp_security->configs->get_value('aiowps_deny_bad_query_strings') == '1') {
756
+ $rules .= AIOWPSecurity_Utility_Htaccess::$deny_bad_query_strings_marker_start . PHP_EOL; //Add feature marker start
757
+ $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
758
+ $rules .= 'RewriteEngine On' . PHP_EOL;
759
+ //$rules .= 'RewriteCond %{QUERY_STRING} ../ [NC,OR]' . PHP_EOL;
760
+ //$rules .= 'RewriteCond %{QUERY_STRING} boot.ini [NC,OR]' . PHP_EOL;
761
+ //$rules .= 'RewriteCond %{QUERY_STRING} tag= [NC,OR]' . PHP_EOL;
762
+ $rules .= 'RewriteCond %{QUERY_STRING} ftp: [NC,OR]' . PHP_EOL;
763
+ $rules .= 'RewriteCond %{QUERY_STRING} http: [NC,OR]' . PHP_EOL;
764
+ $rules .= 'RewriteCond %{QUERY_STRING} https: [NC,OR]' . PHP_EOL;
765
+ $rules .= 'RewriteCond %{QUERY_STRING} mosConfig [NC,OR]' . PHP_EOL;
766
+ //$rules .= 'RewriteCond %{QUERY_STRING} ^.*([|]|(|)||\'|"|;|?|*).* [NC,OR]' . PHP_EOL;
767
+ //$rules .= 'RewriteCond %{QUERY_STRING} ^.*(%22|%27|%3C|%3E|%5C|%7B|%7C).* [NC,OR]' . PHP_EOL;
768
+ //$rules .= 'RewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F|127.0).* [NC,OR]' . PHP_EOL;
769
+ $rules .= 'RewriteCond %{QUERY_STRING} ^.*(globals|encode|localhost|loopback).* [NC,OR]' . PHP_EOL;
770
+ $rules .= 'RewriteCond %{QUERY_STRING} (\;|\'|\"|%22).*(request|insert|union|declare|drop) [NC]' . PHP_EOL;
771
+ $rules .= 'RewriteRule ^(.*)$ - [F,L]' . PHP_EOL;
772
+ $rules .= '</IfModule>' . PHP_EOL;
773
+ $rules .= AIOWPSecurity_Utility_Htaccess::$deny_bad_query_strings_marker_end . PHP_EOL; //Add feature marker end
774
+ }
775
+
776
+ return $rules;
777
+ }
778
+
779
+ /**
780
+ * This function will write rules to produce an advanced character string filter to prevent malicious string attacks from Cross Site Scripting (XSS)
781
+ * NOTE: Some of these strings might be used for plugins or themes and doing so will disable the functionality.
782
+ * This script is from perishablepress and is fairly safe to use and should not break anything important
783
+ * TODO - the rules below break the site - need to investigate why or if we can tweak the rules a bit
784
+ * RedirectMatch 403 ^
785
+ * RedirectMatch 403 $
786
+ * RedirectMatch 403 |
787
+ * RedirectMatch 403 ..
788
+ * Redirectmatch 403 select(
789
+ * Redirectmatch 403 convert(
790
+ * RedirectMatch 403 .inc
791
+ * RedirectMatch 403 include.
792
+ *
793
+ * The "@" sign is often used in filenames of retina-ready images like
794
+ * "logo@2x.jpg", therefore it has been removed from the list.
795
+ * RedirectMatch 403 \@
796
+ *
797
+ * @return string
798
+ */
799
+ public static function getrules_advanced_character_string_filter() {
800
+ global $aio_wp_security;
801
+ $rules = '';
802
+ if ($aio_wp_security->configs->get_value('aiowps_advanced_char_string_filter') == '1') {
803
+ $rules .= AIOWPSecurity_Utility_Htaccess::$advanced_char_string_filter_marker_start . PHP_EOL; //Add feature marker start
804
+
805
+ $rules .= '<IfModule mod_alias.c>
806
+ RedirectMatch 403 \,
807
+ RedirectMatch 403 \:
808
+ RedirectMatch 403 \;
809
+ RedirectMatch 403 \=
810
+ RedirectMatch 403 \[
811
+ RedirectMatch 403 \]
812
+ RedirectMatch 403 \^
813
+ RedirectMatch 403 \`
814
+ RedirectMatch 403 \{
815
+ RedirectMatch 403 \}
816
+ RedirectMatch 403 \~
817
+ RedirectMatch 403 \"
818
+ RedirectMatch 403 \$
819
+ RedirectMatch 403 \<
820
+ RedirectMatch 403 \>
821
+ RedirectMatch 403 \|
822
+ RedirectMatch 403 \.\.
823
+ RedirectMatch 403 \%0
824
+ RedirectMatch 403 \%A
825
+ RedirectMatch 403 \%B
826
+ RedirectMatch 403 \%C
827
+ RedirectMatch 403 \%D
828
+ RedirectMatch 403 \%E
829
+ RedirectMatch 403 \%F
830
+ RedirectMatch 403 \%22
831
+ RedirectMatch 403 \%27
832
+ RedirectMatch 403 \%28
833
+ RedirectMatch 403 \%29
834
+ RedirectMatch 403 \%3C
835
+ RedirectMatch 403 \%3E
836
+ RedirectMatch 403 \%3F
837
+ RedirectMatch 403 \%5B
838
+ RedirectMatch 403 \%5C
839
+ RedirectMatch 403 \%5D
840
+ RedirectMatch 403 \%7B
841
+ RedirectMatch 403 \%7C
842
+ RedirectMatch 403 \%7D
843
+ # COMMON PATTERNS
844
+ Redirectmatch 403 \_vpi
845
+ RedirectMatch 403 \.inc
846
+ Redirectmatch 403 xAou6
847
+ Redirectmatch 403 db\_name
848
+ Redirectmatch 403 select\(
849
+ Redirectmatch 403 convert\(
850
+ Redirectmatch 403 \/query\/
851
+ RedirectMatch 403 ImpEvData
852
+ Redirectmatch 403 \.XMLHTTP
853
+ Redirectmatch 403 proxydeny
854
+ RedirectMatch 403 function\.
855
+ Redirectmatch 403 remoteFile
856
+ Redirectmatch 403 servername
857
+ Redirectmatch 403 \&rptmode\=
858
+ Redirectmatch 403 sys\_cpanel
859
+ RedirectMatch 403 db\_connect
860
+ RedirectMatch 403 doeditconfig
861
+ RedirectMatch 403 check\_proxy
862
+ Redirectmatch 403 system\_user
863
+ Redirectmatch 403 \/\(null\)\/
864
+ Redirectmatch 403 clientrequest
865
+ Redirectmatch 403 option\_value
866
+ RedirectMatch 403 ref\.outcontrol
867
+ # SPECIFIC EXPLOITS
868
+ RedirectMatch 403 errors\.
869
+ RedirectMatch 403 config\.
870
+ RedirectMatch 403 include\.
871
+ RedirectMatch 403 display\.
872
+ RedirectMatch 403 register\.
873
+ Redirectmatch 403 password\.
874
+ RedirectMatch 403 maincore\.
875
+ RedirectMatch 403 authorize\.
876
+ Redirectmatch 403 macromates\.
877
+ RedirectMatch 403 head\_auth\.
878
+ RedirectMatch 403 submit\_links\.
879
+ RedirectMatch 403 change\_action\.
880
+ Redirectmatch 403 com\_facileforms\/
881
+ RedirectMatch 403 admin\_db\_utilities\.
882
+ RedirectMatch 403 admin\.webring\.docs\.
883
+ Redirectmatch 403 Table\/Latest\/index\.
884
+ </IfModule>' . PHP_EOL;
885
+ $rules .= AIOWPSecurity_Utility_Htaccess::$advanced_char_string_filter_marker_end . PHP_EOL; //Add feature marker end
886
+ }
887
+
888
+ return $rules;
889
+ }
890
+
891
+ /**
892
+ * This function contains the rules for the 5G blacklist produced by Jeff Starr from perishablepress.com
893
+ * NOTE: Since Jeff regularly updates and evolves his blacklist rules, ie, 5G->6G->7G.... we will update this function to reflect the latest blacklist release
894
+ */
895
+ public static function getrules_5g_blacklist() {
896
+ global $aio_wp_security;
897
+ $rules = '';
898
+ if ($aio_wp_security->configs->get_value('aiowps_enable_5g_firewall') == '1') {
899
+ $rules .= AIOWPSecurity_Utility_Htaccess::$five_g_blacklist_marker_start . PHP_EOL; //Add feature marker start
900
+
901
+ $rules .= '# 5G BLACKLIST/FIREWALL (2013)
902
+ # @ http://perishablepress.com/5g-blacklist-2013/
903
+
904
+ # 5G:[QUERY STRINGS]
905
+ <IfModule mod_rewrite.c>
906
+ RewriteEngine On
907
+ RewriteBase /
908
+ RewriteCond %{QUERY_STRING} (\"|%22).*(<|>|%3) [NC,OR]
909
+ RewriteCond %{QUERY_STRING} (javascript:).*(\;) [NC,OR]
910
+ RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3) [NC,OR]
911
+ RewriteCond %{QUERY_STRING} (\\\|\.\./|`|=\'$|=%27$) [NC,OR]
912
+ RewriteCond %{QUERY_STRING} (\;|\'|\"|%22).*(union|select|insert|drop|update|md5|benchmark|or|and|if) [NC,OR]
913
+ RewriteCond %{QUERY_STRING} (base64_encode|localhost|mosconfig) [NC,OR]
914
+ RewriteCond %{QUERY_STRING} (boot\.ini|echo.*kae|etc/passwd) [NC,OR]
915
+ RewriteCond %{QUERY_STRING} (GLOBALS|REQUEST)(=|\[|%) [NC]
916
+ RewriteRule .* - [F]
917
+ </IfModule>
918
+
919
+ # 5G:[USER AGENTS]
920
+ <IfModule mod_setenvif.c>
921
+ # SetEnvIfNoCase User-Agent ^$ keep_out
922
+ SetEnvIfNoCase User-Agent (binlar|casper|cmsworldmap|comodo|diavol|dotbot|feedfinder|flicky|ia_archiver|jakarta|kmccrew|nutch|planetwork|purebot|pycurl|skygrid|sucker|turnit|vikspider|zmeu) keep_out
923
+ <limit GET POST PUT>
924
+ Order Allow,Deny
925
+ Allow from all
926
+ Deny from env=keep_out
927
+ </limit>
928
+ </IfModule>
929
+
930
+ # 5G:[REQUEST STRINGS]
931
+ <IfModule mod_alias.c>
932
+ RedirectMatch 403 (https?|ftp|php)\://
933
+ RedirectMatch 403 /(https?|ima|ucp)/
934
+ RedirectMatch 403 /(Permanent|Better)$
935
+ RedirectMatch 403 (\=\\\\\\\'|\=\\\%27|/\\\\\\\'/?|\)\.css\()$
936
+ RedirectMatch 403 (\,|\)\+|/\,/|\{0\}|\(/\(|\.\.\.|\+\+\+|\||\\\\\"\\\\\")
937
+ RedirectMatch 403 \.(cgi|asp|aspx|cfg|dll|exe|jsp|mdb|sql|ini|rar)$
938
+ RedirectMatch 403 /(contac|fpw|install|pingserver|register)\.php$
939
+ RedirectMatch 403 (base64|crossdomain|localhost|wwwroot|e107\_)
940
+ RedirectMatch 403 (eval\(|\_vti\_|\(null\)|echo.*kae|config\.xml)
941
+ RedirectMatch 403 \.well\-known/host\-meta
942
+ RedirectMatch 403 /function\.array\-rand
943
+ RedirectMatch 403 \)\;\$\(this\)\.html\(
944
+ RedirectMatch 403 proc/self/environ
945
+ RedirectMatch 403 msnbot\.htm\)\.\_
946
+ RedirectMatch 403 /ref\.outcontrol
947
+ RedirectMatch 403 com\_cropimage
948
+ RedirectMatch 403 indonesia\.htm
949
+ RedirectMatch 403 \{\$itemURL\}
950
+ RedirectMatch 403 function\(\)
951
+ RedirectMatch 403 labels\.rdf
952
+ RedirectMatch 403 /playing.php
953
+ RedirectMatch 403 muieblackcat
954
+ </IfModule>
955
+
956
+ # 5G:[REQUEST METHOD]
957
+ <ifModule mod_rewrite.c>
958
+ RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
959
+ RewriteRule .* - [F]
960
+ </IfModule>' . PHP_EOL;
961
+ $rules .= AIOWPSecurity_Utility_Htaccess::$five_g_blacklist_marker_end . PHP_EOL; //Add feature marker end
962
+ }
963
+
964
+ return $rules;
965
+ }
966
+
967
+ /**
968
+ * This function contains the rules for the 6G blacklist produced by Jeff Starr:
969
  * https://perishablepress.com/6g/
970
+ */
971
+ public static function getrules_6g_blacklist() {
972
+ global $aio_wp_security;
973
+ $rules = '';
974
+ $ip_blacklist_23 = '';
975
+ $ip_blacklist_24 = '';
976
+ if ($aio_wp_security->configs->get_value('aiowps_enable_6g_firewall') == '1') {
977
+ //if ip blacklist is enabled we will merge that code with the 6G rules to prevent clashes
978
+ if ($aio_wp_security->configs->get_value('aiowps_enable_blacklisting') == '1') {
979
+ // Let's do the list of blacklisted IPs first
980
+ $hosts = AIOWPSecurity_Utility::explode_trim_filter_empty($aio_wp_security->configs->get_value('aiowps_banned_ip_addresses'));
981
+ // Filter out duplicate lines, add netmask to IP addresses
982
+ $ips_with_netmask = self::add_netmask(array_unique($hosts));
983
+
984
+ if (!empty($ips_with_netmask)) {
985
+ // Apache or LiteSpeed webserver
986
+ // Apache 2.2 and older
987
+ $ip_blacklist_23 .= '#AIOWPS_IP_BLACKLIST_2_3_START' . PHP_EOL;
988
+ $ip_blacklist_24 .= '#AIOWPS_IP_BLACKLIST_2_4_START' . PHP_EOL;
989
+ foreach ($ips_with_netmask as $ip_with_netmask) {
990
+ $ip_blacklist_23 .= "Deny from " . $ip_with_netmask . PHP_EOL;
991
+ $ip_blacklist_24 .= "Require not ip " . $ip_with_netmask . PHP_EOL;
992
+ }
993
+ $ip_blacklist_23 .= '#AIOWPS_IP_BLACKLIST_2_3_END' . PHP_EOL;
994
+ $ip_blacklist_24 .= '#AIOWPS_IP_BLACKLIST_2_4_END' . PHP_EOL;
995
+ }
996
+ }
997
+
998
+ $rules .= AIOWPSecurity_Utility_Htaccess::$six_g_blacklist_marker_start . PHP_EOL; //Add feature marker start
999
+
1000
+ $rules .= '# 6G FIREWALL/BLACKLIST
1001
+ # @ https://perishablepress.com/6g/
1002
+
1003
+ # 6G:[QUERY STRINGS]
1004
+ <IfModule mod_rewrite.c>
1005
+ RewriteEngine On
1006
+ RewriteCond %{QUERY_STRING} (eval\() [NC,OR]
1007
+ RewriteCond %{QUERY_STRING} (127\.0\.0\.1) [NC,OR]
1008
+ RewriteCond %{QUERY_STRING} ([a-z0-9]{2000,}) [NC,OR]
1009
+ RewriteCond %{QUERY_STRING} (javascript:)(.*)(;) [NC,OR]
1010
+ RewriteCond %{QUERY_STRING} (base64_encode)(.*)(\() [NC,OR]
1011
+ RewriteCond %{QUERY_STRING} (GLOBALS|REQUEST)(=|\[|%) [NC,OR]
1012
+ RewriteCond %{QUERY_STRING} (<|%3C)(.*)script(.*)(>|%3) [NC,OR]
1013
+ RewriteCond %{QUERY_STRING} (\\|\.\.\.|\.\./|~|`|<|>|\|) [NC,OR]
1014
+ RewriteCond %{QUERY_STRING} (boot\.ini|etc/passwd|self/environ) [NC,OR]
1015
+ RewriteCond %{QUERY_STRING} (thumbs?(_editor|open)?|tim(thumb)?)\.php [NC,OR]
1016
+ RewriteCond %{QUERY_STRING} (\'|\")(.*)(drop|insert|md5|select|union) [NC]
1017
+ RewriteRule .* - [F]
1018
+ </IfModule>
1019
+
1020
+ # 6G:[REQUEST METHOD]
1021
+ <IfModule mod_rewrite.c>
1022
+ RewriteCond %{REQUEST_METHOD} ^(connect|debug|move|put|trace|track) [NC]
1023
+ RewriteRule .* - [F]
1024
+ </IfModule>
1025
+
1026
+ # 6G:[REFERRERS]
1027
+ <IfModule mod_rewrite.c>
1028
+ RewriteCond %{HTTP_REFERER} ([a-z0-9]{2000,}) [NC,OR]
1029
+ RewriteCond %{HTTP_REFERER} (semalt.com|todaperfeita) [NC]
1030
+ RewriteRule .* - [F]
1031
+ </IfModule>
1032
+
1033
+ # 6G:[REQUEST STRINGS]
1034
+ <IfModule mod_alias.c>
1035
+ RedirectMatch 403 (?i)([a-z0-9]{2000,})
1036
+ RedirectMatch 403 (?i)(https?|ftp|php):/
1037
+ RedirectMatch 403 (?i)(base64_encode)(.*)(\()
1038
+ RedirectMatch 403 (?i)(=\\\'|=\\%27|/\\\'/?)\.
1039
+ RedirectMatch 403 (?i)/(\$(\&)?|\*|\"|\.|,|&|&amp;?)/?$
1040
+ RedirectMatch 403 (?i)(\{0\}|\(/\(|\.\.\.|\+\+\+|\\\"\\\")
1041
+ RedirectMatch 403 (?i)(~|`|<|>|:|;|,|%|\\|\s|\{|\}|\[|\]|\|)
1042
+ RedirectMatch 403 (?i)/(=|\$&|_mm|cgi-|etc/passwd|muieblack)
1043
+ RedirectMatch 403 (?i)(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ)
1044
+ RedirectMatch 403 (?i)\.(aspx?|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf)$
1045
+ RedirectMatch 403 (?i)/(^$|(wp-)?config|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell)\.php
1046
+ </IfModule>
1047
+
1048
+ # 6G:[USER AGENTS]
1049
+ <IfModule mod_setenvif.c>
1050
+ SetEnvIfNoCase User-Agent ([a-z0-9]{2000,}) bad_bot
1051
+ SetEnvIfNoCase User-Agent (archive.org|binlar|casper|checkpriv|choppy|clshttp|cmsworld|diavol|dotbot|extract|feedfinder|flicky|g00g1e|harvest|heritrix|httrack|kmccrew|loader|miner|nikto|nutch|planetwork|postrank|purebot|pycurl|python|seekerspider|siclab|skygrid|sqlmap|sucker|turnit|vikspider|winhttp|xxxyy|youda|zmeu|zune) bad_bot
1052
+
1053
+ # Apache < 2.3
1054
+ <IfModule !mod_authz_core.c>
1055
+ Order Allow,Deny
1056
+ Allow from all
1057
+ Deny from env=bad_bot';
1058
+ if (!empty($ip_blacklist_23))
1059
+ $rules .= PHP_EOL.$ip_blacklist_23; //add ip blacklist if applicable
1060
+ $rules .= '
1061
+ </IfModule>
1062
+
1063
+ # Apache >= 2.3
1064
+ <IfModule mod_authz_core.c>
1065
+ <RequireAll>
1066
+ Require all Granted
1067
+ Require not env bad_bot';
1068
+ if (!empty($ip_blacklist_24))
1069
+ $rules .= PHP_EOL.$ip_blacklist_24; //add ip blacklist if applicable
1070
+ $rules .= '
1071
+ </RequireAll>
1072
+ </IfModule>
1073
+ </IfModule>' . PHP_EOL;
1074
+ $rules .= AIOWPSecurity_Utility_Htaccess::$six_g_blacklist_marker_end . PHP_EOL; //Add feature marker end
1075
+ }
1076
+
1077
+ return $rules;
1078
+ }
1079
+
1080
+ /**
1081
+ * This function will write some directives to block all comments which do not originate from the blog's domain
1082
+ * OR if the user agent is empty. All blocked requests will be redirected to 127.0.0.1
1083
+ */
1084
+ public static function getrules_block_spambots() {
1085
+ global $aio_wp_security;
1086
+ $rules = '';
1087
+ if ($aio_wp_security->configs->get_value('aiowps_enable_spambot_blocking') == '1') {
1088
+ $url_string = AIOWPSecurity_Utility_Htaccess::return_regularized_url(AIOWPSEC_WP_HOME_URL);
1089
+ if (false == $url_string) {
1090
+ $url_string = AIOWPSEC_WP_HOME_URL;
1091
+ }
1092
+ $rules .= AIOWPSecurity_Utility_Htaccess::$block_spambots_marker_start . PHP_EOL; //Add feature marker start
1093
+ $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
1094
+ $rules .= 'RewriteEngine On' . PHP_EOL;
1095
+ $rules .= 'RewriteCond %{REQUEST_METHOD} POST' . PHP_EOL;
1096
+ $rules .= 'RewriteCond %{REQUEST_URI} ^(.*)?wp-comments-post\.php(.*)$' . PHP_EOL;
1097
+ $rules .= 'RewriteCond %{HTTP_REFERER} !^' . $url_string . ' [NC,OR]' . PHP_EOL;
1098
+ $rules .= 'RewriteCond %{HTTP_USER_AGENT} ^$' . PHP_EOL;
1099
+ $rules .= 'RewriteRule .* http://127.0.0.1 [L]' . PHP_EOL;
1100
+ $rules .= '</IfModule>' . PHP_EOL;
1101
+ $rules .= AIOWPSecurity_Utility_Htaccess::$block_spambots_marker_end . PHP_EOL; //Add feature marker end
1102
+ }
1103
+
1104
+ return $rules;
1105
+ }
1106
+
1107
+ /**
1108
+ * This function will write some directives to prevent image hotlinking
1109
+ */
1110
+ public static function prevent_image_hotlinks() {
1111
+ global $aio_wp_security;
1112
+ $rules = '';
1113
+ if ($aio_wp_security->configs->get_value('aiowps_prevent_hotlinking') == '1') {
1114
+ $url_string = AIOWPSecurity_Utility_Htaccess::return_regularized_url(AIOWPSEC_WP_HOME_URL);
1115
+ if (false == $url_string) {
1116
+ $url_string = AIOWPSEC_WP_HOME_URL;
1117
+ }
1118
+ $rules .= AIOWPSecurity_Utility_Htaccess::$prevent_image_hotlinks_marker_start . PHP_EOL; //Add feature marker start
1119
+ $rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
1120
+ $rules .= 'RewriteEngine On' . PHP_EOL;
1121
+ $rules .= 'RewriteCond %{HTTP_REFERER} !^$' . PHP_EOL;
1122
+ $rules .= 'RewriteCond %{REQUEST_FILENAME} -f' . PHP_EOL;
1123
+ $rules .= 'RewriteCond %{REQUEST_FILENAME} \.(gif|jpe?g?|png)$ [NC]' . PHP_EOL;
1124
+ $rules .= 'RewriteCond %{HTTP_REFERER} !^' . $url_string . ' [NC]' . PHP_EOL;
1125
+ $rules .= 'RewriteRule \.(gif|jpe?g?|png)$ - [F,NC,L]' . PHP_EOL;
1126
+ $rules .= '</IfModule>' . PHP_EOL;
1127
+ $rules .= AIOWPSecurity_Utility_Htaccess::$prevent_image_hotlinks_marker_end . PHP_EOL; //Add feature marker end
1128
+ }
1129
+
1130
+ return $rules;
1131
+ }
1132
+
1133
+ /**
1134
+ * This function will write any custom htaccess rules into the server's .htaccess file
1135
+ *
1136
+ * @return string
1137
+ */
1138
+ public static function getrules_custom_rules() {
1139
+ global $aio_wp_security;
1140
+ $rules = '';
1141
+ if ($aio_wp_security->configs->get_value('aiowps_enable_custom_rules') == '1') {
1142
+ $custom_rules = $aio_wp_security->configs->get_value('aiowps_custom_rules');
1143
+ $rules .= AIOWPSecurity_Utility_Htaccess::$custom_rules_marker_start . PHP_EOL; //Add feature marker start
1144
+ $rules .= $custom_rules . PHP_EOL;
1145
+ $rules .= AIOWPSecurity_Utility_Htaccess::$custom_rules_marker_end . PHP_EOL; //Add feature marker end
1146
+ }
1147
+
1148
+ return $rules;
1149
+ }
1150
+
1151
+ /**
1152
+ * This function will do a quick check to see if a file's contents are actually .htaccess specific.
1153
+ * At the moment it will look for the following tag somewhere in the file - "# BEGIN WordPress"
1154
+ * If it finds the tag it will deem the file as being .htaccess specific.
1155
+ * This was written to supplement the .htaccess restore functionality
1156
+ *
1157
+ * @param string $file
1158
+ * @return boolean
1159
+ */
1160
+ public static function check_if_htaccess_contents($file) {
1161
+ $is_htaccess = false;
1162
+ $file_contents = file_get_contents($file);
1163
+ if (false === $file_contents || strlen($file_contents) == 0) {
1164
+ return -1;
1165
+ }
1166
+
1167
+ if ((strpos($file_contents, '# BEGIN WordPress') !== false) || (strpos($file_contents, '# BEGIN') !== false)) {
1168
+ $is_htaccess = true; //It appears that we have some sort of .htacces file
1169
+ } else {
1170
+ //see if we're at the end of the section
1171
+ $is_htaccess = false;
1172
+ }
1173
+
1174
+ if ($is_htaccess) {
1175
+ return 1;
1176
+ } else {
1177
+ return -1;
1178
+ }
1179
+ }
1180
+
1181
+ /**
1182
+ * This function will take a URL string and convert it to a form useful for using in htaccess rules.
1183
+ * Example: If URL passed to function = "http://www.mysite.com"
1184
+ * Result = "http(s)?://(.*)?mysite\.com"
1185
+ *
1186
+ * @param string $url
1187
+ * @return string
1188
+ */
1189
+ public static function return_regularized_url($url) {
1190
+ if (filter_var($url, FILTER_VALIDATE_URL)) {
1191
+ $xyz = explode('.', $url);
1192
+ $y = '';
1193
+ if (count($xyz) > 1) {
1194
+ $j = 1;
1195
+ foreach ($xyz as $x) {
1196
+ if (strpos($x, 'www') !== false) {
1197
+ $y .= str_replace('www', '(.*)?', $x);
1198
+ } elseif (1 == $j) {
1199
+ $y .= $x;
1200
+ } elseif ($j > 1) {
1201
+ $y .= '\.' . $x;
1202
+ }
1203
+ $j++;
1204
+ }
1205
+ //Now replace the "http" with "http(s)?" to cover both secure and non-secure
1206
+ if (strpos($y, 'https') !== false) {
1207
+ $y = str_replace('https', 'http(s)?', $y);
1208
+ } elseif (strpos($y, 'http') !== false) {
1209
+ $y = str_replace('http', 'http(s)?', $y);
1210
+ }
1211
+ return $y;
1212
+ } else {
1213
+ return $url;
1214
+ }
1215
+ } else {
1216
+ return false;
1217
+ }
1218
+ }
1219
+
1220
+ /**
1221
+ * Returns a string with <Files $filename> directive that contains rules
1222
+ * to effectively block access to any file that has basename matching
1223
+ * $filename under Apache webserver.
1224
+ *
1225
+ * @link http://httpd.apache.org/docs/current/mod/core.html#files
1226
+ *
1227
+ * @param string $filename
1228
+ * @return string
1229
+ */
1230
+ protected static function create_apache2_access_denied_rule($filename) {
1231
+ return <<<END
 
1232
  <Files $filename>
1233
  <IfModule mod_authz_core.c>
1234
+ Require all denied
1235
  </IfModule>
1236
  <IfModule !mod_authz_core.c>
1237
+ Order deny,allow
1238
+ Deny from all
1239
  </IfModule>
1240
  </Files>
1241
 
1242
  END;
1243
+ // Keep the empty line at the end of heredoc string,
1244
+ // otherwise the string will not end with end-of-line character!
1245
+ }
1246
+
1247
+
1248
+ /**
1249
+ * Convert an array of optionally asterisk-masked or partial IPv4 addresses
1250
+ * into network/netmask notation. Netmask value for a "full" IP is not
1251
+ * added (see example below)
1252
+ *
1253
+ * Example:
1254
+ * In: array('1.2.3.4', '5.6', '7.8.9.*')
1255
+ * Out: array('1.2.3.4', '5.6.0.0/16', '7.8.9.0/24')
1256
+ *
1257
+ * Simple validation is performed:
1258
+ * In: array('1.2.3.4.5', 'abc', '1.2.xyz.4')
1259
+ * Out: array()
1260
+ *
1261
+ * Simple sanitization is performed:
1262
+ * In: array('6.7.*.9')
1263
+ * Out: array('6.7.0.0/16')
1264
+ *
1265
+ * @param array $ips
1266
+ * @return array
1267
+ */
1268
+ protected static function add_netmask($ips = array()) {
1269
+
1270
+ $output = array();
1271
+ if (empty($ips)) return array();
1272
+ foreach ($ips as $ip) {
1273
+ //Check if ipv6
1274
+ if (strpos($ip, ':') !== false) {
1275
+ //for now we'll only support whole ipv6 (not address ranges)
1276
+ $ipv6 = WP_Http::is_ip_address($ip);
1277
+ if (false === $ipv6) {
1278
+ continue;
1279
+ }
1280
+ $output[] = $ip;
1281
+ }
1282
+
1283
+
1284
+ $parts = explode('.', $ip);
1285
+
1286
+ // Skip any IP that is empty, has more parts than expected or has
1287
+ // a non-numeric first part.
1288
+ if (empty($parts) || (count($parts) > 4) || !is_numeric($parts[0])) {
1289
+ continue;
1290
+ }
1291
+
1292
+ $ip_out = array($parts[0]);
1293
+ $netmask = 8;
1294
+
1295
+ for ($i = 1, $force_zero = false; ($i < 4) && $ip_out; $i++) {
1296
+ if ($force_zero || !isset($parts[$i]) || ('' === $parts[$i]) || ('*' === $parts[$i])) {
1297
+ $ip_out[$i] = '0';
1298
+ $force_zero = true; // Forces all subsequent parts to be a zero
1299
+ } elseif (is_numeric($parts[$i])) {
1300
+ $ip_out[$i] = $parts[$i];
1301
+ $netmask += 8;
1302
+ } else {
1303
+ // Invalid IP part detected, invalidate entire IP
1304
+ $ip_out = false;
1305
+ }
1306
+ }
1307
+
1308
+ if ($ip_out) {
1309
+ // Glue IP back together, add netmask if IP denotes a subnet, store for output.
1310
+ $output[] = implode('.', $ip_out) . (($netmask < 32) ? ('/' . $netmask) : '');
1311
+ }
1312
+ }
1313
+
1314
+ return $output;
1315
+ }
1316
+ }
 
 
classes/wp-security-utility-ip-address.php CHANGED
@@ -1,249 +1,197 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Utility_IP
7
- {
8
- function __construct(){
9
- //NOP
10
- }
11
-
12
- static function get_user_ip_address()
13
- {
14
- global $aio_wp_security;
 
 
 
 
 
 
15
 
16
- //check if user configured custom IP retrieval method
17
- $ip_method = $aio_wp_security->configs->get_value('aiowps_ip_retrieve_method');
18
- $visitor_ip = ''; //set default
19
- if(!empty($ip_method)){
20
- //means user has configured non default IP retrieval
21
- if($ip_method == 1 && !empty($_SERVER['HTTP_CF_CONNECTING_IP'])){
22
- $visitor_ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
23
- }else if($ip_method == 2 && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
24
- $visitor_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
25
- }else if($ip_method == 3 && !empty($_SERVER['HTTP_X_FORWARDED'])){
26
- $visitor_ip = $_SERVER['HTTP_X_FORWARDED'];
27
- }else if($ip_method == 4 && !empty($_SERVER['HTTP_CLIENT_IP'])){
28
- $visitor_ip = $_SERVER['HTTP_CLIENT_IP'];
29
- }
30
- }
31
-
32
- //Check if multiple IPs were given - these will be present as comma-separated list
33
-
34
- if(stristr($visitor_ip, ',')){
35
- $temp = explode(',', $visitor_ip);
36
- $visitor_ip = trim(reset($temp)); //get first address because this will likely be the original connecting IP
37
- }
38
-
39
- //Now remove port portion if applicable
40
- if(strpos($visitor_ip, '.') !== FALSE && strpos($visitor_ip, ':') !== FALSE){
41
- //likely ipv4 address with port
42
- $visitor_ip = preg_replace('/:\d+$/', '', $visitor_ip); //Strip off port
43
- }
44
 
45
- if(filter_var($visitor_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
46
- return $visitor_ip;
47
- }else if(filter_var($visitor_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)){
48
- return $visitor_ip;
49
- }else{
50
- $visitor_ip = !empty($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:'';
51
- return $visitor_ip;
52
- }
53
- }
54
-
55
- /*
56
- * Returns the first three octets of a sanitized IP address so it can used as an IP address range
57
- */
58
- static function get_sanitized_ip_range($ip)
59
- {
60
- global $aio_wp_security;
61
- $ip_range = '';
62
- $valid_ip = filter_var($ip, FILTER_VALIDATE_IP); //Sanitize the IP address
63
- if ($valid_ip)
64
- {
65
- $ip_type = WP_Http::is_ip_address($ip); //returns 4 or 6 if ipv4 or ipv6 or false if invalid
66
- if($ip_type == 6 || $ip_type === false) return ''; // for now return empty if ipv6 or invalid IP
67
- $ip_range = substr($valid_ip, 0 , strrpos ($valid_ip, ".")); //strip last portion of address to leave an IP range
68
- }
69
- else
70
- {
71
- //Write log if the 'REMOTE_ADDR' contains something which is not an IP
72
- $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility_IP - Invalid IP received ".$ip,4);
73
- }
74
- return $ip_range;
75
- }
76
 
77
-
78
- static function create_ip_list_array_from_string_with_newline($ip_addresses)
79
- {
80
- $ip_list_array = preg_split("/\R/", $ip_addresses);
81
- return $ip_list_array;
82
- }
83
-
84
- static function validate_ip_list($ip_list_array, $list_type='')
85
- {
86
- @ini_set('auto_detect_line_endings', true);
87
- $errors = '';
88
 
89
- //validate list
90
- $submitted_ips = $ip_list_array;
91
- $list = array();
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
- if(!empty($submitted_ips))
94
- {
95
- foreach($submitted_ips as $item)
96
- {
97
- $item = filter_var($item, FILTER_SANITIZE_STRING);
98
- if (strlen( $item ) > 0)
99
- {
100
- //ipv6 - for now we will support only whole ipv6 addresses, NOT ranges
101
- if(strpos($item, ':') !== false){
102
- //possible ipv6 addr
103
- $res = WP_Http::is_ip_address($item);
104
- if(FALSE === $res){
105
- $errors .= "\n".$item.__(' is not a valid ip address format.', 'all-in-one-wp-security-and-firewall');
106
- }else if($res == '6'){
107
- $list[] = trim($item);
108
- }
109
- continue;
110
- }
111
 
112
- $ipParts = explode('.', $item);
113
- $isIP = 0;
114
- $partcount = 1;
115
- $goodip = true;
116
- $foundwild = false;
117
-
118
- if (count($ipParts) < 2)
119
- {
120
- $errors .= "\n".$item.__(' is not a valid ip address format.', 'all-in-one-wp-security-and-firewall');
121
- continue;
122
- }
123
 
124
- foreach ($ipParts as $part)
125
- {
126
- if ($goodip == true)
127
- {
128
- if ((is_numeric(trim($part)) && trim($part) <= 255 && trim($part) >= 0) || trim($part) == '*')
129
- {
130
- $isIP++;
131
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
- switch ($partcount)
134
- {
135
- case 1:
136
- if (trim($part) == '*')
137
- {
138
- $goodip = false;
139
- $errors .= "\n".$item.__(' is not a valid ip address format.', 'all-in-one-wp-security-and-firewall');
140
- }
141
- break;
142
- case 2:
143
- if (trim($part) == '*')
144
- {
145
- $foundwild = true;
146
- }
147
- break;
148
- default:
149
- if (trim($part) != '*')
150
- {
151
- if ($foundwild == true)
152
- {
153
- $goodip = false;
154
- $errors .= "\n".$item.__(' is not a valid ip address format.', 'all-in-one-wp-security-and-firewall');
155
- }
156
- }
157
- else
158
- {
159
- $foundwild = true;
160
- }
161
- break;
162
- }
163
 
164
- $partcount++;
165
- }
166
- }
167
- if (ip2long(trim(str_replace('*', '0', $item))) == false)
168
- { //invalid ip
169
- $errors .= "\n".$item.__(' is not a valid ip address format.', 'all-in-one-wp-security-and-firewall');
170
- }
171
- elseif (strlen($item) > 4 && !in_array($item, $list))
172
- {
173
- $current_user_ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
174
- if ($current_user_ip == $item && $list_type == 'blacklist')
175
- {
176
- //You can't ban your own IP
177
- $errors .= "\n".__('You cannot ban your own IP address: ', 'all-in-one-wp-security-and-firewall').$item;
178
- }
179
- else
180
- {
181
- $list[] = trim($item);
182
- }
183
- }
184
- }
185
- }
186
- }
187
- else{
188
- //This function was called with an empty IP address array list
189
- }
190
 
191
- if (strlen($errors)> 0)
192
- {
193
- $return_payload = array(-1, array($errors));
194
- return $return_payload;
195
- }
196
-
197
- if (sizeof($list) >= 1)
198
- {
199
- sort($list);
200
- $list = array_unique($list, SORT_STRING);
201
-
202
- $return_payload = array(1, $list);
203
- return $return_payload;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  }
205
 
206
- $return_payload = array(1, array());
207
- return $return_payload;
208
- }
209
-
210
-
211
- /**
212
- * Checks if IP address matches against the specified whitelist of IP addresses or IP ranges
213
- * @global type $aio_wp_security
214
- * @param type $ip_address
215
- * @param type $whitelisted_ips (newline separated string of IPs)
216
- * @return boolean
217
- */
218
- static function is_ip_whitelisted($ip_address, $whitelisted_ips){
219
- global $aio_wp_security;
220
- if(empty($ip_address) || empty($whitelisted_ips)) return false;
221
-
222
- $ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($whitelisted_ips);
223
-
224
- if(empty($ip_list_array)) return false;
225
-
226
- $visitor_ipParts = explode('.', $ip_address);
227
- foreach ($ip_list_array as $white_ip){
228
- $ipParts = explode('.', $white_ip);
229
- $found = array_search('*', $ipParts);
230
- if($found !== false){
231
- //Means we have a whitelisted IP range so do some checks
232
- if($found == 1){
233
- //means last 3 octets are wildcards - check if visitor IP falls inside this range
234
- if($visitor_ipParts[0] == $ipParts[0]){return true;}
235
- }elseif($found == 2){
236
- //means last 2 octets are wildcards - check if visitor IP falls inside this range
237
- if($visitor_ipParts[0] == $ipParts[0] && $visitor_ipParts[1] == $ipParts[1]){return true;}
238
- }elseif($found == 3){
239
- //means last octet is wildcard - check if visitor IP falls inside this range
240
- if($visitor_ipParts[0] == $ipParts[0] && $visitor_ipParts[1] == $ipParts[1] && $visitor_ipParts[2] == $ipParts[2]){return true;}
241
- }
242
- }elseif($white_ip == $ip_address){
243
- return true;
244
- }
245
- }
246
- return false;
247
- }
248
-
249
- }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Utility_IP {
7
+ public function __construct() {
8
+ //NOP
9
+ }
10
+
11
+ public static function get_user_ip_address() {
12
+ if (isset($_SERVER['HTTP_X_REAL_IP'])) {
13
+ return sanitize_text_field(wp_unslash($_SERVER['HTTP_X_REAL_IP']));
14
+ } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
15
+ // Proxy servers can send through this header like this: X-Forwarded-For: client1, proxy1, proxy2
16
+ // Make sure we always only send through the first IP in the list which should always be the client IP.
17
+ return (string) rest_is_ip_address(trim(current(preg_split('/,/', sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR']))))));
18
+ } elseif (isset($_SERVER['REMOTE_ADDR'])) {
19
+ return sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR']));
20
+ }
21
 
22
+ return '';
23
+ }
24
+
25
+ /**
26
+ * Returns the first three octets of a sanitized IP address so it can used as an IP address range
27
+ *
28
+ * @param int $ip
29
+ * @return int
30
+ */
31
+ public static function get_sanitized_ip_range($ip) {
32
+ global $aio_wp_security;
33
+ $ip_range = '';
34
+ $valid_ip = filter_var($ip, FILTER_VALIDATE_IP); //Sanitize the IP address
35
+ if ($valid_ip) {
36
+ $ip_type = WP_Http::is_ip_address($ip); //returns 4 or 6 if ipv4 or ipv6 or false if invalid
37
+ if (6 == $ip_type || false === $ip_type) return ''; // for now return empty if ipv6 or invalid IP
38
+ $ip_range = substr($valid_ip, 0, strrpos($valid_ip, ".")); //strip last portion of address to leave an IP range
39
+ } else {
40
+ //Write log if the 'REMOTE_ADDR' contains something which is not an IP
41
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility_IP - Invalid IP received ".$ip, 4);
42
+ }
43
+ return $ip_range;
44
+ }
 
 
 
 
 
45
 
46
+
47
+ public static function create_ip_list_array_from_string_with_newline($ip_addresses) {
48
+ $ip_list_array = preg_split("/\R/", $ip_addresses);
49
+ return $ip_list_array;
50
+ }
51
+
52
+ public static function validate_ip_list($ip_list_array, $list_type = '') {
53
+ $errors = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
+ //validate list
56
+ $submitted_ips = $ip_list_array;
57
+ $list = array();
 
 
 
 
 
 
 
 
58
 
59
+ if (!empty($submitted_ips)) {
60
+ foreach ($submitted_ips as $item) {
61
+ $item = sanitize_text_field($item);
62
+ if (strlen($item) > 0) {
63
+ //ipv6 - for now we will support only whole ipv6 addresses, NOT ranges
64
+ if (strpos($item, ':') !== false) {
65
+ //possible ipv6 addr
66
+ $res = WP_Http::is_ip_address($item);
67
+ if (false === $res) {
68
+ $errors .= "\n".$item.__(' is not a valid ip address format.', 'all-in-one-wp-security-and-firewall');
69
+ } elseif ('6' == $res) {
70
+ $list[] = trim($item);
71
+ }
72
+ continue;
73
+ }
74
 
75
+ $ipParts = explode('.', $item);
76
+ $isIP = 0;
77
+ $partcount = 1;
78
+ $goodip = true;
79
+ $foundwild = false;
80
+
81
+ if (count($ipParts) < 2) {
82
+ $errors .= "\n".$item.__(' is not a valid ip address format.', 'all-in-one-wp-security-and-firewall');
83
+ continue;
84
+ }
 
 
 
 
 
 
 
 
85
 
86
+ foreach ($ipParts as $part) {
87
+ if (true == $goodip) {
88
+ if ((is_numeric(trim($part)) && trim($part) <= 255 && trim($part) >= 0) || trim($part) == '*') {
89
+ $isIP++;
90
+ }
 
 
 
 
 
 
91
 
92
+ switch ($partcount) {
93
+ case 1:
94
+ if (trim($part) == '*') {
95
+ $goodip = false;
96
+ $errors .= "\n".$item.__(' is not a valid ip address format.', 'all-in-one-wp-security-and-firewall');
97
+ }
98
+ break;
99
+ case 2:
100
+ if (trim($part) == '*') {
101
+ $foundwild = true;
102
+ }
103
+ break;
104
+ default:
105
+ if (trim($part) != '*') {
106
+ if (true == $foundwild) {
107
+ $goodip = false;
108
+ $errors .= "\n".$item.__(' is not a valid ip address format.', 'all-in-one-wp-security-and-firewall');
109
+ }
110
+ } else {
111
+ $foundwild = true;
112
+ }
113
+ break;
114
+ }
115
 
116
+ $partcount++;
117
+ }
118
+ }
119
+ if (ip2long(trim(str_replace('*', '0', $item))) == false) { //invalid ip
120
+ $errors .= "\n".$item.__(' is not a valid ip address format.', 'all-in-one-wp-security-and-firewall');
121
+ } elseif (strlen($item) > 4 && !in_array($item, $list)) {
122
+ $current_user_ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
123
+ if ($item == $current_user_ip && 'blacklist' == $list_type) {
124
+ //You can't ban your own IP
125
+ $errors .= "\n".__('You cannot ban your own IP address: ', 'all-in-one-wp-security-and-firewall').$item;
126
+ } else {
127
+ $list[] = trim($item);
128
+ }
129
+ }
130
+ }
131
+ }
132
+ } else {
133
+ //This function was called with an empty IP address array list
134
+ }
 
 
 
 
 
 
 
 
 
 
 
135
 
136
+ if (strlen($errors)> 0) {
137
+ $return_payload = array(-1, array($errors));
138
+ return $return_payload;
139
+ }
140
+
141
+ if (sizeof($list) >= 1) {
142
+ sort($list);
143
+ $list = array_unique($list, SORT_STRING);
144
+
145
+ $return_payload = array(1, $list);
146
+ return $return_payload;
147
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
+ $return_payload = array(1, array());
150
+ return $return_payload;
151
+ }
152
+
153
+
154
+ /**
155
+ * Checks if IP address matches against the specified whitelist of IP addresses or IP ranges
156
+ *
157
+ * @param type $ip_address
158
+ * @param type $whitelisted_ips (newline separated string of IPs)
159
+ * @return boolean
160
+ */
161
+ public static function is_ip_whitelisted($ip_address, $whitelisted_ips) {
162
+ if (empty($ip_address) || empty($whitelisted_ips)) return false;
163
+
164
+ $ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($whitelisted_ips);
165
+
166
+ if (empty($ip_list_array)) return false;
167
+
168
+ $visitor_ipParts = explode('.', $ip_address);
169
+ foreach ($ip_list_array as $white_ip) {
170
+ $ipParts = explode('.', $white_ip);
171
+ $found = array_search('*', $ipParts);
172
+ if (false !== $found) {
173
+ //Means we have a whitelisted IP range so do some checks
174
+ if (1 == $found) {
175
+ //means last 3 octets are wildcards - check if visitor IP falls inside this range
176
+ if ($visitor_ipParts[0] == $ipParts[0]) {
177
+ return true;
178
+ }
179
+ } elseif (2 == $found) {
180
+ //means last 2 octets are wildcards - check if visitor IP falls inside this range
181
+ if ($visitor_ipParts[0] == $ipParts[0] && $visitor_ipParts[1] == $ipParts[1]) {
182
+ return true;
183
+ }
184
+ } elseif (3 == $found) {
185
+ //means last octet is wildcard - check if visitor IP falls inside this range
186
+ if ($visitor_ipParts[0] == $ipParts[0] && $visitor_ipParts[1] == $ipParts[1] && $visitor_ipParts[2] == $ipParts[2]) {
187
+ return true;
188
+ }
189
+ }
190
+ } elseif ($white_ip == $ip_address) {
191
+ return true;
192
+ }
193
+ }
194
+ return false;
195
  }
196
 
197
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/wp-security-utility.php CHANGED
@@ -1,631 +1,623 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
- class AIOWPSecurity_Utility
7
- {
8
- function __construct()
9
- {
10
- //NOP
11
- }
12
-
13
- /**
14
- * Explode $string with $delimiter, trim all lines and filter out empty ones.
15
- * @param string $string
16
- * @param string $delimiter
17
- * @return array
18
- */
19
- static function explode_trim_filter_empty($string, $delimiter = PHP_EOL) {
20
- return array_filter(array_map('trim', explode($delimiter, $string)), 'strlen');
21
- }
22
-
23
- /**
24
- * Returns the current URL
25
- *
26
- * @return string
27
- */
28
- static function get_current_page_url()
29
- {
30
- $pageURL = 'http';
31
- if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") {
32
- $pageURL .= "s";
33
- }
34
- $pageURL .= "://";
35
- if ($_SERVER["SERVER_PORT"] != "80") {
36
- $pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
37
- } else {
38
- $pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
39
- }
40
- return $pageURL;
41
- }
42
-
43
- /**
44
- * Redirects to specified URL
45
- *
46
- * @param type $url
47
- * @param type $delay
48
- * @param type $exit
49
- */
50
- static function redirect_to_url($url, $delay = '0', $exit = '1')
51
- {
52
- if (empty($url)) {
53
- echo "<br /><strong>Error! The URL value is empty. Please specify a correct URL value to redirect to!</strong>";
54
- exit;
55
- }
56
- if (!headers_sent()) {
57
- header('Location: ' . $url);
58
- } else {
59
- echo '<meta http-equiv="refresh" content="' . $delay . ';url=' . $url . '" />';
60
- }
61
- if ($exit == '1') {
62
- exit;
63
- }
64
- }
65
-
66
- /**
67
- * Returns logout URL with "after logout URL" query params
68
- *
69
- * @param type $after_logout_url
70
- * @return type
71
- */
72
- static function get_logout_url_with_after_logout_url_value($after_logout_url)
73
- {
74
- return AIOWPSEC_WP_URL . '?aiowpsec_do_log_out=1&after_logout=' . $after_logout_url;
75
- }
76
-
77
- /**
78
- * Checks if a particular username exists in the WP Users table
79
- * @global type $wpdb
80
- * @param type $username
81
- * @return boolean
82
- */
83
- static function check_user_exists($username)
84
- {
85
- global $wpdb;
86
-
87
- //if username is empty just return false
88
- if ($username == '') {
89
- return false;
90
- }
91
-
92
- //If multisite
93
- if (AIOWPSecurity_Utility::is_multisite_install()) {
94
- $blog_id = get_current_blog_id();
95
- $admin_users = get_users('blog_id=' . $blog_id . '&orderby=login&role=administrator');
96
- foreach ($admin_users as $user) {
97
- if ($user->user_login == $username) {
98
- return true;
99
- }
100
- }
101
- return false;
102
- }
103
-
104
- //check users table
105
- $sanitized_username = sanitize_text_field($username);
106
- $sql_1 = $wpdb->prepare("SELECT user_login FROM $wpdb->users WHERE user_login=%s", $sanitized_username);
107
- $user_login = $wpdb->get_var($sql_1);
108
- if ($user_login == $sanitized_username) {
109
- return true;
110
- } else {
111
- //make sure that the sanitized username is an integer before comparing it to the users table's ID column
112
- $sanitized_username_is_an_integer = (1 === preg_match('/^\d+$/', $sanitized_username));
113
- if ($sanitized_username_is_an_integer) {
114
- $sql_2 = $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE ID=%d", intval($sanitized_username));
115
- $userid = $wpdb->get_var($sql_2);
116
- return ($userid == $sanitized_username);
117
- } else {
118
- return false;
119
- }
120
- }
121
- }
122
-
123
- /**
124
- * This function will return a list of user accounts which have login and nick names which are identical
125
- * @global type $wpdb
126
- * @return type
127
- */
128
- static function check_identical_login_and_nick_names()
129
- {
130
- global $wpdb;
131
- $accounts_found = $wpdb->get_results("SELECT ID,user_login FROM `" . $wpdb->users . "` WHERE user_login<=>display_name;", ARRAY_A);
132
- return $accounts_found;
133
- }
134
-
135
-
136
- static function add_query_data_to_url($url, $name, $value)
137
- {
138
- if (strpos($url, '?') === false) {
139
- $url .= '?';
140
- } else {
141
- $url .= '&';
142
- }
143
- $url .= $name . '=' . urlencode($value);
144
- return $url;
145
- }
146
-
147
-
148
- /**
149
- * Generates a random alpha-numeric number
150
- * @param type $string_length
151
- * @return string
152
- */
153
- static function generate_alpha_numeric_random_string($string_length)
154
- {
155
- //Charecters present in table prefix
156
- $allowed_chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
157
- $string = '';
158
- //Generate random string
159
- for ($i = 0; $i < $string_length; $i++) {
160
- $string .= $allowed_chars[rand(0, strlen($allowed_chars) - 1)];
161
- }
162
- return $string;
163
- }
164
-
165
-
166
- /**
167
- * Generates a random string using a-z characters
168
- * @param type $string_length
169
- * @return string
170
- */
171
- static function generate_alpha_random_string($string_length)
172
- {
173
- //Charecters present in table prefix
174
- $allowed_chars = 'abcdefghijklmnopqrstuvwxyz';
175
- $string = '';
176
- //Generate random string
177
- for ($i = 0; $i < $string_length; $i++) {
178
- $string .= $allowed_chars[rand(0, strlen($allowed_chars) - 1)];
179
- }
180
- return $string;
181
- }
182
-
183
- /**
184
- * Sets cookie
185
- * @param type $cookie_name
186
- * @param type $cookie_value
187
- * @param type $expiry_seconds
188
- * @param type $path
189
- * @param string $cookie_domain
190
- */
191
- static function set_cookie_value($cookie_name, $cookie_value, $expiry_seconds = 86400, $path = '/', $cookie_domain = '')
192
- {
193
- $expiry_time = time() + intval($expiry_seconds);
194
- if (empty($cookie_domain)) {
195
- $cookie_domain = COOKIE_DOMAIN;
196
- }
197
- setcookie($cookie_name, $cookie_value, $expiry_time, $path, $cookie_domain);
198
- }
199
-
200
- /**
201
- * Gets cookie
202
- * @param type $cookie_name
203
- * @return string
204
- */
205
- static function get_cookie_value($cookie_name)
206
- {
207
- if (isset($_COOKIE[$cookie_name])) {
208
- return $_COOKIE[$cookie_name];
209
- }
210
- return "";
211
- }
212
-
213
- /**
214
- * Checks if installation is multisite
215
- * @return type
216
- */
217
- static function is_multisite_install()
218
- {
219
- return function_exists('is_multisite') && is_multisite();
220
- }
221
-
222
- /**
223
- * This is a general yellow box message for when we want to suppress a feature's config items because site is subsite of multi-site
224
- */
225
- static function display_multisite_message()
226
- {
227
- echo '<div class="aio_yellow_box">';
228
- echo '<p>' . __('The plugin has detected that you are using a Multi-Site WordPress installation.', 'all-in-one-wp-security-and-firewall') . '</p>
229
- <p>' . __('This feature can only be configured by the "superadmin" on the main site.', 'all-in-one-wp-security-and-firewall') . '</p>';
230
- echo '</div>';
231
- }
232
-
233
- /**
234
- * Modifies the wp-config.php file to disable PHP file editing from the admin panel
235
- * This function will add the following code:
236
- * define('DISALLOW_FILE_EDIT', false);
237
- *
238
- * NOTE: This function will firstly check if the above code already exists
239
- * and it will modify the bool value, otherwise it will insert the code mentioned above
240
- *
241
- * @global type $aio_wp_security
242
- * @return boolean
243
- */
244
- static function disable_file_edits()
245
- {
246
- global $aio_wp_security;
247
- $edit_file_config_entry_exists = false;
248
-
249
- //Config file path
250
- $config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
251
-
252
- //Get wp-config.php file contents so we can check if the "DISALLOW_FILE_EDIT" variable already exists
253
- $config_contents = file($config_file);
254
-
255
- foreach ($config_contents as $line_num => $line) {
256
- if (strpos($line, "'DISALLOW_FILE_EDIT', false")) {
257
- $config_contents[$line_num] = str_replace('false', 'true', $line);
258
- $edit_file_config_entry_exists = true;
259
- //$this->show_msg_updated(__('Settings Saved - The ability to edit PHP files via the admin the panel has been DISABLED.', 'all-in-one-wp-security-and-firewall'));
260
- } else if (strpos($line, "'DISALLOW_FILE_EDIT', true")) {
261
- $edit_file_config_entry_exists = true;
262
- //$this->show_msg_updated(__('Your system config file is already configured to disallow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
263
- return true;
264
-
265
- }
266
-
267
- //For wp-config.php files originating from early WP versions we will remove the closing php tag
268
- if (strpos($line, "?>") !== false) {
269
- $config_contents[$line_num] = str_replace("?>", "", $line);
270
- }
271
- }
272
-
273
- if (!$edit_file_config_entry_exists) {
274
- //Construct the config code which we will insert into wp-config.php
275
- $new_snippet = '//Disable File Edits' . PHP_EOL;
276
- $new_snippet .= 'define(\'DISALLOW_FILE_EDIT\', true);';
277
- $config_contents[] = $new_snippet; //Append the new snippet to the end of the array
278
- }
279
-
280
- //Make a backup of the config file
281
- if (!AIOWPSecurity_Utility_File::backup_and_rename_wp_config($config_file)) {
282
- AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Failed to make a backup of the wp-config.php file. This operation will not go ahead.', 'all-in-one-wp-security-and-firewall'));
283
- //$aio_wp_security->debug_logger->log_debug("Disable PHP File Edit - Failed to make a backup of the wp-config.php file.",4);
284
- return false;
285
- } else {
286
- //$this->show_msg_updated(__('A backup copy of your wp-config.php file was created successfully....', 'all-in-one-wp-security-and-firewall'));
287
- }
288
-
289
- //Now let's modify the wp-config.php file
290
- if (AIOWPSecurity_Utility_File::write_content_to_file($config_file, $config_contents)) {
291
- //$this->show_msg_updated(__('Settings Saved - Your system is now configured to not allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
292
- return true;
293
- } else {
294
- //$this->show_msg_error(__('Operation failed! Unable to modify wp-config.php file!', 'all-in-one-wp-security-and-firewall'));
295
- $aio_wp_security->debug_logger->log_debug("Disable PHP File Edit - Unable to modify wp-config.php", 4);
296
- return false;
297
- }
298
- }
299
-
300
- /**
301
- * Modifies the wp-config.php file to allow PHP file editing from the admin panel
302
- * This func will modify the following code by replacing "true" with "false":
303
- * define('DISALLOW_FILE_EDIT', true);
304
- *
305
- * @global type $aio_wp_security
306
- * @return boolean
307
- */
308
- static function enable_file_edits()
309
- {
310
- global $aio_wp_security;
311
- $edit_file_config_entry_exists = false;
312
-
313
- //Config file path
314
- $config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
315
-
316
- //Get wp-config.php file contents
317
- $config_contents = file($config_file);
318
- foreach ($config_contents as $line_num => $line) {
319
- if (strpos($line, "'DISALLOW_FILE_EDIT', true")) {
320
- $config_contents[$line_num] = str_replace('true', 'false', $line);
321
- $edit_file_config_entry_exists = true;
322
- } else if (strpos($line, "'DISALLOW_FILE_EDIT', false")) {
323
- $edit_file_config_entry_exists = true;
324
- //$this->show_msg_updated(__('Your system config file is already configured to allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
325
- return true;
326
- }
327
- }
328
-
329
- if (!$edit_file_config_entry_exists) {
330
- //if the DISALLOW_FILE_EDIT settings don't exist in wp-config.php then we don't need to do anything
331
- //$this->show_msg_updated(__('Your system config file is already configured to allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
332
- return true;
333
- } else {
334
- //Now let's modify the wp-config.php file
335
- if (AIOWPSecurity_Utility_File::write_content_to_file($config_file, $config_contents)) {
336
- //$this->show_msg_updated(__('Settings Saved - Your system is now configured to allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
337
- return true;
338
- } else {
339
- //$this->show_msg_error(__('Operation failed! Unable to modify wp-config.php file!', 'all-in-one-wp-security-and-firewall'));
340
- //$aio_wp_security->debug_logger->log_debug("Disable PHP File Edit - Unable to modify wp-config.php",4);
341
- return false;
342
- }
343
- }
344
- }
345
-
346
-
347
- /**
348
- * Inserts event logs to the database
349
- * For now we are using for 404 events but in future will expand for other events
350
- *
351
- * @param string $event_type : Event type, eg, 404 (see below for list of event types)
352
- * @param string $username (optional): username
353
- *
354
- * Event types: 404 (...add more as we expand this)
355
- * @param $event_type
356
- * @param string $username
357
- * @return bool
358
- */
359
- static function event_logger($event_type, $username = '')
360
- {
361
- global $wpdb, $aio_wp_security;
362
-
363
- //Some initialising
364
- $url = '';
365
- $referer_info = '';
366
-
367
- $events_table_name = AIOWPSEC_TBL_EVENTS;
368
-
369
- $ip_or_host = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
370
- $username = sanitize_user($username);
371
- $user = get_user_by('login', $username); //Returns WP_User object if exists
372
- if ($user) {
373
- //If valid user set variables for DB storage later on
374
- $user_id = (absint($user->ID) > 0) ? $user->ID : 0;
375
- } else {
376
- //If the login attempt was made using a non-existent user then let's set user_id to blank and record the attempted user login name for DB storage later on
377
- $user_id = 0;
378
- }
379
-
380
- if ($event_type == '404') {
381
- //if 404 event get some relevant data
382
- $url = isset($_SERVER['REQUEST_URI']) ? esc_attr($_SERVER['REQUEST_URI']) : '';
383
- $referer_info = isset($_SERVER['HTTP_REFERER']) ? esc_attr($_SERVER['HTTP_REFERER']) : '';
384
- }
385
-
386
- $current_time = current_time( 'mysql' );
387
- $data = array(
388
- 'event_type' => $event_type,
389
- 'username' => $username,
390
- 'user_id' => $user_id,
391
- 'event_date' => $current_time,
392
- 'ip_or_host' => $ip_or_host,
393
- 'referer_info' => $referer_info,
394
- 'url' => $url,
395
- 'event_data' => '',
396
- );
397
-
398
- $data = apply_filters( 'filter_event_logger_data', $data );
399
- //log to database
400
- $result = $wpdb->insert($events_table_name, $data);
401
- if ($result === FALSE) {
402
- $aio_wp_security->debug_logger->log_debug("event_logger: Error inserting record into " . $events_table_name, 4);//Log the highly unlikely event of DB error
403
- return false;
404
- }
405
- return true;
406
- }
407
-
408
- /**
409
- * Checks if IP address is locked
410
- *
411
- * @param string $ip : ip address
412
- * @returns TRUE if locked, FALSE otherwise
413
- *
414
- **/
415
- static function check_locked_ip($ip)
416
- {
417
- global $wpdb;
418
- $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
419
- $locked_ip = $wpdb->get_row("SELECT * FROM $login_lockdown_table " .
420
- "WHERE release_date > now() AND " .
421
- "failed_login_ip = '" . esc_sql($ip) . "'", ARRAY_A);
422
- if ($locked_ip != NULL) {
423
- return TRUE;
424
- } else {
425
- return FALSE;
426
- }
427
- }
428
-
429
- /**
430
- * Returns list of IP addresses locked out
431
- * @global type $wpdb
432
- * @return array of addresses found or FALSE otherwise
433
- */
434
- static function get_locked_ips()
435
- {
436
- global $wpdb;
437
- $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
438
- $now = current_time( 'mysql' );
439
  $locked_ips = $wpdb->get_results($wpdb->prepare("SELECT * FROM $login_lockdown_table WHERE release_date > %s", $now), ARRAY_A);
440
-
441
- if (empty($locked_ips)) {
442
- return FALSE;
443
- } else {
444
- return $locked_ips;
445
- }
446
- }
447
-
448
-
449
- /**
450
- * Locks an IP address - Adds an entry to the aiowps_lockdowns table
451
- * @global type $wpdb
452
- * @global type $aio_wp_security
453
- * @param type $ip
454
- * @param type $lock_reason
455
- * @param type $username
456
- */
457
- static function lock_IP($ip, $lock_reason = '', $username = '')
458
- {
459
- global $wpdb, $aio_wp_security;
460
- $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
461
- $lockout_time_length = $aio_wp_security->configs->get_value('aiowps_lockout_time_length'); //TODO add a setting for this feature
462
- $username = sanitize_user($username);
463
- $user = get_user_by('login', $username); //Returns WP_User object if exists
464
-
465
- if (FALSE == $user) {
466
- // Not logged in.
467
- $username = '';
468
- $user_id = 0;
469
- } else {
470
- // Logged in.
471
- $username = sanitize_user($user->user_login);
472
- $user_id = $user->ID;
473
- }
474
-
475
- $ip_str = esc_sql($ip);
476
- $insert = "INSERT INTO " . $login_lockdown_table . " (user_id, user_login, lockdown_date, release_date, failed_login_IP, lock_reason) " .
477
- "VALUES ('" . $user_id . "', '" . $username . "', now(), date_add(now(), INTERVAL " .
478
- $lockout_time_length . " MINUTE), '" . $ip_str . "', '" . $lock_reason . "')";
479
- $result = $wpdb->query($insert);
480
- if ($result > 0) {
481
- } else if ($result === FALSE) {
482
- $aio_wp_security->debug_logger->log_debug("lock_IP: Error inserting record into " . $login_lockdown_table, 4);//Log the highly unlikely event of DB error
483
- }
484
- }
485
-
486
- /**
487
- * Returns an array of blog_ids for a multisite install
488
- *
489
- * @global type $wpdb
490
- * @global type $wpdb
491
- * @return array or empty array if not multisite
492
- */
493
- static function get_blog_ids()
494
- {
495
- global $wpdb;
496
- if (AIOWPSecurity_Utility::is_multisite_install()) {
497
- global $wpdb;
498
- $blog_ids = $wpdb->get_col("SELECT blog_id FROM " . $wpdb->prefix . "blogs");
499
- } else {
500
- $blog_ids = array();
501
- }
502
- return $blog_ids;
503
- }
504
-
505
-
506
- /**
507
- * This function will delete the oldest rows from a table which are over the max amount of rows specified
508
- * @global type $wpdb
509
- * @global type $aio_wp_security
510
- * @param type $table_name
511
- * @param type $max_rows
512
- * @return bool
513
- */
514
- static function cleanup_table($table_name, $max_rows = '10000')
515
- {
516
- global $wpdb, $aio_wp_security;
517
-
518
- $num_rows = $wpdb->get_var("select count(*) from $table_name");
519
- $result = true;
520
- if ($num_rows > $max_rows) {
521
- //if the table has more than max entries delete oldest rows
522
-
523
- $del_sql = "DELETE FROM $table_name
524
- WHERE id <= (
525
- SELECT id
526
- FROM (
527
- SELECT id
528
- FROM $table_name
529
- ORDER BY id DESC
530
- LIMIT 1 OFFSET $max_rows
531
- ) foo_tmp
532
- )";
533
-
534
- $result = $wpdb->query($del_sql);
535
- if ($result === false) {
536
- $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility::cleanup_table failed for table name: " . $table_name, 4);
537
- }
538
- }
539
- return ($result === false) ? false : true;
540
- }
541
-
542
- /**
543
- * Delete expired captcha info transients
544
- *
545
- * Note: A unique instance these transients is created everytime the login page is loaded with captcha enabled
546
- * This function will help prune the options table of old expired entries.
547
- *
548
- * @global wpdb $wpdb
549
- */
550
- static function delete_expired_captcha_transients(){
551
- global $wpdb;
552
-
553
- $current_unix_time = current_time( 'timestamp', true );
554
- $tbl = $wpdb->prefix . 'options';
555
- $query = "SELECT * FROM ".$tbl." WHERE `option_name` LIKE '%\_transient\_timeout\_aiowps\_captcha\_string\_info%' AND `option_value` < ".$current_unix_time;
556
- $res = $wpdb->get_results( $query, ARRAY_A );
557
- if(!empty($res)){
558
- foreach($res as $item){
559
- $transient_name = str_replace('_transient_timeout_', '', $item['option_name']); //extract transient name
560
- AIOWPSecurity_Utility::is_multisite_install()?delete_site_transient($transient_name):delete_transient($transient_name);
561
- }
562
- }
563
- }
564
-
565
- /**
566
- * Gets server type.
567
- *
568
- * @return string or -1 if server is not supported
569
- */
570
- static function get_server_type()
571
- {
572
- //figure out what server they're using
573
- if (strstr(strtolower(filter_var($_SERVER['SERVER_SOFTWARE'], FILTER_SANITIZE_STRING)), 'apache')) {
574
- return 'apache';
575
- } else if (strstr(strtolower(filter_var($_SERVER['SERVER_SOFTWARE'], FILTER_SANITIZE_STRING)), 'nginx')) {
576
- return 'nginx';
577
- } else if (strstr(strtolower(filter_var($_SERVER['SERVER_SOFTWARE'], FILTER_SANITIZE_STRING)), 'litespeed')) {
578
- return 'litespeed';
579
- } else if (strstr(strtolower(filter_var($_SERVER['SERVER_SOFTWARE'], FILTER_SANITIZE_STRING)), 'iis')) {
580
- return 'iis';
581
- } else { //unsupported server
582
- return -1;
583
- }
584
-
585
- }
586
-
587
- /**
588
- * Checks if the string exists in the array key value of the provided array.
589
- * If it doesn't exist, it returns the first key element from the valid values.
590
- * @param type $to_check
591
- * @param type $valid_values
592
- * @return type
593
- */
594
- static function sanitize_value_by_array($to_check, $valid_values)
595
- {
596
- $keys = array_keys($valid_values);
597
- $keys = array_map('strtolower', $keys);
598
- if (in_array(strtolower($to_check), $keys)) {
599
- return $to_check;
600
- }
601
- return reset($keys); //Return the first element from the valid values
602
- }
603
-
604
- /**
605
- * Partially or fully masks a string using '*' to replace original characters
606
- *
607
- * @param type string $str
608
- * @param type int $chars_unmasked
609
- * @return type string
610
- */
611
- static function mask_string($str, $chars_unmasked = 0) {
612
- $str_length = strlen( $str );
613
- $chars_unmasked = absint( $chars_unmasked );
614
-
615
- if (0 == $chars_unmasked) {
616
- if ( 8 < $str_length ) {
617
- // mask all but last 4 characters
618
- return preg_replace("/(.{4}$)(*SKIP)(*F)|(.)/u", "*", $str);
619
- } else if ( 3 < $str_length ) {
620
- // mask all but last 2 characters
621
- return preg_replace("/(.{2}$)(*SKIP)(*F)|(.)/u", "*", $str);
622
- } else {
623
- // return whole string masked
624
- return str_pad( "", $str_length, "*", STR_PAD_LEFT );
625
- }
626
- }
627
- if( $chars_unmasked >= $str_length ) return $str;
628
- return preg_replace("/(.{".$chars_unmasked."}$)(*SKIP)(*F)|(.)/u","*", $str);
629
- }
 
 
 
 
 
 
 
 
 
630
 
631
  }
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
+ class AIOWPSecurity_Utility {
7
+ public function __construct() {
8
+ //NOP
9
+ }
10
+
11
+ /**
12
+ * Explode $string with $delimiter, trim all lines and filter out empty ones.
13
+ *
14
+ * @param string $string
15
+ * @param string $delimiter
16
+ * @return array
17
+ */
18
+ public static function explode_trim_filter_empty($string, $delimiter = PHP_EOL) {
19
+ return array_filter(array_map('trim', explode($delimiter, $string)), 'strlen');
20
+ }
21
+
22
+ /**
23
+ * Returns the current URL
24
+ *
25
+ * @return string
26
+ */
27
+ public static function get_current_page_url() {
28
+ $pageURL = 'http';
29
+ if (isset($_SERVER["HTTPS"]) && "on" == $_SERVER["HTTPS"]) {
30
+ $pageURL .= "s";
31
+ }
32
+ $pageURL .= "://";
33
+ if ("80" != $_SERVER["SERVER_PORT"]) {
34
+ $pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
35
+ } else {
36
+ $pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
37
+ }
38
+ return $pageURL;
39
+ }
40
+
41
+ /**
42
+ * Redirects to specified URL
43
+ *
44
+ * @param type $url
45
+ * @param type $delay
46
+ * @param type $exit
47
+ */
48
+ public static function redirect_to_url($url, $delay = '0', $exit = '1') {
49
+ if (empty($url)) {
50
+ echo "<br /><strong>Error! The URL value is empty. Please specify a correct URL value to redirect to!</strong>";
51
+ exit;
52
+ }
53
+ if (!headers_sent()) {
54
+ header('Location: ' . $url);
55
+ } else {
56
+ echo '<meta http-equiv="refresh" content="' . $delay . ';url=' . $url . '" />';
57
+ }
58
+ if ('1' == $exit) {
59
+ exit;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Returns logout URL with "after logout URL" query params
65
+ *
66
+ * @param type $after_logout_url
67
+ * @return type
68
+ */
69
+ public static function get_logout_url_with_after_logout_url_value($after_logout_url) {
70
+ return AIOWPSEC_WP_URL . '?aiowpsec_do_log_out=1&after_logout=' . $after_logout_url;
71
+ }
72
+
73
+ /**
74
+ * Checks if a particular username exists in the WP Users table
75
+ *
76
+ * @global type $wpdb
77
+ * @param type $username
78
+ * @return boolean
79
+ */
80
+ public static function check_user_exists($username) {
81
+ global $wpdb;
82
+
83
+ //if username is empty just return false
84
+ if ('' == $username) {
85
+ return false;
86
+ }
87
+
88
+ //If multisite
89
+ if (AIOWPSecurity_Utility::is_multisite_install()) {
90
+ $blog_id = get_current_blog_id();
91
+ $admin_users = get_users('blog_id=' . $blog_id . '&orderby=login&role=administrator');
92
+ foreach ($admin_users as $user) {
93
+ if ($user->user_login == $username) {
94
+ return true;
95
+ }
96
+ }
97
+ return false;
98
+ }
99
+
100
+ //check users table
101
+ $sanitized_username = sanitize_text_field($username);
102
+ $sql_1 = $wpdb->prepare("SELECT user_login FROM $wpdb->users WHERE user_login=%s", $sanitized_username);
103
+ $user_login = $wpdb->get_var($sql_1);
104
+ if ($user_login == $sanitized_username) {
105
+ return true;
106
+ } else {
107
+ //make sure that the sanitized username is an integer before comparing it to the users table's ID column
108
+ $sanitized_username_is_an_integer = (1 === preg_match('/^\d+$/', $sanitized_username));
109
+ if ($sanitized_username_is_an_integer) {
110
+ $sql_2 = $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE ID=%d", intval($sanitized_username));
111
+ $userid = $wpdb->get_var($sql_2);
112
+ return ($userid == $sanitized_username);
113
+ } else {
114
+ return false;
115
+ }
116
+ }
117
+ }
118
+
119
+ /**
120
+ * This function will return a list of user accounts which have login and nick names which are identical
121
+ *
122
+ * @global type $wpdb
123
+ * @return type
124
+ */
125
+ public static function check_identical_login_and_nick_names() {
126
+ global $wpdb;
127
+ $accounts_found = $wpdb->get_results("SELECT ID,user_login FROM `" . $wpdb->users . "` WHERE user_login<=>display_name;", ARRAY_A);
128
+ return $accounts_found;
129
+ }
130
+
131
+
132
+ public static function add_query_data_to_url($url, $name, $value) {
133
+ if (strpos($url, '?') === false) {
134
+ $url .= '?';
135
+ } else {
136
+ $url .= '&';
137
+ }
138
+ $url .= $name . '=' . urlencode($value);
139
+ return $url;
140
+ }
141
+
142
+
143
+ /**
144
+ * Generates a random alpha-numeric number
145
+ *
146
+ * @param type $string_length
147
+ * @return string
148
+ */
149
+ public static function generate_alpha_numeric_random_string($string_length) {
150
+ //Charecters present in table prefix
151
+ $allowed_chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
152
+ $string = '';
153
+ //Generate random string
154
+ for ($i = 0; $i < $string_length; $i++) {
155
+ $string .= $allowed_chars[rand(0, strlen($allowed_chars) - 1)];
156
+ }
157
+ return $string;
158
+ }
159
+
160
+
161
+ /**
162
+ * Generates a random string using a-z characters
163
+ *
164
+ * @param type $string_length
165
+ * @return string
166
+ */
167
+ public static function generate_alpha_random_string($string_length) {
168
+ //Charecters present in table prefix
169
+ $allowed_chars = 'abcdefghijklmnopqrstuvwxyz';
170
+ $string = '';
171
+ //Generate random string
172
+ for ($i = 0; $i < $string_length; $i++) {
173
+ $string .= $allowed_chars[rand(0, strlen($allowed_chars) - 1)];
174
+ }
175
+ return $string;
176
+ }
177
+
178
+ /**
179
+ * Sets cookie
180
+ *
181
+ * @param type $cookie_name
182
+ * @param type $cookie_value
183
+ * @param type $expiry_seconds
184
+ * @param type $path
185
+ * @param string $cookie_domain
186
+ */
187
+ public static function set_cookie_value($cookie_name, $cookie_value, $expiry_seconds = 86400, $path = '/', $cookie_domain = '') {
188
+ $expiry_time = time() + intval($expiry_seconds);
189
+ if (empty($cookie_domain)) {
190
+ $cookie_domain = COOKIE_DOMAIN;
191
+ }
192
+ setcookie($cookie_name, $cookie_value, $expiry_time, $path, $cookie_domain);
193
+ }
194
+
195
+ /**
196
+ * Gets cookie
197
+ *
198
+ * @param type $cookie_name
199
+ * @return string
200
+ */
201
+ public static function get_cookie_value($cookie_name) {
202
+ if (isset($_COOKIE[$cookie_name])) {
203
+ return $_COOKIE[$cookie_name];
204
+ }
205
+ return "";
206
+ }
207
+
208
+ /**
209
+ * Checks if installation is multisite
210
+ *
211
+ * @return type
212
+ */
213
+ public static function is_multisite_install() {
214
+ return function_exists('is_multisite') && is_multisite();
215
+ }
216
+
217
+ /**
218
+ * This is a general yellow box message for when we want to suppress a feature's config items because site is subsite of multi-site
219
+ */
220
+ public static function display_multisite_message() {
221
+ echo '<div class="aio_yellow_box">';
222
+ echo '<p>' . __('The plugin has detected that you are using a Multi-Site WordPress installation.', 'all-in-one-wp-security-and-firewall') . '</p>
223
+ <p>' . __('This feature can only be configured by the "superadmin" on the main site.', 'all-in-one-wp-security-and-firewall') . '</p>';
224
+ echo '</div>';
225
+ }
226
+
227
+ /**
228
+ * Modifies the wp-config.php file to disable PHP file editing from the admin panel
229
+ * This function will add the following code:
230
+ * define('DISALLOW_FILE_EDIT', false);
231
+ *
232
+ * NOTE: This function will firstly check if the above code already exists
233
+ * and it will modify the bool value, otherwise it will insert the code mentioned above
234
+ *
235
+ * @global type $aio_wp_security
236
+ * @return boolean
237
+ */
238
+ public static function disable_file_edits() {
239
+ global $aio_wp_security;
240
+ $edit_file_config_entry_exists = false;
241
+
242
+ //Config file path
243
+ $config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
244
+
245
+ //Get wp-config.php file contents so we can check if the "DISALLOW_FILE_EDIT" variable already exists
246
+ $config_contents = file($config_file);
247
+
248
+ foreach ($config_contents as $line_num => $line) {
249
+ if (strpos($line, "'DISALLOW_FILE_EDIT', false")) {
250
+ $config_contents[$line_num] = str_replace('false', 'true', $line);
251
+ $edit_file_config_entry_exists = true;
252
+ //$this->show_msg_updated(__('Settings Saved - The ability to edit PHP files via the admin the panel has been DISABLED.', 'all-in-one-wp-security-and-firewall'));
253
+ } elseif (strpos($line, "'DISALLOW_FILE_EDIT', true")) {
254
+ $edit_file_config_entry_exists = true;
255
+ //$this->show_msg_updated(__('Your system config file is already configured to disallow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
256
+ return true;
257
+
258
+ }
259
+
260
+ //For wp-config.php files originating from early WP versions we will remove the closing php tag
261
+ if (strpos($line, "?>") !== false) {
262
+ $config_contents[$line_num] = str_replace("?>", "", $line);
263
+ }
264
+ }
265
+
266
+ if (!$edit_file_config_entry_exists) {
267
+ //Construct the config code which we will insert into wp-config.php
268
+ $new_snippet = '//Disable File Edits' . PHP_EOL;
269
+ $new_snippet .= 'define(\'DISALLOW_FILE_EDIT\', true);';
270
+ $config_contents[] = $new_snippet; //Append the new snippet to the end of the array
271
+ }
272
+
273
+ //Make a backup of the config file
274
+ if (!AIOWPSecurity_Utility_File::backup_and_rename_wp_config($config_file)) {
275
+ AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Failed to make a backup of the wp-config.php file. This operation will not go ahead.', 'all-in-one-wp-security-and-firewall'));
276
+ //$aio_wp_security->debug_logger->log_debug("Disable PHP File Edit - Failed to make a backup of the wp-config.php file.",4);
277
+ return false;
278
+ } else {
279
+ //$this->show_msg_updated(__('A backup copy of your wp-config.php file was created successfully....', 'all-in-one-wp-security-and-firewall'));
280
+ }
281
+
282
+ //Now let's modify the wp-config.php file
283
+ if (AIOWPSecurity_Utility_File::write_content_to_file($config_file, $config_contents)) {
284
+ //$this->show_msg_updated(__('Settings Saved - Your system is now configured to not allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
285
+ return true;
286
+ } else {
287
+ //$this->show_msg_error(__('Operation failed! Unable to modify wp-config.php file!', 'all-in-one-wp-security-and-firewall'));
288
+ $aio_wp_security->debug_logger->log_debug("Disable PHP File Edit - Unable to modify wp-config.php", 4);
289
+ return false;
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Modifies the wp-config.php file to allow PHP file editing from the admin panel
295
+ * This func will modify the following code by replacing "true" with "false":
296
+ * define('DISALLOW_FILE_EDIT', true);
297
+ *
298
+ * @global type $aio_wp_security
299
+ * @return boolean
300
+ */
301
+ public static function enable_file_edits() {
302
+ $edit_file_config_entry_exists = false;
303
+
304
+ //Config file path
305
+ $config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
306
+
307
+ //Get wp-config.php file contents
308
+ $config_contents = file($config_file);
309
+ foreach ($config_contents as $line_num => $line) {
310
+ if (strpos($line, "'DISALLOW_FILE_EDIT', true")) {
311
+ $config_contents[$line_num] = str_replace('true', 'false', $line);
312
+ $edit_file_config_entry_exists = true;
313
+ } elseif (strpos($line, "'DISALLOW_FILE_EDIT', false")) {
314
+ $edit_file_config_entry_exists = true;
315
+ //$this->show_msg_updated(__('Your system config file is already configured to allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
316
+ return true;
317
+ }
318
+ }
319
+
320
+ if (!$edit_file_config_entry_exists) {
321
+ //if the DISALLOW_FILE_EDIT settings don't exist in wp-config.php then we don't need to do anything
322
+ //$this->show_msg_updated(__('Your system config file is already configured to allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
323
+ return true;
324
+ } else {
325
+ //Now let's modify the wp-config.php file
326
+ if (AIOWPSecurity_Utility_File::write_content_to_file($config_file, $config_contents)) {
327
+ //$this->show_msg_updated(__('Settings Saved - Your system is now configured to allow PHP file editing.', 'all-in-one-wp-security-and-firewall'));
328
+ return true;
329
+ } else {
330
+ //$this->show_msg_error(__('Operation failed! Unable to modify wp-config.php file!', 'all-in-one-wp-security-and-firewall'));
331
+ //$aio_wp_security->debug_logger->log_debug("Disable PHP File Edit - Unable to modify wp-config.php",4);
332
+ return false;
333
+ }
334
+ }
335
+ }
336
+
337
+
338
+ /**
339
+ * Inserts event logs to the database
340
+ * For now we are using for 404 events but in future will expand for other events
341
+ * Event types: 404 (...add more as we expand this)
342
+ *
343
+ * @param string $event_type :Event type, eg, 404 (see below for list of event types)
344
+ * @param string $username (optional): username
345
+ * @return bool
346
+ */
347
+ public static function event_logger($event_type, $username = '') {
348
+ global $wpdb, $aio_wp_security;
349
+
350
+ //Some initialising
351
+ $url = '';
352
+ $referer_info = '';
353
+
354
+ $events_table_name = AIOWPSEC_TBL_EVENTS;
355
+
356
+ $ip_or_host = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
357
+ $username = sanitize_user($username);
358
+ $user = get_user_by('login', $username); //Returns WP_User object if exists
359
+ if ($user) {
360
+ //If valid user set variables for DB storage later on
361
+ $user_id = (absint($user->ID) > 0) ? $user->ID : 0;
362
+ } else {
363
+ //If the login attempt was made using a non-existent user then let's set user_id to blank and record the attempted user login name for DB storage later on
364
+ $user_id = 0;
365
+ }
366
+
367
+ if ('404' == $event_type) {
368
+ //if 404 event get some relevant data
369
+ $url = isset($_SERVER['REQUEST_URI']) ? esc_attr($_SERVER['REQUEST_URI']) : '';
370
+ $referer_info = isset($_SERVER['HTTP_REFERER']) ? esc_attr($_SERVER['HTTP_REFERER']) : '';
371
+ }
372
+
373
+ $current_time = current_time('mysql');
374
+ $data = array(
375
+ 'event_type' => $event_type,
376
+ 'username' => $username,
377
+ 'user_id' => $user_id,
378
+ 'event_date' => $current_time,
379
+ 'ip_or_host' => $ip_or_host,
380
+ 'referer_info' => $referer_info,
381
+ 'url' => $url,
382
+ 'event_data' => '',
383
+ );
384
+
385
+ $data = apply_filters('filter_event_logger_data', $data);
386
+ //log to database
387
+ $result = $wpdb->insert($events_table_name, $data);
388
+ if (false === $result) {
389
+ $aio_wp_security->debug_logger->log_debug("event_logger: Error inserting record into " . $events_table_name, 4);//Log the highly unlikely event of DB error
390
+ return false;
391
+ }
392
+ return true;
393
+ }
394
+
395
+ /**
396
+ * Checks if IP address is locked
397
+ *
398
+ * @param string $ip : ip address
399
+ * @returns true if locked, false otherwise
400
+ **/
401
+ public static function check_locked_ip($ip) {
402
+ global $wpdb;
403
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
404
+ $locked_ip = $wpdb->get_row("SELECT * FROM $login_lockdown_table " . "WHERE release_date > now() AND " . "failed_login_ip = '" . esc_sql($ip) . "'", ARRAY_A);
405
+ if (null != $locked_ip) {
406
+ return true;
407
+ } else {
408
+ return false;
409
+ }
410
+ }
411
+
412
+ /**
413
+ * Returns list of IP addresses locked out
414
+ *
415
+ * @global type $wpdb
416
+ * @return array of addresses found or false otherwise
417
+ */
418
+ public static function get_locked_ips() {
419
+ global $wpdb;
420
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
421
+ $now = current_time('mysql');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
422
  $locked_ips = $wpdb->get_results($wpdb->prepare("SELECT * FROM $login_lockdown_table WHERE release_date > %s", $now), ARRAY_A);
423
+
424
+ if (empty($locked_ips)) {
425
+ return false;
426
+ } else {
427
+ return $locked_ips;
428
+ }
429
+ }
430
+
431
+
432
+ /**
433
+ * Locks an IP address - Adds an entry to the aiowps_lockdowns table
434
+ *
435
+ * @global type $wpdb
436
+ * @global type $aio_wp_security
437
+ * @param type $ip
438
+ * @param type $lock_reason
439
+ * @param type $username
440
+ */
441
+ public static function lock_IP($ip, $lock_reason = '', $username = '') {
442
+ global $wpdb, $aio_wp_security;
443
+ $login_lockdown_table = AIOWPSEC_TBL_LOGIN_LOCKDOWN;
444
+ $lockout_time_length = $aio_wp_security->configs->get_value('aiowps_lockout_time_length'); //TODO add a setting for this feature
445
+ $username = sanitize_user($username);
446
+ $user = get_user_by('login', $username); //Returns WP_User object if exists
447
+
448
+ if (false == $user) {
449
+ // Not logged in.
450
+ $username = '';
451
+ $user_id = 0;
452
+ } else {
453
+ // Logged in.
454
+ $username = sanitize_user($user->user_login);
455
+ $user_id = $user->ID;
456
+ }
457
+
458
+ $ip_str = esc_sql($ip);
459
+ $insert = "INSERT INTO " . $login_lockdown_table . " (user_id, user_login, lockdown_date, release_date, failed_login_IP, lock_reason) " .
460
+ "VALUES ('" . $user_id . "', '" . $username . "', now(), date_add(now(), INTERVAL " .
461
+ $lockout_time_length . " MINUTE), '" . $ip_str . "', '" . $lock_reason . "')";
462
+ $result = $wpdb->query($insert);
463
+ if ($result > 0) {
464
+ } elseif (false === $result) {
465
+ $aio_wp_security->debug_logger->log_debug("lock_IP: Error inserting record into " . $login_lockdown_table, 4);//Log the highly unlikely event of DB error
466
+ }
467
+ }
468
+
469
+ /**
470
+ * Returns an array of blog_ids for a multisite install
471
+ *
472
+ * @global type $wpdb
473
+ * @global type $wpdb
474
+ * @return array or empty array if not multisite
475
+ */
476
+ public static function get_blog_ids() {
477
+ global $wpdb;
478
+ if (AIOWPSecurity_Utility::is_multisite_install()) {
479
+ global $wpdb;
480
+ $blog_ids = $wpdb->get_col("SELECT blog_id FROM " . $wpdb->prefix . "blogs");
481
+ } else {
482
+ $blog_ids = array();
483
+ }
484
+ return $blog_ids;
485
+ }
486
+
487
+
488
+ /**
489
+ * This function will delete the oldest rows from a table which are over the max amount of rows specified
490
+ *
491
+ * @global type $wpdb
492
+ * @global type $aio_wp_security
493
+ * @param type $table_name
494
+ * @param type $max_rows
495
+ * @return bool
496
+ */
497
+ public static function cleanup_table($table_name, $max_rows = '10000') {
498
+ global $wpdb, $aio_wp_security;
499
+
500
+ $num_rows = $wpdb->get_var("select count(*) from $table_name");
501
+ $result = true;
502
+ if ($num_rows > $max_rows) {
503
+ //if the table has more than max entries delete oldest rows
504
+
505
+ $del_sql = "DELETE FROM $table_name
506
+ WHERE id <= (
507
+ SELECT id
508
+ FROM (
509
+ SELECT id
510
+ FROM $table_name
511
+ ORDER BY id DESC
512
+ LIMIT 1 OFFSET $max_rows
513
+ ) foo_tmp
514
+ )";
515
+
516
+ $result = $wpdb->query($del_sql);
517
+ if (false === $result) {
518
+ $aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Utility::cleanup_table failed for table name: " . $table_name, 4);
519
+ }
520
+ }
521
+ return (false === $result) ? false : true;
522
+ }
523
+
524
+ /**
525
+ * Delete expired captcha info option
526
+ *
527
+ * Note: A unique instance these option is created everytime the login page is loaded with captcha enabled
528
+ * This function will help prune the options table of old expired entries.
529
+ *
530
+ * @global wpdb $wpdb
531
+ */
532
+ public static function delete_expired_captcha_options() {
533
+ global $wpdb;
534
+ $current_unix_time = current_time('timestamp', true);
535
+ $previous_hour = $current_unix_time - 3600;
536
+ AIOWPSecurity_Utility::is_multisite_install() ? $tbl = $wpdb->sitemeta : $tbl = $wpdb->prefix . 'options';
537
+ $query = $wpdb->prepare("SELECT * FROM {$tbl} WHERE option_name LIKE 'aiowps_captcha_string_info_time_%' AND option_value < %s", $previous_hour);
538
+ $res = $wpdb->get_results($query, ARRAY_A);
539
+ if (!empty($res)) {
540
+ foreach ($res as $item) {
541
+ $option_name = $item['option_name'];
542
+ if (AIOWPSecurity_Utility::is_multisite_install()) {
543
+ delete_site_option($option_name);
544
+ delete_site_option(str_replace('time_', '', $option_name));
545
+ } else {
546
+ delete_option($option_name);
547
+ delete_option(str_replace('time_', '', $option_name));
548
+ }
549
+ }
550
+ }
551
+ }
552
+
553
+ /**
554
+ * Get server type.
555
+ *
556
+ * @return string|integer Server type or -1 if server is not supported
557
+ */
558
+ public static function get_server_type() {
559
+ if (!isset($_SERVER['SERVER_SOFTWARE'])) {
560
+ return -1;
561
+ }
562
+
563
+ // Figure out what server they're using.
564
+ $server_software = strtolower(sanitize_text_field(wp_unslash(($_SERVER['SERVER_SOFTWARE']))));
565
+
566
+ if (strstr($server_software, 'apache')) {
567
+ return 'apache';
568
+ } elseif (strstr($server_software, 'nginx')) {
569
+ return 'nginx';
570
+ } elseif (strstr($server_software, 'litespeed')) {
571
+ return 'litespeed';
572
+ } elseif (strstr($server_software, 'iis')) {
573
+ return 'iis';
574
+ } else { // Unsupported server
575
+ return -1;
576
+ }
577
+ }
578
+
579
+ /**
580
+ * Checks if the string exists in the array key value of the provided array.
581
+ * If it doesn't exist, it returns the first key element from the valid values.
582
+ *
583
+ * @param type $to_check
584
+ * @param type $valid_values
585
+ * @return type
586
+ */
587
+ public static function sanitize_value_by_array($to_check, $valid_values) {
588
+ $keys = array_keys($valid_values);
589
+ $keys = array_map('strtolower', $keys);
590
+ if (in_array(strtolower($to_check), $keys)) {
591
+ return $to_check;
592
+ }
593
+ return reset($keys); //Return the first element from the valid values
594
+ }
595
+
596
+ /**
597
+ * Partially or fully masks a string using '*' to replace original characters
598
+ *
599
+ * @param type string $str
600
+ * @param type int $chars_unmasked
601
+ * @return type string
602
+ */
603
+ public static function mask_string($str, $chars_unmasked = 0) {
604
+ $str_length = strlen($str);
605
+ $chars_unmasked = absint($chars_unmasked);
606
+
607
+ if (0 == $chars_unmasked) {
608
+ if (8 < $str_length) {
609
+ // mask all but last 4 characters
610
+ return preg_replace("/(.{4}$)(*SKIP)(*F)|(.)/u", "*", $str);
611
+ } elseif (3 < $str_length) {
612
+ // mask all but last 2 characters
613
+ return preg_replace("/(.{2}$)(*SKIP)(*F)|(.)/u", "*", $str);
614
+ } else {
615
+ // return whole string masked
616
+ return str_pad("", $str_length, "*", STR_PAD_LEFT);
617
+ }
618
+ }
619
+ if ($chars_unmasked >= $str_length) return $str;
620
+ return preg_replace("/(.{".$chars_unmasked."}$)(*SKIP)(*F)|(.)/u", "*", $str);
621
+ }
622
 
623
  }
classes/wp-security-wp-footer-content.php CHANGED
@@ -1,136 +1,129 @@
1
  <?php
2
- if(!defined('ABSPATH')){
3
- exit;//Exit if accessed directly
4
  }
5
 
6
  class AIOWPSecurity_WP_Footer_Content {
7
 
8
- function __construct() {
9
- //Add content that need to be outputted in the footer area.
10
 
11
- global $aio_wp_security;
12
-
13
- // If Google recaptcha is enabled do relevant tasks
14
- if($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
15
- // For Woocommerce forms.
16
- // Only proceed if woocommerce installed and active
17
- if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) )
18
- {
19
- if($aio_wp_security->configs->get_value('aiowps_enable_woo_login_captcha') == '1' ||
20
- $aio_wp_security->configs->get_value('aiowps_enable_woo_register_captcha') == '1' ||
21
- $aio_wp_security->configs->get_value('aiowps_enable_woo_lostpassword_captcha') == '1')
22
- {
23
- $this->print_recaptcha_api_woo();
24
- }
25
- }
26
-
27
- // For custom wp login form
28
- if($aio_wp_security->configs->get_value('aiowps_enable_custom_login_captcha') == '1')
29
- {
30
- $this->print_recaptcha_api_custom_login();
31
- }
32
-
33
- }
34
 
35
- // Activate the copy protection feature for non-admin users
36
- $copy_protection_active = $aio_wp_security->configs->get_value('aiowps_copy_protection') == '1';
37
- if ( $copy_protection_active && !current_user_can(AIOWPSEC_MANAGEMENT_PERMISSION) )
38
- {
39
- $this->output_copy_protection_code();
40
- }
41
-
42
- //TODO - add other footer output content here
43
- }
44
-
45
- /**
46
- * For Woocommerce my account page - display two separate Google reCaptcha forms "explicitly"
47
- * @global type $aio_wp_security
48
- */
49
- function print_recaptcha_api_woo() {
50
- global $aio_wp_security;
51
- $is_woo = false;
52
- $is_woo = is_account_page();
53
- if(!$is_woo) {
54
- return; // if current page is not woo account page don't do anything
55
- }
56
- $site_key = esc_html( $aio_wp_security->configs->get_value('aiowps_recaptcha_site_key') );
57
- ?>
58
- <script type="text/javascript">
59
- var verifyCallback = function(response) {
60
- alert(response);
61
- };
62
- var onloadCallback = function() {
63
- if ( jQuery('#woo_recaptcha_1').length ) {
64
- grecaptcha.render('woo_recaptcha_1', {
65
- 'sitekey' : '<?php echo $site_key; ?>',
66
- });
67
- }
68
- if ( jQuery('#woo_recaptcha_2').length ) {
69
- grecaptcha.render('woo_recaptcha_2', {
70
- 'sitekey' : '<?php echo $site_key; ?>',
71
- });
72
- }
73
- };
74
- </script>
75
- <script src='https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit' async defer></script>
76
- <?php
77
- }
78
 
79
- function output_copy_protection_code() {
80
- ?>
81
- <meta http-equiv="imagetoolbar" content="no"><!-- disable image toolbar (if any) -->
82
- <script type="text/javascript">
83
- /*<![CDATA[*/
84
- document.oncontextmenu = function() {
85
- return false;
86
- };
87
- document.onselectstart = function() {
88
- if (event.srcElement.type != "text" && event.srcElement.type != "textarea" && event.srcElement.type != "password") {
89
- return false;
90
- }
91
- else {
92
- return true;
93
- }
94
- };
95
- if (window.sidebar) {
96
- document.onmousedown = function(e) {
97
- var obj = e.target;
98
- if (obj.tagName.toUpperCase() == 'SELECT'
99
- || obj.tagName.toUpperCase() == "INPUT"
100
- || obj.tagName.toUpperCase() == "TEXTAREA"
101
- || obj.tagName.toUpperCase() == "PASSWORD") {
102
- return true;
103
- }
104
- else {
105
- return false;
106
- }
107
- };
108
- }
109
- document.ondragstart = function() {
110
- return false;
111
- };
112
- /*]]>*/
113
- </script>
114
- <?php
115
- }
116
 
117
- /**
118
- * For case when a custom wp_login_form() is displayed anywhere on a page.
119
- * Inserts a script element referencing google recaptcha api v2.
120
- * Only inserts the recaptcha script element if the wp login form exists.
121
- */
122
- function print_recaptcha_api_custom_login()
123
- {
124
- ?>
125
- <script type="text/javascript">
126
- let cust_login = document.getElementById("loginform");
127
- if(cust_login !== null) {
128
- var recaptcha_script = document.createElement('script');
129
- recaptcha_script.setAttribute('src','https://www.google.com/recaptcha/api.js');
130
- document.head.appendChild(recaptcha_script);
131
- }
132
- </script>
133
- <?php
134
- }
135
- }
136
- //End of class
1
  <?php
2
+ if (!defined('ABSPATH')) {
3
+ exit;//Exit if accessed directly
4
  }
5
 
6
  class AIOWPSecurity_WP_Footer_Content {
7
 
8
+ public function __construct() {
9
+ //Add content that need to be outputted in the footer area.
10
 
11
+ global $aio_wp_security;
12
+
13
+ // If Google recaptcha is enabled do relevant tasks
14
+ if ($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
15
+ // For Woocommerce forms.
16
+ // Only proceed if woocommerce installed and active
17
+ if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
18
+ if ($aio_wp_security->configs->get_value('aiowps_enable_woo_login_captcha') == '1' || $aio_wp_security->configs->get_value('aiowps_enable_woo_register_captcha') == '1' || $aio_wp_security->configs->get_value('aiowps_enable_woo_lostpassword_captcha') == '1') {
19
+ $this->print_recaptcha_api_woo();
20
+ }
21
+ }
22
+
23
+ // For custom wp login form
24
+ if ($aio_wp_security->configs->get_value('aiowps_enable_custom_login_captcha') == '1') {
25
+ $this->print_recaptcha_api_custom_login();
26
+ }
27
+
28
+ }
 
 
 
 
 
29
 
30
+ // Activate the copy protection feature for non-admin users
31
+ $copy_protection_active = $aio_wp_security->configs->get_value('aiowps_copy_protection') == '1';
32
+ if ($copy_protection_active && !current_user_can(AIOWPSEC_MANAGEMENT_PERMISSION)) {
33
+ $this->output_copy_protection_code();
34
+ }
35
+
36
+ //TODO - add other footer output content here
37
+ }
38
+
39
+ /**
40
+ * For Woocommerce my account page - display two separate Google reCaptcha forms "explicitly"
41
+ *
42
+ * @global type $aio_wp_security
43
+ */
44
+ public function print_recaptcha_api_woo() {
45
+ global $aio_wp_security;
46
+ $is_woo = false;
47
+ $is_woo = is_account_page();
48
+ if (!$is_woo) {
49
+ return; // if current page is not woo account page don't do anything
50
+ }
51
+ $site_key = esc_html($aio_wp_security->configs->get_value('aiowps_recaptcha_site_key'));
52
+ ?>
53
+ <script type="text/javascript">
54
+ var verifyCallback = function(response) {
55
+ alert(response);
56
+ };
57
+ var onloadCallback = function() {
58
+ if ( jQuery('#woo_recaptcha_1').length ) {
59
+ grecaptcha.render('woo_recaptcha_1', {
60
+ 'sitekey' : '<?php echo $site_key; ?>',
61
+ });
62
+ }
63
+ if ( jQuery('#woo_recaptcha_2').length ) {
64
+ grecaptcha.render('woo_recaptcha_2', {
65
+ 'sitekey' : '<?php echo $site_key; ?>',
66
+ });
67
+ }
68
+ };
69
+ </script>
70
+ <script src='https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit' async defer></script>
71
+ <?php
72
+ }
73
 
74
+ public function output_copy_protection_code() {
75
+ ?>
76
+ <meta http-equiv="imagetoolbar" content="no"><!-- disable image toolbar (if any) -->
77
+ <script type="text/javascript">
78
+ /*<![CDATA[*/
79
+ document.oncontextmenu = function() {
80
+ return false;
81
+ };
82
+ document.onselectstart = function() {
83
+ if (event.srcElement.type != "text" && event.srcElement.type != "textarea" && event.srcElement.type != "password") {
84
+ return false;
85
+ }
86
+ else {
87
+ return true;
88
+ }
89
+ };
90
+ if (window.sidebar) {
91
+ document.onmousedown = function(e) {
92
+ var obj = e.target;
93
+ if (obj.tagName.toUpperCase() == 'SELECT'
94
+ || obj.tagName.toUpperCase() == "INPUT"
95
+ || obj.tagName.toUpperCase() == "TEXTAREA"
96
+ || obj.tagName.toUpperCase() == "PASSWORD") {
97
+ return true;
98
+ }
99
+ else {
100
+ return false;
101
+ }
102
+ };
103
+ }
104
+ document.ondragstart = function() {
105
+ return false;
106
+ };
107
+ /*]]>*/
108
+ </script>
109
+ <?php
110
+ }
111
 
112
+ /**
113
+ * For case when a custom wp_login_form() is displayed anywhere on a page.
114
+ * Inserts a script element referencing google recaptcha api v2.
115
+ * Only inserts the recaptcha script element if the wp login form exists.
116
+ */
117
+ public function print_recaptcha_api_custom_login() {
118
+ ?>
119
+ <script type="text/javascript">
120
+ let cust_login = document.getElementById("loginform");
121
+ if(cust_login !== null) {
122
+ var recaptcha_script = document.createElement('script');
123
+ recaptcha_script.setAttribute('src','https://www.google.com/recaptcha/api.js');
124
+ document.head.appendChild(recaptcha_script);
125
+ }
126
+ </script>
127
+ <?php
128
+ }
129
+ }//End of class
 
 
classes/wp-security-wp-loaded-tasks.php CHANGED
@@ -1,64 +1,65 @@
1
  <?php
2
-
3
- /* * * This class handles tasks that need to be executed at wp-loaded time ** */
4
- if(!defined('ABSPATH')){
5
- exit;//Exit if accessed directly
 
6
  }
7
 
8
  class AIOWPSecurity_WP_Loaded_Tasks {
9
 
10
- function __construct() {
11
- //Add tasks that need to be executed at wp-loaded time
12
 
13
- global $aio_wp_security;
14
- do_action( 'aiowps_wp_loaded_tasks_start', $this);
15
 
16
- //Handle the rename login page feature
17
- if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
18
- include_once(AIO_WP_SECURITY_PATH . '/classes/wp-security-process-renamed-login-page.php');
19
- $login_object = new AIOWPSecurity_Process_Renamed_Login_Page();
20
- AIOWPSecurity_Process_Renamed_Login_Page::renamed_login_init_tasks();
21
- }else{
22
- add_action('login_init', array($this, 'aiowps_login_init'));
23
- }
24
 
25
- //For site lockout feature (ie, maintenance mode). It needs to be checked after the rename login page
26
- if ($aio_wp_security->configs->get_value('aiowps_site_lockout') == '1') {
27
- if (!is_user_logged_in()) {
28
- //now check if user trying to reach login pages
29
- if(!in_array($GLOBALS['pagenow'], array('wp-login.php'))){
30
- self::site_lockout_tasks();
31
- }
32
- }else if(is_user_logged_in() && !current_user_can('manage_options') && !is_admin() && !in_array($GLOBALS['pagenow'], array('wp-login.php')) ){
33
- self::site_lockout_tasks();
34
- }
35
- }
36
- do_action( 'aiowps_wp_loaded_tasks_end', $this);
37
 
38
- }
39
 
40
- static function site_lockout_tasks() {
41
- $lockout_output = apply_filters('aiowps_site_lockout_output', '');
42
- if (empty($lockout_output)) {
43
- nocache_headers();
44
- header("HTTP/1.0 503 Service Unavailable");
45
- remove_action('wp_head', 'head_addons', 7);
46
- $template = apply_filters('aiowps_site_lockout_template_include', AIO_WP_SECURITY_PATH . '/other-includes/wp-security-visitor-lockout-page.php');
47
- include_once($template);
48
- } else {
49
- echo $lockout_output;
50
- }
51
 
52
- exit();
53
- }
54
-
55
- static function aiowps_login_init(){
56
- //if user is logged in and tries to access login page - redirect them to wp-admin
57
- //this will prevent issues such as the following:
58
- //https://wordpress.org/support/topic/already-logged-in-no-captcha
59
- if(is_user_logged_in()){
60
- wp_redirect(admin_url());
61
- }
62
- }
63
 
64
- }
1
  <?php
2
+ /**
3
+ * This class handles tasks that need to be executed at wp-loaded time
4
+ */
5
+ if (!defined('ABSPATH')) {
6
+ exit;//Exit if accessed directly
7
  }
8
 
9
  class AIOWPSecurity_WP_Loaded_Tasks {
10
 
11
+ public function __construct() {
12
+ //Add tasks that need to be executed at wp-loaded time
13
 
14
+ global $aio_wp_security;
15
+ do_action('aiowps_wp_loaded_tasks_start', $this);
16
 
17
+ //Handle the rename login page feature
18
+ if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
19
+ include_once(AIO_WP_SECURITY_PATH . '/classes/wp-security-process-renamed-login-page.php');
20
+ new AIOWPSecurity_Process_Renamed_Login_Page();
21
+ AIOWPSecurity_Process_Renamed_Login_Page::renamed_login_init_tasks();
22
+ } else {
23
+ add_action('login_init', array($this, 'aiowps_login_init'));
24
+ }
25
 
26
+ //For site lockout feature (ie, maintenance mode). It needs to be checked after the rename login page
27
+ if ($aio_wp_security->configs->get_value('aiowps_site_lockout') == '1') {
28
+ if (!is_user_logged_in()) {
29
+ //now check if user trying to reach login pages
30
+ if (!in_array($GLOBALS['pagenow'], array('wp-login.php'))) {
31
+ self::site_lockout_tasks();
32
+ }
33
+ } elseif (is_user_logged_in() && !current_user_can('manage_options') && !is_admin() && !in_array($GLOBALS['pagenow'], array('wp-login.php'))) {
34
+ self::site_lockout_tasks();
35
+ }
36
+ }
37
+ do_action('aiowps_wp_loaded_tasks_end', $this);
38
 
39
+ }
40
 
41
+ public static function site_lockout_tasks() {
42
+ $lockout_output = apply_filters('aiowps_site_lockout_output', '');
43
+ if (empty($lockout_output)) {
44
+ nocache_headers();
45
+ header("HTTP/1.0 503 Service Unavailable");
46
+ remove_action('wp_head', 'head_addons', 7);
47
+ $template = apply_filters('aiowps_site_lockout_template_include', AIO_WP_SECURITY_PATH . '/other-includes/wp-security-visitor-lockout-page.php');
48
+ include_once($template);
49
+ } else {
50
+ echo $lockout_output;
51
+ }
52
 
53
+ exit();
54
+ }
55
+
56
+ public static function aiowps_login_init() {
57
+ //if user is logged in and tries to access login page - redirect them to wp-admin
58
+ //this will prevent issues such as the following:
59
+ //https://wordpress.org/support/topic/already-logged-in-no-captcha
60
+ if (is_user_logged_in()) {
61
+ wp_redirect(admin_url());
62
+ }
63
+ }
64
 
65
+ }
css/wp-security-notices.css ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* CSS for adverts */
2
+
3
+ .aiowps_notice_container {
4
+ height: auto;
5
+ overflow: hidden;
6
+ }
7
+
8
+ .aiowps_review_notice_container {
9
+ padding: 12px;
10
+ display: flex;
11
+ }
12
+
13
+ .aiowps_advert_button_container {
14
+ margin-bottom: 10px;
15
+ display: flex;
16
+ align-items: center;
17
+ }
18
+
19
+ .aiowps_advert_button_container .dashicons {
20
+ margin-left: 10px;
21
+ }
22
+
23
+ .aiowps_advert_content_left {
24
+ float: none;
25
+ width: 65px;
26
+ }
27
+
28
+ .aiowps_advert_content_left_extra {
29
+ float: none;
30
+ width: 100px;
31
+ padding-right: 15px;
32
+ display: flex;
33
+ align-items: center;
34
+ }
35
+
36
+ .aiowps_advert_content_right {
37
+ float: none;
38
+ width: auto;
39
+ overflow: hidden;
40
+ }
41
+
42
+ .aiowps_advert_bottom {
43
+ margin: 10px 0;
44
+ padding: 10px;
45
+ font-size: 140%;
46
+ background-color: white;
47
+ border-color: #E6DB55;
48
+ border: 1px solid;
49
+ border-radius: 4px;
50
+ }
51
+
52
+ .aiowps_advert_dismiss {
53
+ float: right;
54
+ font-size: 13px;
55
+ font-weight: normal;
56
+ }
57
+
58
+ h3.aiowps_advert_heading {
59
+ margin-top: 5px !important;
60
+ margin-bottom: 5px !important;
61
+ }
62
+
63
+ h4.aiowps_advert_heading {
64
+ margin-top: 2px !important;
65
+ margin-bottom: 3px !important;
66
+ }
67
+
68
+ .aiowps_center_content {
69
+ text-align: center;
70
+ margin-bottom: 5px;
71
+ }
72
+
73
+ .aiowps_notice_link {
74
+ padding-left: 5px;
75
+ }
76
+
77
+ .aiowps_text_center {
78
+ text-align: center;
79
+ }
80
+
81
+ @media screen and (min-width: 560px) {
82
+
83
+ .aiowps_advert_content_left, .aiowps_advert_content_left_extra {
84
+ float: left;
85
+ }
86
+
87
+ }
images/notices/aiowps-logo.png ADDED
Binary file
images/notices/black_friday.png ADDED
Binary file
images/notices/new_year.png ADDED
Binary file
images/notices/spring.png ADDED
Binary file
images/notices/summer.png ADDED
Binary file
images/notices/ud_smile.png ADDED
Binary file
images/notices/updraft_logo.png ADDED
Binary file
images/notices/wp_optimize_logo.png ADDED
Binary file
other-includes/wp-security-rename-login-feature-pre-5-2.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  /**
3
  * WordPress User Page
4
  *
@@ -10,14 +11,14 @@
10
 
11
 
12
  // Redirect to https login if forced to use SSL
13
- if ( force_ssl_admin() && ! is_ssl() ) {
14
- if ( 0 === strpos($_SERVER['REQUEST_URI'], 'http') ) {
15
- wp_safe_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
16
- exit();
17
- } else {
18
- wp_safe_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
19
- exit();
20
- }
21
  }
22
 
23
  /**
@@ -28,19 +29,19 @@ if ( force_ssl_admin() && ! is_ssl() ) {
28
  * @param string $message Optional. Message to display in header. Default empty.
29
  * @param WP_Error $wp_error Optional. The error to pass. Default empty.
30
  */
31
- function login_header( $title = 'Log In', $message = '', $wp_error = '' ) {
32
  global $error, $interim_login, $action;
33
 
34
  // Don't index any of these forms
35
- add_action( 'login_head', 'wp_no_robots' );
36
 
37
- add_action( 'login_head', 'wp_login_viewport_meta' );
38
 
39
- if ( empty($wp_error) )
40
- $wp_error = new WP_Error();
41
 
42
  // Shake it!
43
- $shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password' );
44
  /**
45
  * Filter the error codes array for shaking the login form.
46
  *
@@ -48,15 +49,15 @@ $shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'i
48
  *
49
  * @param array $shake_error_codes Error codes that shake the login form.
50
  */
51
- $shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
52
 
53
- if ( $shake_error_codes && $wp_error->get_error_code() && in_array( $wp_error->get_error_code(), $shake_error_codes ) )
54
- add_action( 'login_head', 'wp_shake_js', 12 );
55
 
56
- $login_title = get_bloginfo( 'name', 'display' );
57
 
58
  /* translators: Login screen title. 1: Login screen name, 2: Network or site name */
59
- $login_title = sprintf( __( '%1$s &lsaquo; %2$s &#8212; WordPress' ), $title, $login_title );
60
 
61
  /**
62
  * Filters the title tag content for login page.
@@ -66,205 +67,205 @@ $login_title = sprintf( __( '%1$s &lsaquo; %2$s &#8212; WordPress' ), $title, $l
66
  * @param string $login_title The page title, with extra context added.
67
  * @param string $title The original page title.
68
  */
69
- $login_title = apply_filters( 'login_title', $login_title, $title );
70
 
71
  ?><!DOCTYPE html>
72
  <!--[if IE 8]>
73
  <html xmlns="http://www.w3.org/1999/xhtml" class="ie8" <?php language_attributes(); ?>>
74
  <![endif]-->
75
- <!--[if !(IE 8) ]><!-->
76
  <html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
77
  <!--<![endif]-->
78
  <head>
79
- <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
80
- <title><?php echo $login_title; ?></title>
81
- <?php
82
-
83
- wp_enqueue_style( 'login' );
84
-
85
- /*
86
- * Remove all stored post data on logging out.
87
- * This could be added by add_action('login_head'...) like wp_shake_js(),
88
- * but maybe better if it's not removable by plugins
89
- */
90
- if ( 'loggedout' == $wp_error->get_error_code() ) {
91
- ?>
92
- <script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
93
- <?php
94
- }
95
-
96
- /**
97
- * Enqueue scripts and styles for the login page.
98
- *
99
- * @since 3.1.0
100
- */
101
- do_action( 'login_enqueue_scripts' );
102
-
103
- /**
104
- * Fires in the login page header after scripts are enqueued.
105
- *
106
- * @since 2.1.0
107
- */
108
- do_action( 'login_head' );
109
-
110
- if ( is_multisite() ) {
111
- $login_header_url = network_home_url();
112
- $login_header_title = get_network()->site_name;
113
- } else {
114
- $login_header_url = __( 'https://wordpress.org/' );
115
- $login_header_title = __( 'Powered by WordPress' );
116
- }
117
-
118
- /**
119
- * Filter link URL of the header logo above login form.
120
- *
121
- * @since 2.1.0
122
- *
123
- * @param string $login_header_url Login header logo URL.
124
- */
125
- $login_header_url = apply_filters( 'login_headerurl', $login_header_url );
126
-
127
- /**
128
- * Filter the title attribute of the header logo above login form.
129
- *
130
- * @since 2.1.0
131
- *
132
- * @param string $login_header_title Login header logo title attribute.
133
- */
134
- $login_header_title = apply_filters( 'login_headertitle', $login_header_title );
135
-
136
- /*
137
- * To match the URL/title set above, Multisite sites have the blog name,
138
- * while single sites get the header title.
139
- */
140
- if ( is_multisite() ) {
141
- $login_header_text = get_bloginfo( 'name', 'display' );
142
- } else {
143
- $login_header_text = $login_header_title;
144
- }
145
-
146
- $classes = array( 'login-action-' . $action, 'wp-core-ui' );
147
- if ( is_rtl() )
148
- $classes[] = 'rtl';
149
- if ( $interim_login ) {
150
- $classes[] = 'interim-login';
151
- ?>
152
- <style type="text/css">html{background-color: transparent;}</style>
153
- <?php
154
-
155
- if ( 'success' === $interim_login )
156
- $classes[] = 'interim-login-success';
157
- }
158
- $classes[] =' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
159
-
160
- /**
161
- * Filter the login page body classes.
162
- *
163
- * @since 3.5.0
164
- *
165
- * @param array $classes An array of body classes.
166
- * @param string $action The action that brought the visitor to the login page.
167
- */
168
- $classes = apply_filters( 'login_body_class', $classes, $action );
169
-
170
- ?>
171
  </head>
172
- <body class="login <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
173
  <?php
174
  /**
175
  * Fires in the login page header after the body tag is opened.
176
  *
177
  * @since 4.6.0
178
  */
179
- do_action( 'login_header' );
180
  ?>
181
  <div id="login">
182
- <h1><a href="<?php echo esc_url( $login_header_url ); ?>" title="<?php echo esc_attr( $login_header_title ); ?>" tabindex="-1"><?php echo $login_header_text; ?></a></h1>
183
- <?php
184
-
185
- unset( $login_header_url, $login_header_title );
186
-
187
- /**
188
- * Filter the message to display above the login form.
189
- *
190
- * @since 2.1.0
191
- *
192
- * @param string $message Login message text.
193
- */
194
-
195
- $message = apply_filters( 'login_message', $message );
196
- if ( !empty( $message ) )
197
- echo $message . "\n";
198
-
199
- // In case a plugin uses $error rather than the $wp_errors object
200
- if ( !empty( $error ) ) {
201
- $wp_error->add('error', $error);
202
- unset($error);
203
- }
204
-
205
- if ( $wp_error->get_error_code() ) {
206
- $errors = '';
207
- $messages = '';
208
- foreach ( $wp_error->get_error_codes() as $code ) {
209
- $severity = $wp_error->get_error_data( $code );
210
- foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
211
- if ( 'message' == $severity )
212
- $messages .= ' ' . $error_message . "<br />\n";
213
- else
214
- $errors .= ' ' . $error_message . "<br />\n";
215
- }
216
- }
217
- if ( ! empty( $errors ) ) {
218
- /**
219
- * Filter the error messages displayed above the login form.
220
- *
221
- * @since 2.1.0
222
- *
223
- * @param string $errors Login error message.
224
- */
225
- echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
226
- }
227
- if ( ! empty( $messages ) ) {
228
- /**
229
- * Filter instructional messages displayed above the login form.
230
- *
231
- * @since 2.5.0
232
- *
233
- * @param string $messages Login messages.
234
- */
235
- echo '<p class="message">' . apply_filters( 'login_messages', $messages ) . "</p>\n";
236
- }
237
- }
238
- } // End of login_header()
239
-
240
- /**
241
- * Outputs the footer for the login page.
242
- *
243
- * @param string $input_id Which input to auto-focus
244
- */
245
- function login_footer($input_id = '') {
246
- global $interim_login;
247
-
248
- // Don't allow interim logins to navigate away from the page.
249
- if ( ! $interim_login ): ?>
250
- <p id="backtoblog"><a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php
 
251
  /* translators: %s: site title */
252
- printf( _x( '&larr; Back to %s', 'site' ), get_bloginfo( 'title', 'display' ) );
253
  ?></a></p>
254
- <?php
255
- if(function_exists('the_privacy_policy_link')){
256
- the_privacy_policy_link( '<div class="privacy-policy-page-link">', '</div>' );
257
- }
258
- ?>
259
- <?php endif; ?>
260
 
261
  </div>
262
 
263
- <?php if ( !empty($input_id) ) : ?>
264
- <script type="text/javascript">
265
- try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e){}
266
- if(typeof wpOnload=='function')wpOnload();
267
- </script>
268
  <?php endif; ?>
269
 
270
  <?php
@@ -273,7 +274,7 @@ do_action( 'login_header' );
273
  *
274
  * @since 3.1.0
275
  */
276
- do_action( 'login_footer' ); ?>
277
  <div class="clear"></div>
278
  </body>
279
  </html>
@@ -281,26 +282,30 @@ do_action( 'login_footer' ); ?>
281
  }
282
 
283
  /**
 
 
284
  * @since 3.0.0
285
  */
286
  function wp_shake_js() {
287
- ?>
288
- <script type="text/javascript">
289
- addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
290
- function s(id,pos){g(id).left=pos+'px';}
291
- function g(id){return document.getElementById(id).style;}
292
- function shake(id,a,d){c=a.shift();s(id,c);if(a.length>0){setTimeout(function(){shake(id,a,d);},d);}else{try{g(id).position='static';wp_attempt_focus();}catch(e){}}}
293
- addLoadEvent(function(){ var p=new Array(15,30,15,0,-15,-30,-15,0);p=p.concat(p.concat(p));var i=document.forms[0].id;g(i).position='relative';shake(i,p,20);});
294
- </script>
295
  <?php
296
  }
297
 
298
  /**
 
 
299
  * @since 3.7.0
300
  */
301
  function wp_login_viewport_meta() {
302
- ?>
303
- <meta name="viewport" content="width=device-width" />
304
  <?php
305
  }
306
 
@@ -310,100 +315,100 @@ function wp_login_viewport_meta() {
310
  * @return bool|WP_Error True: when finish. WP_Error on error
311
  */
312
  function retrieve_password() {
313
- $errors = new WP_Error();
314
-
315
- if ( empty( $_POST['user_login'] ) || ! is_string( $_POST['user_login'] ) ) {
316
- $errors->add('empty_username', __('<strong>ERROR</strong>: Enter a username or email address.' ));
317
- } elseif ( strpos( $_POST['user_login'], '@' ) ) {
318
- $user_data = get_user_by( 'email', trim( wp_unslash( $_POST['user_login'] ) ) );
319
- if ( empty( $user_data ) )
320
- $errors->add('invalid_email', __('<strong>ERROR</strong>: There is no user registered with that email address.' ));
321
- } else {
322
- $login = trim($_POST['user_login']);
323
- $user_data = get_user_by('login', $login);
324
- }
325
-
326
- /**
327
- * Fires before errors are returned from a password reset request.
328
- *
329
- * @since 2.1.0
330
- * @since 4.4.0 Added the `$errors` parameter.
331
- *
332
- * @param WP_Error $errors A WP_Error object containing any errors generated
333
- * by using invalid credentials.
334
- */
335
- do_action( 'lostpassword_post', $errors );
336
-
337
- if ( $errors->get_error_code() )
338
- return $errors;
339
-
340
- if ( !$user_data ) {
341
- $errors->add('invalidcombo', __('<strong>ERROR</strong>: Invalid username or email.' ));
342
- return $errors;
343
- }
344
-
345
- // Redefining user_login ensures we return the right case in the email.
346
- $user_login = $user_data->user_login;
347
- $user_email = $user_data->user_email;
348
- $key = get_password_reset_key( $user_data );
349
-
350
- if ( is_wp_error( $key ) ) {
351
- return $key;
352
- }
353
-
354
- if ( is_multisite() ) {
355
- $site_name = get_network()->site_name;
356
- } else {
357
- /*
358
- * The blogname option is escaped with esc_html on the way into the database
359
- * in sanitize_option we want to reverse this for the plain text arena of emails.
360
- */
361
- $site_name = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
362
- }
363
-
364
- $message = __( 'Someone has requested a password reset for the following account:' ) . "\r\n\r\n";
365
- /* translators: %s: site name */
366
- $message .= sprintf( __( 'Site Name: %s'), $site_name ) . "\r\n\r\n";
367
- /* translators: %s: user login */
368
- $message .= sprintf( __( 'Username: %s'), $user_login ) . "\r\n\r\n";
369
- $message .= __( 'If this was a mistake, just ignore this email and nothing will happen.' ) . "\r\n\r\n";
370
- $message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n";
371
- $message .= '<' . network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' ) . ">\r\n";
372
-
373
- /* translators: Password reset email subject. %s: Site name */
374
- $title = sprintf( __( '[%s] Password Reset' ), $site_name );
375
-
376
- /**
377
- * Filters the subject of the password reset email.
378
- *
379
- * @since 2.8.0
380
- * @since 4.4.0 Added the `$user_login` and `$user_data` parameters.
381
- *
382
- * @param string $title Default email title.
383
- * @param string $user_login The username for the user.
384
- * @param WP_User $user_data WP_User object.
385
- */
386
- $title = apply_filters( 'retrieve_password_title', $title, $user_login, $user_data );
387
-
388
- /**
389
- * Filter the message body of the password reset mail.
390
- *
391
- * If the filtered message is empty, the password reset email will not be sent.
392
- *
393
- * @since 2.8.0
394
- * @since 4.1.0 Added `$user_login` and `$user_data` parameters.
395
- *
396
- * @param string $message Default mail message.
397
- * @param string $key The activation key.
398
- * @param string $user_login The username for the user.
399
- * @param WP_User $user_data WP_User object.
400
- */
401
- $message = apply_filters( 'retrieve_password_message', $message, $key, $user_login, $user_data );
402
-
403
- if ( $message && !wp_mail( $user_email, wp_specialchars_decode( $title ), $message ) )
404
- wp_die( __('The email could not be sent.' ) . "<br />\n" . __('Possible reason: your host may have disabled the mail() function.' ) );
405
-
406
- return true;
407
  }
408
 
409
  //
@@ -413,37 +418,37 @@ function retrieve_password() {
413
  $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'login';
414
  $errors = new WP_Error();
415
 
416
- if ( isset($_GET['key']) )
417
- $action = 'resetpass';
418
 
419
  // validate action so as to default to the login screen
420
- if ( !in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login', 'confirmaction' ), true ) && false === has_filter( 'login_form_' . $action ) )
421
- $action = 'login';
422
 
423
  nocache_headers();
424
 
425
  header('Content-Type: '.get_bloginfo('html_type').'; charset='.get_bloginfo('charset'));
426
 
427
- if ( defined( 'RELOCATE' ) && RELOCATE ) { // Move flag is set
428
- if ( isset( $_SERVER['PATH_INFO'] ) && ($_SERVER['PATH_INFO'] != $_SERVER['PHP_SELF']) )
429
- $_SERVER['PHP_SELF'] = str_replace( $_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF'] );
430
 
431
- $url = dirname( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] ) );
432
- if ( $url != get_option( 'siteurl' ) )
433
- update_option( 'siteurl', $url );
434
  }
435
 
436
  //Set a cookie now to see if they are supported by the browser.
437
- $secure = ( 'https' === parse_url( wp_login_url(), PHP_URL_SCHEME ) );
438
- setcookie( TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN, $secure );
439
- if ( SITECOOKIEPATH != COOKIEPATH )
440
- setcookie( TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN, $secure );
441
 
442
- $lang = ! empty( $_GET['wp_lang'] ) ? sanitize_text_field( $_GET['wp_lang'] ) : '';
443
  $switched_locale = false;
444
 
445
- if ( function_exists( 'switch_to_locale' ) ) {
446
- $switched_locale = switch_to_locale( $lang );
447
  }
448
 
449
  /**
@@ -451,7 +456,7 @@ if ( function_exists( 'switch_to_locale' ) ) {
451
  *
452
  * @since 3.2.0
453
  */
454
- do_action( 'login_init' );
455
 
456
  /**
457
  * Fires before a specified login form action.
@@ -462,7 +467,7 @@ do_action( 'login_init' );
462
  *
463
  * @since 2.8.0
464
  */
465
- do_action( "login_form_{$action}" );
466
 
467
  $http_post = ('POST' == $_SERVER['REQUEST_METHOD']);
468
  $interim_login = isset($_REQUEST['interim-login']);
@@ -474,633 +479,624 @@ $interim_login = isset($_REQUEST['interim-login']);
474
  *
475
  * @param string $login_link_separator The separator used between login form navigation links.
476
  */
477
- $login_link_separator = apply_filters( 'login_link_separator', ' | ' );
478
 
479
  switch ($action) {
480
 
481
- case 'postpass' :
482
- if ( ! array_key_exists( 'post_password', $_POST ) ) {
483
- wp_safe_redirect( wp_get_referer() );
484
  exit();
485
  }
486
-
487
- require_once ABSPATH . WPINC . '/class-phpass.php';
488
- $hasher = new PasswordHash( 8, true );
489
-
490
- /**
491
- * Filter the life span of the post password cookie.
492
- *
493
- * By default, the cookie expires 10 days from creation. To turn this
494
- * into a session cookie, return 0.
495
- *
496
- * @since 3.7.0
497
- *
498
- * @param int $expires The expiry time, as passed to setcookie().
499
- */
500
- $expire = apply_filters( 'post_password_expires', time() + 10 * DAY_IN_SECONDS );
501
  $referer = wp_get_referer();
502
- if ( $referer ) {
503
- $secure = ( 'https' === parse_url( $referer, PHP_URL_SCHEME ) );
504
  } else {
505
  $secure = false;
506
  }
507
- setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure );
508
 
509
- if ( $switched_locale ) {
510
- restore_previous_locale();
511
  }
512
-
513
- wp_safe_redirect( wp_get_referer() );
514
- exit();
515
-
516
- case 'logout' :
517
- check_admin_referer('log-out');
518
 
519
- $user = wp_get_current_user();
520
 
521
- wp_logout();
522
 
523
- if ( ! empty( $_REQUEST['redirect_to'] ) ) {
524
- $redirect_to = $requested_redirect_to = $_REQUEST['redirect_to'];
525
- } else {
526
- $redirect_to = 'wp-login.php?loggedout=true';
527
- $requested_redirect_to = '';
528
- }
529
 
530
- if ( $switched_locale ) {
531
- restore_previous_locale();
532
  }
533
-
534
- /**
535
- * Filter the log out redirect URL.
536
- *
537
- * @since 4.2.0
538
- *
539
- * @param string $redirect_to The redirect destination URL.
540
- * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
541
- * @param WP_User $user The WP_User object for the user that's logging out.
542
- */
543
- $redirect_to = apply_filters( 'logout_redirect', $redirect_to, $requested_redirect_to, $user );
544
- wp_safe_redirect( $redirect_to );
545
- exit();
546
-
547
- case 'lostpassword' :
548
- case 'retrievepassword' :
549
-
550
- if ( $http_post ) {
551
- $errors = retrieve_password();
552
- if ( !is_wp_error($errors) ) {
553
- $redirect_to = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
554
- wp_safe_redirect( $redirect_to );
555
- exit();
556
- }
557
- }
558
-
559
- if ( isset( $_GET['error'] ) ) {
560
- if ( 'invalidkey' == $_GET['error'] ) {
561
- $errors->add( 'invalidkey', __( 'Your password reset link appears to be invalid. Please request a new link below.' ) );
562
- } elseif ( 'expiredkey' == $_GET['error'] ) {
563
- $errors->add( 'expiredkey', __( 'Your password reset link has expired. Please request a new link below.' ) );
564
- }
565
- }
566
-
567
- $lostpassword_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
568
- /**
569
- * Filter the URL redirected to after submitting the lostpassword/retrievepassword form.
570
- *
571
- * @since 3.0.0
572
- *
573
- * @param string $lostpassword_redirect The redirect destination URL.
574
- */
575
- $redirect_to = apply_filters( 'lostpassword_redirect', $lostpassword_redirect );
576
-
577
- /**
578
- * Fires before the lost password form.
579
- *
580
- * @since 1.5.1
581
- */
582
- do_action( 'lost_password' );
583
-
584
- login_header(__('Lost Password' ), '<p class="message">' . __('Please enter your username or email address. You will receive a link to create a new password via email.' ) . '</p>', $errors);
585
 
586
  $user_login = '';
587
 
588
- if ( isset( $_POST['user_login'] ) && is_string( $_POST['user_login'] ) ) {
589
- $user_login = wp_unslash( $_POST['user_login'] );
590
- }
591
-
592
- ?>
593
-
594
- <form name="lostpasswordform" id="lostpasswordform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=lostpassword', 'login_post' ) ); ?>" method="post">
595
- <p>
596
- <label for="user_login" ><?php _e('Username or Email Address'); ?><br />
597
- <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr($user_login); ?>" size="20" /></label>
598
- </p>
599
- <?php
600
- /**
601
- * Fires inside the lostpassword form tags, before the hidden fields.
602
- *
603
- * @since 2.1.0
604
- */
605
- do_action( 'lostpassword_form' ); ?>
606
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
607
- <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Get New Password'); ?>" /></p>
608
- </form>
609
-
610
- <p id="nav">
611
- <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e('Log in') ?></a>
612
- <?php
613
- if ( get_option( 'users_can_register' ) ) :
614
- $registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
615
-
616
- echo esc_html( $login_link_separator );
617
-
618
- /** This filter is documented in wp-includes/general-template.php */
619
- echo apply_filters( 'register', $registration_url );
620
- endif;
621
- ?>
622
- </p>
623
-
624
- <?php
625
- login_footer('user_login');
626
-
627
- if ( $switched_locale ) {
628
- restore_previous_locale();
629
- }
630
-
631
- break;
632
-
633
- case 'resetpass' :
634
- case 'rp' :
635
- list( $rp_path ) = explode( '?', wp_unslash( $_SERVER['REQUEST_URI'] ) );
636
- $rp_cookie = 'wp-resetpass-' . COOKIEHASH;
637
- if ( isset( $_GET['key'] ) ) {
638
- $value = sprintf( '%s:%s', wp_unslash( $_GET['login'] ), wp_unslash( $_GET['key'] ) );
639
- setcookie( $rp_cookie, $value, 0, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
640
- wp_safe_redirect( remove_query_arg( array( 'key', 'login' ) ) );
641
- exit;
642
- }
643
-
644
- if ( isset( $_COOKIE[ $rp_cookie ] ) && 0 < strpos( $_COOKIE[ $rp_cookie ], ':' ) ) {
645
- list( $rp_login, $rp_key ) = explode( ':', wp_unslash( $_COOKIE[ $rp_cookie ] ), 2 );
646
- $user = check_password_reset_key( $rp_key, $rp_login );
647
- if ( isset( $_POST['pass1'] ) && ! hash_equals( $rp_key, $_POST['rp_key'] ) ) {
648
- $user = false;
649
- }
650
- } else {
651
- $user = false;
652
- }
653
-
654
- if ( ! $user || is_wp_error( $user ) ) {
655
- setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
656
- if ( $user && $user->get_error_code() === 'expired_key' )
657
- wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=expiredkey' ) );
658
- else
659
- wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=invalidkey' ) );
660
- exit;
661
- }
662
-
663
- $errors = new WP_Error();
664
-
665
- if ( isset($_POST['pass1']) && $_POST['pass1'] != $_POST['pass2'] )
666
- $errors->add( 'password_reset_mismatch', __( 'The passwords do not match.' ) );
667
-
668
- /**
669
- * Fires before the password reset procedure is validated.
670
- *
671
- * @since 3.5.0
672
- *
673
- * @param object $errors WP Error object.
674
- * @param WP_User|WP_Error $user WP_User object if the login and reset key match. WP_Error object otherwise.
675
- */
676
- do_action( 'validate_password_reset', $errors, $user );
677
-
678
- if ( ( ! $errors->get_error_code() ) && isset( $_POST['pass1'] ) && !empty( $_POST['pass1'] ) ) {
679
- reset_password($user, $_POST['pass1']);
680
- setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
681
- login_header( __( 'Password Reset' ), '<p class="message reset-pass">' . __( 'Your password has been reset.' ) . ' <a href="' . esc_url( wp_login_url() ) . '">' . __( 'Log in' ) . '</a></p>' );
682
- login_footer();
683
- exit;
684
- }
685
-
686
- wp_enqueue_script('utils');
687
- wp_enqueue_script('user-profile');
688
-
689
- login_header(__('Reset Password' ), '<p class="message reset-pass">' . __('Enter your new password below.' ) . '</p>', $errors );
690
-
691
- ?>
692
- <form name="resetpassform" id="resetpassform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=resetpass', 'login_post' ) ); ?>" method="post" autocomplete="off">
693
- <input type="hidden" id="user_login" value="<?php echo esc_attr( $rp_login ); ?>" autocomplete="off" />
694
-
695
- <div class="user-pass1-wrap">
696
- <p>
697
- <label for="pass1"><?php _e( 'New password' ) ?></label>
698
- </p>
699
-
700
- <div class="wp-pwd">
701
- <div class="password-input-wrapper">
702
- <input type="password" data-reveal="1" data-pw="<?php echo esc_attr( wp_generate_password( 16 ) ); ?>" name="pass1" id="pass1" class="input password-input" size="24" value="" autocomplete="off" aria-describedby="pass-strength-result" />
703
- <span class="button button-secondary wp-hide-pw hide-if-no-js">
704
- <span class="dashicons dashicons-hidden"></span>
705
- </span>
706
- </div>
707
- <div id="pass-strength-result" class="hide-if-no-js" aria-live="polite"><?php _e( 'Strength indicator' ); ?></div>
708
- </div>
709
- <div class="pw-weak">
710
- <label>
711
- <input type="checkbox" name="pw_weak" class="pw-checkbox" />
712
- <?php _e( 'Confirm use of weak password' ); ?>
713
- </label>
714
- </div>
715
- </div>
716
- <p class="user-pass2-wrap">
717
- <label for="pass2"><?php _e('Confirm new password') ?></label><br />
718
- <input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off" />
719
- </p>
720
-
721
- <p class="description indicator-hint"><?php echo wp_get_password_hint(); ?></p>
722
- <br class="clear" />
723
-
724
- <?php
725
- /**
726
- * Fires following the 'Strength indicator' meter in the user password reset form.
727
- *
728
- * @since 3.9.0
729
- *
730
- * @param WP_User $user User object of the user whose password is being reset.
731
- */
732
- do_action( 'resetpass_form', $user );
733
- ?>
734
- <input type="hidden" name="rp_key" value="<?php echo esc_attr( $rp_key ); ?>" />
735
- <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Reset Password'); ?>" /></p>
736
- </form>
737
-
738
- <p id="nav">
739
- <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
740
- <?php
741
- if ( get_option( 'users_can_register' ) ) :
742
- $registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
743
-
744
- echo esc_html( $login_link_separator );
745
-
746
- /** This filter is documented in wp-includes/general-template.php */
747
- echo apply_filters( 'register', $registration_url );
748
- endif;
749
- ?>
750
- </p>
751
-
752
- <?php
753
- login_footer('user_pass');
754
-
755
- if ( $switched_locale ) {
756
- restore_previous_locale();
757
- }
758
-
759
- break;
760
-
761
- case 'register' :
762
- if ( is_multisite() ) {
763
- /**
764
- * Filter the Multisite sign up URL.
765
- *
766
- * @since 3.0.0
767
- *
768
- * @param string $sign_up_url The sign up URL.
769
- */
770
- wp_redirect( apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) ) );
771
- exit;
772
- }
773
-
774
- if ( !get_option('users_can_register') ) {
775
- wp_redirect( site_url('wp-login.php?registration=disabled') );
776
- exit();
777
- }
778
-
779
- $user_login = '';
780
- $user_email = '';
781
- if ( $http_post ) {
782
- if ( isset( $_POST['user_login'] ) && is_string( $_POST['user_login'] ) ) {
783
- $user_login = $_POST['user_login'];
784
- }
785
-
786
- if ( isset( $_POST['user_email'] ) && is_string( $_POST['user_email'] ) ) {
787
- $user_email = wp_unslash( $_POST['user_email'] );
788
- }
789
-
790
- $errors = register_new_user($user_login, $user_email);
791
- if ( !is_wp_error($errors) ) {
792
- $redirect_to = !empty( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : 'wp-login.php?checkemail=registered';
793
- wp_safe_redirect( $redirect_to );
794
- exit();
795
- }
796
- }
797
-
798
- $registration_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
799
- /**
800
- * Filter the registration redirect URL.
801
- *
802
- * @since 3.0.0
803
- *
804
- * @param string $registration_redirect The redirect destination URL.
805
- */
806
- $redirect_to = apply_filters( 'registration_redirect', $registration_redirect );
807
- login_header(__('Registration Form' ), '<p class="message register">' . __('Register For This Site' ) . '</p>', $errors);
808
- ?>
809
-
810
- <form name="registerform" id="registerform" action="<?php echo esc_url( site_url( 'wp-login.php?action=register', 'login_post' ) ); ?>" method="post" novalidate="novalidate">
811
- <p>
812
- <label for="user_login"><?php _e('Username') ?><br />
813
- <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr(wp_unslash($user_login)); ?>" size="20" /></label>
814
- </p>
815
- <p>
816
- <label for="user_email"><?php _e('Email') ?><br />
817
- <input type="email" name="user_email" id="user_email" class="input" value="<?php echo esc_attr( wp_unslash( $user_email ) ); ?>" size="25" /></label>
818
- </p>
819
- <?php
820
- /**
821
- * Fires following the 'Email' field in the user registration form.
822
- *
823
- * @since 2.1.0
824
- */
825
- do_action( 'register_form' );
826
- ?>
827
- <p id="reg_passmail"><?php _e( 'Registration confirmation will be emailed to you.' ); ?></p>
828
- <br class="clear" />
829
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
830
- <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Register'); ?>" /></p>
831
- </form>
832
-
833
- <p id="nav">
834
- <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
835
- <?php echo esc_html( $login_link_separator ); ?>
836
- <a href="<?php echo esc_url( wp_lostpassword_url() ); ?>"><?php _e( 'Lost your password?' ); ?></a>
837
- </p>
838
-
839
- <?php
840
- login_footer('user_login');
841
-
842
- if ( $switched_locale ) {
843
- restore_previous_locale();
844
- }
845
-
846
- break;
847
-
848
- case 'confirmaction' :
849
- if ( ! isset( $_GET['request_id'] ) ) {
850
- wp_die( __( 'Invalid request.' ) );
851
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
852
 
853
- $request_id = (int) $_GET['request_id'];
854
 
855
- if ( isset( $_GET['confirm_key'] ) ) {
856
- $key = sanitize_text_field( wp_unslash( $_GET['confirm_key'] ) );
857
- $result = wp_validate_user_request_key( $request_id, $key );
858
- } else {
859
- $result = new WP_Error( 'invalid_key', __( 'Invalid key' ) );
860
- }
861
 
862
- if ( is_wp_error( $result ) ) {
863
- wp_die( $result );
864
- }
865
-
866
- /**
867
- * Fires an action hook when the account action has been confirmed by the user.
868
- *
869
- * Using this you can assume the user has agreed to perform the action by
870
- * clicking on the link in the confirmation email.
871
- *
872
- * After firing this action hook the page will redirect to wp-login a callback
873
- * redirects or exits first.
874
- *
875
- * @param int $request_id Request ID.
876
- */
877
- do_action( 'user_request_action_confirmed', $request_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
878
 
879
- $message = _wp_privacy_account_request_confirmed_message( $request_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
880
 
881
- login_header( __( 'User action confirmed.' ), $message );
882
- login_footer();
883
- exit;
 
884
 
885
- case 'login' :
886
- default:
887
- $secure_cookie = '';
888
- $customize_login = isset( $_REQUEST['customize-login'] );
889
- if ( $customize_login )
890
- wp_enqueue_script( 'customize-base' );
891
 
892
- // If the user wants ssl but the session is not ssl, force a secure cookie.
893
- if ( !empty($_POST['log']) && !force_ssl_admin() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894
  $user_name = sanitize_user($_POST['log']);
895
- $user = get_user_by( 'login', $user_name );
896
 
897
- if ( ! $user && strpos( $user_name, '@' ) ) {
898
- $user = get_user_by( 'email', $user_name );
899
  }
900
 
901
- if ( $user ) {
902
- if ( get_user_option('use_ssl', $user->ID) ) {
903
  $secure_cookie = true;
904
  force_ssl_admin(true);
905
  }
906
  }
907
  }
908
 
909
- if ( isset( $_REQUEST['redirect_to'] ) ) {
910
- $redirect_to = $_REQUEST['redirect_to'];
911
- // Redirect to https if user wants ssl
912
- if ( $secure_cookie && false !== strpos($redirect_to, 'wp-admin') )
913
- $redirect_to = preg_replace('|^http://|', 'https://', $redirect_to);
914
- } else {
915
- $redirect_to = admin_url();
916
- }
917
-
918
- $reauth = empty($_REQUEST['reauth']) ? false : true;
919
-
920
- $user = wp_signon( array(), $secure_cookie );
921
-
922
- if ( empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
923
- if ( headers_sent() ) {
924
- /* translators: 1: Browser cookie documentation URL, 2: Support forums URL */
925
- $user = new WP_Error( 'test_cookie', sprintf( __( '<strong>ERROR</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.' ),
926
- __( 'https://codex.wordpress.org/Cookies' ), __( 'https://wordpress.org/support/' ) ) );
927
- } elseif ( isset( $_POST['testcookie'] ) && empty( $_COOKIE[ TEST_COOKIE ] ) ) {
928
- // If cookies are disabled we can't log in even with a valid user+pass
929
- /* translators: 1: Browser cookie documentation URL */
930
- $user = new WP_Error( 'test_cookie', sprintf( __( '<strong>ERROR</strong>: Cookies are blocked or not supported by your browser. You must <a href="%s">enable cookies</a> to use WordPress.' ),
931
- __( 'https://codex.wordpress.org/Cookies' ) ) );
932
- }
933
- }
934
-
935
- $requested_redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
936
- /**
937
- * Filter the login redirect URL.
938
- *
939
- * @since 3.0.0
940
- *
941
- * @param string $redirect_to The redirect destination URL.
942
- * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
943
- * @param WP_User|WP_Error $user WP_User object if login was successful, WP_Error object otherwise.
944
- */
945
- $redirect_to = apply_filters( 'login_redirect', $redirect_to, $requested_redirect_to, $user );
946
-
947
- if ( !is_wp_error($user) && !$reauth ) {
948
- if ( $interim_login ) {
949
- $message = '<p class="message">' . __('You have logged in successfully.' ) . '</p>';
950
- $interim_login = 'success';
951
- login_header( '', $message ); ?>
952
  </div>
953
  <?php
954
- /** This action is documented in wp-login.php */
955
- do_action( 'login_footer' ); ?>
956
- <?php if ( $customize_login ) : ?>
957
- <script type="text/javascript">setTimeout( function(){ new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); ?>', channel: 'login' }).send('login') }, 1000 );</script>
958
- <?php endif; ?>
959
  </body></html>
960
  <?php exit;
961
- }
962
-
963
- if ( ( empty( $redirect_to ) || $redirect_to == 'wp-admin/' || $redirect_to == admin_url() ) ) {
964
- // If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
965
- if ( is_multisite() && !get_active_blog_for_user($user->ID) && !is_super_admin( $user->ID ) )
966
- $redirect_to = user_admin_url();
967
- elseif ( is_multisite() && !$user->has_cap('read') )
968
- $redirect_to = get_dashboard_url( $user->ID );
969
- elseif ( !$user->has_cap('edit_posts') )
970
- $redirect_to = $user->has_cap( 'read' ) ? admin_url( 'profile.php' ) : home_url();
971
-
972
- wp_redirect( $redirect_to );
973
- exit();
974
- }
975
- wp_safe_redirect($redirect_to);
976
- exit();
977
- }
978
-
979
- $errors = $user;
980
- // Clear errors if loggedout is set.
981
- if ( !empty($_GET['loggedout']) || $reauth )
982
- $errors = new WP_Error();
983
-
984
- if ( $interim_login ) {
985
- if ( ! $errors->get_error_code() )
986
- $errors->add('expired', __('Your session has expired. Please log in to continue where you left off.' ), 'message');
987
- } else {
988
- // Some parts of this script use the main login form to display a message
989
- if ( isset($_GET['loggedout']) && true == $_GET['loggedout'] )
990
- $errors->add('loggedout', __('You are now logged out.' ), 'message');
991
- elseif ( isset($_GET['registration']) && 'disabled' == $_GET['registration'] )
992
- $errors->add('registerdisabled', __('User registration is currently not allowed.' ));
993
- elseif ( isset($_GET['checkemail']) && 'confirm' == $_GET['checkemail'] )
994
- $errors->add('confirm', __('Check your email for the confirmation link.' ), 'message');
995
- elseif ( isset($_GET['checkemail']) && 'newpass' == $_GET['checkemail'] )
996
- $errors->add('newpass', __('Check your email for your new password.' ), 'message');
997
- elseif ( isset($_GET['checkemail']) && 'registered' == $_GET['checkemail'] )
998
- $errors->add('registered', __('Registration complete. Please check your email.' ), 'message');
999
- elseif ( strpos( $redirect_to, 'about.php?updated' ) )
1000
- $errors->add('updated', __( '<strong>You have successfully updated WordPress!</strong> Please log back in to see what&#8217;s new.' ), 'message' );
1001
- }
1002
-
1003
- /**
1004
- * Filter the login page errors.
1005
- *
1006
- * @since 3.6.0
1007
- *
1008
- * @param object $errors WP Error object.
1009
- * @param string $redirect_to Redirect destination URL.
1010
- */
1011
- $errors = apply_filters( 'wp_login_errors', $errors, $redirect_to );
1012
-
1013
- // Clear any stale cookies.
1014
- if ( $reauth )
1015
- wp_clear_auth_cookie();
1016
-
1017
- login_header(__('Log In' ), '', $errors);
1018
-
1019
- if ( isset($_POST['log']) )
1020
- $user_login = ( 'incorrect_password' == $errors->get_error_code() || 'empty_password' == $errors->get_error_code() ) ? esc_attr(wp_unslash($_POST['log'])) : '';
1021
- $rememberme = ! empty( $_POST['rememberme'] );
1022
-
1023
- if ( ! empty( $errors->errors ) ) {
1024
- $aria_describedby_error = ' aria-describedby="login_error"';
1025
- } else {
1026
- $aria_describedby_error = '';
1027
- }
1028
-
1029
- //aiowps - this check is necessary because otherwise if variables are undefined we get a warning!
1030
- if(empty($user_login)){
1031
  $user_login = '';
1032
- }
1033
- if(empty($error)){
 
1034
  $error = '';
1035
- }
1036
- ?>
1037
 
1038
- <form name="loginform" id="loginform" action="<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ); ?>" method="post">
1039
  <p>
1040
  <label for="user_login"><?php _e('Username or Email Address'); ?><br />
1041
- <input type="text" name="log" id="user_login"<?php echo $aria_describedby_error; ?> class="input" value="<?php echo esc_attr( $user_login ); ?>" size="20" /></label>
1042
  </p>
1043
  <p>
1044
  <label for="user_pass"><?php _e('Password'); ?><br />
1045
  <input type="password" name="pwd" id="user_pass"<?php echo $aria_describedby_error; ?> class="input" value="" size="20" /></label>
1046
  </p>
1047
  <?php
1048
- /**
1049
- * Fires following the 'Password' field in the login form.
1050
- *
1051
- * @since 2.1.0
1052
- */
1053
- do_action( 'login_form' );
1054
- ?>
1055
- <p class="forgetmenot"><label for="rememberme"><input name="rememberme" type="checkbox" id="rememberme" value="forever" <?php checked( $rememberme ); ?> /> <?php esc_html_e('Remember Me'); ?></label></p>
1056
  <p class="submit">
1057
  <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Log In'); ?>" />
1058
- <?php if ( $interim_login ) { ?>
1059
- <input type="hidden" name="interim-login" value="1" />
1060
- <?php } else { ?>
1061
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
1062
- <?php } ?>
1063
- <?php if ( $customize_login ) : ?>
1064
- <input type="hidden" name="customize-login" value="1" />
1065
- <?php endif; ?>
1066
  <input type="hidden" name="testcookie" value="1" />
1067
  </p>
1068
  </form>
1069
 
1070
- <?php if ( ! $interim_login ) { ?>
1071
- <p id="nav">
1072
- <?php if ( ! isset( $_GET['checkemail'] ) || ! in_array( $_GET['checkemail'], array( 'confirm', 'newpass' ) ) ) :
1073
- if ( get_option( 'users_can_register' ) ) :
1074
- $registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
1075
 
1076
- /** This filter is documented in wp-includes/general-template.php */
1077
- echo apply_filters( 'register', $registration_url );
1078
 
1079
- echo esc_html( $login_link_separator );
1080
- endif;
1081
- ?>
1082
- <a href="<?php echo esc_url( wp_lostpassword_url() ); ?>"><?php _e( 'Lost your password?' ); ?></a>
1083
- <?php endif; ?>
1084
- </p>
1085
- <?php } ?>
1086
 
1087
  <script type="text/javascript">
1088
- function wp_attempt_focus(){
1089
- setTimeout( function(){ try{
1090
- <?php if ( $user_login ) { ?>
1091
- d = document.getElementById('user_pass');
1092
- d.value = '';
1093
- <?php } else { ?>
1094
- d = document.getElementById('user_login');
1095
- <?php if ( 'invalid_username' == $errors->get_error_code() ) { ?>
1096
- if( d.value != '' )
1097
- d.value = '';
1098
- <?php
1099
- }
1100
- }?>
1101
  d.focus();
1102
  d.select();
1103
- } catch(e){}
1104
  }, 200);
1105
  }
1106
 
@@ -1112,29 +1108,28 @@ d.select();
1112
  *
1113
  * @param bool $print Whether to print the function call. Default true.
1114
  */
1115
- if ( apply_filters( 'enable_login_autofocus', true ) && ! $error ) { ?>
1116
  wp_attempt_focus();
1117
  <?php } ?>
1118
- if(typeof wpOnload=='function')wpOnload();
1119
- <?php if ( $interim_login ) { ?>
1120
- (function(){
1121
- try {
1122
- var i, links = document.getElementsByTagName('a');
1123
- for ( i in links ) {
1124
- if ( links[i].href )
1125
- links[i].target = '_blank';
1126
- }
1127
- } catch(e){}
1128
- }());
1129
- <?php } ?>
1130
  </script>
1131
 
1132
  <?php
1133
- login_footer();
1134
 
1135
- if ( $switched_locale ) {
1136
- restore_previous_locale();
1137
- }
1138
-
1139
- break;
1140
  } // end action switch
1
  <?php
2
+ // phpcs:disable PEAR.WhiteSpace.ScopeClosingBrace.Indent,Squiz.WhiteSpace.ScopeClosingBrace.Indent,Squiz.PHP.EmbeddedPhp.ContentBeforeEnd,Squiz.PHP.EmbeddedPhp.SpacingAfterOpen -- Specifically disabled these as I feel the PHP tag indentation is fine and would make the code unreadable.
3
  /**
4
  * WordPress User Page
5
  *
11
 
12
 
13
  // Redirect to https login if forced to use SSL
14
+ if (force_ssl_admin() && ! is_ssl()) {
15
+ if (0 === strpos($_SERVER['REQUEST_URI'], 'http')) {
16
+ wp_safe_redirect(set_url_scheme($_SERVER['REQUEST_URI'], 'https'));
17
+ exit();
18
+ } else {
19
+ wp_safe_redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
20
+ exit();
21
+ }
22
  }
23
 
24
  /**
29
  * @param string $message Optional. Message to display in header. Default empty.
30
  * @param WP_Error $wp_error Optional. The error to pass. Default empty.
31
  */
32
+ function login_header($title = 'Log In', $message = '', $wp_error = '') {
33
  global $error, $interim_login, $action;
34
 
35
  // Don't index any of these forms
36
+ add_action('login_head', 'wp_no_robots');
37
 
38
+ add_action('login_head', 'wp_login_viewport_meta');
39
 
40
+ if (empty($wp_error))
41
+ $wp_error = new WP_Error();
42
 
43
  // Shake it!
44
+ $shake_error_codes = array('empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password');
45
  /**
46
  * Filter the error codes array for shaking the login form.
47
  *
49
  *
50
  * @param array $shake_error_codes Error codes that shake the login form.
51
  */
52
+ $shake_error_codes = apply_filters('shake_error_codes', $shake_error_codes);
53
 
54
+ if ($shake_error_codes && $wp_error->get_error_code() && in_array($wp_error->get_error_code(), $shake_error_codes))
55
+ add_action('login_head', 'wp_shake_js', 12);
56
 
57
+ $login_title = get_bloginfo('name', 'display');
58
 
59
  /* translators: Login screen title. 1: Login screen name, 2: Network or site name */
60
+ $login_title = sprintf(__('%1$s &lsaquo; %2$s &#8212; WordPress'), $title, $login_title);
61
 
62
  /**
63
  * Filters the title tag content for login page.
67
  * @param string $login_title The page title, with extra context added.
68
  * @param string $title The original page title.
69
  */
70
+ $login_title = apply_filters('login_title', $login_title, $title);
71
 
72
  ?><!DOCTYPE html>
73
  <!--[if IE 8]>
74
  <html xmlns="http://www.w3.org/1999/xhtml" class="ie8" <?php language_attributes(); ?>>
75
  <![endif]-->
76
+ <!--[if !(IE 8)]><!-->
77
  <html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
78
  <!--<![endif]-->
79
  <head>
80
+ <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
81
+ <title><?php echo $login_title; ?></title>
82
+ <?php
83
+
84
+ wp_enqueue_style('login');
85
+
86
+ /*
87
+ * Remove all stored post data on logging out.
88
+ * This could be added by add_action('login_head'...) like wp_shake_js(),
89
+ * but maybe better if it's not removable by plugins
90
+ */
91
+ if ('loggedout' == $wp_error->get_error_code()) {
92
+ ?>
93
+ <script>if ("sessionStorage" in window) {try{for(var key in sessionStorage) {if (key.indexOf("wp-autosave-")!=-1) {sessionStorage.removeItem(key)}}}catch(e) {}};</script>
94
+ <?php
95
+ }
96
+
97
+ /**
98
+ * Enqueue scripts and styles for the login page.
99
+ *
100
+ * @since 3.1.0
101
+ */
102
+ do_action('login_enqueue_scripts');
103
+
104
+ /**
105
+ * Fires in the login page header after scripts are enqueued.
106
+ *
107
+ * @since 2.1.0
108
+ */
109
+ do_action('login_head');
110
+
111
+ if (is_multisite()) {
112
+ $login_header_url = network_home_url();
113
+ $login_header_title = get_network()->site_name;
114
+ } else {
115
+ $login_header_url = __('https://wordpress.org/');
116
+ $login_header_title = __('Powered by WordPress');
117
+ }
118
+
119
+ /**
120
+ * Filter link URL of the header logo above login form.
121
+ *
122
+ * @since 2.1.0
123
+ *
124
+ * @param string $login_header_url Login header logo URL.
125
+ */
126
+ $login_header_url = apply_filters('login_headerurl', $login_header_url);
127
+
128
+ /**
129
+ * Filter the title attribute of the header logo above login form.
130
+ *
131
+ * @since 2.1.0
132
+ *
133
+ * @param string $login_header_title Login header logo title attribute.
134
+ */
135
+ $login_header_title = apply_filters('login_headertitle', $login_header_title);
136
+
137
+ /*
138
+ * To match the URL/title set above, Multisite sites have the blog name,
139
+ * while single sites get the header title.
140
+ */
141
+ if (is_multisite()) {
142
+ $login_header_text = get_bloginfo('name', 'display');
143
+ } else {
144
+ $login_header_text = $login_header_title;
145
+ }
146
+
147
+ $classes = array('login-action-' . $action, 'wp-core-ui');
148
+ if (is_rtl())
149
+ $classes[] = 'rtl';
150
+ if ($interim_login) {
151
+ $classes[] = 'interim-login';
152
+ ?>
153
+ <style type="text/css">html{background-color: transparent;}</style>
154
+ <?php
155
+
156
+ if ('success' === $interim_login)
157
+ $classes[] = 'interim-login-success';
158
+ }
159
+ $classes[] =' locale-' . sanitize_html_class(strtolower(str_replace('_', '-', get_locale())));
160
+
161
+ /**
162
+ * Filter the login page body classes.
163
+ *
164
+ * @since 3.5.0
165
+ *
166
+ * @param array $classes An array of body classes.
167
+ * @param string $action The action that brought the visitor to the login page.
168
+ */
169
+ $classes = apply_filters('login_body_class', $classes, $action);
170
+ ?>
 
171
  </head>
172
+ <body class="login <?php echo esc_attr(implode(' ', $classes)); ?>">
173
  <?php
174
  /**
175
  * Fires in the login page header after the body tag is opened.
176
  *
177
  * @since 4.6.0
178
  */
179
+ do_action('login_header');
180
  ?>
181
  <div id="login">
182
+ <h1><a href="<?php echo esc_url($login_header_url); ?>" title="<?php echo esc_attr($login_header_title); ?>" tabindex="-1"><?php echo $login_header_text; ?></a></h1>
183
+ <?php
184
+
185
+ unset($login_header_url, $login_header_title);
186
+
187
+ /**
188
+ * Filter the message to display above the login form.
189
+ *
190
+ * @since 2.1.0
191
+ *
192
+ * @param string $message Login message text.
193
+ */
194
+
195
+ $message = apply_filters('login_message', $message);
196
+ if (!empty($message))
197
+ echo $message . "\n";
198
+
199
+ // In case a plugin uses $error rather than the $wp_errors object
200
+ if (!empty($error)) {
201
+ $wp_error->add('error', $error);
202
+ unset($error);
203
+ }
204
+
205
+ if ($wp_error->get_error_code()) {
206
+ $errors = '';
207
+ $messages = '';
208
+ foreach ($wp_error->get_error_codes() as $code) {
209
+ $severity = $wp_error->get_error_data($code);
210
+ foreach ($wp_error->get_error_messages($code) as $error_message) {
211
+ if ('message' == $severity) {
212
+ $messages .= ' ' . $error_message . "<br />\n";
213
+ } else {
214
+ $errors .= ' ' . $error_message . "<br />\n";
215
+ }
216
+ }
217
+ }
218
+ if (! empty($errors)) {
219
+ /**
220
+ * Filter the error messages displayed above the login form.
221
+ *
222
+ * @since 2.1.0
223
+ *
224
+ * @param string $errors Login error message.
225
+ */
226
+ echo '<div id="login_error">' . apply_filters('login_errors', $errors) . "</div>\n";
227
+ }
228
+ if (! empty($messages)) {
229
+ /**
230
+ * Filter instructional messages displayed above the login form.
231
+ *
232
+ * @since 2.5.0
233
+ *
234
+ * @param string $messages Login messages.
235
+ */
236
+ echo '<p class="message">' . apply_filters('login_messages', $messages) . "</p>\n";
237
+ }
238
+ }
239
+ } // End of login_header()
240
+
241
+ /**
242
+ * Outputs the footer for the login page.
243
+ *
244
+ * @param string $input_id Which input to auto-focus
245
+ */
246
+ function login_footer($input_id = '') {
247
+ global $interim_login;
248
+
249
+ // Don't allow interim logins to navigate away from the page.
250
+ if (!$interim_login) : ?>
251
+ <p id="backtoblog"><a href="<?php echo esc_url(home_url('/')); ?>"><?php
252
  /* translators: %s: site title */
253
+ printf(_x('&larr; Back to %s', 'site'), get_bloginfo('title', 'display'));
254
  ?></a></p>
255
+ <?php
256
+ if (function_exists('the_privacy_policy_link')) {
257
+ the_privacy_policy_link('<div class="privacy-policy-page-link">', '</div>');
258
+ }
259
+ ?>
260
+ <?php endif; ?>
261
 
262
  </div>
263
 
264
+ <?php if (!empty($input_id)) : ?>
265
+ <script type="text/javascript">
266
+ try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e) {}
267
+ if (typeof wpOnload=='function')wpOnload();
268
+ </script>
269
  <?php endif; ?>
270
 
271
  <?php
274
  *
275
  * @since 3.1.0
276
  */
277
+ do_action('login_footer'); ?>
278
  <div class="clear"></div>
279
  </body>
280
  </html>
282
  }
283
 
284
  /**
285
+ * WP JS SHake script
286
+ *
287
  * @since 3.0.0
288
  */
289
  function wp_shake_js() {
290
+ ?>
291
+ <script type="text/javascript">
292
+ addLoadEvent = function(func) {if (typeof jQuery!="undefined")jQuery(document).ready(func);else if (typeof wpOnload!='function') {wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function() {oldonload();func();}}};
293
+ function s(id,pos) {g(id).left=pos+'px';}
294
+ function g(id) {return document.getElementById(id).style;}
295
+ function shake(id,a,d) {c=a.shift();s(id,c);if (a.length>0) {setTimeout(function() {shake(id,a,d);},d);}else{try{g(id).position='static';wp_attempt_focus();}catch(e) {}}}
296
+ addLoadEvent(function() { var p=new Array(15,30,15,0,-15,-30,-15,0);p=p.concat(p.concat(p));var i=document.forms[0].id;g(i).position='relative';shake(i,p,20);});
297
+ </script>
298
  <?php
299
  }
300
 
301
  /**
302
+ * WP Login Viewpoint Meta Tag
303
+ *
304
  * @since 3.7.0
305
  */
306
  function wp_login_viewport_meta() {
307
+ ?>
308
+ <meta name="viewport" content="width=device-width" />
309
  <?php
310
  }
311
 
315
  * @return bool|WP_Error True: when finish. WP_Error on error
316
  */
317
  function retrieve_password() {
318
+ $errors = new WP_Error();
319
+
320
+ if (empty($_POST['user_login']) || ! is_string($_POST['user_login'])) {
321
+ $errors->add('empty_username', __('<strong>ERROR</strong>: Enter a username or email address.'));
322
+ } elseif (strpos($_POST['user_login'], '@')) {
323
+ $user_data = get_user_by('email', trim(wp_unslash($_POST['user_login'])));
324
+ if (empty($user_data))
325
+ $errors->add('invalid_email', __('<strong>ERROR</strong>: There is no user registered with that email address.'));
326
+ } else {
327
+ $login = trim($_POST['user_login']);
328
+ $user_data = get_user_by('login', $login);
329
+ }
330
+
331
+ /**
332
+ * Fires before errors are returned from a password reset request.
333
+ *
334
+ * @since 2.1.0
335
+ * @since 4.4.0 Added the `$errors` parameter.
336
+ *
337
+ * @param WP_Error $errors A WP_Error object containing any errors generated
338
+ * by using invalid credentials.
339
+ */
340
+ do_action('lostpassword_post', $errors);
341
+
342
+ if ($errors->get_error_code())
343
+ return $errors;
344
+
345
+ if (!$user_data) {
346
+ $errors->add('invalidcombo', __('<strong>ERROR</strong>: Invalid username or email.'));
347
+ return $errors;
348
+ }
349
+
350
+ // Redefining user_login ensures we return the right case in the email.
351
+ $user_login = $user_data->user_login;
352
+ $user_email = $user_data->user_email;
353
+ $key = get_password_reset_key($user_data);
354
+
355
+ if (is_wp_error($key)) {
356
+ return $key;
357
+ }
358
+
359
+ if (is_multisite()) {
360
+ $site_name = get_network()->site_name;
361
+ } else {
362
+ /*
363
+ * The blogname option is escaped with esc_html on the way into the database
364
+ * in sanitize_option we want to reverse this for the plain text arena of emails.
365
+ */
366
+ $site_name = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
367
+ }
368
+
369
+ $message = __('Someone has requested a password reset for the following account:') . "\r\n\r\n";
370
+ /* translators: %s: site name */
371
+ $message .= sprintf(__('Site Name: %s'), $site_name) . "\r\n\r\n";
372
+ /* translators: %s: user login */
373
+ $message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n";
374
+ $message .= __('If this was a mistake, just ignore this email and nothing will happen.') . "\r\n\r\n";
375
+ $message .= __('To reset your password, visit the following address:') . "\r\n\r\n";
376
+ $message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . ">\r\n";
377
+
378
+ // translators: Password reset email subject. %s: Site name
379
+ $title = sprintf(__('[%s] Password Reset'), $site_name);
380
+
381
+ /**
382
+ * Filters the subject of the password reset email.
383
+ *
384
+ * @since 2.8.0
385
+ * @since 4.4.0 Added the `$user_login` and `$user_data` parameters.
386
+ *
387
+ * @param string $title Default email title.
388
+ * @param string $user_login The username for the user.
389
+ * @param WP_User $user_data WP_User object.
390
+ */
391
+ $title = apply_filters('retrieve_password_title', $title, $user_login, $user_data);
392
+
393
+ /**
394
+ * Filter the message body of the password reset mail.
395
+ *
396
+ * If the filtered message is empty, the password reset email will not be sent.
397
+ *
398
+ * @since 2.8.0
399
+ * @since 4.1.0 Added `$user_login` and `$user_data` parameters.
400
+ *
401
+ * @param string $message Default mail message.
402
+ * @param string $key The activation key.
403
+ * @param string $user_login The username for the user.
404
+ * @param WP_User $user_data WP_User object.
405
+ */
406
+ $message = apply_filters('retrieve_password_message', $message, $key, $user_login, $user_data);
407
+
408
+ if ($message && !wp_mail($user_email, wp_specialchars_decode($title), $message))
409
+ wp_die(__('The email could not be sent.') . "<br />\n" . __('Possible reason: your host may have disabled the mail() function.'));
410
+
411
+ return true;
412
  }
413
 
414
  //
418
  $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'login';
419
  $errors = new WP_Error();
420
 
421
+ if (isset($_GET['key']))
422
+ $action = 'resetpass';
423
 
424
  // validate action so as to default to the login screen
425
+ if (!in_array($action, array('postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login', 'confirmaction'), true) && false === has_filter('login_form_' . $action))
426
+ $action = 'login';
427
 
428
  nocache_headers();
429
 
430
  header('Content-Type: '.get_bloginfo('html_type').'; charset='.get_bloginfo('charset'));
431
 
432
+ if (defined('RELOCATE') && RELOCATE) { // Move flag is set
433
+ if (isset($_SERVER['PATH_INFO']) && ($_SERVER['PATH_INFO'] != $_SERVER['PHP_SELF']))
434
+ $_SERVER['PHP_SELF'] = str_replace($_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF']);
435
 
436
+ $url = dirname(set_url_scheme('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']));
437
+ if (get_option('siteurl') != $url)
438
+ update_option('siteurl', $url);
439
  }
440
 
441
  //Set a cookie now to see if they are supported by the browser.
442
+ $secure = ('https' === parse_url(wp_login_url(), PHP_URL_SCHEME));
443
+ setcookie(TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN, $secure);
444
+ if (SITECOOKIEPATH != COOKIEPATH)
445
+ setcookie(TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN, $secure);
446
 
447
+ $lang = ! empty($_GET['wp_lang']) ? sanitize_text_field($_GET['wp_lang']) : '';
448
  $switched_locale = false;
449
 
450
+ if (function_exists('switch_to_locale')) {
451
+ $switched_locale = switch_to_locale($lang);
452
  }
453
 
454
  /**
456
  *
457
  * @since 3.2.0
458
  */
459
+ do_action('login_init');
460
 
461
  /**
462
  * Fires before a specified login form action.
467
  *
468
  * @since 2.8.0
469
  */
470
+ do_action("login_form_{$action}");
471
 
472
  $http_post = ('POST' == $_SERVER['REQUEST_METHOD']);
473
  $interim_login = isset($_REQUEST['interim-login']);
479
  *
480
  * @param string $login_link_separator The separator used between login form navigation links.
481
  */
482
+ $login_link_separator = apply_filters('login_link_separator', ' | ');
483
 
484
  switch ($action) {
485
 
486
+ case 'postpass':
487
+ if (! array_key_exists('post_password', $_POST)) {
488
+ wp_safe_redirect(wp_get_referer());
489
  exit();
490
  }
491
+
492
+ require_once ABSPATH . WPINC . '/class-phpass.php';
493
+ $hasher = new PasswordHash(8, true);
494
+
495
+ /**
496
+ * Filter the life span of the post password cookie.
497
+ *
498
+ * By default, the cookie expires 10 days from creation. To turn this
499
+ * into a session cookie, return 0.
500
+ *
501
+ * @since 3.7.0
502
+ *
503
+ * @param int $expires The expiry time, as passed to setcookie().
504
+ */
505
+ $expire = apply_filters('post_password_expires', time() + 10 * DAY_IN_SECONDS);
506
  $referer = wp_get_referer();
507
+ if ($referer) {
508
+ $secure = ('https' === parse_url($referer, PHP_URL_SCHEME));
509
  } else {
510
  $secure = false;
511
  }
512
+ setcookie('wp-postpass_' . COOKIEHASH, $hasher->HashPassword(wp_unslash($_POST['post_password'])), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure);
513
 
514
+ if ($switched_locale) {
515
+ restore_previous_locale();
516
  }
517
+
518
+ wp_safe_redirect(wp_get_referer());
519
+ exit();
520
+ case 'logout':
521
+ check_admin_referer('log-out');
 
522
 
523
+ $user = wp_get_current_user();
524
 
525
+ wp_logout();
526
 
527
+ if (! empty($_REQUEST['redirect_to'])) {
528
+ $redirect_to = $requested_redirect_to = $_REQUEST['redirect_to'];
529
+ } else {
530
+ $redirect_to = 'wp-login.php?loggedout=true';
531
+ $requested_redirect_to = '';
532
+ }
533
 
534
+ if ($switched_locale) {
535
+ restore_previous_locale();
536
  }
537
+
538
+ /**
539
+ * Filter the log out redirect URL.
540
+ *
541
+ * @since 4.2.0
542
+ *
543
+ * @param string $redirect_to The redirect destination URL.
544
+ * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
545
+ * @param WP_User $user The WP_User object for the user that's logging out.
546
+ */
547
+ $redirect_to = apply_filters('logout_redirect', $redirect_to, $requested_redirect_to, $user);
548
+ wp_safe_redirect($redirect_to);
549
+ exit();
550
+
551
+ case 'lostpassword':
552
+ case 'retrievepassword':
553
+ if ($http_post) {
554
+ $errors = retrieve_password();
555
+ if (!is_wp_error($errors)) {
556
+ $redirect_to = !empty($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
557
+ wp_safe_redirect($redirect_to);
558
+ exit();
559
+ }
560
+ }
561
+
562
+ if (isset($_GET['error'])) {
563
+ if ('invalidkey' == $_GET['error']) {
564
+ $errors->add('invalidkey', __('Your password reset link appears to be invalid. Please request a new link below.'));
565
+ } elseif ('expiredkey' == $_GET['error']) {
566
+ $errors->add('expiredkey', __('Your password reset link has expired. Please request a new link below.'));
567
+ }
568
+ }
569
+
570
+ $lostpassword_redirect = ! empty($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : '';
571
+ /**
572
+ * Filter the URL redirected to after submitting the lostpassword/retrievepassword form.
573
+ *
574
+ * @since 3.0.0
575
+ *
576
+ * @param string $lostpassword_redirect The redirect destination URL.
577
+ */
578
+ $redirect_to = apply_filters('lostpassword_redirect', $lostpassword_redirect);
579
+
580
+ /**
581
+ * Fires before the lost password form.
582
+ *
583
+ * @since 1.5.1
584
+ */
585
+ do_action('lost_password');
586
+
587
+ login_header(__('Lost Password'), '<p class="message">' . __('Please enter your username or email address. You will receive a link to create a new password via email.') . '</p>', $errors);
 
588
 
589
  $user_login = '';
590
 
591
+ if (isset($_POST['user_login']) && is_string($_POST['user_login'])) {
592
+ $user_login = wp_unslash($_POST['user_login']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
593
  }
594
+
595
+ ?>
596
+
597
+ <form name="lostpasswordform" id="lostpasswordform" action="<?php echo esc_url(network_site_url('wp-login.php?action=lostpassword', 'login_post')); ?>" method="post">
598
+ <p>
599
+ <label for="user_login" ><?php _e('Username or Email Address'); ?><br />
600
+ <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr($user_login); ?>" size="20" /></label>
601
+ </p>
602
+ <?php
603
+ /**
604
+ * Fires inside the lostpassword form tags, before the hidden fields.
605
+ *
606
+ * @since 2.1.0
607
+ */
608
+ do_action('lostpassword_form'); ?>
609
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
610
+ <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Get New Password'); ?>" /></p>
611
+ </form>
612
+
613
+ <p id="nav">
614
+ <a href="<?php echo esc_url(wp_login_url()); ?>"><?php _e('Log in'); ?></a>
615
+ <?php
616
+ if (get_option('users_can_register')) :
617
+ $registration_url = sprintf('<a href="%s">%s</a>', esc_url(wp_registration_url()), __('Register'));
618
 
619
+ echo esc_html($login_link_separator);
620
 
621
+ // This filter is documented in wp-includes/general-template.php
622
+ echo apply_filters('register', $registration_url);
623
+ endif;
624
+ ?>
625
+ </p>
 
626
 
627
+ <?php
628
+ login_footer('user_login');
629
+
630
+ if ($switched_locale) {
631
+ restore_previous_locale();
632
+ }
633
+ break;
634
+ case 'resetpass':
635
+ case 'rp':
636
+ list($rp_path) = explode('?', wp_unslash($_SERVER['REQUEST_URI']));
637
+ $rp_cookie = 'wp-resetpass-' . COOKIEHASH;
638
+ if (isset($_GET['key'])) {
639
+ $value = sprintf('%s:%s', wp_unslash($_GET['login']), wp_unslash($_GET['key']));
640
+ setcookie($rp_cookie, $value, 0, $rp_path, COOKIE_DOMAIN, is_ssl(), true);
641
+ wp_safe_redirect(remove_query_arg(array('key', 'login')));
642
+ exit;
643
+ }
644
+
645
+ if (isset($_COOKIE[$rp_cookie]) && 0 < strpos($_COOKIE[$rp_cookie], ':')) {
646
+ list($rp_login, $rp_key) = explode(':', wp_unslash($_COOKIE[$rp_cookie]), 2);
647
+ $user = check_password_reset_key($rp_key, $rp_login);
648
+ if (isset($_POST['pass1']) && ! hash_equals($rp_key, $_POST['rp_key'])) {
649
+ $user = false;
650
+ }
651
+ } else {
652
+ $user = false;
653
+ }
654
+
655
+ if (! $user || is_wp_error($user)) {
656
+ setcookie($rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true);
657
+ if ($user && $user->get_error_code() === 'expired_key') {
658
+ wp_redirect(site_url('wp-login.php?action=lostpassword&error=expiredkey'));
659
+ } else {
660
+ wp_redirect(site_url('wp-login.php?action=lostpassword&error=invalidkey'));
661
+ }
662
+ exit;
663
+ }
664
+
665
+ $errors = new WP_Error();
666
+
667
+ if (isset($_POST['pass1']) && $_POST['pass1'] != $_POST['pass2'])
668
+ $errors->add('password_reset_mismatch', __('The passwords do not match.'));
669
+
670
+ /**
671
+ * Fires before the password reset procedure is validated.
672
+ *
673
+ * @since 3.5.0
674
+ *
675
+ * @param object $errors WP Error object.
676
+ * @param WP_User|WP_Error $user WP_User object if the login and reset key match. WP_Error object otherwise.
677
+ */
678
+ do_action('validate_password_reset', $errors, $user);
679
+
680
+ if ((! $errors->get_error_code()) && isset($_POST['pass1']) && !empty($_POST['pass1'])) {
681
+ reset_password($user, $_POST['pass1']);
682
+ setcookie($rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true);
683
+ login_header(__('Password Reset'), '<p class="message reset-pass">' . __('Your password has been reset.') . ' <a href="' . esc_url(wp_login_url()) . '">' . __('Log in') . '</a></p>');
684
+ login_footer();
685
+ exit;
686
+ }
687
+
688
+ wp_enqueue_script('utils');
689
+ wp_enqueue_script('user-profile');
690
+
691
+ login_header(__('Reset Password'), '<p class="message reset-pass">' . __('Enter your new password below.') . '</p>', $errors);
692
+ ?>
693
+ <form name="resetpassform" id="resetpassform" action="<?php echo esc_url(network_site_url('wp-login.php?action=resetpass', 'login_post')); ?>" method="post" autocomplete="off">
694
+ <input type="hidden" id="user_login" value="<?php echo esc_attr($rp_login); ?>" autocomplete="off" />
695
+
696
+ <div class="user-pass1-wrap">
697
+ <p>
698
+ <label for="pass1"><?php _e('New password'); ?></label>
699
+ </p>
700
+
701
+ <div class="wp-pwd">
702
+ <div class="password-input-wrapper">
703
+ <input type="password" data-reveal="1" data-pw="<?php echo esc_attr(wp_generate_password(16)); ?>" name="pass1" id="pass1" class="input password-input" size="24" value="" autocomplete="off" aria-describedby="pass-strength-result" />
704
+ <span class="button button-secondary wp-hide-pw hide-if-no-js">
705
+ <span class="dashicons dashicons-hidden"></span>
706
+ </span>
707
+ </div>
708
+ <div id="pass-strength-result" class="hide-if-no-js" aria-live="polite"><?php _e('Strength indicator'); ?></div>
709
+ </div>
710
+ <div class="pw-weak">
711
+ <label>
712
+ <input type="checkbox" name="pw_weak" class="pw-checkbox" />
713
+ <?php _e('Confirm use of weak password'); ?>
714
+ </label>
715
+ </div>
716
+ </div>
717
+ <p class="user-pass2-wrap">
718
+ <label for="pass2"><?php _e('Confirm new password'); ?></label><br />
719
+ <input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off" />
720
+ </p>
721
+
722
+ <p class="description indicator-hint"><?php echo wp_get_password_hint(); ?></p>
723
+ <br class="clear" />
724
+
725
+ <?php
726
+ /**
727
+ * Fires following the 'Strength indicator' meter in the user password reset form.
728
+ *
729
+ * @since 3.9.0
730
+ *
731
+ * @param WP_User $user User object of the user whose password is being reset.
732
+ */
733
+ do_action('resetpass_form', $user);
734
+ ?>
735
+ <input type="hidden" name="rp_key" value="<?php echo esc_attr($rp_key); ?>" />
736
+ <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Reset Password'); ?>" /></p>
737
+ </form>
738
+
739
+ <p id="nav">
740
+ <a href="<?php echo esc_url(wp_login_url()); ?>"><?php _e('Log in'); ?></a>
741
+ <?php
742
+ if (get_option('users_can_register')) :
743
+ $registration_url = sprintf('<a href="%s">%s</a>', esc_url(wp_registration_url()), __('Register'));
744
+
745
+ echo esc_html($login_link_separator);
746
+
747
+ // This filter is documented in wp-includes/general-template.php
748
+ echo apply_filters('register', $registration_url);
749
+ endif;
750
+ ?>
751
+ </p>
752
+
753
+ <?php
754
+ login_footer('user_pass');
755
 
756
+ if ($switched_locale) {
757
+ restore_previous_locale();
758
+ }
759
+ break;
760
+ case 'register':
761
+ if (is_multisite()) {
762
+ /**
763
+ * Filter the Multisite sign up URL.
764
+ *
765
+ * @since 3.0.0
766
+ *
767
+ * @param string $sign_up_url The sign up URL.
768
+ */
769
+ wp_redirect(apply_filters('wp_signup_location', network_site_url('wp-signup.php')));
770
+ exit;
771
+ }
772
 
773
+ if (!get_option('users_can_register')) {
774
+ wp_redirect(site_url('wp-login.php?registration=disabled'));
775
+ exit();
776
+ }
777
 
778
+ $user_login = '';
779
+ $user_email = '';
780
+ if ($http_post) {
781
+ if (isset($_POST['user_login']) && is_string($_POST['user_login'])) {
782
+ $user_login = $_POST['user_login'];
783
+ }
784
 
785
+ if (isset($_POST['user_email']) && is_string($_POST['user_email'])) {
786
+ $user_email = wp_unslash($_POST['user_email']);
787
+ }
788
+
789
+ $errors = register_new_user($user_login, $user_email);
790
+ if (!is_wp_error($errors)) {
791
+ $redirect_to = !empty($_POST['redirect_to']) ? $_POST['redirect_to'] : 'wp-login.php?checkemail=registered';
792
+ wp_safe_redirect($redirect_to);
793
+ exit();
794
+ }
795
+ }
796
+
797
+ $registration_redirect = ! empty($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : '';
798
+ /**
799
+ * Filter the registration redirect URL.
800
+ *
801
+ * @since 3.0.0
802
+ *
803
+ * @param string $registration_redirect The redirect destination URL.
804
+ */
805
+ $redirect_to = apply_filters('registration_redirect', $registration_redirect);
806
+ login_header(__('Registration Form'), '<p class="message register">' . __('Register For This Site') . '</p>', $errors);
807
+ ?>
808
+
809
+ <form name="registerform" id="registerform" action="<?php echo esc_url(site_url('wp-login.php?action=register', 'login_post')); ?>" method="post" novalidate="novalidate">
810
+ <p>
811
+ <label for="user_login"><?php _e('Username'); ?><br />
812
+ <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr(wp_unslash($user_login)); ?>" size="20" /></label>
813
+ </p>
814
+ <p>
815
+ <label for="user_email"><?php _e('Email'); ?><br />
816
+ <input type="email" name="user_email" id="user_email" class="input" value="<?php echo esc_attr(wp_unslash($user_email)); ?>" size="25" /></label>
817
+ </p>
818
+ <?php
819
+ /**
820
+ * Fires following the 'Email' field in the user registration form.
821
+ *
822
+ * @since 2.1.0
823
+ */
824
+ do_action('register_form');
825
+ ?>
826
+ <p id="reg_passmail"><?php _e('Registration confirmation will be emailed to you.'); ?></p>
827
+ <br class="clear" />
828
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
829
+ <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Register'); ?>" /></p>
830
+ </form>
831
+
832
+ <p id="nav">
833
+ <a href="<?php echo esc_url(wp_login_url()); ?>"><?php _e('Log in'); ?></a>
834
+ <?php echo esc_html($login_link_separator); ?>
835
+ <a href="<?php echo esc_url(wp_lostpassword_url()); ?>"><?php _e('Lost your password?'); ?></a>
836
+ </p>
837
+
838
+ <?php
839
+ login_footer('user_login');
840
+
841
+ if ($switched_locale) {
842
+ restore_previous_locale();
843
+ }
844
+ break;
845
+ case 'confirmaction':
846
+ if (! isset($_GET['request_id'])) {
847
+ wp_die(__('Invalid request.'));
848
+ }
849
+
850
+ $request_id = (int) $_GET['request_id'];
851
+
852
+ if (isset($_GET['confirm_key'])) {
853
+ $key = sanitize_text_field(wp_unslash($_GET['confirm_key']));
854
+ $result = wp_validate_user_request_key($request_id, $key);
855
+ } else {
856
+ $result = new WP_Error('invalid_key', __('Invalid key'));
857
+ }
858
+
859
+ if (is_wp_error($result)) {
860
+ wp_die($result);
861
+ }
862
+
863
+ /**
864
+ * Fires an action hook when the account action has been confirmed by the user.
865
+ *
866
+ * Using this you can assume the user has agreed to perform the action by
867
+ * clicking on the link in the confirmation email.
868
+ *
869
+ * After firing this action hook the page will redirect to wp-login a callback
870
+ * redirects or exits first.
871
+ *
872
+ * @param int $request_id Request ID.
873
+ */
874
+ do_action('user_request_action_confirmed', $request_id);
875
+
876
+ $message = _wp_privacy_account_request_confirmed_message($request_id);
877
+
878
+ login_header(__('User action confirmed.'), $message);
879
+ login_footer();
880
+ exit;
881
+
882
+ case 'login':
883
+ default:
884
+ $secure_cookie = '';
885
+ $customize_login = isset($_REQUEST['customize-login']);
886
+ if ($customize_login)
887
+ wp_enqueue_script('customize-base');
888
+
889
+ // If the user wants ssl but the session is not ssl, force a secure cookie.
890
+ if (!empty($_POST['log']) && !force_ssl_admin()) {
891
  $user_name = sanitize_user($_POST['log']);
892
+ $user = get_user_by('login', $user_name);
893
 
894
+ if (! $user && strpos($user_name, '@')) {
895
+ $user = get_user_by('email', $user_name);
896
  }
897
 
898
+ if ($user) {
899
+ if (get_user_option('use_ssl', $user->ID)) {
900
  $secure_cookie = true;
901
  force_ssl_admin(true);
902
  }
903
  }
904
  }
905
 
906
+ if (isset($_REQUEST['redirect_to'])) {
907
+ $redirect_to = $_REQUEST['redirect_to'];
908
+ // Redirect to https if user wants ssl
909
+ if ($secure_cookie && false !== strpos($redirect_to, 'wp-admin'))
910
+ $redirect_to = preg_replace('|^http://|', 'https://', $redirect_to);
911
+ } else {
912
+ $redirect_to = admin_url();
913
+ }
914
+
915
+ $reauth = empty($_REQUEST['reauth']) ? false : true;
916
+
917
+ $user = wp_signon(array(), $secure_cookie);
918
+
919
+ if (empty($_COOKIE[LOGGED_IN_COOKIE])) {
920
+ if (headers_sent()) {
921
+ // translators: 1: Browser cookie documentation URL, 2: Support forums URL
922
+ $user = new WP_Error('test_cookie', sprintf(__('<strong>ERROR</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.'), __('https://codex.wordpress.org/Cookies'), __('https://wordpress.org/support/')));
923
+ } elseif (isset($_POST['testcookie']) && empty($_COOKIE[TEST_COOKIE])) {
924
+ // If cookies are disabled we can't log in even with a valid user+pass
925
+ // translators: 1: Browser cookie documentation URL
926
+ $user = new WP_Error('test_cookie', sprintf(__('<strong>ERROR</strong>: Cookies are blocked or not supported by your browser. You must <a href="%s">enable cookies</a> to use WordPress.'), __('https://codex.wordpress.org/Cookies')));
927
+ }
928
+ }
929
+
930
+ $requested_redirect_to = isset($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : '';
931
+ /**
932
+ * Filter the login redirect URL.
933
+ *
934
+ * @since 3.0.0
935
+ *
936
+ * @param string $redirect_to The redirect destination URL.
937
+ * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
938
+ * @param WP_User|WP_Error $user WP_User object if login was successful, WP_Error object otherwise.
939
+ */
940
+ $redirect_to = apply_filters('login_redirect', $redirect_to, $requested_redirect_to, $user);
941
+
942
+ if (!is_wp_error($user) && !$reauth) {
943
+ if ($interim_login) {
944
+ $message = '<p class="message">' . __('You have logged in successfully.') . '</p>';
945
+ $interim_login = 'success';
946
+ login_header('', $message); ?>
 
 
947
  </div>
948
  <?php
949
+ // This action is documented in wp-login.php
950
+ do_action('login_footer'); ?>
951
+ <?php if ($customize_login) : ?>
952
+ <script type="text/javascript">setTimeout(function() { new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); ?>', channel: 'login' }).send('login') }, 1000);</script>
953
+ <?php endif; ?>
954
  </body></html>
955
  <?php exit;
956
+ }
957
+
958
+ if ((empty($redirect_to) || 'wp-admin/' == $redirect_to || admin_url() == $redirect_to)) {
959
+ // If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
960
+ if (is_multisite() && !get_active_blog_for_user($user->ID) && !is_super_admin($user->ID))
961
+ $redirect_to = user_admin_url();
962
+ elseif (is_multisite() && !$user->has_cap('read'))
963
+ $redirect_to = get_dashboard_url($user->ID);
964
+ elseif (!$user->has_cap('edit_posts'))
965
+ $redirect_to = $user->has_cap('read') ? admin_url('profile.php') : home_url();
966
+
967
+ wp_redirect($redirect_to);
968
+ exit();
969
+ }
970
+ wp_safe_redirect($redirect_to);
971
+ exit();
972
+ }
973
+
974
+ $errors = $user;
975
+ // Clear errors if loggedout is set.
976
+ if (!empty($_GET['loggedout']) || $reauth)
977
+ $errors = new WP_Error();
978
+
979
+ if ($interim_login) {
980
+ if (! $errors->get_error_code())
981
+ $errors->add('expired', __('Your session has expired. Please log in to continue where you left off.'), 'message');
982
+ } else {
983
+ // Some parts of this script use the main login form to display a message
984
+ if (isset($_GET['loggedout']) && true == $_GET['loggedout'])
985
+ $errors->add('loggedout', __('You are now logged out.'), 'message');
986
+ elseif (isset($_GET['registration']) && 'disabled' == $_GET['registration'])
987
+ $errors->add('registerdisabled', __('User registration is currently not allowed.'));
988
+ elseif (isset($_GET['checkemail']) && 'confirm' == $_GET['checkemail'])
989
+ $errors->add('confirm', __('Check your email for the confirmation link.'), 'message');
990
+ elseif (isset($_GET['checkemail']) && 'newpass' == $_GET['checkemail'])
991
+ $errors->add('newpass', __('Check your email for your new password.'), 'message');
992
+ elseif (isset($_GET['checkemail']) && 'registered' == $_GET['checkemail'])
993
+ $errors->add('registered', __('Registration complete. Please check your email.'), 'message');
994
+ elseif (strpos($redirect_to, 'about.php?updated'))
995
+ $errors->add('updated', __('<strong>You have successfully updated WordPress!</strong> Please log back in to see what&#8217;s new.'), 'message');
996
+ }
997
+
998
+ /**
999
+ * Filter the login page errors.
1000
+ *
1001
+ * @since 3.6.0
1002
+ *
1003
+ * @param object $errors WP Error object.
1004
+ * @param string $redirect_to Redirect destination URL.
1005
+ */
1006
+ $errors = apply_filters('wp_login_errors', $errors, $redirect_to);
1007
+
1008
+ // Clear any stale cookies.
1009
+ if ($reauth)
1010
+ wp_clear_auth_cookie();
1011
+
1012
+ login_header(__('Log In'), '', $errors);
1013
+
1014
+ if (isset($_POST['log']))
1015
+ $user_login = ('incorrect_password' == $errors->get_error_code() || 'empty_password' == $errors->get_error_code()) ? esc_attr(wp_unslash($_POST['log'])) : '';
1016
+ $rememberme = ! empty($_POST['rememberme']);
1017
+
1018
+ if (! empty($errors->errors)) {
1019
+ $aria_describedby_error = ' aria-describedby="login_error"';
1020
+ } else {
1021
+ $aria_describedby_error = '';
1022
+ }
1023
+
1024
+ //aiowps - this check is necessary because otherwise if variables are undefined we get a warning!
1025
+ if (empty($user_login)) {
1026
  $user_login = '';
1027
+ }
1028
+
1029
+ if (empty($error)) {
1030
  $error = '';
1031
+ }
1032
+ ?>
1033
 
1034
+ <form name="loginform" id="loginform" action="<?php echo esc_url(site_url('wp-login.php', 'login_post')); ?>" method="post">
1035
  <p>
1036
  <label for="user_login"><?php _e('Username or Email Address'); ?><br />
1037
+ <input type="text" name="log" id="user_login"<?php echo $aria_describedby_error; ?> class="input" value="<?php echo esc_attr($user_login); ?>" size="20" /></label>
1038
  </p>
1039
  <p>
1040
  <label for="user_pass"><?php _e('Password'); ?><br />
1041
  <input type="password" name="pwd" id="user_pass"<?php echo $aria_describedby_error; ?> class="input" value="" size="20" /></label>
1042
  </p>
1043
  <?php
1044
+ /**
1045
+ * Fires following the 'Password' field in the login form.
1046
+ *
1047
+ * @since 2.1.0
1048
+ */
1049
+ do_action('login_form');
1050
+ ?>
1051
+ <p class="forgetmenot"><label for="rememberme"><input name="rememberme" type="checkbox" id="rememberme" value="forever" <?php checked($rememberme); ?> /> <?php esc_html_e('Remember Me'); ?></label></p>
1052
  <p class="submit">
1053
  <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Log In'); ?>" />
1054
+ <?php if ($interim_login) { ?>
1055
+ <input type="hidden" name="interim-login" value="1" />
1056
+ <?php } else { ?>
1057
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
1058
+ <?php } ?>
1059
+ <?php if ($customize_login) : ?>
1060
+ <input type="hidden" name="customize-login" value="1" />
1061
+ <?php endif; ?>
1062
  <input type="hidden" name="testcookie" value="1" />
1063
  </p>
1064
  </form>
1065
 
1066
+ <?php if (! $interim_login) { ?>
1067
+ <p id="nav">
1068
+ <?php if (! isset($_GET['checkemail']) || ! in_array($_GET['checkemail'], array('confirm', 'newpass'))) :
1069
+ if (get_option('users_can_register')) :
1070
+ $registration_url = sprintf('<a href="%s">%s</a>', esc_url(wp_registration_url()), __('Register'));
1071
 
1072
+ // This filter is documented in wp-includes/general-template.php
1073
+ echo apply_filters('register', $registration_url);
1074
 
1075
+ echo esc_html($login_link_separator);
1076
+ endif;
1077
+ ?>
1078
+ <a href="<?php echo esc_url(wp_lostpassword_url()); ?>"><?php _e('Lost your password?'); ?></a>
1079
+ <?php endif; ?>
1080
+ </p>
1081
+ <?php } ?>
1082
 
1083
  <script type="text/javascript">
1084
+ function wp_attempt_focus() {
1085
+ setTimeout(function() { try{
1086
+ <?php if ($user_login) { ?>
1087
+ d = document.getElementById('user_pass');
1088
+ d.value = '';
1089
+ <?php } else { ?>
1090
+ d = document.getElementById('user_login');
1091
+ <?php if ('invalid_username' == $errors->get_error_code()) { ?>
1092
+ if (d.value != '')
1093
+ d.value = '';
1094
+ <?php
1095
+ }
1096
+ }?>
1097
  d.focus();
1098
  d.select();
1099
+ } catch(e) {}
1100
  }, 200);
1101
  }
1102
 
1108
  *
1109
  * @param bool $print Whether to print the function call. Default true.
1110
  */
1111
+ if (apply_filters('enable_login_autofocus', true) && ! $error) { ?>
1112
  wp_attempt_focus();
1113
  <?php } ?>
1114
+ if (typeof wpOnload=='function')wpOnload();
1115
+ <?php if ($interim_login) { ?>
1116
+ (function() {
1117
+ try {
1118
+ var i, links = document.getElementsByTagName('a');
1119
+ for (i in links) {
1120
+ if (links[i].href)
1121
+ links[i].target = '_blank';
1122
+ }
1123
+ } catch(e) {}
1124
+ }());
1125
+ <?php } ?>
1126
  </script>
1127
 
1128
  <?php
1129
+ login_footer();
1130
 
1131
+ if ($switched_locale) {
1132
+ restore_previous_locale();
1133
+ }
1134
+ break;
 
1135
  } // end action switch
other-includes/wp-security-rename-login-feature-pre-5-7.php CHANGED
@@ -8,18 +8,17 @@
8
  * @package WordPress
9
  */
10
 
11
- /** Make sure that the WordPress bootstrap has run before continuing. */
12
-
13
- // aiowps - for our special case we do not want to include wp-load.php
14
  //require __DIR__ . '/wp-load.php';
15
 
16
  // Redirect to HTTPS login if forced to use SSL.
17
- if ( force_ssl_admin() && ! is_ssl() ) {
18
- if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
19
- wp_safe_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
20
  exit;
21
  } else {
22
- wp_safe_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
23
  exit;
24
  }
25
  }
@@ -40,20 +39,20 @@ if ( force_ssl_admin() && ! is_ssl() ) {
40
  * @param string $message Optional. Message to display in header. Default empty.
41
  * @param WP_Error $wp_error Optional. The error to pass. Default is a WP_Error instance.
42
  */
43
- function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
44
  global $error, $interim_login, $action;
45
 
46
  // Don't index any of these forms.
47
- add_action( 'login_head', 'wp_sensitive_page_meta' );
48
 
49
- add_action( 'login_head', 'wp_login_viewport_meta' );
50
 
51
- if ( ! is_wp_error( $wp_error ) ) {
52
  $wp_error = new WP_Error();
53
  }
54
 
55
  // Shake it!
56
- $shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password', 'retrieve_password_email_failure' );
57
  /**
58
  * Filters the error codes array for shaking the login form.
59
  *
@@ -61,20 +60,20 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
61
  *
62
  * @param array $shake_error_codes Error codes that shake the login form.
63
  */
64
- $shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
65
 
66
- if ( $shake_error_codes && $wp_error->has_errors() && in_array( $wp_error->get_error_code(), $shake_error_codes, true ) ) {
67
- add_action( 'login_footer', 'wp_shake_js', 12 );
68
  }
69
 
70
- $login_title = get_bloginfo( 'name', 'display' );
71
 
72
  /* translators: Login screen title. 1: Login screen name, 2: Network or site name. */
73
- $login_title = sprintf( __( '%1$s &lsaquo; %2$s &#8212; WordPress' ), $title, $login_title );
74
 
75
- if ( wp_is_recovery_mode() ) {
76
  /* translators: %s: Login screen title. */
77
- $login_title = sprintf( __( 'Recovery Mode &#8212; %s' ), $login_title );
78
  }
79
 
80
  /**
@@ -85,25 +84,25 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
85
  * @param string $login_title The page title, with extra context added.
86
  * @param string $title The original page title.
87
  */
88
- $login_title = apply_filters( 'login_title', $login_title, $title );
89
 
90
  ?><!DOCTYPE html>
91
  <html <?php language_attributes(); ?>>
92
  <head>
93
- <meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php bloginfo( 'charset' ); ?>" />
94
  <title><?php echo $login_title; ?></title>
95
  <?php
96
 
97
- wp_enqueue_style( 'login' );
98
 
99
  /*
100
  * Remove all stored post data on logging out.
101
  * This could be added by add_action('login_head'...) like wp_shake_js(),
102
  * but maybe better if it's not removable by plugins.
103
  */
104
- if ( 'loggedout' === $wp_error->get_error_code() ) {
105
  ?>
106
- <script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
107
  <?php
108
  }
109
 
@@ -112,16 +111,16 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
112
  *
113
  * @since 3.1.0
114
  */
115
- do_action( 'login_enqueue_scripts' );
116
 
117
  /**
118
  * Fires in the login page header after scripts are enqueued.
119
  *
120
  * @since 2.1.0
121
  */
122
- do_action( 'login_head' );
123
 
124
- $login_header_url = __( 'https://wordpress.org/' );
125
 
126
  /**
127
  * Filters link URL of the header logo above login form.
@@ -130,7 +129,7 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
130
  *
131
  * @param string $login_header_url Login header logo URL.
132
  */
133
- $login_header_url = apply_filters( 'login_headerurl', $login_header_url );
134
 
135
  $login_header_title = '';
136
 
@@ -144,13 +143,13 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
144
  */
145
  $login_header_title = apply_filters_deprecated(
146
  'login_headertitle',
147
- array( $login_header_title ),
148
  '5.2.0',
149
  'login_headertext',
150
- __( 'Usage of the title attribute on the login logo is not recommended for accessibility reasons. Use the link text instead.' )
151
  );
152
 
153
- $login_header_text = empty( $login_header_title ) ? __( 'Powered by WordPress' ) : $login_header_title;
154
 
155
  /**
156
  * Filters the link text of the header logo above the login form.
@@ -159,27 +158,26 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
159
  *
160
  * @param string $login_header_text The login header logo link text.
161
  */
162
- $login_header_text = apply_filters( 'login_headertext', $login_header_text );
163
 
164
- $classes = array( 'login-action-' . $action, 'wp-core-ui' );
165
 
166
- if ( is_rtl() ) {
167
  $classes[] = 'rtl';
168
  }
169
 
170
- if ( $interim_login ) {
171
  $classes[] = 'interim-login';
172
-
173
  ?>
174
  <style type="text/css">html{background-color: transparent;}</style>
175
  <?php
176
 
177
- if ( 'success' === $interim_login ) {
178
  $classes[] = 'interim-login-success';
179
  }
180
  }
181
 
182
- $classes[] = ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
183
 
184
  /**
185
  * Filters the login page body classes.
@@ -189,11 +187,10 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
189
  * @param array $classes An array of body classes.
190
  * @param string $action The action that brought the visitor to the login page.
191
  */
192
- $classes = apply_filters( 'login_body_class', $classes, $action );
193
-
194
  ?>
195
  </head>
196
- <body class="login no-js <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
197
  <script type="text/javascript">
198
  document.body.className = document.body.className.replace('no-js','js');
199
  </script>
@@ -203,11 +200,10 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
203
  *
204
  * @since 4.6.0
205
  */
206
- do_action( 'login_header' );
207
-
208
  ?>
209
  <div id="login">
210
- <h1><a href="<?php echo esc_url( $login_header_url ); ?>"><?php echo $login_header_text; ?></a></h1>
211
  <?php
212
  /**
213
  * Filters the message to display above the login form.
@@ -216,26 +212,26 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
216
  *
217
  * @param string $message Login message text.
218
  */
219
- $message = apply_filters( 'login_message', $message );
220
 
221
- if ( ! empty( $message ) ) {
222
  echo $message . "\n";
223
  }
224
 
225
  // In case a plugin uses $error rather than the $wp_errors object.
226
- if ( ! empty( $error ) ) {
227
- $wp_error->add( 'error', $error );
228
- unset( $error );
229
  }
230
 
231
- if ( $wp_error->has_errors() ) {
232
  $errors = '';
233
  $messages = '';
234
 
235
- foreach ( $wp_error->get_error_codes() as $code ) {
236
- $severity = $wp_error->get_error_data( $code );
237
- foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
238
- if ( 'message' === $severity ) {
239
  $messages .= ' ' . $error_message . "<br />\n";
240
  } else {
241
  $errors .= ' ' . $error_message . "<br />\n";
@@ -243,7 +239,7 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
243
  }
244
  }
245
 
246
- if ( ! empty( $errors ) ) {
247
  /**
248
  * Filters the error messages displayed above the login form.
249
  *
@@ -251,10 +247,10 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
251
  *
252
  * @param string $errors Login error message.
253
  */
254
- echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
255
  }
256
 
257
- if ( ! empty( $messages ) ) {
258
  /**
259
  * Filters instructional messages displayed above the login form.
260
  *
@@ -262,7 +258,7 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
262
  *
263
  * @param string $messages Login messages.
264
  */
265
- echo '<p class="message">' . apply_filters( 'login_messages', $messages ) . "</p>\n";
266
  }
267
  }
268
  } // End of login_header().
@@ -277,23 +273,22 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
277
  *
278
  * @param string $input_id Which input to auto-focus.
279
  */
280
- function login_footer( $input_id = '' ) {
281
  global $interim_login;
282
 
283
  // Don't allow interim logins to navigate away from the page.
284
- if ( ! $interim_login ) {
285
  ?>
286
- <p id="backtoblog"><a href="<?php echo esc_url( home_url( '/' ) ); ?>">
287
  <?php
288
 
289
  /* translators: %s: Site title. */
290
- printf( _x( '&larr; Go to %s', 'site' ), get_bloginfo( 'title', 'display' ) );
291
-
292
  ?>
293
  </a></p>
294
  <?php
295
 
296
- the_privacy_policy_link( '<div class="privacy-policy-page-link">', '</div>' );
297
  }
298
 
299
  ?>
@@ -301,11 +296,11 @@ function login_footer( $input_id = '' ) {
301
 
302
  <?php
303
 
304
- if ( ! empty( $input_id ) ) {
305
  ?>
306
  <script type="text/javascript">
307
- try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e){}
308
- if(typeof wpOnload=='function')wpOnload();
309
  </script>
310
  <?php
311
  }
@@ -315,8 +310,7 @@ function login_footer( $input_id = '' ) {
315
  *
316
  * @since 3.1.0
317
  */
318
- do_action( 'login_footer' );
319
-
320
  ?>
321
  <div class="clear"></div>
322
  </body>
@@ -359,16 +353,16 @@ function retrieve_password() {
359
  $errors = new WP_Error();
360
  $user_data = false;
361
 
362
- if ( empty( $_POST['user_login'] ) || ! is_string( $_POST['user_login'] ) ) {
363
- $errors->add( 'empty_username', __( '<strong>Error</strong>: Please enter a username or email address.' ) );
364
- } elseif ( strpos( $_POST['user_login'], '@' ) ) {
365
- $user_data = get_user_by( 'email', trim( wp_unslash( $_POST['user_login'] ) ) );
366
- if ( empty( $user_data ) ) {
367
- $errors->add( 'invalid_email', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
368
  }
369
  } else {
370
- $login = trim( wp_unslash( $_POST['user_login'] ) );
371
- $user_data = get_user_by( 'login', $login );
372
  }
373
 
374
  /**
@@ -382,7 +376,7 @@ function retrieve_password() {
382
  * by using invalid credentials.
383
  * @param WP_User|false $user_data WP_User object if found, false if the user does not exist.
384
  */
385
- do_action( 'lostpassword_post', $errors, $user_data );
386
 
387
  /**
388
  * Filters the errors encountered on a password reset request.
@@ -399,56 +393,56 @@ function retrieve_password() {
399
  * by using invalid credentials.
400
  * @param WP_User|false $user_data WP_User object if found, false if the user does not exist.
401
  */
402
- $errors = apply_filters( 'lostpassword_errors', $errors, $user_data );
403
 
404
- if ( $errors->has_errors() ) {
405
  return $errors;
406
  }
407
 
408
- if ( ! $user_data ) {
409
- $errors->add( 'invalidcombo', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
410
  return $errors;
411
  }
412
 
413
  // Redefining user_login ensures we return the right case in the email.
414
  $user_login = $user_data->user_login;
415
  $user_email = $user_data->user_email;
416
- $key = get_password_reset_key( $user_data );
417
 
418
- if ( is_wp_error( $key ) ) {
419
  return $key;
420
  }
421
 
422
- if ( is_multisite() ) {
423
  $site_name = get_network()->site_name;
424
  } else {
425
  /*
426
  * The blogname option is escaped with esc_html on the way into the database
427
  * in sanitize_option. We want to reverse this for the plain text arena of emails.
428
  */
429
- $site_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
430
  }
431
 
432
- $message = __( 'Someone has requested a password reset for the following account:' ) . "\r\n\r\n";
433
  /* translators: %s: Site name. */
434
- $message .= sprintf( __( 'Site Name: %s' ), $site_name ) . "\r\n\r\n";
435
  /* translators: %s: User login. */
436
- $message .= sprintf( __( 'Username: %s' ), $user_login ) . "\r\n\r\n";
437
- $message .= __( 'If this was a mistake, ignore this email and nothing will happen.' ) . "\r\n\r\n";
438
- $message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n";
439
- $message .= network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' ) . "\r\n\r\n";
440
 
441
  $requester_ip = $_SERVER['REMOTE_ADDR'];
442
- if ( $requester_ip ) {
443
  $message .= sprintf(
444
  /* translators: %s: IP address of password reset requester. */
445
- __( 'This password reset request originated from the IP address %s.' ),
446
  $requester_ip
447
  ) . "\r\n";
448
  }
449
 
450
  /* translators: Password reset notification email subject. %s: Site title. */
451
- $title = sprintf( __( '[%s] Password Reset' ), $site_name );
452
 
453
  /**
454
  * Filters the subject of the password reset email.
@@ -460,7 +454,7 @@ function retrieve_password() {
460
  * @param string $user_login The username for the user.
461
  * @param WP_User $user_data WP_User object.
462
  */
463
- $title = apply_filters( 'retrieve_password_title', $title, $user_login, $user_data );
464
 
465
  /**
466
  * Filters the message body of the password reset mail.
@@ -475,15 +469,15 @@ function retrieve_password() {
475
  * @param string $user_login The username for the user.
476
  * @param WP_User $user_data WP_User object.
477
  */
478
- $message = apply_filters( 'retrieve_password_message', $message, $key, $user_login, $user_data );
479
 
480
- if ( $message && ! wp_mail( $user_email, wp_specialchars_decode( $title ), $message ) ) {
481
  $errors->add(
482
  'retrieve_password_email_failure',
483
  sprintf(
484
  /* translators: %s: Documentation URL. */
485
- __( '<strong>Error</strong>: The email could not be sent. Your site may not be correctly configured to send emails. <a href="%s">Get support for resetting your password</a>.' ),
486
- esc_url( __( 'https://wordpress.org/support/article/resetting-your-password/' ) )
487
  )
488
  );
489
  return $errors;
@@ -496,14 +490,14 @@ function retrieve_password() {
496
  // Main.
497
  //
498
 
499
- $action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
500
  $errors = new WP_Error();
501
 
502
- if ( isset( $_GET['key'] ) ) {
503
  $action = 'resetpass';
504
  }
505
 
506
- if ( isset( $_GET['checkemail'] ) ) {
507
  $action = 'checkemail';
508
  }
509
 
@@ -523,32 +517,32 @@ $default_actions = array(
523
  );
524
 
525
  // Validate action so as to default to the login screen.
526
- if ( ! in_array( $action, $default_actions, true ) && false === has_filter( 'login_form_' . $action ) ) {
527
  $action = 'login';
528
  }
529
 
530
  nocache_headers();
531
 
532
- header( 'Content-Type: ' . get_bloginfo( 'html_type' ) . '; charset=' . get_bloginfo( 'charset' ) );
533
 
534
- if ( defined( 'RELOCATE' ) && RELOCATE ) { // Move flag is set.
535
- if ( isset( $_SERVER['PATH_INFO'] ) && ( $_SERVER['PATH_INFO'] !== $_SERVER['PHP_SELF'] ) ) {
536
- $_SERVER['PHP_SELF'] = str_replace( $_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF'] );
537
  }
538
 
539
- $url = dirname( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] ) );
540
 
541
- if ( get_option( 'siteurl' ) !== $url ) {
542
- update_option( 'siteurl', $url );
543
  }
544
  }
545
 
546
  // Set a cookie now to see if they are supported by the browser.
547
- $secure = ( 'https' === parse_url( wp_login_url(), PHP_URL_SCHEME ) );
548
- setcookie( TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN, $secure );
549
 
550
- if ( SITECOOKIEPATH !== COOKIEPATH ) {
551
- setcookie( TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN, $secure );
552
  }
553
 
554
  /**
@@ -556,7 +550,7 @@ if ( SITECOOKIEPATH !== COOKIEPATH ) {
556
  *
557
  * @since 3.2.0
558
  */
559
- do_action( 'login_init' );
560
 
561
  /**
562
  * Fires before a specified login form action.
@@ -567,10 +561,10 @@ do_action( 'login_init' );
567
  *
568
  * @since 2.8.0
569
  */
570
- do_action( "login_form_{$action}" );
571
 
572
- $http_post = ( 'POST' === $_SERVER['REQUEST_METHOD'] );
573
- $interim_login = isset( $_REQUEST['interim-login'] );
574
 
575
  /**
576
  * Filters the separator used between login form navigation links.
@@ -579,9 +573,9 @@ $interim_login = isset( $_REQUEST['interim-login'] );
579
  *
580
  * @param string $login_link_separator The separator used between login form navigation links.
581
  */
582
- $login_link_separator = apply_filters( 'login_link_separator', ' | ' );
583
 
584
- switch ( $action ) {
585
 
586
  case 'confirm_admin_email':
587
  /*
@@ -589,21 +583,21 @@ switch ( $action ) {
589
  * as the current user is not set, see wp-includes/pluggable.php.
590
  * However this action runs on a redirect after logging in.
591
  */
592
- if ( ! is_user_logged_in() ) {
593
- wp_safe_redirect( wp_login_url() );
594
  exit;
595
  }
596
 
597
- if ( ! empty( $_REQUEST['redirect_to'] ) ) {
598
  $redirect_to = $_REQUEST['redirect_to'];
599
  } else {
600
  $redirect_to = admin_url();
601
  }
602
 
603
- if ( current_user_can( 'manage_options' ) ) {
604
- $admin_email = get_option( 'admin_email' );
605
  } else {
606
- wp_safe_redirect( $redirect_to );
607
  exit;
608
  }
609
 
@@ -616,26 +610,26 @@ switch ( $action ) {
616
  *
617
  * @param int $interval Interval time (in seconds). Default is 3 days.
618
  */
619
- $remind_interval = (int) apply_filters( 'admin_email_remind_interval', 3 * DAY_IN_SECONDS );
620
 
621
- if ( ! empty( $_GET['remind_me_later'] ) ) {
622
- if ( ! wp_verify_nonce( $_GET['remind_me_later'], 'remind_me_later_nonce' ) ) {
623
- wp_safe_redirect( wp_login_url() );
624
  exit;
625
  }
626
 
627
- if ( $remind_interval > 0 ) {
628
- update_option( 'admin_email_lifespan', time() + $remind_interval );
629
  }
630
 
631
- $redirect_to = add_query_arg( 'admin_email_remind_later', 1, $redirect_to );
632
- wp_safe_redirect( $redirect_to );
633
  exit;
634
  }
635
 
636
- if ( ! empty( $_POST['correct-admin-email'] ) ) {
637
- if ( ! check_admin_referer( 'confirm_admin_email', 'confirm_admin_email_nonce' ) ) {
638
- wp_safe_redirect( wp_login_url() );
639
  exit;
640
  }
641
 
@@ -648,17 +642,17 @@ switch ( $action ) {
648
  *
649
  * @param int $interval Interval time (in seconds). Default is 6 months.
650
  */
651
- $admin_email_check_interval = (int) apply_filters( 'admin_email_check_interval', 6 * MONTH_IN_SECONDS );
652
 
653
- if ( $admin_email_check_interval > 0 ) {
654
- update_option( 'admin_email_lifespan', time() + $admin_email_check_interval );
655
  }
656
 
657
- wp_safe_redirect( $redirect_to );
658
  exit;
659
  }
660
 
661
- login_header( __( 'Confirm your administration email' ), '', $errors );
662
 
663
  /**
664
  * Fires before the admin email confirm form.
@@ -668,44 +662,41 @@ switch ( $action ) {
668
  * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
669
  * credentials. Note that the error object may not contain any errors.
670
  */
671
- do_action( 'admin_email_confirm', $errors );
672
-
673
  ?>
674
 
675
- <form class="admin-email-confirm-form" name="admin-email-confirm-form" action="<?php echo esc_url( site_url( 'wp-login.php?action=confirm_admin_email', 'login_post' ) ); ?>" method="post">
676
  <?php
677
  /**
678
  * Fires inside the admin-email-confirm-form form tags, before the hidden fields.
679
  *
680
  * @since 5.3.0
681
  */
682
- do_action( 'admin_email_confirm_form' );
683
-
684
- wp_nonce_field( 'confirm_admin_email', 'confirm_admin_email_nonce' );
685
 
 
686
  ?>
687
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
688
 
689
  <h1 class="admin-email__heading">
690
- <?php _e( 'Administration email verification' ); ?>
691
  </h1>
692
  <p class="admin-email__details">
693
- <?php _e( 'Please verify that the <strong>administration email</strong> for this website is still correct.' ); ?>
694
  <?php
695
 
696
  /* translators: URL to the WordPress help section about admin email. */
697
- $admin_email_help_url = __( 'https://wordpress.org/support/article/settings-general-screen/#email-address' );
698
 
699
  /* translators: Accessibility text. */
700
- $accessibility_text = sprintf( '<span class="screen-reader-text"> %s</span>', __( '(opens in a new tab)' ) );
701
 
702
  printf(
703
  '<a href="%s" rel="noopener" target="_blank">%s%s</a>',
704
- esc_url( $admin_email_help_url ),
705
- __( 'Why is this important?' ),
706
  $accessibility_text
707
  );
708
-
709
  ?>
710
  </p>
711
  <p class="admin-email__details">
@@ -713,42 +704,39 @@ switch ( $action ) {
713
 
714
  printf(
715
  /* translators: %s: Admin email address. */
716
- __( 'Current administration email: %s' ),
717
- '<strong>' . esc_html( $admin_email ) . '</strong>'
718
  );
719
-
720
  ?>
721
  </p>
722
  <p class="admin-email__details">
723
- <?php _e( 'This email may be different from your personal email address.' ); ?>
724
  </p>
725
 
726
  <div class="admin-email__actions">
727
  <div class="admin-email__actions-primary">
728
  <?php
729
 
730
- $change_link = admin_url( 'options-general.php' );
731
- $change_link = add_query_arg( 'highlight', 'confirm_admin_email', $change_link );
732
-
733
  ?>
734
- <a class="button button-large" href="<?php echo esc_url( $change_link ); ?>"><?php _e( 'Update' ); ?></a>
735
- <input type="submit" name="correct-admin-email" id="correct-admin-email" class="button button-primary button-large" value="<?php esc_attr_e( 'The email is correct' ); ?>" />
736
  </div>
737
- <?php if ( $remind_interval > 0 ) : ?>
738
  <div class="admin-email__actions-secondary">
739
  <?php
740
 
741
- $remind_me_link = wp_login_url( $redirect_to );
742
  $remind_me_link = add_query_arg(
743
  array(
744
  'action' => 'confirm_admin_email',
745
- 'remind_me_later' => wp_create_nonce( 'remind_me_later_nonce' ),
746
  ),
747
  $remind_me_link
748
  );
749
-
750
  ?>
751
- <a href="<?php echo esc_url( $remind_me_link ); ?>"><?php _e( 'Remind me later' ); ?></a>
752
  </div>
753
  <?php endif; ?>
754
  </div>
@@ -760,13 +748,13 @@ switch ( $action ) {
760
  break;
761
 
762
  case 'postpass':
763
- if ( ! array_key_exists( 'post_password', $_POST ) ) {
764
- wp_safe_redirect( wp_get_referer() );
765
  exit;
766
  }
767
 
768
  require_once ABSPATH . WPINC . '/class-phpass.php';
769
- $hasher = new PasswordHash( 8, true );
770
 
771
  /**
772
  * Filters the life span of the post password cookie.
@@ -778,35 +766,35 @@ switch ( $action ) {
778
  *
779
  * @param int $expires The expiry time, as passed to setcookie().
780
  */
781
- $expire = apply_filters( 'post_password_expires', time() + 10 * DAY_IN_SECONDS );
782
  $referer = wp_get_referer();
783
 
784
- if ( $referer ) {
785
- $secure = ( 'https' === parse_url( $referer, PHP_URL_SCHEME ) );
786
  } else {
787
  $secure = false;
788
  }
789
 
790
- setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure );
791
 
792
- wp_safe_redirect( wp_get_referer() );
793
  exit;
794
 
795
  case 'logout':
796
- check_admin_referer( 'log-out' );
797
 
798
  $user = wp_get_current_user();
799
 
800
  wp_logout();
801
 
802
- if ( ! empty( $_REQUEST['redirect_to'] ) ) {
803
  $redirect_to = $_REQUEST['redirect_to'];
804
  $requested_redirect_to = $redirect_to;
805
  } else {
806
  $redirect_to = add_query_arg(
807
  array(
808
  'loggedout' => 'true',
809
- 'wp_lang' => get_user_locale( $user ),
810
  ),
811
  wp_login_url()
812
  );
@@ -823,32 +811,32 @@ switch ( $action ) {
823
  * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
824
  * @param WP_User $user The WP_User object for the user that's logging out.
825
  */
826
- $redirect_to = apply_filters( 'logout_redirect', $redirect_to, $requested_redirect_to, $user );
827
 
828
- wp_safe_redirect( $redirect_to );
829
  exit;
830
 
831
  case 'lostpassword':
832
  case 'retrievepassword':
833
- if ( $http_post ) {
834
  $errors = retrieve_password();
835
 
836
- if ( ! is_wp_error( $errors ) ) {
837
- $redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
838
- wp_safe_redirect( $redirect_to );
839
  exit;
840
  }
841
  }
842
 
843
- if ( isset( $_GET['error'] ) ) {
844
- if ( 'invalidkey' === $_GET['error'] ) {
845
- $errors->add( 'invalidkey', __( 'Your password reset link appears to be invalid. Please request a new link below.' ) );
846
- } elseif ( 'expiredkey' === $_GET['error'] ) {
847
- $errors->add( 'expiredkey', __( 'Your password reset link has expired. Please request a new link below.' ) );
848
  }
849
  }
850
 
851
- $lostpassword_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
852
  /**
853
  * Filters the URL redirected to after submitting the lostpassword/retrievepassword form.
854
  *
@@ -856,7 +844,7 @@ switch ( $action ) {
856
  *
857
  * @param string $lostpassword_redirect The redirect destination URL.
858
  */
859
- $redirect_to = apply_filters( 'lostpassword_redirect', $lostpassword_redirect );
860
 
861
  /**
862
  * Fires before the lost password form.
@@ -867,22 +855,22 @@ switch ( $action ) {
867
  * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
868
  * credentials. Note that the error object may not contain any errors.
869
  */
870
- do_action( 'lost_password', $errors );
871
 
872
- login_header( __( 'Lost Password' ), '<p class="message">' . __( 'Please enter your username or email address. You will receive an email message with instructions on how to reset your password.' ) . '</p>', $errors );
873
 
874
  $user_login = '';
875
 
876
- if ( isset( $_POST['user_login'] ) && is_string( $_POST['user_login'] ) ) {
877
- $user_login = wp_unslash( $_POST['user_login'] );
878
  }
879
 
880
  ?>
881
 
882
- <form name="lostpasswordform" id="lostpasswordform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=lostpassword', 'login_post' ) ); ?>" method="post">
883
  <p>
884
- <label for="user_login"><?php _e( 'Username or Email Address' ); ?></label>
885
- <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr( $user_login ); ?>" size="20" autocapitalize="off" />
886
  </p>
887
  <?php
888
 
@@ -891,67 +879,66 @@ switch ( $action ) {
891
  *
892
  * @since 2.1.0
893
  */
894
- do_action( 'lostpassword_form' );
895
-
896
  ?>
897
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
898
  <p class="submit">
899
- <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Get New Password' ); ?>" />
900
  </p>
901
  </form>
902
 
903
  <p id="nav">
904
- <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
905
  <?php
906
 
907
- if ( get_option( 'users_can_register' ) ) {
908
- $registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
909
 
910
- echo esc_html( $login_link_separator );
911
 
912
- /** This filter is documented in wp-includes/general-template.php */
913
- echo apply_filters( 'register', $registration_url );
914
  }
915
 
916
  ?>
917
  </p>
918
  <?php
919
 
920
- login_footer( 'user_login' );
921
  break;
922
 
923
  case 'resetpass':
924
  case 'rp':
925
- list( $rp_path ) = explode( '?', wp_unslash( $_SERVER['REQUEST_URI'] ) );
926
  $rp_cookie = 'wp-resetpass-' . COOKIEHASH;
927
 
928
- if ( isset( $_GET['key'] ) ) {
929
- $value = sprintf( '%s:%s', wp_unslash( $_GET['login'] ), wp_unslash( $_GET['key'] ) );
930
- setcookie( $rp_cookie, $value, 0, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
931
 
932
- wp_safe_redirect( remove_query_arg( array( 'key', 'login' ) ) );
933
  exit;
934
  }
935
 
936
- if ( isset( $_COOKIE[ $rp_cookie ] ) && 0 < strpos( $_COOKIE[ $rp_cookie ], ':' ) ) {
937
- list( $rp_login, $rp_key ) = explode( ':', wp_unslash( $_COOKIE[ $rp_cookie ] ), 2 );
938
 
939
- $user = check_password_reset_key( $rp_key, $rp_login );
940
 
941
- if ( isset( $_POST['pass1'] ) && ! hash_equals( $rp_key, $_POST['rp_key'] ) ) {
942
  $user = false;
943
  }
944
  } else {
945
  $user = false;
946
  }
947
 
948
- if ( ! $user || is_wp_error( $user ) ) {
949
- setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
950
 
951
- if ( $user && $user->get_error_code() === 'expired_key' ) {
952
- wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=expiredkey' ) );
953
  } else {
954
- wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=invalidkey' ) );
955
  }
956
 
957
  exit;
@@ -959,8 +946,8 @@ switch ( $action ) {
959
 
960
  $errors = new WP_Error();
961
 
962
- if ( isset( $_POST['pass1'] ) && $_POST['pass1'] !== $_POST['pass2'] ) {
963
- $errors->add( 'password_reset_mismatch', __( 'The passwords do not match.' ) );
964
  }
965
 
966
  /**
@@ -971,46 +958,45 @@ switch ( $action ) {
971
  * @param WP_Error $errors WP Error object.
972
  * @param WP_User|WP_Error $user WP_User object if the login and reset key match. WP_Error object otherwise.
973
  */
974
- do_action( 'validate_password_reset', $errors, $user );
975
 
976
- if ( ( ! $errors->has_errors() ) && isset( $_POST['pass1'] ) && ! empty( $_POST['pass1'] ) ) {
977
- reset_password( $user, $_POST['pass1'] );
978
- setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
979
- login_header( __( 'Password Reset' ), '<p class="message reset-pass">' . __( 'Your password has been reset.' ) . ' <a href="' . esc_url( wp_login_url() ) . '">' . __( 'Log in' ) . '</a></p>' );
980
  login_footer();
981
  exit;
982
  }
983
 
984
- wp_enqueue_script( 'utils' );
985
- wp_enqueue_script( 'user-profile' );
986
-
987
- login_header( __( 'Reset Password' ), '<p class="message reset-pass">' . __( 'Enter your new password below.' ) . '</p>', $errors );
988
 
 
989
  ?>
990
- <form name="resetpassform" id="resetpassform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=resetpass', 'login_post' ) ); ?>" method="post" autocomplete="off">
991
- <input type="hidden" id="user_login" value="<?php echo esc_attr( $rp_login ); ?>" autocomplete="off" />
992
 
993
  <div class="user-pass1-wrap">
994
  <p>
995
- <label for="pass1"><?php _e( 'New password' ); ?></label>
996
  </p>
997
 
998
  <div class="wp-pwd">
999
- <input type="password" data-reveal="1" data-pw="<?php echo esc_attr( wp_generate_password( 16 ) ); ?>" name="pass1" id="pass1" class="input password-input" size="24" value="" autocomplete="off" aria-describedby="pass-strength-result" />
1000
 
1001
- <button type="button" class="button button-secondary wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Hide password' ); ?>">
1002
  <span class="dashicons dashicons-hidden" aria-hidden="true"></span>
1003
  </button>
1004
- <div id="pass-strength-result" class="hide-if-no-js" aria-live="polite"><?php _e( 'Strength indicator' ); ?></div>
1005
  </div>
1006
  <div class="pw-weak">
1007
  <input type="checkbox" name="pw_weak" id="pw-weak" class="pw-checkbox" />
1008
- <label for="pw-weak"><?php _e( 'Confirm use of weak password' ); ?></label>
1009
  </div>
1010
  </div>
1011
 
1012
  <p class="user-pass2-wrap">
1013
- <label for="pass2"><?php _e( 'Confirm new password' ); ?></label>
1014
  <input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off" />
1015
  </p>
1016
 
@@ -1026,37 +1012,36 @@ switch ( $action ) {
1026
  *
1027
  * @param WP_User $user User object of the user whose password is being reset.
1028
  */
1029
- do_action( 'resetpass_form', $user );
1030
-
1031
  ?>
1032
- <input type="hidden" name="rp_key" value="<?php echo esc_attr( $rp_key ); ?>" />
1033
  <p class="submit">
1034
- <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Reset Password' ); ?>" />
1035
  </p>
1036
  </form>
1037
 
1038
  <p id="nav">
1039
- <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
1040
  <?php
1041
 
1042
- if ( get_option( 'users_can_register' ) ) {
1043
- $registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
1044
 
1045
- echo esc_html( $login_link_separator );
1046
 
1047
- /** This filter is documented in wp-includes/general-template.php */
1048
- echo apply_filters( 'register', $registration_url );
1049
  }
1050
 
1051
  ?>
1052
  </p>
1053
  <?php
1054
 
1055
- login_footer( 'user_pass' );
1056
  break;
1057
 
1058
  case 'register':
1059
- if ( is_multisite() ) {
1060
  /**
1061
  * Filters the Multisite sign up URL.
1062
  *
@@ -1064,37 +1049,37 @@ switch ( $action ) {
1064
  *
1065
  * @param string $sign_up_url The sign up URL.
1066
  */
1067
- wp_redirect( apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) ) );
1068
  exit;
1069
  }
1070
 
1071
- if ( ! get_option( 'users_can_register' ) ) {
1072
- wp_redirect( site_url( 'wp-login.php?registration=disabled' ) );
1073
  exit;
1074
  }
1075
 
1076
  $user_login = '';
1077
  $user_email = '';
1078
 
1079
- if ( $http_post ) {
1080
- if ( isset( $_POST['user_login'] ) && is_string( $_POST['user_login'] ) ) {
1081
- $user_login = wp_unslash( $_POST['user_login'] );
1082
  }
1083
 
1084
- if ( isset( $_POST['user_email'] ) && is_string( $_POST['user_email'] ) ) {
1085
- $user_email = wp_unslash( $_POST['user_email'] );
1086
  }
1087
 
1088
- $errors = register_new_user( $user_login, $user_email );
1089
 
1090
- if ( ! is_wp_error( $errors ) ) {
1091
- $redirect_to = ! empty( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : 'wp-login.php?checkemail=registered';
1092
- wp_safe_redirect( $redirect_to );
1093
  exit;
1094
  }
1095
  }
1096
 
1097
- $registration_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
1098
 
1099
  /**
1100
  * Filters the registration redirect URL.
@@ -1103,19 +1088,18 @@ switch ( $action ) {
1103
  *
1104
  * @param string $registration_redirect The redirect destination URL.
1105
  */
1106
- $redirect_to = apply_filters( 'registration_redirect', $registration_redirect );
1107
-
1108
- login_header( __( 'Registration Form' ), '<p class="message register">' . __( 'Register For This Site' ) . '</p>', $errors );
1109
 
 
1110
  ?>
1111
- <form name="registerform" id="registerform" action="<?php echo esc_url( site_url( 'wp-login.php?action=register', 'login_post' ) ); ?>" method="post" novalidate="novalidate">
1112
  <p>
1113
- <label for="user_login"><?php _e( 'Username' ); ?></label>
1114
- <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr( wp_unslash( $user_login ) ); ?>" size="20" autocapitalize="off" />
1115
  </p>
1116
  <p>
1117
- <label for="user_email"><?php _e( 'Email' ); ?></label>
1118
- <input type="email" name="user_email" id="user_email" class="input" value="<?php echo esc_attr( wp_unslash( $user_email ) ); ?>" size="25" />
1119
  </p>
1120
  <?php
1121
 
@@ -1124,77 +1108,76 @@ switch ( $action ) {
1124
  *
1125
  * @since 2.1.0
1126
  */
1127
- do_action( 'register_form' );
1128
-
1129
  ?>
1130
  <p id="reg_passmail">
1131
- <?php _e( 'Registration confirmation will be emailed to you.' ); ?>
1132
  </p>
1133
  <br class="clear" />
1134
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
1135
  <p class="submit">
1136
- <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Register' ); ?>" />
1137
  </p>
1138
  </form>
1139
 
1140
  <p id="nav">
1141
- <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
1142
- <?php echo esc_html( $login_link_separator ); ?>
1143
- <a href="<?php echo esc_url( wp_lostpassword_url() ); ?>"><?php _e( 'Lost your password?' ); ?></a>
1144
  </p>
1145
  <?php
1146
 
1147
- login_footer( 'user_login' );
1148
  break;
1149
 
1150
  case 'checkemail':
1151
  $redirect_to = admin_url();
1152
  $errors = new WP_Error();
1153
 
1154
- if ( 'confirm' === $_GET['checkemail'] ) {
1155
  $errors->add(
1156
  'confirm',
1157
  sprintf(
1158
  /* translators: %s: Link to the login page. */
1159
- __( 'Check your email for the confirmation link, then visit the <a href="%s">login page</a>.' ),
1160
  wp_login_url()
1161
  ),
1162
  'message'
1163
  );
1164
- } elseif ( 'registered' === $_GET['checkemail'] ) {
1165
  $errors->add(
1166
  'registered',
1167
  sprintf(
1168
  /* translators: %s: Link to the login page. */
1169
- __( 'Registration complete. Please check your email, then visit the <a href="%s">login page</a>.' ),
1170
  wp_login_url()
1171
  ),
1172
  'message'
1173
  );
1174
  }
1175
 
1176
- /** This action is documented in wp-login.php */
1177
- $errors = apply_filters( 'wp_login_errors', $errors, $redirect_to );
1178
 
1179
- login_header( __( 'Check your email' ), '', $errors );
1180
  login_footer();
1181
  break;
1182
 
1183
  case 'confirmaction':
1184
- if ( ! isset( $_GET['request_id'] ) ) {
1185
- wp_die( __( 'Missing request ID.' ) );
1186
  }
1187
 
1188
- if ( ! isset( $_GET['confirm_key'] ) ) {
1189
- wp_die( __( 'Missing confirm key.' ) );
1190
  }
1191
 
1192
  $request_id = (int) $_GET['request_id'];
1193
- $key = sanitize_text_field( wp_unslash( $_GET['confirm_key'] ) );
1194
- $result = wp_validate_user_request_key( $request_id, $key );
1195
 
1196
- if ( is_wp_error( $result ) ) {
1197
- wp_die( $result );
1198
  }
1199
 
1200
  /**
@@ -1210,79 +1193,79 @@ switch ( $action ) {
1210
  *
1211
  * @param int $request_id Request ID.
1212
  */
1213
- do_action( 'user_request_action_confirmed', $request_id );
1214
 
1215
- $message = _wp_privacy_account_request_confirmed_message( $request_id );
1216
 
1217
- login_header( __( 'User action confirmed.' ), $message );
1218
  login_footer();
1219
  exit;
1220
 
1221
  case 'login':
1222
  default:
1223
  $secure_cookie = '';
1224
- $customize_login = isset( $_REQUEST['customize-login'] );
1225
 
1226
- if ( $customize_login ) {
1227
- wp_enqueue_script( 'customize-base' );
1228
  }
1229
 
1230
  // If the user wants SSL but the session is not SSL, force a secure cookie.
1231
- if ( ! empty( $_POST['log'] ) && ! force_ssl_admin() ) {
1232
- $user_name = sanitize_user( wp_unslash( $_POST['log'] ) );
1233
- $user = get_user_by( 'login', $user_name );
1234
 
1235
- if ( ! $user && strpos( $user_name, '@' ) ) {
1236
- $user = get_user_by( 'email', $user_name );
1237
  }
1238
 
1239
- if ( $user ) {
1240
- if ( get_user_option( 'use_ssl', $user->ID ) ) {
1241
  $secure_cookie = true;
1242
- force_ssl_admin( true );
1243
  }
1244
  }
1245
  }
1246
 
1247
- if ( isset( $_REQUEST['redirect_to'] ) ) {
1248
  $redirect_to = $_REQUEST['redirect_to'];
1249
  // Redirect to HTTPS if user wants SSL.
1250
- if ( $secure_cookie && false !== strpos( $redirect_to, 'wp-admin' ) ) {
1251
- $redirect_to = preg_replace( '|^http://|', 'https://', $redirect_to );
1252
  }
1253
  } else {
1254
  $redirect_to = admin_url();
1255
  }
1256
 
1257
- $reauth = empty( $_REQUEST['reauth'] ) ? false : true;
1258
 
1259
- $user = wp_signon( array(), $secure_cookie );
1260
 
1261
- if ( empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
1262
- if ( headers_sent() ) {
1263
  $user = new WP_Error(
1264
  'test_cookie',
1265
  sprintf(
1266
  /* translators: 1: Browser cookie documentation URL, 2: Support forums URL. */
1267
- __( '<strong>Error</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.' ),
1268
- __( 'https://wordpress.org/support/article/cookies/' ),
1269
- __( 'https://wordpress.org/support/forums/' )
1270
  )
1271
  );
1272
- } elseif ( isset( $_POST['testcookie'] ) && empty( $_COOKIE[ TEST_COOKIE ] ) ) {
1273
  // If cookies are disabled, we can't log in even with a valid user and password.
1274
  $user = new WP_Error(
1275
  'test_cookie',
1276
  sprintf(
1277
  /* translators: %s: Browser cookie documentation URL. */
1278
- __( '<strong>Error</strong>: Cookies are blocked or not supported by your browser. You must <a href="%s">enable cookies</a> to use WordPress.' ),
1279
- __( 'https://wordpress.org/support/article/cookies/#enable-cookies-in-your-browser' )
1280
  )
1281
  );
1282
  }
1283
  }
1284
 
1285
- $requested_redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
1286
  /**
1287
  * Filters the login redirect URL.
1288
  *
@@ -1292,24 +1275,23 @@ switch ( $action ) {
1292
  * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
1293
  * @param WP_User|WP_Error $user WP_User object if login was successful, WP_Error object otherwise.
1294
  */
1295
- $redirect_to = apply_filters( 'login_redirect', $redirect_to, $requested_redirect_to, $user );
1296
 
1297
- if ( ! is_wp_error( $user ) && ! $reauth ) {
1298
- if ( $interim_login ) {
1299
- $message = '<p class="message">' . __( 'You have logged in successfully.' ) . '</p>';
1300
  $interim_login = 'success';
1301
- login_header( '', $message );
1302
-
1303
  ?>
1304
  </div>
1305
  <?php
1306
 
1307
- /** This action is documented in wp-login.php */
1308
- do_action( 'login_footer' );
1309
 
1310
- if ( $customize_login ) {
1311
  ?>
1312
- <script type="text/javascript">setTimeout( function(){ new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); ?>', channel: 'login' }).send('login') }, 1000 );</script>
1313
  <?php
1314
  }
1315
 
@@ -1321,80 +1303,80 @@ switch ( $action ) {
1321
  }
1322
 
1323
  // Check if it is time to add a redirect to the admin email confirmation screen.
1324
- if ( is_a( $user, 'WP_User' ) && $user->exists() && $user->has_cap( 'manage_options' ) ) {
1325
- $admin_email_lifespan = (int) get_option( 'admin_email_lifespan' );
1326
 
1327
  // If `0` (or anything "falsey" as it is cast to int) is returned, the user will not be redirected
1328
  // to the admin email confirmation screen.
1329
- /** This filter is documented in wp-login.php */
1330
- $admin_email_check_interval = (int) apply_filters( 'admin_email_check_interval', 6 * MONTH_IN_SECONDS );
1331
 
1332
- if ( $admin_email_check_interval > 0 && time() > $admin_email_lifespan ) {
1333
  $redirect_to = add_query_arg(
1334
  array(
1335
  'action' => 'confirm_admin_email',
1336
- 'wp_lang' => get_user_locale( $user ),
1337
  ),
1338
- wp_login_url( $redirect_to )
1339
  );
1340
  }
1341
  }
1342
 
1343
- if ( ( empty( $redirect_to ) || 'wp-admin/' === $redirect_to || admin_url() === $redirect_to ) ) {
1344
  // If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
1345
- if ( is_multisite() && ! get_active_blog_for_user( $user->ID ) && ! is_super_admin( $user->ID ) ) {
1346
  $redirect_to = user_admin_url();
1347
- } elseif ( is_multisite() && ! $user->has_cap( 'read' ) ) {
1348
- $redirect_to = get_dashboard_url( $user->ID );
1349
- } elseif ( ! $user->has_cap( 'edit_posts' ) ) {
1350
- $redirect_to = $user->has_cap( 'read' ) ? admin_url( 'profile.php' ) : home_url();
1351
  }
1352
 
1353
- wp_redirect( $redirect_to );
1354
  exit;
1355
  }
1356
 
1357
- wp_safe_redirect( $redirect_to );
1358
  exit;
1359
  }
1360
 
1361
  $errors = $user;
1362
  // Clear errors if loggedout is set.
1363
- if ( ! empty( $_GET['loggedout'] ) || $reauth ) {
1364
  $errors = new WP_Error();
1365
  }
1366
 
1367
- if ( empty( $_POST ) && $errors->get_error_codes() === array( 'empty_username', 'empty_password' ) ) {
1368
- $errors = new WP_Error( '', '' );
1369
  }
1370
 
1371
- if ( $interim_login ) {
1372
- if ( ! $errors->has_errors() ) {
1373
- $errors->add( 'expired', __( 'Your session has expired. Please log in to continue where you left off.' ), 'message' );
1374
  }
1375
  } else {
1376
  // Some parts of this script use the main login form to display a message.
1377
- if ( isset( $_GET['loggedout'] ) && $_GET['loggedout'] ) {
1378
- $errors->add( 'loggedout', __( 'You are now logged out.' ), 'message' );
1379
- } elseif ( isset( $_GET['registration'] ) && 'disabled' === $_GET['registration'] ) {
1380
- $errors->add( 'registerdisabled', __( 'User registration is currently not allowed.' ) );
1381
- } elseif ( strpos( $redirect_to, 'about.php?updated' ) ) {
1382
- $errors->add( 'updated', __( '<strong>You have successfully updated WordPress!</strong> Please log back in to see what&#8217;s new.' ), 'message' );
1383
- } elseif ( WP_Recovery_Mode_Link_Service::LOGIN_ACTION_ENTERED === $action ) {
1384
- $errors->add( 'enter_recovery_mode', __( 'Recovery Mode Initialized. Please log in to continue.' ), 'message' );
1385
- } elseif ( isset( $_GET['redirect_to'] ) && false !== strpos( $_GET['redirect_to'], 'wp-admin/authorize-application.php' ) ) {
1386
- $query_component = wp_parse_url( $_GET['redirect_to'], PHP_URL_QUERY );
1387
- parse_str( $query_component, $query );
1388
-
1389
- if ( ! empty( $query['app_name'] ) ) {
1390
  /* translators: 1: Website name, 2: Application name. */
1391
- $message = sprintf( 'Please log in to %1$s to authorize %2$s to connect to your account.', get_bloginfo( 'name', 'display' ), '<strong>' . esc_html( $query['app_name'] ) . '</strong>' );
1392
  } else {
1393
  /* translators: %s: Website name. */
1394
- $message = sprintf( 'Please log in to %s to proceed with authorization.', get_bloginfo( 'name', 'display' ) );
1395
  }
1396
 
1397
- $errors->add( 'authorize_application', $message, 'message' );
1398
  }
1399
  }
1400
 
@@ -1406,49 +1388,49 @@ switch ( $action ) {
1406
  * @param WP_Error $errors WP Error object.
1407
  * @param string $redirect_to Redirect destination URL.
1408
  */
1409
- $errors = apply_filters( 'wp_login_errors', $errors, $redirect_to );
1410
 
1411
  // Clear any stale cookies.
1412
- if ( $reauth ) {
1413
  wp_clear_auth_cookie();
1414
  }
1415
 
1416
- login_header( __( 'Log In' ), '', $errors );
1417
 
1418
- if ( isset( $_POST['log'] ) ) {
1419
- $user_login = ( 'incorrect_password' === $errors->get_error_code() || 'empty_password' === $errors->get_error_code() ) ? esc_attr( wp_unslash( $_POST['log'] ) ) : '';
1420
  }
1421
 
1422
- $rememberme = ! empty( $_POST['rememberme'] );
1423
 
1424
- if ( $errors->has_errors() ) {
1425
  $aria_describedby_error = ' aria-describedby="login_error"';
1426
  } else {
1427
  $aria_describedby_error = '';
1428
  }
1429
 
1430
- wp_enqueue_script( 'user-profile' );
1431
 
1432
  //aiowps - this check is necessary because otherwise if variables are undefined we get a warning!
1433
- if(empty($user_login)){
1434
  $user_login = '';
1435
- }
1436
- if(empty($error)){
1437
  $error = '';
1438
- }
1439
  ?>
1440
 
1441
- <form name="loginform" id="loginform" action="<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ); ?>" method="post">
1442
  <p>
1443
- <label for="user_login"><?php _e( 'Username or Email Address' ); ?></label>
1444
- <input type="text" name="log" id="user_login"<?php echo $aria_describedby_error; ?> class="input" value="<?php echo esc_attr( $user_login ); ?>" size="20" autocapitalize="off" />
1445
  </p>
1446
 
1447
  <div class="user-pass-wrap">
1448
- <label for="user_pass"><?php _e( 'Password' ); ?></label>
1449
  <div class="wp-pwd">
1450
  <input type="password" name="pwd" id="user_pass"<?php echo $aria_describedby_error; ?> class="input password-input" value="" size="20" />
1451
- <button type="button" class="button button-secondary wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Show password' ); ?>">
1452
  <span class="dashicons dashicons-visibility" aria-hidden="true"></span>
1453
  </button>
1454
  </div>
@@ -1460,25 +1442,24 @@ switch ( $action ) {
1460
  *
1461
  * @since 2.1.0
1462
  */
1463
- do_action( 'login_form' );
1464
-
1465
  ?>
1466
- <p class="forgetmenot"><input name="rememberme" type="checkbox" id="rememberme" value="forever" <?php checked( $rememberme ); ?> /> <label for="rememberme"><?php esc_html_e( 'Remember Me' ); ?></label></p>
1467
  <p class="submit">
1468
- <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Log In' ); ?>" />
1469
  <?php
1470
 
1471
- if ( $interim_login ) {
1472
  ?>
1473
  <input type="hidden" name="interim-login" value="1" />
1474
  <?php
1475
  } else {
1476
  ?>
1477
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
1478
  <?php
1479
  }
1480
 
1481
- if ( $customize_login ) {
1482
  ?>
1483
  <input type="hidden" name="customize-login" value="1" />
1484
  <?php
@@ -1491,42 +1472,42 @@ switch ( $action ) {
1491
 
1492
  <?php
1493
 
1494
- if ( ! $interim_login ) {
1495
  ?>
1496
  <p id="nav">
1497
  <?php
1498
 
1499
- if ( get_option( 'users_can_register' ) ) {
1500
- $registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
1501
 
1502
- /** This filter is documented in wp-includes/general-template.php */
1503
- echo apply_filters( 'register', $registration_url );
1504
 
1505
- echo esc_html( $login_link_separator );
1506
  }
1507
 
1508
  ?>
1509
- <a href="<?php echo esc_url( wp_lostpassword_url() ); ?>"><?php _e( 'Lost your password?' ); ?></a>
1510
  </p>
1511
  <?php
1512
  }
1513
 
1514
  $login_script = 'function wp_attempt_focus() {';
1515
- $login_script .= 'setTimeout( function() {';
1516
  $login_script .= 'try {';
1517
 
1518
- if ( $user_login ) {
1519
- $login_script .= 'd = document.getElementById( "user_pass" ); d.value = "";';
1520
  } else {
1521
- $login_script .= 'd = document.getElementById( "user_login" );';
1522
 
1523
- if ( $errors->get_error_code() === 'invalid_username' ) {
1524
  $login_script .= 'd.value = "";';
1525
  }
1526
  }
1527
 
1528
  $login_script .= 'd.focus(); d.select();';
1529
- $login_script .= '} catch( er ) {}';
1530
  $login_script .= '}, 200);';
1531
  $login_script .= "}\n"; // End of wp_attempt_focus().
1532
 
@@ -1537,32 +1518,31 @@ switch ( $action ) {
1537
  *
1538
  * @param bool $print Whether to print the function call. Default true.
1539
  */
1540
- if ( apply_filters( 'enable_login_autofocus', true ) && ! $error ) {
1541
  $login_script .= "wp_attempt_focus();\n";
1542
  }
1543
 
1544
  // Run `wpOnload()` if defined.
1545
- $login_script .= "if ( typeof wpOnload === 'function' ) { wpOnload() }";
1546
-
1547
  ?>
1548
  <script type="text/javascript">
1549
  <?php echo $login_script; ?>
1550
  </script>
1551
  <?php
1552
 
1553
- if ( $interim_login ) {
1554
  ?>
1555
  <script type="text/javascript">
1556
- ( function() {
1557
  try {
1558
- var i, links = document.getElementsByTagName( 'a' );
1559
- for ( i in links ) {
1560
- if ( links[i].href ) {
1561
  links[i].target = '_blank';
1562
  links[i].rel = 'noopener';
1563
  }
1564
  }
1565
- } catch( er ) {}
1566
  }());
1567
  </script>
1568
  <?php
8
  * @package WordPress
9
  */
10
 
11
+ // Make sure that the WordPress bootstrap has run before continuing.
12
+ // aiowps - for our special case we do not want to include wp-load.php
 
13
  //require __DIR__ . '/wp-load.php';
14
 
15
  // Redirect to HTTPS login if forced to use SSL.
16
+ if (force_ssl_admin() && ! is_ssl()) {
17
+ if (0 === strpos($_SERVER['REQUEST_URI'], 'http')) {
18
+ wp_safe_redirect(set_url_scheme($_SERVER['REQUEST_URI'], 'https'));
19
  exit;
20
  } else {
21
+ wp_safe_redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
22
  exit;
23
  }
24
  }
39
  * @param string $message Optional. Message to display in header. Default empty.
40
  * @param WP_Error $wp_error Optional. The error to pass. Default is a WP_Error instance.
41
  */
42
+ function login_header($title = 'Log In', $message = '', $wp_error = null) {
43
  global $error, $interim_login, $action;
44
 
45
  // Don't index any of these forms.
46
+ add_action('login_head', 'wp_sensitive_page_meta');
47
 
48
+ add_action('login_head', 'wp_login_viewport_meta');
49
 
50
+ if (! is_wp_error($wp_error)) {
51
  $wp_error = new WP_Error();
52
  }
53
 
54
  // Shake it!
55
+ $shake_error_codes = array('empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password', 'retrieve_password_email_failure');
56
  /**
57
  * Filters the error codes array for shaking the login form.
58
  *
60
  *
61
  * @param array $shake_error_codes Error codes that shake the login form.
62
  */
63
+ $shake_error_codes = apply_filters('shake_error_codes', $shake_error_codes);
64
 
65
+ if ($shake_error_codes && $wp_error->has_errors() && in_array($wp_error->get_error_code(), $shake_error_codes, true)) {
66
+ add_action('login_footer', 'wp_shake_js', 12);
67
  }
68
 
69
+ $login_title = get_bloginfo('name', 'display');
70
 
71
  /* translators: Login screen title. 1: Login screen name, 2: Network or site name. */
72
+ $login_title = sprintf(__('%1$s &lsaquo; %2$s &#8212; WordPress'), $title, $login_title);
73
 
74
+ if (wp_is_recovery_mode()) {
75
  /* translators: %s: Login screen title. */
76
+ $login_title = sprintf(__('Recovery Mode &#8212; %s'), $login_title);
77
  }
78
 
79
  /**
84
  * @param string $login_title The page title, with extra context added.
85
  * @param string $title The original page title.
86
  */
87
+ $login_title = apply_filters('login_title', $login_title, $title);
88
 
89
  ?><!DOCTYPE html>
90
  <html <?php language_attributes(); ?>>
91
  <head>
92
+ <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
93
  <title><?php echo $login_title; ?></title>
94
  <?php
95
 
96
+ wp_enqueue_style('login');
97
 
98
  /*
99
  * Remove all stored post data on logging out.
100
  * This could be added by add_action('login_head'...) like wp_shake_js(),
101
  * but maybe better if it's not removable by plugins.
102
  */
103
+ if ('loggedout' === $wp_error->get_error_code()) {
104
  ?>
105
+ <script>if ("sessionStorage" in window) {try{for(var key in sessionStorage) {if (key.indexOf("wp-autosave-")!=-1) {sessionStorage.removeItem(key)}}}catch(e) {}};</script>
106
  <?php
107
  }
108
 
111
  *
112
  * @since 3.1.0
113
  */
114
+ do_action('login_enqueue_scripts');
115
 
116
  /**
117
  * Fires in the login page header after scripts are enqueued.
118
  *
119
  * @since 2.1.0
120
  */
121
+ do_action('login_head');
122
 
123
+ $login_header_url = __('https://wordpress.org/');
124
 
125
  /**
126
  * Filters link URL of the header logo above login form.
129
  *
130
  * @param string $login_header_url Login header logo URL.
131
  */
132
+ $login_header_url = apply_filters('login_headerurl', $login_header_url);
133
 
134
  $login_header_title = '';
135
 
143
  */
144
  $login_header_title = apply_filters_deprecated(
145
  'login_headertitle',
146
+ array($login_header_title),
147
  '5.2.0',
148
  'login_headertext',
149
+ __('Usage of the title attribute on the login logo is not recommended for accessibility reasons. Use the link text instead.')
150
  );
151
 
152
+ $login_header_text = empty($login_header_title) ? __('Powered by WordPress') : $login_header_title;
153
 
154
  /**
155
  * Filters the link text of the header logo above the login form.
158
  *
159
  * @param string $login_header_text The login header logo link text.
160
  */
161
+ $login_header_text = apply_filters('login_headertext', $login_header_text);
162
 
163
+ $classes = array('login-action-' . $action, 'wp-core-ui');
164
 
165
+ if (is_rtl()) {
166
  $classes[] = 'rtl';
167
  }
168
 
169
+ if ($interim_login) {
170
  $classes[] = 'interim-login';
 
171
  ?>
172
  <style type="text/css">html{background-color: transparent;}</style>
173
  <?php
174
 
175
+ if ('success' === $interim_login) {
176
  $classes[] = 'interim-login-success';
177
  }
178
  }
179
 
180
+ $classes[] = ' locale-' . sanitize_html_class(strtolower(str_replace('_', '-', get_locale())));
181
 
182
  /**
183
  * Filters the login page body classes.
187
  * @param array $classes An array of body classes.
188
  * @param string $action The action that brought the visitor to the login page.
189
  */
190
+ $classes = apply_filters('login_body_class', $classes, $action);
 
191
  ?>
192
  </head>
193
+ <body class="login no-js <?php echo esc_attr(implode(' ', $classes)); ?>">
194
  <script type="text/javascript">
195
  document.body.className = document.body.className.replace('no-js','js');
196
  </script>
200
  *
201
  * @since 4.6.0
202
  */
203
+ do_action('login_header');
 
204
  ?>
205
  <div id="login">
206
+ <h1><a href="<?php echo esc_url($login_header_url); ?>"><?php echo $login_header_text; ?></a></h1>
207
  <?php
208
  /**
209
  * Filters the message to display above the login form.
212
  *
213
  * @param string $message Login message text.
214
  */
215
+ $message = apply_filters('login_message', $message);
216
 
217
+ if (! empty($message)) {
218
  echo $message . "\n";
219
  }
220
 
221
  // In case a plugin uses $error rather than the $wp_errors object.
222
+ if (! empty($error)) {
223
+ $wp_error->add('error', $error);
224
+ unset($error);
225
  }
226
 
227
+ if ($wp_error->has_errors()) {
228
  $errors = '';
229
  $messages = '';
230
 
231
+ foreach ($wp_error->get_error_codes() as $code) {
232
+ $severity = $wp_error->get_error_data($code);
233
+ foreach ($wp_error->get_error_messages($code) as $error_message) {
234
+ if ('message' === $severity) {
235
  $messages .= ' ' . $error_message . "<br />\n";
236
  } else {
237
  $errors .= ' ' . $error_message . "<br />\n";
239
  }
240
  }
241
 
242
+ if (! empty($errors)) {
243
  /**
244
  * Filters the error messages displayed above the login form.
245
  *
247
  *
248
  * @param string $errors Login error message.
249
  */
250
+ echo '<div id="login_error">' . apply_filters('login_errors', $errors) . "</div>\n";
251
  }
252
 
253
+ if (! empty($messages)) {
254
  /**
255
  * Filters instructional messages displayed above the login form.
256
  *
258
  *
259
  * @param string $messages Login messages.
260
  */
261
+ echo '<p class="message">' . apply_filters('login_messages', $messages) . "</p>\n";
262
  }
263
  }
264
  } // End of login_header().
273
  *
274
  * @param string $input_id Which input to auto-focus.
275
  */
276
+ function login_footer($input_id = '') {
277
  global $interim_login;
278
 
279
  // Don't allow interim logins to navigate away from the page.
280
+ if (! $interim_login) {
281
  ?>
282
+ <p id="backtoblog"><a href="<?php echo esc_url(home_url('/')); ?>">
283
  <?php
284
 
285
  /* translators: %s: Site title. */
286
+ printf(_x('&larr; Go to %s', 'site'), get_bloginfo('title', 'display'));
 
287
  ?>
288
  </a></p>
289
  <?php
290
 
291
+ the_privacy_policy_link('<div class="privacy-policy-page-link">', '</div>');
292
  }
293
 
294
  ?>
296
 
297
  <?php
298
 
299
+ if (! empty($input_id)) {
300
  ?>
301
  <script type="text/javascript">
302
+ try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e) {}
303
+ if (typeof wpOnload=='function')wpOnload();
304
  </script>
305
  <?php
306
  }
310
  *
311
  * @since 3.1.0
312
  */
313
+ do_action('login_footer');
 
314
  ?>
315
  <div class="clear"></div>
316
  </body>
353
  $errors = new WP_Error();
354
  $user_data = false;
355
 
356
+ if (empty($_POST['user_login']) || ! is_string($_POST['user_login'])) {
357
+ $errors->add('empty_username', __('<strong>Error</strong>: Please enter a username or email address.'));
358
+ } elseif (strpos($_POST['user_login'], '@')) {
359
+ $user_data = get_user_by('email', trim(wp_unslash($_POST['user_login'])));
360
+ if (empty($user_data)) {
361
+ $errors->add('invalid_email', __('<strong>Error</strong>: There is no account with that username or email address.'));
362
  }
363
  } else {
364
+ $login = trim(wp_unslash($_POST['user_login']));
365
+ $user_data = get_user_by('login', $login);
366
  }
367
 
368
  /**
376
  * by using invalid credentials.
377
  * @param WP_User|false $user_data WP_User object if found, false if the user does not exist.
378
  */
379
+ do_action('lostpassword_post', $errors, $user_data);
380
 
381
  /**
382
  * Filters the errors encountered on a password reset request.
393
  * by using invalid credentials.
394
  * @param WP_User|false $user_data WP_User object if found, false if the user does not exist.
395
  */
396
+ $errors = apply_filters('lostpassword_errors', $errors, $user_data);
397
 
398
+ if ($errors->has_errors()) {
399
  return $errors;
400
  }
401
 
402
+ if (! $user_data) {
403
+ $errors->add('invalidcombo', __('<strong>Error</strong>: There is no account with that username or email address.'));
404
  return $errors;
405
  }
406
 
407
  // Redefining user_login ensures we return the right case in the email.
408
  $user_login = $user_data->user_login;
409
  $user_email = $user_data->user_email;
410
+ $key = get_password_reset_key($user_data);
411
 
412
+ if (is_wp_error($key)) {
413
  return $key;
414
  }
415
 
416
+ if (is_multisite()) {
417
  $site_name = get_network()->site_name;
418
  } else {
419
  /*
420
  * The blogname option is escaped with esc_html on the way into the database
421
  * in sanitize_option. We want to reverse this for the plain text arena of emails.
422
  */
423
+ $site_name = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
424
  }
425
 
426
+ $message = __('Someone has requested a password reset for the following account:') . "\r\n\r\n";
427
  /* translators: %s: Site name. */
428
+ $message .= sprintf(__('Site Name: %s'), $site_name) . "\r\n\r\n";
429
  /* translators: %s: User login. */
430
+ $message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n";
431
+ $message .= __('If this was a mistake, ignore this email and nothing will happen.') . "\r\n\r\n";
432
+ $message .= __('To reset your password, visit the following address:') . "\r\n\r\n";
433
+ $message .= network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . "\r\n\r\n";
434
 
435
  $requester_ip = $_SERVER['REMOTE_ADDR'];
436
+ if ($requester_ip) {
437
  $message .= sprintf(
438
  /* translators: %s: IP address of password reset requester. */
439
+ __('This password reset request originated from the IP address %s.'),
440
  $requester_ip
441
  ) . "\r\n";
442
  }
443
 
444
  /* translators: Password reset notification email subject. %s: Site title. */
445
+ $title = sprintf(__('[%s] Password Reset'), $site_name);
446
 
447
  /**
448
  * Filters the subject of the password reset email.
454
  * @param string $user_login The username for the user.
455
  * @param WP_User $user_data WP_User object.
456
  */
457
+ $title = apply_filters('retrieve_password_title', $title, $user_login, $user_data);
458
 
459
  /**
460
  * Filters the message body of the password reset mail.
469
  * @param string $user_login The username for the user.
470
  * @param WP_User $user_data WP_User object.
471
  */
472
+ $message = apply_filters('retrieve_password_message', $message, $key, $user_login, $user_data);
473
 
474
+ if ($message && ! wp_mail($user_email, wp_specialchars_decode($title), $message)) {
475
  $errors->add(
476
  'retrieve_password_email_failure',
477
  sprintf(
478
  /* translators: %s: Documentation URL. */
479
+ __('<strong>Error</strong>: The email could not be sent. Your site may not be correctly configured to send emails. <a href="%s">Get support for resetting your password</a>.'),
480
+ esc_url(__('https://wordpress.org/support/article/resetting-your-password/'))
481
  )
482
  );
483
  return $errors;
490
  // Main.
491
  //
492
 
493
+ $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'login';
494
  $errors = new WP_Error();
495
 
496
+ if (isset($_GET['key'])) {
497
  $action = 'resetpass';
498
  }
499
 
500
+ if (isset($_GET['checkemail'])) {
501
  $action = 'checkemail';
502
  }
503
 
517
  );
518
 
519
  // Validate action so as to default to the login screen.
520
+ if (! in_array($action, $default_actions, true) && false === has_filter('login_form_' . $action)) {
521
  $action = 'login';
522
  }
523
 
524
  nocache_headers();
525
 
526
+ header('Content-Type: ' . get_bloginfo('html_type') . '; charset=' . get_bloginfo('charset'));
527
 
528
+ if (defined('RELOCATE') && RELOCATE) { // Move flag is set.
529
+ if (isset($_SERVER['PATH_INFO']) && ($_SERVER['PATH_INFO'] !== $_SERVER['PHP_SELF'])) {
530
+ $_SERVER['PHP_SELF'] = str_replace($_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF']);
531
  }
532
 
533
+ $url = dirname(set_url_scheme('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']));
534
 
535
+ if (get_option('siteurl') !== $url) {
536
+ update_option('siteurl', $url);
537
  }
538
  }
539
 
540
  // Set a cookie now to see if they are supported by the browser.
541
+ $secure = ('https' === parse_url(wp_login_url(), PHP_URL_SCHEME));
542
+ setcookie(TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN, $secure);
543
 
544
+ if (SITECOOKIEPATH !== COOKIEPATH) {
545
+ setcookie(TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN, $secure);
546
  }
547
 
548
  /**
550
  *
551
  * @since 3.2.0
552
  */
553
+ do_action('login_init');
554
 
555
  /**
556
  * Fires before a specified login form action.
561
  *
562
  * @since 2.8.0
563
  */
564
+ do_action("login_form_{$action}");
565
 
566
+ $http_post = ('POST' === $_SERVER['REQUEST_METHOD']);
567
+ $interim_login = isset($_REQUEST['interim-login']);
568
 
569
  /**
570
  * Filters the separator used between login form navigation links.
573
  *
574
  * @param string $login_link_separator The separator used between login form navigation links.
575
  */
576
+ $login_link_separator = apply_filters('login_link_separator', ' | ');
577
 
578
+ switch ($action) {
579
 
580
  case 'confirm_admin_email':
581
  /*
583
  * as the current user is not set, see wp-includes/pluggable.php.
584
  * However this action runs on a redirect after logging in.
585
  */
586
+ if (! is_user_logged_in()) {
587
+ wp_safe_redirect(wp_login_url());
588
  exit;
589
  }
590
 
591
+ if (! empty($_REQUEST['redirect_to'])) {
592
  $redirect_to = $_REQUEST['redirect_to'];
593
  } else {
594
  $redirect_to = admin_url();
595
  }
596
 
597
+ if (current_user_can('manage_options')) {
598
+ $admin_email = get_option('admin_email');
599
  } else {
600
+ wp_safe_redirect($redirect_to);
601
  exit;
602
  }
603
 
610
  *
611
  * @param int $interval Interval time (in seconds). Default is 3 days.
612
  */
613
+ $remind_interval = (int) apply_filters('admin_email_remind_interval', 3 * DAY_IN_SECONDS);
614
 
615
+ if (! empty($_GET['remind_me_later'])) {
616
+ if (! wp_verify_nonce($_GET['remind_me_later'], 'remind_me_later_nonce')) {
617
+ wp_safe_redirect(wp_login_url());
618
  exit;
619
  }
620
 
621
+ if ($remind_interval > 0) {
622
+ update_option('admin_email_lifespan', time() + $remind_interval);
623
  }
624
 
625
+ $redirect_to = add_query_arg('admin_email_remind_later', 1, $redirect_to);
626
+ wp_safe_redirect($redirect_to);
627
  exit;
628
  }
629
 
630
+ if (! empty($_POST['correct-admin-email'])) {
631
+ if (! check_admin_referer('confirm_admin_email', 'confirm_admin_email_nonce')) {
632
+ wp_safe_redirect(wp_login_url());
633
  exit;
634
  }
635
 
642
  *
643
  * @param int $interval Interval time (in seconds). Default is 6 months.
644
  */
645
+ $admin_email_check_interval = (int) apply_filters('admin_email_check_interval', 6 * MONTH_IN_SECONDS);
646
 
647
+ if ($admin_email_check_interval > 0) {
648
+ update_option('admin_email_lifespan', time() + $admin_email_check_interval);
649
  }
650
 
651
+ wp_safe_redirect($redirect_to);
652
  exit;
653
  }
654
 
655
+ login_header(__('Confirm your administration email'), '', $errors);
656
 
657
  /**
658
  * Fires before the admin email confirm form.
662
  * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
663
  * credentials. Note that the error object may not contain any errors.
664
  */
665
+ do_action('admin_email_confirm', $errors);
 
666
  ?>
667
 
668
+ <form class="admin-email-confirm-form" name="admin-email-confirm-form" action="<?php echo esc_url(site_url('wp-login.php?action=confirm_admin_email', 'login_post')); ?>" method="post">
669
  <?php
670
  /**
671
  * Fires inside the admin-email-confirm-form form tags, before the hidden fields.
672
  *
673
  * @since 5.3.0
674
  */
675
+ do_action('admin_email_confirm_form');
 
 
676
 
677
+ wp_nonce_field('confirm_admin_email', 'confirm_admin_email_nonce');
678
  ?>
679
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
680
 
681
  <h1 class="admin-email__heading">
682
+ <?php _e('Administration email verification'); ?>
683
  </h1>
684
  <p class="admin-email__details">
685
+ <?php _e('Please verify that the <strong>administration email</strong> for this website is still correct.'); ?>
686
  <?php
687
 
688
  /* translators: URL to the WordPress help section about admin email. */
689
+ $admin_email_help_url = __('https://wordpress.org/support/article/settings-general-screen/#email-address');
690
 
691
  /* translators: Accessibility text. */
692
+ $accessibility_text = sprintf('<span class="screen-reader-text"> %s</span>', __('(opens in a new tab)'));
693
 
694
  printf(
695
  '<a href="%s" rel="noopener" target="_blank">%s%s</a>',
696
+ esc_url($admin_email_help_url),
697
+ __('Why is this important?'),
698
  $accessibility_text
699
  );
 
700
  ?>
701
  </p>
702
  <p class="admin-email__details">
704
 
705
  printf(
706
  /* translators: %s: Admin email address. */
707
+ __('Current administration email: %s'),
708
+ '<strong>' . esc_html($admin_email) . '</strong>'
709
  );
 
710
  ?>
711
  </p>
712
  <p class="admin-email__details">
713
+ <?php _e('This email may be different from your personal email address.'); ?>
714
  </p>
715
 
716
  <div class="admin-email__actions">
717
  <div class="admin-email__actions-primary">
718
  <?php
719
 
720
+ $change_link = admin_url('options-general.php');
721
+ $change_link = add_query_arg('highlight', 'confirm_admin_email', $change_link);
 
722
  ?>
723
+ <a class="button button-large" href="<?php echo esc_url($change_link); ?>"><?php _e('Update'); ?></a>
724
+ <input type="submit" name="correct-admin-email" id="correct-admin-email" class="button button-primary button-large" value="<?php esc_attr_e('The email is correct'); ?>" />
725
  </div>
726
+ <?php if ($remind_interval > 0) : ?>
727
  <div class="admin-email__actions-secondary">
728
  <?php
729
 
730
+ $remind_me_link = wp_login_url($redirect_to);
731
  $remind_me_link = add_query_arg(
732
  array(
733
  'action' => 'confirm_admin_email',
734
+ 'remind_me_later' => wp_create_nonce('remind_me_later_nonce'),
735
  ),
736
  $remind_me_link
737
  );
 
738
  ?>
739
+ <a href="<?php echo esc_url($remind_me_link); ?>"><?php _e('Remind me later'); ?></a>
740
  </div>
741
  <?php endif; ?>
742
  </div>
748
  break;
749
 
750
  case 'postpass':
751
+ if (! array_key_exists('post_password', $_POST)) {
752
+ wp_safe_redirect(wp_get_referer());
753
  exit;
754
  }
755
 
756
  require_once ABSPATH . WPINC . '/class-phpass.php';
757
+ $hasher = new PasswordHash(8, true);
758
 
759
  /**
760
  * Filters the life span of the post password cookie.
766
  *
767
  * @param int $expires The expiry time, as passed to setcookie().
768
  */
769
+ $expire = apply_filters('post_password_expires', time() + 10 * DAY_IN_SECONDS);
770
  $referer = wp_get_referer();
771
 
772
+ if ($referer) {
773
+ $secure = ('https' === parse_url($referer, PHP_URL_SCHEME));
774
  } else {
775
  $secure = false;
776
  }
777
 
778
+ setcookie('wp-postpass_' . COOKIEHASH, $hasher->HashPassword(wp_unslash($_POST['post_password'])), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure);
779
 
780
+ wp_safe_redirect(wp_get_referer());
781
  exit;
782
 
783
  case 'logout':
784
+ check_admin_referer('log-out');
785
 
786
  $user = wp_get_current_user();
787
 
788
  wp_logout();
789
 
790
+ if (! empty($_REQUEST['redirect_to'])) {
791
  $redirect_to = $_REQUEST['redirect_to'];
792
  $requested_redirect_to = $redirect_to;
793
  } else {
794
  $redirect_to = add_query_arg(
795
  array(
796
  'loggedout' => 'true',
797
+ 'wp_lang' => get_user_locale($user),
798
  ),
799
  wp_login_url()
800
  );
811
  * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
812
  * @param WP_User $user The WP_User object for the user that's logging out.
813
  */
814
+ $redirect_to = apply_filters('logout_redirect', $redirect_to, $requested_redirect_to, $user);
815
 
816
+ wp_safe_redirect($redirect_to);
817
  exit;
818
 
819
  case 'lostpassword':
820
  case 'retrievepassword':
821
+ if ($http_post) {
822
  $errors = retrieve_password();
823
 
824
+ if (! is_wp_error($errors)) {
825
+ $redirect_to = ! empty($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
826
+ wp_safe_redirect($redirect_to);
827
  exit;
828
  }
829
  }
830
 
831
+ if (isset($_GET['error'])) {
832
+ if ('invalidkey' === $_GET['error']) {
833
+ $errors->add('invalidkey', __('Your password reset link appears to be invalid. Please request a new link below.'));
834
+ } elseif ('expiredkey' === $_GET['error']) {
835
+ $errors->add('expiredkey', __('Your password reset link has expired. Please request a new link below.'));
836
  }
837
  }
838
 
839
+ $lostpassword_redirect = ! empty($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : '';
840
  /**
841
  * Filters the URL redirected to after submitting the lostpassword/retrievepassword form.
842
  *
844
  *
845
  * @param string $lostpassword_redirect The redirect destination URL.
846
  */
847
+ $redirect_to = apply_filters('lostpassword_redirect', $lostpassword_redirect);
848
 
849
  /**
850
  * Fires before the lost password form.
855
  * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
856
  * credentials. Note that the error object may not contain any errors.
857
  */
858
+ do_action('lost_password', $errors);
859
 
860
+ login_header(__('Lost Password'), '<p class="message">' . __('Please enter your username or email address. You will receive an email message with instructions on how to reset your password.') . '</p>', $errors);
861
 
862
  $user_login = '';
863
 
864
+ if (isset($_POST['user_login']) && is_string($_POST['user_login'])) {
865
+ $user_login = wp_unslash($_POST['user_login']);
866
  }
867
 
868
  ?>
869
 
870
+ <form name="lostpasswordform" id="lostpasswordform" action="<?php echo esc_url(network_site_url('wp-login.php?action=lostpassword', 'login_post')); ?>" method="post">
871
  <p>
872
+ <label for="user_login"><?php _e('Username or Email Address'); ?></label>
873
+ <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr($user_login); ?>" size="20" autocapitalize="off" />
874
  </p>
875
  <?php
876
 
879
  *
880
  * @since 2.1.0
881
  */
882
+ do_action('lostpassword_form');
 
883
  ?>
884
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
885
  <p class="submit">
886
+ <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Get New Password'); ?>" />
887
  </p>
888
  </form>
889
 
890
  <p id="nav">
891
+ <a href="<?php echo esc_url(wp_login_url()); ?>"><?php _e('Log in'); ?></a>
892
  <?php
893
 
894
+ if (get_option('users_can_register')) {
895
+ $registration_url = sprintf('<a href="%s">%s</a>', esc_url(wp_registration_url()), __('Register'));
896
 
897
+ echo esc_html($login_link_separator);
898
 
899
+ // This filter is documented in wp-includes/general-template.php
900
+ echo apply_filters('register', $registration_url);
901
  }
902
 
903
  ?>
904
  </p>
905
  <?php
906
 
907
+ login_footer('user_login');
908
  break;
909
 
910
  case 'resetpass':
911
  case 'rp':
912
+ list($rp_path) = explode('?', wp_unslash($_SERVER['REQUEST_URI']));
913
  $rp_cookie = 'wp-resetpass-' . COOKIEHASH;
914
 
915
+ if (isset($_GET['key'])) {
916
+ $value = sprintf('%s:%s', wp_unslash($_GET['login']), wp_unslash($_GET['key']));
917
+ setcookie($rp_cookie, $value, 0, $rp_path, COOKIE_DOMAIN, is_ssl(), true);
918
 
919
+ wp_safe_redirect(remove_query_arg(array('key', 'login')));
920
  exit;
921
  }
922
 
923
+ if (isset($_COOKIE[$rp_cookie]) && 0 < strpos($_COOKIE[$rp_cookie], ':')) {
924
+ list($rp_login, $rp_key) = explode(':', wp_unslash($_COOKIE[$rp_cookie]), 2);
925
 
926
+ $user = check_password_reset_key($rp_key, $rp_login);
927
 
928
+ if (isset($_POST['pass1']) && ! hash_equals($rp_key, $_POST['rp_key'])) {
929
  $user = false;
930
  }
931
  } else {
932
  $user = false;
933
  }
934
 
935
+ if (! $user || is_wp_error($user)) {
936
+ setcookie($rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true);
937
 
938
+ if ($user && $user->get_error_code() === 'expired_key') {
939
+ wp_redirect(site_url('wp-login.php?action=lostpassword&error=expiredkey'));
940
  } else {
941
+ wp_redirect(site_url('wp-login.php?action=lostpassword&error=invalidkey'));
942
  }
943
 
944
  exit;
946
 
947
  $errors = new WP_Error();
948
 
949
+ if (isset($_POST['pass1']) && $_POST['pass1'] !== $_POST['pass2']) {
950
+ $errors->add('password_reset_mismatch', __('The passwords do not match.'));
951
  }
952
 
953
  /**
958
  * @param WP_Error $errors WP Error object.
959
  * @param WP_User|WP_Error $user WP_User object if the login and reset key match. WP_Error object otherwise.
960
  */
961
+ do_action('validate_password_reset', $errors, $user);
962
 
963
+ if ((! $errors->has_errors()) && isset($_POST['pass1']) && ! empty($_POST['pass1'])) {
964
+ reset_password($user, $_POST['pass1']);
965
+ setcookie($rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true);
966
+ login_header(__('Password Reset'), '<p class="message reset-pass">' . __('Your password has been reset.') . ' <a href="' . esc_url(wp_login_url()) . '">' . __('Log in') . '</a></p>');
967
  login_footer();
968
  exit;
969
  }
970
 
971
+ wp_enqueue_script('utils');
972
+ wp_enqueue_script('user-profile');
 
 
973
 
974
+ login_header(__('Reset Password'), '<p class="message reset-pass">' . __('Enter your new password below.') . '</p>', $errors);
975
  ?>
976
+ <form name="resetpassform" id="resetpassform" action="<?php echo esc_url(network_site_url('wp-login.php?action=resetpass', 'login_post')); ?>" method="post" autocomplete="off">
977
+ <input type="hidden" id="user_login" value="<?php echo esc_attr($rp_login); ?>" autocomplete="off" />
978
 
979
  <div class="user-pass1-wrap">
980
  <p>
981
+ <label for="pass1"><?php _e('New password'); ?></label>
982
  </p>
983
 
984
  <div class="wp-pwd">
985
+ <input type="password" data-reveal="1" data-pw="<?php echo esc_attr(wp_generate_password(16)); ?>" name="pass1" id="pass1" class="input password-input" size="24" value="" autocomplete="off" aria-describedby="pass-strength-result" />
986
 
987
+ <button type="button" class="button button-secondary wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e('Hide password'); ?>">
988
  <span class="dashicons dashicons-hidden" aria-hidden="true"></span>
989
  </button>
990
+ <div id="pass-strength-result" class="hide-if-no-js" aria-live="polite"><?php _e('Strength indicator'); ?></div>
991
  </div>
992
  <div class="pw-weak">
993
  <input type="checkbox" name="pw_weak" id="pw-weak" class="pw-checkbox" />
994
+ <label for="pw-weak"><?php _e('Confirm use of weak password'); ?></label>
995
  </div>
996
  </div>
997
 
998
  <p class="user-pass2-wrap">
999
+ <label for="pass2"><?php _e('Confirm new password'); ?></label>
1000
  <input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off" />
1001
  </p>
1002
 
1012
  *
1013
  * @param WP_User $user User object of the user whose password is being reset.
1014
  */
1015
+ do_action('resetpass_form', $user);
 
1016
  ?>
1017
+ <input type="hidden" name="rp_key" value="<?php echo esc_attr($rp_key); ?>" />
1018
  <p class="submit">
1019
+ <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Reset Password'); ?>" />
1020
  </p>
1021
  </form>
1022
 
1023
  <p id="nav">
1024
+ <a href="<?php echo esc_url(wp_login_url()); ?>"><?php _e('Log in'); ?></a>
1025
  <?php
1026
 
1027
+ if (get_option('users_can_register')) {
1028
+ $registration_url = sprintf('<a href="%s">%s</a>', esc_url(wp_registration_url()), __('Register'));
1029
 
1030
+ echo esc_html($login_link_separator);
1031
 
1032
+ // This filter is documented in wp-includes/general-template.php
1033
+ echo apply_filters('register', $registration_url);
1034
  }
1035
 
1036
  ?>
1037
  </p>
1038
  <?php
1039
 
1040
+ login_footer('user_pass');
1041
  break;
1042
 
1043
  case 'register':
1044
+ if (is_multisite()) {
1045
  /**
1046
  * Filters the Multisite sign up URL.
1047
  *
1049
  *
1050
  * @param string $sign_up_url The sign up URL.
1051
  */
1052
+ wp_redirect(apply_filters('wp_signup_location', network_site_url('wp-signup.php')));
1053
  exit;
1054
  }
1055
 
1056
+ if (! get_option('users_can_register')) {
1057
+ wp_redirect(site_url('wp-login.php?registration=disabled'));
1058
  exit;
1059
  }
1060
 
1061
  $user_login = '';
1062
  $user_email = '';
1063
 
1064
+ if ($http_post) {
1065
+ if (isset($_POST['user_login']) && is_string($_POST['user_login'])) {
1066
+ $user_login = wp_unslash($_POST['user_login']);
1067
  }
1068
 
1069
+ if (isset($_POST['user_email']) && is_string($_POST['user_email'])) {
1070
+ $user_email = wp_unslash($_POST['user_email']);
1071
  }
1072
 
1073
+ $errors = register_new_user($user_login, $user_email);
1074
 
1075
+ if (! is_wp_error($errors)) {
1076
+ $redirect_to = ! empty($_POST['redirect_to']) ? $_POST['redirect_to'] : 'wp-login.php?checkemail=registered';
1077
+ wp_safe_redirect($redirect_to);
1078
  exit;
1079
  }
1080
  }
1081
 
1082
+ $registration_redirect = ! empty($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : '';
1083
 
1084
  /**
1085
  * Filters the registration redirect URL.
1088
  *
1089
  * @param string $registration_redirect The redirect destination URL.
1090
  */
1091
+ $redirect_to = apply_filters('registration_redirect', $registration_redirect);
 
 
1092
 
1093
+ login_header(__('Registration Form'), '<p class="message register">' . __('Register For This Site') . '</p>', $errors);
1094
  ?>
1095
+ <form name="registerform" id="registerform" action="<?php echo esc_url(site_url('wp-login.php?action=register', 'login_post')); ?>" method="post" novalidate="novalidate">
1096
  <p>
1097
+ <label for="user_login"><?php _e('Username'); ?></label>
1098
+ <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr(wp_unslash($user_login)); ?>" size="20" autocapitalize="off" />
1099
  </p>
1100
  <p>
1101
+ <label for="user_email"><?php _e('Email'); ?></label>
1102
+ <input type="email" name="user_email" id="user_email" class="input" value="<?php echo esc_attr(wp_unslash($user_email)); ?>" size="25" />
1103
  </p>
1104
  <?php
1105
 
1108
  *
1109
  * @since 2.1.0
1110
  */
1111
+ do_action('register_form');
 
1112
  ?>
1113
  <p id="reg_passmail">
1114
+ <?php _e('Registration confirmation will be emailed to you.'); ?>
1115
  </p>
1116
  <br class="clear" />
1117
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
1118
  <p class="submit">
1119
+ <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Register'); ?>" />
1120
  </p>
1121
  </form>
1122
 
1123
  <p id="nav">
1124
+ <a href="<?php echo esc_url(wp_login_url()); ?>"><?php _e('Log in'); ?></a>
1125
+ <?php echo esc_html($login_link_separator); ?>
1126
+ <a href="<?php echo esc_url(wp_lostpassword_url()); ?>"><?php _e('Lost your password?'); ?></a>
1127
  </p>
1128
  <?php
1129
 
1130
+ login_footer('user_login');
1131
  break;
1132
 
1133
  case 'checkemail':
1134
  $redirect_to = admin_url();
1135
  $errors = new WP_Error();
1136
 
1137
+ if ('confirm' === $_GET['checkemail']) {
1138
  $errors->add(
1139
  'confirm',
1140
  sprintf(
1141
  /* translators: %s: Link to the login page. */
1142
+ __('Check your email for the confirmation link, then visit the <a href="%s">login page</a>.'),
1143
  wp_login_url()
1144
  ),
1145
  'message'
1146
  );
1147
+ } elseif ('registered' === $_GET['checkemail']) {
1148
  $errors->add(
1149
  'registered',
1150
  sprintf(
1151
  /* translators: %s: Link to the login page. */
1152
+ __('Registration complete. Please check your email, then visit the <a href="%s">login page</a>.'),
1153
  wp_login_url()
1154
  ),
1155
  'message'
1156
  );
1157
  }
1158
 
1159
+ // This action is documented in wp-login.php
1160
+ $errors = apply_filters('wp_login_errors', $errors, $redirect_to);
1161
 
1162
+ login_header(__('Check your email'), '', $errors);
1163
  login_footer();
1164
  break;
1165
 
1166
  case 'confirmaction':
1167
+ if (! isset($_GET['request_id'])) {
1168
+ wp_die(__('Missing request ID.'));
1169
  }
1170
 
1171
+ if (! isset($_GET['confirm_key'])) {
1172
+ wp_die(__('Missing confirm key.'));
1173
  }
1174
 
1175
  $request_id = (int) $_GET['request_id'];
1176
+ $key = sanitize_text_field(wp_unslash($_GET['confirm_key']));
1177
+ $result = wp_validate_user_request_key($request_id, $key);
1178
 
1179
+ if (is_wp_error($result)) {
1180
+ wp_die($result);
1181
  }
1182
 
1183
  /**
1193
  *
1194
  * @param int $request_id Request ID.
1195
  */
1196
+ do_action('user_request_action_confirmed', $request_id);
1197
 
1198
+ $message = _wp_privacy_account_request_confirmed_message($request_id);
1199
 
1200
+ login_header(__('User action confirmed.'), $message);
1201
  login_footer();
1202
  exit;
1203
 
1204
  case 'login':
1205
  default:
1206
  $secure_cookie = '';
1207
+ $customize_login = isset($_REQUEST['customize-login']);
1208
 
1209
+ if ($customize_login) {
1210
+ wp_enqueue_script('customize-base');
1211
  }
1212
 
1213
  // If the user wants SSL but the session is not SSL, force a secure cookie.
1214
+ if (! empty($_POST['log']) && ! force_ssl_admin()) {
1215
+ $user_name = sanitize_user(wp_unslash($_POST['log']));
1216
+ $user = get_user_by('login', $user_name);
1217
 
1218
+ if (! $user && strpos($user_name, '@')) {
1219
+ $user = get_user_by('email', $user_name);
1220
  }
1221
 
1222
+ if ($user) {
1223
+ if (get_user_option('use_ssl', $user->ID)) {
1224
  $secure_cookie = true;
1225
+ force_ssl_admin(true);
1226
  }
1227
  }
1228
  }
1229
 
1230
+ if (isset($_REQUEST['redirect_to'])) {
1231
  $redirect_to = $_REQUEST['redirect_to'];
1232
  // Redirect to HTTPS if user wants SSL.
1233
+ if ($secure_cookie && false !== strpos($redirect_to, 'wp-admin')) {
1234
+ $redirect_to = preg_replace('|^http://|', 'https://', $redirect_to);
1235
  }
1236
  } else {
1237
  $redirect_to = admin_url();
1238
  }
1239
 
1240
+ $reauth = empty($_REQUEST['reauth']) ? false : true;
1241
 
1242
+ $user = wp_signon(array(), $secure_cookie);
1243
 
1244
+ if (empty($_COOKIE[LOGGED_IN_COOKIE])) {
1245
+ if (headers_sent()) {
1246
  $user = new WP_Error(
1247
  'test_cookie',
1248
  sprintf(
1249
  /* translators: 1: Browser cookie documentation URL, 2: Support forums URL. */
1250
+ __('<strong>Error</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.'),
1251
+ __('https://wordpress.org/support/article/cookies/'),
1252
+ __('https://wordpress.org/support/forums/')
1253
  )
1254
  );
1255
+ } elseif (isset($_POST['testcookie']) && empty($_COOKIE[TEST_COOKIE])) {
1256
  // If cookies are disabled, we can't log in even with a valid user and password.
1257
  $user = new WP_Error(
1258
  'test_cookie',
1259
  sprintf(
1260
  /* translators: %s: Browser cookie documentation URL. */
1261
+ __('<strong>Error</strong>: Cookies are blocked or not supported by your browser. You must <a href="%s">enable cookies</a> to use WordPress.'),
1262
+ __('https://wordpress.org/support/article/cookies/#enable-cookies-in-your-browser')
1263
  )
1264
  );
1265
  }
1266
  }
1267
 
1268
+ $requested_redirect_to = isset($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : '';
1269
  /**
1270
  * Filters the login redirect URL.
1271
  *
1275
  * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
1276
  * @param WP_User|WP_Error $user WP_User object if login was successful, WP_Error object otherwise.
1277
  */
1278
+ $redirect_to = apply_filters('login_redirect', $redirect_to, $requested_redirect_to, $user);
1279
 
1280
+ if (! is_wp_error($user) && ! $reauth) {
1281
+ if ($interim_login) {
1282
+ $message = '<p class="message">' . __('You have logged in successfully.') . '</p>';
1283
  $interim_login = 'success';
1284
+ login_header('', $message);
 
1285
  ?>
1286
  </div>
1287
  <?php
1288
 
1289
+ // This action is documented in wp-login.php
1290
+ do_action('login_footer');
1291
 
1292
+ if ($customize_login) {
1293
  ?>
1294
+ <script type="text/javascript">setTimeout(function() { new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); ?>', channel: 'login' }).send('login') }, 1000);</script>
1295
  <?php
1296
  }
1297
 
1303
  }
1304
 
1305
  // Check if it is time to add a redirect to the admin email confirmation screen.
1306
+ if (is_a($user, 'WP_User') && $user->exists() && $user->has_cap('manage_options')) {
1307
+ $admin_email_lifespan = (int) get_option('admin_email_lifespan');
1308
 
1309
  // If `0` (or anything "falsey" as it is cast to int) is returned, the user will not be redirected
1310
  // to the admin email confirmation screen.
1311
+ // This filter is documented in wp-login.php
1312
+ $admin_email_check_interval = (int) apply_filters('admin_email_check_interval', 6 * MONTH_IN_SECONDS);
1313
 
1314
+ if ($admin_email_check_interval > 0 && time() > $admin_email_lifespan) {
1315
  $redirect_to = add_query_arg(
1316
  array(
1317
  'action' => 'confirm_admin_email',
1318
+ 'wp_lang' => get_user_locale($user),
1319
  ),
1320
+ wp_login_url($redirect_to)
1321
  );
1322
  }
1323
  }
1324
 
1325
+ if ((empty($redirect_to) || 'wp-admin/' === $redirect_to || admin_url() === $redirect_to)) {
1326
  // If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
1327
+ if (is_multisite() && ! get_active_blog_for_user($user->ID) && ! is_super_admin($user->ID)) {
1328
  $redirect_to = user_admin_url();
1329
+ } elseif (is_multisite() && ! $user->has_cap('read')) {
1330
+ $redirect_to = get_dashboard_url($user->ID);
1331
+ } elseif (! $user->has_cap('edit_posts')) {
1332
+ $redirect_to = $user->has_cap('read') ? admin_url('profile.php') : home_url();
1333
  }
1334
 
1335
+ wp_redirect($redirect_to);
1336
  exit;
1337
  }
1338
 
1339
+ wp_safe_redirect($redirect_to);
1340
  exit;
1341
  }
1342
 
1343
  $errors = $user;
1344
  // Clear errors if loggedout is set.
1345
+ if (! empty($_GET['loggedout']) || $reauth) {
1346
  $errors = new WP_Error();
1347
  }
1348
 
1349
+ if (empty($_POST) && $errors->get_error_codes() === array('empty_username', 'empty_password')) {
1350
+ $errors = new WP_Error('', '');
1351
  }
1352
 
1353
+ if ($interim_login) {
1354
+ if (! $errors->has_errors()) {
1355
+ $errors->add('expired', __('Your session has expired. Please log in to continue where you left off.'), 'message');
1356
  }
1357
  } else {
1358
  // Some parts of this script use the main login form to display a message.
1359
+ if (isset($_GET['loggedout']) && $_GET['loggedout']) {
1360
+ $errors->add('loggedout', __('You are now logged out.'), 'message');
1361
+ } elseif (isset($_GET['registration']) && 'disabled' === $_GET['registration']) {
1362
+ $errors->add('registerdisabled', __('User registration is currently not allowed.'));
1363
+ } elseif (strpos($redirect_to, 'about.php?updated')) {
1364
+ $errors->add('updated', __('<strong>You have successfully updated WordPress!</strong> Please log back in to see what&#8217;s new.'), 'message');
1365
+ } elseif (WP_Recovery_Mode_Link_Service::LOGIN_ACTION_ENTERED === $action) {
1366
+ $errors->add('enter_recovery_mode', __('Recovery Mode Initialized. Please log in to continue.'), 'message');
1367
+ } elseif (isset($_GET['redirect_to']) && false !== strpos($_GET['redirect_to'], 'wp-admin/authorize-application.php')) {
1368
+ $query_component = wp_parse_url($_GET['redirect_to'], PHP_URL_QUERY);
1369
+ parse_str($query_component, $query);
1370
+
1371
+ if (! empty($query['app_name'])) {
1372
  /* translators: 1: Website name, 2: Application name. */
1373
+ $message = sprintf('Please log in to %1$s to authorize %2$s to connect to your account.', get_bloginfo('name', 'display'), '<strong>' . esc_html($query['app_name']) . '</strong>');
1374
  } else {
1375
  /* translators: %s: Website name. */
1376
+ $message = sprintf('Please log in to %s to proceed with authorization.', get_bloginfo('name', 'display'));
1377
  }
1378
 
1379
+ $errors->add('authorize_application', $message, 'message');
1380
  }
1381
  }
1382
 
1388
  * @param WP_Error $errors WP Error object.
1389
  * @param string $redirect_to Redirect destination URL.
1390
  */
1391
+ $errors = apply_filters('wp_login_errors', $errors, $redirect_to);
1392
 
1393
  // Clear any stale cookies.
1394
+ if ($reauth) {
1395
  wp_clear_auth_cookie();
1396
  }
1397
 
1398
+ login_header(__('Log In'), '', $errors);
1399
 
1400
+ if (isset($_POST['log'])) {
1401
+ $user_login = ('incorrect_password' === $errors->get_error_code() || 'empty_password' === $errors->get_error_code()) ? esc_attr(wp_unslash($_POST['log'])) : '';
1402
  }
1403
 
1404
+ $rememberme = ! empty($_POST['rememberme']);
1405
 
1406
+ if ($errors->has_errors()) {
1407
  $aria_describedby_error = ' aria-describedby="login_error"';
1408
  } else {
1409
  $aria_describedby_error = '';
1410
  }
1411
 
1412
+ wp_enqueue_script('user-profile');
1413
 
1414
  //aiowps - this check is necessary because otherwise if variables are undefined we get a warning!
1415
+ if (empty($user_login)) {
1416
  $user_login = '';
1417
+ }
1418
+ if (empty($error)) {
1419
  $error = '';
1420
+ }
1421
  ?>
1422
 
1423
+ <form name="loginform" id="loginform" action="<?php echo esc_url(site_url('wp-login.php', 'login_post')); ?>" method="post">
1424
  <p>
1425
+ <label for="user_login"><?php _e('Username or Email Address'); ?></label>
1426
+ <input type="text" name="log" id="user_login"<?php echo $aria_describedby_error; ?> class="input" value="<?php echo esc_attr($user_login); ?>" size="20" autocapitalize="off" />
1427
  </p>
1428
 
1429
  <div class="user-pass-wrap">
1430
+ <label for="user_pass"><?php _e('Password'); ?></label>
1431
  <div class="wp-pwd">
1432
  <input type="password" name="pwd" id="user_pass"<?php echo $aria_describedby_error; ?> class="input password-input" value="" size="20" />
1433
+ <button type="button" class="button button-secondary wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e('Show password'); ?>">
1434
  <span class="dashicons dashicons-visibility" aria-hidden="true"></span>
1435
  </button>
1436
  </div>
1442
  *
1443
  * @since 2.1.0
1444
  */
1445
+ do_action('login_form');
 
1446
  ?>
1447
+ <p class="forgetmenot"><input name="rememberme" type="checkbox" id="rememberme" value="forever" <?php checked($rememberme); ?> /> <label for="rememberme"><?php esc_html_e('Remember Me'); ?></label></p>
1448
  <p class="submit">
1449
+ <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Log In'); ?>" />
1450
  <?php
1451
 
1452
+ if ($interim_login) {
1453
  ?>
1454
  <input type="hidden" name="interim-login" value="1" />
1455
  <?php
1456
  } else {
1457
  ?>
1458
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
1459
  <?php
1460
  }
1461
 
1462
+ if ($customize_login) {
1463
  ?>
1464
  <input type="hidden" name="customize-login" value="1" />
1465
  <?php
1472
 
1473
  <?php
1474
 
1475
+ if (! $interim_login) {
1476
  ?>
1477
  <p id="nav">
1478
  <?php
1479
 
1480
+ if (get_option('users_can_register')) {
1481
+ $registration_url = sprintf('<a href="%s">%s</a>', esc_url(wp_registration_url()), __('Register'));
1482
 
1483
+ // This filter is documented in wp-includes/general-template.php
1484
+ echo apply_filters('register', $registration_url);
1485
 
1486
+ echo esc_html($login_link_separator);
1487
  }
1488
 
1489
  ?>
1490
+ <a href="<?php echo esc_url(wp_lostpassword_url()); ?>"><?php _e('Lost your password?'); ?></a>
1491
  </p>
1492
  <?php
1493
  }
1494
 
1495
  $login_script = 'function wp_attempt_focus() {';
1496
+ $login_script .= 'setTimeout(function() {';
1497
  $login_script .= 'try {';
1498
 
1499
+ if ($user_login) {
1500
+ $login_script .= 'd = document.getElementById("user_pass"); d.value = "";';
1501
  } else {
1502
+ $login_script .= 'd = document.getElementById("user_login");';
1503
 
1504
+ if ($errors->get_error_code() === 'invalid_username') {
1505
  $login_script .= 'd.value = "";';
1506
  }
1507
  }
1508
 
1509
  $login_script .= 'd.focus(); d.select();';
1510
+ $login_script .= '} catch(er) {}';
1511
  $login_script .= '}, 200);';
1512
  $login_script .= "}\n"; // End of wp_attempt_focus().
1513
 
1518
  *
1519
  * @param bool $print Whether to print the function call. Default true.
1520
  */
1521
+ if (apply_filters('enable_login_autofocus', true) && ! $error) {
1522
  $login_script .= "wp_attempt_focus();\n";
1523
  }
1524
 
1525
  // Run `wpOnload()` if defined.
1526
+ $login_script .= "if (typeof wpOnload === 'function') { wpOnload() }";
 
1527
  ?>
1528
  <script type="text/javascript">
1529
  <?php echo $login_script; ?>
1530
  </script>
1531
  <?php
1532
 
1533
+ if ($interim_login) {
1534
  ?>
1535
  <script type="text/javascript">
1536
+ (function() {
1537
  try {
1538
+ var i, links = document.getElementsByTagName('a');
1539
+ for (i in links) {
1540
+ if (links[i].href) {
1541
  links[i].target = '_blank';
1542
  links[i].rel = 'noopener';
1543
  }
1544
  }
1545
+ } catch(er) {}
1546
  }());
1547
  </script>
1548
  <?php
other-includes/wp-security-rename-login-feature.php CHANGED
@@ -8,18 +8,17 @@
8
  * @package WordPress
9
  */
10
 
11
- /** Make sure that the WordPress bootstrap has run before continuing. */
12
-
13
- // aiowps - for our special case we do not want to include wp-load.php
14
- //require __DIR__ . '/wp-load.php';
15
 
16
  // Redirect to HTTPS login if forced to use SSL.
17
- if ( force_ssl_admin() && ! is_ssl() ) {
18
- if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
19
- wp_safe_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
20
  exit;
21
  } else {
22
- wp_safe_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
23
  exit;
24
  }
25
  }
@@ -40,21 +39,21 @@ if ( force_ssl_admin() && ! is_ssl() ) {
40
  * @param string $message Optional. Message to display in header. Default empty.
41
  * @param WP_Error $wp_error Optional. The error to pass. Default is a WP_Error instance.
42
  */
43
- function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
44
  global $error, $interim_login, $action;
45
 
46
  // Don't index any of these forms.
47
- add_filter( 'wp_robots', 'wp_robots_sensitive_page' );
48
- add_action( 'login_head', 'wp_strict_cross_origin_referrer' );
49
 
50
- add_action( 'login_head', 'wp_login_viewport_meta' );
51
 
52
- if ( ! is_wp_error( $wp_error ) ) {
53
  $wp_error = new WP_Error();
54
  }
55
 
56
  // Shake it!
57
- $shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password', 'retrieve_password_email_failure' );
58
  /**
59
  * Filters the error codes array for shaking the login form.
60
  *
@@ -62,20 +61,20 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
62
  *
63
  * @param array $shake_error_codes Error codes that shake the login form.
64
  */
65
- $shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
66
 
67
- if ( $shake_error_codes && $wp_error->has_errors() && in_array( $wp_error->get_error_code(), $shake_error_codes, true ) ) {
68
- add_action( 'login_footer', 'wp_shake_js', 12 );
69
  }
70
 
71
- $login_title = get_bloginfo( 'name', 'display' );
72
 
73
  /* translators: Login screen title. 1: Login screen name, 2: Network or site name. */
74
- $login_title = sprintf( __( '%1$s &lsaquo; %2$s &#8212; WordPress' ), $title, $login_title );
75
 
76
- if ( wp_is_recovery_mode() ) {
77
  /* translators: %s: Login screen title. */
78
- $login_title = sprintf( __( 'Recovery Mode &#8212; %s' ), $login_title );
79
  }
80
 
81
  /**
@@ -86,25 +85,25 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
86
  * @param string $login_title The page title, with extra context added.
87
  * @param string $title The original page title.
88
  */
89
- $login_title = apply_filters( 'login_title', $login_title, $title );
90
 
91
  ?><!DOCTYPE html>
92
  <html <?php language_attributes(); ?>>
93
  <head>
94
- <meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php bloginfo( 'charset' ); ?>" />
95
  <title><?php echo $login_title; ?></title>
96
  <?php
97
 
98
- wp_enqueue_style( 'login' );
99
 
100
  /*
101
  * Remove all stored post data on logging out.
102
  * This could be added by add_action('login_head'...) like wp_shake_js(),
103
  * but maybe better if it's not removable by plugins.
104
  */
105
- if ( 'loggedout' === $wp_error->get_error_code() ) {
106
  ?>
107
- <script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
108
  <?php
109
  }
110
 
@@ -113,16 +112,16 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
113
  *
114
  * @since 3.1.0
115
  */
116
- do_action( 'login_enqueue_scripts' );
117
 
118
  /**
119
  * Fires in the login page header after scripts are enqueued.
120
  *
121
  * @since 2.1.0
122
  */
123
- do_action( 'login_head' );
124
 
125
- $login_header_url = __( 'https://wordpress.org/' );
126
 
127
  /**
128
  * Filters link URL of the header logo above login form.
@@ -131,7 +130,7 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
131
  *
132
  * @param string $login_header_url Login header logo URL.
133
  */
134
- $login_header_url = apply_filters( 'login_headerurl', $login_header_url );
135
 
136
  $login_header_title = '';
137
 
@@ -145,13 +144,13 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
145
  */
146
  $login_header_title = apply_filters_deprecated(
147
  'login_headertitle',
148
- array( $login_header_title ),
149
  '5.2.0',
150
  'login_headertext',
151
- __( 'Usage of the title attribute on the login logo is not recommended for accessibility reasons. Use the link text instead.' )
152
  );
153
 
154
- $login_header_text = empty( $login_header_title ) ? __( 'Powered by WordPress' ) : $login_header_title;
155
 
156
  /**
157
  * Filters the link text of the header logo above the login form.
@@ -160,27 +159,26 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
160
  *
161
  * @param string $login_header_text The login header logo link text.
162
  */
163
- $login_header_text = apply_filters( 'login_headertext', $login_header_text );
164
 
165
- $classes = array( 'login-action-' . $action, 'wp-core-ui' );
166
 
167
- if ( is_rtl() ) {
168
  $classes[] = 'rtl';
169
  }
170
 
171
- if ( $interim_login ) {
172
  $classes[] = 'interim-login';
173
-
174
  ?>
175
  <style type="text/css">html{background-color: transparent;}</style>
176
  <?php
177
 
178
- if ( 'success' === $interim_login ) {
179
  $classes[] = 'interim-login-success';
180
  }
181
  }
182
 
183
- $classes[] = ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
184
 
185
  /**
186
  * Filters the login page body classes.
@@ -190,11 +188,10 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
190
  * @param array $classes An array of body classes.
191
  * @param string $action The action that brought the visitor to the login page.
192
  */
193
- $classes = apply_filters( 'login_body_class', $classes, $action );
194
-
195
  ?>
196
  </head>
197
- <body class="login no-js <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
198
  <script type="text/javascript">
199
  document.body.className = document.body.className.replace('no-js','js');
200
  </script>
@@ -204,11 +201,10 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
204
  *
205
  * @since 4.6.0
206
  */
207
- do_action( 'login_header' );
208
-
209
  ?>
210
  <div id="login">
211
- <h1><a href="<?php echo esc_url( $login_header_url ); ?>"><?php echo $login_header_text; ?></a></h1>
212
  <?php
213
  /**
214
  * Filters the message to display above the login form.
@@ -217,26 +213,26 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
217
  *
218
  * @param string $message Login message text.
219
  */
220
- $message = apply_filters( 'login_message', $message );
221
 
222
- if ( ! empty( $message ) ) {
223
  echo $message . "\n";
224
  }
225
 
226
  // In case a plugin uses $error rather than the $wp_errors object.
227
- if ( ! empty( $error ) ) {
228
- $wp_error->add( 'error', $error );
229
- unset( $error );
230
  }
231
 
232
- if ( $wp_error->has_errors() ) {
233
  $errors = '';
234
  $messages = '';
235
 
236
- foreach ( $wp_error->get_error_codes() as $code ) {
237
- $severity = $wp_error->get_error_data( $code );
238
- foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
239
- if ( 'message' === $severity ) {
240
  $messages .= ' ' . $error_message . "<br />\n";
241
  } else {
242
  $errors .= ' ' . $error_message . "<br />\n";
@@ -244,7 +240,7 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
244
  }
245
  }
246
 
247
- if ( ! empty( $errors ) ) {
248
  /**
249
  * Filters the error messages displayed above the login form.
250
  *
@@ -252,10 +248,10 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
252
  *
253
  * @param string $errors Login error message.
254
  */
255
- echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
256
  }
257
 
258
- if ( ! empty( $messages ) ) {
259
  /**
260
  * Filters instructional messages displayed above the login form.
261
  *
@@ -263,7 +259,7 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
263
  *
264
  * @param string $messages Login messages.
265
  */
266
- echo '<p class="message">' . apply_filters( 'login_messages', $messages ) . "</p>\n";
267
  }
268
  }
269
  } // End of login_header().
@@ -278,23 +274,22 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
278
  *
279
  * @param string $input_id Which input to auto-focus.
280
  */
281
- function login_footer( $input_id = '' ) {
282
  global $interim_login;
283
 
284
  // Don't allow interim logins to navigate away from the page.
285
- if ( ! $interim_login ) {
286
  ?>
287
- <p id="backtoblog"><a href="<?php echo esc_url( home_url( '/' ) ); ?>">
288
  <?php
289
 
290
  /* translators: %s: Site title. */
291
- printf( _x( '&larr; Go to %s', 'site' ), get_bloginfo( 'title', 'display' ) );
292
-
293
  ?>
294
  </a></p>
295
  <?php
296
 
297
- the_privacy_policy_link( '<div class="privacy-policy-page-link">', '</div>' );
298
  }
299
 
300
  ?>
@@ -302,11 +297,11 @@ function login_footer( $input_id = '' ) {
302
 
303
  <?php
304
 
305
- if ( ! empty( $input_id ) ) {
306
  ?>
307
  <script type="text/javascript">
308
- try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e){}
309
- if(typeof wpOnload=='function')wpOnload();
310
  </script>
311
  <?php
312
  }
@@ -316,8 +311,7 @@ function login_footer( $input_id = '' ) {
316
  *
317
  * @since 3.1.0
318
  */
319
- do_action( 'login_footer' );
320
-
321
  ?>
322
  <div class="clear"></div>
323
  </body>
@@ -354,14 +348,14 @@ function wp_login_viewport_meta() {
354
  // Main.
355
  //
356
 
357
- $action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
358
  $errors = new WP_Error();
359
 
360
- if ( isset( $_GET['key'] ) ) {
361
  $action = 'resetpass';
362
  }
363
 
364
- if ( isset( $_GET['checkemail'] ) ) {
365
  $action = 'checkemail';
366
  }
367
 
@@ -381,32 +375,32 @@ $default_actions = array(
381
  );
382
 
383
  // Validate action so as to default to the login screen.
384
- if ( ! in_array( $action, $default_actions, true ) && false === has_filter( 'login_form_' . $action ) ) {
385
  $action = 'login';
386
  }
387
 
388
  nocache_headers();
389
 
390
- header( 'Content-Type: ' . get_bloginfo( 'html_type' ) . '; charset=' . get_bloginfo( 'charset' ) );
391
 
392
- if ( defined( 'RELOCATE' ) && RELOCATE ) { // Move flag is set.
393
- if ( isset( $_SERVER['PATH_INFO'] ) && ( $_SERVER['PATH_INFO'] !== $_SERVER['PHP_SELF'] ) ) {
394
- $_SERVER['PHP_SELF'] = str_replace( $_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF'] );
395
  }
396
 
397
- $url = dirname( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] ) );
398
 
399
- if ( get_option( 'siteurl' ) !== $url ) {
400
- update_option( 'siteurl', $url );
401
  }
402
  }
403
 
404
  // Set a cookie now to see if they are supported by the browser.
405
- $secure = ( 'https' === parse_url( wp_login_url(), PHP_URL_SCHEME ) );
406
- setcookie( TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN, $secure );
407
 
408
- if ( SITECOOKIEPATH !== COOKIEPATH ) {
409
- setcookie( TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN, $secure );
410
  }
411
 
412
  /**
@@ -414,7 +408,7 @@ if ( SITECOOKIEPATH !== COOKIEPATH ) {
414
  *
415
  * @since 3.2.0
416
  */
417
- do_action( 'login_init' );
418
 
419
  /**
420
  * Fires before a specified login form action.
@@ -425,10 +419,10 @@ do_action( 'login_init' );
425
  *
426
  * @since 2.8.0
427
  */
428
- do_action( "login_form_{$action}" );
429
 
430
- $http_post = ( 'POST' === $_SERVER['REQUEST_METHOD'] );
431
- $interim_login = isset( $_REQUEST['interim-login'] );
432
 
433
  /**
434
  * Filters the separator used between login form navigation links.
@@ -437,9 +431,9 @@ $interim_login = isset( $_REQUEST['interim-login'] );
437
  *
438
  * @param string $login_link_separator The separator used between login form navigation links.
439
  */
440
- $login_link_separator = apply_filters( 'login_link_separator', ' | ' );
441
 
442
- switch ( $action ) {
443
 
444
  case 'confirm_admin_email':
445
  /*
@@ -447,21 +441,21 @@ switch ( $action ) {
447
  * as the current user is not set, see wp-includes/pluggable.php.
448
  * However this action runs on a redirect after logging in.
449
  */
450
- if ( ! is_user_logged_in() ) {
451
- wp_safe_redirect( wp_login_url() );
452
  exit;
453
  }
454
 
455
- if ( ! empty( $_REQUEST['redirect_to'] ) ) {
456
  $redirect_to = $_REQUEST['redirect_to'];
457
  } else {
458
  $redirect_to = admin_url();
459
  }
460
 
461
- if ( current_user_can( 'manage_options' ) ) {
462
- $admin_email = get_option( 'admin_email' );
463
  } else {
464
- wp_safe_redirect( $redirect_to );
465
  exit;
466
  }
467
 
@@ -474,26 +468,26 @@ switch ( $action ) {
474
  *
475
  * @param int $interval Interval time (in seconds). Default is 3 days.
476
  */
477
- $remind_interval = (int) apply_filters( 'admin_email_remind_interval', 3 * DAY_IN_SECONDS );
478
 
479
- if ( ! empty( $_GET['remind_me_later'] ) ) {
480
- if ( ! wp_verify_nonce( $_GET['remind_me_later'], 'remind_me_later_nonce' ) ) {
481
- wp_safe_redirect( wp_login_url() );
482
  exit;
483
  }
484
 
485
- if ( $remind_interval > 0 ) {
486
- update_option( 'admin_email_lifespan', time() + $remind_interval );
487
  }
488
 
489
- $redirect_to = add_query_arg( 'admin_email_remind_later', 1, $redirect_to );
490
- wp_safe_redirect( $redirect_to );
491
  exit;
492
  }
493
 
494
- if ( ! empty( $_POST['correct-admin-email'] ) ) {
495
- if ( ! check_admin_referer( 'confirm_admin_email', 'confirm_admin_email_nonce' ) ) {
496
- wp_safe_redirect( wp_login_url() );
497
  exit;
498
  }
499
 
@@ -506,17 +500,17 @@ switch ( $action ) {
506
  *
507
  * @param int $interval Interval time (in seconds). Default is 6 months.
508
  */
509
- $admin_email_check_interval = (int) apply_filters( 'admin_email_check_interval', 6 * MONTH_IN_SECONDS );
510
 
511
- if ( $admin_email_check_interval > 0 ) {
512
- update_option( 'admin_email_lifespan', time() + $admin_email_check_interval );
513
  }
514
 
515
- wp_safe_redirect( $redirect_to );
516
  exit;
517
  }
518
 
519
- login_header( __( 'Confirm your administration email' ), '', $errors );
520
 
521
  /**
522
  * Fires before the admin email confirm form.
@@ -526,44 +520,41 @@ switch ( $action ) {
526
  * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
527
  * credentials. Note that the error object may not contain any errors.
528
  */
529
- do_action( 'admin_email_confirm', $errors );
530
-
531
  ?>
532
 
533
- <form class="admin-email-confirm-form" name="admin-email-confirm-form" action="<?php echo esc_url( site_url( 'wp-login.php?action=confirm_admin_email', 'login_post' ) ); ?>" method="post">
534
  <?php
535
  /**
536
  * Fires inside the admin-email-confirm-form form tags, before the hidden fields.
537
  *
538
  * @since 5.3.0
539
  */
540
- do_action( 'admin_email_confirm_form' );
541
-
542
- wp_nonce_field( 'confirm_admin_email', 'confirm_admin_email_nonce' );
543
 
 
544
  ?>
545
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
546
 
547
  <h1 class="admin-email__heading">
548
- <?php _e( 'Administration email verification' ); ?>
549
  </h1>
550
  <p class="admin-email__details">
551
- <?php _e( 'Please verify that the <strong>administration email</strong> for this website is still correct.' ); ?>
552
  <?php
553
 
554
  /* translators: URL to the WordPress help section about admin email. */
555
- $admin_email_help_url = __( 'https://wordpress.org/support/article/settings-general-screen/#email-address' );
556
 
557
  /* translators: Accessibility text. */
558
- $accessibility_text = sprintf( '<span class="screen-reader-text"> %s</span>', __( '(opens in a new tab)' ) );
559
 
560
  printf(
561
  '<a href="%s" rel="noopener" target="_blank">%s%s</a>',
562
- esc_url( $admin_email_help_url ),
563
- __( 'Why is this important?' ),
564
  $accessibility_text
565
  );
566
-
567
  ?>
568
  </p>
569
  <p class="admin-email__details">
@@ -571,42 +562,39 @@ switch ( $action ) {
571
 
572
  printf(
573
  /* translators: %s: Admin email address. */
574
- __( 'Current administration email: %s' ),
575
- '<strong>' . esc_html( $admin_email ) . '</strong>'
576
  );
577
-
578
  ?>
579
  </p>
580
  <p class="admin-email__details">
581
- <?php _e( 'This email may be different from your personal email address.' ); ?>
582
  </p>
583
 
584
  <div class="admin-email__actions">
585
  <div class="admin-email__actions-primary">
586
  <?php
587
 
588
- $change_link = admin_url( 'options-general.php' );
589
- $change_link = add_query_arg( 'highlight', 'confirm_admin_email', $change_link );
590
-
591
  ?>
592
- <a class="button button-large" href="<?php echo esc_url( $change_link ); ?>"><?php _e( 'Update' ); ?></a>
593
- <input type="submit" name="correct-admin-email" id="correct-admin-email" class="button button-primary button-large" value="<?php esc_attr_e( 'The email is correct' ); ?>" />
594
  </div>
595
- <?php if ( $remind_interval > 0 ) : ?>
596
  <div class="admin-email__actions-secondary">
597
  <?php
598
 
599
- $remind_me_link = wp_login_url( $redirect_to );
600
  $remind_me_link = add_query_arg(
601
  array(
602
  'action' => 'confirm_admin_email',
603
- 'remind_me_later' => wp_create_nonce( 'remind_me_later_nonce' ),
604
  ),
605
  $remind_me_link
606
  );
607
-
608
  ?>
609
- <a href="<?php echo esc_url( $remind_me_link ); ?>"><?php _e( 'Remind me later' ); ?></a>
610
  </div>
611
  <?php endif; ?>
612
  </div>
@@ -618,13 +606,13 @@ switch ( $action ) {
618
  break;
619
 
620
  case 'postpass':
621
- if ( ! array_key_exists( 'post_password', $_POST ) ) {
622
- wp_safe_redirect( wp_get_referer() );
623
  exit;
624
  }
625
 
626
  require_once ABSPATH . WPINC . '/class-phpass.php';
627
- $hasher = new PasswordHash( 8, true );
628
 
629
  /**
630
  * Filters the life span of the post password cookie.
@@ -636,35 +624,35 @@ switch ( $action ) {
636
  *
637
  * @param int $expires The expiry time, as passed to setcookie().
638
  */
639
- $expire = apply_filters( 'post_password_expires', time() + 10 * DAY_IN_SECONDS );
640
  $referer = wp_get_referer();
641
 
642
- if ( $referer ) {
643
- $secure = ( 'https' === parse_url( $referer, PHP_URL_SCHEME ) );
644
  } else {
645
  $secure = false;
646
  }
647
 
648
- setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure );
649
 
650
- wp_safe_redirect( wp_get_referer() );
651
  exit;
652
 
653
  case 'logout':
654
- check_admin_referer( 'log-out' );
655
 
656
  $user = wp_get_current_user();
657
 
658
  wp_logout();
659
 
660
- if ( ! empty( $_REQUEST['redirect_to'] ) ) {
661
  $redirect_to = $_REQUEST['redirect_to'];
662
  $requested_redirect_to = $redirect_to;
663
  } else {
664
  $redirect_to = add_query_arg(
665
  array(
666
  'loggedout' => 'true',
667
- 'wp_lang' => get_user_locale( $user ),
668
  ),
669
  wp_login_url()
670
  );
@@ -681,32 +669,32 @@ switch ( $action ) {
681
  * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
682
  * @param WP_User $user The WP_User object for the user that's logging out.
683
  */
684
- $redirect_to = apply_filters( 'logout_redirect', $redirect_to, $requested_redirect_to, $user );
685
 
686
- wp_safe_redirect( $redirect_to );
687
  exit;
688
 
689
  case 'lostpassword':
690
  case 'retrievepassword':
691
- if ( $http_post ) {
692
  $errors = retrieve_password();
693
 
694
- if ( ! is_wp_error( $errors ) ) {
695
- $redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
696
- wp_safe_redirect( $redirect_to );
697
  exit;
698
  }
699
  }
700
 
701
- if ( isset( $_GET['error'] ) ) {
702
- if ( 'invalidkey' === $_GET['error'] ) {
703
- $errors->add( 'invalidkey', __( 'Your password reset link appears to be invalid. Please request a new link below.' ) );
704
- } elseif ( 'expiredkey' === $_GET['error'] ) {
705
- $errors->add( 'expiredkey', __( 'Your password reset link has expired. Please request a new link below.' ) );
706
  }
707
  }
708
 
709
- $lostpassword_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
710
  /**
711
  * Filters the URL redirected to after submitting the lostpassword/retrievepassword form.
712
  *
@@ -714,7 +702,7 @@ switch ( $action ) {
714
  *
715
  * @param string $lostpassword_redirect The redirect destination URL.
716
  */
717
- $redirect_to = apply_filters( 'lostpassword_redirect', $lostpassword_redirect );
718
 
719
  /**
720
  * Fires before the lost password form.
@@ -725,22 +713,22 @@ switch ( $action ) {
725
  * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
726
  * credentials. Note that the error object may not contain any errors.
727
  */
728
- do_action( 'lost_password', $errors );
729
 
730
- login_header( __( 'Lost Password' ), '<p class="message">' . __( 'Please enter your username or email address. You will receive an email message with instructions on how to reset your password.' ) . '</p>', $errors );
731
 
732
  $user_login = '';
733
 
734
- if ( isset( $_POST['user_login'] ) && is_string( $_POST['user_login'] ) ) {
735
- $user_login = wp_unslash( $_POST['user_login'] );
736
  }
737
 
738
  ?>
739
 
740
- <form name="lostpasswordform" id="lostpasswordform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=lostpassword', 'login_post' ) ); ?>" method="post">
741
  <p>
742
- <label for="user_login"><?php _e( 'Username or Email Address' ); ?></label>
743
- <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr( $user_login ); ?>" size="20" autocapitalize="off" />
744
  </p>
745
  <?php
746
 
@@ -749,67 +737,66 @@ switch ( $action ) {
749
  *
750
  * @since 2.1.0
751
  */
752
- do_action( 'lostpassword_form' );
753
-
754
  ?>
755
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
756
  <p class="submit">
757
- <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Get New Password' ); ?>" />
758
  </p>
759
  </form>
760
 
761
  <p id="nav">
762
- <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
763
  <?php
764
 
765
- if ( get_option( 'users_can_register' ) ) {
766
- $registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
767
 
768
- echo esc_html( $login_link_separator );
769
 
770
- /** This filter is documented in wp-includes/general-template.php */
771
- echo apply_filters( 'register', $registration_url );
772
  }
773
 
774
  ?>
775
  </p>
776
  <?php
777
 
778
- login_footer( 'user_login' );
779
  break;
780
 
781
  case 'resetpass':
782
  case 'rp':
783
- list( $rp_path ) = explode( '?', wp_unslash( $_SERVER['REQUEST_URI'] ) );
784
  $rp_cookie = 'wp-resetpass-' . COOKIEHASH;
785
 
786
- if ( isset( $_GET['key'] ) ) {
787
- $value = sprintf( '%s:%s', wp_unslash( $_GET['login'] ), wp_unslash( $_GET['key'] ) );
788
- setcookie( $rp_cookie, $value, 0, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
789
 
790
- wp_safe_redirect( remove_query_arg( array( 'key', 'login' ) ) );
791
  exit;
792
  }
793
 
794
- if ( isset( $_COOKIE[ $rp_cookie ] ) && 0 < strpos( $_COOKIE[ $rp_cookie ], ':' ) ) {
795
- list( $rp_login, $rp_key ) = explode( ':', wp_unslash( $_COOKIE[ $rp_cookie ] ), 2 );
796
 
797
- $user = check_password_reset_key( $rp_key, $rp_login );
798
 
799
- if ( isset( $_POST['pass1'] ) && ! hash_equals( $rp_key, $_POST['rp_key'] ) ) {
800
  $user = false;
801
  }
802
  } else {
803
  $user = false;
804
  }
805
 
806
- if ( ! $user || is_wp_error( $user ) ) {
807
- setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
808
 
809
- if ( $user && $user->get_error_code() === 'expired_key' ) {
810
- wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=expiredkey' ) );
811
  } else {
812
- wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=invalidkey' ) );
813
  }
814
 
815
  exit;
@@ -817,8 +804,8 @@ switch ( $action ) {
817
 
818
  $errors = new WP_Error();
819
 
820
- if ( isset( $_POST['pass1'] ) && $_POST['pass1'] !== $_POST['pass2'] ) {
821
- $errors->add( 'password_reset_mismatch', __( 'The passwords do not match.' ) );
822
  }
823
 
824
  /**
@@ -829,46 +816,45 @@ switch ( $action ) {
829
  * @param WP_Error $errors WP Error object.
830
  * @param WP_User|WP_Error $user WP_User object if the login and reset key match. WP_Error object otherwise.
831
  */
832
- do_action( 'validate_password_reset', $errors, $user );
833
 
834
- if ( ( ! $errors->has_errors() ) && isset( $_POST['pass1'] ) && ! empty( $_POST['pass1'] ) ) {
835
- reset_password( $user, $_POST['pass1'] );
836
- setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
837
- login_header( __( 'Password Reset' ), '<p class="message reset-pass">' . __( 'Your password has been reset.' ) . ' <a href="' . esc_url( wp_login_url() ) . '">' . __( 'Log in' ) . '</a></p>' );
838
  login_footer();
839
  exit;
840
  }
841
 
842
- wp_enqueue_script( 'utils' );
843
- wp_enqueue_script( 'user-profile' );
844
-
845
- login_header( __( 'Reset Password' ), '<p class="message reset-pass">' . __( 'Enter your new password below.' ) . '</p>', $errors );
846
 
 
847
  ?>
848
- <form name="resetpassform" id="resetpassform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=resetpass', 'login_post' ) ); ?>" method="post" autocomplete="off">
849
- <input type="hidden" id="user_login" value="<?php echo esc_attr( $rp_login ); ?>" autocomplete="off" />
850
 
851
  <div class="user-pass1-wrap">
852
  <p>
853
- <label for="pass1"><?php _e( 'New password' ); ?></label>
854
  </p>
855
 
856
  <div class="wp-pwd">
857
- <input type="password" data-reveal="1" data-pw="<?php echo esc_attr( wp_generate_password( 16 ) ); ?>" name="pass1" id="pass1" class="input password-input" size="24" value="" autocomplete="off" aria-describedby="pass-strength-result" />
858
 
859
- <button type="button" class="button button-secondary wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Hide password' ); ?>">
860
  <span class="dashicons dashicons-hidden" aria-hidden="true"></span>
861
  </button>
862
- <div id="pass-strength-result" class="hide-if-no-js" aria-live="polite"><?php _e( 'Strength indicator' ); ?></div>
863
  </div>
864
  <div class="pw-weak">
865
  <input type="checkbox" name="pw_weak" id="pw-weak" class="pw-checkbox" />
866
- <label for="pw-weak"><?php _e( 'Confirm use of weak password' ); ?></label>
867
  </div>
868
  </div>
869
 
870
  <p class="user-pass2-wrap">
871
- <label for="pass2"><?php _e( 'Confirm new password' ); ?></label>
872
  <input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off" />
873
  </p>
874
 
@@ -884,37 +870,36 @@ switch ( $action ) {
884
  *
885
  * @param WP_User $user User object of the user whose password is being reset.
886
  */
887
- do_action( 'resetpass_form', $user );
888
-
889
  ?>
890
- <input type="hidden" name="rp_key" value="<?php echo esc_attr( $rp_key ); ?>" />
891
  <p class="submit">
892
- <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Reset Password' ); ?>" />
893
  </p>
894
  </form>
895
 
896
  <p id="nav">
897
- <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
898
  <?php
899
 
900
- if ( get_option( 'users_can_register' ) ) {
901
- $registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
902
 
903
- echo esc_html( $login_link_separator );
904
 
905
- /** This filter is documented in wp-includes/general-template.php */
906
- echo apply_filters( 'register', $registration_url );
907
  }
908
 
909
  ?>
910
  </p>
911
  <?php
912
 
913
- login_footer( 'user_pass' );
914
  break;
915
 
916
  case 'register':
917
- if ( is_multisite() ) {
918
  /**
919
  * Filters the Multisite sign up URL.
920
  *
@@ -922,37 +907,37 @@ switch ( $action ) {
922
  *
923
  * @param string $sign_up_url The sign up URL.
924
  */
925
- wp_redirect( apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) ) );
926
  exit;
927
  }
928
 
929
- if ( ! get_option( 'users_can_register' ) ) {
930
- wp_redirect( site_url( 'wp-login.php?registration=disabled' ) );
931
  exit;
932
  }
933
 
934
  $user_login = '';
935
  $user_email = '';
936
 
937
- if ( $http_post ) {
938
- if ( isset( $_POST['user_login'] ) && is_string( $_POST['user_login'] ) ) {
939
- $user_login = wp_unslash( $_POST['user_login'] );
940
  }
941
 
942
- if ( isset( $_POST['user_email'] ) && is_string( $_POST['user_email'] ) ) {
943
- $user_email = wp_unslash( $_POST['user_email'] );
944
  }
945
 
946
- $errors = register_new_user( $user_login, $user_email );
947
 
948
- if ( ! is_wp_error( $errors ) ) {
949
- $redirect_to = ! empty( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : 'wp-login.php?checkemail=registered';
950
- wp_safe_redirect( $redirect_to );
951
  exit;
952
  }
953
  }
954
 
955
- $registration_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
956
 
957
  /**
958
  * Filters the registration redirect URL.
@@ -961,19 +946,18 @@ switch ( $action ) {
961
  *
962
  * @param string $registration_redirect The redirect destination URL.
963
  */
964
- $redirect_to = apply_filters( 'registration_redirect', $registration_redirect );
965
-
966
- login_header( __( 'Registration Form' ), '<p class="message register">' . __( 'Register For This Site' ) . '</p>', $errors );
967
 
 
968
  ?>
969
- <form name="registerform" id="registerform" action="<?php echo esc_url( site_url( 'wp-login.php?action=register', 'login_post' ) ); ?>" method="post" novalidate="novalidate">
970
  <p>
971
- <label for="user_login"><?php _e( 'Username' ); ?></label>
972
- <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr( wp_unslash( $user_login ) ); ?>" size="20" autocapitalize="off" />
973
  </p>
974
  <p>
975
- <label for="user_email"><?php _e( 'Email' ); ?></label>
976
- <input type="email" name="user_email" id="user_email" class="input" value="<?php echo esc_attr( wp_unslash( $user_email ) ); ?>" size="25" />
977
  </p>
978
  <?php
979
 
@@ -982,77 +966,76 @@ switch ( $action ) {
982
  *
983
  * @since 2.1.0
984
  */
985
- do_action( 'register_form' );
986
-
987
  ?>
988
  <p id="reg_passmail">
989
- <?php _e( 'Registration confirmation will be emailed to you.' ); ?>
990
  </p>
991
  <br class="clear" />
992
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
993
  <p class="submit">
994
- <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Register' ); ?>" />
995
  </p>
996
  </form>
997
 
998
  <p id="nav">
999
- <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
1000
- <?php echo esc_html( $login_link_separator ); ?>
1001
- <a href="<?php echo esc_url( wp_lostpassword_url() ); ?>"><?php _e( 'Lost your password?' ); ?></a>
1002
  </p>
1003
  <?php
1004
 
1005
- login_footer( 'user_login' );
1006
  break;
1007
 
1008
  case 'checkemail':
1009
  $redirect_to = admin_url();
1010
  $errors = new WP_Error();
1011
 
1012
- if ( 'confirm' === $_GET['checkemail'] ) {
1013
  $errors->add(
1014
  'confirm',
1015
  sprintf(
1016
  /* translators: %s: Link to the login page. */
1017
- __( 'Check your email for the confirmation link, then visit the <a href="%s">login page</a>.' ),
1018
  wp_login_url()
1019
  ),
1020
  'message'
1021
  );
1022
- } elseif ( 'registered' === $_GET['checkemail'] ) {
1023
  $errors->add(
1024
  'registered',
1025
  sprintf(
1026
  /* translators: %s: Link to the login page. */
1027
- __( 'Registration complete. Please check your email, then visit the <a href="%s">login page</a>.' ),
1028
  wp_login_url()
1029
  ),
1030
  'message'
1031
  );
1032
  }
1033
 
1034
- /** This action is documented in wp-login.php */
1035
- $errors = apply_filters( 'wp_login_errors', $errors, $redirect_to );
1036
 
1037
- login_header( __( 'Check your email' ), '', $errors );
1038
  login_footer();
1039
  break;
1040
 
1041
  case 'confirmaction':
1042
- if ( ! isset( $_GET['request_id'] ) ) {
1043
- wp_die( __( 'Missing request ID.' ) );
1044
  }
1045
 
1046
- if ( ! isset( $_GET['confirm_key'] ) ) {
1047
- wp_die( __( 'Missing confirm key.' ) );
1048
  }
1049
 
1050
  $request_id = (int) $_GET['request_id'];
1051
- $key = sanitize_text_field( wp_unslash( $_GET['confirm_key'] ) );
1052
- $result = wp_validate_user_request_key( $request_id, $key );
1053
 
1054
- if ( is_wp_error( $result ) ) {
1055
- wp_die( $result );
1056
  }
1057
 
1058
  /**
@@ -1068,79 +1051,79 @@ switch ( $action ) {
1068
  *
1069
  * @param int $request_id Request ID.
1070
  */
1071
- do_action( 'user_request_action_confirmed', $request_id );
1072
 
1073
- $message = _wp_privacy_account_request_confirmed_message( $request_id );
1074
 
1075
- login_header( __( 'User action confirmed.' ), $message );
1076
  login_footer();
1077
  exit;
1078
 
1079
  case 'login':
1080
  default:
1081
  $secure_cookie = '';
1082
- $customize_login = isset( $_REQUEST['customize-login'] );
1083
 
1084
- if ( $customize_login ) {
1085
- wp_enqueue_script( 'customize-base' );
1086
  }
1087
 
1088
  // If the user wants SSL but the session is not SSL, force a secure cookie.
1089
- if ( ! empty( $_POST['log'] ) && ! force_ssl_admin() ) {
1090
- $user_name = sanitize_user( wp_unslash( $_POST['log'] ) );
1091
- $user = get_user_by( 'login', $user_name );
1092
 
1093
- if ( ! $user && strpos( $user_name, '@' ) ) {
1094
- $user = get_user_by( 'email', $user_name );
1095
  }
1096
 
1097
- if ( $user ) {
1098
- if ( get_user_option( 'use_ssl', $user->ID ) ) {
1099
  $secure_cookie = true;
1100
- force_ssl_admin( true );
1101
  }
1102
  }
1103
  }
1104
 
1105
- if ( isset( $_REQUEST['redirect_to'] ) ) {
1106
  $redirect_to = $_REQUEST['redirect_to'];
1107
  // Redirect to HTTPS if user wants SSL.
1108
- if ( $secure_cookie && false !== strpos( $redirect_to, 'wp-admin' ) ) {
1109
- $redirect_to = preg_replace( '|^http://|', 'https://', $redirect_to );
1110
  }
1111
  } else {
1112
  $redirect_to = admin_url();
1113
  }
1114
 
1115
- $reauth = empty( $_REQUEST['reauth'] ) ? false : true;
1116
 
1117
- $user = wp_signon( array(), $secure_cookie );
1118
 
1119
- if ( empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
1120
- if ( headers_sent() ) {
1121
  $user = new WP_Error(
1122
  'test_cookie',
1123
  sprintf(
1124
  /* translators: 1: Browser cookie documentation URL, 2: Support forums URL. */
1125
- __( '<strong>Error</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.' ),
1126
- __( 'https://wordpress.org/support/article/cookies/' ),
1127
- __( 'https://wordpress.org/support/forums/' )
1128
  )
1129
  );
1130
- } elseif ( isset( $_POST['testcookie'] ) && empty( $_COOKIE[ TEST_COOKIE ] ) ) {
1131
  // If cookies are disabled, we can't log in even with a valid user and password.
1132
  $user = new WP_Error(
1133
  'test_cookie',
1134
  sprintf(
1135
  /* translators: %s: Browser cookie documentation URL. */
1136
- __( '<strong>Error</strong>: Cookies are blocked or not supported by your browser. You must <a href="%s">enable cookies</a> to use WordPress.' ),
1137
- __( 'https://wordpress.org/support/article/cookies/#enable-cookies-in-your-browser' )
1138
  )
1139
  );
1140
  }
1141
  }
1142
 
1143
- $requested_redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
1144
  /**
1145
  * Filters the login redirect URL.
1146
  *
@@ -1150,24 +1133,23 @@ switch ( $action ) {
1150
  * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
1151
  * @param WP_User|WP_Error $user WP_User object if login was successful, WP_Error object otherwise.
1152
  */
1153
- $redirect_to = apply_filters( 'login_redirect', $redirect_to, $requested_redirect_to, $user );
1154
 
1155
- if ( ! is_wp_error( $user ) && ! $reauth ) {
1156
- if ( $interim_login ) {
1157
- $message = '<p class="message">' . __( 'You have logged in successfully.' ) . '</p>';
1158
  $interim_login = 'success';
1159
- login_header( '', $message );
1160
-
1161
  ?>
1162
  </div>
1163
  <?php
1164
 
1165
- /** This action is documented in wp-login.php */
1166
- do_action( 'login_footer' );
1167
 
1168
- if ( $customize_login ) {
1169
  ?>
1170
- <script type="text/javascript">setTimeout( function(){ new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); ?>', channel: 'login' }).send('login') }, 1000 );</script>
1171
  <?php
1172
  }
1173
 
@@ -1179,80 +1161,80 @@ switch ( $action ) {
1179
  }
1180
 
1181
  // Check if it is time to add a redirect to the admin email confirmation screen.
1182
- if ( is_a( $user, 'WP_User' ) && $user->exists() && $user->has_cap( 'manage_options' ) ) {
1183
- $admin_email_lifespan = (int) get_option( 'admin_email_lifespan' );
1184
 
1185
  // If `0` (or anything "falsey" as it is cast to int) is returned, the user will not be redirected
1186
  // to the admin email confirmation screen.
1187
- /** This filter is documented in wp-login.php */
1188
- $admin_email_check_interval = (int) apply_filters( 'admin_email_check_interval', 6 * MONTH_IN_SECONDS );
1189
 
1190
- if ( $admin_email_check_interval > 0 && time() > $admin_email_lifespan ) {
1191
  $redirect_to = add_query_arg(
1192
  array(
1193
  'action' => 'confirm_admin_email',
1194
- 'wp_lang' => get_user_locale( $user ),
1195
  ),
1196
- wp_login_url( $redirect_to )
1197
  );
1198
  }
1199
  }
1200
 
1201
- if ( ( empty( $redirect_to ) || 'wp-admin/' === $redirect_to || admin_url() === $redirect_to ) ) {
1202
  // If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
1203
- if ( is_multisite() && ! get_active_blog_for_user( $user->ID ) && ! is_super_admin( $user->ID ) ) {
1204
  $redirect_to = user_admin_url();
1205
- } elseif ( is_multisite() && ! $user->has_cap( 'read' ) ) {
1206
- $redirect_to = get_dashboard_url( $user->ID );
1207
- } elseif ( ! $user->has_cap( 'edit_posts' ) ) {
1208
- $redirect_to = $user->has_cap( 'read' ) ? admin_url( 'profile.php' ) : home_url();
1209
  }
1210
 
1211
- wp_redirect( $redirect_to );
1212
  exit;
1213
  }
1214
 
1215
- wp_safe_redirect( $redirect_to );
1216
  exit;
1217
  }
1218
 
1219
  $errors = $user;
1220
  // Clear errors if loggedout is set.
1221
- if ( ! empty( $_GET['loggedout'] ) || $reauth ) {
1222
  $errors = new WP_Error();
1223
  }
1224
 
1225
- if ( empty( $_POST ) && $errors->get_error_codes() === array( 'empty_username', 'empty_password' ) ) {
1226
- $errors = new WP_Error( '', '' );
1227
  }
1228
 
1229
- if ( $interim_login ) {
1230
- if ( ! $errors->has_errors() ) {
1231
- $errors->add( 'expired', __( 'Your session has expired. Please log in to continue where you left off.' ), 'message' );
1232
  }
1233
  } else {
1234
  // Some parts of this script use the main login form to display a message.
1235
- if ( isset( $_GET['loggedout'] ) && $_GET['loggedout'] ) {
1236
- $errors->add( 'loggedout', __( 'You are now logged out.' ), 'message' );
1237
- } elseif ( isset( $_GET['registration'] ) && 'disabled' === $_GET['registration'] ) {
1238
- $errors->add( 'registerdisabled', __( 'User registration is currently not allowed.' ) );
1239
- } elseif ( strpos( $redirect_to, 'about.php?updated' ) ) {
1240
- $errors->add( 'updated', __( '<strong>You have successfully updated WordPress!</strong> Please log back in to see what&#8217;s new.' ), 'message' );
1241
- } elseif ( WP_Recovery_Mode_Link_Service::LOGIN_ACTION_ENTERED === $action ) {
1242
- $errors->add( 'enter_recovery_mode', __( 'Recovery Mode Initialized. Please log in to continue.' ), 'message' );
1243
- } elseif ( isset( $_GET['redirect_to'] ) && false !== strpos( $_GET['redirect_to'], 'wp-admin/authorize-application.php' ) ) {
1244
- $query_component = wp_parse_url( $_GET['redirect_to'], PHP_URL_QUERY );
1245
- parse_str( $query_component, $query );
1246
-
1247
- if ( ! empty( $query['app_name'] ) ) {
1248
  /* translators: 1: Website name, 2: Application name. */
1249
- $message = sprintf( 'Please log in to %1$s to authorize %2$s to connect to your account.', get_bloginfo( 'name', 'display' ), '<strong>' . esc_html( $query['app_name'] ) . '</strong>' );
1250
  } else {
1251
  /* translators: %s: Website name. */
1252
- $message = sprintf( 'Please log in to %s to proceed with authorization.', get_bloginfo( 'name', 'display' ) );
1253
  }
1254
 
1255
- $errors->add( 'authorize_application', $message, 'message' );
1256
  }
1257
  }
1258
 
@@ -1264,49 +1246,49 @@ switch ( $action ) {
1264
  * @param WP_Error $errors WP Error object.
1265
  * @param string $redirect_to Redirect destination URL.
1266
  */
1267
- $errors = apply_filters( 'wp_login_errors', $errors, $redirect_to );
1268
 
1269
  // Clear any stale cookies.
1270
- if ( $reauth ) {
1271
  wp_clear_auth_cookie();
1272
  }
1273
 
1274
- login_header( __( 'Log In' ), '', $errors );
1275
 
1276
- if ( isset( $_POST['log'] ) ) {
1277
- $user_login = ( 'incorrect_password' === $errors->get_error_code() || 'empty_password' === $errors->get_error_code() ) ? esc_attr( wp_unslash( $_POST['log'] ) ) : '';
1278
  }
1279
 
1280
- $rememberme = ! empty( $_POST['rememberme'] );
1281
 
1282
- if ( $errors->has_errors() ) {
1283
  $aria_describedby_error = ' aria-describedby="login_error"';
1284
  } else {
1285
  $aria_describedby_error = '';
1286
  }
1287
 
1288
- wp_enqueue_script( 'user-profile' );
1289
 
1290
  //aiowps - this check is necessary because otherwise if variables are undefined we get a warning!
1291
- if(empty($user_login)){
1292
  $user_login = '';
1293
- }
1294
- if(empty($error)){
1295
  $error = '';
1296
- }
1297
  ?>
1298
 
1299
- <form name="loginform" id="loginform" action="<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ); ?>" method="post">
1300
  <p>
1301
- <label for="user_login"><?php _e( 'Username or Email Address' ); ?></label>
1302
- <input type="text" name="log" id="user_login"<?php echo $aria_describedby_error; ?> class="input" value="<?php echo esc_attr( $user_login ); ?>" size="20" autocapitalize="off" />
1303
  </p>
1304
 
1305
  <div class="user-pass-wrap">
1306
- <label for="user_pass"><?php _e( 'Password' ); ?></label>
1307
  <div class="wp-pwd">
1308
  <input type="password" name="pwd" id="user_pass"<?php echo $aria_describedby_error; ?> class="input password-input" value="" size="20" />
1309
- <button type="button" class="button button-secondary wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Show password' ); ?>">
1310
  <span class="dashicons dashicons-visibility" aria-hidden="true"></span>
1311
  </button>
1312
  </div>
@@ -1318,25 +1300,24 @@ switch ( $action ) {
1318
  *
1319
  * @since 2.1.0
1320
  */
1321
- do_action( 'login_form' );
1322
-
1323
  ?>
1324
- <p class="forgetmenot"><input name="rememberme" type="checkbox" id="rememberme" value="forever" <?php checked( $rememberme ); ?> /> <label for="rememberme"><?php esc_html_e( 'Remember Me' ); ?></label></p>
1325
  <p class="submit">
1326
- <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Log In' ); ?>" />
1327
  <?php
1328
 
1329
- if ( $interim_login ) {
1330
  ?>
1331
  <input type="hidden" name="interim-login" value="1" />
1332
  <?php
1333
  } else {
1334
  ?>
1335
- <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
1336
  <?php
1337
  }
1338
 
1339
- if ( $customize_login ) {
1340
  ?>
1341
  <input type="hidden" name="customize-login" value="1" />
1342
  <?php
@@ -1349,42 +1330,42 @@ switch ( $action ) {
1349
 
1350
  <?php
1351
 
1352
- if ( ! $interim_login ) {
1353
  ?>
1354
  <p id="nav">
1355
  <?php
1356
 
1357
- if ( get_option( 'users_can_register' ) ) {
1358
- $registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
1359
 
1360
- /** This filter is documented in wp-includes/general-template.php */
1361
- echo apply_filters( 'register', $registration_url );
1362
 
1363
- echo esc_html( $login_link_separator );
1364
  }
1365
 
1366
  ?>
1367
- <a href="<?php echo esc_url( wp_lostpassword_url() ); ?>"><?php _e( 'Lost your password?' ); ?></a>
1368
  </p>
1369
  <?php
1370
  }
1371
 
1372
  $login_script = 'function wp_attempt_focus() {';
1373
- $login_script .= 'setTimeout( function() {';
1374
  $login_script .= 'try {';
1375
 
1376
- if ( $user_login ) {
1377
- $login_script .= 'd = document.getElementById( "user_pass" ); d.value = "";';
1378
  } else {
1379
- $login_script .= 'd = document.getElementById( "user_login" );';
1380
 
1381
- if ( $errors->get_error_code() === 'invalid_username' ) {
1382
  $login_script .= 'd.value = "";';
1383
  }
1384
  }
1385
 
1386
  $login_script .= 'd.focus(); d.select();';
1387
- $login_script .= '} catch( er ) {}';
1388
  $login_script .= '}, 200);';
1389
  $login_script .= "}\n"; // End of wp_attempt_focus().
1390
 
@@ -1395,32 +1376,31 @@ switch ( $action ) {
1395
  *
1396
  * @param bool $print Whether to print the function call. Default true.
1397
  */
1398
- if ( apply_filters( 'enable_login_autofocus', true ) && ! $error ) {
1399
  $login_script .= "wp_attempt_focus();\n";
1400
  }
1401
 
1402
  // Run `wpOnload()` if defined.
1403
- $login_script .= "if ( typeof wpOnload === 'function' ) { wpOnload() }";
1404
-
1405
  ?>
1406
  <script type="text/javascript">
1407
  <?php echo $login_script; ?>
1408
  </script>
1409
  <?php
1410
 
1411
- if ( $interim_login ) {
1412
  ?>
1413
  <script type="text/javascript">
1414
- ( function() {
1415
  try {
1416
- var i, links = document.getElementsByTagName( 'a' );
1417
- for ( i in links ) {
1418
- if ( links[i].href ) {
1419
  links[i].target = '_blank';
1420
  links[i].rel = 'noopener';
1421
  }
1422
  }
1423
- } catch( er ) {}
1424
  }());
1425
  </script>
1426
  <?php
8
  * @package WordPress
9
  */
10
 
11
+ // Make sure that the WordPress bootstrap has run before continuing.
12
+ // aiowps - for our special case we do not want to include wp-load.php
13
+ // require __DIR__ . '/wp-load.php';
 
14
 
15
  // Redirect to HTTPS login if forced to use SSL.
16
+ if (force_ssl_admin() && ! is_ssl()) {
17
+ if (0 === strpos($_SERVER['REQUEST_URI'], 'http')) {
18
+ wp_safe_redirect(set_url_scheme($_SERVER['REQUEST_URI'], 'https'));
19
  exit;
20
  } else {
21
+ wp_safe_redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
22
  exit;
23
  }
24
  }
39
  * @param string $message Optional. Message to display in header. Default empty.
40
  * @param WP_Error $wp_error Optional. The error to pass. Default is a WP_Error instance.
41
  */
42
+ function login_header($title = 'Log In', $message = '', $wp_error = null) {
43
  global $error, $interim_login, $action;
44
 
45
  // Don't index any of these forms.
46
+ add_filter('wp_robots', 'wp_robots_sensitive_page');
47
+ add_action('login_head', 'wp_strict_cross_origin_referrer');
48
 
49
+ add_action('login_head', 'wp_login_viewport_meta');
50
 
51
+ if (! is_wp_error($wp_error)) {
52
  $wp_error = new WP_Error();
53
  }
54
 
55
  // Shake it!
56
+ $shake_error_codes = array('empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password', 'retrieve_password_email_failure');
57
  /**
58
  * Filters the error codes array for shaking the login form.
59
  *
61
  *
62
  * @param array $shake_error_codes Error codes that shake the login form.
63
  */
64
+ $shake_error_codes = apply_filters('shake_error_codes', $shake_error_codes);
65
 
66
+ if ($shake_error_codes && $wp_error->has_errors() && in_array($wp_error->get_error_code(), $shake_error_codes, true)) {
67
+ add_action('login_footer', 'wp_shake_js', 12);
68
  }
69
 
70
+ $login_title = get_bloginfo('name', 'display');
71
 
72
  /* translators: Login screen title. 1: Login screen name, 2: Network or site name. */
73
+ $login_title = sprintf(__('%1$s &lsaquo; %2$s &#8212; WordPress'), $title, $login_title);
74
 
75
+ if (wp_is_recovery_mode()) {
76
  /* translators: %s: Login screen title. */
77
+ $login_title = sprintf(__('Recovery Mode &#8212; %s'), $login_title);
78
  }
79
 
80
  /**
85
  * @param string $login_title The page title, with extra context added.
86
  * @param string $title The original page title.
87
  */
88
+ $login_title = apply_filters('login_title', $login_title, $title);
89
 
90
  ?><!DOCTYPE html>
91
  <html <?php language_attributes(); ?>>
92
  <head>
93
+ <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
94
  <title><?php echo $login_title; ?></title>
95
  <?php
96
 
97
+ wp_enqueue_style('login');
98
 
99
  /*
100
  * Remove all stored post data on logging out.
101
  * This could be added by add_action('login_head'...) like wp_shake_js(),
102
  * but maybe better if it's not removable by plugins.
103
  */
104
+ if ('loggedout' === $wp_error->get_error_code()) {
105
  ?>
106
+ <script>if ("sessionStorage" in window) {try{for(var key in sessionStorage) {if (key.indexOf("wp-autosave-")!=-1) {sessionStorage.removeItem(key)}}}catch(e) {}};</script>
107
  <?php
108
  }
109
 
112
  *
113
  * @since 3.1.0
114
  */
115
+ do_action('login_enqueue_scripts');
116
 
117
  /**
118
  * Fires in the login page header after scripts are enqueued.
119
  *
120
  * @since 2.1.0
121
  */
122
+ do_action('login_head');
123
 
124
+ $login_header_url = __('https://wordpress.org/');
125
 
126
  /**
127
  * Filters link URL of the header logo above login form.
130
  *
131
  * @param string $login_header_url Login header logo URL.
132
  */
133
+ $login_header_url = apply_filters('login_headerurl', $login_header_url);
134
 
135
  $login_header_title = '';
136
 
144
  */
145
  $login_header_title = apply_filters_deprecated(
146
  'login_headertitle',
147
+ array($login_header_title),
148
  '5.2.0',
149
  'login_headertext',
150
+ __('Usage of the title attribute on the login logo is not recommended for accessibility reasons. Use the link text instead.')
151
  );
152
 
153
+ $login_header_text = empty($login_header_title) ? __('Powered by WordPress') : $login_header_title;
154
 
155
  /**
156
  * Filters the link text of the header logo above the login form.
159
  *
160
  * @param string $login_header_text The login header logo link text.
161
  */
162
+ $login_header_text = apply_filters('login_headertext', $login_header_text);
163
 
164
+ $classes = array('login-action-' . $action, 'wp-core-ui');
165
 
166
+ if (is_rtl()) {
167
  $classes[] = 'rtl';
168
  }
169
 
170
+ if ($interim_login) {
171
  $classes[] = 'interim-login';
 
172
  ?>
173
  <style type="text/css">html{background-color: transparent;}</style>
174
  <?php
175
 
176
+ if ('success' === $interim_login) {
177
  $classes[] = 'interim-login-success';
178
  }
179
  }
180
 
181
+ $classes[] = ' locale-' . sanitize_html_class(strtolower(str_replace('_', '-', get_locale())));
182
 
183
  /**
184
  * Filters the login page body classes.
188
  * @param array $classes An array of body classes.
189
  * @param string $action The action that brought the visitor to the login page.
190
  */
191
+ $classes = apply_filters('login_body_class', $classes, $action);
 
192
  ?>
193
  </head>
194
+ <body class="login no-js <?php echo esc_attr(implode(' ', $classes)); ?>">
195
  <script type="text/javascript">
196
  document.body.className = document.body.className.replace('no-js','js');
197
  </script>
201
  *
202
  * @since 4.6.0
203
  */
204
+ do_action('login_header');
 
205
  ?>
206
  <div id="login">
207
+ <h1><a href="<?php echo esc_url($login_header_url); ?>"><?php echo $login_header_text; ?></a></h1>
208
  <?php
209
  /**
210
  * Filters the message to display above the login form.
213
  *
214
  * @param string $message Login message text.
215
  */
216
+ $message = apply_filters('login_message', $message);
217
 
218
+ if (! empty($message)) {
219
  echo $message . "\n";
220
  }
221
 
222
  // In case a plugin uses $error rather than the $wp_errors object.
223
+ if (! empty($error)) {
224
+ $wp_error->add('error', $error);
225
+ unset($error);
226
  }
227
 
228
+ if ($wp_error->has_errors()) {
229
  $errors = '';
230
  $messages = '';
231
 
232
+ foreach ($wp_error->get_error_codes() as $code) {
233
+ $severity = $wp_error->get_error_data($code);
234
+ foreach ($wp_error->get_error_messages($code) as $error_message) {
235
+ if ('message' === $severity) {
236
  $messages .= ' ' . $error_message . "<br />\n";
237
  } else {
238
  $errors .= ' ' . $error_message . "<br />\n";
240
  }
241
  }
242
 
243
+ if (! empty($errors)) {
244
  /**
245
  * Filters the error messages displayed above the login form.
246
  *
248
  *
249
  * @param string $errors Login error message.
250
  */
251
+ echo '<div id="login_error">' . apply_filters('login_errors', $errors) . "</div>\n";
252
  }
253
 
254
+ if (! empty($messages)) {
255
  /**
256
  * Filters instructional messages displayed above the login form.
257
  *
259
  *
260
  * @param string $messages Login messages.
261
  */
262
+ echo '<p class="message">' . apply_filters('login_messages', $messages) . "</p>\n";
263
  }
264
  }
265
  } // End of login_header().
274
  *
275
  * @param string $input_id Which input to auto-focus.
276
  */
277
+ function login_footer($input_id = '') {
278
  global $interim_login;
279
 
280
  // Don't allow interim logins to navigate away from the page.
281
+ if (! $interim_login) {
282
  ?>
283
+ <p id="backtoblog"><a href="<?php echo esc_url(home_url('/')); ?>">
284
  <?php
285
 
286
  /* translators: %s: Site title. */
287
+ printf(_x('&larr; Go to %s', 'site'), get_bloginfo('title', 'display'));
 
288
  ?>
289
  </a></p>
290
  <?php
291
 
292
+ the_privacy_policy_link('<div class="privacy-policy-page-link">', '</div>');
293
  }
294
 
295
  ?>
297
 
298
  <?php
299
 
300
+ if (! empty($input_id)) {
301
  ?>
302
  <script type="text/javascript">
303
+ try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e) {}
304
+ if (typeof wpOnload=='function')wpOnload();
305
  </script>
306
  <?php
307
  }
311
  *
312
  * @since 3.1.0
313
  */
314
+ do_action('login_footer');
 
315
  ?>
316
  <div class="clear"></div>
317
  </body>
348
  // Main.
349
  //
350
 
351
+ $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'login';
352
  $errors = new WP_Error();
353
 
354
+ if (isset($_GET['key'])) {
355
  $action = 'resetpass';
356
  }
357
 
358
+ if (isset($_GET['checkemail'])) {
359
  $action = 'checkemail';
360
  }
361
 
375
  );
376
 
377
  // Validate action so as to default to the login screen.
378
+ if (! in_array($action, $default_actions, true) && false === has_filter('login_form_' . $action)) {
379
  $action = 'login';
380
  }
381
 
382
  nocache_headers();
383
 
384
+ header('Content-Type: ' . get_bloginfo('html_type') . '; charset=' . get_bloginfo('charset'));
385
 
386
+ if (defined('RELOCATE') && RELOCATE) { // Move flag is set.
387
+ if (isset($_SERVER['PATH_INFO']) && ($_SERVER['PATH_INFO'] !== $_SERVER['PHP_SELF'])) {
388
+ $_SERVER['PHP_SELF'] = str_replace($_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF']);
389
  }
390
 
391
+ $url = dirname(set_url_scheme('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']));
392
 
393
+ if (get_option('siteurl') !== $url) {
394
+ update_option('siteurl', $url);
395
  }
396
  }
397
 
398
  // Set a cookie now to see if they are supported by the browser.
399
+ $secure = ('https' === parse_url(wp_login_url(), PHP_URL_SCHEME));
400
+ setcookie(TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN, $secure);
401
 
402
+ if (SITECOOKIEPATH !== COOKIEPATH) {
403
+ setcookie(TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN, $secure);
404
  }
405
 
406
  /**
408
  *
409
  * @since 3.2.0
410
  */
411
+ do_action('login_init');
412
 
413
  /**
414
  * Fires before a specified login form action.
419
  *
420
  * @since 2.8.0
421
  */
422
+ do_action("login_form_{$action}");
423
 
424
+ $http_post = ('POST' === $_SERVER['REQUEST_METHOD']);
425
+ $interim_login = isset($_REQUEST['interim-login']);
426
 
427
  /**
428
  * Filters the separator used between login form navigation links.
431
  *
432
  * @param string $login_link_separator The separator used between login form navigation links.
433
  */
434
+ $login_link_separator = apply_filters('login_link_separator', ' | ');
435
 
436
+ switch ($action) {
437
 
438
  case 'confirm_admin_email':
439
  /*
441
  * as the current user is not set, see wp-includes/pluggable.php.
442
  * However this action runs on a redirect after logging in.
443
  */
444
+ if (! is_user_logged_in()) {
445
+ wp_safe_redirect(wp_login_url());
446
  exit;
447
  }
448
 
449
+ if (! empty($_REQUEST['redirect_to'])) {
450
  $redirect_to = $_REQUEST['redirect_to'];
451
  } else {
452
  $redirect_to = admin_url();
453
  }
454
 
455
+ if (current_user_can('manage_options')) {
456
+ $admin_email = get_option('admin_email');
457
  } else {
458
+ wp_safe_redirect($redirect_to);
459
  exit;
460
  }
461
 
468
  *
469
  * @param int $interval Interval time (in seconds). Default is 3 days.
470
  */
471
+ $remind_interval = (int) apply_filters('admin_email_remind_interval', 3 * DAY_IN_SECONDS);
472
 
473
+ if (! empty($_GET['remind_me_later'])) {
474
+ if (! wp_verify_nonce($_GET['remind_me_later'], 'remind_me_later_nonce')) {
475
+ wp_safe_redirect(wp_login_url());
476
  exit;
477
  }
478
 
479
+ if ($remind_interval > 0) {
480
+ update_option('admin_email_lifespan', time() + $remind_interval);
481
  }
482
 
483
+ $redirect_to = add_query_arg('admin_email_remind_later', 1, $redirect_to);
484
+ wp_safe_redirect($redirect_to);
485
  exit;
486
  }
487
 
488
+ if (! empty($_POST['correct-admin-email'])) {
489
+ if (! check_admin_referer('confirm_admin_email', 'confirm_admin_email_nonce')) {
490
+ wp_safe_redirect(wp_login_url());
491
  exit;
492
  }
493
 
500
  *
501
  * @param int $interval Interval time (in seconds). Default is 6 months.
502
  */
503
+ $admin_email_check_interval = (int) apply_filters('admin_email_check_interval', 6 * MONTH_IN_SECONDS);
504
 
505
+ if ($admin_email_check_interval > 0) {
506
+ update_option('admin_email_lifespan', time() + $admin_email_check_interval);
507
  }
508
 
509
+ wp_safe_redirect($redirect_to);
510
  exit;
511
  }
512
 
513
+ login_header(__('Confirm your administration email'), '', $errors);
514
 
515
  /**
516
  * Fires before the admin email confirm form.
520
  * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
521
  * credentials. Note that the error object may not contain any errors.
522
  */
523
+ do_action('admin_email_confirm', $errors);
 
524
  ?>
525
 
526
+ <form class="admin-email-confirm-form" name="admin-email-confirm-form" action="<?php echo esc_url(site_url('wp-login.php?action=confirm_admin_email', 'login_post')); ?>" method="post">
527
  <?php
528
  /**
529
  * Fires inside the admin-email-confirm-form form tags, before the hidden fields.
530
  *
531
  * @since 5.3.0
532
  */
533
+ do_action('admin_email_confirm_form');
 
 
534
 
535
+ wp_nonce_field('confirm_admin_email', 'confirm_admin_email_nonce');
536
  ?>
537
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
538
 
539
  <h1 class="admin-email__heading">
540
+ <?php _e('Administration email verification'); ?>
541
  </h1>
542
  <p class="admin-email__details">
543
+ <?php _e('Please verify that the <strong>administration email</strong> for this website is still correct.'); ?>
544
  <?php
545
 
546
  /* translators: URL to the WordPress help section about admin email. */
547
+ $admin_email_help_url = __('https://wordpress.org/support/article/settings-general-screen/#email-address');
548
 
549
  /* translators: Accessibility text. */
550
+ $accessibility_text = sprintf('<span class="screen-reader-text"> %s</span>', __('(opens in a new tab)'));
551
 
552
  printf(
553
  '<a href="%s" rel="noopener" target="_blank">%s%s</a>',
554
+ esc_url($admin_email_help_url),
555
+ __('Why is this important?'),
556
  $accessibility_text
557
  );
 
558
  ?>
559
  </p>
560
  <p class="admin-email__details">
562
 
563
  printf(
564
  /* translators: %s: Admin email address. */
565
+ __('Current administration email: %s'),
566
+ '<strong>' . esc_html($admin_email) . '</strong>'
567
  );
 
568
  ?>
569
  </p>
570
  <p class="admin-email__details">
571
+ <?php _e('This email may be different from your personal email address.'); ?>
572
  </p>
573
 
574
  <div class="admin-email__actions">
575
  <div class="admin-email__actions-primary">
576
  <?php
577
 
578
+ $change_link = admin_url('options-general.php');
579
+ $change_link = add_query_arg('highlight', 'confirm_admin_email', $change_link);
 
580
  ?>
581
+ <a class="button button-large" href="<?php echo esc_url($change_link); ?>"><?php _e('Update'); ?></a>
582
+ <input type="submit" name="correct-admin-email" id="correct-admin-email" class="button button-primary button-large" value="<?php esc_attr_e('The email is correct'); ?>" />
583
  </div>
584
+ <?php if ($remind_interval > 0) : ?>
585
  <div class="admin-email__actions-secondary">
586
  <?php
587
 
588
+ $remind_me_link = wp_login_url($redirect_to);
589
  $remind_me_link = add_query_arg(
590
  array(
591
  'action' => 'confirm_admin_email',
592
+ 'remind_me_later' => wp_create_nonce('remind_me_later_nonce'),
593
  ),
594
  $remind_me_link
595
  );
 
596
  ?>
597
+ <a href="<?php echo esc_url($remind_me_link); ?>"><?php _e('Remind me later'); ?></a>
598
  </div>
599
  <?php endif; ?>
600
  </div>
606
  break;
607
 
608
  case 'postpass':
609
+ if (! array_key_exists('post_password', $_POST)) {
610
+ wp_safe_redirect(wp_get_referer());
611
  exit;
612
  }
613
 
614
  require_once ABSPATH . WPINC . '/class-phpass.php';
615
+ $hasher = new PasswordHash(8, true);
616
 
617
  /**
618
  * Filters the life span of the post password cookie.
624
  *
625
  * @param int $expires The expiry time, as passed to setcookie().
626
  */
627
+ $expire = apply_filters('post_password_expires', time() + 10 * DAY_IN_SECONDS);
628
  $referer = wp_get_referer();
629
 
630
+ if ($referer) {
631
+ $secure = ('https' === parse_url($referer, PHP_URL_SCHEME));
632
  } else {
633
  $secure = false;
634
  }
635
 
636
+ setcookie('wp-postpass_' . COOKIEHASH, $hasher->HashPassword(wp_unslash($_POST['post_password'])), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure);
637
 
638
+ wp_safe_redirect(wp_get_referer());
639
  exit;
640
 
641
  case 'logout':
642
+ check_admin_referer('log-out');
643
 
644
  $user = wp_get_current_user();
645
 
646
  wp_logout();
647
 
648
+ if (! empty($_REQUEST['redirect_to'])) {
649
  $redirect_to = $_REQUEST['redirect_to'];
650
  $requested_redirect_to = $redirect_to;
651
  } else {
652
  $redirect_to = add_query_arg(
653
  array(
654
  'loggedout' => 'true',
655
+ 'wp_lang' => get_user_locale($user),
656
  ),
657
  wp_login_url()
658
  );
669
  * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
670
  * @param WP_User $user The WP_User object for the user that's logging out.
671
  */
672
+ $redirect_to = apply_filters('logout_redirect', $redirect_to, $requested_redirect_to, $user);
673
 
674
+ wp_safe_redirect($redirect_to);
675
  exit;
676
 
677
  case 'lostpassword':
678
  case 'retrievepassword':
679
+ if ($http_post) {
680
  $errors = retrieve_password();
681
 
682
+ if (! is_wp_error($errors)) {
683
+ $redirect_to = ! empty($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
684
+ wp_safe_redirect($redirect_to);
685
  exit;
686
  }
687
  }
688
 
689
+ if (isset($_GET['error'])) {
690
+ if ('invalidkey' === $_GET['error']) {
691
+ $errors->add('invalidkey', __('Your password reset link appears to be invalid. Please request a new link below.'));
692
+ } elseif ('expiredkey' === $_GET['error']) {
693
+ $errors->add('expiredkey', __('Your password reset link has expired. Please request a new link below.'));
694
  }
695
  }
696
 
697
+ $lostpassword_redirect = ! empty($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : '';
698
  /**
699
  * Filters the URL redirected to after submitting the lostpassword/retrievepassword form.
700
  *
702
  *
703
  * @param string $lostpassword_redirect The redirect destination URL.
704
  */
705
+ $redirect_to = apply_filters('lostpassword_redirect', $lostpassword_redirect);
706
 
707
  /**
708
  * Fires before the lost password form.
713
  * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
714
  * credentials. Note that the error object may not contain any errors.
715
  */
716
+ do_action('lost_password', $errors);
717
 
718
+ login_header(__('Lost Password'), '<p class="message">' . __('Please enter your username or email address. You will receive an email message with instructions on how to reset your password.') . '</p>', $errors);
719
 
720
  $user_login = '';
721
 
722
+ if (isset($_POST['user_login']) && is_string($_POST['user_login'])) {
723
+ $user_login = wp_unslash($_POST['user_login']);
724
  }
725
 
726
  ?>
727
 
728
+ <form name="lostpasswordform" id="lostpasswordform" action="<?php echo esc_url(network_site_url('wp-login.php?action=lostpassword', 'login_post')); ?>" method="post">
729
  <p>
730
+ <label for="user_login"><?php _e('Username or Email Address'); ?></label>
731
+ <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr($user_login); ?>" size="20" autocapitalize="off" />
732
  </p>
733
  <?php
734
 
737
  *
738
  * @since 2.1.0
739
  */
740
+ do_action('lostpassword_form');
 
741
  ?>
742
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
743
  <p class="submit">
744
+ <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Get New Password'); ?>" />
745
  </p>
746
  </form>
747
 
748
  <p id="nav">
749
+ <a href="<?php echo esc_url(wp_login_url()); ?>"><?php _e('Log in'); ?></a>
750
  <?php
751
 
752
+ if (get_option('users_can_register')) {
753
+ $registration_url = sprintf('<a href="%s">%s</a>', esc_url(wp_registration_url()), __('Register'));
754
 
755
+ echo esc_html($login_link_separator);
756
 
757
+ // This filter is documented in wp-includes/general-template.php
758
+ echo apply_filters('register', $registration_url);
759
  }
760
 
761
  ?>
762
  </p>
763
  <?php
764
 
765
+ login_footer('user_login');
766
  break;
767
 
768
  case 'resetpass':
769
  case 'rp':
770
+ list($rp_path) = explode('?', wp_unslash($_SERVER['REQUEST_URI']));
771
  $rp_cookie = 'wp-resetpass-' . COOKIEHASH;
772
 
773
+ if (isset($_GET['key'])) {
774
+ $value = sprintf('%s:%s', wp_unslash($_GET['login']), wp_unslash($_GET['key']));
775
+ setcookie($rp_cookie, $value, 0, $rp_path, COOKIE_DOMAIN, is_ssl(), true);
776
 
777
+ wp_safe_redirect(remove_query_arg(array('key', 'login')));
778
  exit;
779
  }
780
 
781
+ if (isset($_COOKIE[$rp_cookie]) && 0 < strpos($_COOKIE[$rp_cookie], ':')) {
782
+ list($rp_login, $rp_key) = explode(':', wp_unslash($_COOKIE[$rp_cookie]), 2);
783
 
784
+ $user = check_password_reset_key($rp_key, $rp_login);
785
 
786
+ if (isset($_POST['pass1']) && ! hash_equals($rp_key, $_POST['rp_key'])) {
787
  $user = false;
788
  }
789
  } else {
790
  $user = false;
791
  }
792
 
793
+ if (! $user || is_wp_error($user)) {
794
+ setcookie($rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true);
795
 
796
+ if ($user && $user->get_error_code() === 'expired_key') {
797
+ wp_redirect(site_url('wp-login.php?action=lostpassword&error=expiredkey'));
798
  } else {
799
+ wp_redirect(site_url('wp-login.php?action=lostpassword&error=invalidkey'));
800
  }
801
 
802
  exit;
804
 
805
  $errors = new WP_Error();
806
 
807
+ if (isset($_POST['pass1']) && $_POST['pass1'] !== $_POST['pass2']) {
808
+ $errors->add('password_reset_mismatch', __('The passwords do not match.'));
809
  }
810
 
811
  /**
816
  * @param WP_Error $errors WP Error object.
817
  * @param WP_User|WP_Error $user WP_User object if the login and reset key match. WP_Error object otherwise.
818
  */
819
+ do_action('validate_password_reset', $errors, $user);
820
 
821
+ if ((! $errors->has_errors()) && isset($_POST['pass1']) && ! empty($_POST['pass1'])) {
822
+ reset_password($user, $_POST['pass1']);
823
+ setcookie($rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true);
824
+ login_header(__('Password Reset'), '<p class="message reset-pass">' . __('Your password has been reset.') . ' <a href="' . esc_url(wp_login_url()) . '">' . __('Log in') . '</a></p>');
825
  login_footer();
826
  exit;
827
  }
828
 
829
+ wp_enqueue_script('utils');
830
+ wp_enqueue_script('user-profile');
 
 
831
 
832
+ login_header(__('Reset Password'), '<p class="message reset-pass">' . __('Enter your new password below.') . '</p>', $errors);
833
  ?>
834
+ <form name="resetpassform" id="resetpassform" action="<?php echo esc_url(network_site_url('wp-login.php?action=resetpass', 'login_post')); ?>" method="post" autocomplete="off">
835
+ <input type="hidden" id="user_login" value="<?php echo esc_attr($rp_login); ?>" autocomplete="off" />
836
 
837
  <div class="user-pass1-wrap">
838
  <p>
839
+ <label for="pass1"><?php _e('New password'); ?></label>
840
  </p>
841
 
842
  <div class="wp-pwd">
843
+ <input type="password" data-reveal="1" data-pw="<?php echo esc_attr(wp_generate_password(16)); ?>" name="pass1" id="pass1" class="input password-input" size="24" value="" autocomplete="off" aria-describedby="pass-strength-result" />
844
 
845
+ <button type="button" class="button button-secondary wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e('Hide password'); ?>">
846
  <span class="dashicons dashicons-hidden" aria-hidden="true"></span>
847
  </button>
848
+ <div id="pass-strength-result" class="hide-if-no-js" aria-live="polite"><?php _e('Strength indicator'); ?></div>
849
  </div>
850
  <div class="pw-weak">
851
  <input type="checkbox" name="pw_weak" id="pw-weak" class="pw-checkbox" />
852
+ <label for="pw-weak"><?php _e('Confirm use of weak password'); ?></label>
853
  </div>
854
  </div>
855
 
856
  <p class="user-pass2-wrap">
857
+ <label for="pass2"><?php _e('Confirm new password'); ?></label>
858
  <input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off" />
859
  </p>
860
 
870
  *
871
  * @param WP_User $user User object of the user whose password is being reset.
872
  */
873
+ do_action('resetpass_form', $user);
 
874
  ?>
875
+ <input type="hidden" name="rp_key" value="<?php echo esc_attr($rp_key); ?>" />
876
  <p class="submit">
877
+ <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Reset Password'); ?>" />
878
  </p>
879
  </form>
880
 
881
  <p id="nav">
882
+ <a href="<?php echo esc_url(wp_login_url()); ?>"><?php _e('Log in'); ?></a>
883
  <?php
884
 
885
+ if (get_option('users_can_register')) {
886
+ $registration_url = sprintf('<a href="%s">%s</a>', esc_url(wp_registration_url()), __('Register'));
887
 
888
+ echo esc_html($login_link_separator);
889
 
890
+ // This filter is documented in wp-includes/general-template.php
891
+ echo apply_filters('register', $registration_url);
892
  }
893
 
894
  ?>
895
  </p>
896
  <?php
897
 
898
+ login_footer('user_pass');
899
  break;
900
 
901
  case 'register':
902
+ if (is_multisite()) {
903
  /**
904
  * Filters the Multisite sign up URL.
905
  *
907
  *
908
  * @param string $sign_up_url The sign up URL.
909
  */
910
+ wp_redirect(apply_filters('wp_signup_location', network_site_url('wp-signup.php')));
911
  exit;
912
  }
913
 
914
+ if (! get_option('users_can_register')) {
915
+ wp_redirect(site_url('wp-login.php?registration=disabled'));
916
  exit;
917
  }
918
 
919
  $user_login = '';
920
  $user_email = '';
921
 
922
+ if ($http_post) {
923
+ if (isset($_POST['user_login']) && is_string($_POST['user_login'])) {
924
+ $user_login = wp_unslash($_POST['user_login']);
925
  }
926
 
927
+ if (isset($_POST['user_email']) && is_string($_POST['user_email'])) {
928
+ $user_email = wp_unslash($_POST['user_email']);
929
  }
930
 
931
+ $errors = register_new_user($user_login, $user_email);
932
 
933
+ if (! is_wp_error($errors)) {
934
+ $redirect_to = ! empty($_POST['redirect_to']) ? $_POST['redirect_to'] : 'wp-login.php?checkemail=registered';
935
+ wp_safe_redirect($redirect_to);
936
  exit;
937
  }
938
  }
939
 
940
+ $registration_redirect = ! empty($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : '';
941
 
942
  /**
943
  * Filters the registration redirect URL.
946
  *
947
  * @param string $registration_redirect The redirect destination URL.
948
  */
949
+ $redirect_to = apply_filters('registration_redirect', $registration_redirect);
 
 
950
 
951
+ login_header(__('Registration Form'), '<p class="message register">' . __('Register For This Site') . '</p>', $errors);
952
  ?>
953
+ <form name="registerform" id="registerform" action="<?php echo esc_url(site_url('wp-login.php?action=register', 'login_post')); ?>" method="post" novalidate="novalidate">
954
  <p>
955
+ <label for="user_login"><?php _e('Username'); ?></label>
956
+ <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr(wp_unslash($user_login)); ?>" size="20" autocapitalize="off" />
957
  </p>
958
  <p>
959
+ <label for="user_email"><?php _e('Email'); ?></label>
960
+ <input type="email" name="user_email" id="user_email" class="input" value="<?php echo esc_attr(wp_unslash($user_email)); ?>" size="25" />
961
  </p>
962
  <?php
963
 
966
  *
967
  * @since 2.1.0
968
  */
969
+ do_action('register_form');
 
970
  ?>
971
  <p id="reg_passmail">
972
+ <?php _e('Registration confirmation will be emailed to you.'); ?>
973
  </p>
974
  <br class="clear" />
975
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
976
  <p class="submit">
977
+ <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Register'); ?>" />
978
  </p>
979
  </form>
980
 
981
  <p id="nav">
982
+ <a href="<?php echo esc_url(wp_login_url()); ?>"><?php _e('Log in'); ?></a>
983
+ <?php echo esc_html($login_link_separator); ?>
984
+ <a href="<?php echo esc_url(wp_lostpassword_url()); ?>"><?php _e('Lost your password?'); ?></a>
985
  </p>
986
  <?php
987
 
988
+ login_footer('user_login');
989
  break;
990
 
991
  case 'checkemail':
992
  $redirect_to = admin_url();
993
  $errors = new WP_Error();
994
 
995
+ if ('confirm' === $_GET['checkemail']) {
996
  $errors->add(
997
  'confirm',
998
  sprintf(
999
  /* translators: %s: Link to the login page. */
1000
+ __('Check your email for the confirmation link, then visit the <a href="%s">login page</a>.'),
1001
  wp_login_url()
1002
  ),
1003
  'message'
1004
  );
1005
+ } elseif ('registered' === $_GET['checkemail']) {
1006
  $errors->add(
1007
  'registered',
1008
  sprintf(
1009
  /* translators: %s: Link to the login page. */
1010
+ __('Registration complete. Please check your email, then visit the <a href="%s">login page</a>.'),
1011
  wp_login_url()
1012
  ),
1013
  'message'
1014
  );
1015
  }
1016
 
1017
+ // This action is documented in wp-login.php
1018
+ $errors = apply_filters('wp_login_errors', $errors, $redirect_to);
1019
 
1020
+ login_header(__('Check your email'), '', $errors);
1021
  login_footer();
1022
  break;
1023
 
1024
  case 'confirmaction':
1025
+ if (! isset($_GET['request_id'])) {
1026
+ wp_die(__('Missing request ID.'));
1027
  }
1028
 
1029
+ if (! isset($_GET['confirm_key'])) {
1030
+ wp_die(__('Missing confirm key.'));
1031
  }
1032
 
1033
  $request_id = (int) $_GET['request_id'];
1034
+ $key = sanitize_text_field(wp_unslash($_GET['confirm_key']));
1035
+ $result = wp_validate_user_request_key($request_id, $key);
1036
 
1037
+ if (is_wp_error($result)) {
1038
+ wp_die($result);
1039
  }
1040
 
1041
  /**
1051
  *
1052
  * @param int $request_id Request ID.
1053
  */
1054
+ do_action('user_request_action_confirmed', $request_id);
1055
 
1056
+ $message = _wp_privacy_account_request_confirmed_message($request_id);
1057
 
1058
+ login_header(__('User action confirmed.'), $message);
1059
  login_footer();
1060
  exit;
1061
 
1062
  case 'login':
1063
  default:
1064
  $secure_cookie = '';
1065
+ $customize_login = isset($_REQUEST['customize-login']);
1066
 
1067
+ if ($customize_login) {
1068
+ wp_enqueue_script('customize-base');
1069
  }
1070
 
1071
  // If the user wants SSL but the session is not SSL, force a secure cookie.
1072
+ if (! empty($_POST['log']) && ! force_ssl_admin()) {
1073
+ $user_name = sanitize_user(wp_unslash($_POST['log']));
1074
+ $user = get_user_by('login', $user_name);
1075
 
1076
+ if (! $user && strpos($user_name, '@')) {
1077
+ $user = get_user_by('email', $user_name);
1078
  }
1079
 
1080
+ if ($user) {
1081
+ if (get_user_option('use_ssl', $user->ID)) {
1082
  $secure_cookie = true;
1083
+ force_ssl_admin(true);
1084
  }
1085
  }
1086
  }
1087
 
1088
+ if (isset($_REQUEST['redirect_to'])) {
1089
  $redirect_to = $_REQUEST['redirect_to'];
1090
  // Redirect to HTTPS if user wants SSL.
1091
+ if ($secure_cookie && false !== strpos($redirect_to, 'wp-admin')) {
1092
+ $redirect_to = preg_replace('|^http://|', 'https://', $redirect_to);
1093
  }
1094
  } else {
1095
  $redirect_to = admin_url();
1096
  }
1097
 
1098
+ $reauth = empty($_REQUEST['reauth']) ? false : true;
1099
 
1100
+ $user = wp_signon(array(), $secure_cookie);
1101
 
1102
+ if (empty($_COOKIE[LOGGED_IN_COOKIE])) {
1103
+ if (headers_sent()) {
1104
  $user = new WP_Error(
1105
  'test_cookie',
1106
  sprintf(
1107
  /* translators: 1: Browser cookie documentation URL, 2: Support forums URL. */
1108
+ __('<strong>Error</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.'),
1109
+ __('https://wordpress.org/support/article/cookies/'),
1110
+ __('https://wordpress.org/support/forums/')
1111
  )
1112
  );
1113
+ } elseif (isset($_POST['testcookie']) && empty($_COOKIE[TEST_COOKIE])) {
1114
  // If cookies are disabled, we can't log in even with a valid user and password.
1115
  $user = new WP_Error(
1116
  'test_cookie',
1117
  sprintf(
1118
  /* translators: %s: Browser cookie documentation URL. */
1119
+ __('<strong>Error</strong>: Cookies are blocked or not supported by your browser. You must <a href="%s">enable cookies</a> to use WordPress.'),
1120
+ __('https://wordpress.org/support/article/cookies/#enable-cookies-in-your-browser')
1121
  )
1122
  );
1123
  }
1124
  }
1125
 
1126
+ $requested_redirect_to = isset($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : '';
1127
  /**
1128
  * Filters the login redirect URL.
1129
  *
1133
  * @param string $requested_redirect_to The requested redirect destination URL passed as a parameter.
1134
  * @param WP_User|WP_Error $user WP_User object if login was successful, WP_Error object otherwise.
1135
  */
1136
+ $redirect_to = apply_filters('login_redirect', $redirect_to, $requested_redirect_to, $user);
1137
 
1138
+ if (! is_wp_error($user) && ! $reauth) {
1139
+ if ($interim_login) {
1140
+ $message = '<p class="message">' . __('You have logged in successfully.') . '</p>';
1141
  $interim_login = 'success';
1142
+ login_header('', $message);
 
1143
  ?>
1144
  </div>
1145
  <?php
1146
 
1147
+ // This action is documented in wp-login.php
1148
+ do_action('login_footer');
1149
 
1150
+ if ($customize_login) {
1151
  ?>
1152
+ <script type="text/javascript">setTimeout(function() { new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); ?>', channel: 'login' }).send('login') }, 1000);</script>
1153
  <?php
1154
  }
1155
 
1161
  }
1162
 
1163
  // Check if it is time to add a redirect to the admin email confirmation screen.
1164
+ if (is_a($user, 'WP_User') && $user->exists() && $user->has_cap('manage_options')) {
1165
+ $admin_email_lifespan = (int) get_option('admin_email_lifespan');
1166
 
1167
  // If `0` (or anything "falsey" as it is cast to int) is returned, the user will not be redirected
1168
  // to the admin email confirmation screen.
1169
+ // This filter is documented in wp-login.php
1170
+ $admin_email_check_interval = (int) apply_filters('admin_email_check_interval', 6 * MONTH_IN_SECONDS);
1171
 
1172
+ if ($admin_email_check_interval > 0 && time() > $admin_email_lifespan) {
1173
  $redirect_to = add_query_arg(
1174
  array(
1175
  'action' => 'confirm_admin_email',
1176
+ 'wp_lang' => get_user_locale($user),
1177
  ),
1178
+ wp_login_url($redirect_to)
1179
  );
1180
  }
1181
  }
1182
 
1183
+ if ((empty($redirect_to) || 'wp-admin/' === $redirect_to || admin_url() === $redirect_to)) {
1184
  // If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
1185
+ if (is_multisite() && ! get_active_blog_for_user($user->ID) && ! is_super_admin($user->ID)) {
1186
  $redirect_to = user_admin_url();
1187
+ } elseif (is_multisite() && ! $user->has_cap('read')) {
1188
+ $redirect_to = get_dashboard_url($user->ID);
1189
+ } elseif (! $user->has_cap('edit_posts')) {
1190
+ $redirect_to = $user->has_cap('read') ? admin_url('profile.php') : home_url();
1191
  }
1192
 
1193
+ wp_redirect($redirect_to);
1194
  exit;
1195
  }
1196
 
1197
+ wp_safe_redirect($redirect_to);
1198
  exit;
1199
  }
1200
 
1201
  $errors = $user;
1202
  // Clear errors if loggedout is set.
1203
+ if (! empty($_GET['loggedout']) || $reauth) {
1204
  $errors = new WP_Error();
1205
  }
1206
 
1207
+ if (empty($_POST) && $errors->get_error_codes() === array('empty_username', 'empty_password')) {
1208
+ $errors = new WP_Error('', '');
1209
  }
1210
 
1211
+ if ($interim_login) {
1212
+ if (! $errors->has_errors()) {
1213
+ $errors->add('expired', __('Your session has expired. Please log in to continue where you left off.'), 'message');
1214
  }
1215
  } else {
1216
  // Some parts of this script use the main login form to display a message.
1217
+ if (isset($_GET['loggedout']) && $_GET['loggedout']) {
1218
+ $errors->add('loggedout', __('You are now logged out.'), 'message');
1219
+ } elseif (isset($_GET['registration']) && 'disabled' === $_GET['registration']) {
1220
+ $errors->add('registerdisabled', __('User registration is currently not allowed.'));
1221
+ } elseif (strpos($redirect_to, 'about.php?updated')) {
1222
+ $errors->add('updated', __('<strong>You have successfully updated WordPress!</strong> Please log back in to see what&#8217;s new.'), 'message');
1223
+ } elseif (WP_Recovery_Mode_Link_Service::LOGIN_ACTION_ENTERED === $action) {
1224
+ $errors->add('enter_recovery_mode', __('Recovery Mode Initialized. Please log in to continue.'), 'message');
1225
+ } elseif (isset($_GET['redirect_to']) && false !== strpos($_GET['redirect_to'], 'wp-admin/authorize-application.php')) {
1226
+ $query_component = wp_parse_url($_GET['redirect_to'], PHP_URL_QUERY);
1227
+ parse_str($query_component, $query);
1228
+
1229
+ if (! empty($query['app_name'])) {
1230
  /* translators: 1: Website name, 2: Application name. */
1231
+ $message = sprintf('Please log in to %1$s to authorize %2$s to connect to your account.', get_bloginfo('name', 'display'), '<strong>' . esc_html($query['app_name']) . '</strong>');
1232
  } else {
1233
  /* translators: %s: Website name. */
1234
+ $message = sprintf('Please log in to %s to proceed with authorization.', get_bloginfo('name', 'display'));
1235
  }
1236
 
1237
+ $errors->add('authorize_application', $message, 'message');
1238
  }
1239
  }
1240
 
1246
  * @param WP_Error $errors WP Error object.
1247
  * @param string $redirect_to Redirect destination URL.
1248
  */
1249
+ $errors = apply_filters('wp_login_errors', $errors, $redirect_to);
1250
 
1251
  // Clear any stale cookies.
1252
+ if ($reauth) {
1253
  wp_clear_auth_cookie();
1254
  }
1255
 
1256
+ login_header(__('Log In'), '', $errors);
1257
 
1258
+ if (isset($_POST['log'])) {
1259
+ $user_login = ('incorrect_password' === $errors->get_error_code() || 'empty_password' === $errors->get_error_code()) ? esc_attr(wp_unslash($_POST['log'])) : '';
1260
  }
1261
 
1262
+ $rememberme = ! empty($_POST['rememberme']);
1263
 
1264
+ if ($errors->has_errors()) {
1265
  $aria_describedby_error = ' aria-describedby="login_error"';
1266
  } else {
1267
  $aria_describedby_error = '';
1268
  }
1269
 
1270
+ wp_enqueue_script('user-profile');
1271
 
1272
  //aiowps - this check is necessary because otherwise if variables are undefined we get a warning!
1273
+ if (empty($user_login)) {
1274
  $user_login = '';
1275
+ }
1276
+ if (empty($error)) {
1277
  $error = '';
1278
+ }
1279
  ?>
1280
 
1281
+ <form name="loginform" id="loginform" action="<?php echo esc_url(site_url('wp-login.php', 'login_post')); ?>" method="post">
1282
  <p>
1283
+ <label for="user_login"><?php _e('Username or Email Address'); ?></label>
1284
+ <input type="text" name="log" id="user_login"<?php echo $aria_describedby_error; ?> class="input" value="<?php echo esc_attr($user_login); ?>" size="20" autocapitalize="off" />
1285
  </p>
1286
 
1287
  <div class="user-pass-wrap">
1288
+ <label for="user_pass"><?php _e('Password'); ?></label>
1289
  <div class="wp-pwd">
1290
  <input type="password" name="pwd" id="user_pass"<?php echo $aria_describedby_error; ?> class="input password-input" value="" size="20" />
1291
+ <button type="button" class="button button-secondary wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e('Show password'); ?>">
1292
  <span class="dashicons dashicons-visibility" aria-hidden="true"></span>
1293
  </button>
1294
  </div>
1300
  *
1301
  * @since 2.1.0
1302
  */
1303
+ do_action('login_form');
 
1304
  ?>
1305
+ <p class="forgetmenot"><input name="rememberme" type="checkbox" id="rememberme" value="forever" <?php checked($rememberme); ?> /> <label for="rememberme"><?php esc_html_e('Remember Me'); ?></label></p>
1306
  <p class="submit">
1307
+ <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Log In'); ?>" />
1308
  <?php
1309
 
1310
+ if ($interim_login) {
1311
  ?>
1312
  <input type="hidden" name="interim-login" value="1" />
1313
  <?php
1314
  } else {
1315
  ?>
1316
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
1317
  <?php
1318
  }
1319
 
1320
+ if ($customize_login) {
1321
  ?>
1322
  <input type="hidden" name="customize-login" value="1" />
1323
  <?php
1330
 
1331
  <?php
1332
 
1333
+ if (! $interim_login) {
1334
  ?>
1335
  <p id="nav">
1336
  <?php
1337
 
1338
+ if (get_option('users_can_register')) {
1339
+ $registration_url = sprintf('<a href="%s">%s</a>', esc_url(wp_registration_url()), __('Register'));
1340
 
1341
+ // This filter is documented in wp-includes/general-template.php
1342
+ echo apply_filters('register', $registration_url);
1343
 
1344
+ echo esc_html($login_link_separator);
1345
  }
1346
 
1347
  ?>
1348
+ <a href="<?php echo esc_url(wp_lostpassword_url()); ?>"><?php _e('Lost your password?'); ?></a>
1349
  </p>
1350
  <?php
1351
  }
1352
 
1353
  $login_script = 'function wp_attempt_focus() {';
1354
+ $login_script .= 'setTimeout(function() {';
1355
  $login_script .= 'try {';
1356
 
1357
+ if ($user_login) {
1358
+ $login_script .= 'd = document.getElementById("user_pass"); d.value = "";';
1359
  } else {
1360
+ $login_script .= 'd = document.getElementById("user_login");';
1361
 
1362
+ if ($errors->get_error_code() === 'invalid_username') {
1363
  $login_script .= 'd.value = "";';
1364
  }
1365
  }
1366
 
1367
  $login_script .= 'd.focus(); d.select();';
1368
+ $login_script .= '} catch(er) {}';
1369
  $login_script .= '}, 200);';
1370
  $login_script .= "}\n"; // End of wp_attempt_focus().
1371
 
1376
  *
1377
  * @param bool $print Whether to print the function call. Default true.
1378
  */
1379
+ if (apply_filters('enable_login_autofocus', true) && ! $error) {
1380
  $login_script .= "wp_attempt_focus();\n";
1381
  }
1382
 
1383
  // Run `wpOnload()` if defined.
1384
+ $login_script .= "if (typeof wpOnload === 'function') { wpOnload() }";
 
1385
  ?>
1386
  <script type="text/javascript">
1387
  <?php echo $login_script; ?>
1388
  </script>
1389
  <?php
1390
 
1391
+ if ($interim_login) {
1392
  ?>
1393
  <script type="text/javascript">
1394
+ (function() {
1395
  try {
1396
+ var i, links = document.getElementsByTagName('a');
1397
+ for (i in links) {
1398
+ if (links[i].href) {
1399
  links[i].target = '_blank';
1400
  links[i].rel = 'noopener';
1401
  }
1402
  }
1403
+ } catch(er) {}
1404
  }());
1405
  </script>
1406
  <?php
other-includes/wp-security-stop-users-enumeration.php CHANGED
@@ -1,11 +1,10 @@
1
  <?php
2
-
3
- /*
4
  * Merged by Davide Giunchi, from plugin "Stop User Enumeration"
5
  */
6
 
7
  if (!is_admin() && isset($_SERVER['REQUEST_URI'])) {
8
- if (preg_match('/(wp-comments-post)/', $_SERVER['REQUEST_URI']) === 0 && !empty($_REQUEST['author'])) {
9
- wp_die('Accessing author info via link is forbidden');
10
- }
11
  }
1
  <?php
2
+ /**
 
3
  * Merged by Davide Giunchi, from plugin "Stop User Enumeration"
4
  */
5
 
6
  if (!is_admin() && isset($_SERVER['REQUEST_URI'])) {
7
+ if (preg_match('/(wp-comments-post)/', $_SERVER['REQUEST_URI']) === 0 && !empty($_REQUEST['author'])) {
8
+ wp_die('Accessing author info via link is forbidden');
9
+ }
10
  }
other-includes/wp-security-unlock-request.php CHANGED
@@ -8,115 +8,107 @@ global $aio_wp_security;
8
  $display_form = true;
9
  //Make this page look like the WP login page
10
  wp_head();
11
- wp_admin_css( 'login', true );
12
- wp_admin_css( 'colors-fresh', true );
13
- $login_header_url = __( 'http://wordpress.org/' );
14
- $login_header_title = __( 'Powered by WordPress' );
15
  ?>
16
  </head>
17
 
18
  <body class="login login-action-login wp-core-ui aiowps-unlock-request">
19
  <div id="login">
20
- <h1><a href="<?php echo esc_url( $login_header_url ); ?>" title="<?php echo esc_attr( $login_header_title ); ?>"><?php bloginfo( 'name' ); ?></a></h1>
21
-
22
  <?php
23
- if (isset($_POST['aiowps_unlock_request']))
24
- {
25
- //This catches the $_POST from the "Request Unlock" button on the main WP login page
26
- isset($_POST['aiowps-unlock-string-info'])?($unlock_encoded_info = strip_tags(trim($_POST['aiowps-unlock-string-info']))):($unlock_encoded_info = '');
27
- $unlock_secret_string = $aio_wp_security->configs->get_value('aiowps_unlock_request_secret_key');
28
- $unlock_temp_string = isset($_POST['aiowps-unlock-temp-string'])?strip_tags($_POST['aiowps-unlock-temp-string']):'';
29
- $submitted_encoded_string = base64_encode($unlock_temp_string.$unlock_secret_string);
30
- if($submitted_encoded_string !== $unlock_encoded_info)
31
- {
32
- //Someone somehow landed on this page directly without clicking the unlock button on login form
33
- echo '<div id="login_error">'.__('ERROR: Unable to process your request!','all-in-one-wp-security-and-firewall').'</div>';
34
- die();
35
- }
36
- else if($display_form)
37
- {
38
- echo display_unlock_form();
39
- }
40
  } //End if block
41
 
42
- if (isset($_POST['aiowps_wp_submit_unlock_request']))
43
- {
44
- //This catches the $_POST when someone submits the form from our special unlock request page where visitor enters email address
45
- $errors = '';
46
 
47
- $email = trim($_POST['aiowps_unlock_request_email']);
48
- if (empty($email) || !is_email($email))
49
- {
50
- $errors .= '<p>'.__('Please enter a valid email address','all-in-one-wp-security-and-firewall').'</p>';
51
- }
52
-
53
- if($errors){
54
- $display_form = true;
55
- echo '<div id="login_error">'.$errors.'</div>';
56
- $sanitized_email = sanitize_email($email);
57
- echo display_unlock_form($sanitized_email);
58
- }else{
59
- $locked_user = get_user_by('email', $email);
60
- if(!$locked_user){
61
- //user with this email does not exist in the system
62
- $errors .= '<p>'.__('User account not found!','all-in-one-wp-security-and-firewall').'</p>';
63
- echo '<div id="login_error">'.$errors.'</div>';
64
- }else{
65
- //Process unlock request
66
- //Generate a special code and unlock url
67
- $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
68
- if(empty($ip)){
69
- $unlock_url = false;
70
- }else{
71
- $unlock_url = AIOWPSecurity_User_Login::generate_unlock_request_link($ip);
72
- }
73
 
74
- if (!$unlock_url){
75
- //No entry found in lockdown table with this IP range
76
- $error_msg = '<p>'.__('Error: No locked entry was found in the DB with your IP address range!','all-in-one-wp-security-and-firewall').'</p>';
77
- echo '<div id="login_error">'.$error_msg.'</div>';
78
- }else{
79
- //Send an email to the user
80
- AIOWPSecurity_User_Login::send_unlock_request_email($email, $unlock_url);
81
- echo '<p class="message">' . __('An email has been sent to you with the unlock instructions.', 'all-in-one-wp-security-and-firewall') . '</p>';
82
- }
83
- }
84
- $display_form = false;
85
- }
86
  }
87
  ?>
88
  </div> <!-- end #login -->
89
 
90
  </body>
91
  </html>
92
- <?php
93
 
94
- function display_unlock_form($email='')
95
- {
96
- ob_start();
97
- // Display the unlock request form
98
- $unlock_form_msg
99
- = '<p>' . __('You are here because you have been locked out due to too many incorrect login attempts.', 'all-in-one-wp-security-and-firewall') . '</p>'
100
- . '<p>' . __('Please enter your email address and you will receive an email with instructions on how to unlock yourself.', 'all-in-one-wp-security-and-firewall') . '</p>'
101
- ;
102
  ?>
103
  <div class="message"><?php echo $unlock_form_msg; ?></div>
104
  <form name="loginform" id="loginform" action="<?php echo wp_login_url(); ?>" method="post">
105
- <?php
106
- if(isset($_POST['aiowps-woo-login'])){
107
- echo '<input type="hidden" name="aiowps-woo-login" id="aiowps-woo-login" value="1" />';
108
- }
109
- ?>
110
  <p>
111
  <label for="aiowps_unlock_request_email"><?php _e('Email Address', 'all-in-one-wp-security-and-firewall'); ?><br>
112
  <input type="text" name="aiowps_unlock_request_email" id="aiowps_unlock_request_email" class="input" value="<?php echo $email; ?>" size="20"></label>
113
  </p>
114
- <p class="submit">
115
- <input type="submit" name="aiowps_wp_submit_unlock_request" id="aiowps_wp_submit_unlock_request" class="button button-primary button-large" value="<?php esc_attr_e('Send Unlock Request', 'all-in-one-wp-security-and-firewall'); ?>">
116
  </p>
117
  </form>
118
- <?php
119
- $output = ob_get_contents();
120
- ob_end_clean();
121
- return $output;
122
  }
8
  $display_form = true;
9
  //Make this page look like the WP login page
10
  wp_head();
11
+ wp_admin_css('login', true);
12
+ wp_admin_css('colors-fresh', true);
13
+ $login_header_url = __('http://wordpress.org/');
14
+ $login_header_title = __('Powered by WordPress');
15
  ?>
16
  </head>
17
 
18
  <body class="login login-action-login wp-core-ui aiowps-unlock-request">
19
  <div id="login">
20
+ <h1><a href="<?php echo esc_url($login_header_url); ?>" title="<?php echo esc_attr($login_header_title); ?>"><?php bloginfo('name'); ?></a></h1>
21
+
22
  <?php
23
+ if (isset($_POST['aiowps_unlock_request'])) {
24
+ //This catches the $_POST from the "Request Unlock" button on the main WP login page
25
+ isset($_POST['aiowps-unlock-string-info']) ? ($unlock_encoded_info = strip_tags(trim($_POST['aiowps-unlock-string-info']))) : ($unlock_encoded_info = '');
26
+ $unlock_secret_string = $aio_wp_security->configs->get_value('aiowps_unlock_request_secret_key');
27
+ $unlock_temp_string = isset($_POST['aiowps-unlock-temp-string']) ? strip_tags($_POST['aiowps-unlock-temp-string']) : '';
28
+ $submitted_encoded_string = base64_encode($unlock_temp_string.$unlock_secret_string);
29
+ if ($submitted_encoded_string !== $unlock_encoded_info) {
30
+ //Someone somehow landed on this page directly without clicking the unlock button on login form
31
+ echo '<div id="login_error">'.__('ERROR: Unable to process your request!', 'all-in-one-wp-security-and-firewall').'</div>';
32
+ die();
33
+ } elseif ($display_form) {
34
+ echo display_unlock_form();
35
+ }
 
 
 
 
36
  } //End if block
37
 
38
+ if (isset($_POST['aiowps_wp_submit_unlock_request'])) {
39
+ //This catches the $_POST when someone submits the form from our special unlock request page where visitor enters email address
40
+ $errors = '';
 
41
 
42
+ $email = trim($_POST['aiowps_unlock_request_email']);
43
+ if (empty($email) || !is_email($email)) {
44
+ $errors .= '<p>'.__('Please enter a valid email address', 'all-in-one-wp-security-and-firewall').'</p>';
45
+ }
46
+
47
+ if ($errors) {
48
+ $display_form = true;
49
+ echo '<div id="login_error">'.$errors.'</div>';
50
+ $sanitized_email = sanitize_email($email);
51
+ echo display_unlock_form($sanitized_email);
52
+ } else {
53
+ $locked_user = get_user_by('email', $email);
54
+ if (!$locked_user) {
55
+ //user with this email does not exist in the system
56
+ $errors .= '<p>'.__('User account not found!', 'all-in-one-wp-security-and-firewall').'</p>';
57
+ echo '<div id="login_error">'.$errors.'</div>';
58
+ } else {
59
+ //Process unlock request
60
+ //Generate a special code and unlock url
61
+ $ip = AIOWPSecurity_Utility_IP::get_user_ip_address(); //Get the IP address of user
62
+ if (empty($ip)) {
63
+ $unlock_url = false;
64
+ } else {
65
+ $unlock_url = AIOWPSecurity_User_Login::generate_unlock_request_link($ip);
66
+ }
 
67
 
68
+ if (!$unlock_url) {
69
+ //No entry found in lockdown table with this IP range
70
+ $error_msg = '<p>'.__('Error: No locked entry was found in the DB with your IP address range!', 'all-in-one-wp-security-and-firewall').'</p>';
71
+ echo '<div id="login_error">'.$error_msg.'</div>';
72
+ } else {
73
+ //Send an email to the user
74
+ AIOWPSecurity_User_Login::send_unlock_request_email($email, $unlock_url);
75
+ echo '<p class="message">' . __('An email has been sent to you with the unlock instructions.', 'all-in-one-wp-security-and-firewall') . '</p>';
76
+ }
77
+ }
78
+ $display_form = false;
79
+ }
80
  }
81
  ?>
82
  </div> <!-- end #login -->
83
 
84
  </body>
85
  </html>
86
+ <?php
87
 
88
+ function display_unlock_form($email = '') {
89
+ ob_start();
90
+ // Display the unlock request form
91
+ $unlock_form_msg
92
+ = '<p>' . __('You are here because you have been locked out due to too many incorrect login attempts.', 'all-in-one-wp-security-and-firewall') . '</p>'
93
+ . '<p>' . __('Please enter your email address and you will receive an email with instructions on how to unlock yourself.', 'all-in-one-wp-security-and-firewall') . '</p>';
 
 
94
  ?>
95
  <div class="message"><?php echo $unlock_form_msg; ?></div>
96
  <form name="loginform" id="loginform" action="<?php echo wp_login_url(); ?>" method="post">
97
+ <?php
98
+ if (isset($_POST['aiowps-woo-login'])) {
99
+ echo '<input type="hidden" name="aiowps-woo-login" id="aiowps-woo-login" value="1" />';
100
+ }
101
+ ?>
102
  <p>
103
  <label for="aiowps_unlock_request_email"><?php _e('Email Address', 'all-in-one-wp-security-and-firewall'); ?><br>
104
  <input type="text" name="aiowps_unlock_request_email" id="aiowps_unlock_request_email" class="input" value="<?php echo $email; ?>" size="20"></label>
105
  </p>
106
+ <p class="submit">
107
+ <input type="submit" name="aiowps_wp_submit_unlock_request" id="aiowps_wp_submit_unlock_request" class="button button-primary button-large" value="<?php esc_attr_e('Send Unlock Request', 'all-in-one-wp-security-and-firewall'); ?>">
108
  </p>
109
  </form>
110
+ <?php
111
+ $output = ob_get_contents();
112
+ ob_end_clean();
113
+ return $output;
114
  }
other-includes/wp-security-visitor-lockout-page.php CHANGED
@@ -1,8 +1,8 @@
1
  <?php
2
  global $aio_wp_security;
3
  $aiowps_site_lockout_msg_raw = $aio_wp_security->configs->get_value('aiowps_site_lockout_msg');
4
- if(empty($aiowps_site_lockout_msg_raw)){
5
- $aiowps_site_lockout_msg_raw = '<p>This site is currently not available. Please try again later.</p>';
6
  }
7
  $maintenance_msg = html_entity_decode($aiowps_site_lockout_msg_raw, ENT_COMPAT, "UTF-8");
8
  $maintenance_msg = apply_filters('the_content', $maintenance_msg);
@@ -13,19 +13,19 @@ $maintenance_msg = apply_filters('the_content', $maintenance_msg);
13
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
14
  <title><?php bloginfo('name'); ?></title>
15
 
16
- <link rel="stylesheet" type="text/css" href="<?php echo AIO_WP_SECURITY_URL ; ?>/css/wp-security-site-lockout-page.css" />
17
  <?php wp_head(); ?>
18
  </head>
19
 
20
  <body>
21
  <div class="aiowps-site-lockout-body">
22
- <div class="aiowps-site-lockout-body-content">
23
- <div class="aiowps-site-lockout-box">
24
- <div class="aiowps-site-lockout-msg">
25
- <?php echo $maintenance_msg; ?>
26
- </div>
27
- </div> <!-- end .aiowps-site-lockout-box -->
28
- </div> <!-- end .aiowps-site-lockout-body-content -->
29
  </div> <!-- end .aiowps-site-lockout-body -->
30
  </body>
31
  </html>
1
  <?php
2
  global $aio_wp_security;
3
  $aiowps_site_lockout_msg_raw = $aio_wp_security->configs->get_value('aiowps_site_lockout_msg');
4
+ if (empty($aiowps_site_lockout_msg_raw)) {
5
+ $aiowps_site_lockout_msg_raw = '<p>This site is currently not available. Please try again later.</p>';
6
  }
7
  $maintenance_msg = html_entity_decode($aiowps_site_lockout_msg_raw, ENT_COMPAT, "UTF-8");
8
  $maintenance_msg = apply_filters('the_content', $maintenance_msg);
13
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
14
  <title><?php bloginfo('name'); ?></title>
15
 
16
+ <link rel="stylesheet" type="text/css" href="<?php echo AIO_WP_SECURITY_URL; ?>/css/wp-security-site-lockout-page.css" />
17
  <?php wp_head(); ?>
18
  </head>
19
 
20
  <body>
21
  <div class="aiowps-site-lockout-body">
22
+ <div class="aiowps-site-lockout-body-content">
23
+ <div class="aiowps-site-lockout-box">
24
+ <div class="aiowps-site-lockout-msg">
25
+ <?php echo $maintenance_msg; ?>
26
+ </div>
27
+ </div> <!-- end .aiowps-site-lockout-box -->
28
+ </div> <!-- end .aiowps-site-lockout-body-content -->
29
  </div> <!-- end .aiowps-site-lockout-body -->
30
  </body>
31
  </html>
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: security, secure, Anti Virus, antivirus, ban, ban hacker, virus, firewall,
5
  Requires PHP: 5.6
6
  Requires at least: 5.0
7
  Tested up to: 5.9
8
- Stable tag: 4.4.10
9
  License: GPLv3
10
 
11
  A comprehensive, user-friendly, all in one WordPress security and firewall plugin for your site.
@@ -185,6 +185,32 @@ None
185
 
186
  == Changelog ==
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  = 4.4.10 - 21/Jan/2022 =
189
 
190
  * FEATURE: Auto-purge failed login records after 90 days.
@@ -194,7 +220,10 @@ None
194
  * FIX: Logout date-time shows 1000-10-10 10:00:00 for non-logged out user.
195
  * FIX: The notification for re-inserting the security rules in your .htaccess file appears after deactivating and activating the plugin to non-admin users.
196
  * TWEAK: Replace obsolete variable reference style
 
197
  * TWEAK: View debug logs from within the UI
 
 
198
 
199
  = 4.4.9 =
200
  - Added Polish language translation file to the plugin. Thanks to Dariusz for submitting the language files.
5
  Requires PHP: 5.6
6
  Requires at least: 5.0
7
  Tested up to: 5.9
8
+ Stable tag: 4.4.11
9
  License: GPLv3
10
 
11
  A comprehensive, user-friendly, all in one WordPress security and firewall plugin for your site.
185
 
186
  == Changelog ==
187
 
188
+ = 4.4.11 - 29/March/2022 =
189
+
190
+ * FEATURE: Reset all settings by clicking on the "Reset Settings" button on the Settings Page.
191
+ * FEATURE: Verify the Google reCaptcha Site key before rendering and disable it if the Google reCaptcha site key is invalid.
192
+ * FIX: PHP Fatal error: Cannot redeclare wp_install_maybe_enable_pretty_permalinks() in specific server.
193
+ * FIX: throwing database error for creating debug log table in specific MySQL server.
194
+ * FIX: Compatibility issue with WPML plugin for login and logout functionality.
195
+ * FIX: Update email sent in English instead of setting language.
196
+ * FIX: The Simple Math Captcha can't be validated when a third-party plugin clears transients more frequently.
197
+ * FIX: The login lockdown unlock request was not working in a few specific server environments.
198
+ * FIX: The warning headers already sent was displayed in a few specific server environments.
199
+ * FIX: Handle invalid tabs appropriately in setting pages.
200
+ * TWEAK: Add review notice.
201
+ * TWEAK: Improve functionality of fake google bot prevents to access the site.
202
+ * TWEAK: Remove IP address retrieval setting and detect IP address automatically.
203
+ * TWEAK: Verify Google reCaptcha site key before rendering the reCaptcha.
204
+ * TWEAK: Remove force logout checking from REST API Call.
205
+ * TWEAK: Made Admin Dashboard > WP Security > Settings tabs extensible.
206
+ * TWEAK: Add G2 review message in the admin footer.
207
+ * TWEAK: Format failed login date time according to WordPress general settings.
208
+ * TWEAK: Remove unused codes from AIOWPSecurity_Config.
209
+ * TWEAK: Add more specific instructions to change the Display name compared to the username in Admin Dashboard > WP Security > User Accounts > "Display Name" tab > "Modify Accounts With Identical Login Name & Display Name" section.
210
+ * TWEAK: Remove Admin Dashboard > WP Security > Site Info tab (now redundant because of WP's "Site Health" tool)
211
+ * TWEAK: The "Allow Login Lockout Request" checkbox is ticked by default.
212
+ * FIX: Fix login lockout issue with different timezone.
213
+
214
  = 4.4.10 - 21/Jan/2022 =
215
 
216
  * FEATURE: Auto-purge failed login records after 90 days.
220
  * FIX: Logout date-time shows 1000-10-10 10:00:00 for non-logged out user.
221
  * FIX: The notification for re-inserting the security rules in your .htaccess file appears after deactivating and activating the plugin to non-admin users.
222
  * TWEAK: Replace obsolete variable reference style
223
+ * TWEAK: Sanitize $_REQUEST parameters in redirect function
224
  * TWEAK: View debug logs from within the UI
225
+ * FIX: Compatibility issues with PHP 8.1.
226
+ * TWEAK: Advertise All in One WP Security Premium Plugin instead of Addons.
227
 
228
  = 4.4.9 =
229
  - Added Polish language translation file to the plugin. Thanks to Dariusz for submitting the language files.
templates/notices/horizontal-notice.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if (!defined('AIO_WP_SECURITY_PATH')) die('No direct access allowed'); ?>
2
+
3
+ <?php if (!empty($button_meta) && 'review' == $button_meta) : ?>
4
+
5
+ <div class="aiowps_ad_container updated">
6
+ <div class="aiowps_notice_container aiowps_review_notice_container">
7
+ <div class="aiowps_advert_content_left_extra">
8
+ <img src="<?php echo AIO_WP_SECURITY_URL.'/images/'.$image;?>" width="100" alt="<?php _e('notice image', 'all-in-one-wp-security-and-firewall');?>" />
9
+ </div>
10
+ <div class="aiowps_advert_content_right">
11
+ <p>
12
+ <?php echo $text; ?>
13
+ </p>
14
+
15
+ <?php if (!empty($button_link)) { ?>
16
+ <div class="aiowps_advert_button_container">
17
+ <a class="button button-primary" href="<?php esc_attr_e($button_link);?>" target="_blank" onclick="jQuery('.aiowps_ad_container').slideUp(); jQuery.post(ajaxurl, {action: 'aiowps_ajax', subaction: '<?php echo $dismiss_time;?>', nonce: '<?php echo wp_create_nonce('wp-security-ajax-nonce');?>', dismiss_forever: '1' });">
18
+ <?php _e('Ok, you deserve it', 'all-in-one-wp-security-and-firewall'); ?>
19
+ </a>
20
+ <div class="dashicons dashicons-calendar"></div>
21
+ <a class="aiowps_notice_link" href="#" onclick="jQuery('.aiowps_ad_container').slideUp(); jQuery.post(ajaxurl, {action: 'aiowps_ajax', subaction: '<?php echo $dismiss_time;?>', nonce: '<?php echo wp_create_nonce('wp-security-ajax-nonce');?>', dismiss_forever: '0' });">
22
+ <?php _e('Maybe later', 'all-in-one-wp-security-and-firewall'); ?>
23
+ </a>
24
+ <div class="dashicons dashicons-no-alt"></div>
25
+ <a class="aiowps_notice_link" href="#" onclick="jQuery('.aiowps_ad_container').slideUp(); jQuery.post(ajaxurl, {action: 'aiowps_ajax', subaction: '<?php echo $dismiss_time;?>', nonce: '<?php echo wp_create_nonce('wp-security-ajax-nonce');?>', dismiss_forever: '1' });">
26
+ <?php _e('Never', 'all-in-one-wp-security-and-firewall'); ?>
27
+ </a>
28
+ </div>
29
+ <?php } ?>
30
+ </div>
31
+ </div>
32
+ <div class="clear"></div>
33
+ </div>
34
+
35
+ <?php else : ?>
36
+
37
+ <div class="aiowps_ad_container updated">
38
+ <div class="aiowps_notice_container">
39
+ <div class="aiowps_advert_content_left">
40
+ <img src="<?php echo AIO_WP_SECURITY_URL.'/images/'.$image;?>" width="60" height="60" alt="<?php _e('notice image', 'all-in-one-wp-security-and-firewall');?>" />
41
+ </div>
42
+ <div class="aiowps_advert_content_right">
43
+ <h3 class="aiowps_advert_heading">
44
+ <?php
45
+ if (!empty($prefix)) echo $prefix.' ';
46
+ echo $title;
47
+ ?>
48
+ <div class="aiowps_advert_dismiss">
49
+ <?php if (!empty($dismiss_time)) { ?>
50
+ <a href="#" onclick="jQuery('.aiowps_ad_container').slideUp(); jQuery.post(ajaxurl, {action: 'aiowps_ajax', subaction: '<?php echo $dismiss_time;?>', nonce: '<?php echo wp_create_nonce('wp-security-ajax-nonce');?>' });"><?php _e('Dismiss', 'all-in-one-wp-security-and-firewall'); ?></a>
51
+ <?php } else { ?>
52
+ <a href="#" onclick="jQuery('.aiowps_ad_container').slideUp();"><?php _e('Dismiss', 'all-in-one-wp-security-and-firewall'); ?></a>
53
+ <?php } ?>
54
+ </div>
55
+ </h3>
56
+ <p>
57
+ <?php
58
+ echo $text;
59
+
60
+ if (isset($discount_code)) echo ' <b>' . $discount_code . '</b>';
61
+
62
+ if (!empty($button_link) && !empty($button_meta)) {
63
+ ?>
64
+ <a class="aiowps_notice_link" href="<?php esc_attr_e($button_link);?>"><?php
65
+ if ('updraftcentral' == $button_meta) {
66
+ _e('Get UpdraftCentral', 'all-in-one-wp-security-and-firewall');
67
+ } elseif ('updraftplus' == $button_meta) {
68
+ _e('Get UpdraftPlus', 'all-in-one-wp-security-and-firewall');
69
+ } elseif ('wp-optimize' == $button_meta) {
70
+ _e('Get WP-Optimize', 'all-in-one-wp-security-and-firewall');
71
+ } elseif ('all-in-one-wp-security-and-firewall' == $button_meta) {
72
+ _e('Find out more.', 'all-in-one-wp-security-and-firewall');
73
+ } elseif ('signup' == $button_meta) {
74
+ _e('Sign up', 'all-in-one-wp-security-and-firewall');
75
+ } elseif ('go_there' == $button_meta) {
76
+ _e('Go there', 'all-in-one-wp-security-and-firewall');
77
+ } else {
78
+ _e('Read more', 'all-in-one-wp-security-and-firewall');
79
+ }
80
+ ?></a>
81
+ <?php
82
+ }
83
+ ?>
84
+ </p>
85
+ </div>
86
+ </div>
87
+ <div class="clear"></div>
88
+ </div>
89
+
90
+ <?php
91
+
92
+ endif;
templates/notices/thanks-for-using-main-dash.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if (!defined('AIO_WP_SECURITY_PATH')) die('No direct access allowed'); ?>
2
+
3
+ <div id="aiowps-dashnotice" class="updated">
4
+ <div style="float:right;"><a href="#" onclick="jQuery('#aiowps-dashnotice').slideUp(); jQuery.post(ajaxurl, {action: 'aiowps_ajax', subaction: 'dismissdashnotice', nonce: '<?php echo wp_create_nonce('wp-security-ajax-nonce');?>' });"><?php printf(__('Dismiss (for %s months)', 'all-in-one-wp-security-and-firewall'), 12); ?></a></div>
5
+
6
+ <h3><?php _e('Thank you for installing All In One WP Security & Firewall!', 'all-in-one-wp-security-and-firewall');?></h3>
7
+
8
+ <a href="https://aiowpsecurity.com/"><img style="border: 0px; float: right; width: 150px; margin-right: 40px;" alt="All In One WP Security & Firewall" src="<?php echo AIO_WP_SECURITY_URL.'/images/notices/ud_smile.png'; ?>"></a>
9
+
10
+ <div id="aiowps-dashnotice_wrapper" style="max-width: 800px;">
11
+
12
+ <p>
13
+ <?php echo htmlspecialchars(__('Super-charge and secure your WordPress site even more with our other top plugins:', 'all-in-one-wp-security-and-firewall')); ?>
14
+ </p>
15
+
16
+ <p>
17
+ <?php printf(__('%s makes your site fast and efficient. It cleans the database, compresses images and caches pages for ultimate speed.', 'all-in-one-wp-security-and-firewall'), '<strong><a href="https://getwpo.com" target="_blank">WP-Optimize</a></strong>'); ?>
18
+ </p>
19
+
20
+ <p>
21
+ <?php printf(__('%s simplifies backups and restoration. It is the world’s highest ranking and most popular scheduled backup plugin, with over a million currently-active installs.', 'wp-optimize'), '<strong><a href="https://wordpress.org/plugins/updraftplus/" target="_blank">UpdraftPlus</a></strong>'); ?>
22
+ </p>
23
+
24
+ <p>
25
+ <?php printf(__('%s is a highly efficient way to manage, optimize, update and backup multiple websites from one place.', 'all-in-one-wp-security-and-firewall'), '<strong><a href="https://updraftplus.com/updraftcentral/" target="_blank">UpdraftCentral</a></strong>'); ?>
26
+ </p>
27
+
28
+ <p>
29
+ <?php printf(__('%s is a WordPress subscription extension for WooCommerce store owners.', 'all-in-one-wp-security-and-firewall'), '<strong><a href="https://subscribenplugin.com" target="_blank">Subscriben</a></strong>'); ?>
30
+ </p>
31
+
32
+ <p>
33
+ <?php echo '<strong>'.__('More quality plugins', 'all-in-one-wp-security-and-firewall').': </strong>'.'<a href="https://www.simbahosting.co.uk/s3/shop/" target="_blank">'.__('Premium WooCommerce plugins', 'all-in-one-wp-security-and-firewall').'</a> | <a href="https://wordpress.org/plugins/two-factor-authentication/" target="_blank">'.__('Free two-factor security plugin', 'all-in-one-wp-security-and-firewall');?></a>
34
+ </p>
35
+ </div>
36
+ <p>&nbsp;</p>
37
+ </div>
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit84b3a074ae80fe4e45e60e64d295d330::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit888bc1b214a0205c02dae97361d36f08::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit84b3a074ae80fe4e45e60e64d295d330
6
  {
7
  private static $loader;
8
 
@@ -22,15 +22,15 @@ class ComposerAutoloaderInit84b3a074ae80fe4e45e60e64d295d330
22
  return self::$loader;
23
  }
24
 
25
- spl_autoload_register(array('ComposerAutoloaderInit84b3a074ae80fe4e45e60e64d295d330', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
27
- spl_autoload_unregister(array('ComposerAutoloaderInit84b3a074ae80fe4e45e60e64d295d330', 'loadClassLoader'));
28
 
29
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30
  if ($useStaticLoader) {
31
  require __DIR__ . '/autoload_static.php';
32
 
33
- call_user_func(\Composer\Autoload\ComposerStaticInit84b3a074ae80fe4e45e60e64d295d330::getInitializer($loader));
34
  } else {
35
  $map = require __DIR__ . '/autoload_namespaces.php';
36
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit888bc1b214a0205c02dae97361d36f08
6
  {
7
  private static $loader;
8
 
22
  return self::$loader;
23
  }
24
 
25
+ spl_autoload_register(array('ComposerAutoloaderInit888bc1b214a0205c02dae97361d36f08', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
27
+ spl_autoload_unregister(array('ComposerAutoloaderInit888bc1b214a0205c02dae97361d36f08', 'loadClassLoader'));
28
 
29
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30
  if ($useStaticLoader) {
31
  require __DIR__ . '/autoload_static.php';
32
 
33
+ call_user_func(\Composer\Autoload\ComposerStaticInit888bc1b214a0205c02dae97361d36f08::getInitializer($loader));
34
  } else {
35
  $map = require __DIR__ . '/autoload_namespaces.php';
36
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit84b3a074ae80fe4e45e60e64d295d330
8
  {
9
  public static $classMap = array (
10
  'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
@@ -13,7 +13,7 @@ class ComposerStaticInit84b3a074ae80fe4e45e60e64d295d330
13
  public static function getInitializer(ClassLoader $loader)
14
  {
15
  return \Closure::bind(function () use ($loader) {
16
- $loader->classMap = ComposerStaticInit84b3a074ae80fe4e45e60e64d295d330::$classMap;
17
 
18
  }, null, ClassLoader::class);
19
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit888bc1b214a0205c02dae97361d36f08
8
  {
9
  public static $classMap = array (
10
  'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
13
  public static function getInitializer(ClassLoader $loader)
14
  {
15
  return \Closure::bind(function () use ($loader) {
16
+ $loader->classMap = ComposerStaticInit888bc1b214a0205c02dae97361d36f08::$classMap;
17
 
18
  }, null, ClassLoader::class);
19
  }
vendor/composer/installed.php CHANGED
@@ -5,7 +5,7 @@
5
  'type' => 'project',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
- 'reference' => 'b41fa2687f66c51968baf679d6ac9752365244cd',
9
  'name' => 'updraftplus/all-in-one-wp-security-and-firewall',
10
  'dev' => false,
11
  ),
@@ -16,7 +16,7 @@
16
  'type' => 'project',
17
  'install_path' => __DIR__ . '/../../',
18
  'aliases' => array(),
19
- 'reference' => 'b41fa2687f66c51968baf679d6ac9752365244cd',
20
  'dev_requirement' => false,
21
  ),
22
  ),
5
  'type' => 'project',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
+ 'reference' => '99272831f971fd7ef6475fcee60f0380643f0db7',
9
  'name' => 'updraftplus/all-in-one-wp-security-and-firewall',
10
  'dev' => false,
11
  ),
16
  'type' => 'project',
17
  'install_path' => __DIR__ . '/../../',
18
  'aliases' => array(),
19
+ 'reference' => '99272831f971fd7ef6475fcee60f0380643f0db7',
20
  'dev_requirement' => false,
21
  ),
22
  ),
wp-security-core.php CHANGED
@@ -1,277 +1,525 @@
1
  <?php
2
 
3
- if ( !defined('ABSPATH') ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
- if (!class_exists('AIO_WP_Security')){
8
-
9
- class AIO_WP_Security{
10
- var $version = '4.4.10';
11
- var $db_version = '1.9';
12
- var $plugin_url;
13
- var $plugin_path;
14
- var $configs;
15
- var $admin_init;
16
- var $debug_logger;
17
- var $cron_handler;
18
- var $user_login_obj;
19
- var $user_registration_obj;
20
- var $backup_obj;
21
- var $scan_obj;
22
- var $captcha_obj;
23
-
24
- function __construct()
25
- {
26
- $this->load_configs();
27
- $this->define_constants();
28
- $this->includes();
29
- $this->loader_operations();
30
-
31
- add_action('init', array($this, 'wp_security_plugin_init'), 0);
32
- add_action('wp_loaded',array($this, 'aiowps_wp_loaded_handler'));
33
- do_action('aiowpsecurity_loaded');
34
- }
35
-
36
- function plugin_url()
37
- {
38
- if ($this->plugin_url) return $this->plugin_url;
39
- return $this->plugin_url = plugins_url('', __FILE__);
40
- }
41
-
42
- function plugin_path()
43
- {
44
- if ($this->plugin_path) return $this->plugin_path;
45
- return $this->plugin_path = untrailingslashit( plugin_dir_path( __FILE__ ) );
46
- }
47
-
48
- function load_configs()
49
- {
50
- include_once('classes/wp-security-config.php');
51
- $this->configs = AIOWPSecurity_Config::get_instance();
52
- }
53
-
54
- function define_constants()
55
- {
56
- define('AIO_WP_SECURITY_VERSION', $this->version);
57
- define('AIO_WP_SECURITY_DB_VERSION', $this->db_version);
58
- define('AIOWPSEC_WP_HOME_URL', home_url());
59
- define('AIOWPSEC_WP_SITE_URL', site_url());
60
- define('AIOWPSEC_WP_URL', AIOWPSEC_WP_SITE_URL); // for backwards compatibility
61
- define('AIO_WP_SECURITY_URL', $this->plugin_url());
62
- define('AIO_WP_SECURITY_PATH', $this->plugin_path());
63
- define('AIO_WP_SECURITY_BACKUPS_DIR_NAME', 'aiowps_backups');
64
- define('AIO_WP_SECURITY_BACKUPS_PATH', AIO_WP_SECURITY_PATH.'/backups');
65
- define('AIO_WP_SECURITY_LIB_PATH', AIO_WP_SECURITY_PATH.'/lib');
66
- if (!defined('AIOWPSEC_MANAGEMENT_PERMISSION')){//This will allow the user to define custom capability for this constant in wp-config file
67
- define('AIOWPSEC_MANAGEMENT_PERMISSION', 'manage_options');
68
- }
69
- define('AIOWPSEC_MENU_SLUG_PREFIX', 'aiowpsec');
70
- define('AIOWPSEC_MAIN_MENU_SLUG', 'aiowpsec');
71
- define('AIOWPSEC_SETTINGS_MENU_SLUG', 'aiowpsec_settings');
72
- define('AIOWPSEC_USER_ACCOUNTS_MENU_SLUG', 'aiowpsec_useracc');
73
- define('AIOWPSEC_USER_LOGIN_MENU_SLUG', 'aiowpsec_userlogin');
74
- define('AIOWPSEC_USER_REGISTRATION_MENU_SLUG', 'aiowpsec_user_registration');
75
- define('AIOWPSEC_DB_SEC_MENU_SLUG', 'aiowpsec_database');
76
- define('AIOWPSEC_FILESYSTEM_MENU_SLUG', 'aiowpsec_filesystem');
77
- define('AIOWPSEC_BLACKLIST_MENU_SLUG', 'aiowpsec_blacklist');
78
- define('AIOWPSEC_FIREWALL_MENU_SLUG', 'aiowpsec_firewall');
79
- define('AIOWPSEC_MAINTENANCE_MENU_SLUG', 'aiowpsec_maintenance');
80
- define('AIOWPSEC_SPAM_MENU_SLUG', 'aiowpsec_spam');
81
- define('AIOWPSEC_FILESCAN_MENU_SLUG', 'aiowpsec_filescan');
82
- define('AIOWPSEC_BRUTE_FORCE_MENU_SLUG', 'aiowpsec_brute_force');
83
- define('AIOWPSEC_MISC_MENU_SLUG', 'aiowpsec_misc');
84
- if (!defined('AIOWPSEC_PURGE_FAILED_LOGIN_RECORDS_AFTER_DAYS')) define('AIOWPSEC_PURGE_FAILED_LOGIN_RECORDS_AFTER_DAYS', 90);
85
-
86
- global $wpdb;
87
- define('AIOWPSEC_TBL_LOGIN_LOCKDOWN', $wpdb->prefix . 'aiowps_login_lockdown');
88
- define('AIOWPSEC_TBL_FAILED_LOGINS', $wpdb->prefix . 'aiowps_failed_logins');
89
- define('AIOWPSEC_TBL_USER_LOGIN_ACTIVITY', $wpdb->prefix . 'aiowps_login_activity');
90
- define('AIOWPSEC_TBL_GLOBAL_META_DATA', $wpdb->prefix . 'aiowps_global_meta');
91
- define('AIOWPSEC_TBL_EVENTS', $wpdb->prefix . 'aiowps_events');
92
- define('AIOWPSEC_TBL_PERM_BLOCK', $wpdb->prefix . 'aiowps_permanent_block');
93
- define('AIOWPSEC_TBL_DEBUG_LOG', $wpdb->prefix . 'aiowps_debug_log');
94
-
95
- }
96
-
97
- function includes()
98
- {
99
- //Load common files for everywhere
100
- include_once('classes/wp-security-debug-logger.php');
101
- include_once('classes/wp-security-utility.php');
102
- include_once('classes/wp-security-utility-htaccess.php');
103
- include_once('classes/wp-security-utility-ip-address.php');
104
- include_once('classes/wp-security-utility-file.php');
105
- include_once('classes/wp-security-general-init-tasks.php');
106
- include_once('classes/wp-security-wp-loaded-tasks.php');
107
-
108
- include_once('classes/wp-security-user-login.php');
109
- include_once('classes/wp-security-user-registration.php');
110
- include_once('classes/wp-security-captcha.php');
111
- include_once('classes/wp-security-backup.php');
112
- include_once('classes/wp-security-file-scan.php');
113
- include_once('classes/wp-security-cronjob-handler.php');
114
- include_once('classes/grade-system/wp-security-feature-item.php');
115
- include_once('classes/grade-system/wp-security-feature-item-manager.php');
116
- include_once('classes/wp-security-wp-footer-content.php');
117
- include_once('classes/wp-security-blocking.php');
118
-
119
- if (is_admin()){ //Load admin side only files
120
- include_once('classes/wp-security-configure-settings.php');
121
- include_once('admin/wp-security-admin-init.php');
122
- include_once('admin/general/wp-security-list-table.php');
123
-
124
- }
125
- else{ //Load front end side only files
126
- }
127
- }
128
-
129
- function loader_operations()
130
- {
131
- add_action('plugins_loaded',array($this, 'plugins_loaded_handler'));//plugins loaded hook
132
-
133
- $debug_config = $this->configs->get_value('aiowps_enable_debug');
134
- $debug_enabled = empty($debug_config) ? false : true;
135
- $this->debug_logger = new AIOWPSecurity_Logger($debug_enabled);
136
-
137
- if(is_admin()){
138
- $this->admin_init = new AIOWPSecurity_Admin_Init();
139
- }
140
- }
141
-
142
- static function activate_handler($networkwide)
143
- {
144
- global $wpdb;
145
- //Only runs when the plugin activates
146
- include_once ('classes/wp-security-installer.php');
147
- AIOWPSecurity_Installer::run_installer($networkwide);
148
- AIOWPSecurity_Installer::set_cron_tasks_upon_activation($networkwide);
149
- }
150
-
151
- static function deactivate_handler($networkwide)
152
- {
153
- //Only runs with the pluign is deactivated
154
- include_once ('classes/wp-security-deactivation-tasks.php');
155
- AIOWPSecurity_Deactivation::run_deactivation_tasks($networkwide);
156
- do_action('aiowps_deactivation_complete');
157
- }
158
-
159
- function db_upgrade_handler()
160
- {
161
- if(is_admin()){//Check if DB needs to be upgraded
162
- if (get_option('aiowpsec_db_version') != AIO_WP_SECURITY_DB_VERSION) {
163
- include_once ('classes/wp-security-installer.php');
164
- AIOWPSecurity_Installer::run_installer();
165
- }
166
- }
167
- }
168
-
169
- function plugins_loaded_handler()
170
- {
171
- //Runs when plugins_loaded action gets fired
172
- if(is_admin()){
173
- //Do plugins_loaded operations for admin side
174
- $this->db_upgrade_handler();
175
- }
176
- $this->do_additional_plugins_loaded_tasks();
177
- }
178
-
179
- function wp_security_plugin_init()
180
- {
181
- //Set up localisation. First loaded overrides strings present in later loaded file
182
- $locale = apply_filters( 'plugin_locale', get_locale(), 'all-in-one-wp-security-and-firewall' );
183
- load_textdomain( 'all-in-one-wp-security-and-firewall', WP_LANG_DIR . "/all-in-one-wp-security-and-firewall-$locale.mo" );
184
- load_plugin_textdomain('all-in-one-wp-security-and-firewall', false, dirname(plugin_basename(__FILE__ )) . '/languages/');
185
-
186
- //Actions, filters, shortcodes goes here
187
- $this->user_login_obj = new AIOWPSecurity_User_Login();//Do the user login operation tasks
188
- $this->user_registration_obj = new AIOWPSecurity_User_Registration();//Do the user login operation tasks
189
- $this->captcha_obj = new AIOWPSecurity_Captcha();//Do the captcha tasks
190
- $this->backup_obj = new AIOWPSecurity_Backup();//Object to handle backup tasks
191
- $this->scan_obj = new AIOWPSecurity_Scan();//Object to handle scan tasks
192
- $this->cron_handler = new AIOWPSecurity_Cronjob_Handler();
193
-
194
- add_action('login_enqueue_scripts',array($this, 'aiowps_login_enqueue'));
195
- add_action('wp_footer',array($this, 'aiowps_footer_content'));
196
-
197
- add_action('wp_login', array('AIOWPSecurity_User_Login', 'wp_login_action_handler'), 10, 2);
198
- do_action('aiowps_force_logout_check');
199
- new AIOWPSecurity_General_Init_Tasks();
200
- }
201
-
202
- function aiowps_wp_loaded_handler()
203
- {
204
- new AIOWPSecurity_WP_Loaded_Tasks();
205
- }
206
-
207
- /**
208
- * Enqueues the Google recaptcha v2 api URL for the standard WP login page
209
- * @global type $aio_wp_security
210
- */
211
- function aiowps_login_enqueue()
212
- {
213
- global $aio_wp_security;
214
- if($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
215
- if($aio_wp_security->configs->get_value('aiowps_enable_login_captcha') == '1' || $aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') {
216
- wp_enqueue_script( 'google-recaptcha', 'https://www.google.com/recaptcha/api.js', false );
217
- // below is needed to provide some space for the google reCaptcha form (otherwise it appears partially hidden on RHS)
218
- wp_add_inline_script( 'google-recaptcha', 'document.addEventListener("DOMContentLoaded", ()=>{document.getElementById("login").style.width = "340px";});' );
219
- }
220
- }
221
- }
222
-
223
- function aiowps_footer_content()
224
- {
225
- new AIOWPSecurity_WP_Footer_Content();
226
- }
227
-
228
- function do_additional_plugins_loaded_tasks()
229
- {
230
- global $aio_wp_security;
231
- if(isset($_GET['aiowpsec_do_log_out']))
232
- {
233
- $nonce = isset($_GET['_wpnonce'])?$_GET['_wpnonce']:'';
234
- if ( !wp_verify_nonce( $nonce, 'aio_logout' ) ) {
235
- return;
236
- }
237
- wp_logout();
238
- if(isset($_GET['after_logout']))//Redirect to the after logout url directly
239
- {
240
- $after_logout_url = esc_url($_GET['after_logout']);
241
- AIOWPSecurity_Utility::redirect_to_url($after_logout_url);
242
- }
243
- $additional_data = strip_tags($_GET['al_additional_data']);
244
- if(isset($additional_data))
245
- {
246
- $login_url = '';
247
- //Check if rename login feature enabled
248
- if($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page')=='1'){
249
- if (get_option('permalink_structure')){
250
- $home_url = trailingslashit(home_url());
251
- }else{
252
- $home_url = trailingslashit(home_url()) . '?';
253
- }
254
- $login_url = $home_url.$aio_wp_security->configs->get_value('aiowps_login_page_slug');
255
- }else{
256
- $login_url = wp_login_url();
257
- }
258
-
259
- //Inspect the payload and do redirect to login page with a msg and redirect url
260
- $logout_payload = (AIOWPSecurity_Utility::is_multisite_install() ? get_site_transient('aiowps_logout_payload') : get_transient('aiowps_logout_payload'));
261
- if(!empty($logout_payload['redirect_to'])){
262
- $login_url = AIOWPSecurity_Utility::add_query_data_to_url($login_url,'redirect_to',$logout_payload['redirect_to']);
263
- }
264
- if(!empty($logout_payload['msg'])){
265
- $login_url .= '&'.$logout_payload['msg'];
266
- }
267
- if(!empty($login_url)){
268
- AIOWPSecurity_Utility::redirect_to_url($login_url);
269
- }
270
- }
271
- }
272
- }
273
-
274
- }//End of class
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
 
276
  }//End of class not exists check
277
 
1
  <?php
2
 
3
+ if (!defined('ABSPATH')) {
4
+ exit; // Exit if accessed directly
5
  }
6
 
7
+ if (!class_exists('AIO_WP_Security')) {
8
+
9
+ class AIO_WP_Security {
10
+
11
+ public $version = '4.4.11';
12
+
13
+ public $db_version = '1.9';
14
+
15
+ public $plugin_url;
16
+
17
+ public $plugin_path;
18
+
19
+ public $configs;
20
+
21
+ /**
22
+ * Notice class object.
23
+ *
24
+ * @var object instance of AIOWPSecurity_Notices
25
+ */
26
+ public $notices;
27
+
28
+ public $admin_init;
29
+
30
+ public $debug_logger;
31
+
32
+ public $cron_handler;
33
+
34
+ public $user_login_obj;
35
+
36
+ public $user_registration_obj;
37
+
38
+ public $backup_obj;
39
+
40
+ public $scan_obj;
41
+
42
+ public $captcha_obj;
43
+
44
+ /**
45
+ * Whether the page is admin dashboard page.
46
+ *
47
+ * @var boolean
48
+ */
49
+ public $is_admin_dashboard_page;
50
+
51
+ /**
52
+ * Whether the page is admin plugin page.
53
+ *
54
+ * @var boolean
55
+ */
56
+ public $is_plugin_admin_page;
57
+
58
+ /**
59
+ * Whether the page is admin AIOWPS page.
60
+ *
61
+ * @var boolean
62
+ */
63
+ public $is_aiowps_admin_page;
64
+
65
+ /**
66
+ * Whether the page is AIOWPS Login recaptcha page.
67
+ *
68
+ * @var boolean
69
+ */
70
+ public $is_aiowps_google_recaptcha_tab_page;
71
+
72
+ public function __construct() {
73
+ $this->load_configs();
74
+ $this->define_constants();
75
+ $this->includes();
76
+ $this->loader_operations();
77
+
78
+ add_action('init', array($this, 'wp_security_plugin_init'), 0);
79
+ add_action('wp_loaded', array($this, 'aiowps_wp_loaded_handler'));
80
+ do_action('aiowpsecurity_loaded');
81
+ }
82
+
83
+ public function plugin_url() {
84
+ if ($this->plugin_url) return $this->plugin_url;
85
+ return $this->plugin_url = plugins_url('', __FILE__);
86
+ }
87
+
88
+ public function plugin_path() {
89
+ if ($this->plugin_path) return $this->plugin_path;
90
+ return $this->plugin_path = untrailingslashit(plugin_dir_path(__FILE__));
91
+ }
92
+
93
+ public function load_configs() {
94
+ include_once('classes/wp-security-config.php');
95
+ $this->configs = AIOWPSecurity_Config::get_instance();
96
+ }
97
+
98
+ public function define_constants() {
99
+ define('AIO_WP_SECURITY_VERSION', $this->version);
100
+ define('AIO_WP_SECURITY_DB_VERSION', $this->db_version);
101
+ define('AIOWPSEC_WP_HOME_URL', home_url());
102
+ define('AIOWPSEC_WP_SITE_URL', site_url());
103
+ define('AIOWPSEC_WP_URL', AIOWPSEC_WP_SITE_URL); // for backwards compatibility
104
+ define('AIO_WP_SECURITY_URL', $this->plugin_url());
105
+ define('AIO_WP_SECURITY_PATH', $this->plugin_path());
106
+ define('AIO_WP_SECURITY_BACKUPS_DIR_NAME', 'aiowps_backups');
107
+ define('AIO_WP_SECURITY_BACKUPS_PATH', AIO_WP_SECURITY_PATH.'/backups');
108
+ define('AIO_WP_SECURITY_LIB_PATH', AIO_WP_SECURITY_PATH.'/lib');
109
+ if (!defined('AIOWPSEC_MANAGEMENT_PERMISSION')) {//This will allow the user to define custom capability for this constant in wp-config file
110
+ define('AIOWPSEC_MANAGEMENT_PERMISSION', 'manage_options');
111
+ }
112
+ define('AIOWPSEC_MENU_SLUG_PREFIX', 'aiowpsec');
113
+ define('AIOWPSEC_MAIN_MENU_SLUG', 'aiowpsec');
114
+ define('AIOWPSEC_SETTINGS_MENU_SLUG', 'aiowpsec_settings');
115
+ define('AIOWPSEC_USER_ACCOUNTS_MENU_SLUG', 'aiowpsec_useracc');
116
+ define('AIOWPSEC_USER_LOGIN_MENU_SLUG', 'aiowpsec_userlogin');
117
+ define('AIOWPSEC_USER_REGISTRATION_MENU_SLUG', 'aiowpsec_user_registration');
118
+ define('AIOWPSEC_DB_SEC_MENU_SLUG', 'aiowpsec_database');
119
+ define('AIOWPSEC_FILESYSTEM_MENU_SLUG', 'aiowpsec_filesystem');
120
+ define('AIOWPSEC_BLACKLIST_MENU_SLUG', 'aiowpsec_blacklist');
121
+ define('AIOWPSEC_FIREWALL_MENU_SLUG', 'aiowpsec_firewall');
122
+ define('AIOWPSEC_MAINTENANCE_MENU_SLUG', 'aiowpsec_maintenance');
123
+ define('AIOWPSEC_SPAM_MENU_SLUG', 'aiowpsec_spam');
124
+ define('AIOWPSEC_FILESCAN_MENU_SLUG', 'aiowpsec_filescan');
125
+ define('AIOWPSEC_BRUTE_FORCE_MENU_SLUG', 'aiowpsec_brute_force');
126
+ define('AIOWPSEC_MISC_MENU_SLUG', 'aiowpsec_misc');
127
+ if (!defined('AIOWPSEC_PURGE_FAILED_LOGIN_RECORDS_AFTER_DAYS')) define('AIOWPSEC_PURGE_FAILED_LOGIN_RECORDS_AFTER_DAYS', 90);
128
+
129
+ global $wpdb;
130
+ define('AIOWPSEC_TBL_LOGIN_LOCKDOWN', $wpdb->prefix . 'aiowps_login_lockdown');
131
+ define('AIOWPSEC_TBL_FAILED_LOGINS', $wpdb->prefix . 'aiowps_failed_logins');
132
+ define('AIOWPSEC_TBL_USER_LOGIN_ACTIVITY', $wpdb->prefix . 'aiowps_login_activity');
133
+ define('AIOWPSEC_TBL_GLOBAL_META_DATA', $wpdb->prefix . 'aiowps_global_meta');
134
+ define('AIOWPSEC_TBL_EVENTS', $wpdb->prefix . 'aiowps_events');
135
+ define('AIOWPSEC_TBL_PERM_BLOCK', $wpdb->prefix . 'aiowps_permanent_block');
136
+ define('AIOWPSEC_TBL_DEBUG_LOG', $wpdb->prefix . 'aiowps_debug_log');
137
+
138
+ }
139
+
140
+ public function includes() {
141
+ //Load common files for everywhere
142
+ include_once('classes/wp-security-debug-logger.php');
143
+ include_once('classes/wp-security-utility.php');
144
+ include_once('classes/wp-security-utility-htaccess.php');
145
+ include_once('classes/wp-security-utility-ip-address.php');
146
+ include_once('classes/wp-security-utility-file.php');
147
+ include_once('classes/wp-security-general-init-tasks.php');
148
+ include_once('classes/wp-security-wp-loaded-tasks.php');
149
+
150
+ include_once('classes/wp-security-user-login.php');
151
+ include_once('classes/wp-security-user-registration.php');
152
+ include_once('classes/wp-security-captcha.php');
153
+ include_once('classes/wp-security-backup.php');
154
+ include_once('classes/wp-security-file-scan.php');
155
+ include_once('classes/wp-security-cronjob-handler.php');
156
+ include_once('classes/grade-system/wp-security-feature-item.php');
157
+ include_once('classes/grade-system/wp-security-feature-item-manager.php');
158
+ include_once('classes/wp-security-wp-footer-content.php');
159
+ include_once('classes/wp-security-blocking.php');
160
+
161
+ if (is_admin()) { //Load admin side only files
162
+ include_once('classes/wp-security-configure-settings.php');
163
+ include_once('classes/wp-security-notices.php');
164
+ include_once('admin/wp-security-admin-init.php');
165
+ include_once('admin/general/wp-security-list-table.php');
166
+
167
+ } else {
168
+ //Load front end side only files
169
+ }
170
+ }
171
+
172
+ public function loader_operations() {
173
+ add_action('plugins_loaded', array($this, 'plugins_loaded_handler'));//plugins loaded hook
174
+ add_action('plugins_loaded', array($this, 'load_plugin_textdomain'));
175
+
176
+ $debug_config = $this->configs->get_value('aiowps_enable_debug');
177
+ $debug_enabled = empty($debug_config) ? false : true;
178
+ $this->debug_logger = new AIOWPSecurity_Logger($debug_enabled);
179
+
180
+ if (is_admin()) {
181
+ $this->admin_init = new AIOWPSecurity_Admin_Init();
182
+ $this->notices = new AIOWPSecurity_Notices();
183
+ }
184
+ }
185
+
186
+ public static function activate_handler($networkwide) {
187
+ global $wpdb;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Used for the include below
188
+ //Only runs when the plugin activates
189
+ include_once('classes/wp-security-installer.php');
190
+ AIOWPSecurity_Installer::run_installer($networkwide);
191
+ AIOWPSecurity_Installer::set_cron_tasks_upon_activation($networkwide);
192
+ }
193
+
194
+ /**
195
+ * Handles ajax. This is hooked into the inbuilt 'wp_ajax_(action)' action through 'wp_ajax_aiowps_ajax'.
196
+ *
197
+ * @return Void
198
+ */
199
+ public function aiowps_ajax_handler() {
200
+ $nonce = empty($_POST['nonce']) ? '' : $_POST['nonce'];
201
+
202
+ if (!wp_verify_nonce($nonce, 'wp-security-ajax-nonce') || empty($_POST['subaction'])) {
203
+ wp_send_json(array(
204
+ 'result' => false,
205
+ 'error_code' => 'security_check',
206
+ 'error_message' => __('The security check failed; try refreshing the page.', 'all-in-one-wp-security-and-firewall')
207
+ ));
208
+ }
209
+
210
+ $subaction = sanitize_text_field($_POST['subaction']);
211
+
212
+ if (!current_user_can(AIOWPSEC_MANAGEMENT_PERMISSION)) {
213
+ wp_send_json(array(
214
+ 'result' => false,
215
+ 'error_code' => 'security_check',
216
+ 'error_message' => __('You are not allowed to run this command.', 'all-in-one-wp-security-and-firewall')
217
+ ));
218
+ }
219
+
220
+
221
+ // Currently the settings are only available to network admins.
222
+ if (is_multisite() && !current_user_can('manage_network_options')) {
223
+ /**
224
+ * Filters the commands allowed to the subsite admins. Other commands are only available to network admin. Only used in a multisite context.
225
+ */
226
+ $allowed_commands = apply_filters('aiowps_multisite_allowed_commands', array());
227
+ if (!in_array($subaction, $allowed_commands)) wp_send_json(array(
228
+ 'result' => false,
229
+ 'error_code' => 'update_failed',
230
+ 'error_message' => __('Options can only be saved by network admin', 'all-in-one-wp-security-and-firewall')
231
+ ));
232
+ }
233
+
234
+ $time_now = $this->notices->get_time_now();
235
+ $results = array();
236
+
237
+ // Some commands that are available via AJAX only.
238
+ if (in_array($subaction, array('dismissdashnotice', 'dismiss_season'))) {
239
+ $this->configs->set_value($subaction, $time_now + (366 * 86400));
240
+ } elseif (in_array($subaction, array('dismiss_page_notice_until', 'dismiss_notice'))) {
241
+ $this->configs->set_value($subaction, $time_now + (84 * 86400));
242
+ } elseif ('dismiss_review_notice' == $subaction) {
243
+ if (empty($_POST['dismiss_forever'])) {
244
+ $this->configs->set_value($subaction, $time_now + (84 * 86400));
245
+ } else {
246
+ $this->configs->set_value($subaction, $time_now + (100 * 365.25 * 86400));
247
+ }
248
+ } else {
249
+ // Other commands, available for any remote method.
250
+ }
251
+
252
+ $this->configs->save_config();
253
+
254
+ $result = json_encode($results);
255
+
256
+ $json_last_error = json_last_error();
257
+
258
+ // if json_encode returned error then return error.
259
+ if ($json_last_error) {
260
+ $result = array(
261
+ 'result' => false,
262
+ 'error_code' => $json_last_error,
263
+ 'error_message' => 'json_encode error : '.$json_last_error,
264
+ 'error_data' => '',
265
+ );
266
+
267
+ $result = json_encode($result);
268
+ }
269
+
270
+ echo $result;
271
+
272
+ die;
273
+ }
274
+
275
+ /**
276
+ * Output, or return, the results of running a template (from the 'templates' directory, unless a filter over-rides it). Templates are run with $aio_wp_security and $wpdb set.
277
+ *
278
+ * @param String $path - path to the template
279
+ * @param Boolean $return_instead_of_echo - by default, the template is echo-ed; set this to instead return it
280
+ * @param Array $extract_these - variables to inject into the template's run context
281
+ *
282
+ * @return Void|String
283
+ */
284
+ public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
285
+ if ($return_instead_of_echo) ob_start();
286
+
287
+ if (!isset($template_file)) $template_file = AIO_WP_SECURITY_PATH.'/templates/'.$path;
288
+
289
+ $template_file = apply_filters('aio_wp_security_template', $template_file, $path);
290
+
291
+ do_action('aio_wp_security_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);
292
+
293
+ if (!file_exists($template_file)) {
294
+ error_log("All In One WP Security: template not found: $template_file");
295
+ echo __('Error:', 'all-in-one-wp-security-and-firewall').' '.__('template not found', 'all-in-one-wp-security-and-firewall')." ($template_file)";
296
+ } else {
297
+ extract($extract_these);
298
+ global $wpdb;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
299
+ $aio_wp_security = $this;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
300
+ include $template_file;
301
+ }
302
+
303
+ do_action('aio_wp_security_after_template', $path, $template_file, $return_instead_of_echo, $extract_these);
304
+
305
+ if ($return_instead_of_echo) return ob_get_clean();
306
+ }
307
+
308
+
309
+
310
+ public static function deactivate_handler($networkwide) {
311
+ //Only runs with the pluign is deactivated
312
+ include_once('classes/wp-security-deactivation-tasks.php');
313
+ AIOWPSecurity_Deactivation::run_deactivation_tasks($networkwide);
314
+ do_action('aiowps_deactivation_complete');
315
+ }
316
+
317
+ public function db_upgrade_handler() {
318
+ if (is_admin()) {//Check if DB needs to be upgraded
319
+ if (get_option('aiowpsec_db_version') != AIO_WP_SECURITY_DB_VERSION) {
320
+ include_once('classes/wp-security-installer.php');
321
+ AIOWPSecurity_Installer::run_installer();
322
+ }
323
+ }
324
+ }
325
+
326
+ public function plugins_loaded_handler() {
327
+ //Runs when plugins_loaded action gets fired
328
+ if (is_admin()) {
329
+ //Do plugins_loaded operations for admin side
330
+ $this->db_upgrade_handler();
331
+ }
332
+ $this->do_additional_plugins_loaded_tasks();
333
+ }
334
+
335
+ /**
336
+ * Load plugin text domain
337
+ *
338
+ * @return void
339
+ */
340
+ public function load_plugin_textdomain() {
341
+ load_plugin_textdomain('all-in-one-wp-security-and-firewall', false, dirname(plugin_basename(__FILE__)) . '/languages/');
342
+ }
343
+
344
+ /**
345
+ * Initializes the plugin. This is hooked into the inbuilt 'init' action.
346
+ *
347
+ * @return Void
348
+ */
349
+ public function wp_security_plugin_init() {
350
+ //Actions, filters, shortcodes goes here
351
+ $this->user_login_obj = new AIOWPSecurity_User_Login();//Do the user login operation tasks
352
+ $this->user_registration_obj = new AIOWPSecurity_User_Registration();//Do the user login operation tasks
353
+ $this->captcha_obj = new AIOWPSecurity_Captcha();//Do the captcha tasks
354
+ $this->backup_obj = new AIOWPSecurity_Backup();//Object to handle backup tasks
355
+ $this->scan_obj = new AIOWPSecurity_Scan();//Object to handle scan tasks
356
+ $this->cron_handler = new AIOWPSecurity_Cronjob_Handler();
357
+
358
+ add_action('login_enqueue_scripts', array($this, 'aiowps_login_enqueue'));
359
+ add_action('wp_footer', array($this, 'aiowps_footer_content'));
360
+
361
+ $this->configs->add_value('installed-at', time());
362
+
363
+ add_action('wp_ajax_aiowps_ajax', array($this, 'aiowps_ajax_handler'));
364
+
365
+ add_action('wp_login', array('AIOWPSecurity_User_Login', 'wp_login_action_handler'), 10, 2);
366
+ // For admin side force log out.
367
+ add_action('admin_init', array($this, 'do_action_force_logout_check'));
368
+ // For front side force log out.
369
+ add_action('template_redirect', array($this, 'do_action_force_logout_check'));
370
+ new AIOWPSecurity_General_Init_Tasks();
371
+ }
372
+
373
+ public function aiowps_wp_loaded_handler() {
374
+ new AIOWPSecurity_WP_Loaded_Tasks();
375
+ }
376
+
377
+ /**
378
+ * Enqueues the Google recaptcha v2 api URL for the standard WP login page
379
+ */
380
+ public function aiowps_login_enqueue() {
381
+ global $aio_wp_security;
382
+ if ($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) {
383
+ if ($aio_wp_security->configs->get_value('aiowps_enable_login_captcha') == '1' || $aio_wp_security->configs->get_value('aiowps_enable_registration_page_captcha') == '1') {
384
+ wp_enqueue_script('google-recaptcha', 'https://www.google.com/recaptcha/api.js', false, AIO_WP_SECURITY_VERSION);
385
+ // below is needed to provide some space for the google reCaptcha form (otherwise it appears partially hidden on RHS)
386
+ wp_add_inline_script('google-recaptcha', 'document.addEventListener("DOMContentLoaded", ()=>{document.getElementById("login").style.width = "340px";});');
387
+ }
388
+ }
389
+ }
390
+
391
+ public function aiowps_footer_content() {
392
+ new AIOWPSecurity_WP_Footer_Content();
393
+ }
394
+
395
+ public function do_additional_plugins_loaded_tasks() {
396
+ global $aio_wp_security;
397
+ if (isset($_GET['aiowpsec_do_log_out'])) {
398
+ $nonce = isset($_GET['_wpnonce']) ? $_GET['_wpnonce'] : '';
399
+ if (!wp_verify_nonce($nonce, 'aio_logout')) {
400
+ return;
401
+ }
402
+ wp_logout();
403
+ if (isset($_GET['after_logout'])) { //Redirect to the after logout url directly
404
+ $after_logout_url = esc_url($_GET['after_logout']);
405
+ AIOWPSecurity_Utility::redirect_to_url($after_logout_url);
406
+ }
407
+ $additional_data = strip_tags($_GET['al_additional_data']);
408
+ if (isset($additional_data)) {
409
+ $login_url = '';
410
+ //Check if rename login feature enabled
411
+ if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page')=='1') {
412
+ if (get_option('permalink_structure')) {
413
+ $home_url = trailingslashit(home_url());
414
+ } else {
415
+ $home_url = trailingslashit(home_url()) . '?';
416
+ }
417
+ $login_url = $home_url.$aio_wp_security->configs->get_value('aiowps_login_page_slug');
418
+ } else {
419
+ $login_url = wp_login_url();
420
+ }
421
+
422
+ //Inspect the payload and do redirect to login page with a msg and redirect url
423
+ $logout_payload = (AIOWPSecurity_Utility::is_multisite_install() ? get_site_transient('aiowps_logout_payload') : get_transient('aiowps_logout_payload'));
424
+ if (!empty($logout_payload['redirect_to'])) {
425
+ $login_url = AIOWPSecurity_Utility::add_query_data_to_url($login_url, 'redirect_to', $logout_payload['redirect_to']);
426
+ }
427
+ if (!empty($logout_payload['msg'])) {
428
+ $login_url .= '&'.$logout_payload['msg'];
429
+ }
430
+ if (!empty($login_url)) {
431
+ AIOWPSecurity_Utility::redirect_to_url($login_url);
432
+ }
433
+ }
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Verify google reCaptcha site key
439
+ *
440
+ * @param string $site_key recaptcha site key.
441
+ * @return boolean True if site key is verified, Otherwise false.
442
+ */
443
+ public function google_recaptcha_sitekey_verification($site_key) {
444
+ $result = true;
445
+ $arr_params = array( 'k' => $site_key, 'size' => 'checkbox' );
446
+ $recaptcha_url = esc_url(add_query_arg($arr_params, 'https://www.google.com/recaptcha/api2/anchor'));
447
+ $response = wp_remote_get($recaptcha_url);
448
+ $response_body = wp_remote_retrieve_body($response);
449
+ if (false !== strpos($response_body, 'Invalid site key')) $result = false;
450
+ return $result;
451
+ }
452
+
453
+ /**
454
+ * Check whether current admin page is Admin Dashboard page or not.
455
+ *
456
+ * @return boolean True if Admin Dashboard page, Otherwise false.
457
+ */
458
+ public function is_admin_dashboard_page() {
459
+ if (isset($this->is_admin_dashboard_page)) {
460
+ return $this->is_admin_dashboard_page;
461
+ }
462
+ global $pagenow;
463
+ $this->is_admin_dashboard_page = 'index.php' == $pagenow;
464
+ return $this->is_admin_dashboard_page;
465
+ }
466
+
467
+ /**
468
+ * Check whether current admin page is plugin page or not.
469
+ *
470
+ * @return boolean True if Admin Plugin page, Otherwise false.
471
+ */
472
+ public function is_plugin_admin_page() {
473
+ if (isset($this->is_plugin_admin_page)) {
474
+ return $this->is_plugin_admin_page;
475
+ }
476
+ global $pagenow;
477
+ $this->is_plugin_admin_page = 'plugins.php' == $pagenow;
478
+ return $this->is_plugin_admin_page;
479
+ }
480
+
481
+ /**
482
+ * Check whether current admin page is All In One WP Security admin page or not.
483
+ *
484
+ * @return boolean True if All In One WP Security admin page, Otherwise false.
485
+ */
486
+ public function is_aiowps_admin_page() {
487
+ if (isset($this->is_aiowps_admin_page)) {
488
+ return $this->is_aiowps_admin_page;
489
+ }
490
+ global $pagenow;
491
+ $this->is_aiowps_admin_page = ('admin.php' == $pagenow && isset($_GET['page']) && false !== strpos($_GET['page'], AIOWPSEC_MENU_SLUG_PREFIX));
492
+ return $this->is_aiowps_admin_page;
493
+ }
494
+
495
+ /**
496
+ * Check whether current admin page is Google recaptcha tab page or not.
497
+ *
498
+ * @return boolean True if Google recaptcha tab page, Otherwise false.
499
+ */
500
+ public function is_aiowps_google_recaptcha_tab_page() {
501
+ if (isset($this->is_aiowps_google_recaptcha_tab_page)) {
502
+ return $this->is_aiowps_google_recaptcha_tab_page;
503
+ }
504
+ global $pagenow;
505
+ $this->is_aiowps_google_recaptcha_tab_page = ('admin.php' == $pagenow
506
+ && isset($_GET['page'])
507
+ && 'aiowpsec_brute_force' == $_GET['page']
508
+ && isset($_GET['tab'])
509
+ && 'tab3' == $_GET['tab']
510
+ );
511
+ return $this->is_aiowps_google_recaptcha_tab_page;
512
+ }
513
+
514
+ /**
515
+ * Invokes all functions attached to action hook aiowps_force_logout_check
516
+ *
517
+ * @return void
518
+ */
519
+ public function do_action_force_logout_check() {
520
+ do_action('aiowps_force_logout_check');
521
+ }
522
+ }//End of class
523
 
524
  }//End of class not exists check
525
 
wp-security.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
 
2
  /*
3
  Plugin Name: All In One WP Security
4
- Version: 4.4.10
5
  Plugin URI: https://www.tipsandtricks-hq.com/wordpress-security-and-firewall-plugin
6
  Update URI: https://wordpress.org/plugins/all-in-one-wp-security-and-firewall/
7
  Author: Tips and Tricks HQ, Peter Petreski, Ruhul, Ivy
@@ -14,38 +15,38 @@ License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
14
  Requires at least: 5.0
15
  Requires PHP: 5.6
16
  */
 
17
 
18
- if(!defined('ABSPATH')){
19
- exit;//Exit if accessed directly
20
  }
21
 
22
- include_once('wp-security-core.php');
23
- register_activation_hook(__FILE__,array('AIO_WP_Security','activate_handler'));//activation hook
24
- register_deactivation_hook(__FILE__,array('AIO_WP_Security','deactivate_handler'));//deactivation hook
25
 
26
- function aiowps_show_plugin_settings_link($links, $file)
27
- {
28
- if ($file == plugin_basename(__FILE__)){
29
- $settings_link = '<a href="admin.php?page=aiowpsec_settings">Settings</a>';
30
- array_unshift($links, $settings_link);
31
- }
32
- return $links;
 
 
33
  }
34
- add_filter('plugin_action_links', 'aiowps_show_plugin_settings_link', 10, 2 );
35
 
36
- function aiowps_ms_handle_new_site($new_site){
37
- global $wpdb;
38
- $plugin_basename = plugin_basename( __FILE__ );
39
- if (is_plugin_active_for_network($plugin_basename))
40
- {
41
- if(!class_exists('AIOWPSecurity_Installer')){
42
- include_once('classes/wp-security-installer.php');
43
- }
44
- $old_blog = $wpdb->blogid;
45
- switch_to_blog($new_site->blog_id);
46
- AIOWPSecurity_Installer::create_db_tables();
47
- switch_to_blog($old_blog);
48
- }
49
 
50
 
51
  }
1
  <?php
2
+ // @codingStandardsIgnoreStart
3
  /*
4
  Plugin Name: All In One WP Security
5
+ Version: 4.4.11
6
  Plugin URI: https://www.tipsandtricks-hq.com/wordpress-security-and-firewall-plugin
7
  Update URI: https://wordpress.org/plugins/all-in-one-wp-security-and-firewall/
8
  Author: Tips and Tricks HQ, Peter Petreski, Ruhul, Ivy
15
  Requires at least: 5.0
16
  Requires PHP: 5.6
17
  */
18
+ // @codingStandardsIgnoreEnd
19
 
20
+ if (!defined('ABSPATH')) {
21
+ exit; // Exit if accessed directly
22
  }
23
 
24
+ require_once('wp-security-core.php');
 
 
25
 
26
+ register_activation_hook(__FILE__, array('AIO_WP_Security', 'activate_handler'));//activation hook
27
+ register_deactivation_hook(__FILE__, array('AIO_WP_Security', 'deactivate_handler'));//deactivation hook
28
+
29
+ function aiowps_show_plugin_settings_link($links, $file) {
30
+ if (plugin_basename(__FILE__) == $file) {
31
+ $settings_link = '<a href="admin.php?page=aiowpsec_settings">Settings</a>';
32
+ array_unshift($links, $settings_link);
33
+ }
34
+ return $links;
35
  }
36
+ add_filter('plugin_action_links', 'aiowps_show_plugin_settings_link', 10, 2);
37
 
38
+ function aiowps_ms_handle_new_site($new_site) {
39
+ global $wpdb;
40
+ $plugin_basename = plugin_basename(__FILE__);
41
+ if (is_plugin_active_for_network($plugin_basename)) {
42
+ if (!class_exists('AIOWPSecurity_Installer')) {
43
+ include_once('classes/wp-security-installer.php');
44
+ }
45
+ $old_blog = $wpdb->blogid;
46
+ switch_to_blog($new_site->blog_id);
47
+ AIOWPSecurity_Installer::create_db_tables();
48
+ switch_to_blog($old_blog);
49
+ }
 
50
 
51
 
52
  }