PluginProbe
Patchstack – WordPress & Plugins Security / 2.2.4
Patchstack – WordPress & Plugins Security v2.2.4
2.3.7 trunk 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.17 2.1.18 2.1.19 2.1.2 2.1.20 2.1.21 2.1.22 2.1.23 2.1.24 2.1.25 2.1.3 2.1.4 2.1.5 2.1.6 All 49 releases
← All changes | includes/admin/options.php +109 -83 2.1.212.2.4 View file →
@@ -18,9 +18,9 @@
18 18 * @return void
19 19 */
20 20 public function __construct( $core ) {
21 21 parent::__construct( $core );
22 - add_action( 'admin_init', array( $this, 'settings_init' ) );
22 + add_action( 'admin_init', [ $this, 'settings_init' ] );
23 23 }
24 24
25 25 /**
26 26 * All options and their default values.
@@ -26,9 +26,9 @@
26 26 * All options and their default values.
27 27 *
28 28 * @var array
29 29 */
30 - public $options = array(
30 + public $options = [
31 31 // Hardening options.
32 32 'patchstack_pluginedit' => 1,
33 33 'patchstack_userenum' => 1,
34 34 'patchstack_basicscanblock' => 1,
@@ -52,20 +52,23 @@
52 52 'patchstack_captcha_on_comments' => 0,
53 53 'patchstack_prevent_default_file_access' => 1,
54 54 'patchstack_register_email_blacklist' => '',
55 55 'patchstack_json_is_disabled' => 0,
56 - 'patchstack_auto_update' => array(),
56 + 'patchstack_auto_update' => [],
57 57 'patchstack_application_passwords_disabled' => 1,
58 58
59 59 // The firewall and whitelist rules.
60 60 'patchstack_firewall_rules' => '',
61 + 'patchstack_firewall_rules_v3' => '[]',
61 62 'patchstack_whitelist_rules' => '',
63 + 'patchstack_whitelist_rules_v3' => '[]',
62 64 'patchstack_whitelist_keys_rules' => '',
63 65
64 66 // Firewall options.
65 67 'patchstack_basic_firewall' => 1,
66 - 'patchstack_basic_firewall_roles' => array( 'administrator', 'editor', 'author', 'contributor' ),
68 + 'patchstack_basic_firewall_roles' => [ 'administrator', 'editor', 'author', 'contributor' ],
67 69 'patchstack_firewall_ip_header' => '',
70 + 'patchstack_ip_header_computed' => 0,
68 71 'patchstack_disable_htaccess' => 0,
69 72 'patchstack_known_blacklist' => 0,
70 73 'patchstack_block_debug_log_access' => 1,
71 74 'patchstack_block_fake_bots' => 1,
@@ -82,9 +85,9 @@
82 85 'patchstack_blocked_attacks' => 0,
83 86 'patchstack_ip_block_list' => '',
84 87 'patchstack_geo_block_enabled' => 0,
85 88 'patchstack_geo_block_inverse' => 0,
86 - 'patchstack_geo_block_countries' => array(),
89 + 'patchstack_geo_block_countries' => [],
87 90
88 91 // Cookie notice options.
89 92 'patchstack_enable_cookie_notice_message' => 0,
90 93 'patchstack_cookie_notice_message' => 'We use cookies for various purposes including analytics and personalized marketing. By continuing to use the service, you agree to our use of cookies.',
@@ -115,22 +118,32 @@
115 118 // General options.
116 119 'patchstack_blackhole_log' => '',
117 120 'patchstack_software_data_hash' => '',
118 121 'patchstack_firewall_htaccess_hash' => '',
122 + 'patchstack_license_expiry' => '',
119 123 'patchstack_clientid' => false,
120 124 'patchstack_secretkey' => false,
125 + 'patchstack_secretkey_nonce' => '',
121 126 'patchstack_license_free' => 0,
122 127 'patchstack_api_token' => '',
128 + 'patchstack_subscription_class' => '',
129 + 'patchstack_last_license_check' => 0,
123 130 'patchstack_whitelist' => '',
124 131 'patchstack_show_settings' => 0,
125 132 'patchstack_firewall_log_lastid' => 0,
126 133 'patchstack_eventlog_lastid' => 0,
134 + 'patchstack_ott_action' => '',
135 + 'patchstack_enc_nonce' => '',
136 + 'patchstack_managed' => false,
137 + 'patchstack_managed_text' => '',
138 + 'patchstack_latest_vulnerable' => [],
139 + 'patchstack_site_id' => 0,
127 140
128 141 // Admin page rename options.
129 142 'patchstack_mv_wp_login' => 0,
130 143 'patchstack_rename_wp_login' => 'swlogin',
131 - 'patchstack_rename_wp_login_whitelist' => array()
132 - );
144 + 'patchstack_rename_wp_login_whitelist' => []
145 + ];
133 146
134 147 /**
135 148 * Register all the options, if not set already.
136 149 *
@@ -150,16 +163,24 @@
150 163
151 164 // Multisite options
152 165 add_network_option( null, 'patchstack_multisite_installed', 0 );
153 166
167 + // Get the class value and convert.
168 + $class = get_option( 'patchstack_subscription_class', '' );
169 + $is_community = $class != '' && (int) $class === 0;
170 +
154 171 // All (sub)sections that show up.
155 172 add_settings_section( 'patchstack_settings_section_hardening', __( 'Security Configurations', 'patchstack' ), false, 'patchstack_hardening_settings' );
156 173 add_settings_section( 'patchstack_settings_section_hardening_captcha', __( '<hr style="height:1px;border:none;background-color: rgba(170, 189, 215, 0.1);"><br /> reCAPTCHA<br /><span style="font-size: 13px; color: #d0d0d0;">It should be noted that the reCAPTCHA feature only applies to WordPress its core features at this time. Not custom forms or of third party plugins.</span>', 'patchstack' ), false, 'patchstack_hardening_settings' );
157 174 add_settings_section( 'patchstack_settings_section_firewall', __( 'Firewall settings', 'patchstack' ), false, 'patchstack_firewall_settings' );
158 - if ( ! is_multisite() || ( isset( $_GET['page'] ) && $_GET['page'] == 'patchstack-multisite-settings' ) ) {
175 + if ( ( ! is_multisite() || ( isset( $_GET['page'] ) && $_GET['page'] == 'patchstack-multisite-settings' ) ) && ! $is_community ) {
159 176 add_settings_section( 'patchstack_settings_section_firewall_htaccess', __( '.htaccess Features', 'patchstack' ), false, 'patchstack_firewall_settings' );
160 177 }
161 - add_settings_section( 'patchstack_settings_section_firewall_geo', __( 'Country Blocking', 'patchstack' ), false, 'patchstack_firewall_settings' );
178 +
179 + if (! $is_community ) {
180 + add_settings_section( 'patchstack_settings_section_firewall_geo', __( 'Country Blocking', 'patchstack' ), false, 'patchstack_firewall_settings' );
181 + }
182 +
162 183 add_settings_section( 'patchstack_settings_section_firewall_wlbl', __( 'IP Whitelist &amp; Blacklist', 'patchstack' ), false, 'patchstack_firewall_settings' );
163 184 add_settings_section( 'patchstack_settings_section_cookienotice', __( 'Cookie Notice Settings', 'patchstack' ), false, 'patchstack_cookienotice_settings' );
164 185 add_settings_section( 'patchstack_settings_section_login', __( 'Login Protection', 'patchstack' ), false, 'patchstack_login_settings' );
165 186 add_settings_section( 'patchstack_settings_section_login_2fa', __( '<hr style="height:1px;border:none;background-color: rgba(170, 189, 215, 0.1);"><br /> Two Factor Authentication', 'patchstack' ), false, 'patchstack_login_settings' );
@@ -167,84 +188,89 @@
167 188 add_settings_section( 'patchstack_settings_section_login_whitelist', __( '<hr style="height:1px;border:none;background-color: rgba(170, 189, 215, 0.1);"><br /> Whitelisted IP Addresses', 'patchstack' ), false, 'patchstack_login_settings' );
168 189
169 190 // Hardening.
170 191 if ( ! is_multisite() || ( isset( $_GET['page'] ) && $_GET['page'] == 'patchstack-multisite-settings' ) ) {
171 - add_settings_field( 'patchstack_rm_readme', __( 'Remove readme.html', 'patchstack' ), array( $this, 'patchstack_rm_readme_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
172 - add_settings_field( 'patchstack_auto_update', __( 'Auto Update Software', 'patchstack' ), array( $this, 'patchstack_auto_update_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
192 + add_settings_field( 'patchstack_rm_readme', __( 'Remove readme.html', 'patchstack' ), [ $this, 'patchstack_rm_readme_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
193 + add_settings_field( 'patchstack_auto_update', __( 'Auto Update Software', 'patchstack' ), [ $this, 'patchstack_auto_update_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
173 194 }
174 - add_settings_field( 'patchstack_basicscanblock', __( 'Stop readme.txt Scans', 'patchstack' ), array( $this, 'patchstack_basicscanblock_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
175 - add_settings_field( 'patchstack_pluginedit', __( 'Disable theme editor', 'patchstack' ), array( $this, 'patchstack_pluginedit_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
176 - add_settings_field( 'patchstack_userenum', __( 'Disable user enumeration', 'patchstack' ), array( $this, 'patchstack_userenum_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
177 - add_settings_field( 'patchstack_hidewpversion', __( 'Hide WordPress version', 'patchstack' ), array( $this, 'patchstack_hidewpversion_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
178 - add_settings_field( 'patchstack_activity_log_is_enabled', __( 'Enable activity log', 'patchstack' ), array( $this, 'patchstack_activity_log_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
179 - add_settings_field( 'patchstack_activity_log_failed_logins', __( 'Log failed logins', 'patchstack' ), array( $this, 'patchstack_activity_log_failed_logins_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
180 - add_settings_field( 'patchstack_activity_log_failed_logins_db', __( 'Upload failed logins to Patchstack', 'patchstack' ), array( $this, 'patchstack_activity_log_failed_logins_db_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
181 - add_settings_field( 'patchstack_application_passwords_disabled', __( 'Block Application Passwords', 'patchstack' ), array( $this, 'patchstack_application_passwords_disabled_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
182 - add_settings_field( 'patchstack_xmlrpc_is_disabled', __( 'Restrict XML-RPC Access', 'patchstack' ), array( $this, 'patchstack_xmlrpc_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
183 - add_settings_field( 'patchstack_json_is_disabled', __( 'Restrict WP REST API Access', 'patchstack' ), array( $this, 'patchstack_json_is_disabled_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
184 - add_settings_field( 'patchstack_register_email_blacklist', __( 'Registration Email Blacklist', 'patchstack' ), array( $this, 'patchstack_register_email_blacklist_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
195 + add_settings_field( 'patchstack_basicscanblock', __( 'Stop readme.txt Scans', 'patchstack' ), [ $this, 'patchstack_basicscanblock_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
196 + add_settings_field( 'patchstack_pluginedit', __( 'Disable theme editor', 'patchstack' ), [ $this, 'patchstack_pluginedit_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
197 + add_settings_field( 'patchstack_userenum', __( 'Disable user enumeration', 'patchstack' ), [ $this, 'patchstack_userenum_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
198 + add_settings_field( 'patchstack_hidewpversion', __( 'Hide WordPress version', 'patchstack' ), [ $this, 'patchstack_hidewpversion_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
199 + add_settings_field( 'patchstack_activity_log_is_enabled', __( 'Enable activity log', 'patchstack' ), [ $this, 'patchstack_activity_log_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
200 + add_settings_field( 'patchstack_activity_log_failed_logins', __( 'Log failed logins', 'patchstack' ), [ $this, 'patchstack_activity_log_failed_logins_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
201 + add_settings_field( 'patchstack_activity_log_failed_logins_db', __( 'Upload failed logins to Patchstack', 'patchstack' ), [ $this, 'patchstack_activity_log_failed_logins_db_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
202 + add_settings_field( 'patchstack_application_passwords_disabled', __( 'Block Application Passwords', 'patchstack' ), [ $this, 'patchstack_application_passwords_disabled_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
203 + add_settings_field( 'patchstack_xmlrpc_is_disabled', __( 'Restrict XML-RPC Access', 'patchstack' ), [ $this, 'patchstack_xmlrpc_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
204 + add_settings_field( 'patchstack_json_is_disabled', __( 'Restrict WP REST API Access', 'patchstack' ), [ $this, 'patchstack_json_is_disabled_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
205 + add_settings_field( 'patchstack_register_email_blacklist', __( 'Registration Email Blacklist', 'patchstack' ), [ $this, 'patchstack_register_email_blacklist_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening' );
185 206
186 207 // reCAPTCHA.
187 - add_settings_field( 'patchstack_captcha_on_comments', __( 'Post comments form', 'patchstack' ), array( $this, 'patchstack_captcha_on_comments_callback' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
188 - add_settings_field( 'patchstack_captcha_login_form', __( 'Login form', 'patchstack' ), array( $this, 'patchstack_captcha_login_form_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
189 - add_settings_field( 'patchstack_captcha_registration_form', __( 'Registration form', 'patchstack' ), array( $this, 'patchstack_captcha_registration_form_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
190 - add_settings_field( 'patchstack_captcha_reset_pwd_form', __( 'Password reset form', 'patchstack' ), array( $this, 'patchstack_captcha_reset_pwd_form_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
191 - add_settings_field( 'patchstack_captcha_type', __( 'reCAPTCHA version (invisible/normal)' ), array( $this, 'patchstack_captcha_type_callback' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
192 - add_settings_field( 'patchstack_captcha_public_key', __( 'Site Key ', 'patchstack' ), array( $this, 'patchstack_captcha_public_key_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
193 - add_settings_field( 'patchstack_captcha_private_key', __( 'Secret Key', 'patchstack' ), array( $this, 'patchstack_captcha_private_key_input' ), 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
208 + add_settings_field( 'patchstack_captcha_on_comments', __( 'Post comments form', 'patchstack' ), [ $this, 'patchstack_captcha_on_comments_callback' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
209 + add_settings_field( 'patchstack_captcha_login_form', __( 'Login form', 'patchstack' ), [ $this, 'patchstack_captcha_login_form_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
210 + add_settings_field( 'patchstack_captcha_registration_form', __( 'Registration form', 'patchstack' ), [ $this, 'patchstack_captcha_registration_form_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
211 + add_settings_field( 'patchstack_captcha_reset_pwd_form', __( 'Password reset form', 'patchstack' ), [ $this, 'patchstack_captcha_reset_pwd_form_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
212 + add_settings_field( 'patchstack_captcha_type', __( 'reCAPTCHA version (invisible/normal)' ), [ $this, 'patchstack_captcha_type_callback' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
213 + add_settings_field( 'patchstack_captcha_public_key', __( 'Site Key ', 'patchstack' ), [ $this, 'patchstack_captcha_public_key_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
214 + add_settings_field( 'patchstack_captcha_private_key', __( 'Secret Key', 'patchstack' ), [ $this, 'patchstack_captcha_private_key_input' ], 'patchstack_hardening_settings', 'patchstack_settings_section_hardening_captcha' );
194 215
195 216 // Firewall.
196 - add_settings_field( 'patchstack_basic_firewall', __( 'Enable firewall', 'patchstack' ), array( $this, 'patchstack_basic_firewall_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall' );
197 - add_settings_field( 'patchstack_basic_firewall_roles', __( 'Firewall user role whitelist', 'patchstack' ), array( $this, 'patchstack_basic_firewall_roles_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall' );
198 - add_settings_field( 'patchstack_basic_firewall_geo_enabled', __( 'Country Blocking Enabled', 'patchstack' ), array( $this, 'patchstack_basic_firewall_geo_enabled_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_geo' );
199 - add_settings_field( 'patchstack_basic_firewall_geo_inverse', __( 'Inversed Check', 'patchstack' ), array( $this, 'patchstack_basic_firewall_geo_inverse_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_geo' );
200 - add_settings_field( 'patchstack_basic_firewall_geo_countries', __( 'Countries To Block', 'patchstack' ), array( $this, 'patchstack_basic_firewall_geo_countries_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_geo' );
201 - if ( ! is_multisite() || ( isset( $_GET['page'] ) && $_GET['page'] == 'patchstack-multisite-settings' ) ) {
202 - add_settings_field( 'patchstack_firewall_ip_header', __( 'IP Address Header Override', 'patchstack' ), array( $this, 'patchstack_firewall_ip_header_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall' );
203 - add_settings_field( 'patchstack_disable_htaccess', __( 'Disable .htaccess features', 'patchstack' ), array( $this, 'patchstack_disable_htaccess_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
204 - add_settings_field( 'patchstack_add_security_headers', __( 'Add security headers', 'patchstack' ), array( $this, 'patchstack_add_security_headers_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
205 - add_settings_field( 'patchstack_prevent_default_file_access', __( 'Prevent default WordPress file access', 'patchstack' ), array( $this, 'patchstack_prevent_default_file_access_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
206 - add_settings_field( 'patchstack_block_debug_log_access', __( 'Block access to debug.log file', 'patchstack' ), array( $this, 'patchstack_block_debug_log_access_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
207 - add_settings_field( 'patchstack_index_views', __( 'Disable index views', 'patchstack' ), array( $this, 'patchstack_index_views_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
208 - add_settings_field( 'patchstack_proxy_comment_posting', __( 'Forbid proxy comment posting', 'patchstack' ), array( $this, 'patchstack_proxy_comment_posting_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
209 - add_settings_field( 'patchstack_image_hotlinking', __( 'Prevent image hotlinking', 'patchstack' ), array( $this, 'patchstack_image_hotlinking_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
210 - add_settings_field( 'patchstack_firewall_custom_rules', __( 'Add custom .htaccess rules here', 'patchstack' ), array( $this, 'patchstack_firewall_custom_rules_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
211 - add_settings_field( 'patchstack_firewall_custom_rules_loc', __( 'Custom .htaccess rules location', 'patchstack' ), array( $this, 'patchstack_firewall_custom_rules_loc_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
217 + add_settings_field( 'patchstack_basic_firewall', __( 'Enable firewall', 'patchstack' ), [ $this, 'patchstack_basic_firewall_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall' );
218 + add_settings_field( 'patchstack_basic_firewall_roles', __( 'Firewall user role whitelist', 'patchstack' ), [ $this, 'patchstack_basic_firewall_roles_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall' );
219 +
220 + if ( ! $is_community ) {
221 + add_settings_field( 'patchstack_basic_firewall_geo_enabled', __( 'Country Blocking Enabled', 'patchstack' ), [ $this, 'patchstack_basic_firewall_geo_enabled_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_geo' );
222 + add_settings_field( 'patchstack_basic_firewall_geo_inverse', __( 'Inversed Check', 'patchstack' ), [ $this, 'patchstack_basic_firewall_geo_inverse_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_geo' );
223 + add_settings_field( 'patchstack_basic_firewall_geo_countries', __( 'Countries To Block', 'patchstack' ), [ $this, 'patchstack_basic_firewall_geo_countries_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_geo' );
212 224 }
213 - add_settings_field( 'patchstack_blackhole_log', __( 'Block IP List', 'patchstack' ), array( $this, 'patchstack_blackhole_log_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_wlbl' );
214 - add_settings_field( 'patchstack_whitelist', __( 'Whitelist', 'patchstack' ), array( $this, 'patchstack_whitelist_input' ), 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_wlbl' );
215 225
226 + add_settings_field( 'patchstack_firewall_ip_header', __( 'IP Address Header Override', 'patchstack' ), [ $this, 'patchstack_firewall_ip_header_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall' );
227 +
228 + if ( ( ! is_multisite() || ( isset( $_GET['page'] ) && $_GET['page'] == 'patchstack-multisite-settings' ) ) && ! $is_community ) {
229 + add_settings_field( 'patchstack_disable_htaccess', __( 'Disable .htaccess features', 'patchstack' ), [ $this, 'patchstack_disable_htaccess_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
230 + add_settings_field( 'patchstack_add_security_headers', __( 'Add security headers', 'patchstack' ), [ $this, 'patchstack_add_security_headers_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
231 + add_settings_field( 'patchstack_prevent_default_file_access', __( 'Prevent default WordPress file access', 'patchstack' ), [ $this, 'patchstack_prevent_default_file_access_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
232 + add_settings_field( 'patchstack_block_debug_log_access', __( 'Block access to debug.log file', 'patchstack' ), [ $this, 'patchstack_block_debug_log_access_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
233 + add_settings_field( 'patchstack_index_views', __( 'Disable index views', 'patchstack' ), [ $this, 'patchstack_index_views_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
234 + add_settings_field( 'patchstack_proxy_comment_posting', __( 'Forbid proxy comment posting', 'patchstack' ), [ $this, 'patchstack_proxy_comment_posting_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
235 + add_settings_field( 'patchstack_image_hotlinking', __( 'Prevent image hotlinking', 'patchstack' ), [ $this, 'patchstack_image_hotlinking_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
236 + add_settings_field( 'patchstack_firewall_custom_rules', __( 'Add custom .htaccess rules here', 'patchstack' ), [ $this, 'patchstack_firewall_custom_rules_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
237 + add_settings_field( 'patchstack_firewall_custom_rules_loc', __( 'Custom .htaccess rules location', 'patchstack' ), [ $this, 'patchstack_firewall_custom_rules_loc_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_htaccess' );
238 + }
239 + add_settings_field( 'patchstack_blackhole_log', __( 'Block IP List', 'patchstack' ), [ $this, 'patchstack_blackhole_log_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_wlbl' );
240 + add_settings_field( 'patchstack_whitelist', __( 'Whitelist', 'patchstack' ), [ $this, 'patchstack_whitelist_input' ], 'patchstack_firewall_settings', 'patchstack_settings_section_firewall_wlbl' );
241 +
216 242 // Login protection.
217 243 if ( ( ! is_multisite() || ( isset( $_GET['page'] ) && $_GET['page'] == 'patchstack-multisite-settings' ) ) && floatval( substr( phpversion(), 0, 5 ) ) > 5.5 ) {
218 - add_settings_field( 'patchstack_mv_wp_login', __( 'Block access to wp-login.php', 'patchstack' ), array( $this, 'patchstack_hidewplogin_input' ), 'patchstack_login_settings', 'patchstack_settings_section_login' );
219 - add_settings_field( 'patchstack_rename_wp_login', '', array( $this, 'patchstack_hidewplogin_rename_input' ), 'patchstack_login_settings', 'patchstack_settings_section_login' );
244 + add_settings_field( 'patchstack_mv_wp_login', __( 'Block access to wp-login.php', 'patchstack' ), [ $this, 'patchstack_hidewplogin_input' ], 'patchstack_login_settings', 'patchstack_settings_section_login' );
245 + add_settings_field( 'patchstack_rename_wp_login', '', [ $this, 'patchstack_hidewplogin_rename_input' ], 'patchstack_login_settings', 'patchstack_settings_section_login' );
220 246 }
221 - add_settings_field( 'patchstack_block_bruteforce_ips', __( 'Automatic brute-force IP ban', 'patchstack' ), array( $this, 'patchstack_block_bruteforce_ips_input' ), 'patchstack_login_settings', 'patchstack_settings_section_login' );
222 - add_settings_field( 'patchstack_login_time_block', __( 'Logon hours', 'patchstack' ), array( $this, 'patchstack_login_time_block_input' ), 'patchstack_login_settings', 'patchstack_settings_section_login' );
223 - add_settings_field( 'patchstack_login_2fa', __( 'Two Factor Authentication', 'patchstack' ), array( $this, 'patchstack_login_2fa_input' ), 'patchstack_login_settings', 'patchstack_settings_section_login_2fa' );
224 - add_settings_field( 'patchstack_login_blocked', __( 'Blocked', 'patchstack' ), array( $this, 'patchstack_login_blocked_input' ), 'patchstack_login_settings', 'patchstack_settings_section_login_blocked' );
225 - add_settings_field( 'patchstack_login_whitelist', __( 'Whitelist', 'patchstack' ), array( $this, 'patchstack_login_whitelist_input' ), 'patchstack_login_settings', 'patchstack_settings_section_login_whitelist' );
247 + add_settings_field( 'patchstack_block_bruteforce_ips', __( 'Automatic brute-force IP ban', 'patchstack' ), [ $this, 'patchstack_block_bruteforce_ips_input' ], 'patchstack_login_settings', 'patchstack_settings_section_login' );
248 + add_settings_field( 'patchstack_login_time_block', __( 'Logon hours', 'patchstack' ), [ $this, 'patchstack_login_time_block_input' ], 'patchstack_login_settings', 'patchstack_settings_section_login' );
249 + add_settings_field( 'patchstack_login_2fa', __( 'Two Factor Authentication', 'patchstack' ), [ $this, 'patchstack_login_2fa_input' ], 'patchstack_login_settings', 'patchstack_settings_section_login_2fa' );
250 + add_settings_field( 'patchstack_login_blocked', __( 'Blocked', 'patchstack' ), [ $this, 'patchstack_login_blocked_input' ], 'patchstack_login_settings', 'patchstack_settings_section_login_blocked' );
251 + add_settings_field( 'patchstack_login_whitelist', __( 'Whitelist', 'patchstack' ), [ $this, 'patchstack_login_whitelist_input' ], 'patchstack_login_settings', 'patchstack_settings_section_login_whitelist' );
226 252
227 253 // Cookie notice.
228 - add_settings_field( 'patchstack_enable_cookie_notice_message', 'Enable Cookie Notice', array( $this, 'patchstack_enable_cookie_notice_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
229 - add_settings_field( 'patchstack_cookie_notice_message', 'Enter message for displaying', array( $this, 'patchstack_cookie_notice_message_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
230 - add_settings_field( 'patchstack_cookie_notice_accept_text', 'Cookie acceptance button text', array( $this, 'patchstack_cookie_notice_accept_text_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
231 - add_settings_field( 'patchstack_cookie_notice_backgroundcolor', 'Background color (HEX)', array( $this, 'patchstack_cookie_notice_backgroundcolor_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
232 - add_settings_field( 'patchstack_cookie_notice_textcolor', 'Text color (HEX)', array( $this, 'patchstack_cookie_notice_textcolor_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
233 - add_settings_field( 'patchstack_cookie_notice_privacypolicy_enable', 'Enable Policy Link', array( $this, 'patchstack_cookie_notice_privacypolicy_enable_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
234 - add_settings_field( 'patchstack_cookie_notice_privacypolicy_text', 'Enter Policy Text', array( $this, 'patchstack_cookie_notice_privacypolicy_text_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
235 - add_settings_field( 'patchstack_cookie_notice_privacypolicy_link', 'Enter Policy Link', array( $this, 'patchstack_cookie_notice_privacypolicy_link_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
236 - add_settings_field( 'patchstack_cookie_notice_cookie_expiration', 'When to ask user permission again', array( $this, 'patchstack_cookie_notice_cookie_expiration_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
237 - add_settings_field( 'patchstack_cookie_notice_opacity', 'Background opacity (in percentage)', array( $this, 'patchstack_cookie_notice_opacity_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
238 - add_settings_field( 'patchstack_cookie_notice_credits', 'Display Patchstack credits', array( $this, 'patchstack_cookie_notice_credits_callback' ), 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
254 + add_settings_field( 'patchstack_enable_cookie_notice_message', 'Enable Cookie Notice', [ $this, 'patchstack_enable_cookie_notice_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
255 + add_settings_field( 'patchstack_cookie_notice_message', 'Enter message for displaying', [ $this, 'patchstack_cookie_notice_message_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
256 + add_settings_field( 'patchstack_cookie_notice_accept_text', 'Cookie acceptance button text', [ $this, 'patchstack_cookie_notice_accept_text_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
257 + add_settings_field( 'patchstack_cookie_notice_backgroundcolor', 'Background color (HEX)', [ $this, 'patchstack_cookie_notice_backgroundcolor_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
258 + add_settings_field( 'patchstack_cookie_notice_textcolor', 'Text color (HEX)', [ $this, 'patchstack_cookie_notice_textcolor_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
259 + add_settings_field( 'patchstack_cookie_notice_privacypolicy_enable', 'Enable Policy Link', [ $this, 'patchstack_cookie_notice_privacypolicy_enable_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
260 + add_settings_field( 'patchstack_cookie_notice_privacypolicy_text', 'Enter Policy Text', [ $this, 'patchstack_cookie_notice_privacypolicy_text_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
261 + add_settings_field( 'patchstack_cookie_notice_privacypolicy_link', 'Enter Policy Link', [ $this, 'patchstack_cookie_notice_privacypolicy_link_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
262 + add_settings_field( 'patchstack_cookie_notice_cookie_expiration', 'When to ask user permission again', [ $this, 'patchstack_cookie_notice_cookie_expiration_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
263 + add_settings_field( 'patchstack_cookie_notice_opacity', 'Background opacity (in percentage)', [ $this, 'patchstack_cookie_notice_opacity_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
264 + add_settings_field( 'patchstack_cookie_notice_credits', 'Display Patchstack credits', [ $this, 'patchstack_cookie_notice_credits_callback' ], 'patchstack_cookienotice_settings', 'patchstack_settings_section_cookienotice' );
239 265
240 266 // Register the group settings.
241 - $settings = array(
242 - 'hardening' => array( 'patchstack_auto_update', 'patchstack_json_is_disabled', 'patchstack_register_email_blacklist', 'patchstack_pluginedit', 'patchstack_basicscanblock', 'patchstack_userenum', 'patchstack_rm_readme', 'patchstack_hidewpcontent', 'patchstack_hidewpversion', 'patchstack_activity_log_is_enabled', 'patchstack_activity_log_failed_logins', 'patchstack_activity_log_failed_logins_db', 'patchstack_movewpconfig', 'patchstack_captcha_on_comments', 'patchstack_captcha_login_form', 'patchstack_captcha_registration_form', 'patchstack_captcha_reset_pwd_form', 'patchstack_captcha_public_key', 'patchstack_captcha_private_key', 'patchstack_captcha_type', 'patchstack_captcha_public_key_v3', 'patchstack_captcha_private_key_v3', 'patchstack_captcha_public_key_v3_new', 'patchstack_captcha_private_key_v3_new', 'patchstack_xmlrpc_is_disabled', 'patchstack_application_passwords_disabled' ),
243 - 'firewall' => array( 'patchstack_geo_block_enabled', 'patchstack_geo_block_inverse', 'patchstack_basic_firewall_geo_countries', 'patchstack_ip_block_list', 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_firewall_ip_header', 'patchstack_basic_firewall_roles', 'patchstack_disable_htaccess', 'patchstack_add_security_headers', 'patchstack_known_blacklist', 'patchstack_block_debug_log_access', 'patchstack_block_fake_bots', 'patchstack_index_views', 'patchstack_proxy_comment_posting', 'patchstack_bad_query_strings', 'patchstack_advanced_character_string_filter', 'patchstack_advanced_blacklist_firewall', 'patchstack_forbid_rfi', 'patchstack_image_hotlinking', 'patchstack_firewall_custom_rules', 'patchstack_firewall_custom_rules_loc', 'patchstack_blackhole_log', 'patchstack_whitelist', 'patchstack_autoblock_blocktime', 'patchstack_autoblock_attempts', 'patchstack_autoblock_minutes' ),
244 - 'cookienotice' => array( 'patchstack_enable_cookie_notice_message', 'patchstack_cookie_notice_message', 'patchstack_cookie_notice_backgroundcolor', 'patchstack_cookie_notice_textcolor', 'patchstack_cookie_notice_privacypolicy_enable', 'patchstack_cookie_notice_privacypolicy_text', 'patchstack_cookie_notice_privacypolicy_link', 'patchstack_cookie_notice_cookie_expiration', 'patchstack_cookie_notice_opacity', 'patchstack_cookie_notice_accept_text', 'patchstack_cookie_notice_credits' ),
245 - 'login' => array( 'patchstack_mv_wp_login', 'patchstack_rename_wp_login', 'patchstack_block_bruteforce_ips', 'patchstack_anti_bruteforce_attempts', 'patchstack_anti_bruteforce_minutes', 'patchstack_anti_bruteforce_blocktime', 'patchstack_login_time_block', 'patchstack_login_time_start', 'patchstack_login_time_end', 'patchstack_login_2fa', 'patchstack_login_blocked', 'patchstack_login_whitelist' ),
246 - );
267 + $settings = [
268 + 'hardening' => [ 'patchstack_auto_update', 'patchstack_json_is_disabled', 'patchstack_register_email_blacklist', 'patchstack_pluginedit', 'patchstack_basicscanblock', 'patchstack_userenum', 'patchstack_rm_readme', 'patchstack_hidewpcontent', 'patchstack_hidewpversion', 'patchstack_activity_log_is_enabled', 'patchstack_activity_log_failed_logins', 'patchstack_activity_log_failed_logins_db', 'patchstack_movewpconfig', 'patchstack_captcha_on_comments', 'patchstack_captcha_login_form', 'patchstack_captcha_registration_form', 'patchstack_captcha_reset_pwd_form', 'patchstack_captcha_public_key', 'patchstack_captcha_private_key', 'patchstack_captcha_type', 'patchstack_captcha_public_key_v3', 'patchstack_captcha_private_key_v3', 'patchstack_captcha_public_key_v3_new', 'patchstack_captcha_private_key_v3_new', 'patchstack_xmlrpc_is_disabled', 'patchstack_application_passwords_disabled' ],
269 + 'firewall' => [ 'patchstack_geo_block_enabled', 'patchstack_geo_block_inverse', 'patchstack_basic_firewall_geo_countries', 'patchstack_ip_block_list', 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_firewall_ip_header', 'patchstack_basic_firewall_roles', 'patchstack_disable_htaccess', 'patchstack_add_security_headers', 'patchstack_known_blacklist', 'patchstack_block_debug_log_access', 'patchstack_block_fake_bots', 'patchstack_index_views', 'patchstack_proxy_comment_posting', 'patchstack_bad_query_strings', 'patchstack_advanced_character_string_filter', 'patchstack_advanced_blacklist_firewall', 'patchstack_forbid_rfi', 'patchstack_image_hotlinking', 'patchstack_firewall_custom_rules', 'patchstack_firewall_custom_rules_loc', 'patchstack_blackhole_log', 'patchstack_whitelist', 'patchstack_autoblock_blocktime', 'patchstack_autoblock_attempts', 'patchstack_autoblock_minutes' ],
270 + 'cookienotice' => [ 'patchstack_enable_cookie_notice_message', 'patchstack_cookie_notice_message', 'patchstack_cookie_notice_backgroundcolor', 'patchstack_cookie_notice_textcolor', 'patchstack_cookie_notice_privacypolicy_enable', 'patchstack_cookie_notice_privacypolicy_text', 'patchstack_cookie_notice_privacypolicy_link', 'patchstack_cookie_notice_cookie_expiration', 'patchstack_cookie_notice_opacity', 'patchstack_cookie_notice_accept_text', 'patchstack_cookie_notice_credits' ],
271 + 'login' => [ 'patchstack_mv_wp_login', 'patchstack_rename_wp_login', 'patchstack_block_bruteforce_ips', 'patchstack_anti_bruteforce_attempts', 'patchstack_anti_bruteforce_minutes', 'patchstack_anti_bruteforce_blocktime', 'patchstack_login_time_block', 'patchstack_login_time_start', 'patchstack_login_time_end', 'patchstack_login_2fa', 'patchstack_login_blocked', 'patchstack_login_whitelist' ],
272 + ];
247 273
248 274 foreach ( $settings as $key => $setting ) {
249 275 foreach ( $setting as $option ) {
250 276 register_setting( 'patchstack_' . $key . '_settings_group', $option );
@@ -257,16 +283,16 @@
257 283 echo wp_kses( '<p style="color: red;">The auto update feature cannot be enabled because a plugin or code change forces automatic updates to be disabled. (AUTOMATIC_UPDATER_DISABLED)</p>', $this->allowed_html );
258 284 return;
259 285 }
260 286
261 - $selected = get_site_option( 'patchstack_auto_update', array() );
262 - $selected = ! is_array( $selected ) ? array() : $selected;
263 - $options = array(
287 + $selected = get_site_option( 'patchstack_auto_update', [] );
288 + $selected = ! is_array( $selected ) ? [] : $selected;
289 + $options = [
264 290 'core' => 'WordPress Core',
265 291 'plugin' => 'Plugins',
266 292 'theme' => 'Themes',
267 293 'vulnerable' => 'Vulnerable Plugins',
268 - );
294 + ];
269 295 $out = '';
270 296 foreach ( $options as $option => $text ) {
271 297 $out .= '<input type="checkbox" id="patchstack_auto_update_' . $option . '" name="patchstack_auto_update[]" value="' . $option . '" ' . checked( 1, in_array( $option, $selected ), false ) . '/>'
272 298 . '<label for="patchstack_auto_update_' . $option . '"><i>' . $text . '</i></label><br>';
@@ -287,9 +313,9 @@
287 313 }
288 314
289 315 public function patchstack_basic_firewall_geo_countries_input() {
290 316 $string1 = __( 'Specify which countries should be blocked.<br />Note that this will also block any type of (legitimate) bot traffic coming from this country. IP to country resolution might also not be 100% accurate.', 'patchstack' );
291 - $countries = $this->get_option( 'patchstack_geo_block_countries', array() );
317 + $countries = $this->get_option( 'patchstack_geo_block_countries', [] );
292 318 $country_list = '';
293 319 if ( ! empty( $countries ) ) {
294 320 foreach ( $countries as $country ) {
295 321 $country_list .= esc_attr( $country ) . ",";
@@ -452,10 +478,10 @@
452 478 echo wp_kses( '<input type="checkbox" name="patchstack_basic_firewall" id="patchstack_basic_firewall" value="1" ' . checked( 1, $this->get_option( 'patchstack_basic_firewall' ), false ) . '/><label for="patchstack_basic_firewall"><i>' . $string1 . '</i></label><br /><br /><i style="color:#d0d0d0">Block IP for <input style="width: 50px;" type="number" name="patchstack_autoblock_blocktime" value="' . esc_attr( $this->get_option( 'patchstack_autoblock_blocktime', 60 ) ) . '" id="patchstack_autoblock_blocktime"> minutes after <input style="width: 50px;" type="number" name="patchstack_autoblock_attempts" value="' . esc_attr( $this->get_option( 'patchstack_autoblock_attempts', 10 ) ) . '" id="patchstack_autoblock_attempts"> blocked requests over a period of <input style="width: 50px;" type="number" name="patchstack_autoblock_minutes" value="' . esc_attr( $this->get_option( 'patchstack_autoblock_minutes', 30 ) ) . '" id="patchstack_autoblock_minutes"> minutes</i>', $this->allowed_html);
453 479 }
454 480
455 481 public function patchstack_basic_firewall_roles_input() {
456 - $selected = $this->get_option( 'patchstack_basic_firewall_roles', array( 'administrator', 'editor', 'author' ) );
457 - $selected = ! is_array( $selected ) ? array() : $selected;
482 + $selected = $this->get_option( 'patchstack_basic_firewall_roles', [ 'administrator', 'editor', 'author' ] );
483 + $selected = ! is_array( $selected ) ? [] : $selected;
458 484 $roles = wp_roles();
459 485 $roles = $roles->get_names();
460 486 $text = '';
461 487 foreach ( $roles as $key => $val ) {
@@ -523,9 +549,9 @@
523 549
524 550 // Check if X failed login attempts were made.
525 551 global $wpdb;
526 552 $results = $wpdb->get_results(
527 - $wpdb->prepare( 'SELECT id, ip, date FROM ' . $wpdb->prefix . "patchstack_event_log WHERE action = 'failed login' AND date >= ('" . current_time( 'mysql' ) . "' - INTERVAL %d MINUTE) GROUP BY ip HAVING COUNT(ip) >= %d ORDER BY date DESC", array( $time, $this->get_option( 'patchstack_anti_bruteforce_attempts', 10 ) ) ),
553 + $wpdb->prepare( 'SELECT id, ip, date FROM ' . $wpdb->prefix . "patchstack_event_log WHERE action = 'failed login' AND date >= ('" . current_time( 'mysql' ) . "' - INTERVAL %d MINUTE) GROUP BY ip HAVING COUNT(ip) >= %d ORDER BY date DESC", [ $time, $this->get_option( 'patchstack_anti_bruteforce_attempts', 10 ) ] ),
528 554 OBJECT
529 555 );
530 556
531 557 // Render the rows.
@@ -535,19 +561,19 @@
535 561 } else {
536 562 $nonce = wp_create_nonce( 'patchstack-nonce-alter-ips' );
537 563 foreach ( $results as $result ) {
538 564 $rows .= '<tr><td>' . esc_html( $result->ip ) . '</td><td>' . ( isset( $result->log_date ) ? $result->log_date : $result->date ) . '</td><td><a href="' . esc_url( add_query_arg(
539 - array(
565 + [
540 566 'PatchstackNonce' => $nonce,
541 567 'action' => 'patchstack_unblock',
542 568 'id' => $result->id,
543 - )
569 + ]
544 570 ) ) . '">Unblock</a></td><td><a href="' . esc_url( add_query_arg(
545 - array(
571 + [
546 572 'PatchstackNonce' => $nonce,
547 573 'action' => 'patchstack_unblock_whitelist',
548 574 'id' => $result->id,
549 - )
575 + ]
550 576 ) ) . '">Unblock &amp; Whitelist</a></td></tr>';
551 577 }
552 578 }
553 579