| @@ -27,8 +27,9 @@ | ||
| 27 | 27 | |
| 28 | 28 | use Vigilante_Admin_Ajax; |
| 29 | 29 | use Vigilante_Admin_Analyzer_Ajax; |
| 30 | 30 | use Vigilante_Admin_Audit_Alerts_Ajax; |
| 31 | + use Vigilante_Admin_Recovery_Ajax; | |
| 31 | 32 | |
| 32 | 33 | /** |
| 33 | 34 | * Settings instance |
| 34 | 35 | * |
| @@ -182,8 +183,13 @@ | ||
| 182 | 183 | add_action( 'wp_ajax_vigilante_analyzer_history', array( $this, 'ajax_analyzer_history' ) ); |
| 183 | 184 | add_action( 'wp_ajax_vigilante_analyzer_dismiss_notice', array( $this, 'ajax_analyzer_dismiss_notice' ) ); |
| 184 | 185 | add_action( 'wp_ajax_vigilante_analyzer_save_settings', array( $this, 'ajax_analyzer_save_settings' ) ); |
| 185 | 186 | |
| 187 | + // Security Headers settings recovery (2.10.0) | |
| 188 | + add_action( 'wp_ajax_vigilante_headers_recovery_restore', array( $this, 'ajax_headers_recovery_restore' ) ); | |
| 189 | + add_action( 'wp_ajax_vigilante_headers_recovery_undo', array( $this, 'ajax_headers_recovery_undo' ) ); | |
| 190 | + add_action( 'wp_ajax_vigilante_headers_recovery_dismiss', array( $this, 'ajax_headers_recovery_dismiss' ) ); | |
| 191 | + | |
| 186 | 192 | // Shared "Send test email" handler — Notification settings, File Integrity, Audit Alerts (v2.8.0) |
| 187 | 193 | add_action( 'wp_ajax_vigilante_send_test_email', array( $this, 'ajax_send_test_email' ) ); |
| 188 | 194 | |
| 189 | 195 | // Run migrations on admin load |
| @@ -267,9 +273,29 @@ | ||
| 267 | 273 | if ( ! class_exists( 'Vigilante_File_Integrity' ) ) { |
| 268 | 274 | require_once VIGILANTE_INCLUDES_DIR . 'class-file-integrity.php'; |
| 269 | 275 | } |
| 270 | 276 | $fi = new Vigilante_File_Integrity( $this->settings, $this->database, $this->activity_log ); |
| 271 | - $fi->regenerate_all_baselines(); | |
| 277 | + | |
| 278 | + /* | |
| 279 | + * Only when there is nothing on record. This migration exists to | |
| 280 | + * create the baseline that did not exist, never to discard the one | |
| 281 | + * the owner approved: rebuilding it from the files takes whatever | |
| 282 | + * is on disk right now as approved, so a wp-config.php modified and | |
| 283 | + * awaiting review would be blessed in silence. | |
| 284 | + * | |
| 285 | + * And this is not theory. vigilante_db_version is written on two | |
| 286 | + * different scales into the same option: this file counts in plugin | |
| 287 | + * versions (2.11.0) and Vigilante_Database counts in schema | |
| 288 | + * versions, currently 1.4.0 (class-database.php:322 and :380). For | |
| 289 | + * version_compare, 1.4.0 is LOWER than 1.14.0, so any site whose | |
| 290 | + * option was last written by the schema runs this migration again. | |
| 291 | + * Measured on the Multisite install on 10 sep 2026: one of the three | |
| 292 | + * sites was sitting on 1.4.0. | |
| 293 | + */ | |
| 294 | + if ( ! $fi->get_critical_files_baseline() ) { | |
| 295 | + $fi->regenerate_all_baselines(); | |
| 296 | + } | |
| 297 | + | |
| 272 | 298 | update_option( 'vigilante_db_version', '1.14.0' ); |
| 273 | 299 | } |
| 274 | 300 | |
| 275 | 301 | // 2.0.0: Move hide_server_signature and remove_fingerprinting_headers |
| @@ -343,8 +369,103 @@ | ||
| 343 | 369 | } |
| 344 | 370 | |
| 345 | 371 | update_option( 'vigilante_db_version', '2.9.3' ); |
| 346 | 372 | } |
| 373 | + | |
| 374 | + /* | |
| 375 | + * 2.9.8: the mixed content handling changes shape. "Upgrade Insecure | |
| 376 | + * Requests" becomes a setting of its own, and Fix Mixed Content ships | |
| 377 | + * off, where before it shipped on and carried the directive with it. | |
| 378 | + * Both have to be written down for sites that are updating, so their | |
| 379 | + * pages keep loading exactly what they loaded yesterday. | |
| 380 | + * | |
| 381 | + * Read the RAW stored options, not get_section(): that one merges the | |
| 382 | + * defaults, so a site that never stored the key would be read with the | |
| 383 | + * new default and silently lose the behaviour it had. Absent means the | |
| 384 | + * site was running on the old default, which was on. | |
| 385 | + */ | |
| 386 | + if ( version_compare( $db_version, '2.9.8', '<' ) ) { | |
| 387 | + $raw = get_option( Vigilante_Settings::OPTION_NAME, array() ); | |
| 388 | + $stored = ( is_array( $raw ) && isset( $raw['security_headers'] ) && is_array( $raw['security_headers'] ) ) ? $raw['security_headers'] : array(); | |
| 389 | + $had_fix = array_key_exists( 'fix_mixed_content', $stored ) ? ! empty( $stored['fix_mixed_content'] ) : true; | |
| 390 | + | |
| 391 | + /* | |
| 392 | + * Merge, never replace. update_section() overwrites the whole | |
| 393 | + * section, so passing just these two keys wiped every other header | |
| 394 | + * setting the site had stored (HSTS, CSP, cross-origin policies, | |
| 395 | + * the HTTPS switches, Server Identity) and left the screen showing | |
| 396 | + * factory defaults while the .htaccess kept serving the old values. | |
| 397 | + */ | |
| 398 | + $this->settings->update_section( | |
| 399 | + 'security_headers', | |
| 400 | + array_merge( | |
| 401 | + $stored, | |
| 402 | + array( | |
| 403 | + 'fix_mixed_content' => $had_fix, | |
| 404 | + 'upgrade_insecure_requests' => $had_fix, | |
| 405 | + ) | |
| 406 | + ) | |
| 407 | + ); | |
| 408 | + | |
| 409 | + update_option( 'vigilante_db_version', '2.9.8' ); | |
| 410 | + } | |
| 411 | + | |
| 412 | + /* | |
| 413 | + * 2.9.9: drop the settings that no code has read for versions. | |
| 414 | + * | |
| 415 | + * They were carried in the defaults and therefore written into every | |
| 416 | + * saved configuration, they show up in an exported configuration, and | |
| 417 | + * anyone reading them assumes a feature exists behind them. Removing | |
| 418 | + * them from the defaults is not enough: the stored copies survive, so | |
| 419 | + * they are swept here too. Nothing reads them, so nothing changes. | |
| 420 | + */ | |
| 421 | + if ( version_compare( $db_version, '2.9.9', '<' ) ) { | |
| 422 | + $raw = get_option( Vigilante_Settings::OPTION_NAME, array() ); | |
| 423 | + $dead = array( | |
| 424 | + 'firewall' => array( 'country_blocking', 'protected_file_extensions' ), | |
| 425 | + 'file_integrity' => array( 'suspicious_patterns' ), | |
| 426 | + 'backup' => array( 'auto_backup', 'backup_before_update' ), | |
| 427 | + 'advanced' => array( 'block_author_archives', 'disable_embeds', 'uninstall_cleanup', 'debug_mode' ), | |
| 428 | + ); | |
| 429 | + | |
| 430 | + $changed = false; | |
| 431 | + foreach ( $dead as $section => $keys ) { | |
| 432 | + if ( ! isset( $raw[ $section ] ) || ! is_array( $raw[ $section ] ) ) { | |
| 433 | + continue; | |
| 434 | + } | |
| 435 | + foreach ( $keys as $key ) { | |
| 436 | + if ( array_key_exists( $key, $raw[ $section ] ) ) { | |
| 437 | + unset( $raw[ $section ][ $key ] ); | |
| 438 | + $changed = true; | |
| 439 | + } | |
| 440 | + } | |
| 441 | + } | |
| 442 | + | |
| 443 | + if ( $changed ) { | |
| 444 | + update_option( Vigilante_Settings::OPTION_NAME, $raw ); | |
| 445 | + } | |
| 446 | + | |
| 447 | + update_option( 'vigilante_db_version', '2.9.9' ); | |
| 448 | + } | |
| 449 | + | |
| 450 | + /* | |
| 451 | + * 2.11.0: security release (audit of 28 Aug 2026). Runs here and not | |
| 452 | + * from Vigilante_Database::needs_update(): this option is shared with | |
| 453 | + * that class, and on any updated site it already holds a plugin version | |
| 454 | + * (2.9.9 or later), so a bump of DB_VERSION would never fire. | |
| 455 | + * create_tables() widens the email code column through dbDelta (varchar | |
| 456 | + * 6 to 64, the code is stored hashed since 2.11.0) and purge_for_2_11_0() | |
| 457 | + * does what dbDelta cannot: it empties the trusted devices, which were | |
| 458 | + * identified by User-Agent until now (S1), and the pending email codes, | |
| 459 | + * stored in clear until now (S11). Every remembered device asks for the | |
| 460 | + * second factor once more after this update, and the changelog says so. | |
| 461 | + */ | |
| 462 | + if ( version_compare( $db_version, '2.11.0', '<' ) ) { | |
| 463 | + $this->database->create_tables(); | |
| 464 | + $this->database->purge_for_2_11_0(); | |
| 465 | + | |
| 466 | + update_option( 'vigilante_db_version', '2.11.0' ); | |
| 467 | + } | |
| 347 | 468 | } |
| 348 | 469 | |
| 349 | 470 | /** |
| 350 | 471 | * Migration: Remove orphaned email fields from saved options |
| @@ -1104,96 +1225,215 @@ | ||
| 1104 | 1225 | ); |
| 1105 | 1226 | } |
| 1106 | 1227 | |
| 1107 | 1228 | /** |
| 1108 | - * Build the settings search index | |
| 1229 | + * Index behind the settings search box. | |
| 1109 | 1230 | * |
| 1110 | - * Flat list of searchable entries consumed by the client-side search. | |
| 1111 | - * Each entry contains tab + section metadata, a translated label and an | |
| 1112 | - * English fallback so locales with partial translation still match. | |
| 1231 | + * Each entry points at one settings row. The search matches on the label, | |
| 1232 | + * on its English original and on 'keywords', which are extra terms someone | |
| 1233 | + * might type instead of the label itself. | |
| 1113 | 1234 | * |
| 1235 | + * Those keywords are wrapped in _x() with the context "settings search | |
| 1236 | + * keywords" so every locale can supply its own: the source strings are in | |
| 1237 | + * English, and a Spanish user typing "contrasena" or a German one typing | |
| 1238 | + * "Kennwort" only reaches the password settings if that locale translated | |
| 1239 | + * them. Translators can add, drop or replace terms freely, one per space; | |
| 1240 | + * they are never displayed, only matched against what the user types. | |
| 1241 | + * | |
| 1242 | + * The list is maintained by hand, so a new settings row needs an entry here | |
| 1243 | + * or it cannot be found. It had drifted to 68 of 131 rows before 2.9.7. | |
| 1244 | + * | |
| 1114 | 1245 | * @return array |
| 1115 | 1246 | */ |
| 1116 | 1247 | private function get_search_index() { |
| 1117 | 1248 | return array( |
| 1118 | 1249 | // Firewall - Main |
| 1119 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Block bad bots', 'vigilante' ), 'label_en' => 'Block bad bots', 'keywords' => 'bots robots malos bloquear bad block crawlers arañas scrapers' ), | |
| 1120 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Block malicious requests', 'vigilante' ), 'label_en' => 'Block malicious requests', 'keywords' => 'malicioso maliciosas peticiones ataques sqli xss rfi lfi ataque exploit injection inyección' ), | |
| 1121 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Rate limiting', 'vigilante' ), 'label_en' => 'Rate limiting', 'keywords' => 'limitar tasa velocidad throttle peticiones minuto abuso flood' ), | |
| 1122 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Brute force protection', 'vigilante' ), 'label_en' => 'Brute force protection', 'keywords' => 'fuerza bruta brute force contraseñas ataque login diccionario' ), | |
| 1123 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'IP Whitelist', 'vigilante' ), 'label_en' => 'IP Whitelist', 'keywords' => 'lista blanca permitida permitidas whitelist allowlist ip direcciones permitir' ), | |
| 1124 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'IP Blacklist', 'vigilante' ), 'label_en' => 'IP Blacklist', 'keywords' => 'lista negra bloqueada bloqueadas blacklist blocklist denylist ip direcciones bloquear' ), | |
| 1125 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'User-Agent Whitelist', 'vigilante' ), 'label_en' => 'User-Agent Whitelist', 'keywords' => 'ua user agent agente usuario navegador lista blanca permitida whitelist allowlist' ), | |
| 1126 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'User-Agent Blacklist', 'vigilante' ), 'label_en' => 'User-Agent Blacklist', 'keywords' => 'ua user agent agente usuario navegador lista negra bloqueada blacklist blocklist denylist' ), | |
| 1250 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Block bad bots', 'vigilante' ), 'label_en' => 'Block bad bots', 'keywords' => _x( 'block bad bots blocking blocked deny malicious harmful bot crawler crawlers spider scraper robots', 'settings search keywords', 'vigilante' ) ), | |
| 1251 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Block malicious requests', 'vigilante' ), 'label_en' => 'Block malicious requests', 'keywords' => _x( 'block malicious requests blocking blocked deny attack attacks exploit injection sqli xss rfi lfi request traffic', 'settings search keywords', 'vigilante' ) ), | |
| 1252 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Rate limiting', 'vigilante' ), 'label_en' => 'Rate limiting', 'keywords' => _x( 'rate limiting throttle flood burst limit limits', 'settings search keywords', 'vigilante' ) ), | |
| 1253 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Brute force protection', 'vigilante' ), 'label_en' => 'Brute force protection', 'keywords' => _x( 'brute force protection bruteforce login', 'settings search keywords', 'vigilante' ) ), | |
| 1254 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'IP Whitelist', 'vigilante' ), 'label_en' => 'IP Whitelist', 'keywords' => _x( 'ip whitelist ips address addresses cidr ipv4 ipv6 allowlist allowed trusted', 'settings search keywords', 'vigilante' ) ), | |
| 1255 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'IP Blacklist', 'vigilante' ), 'label_en' => 'IP Blacklist', 'keywords' => _x( 'ip blacklist ips address addresses cidr ipv4 ipv6 blocklist denylist banned', 'settings search keywords', 'vigilante' ) ), | |
| 1256 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'User-Agent Whitelist', 'vigilante' ), 'label_en' => 'User-Agent Whitelist', 'keywords' => _x( 'user-agent whitelist ua useragent browser allowlist allowed trusted user', 'settings search keywords', 'vigilante' ) ), | |
| 1257 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'User-Agent Blacklist', 'vigilante' ), 'label_en' => 'User-Agent Blacklist', 'keywords' => _x( 'user-agent blacklist ua useragent browser blocklist denylist banned user', 'settings search keywords', 'vigilante' ) ), | |
| 1127 | 1258 | // Firewall - Server Protection |
| 1128 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'Directory Browsing', 'vigilante' ), 'label_en' => 'Directory Browsing', 'keywords' => 'directorio navegación listado listing indexing indexado carpetas' ), | |
| 1129 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'Protect wp-config.php', 'vigilante' ), 'label_en' => 'Protect wp-config.php', 'keywords' => 'proteger wp-config configuración config archivo' ), | |
| 1130 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'field-protect-wp-cron', 'label' => __( 'Protect wp-cron.php', 'vigilante' ), 'label_en' => 'Protect wp-cron.php', 'keywords' => 'proteger wp-cron cron tareas programadas scheduled tasks bloquear block dos abuse spam htaccess' ), | |
| 1131 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'Protect wp-includes', 'vigilante' ), 'label_en' => 'Protect wp-includes', 'keywords' => 'proteger wp-includes includes core núcleo archivos' ), | |
| 1132 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'PHP in Uploads', 'vigilante' ), 'label_en' => 'PHP in Uploads', 'keywords' => 'php uploads subidas archivos bloquear ejecución' ), | |
| 1133 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'Sensitive Files', 'vigilante' ), 'label_en' => 'Sensitive Files', 'keywords' => 'sensibles sensitive files archivos readme license htaccess log' ), | |
| 1134 | - array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'Limit HTTP Methods', 'vigilante' ), 'label_en' => 'Limit HTTP Methods', 'keywords' => 'métodos http limit limitar trace options put delete verbs verbos' ), | |
| 1259 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'Directory Browsing', 'vigilante' ), 'label_en' => 'Directory Browsing', 'keywords' => _x( 'directory browsing folder folders listing indexing index', 'settings search keywords', 'vigilante' ) ), | |
| 1260 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'Protect wp-config.php', 'vigilante' ), 'label_en' => 'Protect wp-config.php', 'keywords' => _x( 'protect wp-config php protection secure lock', 'settings search keywords', 'vigilante' ) ), | |
| 1261 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'field-protect-wp-cron', 'label' => __( 'Protect wp-cron.php', 'vigilante' ), 'label_en' => 'Protect wp-cron.php', 'keywords' => _x( 'protect wp-cron php protection secure lock cron scheduled tasks block spam', 'settings search keywords', 'vigilante' ) ), | |
| 1262 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'Protect wp-includes', 'vigilante' ), 'label_en' => 'Protect wp-includes', 'keywords' => _x( 'protect wp-includes protection secure lock', 'settings search keywords', 'vigilante' ) ), | |
| 1263 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'PHP in Uploads', 'vigilante' ), 'label_en' => 'PHP in Uploads', 'keywords' => _x( 'php in uploads media upload', 'settings search keywords', 'vigilante' ) ), | |
| 1264 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'Sensitive Files', 'vigilante' ), 'label_en' => 'Sensitive Files', 'keywords' => _x( 'sensitive files private secret file log', 'settings search keywords', 'vigilante' ) ), | |
| 1265 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Server Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-server', 'label' => __( 'Limit HTTP Methods', 'vigilante' ), 'label_en' => 'Limit HTTP Methods', 'keywords' => _x( 'limit http methods', 'settings search keywords', 'vigilante' ) ), | |
| 1135 | 1266 | // Security Headers |
| 1136 | - array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'X-Frame-Options', 'vigilante' ), 'label_en' => 'X-Frame-Options', 'keywords' => 'xframe clickjacking iframe cabeceras headers' ), | |
| 1137 | - array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'X-Content-Type-Options', 'vigilante' ), 'label_en' => 'X-Content-Type-Options', 'keywords' => 'mime sniffing nosniff content type cabeceras headers' ), | |
| 1138 | - array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Referrer-Policy', 'vigilante' ), 'label_en' => 'Referrer-Policy', 'keywords' => 'referer referrer política privacidad cabeceras headers' ), | |
| 1139 | - array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'HSTS', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'HSTS', 'vigilante' ), 'label_en' => 'HSTS', 'keywords' => 'strict transport security ssl tls https forzar cabeceras headers' ), | |
| 1140 | - array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Content Security Policy', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Content Security Policy', 'vigilante' ), 'label_en' => 'Content Security Policy', 'keywords' => 'csp política seguridad contenido xss scripts inline eval cabeceras headers' ), | |
| 1141 | - array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Server Identity', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Server Signature', 'vigilante' ), 'label_en' => 'Server Signature', 'keywords' => 'firma servidor server signature identidad apache nginx ocultar hide fingerprint protección servidor' ), | |
| 1142 | - array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Server Identity', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Remove Fingerprinting Headers', 'vigilante' ), 'label_en' => 'Remove Fingerprinting Headers', 'keywords' => 'fingerprint huella identificación cabeceras headers x-powered-by server ocultar eliminar protección servidor' ), | |
| 1267 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'X-Frame-Options', 'vigilante' ), 'label_en' => 'X-Frame-Options', 'keywords' => _x( 'x-frame-options headers', 'settings search keywords', 'vigilante' ) ), | |
| 1268 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'X-Content-Type-Options', 'vigilante' ), 'label_en' => 'X-Content-Type-Options', 'keywords' => _x( 'x-content-type-options content headers', 'settings search keywords', 'vigilante' ) ), | |
| 1269 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Referrer-Policy', 'vigilante' ), 'label_en' => 'Referrer-Policy', 'keywords' => _x( 'referrer-policy headers', 'settings search keywords', 'vigilante' ) ), | |
| 1270 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'HSTS', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'HSTS', 'vigilante' ), 'label_en' => 'HSTS', 'keywords' => _x( 'hsts strict transport security ssl tls https headers', 'settings search keywords', 'vigilante' ) ), | |
| 1271 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Content Security Policy', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Content Security Policy', 'vigilante' ), 'label_en' => 'Content Security Policy', 'keywords' => _x( 'content security policy csp xss headers', 'settings search keywords', 'vigilante' ) ), | |
| 1272 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Server Identity', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Server Signature', 'vigilante' ), 'label_en' => 'Server Signature', 'keywords' => _x( 'server signature fingerprint banner', 'settings search keywords', 'vigilante' ) ), | |
| 1273 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Server Identity', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Remove Fingerprinting Headers', 'vigilante' ), 'label_en' => 'Remove Fingerprinting Headers', 'keywords' => _x( 'remove fingerprinting headers fingerprint banner header http', 'settings search keywords', 'vigilante' ) ), | |
| 1274 | + // Security Headers - Cross-Origin Policies | |
| 1275 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Cross-Origin Policies', 'vigilante' ), 'anchor' => 'vigilante-section-headers-cross-origin', 'label' => __( 'Cross-Origin-Opener-Policy (COOP)', 'vigilante' ), 'label_en' => 'Cross-Origin-Opener-Policy (COOP)', 'keywords' => _x( 'coop cross-origin opener policy popup popups window opener tag assistant google isolation browsing context headers', 'settings search keywords', 'vigilante' ) ), | |
| 1276 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Cross-Origin Policies', 'vigilante' ), 'anchor' => 'vigilante-section-headers-cross-origin', 'label' => __( 'Cross-Origin-Embedder-Policy (COEP)', 'vigilante' ), 'label_en' => 'Cross-Origin-Embedder-Policy (COEP)', 'keywords' => _x( 'coep cross-origin embedder policy require-corp credentialless embed embeds iframe fonts headers', 'settings search keywords', 'vigilante' ) ), | |
| 1277 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Cross-Origin Policies', 'vigilante' ), 'anchor' => 'vigilante-section-headers-cross-origin', 'label' => __( 'Cross-Origin-Resource-Policy (CORP)', 'vigilante' ), 'label_en' => 'Cross-Origin-Resource-Policy (CORP)', 'keywords' => _x( 'corp cross-origin resource policy hotlink hotlinking cdn images assets headers', 'settings search keywords', 'vigilante' ) ), | |
| 1143 | 1278 | // Login Security |
| 1144 | - array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Custom login URL', 'vigilante' ), 'label_en' => 'Custom login URL', 'keywords' => 'url personalizada login acceso entrar wp-login wp-admin slug ocultar esconder' ), | |
| 1145 | - array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Two-Factor Authentication', 'vigilante' ), 'label_en' => 'Two-Factor Authentication', 'keywords' => '2fa doble factor autenticación totp google authenticator mfa' ), | |
| 1146 | - array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( '2FA', 'vigilante' ), 'label_en' => '2FA', 'keywords' => '2fa doble factor autenticación totp google authenticator mfa two factor' ), | |
| 1147 | - array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Failed login attempts', 'vigilante' ), 'label_en' => 'Failed login attempts', 'keywords' => 'intentos fallidos login acceso failed attempts bloqueo bloqueos contraseña errónea' ), | |
| 1148 | - array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Lockout', 'vigilante' ), 'label_en' => 'Lockout', 'keywords' => 'bloqueo bloqueado lockout baneo ban duración login' ), | |
| 1279 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Custom login URL', 'vigilante' ), 'label_en' => 'Custom login URL', 'keywords' => _x( 'custom login url signin log-in access slug', 'settings search keywords', 'vigilante' ) ), | |
| 1280 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Two-Factor Authentication', 'vigilante' ), 'label_en' => 'Two-Factor Authentication', 'keywords' => _x( 'two-factor authentication 2fa mfa otp totp authenticator', 'settings search keywords', 'vigilante' ) ), | |
| 1281 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( '2FA', 'vigilante' ), 'label_en' => '2FA', 'keywords' => _x( '2fa two-factor mfa otp totp authenticator', 'settings search keywords', 'vigilante' ) ), | |
| 1282 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Failed login attempts', 'vigilante' ), 'label_en' => 'Failed login attempts', 'keywords' => _x( 'failed login attempts signin log-in access tries retries', 'settings search keywords', 'vigilante' ) ), | |
| 1283 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Lockout', 'vigilante' ), 'label_en' => 'Lockout', 'keywords' => _x( 'lockout lock ban block login', 'settings search keywords', 'vigilante' ) ), | |
| 1149 | 1284 | // REST API |
| 1150 | - array( 'tab' => 'rest-api', 'tab_label' => __( 'REST API', 'vigilante' ), 'section' => __( 'REST API Security', 'vigilante' ), 'anchor' => 'vigilante-section-rest-api-main', 'label' => __( 'Access Mode', 'vigilante' ), 'label_en' => 'Access Mode', 'keywords' => 'modo acceso rest api público privado autenticado' ), | |
| 1151 | - array( 'tab' => 'rest-api', 'tab_label' => __( 'REST API', 'vigilante' ), 'section' => __( 'REST API Security', 'vigilante' ), 'anchor' => 'vigilante-section-rest-api-main', 'label' => __( 'Block User Enumeration', 'vigilante' ), 'label_en' => 'Block User Enumeration', 'keywords' => 'enumeración usuarios users block bloquear autores author slug ?author' ), | |
| 1152 | - array( 'tab' => 'rest-api', 'tab_label' => __( 'REST API', 'vigilante' ), 'section' => __( 'REST API Security', 'vigilante' ), 'anchor' => 'vigilante-section-rest-api-main', 'label' => __( 'Disable JSONP', 'vigilante' ), 'label_en' => 'Disable JSONP', 'keywords' => 'jsonp desactivar deshabilitar disable callback' ), | |
| 1285 | + array( 'tab' => 'rest-api', 'tab_label' => __( 'REST API', 'vigilante' ), 'section' => __( 'REST API Security', 'vigilante' ), 'anchor' => 'vigilante-section-rest-api-main', 'label' => __( 'Access Mode', 'vigilante' ), 'label_en' => 'Access Mode', 'keywords' => _x( 'access mode rest api', 'settings search keywords', 'vigilante' ) ), | |
| 1286 | + array( 'tab' => 'rest-api', 'tab_label' => __( 'REST API', 'vigilante' ), 'section' => __( 'REST API Security', 'vigilante' ), 'anchor' => 'vigilante-section-rest-api-main', 'label' => __( 'Block User Enumeration', 'vigilante' ), 'label_en' => 'Block User Enumeration', 'keywords' => _x( 'block user enumeration blocking blocked deny users account author slug', 'settings search keywords', 'vigilante' ) ), | |
| 1287 | + array( 'tab' => 'rest-api', 'tab_label' => __( 'REST API', 'vigilante' ), 'section' => __( 'REST API Security', 'vigilante' ), 'anchor' => 'vigilante-section-rest-api-main', 'label' => __( 'Disable JSONP', 'vigilante' ), 'label_en' => 'Disable JSONP', 'keywords' => _x( 'disable jsonp', 'settings search keywords', 'vigilante' ) ), | |
| 1153 | 1288 | // User Security |
| 1154 | - array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Username protection', 'vigilante' ), 'label_en' => 'Username protection', 'keywords' => 'nombre usuario username admin reservado prohibido protección' ), | |
| 1155 | - array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Password strength', 'vigilante' ), 'label_en' => 'Password strength', 'keywords' => 'fortaleza fuerza contraseña password débil fuerte complejidad requisitos' ), | |
| 1156 | - array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Admin monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-users-admin-monitoring', 'label' => __( 'Admin monitoring', 'vigilante' ), 'label_en' => 'Admin monitoring', 'keywords' => 'monitorización administradores admin supervisión alertas cambios' ), | |
| 1157 | - array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Registration approval', 'vigilante' ), 'anchor' => 'vigilante-section-users-registration', 'label' => __( 'Registration approval', 'vigilante' ), 'label_en' => 'Registration approval', 'keywords' => 'aprobación registro registration moderación nuevos usuarios signup' ), | |
| 1158 | - array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Session limits', 'vigilante' ), 'anchor' => 'vigilante-section-users-sessions', 'label' => __( 'Session limits', 'vigilante' ), 'label_en' => 'Session limits', 'keywords' => 'sesiones limits límite concurrentes sessions simultáneas' ), | |
| 1159 | - array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Password expiration', 'vigilante' ), 'anchor' => 'vigilante-section-users-password-exp', 'label' => __( 'Password expiration', 'vigilante' ), 'label_en' => 'Password expiration', 'keywords' => 'expiración caducidad contraseña password cambiar renovar rotación' ), | |
| 1160 | - array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Email verification', 'vigilante' ), 'anchor' => 'vigilante-section-users-email-verify', 'label' => __( 'Email verification', 'vigilante' ), 'label_en' => 'Email verification', 'keywords' => 'verificación correo email confirmación validación' ), | |
| 1289 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Username protection', 'vigilante' ), 'label_en' => 'Username protection', 'keywords' => _x( 'username protection admin', 'settings search keywords', 'vigilante' ) ), | |
| 1290 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Password strength', 'vigilante' ), 'label_en' => 'Password strength', 'keywords' => _x( 'password strength passwords credentials', 'settings search keywords', 'vigilante' ) ), | |
| 1291 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Admin monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-users-admin-monitoring', 'label' => __( 'Admin monitoring', 'vigilante' ), 'label_en' => 'Admin monitoring', 'keywords' => _x( 'admin monitoring administrator administrators', 'settings search keywords', 'vigilante' ) ), | |
| 1292 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Registration approval', 'vigilante' ), 'anchor' => 'vigilante-section-users-registration', 'label' => __( 'Registration approval', 'vigilante' ), 'label_en' => 'Registration approval', 'keywords' => _x( 'registration approval signup register approve moderate', 'settings search keywords', 'vigilante' ) ), | |
| 1293 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Session limits', 'vigilante' ), 'anchor' => 'vigilante-section-users-sessions', 'label' => __( 'Session limits', 'vigilante' ), 'label_en' => 'Session limits', 'keywords' => _x( 'session limits sessions concurrent', 'settings search keywords', 'vigilante' ) ), | |
| 1294 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Password expiration', 'vigilante' ), 'anchor' => 'vigilante-section-users-password-exp', 'label' => __( 'Password expiration', 'vigilante' ), 'label_en' => 'Password expiration', 'keywords' => _x( 'password expiration passwords credentials expiry expire caducity', 'settings search keywords', 'vigilante' ) ), | |
| 1295 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Email verification', 'vigilante' ), 'anchor' => 'vigilante-section-users-email-verify', 'label' => __( 'Email verification', 'vigilante' ), 'label_en' => 'Email verification', 'keywords' => _x( 'email verification mail notification notify verify confirm', 'settings search keywords', 'vigilante' ) ), | |
| 1161 | 1296 | // WP Hardening |
| 1162 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Database Hardening', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-database', 'label' => __( 'Database Hardening', 'vigilante' ), 'label_en' => 'Database Hardening', 'keywords' => 'base datos database db mysql fortalecer hardening endurecer' ), | |
| 1163 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Database Hardening', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-database', 'label' => __( 'Database prefix', 'vigilante' ), 'label_en' => 'Database prefix', 'keywords' => 'prefijo base datos database db mysql tabla tablas wp_ cambiar renombrar' ), | |
| 1164 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-wpconfig', 'label' => __( 'Disable file editing', 'vigilante' ), 'label_en' => 'Disable file editing', 'keywords' => 'desactivar deshabilitar disable edición editor archivos file edit disallow' ), | |
| 1165 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-wpconfig', 'label' => __( 'Disable plugin/theme installation', 'vigilante' ), 'label_en' => 'Disable plugin/theme installation', 'keywords' => 'desactivar deshabilitar disable instalación plugins temas themes install disallow' ), | |
| 1166 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-wpconfig', 'label' => __( 'Force SSL admin', 'vigilante' ), 'label_en' => 'Force SSL admin', 'keywords' => 'forzar ssl tls https admin administración certificado' ), | |
| 1167 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'field-disable-wp-cron', 'label' => __( 'Disable WP Cron', 'vigilante' ), 'label_en' => 'Disable WP Cron', 'keywords' => 'desactivar deshabilitar disable wp cron tareas programadas scheduled real server crontab pseudo' ), | |
| 1168 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Comment Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-comments', 'label' => __( 'Comment Security', 'vigilante' ), 'label_en' => 'Comment Security', 'keywords' => 'comentarios comments spam protección honeypot autores url' ), | |
| 1169 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-headers', 'label' => __( 'Header Cleanup', 'vigilante' ), 'label_en' => 'Header Cleanup', 'keywords' => 'limpieza cabeceras headers meta tags wordpress generator rsd wlwmanifest' ), | |
| 1170 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-headers', 'label' => __( 'Remove WordPress version', 'vigilante' ), 'label_en' => 'Remove WordPress version', 'keywords' => 'eliminar quitar versión wordpress wp generator meta ocultar hide' ), | |
| 1171 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'field-remove-wp-version-assets', 'label' => __( 'Remove version from assets', 'vigilante' ), 'label_en' => 'Remove version from assets', 'keywords' => 'eliminar quitar versión wordpress wp ver query string assets recursos urls scripts styles css js cache busting' ), | |
| 1172 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-headers', 'label' => __( 'Disable XML-RPC', 'vigilante' ), 'label_en' => 'Disable XML-RPC', 'keywords' => 'xmlrpc xml-rpc desactivar deshabilitar disable pingback trackback' ), | |
| 1173 | - array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'RSS Feed Settings', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-rss', 'label' => __( 'RSS Feed Settings', 'vigilante' ), 'label_en' => 'RSS Feed Settings', 'keywords' => 'rss feed sindicación feeds ajustes configuración' ), | |
| 1297 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Database Hardening', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-database', 'label' => __( 'Database Hardening', 'vigilante' ), 'label_en' => 'Database Hardening', 'keywords' => _x( 'database hardening db mysql tables', 'settings search keywords', 'vigilante' ) ), | |
| 1298 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Database Hardening', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-database', 'label' => __( 'Database prefix', 'vigilante' ), 'label_en' => 'Database prefix', 'keywords' => _x( 'database prefix db mysql tables table', 'settings search keywords', 'vigilante' ) ), | |
| 1299 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-wpconfig', 'label' => __( 'Disable file editing', 'vigilante' ), 'label_en' => 'Disable file editing', 'keywords' => _x( 'disable file editing files editor edit', 'settings search keywords', 'vigilante' ) ), | |
| 1300 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-wpconfig', 'label' => __( 'Disable plugin/theme installation', 'vigilante' ), 'label_en' => 'Disable plugin/theme installation', 'keywords' => _x( 'disable plugin theme installation install', 'settings search keywords', 'vigilante' ) ), | |
| 1301 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-wpconfig', 'label' => __( 'Force SSL admin', 'vigilante' ), 'label_en' => 'Force SSL admin', 'keywords' => _x( 'force ssl admin bruteforce administrator administrators tls https', 'settings search keywords', 'vigilante' ) ), | |
| 1302 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'field-disable-wp-cron', 'label' => __( 'Disable WP Cron', 'vigilante' ), 'label_en' => 'Disable WP Cron', 'keywords' => _x( 'disable wp cron scheduled tasks wp-cron', 'settings search keywords', 'vigilante' ) ), | |
| 1303 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Comment Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-comments', 'label' => __( 'Comment Security', 'vigilante' ), 'label_en' => 'Comment Security', 'keywords' => _x( 'comment security comments spam honeypot url', 'settings search keywords', 'vigilante' ) ), | |
| 1304 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-headers', 'label' => __( 'Header Cleanup', 'vigilante' ), 'label_en' => 'Header Cleanup', 'keywords' => _x( 'header cleanup headers http meta generator rsd wlwmanifest', 'settings search keywords', 'vigilante' ) ), | |
| 1305 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-headers', 'label' => __( 'Remove WordPress version', 'vigilante' ), 'label_en' => 'Remove WordPress version', 'keywords' => _x( 'remove wordpress version generator meta', 'settings search keywords', 'vigilante' ) ), | |
| 1306 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'field-remove-wp-version-assets', 'label' => __( 'Remove version from assets', 'vigilante' ), 'label_en' => 'Remove version from assets', 'keywords' => _x( 'remove version from assets', 'settings search keywords', 'vigilante' ) ), | |
| 1307 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-xmlrpc', 'label' => __( 'Disable XML-RPC', 'vigilante' ), 'label_en' => 'Disable XML-RPC', 'keywords' => _x( 'disable xml-rpc xmlrpc rpc remote jetpack app pingback trackback', 'settings search keywords', 'vigilante' ) ), | |
| 1308 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'RSS Feed Settings', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-rss', 'label' => __( 'RSS Feed Settings', 'vigilante' ), 'label_en' => 'RSS Feed Settings', 'keywords' => _x( 'rss feed settings feeds atom', 'settings search keywords', 'vigilante' ) ), | |
| 1174 | 1309 | // File Integrity |
| 1175 | - array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'File Integrity Monitoring', 'vigilante' ), 'label_en' => 'File Integrity Monitoring', 'keywords' => 'integridad archivos monitorización supervisión hash checksum malware cambios' ), | |
| 1176 | - array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Scan schedule', 'vigilante' ), 'label_en' => 'Scan schedule', 'keywords' => 'escaneo escáner programación planificación horario frecuencia cron' ), | |
| 1177 | - array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Instant alert', 'vigilante' ), 'label_en' => 'Instant alert', 'keywords' => 'alerta instantánea inmediata notificación aviso email tiempo real' ), | |
| 1178 | - array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'Ignored Files', 'vigilante' ), 'anchor' => 'vigilante-section-fi-ignored', 'label' => __( 'Ignored Files', 'vigilante' ), 'label_en' => 'Ignored Files', 'keywords' => 'ignorados ignorar excluir exclusiones archivos ignored exclude' ), | |
| 1310 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'File Integrity Monitoring', 'vigilante' ), 'label_en' => 'File Integrity Monitoring', 'keywords' => _x( 'file integrity monitoring files checksum checksums tamper', 'settings search keywords', 'vigilante' ) ), | |
| 1311 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Scan schedule', 'vigilante' ), 'label_en' => 'Scan schedule', 'keywords' => _x( 'scan schedule scans scanning check cron', 'settings search keywords', 'vigilante' ) ), | |
| 1312 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Instant alert', 'vigilante' ), 'label_en' => 'Instant alert', 'keywords' => _x( 'instant alert alerts notification warning email', 'settings search keywords', 'vigilante' ) ), | |
| 1313 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'Ignored Files', 'vigilante' ), 'anchor' => 'vigilante-section-fi-ignored', 'label' => __( 'Ignored Files', 'vigilante' ), 'label_en' => 'Ignored Files', 'keywords' => _x( 'ignored files file exclude', 'settings search keywords', 'vigilante' ) ), | |
| 1179 | 1314 | // Security Audit |
| 1180 | - array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Security Audit Settings', 'vigilante' ), 'anchor' => 'vigilante-section-audit-settings', 'label' => __( 'Retention', 'vigilante' ), 'label_en' => 'Retention', 'keywords' => 'retención días log registro conservación purga auditoría' ), | |
| 1181 | - array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Security Audit Settings', 'vigilante' ), 'anchor' => 'vigilante-section-audit-settings', 'label' => __( 'Events to Log', 'vigilante' ), 'label_en' => 'Events to Log', 'keywords' => 'eventos log registro auditoría registrar capturar' ), | |
| 1182 | - array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Security Audit Settings', 'vigilante' ), 'anchor' => 'vigilante-section-audit-settings', 'label' => __( 'Option Tracking', 'vigilante' ), 'label_en' => 'Option Tracking', 'keywords' => 'opciones seguimiento rastreo cambios ajustes options tracking' ), | |
| 1183 | - array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Security Audit Settings', 'vigilante' ), 'anchor' => 'vigilante-section-audit-settings', 'label' => __( 'Exclusions', 'vigilante' ), 'label_en' => 'Exclusions', 'keywords' => 'exclusiones excluir ignorar usuarios roles ip filtros' ), | |
| 1184 | - array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Audit Alerts', 'vigilante' ), 'anchor' => 'vigilante-section-audit-alerts', 'label' => __( 'Audit Alerts', 'vigilante' ), 'label_en' => 'Audit Alerts', 'keywords' => 'alertas avisos aviso notificaciones email correo mail auditoría audit seguridad warning critical destinatarios test prueba' ), | |
| 1185 | - array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Audit Alerts', 'vigilante' ), 'anchor' => 'field-audit-alerts-immediate', 'label' => __( 'Immediate alerts', 'vigilante' ), 'label_en' => 'Immediate alerts', 'keywords' => 'alertas inmediatas email correo mail aviso severidad crítico critical warning evento auditoría inmediato' ), | |
| 1186 | - array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Audit Alerts', 'vigilante' ), 'anchor' => 'field-audit-alerts-threshold', 'label' => __( 'Threshold alerts', 'vigilante' ), 'label_en' => 'Threshold alerts', 'keywords' => 'alertas umbral pico ráfaga email correo mail aviso categoría ventana threshold auditoría cortafuegos login' ), | |
| 1187 | - array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Recent Activity', 'vigilante' ), 'anchor' => 'vigilante-section-audit-recent', 'label' => __( 'Recent Activity', 'vigilante' ), 'label_en' => 'Recent Activity', 'keywords' => 'actividad reciente log registro eventos últimos historial' ), | |
| 1315 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Security Audit Settings', 'vigilante' ), 'anchor' => 'vigilante-section-audit-settings', 'label' => __( 'Retention', 'vigilante' ), 'label_en' => 'Retention', 'keywords' => _x( 'retention keep days storage log', 'settings search keywords', 'vigilante' ) ), | |
| 1316 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Security Audit Settings', 'vigilante' ), 'anchor' => 'vigilante-section-audit-settings', 'label' => __( 'Events to Log', 'vigilante' ), 'label_en' => 'Events to Log', 'keywords' => _x( 'events to log', 'settings search keywords', 'vigilante' ) ), | |
| 1317 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Security Audit Settings', 'vigilante' ), 'anchor' => 'vigilante-section-audit-settings', 'label' => __( 'Option Tracking', 'vigilante' ), 'label_en' => 'Option Tracking', 'keywords' => _x( 'option tracking', 'settings search keywords', 'vigilante' ) ), | |
| 1318 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Security Audit Settings', 'vigilante' ), 'anchor' => 'vigilante-section-audit-settings', 'label' => __( 'Exclusions', 'vigilante' ), 'label_en' => 'Exclusions', 'keywords' => _x( 'exclusions roles ip', 'settings search keywords', 'vigilante' ) ), | |
| 1319 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Audit Alerts', 'vigilante' ), 'anchor' => 'vigilante-section-audit-alerts', 'label' => __( 'Audit Alerts', 'vigilante' ), 'label_en' => 'Audit Alerts', 'keywords' => _x( 'audit alerts email mail warning critical', 'settings search keywords', 'vigilante' ) ), | |
| 1320 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Audit Alerts', 'vigilante' ), 'anchor' => 'field-audit-alerts-immediate', 'label' => __( 'Immediate alerts', 'vigilante' ), 'label_en' => 'Immediate alerts', 'keywords' => _x( 'immediate alerts email mail critical warning', 'settings search keywords', 'vigilante' ) ), | |
| 1321 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Audit Alerts', 'vigilante' ), 'anchor' => 'field-audit-alerts-threshold', 'label' => __( 'Threshold alerts', 'vigilante' ), 'label_en' => 'Threshold alerts', 'keywords' => _x( 'threshold alerts email mail login', 'settings search keywords', 'vigilante' ) ), | |
| 1322 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Recent Activity', 'vigilante' ), 'anchor' => 'vigilante-section-audit-recent', 'label' => __( 'Recent Activity', 'vigilante' ), 'label_en' => 'Recent Activity', 'keywords' => _x( 'recent activity log', 'settings search keywords', 'vigilante' ) ), | |
| 1188 | 1323 | // Settings & Tools |
| 1189 | - array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Notification settings', 'vigilante' ), 'anchor' => 'vigilante-section-tools-notifications', 'label' => __( 'Notification settings', 'vigilante' ), 'label_en' => 'Notification settings', 'keywords' => 'notificaciones ajustes settings email correo avisos alertas' ), | |
| 1190 | - array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Notification settings', 'vigilante' ), 'anchor' => 'vigilante-section-tools-notifications', 'label' => __( 'Additional Recipients', 'vigilante' ), 'label_en' => 'Additional Recipients', 'keywords' => 'destinatarios adicionales correo email cc copia recipients' ), | |
| 1191 | - array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Tools', 'vigilante' ), 'anchor' => 'vigilante-section-tools-main', 'label' => __( 'Export Settings', 'vigilante' ), 'label_en' => 'Export Settings', 'keywords' => 'exportar export ajustes configuración settings json' ), | |
| 1192 | - array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Tools', 'vigilante' ), 'anchor' => 'vigilante-section-tools-main', 'label' => __( 'Import Settings', 'vigilante' ), 'label_en' => 'Import Settings', 'keywords' => 'importar import ajustes configuración settings json' ), | |
| 1193 | - array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Tools', 'vigilante' ), 'anchor' => 'vigilante-section-tools-main', 'label' => __( 'Reset to Defaults', 'vigilante' ), 'label_en' => 'Reset to Defaults', 'keywords' => 'restablecer resetear reset defaults predeterminados valores originales fábrica' ), | |
| 1194 | - array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Tools', 'vigilante' ), 'anchor' => 'vigilante-section-tools-main', 'label' => __( 'Create Backup', 'vigilante' ), 'label_en' => 'Create Backup', 'keywords' => 'copia seguridad backup crear generar respaldo' ), | |
| 1195 | - array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Tools', 'vigilante' ), 'anchor' => 'vigilante-section-tools-main', 'label' => __( 'Database Backup', 'vigilante' ), 'label_en' => 'Database Backup', 'keywords' => 'base datos database db mysql copia seguridad backup respaldo tablas exportar' ), | |
| 1324 | + array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Notification settings', 'vigilante' ), 'anchor' => 'vigilante-section-tools-notifications', 'label' => __( 'Notification settings', 'vigilante' ), 'label_en' => 'Notification settings', 'keywords' => _x( 'notification settings email', 'settings search keywords', 'vigilante' ) ), | |
| 1325 | + array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Notification settings', 'vigilante' ), 'anchor' => 'vigilante-section-tools-notifications', 'label' => __( 'Additional Recipients', 'vigilante' ), 'label_en' => 'Additional Recipients', 'keywords' => _x( 'additional recipients email recipient', 'settings search keywords', 'vigilante' ) ), | |
| 1326 | + array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Tools', 'vigilante' ), 'anchor' => 'vigilante-section-tools-main', 'label' => __( 'Export Settings', 'vigilante' ), 'label_en' => 'Export Settings', 'keywords' => _x( 'export settings json', 'settings search keywords', 'vigilante' ) ), | |
| 1327 | + array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Tools', 'vigilante' ), 'anchor' => 'vigilante-section-tools-main', 'label' => __( 'Import Settings', 'vigilante' ), 'label_en' => 'Import Settings', 'keywords' => _x( 'import settings json', 'settings search keywords', 'vigilante' ) ), | |
| 1328 | + array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Tools', 'vigilante' ), 'anchor' => 'vigilante-section-tools-main', 'label' => __( 'Reset to Defaults', 'vigilante' ), 'label_en' => 'Reset to Defaults', 'keywords' => _x( 'reset to defaults', 'settings search keywords', 'vigilante' ) ), | |
| 1329 | + array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Tools', 'vigilante' ), 'anchor' => 'vigilante-section-tools-main', 'label' => __( 'Create Backup', 'vigilante' ), 'label_en' => 'Create Backup', 'keywords' => _x( 'create backup', 'settings search keywords', 'vigilante' ) ), | |
| 1330 | + array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Tools', 'vigilante' ), 'anchor' => 'vigilante-section-tools-main', 'label' => __( 'Database Backup', 'vigilante' ), 'label_en' => 'Database Backup', 'keywords' => _x( 'database backup db mysql tables', 'settings search keywords', 'vigilante' ) ), | |
| 1331 | + // Entradas anadidas en la 2.9.7 tras comprobar que el indice cubria 68 de | |
| 1332 | + // las 131 filas de ajustes: buscar XML-RPC, por ejemplo, no devolvia nada. | |
| 1333 | + // El indice se mantiene a mano, asi que al anadir una fila de ajustes hay | |
| 1334 | + // que anadirla tambien aqui. | |
| 1335 | + array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Notification settings', 'vigilante' ), 'anchor' => 'vigilante-section-tools-notifications', 'label' => __( 'WordPress Admin Email', 'vigilante' ), 'label_en' => 'WordPress Admin Email', 'keywords' => _x( 'wordpress admin email administrator administrators mail notification notify', 'settings search keywords', 'vigilante' ) ), | |
| 1336 | + array( 'tab' => 'tools', 'tab_label' => __( 'Settings & Tools', 'vigilante' ), 'section' => __( 'Notification settings', 'vigilante' ), 'anchor' => 'vigilante-section-tools-notifications', 'label' => __( 'Plugin Deactivation', 'vigilante' ), 'label_en' => 'Plugin Deactivation', 'keywords' => _x( 'plugin deactivation', 'settings search keywords', 'vigilante' ) ), | |
| 1337 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Block Bad Query Strings', 'vigilante' ), 'label_en' => 'Block Bad Query Strings', 'keywords' => _x( 'block bad query strings blocking blocked deny malicious harmful', 'settings search keywords', 'vigilante' ) ), | |
| 1338 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'SQL Injection Protection', 'vigilante' ), 'label_en' => 'SQL Injection Protection', 'keywords' => _x( 'sql injection protection', 'settings search keywords', 'vigilante' ) ), | |
| 1339 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'XSS Protection', 'vigilante' ), 'label_en' => 'XSS Protection', 'keywords' => _x( 'xss protection', 'settings search keywords', 'vigilante' ) ), | |
| 1340 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'File Inclusion Protection', 'vigilante' ), 'label_en' => 'File Inclusion Protection', 'keywords' => _x( 'file inclusion protection files', 'settings search keywords', 'vigilante' ) ), | |
| 1341 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Directory Traversal Protection', 'vigilante' ), 'label_en' => 'Directory Traversal Protection', 'keywords' => _x( 'directory traversal protection folder folders', 'settings search keywords', 'vigilante' ) ), | |
| 1342 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Enable Rate Limiting', 'vigilante' ), 'label_en' => 'Enable Rate Limiting', 'keywords' => _x( 'enable rate limiting throttle flood burst limit limits', 'settings search keywords', 'vigilante' ) ), | |
| 1343 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Requests per Minute', 'vigilante' ), 'label_en' => 'Requests per Minute', 'keywords' => _x( 'requests per minute request traffic', 'settings search keywords', 'vigilante' ) ), | |
| 1344 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Block Duration (seconds)', 'vigilante' ), 'label_en' => 'Block Duration (seconds)', 'keywords' => _x( 'block duration seconds blocking blocked deny', 'settings search keywords', 'vigilante' ) ), | |
| 1345 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Progressive Blocking', 'vigilante' ), 'label_en' => 'Progressive Blocking', 'keywords' => _x( 'progressive blocking', 'settings search keywords', 'vigilante' ) ), | |
| 1346 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Maximum Block Duration', 'vigilante' ), 'label_en' => 'Maximum Block Duration', 'keywords' => _x( 'maximum block duration blocking blocked deny', 'settings search keywords', 'vigilante' ) ), | |
| 1347 | + array( 'tab' => 'firewall', 'tab_label' => __( 'Firewall', 'vigilante' ), 'section' => __( 'Firewall Protection', 'vigilante' ), 'anchor' => 'vigilante-section-firewall-main', 'label' => __( 'Visitor IP detection', 'vigilante' ), 'label_en' => 'Visitor IP detection', 'keywords' => _x( 'visitor ip detection ips address addresses cidr ipv4 ipv6', 'settings search keywords', 'vigilante' ) ), | |
| 1348 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Max Login Attempts', 'vigilante' ), 'label_en' => 'Max Login Attempts', 'keywords' => _x( 'max login attempts signin log-in access tries retries', 'settings search keywords', 'vigilante' ) ), | |
| 1349 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Lockout Duration', 'vigilante' ), 'label_en' => 'Lockout Duration', 'keywords' => _x( 'lockout duration lock ban block', 'settings search keywords', 'vigilante' ) ), | |
| 1350 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Progressive Lockout', 'vigilante' ), 'label_en' => 'Progressive Lockout', 'keywords' => _x( 'progressive lockout lock ban block', 'settings search keywords', 'vigilante' ) ), | |
| 1351 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Hide Login Errors', 'vigilante' ), 'label_en' => 'Hide Login Errors', 'keywords' => _x( 'hide login errors signin log-in access error debug log', 'settings search keywords', 'vigilante' ) ), | |
| 1352 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Disable Application Passwords', 'vigilante' ), 'label_en' => 'Disable Application Passwords', 'keywords' => _x( 'disable application passwords password credentials', 'settings search keywords', 'vigilante' ) ), | |
| 1353 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Login URL Slug', 'vigilante' ), 'label_en' => 'Login URL Slug', 'keywords' => _x( 'login url slug signin log-in access path', 'settings search keywords', 'vigilante' ) ), | |
| 1354 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Notify users', 'vigilante' ), 'label_en' => 'Notify users', 'keywords' => _x( 'notify users notification alert email user accounts', 'settings search keywords', 'vigilante' ) ), | |
| 1355 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Notify on Lockout', 'vigilante' ), 'label_en' => 'Notify on Lockout', 'keywords' => _x( 'notify on lockout notification alert email lock ban block', 'settings search keywords', 'vigilante' ) ), | |
| 1356 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Notify on Admin Login', 'vigilante' ), 'label_en' => 'Notify on Admin Login', 'keywords' => _x( 'notify on admin login notification alert email administrator administrators signin log-in access', 'settings search keywords', 'vigilante' ) ), | |
| 1357 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Current settings', 'vigilante' ), 'label_en' => 'Current settings', 'keywords' => _x( 'current settings', 'settings search keywords', 'vigilante' ) ), | |
| 1358 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Blocked IPs', 'vigilante' ), 'label_en' => 'Blocked IPs', 'keywords' => _x( 'blocked ips', 'settings search keywords', 'vigilante' ) ), | |
| 1359 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Enable 2FA', 'vigilante' ), 'label_en' => 'Enable 2FA', 'keywords' => _x( 'enable 2fa two-factor mfa otp totp authenticator', 'settings search keywords', 'vigilante' ) ), | |
| 1360 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Verification method', 'vigilante' ), 'label_en' => 'Verification method', 'keywords' => _x( 'verification method verify confirm', 'settings search keywords', 'vigilante' ) ), | |
| 1361 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Enforce for roles', 'vigilante' ), 'label_en' => 'Enforce for roles', 'keywords' => _x( 'enforce for roles role capabilities', 'settings search keywords', 'vigilante' ) ), | |
| 1362 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Exclude specific users', 'vigilante' ), 'label_en' => 'Exclude specific users', 'keywords' => _x( 'exclude specific users user accounts', 'settings search keywords', 'vigilante' ) ), | |
| 1363 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Remember device', 'vigilante' ), 'label_en' => 'Remember device', 'keywords' => _x( 'remember device', 'settings search keywords', 'vigilante' ) ), | |
| 1364 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Grace period', 'vigilante' ), 'label_en' => 'Grace period', 'keywords' => _x( 'grace period', 'settings search keywords', 'vigilante' ) ), | |
| 1365 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Email sender name', 'vigilante' ), 'label_en' => 'Email sender name', 'keywords' => _x( 'email sender name mail notification notify names', 'settings search keywords', 'vigilante' ) ), | |
| 1366 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Reset user TOTP', 'vigilante' ), 'label_en' => 'Reset user TOTP', 'keywords' => _x( 'reset user totp users account 2fa authenticator app', 'settings search keywords', 'vigilante' ) ), | |
| 1367 | + array( 'tab' => 'login', 'tab_label' => __( 'Login Security', 'vigilante' ), 'section' => __( 'Login Protection Status', 'vigilante' ), 'anchor' => 'vigilante-section-login-main', 'label' => __( 'Notify on enable', 'vigilante' ), 'label_en' => 'Notify on enable', 'keywords' => _x( 'notify on enable notification alert email', 'settings search keywords', 'vigilante' ) ), | |
| 1368 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Enable CSP', 'vigilante' ), 'label_en' => 'Enable CSP', 'keywords' => _x( 'enable csp content security policy', 'settings search keywords', 'vigilante' ) ), | |
| 1369 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Report Only Mode', 'vigilante' ), 'label_en' => 'Report Only Mode', 'keywords' => _x( 'report only mode', 'settings search keywords', 'vigilante' ) ), | |
| 1370 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Redirect HTTP to HTTPS', 'vigilante' ), 'label_en' => 'Redirect HTTP to HTTPS', 'keywords' => _x( 'redirect http to https redirection forward ssl tls secure', 'settings search keywords', 'vigilante' ) ), | |
| 1371 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Fix Mixed Content', 'vigilante' ), 'label_en' => 'Fix Mixed Content', 'keywords' => _x( 'fix mixed content insecure http', 'settings search keywords', 'vigilante' ) ), | |
| 1372 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'field-upgrade-insecure-requests', 'label' => __( 'Upgrade Insecure Requests', 'vigilante' ), 'label_en' => 'Upgrade Insecure Requests', 'keywords' => _x( 'upgrade insecure requests mixed content csp https external resources', 'settings search keywords', 'vigilante' ) ), | |
| 1373 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Rewrite Site Address on Activation', 'vigilante' ), 'label_en' => 'Rewrite Site Address on Activation', 'keywords' => _x( 'rewrite site address on activation', 'settings search keywords', 'vigilante' ) ), | |
| 1374 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Enable HSTS', 'vigilante' ), 'label_en' => 'Enable HSTS', 'keywords' => _x( 'enable hsts strict transport security', 'settings search keywords', 'vigilante' ) ), | |
| 1375 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Max Age', 'vigilante' ), 'label_en' => 'Max Age', 'keywords' => _x( 'max age', 'settings search keywords', 'vigilante' ) ), | |
| 1376 | + array( 'tab' => 'headers', 'tab_label' => __( 'Security Headers', 'vigilante' ), 'section' => __( 'Security Headers', 'vigilante' ), 'anchor' => 'vigilante-section-headers-main', 'label' => __( 'Include Subdomains', 'vigilante' ), 'label_en' => 'Include Subdomains', 'keywords' => _x( 'include subdomains', 'settings search keywords', 'vigilante' ) ), | |
| 1377 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Block Insecure Usernames', 'vigilante' ), 'label_en' => 'Block Insecure Usernames', 'keywords' => _x( 'block insecure usernames blocking blocked deny weak unsafe', 'settings search keywords', 'vigilante' ) ), | |
| 1378 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Enforce Strong Passwords', 'vigilante' ), 'label_en' => 'Enforce Strong Passwords', 'keywords' => _x( 'enforce strong passwords complexity password credentials', 'settings search keywords', 'vigilante' ) ), | |
| 1379 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Minimum Password Length', 'vigilante' ), 'label_en' => 'Minimum Password Length', 'keywords' => _x( 'minimum password length passwords credentials characters', 'settings search keywords', 'vigilante' ) ), | |
| 1380 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Password Requirements', 'vigilante' ), 'label_en' => 'Password Requirements', 'keywords' => _x( 'password requirements passwords credentials', 'settings search keywords', 'vigilante' ) ), | |
| 1381 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Apply Password Rules To', 'vigilante' ), 'label_en' => 'Apply Password Rules To', 'keywords' => _x( 'apply password rules to passwords credentials', 'settings search keywords', 'vigilante' ) ), | |
| 1382 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Block Author Scanning', 'vigilante' ), 'label_en' => 'Block Author Scanning', 'keywords' => _x( 'block author scanning blocking blocked deny authors enumeration probing', 'settings search keywords', 'vigilante' ) ), | |
| 1383 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Username & password protection', 'vigilante' ), 'anchor' => 'vigilante-section-users-password', 'label' => __( 'Display Name Protection', 'vigilante' ), 'label_en' => 'Display Name Protection', 'keywords' => _x( 'display name protection public visible names', 'settings search keywords', 'vigilante' ) ), | |
| 1384 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Admin monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-users-admin-monitoring', 'label' => __( 'New Administrator Alert', 'vigilante' ), 'label_en' => 'New Administrator Alert', 'keywords' => _x( 'new administrator alert alerts notification warning', 'settings search keywords', 'vigilante' ) ), | |
| 1385 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Admin monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-users-admin-monitoring', 'label' => __( 'Admin Email Change Alert', 'vigilante' ), 'label_en' => 'Admin Email Change Alert', 'keywords' => _x( 'admin email change alert administrator administrators mail notification notify alerts warning', 'settings search keywords', 'vigilante' ) ), | |
| 1386 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Admin monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-users-admin-monitoring', 'label' => __( 'Permission Elevation Alert', 'vigilante' ), 'label_en' => 'Permission Elevation Alert', 'keywords' => _x( 'permission elevation alert alerts notification warning', 'settings search keywords', 'vigilante' ) ), | |
| 1387 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Admin monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-users-admin-monitoring', 'label' => __( 'Admin Password Change Alert', 'vigilante' ), 'label_en' => 'Admin Password Change Alert', 'keywords' => _x( 'admin password change alert administrator administrators passwords credentials alerts notification warning', 'settings search keywords', 'vigilante' ) ), | |
| 1388 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Registration approval', 'vigilante' ), 'anchor' => 'vigilante-section-users-registration', 'label' => __( 'Enable Registration Approval', 'vigilante' ), 'label_en' => 'Enable Registration Approval', 'keywords' => _x( 'enable registration approval signup register approve moderate', 'settings search keywords', 'vigilante' ) ), | |
| 1389 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Registration approval', 'vigilante' ), 'anchor' => 'vigilante-section-users-registration', 'label' => __( 'Notify Admin', 'vigilante' ), 'label_en' => 'Notify Admin', 'keywords' => _x( 'notify admin notification alert email administrator administrators', 'settings search keywords', 'vigilante' ) ), | |
| 1390 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Registration approval', 'vigilante' ), 'anchor' => 'vigilante-section-users-registration', 'label' => __( 'Auto-reject After', 'vigilante' ), 'label_en' => 'Auto-reject After', 'keywords' => _x( 'auto-reject after', 'settings search keywords', 'vigilante' ) ), | |
| 1391 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Session limits', 'vigilante' ), 'anchor' => 'vigilante-section-users-sessions', 'label' => __( 'Enable Session Limits', 'vigilante' ), 'label_en' => 'Enable Session Limits', 'keywords' => _x( 'enable session limits sessions concurrent', 'settings search keywords', 'vigilante' ) ), | |
| 1392 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Session limits', 'vigilante' ), 'anchor' => 'vigilante-section-users-sessions', 'label' => __( 'Maximum Sessions', 'vigilante' ), 'label_en' => 'Maximum Sessions', 'keywords' => _x( 'maximum sessions session concurrent', 'settings search keywords', 'vigilante' ) ), | |
| 1393 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Session limits', 'vigilante' ), 'anchor' => 'vigilante-section-users-sessions', 'label' => __( 'When Limit Exceeded', 'vigilante' ), 'label_en' => 'When Limit Exceeded', 'keywords' => _x( 'when limit exceeded', 'settings search keywords', 'vigilante' ) ), | |
| 1394 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Session limits', 'vigilante' ), 'anchor' => 'vigilante-section-users-sessions', 'label' => __( 'Exclude Administrators', 'vigilante' ), 'label_en' => 'Exclude Administrators', 'keywords' => _x( 'exclude administrators', 'settings search keywords', 'vigilante' ) ), | |
| 1395 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Password expiration', 'vigilante' ), 'anchor' => 'vigilante-section-users-password-exp', 'label' => __( 'Enable Password Expiration', 'vigilante' ), 'label_en' => 'Enable Password Expiration', 'keywords' => _x( 'enable password expiration passwords credentials expiry expire caducity', 'settings search keywords', 'vigilante' ) ), | |
| 1396 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Password expiration', 'vigilante' ), 'anchor' => 'vigilante-section-users-password-exp', 'label' => __( 'Expire After', 'vigilante' ), 'label_en' => 'Expire After', 'keywords' => _x( 'expire after', 'settings search keywords', 'vigilante' ) ), | |
| 1397 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Password expiration', 'vigilante' ), 'anchor' => 'vigilante-section-users-password-exp', 'label' => __( 'Warning Period', 'vigilante' ), 'label_en' => 'Warning Period', 'keywords' => _x( 'warning period', 'settings search keywords', 'vigilante' ) ), | |
| 1398 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Password expiration', 'vigilante' ), 'anchor' => 'vigilante-section-users-password-exp', 'label' => __( 'Password History', 'vigilante' ), 'label_en' => 'Password History', 'keywords' => _x( 'password history passwords credentials reuse previous', 'settings search keywords', 'vigilante' ) ), | |
| 1399 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Password expiration', 'vigilante' ), 'anchor' => 'vigilante-section-users-password-exp', 'label' => __( 'Email Reminder', 'vigilante' ), 'label_en' => 'Email Reminder', 'keywords' => _x( 'email reminder mail notification notify', 'settings search keywords', 'vigilante' ) ), | |
| 1400 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Password expiration', 'vigilante' ), 'anchor' => 'vigilante-section-users-password-exp', 'label' => __( 'Affected Roles', 'vigilante' ), 'label_en' => 'Affected Roles', 'keywords' => _x( 'affected roles role capabilities', 'settings search keywords', 'vigilante' ) ), | |
| 1401 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Password expiration', 'vigilante' ), 'anchor' => 'vigilante-section-users-password-exp', 'label' => __( 'Exclude specific users', 'vigilante' ), 'label_en' => 'Exclude specific users', 'keywords' => _x( 'exclude specific users user accounts', 'settings search keywords', 'vigilante' ) ), | |
| 1402 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Email verification', 'vigilante' ), 'anchor' => 'vigilante-section-users-email-verify', 'label' => __( 'Enable Email Verification', 'vigilante' ), 'label_en' => 'Enable Email Verification', 'keywords' => _x( 'enable email verification mail notification notify verify confirm', 'settings search keywords', 'vigilante' ) ), | |
| 1403 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Email verification', 'vigilante' ), 'anchor' => 'vigilante-section-users-email-verify', 'label' => __( 'Link Expiration', 'vigilante' ), 'label_en' => 'Link Expiration', 'keywords' => _x( 'link expiration expiry expire caducity', 'settings search keywords', 'vigilante' ) ), | |
| 1404 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Email verification', 'vigilante' ), 'anchor' => 'vigilante-section-users-email-verify', 'label' => __( 'Allow Resend', 'vigilante' ), 'label_en' => 'Allow Resend', 'keywords' => _x( 'allow resend', 'settings search keywords', 'vigilante' ) ), | |
| 1405 | + array( 'tab' => 'users', 'tab_label' => __( 'User Security', 'vigilante' ), 'section' => __( 'Email verification', 'vigilante' ), 'anchor' => 'vigilante-section-users-email-verify', 'label' => __( 'Auto-delete Unverified', 'vigilante' ), 'label_en' => 'Auto-delete Unverified', 'keywords' => _x( 'auto-delete unverified', 'settings search keywords', 'vigilante' ) ), | |
| 1406 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Database Hardening', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-database', 'label' => __( 'Current prefix', 'vigilante' ), 'label_en' => 'Current prefix', 'keywords' => _x( 'current prefix database db table tables mysql', 'settings search keywords', 'vigilante' ) ), | |
| 1407 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Database Hardening', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-database', 'label' => __( 'New prefix', 'vigilante' ), 'label_en' => 'New prefix', 'keywords' => _x( 'new prefix database db table tables mysql', 'settings search keywords', 'vigilante' ) ), | |
| 1408 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-wpconfig', 'label' => __( 'Disable File Editor', 'vigilante' ), 'label_en' => 'Disable File Editor', 'keywords' => _x( 'disable file editor files edit editing', 'settings search keywords', 'vigilante' ) ), | |
| 1409 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-wpconfig', 'label' => __( 'Disable File Modifications', 'vigilante' ), 'label_en' => 'Disable File Modifications', 'keywords' => _x( 'disable file modifications files modify install update', 'settings search keywords', 'vigilante' ) ), | |
| 1410 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'wp-config.php Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-wpconfig', 'label' => __( 'Hide PHP errors from visitors', 'vigilante' ), 'label_en' => 'Hide PHP errors from visitors', 'keywords' => _x( 'hide php errors from visitors error debug log', 'settings search keywords', 'vigilante' ) ), | |
| 1411 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'XML-RPC', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-xmlrpc', 'label' => __( 'XML-RPC access', 'vigilante' ), 'label_en' => 'XML-RPC access', 'keywords' => _x( 'xml-rpc access xmlrpc rpc remote jetpack app', 'settings search keywords', 'vigilante' ) ), | |
| 1412 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Comment Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-comments', 'label' => __( 'Disable Pingbacks', 'vigilante' ), 'label_en' => 'Disable Pingbacks', 'keywords' => _x( 'disable pingbacks pingback ping', 'settings search keywords', 'vigilante' ) ), | |
| 1413 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Comment Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-comments', 'label' => __( 'Disable Trackbacks', 'vigilante' ), 'label_en' => 'Disable Trackbacks', 'keywords' => _x( 'disable trackbacks trackback ping', 'settings search keywords', 'vigilante' ) ), | |
| 1414 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Comment Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-comments', 'label' => __( 'Require Moderation', 'vigilante' ), 'label_en' => 'Require Moderation', 'keywords' => _x( 'require moderation moderate approve', 'settings search keywords', 'vigilante' ) ), | |
| 1415 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Comment Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-comments', 'label' => __( 'Close Old Comments', 'vigilante' ), 'label_en' => 'Close Old Comments', 'keywords' => _x( 'close old comments comment discussion', 'settings search keywords', 'vigilante' ) ), | |
| 1416 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Comment Security', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-comments', 'label' => __( 'Honeypot Protection', 'vigilante' ), 'label_en' => 'Honeypot Protection', 'keywords' => _x( 'honeypot protection spam bots trap', 'settings search keywords', 'vigilante' ) ), | |
| 1417 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-headers', 'label' => __( 'Remove Generator', 'vigilante' ), 'label_en' => 'Remove Generator', 'keywords' => _x( 'remove generator version meta', 'settings search keywords', 'vigilante' ) ), | |
| 1418 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-headers', 'label' => __( 'Remove RSD Link', 'vigilante' ), 'label_en' => 'Remove RSD Link', 'keywords' => _x( 'remove rsd link discovery', 'settings search keywords', 'vigilante' ) ), | |
| 1419 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-headers', 'label' => __( 'Remove WLW Manifest', 'vigilante' ), 'label_en' => 'Remove WLW Manifest', 'keywords' => _x( 'remove wlw manifest wlwmanifest', 'settings search keywords', 'vigilante' ) ), | |
| 1420 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-headers', 'label' => __( 'Remove Shortlink', 'vigilante' ), 'label_en' => 'Remove Shortlink', 'keywords' => _x( 'remove shortlink link', 'settings search keywords', 'vigilante' ) ), | |
| 1421 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'Header Cleanup', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-headers', 'label' => __( 'Remove REST API Link', 'vigilante' ), 'label_en' => 'Remove REST API Link', 'keywords' => _x( 'remove rest api link json endpoint', 'settings search keywords', 'vigilante' ) ), | |
| 1422 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'RSS Feed Settings', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-rss', 'label' => __( 'Disable Feeds', 'vigilante' ), 'label_en' => 'Disable Feeds', 'keywords' => _x( 'disable feeds feed rss atom syndication', 'settings search keywords', 'vigilante' ) ), | |
| 1423 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'RSS Feed Settings', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-rss', 'label' => __( 'Disable If No Content', 'vigilante' ), 'label_en' => 'Disable If No Content', 'keywords' => _x( 'disable if no content', 'settings search keywords', 'vigilante' ) ), | |
| 1424 | + array( 'tab' => 'wp-hardening', 'tab_label' => __( 'WP Hardening', 'vigilante' ), 'section' => __( 'RSS Feed Settings', 'vigilante' ), 'anchor' => 'vigilante-section-hardening-rss', 'label' => __( 'Remove Feed Version', 'vigilante' ), 'label_en' => 'Remove Feed Version', 'keywords' => _x( 'remove feed version feeds rss atom', 'settings search keywords', 'vigilante' ) ), | |
| 1425 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Audit Alerts', 'vigilante' ), 'anchor' => 'vigilante-section-audit-alerts', 'label' => __( 'Alert on severity', 'vigilante' ), 'label_en' => 'Alert on severity', 'keywords' => _x( 'alert on severity alerts notification warning level critical', 'settings search keywords', 'vigilante' ) ), | |
| 1426 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Audit Alerts', 'vigilante' ), 'anchor' => 'vigilante-section-audit-alerts', 'label' => __( 'Time window', 'vigilante' ), 'label_en' => 'Time window', 'keywords' => _x( 'time window', 'settings search keywords', 'vigilante' ) ), | |
| 1427 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Audit Alerts', 'vigilante' ), 'anchor' => 'vigilante-section-audit-alerts', 'label' => __( 'Thresholds per category', 'vigilante' ), 'label_en' => 'Thresholds per category', 'keywords' => _x( 'thresholds per category threshold limit', 'settings search keywords', 'vigilante' ) ), | |
| 1428 | + array( 'tab' => 'activity-log', 'tab_label' => __( 'Security Audit', 'vigilante' ), 'section' => __( 'Audit Alerts', 'vigilante' ), 'anchor' => 'vigilante-section-audit-alerts', 'label' => __( 'Recipients', 'vigilante' ), 'label_en' => 'Recipients', 'keywords' => _x( 'recipients email recipient', 'settings search keywords', 'vigilante' ) ), | |
| 1429 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Automatic Scans', 'vigilante' ), 'label_en' => 'Automatic Scans', 'keywords' => _x( 'automatic scans scan scanning', 'settings search keywords', 'vigilante' ) ), | |
| 1430 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Scan Frequency', 'vigilante' ), 'label_en' => 'Scan Frequency', 'keywords' => _x( 'scan frequency scans scanning check', 'settings search keywords', 'vigilante' ) ), | |
| 1431 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Email Notifications', 'vigilante' ), 'label_en' => 'Email Notifications', 'keywords' => _x( 'email notifications mail notification notify', 'settings search keywords', 'vigilante' ) ), | |
| 1432 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Test email', 'vigilante' ), 'label_en' => 'Test email', 'keywords' => _x( 'test email mail notification notify', 'settings search keywords', 'vigilante' ) ), | |
| 1433 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Scan Scope', 'vigilante' ), 'label_en' => 'Scan Scope', 'keywords' => _x( 'scan scope scans scanning check', 'settings search keywords', 'vigilante' ) ), | |
| 1434 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Excluded Paths', 'vigilante' ), 'label_en' => 'Excluded Paths', 'keywords' => _x( 'excluded paths exclude exclusions ignore ignored path folder folders', 'settings search keywords', 'vigilante' ) ), | |
| 1435 | + array( 'tab' => 'file-integrity', 'tab_label' => __( 'File Integrity', 'vigilante' ), 'section' => __( 'File Integrity Monitoring', 'vigilante' ), 'anchor' => 'vigilante-section-fi-monitoring', 'label' => __( 'Excluded Extensions', 'vigilante' ), 'label_en' => 'Excluded Extensions', 'keywords' => _x( 'excluded extensions exclude exclusions ignore ignored extension filetype', 'settings search keywords', 'vigilante' ) ), | |
| 1196 | 1436 | ); |
| 1197 | 1437 | } |
| 1198 | 1438 | |
| 1199 | 1439 | /** |
| @@ -1228,8 +1468,11 @@ | ||
| 1228 | 1468 | 'currentUserId' => get_current_user_id(), |
| 1229 | 1469 | 'logoutUrl' => wp_logout_url( wp_login_url() ), |
| 1230 | 1470 | 'adminUrl' => admin_url( 'admin.php?page=vigilante' ), |
| 1231 | 1471 | 'searchIndex' => $this->get_search_index(), |
| 1472 | + // The scan repaints this table from JavaScript, so the same gate | |
| 1473 | + // has to travel with it or half the screen keeps the dead button. | |
| 1474 | + 'approvalLocked' => $this->critical_approval_locked(), | |
| 1232 | 1475 | 'underAttack' => array( |
| 1233 | 1476 | 'active' => ( new Vigilante_Under_Attack( $this->settings, $this->activity_log ) )->is_active(), |
| 1234 | 1477 | 'remaining' => ( new Vigilante_Under_Attack( $this->settings, $this->activity_log ) )->get_remaining_time(), |
| 1235 | 1478 | ), |
| @@ -1296,13 +1539,17 @@ | ||
| 1296 | 1539 | 'criticalConfigTitle' => __( 'Critical config files modified', 'vigilante' ), |
| 1297 | 1540 | 'criticalConfigDesc' => __( 'These files are common targets for code injection. Review the changes and approve if they are legitimate. Vigilant\'s own blocks are excluded from this check.', 'vigilante' ), |
| 1298 | 1541 | 'approve' => __( 'Approve', 'vigilante' ), |
| 1299 | 1542 | 'approving' => __( 'Approving...', 'vigilante' ), |
| 1543 | + 'approvalLockedNotice' => $this->critical_approval_notice(), | |
| 1300 | 1544 | 'criticalApproved' => __( 'Change approved. Next scan will use the current state as baseline.', 'vigilante' ), |
| 1301 | 1545 | 'reviewChanges' => __( 'Review changes', 'vigilante' ), |
| 1302 | 1546 | 'hideChanges' => __( 'Hide changes', 'vigilante' ), |
| 1303 | 1547 | 'changes' => __( 'Changes', 'vigilante' ), |
| 1304 | 1548 | 'diffUnavailable' => __( 'Diff not available for this file (baseline was created before diff tracking was added). Approve to enable diff on future changes.', 'vigilante' ), |
| 1549 | + 'diffNetwork' => __( 'This file belongs to the whole network, so its line changes are only shown to network administrators, on the main site.', 'vigilante' ), | |
| 1550 | + 'diffRescan' => __( 'Run a new scan to see the line changes of this file.', 'vigilante' ), | |
| 1551 | + 'diffRedaction' => __( 'The line changes of this file are not shown because a value in it could not be hidden safely. The change itself is still detected.', 'vigilante' ), | |
| 1305 | 1552 | 'diffEmpty' => __( 'No line-level changes detected (may be whitespace or reordering).', 'vigilante' ), |
| 1306 | 1553 | 'diffLines' => __( 'lines', 'vigilante' ), |
| 1307 | 1554 | // Under Attack mode strings |
| 1308 | 1555 | 'underAttackConfirmActivate' => __( 'Activate Under Attack mode? All visitors will see a verification page for the next 4 hours.', 'vigilante' ), |
| @@ -1358,8 +1605,9 @@ | ||
| 1358 | 1605 | 'logType' => __( 'Type', 'vigilante' ), |
| 1359 | 1606 | 'logAction' => __( 'Action', 'vigilante' ), |
| 1360 | 1607 | 'logSeverity' => __( 'Severity', 'vigilante' ), |
| 1361 | 1608 | 'logMessage' => __( 'Message', 'vigilante' ), |
| 1609 | + 'logRequestUri' => __( 'Address', 'vigilante' ), | |
| 1362 | 1610 | 'logClient' => __( 'Client', 'vigilante' ), |
| 1363 | 1611 | 'logUser' => __( 'User', 'vigilante' ), |
| 1364 | 1612 | 'logIpAddress' => __( 'IP Address', 'vigilante' ), |
| 1365 | 1613 | 'logUserAgent' => __( 'User Agent', 'vigilante' ), |
| @@ -1394,8 +1642,10 @@ | ||
| 1394 | 1642 | /* translators: 1: selected count, 2: human-readable size */ |
| 1395 | 1643 | 'dbTablesSelected' => __( '%1$d tables selected (%2$s)', 'vigilante' ), |
| 1396 | 1644 | // Settings search strings |
| 1397 | 1645 | 'searchNoResults' => __( 'No matching settings found.', 'vigilante' ), |
| 1646 | + /* translators: %d: number of results that did not fit in the list. */ | |
| 1647 | + 'searchMoreResults' => __( '%d more results. Refine the search to see them.', 'vigilante' ), | |
| 1398 | 1648 | 'searchInTab' => __( 'in', 'vigilante' ), |
| 1399 | 1649 | // Modules string |
| 1400 | 1650 | /* translators: 1: enabled count, 2: total count */ |
| 1401 | 1651 | 'modulesEnabled' => __( '%1$d / %2$d modules enabled', 'vigilante' ), |
| @@ -1562,8 +1812,21 @@ | ||
| 1562 | 1812 | </p> |
| 1563 | 1813 | <p> |
| 1564 | 1814 | <em><?php esc_html_e( 'Vigilant has applied the Maximum preset plus extra hardening on top of your previous configuration. Any changes you make to Vigilant settings while this mode is active will be reverted when it ends.', 'vigilante' ); ?></em> |
| 1565 | 1815 | </p> |
| 1816 | + <?php | |
| 1817 | + // The cache-bypass rules could not be written (a host where | |
| 1818 | + // WordPress cannot write files by itself, a held lock, a | |
| 1819 | + // failed read-back): show them, so they can be added by hand. | |
| 1820 | + $ua_instance = new Vigilante_Under_Attack( $this->settings, $this->activity_log ); | |
| 1821 | + if ( $ua_instance->cache_rules_missing() ) : | |
| 1822 | + ?> | |
| 1823 | + <p> | |
| 1824 | + <strong><?php esc_html_e( 'The cache-bypass rules could not be written to your .htaccess.', 'vigilante' ); ?></strong> | |
| 1825 | + <?php esc_html_e( 'Without them a page cache may keep serving stored pages during the attack. Add this block at the top of the .htaccess in your site root (the activity log records why it was not written):', 'vigilante' ); ?> | |
| 1826 | + </p> | |
| 1827 | + <textarea readonly rows="9" class="large-text code" onclick="this.select();"><?php echo esc_textarea( Vigilante_Under_Attack::get_cache_bypass_block() ); ?></textarea> | |
| 1828 | + <?php endif; ?> | |
| 1566 | 1829 | </div> |
| 1567 | 1830 | <?php |
| 1568 | 1831 | } |
| 1569 | 1832 | } |
| @@ -1665,9 +1928,9 @@ | ||
| 1665 | 1928 | </h1> |
| 1666 | 1929 | <div class="vigilante-search-wrapper"> |
| 1667 | 1930 | <div class="vigilante-search-input-wrap"> |
| 1668 | 1931 | <span class="vigilante-search-icon dashicons dashicons-search" aria-hidden="true"></span> |
| 1669 | - <input type="search" id="vigilante-settings-search" class="vigilante-settings-search" placeholder="<?php esc_attr_e( 'Search settings…', 'vigilante' ); ?>" autocomplete="off"> | |
| 1932 | + <input type="search" id="vigilante-settings-search" class="vigilante-settings-search" aria-label="<?php esc_attr_e( 'Search settings', 'vigilante' ); ?>" placeholder="<?php esc_attr_e( 'Search settings…', 'vigilante' ); ?>" autocomplete="off"> | |
| 1670 | 1933 | <span class="vigilante-search-shortcut" aria-hidden="true">/</span> |
| 1671 | 1934 | </div> |
| 1672 | 1935 | <div id="vigilante-settings-search-results" class="vigilante-search-results" hidden role="listbox"></div> |
| 1673 | 1936 | </div> |
| @@ -1749,8 +2012,204 @@ | ||
| 1749 | 2012 | <?php |
| 1750 | 2013 | } |
| 1751 | 2014 | |
| 1752 | 2015 | /** |
| 2016 | + * Values to display for a section that this site does not control | |
| 2017 | + * | |
| 2018 | + * On a subsite the stored options are its own copy, which nothing acts on: | |
| 2019 | + * wp-config.php and .htaccess are written from the main site. Painting the | |
| 2020 | + * local copy describes a configuration that is not running, so a subsite | |
| 2021 | + * admin sees a box ticked here and the constant absent from the file, or the | |
| 2022 | + * other way round. Read the main site's values instead, which are the ones in | |
| 2023 | + * force, and fall back to the local ones if they cannot be read. | |
| 2024 | + * | |
| 2025 | + * @since 2.9.8 | |
| 2026 | + * | |
| 2027 | + * @param string $section Settings section. | |
| 2028 | + * @return array | |
| 2029 | + */ | |
| 2030 | + private function get_section_for_display( $section ) { | |
| 2031 | + $local = $this->settings->get_section( $section ); | |
| 2032 | + | |
| 2033 | + if ( ! $this->shared_files_locked() ) { | |
| 2034 | + return $local; | |
| 2035 | + } | |
| 2036 | + | |
| 2037 | + // shared_files_locked() is only true on multisite, where get_blog_option() exists. | |
| 2038 | + $main = get_blog_option( get_main_site_id(), Vigilante_Settings::OPTION_NAME, array() ); | |
| 2039 | + | |
| 2040 | + if ( ! is_array( $main ) || empty( $main[ $section ] ) || ! is_array( $main[ $section ] ) ) { | |
| 2041 | + return $local; | |
| 2042 | + } | |
| 2043 | + | |
| 2044 | + return wp_parse_args( $main[ $section ], $local ); | |
| 2045 | + } | |
| 2046 | + | |
| 2047 | + /** | |
| 2048 | + * Whether the sections that write wp-config.php and .htaccess are read-only here | |
| 2049 | + * | |
| 2050 | + * True on a network when this is not the main site, or the user is not a | |
| 2051 | + * network administrator. See Vigilante_Settings::can_write_shared_files(). | |
| 2052 | + * | |
| 2053 | + * @since 2.9.8 | |
| 2054 | + * | |
| 2055 | + * @return bool | |
| 2056 | + */ | |
| 2057 | + private function shared_files_locked() { | |
| 2058 | + return ! Vigilante_Settings::can_write_shared_files(); | |
| 2059 | + } | |
| 2060 | + | |
| 2061 | + /** | |
| 2062 | + * Whether this is the main site and the user cannot change what it builds the shared files from | |
| 2063 | + * | |
| 2064 | + * See Vigilante_Settings::get_main_site_file_settings(). On a subsite those | |
| 2065 | + * settings only act on that site, so they are never locked there. | |
| 2066 | + * | |
| 2067 | + * @since 2.11.6 | |
| 2068 | + * | |
| 2069 | + * @return bool | |
| 2070 | + */ | |
| 2071 | + private function main_site_files_locked() { | |
| 2072 | + return $this->shared_files_locked() && Vigilante_Settings::owns_shared_files(); | |
| 2073 | + } | |
| 2074 | + | |
| 2075 | + /** | |
| 2076 | + * Sentence added to a bulk change when some settings were left as they were | |
| 2077 | + * | |
| 2078 | + * Importing a file, applying a preset and restoring the defaults touch every | |
| 2079 | + * section at once, so the user is told that the shared file settings did | |
| 2080 | + * not move. | |
| 2081 | + * | |
| 2082 | + * @since 2.11.6 | |
| 2083 | + * | |
| 2084 | + * @return string Empty when the user can change every setting. | |
| 2085 | + */ | |
| 2086 | + private function locked_file_settings_message() { | |
| 2087 | + if ( ! Vigilante_Settings::get_locked_file_settings() ) { | |
| 2088 | + return ''; | |
| 2089 | + } | |
| 2090 | + | |
| 2091 | + return ' ' . __( 'The settings that end up in wp-config.php or .htaccess were left as they were.', 'vigilante' ) . ' ' . Vigilante_Settings::get_shared_files_notice(); | |
| 2092 | + } | |
| 2093 | + | |
| 2094 | + /** | |
| 2095 | + * Print the shared-files notice for a section that cannot be edited here | |
| 2096 | + * | |
| 2097 | + * @since 2.9.8 | |
| 2098 | + */ | |
| 2099 | + private function render_shared_files_notice() { | |
| 2100 | + if ( ! $this->shared_files_locked() ) { | |
| 2101 | + return; | |
| 2102 | + } | |
| 2103 | + ?> | |
| 2104 | + <div class="notice notice-info inline" style="margin:10px 0 16px;padding:8px 12px;"> | |
| 2105 | + <p style="margin:0;"><?php echo esc_html( Vigilante_Settings::get_shared_files_notice() ); ?></p> | |
| 2106 | + </div> | |
| 2107 | + <?php | |
| 2108 | + } | |
| 2109 | + | |
| 2110 | + /** | |
| 2111 | + * Acting on another user's account needs permission over that user | |
| 2112 | + * | |
| 2113 | + * Since 2.10.3 the handlers behind these tools ask for edit_user over the | |
| 2114 | + * target, which is the rule WordPress itself applies. On a network the core | |
| 2115 | + * grants edit_user only to network administrators, so for anybody else these | |
| 2116 | + * controls do nothing. Better to say so than to paint a button that silently | |
| 2117 | + * skips every user. | |
| 2118 | + * | |
| 2119 | + * @since 2.10.4 | |
| 2120 | + * @return bool | |
| 2121 | + */ | |
| 2122 | + private function forwarded_chain_readings() { | |
| 2123 | + // Shown, not decided on: the firewall resolves the address elsewhere. | |
| 2124 | + $chain = Vigilante_IP_Utils::trusted_forwarded_for(); | |
| 2125 | + | |
| 2126 | + if ( '' === $chain ) { | |
| 2127 | + return array(); | |
| 2128 | + } | |
| 2129 | + | |
| 2130 | + $public = array(); | |
| 2131 | + | |
| 2132 | + foreach ( explode( ',', $chain ) as $entry ) { | |
| 2133 | + $address = Vigilante_IP_Utils::unmap_ipv4( trim( $entry ) ); | |
| 2134 | + | |
| 2135 | + if ( filter_var( $address, FILTER_VALIDATE_IP ) && ! Vigilante_IP_Utils::is_own_network( $address ) ) { | |
| 2136 | + $public[] = $address; | |
| 2137 | + } | |
| 2138 | + } | |
| 2139 | + | |
| 2140 | + if ( count( $public ) < 2 ) { | |
| 2141 | + return array(); | |
| 2142 | + } | |
| 2143 | + | |
| 2144 | + return array( | |
| 2145 | + 'now' => Vigilante_IP_Utils::client_from_chain( $chain ), | |
| 2146 | + 'before' => $public[0], | |
| 2147 | + ); | |
| 2148 | + } | |
| 2149 | + | |
| 2150 | + /** | |
| 2151 | + * Whether the user tools of this screen are out of reach for this user | |
| 2152 | + * | |
| 2153 | + * @return bool | |
| 2154 | + */ | |
| 2155 | + private function user_actions_locked() { | |
| 2156 | + // On a single site edit_user maps to edit_users, which a custom role with | |
| 2157 | + // manage_options may lack: since 2.11.8 approving and rejecting a pending | |
| 2158 | + // registration ask for it, so the buttons have to say so there too. | |
| 2159 | + return is_multisite() ? ! current_user_can( 'manage_network_users' ) : ! current_user_can( 'edit_users' ); | |
| 2160 | + } | |
| 2161 | + | |
| 2162 | + /** | |
| 2163 | + * Print the notice for user tools that cannot be used from this site | |
| 2164 | + * | |
| 2165 | + * @since 2.10.4 | |
| 2166 | + */ | |
| 2167 | + private function render_user_actions_notice() { | |
| 2168 | + if ( ! $this->user_actions_locked() ) { | |
| 2169 | + return; | |
| 2170 | + } | |
| 2171 | + ?> | |
| 2172 | + <div class="notice notice-info inline" style="margin:10px 0 16px;padding:8px 12px;"> | |
| 2173 | + <?php if ( is_multisite() ) : ?> | |
| 2174 | + <p style="margin:0;"><?php esc_html_e( 'These tools act on user accounts, which on a network belong to the whole network rather than to one site. WordPress reserves that to network administrators, so they are managed from the network admin.', 'vigilante' ); ?></p> | |
| 2175 | + <?php else : ?> | |
| 2176 | + <p style="margin:0;"><?php esc_html_e( 'These tools act on other user accounts, and your role cannot edit users, so they are not available to you.', 'vigilante' ); ?></p> | |
| 2177 | + <?php endif; ?> | |
| 2178 | + </div> | |
| 2179 | + <?php | |
| 2180 | + } | |
| 2181 | + | |
| 2182 | + /** | |
| 2183 | + * Approving a change to the shared config files needs the network | |
| 2184 | + * | |
| 2185 | + * Since 2.11.3 the handler behind the Approve button asks for | |
| 2186 | + * manage_network_options, because the two files it approves, wp-config.php | |
| 2187 | + * and the root .htaccess, belong to the installation, and so does the | |
| 2188 | + * record of them. The button, though, went on being painted for everybody, | |
| 2189 | + * so the administrator of a subsite saw the warning, saw the button, | |
| 2190 | + * pressed it and got "Permission denied" with no explanation. That is | |
| 2191 | + * exactly what user_actions_locked() above exists to avoid, one release | |
| 2192 | + * later and one screen over. Flagged by @calzbert. | |
| 2193 | + * | |
| 2194 | + * @since 2.11.4 | |
| 2195 | + * @return bool | |
| 2196 | + */ | |
| 2197 | + private function critical_approval_locked() { | |
| 2198 | + return is_multisite() && ! current_user_can( 'manage_network_options' ); | |
| 2199 | + } | |
| 2200 | + | |
| 2201 | + /** | |
| 2202 | + * The line that replaces the Approve button where it cannot be used | |
| 2203 | + * | |
| 2204 | + * @since 2.11.4 | |
| 2205 | + * @return string | |
| 2206 | + */ | |
| 2207 | + private function critical_approval_notice() { | |
| 2208 | + return __( 'These files belong to the whole network rather than to this site, so a change to them is approved from the network admin.', 'vigilante' ); | |
| 2209 | + } | |
| 2210 | + | |
| 2211 | + /** | |
| 1753 | 2212 | * Check if module is disabled and render warning |
| 1754 | 2213 | * |
| 1755 | 2214 | * @param string $module_key Module key. |
| 1756 | 2215 | * @return bool True if disabled. |
| @@ -2294,14 +2753,15 @@ | ||
| 2294 | 2753 | |
| 2295 | 2754 | <?php $this->render_analyzer_widget( $analyzer_last_scan, $analyzer_history, $analyzer_categories_def, $analyzer_settings ); ?> |
| 2296 | 2755 | |
| 2297 | 2756 | <div class="vigilante-modules-grid"> |
| 2298 | - <h2><?php esc_html_e( 'Security Modules', 'vigilante' ); ?></h2> | |
| 2757 | + <h2 id="vigilante-section-dashboard-modules"><?php esc_html_e( 'Security Modules', 'vigilante' ); ?></h2> | |
| 2299 | 2758 | <p class="description"><?php esc_html_e( 'Enable or disable security modules. Each module controls a tab with detailed settings.', 'vigilante' ); ?></p> |
| 2300 | 2759 | <div class="vigilante-modules-list"> |
| 2301 | 2760 | <?php foreach ( $options['modules'] as $module => $enabled ) : |
| 2302 | 2761 | $label = isset( $module_labels[ $module ] ) ? $module_labels[ $module ] : ucwords( str_replace( '_', ' ', $module ) ); |
| 2303 | 2762 | $description = isset( $module_descriptions[ $module ] ) ? $module_descriptions[ $module ] : ''; |
| 2763 | + $vg_module_locked = $this->main_site_files_locked() && in_array( $module, Vigilante_Settings::get_main_site_file_settings()['modules'], true ); | |
| 2304 | 2764 | ?> |
| 2305 | 2765 | <div class="vigilante-module-item <?php echo $enabled ? 'enabled' : 'disabled'; ?>"> |
| 2306 | 2766 | <div class="vigilante-module-header"> |
| 2307 | 2767 | <span class="vigilante-module-status"></span> |
| @@ -2314,8 +2774,9 @@ | ||
| 2314 | 2774 | <input type="checkbox" |
| 2315 | 2775 | name="modules[<?php echo esc_attr( $module ); ?>]" |
| 2316 | 2776 | value="1" |
| 2317 | 2777 | <?php checked( $enabled ); ?> |
| 2778 | + <?php disabled( $vg_module_locked ); ?> | |
| 2318 | 2779 | aria-label="<?php echo esc_attr( $toggle_label ); ?>" |
| 2319 | 2780 | data-module="<?php echo esc_attr( $module ); ?>"> |
| 2320 | 2781 | <span class="vigilante-toggle-slider"></span> |
| 2321 | 2782 | </label> |
| @@ -2322,8 +2783,11 @@ | ||
| 2322 | 2783 | </div> |
| 2323 | 2784 | <?php if ( $description ) : ?> |
| 2324 | 2785 | <p class="vigilante-module-desc"><?php echo esc_html( $description ); ?></p> |
| 2325 | 2786 | <?php endif; ?> |
| 2787 | + <?php if ( $vg_module_locked ) : ?> | |
| 2788 | + <p class="vigilante-module-desc"><?php esc_html_e( 'On the main site of a network this module also writes files every site shares, so only a network administrator can switch it.', 'vigilante' ); ?></p> | |
| 2789 | + <?php endif; ?> | |
| 2326 | 2790 | </div> |
| 2327 | 2791 | <?php endforeach; ?> |
| 2328 | 2792 | </div> |
| 2329 | 2793 | </div> |
| @@ -2355,9 +2819,9 @@ | ||
| 2355 | 2819 | $ua_remaining_hours = floor( $ua_remaining / 3600 ); |
| 2356 | 2820 | $ua_remaining_mins = floor( ( $ua_remaining % 3600 ) / 60 ); |
| 2357 | 2821 | ?> |
| 2358 | 2822 | <div class="vigilante-preset-card vigilante-under-attack-card <?php echo $ua_active ? 'vigilante-under-attack-active' : ''; ?>"> |
| 2359 | - <h3> | |
| 2823 | + <h3 id="vigilante-section-dashboard-under-attack"> | |
| 2360 | 2824 | <span class="dashicons dashicons-shield"></span> |
| 2361 | 2825 | <?php esc_html_e( 'Under Attack', 'vigilante' ); ?> |
| 2362 | 2826 | </h3> |
| 2363 | 2827 | <p><?php esc_html_e( 'Emergency mode. JavaScript challenge for all visitors, aggressive rate limiting, and restricted access. Auto-deactivates after 4 hours.', 'vigilante' ); ?></p> |
| @@ -2435,11 +2899,11 @@ | ||
| 2435 | 2899 | </label> |
| 2436 | 2900 | </td> |
| 2437 | 2901 | </tr> |
| 2438 | 2902 | <tr> |
| 2439 | - <th scope="row"><?php esc_html_e( 'Additional Recipients', 'vigilante' ); ?></th> | |
| 2903 | + <th scope="row"><label for="vigilante-f-email-additional-recipients"><?php esc_html_e( 'Additional Recipients', 'vigilante' ); ?></label></th> | |
| 2440 | 2904 | <td> |
| 2441 | - <textarea name="email[additional_recipients]" rows="3" class="large-text code" placeholder="maintenance@example.com security@example.com"><?php echo esc_textarea( $additional ); ?></textarea> | |
| 2905 | + <textarea id="vigilante-f-email-additional-recipients" name="email[additional_recipients]" rows="3" class="large-text code" placeholder="maintenance@example.com security@example.com"><?php echo esc_textarea( $additional ); ?></textarea> | |
| 2442 | 2906 | <p class="description"><?php esc_html_e( 'One email per line.', 'vigilante' ); ?></p> |
| 2443 | 2907 | </td> |
| 2444 | 2908 | </tr> |
| 2445 | 2909 | <tr> |
| @@ -2614,9 +3078,9 @@ | ||
| 2614 | 3078 | |
| 2615 | 3079 | <div class="vigilante-tool-card"> |
| 2616 | 3080 | <h3><?php esc_html_e( 'Import Settings', 'vigilante' ); ?></h3> |
| 2617 | 3081 | <p><?php esc_html_e( 'Import settings from a previously exported JSON file.', 'vigilante' ); ?></p> |
| 2618 | - <input type="file" id="vigilante-import-file" accept=".json" style="display: none;"> | |
| 3082 | + <input type="file" id="vigilante-import-file" aria-label="<?php esc_attr_e( 'Configuration file to import', 'vigilante' ); ?>" accept=".json" style="display: none;"> | |
| 2619 | 3083 | <button type="button" class="button vigilante-import-settings"> |
| 2620 | 3084 | <?php esc_html_e( 'Import Settings', 'vigilante' ); ?> |
| 2621 | 3085 | </button> |
| 2622 | 3086 | </div> |
| @@ -2622,9 +3086,9 @@ | ||
| 2622 | 3086 | </div> |
| 2623 | 3087 | |
| 2624 | 3088 | <div class="vigilante-tool-card"> |
| 2625 | 3089 | <h3><?php esc_html_e( 'Reset to Defaults', 'vigilante' ); ?></h3> |
| 2626 | - <p><?php esc_html_e( 'Reset all the Vigilant security settings to default values.', 'vigilante' ); ?></p> | |
| 3090 | + <p><?php esc_html_e( 'Reset all the Vigilant security settings to default values. Your IP lists, custom login address, two-factor setup, scan exclusions and extra alert recipients are kept.', 'vigilante' ); ?></p> | |
| 2627 | 3091 | <button type="button" class="button vigilante-reset-settings" style="color: #a00;"> |
| 2628 | 3092 | <?php esc_html_e( 'Reset All Settings', 'vigilante' ); ?> |
| 2629 | 3093 | </button> |
| 2630 | 3094 | </div> |
| @@ -2631,13 +3095,19 @@ | ||
| 2631 | 3095 | |
| 2632 | 3096 | <div class="vigilante-tool-card"> |
| 2633 | 3097 | <h3><?php esc_html_e( 'Download Config Backup', 'vigilante' ); ?></h3> |
| 2634 | 3098 | <p><?php esc_html_e( 'Download a ZIP backup of your wp-config.php and .htaccess (plus robots.txt if present) before making security changes. The archive is built on the fly and sent to your browser, so nothing is left on the server.', 'vigilante' ); ?></p> |
| 3099 | + <?php if ( $this->shared_files_locked() ) : ?> | |
| 3100 | + <p class="description"><?php esc_html_e( 'Both files belong to the whole network, and wp-config.php carries the database credentials and the authentication salts of every site. The copy is taken from the main site.', 'vigilante' ); ?></p> | |
| 3101 | + <?php else : ?> | |
| 2635 | 3102 | <button type="button" class="button vigilante-create-backup"> |
| 2636 | 3103 | <?php esc_html_e( 'Download Backup', 'vigilante' ); ?> |
| 2637 | 3104 | </button> |
| 3105 | + <?php endif; ?> | |
| 2638 | 3106 | </div> |
| 2639 | 3107 | |
| 3108 | + <?php if ( ! $this->shared_files_locked() ) : ?> | |
| 3109 | + | |
| 2640 | 3110 | <div class="vigilante-tool-card vigilante-tool-card-wide"> |
| 2641 | 3111 | <h3><?php esc_html_e( 'Database Backup', 'vigilante' ); ?></h3> |
| 2642 | 3112 | <p><?php esc_html_e( 'Download a backup of your database as a ZIP file. Select which tables to include.', 'vigilante' ); ?></p> |
| 2643 | 3113 | <button type="button" class="button vigilante-db-backup-toggle"> |
| @@ -2676,8 +3146,15 @@ | ||
| 2676 | 3146 | </div> |
| 2677 | 3147 | </div> |
| 2678 | 3148 | </div> |
| 2679 | 3149 | </div> |
| 3150 | + <?php else : ?> | |
| 3151 | + <div class="vigilante-tool-card vigilante-tool-card-wide"> | |
| 3152 | + <h3><?php esc_html_e( 'Database Backup', 'vigilante' ); ?></h3> | |
| 3153 | + <p><?php esc_html_e( 'Download a backup of your database as a ZIP file. Select which tables to include.', 'vigilante' ); ?></p> | |
| 3154 | + <p class="description"><?php esc_html_e( 'The database is shared by the whole network, so a backup taken here would carry every other site and all of the network users. The copy is taken from the main site.', 'vigilante' ); ?></p> | |
| 3155 | + </div> | |
| 3156 | + <?php endif; ?> | |
| 2680 | 3157 | </div> |
| 2681 | 3158 | <?php |
| 2682 | 3159 | } |
| 2683 | 3160 | |
| @@ -2700,14 +3177,21 @@ | ||
| 2700 | 3177 | <?php esc_html_e( 'Full page caching systems that serve cached pages before PHP executes (Varnish, LiteSpeed Cache, NGINX FastCGI Cache, Cloudflare APO) may bypass PHP-level firewall rules for cached requests. The .htaccess rules will still apply on Apache/LiteSpeed servers.', 'vigilante' ); ?> |
| 2701 | 3178 | </p> |
| 2702 | 3179 | </div> |
| 2703 | 3180 | |
| 3181 | + <?php $vg_main_locked = $this->main_site_files_locked(); ?> | |
| 3182 | + <?php if ( $vg_main_locked ) : ?> | |
| 3183 | + <div class="notice notice-info inline" style="margin:10px 0 16px;padding:8px 12px;"> | |
| 3184 | + <p style="margin:0;"><?php esc_html_e( 'On the main site of a network, blocking bad bots and bad query strings, the visitor IP detection and the two whitelists also build the .htaccess rules every site shares, so only a network administrator can change them.', 'vigilante' ); ?></p> | |
| 3185 | + </div> | |
| 3186 | + <?php endif; ?> | |
| 3187 | + | |
| 2704 | 3188 | <table class="form-table"> |
| 2705 | 3189 | <tr> |
| 2706 | 3190 | <th scope="row"><?php esc_html_e( 'Block Bad Query Strings', 'vigilante' ); ?></th> |
| 2707 | 3191 | <td> |
| 2708 | 3192 | <label> |
| 2709 | - <input type="checkbox" name="firewall[block_bad_query_strings]" value="1" <?php checked( ! empty( $options['block_bad_query_strings'] ) ); ?>> | |
| 3193 | + <input type="checkbox" name="firewall[block_bad_query_strings]" value="1" <?php disabled( $vg_main_locked ); ?> <?php checked( ! empty( $options['block_bad_query_strings'] ) ); ?>> | |
| 2710 | 3194 | <?php esc_html_e( 'Block malicious query string patterns', 'vigilante' ); ?> |
| 2711 | 3195 | </label> |
| 2712 | 3196 | </td> |
| 2713 | 3197 | </tr> |
| @@ -2750,9 +3234,9 @@ | ||
| 2750 | 3234 | <tr> |
| 2751 | 3235 | <th scope="row"><?php esc_html_e( 'Block Bad Bots', 'vigilante' ); ?></th> |
| 2752 | 3236 | <td> |
| 2753 | 3237 | <label> |
| 2754 | - <input type="checkbox" name="firewall[block_bad_bots]" value="1" <?php checked( ! empty( $options['block_bad_bots'] ) ); ?>> | |
| 3238 | + <input type="checkbox" name="firewall[block_bad_bots]" value="1" <?php disabled( $vg_main_locked ); ?> <?php checked( ! empty( $options['block_bad_bots'] ) ); ?>> | |
| 2755 | 3239 | <?php esc_html_e( 'Block known malicious bots and scanners', 'vigilante' ); ?> |
| 2756 | 3240 | </label> |
| 2757 | 3241 | </td> |
| 2758 | 3242 | </tr> |
| @@ -2769,11 +3253,11 @@ | ||
| 2769 | 3253 | </label> |
| 2770 | 3254 | </td> |
| 2771 | 3255 | </tr> |
| 2772 | 3256 | <tr> |
| 2773 | - <th scope="row"><?php esc_html_e( 'Requests per Minute', 'vigilante' ); ?></th> | |
| 3257 | + <th scope="row"><label for="vigilante-f-firewall-rate-limiting-requests-per-minute"><?php esc_html_e( 'Requests per Minute', 'vigilante' ); ?></label></th> | |
| 2774 | 3258 | <td> |
| 2775 | - <input type="number" name="firewall[rate_limiting][requests_per_minute]" value="<?php echo esc_attr( $options['rate_limiting']['requests_per_minute'] ?? 120 ); ?>" min="10" max="500" class="small-text"> | |
| 3259 | + <input id="vigilante-f-firewall-rate-limiting-requests-per-minute" type="number" name="firewall[rate_limiting][requests_per_minute]" value="<?php echo esc_attr( $options['rate_limiting']['requests_per_minute'] ?? 120 ); ?>" min="10" max="500" class="small-text"> | |
| 2776 | 3260 | <p class="description"> |
| 2777 | 3261 | <?php esc_html_e( 'Counts only PHP requests to WordPress (pages, admin-ajax, REST, login) from a single IP, not static assets like images, CSS or JS. 120/min suits most sites; sustained traffic above that from one IP is usually a bot. To allow a legitimate service, whitelist its IP instead of raising the limit.', 'vigilante' ); ?> |
| 2778 | 3262 | </p> |
| 2779 | 3263 | </td> |
| @@ -2778,11 +3262,11 @@ | ||
| 2778 | 3262 | </p> |
| 2779 | 3263 | </td> |
| 2780 | 3264 | </tr> |
| 2781 | 3265 | <tr> |
| 2782 | - <th scope="row"><?php esc_html_e( 'Block Duration (seconds)', 'vigilante' ); ?></th> | |
| 3266 | + <th scope="row"><label for="vigilante-f-firewall-rate-limiting-block-duration"><?php esc_html_e( 'Block Duration (seconds)', 'vigilante' ); ?></label></th> | |
| 2783 | 3267 | <td> |
| 2784 | - <input type="number" name="firewall[rate_limiting][block_duration]" value="<?php echo esc_attr( $options['rate_limiting']['block_duration'] ?? 300 ); ?>" min="60" max="3600" class="small-text"> | |
| 3268 | + <input id="vigilante-f-firewall-rate-limiting-block-duration" type="number" name="firewall[rate_limiting][block_duration]" value="<?php echo esc_attr( $options['rate_limiting']['block_duration'] ?? 300 ); ?>" min="60" max="3600" class="small-text"> | |
| 2785 | 3269 | </td> |
| 2786 | 3270 | </tr> |
| 2787 | 3271 | <tr> |
| 2788 | 3272 | <th scope="row"><?php esc_html_e( 'Progressive Blocking', 'vigilante' ); ?></th> |
| @@ -2805,11 +3289,11 @@ | ||
| 2805 | 3289 | </p> |
| 2806 | 3290 | </td> |
| 2807 | 3291 | </tr> |
| 2808 | 3292 | <tr> |
| 2809 | - <th scope="row"><?php esc_html_e( 'Maximum Block Duration', 'vigilante' ); ?></th> | |
| 3293 | + <th scope="row"><label for="vigilante-f-firewall-rate-limiting-max-block-duration"><?php esc_html_e( 'Maximum Block Duration', 'vigilante' ); ?></label></th> | |
| 2810 | 3294 | <td> |
| 2811 | - <select name="firewall[rate_limiting][max_block_duration]"> | |
| 3295 | + <select id="vigilante-f-firewall-rate-limiting-max-block-duration" name="firewall[rate_limiting][max_block_duration]"> | |
| 2812 | 3296 | <?php |
| 2813 | 3297 | $max_options = array( |
| 2814 | 3298 | 3600 => __( '1 hour', 'vigilante' ), |
| 2815 | 3299 | 21600 => __( '6 hours', 'vigilante' ), |
| @@ -2866,8 +3350,29 @@ | ||
| 2866 | 3350 | </table> |
| 2867 | 3351 | </div> |
| 2868 | 3352 | <?php endif; ?> |
| 2869 | 3353 | |
| 3354 | + <?php | |
| 3355 | + // Since 2.11.8 X-Forwarded-For is read from its end, where the proxy | |
| 3356 | + // writes. The administrator's own request shows whether that end is | |
| 3357 | + // a CDN or a balancer for everybody here. Cross review of 2.11.8. | |
| 3358 | + $xff_readings = $this->forwarded_chain_readings(); | |
| 3359 | + if ( $xff_readings ) : | |
| 3360 | + ?> | |
| 3361 | + <div id="vigilante-xff-chain-notice" class="notice notice-warning inline" style="margin:10px 0 16px;padding:8px 12px;"> | |
| 3362 | + <p style="margin:0;"> | |
| 3363 | + <?php | |
| 3364 | + printf( | |
| 3365 | + /* translators: 1: address Vigilant reads now, 2: address earlier versions read */ | |
| 3366 | + esc_html__( 'Your own request reaches the site with more than one public address in X-Forwarded-For. Vigilant reads the last one, %1$s, which is the one your proxy added; up to version 2.11.7 it read the first one, %2$s, which a visitor can write. If %1$s belongs to a CDN or a load balancer rather than to you, every visitor shares it for rate limiting, login lockouts and the IP lists: choose the header of that CDN in Visitor IP detection, such as CF-Connecting-IP for Cloudflare.', 'vigilante' ), | |
| 3367 | + esc_html( $xff_readings['now'] ), | |
| 3368 | + esc_html( $xff_readings['before'] ) | |
| 3369 | + ); | |
| 3370 | + ?> | |
| 3371 | + </p> | |
| 3372 | + </div> | |
| 3373 | + <?php endif; ?> | |
| 3374 | + | |
| 2870 | 3375 | <h3><?php esc_html_e( 'IP Lists', 'vigilante' ); ?></h3> |
| 2871 | 3376 | <p class="description"> |
| 2872 | 3377 | <?php |
| 2873 | 3378 | printf( |
| @@ -2878,12 +3383,12 @@ | ||
| 2878 | 3383 | ?> |
| 2879 | 3384 | </p> |
| 2880 | 3385 | <table class="form-table"> |
| 2881 | 3386 | <tr> |
| 2882 | - <th scope="row"><?php esc_html_e( 'Visitor IP detection', 'vigilante' ); ?></th> | |
| 3387 | + <th scope="row"><label for="vigilante-f-firewall-trusted-proxy-header"><?php esc_html_e( 'Visitor IP detection', 'vigilante' ); ?></label></th> | |
| 2883 | 3388 | <td> |
| 2884 | 3389 | <?php $proxy_header = $options['trusted_proxy_header'] ?? ''; ?> |
| 2885 | - <select name="firewall[trusted_proxy_header]"> | |
| 3390 | + <select id="vigilante-f-firewall-trusted-proxy-header" name="firewall[trusted_proxy_header]" <?php disabled( $vg_main_locked ); ?>> | |
| 2886 | 3391 | <option value="" <?php selected( $proxy_header, '' ); ?>><?php esc_html_e( 'Direct connection, only REMOTE_ADDR (recommended)', 'vigilante' ); ?></option> |
| 2887 | 3392 | <option value="cf-connecting-ip" <?php selected( $proxy_header, 'cf-connecting-ip' ); ?>><?php esc_html_e( 'Behind Cloudflare (CF-Connecting-IP)', 'vigilante' ); ?></option> |
| 2888 | 3393 | <option value="x-forwarded-for" <?php selected( $proxy_header, 'x-forwarded-for' ); ?>><?php esc_html_e( 'Behind a reverse proxy or load balancer (X-Forwarded-For)', 'vigilante' ); ?></option> |
| 2889 | 3394 | <option value="x-real-ip" <?php selected( $proxy_header, 'x-real-ip' ); ?>><?php esc_html_e( 'Behind an nginx proxy (X-Real-IP)', 'vigilante' ); ?></option> |
| @@ -2893,13 +3398,13 @@ | ||
| 2893 | 3398 | </p> |
| 2894 | 3399 | </td> |
| 2895 | 3400 | </tr> |
| 2896 | 3401 | <tr> |
| 2897 | - <th scope="row"><?php esc_html_e( 'IP Whitelist', 'vigilante' ); ?></th> | |
| 3402 | + <th scope="row"><label for="vigilante-f-firewall-ip-whitelist"><?php esc_html_e( 'IP Whitelist', 'vigilante' ); ?></label></th> | |
| 2898 | 3403 | <td> |
| 2899 | - <textarea name="firewall[ip_whitelist]" rows="4" class="large-text code" placeholder="192.168.1.50 192.168.1.0/24 192.168.1.*"><?php echo esc_textarea( implode( "\n", $options['ip_whitelist'] ?? array() ) ); ?></textarea> | |
| 3404 | + <textarea id="vigilante-f-firewall-ip-whitelist" name="firewall[ip_whitelist]" <?php disabled( $vg_main_locked ); ?> rows="4" class="large-text code" placeholder="192.168.1.50 192.168.1.0/24 192.168.1.*"><?php echo esc_textarea( implode( "\n", $options['ip_whitelist'] ?? array() ) ); ?></textarea> | |
| 2900 | 3405 | <p class="description"> |
| 2901 | - <?php esc_html_e( 'One IP per line. These IPs will bypass firewall checks.', 'vigilante' ); ?> | |
| 3406 | + <?php esc_html_e( 'One IP per line. These IPs bypass the firewall checks, and they also reach wp-admin when the login URL is hidden, so remote managers such as MainWP or ManageWP are not turned away with a 404. The hidden login form itself stays hidden for every IP, this one included.', 'vigilante' ); ?> | |
| 2902 | 3407 | <br> |
| 2903 | 3408 | <?php |
| 2904 | 3409 | printf( |
| 2905 | 3410 | /* translators: 1: opening <code>, 2: closing </code>. Placeholders wrap the IP, CIDR and wildcard examples. */ |
| @@ -2911,11 +3416,11 @@ | ||
| 2911 | 3416 | </p> |
| 2912 | 3417 | </td> |
| 2913 | 3418 | </tr> |
| 2914 | 3419 | <tr> |
| 2915 | - <th scope="row"><?php esc_html_e( 'IP Blacklist', 'vigilante' ); ?></th> | |
| 3420 | + <th scope="row"><label for="vigilante-f-firewall-ip-blacklist"><?php esc_html_e( 'IP Blacklist', 'vigilante' ); ?></label></th> | |
| 2916 | 3421 | <td> |
| 2917 | - <textarea name="firewall[ip_blacklist]" rows="4" class="large-text code" placeholder="203.0.113.42 203.0.113.0/24 203.0.113.*"><?php echo esc_textarea( implode( "\n", $options['ip_blacklist'] ?? array() ) ); ?></textarea> | |
| 3422 | + <textarea id="vigilante-f-firewall-ip-blacklist" name="firewall[ip_blacklist]" rows="4" class="large-text code" placeholder="203.0.113.42 203.0.113.0/24 203.0.113.*"><?php echo esc_textarea( implode( "\n", $options['ip_blacklist'] ?? array() ) ); ?></textarea> | |
| 2918 | 3423 | <p class="description"> |
| 2919 | 3424 | <?php esc_html_e( 'One IP per line. These IPs will be blocked immediately.', 'vigilante' ); ?> |
| 2920 | 3425 | <br> |
| 2921 | 3426 | <?php |
| @@ -2934,18 +3439,18 @@ | ||
| 2934 | 3439 | <h3><?php esc_html_e( 'User-Agent Lists', 'vigilante' ); ?></h3> |
| 2935 | 3440 | <p><?php esc_html_e( 'Partial matching: enter a keyword and any User-Agent containing it will be matched.', 'vigilante' ); ?></p> |
| 2936 | 3441 | <table class="form-table"> |
| 2937 | 3442 | <tr> |
| 2938 | - <th scope="row"><?php esc_html_e( 'User-Agent Whitelist', 'vigilante' ); ?></th> | |
| 3443 | + <th scope="row"><label for="vigilante-f-firewall-ua-whitelist"><?php esc_html_e( 'User-Agent Whitelist', 'vigilante' ); ?></label></th> | |
| 2939 | 3444 | <td> |
| 2940 | - <textarea name="firewall[ua_whitelist]" rows="4" class="large-text code"><?php echo esc_textarea( implode( "\n", $options['ua_whitelist'] ?? array() ) ); ?></textarea> | |
| 3445 | + <textarea id="vigilante-f-firewall-ua-whitelist" name="firewall[ua_whitelist]" <?php disabled( $vg_main_locked ); ?> rows="4" class="large-text code"><?php echo esc_textarea( implode( "\n", $options['ua_whitelist'] ?? array() ) ); ?></textarea> | |
| 2941 | 3446 | <p class="description"><?php esc_html_e( 'One User-Agent per line. These will bypass all firewall checks. Example: ManageWP, MainWP, UptimeRobot.', 'vigilante' ); ?></p> |
| 2942 | 3447 | </td> |
| 2943 | 3448 | </tr> |
| 2944 | 3449 | <tr> |
| 2945 | - <th scope="row"><?php esc_html_e( 'User-Agent Blacklist', 'vigilante' ); ?></th> | |
| 3450 | + <th scope="row"><label for="vigilante-f-firewall-ua-blacklist"><?php esc_html_e( 'User-Agent Blacklist', 'vigilante' ); ?></label></th> | |
| 2946 | 3451 | <td> |
| 2947 | - <textarea name="firewall[ua_blacklist]" rows="4" class="large-text code"><?php echo esc_textarea( implode( "\n", $options['ua_blacklist'] ?? array() ) ); ?></textarea> | |
| 3452 | + <textarea id="vigilante-f-firewall-ua-blacklist" name="firewall[ua_blacklist]" rows="4" class="large-text code"><?php echo esc_textarea( implode( "\n", $options['ua_blacklist'] ?? array() ) ); ?></textarea> | |
| 2948 | 3453 | <p class="description"><?php esc_html_e( 'One User-Agent per line. These will be blocked immediately.', 'vigilante' ); ?></p> |
| 2949 | 3454 | </td> |
| 2950 | 3455 | </tr> |
| 2951 | 3456 | </table> |
| @@ -2950,9 +3455,16 @@ | ||
| 2950 | 3455 | </tr> |
| 2951 | 3456 | </table> |
| 2952 | 3457 | </div> |
| 2953 | 3458 | |
| 2954 | - <div id="vigilante-section-firewall-server" class="vigilante-settings-section"> | |
| 3459 | + <?php | |
| 3460 | + $vg_shared_locked = $this->shared_files_locked(); | |
| 3461 | + // Paint what is actually in force, not this site's unused copy. | |
| 3462 | + $vg_local_options = $options; | |
| 3463 | + $options = $this->get_section_for_display( 'firewall' ); | |
| 3464 | + ?> | |
| 3465 | + <?php $this->render_shared_files_notice(); ?> | |
| 3466 | + <div id="vigilante-section-firewall-server" class="vigilante-settings-section <?php echo $vg_shared_locked ? 'vigilante-form-disabled' : ''; ?>" <?php echo $vg_shared_locked ? 'inert' : ''; ?>> | |
| 2955 | 3467 | <h2> |
| 2956 | 3468 | <?php esc_html_e( 'Server Protection', 'vigilante' ); ?> |
| 2957 | 3469 | <span class="vigilante-method-badge htaccess"><?php esc_html_e( 'HTACCESS', 'vigilante' ); ?></span> |
| 2958 | 3470 | </h2> |
| @@ -3033,8 +3545,9 @@ | ||
| 3033 | 3545 | </td> |
| 3034 | 3546 | </tr> |
| 3035 | 3547 | </table> |
| 3036 | 3548 | </div> |
| 3549 | + <?php $options = $vg_local_options; ?> | |
| 3037 | 3550 | |
| 3038 | 3551 | <p class="submit vigilante-submit-buttons"> |
| 3039 | 3552 | <button type="submit" class="button button-primary vigilante-save-btn" data-original-text="<?php esc_attr_e( 'Save Settings', 'vigilante' ); ?>"> |
| 3040 | 3553 | <?php esc_html_e( 'Save Settings', 'vigilante' ); ?> |
| @@ -3065,18 +3578,18 @@ | ||
| 3065 | 3578 | <p><?php esc_html_e( 'Brute force protection and WordPress login hardening.', 'vigilante' ); ?></p> |
| 3066 | 3579 | |
| 3067 | 3580 | <table class="form-table"> |
| 3068 | 3581 | <tr id="field-max-attempts"> |
| 3069 | - <th scope="row"><?php esc_html_e( 'Max Login Attempts', 'vigilante' ); ?></th> | |
| 3582 | + <th scope="row"><label for="vigilante-f-login-security-max-attempts"><?php esc_html_e( 'Max Login Attempts', 'vigilante' ); ?></label></th> | |
| 3070 | 3583 | <td> |
| 3071 | - <input type="number" name="login_security[max_attempts]" value="<?php echo esc_attr( $options['max_attempts'] ?? 5 ); ?>" min="1" max="20" class="small-text"> | |
| 3584 | + <input id="vigilante-f-login-security-max-attempts" type="number" name="login_security[max_attempts]" value="<?php echo esc_attr( $options['max_attempts'] ?? 5 ); ?>" min="1" max="20" class="small-text"> | |
| 3072 | 3585 | <p class="description"><?php esc_html_e( 'Number of failed attempts before lockout.', 'vigilante' ); ?></p> |
| 3073 | 3586 | </td> |
| 3074 | 3587 | </tr> |
| 3075 | 3588 | <tr> |
| 3076 | - <th scope="row"><?php esc_html_e( 'Lockout Duration', 'vigilante' ); ?></th> | |
| 3589 | + <th scope="row"><label for="vigilante-f-login-security-lockout-duration"><?php esc_html_e( 'Lockout Duration', 'vigilante' ); ?></label></th> | |
| 3077 | 3590 | <td> |
| 3078 | - <input type="number" name="login_security[lockout_duration]" value="<?php echo esc_attr( ( $options['lockout_duration'] ?? 1800 ) / 60 ); ?>" min="1" max="1440" class="small-text"> | |
| 3591 | + <input id="vigilante-f-login-security-lockout-duration" type="number" name="login_security[lockout_duration]" value="<?php echo esc_attr( ( $options['lockout_duration'] ?? 1800 ) / 60 ); ?>" min="1" max="1440" class="small-text"> | |
| 3079 | 3592 | <?php esc_html_e( 'minutes', 'vigilante' ); ?> |
| 3080 | 3593 | </td> |
| 3081 | 3594 | </tr> |
| 3082 | 3595 | <tr> |
| @@ -3096,17 +3609,8 @@ | ||
| 3096 | 3609 | <?php esc_html_e( 'Show generic error message instead of specific errors', 'vigilante' ); ?> |
| 3097 | 3610 | </label> |
| 3098 | 3611 | </td> |
| 3099 | 3612 | </tr> |
| 3100 | - <tr id="field-disable-xmlrpc"> | |
| 3101 | - <th scope="row"><?php esc_html_e( 'Disable XML-RPC', 'vigilante' ); ?></th> | |
| 3102 | - <td> | |
| 3103 | - <label> | |
| 3104 | - <input type="checkbox" name="login_security[disable_xmlrpc]" value="1" <?php checked( ! empty( $options['disable_xmlrpc'] ) ); ?>> | |
| 3105 | - <?php esc_html_e( 'Completely disable XML-RPC functionality', 'vigilante' ); ?> | |
| 3106 | - </label> | |
| 3107 | - </td> | |
| 3108 | - </tr> | |
| 3109 | 3613 | <tr> |
| 3110 | 3614 | <th scope="row"><?php esc_html_e( 'Disable Application Passwords', 'vigilante' ); ?></th> |
| 3111 | 3615 | <td> |
| 3112 | 3616 | <label> |
| @@ -3134,8 +3638,11 @@ | ||
| 3134 | 3638 | </p> |
| 3135 | 3639 | <p class="description"> |
| 3136 | 3640 | <?php esc_html_e( 'Direct access to wp-login.php and wp-admin will return a 404 error for non-logged users.', 'vigilante' ); ?> |
| 3137 | 3641 | </p> |
| 3642 | + <p class="description"> | |
| 3643 | + <?php esc_html_e( 'An IP in the firewall whitelist is still allowed into wp-admin, so remote managers keep working, but it does not get the login form: the hidden URL is the only way in for everyone.', 'vigilante' ); ?> | |
| 3644 | + </p> | |
| 3138 | 3645 | </div> |
| 3139 | 3646 | </td> |
| 3140 | 3647 | </tr> |
| 3141 | 3648 | </table> |
| @@ -3224,9 +3731,9 @@ | ||
| 3224 | 3731 | $two_factor = $options['two_factor'] ?? array(); |
| 3225 | 3732 | $two_factor_enabled = ! empty( $two_factor['enabled'] ); |
| 3226 | 3733 | ?> |
| 3227 | 3734 | <div class="vigilante-settings-section vigilante-lockout-section"> |
| 3228 | - <h2><?php esc_html_e( 'Login Protection Status', 'vigilante' ); ?></h2> | |
| 3735 | + <h2 id="vigilante-section-login-status"><?php esc_html_e( 'Login Protection Status', 'vigilante' ); ?></h2> | |
| 3229 | 3736 | |
| 3230 | 3737 | <table class="form-table"> |
| 3231 | 3738 | <tr> |
| 3232 | 3739 | <th scope="row"><?php esc_html_e( 'Current settings', 'vigilante' ); ?></th> |
| @@ -3386,9 +3893,9 @@ | ||
| 3386 | 3893 | $excluded = $two_factor['excluded_users'] ?? array(); |
| 3387 | 3894 | $method = $two_factor['method'] ?? 'email'; |
| 3388 | 3895 | $grace_days = $two_factor['grace_period_days'] ?? 3; |
| 3389 | 3896 | ?> |
| 3390 | - <h3> | |
| 3897 | + <h3 id="vigilante-section-login-2fa"> | |
| 3391 | 3898 | <?php esc_html_e( 'Two-Factor Authentication (2FA)', 'vigilante' ); ?> |
| 3392 | 3899 | <span class="vigilante-method-badge php"><?php esc_html_e( 'PHP', 'vigilante' ); ?></span> |
| 3393 | 3900 | <span class="vigilante-method-badge database"><?php esc_html_e( 'Database', 'vigilante' ); ?></span> |
| 3394 | 3901 | </h3> |
| @@ -3502,11 +4009,11 @@ | ||
| 3502 | 4009 | </tr> |
| 3503 | 4010 | |
| 3504 | 4011 | <!-- TOTP-specific: Grace period --> |
| 3505 | 4012 | <tr class="vigilante-2fa-totp-only" <?php echo 'totp' !== $method ? 'style="display:none;"' : ''; ?>> |
| 3506 | - <th scope="row"><?php esc_html_e( 'Grace period', 'vigilante' ); ?></th> | |
| 4013 | + <th scope="row"><label for="vigilante-f-login-security-two-factor-grace-period-days"><?php esc_html_e( 'Grace period', 'vigilante' ); ?></label></th> | |
| 3507 | 4014 | <td> |
| 3508 | - <input type="number" | |
| 4015 | + <input id="vigilante-f-login-security-two-factor-grace-period-days" type="number" | |
| 3509 | 4016 | name="login_security[two_factor][grace_period_days]" |
| 3510 | 4017 | value="<?php echo esc_attr( $grace_days ); ?>" |
| 3511 | 4018 | min="0" max="30" class="small-text"> |
| 3512 | 4019 | <?php esc_html_e( 'days', 'vigilante' ); ?> |
| @@ -3515,11 +4022,11 @@ | ||
| 3515 | 4022 | </tr> |
| 3516 | 4023 | |
| 3517 | 4024 | <!-- Email-specific: Sender name --> |
| 3518 | 4025 | <tr class="vigilante-2fa-email-only" <?php echo 'email' !== $method ? 'style="display:none;"' : ''; ?>> |
| 3519 | - <th scope="row"><?php esc_html_e( 'Email sender name', 'vigilante' ); ?></th> | |
| 4026 | + <th scope="row"><label for="vigilante-f-login-security-two-factor-email-from-name"><?php esc_html_e( 'Email sender name', 'vigilante' ); ?></label></th> | |
| 3520 | 4027 | <td> |
| 3521 | - <input type="text" | |
| 4028 | + <input id="vigilante-f-login-security-two-factor-email-from-name" type="text" | |
| 3522 | 4029 | name="login_security[two_factor][email_from_name]" |
| 3523 | 4030 | value="<?php echo esc_attr( $two_factor['email_from_name'] ?? '' ); ?>" |
| 3524 | 4031 | class="regular-text vigilante-2fa-email-from" |
| 3525 | 4032 | placeholder="<?php echo esc_attr( get_bloginfo( 'name' ) ); ?>"> |
| @@ -3587,14 +4094,140 @@ | ||
| 3587 | 4094 | |
| 3588 | 4095 | /** |
| 3589 | 4096 | * Render security headers tab |
| 3590 | 4097 | */ |
| 4098 | + /** | |
| 4099 | + * Offer back the header settings the 2.9.8 migration wiped. | |
| 4100 | + * | |
| 4101 | + * Rendered outside the settings form on purpose, so its buttons can never | |
| 4102 | + * submit it, and only when there is something to actually change. Shows the | |
| 4103 | + * difference before anything is written: nothing is applied that the owner | |
| 4104 | + * has not seen first. | |
| 4105 | + * | |
| 4106 | + * @since 2.10.0 | |
| 4107 | + */ | |
| 4108 | + private function render_headers_recovery_offer() { | |
| 4109 | + /* | |
| 4110 | + * On a network the .htaccess belongs to every site and only the main one | |
| 4111 | + * writes it, so this is not a decision a subsite gets to make. Its own | |
| 4112 | + * security_headers options are inert anyway: what the network serves | |
| 4113 | + * comes from the file the main site owns. Without this gate a subsite | |
| 4114 | + * administrator was shown a Restore button that could only ever answer | |
| 4115 | + * with a permission error, which is worse than showing nothing. | |
| 4116 | + */ | |
| 4117 | + if ( ! Vigilante_Settings::can_write_shared_files() ) { | |
| 4118 | + return; | |
| 4119 | + } | |
| 4120 | + | |
| 4121 | + if ( ! Vigilante_Htaccess_Recovery::is_available() ) { | |
| 4122 | + /* | |
| 4123 | + * Already restored. Offer to take it back for as long as the previous | |
| 4124 | + * section is still stored: a restore that cannot be undone is a second | |
| 4125 | + * irreversible change on top of the one being repaired. | |
| 4126 | + */ | |
| 4127 | + if ( Vigilante_Htaccess_Recovery::has_undo() ) { | |
| 4128 | + ?> | |
| 4129 | + <div class="notice notice-info inline" id="vigilante-headers-recovery-undo"> | |
| 4130 | + <p> | |
| 4131 | + <?php esc_html_e( 'The Security Headers settings were restored from the copy Vigilant had kept of your .htaccess.', 'vigilante' ); ?> | |
| 4132 | + <button type="button" class="button button-small" id="vigilante-recovery-undo"> | |
| 4133 | + <?php esc_html_e( 'Undo the restore', 'vigilante' ); ?> | |
| 4134 | + </button> | |
| 4135 | + </p> | |
| 4136 | + </div> | |
| 4137 | + <?php | |
| 4138 | + } | |
| 4139 | + | |
| 4140 | + return; | |
| 4141 | + } | |
| 4142 | + | |
| 4143 | + $rows = Vigilante_Htaccess_Recovery::get_diff( $this->settings ); | |
| 4144 | + | |
| 4145 | + if ( empty( $rows ) ) { | |
| 4146 | + return; | |
| 4147 | + } | |
| 4148 | + | |
| 4149 | + $snapshot = Vigilante_Htaccess_Recovery::get_snapshot(); | |
| 4150 | + $taken = isset( $snapshot['time'] ) ? (int) $snapshot['time'] : 0; | |
| 4151 | + $block = Vigilante_Htaccess_Recovery::get_raw_block(); | |
| 4152 | + ?> | |
| 4153 | + <div class="vigilante-settings-section" id="vigilante-headers-recovery"> | |
| 4154 | + <h2><?php esc_html_e( 'Recover your previous header settings', 'vigilante' ); ?></h2> | |
| 4155 | + <p> | |
| 4156 | + <?php esc_html_e( 'Updating to 2.9.8 reset this tab to factory values: the migration replaced the whole section instead of merging into it. Your server kept sending the right headers, because the .htaccess had not been rewritten yet, so Vigilant saved a copy of that file before touching it. These are the settings it found in that copy.', 'vigilante' ); ?> | |
| 4157 | + </p> | |
| 4158 | + <?php if ( $taken ) : ?> | |
| 4159 | + <p class="description"> | |
| 4160 | + <?php | |
| 4161 | + printf( | |
| 4162 | + /* translators: %s: date and time the .htaccess copy was taken. */ | |
| 4163 | + esc_html__( 'Copy taken on %s.', 'vigilante' ), | |
| 4164 | + esc_html( wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $taken ) ) | |
| 4165 | + ); | |
| 4166 | + ?> | |
| 4167 | + </p> | |
| 4168 | + <?php endif; ?> | |
| 4169 | + | |
| 4170 | + <table class="widefat striped"> | |
| 4171 | + <thead> | |
| 4172 | + <tr> | |
| 4173 | + <th scope="col"><?php esc_html_e( 'Setting', 'vigilante' ); ?></th> | |
| 4174 | + <th scope="col"><?php esc_html_e( 'Now', 'vigilante' ); ?></th> | |
| 4175 | + <th scope="col"><?php esc_html_e( 'Would be restored to', 'vigilante' ); ?></th> | |
| 4176 | + </tr> | |
| 4177 | + </thead> | |
| 4178 | + <tbody> | |
| 4179 | + <?php foreach ( $rows as $row ) : ?> | |
| 4180 | + <tr> | |
| 4181 | + <th scope="row"><?php echo esc_html( $row['label'] ); ?></th> | |
| 4182 | + <td><?php echo esc_html( $row['current'] ); ?></td> | |
| 4183 | + <td> | |
| 4184 | + <?php echo esc_html( $row['recovered'] ); ?> | |
| 4185 | + <?php if ( ! empty( $row['detail'] ) ) : ?> | |
| 4186 | + <br><span class="description"><?php echo esc_html( $row['detail'] ); ?></span> | |
| 4187 | + <?php endif; ?> | |
| 4188 | + </td> | |
| 4189 | + </tr> | |
| 4190 | + <?php endforeach; ?> | |
| 4191 | + </tbody> | |
| 4192 | + </table> | |
| 4193 | + | |
| 4194 | + <p class="description"> | |
| 4195 | + <?php esc_html_e( 'Only these settings are written. The .htaccess is then rebuilt from them, the same way saving this tab rebuilds it. The stored copy of the file is never written back, so nothing your host, your cache plugin or your CDN added to it is touched.', 'vigilante' ); ?> | |
| 4196 | + </p> | |
| 4197 | + | |
| 4198 | + <?php if ( '' !== $block ) : ?> | |
| 4199 | + <details> | |
| 4200 | + <summary><?php esc_html_e( 'Show the saved .htaccess block', 'vigilante' ); ?></summary> | |
| 4201 | + <textarea readonly rows="12" class="large-text code" onclick="this.select();"><?php echo esc_textarea( $block ); ?></textarea> | |
| 4202 | + </details> | |
| 4203 | + <?php endif; ?> | |
| 4204 | + | |
| 4205 | + <p class="submit vigilante-submit-buttons"> | |
| 4206 | + <button type="button" class="button button-primary" id="vigilante-recovery-restore"> | |
| 4207 | + <?php esc_html_e( 'Restore these settings', 'vigilante' ); ?> | |
| 4208 | + </button> | |
| 4209 | + <button type="button" class="button" id="vigilante-recovery-dismiss"> | |
| 4210 | + <?php esc_html_e( 'No thanks, keep what I have', 'vigilante' ); ?> | |
| 4211 | + </button> | |
| 4212 | + </p> | |
| 4213 | + <div id="vigilante-recovery-result"></div> | |
| 4214 | + </div> | |
| 4215 | + <?php | |
| 4216 | + } | |
| 4217 | + | |
| 3591 | 4218 | private function render_tab_headers() { |
| 3592 | 4219 | $is_disabled = $this->render_module_disabled_notice( 'security_headers' ); |
| 3593 | - $options = $this->settings->get_section( 'security_headers' ); | |
| 4220 | + // Every setting on this tab ends up in .htaccess, so on a subsite the | |
| 4221 | + // whole tab is somebody else's, values included. | |
| 4222 | + $vg_shared_locked = $this->shared_files_locked(); | |
| 4223 | + $options = $this->get_section_for_display( 'security_headers' ); | |
| 3594 | 4224 | ?> |
| 4225 | + <?php $this->render_headers_recovery_offer(); ?> | |
| 4226 | + | |
| 3595 | 4227 | <form class="vigilante-settings-form <?php echo $is_disabled ? 'vigilante-form-disabled' : ''; ?>" data-section="security_headers" <?php echo $is_disabled ? 'inert' : ''; ?>> |
| 3596 | - <div id="vigilante-section-headers-main" class="vigilante-settings-section"> | |
| 4228 | + <?php $this->render_shared_files_notice(); ?> | |
| 4229 | + <div id="vigilante-section-headers-main" class="vigilante-settings-section <?php echo $vg_shared_locked ? 'vigilante-form-disabled' : ''; ?>" <?php echo $vg_shared_locked ? 'inert' : ''; ?>> | |
| 3597 | 4230 | <h2> |
| 3598 | 4231 | <?php esc_html_e( 'Security Headers', 'vigilante' ); ?> |
| 3599 | 4232 | <span class="vigilante-method-badge htaccess"><?php esc_html_e( 'HTACCESS', 'vigilante' ); ?></span> |
| 3600 | 4233 | </h2> |
| @@ -3601,11 +4234,11 @@ | ||
| 3601 | 4234 | <p><?php esc_html_e( 'HTTP headers sent with every response via .htaccess (mod_headers).', 'vigilante' ); ?></p> |
| 3602 | 4235 | |
| 3603 | 4236 | <table class="form-table"> |
| 3604 | 4237 | <tr> |
| 3605 | - <th scope="row"><?php esc_html_e( 'X-Frame-Options', 'vigilante' ); ?></th> | |
| 4238 | + <th scope="row"><label for="vigilante-f-security-headers-x-frame-options"><?php esc_html_e( 'X-Frame-Options', 'vigilante' ); ?></label></th> | |
| 3606 | 4239 | <td> |
| 3607 | - <select name="security_headers[x_frame_options]"> | |
| 4240 | + <select id="vigilante-f-security-headers-x-frame-options" name="security_headers[x_frame_options]"> | |
| 3608 | 4241 | <option value="" <?php selected( empty( $options['x_frame_options'] ) ); ?>><?php esc_html_e( 'Disabled', 'vigilante' ); ?></option> |
| 3609 | 4242 | <option value="SAMEORIGIN" <?php selected( $options['x_frame_options'] ?? '', 'SAMEORIGIN' ); ?>>SAMEORIGIN</option> |
| 3610 | 4243 | <option value="DENY" <?php selected( $options['x_frame_options'] ?? '', 'DENY' ); ?>>DENY</option> |
| 3611 | 4244 | </select> |
| @@ -3621,11 +4254,11 @@ | ||
| 3621 | 4254 | </label> |
| 3622 | 4255 | </td> |
| 3623 | 4256 | </tr> |
| 3624 | 4257 | <tr> |
| 3625 | - <th scope="row"><?php esc_html_e( 'Referrer-Policy', 'vigilante' ); ?></th> | |
| 4258 | + <th scope="row"><label for="vigilante-f-security-headers-referrer-policy"><?php esc_html_e( 'Referrer-Policy', 'vigilante' ); ?></label></th> | |
| 3626 | 4259 | <td> |
| 3627 | - <select name="security_headers[referrer_policy]"> | |
| 4260 | + <select id="vigilante-f-security-headers-referrer-policy" name="security_headers[referrer_policy]"> | |
| 3628 | 4261 | <option value="" <?php selected( empty( $options['referrer_policy'] ) ); ?>><?php esc_html_e( 'Disabled', 'vigilante' ); ?></option> |
| 3629 | 4262 | <option value="no-referrer" <?php selected( $options['referrer_policy'] ?? '', 'no-referrer' ); ?>>no-referrer</option> |
| 3630 | 4263 | <option value="strict-origin-when-cross-origin" <?php selected( $options['referrer_policy'] ?? '', 'strict-origin-when-cross-origin' ); ?>>strict-origin-when-cross-origin</option> |
| 3631 | 4264 | <option value="same-origin" <?php selected( $options['referrer_policy'] ?? '', 'same-origin' ); ?>>same-origin</option> |
| @@ -3633,65 +4266,119 @@ | ||
| 3633 | 4266 | </td> |
| 3634 | 4267 | </tr> |
| 3635 | 4268 | </table> |
| 3636 | 4269 | |
| 3637 | - <h3><?php esc_html_e( 'HSTS (HTTP Strict Transport Security)', 'vigilante' ); ?></h3> | |
| 4270 | + <h3 id="vigilante-section-headers-csp"><?php esc_html_e( 'Content Security Policy', 'vigilante' ); ?></h3> | |
| 3638 | 4271 | <table class="form-table"> |
| 3639 | 4272 | <tr> |
| 3640 | - <th scope="row"><?php esc_html_e( 'Enable HSTS', 'vigilante' ); ?></th> | |
| 4273 | + <th scope="row"><?php esc_html_e( 'Enable CSP', 'vigilante' ); ?></th> | |
| 3641 | 4274 | <td> |
| 3642 | 4275 | <label> |
| 3643 | - <input type="checkbox" name="security_headers[hsts][enabled]" value="1" <?php checked( ! empty( $options['hsts']['enabled'] ) ); ?>> | |
| 3644 | - <?php esc_html_e( 'Force HTTPS connections', 'vigilante' ); ?> | |
| 4276 | + <input type="checkbox" name="security_headers[csp][enabled]" value="1" <?php checked( ! empty( $options['csp']['enabled'] ) ); ?>> | |
| 4277 | + <?php esc_html_e( 'Enable Content Security Policy', 'vigilante' ); ?> | |
| 3645 | 4278 | </label> |
| 3646 | - <p class="description"><?php esc_html_e( '⚠ Warning: Only enable if your site fully supports HTTPS.', 'vigilante' ); ?></p> | |
| 3647 | 4279 | </td> |
| 3648 | 4280 | </tr> |
| 3649 | 4281 | <tr> |
| 3650 | - <th scope="row"><?php esc_html_e( 'Max Age', 'vigilante' ); ?></th> | |
| 4282 | + <th scope="row"><?php esc_html_e( 'Report Only Mode', 'vigilante' ); ?></th> | |
| 3651 | 4283 | <td> |
| 3652 | - <select name="security_headers[hsts][max_age]"> | |
| 3653 | - <option value="86400" <?php selected( $options['hsts']['max_age'] ?? 31536000, 86400 ); ?>><?php esc_html_e( '1 day (testing)', 'vigilante' ); ?></option> | |
| 3654 | - <option value="2592000" <?php selected( $options['hsts']['max_age'] ?? 31536000, 2592000 ); ?>><?php esc_html_e( '30 days', 'vigilante' ); ?></option> | |
| 3655 | - <option value="31536000" <?php selected( $options['hsts']['max_age'] ?? 31536000, 31536000 ); ?>><?php esc_html_e( '1 year (recommended)', 'vigilante' ); ?></option> | |
| 3656 | - <option value="63072000" <?php selected( $options['hsts']['max_age'] ?? 31536000, 63072000 ); ?>><?php esc_html_e( '2 years', 'vigilante' ); ?></option> | |
| 3657 | - </select> | |
| 4284 | + <label> | |
| 4285 | + <input type="checkbox" name="security_headers[csp][report_only]" value="1" <?php checked( ! empty( $options['csp']['report_only'] ) ); ?>> | |
| 4286 | + <?php esc_html_e( 'Report violations without blocking (for testing)', 'vigilante' ); ?> | |
| 4287 | + </label> | |
| 3658 | 4288 | </td> |
| 3659 | 4289 | </tr> |
| 4290 | + </table> | |
| 4291 | + | |
| 4292 | + <h3 id="vigilante-section-headers-force-https"><?php esc_html_e( 'HTTPS', 'vigilante' ); ?></h3> | |
| 4293 | + <p class="description"><?php esc_html_e( 'HTTPS is strongly recommended, but Vigilant will not impose it. Enable only what your site already supports.', 'vigilante' ); ?></p> | |
| 4294 | + <table class="form-table"> | |
| 3660 | 4295 | <tr> |
| 3661 | - <th scope="row"><?php esc_html_e( 'Include Subdomains', 'vigilante' ); ?></th> | |
| 4296 | + <th scope="row"><?php esc_html_e( 'Redirect HTTP to HTTPS', 'vigilante' ); ?></th> | |
| 3662 | 4297 | <td> |
| 3663 | 4298 | <label> |
| 3664 | - <input type="checkbox" name="security_headers[hsts][include_subdomains]" value="1" <?php checked( ! empty( $options['hsts']['include_subdomains'] ) ); ?>> | |
| 3665 | - <?php esc_html_e( 'Apply HSTS to all subdomains', 'vigilante' ); ?> | |
| 4299 | + <input type="checkbox" name="security_headers[redirect_http_to_https]" value="1" <?php checked( ! empty( $options['redirect_http_to_https'] ) ); ?>> | |
| 4300 | + <?php esc_html_e( 'Send visitors arriving over HTTP to the HTTPS address', 'vigilante' ); ?> | |
| 3666 | 4301 | </label> |
| 4302 | + <p class="description"><?php esc_html_e( 'Only applies when the site address is already an https:// one. On a site still published over HTTP it does nothing, so it cannot leave the site unreachable.', 'vigilante' ); ?></p> | |
| 3667 | 4303 | </td> |
| 3668 | 4304 | </tr> |
| 4305 | + <tr> | |
| 4306 | + <th scope="row"><?php esc_html_e( 'Fix Mixed Content', 'vigilante' ); ?></th> | |
| 4307 | + <td> | |
| 4308 | + <label> | |
| 4309 | + <input type="checkbox" name="security_headers[fix_mixed_content]" value="1" <?php checked( ! empty( $options['fix_mixed_content'] ) ); ?>> | |
| 4310 | + <?php esc_html_e( 'Rewrite this site http:// resources to https://', 'vigilante' ); ?> | |
| 4311 | + </label> | |
| 4312 | + <p class="description"><?php esc_html_e( 'Off by default. Only touches addresses of this same site, and only when the site is already served over HTTPS, so it cannot break an external resource. Useful right after moving a site to HTTPS, when old content still points at http:// addresses.', 'vigilante' ); ?></p> | |
| 4313 | + </td> | |
| 4314 | + </tr> | |
| 4315 | + <tr id="field-upgrade-insecure-requests"> | |
| 4316 | + <th scope="row"><?php esc_html_e( 'Upgrade Insecure Requests', 'vigilante' ); ?></th> | |
| 4317 | + <td> | |
| 4318 | + <label> | |
| 4319 | + <input type="checkbox" name="security_headers[upgrade_insecure_requests]" value="1" <?php checked( ! empty( $options['upgrade_insecure_requests'] ) ); ?>> | |
| 4320 | + <?php esc_html_e( 'Ask browsers to upgrade every http:// request to https://', 'vigilante' ); ?> | |
| 4321 | + </label> | |
| 4322 | + <p class="description"><?php esc_html_e( '⚠ Off by default. This one also covers resources hosted elsewhere: anything served from a domain with no HTTPS stops loading instead of loading insecurely. Turn it on once you know every external resource the site uses is available over HTTPS.', 'vigilante' ); ?></p> | |
| 4323 | + </td> | |
| 4324 | + </tr> | |
| 4325 | + <tr> | |
| 4326 | + <th scope="row"><?php esc_html_e( 'Rewrite Site Address on Activation', 'vigilante' ); ?></th> | |
| 4327 | + <td> | |
| 4328 | + <label> | |
| 4329 | + <input type="checkbox" name="security_headers[force_https]" value="1" <?php checked( ! empty( $options['force_https'] ) ); ?>> | |
| 4330 | + <?php esc_html_e( 'Change the WordPress and site addresses to https:// when the plugin is activated', 'vigilante' ); ?> | |
| 4331 | + </label> | |
| 4332 | + <p class="description"><?php esc_html_e( '⚠ Off by default. This writes to the WordPress Address and Site Address settings, and turning the plugin off later does not undo it. It only runs on activation, and only when the site answers over HTTPS.', 'vigilante' ); ?></p> | |
| 4333 | + </td> | |
| 4334 | + </tr> | |
| 3669 | 4335 | </table> |
| 3670 | 4336 | |
| 3671 | - <h3><?php esc_html_e( 'Content Security Policy', 'vigilante' ); ?></h3> | |
| 4337 | + <h3 id="vigilante-section-headers-hsts"><?php esc_html_e( 'HSTS (HTTP Strict Transport Security)', 'vigilante' ); ?></h3> | |
| 4338 | + <?php $vig_home_https = ( 0 === strpos( (string) get_option( 'home' ), 'https://' ) ); ?> | |
| 4339 | + <p class="description"><?php esc_html_e( 'Tells browsers to reach this site over HTTPS and never over HTTP, for as long as the max age below.', 'vigilante' ); ?></p> | |
| 4340 | + <?php if ( ! $vig_home_https ) : ?> | |
| 4341 | + <p class="description" style="color:#b32d2e"><strong><?php esc_html_e( 'Unavailable: the site address still starts with http://. Enabling HSTS on a site not published over HTTPS would make it unreachable in any browser that honours it.', 'vigilante' ); ?></strong></p> | |
| 4342 | + <?php endif; ?> | |
| 3672 | 4343 | <table class="form-table"> |
| 3673 | 4344 | <tr> |
| 3674 | - <th scope="row"><?php esc_html_e( 'Enable CSP', 'vigilante' ); ?></th> | |
| 4345 | + <th scope="row"><?php esc_html_e( 'Enable HSTS', 'vigilante' ); ?></th> | |
| 3675 | 4346 | <td> |
| 4347 | + <?php if ( ! $vig_home_https ) : ?> | |
| 4348 | + <?php /* A disabled checkbox is not submitted, and a boolean missing from the post is treated as unticked, so saving the tab would silently switch HSTS off. Carry the stored value instead. */ ?> | |
| 4349 | + <input type="hidden" name="security_headers[hsts][enabled]" value="<?php echo ! empty( $options['hsts']['enabled'] ) ? '1' : '0'; ?>"> | |
| 4350 | + <?php endif; ?> | |
| 3676 | 4351 | <label> |
| 3677 | - <input type="checkbox" name="security_headers[csp][enabled]" value="1" <?php checked( ! empty( $options['csp']['enabled'] ) ); ?>> | |
| 3678 | - <?php esc_html_e( 'Enable Content Security Policy', 'vigilante' ); ?> | |
| 4352 | + <input type="checkbox" name="security_headers[hsts][enabled]" value="1" <?php checked( ! empty( $options['hsts']['enabled'] ) ); ?> <?php disabled( ! $vig_home_https ); ?>> | |
| 4353 | + <?php esc_html_e( 'Send the Strict-Transport-Security header', 'vigilante' ); ?> | |
| 3679 | 4354 | </label> |
| 4355 | + <p class="description"><?php esc_html_e( '⚠ Hard to undo: browsers remember it for the whole max age even if you turn it off later, so a site that loses its certificate stays unreachable until it expires. Start with a short max age.', 'vigilante' ); ?></p> | |
| 3680 | 4356 | </td> |
| 3681 | 4357 | </tr> |
| 3682 | 4358 | <tr> |
| 3683 | - <th scope="row"><?php esc_html_e( 'Report Only Mode', 'vigilante' ); ?></th> | |
| 4359 | + <th scope="row"><label for="vigilante-f-security-headers-hsts-max-age"><?php esc_html_e( 'Max Age', 'vigilante' ); ?></label></th> | |
| 3684 | 4360 | <td> |
| 4361 | + <select id="vigilante-f-security-headers-hsts-max-age" name="security_headers[hsts][max_age]"> | |
| 4362 | + <option value="86400" <?php selected( $options['hsts']['max_age'] ?? 31536000, 86400 ); ?>><?php esc_html_e( '1 day (testing)', 'vigilante' ); ?></option> | |
| 4363 | + <option value="2592000" <?php selected( $options['hsts']['max_age'] ?? 31536000, 2592000 ); ?>><?php esc_html_e( '30 days', 'vigilante' ); ?></option> | |
| 4364 | + <option value="31536000" <?php selected( $options['hsts']['max_age'] ?? 31536000, 31536000 ); ?>><?php esc_html_e( '1 year (recommended)', 'vigilante' ); ?></option> | |
| 4365 | + <option value="63072000" <?php selected( $options['hsts']['max_age'] ?? 31536000, 63072000 ); ?>><?php esc_html_e( '2 years', 'vigilante' ); ?></option> | |
| 4366 | + </select> | |
| 4367 | + </td> | |
| 4368 | + </tr> | |
| 4369 | + <tr> | |
| 4370 | + <th scope="row"><?php esc_html_e( 'Include Subdomains', 'vigilante' ); ?></th> | |
| 4371 | + <td> | |
| 3685 | 4372 | <label> |
| 3686 | - <input type="checkbox" name="security_headers[csp][report_only]" value="1" <?php checked( ! empty( $options['csp']['report_only'] ) ); ?>> | |
| 3687 | - <?php esc_html_e( 'Report violations without blocking (for testing)', 'vigilante' ); ?> | |
| 4373 | + <input type="checkbox" name="security_headers[hsts][include_subdomains]" value="1" <?php checked( ! empty( $options['hsts']['include_subdomains'] ) ); ?>> | |
| 4374 | + <?php esc_html_e( 'Apply HSTS to all subdomains', 'vigilante' ); ?> | |
| 3688 | 4375 | </label> |
| 3689 | 4376 | </td> |
| 3690 | 4377 | </tr> |
| 3691 | 4378 | </table> |
| 3692 | 4379 | |
| 3693 | - <h3><?php esc_html_e( 'Server Identity', 'vigilante' ); ?></h3> | |
| 4380 | + <h3 id="vigilante-section-headers-fingerprint"><?php esc_html_e( 'Server Identity', 'vigilante' ); ?></h3> | |
| 3694 | 4381 | <p class="description"><?php esc_html_e( 'Hide identifying information that servers expose in responses.', 'vigilante' ); ?></p> |
| 3695 | 4382 | <table class="form-table"> |
| 3696 | 4383 | <tr> |
| 3697 | 4384 | <th scope="row"><?php esc_html_e( 'Server Signature', 'vigilante' ); ?></th> |
| @@ -3713,9 +4400,57 @@ | ||
| 3713 | 4400 | </tr> |
| 3714 | 4401 | </table> |
| 3715 | 4402 | </div> |
| 3716 | 4403 | |
| 4404 | + <?php $vg_cop = ( isset( $options['cross_origin_policies'] ) && is_array( $options['cross_origin_policies'] ) ) ? $options['cross_origin_policies'] : array(); ?> | |
| 4405 | + <div id="vigilante-section-headers-cross-origin" class="vigilante-settings-section <?php echo $vg_shared_locked ? 'vigilante-form-disabled' : ''; ?>" <?php echo $vg_shared_locked ? 'inert' : ''; ?>> | |
| 4406 | + <h2> | |
| 4407 | + <?php esc_html_e( 'Cross-Origin Policies', 'vigilante' ); ?> | |
| 4408 | + <span class="vigilante-method-badge htaccess"><?php esc_html_e( 'HTACCESS', 'vigilante' ); ?></span> | |
| 4409 | + </h2> | |
| 4410 | + <p><?php esc_html_e( 'Control how other origins may open, embed or fetch your site. Vigilant already sends these headers with the values below.', 'vigilante' ); ?></p> | |
| 4411 | + | |
| 4412 | + <table class="form-table"> | |
| 4413 | + <tr> | |
| 4414 | + <th scope="row"><label for="vigilante-f-security-headers-coop"><?php esc_html_e( 'Cross-Origin-Opener-Policy (COOP)', 'vigilante' ); ?></label></th> | |
| 4415 | + <td> | |
| 4416 | + <select id="vigilante-f-security-headers-coop" name="security_headers[cross_origin_policies][opener_policy]"> | |
| 4417 | + <option value="" <?php selected( empty( $vg_cop['opener_policy'] ) ); ?>><?php esc_html_e( 'Disabled (header not sent)', 'vigilante' ); ?></option> | |
| 4418 | + <option value="unsafe-none" <?php selected( $vg_cop['opener_policy'] ?? '', 'unsafe-none' ); ?>>unsafe-none</option> | |
| 4419 | + <option value="same-origin-allow-popups" <?php selected( $vg_cop['opener_policy'] ?? '', 'same-origin-allow-popups' ); ?>><?php esc_html_e( 'same-origin-allow-popups (recommended)', 'vigilante' ); ?></option> | |
| 4420 | + <option value="same-origin" <?php selected( $vg_cop['opener_policy'] ?? '', 'same-origin' ); ?>>same-origin</option> | |
| 4421 | + </select> | |
| 4422 | + <p class="description"><?php esc_html_e( 'ⓘ Cuts the link between your site and a window from another origin that opened it. Side effect: external tools that open your site in a new tab and talk to it through window.opener, such as Google Tag Assistant, will report that they cannot connect. Pick unsafe-none or Disabled if you need those tools.', 'vigilante' ); ?></p> | |
| 4423 | + </td> | |
| 4424 | + </tr> | |
| 4425 | + <tr> | |
| 4426 | + <th scope="row"><label for="vigilante-f-security-headers-coep"><?php esc_html_e( 'Cross-Origin-Embedder-Policy (COEP)', 'vigilante' ); ?></label></th> | |
| 4427 | + <td> | |
| 4428 | + <select id="vigilante-f-security-headers-coep" name="security_headers[cross_origin_policies][embedder_policy]"> | |
| 4429 | + <option value="unsafe-none" <?php selected( ( $vg_cop['embedder_policy'] ?? 'unsafe-none' ), 'unsafe-none' ); ?>><?php esc_html_e( 'unsafe-none (header not sent)', 'vigilante' ); ?></option> | |
| 4430 | + <option value="credentialless" <?php selected( $vg_cop['embedder_policy'] ?? '', 'credentialless' ); ?>>credentialless</option> | |
| 4431 | + <option value="require-corp" <?php selected( $vg_cop['embedder_policy'] ?? '', 'require-corp' ); ?>>require-corp</option> | |
| 4432 | + </select> | |
| 4433 | + <p class="description"><?php esc_html_e( 'ⓘ Requires every cross-origin resource to opt in. require-corp can block third-party images, fonts, videos and embeds that do not send their own CORP or CORS headers.', 'vigilante' ); ?></p> | |
| 4434 | + </td> | |
| 4435 | + </tr> | |
| 4436 | + <tr> | |
| 4437 | + <th scope="row"><label for="vigilante-f-security-headers-corp"><?php esc_html_e( 'Cross-Origin-Resource-Policy (CORP)', 'vigilante' ); ?></label></th> | |
| 4438 | + <td> | |
| 4439 | + <select id="vigilante-f-security-headers-corp" name="security_headers[cross_origin_policies][resource_policy]"> | |
| 4440 | + <option value="" <?php selected( empty( $vg_cop['resource_policy'] ) ); ?>><?php esc_html_e( 'Disabled (header not sent)', 'vigilante' ); ?></option> | |
| 4441 | + <option value="same-site" <?php selected( $vg_cop['resource_policy'] ?? '', 'same-site' ); ?>>same-site</option> | |
| 4442 | + <option value="same-origin" <?php selected( $vg_cop['resource_policy'] ?? '', 'same-origin' ); ?>>same-origin</option> | |
| 4443 | + <option value="cross-origin" <?php selected( $vg_cop['resource_policy'] ?? '', 'cross-origin' ); ?>><?php esc_html_e( 'cross-origin (recommended)', 'vigilante' ); ?></option> | |
| 4444 | + </select> | |
| 4445 | + <p class="description"><?php esc_html_e( 'ⓘ Declares who may load resources from this site. same-origin stops hotlinking, but it also breaks CDNs, feed readers and any external service that fetches your images or files.', 'vigilante' ); ?></p> | |
| 4446 | + </td> | |
| 4447 | + </tr> | |
| 4448 | + </table> | |
| 4449 | + </div> | |
| 4450 | + | |
| 3717 | 4451 | <p class="submit vigilante-submit-buttons"> |
| 4452 | + <?php if ( ! $vg_shared_locked ) : ?> | |
| 3718 | 4453 | <button type="submit" class="button button-primary vigilante-save-btn" data-original-text="<?php esc_attr_e( 'Save Settings', 'vigilante' ); ?>"> |
| 3719 | 4454 | <?php esc_html_e( 'Save Settings', 'vigilante' ); ?> |
| 3720 | 4455 | </button> |
| 3721 | 4456 | <button type="button" class="button vigilante-reset-section-btn" data-original-text="<?php esc_attr_e( 'Reset to Defaults', 'vigilante' ); ?>"> |
| @@ -3720,8 +4455,10 @@ | ||
| 3720 | 4455 | </button> |
| 3721 | 4456 | <button type="button" class="button vigilante-reset-section-btn" data-original-text="<?php esc_attr_e( 'Reset to Defaults', 'vigilante' ); ?>"> |
| 3722 | 4457 | <?php esc_html_e( 'Reset to Defaults', 'vigilante' ); ?> |
| 3723 | 4458 | </button> |
| 4459 | + <?php endif; ?> | |
| 4460 | + <?php /* Testing what the server actually sends is read-only and useful from any site of a network. */ ?> | |
| 3724 | 4461 | <button type="button" class="button vigilante-test-headers"> |
| 3725 | 4462 | <?php esc_html_e( 'Test Headers', 'vigilante' ); ?> |
| 3726 | 4463 | </button> |
| 3727 | 4464 | </p> |
| @@ -3747,11 +4484,11 @@ | ||
| 3747 | 4484 | <p><?php esc_html_e( 'Control access to WordPress REST API endpoints.', 'vigilante' ); ?></p> |
| 3748 | 4485 | |
| 3749 | 4486 | <table class="form-table"> |
| 3750 | 4487 | <tr> |
| 3751 | - <th scope="row"><?php esc_html_e( 'Access Mode', 'vigilante' ); ?></th> | |
| 4488 | + <th scope="row"><label for="vigilante-f-rest-api-security-mode"><?php esc_html_e( 'Access Mode', 'vigilante' ); ?></label></th> | |
| 3752 | 4489 | <td> |
| 3753 | - <select name="rest_api_security[mode]"> | |
| 4490 | + <select id="vigilante-f-rest-api-security-mode" name="rest_api_security[mode]"> | |
| 3754 | 4491 | <option value="open" <?php selected( $options['mode'] ?? 'selective', 'open' ); ?>><?php esc_html_e( 'Open - Allow all requests', 'vigilante' ); ?></option> |
| 3755 | 4492 | <option value="selective" <?php selected( $options['mode'] ?? 'selective', 'selective' ); ?>><?php esc_html_e( 'Selective - Protect sensitive endpoints', 'vigilante' ); ?></option> |
| 3756 | 4493 | <option value="authenticated_only" <?php selected( $options['mode'] ?? 'selective', 'authenticated_only' ); ?>><?php esc_html_e( 'Authenticated - Require login for all', 'vigilante' ); ?></option> |
| 3757 | 4494 | </select> |
| @@ -3830,14 +4567,14 @@ | ||
| 3830 | 4567 | <?php |
| 3831 | 4568 | $pw_policy = wp_parse_args( |
| 3832 | 4569 | ( isset( $options['password_policy'] ) && is_array( $options['password_policy'] ) ) ? $options['password_policy'] : array(), |
| 3833 | 4570 | array( |
| 3834 | - 'require_uppercase' => true, | |
| 3835 | - 'require_lowercase' => true, | |
| 3836 | - 'require_number' => true, | |
| 3837 | - 'require_special' => true, | |
| 4571 | + 'require_uppercase' => false, | |
| 4572 | + 'require_lowercase' => false, | |
| 4573 | + 'require_number' => false, | |
| 4574 | + 'require_special' => false, | |
| 3838 | 4575 | 'block_common' => true, |
| 3839 | - 'block_username' => false, | |
| 4576 | + 'block_username' => true, | |
| 3840 | 4577 | 'affected_roles' => array(), |
| 3841 | 4578 | ) |
| 3842 | 4579 | ); |
| 3843 | 4580 | $pw_policy_roles = (array) $pw_policy['affected_roles']; |
| @@ -3851,11 +4588,11 @@ | ||
| 3851 | 4588 | </label> |
| 3852 | 4589 | </td> |
| 3853 | 4590 | </tr> |
| 3854 | 4591 | <tr> |
| 3855 | - <th scope="row"><?php esc_html_e( 'Minimum Password Length', 'vigilante' ); ?></th> | |
| 4592 | + <th scope="row"><label for="vigilante-f-user-security-min-password-length"><?php esc_html_e( 'Minimum Password Length', 'vigilante' ); ?></label></th> | |
| 3856 | 4593 | <td> |
| 3857 | - <input type="number" name="user_security[min_password_length]" value="<?php echo esc_attr( $options['min_password_length'] ?? 12 ); ?>" min="6" max="32" class="small-text"> | |
| 4594 | + <input id="vigilante-f-user-security-min-password-length" type="number" name="user_security[min_password_length]" value="<?php echo esc_attr( $options['min_password_length'] ?? 12 ); ?>" min="6" max="32" class="small-text"> | |
| 3858 | 4595 | <?php esc_html_e( 'characters', 'vigilante' ); ?> |
| 3859 | 4596 | </td> |
| 3860 | 4597 | </tr> |
| 3861 | 4598 | <tr> |
| @@ -4008,11 +4745,11 @@ | ||
| 4008 | 4745 | <p class="description"><?php esc_html_e( 'Disable on high-traffic sites to avoid email overload.', 'vigilante' ); ?></p> |
| 4009 | 4746 | </td> |
| 4010 | 4747 | </tr> |
| 4011 | 4748 | <tr> |
| 4012 | - <th scope="row"><?php esc_html_e( 'Auto-reject After', 'vigilante' ); ?></th> | |
| 4749 | + <th scope="row"><label for="vigilante-f-user-security-registration-approval-auto-reject-days"><?php esc_html_e( 'Auto-reject After', 'vigilante' ); ?></label></th> | |
| 4013 | 4750 | <td> |
| 4014 | - <input type="number" name="user_security[registration_approval][auto_reject_days]" value="<?php echo esc_attr( $registration['auto_reject_days'] ?? 0 ); ?>" min="0" max="365" class="small-text"> | |
| 4751 | + <input id="vigilante-f-user-security-registration-approval-auto-reject-days" type="number" name="user_security[registration_approval][auto_reject_days]" value="<?php echo esc_attr( $registration['auto_reject_days'] ?? 0 ); ?>" min="0" max="365" class="small-text"> | |
| 4015 | 4752 | <?php esc_html_e( 'days (0 = never)', 'vigilante' ); ?> |
| 4016 | 4753 | <p class="description"><?php esc_html_e( 'Automatically reject pending registrations after this many days.', 'vigilante' ); ?></p> |
| 4017 | 4754 | </td> |
| 4018 | 4755 | </tr> |
| @@ -4037,18 +4774,18 @@ | ||
| 4037 | 4774 | </label> |
| 4038 | 4775 | </td> |
| 4039 | 4776 | </tr> |
| 4040 | 4777 | <tr> |
| 4041 | - <th scope="row"><?php esc_html_e( 'Maximum Sessions', 'vigilante' ); ?></th> | |
| 4778 | + <th scope="row"><label for="vigilante-f-user-security-session-limits-max-sessions"><?php esc_html_e( 'Maximum Sessions', 'vigilante' ); ?></label></th> | |
| 4042 | 4779 | <td> |
| 4043 | - <input type="number" name="user_security[session_limits][max_sessions]" value="<?php echo esc_attr( $session_limits['max_sessions'] ?? 3 ); ?>" min="1" max="10" class="small-text"> | |
| 4780 | + <input id="vigilante-f-user-security-session-limits-max-sessions" type="number" name="user_security[session_limits][max_sessions]" value="<?php echo esc_attr( $session_limits['max_sessions'] ?? 3 ); ?>" min="1" max="10" class="small-text"> | |
| 4044 | 4781 | <?php esc_html_e( 'sessions per user', 'vigilante' ); ?> |
| 4045 | 4782 | </td> |
| 4046 | 4783 | </tr> |
| 4047 | 4784 | <tr> |
| 4048 | - <th scope="row"><?php esc_html_e( 'When Limit Exceeded', 'vigilante' ); ?></th> | |
| 4785 | + <th scope="row"><label for="vigilante-f-user-security-session-limits-behavior"><?php esc_html_e( 'When Limit Exceeded', 'vigilante' ); ?></label></th> | |
| 4049 | 4786 | <td> |
| 4050 | - <select name="user_security[session_limits][behavior]"> | |
| 4787 | + <select id="vigilante-f-user-security-session-limits-behavior" name="user_security[session_limits][behavior]"> | |
| 4051 | 4788 | <option value="block_new" <?php selected( ( $session_limits['behavior'] ?? 'close_oldest' ), 'block_new' ); ?>><?php esc_html_e( 'Block new login', 'vigilante' ); ?></option> |
| 4052 | 4789 | <option value="close_oldest" <?php selected( ( $session_limits['behavior'] ?? 'close_oldest' ), 'close_oldest' ); ?>><?php esc_html_e( 'Close oldest session', 'vigilante' ); ?></option> |
| 4053 | 4790 | </select> |
| 4054 | 4791 | <p class="description"><?php esc_html_e( '"Close oldest" is recommended for security - ensures attackers cannot lock out legitimate users.', 'vigilante' ); ?></p> |
| @@ -4084,27 +4821,27 @@ | ||
| 4084 | 4821 | </label> |
| 4085 | 4822 | </td> |
| 4086 | 4823 | </tr> |
| 4087 | 4824 | <tr> |
| 4088 | - <th scope="row"><?php esc_html_e( 'Expire After', 'vigilante' ); ?></th> | |
| 4825 | + <th scope="row"><label for="vigilante-f-user-security-password-expiration-expire-days"><?php esc_html_e( 'Expire After', 'vigilante' ); ?></label></th> | |
| 4089 | 4826 | <td> |
| 4090 | - <input type="number" name="user_security[password_expiration][expire_days]" value="<?php echo esc_attr( $password_exp['expire_days'] ?? 90 ); ?>" min="7" max="365" class="small-text"> | |
| 4827 | + <input id="vigilante-f-user-security-password-expiration-expire-days" type="number" name="user_security[password_expiration][expire_days]" value="<?php echo esc_attr( $password_exp['expire_days'] ?? 90 ); ?>" min="7" max="365" class="small-text"> | |
| 4091 | 4828 | <?php esc_html_e( 'days', 'vigilante' ); ?> |
| 4092 | 4829 | <p class="description"><?php esc_html_e( 'PCI-DSS recommends 90 days.', 'vigilante' ); ?></p> |
| 4093 | 4830 | </td> |
| 4094 | 4831 | </tr> |
| 4095 | 4832 | <tr> |
| 4096 | - <th scope="row"><?php esc_html_e( 'Warning Period', 'vigilante' ); ?></th> | |
| 4833 | + <th scope="row"><label for="vigilante-f-user-security-password-expiration-warning-days"><?php esc_html_e( 'Warning Period', 'vigilante' ); ?></label></th> | |
| 4097 | 4834 | <td> |
| 4098 | - <input type="number" name="user_security[password_expiration][warning_days]" value="<?php echo esc_attr( $password_exp['warning_days'] ?? 14 ); ?>" min="1" max="30" class="small-text"> | |
| 4835 | + <input id="vigilante-f-user-security-password-expiration-warning-days" type="number" name="user_security[password_expiration][warning_days]" value="<?php echo esc_attr( $password_exp['warning_days'] ?? 14 ); ?>" min="1" max="30" class="small-text"> | |
| 4099 | 4836 | <?php esc_html_e( 'days before expiration', 'vigilante' ); ?> |
| 4100 | 4837 | <p class="description"><?php esc_html_e( 'Show warning notice this many days before password expires.', 'vigilante' ); ?></p> |
| 4101 | 4838 | </td> |
| 4102 | 4839 | </tr> |
| 4103 | 4840 | <tr> |
| 4104 | - <th scope="row"><?php esc_html_e( 'Password History', 'vigilante' ); ?></th> | |
| 4841 | + <th scope="row"><label for="vigilante-f-user-security-password-expiration-password-history"><?php esc_html_e( 'Password History', 'vigilante' ); ?></label></th> | |
| 4105 | 4842 | <td> |
| 4106 | - <input type="number" name="user_security[password_expiration][password_history]" value="<?php echo esc_attr( $password_exp['password_history'] ?? 3 ); ?>" min="0" max="24" class="small-text"> | |
| 4843 | + <input id="vigilante-f-user-security-password-expiration-password-history" type="number" name="user_security[password_expiration][password_history]" value="<?php echo esc_attr( $password_exp['password_history'] ?? 3 ); ?>" min="0" max="24" class="small-text"> | |
| 4107 | 4844 | <?php esc_html_e( 'passwords to remember', 'vigilante' ); ?> |
| 4108 | 4845 | <p class="description"><?php esc_html_e( 'Prevent reusing recent passwords. Set to 0 to disable.', 'vigilante' ); ?></p> |
| 4109 | 4846 | </td> |
| 4110 | 4847 | </tr> |
| @@ -4186,11 +4923,11 @@ | ||
| 4186 | 4923 | </label> |
| 4187 | 4924 | </td> |
| 4188 | 4925 | </tr> |
| 4189 | 4926 | <tr> |
| 4190 | - <th scope="row"><?php esc_html_e( 'Link Expiration', 'vigilante' ); ?></th> | |
| 4927 | + <th scope="row"><label for="vigilante-f-user-security-email-verification-token-expiry-hours"><?php esc_html_e( 'Link Expiration', 'vigilante' ); ?></label></th> | |
| 4191 | 4928 | <td> |
| 4192 | - <input type="number" name="user_security[email_verification][token_expiry_hours]" value="<?php echo esc_attr( $email_verify['token_expiry_hours'] ?? 24 ); ?>" min="1" max="168" class="small-text"> | |
| 4929 | + <input id="vigilante-f-user-security-email-verification-token-expiry-hours" type="number" name="user_security[email_verification][token_expiry_hours]" value="<?php echo esc_attr( $email_verify['token_expiry_hours'] ?? 24 ); ?>" min="1" max="168" class="small-text"> | |
| 4193 | 4930 | <?php esc_html_e( 'hours', 'vigilante' ); ?> |
| 4194 | 4931 | </td> |
| 4195 | 4932 | </tr> |
| 4196 | 4933 | <tr> |
| @@ -4202,11 +4939,11 @@ | ||
| 4202 | 4939 | </label> |
| 4203 | 4940 | </td> |
| 4204 | 4941 | </tr> |
| 4205 | 4942 | <tr> |
| 4206 | - <th scope="row"><?php esc_html_e( 'Auto-delete Unverified', 'vigilante' ); ?></th> | |
| 4943 | + <th scope="row"><label for="vigilante-f-user-security-email-verification-auto-delete-days"><?php esc_html_e( 'Auto-delete Unverified', 'vigilante' ); ?></label></th> | |
| 4207 | 4944 | <td> |
| 4208 | - <input type="number" name="user_security[email_verification][auto_delete_days]" value="<?php echo esc_attr( $email_verify['auto_delete_days'] ?? 7 ); ?>" min="0" max="365" class="small-text"> | |
| 4945 | + <input id="vigilante-f-user-security-email-verification-auto-delete-days" type="number" name="user_security[email_verification][auto_delete_days]" value="<?php echo esc_attr( $email_verify['auto_delete_days'] ?? 7 ); ?>" min="0" max="365" class="small-text"> | |
| 4209 | 4946 | <?php esc_html_e( 'days (0 = never)', 'vigilante' ); ?> |
| 4210 | 4947 | <p class="description"><?php esc_html_e( 'Automatically delete users who never verify their email.', 'vigilante' ); ?></p> |
| 4211 | 4948 | </td> |
| 4212 | 4949 | </tr> |
| @@ -4230,8 +4967,11 @@ | ||
| 4230 | 4967 | <h2 class="vigilante-tools-header"> |
| 4231 | 4968 | <?php esc_html_e( 'User security tools', 'vigilante' ); ?> |
| 4232 | 4969 | </h2> |
| 4233 | 4970 | |
| 4971 | + <?php $this->render_user_actions_notice(); ?> | |
| 4972 | + <?php if ( ! $this->user_actions_locked() ) : ?> | |
| 4973 | + | |
| 4234 | 4974 | <!-- Force Password Reset --> |
| 4235 | 4975 | <div class="vigilante-tool-box"> |
| 4236 | 4976 | <h3><?php esc_html_e( 'Force password reset', 'vigilante' ); ?></h3> |
| 4237 | 4977 | <p class="description"><?php esc_html_e( 'Force users to reset their password. Useful after a security incident. Users will receive an email with a reset link.', 'vigilante' ); ?></p> |
| @@ -4367,9 +5107,9 @@ | ||
| 4367 | 5107 | <?php |
| 4368 | 5108 | $user_security = new Vigilante_User_Security( $this->settings, $this->activity_log ); |
| 4369 | 5109 | $pending_users = $user_security->get_pending_users(); |
| 4370 | 5110 | ?> |
| 4371 | - <div class="vigilante-tool-box vigilante-pending-users-section"> | |
| 5111 | + <div id="vigilante-section-users-pending" class="vigilante-tool-box vigilante-pending-users-section"> | |
| 4372 | 5112 | <h3> |
| 4373 | 5113 | <?php esc_html_e( 'Pending registrations', 'vigilante' ); ?> |
| 4374 | 5114 | <?php if ( count( $pending_users ) > 0 ) : ?> |
| 4375 | 5115 | <span class="vigilante-badge vigilante-badge-warning"><?php echo esc_html( count( $pending_users ) ); ?></span> |
| @@ -4386,8 +5126,9 @@ | ||
| 4386 | 5126 | <span class="dashicons dashicons-yes-alt"></span> |
| 4387 | 5127 | <p><?php esc_html_e( 'No pending registrations.', 'vigilante' ); ?></p> |
| 4388 | 5128 | </div> |
| 4389 | 5129 | <?php else : ?> |
| 5130 | + <?php $this->render_user_actions_notice(); ?> | |
| 4390 | 5131 | <table class="wp-list-table widefat fixed striped vigilante-pending-users-table"> |
| 4391 | 5132 | <thead> |
| 4392 | 5133 | <tr> |
| 4393 | 5134 | <th><?php esc_html_e( 'User', 'vigilante' ); ?></th> |
| @@ -4416,12 +5157,12 @@ | ||
| 4416 | 5157 | } |
| 4417 | 5158 | ?> |
| 4418 | 5159 | </td> |
| 4419 | 5160 | <td> |
| 4420 | - <button type="button" class="button button-small vigilante-approve-user" data-user-id="<?php echo esc_attr( $pending_user->ID ); ?>"> | |
| 5161 | + <button type="button" class="button button-small vigilante-approve-user" data-user-id="<?php echo esc_attr( $pending_user->ID ); ?>" <?php disabled( $this->user_actions_locked() ); ?>> | |
| 4421 | 5162 | <?php esc_html_e( 'Approve', 'vigilante' ); ?> |
| 4422 | 5163 | </button> |
| 4423 | - <button type="button" class="button button-small vigilante-reject-user" data-user-id="<?php echo esc_attr( $pending_user->ID ); ?>" style="color: #d63638;"> | |
| 5164 | + <button type="button" class="button button-small vigilante-reject-user" data-user-id="<?php echo esc_attr( $pending_user->ID ); ?>" style="color: #d63638;" <?php disabled( $this->user_actions_locked() ); ?>> | |
| 4424 | 5165 | <?php esc_html_e( 'Reject', 'vigilante' ); ?> |
| 4425 | 5166 | </button> |
| 4426 | 5167 | </td> |
| 4427 | 5168 | </tr> |
| @@ -4543,8 +5284,10 @@ | ||
| 4543 | 5284 | </button> |
| 4544 | 5285 | </p> |
| 4545 | 5286 | </div> |
| 4546 | 5287 | </div> |
| 5288 | + | |
| 5289 | + <?php endif; ?> | |
| 4547 | 5290 | </div> |
| 4548 | 5291 | <?php |
| 4549 | 5292 | } |
| 4550 | 5293 | |
| @@ -4556,9 +5299,11 @@ | ||
| 4556 | 5299 | $options = $this->settings->get_section( 'wp_hardening' ); |
| 4557 | 5300 | ?> |
| 4558 | 5301 | <form class="vigilante-settings-form <?php echo $is_disabled ? 'vigilante-form-disabled' : ''; ?>" data-section="wp_hardening" <?php echo $is_disabled ? 'inert' : ''; ?>> |
| 4559 | 5302 | <!-- Database Hardening (outside form save flow - uses its own AJAX action) --> |
| 4560 | - <div id="vigilante-section-hardening-database" class="vigilante-settings-section"> | |
| 5303 | + <?php $vg_shared_locked = $this->shared_files_locked(); ?> | |
| 5304 | + <?php $this->render_shared_files_notice(); ?> | |
| 5305 | + <div id="vigilante-section-hardening-database" class="vigilante-settings-section <?php echo $vg_shared_locked ? 'vigilante-form-disabled' : ''; ?>" <?php echo $vg_shared_locked ? 'inert' : ''; ?>> | |
| 4561 | 5306 | <h2> |
| 4562 | 5307 | <?php esc_html_e( 'Database Hardening', 'vigilante' ); ?> |
| 4563 | 5308 | <span class="vigilante-method-badge database"><?php esc_html_e( 'Database', 'vigilante' ); ?></span> |
| 4564 | 5309 | <span class="vigilante-method-badge config"><?php esc_html_e( 'WP-CONFIG', 'vigilante' ); ?></span> |
| @@ -4570,8 +5315,14 @@ | ||
| 4570 | 5315 | $current_prefix = $db_prefix->get_current_prefix(); |
| 4571 | 5316 | $is_default = $db_prefix->is_default_prefix(); |
| 4572 | 5317 | ?> |
| 4573 | 5318 | |
| 5319 | + <?php if ( is_multisite() && ! $vg_shared_locked ) : ?> | |
| 5320 | + <div class="notice notice-warning inline" style="margin:10px 0 16px;padding:8px 12px;"> | |
| 5321 | + <p style="margin:0;"><?php esc_html_e( 'Network-wide operation: it renames the tables of every site in the network and rewrites the wp-config.php they all share. Back up the whole database first, not just the main site.', 'vigilante' ); ?></p> | |
| 5322 | + </div> | |
| 5323 | + <?php endif; ?> | |
| 5324 | + | |
| 4574 | 5325 | <table class="form-table"> |
| 4575 | 5326 | <tr> |
| 4576 | 5327 | <th scope="row"><?php esc_html_e( 'Current prefix', 'vigilante' ); ?></th> |
| 4577 | 5328 | <td> |
| @@ -4626,9 +5377,16 @@ | ||
| 4626 | 5377 | </table> |
| 4627 | 5378 | </div> |
| 4628 | 5379 | |
| 4629 | 5380 | <!-- wp-config Security --> |
| 4630 | - <div id="vigilante-section-hardening-wpconfig" class="vigilante-settings-section"> | |
| 5381 | + <?php | |
| 5382 | + $vg_shared_locked = $this->shared_files_locked(); | |
| 5383 | + // Paint what is actually in force, not this site's unused copy. | |
| 5384 | + $vg_local_options = $options; | |
| 5385 | + $options = $this->get_section_for_display( 'wp_hardening' ); | |
| 5386 | + ?> | |
| 5387 | + <?php $this->render_shared_files_notice(); ?> | |
| 5388 | + <div id="vigilante-section-hardening-wpconfig" class="vigilante-settings-section <?php echo $vg_shared_locked ? 'vigilante-form-disabled' : ''; ?>" <?php echo $vg_shared_locked ? 'inert' : ''; ?>> | |
| 4631 | 5389 | <h2> |
| 4632 | 5390 | <?php esc_html_e( 'wp-config.php Security', 'vigilante' ); ?> |
| 4633 | 5391 | <span class="vigilante-method-badge config"><?php esc_html_e( 'WP-CONFIG', 'vigilante' ); ?></span> |
| 4634 | 5392 | </h2> |
| @@ -4693,10 +5451,40 @@ | ||
| 4693 | 5451 | </td> |
| 4694 | 5452 | </tr> |
| 4695 | 5453 | </table> |
| 4696 | 5454 | </div> |
| 5455 | + <?php $options = $vg_local_options; ?> | |
| 4697 | 5456 | |
| 4698 | 5457 | <!-- Comment Security --> |
| 5458 | + <div id="vigilante-section-hardening-xmlrpc" class="vigilante-settings-section"> | |
| 5459 | + <h2> | |
| 5460 | + <?php esc_html_e( 'XML-RPC', 'vigilante' ); ?> | |
| 5461 | + <span class="vigilante-method-badge php"><?php esc_html_e( 'PHP', 'vigilante' ); ?></span> | |
| 5462 | + </h2> | |
| 5463 | + <p><?php esc_html_e( 'The legacy remote interface. It is what the WordPress mobile app, Jetpack and remote managers talk to, and also the way pingback amplification and password guessing reach a site.', 'vigilante' ); ?></p> | |
| 5464 | + | |
| 5465 | + <table class="form-table"> | |
| 5466 | + <tr id="field-disable-xmlrpc"> | |
| 5467 | + <th scope="row"><label for="vigilante-f-wp-hardening-xmlrpc-mode"><?php esc_html_e( 'XML-RPC access', 'vigilante' ); ?></label></th> | |
| 5468 | + <td> | |
| 5469 | + <?php $vig_xmlrpc_mode = Vigilante_Comment_Security::resolve_xmlrpc_mode( $this->settings ); ?> | |
| 5470 | + <select id="vigilante-f-wp-hardening-xmlrpc-mode" name="wp_hardening[xmlrpc_mode]"> | |
| 5471 | + <option value="none" <?php selected( $vig_xmlrpc_mode, 'none' ); ?>> | |
| 5472 | + <?php esc_html_e( 'Leave XML-RPC enabled', 'vigilante' ); ?> | |
| 5473 | + </option> | |
| 5474 | + <option value="pingback" <?php selected( $vig_xmlrpc_mode, 'pingback' ); ?>> | |
| 5475 | + <?php esc_html_e( 'Block the pingback methods only', 'vigilante' ); ?> | |
| 5476 | + </option> | |
| 5477 | + <option value="full" <?php selected( $vig_xmlrpc_mode, 'full' ); ?>> | |
| 5478 | + <?php esc_html_e( 'Disable XML-RPC completely (recommended)', 'vigilante' ); ?> | |
| 5479 | + </option> | |
| 5480 | + </select> | |
| 5481 | + <p class="description"><?php esc_html_e( 'Disable it completely unless something still needs it, such as the WordPress mobile app, Jetpack or a remote manager; in that case block only the pingback methods, which closes the amplification vector and leaves the rest working. Pingbacks are also covered by the Comment Security setting just below, which additionally closes them for comments.', 'vigilante' ); ?></p> | |
| 5482 | + </td> | |
| 5483 | + </tr> | |
| 5484 | + </table> | |
| 5485 | + </div> | |
| 5486 | + | |
| 4699 | 5487 | <div id="vigilante-section-hardening-comments" class="vigilante-settings-section"> |
| 4700 | 5488 | <h2> |
| 4701 | 5489 | <?php esc_html_e( 'Comment Security', 'vigilante' ); ?> |
| 4702 | 5490 | <span class="vigilante-method-badge php"><?php esc_html_e( 'PHP', 'vigilante' ); ?></span> |
| @@ -4738,10 +5526,10 @@ | ||
| 4738 | 5526 | <label> |
| 4739 | 5527 | <input type="checkbox" name="wp_hardening[close_old_comments]" value="1" <?php checked( ! empty( $options['close_old_comments'] ) ); ?>> |
| 4740 | 5528 | <?php esc_html_e( 'Automatically close comments on old posts after', 'vigilante' ); ?> |
| 4741 | 5529 | </label> |
| 4742 | - <input type="number" name="wp_hardening[close_comments_after_days]" value="<?php echo esc_attr( $options['close_comments_after_days'] ?? 30 ); ?>" min="1" max="365" class="small-text"> | |
| 4743 | - <?php esc_html_e( 'days', 'vigilante' ); ?> | |
| 5530 | + <input type="number" id="vigilante-f-wp-hardening-close-comments-after-days" name="wp_hardening[close_comments_after_days]" value="<?php echo esc_attr( $options['close_comments_after_days'] ?? 30 ); ?>" min="1" max="365" class="small-text"> | |
| 5531 | + <label for="vigilante-f-wp-hardening-close-comments-after-days"><?php esc_html_e( 'days', 'vigilante' ); ?></label> | |
| 4744 | 5532 | </td> |
| 4745 | 5533 | </tr> |
| 4746 | 5534 | <tr> |
| 4747 | 5535 | <th scope="row"><?php esc_html_e( 'Honeypot Protection', 'vigilante' ); ?></th> |
| @@ -4893,13 +5681,13 @@ | ||
| 4893 | 5681 | <table class="form-table"> |
| 4894 | 5682 | <tr> |
| 4895 | 5683 | <th scope="row"><?php esc_html_e( 'Retention', 'vigilante' ); ?></th> |
| 4896 | 5684 | <td> |
| 4897 | - <input type="number" name="activity_log[retention_days]" value="<?php echo esc_attr( $options['retention_days'] ?? 30 ); ?>" min="7" max="365" class="small-text"> | |
| 4898 | - <?php esc_html_e( 'days', 'vigilante' ); ?> | |
| 5685 | + <input type="number" id="vigilante-f-activity-log-retention-days" name="activity_log[retention_days]" value="<?php echo esc_attr( $options['retention_days'] ?? 30 ); ?>" min="7" max="365" class="small-text"> | |
| 5686 | + <label for="vigilante-f-activity-log-retention-days"><?php esc_html_e( 'days', 'vigilante' ); ?></label> | |
| 4899 | 5687 | |
| 4900 | - <input type="number" name="activity_log[max_entries]" value="<?php echo esc_attr( $options['max_entries'] ?? 10000 ); ?>" min="100" max="100000" step="100" class="small-text"> | |
| 4901 | - <?php esc_html_e( 'max entries', 'vigilante' ); ?> | |
| 5688 | + <input type="number" id="vigilante-f-activity-log-max-entries" name="activity_log[max_entries]" value="<?php echo esc_attr( $options['max_entries'] ?? 10000 ); ?>" min="100" max="100000" step="100" class="small-text"> | |
| 5689 | + <label for="vigilante-f-activity-log-max-entries"><?php esc_html_e( 'max entries', 'vigilante' ); ?></label> | |
| 4902 | 5690 | <p class="description"><?php esc_html_e( 'Whichever limit is reached first takes effect. Changes apply immediately on save; daily maintenance also enforces these limits automatically.', 'vigilante' ); ?></p> |
| 4903 | 5691 | </td> |
| 4904 | 5692 | </tr> |
| 4905 | 5693 | <tr> |
| @@ -4924,14 +5712,14 @@ | ||
| 4924 | 5712 | </div> |
| 4925 | 5713 | </td> |
| 4926 | 5714 | </tr> |
| 4927 | 5715 | <tr> |
| 4928 | - <th scope="row"><?php esc_html_e( 'Option Tracking', 'vigilante' ); ?></th> | |
| 5716 | + <th scope="row"><label for="vigilante-f-activity-log-tracked-options"><?php esc_html_e( 'Option Tracking', 'vigilante' ); ?></label></th> | |
| 4929 | 5717 | <td> |
| 4930 | 5718 | <p class="description" style="margin-top:0;"><?php esc_html_e( 'When "WordPress option changes" is enabled, Vigilant tracks ~30 core WordPress settings (site URL, admin email, registration, active plugins, theme, comments, privacy, etc.). Use the field below to track additional options from other plugins.', 'vigilante' ); ?></p> |
| 4931 | 5719 | <br> |
| 4932 | 5720 | <label><?php esc_html_e( 'Additional options to track:', 'vigilante' ); ?></label><br> |
| 4933 | - <textarea name="activity_log[tracked_options]" rows="3" cols="50" class="regular-text code" placeholder="woocommerce_ seopress_ wpforms_"><?php echo esc_textarea( implode( "\n", $options['tracked_options'] ?? array() ) ); ?></textarea> | |
| 5721 | + <textarea id="vigilante-f-activity-log-tracked-options" name="activity_log[tracked_options]" rows="3" cols="50" class="regular-text code" placeholder="woocommerce_ seopress_ wpforms_"><?php echo esc_textarea( implode( "\n", $options['tracked_options'] ?? array() ) ); ?></textarea> | |
| 4934 | 5722 | <p class="description"><?php esc_html_e( 'One option name per line. Use a trailing underscore to match all options with that prefix (e.g. "woocommerce_" tracks all WooCommerce settings).', 'vigilante' ); ?></p> |
| 4935 | 5723 | </td> |
| 4936 | 5724 | </tr> |
| 4937 | 5725 | <tr> |
| @@ -4938,15 +5726,15 @@ | ||
| 4938 | 5726 | <th scope="row"><?php esc_html_e( 'Exclusions', 'vigilante' ); ?></th> |
| 4939 | 5727 | <td> |
| 4940 | 5728 | <div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(220px, 1fr)); gap:16px; max-width:600px;"> |
| 4941 | 5729 | <div> |
| 4942 | - <label><?php esc_html_e( 'Excluded user IDs:', 'vigilante' ); ?></label><br> | |
| 4943 | - <textarea name="activity_log[excluded_users]" rows="3" cols="25"><?php echo esc_textarea( implode( "\n", $options['excluded_users'] ?? array() ) ); ?></textarea> | |
| 5730 | + <label for="vigilante-f-activity-log-excluded-users"><?php esc_html_e( 'Excluded user IDs:', 'vigilante' ); ?></label><br> | |
| 5731 | + <textarea id="vigilante-f-activity-log-excluded-users" name="activity_log[excluded_users]" rows="3" cols="25"><?php echo esc_textarea( implode( "\n", $options['excluded_users'] ?? array() ) ); ?></textarea> | |
| 4944 | 5732 | <p class="description"><?php esc_html_e( 'One user ID per line. Actions by these users will not be logged.', 'vigilante' ); ?></p> |
| 4945 | 5733 | </div> |
| 4946 | 5734 | <div> |
| 4947 | - <label><?php esc_html_e( 'Excluded IPs:', 'vigilante' ); ?></label><br> | |
| 4948 | - <textarea name="activity_log[excluded_ips]" rows="3" cols="25"><?php echo esc_textarea( implode( "\n", $options['excluded_ips'] ?? array() ) ); ?></textarea> | |
| 5735 | + <label for="vigilante-f-activity-log-excluded-ips"><?php esc_html_e( 'Excluded IPs:', 'vigilante' ); ?></label><br> | |
| 5736 | + <textarea id="vigilante-f-activity-log-excluded-ips" name="activity_log[excluded_ips]" rows="3" cols="25"><?php echo esc_textarea( implode( "\n", $options['excluded_ips'] ?? array() ) ); ?></textarea> | |
| 4949 | 5737 | <p class="description"><?php esc_html_e( 'One IP per line. Requests from these IPs will not be logged.', 'vigilante' ); ?></p> |
| 4950 | 5738 | </div> |
| 4951 | 5739 | </div> |
| 4952 | 5740 | </td> |
| @@ -4995,11 +5783,11 @@ | ||
| 4995 | 5783 | <p class="description"><?php esc_html_e( 'Sends one email per event type, then waits for the cooldown below before repeating, so a burst of the same event is a single notice.', 'vigilante' ); ?></p> |
| 4996 | 5784 | </td> |
| 4997 | 5785 | </tr> |
| 4998 | 5786 | <tr> |
| 4999 | - <th scope="row"><?php esc_html_e( 'Alert on severity', 'vigilante' ); ?></th> | |
| 5787 | + <th scope="row"><label for="vigilante-f-audit-alerts-immediate-min-severity"><?php esc_html_e( 'Alert on severity', 'vigilante' ); ?></label></th> | |
| 5000 | 5788 | <td> |
| 5001 | - <select name="audit_alerts[immediate][min_severity]"> | |
| 5789 | + <select id="vigilante-f-audit-alerts-immediate-min-severity" name="audit_alerts[immediate][min_severity]"> | |
| 5002 | 5790 | <option value="critical" <?php selected( $alert_severity, 'critical' ); ?>><?php esc_html_e( 'Critical only (recommended)', 'vigilante' ); ?></option> |
| 5003 | 5791 | <option value="warning" <?php selected( $alert_severity, 'warning' ); ?>><?php esc_html_e( 'Warning and Critical', 'vigilante' ); ?></option> |
| 5004 | 5792 | </select> |
| 5005 | 5793 | <p class="description"><?php esc_html_e( 'A new administrator, a closed plugin or a privilege escalation are all logged as Critical, so "Critical only" already covers them.', 'vigilante' ); ?></p> |
| @@ -5015,11 +5803,11 @@ | ||
| 5015 | 5803 | <p class="description"><?php esc_html_e( 'Catches an attack in progress, e.g. hundreds of firewall blocks or login failures in an hour.', 'vigilante' ); ?></p> |
| 5016 | 5804 | </td> |
| 5017 | 5805 | </tr> |
| 5018 | 5806 | <tr> |
| 5019 | - <th scope="row"><?php esc_html_e( 'Time window', 'vigilante' ); ?></th> | |
| 5807 | + <th scope="row"><label for="vigilante-f-audit-alerts-threshold-window"><?php esc_html_e( 'Time window', 'vigilante' ); ?></label></th> | |
| 5020 | 5808 | <td> |
| 5021 | - <select name="audit_alerts[threshold][window]"> | |
| 5809 | + <select id="vigilante-f-audit-alerts-threshold-window" name="audit_alerts[threshold][window]"> | |
| 5022 | 5810 | <option value="30m" <?php selected( $alert_window, '30m' ); ?>><?php esc_html_e( '30 minutes', 'vigilante' ); ?></option> |
| 5023 | 5811 | <option value="1h" <?php selected( $alert_window, '1h' ); ?>><?php esc_html_e( '1 hour', 'vigilante' ); ?></option> |
| 5024 | 5812 | <option value="6h" <?php selected( $alert_window, '6h' ); ?>><?php esc_html_e( '6 hours', 'vigilante' ); ?></option> |
| 5025 | 5813 | <option value="24h" <?php selected( $alert_window, '24h' ); ?>><?php esc_html_e( '24 hours', 'vigilante' ); ?></option> |
| @@ -5046,10 +5834,10 @@ | ||
| 5046 | 5834 | </tr> |
| 5047 | 5835 | <tr> |
| 5048 | 5836 | <th scope="row"><?php esc_html_e( "Don't repeat alerts", 'vigilante' ); ?></th> |
| 5049 | 5837 | <td> |
| 5050 | - <input type="number" name="audit_alerts[cooldown_minutes]" value="<?php echo esc_attr( isset( $alerts['cooldown_minutes'] ) ? (int) $alerts['cooldown_minutes'] : 60 ); ?>" min="0" max="1440" class="small-text"> | |
| 5051 | - <?php esc_html_e( 'minutes', 'vigilante' ); ?> | |
| 5838 | + <input type="number" id="vigilante-f-audit-alerts-cooldown-minutes" name="audit_alerts[cooldown_minutes]" value="<?php echo esc_attr( isset( $alerts['cooldown_minutes'] ) ? (int) $alerts['cooldown_minutes'] : 60 ); ?>" min="0" max="1440" class="small-text"> | |
| 5839 | + <label for="vigilante-f-audit-alerts-cooldown-minutes"><?php esc_html_e( 'minutes', 'vigilante' ); ?></label> | |
| 5052 | 5840 | <p class="description"><?php esc_html_e( 'After an alert, Vigilant waits this long before sending another about the same thing: the same event type for immediate alerts, or the same category for threshold alerts. This prevents a flood during a sustained attack. Applies to both alert types above.', 'vigilante' ); ?></p> |
| 5053 | 5841 | </td> |
| 5054 | 5842 | </tr> |
| 5055 | 5843 | |
| @@ -5122,10 +5910,10 @@ | ||
| 5122 | 5910 | $ua_blacklist = $firewall_options['ua_blacklist'] ?? array(); |
| 5123 | 5911 | ?> |
| 5124 | 5912 | |
| 5125 | 5913 | <div class="vigilante-log-filters"> |
| 5126 | - <input type="text" id="vigilante-log-search" size="1" placeholder="<?php esc_attr_e( 'Search logs (min. 3 characters)...', 'vigilante' ); ?>" class="vigilante-log-search-input"> | |
| 5127 | - <select id="vigilante-log-type-filter"> | |
| 5914 | + <input type="text" id="vigilante-log-search" aria-label="<?php esc_attr_e( 'Search the activity log', 'vigilante' ); ?>" size="1" placeholder="<?php esc_attr_e( 'Search logs (min. 3 characters)...', 'vigilante' ); ?>" class="vigilante-log-search-input"> | |
| 5915 | + <select id="vigilante-log-type-filter" aria-label="<?php esc_attr_e( 'Filter the log by event type', 'vigilante' ); ?>"> | |
| 5128 | 5916 | <option value=""><?php esc_html_e( 'All Types', 'vigilante' ); ?></option> |
| 5129 | 5917 | <option value="login"><?php esc_html_e( 'Login', 'vigilante' ); ?></option> |
| 5130 | 5918 | <option value="user"><?php esc_html_e( 'User', 'vigilante' ); ?></option> |
| 5131 | 5919 | <option value="content"><?php esc_html_e( 'Content', 'vigilante' ); ?></option> |
| @@ -5138,15 +5926,15 @@ | ||
| 5138 | 5926 | <option value="file"><?php esc_html_e( 'File', 'vigilante' ); ?></option> |
| 5139 | 5927 | <option value="security"><?php esc_html_e( 'Security', 'vigilante' ); ?></option> |
| 5140 | 5928 | <option value="system"><?php esc_html_e( 'System', 'vigilante' ); ?></option> |
| 5141 | 5929 | </select> |
| 5142 | - <select id="vigilante-log-severity-filter"> | |
| 5930 | + <select id="vigilante-log-severity-filter" aria-label="<?php esc_attr_e( 'Filter the log by severity', 'vigilante' ); ?>"> | |
| 5143 | 5931 | <option value=""><?php esc_html_e( 'All Severities', 'vigilante' ); ?></option> |
| 5144 | 5932 | <option value="info"><?php esc_html_e( 'Info', 'vigilante' ); ?></option> |
| 5145 | 5933 | <option value="warning"><?php esc_html_e( 'Warning', 'vigilante' ); ?></option> |
| 5146 | 5934 | <option value="critical"><?php esc_html_e( 'Critical', 'vigilante' ); ?></option> |
| 5147 | 5935 | </select> |
| 5148 | - <select id="vigilante-log-method-filter"> | |
| 5936 | + <select id="vigilante-log-method-filter" aria-label="<?php esc_attr_e( 'Filter the log by HTTP method', 'vigilante' ); ?>"> | |
| 5149 | 5937 | <option value=""><?php esc_html_e( 'All Methods', 'vigilante' ); ?></option> |
| 5150 | 5938 | <option value="GET">GET</option> |
| 5151 | 5939 | <option value="POST">POST</option> |
| 5152 | 5940 | <option value="PUT">PUT</option> |
| @@ -5213,8 +6001,9 @@ | ||
| 5213 | 6001 | 'user' => (string) ( $log->user_login ?? '' ), |
| 5214 | 6002 | 'ip' => $ip_val, |
| 5215 | 6003 | 'user_agent' => $ua_val, |
| 5216 | 6004 | 'request_method' => (string) $request_method, |
| 6005 | + 'request_uri' => Vigilante_Activity_Log::extract_request_uri( $log->extra_data ?? '' ), | |
| 5217 | 6006 | 'date' => (string) ( $log->created_at ?? '' ), |
| 5218 | 6007 | 'severity' => (string) ( $log->severity ?? 'info' ), |
| 5219 | 6008 | 'is_ip_whitelisted' => ( '' !== $ip_val && in_array( $ip_val, $ip_whitelist, true ) ), |
| 5220 | 6009 | 'is_ip_blacklisted' => ( '' !== $ip_val && in_array( $ip_val, $ip_blacklist, true ) ), |
| @@ -5267,8 +6056,13 @@ | ||
| 5267 | 6056 | */ |
| 5268 | 6057 | private function render_tab_file_integrity() { |
| 5269 | 6058 | $is_disabled = $this->render_module_disabled_notice( 'file_integrity' ); |
| 5270 | 6059 | $options = $this->settings->get_section( 'file_integrity' ); |
| 6060 | + // On the main site of a network the critical-file scan is the network's | |
| 6061 | + // canary for a change to wp-config.php or the root .htaccess, so a | |
| 6062 | + // main-site admin without network rights cannot turn it off. Since | |
| 6063 | + // 2.11.8; see Vigilante_Settings::get_main_site_file_settings(). | |
| 6064 | + $vg_main_locked = $this->main_site_files_locked(); | |
| 5271 | 6065 | $last_scan = get_option( 'vigilante_last_integrity_scan' ); |
| 5272 | 6066 | $last_results = get_option( 'vigilante_last_integrity_results' ); |
| 5273 | 6067 | $ignored_files = get_option( 'vigilante_ignored_files', array() ); |
| 5274 | 6068 | |
| @@ -5321,11 +6115,11 @@ | ||
| 5321 | 6115 | </label> |
| 5322 | 6116 | </td> |
| 5323 | 6117 | </tr> |
| 5324 | 6118 | <tr> |
| 5325 | - <th scope="row"><?php esc_html_e( 'Scan Frequency', 'vigilante' ); ?></th> | |
| 6119 | + <th scope="row"><label for="vigilante-f-file-integrity-scan-frequency"><?php esc_html_e( 'Scan Frequency', 'vigilante' ); ?></label></th> | |
| 5326 | 6120 | <td> |
| 5327 | - <select name="file_integrity[scan_frequency]"> | |
| 6121 | + <select id="vigilante-f-file-integrity-scan-frequency" name="file_integrity[scan_frequency]"> | |
| 5328 | 6122 | <option value="daily" <?php selected( $options['scan_frequency'] ?? 'daily', 'daily' ); ?>><?php esc_html_e( 'Daily', 'vigilante' ); ?></option> |
| 5329 | 6123 | <option value="weekly" <?php selected( $options['scan_frequency'] ?? 'daily', 'weekly' ); ?>><?php esc_html_e( 'Weekly', 'vigilante' ); ?></option> |
| 5330 | 6124 | </select> |
| 5331 | 6125 | </td> |
| @@ -5330,11 +6124,11 @@ | ||
| 5330 | 6124 | </select> |
| 5331 | 6125 | </td> |
| 5332 | 6126 | </tr> |
| 5333 | 6127 | <tr> |
| 5334 | - <th scope="row"><?php esc_html_e( 'Email Notifications', 'vigilante' ); ?></th> | |
| 6128 | + <th scope="row"><label for="vigilante-f-file-integrity-notify-level"><?php esc_html_e( 'Email Notifications', 'vigilante' ); ?></label></th> | |
| 5335 | 6129 | <td> |
| 5336 | - <select name="file_integrity[notify_level]"> | |
| 6130 | + <select id="vigilante-f-file-integrity-notify-level" name="file_integrity[notify_level]"> | |
| 5337 | 6131 | <option value="all" <?php selected( $notify_level, 'all' ); ?>><?php esc_html_e( 'All issues (modified + suspicious)', 'vigilante' ); ?></option> |
| 5338 | 6132 | <option value="suspicious_only" <?php selected( $notify_level, 'suspicious_only' ); ?>><?php esc_html_e( 'Suspicious files only', 'vigilante' ); ?></option> |
| 5339 | 6133 | <option value="disabled" <?php selected( $notify_level, 'disabled' ); ?>><?php esc_html_e( 'Disabled', 'vigilante' ); ?></option> |
| 5340 | 6134 | </select> |
| @@ -5394,10 +6188,13 @@ | ||
| 5394 | 6188 | <?php esc_html_e( 'Uploads directory (detect PHP files, double extensions, .htaccess)', 'vigilante' ); ?> |
| 5395 | 6189 | </label> |
| 5396 | 6190 | <br> |
| 5397 | 6191 | <label> |
| 5398 | - <input type="checkbox" name="file_integrity[scan_critical_config]" value="1" <?php checked( $options['scan_critical_config'] ?? true ); ?>> | |
| 6192 | + <input type="checkbox" name="file_integrity[scan_critical_config]" value="1" <?php disabled( $vg_main_locked ); ?> <?php checked( $options['scan_critical_config'] ?? true ); ?>> | |
| 5399 | 6193 | <?php esc_html_e( 'Critical config files (wp-config.php, .htaccess baseline monitoring)', 'vigilante' ); ?> |
| 6194 | + <?php if ( $vg_main_locked ) : ?> | |
| 6195 | + <span class="description" style="display:block;margin-left:24px;"><?php echo esc_html( Vigilante_Settings::get_shared_files_notice() ); ?></span> | |
| 6196 | + <?php endif; ?> | |
| 5400 | 6197 | </label> |
| 5401 | 6198 | <br> |
| 5402 | 6199 | <label> |
| 5403 | 6200 | <input type="checkbox" name="file_integrity[check_closed_plugins]" value="1" <?php checked( $options['check_closed_plugins'] ?? true ); ?>> |
| @@ -5406,19 +6203,30 @@ | ||
| 5406 | 6203 | </fieldset> |
| 5407 | 6204 | </td> |
| 5408 | 6205 | </tr> |
| 5409 | 6206 | <tr> |
| 5410 | - <th scope="row"><?php esc_html_e( 'Excluded Paths', 'vigilante' ); ?></th> | |
| 6207 | + <th scope="row"><label for="vigilante-f-file-integrity-excluded-paths"><?php esc_html_e( 'Excluded Paths', 'vigilante' ); ?></label></th> | |
| 5411 | 6208 | <td> |
| 5412 | - <textarea name="file_integrity[excluded_paths]" rows="4" class="large-text code" placeholder="wp-content/cache wp-content/languages"><?php echo esc_textarea( implode( "\n", $options['excluded_paths'] ?? array() ) ); ?></textarea> | |
| 5413 | - <p class="description"><?php esc_html_e( 'One path per line (relative to WordPress root). Files within these paths will be skipped during scans.', 'vigilante' ); ?></p> | |
| 6209 | + <textarea id="vigilante-f-file-integrity-excluded-paths" name="file_integrity[excluded_paths]" rows="4" class="large-text code" placeholder="wp-content/cache wp-content/languages"><?php echo esc_textarea( implode( "\n", $options['excluded_paths'] ?? array() ) ); ?></textarea> | |
| 6210 | + <p class="description"><?php esc_html_e( 'One path per line, relative to the WordPress root. A path such as wp-content/cache excludes exactly that folder and everything under it. A name on its own, such as cache, excludes any folder called exactly that, wherever it is.', 'vigilante' ); ?></p> | |
| 5414 | 6211 | </td> |
| 5415 | 6212 | </tr> |
| 5416 | 6213 | <tr> |
| 5417 | - <th scope="row"><?php esc_html_e( 'Excluded Extensions', 'vigilante' ); ?></th> | |
| 6214 | + <th scope="row"><label for="vigilante-f-file-integrity-excluded-extensions"><?php esc_html_e( 'Excluded Extensions', 'vigilante' ); ?></label></th> | |
| 5418 | 6215 | <td> |
| 5419 | - <textarea name="file_integrity[excluded_extensions]" rows="3" class="large-text code" placeholder=".log .po .mo .pot"><?php echo esc_textarea( implode( "\n", $options['excluded_extensions'] ?? array() ) ); ?></textarea> | |
| 5420 | - <p class="description"><?php esc_html_e( 'One extension per line (e.g. .log, .po, .mo). Files with these extensions will be skipped. Useful to avoid false positives from translation or log files.', 'vigilante' ); ?></p> | |
| 6216 | + <textarea id="vigilante-f-file-integrity-excluded-extensions" name="file_integrity[excluded_extensions]" rows="3" class="large-text code" placeholder=".log .po .mo .pot"><?php echo esc_textarea( implode( "\n", $options['excluded_extensions'] ?? array() ) ); ?></textarea> | |
| 6217 | + <p class="description"> | |
| 6218 | + <?php esc_html_e( 'One extension per line (e.g. .log, .po, .mo). Files with these extensions will be skipped. Useful to avoid false positives from translation or log files.', 'vigilante' ); ?> | |
| 6219 | + <br> | |
| 6220 | + <?php | |
| 6221 | + printf( | |
| 6222 | + /* translators: 1: opening <code>, 2: closing </code>. Placeholders wrap the scoped-extension example. */ | |
| 6223 | + esc_html__( 'An extension on its own applies to the whole site. To limit it to one folder, write it as %1$swp-content/languages/*.json%2$s, which leaves the same extension watched everywhere else.', 'vigilante' ), | |
| 6224 | + '<code>', | |
| 6225 | + '</code>' | |
| 6226 | + ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- HTML tags are hardcoded. | |
| 6227 | + ?> | |
| 6228 | + </p> | |
| 5421 | 6229 | </td> |
| 5422 | 6230 | </tr> |
| 5423 | 6231 | </table> |
| 5424 | 6232 | </div> |
| @@ -5665,9 +6473,15 @@ | ||
| 5665 | 6473 | $crit_diff = $crit_item['diff'] ?? array(); |
| 5666 | 6474 | $crit_id = sanitize_html_class( $crit_file ); |
| 5667 | 6475 | $added_count = is_array( $crit_diff ) ? count( $crit_diff['added'] ?? array() ) : 0; |
| 5668 | 6476 | $removed_count = is_array( $crit_diff ) ? count( $crit_diff['removed'] ?? array() ) : 0; |
| 5669 | - $diff_unavailable = is_array( $crit_diff ) && ! empty( $crit_diff['unavailable'] ); | |
| 6477 | + // The lines of a shared file are for whoever approves it. Results | |
| 6478 | + // stored before 2.11.8 on the main site still carry them, so the | |
| 6479 | + // screen asks too, not only the scan that wrote them. | |
| 6480 | + $diff_network = ( is_array( $crit_diff ) && ! empty( $crit_diff['network'] ) ) || $this->critical_approval_locked(); | |
| 6481 | + $diff_rescan = is_array( $crit_diff ) && ! empty( $crit_diff['rescan'] ); | |
| 6482 | + $diff_redaction = is_array( $crit_diff ) && ! empty( $crit_diff['redaction'] ); | |
| 6483 | + $diff_unavailable = $diff_network || ( is_array( $crit_diff ) && ! empty( $crit_diff['unavailable'] ) ); | |
| 5670 | 6484 | ?> |
| 5671 | 6485 | <tr> |
| 5672 | 6486 | <td><code style="color: #e36210;"><?php echo esc_html( $crit_file ); ?></code></td> |
| 5673 | 6487 | <td> |
| @@ -5690,18 +6504,36 @@ | ||
| 5690 | 6504 | <td> |
| 5691 | 6505 | <button type="button" class="button button-small vigilante-toggle-critical-content" data-target="vigilante-critical-content-<?php echo esc_attr( $crit_id ); ?>" data-label-show="<?php esc_attr_e( 'Review changes', 'vigilante' ); ?>" data-label-hide="<?php esc_attr_e( 'Hide changes', 'vigilante' ); ?>"> |
| 5692 | 6506 | <?php esc_html_e( 'Review changes', 'vigilante' ); ?> |
| 5693 | 6507 | </button> |
| 5694 | - <button type="button" class="button button-small button-primary vigilante-approve-critical-file" data-file="<?php echo esc_attr( $crit_file ); ?>"> | |
| 5695 | - <?php esc_html_e( 'Approve', 'vigilante' ); ?> | |
| 5696 | - </button> | |
| 6508 | + <?php if ( $this->critical_approval_locked() ) : ?> | |
| 6509 | + <span class="description" style="display:block;margin-top:4px;"> | |
| 6510 | + <?php echo esc_html( $this->critical_approval_notice() ); ?> | |
| 6511 | + </span> | |
| 6512 | + <?php else : ?> | |
| 6513 | + <button type="button" class="button button-small button-primary vigilante-approve-critical-file" data-file="<?php echo esc_attr( $crit_file ); ?>"> | |
| 6514 | + <?php esc_html_e( 'Approve', 'vigilante' ); ?> | |
| 6515 | + </button> | |
| 6516 | + <?php endif; ?> | |
| 5697 | 6517 | </td> |
| 5698 | 6518 | </tr> |
| 5699 | 6519 | <tr id="vigilante-critical-content-<?php echo esc_attr( $crit_id ); ?>" class="vigilante-critical-content-row" style="display:none;"> |
| 5700 | 6520 | <td colspan="3" style="padding: 0;"> |
| 5701 | 6521 | <div class="vigilante-critical-content" style="max-height: 400px; overflow: auto; background: #fff; padding: 10px; font-size: 12px; line-height: 1.5; font-family: Consolas, Monaco, monospace; border-top: 1px solid #c3c4c7;"> |
| 5702 | - <?php if ( $diff_unavailable ) : ?> | |
| 6522 | + <?php if ( $diff_network ) : ?> | |
| 5703 | 6523 | <p style="color: #50575e; font-style: italic; margin: 0;"> |
| 6524 | + <?php esc_html_e( 'This file belongs to the whole network, so its line changes are only shown to network administrators, on the main site.', 'vigilante' ); ?> | |
| 6525 | + </p> | |
| 6526 | + <?php elseif ( $diff_rescan ) : ?> | |
| 6527 | + <p style="color: #50575e; font-style: italic; margin: 0;"> | |
| 6528 | + <?php esc_html_e( 'Run a new scan to see the line changes of this file.', 'vigilante' ); ?> | |
| 6529 | + </p> | |
| 6530 | + <?php elseif ( $diff_redaction ) : ?> | |
| 6531 | + <p style="color: #50575e; font-style: italic; margin: 0;"> | |
| 6532 | + <?php esc_html_e( 'The line changes of this file are not shown because a value in it could not be hidden safely. The change itself is still detected.', 'vigilante' ); ?> | |
| 6533 | + </p> | |
| 6534 | + <?php elseif ( $diff_unavailable ) : ?> | |
| 6535 | + <p style="color: #50575e; font-style: italic; margin: 0;"> | |
| 5704 | 6536 | <?php esc_html_e( 'Diff not available for this file (baseline was created before diff tracking was added). Approve to enable diff on future changes.', 'vigilante' ); ?> |
| 5705 | 6537 | </p> |
| 5706 | 6538 | <?php elseif ( empty( $crit_diff['added'] ) && empty( $crit_diff['removed'] ) ) : ?> |
| 5707 | 6539 | <p style="color: #50575e; font-style: italic; margin: 0;"> |
| @@ -5729,9 +6561,9 @@ | ||
| 5729 | 6561 | <?php endif; ?> |
| 5730 | 6562 | |
| 5731 | 6563 | <?php if ( $has_closed ) : ?> |
| 5732 | 6564 | <div class="vigilante-file-list vigilante-closed-plugins"> |
| 5733 | - <h3 style="color: #d63638;"><?php esc_html_e( 'Closed + Removed Plugins', 'vigilante' ); ?></h3> | |
| 6565 | + <h3 id="vigilante-section-fi-closed-plugins" style="color: #d63638;"><?php esc_html_e( 'Closed + Removed Plugins', 'vigilante' ); ?></h3> | |
| 5734 | 6566 | <p class="description" style="color: #d63638;"> |
| 5735 | 6567 | <?php esc_html_e( '⚠ Warning: These plugins have been closed in the WordPress.org repository. Closures usually indicate malware, security issues, guideline violations, or supply chain attacks. Uninstall and replace as soon as possible.', 'vigilante' ); ?> |
| 5736 | 6568 | </p> |
| 5737 | 6569 | <table class="wp-list-table widefat striped"> |
| @@ -5940,8 +6772,15 @@ | ||
| 5940 | 6772 | if ( ! current_user_can( 'manage_options' ) ) { |
| 5941 | 6773 | wp_die( esc_html__( 'Permission denied.', 'vigilante' ), 403 ); |
| 5942 | 6774 | } |
| 5943 | 6775 | |
| 6776 | + // The archive carries wp-config.php, which a whole network shares. On a | |
| 6777 | + // network manage_options is held by every subsite administrator, so the | |
| 6778 | + // same gate the writers use applies here. | |
| 6779 | + if ( ! Vigilante_Settings::can_write_shared_files() ) { | |
| 6780 | + wp_die( esc_html( Vigilante_Settings::get_shared_files_notice() ), 403 ); | |
| 6781 | + } | |
| 6782 | + | |
| 5944 | 6783 | $backup_manager = new Vigilante_Backup_Manager(); |
| 5945 | 6784 | $result = $backup_manager->stream_files_zip(); |
| 5946 | 6785 | |
| 5947 | 6786 | // stream_files_zip() exits on success; only a WP_Error returns here. |
| @@ -6030,8 +6869,29 @@ | ||
| 6030 | 6869 | |
| 6031 | 6870 | // Read ONLY saved options from database (not merged with defaults) |
| 6032 | 6871 | $saved_options = get_option( Vigilante_Settings::OPTION_NAME, array() ); |
| 6033 | 6872 | |
| 6873 | + // What is stored before this request changes anything: the shared file | |
| 6874 | + // settings this user may not change are put back from here (2.11.6). | |
| 6875 | + $stored_options = $saved_options; | |
| 6876 | + $locked = Vigilante_Settings::get_locked_file_settings(); | |
| 6877 | + | |
| 6878 | + if ( isset( $locked[ $section ] ) && true === $locked[ $section ] ) { | |
| 6879 | + wp_send_json_error( Vigilante_Settings::get_shared_files_notice() ); | |
| 6880 | + } | |
| 6881 | + | |
| 6882 | + // A module switch is a single key, so refusing says more than a success | |
| 6883 | + // that changed nothing, and the dashboard puts the toggle back. | |
| 6884 | + if ( 'modules' === $section && isset( $locked['modules'], $data['modules'] ) && is_array( $locked['modules'] ) && is_array( $data['modules'] ) ) { | |
| 6885 | + foreach ( array_keys( $data['modules'] ) as $vg_module ) { | |
| 6886 | + if ( in_array( sanitize_key( $vg_module ), $locked['modules'], true ) ) { | |
| 6887 | + wp_send_json_error( Vigilante_Settings::get_shared_files_notice() ); | |
| 6888 | + } | |
| 6889 | + } | |
| 6890 | + } | |
| 6891 | + | |
| 6892 | + $rejected_ips = array(); | |
| 6893 | + | |
| 6034 | 6894 | // Handle modules |
| 6035 | 6895 | if ( 'modules' === $section && isset( $data['modules'] ) ) { |
| 6036 | 6896 | if ( ! isset( $saved_options['modules'] ) ) { |
| 6037 | 6897 | $saved_options['modules'] = array(); |
| @@ -6049,9 +6909,16 @@ | ||
| 6049 | 6909 | $current_section = isset( $saved_options[ $section ] ) ? $saved_options[ $section ] : array(); |
| 6050 | 6910 | |
| 6051 | 6911 | // Process the submitted data |
| 6052 | 6912 | $processed = $this->process_section_data( $data[ $section ], $section_defaults, $current_section ); |
| 6053 | - | |
| 6913 | + | |
| 6914 | + // The IP boxes are free text and, until 2.9.9, whatever was typed | |
| 6915 | + // went straight into the option. An entry the matcher can never | |
| 6916 | + // match still sits in a security list looking like protection, | |
| 6917 | + // so the ones that cannot match are dropped and reported back | |
| 6918 | + // instead of being stored in silence. | |
| 6919 | + $rejected_ips = $this->filter_ip_lists( $section, $processed ); | |
| 6920 | + | |
| 6054 | 6921 | // Save the processed section |
| 6055 | 6922 | $saved_options[ $section ] = $processed; |
| 6056 | 6923 | |
| 6057 | 6924 | // Clear active preset when any section settings change |
| @@ -6061,8 +6928,10 @@ | ||
| 6061 | 6928 | |
| 6062 | 6929 | // Clear cache before saving |
| 6063 | 6930 | wp_cache_delete( Vigilante_Settings::OPTION_NAME, 'options' ); |
| 6064 | 6931 | |
| 6932 | + $saved_options = Vigilante_Settings::keep_locked_file_settings( $saved_options, $stored_options ); | |
| 6933 | + | |
| 6065 | 6934 | // Save to database |
| 6066 | 6935 | update_option( Vigilante_Settings::OPTION_NAME, $saved_options ); |
| 6067 | 6936 | |
| 6068 | 6937 | // Clear the settings cache |
| @@ -6111,12 +6980,59 @@ | ||
| 6111 | 6980 | $login_url_result['sent'] |
| 6112 | 6981 | ); |
| 6113 | 6982 | } |
| 6114 | 6983 | |
| 6984 | + if ( ! empty( $rejected_ips ) ) { | |
| 6985 | + $message .= ' ' . sprintf( | |
| 6986 | + /* translators: %s: comma separated list of the entries that were not saved. */ | |
| 6987 | + _n( | |
| 6988 | + 'This entry is not a valid IP, CIDR range or wildcard, so it was not saved: %s', | |
| 6989 | + 'These entries are not valid IPs, CIDR ranges or wildcards, so they were not saved: %s', | |
| 6990 | + count( $rejected_ips ), | |
| 6991 | + 'vigilante' | |
| 6992 | + ), | |
| 6993 | + implode( ', ', array_map( 'esc_html', $rejected_ips ) ) | |
| 6994 | + ); | |
| 6995 | + } | |
| 6996 | + | |
| 6115 | 6997 | wp_send_json_success( $message ); |
| 6116 | 6998 | } |
| 6117 | - | |
| 6999 | + | |
| 6118 | 7000 | /** |
| 7001 | + * Keep only the IP patterns the matcher can actually match | |
| 7002 | + * | |
| 7003 | + * @since 2.9.9 | |
| 7004 | + * | |
| 7005 | + * @param string $section Section being saved. | |
| 7006 | + * @param array $processed Section data, edited in place. | |
| 7007 | + * @return array Entries that were dropped, for the message back to the user. | |
| 7008 | + */ | |
| 7009 | + private function filter_ip_lists( $section, &$processed ) { | |
| 7010 | + $lists = array( | |
| 7011 | + 'firewall' => array( 'ip_whitelist', 'ip_blacklist' ), | |
| 7012 | + 'login_security' => array( 'ip_whitelist' ), | |
| 7013 | + ); | |
| 7014 | + | |
| 7015 | + if ( ! isset( $lists[ $section ] ) ) { | |
| 7016 | + return array(); | |
| 7017 | + } | |
| 7018 | + | |
| 7019 | + $rejected = array(); | |
| 7020 | + | |
| 7021 | + foreach ( $lists[ $section ] as $key ) { | |
| 7022 | + if ( ! isset( $processed[ $key ] ) || ! is_array( $processed[ $key ] ) ) { | |
| 7023 | + continue; | |
| 7024 | + } | |
| 7025 | + | |
| 7026 | + $split = Vigilante_IP_Utils::split_list( $processed[ $key ] ); | |
| 7027 | + $processed[ $key ] = $split['valid']; | |
| 7028 | + $rejected = array_merge( $rejected, $split['rejected'] ); | |
| 7029 | + } | |
| 7030 | + | |
| 7031 | + return array_values( array_unique( $rejected ) ); | |
| 7032 | + } | |
| 7033 | + | |
| 7034 | + /** | |
| 6119 | 7035 | * Send 2FA enable notifications to users |
| 6120 | 7036 | * |
| 6121 | 7037 | * @return array Result with 'sent' and 'failed' counts. |
| 6122 | 7038 | */ |
| @@ -6438,13 +7354,27 @@ | ||
| 6438 | 7354 | |
| 6439 | 7355 | // Sanitize imported data recursively |
| 6440 | 7356 | $imported = map_deep( $imported, 'sanitize_text_field' ); |
| 6441 | 7357 | |
| 6442 | - // Validate structure | |
| 6443 | - $defaults = $this->settings->get_default_options(); | |
| 6444 | - $merged = array_replace_recursive( $defaults, $imported ); | |
| 7358 | + // Validate structure: only sections and keys of the schema survive, and | |
| 7359 | + // every value takes the type of its default. Until 2.11.0 this was an | |
| 7360 | + // array_replace_recursive() of the file over the defaults, so any key in | |
| 7361 | + // the file, known or not, landed in vigilante_options (S7). Sections | |
| 7362 | + // the file does not carry keep their defaults; a section it does carry | |
| 7363 | + // replaces the default one whole, because validate_options() has | |
| 7364 | + // already filled in whatever the file left out. | |
| 7365 | + $defaults = $this->settings->get_default_options(); | |
| 7366 | + $validated = $this->settings->validate_options( $imported ); | |
| 7367 | + $merged = $defaults; | |
| 6445 | 7368 | |
| 7369 | + foreach ( $validated as $section => $data ) { | |
| 7370 | + if ( is_array( $data ) ) { | |
| 7371 | + $merged[ $section ] = $data; | |
| 7372 | + } | |
| 7373 | + } | |
| 7374 | + | |
| 6446 | 7375 | // Save |
| 7376 | + $merged = Vigilante_Settings::keep_locked_file_settings( $merged, get_option( Vigilante_Settings::OPTION_NAME, array() ) ); | |
| 6447 | 7377 | update_option( Vigilante_Settings::OPTION_NAME, $merged ); |
| 6448 | 7378 | $this->settings->clear_cache(); |
| 6449 | 7379 | |
| 6450 | 7380 | // Re-evaluate the active preset marker. The imported config may match |
| @@ -6467,9 +7397,9 @@ | ||
| 6467 | 7397 | if ( ! wp_next_scheduled( 'vigilante_under_attack_post_scan' ) ) { |
| 6468 | 7398 | wp_schedule_single_event( time() + 5, 'vigilante_under_attack_post_scan' ); |
| 6469 | 7399 | } |
| 6470 | 7400 | |
| 6471 | - wp_send_json_success( __( 'Settings imported successfully.', 'vigilante' ) ); | |
| 7401 | + wp_send_json_success( __( 'Settings imported successfully.', 'vigilante' ) . $this->locked_file_settings_message() ); | |
| 6472 | 7402 | } |
| 6473 | 7403 | |
| 6474 | 7404 | /** |
| 6475 | 7405 | * Detect whether a vigilante_options array matches a known preset. |
| @@ -6572,9 +7502,11 @@ | ||
| 6572 | 7502 | $preset = isset( $_POST['preset'] ) ? sanitize_key( $_POST['preset'] ) : ''; |
| 6573 | 7503 | |
| 6574 | 7504 | // Handle reset to defaults |
| 6575 | 7505 | if ( 'reset' === $preset ) { |
| 6576 | - $defaults = $this->settings->get_default_options(); | |
| 7506 | + $stored_options = get_option( Vigilante_Settings::OPTION_NAME, array() ); | |
| 7507 | + $defaults = Vigilante_Settings::get_defaults_preserving_user_data( $stored_options ); | |
| 7508 | + $defaults = Vigilante_Settings::keep_locked_file_settings( $defaults, $stored_options ); | |
| 6577 | 7509 | update_option( Vigilante_Settings::OPTION_NAME, $defaults ); |
| 6578 | 7510 | $this->settings->clear_cache(); |
| 6579 | 7511 | |
| 6580 | 7512 | // Clear active preset |
| @@ -6582,9 +7514,9 @@ | ||
| 6582 | 7514 | |
| 6583 | 7515 | // Apply file changes after reset |
| 6584 | 7516 | $this->apply_all_file_changes( $defaults ); |
| 6585 | 7517 | |
| 6586 | - wp_send_json_success( __( 'Settings reset to defaults.', 'vigilante' ) ); | |
| 7518 | + wp_send_json_success( __( 'Settings reset to defaults.', 'vigilante' ) . $this->locked_file_settings_message() ); | |
| 6587 | 7519 | return; |
| 6588 | 7520 | } |
| 6589 | 7521 | |
| 6590 | 7522 | $presets = $this->settings->get_presets(); |
| @@ -6605,13 +7537,14 @@ | ||
| 6605 | 7537 | $current = get_option( Vigilante_Settings::OPTION_NAME, array() ); |
| 6606 | 7538 | if ( ! is_array( $current ) ) { |
| 6607 | 7539 | $current = array(); |
| 6608 | 7540 | } |
| 6609 | - // Make sure all known keys exist before merging — array_replace_recursive | |
| 6610 | - // does not invent keys that are missing on both sides. | |
| 6611 | - $current = array_replace_recursive( $this->settings->get_default_options(), $current ); | |
| 7541 | + // Make sure all known keys exist before merging — the merge does not | |
| 7542 | + // invent keys that are missing on both sides. | |
| 7543 | + $current = Vigilante_Settings::merge_preset( $this->settings->get_default_options(), $current ); | |
| 6612 | 7544 | |
| 6613 | - $merged = array_replace_recursive( $current, $preset_options ); | |
| 7545 | + $merged = Vigilante_Settings::merge_preset( $current, $preset_options ); | |
| 7546 | + $merged = Vigilante_Settings::keep_locked_file_settings( $merged, get_option( Vigilante_Settings::OPTION_NAME, array() ) ); | |
| 6614 | 7547 | |
| 6615 | 7548 | update_option( Vigilante_Settings::OPTION_NAME, $merged ); |
| 6616 | 7549 | $this->settings->clear_cache(); |
| 6617 | 7550 | |
| @@ -6620,9 +7553,9 @@ | ||
| 6620 | 7553 | |
| 6621 | 7554 | // Apply file changes after preset |
| 6622 | 7555 | $this->apply_all_file_changes( $merged ); |
| 6623 | 7556 | |
| 6624 | - wp_send_json_success( __( 'Preset applied successfully.', 'vigilante' ) ); | |
| 7557 | + wp_send_json_success( __( 'Preset applied successfully.', 'vigilante' ) . $this->locked_file_settings_message() ); | |
| 6625 | 7558 | } |
| 6626 | 7559 | |
| 6627 | 7560 | /** |
| 6628 | 7561 | * AJAX: Reset a specific section to defaults |
| @@ -6639,11 +7572,13 @@ | ||
| 6639 | 7572 | if ( empty( $section ) ) { |
| 6640 | 7573 | wp_send_json_error( __( 'No section specified.', 'vigilante' ) ); |
| 6641 | 7574 | } |
| 6642 | 7575 | |
| 6643 | - // Get current options and defaults | |
| 7576 | + // Get current options and defaults. get_defaults_preserving_user_data() | |
| 7577 | + // applies the tweaks a fresh installation gets, so the button and a new | |
| 7578 | + // install agree, and keeps whatever the owner typed in. | |
| 6644 | 7579 | $current_options = $this->settings->get_all_options(); |
| 6645 | - $defaults = $this->settings->get_default_options(); | |
| 7580 | + $defaults = Vigilante_Settings::get_defaults_preserving_user_data( $current_options ); | |
| 6646 | 7581 | |
| 6647 | 7582 | // Check if section exists in defaults |
| 6648 | 7583 | if ( ! isset( $defaults[ $section ] ) ) { |
| 6649 | 7584 | wp_send_json_error( __( 'Invalid section.', 'vigilante' ) ); |
| @@ -6648,11 +7583,27 @@ | ||
| 6648 | 7583 | if ( ! isset( $defaults[ $section ] ) ) { |
| 6649 | 7584 | wp_send_json_error( __( 'Invalid section.', 'vigilante' ) ); |
| 6650 | 7585 | } |
| 6651 | 7586 | |
| 6652 | - // Reset only this section to defaults | |
| 6653 | - $current_options[ $section ] = $defaults[ $section ]; | |
| 7587 | + $new_values = $defaults[ $section ]; | |
| 6654 | 7588 | |
| 7589 | + /* | |
| 7590 | + * On a subsite, the settings written to wp-config.php and .htaccess are | |
| 7591 | + * the main site's business. Resetting the local copy of those would only | |
| 7592 | + * make this screen disagree with the file, so they are carried over | |
| 7593 | + * untouched, and a section that is nothing but shared settings is not | |
| 7594 | + * reset at all. On the main site, a user without network rights keeps | |
| 7595 | + * the ones the shared files are built from as well (2.11.6). | |
| 7596 | + */ | |
| 7597 | + $locked = Vigilante_Settings::get_locked_file_settings(); | |
| 7598 | + | |
| 7599 | + if ( isset( $locked[ $section ] ) && true === $locked[ $section ] ) { | |
| 7600 | + wp_send_json_error( Vigilante_Settings::get_shared_files_notice() ); | |
| 7601 | + } | |
| 7602 | + | |
| 7603 | + $current_options[ $section ] = $new_values; | |
| 7604 | + $current_options = Vigilante_Settings::keep_locked_file_settings( $current_options, get_option( Vigilante_Settings::OPTION_NAME, array() ) ); | |
| 7605 | + | |
| 6655 | 7606 | // Save |
| 6656 | 7607 | update_option( Vigilante_Settings::OPTION_NAME, $current_options ); |
| 6657 | 7608 | $this->settings->clear_cache(); |
| 6658 | 7609 | |
| @@ -6734,8 +7685,19 @@ | ||
| 6734 | 7685 | // Save new results |
| 6735 | 7686 | update_option( 'vigilante_last_integrity_scan', time() ); |
| 6736 | 7687 | update_option( 'vigilante_last_integrity_results', $results ); |
| 6737 | 7688 | |
| 7689 | + // On the main site the scan does compute the lines of wp-config.php and | |
| 7690 | + // .htaccess, for the network administrator. Somebody without network | |
| 7691 | + // rights gets the change and its sizes, not the lines. | |
| 7692 | + if ( $this->critical_approval_locked() && ! empty( $results['modified'] ) && is_array( $results['modified'] ) ) { | |
| 7693 | + foreach ( $results['modified'] as $index => $item ) { | |
| 7694 | + if ( is_array( $item ) && 'critical_config' === ( $item['type'] ?? '' ) ) { | |
| 7695 | + $results['modified'][ $index ]['diff'] = Vigilante_File_Integrity::network_only_diff(); | |
| 7696 | + } | |
| 7697 | + } | |
| 7698 | + } | |
| 7699 | + | |
| 6738 | 7700 | wp_send_json_success( array( |
| 6739 | 7701 | 'message' => __( 'Scan completed.', 'vigilante' ), |
| 6740 | 7702 | 'results' => $results, |
| 6741 | 7703 | 'ignored_count' => count( get_option( 'vigilante_ignored_files', array() ) ), |
| @@ -6769,11 +7731,41 @@ | ||
| 6769 | 7731 | if ( ! current_user_can( 'manage_options' ) ) { |
| 6770 | 7732 | wp_send_json_error( __( 'Permission denied.', 'vigilante' ) ); |
| 6771 | 7733 | } |
| 6772 | 7734 | |
| 7735 | + $results = get_option( 'vigilante_last_integrity_results' ); | |
| 7736 | + $scanned_at = get_option( 'vigilante_last_integrity_scan' ); | |
| 7737 | + | |
| 6773 | 7738 | delete_option( 'vigilante_last_integrity_results' ); |
| 6774 | 7739 | delete_option( 'vigilante_last_integrity_scan' ); |
| 6775 | 7740 | |
| 7741 | + /* | |
| 7742 | + * A pending change to wp-config.php or the root .htaccess is closed by | |
| 7743 | + * approving it, which takes the network. Clearing the results was one | |
| 7744 | + * more way to close it without, until the next scan: the ignore list was | |
| 7745 | + * shut in 2.11.8 and this button was left open, found by the cross | |
| 7746 | + * review of 2.11.8. So for somebody who cannot approve, those entries | |
| 7747 | + * stay and everything else goes. | |
| 7748 | + */ | |
| 7749 | + if ( $this->critical_approval_locked() && is_array( $results ) && ! empty( $results['modified'] ) && is_array( $results['modified'] ) ) { | |
| 7750 | + $critical = array_values( | |
| 7751 | + array_filter( | |
| 7752 | + $results['modified'], | |
| 7753 | + function ( $item ) { | |
| 7754 | + return is_array( $item ) && 'critical_config' === ( $item['type'] ?? '' ); | |
| 7755 | + } | |
| 7756 | + ) | |
| 7757 | + ); | |
| 7758 | + | |
| 7759 | + if ( $critical ) { | |
| 7760 | + $results['modified'] = $critical; | |
| 7761 | + $results['suspicious'] = array(); | |
| 7762 | + $results['extra'] = array(); | |
| 7763 | + update_option( 'vigilante_last_integrity_results', $results ); | |
| 7764 | + update_option( 'vigilante_last_integrity_scan', $scanned_at ? $scanned_at : time() ); | |
| 7765 | + } | |
| 7766 | + } | |
| 7767 | + | |
| 6776 | 7768 | if ( $this->database ) { |
| 6777 | 7769 | $this->database->clear_file_hashes(); |
| 6778 | 7770 | } |
| 6779 | 7771 | |
| @@ -6799,8 +7791,14 @@ | ||
| 6799 | 7791 | if ( empty( $file ) ) { |
| 6800 | 7792 | wp_send_json_error( __( 'No file specified.', 'vigilante' ) ); |
| 6801 | 7793 | } |
| 6802 | 7794 | |
| 7795 | + // A change to a shared file is closed by approving it, and approving it | |
| 7796 | + // takes the network. Ignoring it would close the same warning without. | |
| 7797 | + if ( $this->critical_approval_locked() && in_array( $file, array( 'wp-config.php', '.htaccess' ), true ) ) { | |
| 7798 | + wp_send_json_error( $this->critical_approval_notice() ); | |
| 7799 | + } | |
| 7800 | + | |
| 6803 | 7801 | $file_integrity = new Vigilante_File_Integrity( $this->settings, $this->database ); |
| 6804 | 7802 | $file_integrity->ignore_file( $file ); |
| 6805 | 7803 | |
| 6806 | 7804 | // Also remove the file from stored scan results so UI updates |
| @@ -6864,12 +7862,14 @@ | ||
| 6864 | 7862 | if ( ! is_array( $raw_files ) ) { |
| 6865 | 7863 | wp_send_json_error( __( 'Invalid request.', 'vigilante' ) ); |
| 6866 | 7864 | } |
| 6867 | 7865 | |
| 6868 | - $files = array(); | |
| 7866 | + $files = array(); | |
| 7867 | + $shared = $this->critical_approval_locked() ? array( 'wp-config.php', '.htaccess' ) : array(); | |
| 6869 | 7868 | foreach ( $raw_files as $f ) { |
| 6870 | 7869 | $clean = sanitize_text_field( $f ); |
| 6871 | - if ( '' !== $clean ) { | |
| 7870 | + // Same rule as ajax_ignore_file() for the two shared files. | |
| 7871 | + if ( '' !== $clean && ! in_array( $clean, $shared, true ) ) { | |
| 6872 | 7872 | $files[] = $clean; |
| 6873 | 7873 | } |
| 6874 | 7874 | } |
| 6875 | 7875 | |