-
+
@@ -280,7 +308,7 @@ class WPSP_Two_Factor {
* @param WP_User $user User object.
*/
public function show_user_2fa_settings( $user ) {
- if ( ! Security_Pack::get_setting( 'two_factor_enabled', false ) ) {
+ if ( ! ARKSP_Plugin::get_setting( 'two_factor_enabled', false ) ) {
return;
}
@@ -288,147 +316,67 @@ class WPSP_Two_Factor {
// Show notice if 2FA is required.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
- if ( isset( $_GET['wpsp_2fa_required'] ) && ! $is_enabled ) :
+ if ( isset( $_GET['arksp_2fa_required'] ) && ! $is_enabled ) :
?>
-
+
-
__( 'Permission denied.', 'security-pack' ) ) );
+ wp_send_json_error( array( 'message' => __( 'Permission denied.', 'arkhost-security-pack' ) ) );
}
$secret = $this->generate_secret();
@@ -480,24 +428,24 @@ class WPSP_Two_Factor {
* Verify 2FA setup via AJAX.
*/
public function ajax_verify_setup() {
- check_ajax_referer( 'wpsp_2fa_setup' );
+ check_ajax_referer( 'arksp_2fa_setup' );
$user_id = isset( $_POST['user_id'] ) ? (int) $_POST['user_id'] : 0;
$code = isset( $_POST['code'] ) ? sanitize_text_field( wp_unslash( $_POST['code'] ) ) : '';
if ( ! current_user_can( 'edit_user', $user_id ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
+ wp_send_json_error( array( 'message' => __( 'Permission denied.', 'arkhost-security-pack' ) ) );
}
$pending_secret = get_user_meta( $user_id, self::SECRET_META_KEY . '_pending', true );
if ( empty( $pending_secret ) ) {
- wp_send_json_error( array( 'message' => __( 'No pending setup found.', 'security-pack' ) ) );
+ wp_send_json_error( array( 'message' => __( 'No pending setup found.', 'arkhost-security-pack' ) ) );
}
// Verify the code.
if ( ! $this->verify_totp( $pending_secret, $code ) ) {
- wp_send_json_error( array( 'message' => __( 'Invalid code. Please try again.', 'security-pack' ) ) );
+ wp_send_json_error( array( 'message' => __( 'Invalid code. Please try again.', 'arkhost-security-pack' ) ) );
}
// Enable 2FA.
@@ -511,7 +459,7 @@ class WPSP_Two_Factor {
update_user_meta( $user_id, self::BACKUP_CODES_META_KEY, $hashed_codes );
wp_send_json_success( array(
- 'message' => __( '2FA enabled successfully. Save your backup codes now - they will not be shown again!', 'security-pack' ),
+ 'message' => __( '2FA enabled successfully. Save your backup codes now - they will not be shown again!', 'arkhost-security-pack' ),
'backup_codes' => $plain_codes,
'show_codes' => true,
) );
@@ -521,31 +469,31 @@ class WPSP_Two_Factor {
* Disable 2FA via AJAX.
*/
public function ajax_disable_2fa() {
- check_ajax_referer( 'wpsp_2fa_setup' );
+ check_ajax_referer( 'arksp_2fa_setup' );
$user_id = isset( $_POST['user_id'] ) ? (int) $_POST['user_id'] : 0;
if ( ! current_user_can( 'edit_user', $user_id ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
+ wp_send_json_error( array( 'message' => __( 'Permission denied.', 'arkhost-security-pack' ) ) );
}
delete_user_meta( $user_id, self::SECRET_META_KEY );
delete_user_meta( $user_id, self::ENABLED_META_KEY );
delete_user_meta( $user_id, self::BACKUP_CODES_META_KEY );
- wp_send_json_success( array( 'message' => __( '2FA disabled.', 'security-pack' ) ) );
+ wp_send_json_success( array( 'message' => __( '2FA disabled.', 'arkhost-security-pack' ) ) );
}
/**
* Regenerate backup codes via AJAX.
*/
public function ajax_regenerate_backup_codes() {
- check_ajax_referer( 'wpsp_2fa_setup' );
+ check_ajax_referer( 'arksp_2fa_setup' );
$user_id = isset( $_POST['user_id'] ) ? (int) $_POST['user_id'] : 0;
if ( ! current_user_can( 'edit_user', $user_id ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
+ wp_send_json_error( array( 'message' => __( 'Permission denied.', 'arkhost-security-pack' ) ) );
}
// Generate new codes.
@@ -558,7 +506,7 @@ class WPSP_Two_Factor {
// Return plain codes to show user ONCE.
wp_send_json_success( array(
'codes' => $plain_codes,
- 'message' => __( 'Backup codes regenerated. Save these codes now - they will not be shown again.', 'security-pack' ),
+ 'message' => __( 'Backup codes regenerated. Save these codes now - they will not be shown again.', 'arkhost-security-pack' ),
) );
}
diff --git a/security-pack/assets/css/index.php b/arkhost-security-pack/includes/index.php
similarity index 53%
rename from security-pack/assets/css/index.php
rename to arkhost-security-pack/includes/index.php
index 91bbd2b..f39ff62 100644
--- a/security-pack/assets/css/index.php
+++ b/arkhost-security-pack/includes/index.php
@@ -2,5 +2,5 @@
/**
* Silence is golden.
*
- * @package Security_Pack
+ * @package ArkHost_Security_Pack
*/
diff --git a/security-pack/assets/index.php b/arkhost-security-pack/index.php
similarity index 53%
rename from security-pack/assets/index.php
rename to arkhost-security-pack/index.php
index 91bbd2b..f39ff62 100644
--- a/security-pack/assets/index.php
+++ b/arkhost-security-pack/index.php
@@ -2,5 +2,5 @@
/**
* Silence is golden.
*
- * @package Security_Pack
+ * @package ArkHost_Security_Pack
*/
diff --git a/arkhost-security-pack/languages/index.php b/arkhost-security-pack/languages/index.php
new file mode 100644
index 0000000..f39ff62
--- /dev/null
+++ b/arkhost-security-pack/languages/index.php
@@ -0,0 +1,6 @@
+query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_arksp_%'" );
+// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Cleanup during uninstall, caching not applicable.
+$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_arksp_%'" );
+
+// Clear scheduled events.
+wp_clear_scheduled_hook( 'arksp_daily_cleanup' );
+wp_clear_scheduled_hook( 'arksp_daily_file_scan' );
+wp_clear_scheduled_hook( 'arksp_weekly_malware_scan' );
+
+// Delete user meta for 2FA.
+// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Cleanup during uninstall, caching not applicable.
+$wpdb->query( "DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE '_arksp_%'" );
+
+// Clean up uploads directory (geo-database and quarantine files).
+$arksp_upload_dir = wp_upload_dir();
+$arksp_plugin_data = $arksp_upload_dir['basedir'] . '/arkhost-security-pack';
+if ( is_dir( $arksp_plugin_data ) ) {
+ // Recursively delete all files and subdirectories.
+ $arksp_iterator = new RecursiveIteratorIterator(
+ new RecursiveDirectoryIterator( $arksp_plugin_data, RecursiveDirectoryIterator::SKIP_DOTS ),
+ RecursiveIteratorIterator::CHILD_FIRST
+ );
+ foreach ( $arksp_iterator as $arksp_item ) {
+ if ( $arksp_item->isDir() ) {
+ // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- Uninstall cleanup.
+ rmdir( $arksp_item->getPathname() );
+ } else {
+ // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink -- Uninstall cleanup.
+ unlink( $arksp_item->getPathname() );
+ }
+ }
+ // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- Uninstall cleanup.
+ rmdir( $arksp_plugin_data );
+}
diff --git a/security-pack/assets/icon-128x128.png b/icon-images/icon-128x128.png
similarity index 100%
rename from security-pack/assets/icon-128x128.png
rename to icon-images/icon-128x128.png
diff --git a/security-pack/assets/icon-256x256.png b/icon-images/icon-256x256.png
similarity index 100%
rename from security-pack/assets/icon-256x256.png
rename to icon-images/icon-256x256.png
diff --git a/security-pack/assets/screenshot-1.png b/icon-images/screenshot-1.png
similarity index 100%
rename from security-pack/assets/screenshot-1.png
rename to icon-images/screenshot-1.png
diff --git a/security-pack/assets/screenshot-2.png b/icon-images/screenshot-2.png
similarity index 100%
rename from security-pack/assets/screenshot-2.png
rename to icon-images/screenshot-2.png
diff --git a/security-pack/assets/screenshot-3.png b/icon-images/screenshot-3.png
similarity index 100%
rename from security-pack/assets/screenshot-3.png
rename to icon-images/screenshot-3.png
diff --git a/security-pack/assets/screenshot-4.png b/icon-images/screenshot-4.png
similarity index 100%
rename from security-pack/assets/screenshot-4.png
rename to icon-images/screenshot-4.png
diff --git a/security-pack/assets/screenshot-5.png b/icon-images/screenshot-5.png
similarity index 100%
rename from security-pack/assets/screenshot-5.png
rename to icon-images/screenshot-5.png
diff --git a/security-pack/assets/screenshot-6.png b/icon-images/screenshot-6.png
similarity index 100%
rename from security-pack/assets/screenshot-6.png
rename to icon-images/screenshot-6.png
diff --git a/security-pack/assets/screenshot-7.png b/icon-images/screenshot-7.png
similarity index 100%
rename from security-pack/assets/screenshot-7.png
rename to icon-images/screenshot-7.png
diff --git a/security-pack/assets/screenshot-8.png b/icon-images/screenshot-8.png
similarity index 100%
rename from security-pack/assets/screenshot-8.png
rename to icon-images/screenshot-8.png
diff --git a/security-pack/assets/screenshot-9.png b/icon-images/screenshot-9.png
similarity index 100%
rename from security-pack/assets/screenshot-9.png
rename to icon-images/screenshot-9.png
diff --git a/security-pack/assets/security-pack-logo.png b/icon-images/security-pack-logo.png
similarity index 100%
rename from security-pack/assets/security-pack-logo.png
rename to icon-images/security-pack-logo.png
diff --git a/security-pack/README.md b/security-pack/README.md
deleted file mode 100644
index 2605bf8..0000000
--- a/security-pack/README.md
+++ /dev/null
@@ -1,103 +0,0 @@
-# Security Pack
-
-WordPress security without the bullshit. No upsells, no premium tier, no fake threat counters.
-
-## Requirements
-
-- WordPress 5.0+
-- PHP 7.4+
-
-## What It Does
-
-### Login Protection
-- Blocks IPs after failed login attempts
-- Custom login URL (hides wp-login.php)
-- Hides wp-admin from logged-out users
-- Honeypot field for bots
-- Hides login errors (stops username enumeration)
-- Email alerts for admin logins from new IPs
-- Country/IP restrictions on login page
-
-### IP Control
-- Whitelist and blacklist
-- Auto-blacklist after repeated lockouts
-- IPv4, IPv6, CIDR supported
-
-### Geo Blocking
-- Block countries
-- Uses free IP2Location LITE database
-- One-click download
-
-### Hardening
-- Disable XML-RPC
-- Disable dashboard file editing
-- Disable application passwords
-- Restrict REST API to logged-in users
-- Remove WordPress version
-- Block user enumeration (?author=1 and REST API)
-- Disable pingbacks/trackbacks
-
-### Security Headers
-X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy, Permissions-Policy, Content-Security-Policy, HSTS
-
-### Two-Factor Authentication
-- TOTP (Google Authenticator, Authy, etc.)
-- Backup codes
-- Enforce for admins
-
-### File Integrity Monitoring
-- Checks WordPress core files against official checksums
-- Daily scans
-- Email alerts on changes
-
-### Malware Scanner
-- Scans plugins, themes, uploads
-- Pattern-based detection
-- Weekly scans
-- Does not scan core files (that's what File Integrity is for)
-
-### Activity Log
-- Login attempts, lockouts, blocks
-- IP, country, username, timestamp
-- Configurable retention
-- CSV export
-
-### Tools
-- Export/import settings
-- Force logout all users
-- Test email
-
-## Installation
-
-1. Upload to `/wp-content/plugins/security-pack/`
-2. Activate
-3. Configure under Security menu
-
-## FAQ
-
-**Premium version?**
-No. This is it.
-
-**Will it slow my site?**
-No. Checks run on login and admin access, not frontend loads.
-
-**Locked myself out?**
-Rename the plugin folder via FTP/SSH. Log in. Fix settings.
-
-**Geo-blocking without database?**
-Won't work. Download IP2Location LITE from settings. It's free.
-
-**Use with other security plugins?**
-Possible but likely conflicts. Pick one.
-
-## Privacy
-
-No tracking. No analytics. No telemetry.
-
-External connections:
-- WordPress.org API (core file checksums)
-- IP2Location (database download, only when you click it)
-
-## License
-
-GPLv2 or later
diff --git a/security-pack/assets/css/admin.css b/security-pack/assets/css/admin.css
deleted file mode 100644
index 86cea20..0000000
--- a/security-pack/assets/css/admin.css
+++ /dev/null
@@ -1,524 +0,0 @@
-/**
- * WP Security Pack Admin Styles
- *
- * Clean, modern design - no scary dashboards or fake threat counters.
- */
-
-/* CSS Custom Properties */
-:root {
- --wpsp-primary: #2271b1;
- --wpsp-primary-hover: #135e96;
- --wpsp-success: #00a32a;
- --wpsp-success-bg: #edfaef;
- --wpsp-warning: #dba617;
- --wpsp-warning-bg: #fcf9e8;
- --wpsp-danger: #d63638;
- --wpsp-danger-bg: #fcf0f1;
- --wpsp-info: #72aee6;
- --wpsp-info-bg: #f0f6fc;
- --wpsp-border: #e0e0e0;
- --wpsp-border-light: #f0f0f1;
- --wpsp-text: #1d2327;
- --wpsp-text-light: #646970;
- --wpsp-bg: #fff;
- --wpsp-bg-alt: #f6f7f7;
- --wpsp-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
- --wpsp-shadow-hover: 0 2px 8px rgba(0, 0, 0, 0.08);
- --wpsp-radius: 8px;
- --wpsp-radius-sm: 4px;
- --wpsp-transition: 0.15s ease;
-}
-
-/* Main wrapper */
-.wpsp-wrap {
- max-width: 1200px;
-}
-
-.wpsp-wrap h1 {
- font-size: 24px;
- font-weight: 600;
- margin-bottom: 1.5em;
- padding: 0;
- color: var(--wpsp-text);
-}
-
-/* Tabs */
-.wpsp-tabs {
- margin-bottom: 24px;
- border-bottom: 1px solid var(--wpsp-border);
- display: flex;
- flex-wrap: wrap;
- gap: 2px;
-}
-
-.wpsp-tabs .nav-tab {
- margin-left: 0;
- margin-right: 0;
- border-radius: var(--wpsp-radius-sm) var(--wpsp-radius-sm) 0 0;
- transition: background var(--wpsp-transition), color var(--wpsp-transition);
- padding: 8px 16px;
- font-weight: 500;
-}
-
-.wpsp-tabs .nav-tab:hover {
- background: var(--wpsp-bg-alt);
-}
-
-.wpsp-tabs .nav-tab-active {
- background: var(--wpsp-bg);
- border-bottom-color: var(--wpsp-bg);
-}
-
-/* Sections */
-.wpsp-section {
- background: var(--wpsp-bg);
- border: 1px solid var(--wpsp-border);
- border-radius: var(--wpsp-radius);
- padding: 24px;
- margin-bottom: 20px;
- box-shadow: var(--wpsp-shadow);
- transition: box-shadow var(--wpsp-transition);
-}
-
-.wpsp-section:hover {
- box-shadow: var(--wpsp-shadow-hover);
-}
-
-.wpsp-section h2 {
- margin: 0 0 16px 0;
- padding: 0 0 12px 0;
- font-size: 1.2em;
- font-weight: 600;
- border-bottom: 1px solid var(--wpsp-border-light);
- color: var(--wpsp-text);
-}
-
-.wpsp-section h3 {
- margin-top: 1.5em;
- font-size: 1em;
- font-weight: 600;
- color: var(--wpsp-text);
-}
-
-/* Form tables */
-.wpsp-section .form-table {
- margin-top: 0;
-}
-
-.wpsp-section .form-table th {
- width: 220px;
- padding-left: 0;
- font-weight: 500;
- color: var(--wpsp-text);
-}
-
-.wpsp-section .form-table td {
- padding-top: 12px;
- padding-bottom: 12px;
-}
-
-/* Status indicators */
-.wpsp-status {
- display: inline-flex;
- align-items: center;
- padding: 4px 10px;
- border-radius: 50px;
- font-size: 12px;
- font-weight: 600;
- letter-spacing: 0.02em;
- text-transform: uppercase;
-}
-
-.wpsp-status-ok {
- background: var(--wpsp-success-bg);
- color: var(--wpsp-success);
-}
-
-.wpsp-status-warning {
- background: var(--wpsp-warning-bg);
- color: #8a6d00;
-}
-
-.wpsp-status-error {
- background: var(--wpsp-danger-bg);
- color: var(--wpsp-danger);
-}
-
-/* Stats */
-.wpsp-stats {
- display: flex;
- gap: 16px;
- margin-bottom: 24px;
- flex-wrap: wrap;
-}
-
-.wpsp-stat {
- background: var(--wpsp-bg);
- border: 1px solid var(--wpsp-border);
- padding: 20px 28px;
- border-radius: var(--wpsp-radius);
- text-align: center;
- min-width: 130px;
- transition: transform var(--wpsp-transition), box-shadow var(--wpsp-transition);
-}
-
-.wpsp-stat:hover {
- transform: translateY(-2px);
- box-shadow: var(--wpsp-shadow-hover);
-}
-
-.wpsp-stat-value {
- display: block;
- font-size: 32px;
- font-weight: 700;
- color: var(--wpsp-text);
- line-height: 1.2;
-}
-
-.wpsp-stat-label {
- display: block;
- font-size: 11px;
- font-weight: 500;
- color: var(--wpsp-text-light);
- margin-top: 6px;
- text-transform: uppercase;
- letter-spacing: 0.05em;
-}
-
-/* Stat color variations */
-.wpsp-stat-success {
- border-left: 4px solid var(--wpsp-success);
-}
-
-.wpsp-stat-success .wpsp-stat-value {
- color: var(--wpsp-success);
-}
-
-.wpsp-stat-warning {
- border-left: 4px solid var(--wpsp-warning);
-}
-
-.wpsp-stat-warning .wpsp-stat-value {
- color: #8a6d00;
-}
-
-.wpsp-stat-danger {
- border-left: 4px solid var(--wpsp-danger);
-}
-
-.wpsp-stat-danger .wpsp-stat-value {
- color: var(--wpsp-danger);
-}
-
-.wpsp-stat-info {
- border-left: 4px solid var(--wpsp-primary);
-}
-
-.wpsp-stat-info .wpsp-stat-value {
- color: var(--wpsp-primary);
-}
-
-/* Tables */
-.wpsp-section .widefat {
- margin-top: 16px;
- border-radius: var(--wpsp-radius-sm);
- overflow: hidden;
-}
-
-.wpsp-section .widefat td,
-.wpsp-section .widefat th {
- padding: 12px 14px;
-}
-
-.wpsp-section .widefat thead th {
- font-weight: 600;
- background: var(--wpsp-bg-alt);
-}
-
-.wpsp-section .widefat tbody tr {
- transition: background var(--wpsp-transition);
-}
-
-.wpsp-section .widefat tbody tr:hover {
- background: var(--wpsp-bg-alt);
-}
-
-/* Country select */
-.wpsp-country-select {
- min-width: 300px;
- height: 200px !important;
- border-radius: var(--wpsp-radius-sm);
-}
-
-/* Event type colors */
-.wpsp-event-login_success {
- color: var(--wpsp-success);
-}
-
-.wpsp-event-login_failed {
- color: #8a6d00;
-}
-
-.wpsp-event-lockout,
-.wpsp-event-ip_blocked,
-.wpsp-event-geo_blocked {
- color: var(--wpsp-danger);
-}
-
-/* Country badge */
-.wpsp-country {
- display: inline-block;
- background: var(--wpsp-bg-alt);
- padding: 2px 8px;
- border-radius: 50px;
- font-size: 11px;
- font-weight: 500;
- margin-left: 6px;
-}
-
-/* Severity badges */
-.wpsp-badge {
- display: inline-block;
- padding: 3px 10px;
- border-radius: 50px;
- font-size: 10px;
- font-weight: 700;
- color: #fff;
- margin-right: 6px;
- text-transform: uppercase;
- letter-spacing: 0.03em;
-}
-
-/* Footer */
-.wpsp-footer {
- margin-top: 32px;
- padding-top: 20px;
- border-top: 1px solid var(--wpsp-border);
- color: var(--wpsp-text-light);
- font-size: 13px;
-}
-
-.wpsp-footer a {
- color: var(--wpsp-primary);
- text-decoration: none;
- transition: color var(--wpsp-transition);
-}
-
-.wpsp-footer a:hover {
- color: var(--wpsp-primary-hover);
- text-decoration: underline;
-}
-
-/* 2FA status */
-.wpsp-2fa-status {
- display: inline-flex;
- align-items: center;
- padding: 6px 14px;
- border-radius: 50px;
- font-weight: 600;
- font-size: 13px;
-}
-
-.wpsp-2fa-enabled {
- background: var(--wpsp-success-bg);
- color: var(--wpsp-success);
-}
-
-.wpsp-2fa-disabled {
- background: var(--wpsp-danger-bg);
- color: var(--wpsp-danger);
-}
-
-/* Responsive */
-@media screen and (max-width: 782px) {
- .wpsp-stats {
- flex-direction: column;
- }
-
- .wpsp-stat {
- min-width: auto;
- }
-
- .wpsp-section .form-table th {
- width: auto;
- }
-
- .wpsp-country-select {
- min-width: 100%;
- }
-
- .wpsp-tabs {
- gap: 4px;
- }
-
- .wpsp-tabs .nav-tab {
- padding: 6px 12px;
- font-size: 13px;
- }
-}
-
-/* Code blocks */
-.wpsp-section code {
- background: var(--wpsp-bg-alt);
- padding: 3px 8px;
- border-radius: var(--wpsp-radius-sm);
- font-size: 13px;
-}
-
-/* Button spacing & styling */
-.wpsp-section .button {
- transition: all var(--wpsp-transition);
-}
-
-.wpsp-section .button:hover {
- transform: translateY(-1px);
-}
-
-.wpsp-section .button + .button {
- margin-left: 8px;
-}
-
-/* Tablenav */
-.wpsp-section .tablenav {
- margin: 16px 0;
-}
-
-.wpsp-section .tablenav .actions {
- padding: 0;
-}
-
-/* Alert boxes */
-.wpsp-alert {
- padding: 14px 18px;
- border-radius: var(--wpsp-radius);
- margin-bottom: 16px;
- border-left: 4px solid;
-}
-
-.wpsp-alert-info {
- background: var(--wpsp-info-bg);
- border-left-color: var(--wpsp-info);
- color: #0a4b78;
-}
-
-.wpsp-alert-warning {
- background: var(--wpsp-warning-bg);
- border-left-color: var(--wpsp-warning);
- color: #6e5600;
-}
-
-.wpsp-alert-error {
- background: var(--wpsp-danger-bg);
- border-left-color: var(--wpsp-danger);
- color: #8a1f1f;
-}
-
-/* Loading states */
-.wpsp-loading {
- opacity: 0.5;
- pointer-events: none;
-}
-
-/* QR code container */
-#wpsp-2fa-qr img,
-#wpsp-2fa-qr svg {
- border: 1px solid var(--wpsp-border);
- padding: 12px;
- background: var(--wpsp-bg);
- border-radius: var(--wpsp-radius);
- margin: 12px 0;
-}
-
-/* Backup codes display */
-#wpsp-backup-codes-display pre,
-#wpsp-new-backup-codes {
- background: var(--wpsp-bg-alt);
- padding: 16px;
- border-radius: var(--wpsp-radius-sm);
- font-family: 'SF Mono', Monaco, Consolas, monospace;
- font-size: 14px;
- line-height: 2;
- border: 1px solid var(--wpsp-border);
-}
-
-/* Scan results */
-.wpsp-scan-results {
- max-height: 400px;
- overflow-y: auto;
-}
-
-/* Checkbox styling */
-.wpsp-section input[type="checkbox"] {
- margin-right: 10px;
- width: 18px;
- height: 18px;
-}
-
-/* Description text */
-.wpsp-section .description {
- color: var(--wpsp-text-light);
- font-style: normal;
- margin-top: 6px;
- font-size: 13px;
- line-height: 1.5;
-}
-
-/* Tab intro descriptions */
-.wpsp-section p.wpsp-description {
- color: var(--wpsp-text-light);
- font-style: normal;
- font-size: 14px;
- margin: -8px 0 20px 0;
- line-height: 1.6;
-}
-
-/* Import/export section */
-#wpsp-import-file {
- margin-right: 12px;
-}
-
-#wpsp-import-status {
- margin-left: 12px;
- color: var(--wpsp-success);
- font-weight: 500;
-}
-
-/* System info table */
-.wpsp-section .widefat td:first-child {
- font-weight: 600;
- width: 200px;
- color: var(--wpsp-text);
-}
-
-/* Status checklist icons */
-.wpsp-section .widefat td span[style*="color: #46b450"],
-.wpsp-section .widefat td span[style*="color: #dc3232"] {
- font-size: 20px;
- line-height: 1;
-}
-
-/* Notice improvements within sections */
-.wpsp-section .notice {
- border-radius: var(--wpsp-radius-sm);
- margin: 12px 0;
-}
-
-/* Input focus states */
-.wpsp-section input[type="text"]:focus,
-.wpsp-section input[type="number"]:focus,
-.wpsp-section textarea:focus,
-.wpsp-section select:focus {
- border-color: var(--wpsp-primary);
- box-shadow: 0 0 0 1px var(--wpsp-primary);
- outline: none;
-}
-
-/* Textarea styling */
-.wpsp-section textarea {
- border-radius: var(--wpsp-radius-sm);
-}
-
-/* Select styling */
-.wpsp-section select {
- border-radius: var(--wpsp-radius-sm);
-}
diff --git a/security-pack/includes/class-wpsp-admin.php b/security-pack/includes/class-wpsp-admin.php
deleted file mode 100644
index 7bf1541..0000000
--- a/security-pack/includes/class-wpsp-admin.php
+++ /dev/null
@@ -1,3200 +0,0 @@
- __( 'Status', 'security-pack' ),
- 'login' => __( 'Login Protection', 'security-pack' ),
- 'ip' => __( 'IP Control', 'security-pack' ),
- 'hardening' => __( 'Hardening', 'security-pack' ),
- 'headers' => __( 'Security Headers', 'security-pack' ),
- '2fa' => __( '2FA', 'security-pack' ),
- 'scanner' => __( 'Scanner', 'security-pack' ),
- 'logs' => __( 'Activity Log', 'security-pack' ),
- 'tools' => __( 'Tools', 'security-pack' ),
- );
-
- foreach ( $submenus as $slug => $title ) {
- add_submenu_page(
- 'security-pack',
- $title . ' - ' . __( 'Security Pack', 'security-pack' ),
- $title,
- 'manage_options',
- 'status' === $slug ? 'security-pack' : 'security-pack&tab=' . $slug,
- array( $this, 'render_settings_page' )
- );
- }
- }
-
- /**
- * Highlight the correct submenu based on current tab.
- *
- * @param string $submenu_file The current submenu file.
- * @return string
- */
- public function highlight_submenu( $submenu_file ) {
- global $pagenow;
-
- if ( 'admin.php' !== $pagenow ) {
- return $submenu_file;
- }
-
- // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
-
- if ( 'security-pack' !== $page ) {
- return $submenu_file;
- }
-
- // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- $tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'status';
-
- if ( 'status' === $tab ) {
- return 'security-pack';
- }
-
- return 'security-pack&tab=' . $tab;
- }
-
- /**
- * Add plugin action links (left side - Settings, Deactivate, etc.).
- *
- * @param array $links Existing links.
- * @return array
- */
- public function plugin_action_links( $links ) {
- $settings_link = sprintf(
- '
%s',
- admin_url( 'admin.php?page=security-pack' ),
- __( 'Settings', 'security-pack' )
- );
- array_unshift( $links, $settings_link );
- return $links;
- }
-
- /**
- * Add plugin row meta links (right side - after version).
- *
- * @param array $links Existing meta links.
- * @param string $file Plugin file.
- * @return array
- */
- public function plugin_row_meta( $links, $file ) {
- if ( WPSP_PLUGIN_BASENAME !== $file ) {
- return $links;
- }
-
- $links[] = sprintf(
- '
%s',
- 'https://arkhost.com/products-menu.php',
- __( 'Get Hosting', 'security-pack' )
- );
-
- return $links;
- }
-
- /**
- * Add dashboard widget.
- */
- public function add_dashboard_widget() {
- if ( ! current_user_can( 'manage_options' ) ) {
- return;
- }
-
- wp_add_dashboard_widget(
- 'wpsp_security_widget',
- __( 'Security Status', 'security-pack' ),
- array( $this, 'render_dashboard_widget' )
- );
- }
-
- /**
- * Render dashboard widget.
- */
- public function render_dashboard_widget() {
- $checks = $this->get_security_checks();
- $enabled_count = 0;
- $total_count = count( $checks );
-
- foreach ( $checks as $check ) {
- if ( $check['status'] ) {
- $enabled_count++;
- }
- }
-
- $score = $total_count > 0 ? round( ( $enabled_count / $total_count ) * 100 ) : 0;
-
- // Get recent activity stats.
- $stats = WPSP_Activity_Log::get_stats( 7 );
- ?>
-
-
-
-
-
-
-
- __( 'Status', 'security-pack' ),
- 'login' => __( 'Login Protection', 'security-pack' ),
- 'ip' => __( 'IP Control', 'security-pack' ),
- 'hardening' => __( 'Hardening', 'security-pack' ),
- 'headers' => __( 'Security Headers', 'security-pack' ),
- '2fa' => __( '2FA', 'security-pack' ),
- 'scanner' => __( 'Scanner', 'security-pack' ),
- 'logs' => __( 'Activity Log', 'security-pack' ),
- 'tools' => __( 'Tools', 'security-pack' ),
- );
- ?>
-
-
-
-
-
-
-
-
-
- get_security_checks();
- $enabled_count = 0;
- $total_count = count( $checks );
-
- foreach ( $checks as $check ) {
- if ( $check['status'] ) {
- $enabled_count++;
- }
- }
-
- $score = $total_count > 0 ? round( ( $enabled_count / $total_count ) * 100 ) : 0;
- ?>
-
-
-
-
-
- %
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
- |
- |
- |
-
-
-
- $check ) : ?>
-
- |
-
- ✓
-
- ✗
-
- |
- |
- |
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
- |
- |
-
-
-
-
-
- readme.html |
- |
-
-
- |
-
-
-
-
- license.txt |
- |
-
-
- |
-
-
-
-
-
-
-
- __( 'Login Attempt Limiting', 'security-pack' ),
- 'description' => __( 'Limits failed login attempts to prevent brute force attacks', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'login_limit_enabled', true ),
- 'tab' => 'login',
- );
-
- $checks['honeypot'] = array(
- 'name' => __( 'Login Honeypot', 'security-pack' ),
- 'description' => __( 'Hidden field that traps automated bots', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'honeypot_enabled', true ),
- 'tab' => 'login',
- );
-
- $checks['hide_login_errors'] = array(
- 'name' => __( 'Login Errors Hidden', 'security-pack' ),
- 'description' => __( 'Generic error message prevents username enumeration', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'hide_login_errors', true ),
- 'tab' => 'login',
- );
-
- // Hardening.
- $checks['xmlrpc'] = array(
- 'name' => __( 'XML-RPC Disabled', 'security-pack' ),
- 'description' => __( 'Blocks XML-RPC endpoint commonly used in attacks', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'disable_xmlrpc', true ),
- 'tab' => 'hardening',
- );
-
- $checks['file_editing'] = array(
- 'name' => __( 'File Editor Disabled', 'security-pack' ),
- 'description' => __( 'Prevents editing theme/plugin files from dashboard', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'disable_file_editing', true ),
- 'tab' => 'hardening',
- );
-
- $checks['rest_api'] = array(
- 'name' => __( 'REST API Restricted', 'security-pack' ),
- 'description' => __( 'Requires authentication for REST API access', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'restrict_rest_api', true ),
- 'tab' => 'hardening',
- );
-
- $checks['user_enum'] = array(
- 'name' => __( 'User Enumeration Blocked', 'security-pack' ),
- 'description' => __( 'Prevents attackers from discovering usernames', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'disable_user_enumeration', true ),
- 'tab' => 'hardening',
- );
-
- $checks['pingbacks'] = array(
- 'name' => __( 'Pingbacks Disabled', 'security-pack' ),
- 'description' => __( 'Prevents pingback-based DDoS amplification', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'disable_pingbacks', true ),
- 'tab' => 'hardening',
- );
-
- $checks['wp_version'] = array(
- 'name' => __( 'WP Version Hidden', 'security-pack' ),
- 'description' => __( 'Hides WordPress version from public view', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'remove_wp_version', true ),
- 'tab' => 'hardening',
- );
-
- $checks['security_headers'] = array(
- 'name' => __( 'Security Headers', 'security-pack' ),
- 'description' => __( 'HTTP headers that enable browser security features', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'add_security_headers', true ),
- 'tab' => 'headers',
- );
-
- // 2FA - only green if enforced for admins (just "enabled" means users CAN set it up, not that they have).
- $two_fa_enabled = Security_Pack::get_setting( 'two_factor_enabled', false );
- $two_fa_enforced = Security_Pack::get_setting( 'two_factor_enforce_admin', false );
- $checks['two_factor'] = array(
- 'name' => __( 'Two-Factor Authentication', 'security-pack' ),
- 'description' => $two_fa_enabled && ! $two_fa_enforced
- ? __( 'Available but not enforced for admins', 'security-pack' )
- : __( 'Enforced for administrator accounts', 'security-pack' ),
- 'status' => $two_fa_enabled && $two_fa_enforced,
- 'tab' => '2fa',
- );
-
- // Monitoring.
- $checks['file_integrity'] = array(
- 'name' => __( 'File Integrity Monitoring', 'security-pack' ),
- 'description' => __( 'Detects unauthorized changes to WordPress core', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'file_integrity_enabled', true ),
- 'tab' => 'scanner',
- );
-
- $checks['malware_scan'] = array(
- 'name' => __( 'Malware Scanning', 'security-pack' ),
- 'description' => __( 'Scans files for malicious code patterns', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'malware_scan_enabled', true ),
- 'tab' => 'scanner',
- );
-
- // Optional features (not counted negatively if disabled).
- $checks['custom_login'] = array(
- 'name' => __( 'Custom Login URL', 'security-pack' ),
- 'description' => __( 'Hides wp-login.php from automated scanners', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'login_rename_enabled', false ),
- 'tab' => 'login',
- );
-
- $checks['geo_blocking'] = array(
- 'name' => __( 'Country Blocking', 'security-pack' ),
- 'description' => __( 'Blocks access from specific countries', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'geo_blocking_enabled', false ),
- 'tab' => 'ip',
- );
-
- $checks['auto_blacklist'] = array(
- 'name' => __( 'Auto-Blacklist Repeat Offenders', 'security-pack' ),
- 'description' => __( 'Permanently blocks IPs with repeated lockouts', 'security-pack' ),
- 'status' => Security_Pack::get_setting( 'auto_blacklist_enabled', false ),
- 'tab' => 'ip',
- );
-
- // Environment checks (no tab - these are recommendations).
- global $wpdb;
- $checks['ssl'] = array(
- 'name' => __( 'SSL/HTTPS', 'security-pack' ),
- 'description' => is_ssl()
- ? __( 'Site is served over HTTPS', 'security-pack' )
- : __( 'Site should use HTTPS for security', 'security-pack' ),
- 'status' => is_ssl(),
- 'tab' => '',
- );
-
- $checks['debug_mode'] = array(
- 'name' => __( 'Debug Mode Disabled', 'security-pack' ),
- 'description' => defined( 'WP_DEBUG' ) && WP_DEBUG
- ? __( 'WP_DEBUG is enabled - disable in production', 'security-pack' )
- : __( 'Debug mode is properly disabled', 'security-pack' ),
- 'status' => ! ( defined( 'WP_DEBUG' ) && WP_DEBUG ),
- 'tab' => '',
- );
-
- $checks['db_prefix'] = array(
- 'name' => __( 'Database Prefix Changed', 'security-pack' ),
- 'description' => 'wp_' === $wpdb->prefix
- ? __( 'Using default wp_ prefix - consider changing', 'security-pack' )
- : __( 'Using custom database prefix', 'security-pack' ),
- 'status' => 'wp_' !== $wpdb->prefix,
- 'tab' => '',
- );
-
- $admin_user = get_user_by( 'login', 'admin' );
- $checks['admin_username'] = array(
- 'name' => __( 'No "admin" Username', 'security-pack' ),
- 'description' => $admin_user
- ? __( 'Default "admin" username exists - consider renaming', 'security-pack' )
- : __( 'No user with "admin" username', 'security-pack' ),
- 'status' => ! $admin_user,
- 'tab' => '',
- );
-
- $checks['php_version'] = array(
- 'name' => __( 'PHP Version', 'security-pack' ),
- 'description' => version_compare( PHP_VERSION, '8.0', '<' )
- ? sprintf(
- /* translators: %s: PHP version */
- __( 'PHP %s is outdated - update recommended', 'security-pack' ),
- PHP_VERSION
- )
- : sprintf(
- /* translators: %s: PHP version */
- __( 'Running PHP %s', 'security-pack' ),
- PHP_VERSION
- ),
- 'status' => version_compare( PHP_VERSION, '8.0', '>=' ),
- 'tab' => '',
- );
-
- // Check if auto-updates are enabled for core.
- $auto_updates_enabled = defined( 'WP_AUTO_UPDATE_CORE' ) && WP_AUTO_UPDATE_CORE;
- // Also check the database option.
- if ( ! $auto_updates_enabled ) {
- $auto_updates_enabled = 'true' === get_site_option( 'auto_update_core_major' ) ||
- 'true' === get_site_option( 'auto_update_core_minor' );
- }
- $checks['auto_updates'] = array(
- 'name' => __( 'Auto-Updates Enabled', 'security-pack' ),
- 'description' => $auto_updates_enabled
- ? __( 'WordPress core auto-updates are enabled', 'security-pack' )
- : __( 'Enable auto-updates for security patches', 'security-pack' ),
- 'status' => $auto_updates_enabled,
- 'tab' => '',
- );
-
- return $checks;
- }
-
- /**
- * Render login protection tab.
- */
- private function render_login_tab() {
- ?>
-
-
-
-
-
-
- get_component( 'geo_blocking' );
- $db_exists = $geo_blocking && $geo_blocking->database_exists();
- if ( ! $db_exists ) :
- ?>
-
-
-
- ' . esc_html__( 'IP Control', 'security-pack' ) . ''
- );
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- get_component( 'ip_control' );
- if ( $ip_control ) {
- $blocked_ips = $ip_control->get_blocked_ips();
- }
-
- $geo_blocking = wpsp()->get_component( 'geo_blocking' );
- $db_info = $geo_blocking ? $geo_blocking->get_database_info() : array( 'exists' => false );
- $countries = WPSP_Helper::get_countries_with_flags();
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
- |
- |
- |
-
-
-
-
-
- ip_address ); ?> |
- failed_attempts ); ?> |
- lockout_until ); ?> |
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- get_default_headers();
- $headers = Security_Pack::get_setting( 'security_headers', $default_headers );
- ?>
-
-
-
-
-
-
- securityheaders.com'
- );
- ?>
-
-
-
-
-
-
-
-
- '_wpsp_2fa_enabled', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Required for 2FA user lookup.
- 'meta_value' => '1', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Required for 2FA user lookup.
- 'fields' => 'ID',
- ) );
- $total_admins = count( get_users( array(
- 'role' => 'administrator',
- 'fields' => 'ID',
- ) ) );
- $admins_with_2fa = 0;
- foreach ( $users_with_2fa as $user_id ) {
- if ( user_can( $user_id, 'manage_options' ) ) {
- $admins_with_2fa++;
- }
- }
- ?>
-
-
-
-
-
- 0 || $total_admins > 0 ) : ?>
-
-
-
-
-
-
-
-
-
-
- - Google Authenticator -
- - Authy -
- - Microsoft Authenticator -
- - 1Password -
- - Bitwarden -
-
-
-
-
-
-
-
- -
- ' . esc_html__( 'Profile page', 'security-pack' ) . ''
- );
- ?>
-
-
-
-
-
-
-
-
-
- get_last_scan_results();
-
- $malware_scanner = new WPSP_Malware_Scanner();
- $malware_results = $malware_scanner->get_last_scan_results();
-
- $file_changes_count = count( $file_results['changes']['modified'] ?? array() );
- $malware_issues_count = count( $malware_results['results'] ?? array() );
- ?>
-
-
- 0 || $malware_results['time'] > 0 ) : ?>
-
-
-
- 0 ? esc_html( $file_changes_count ) : '✓'; ?>
-
-
-
-
-
- 0 ? esc_html( $malware_issues_count ) : '✓'; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
- |
-
-
-
-
-
- |
- |
-
-
-
-
-
-
-
-
- 0 ) : ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
- |
- |
-
-
-
- $findings ) : ?>
-
- |
-
-
-
-
-
-
-
-
-
-
- |
-
-
- |
-
-
-
-
-
-
-
-
-
-
- 0 ) : ?>
-
-
-
- get_quarantined_files();
- if ( ! empty( $quarantined_files ) ) :
- ?>
-
-
-
-
- |
- |
- |
- |
-
-
-
- $meta ) : ?>
-
- |
- |
- |
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
- |
- ✓ |
-
-
- |
- |
- ⚠ |
-
-
-
-
-
- $per_page,
- 'offset' => $offset,
- 'event_type' => $filter_type,
- ) );
-
- $total = WPSP_Activity_Log::get_log_count( array( 'event_type' => $filter_type ) );
- $pages = ceil( $total / $per_page );
-
- $stats = WPSP_Activity_Log::get_stats( 30 );
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
- |
- |
- |
- |
- |
-
-
-
-
-
- |
-
-
-
-
- | created_at ); ?> |
-
-
- event_type ) ); ?>
-
- |
-
- country_code ) : ?>
- country_code ) ); ?>
-
- -
-
- |
- ip_address ); ?> |
- username ? $log->username : '-' ); ?> |
- details ? $log->details : '-' ); ?> |
-
-
-
-
-
-
- 1 ) : ?>
-
-
- add_query_arg( 'paged', '%#%' ),
- 'format' => '',
- 'current' => $page,
- 'total' => $pages,
- ) ) );
- ?>
-
-
-
-
-
-
-
-
-
-
- get_component( 'geo_blocking' );
- $geo_info = $geo_blocking ? $geo_blocking->get_database_info() : array( 'exists' => false );
- $country_code = $geo_blocking && $current_ip ? $geo_blocking->get_country_code( $current_ip ) : null;
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
- |
-
-
- |
- |
-
-
- |
- |
-
-
- |
-
-
-
-
-
-
- |
-
-
- |
-
-
- ✓
-
- ✗
- ()
-
- |
-
-
- |
-
-
- ✓
- ()
-
- ○
- ()
-
- |
-
-
- |
-
-
-
-
-
-
- |
-
-
- |
- |
-
-
-
-
-
-
-
- __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- WPSP_Activity_Log::clear_all_logs();
- wp_send_json_success();
- }
-
- /**
- * AJAX: Whitelist IP.
- *
- * Adds an IP to the whitelist setting.
- */
- public function ajax_whitelist_ip() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $ip = isset( $_POST['ip'] ) ? sanitize_text_field( wp_unslash( $_POST['ip'] ) ) : '';
-
- if ( empty( $ip ) || ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
- wp_send_json_error( array( 'message' => __( 'Invalid IP address.', 'security-pack' ) ) );
- }
-
- // Get current whitelist.
- $whitelist = Security_Pack::get_setting( 'ip_whitelist', '' );
-
- // Check if IP is already in whitelist.
- $whitelist_array = array_filter( array_map( 'trim', explode( "\n", $whitelist ) ) );
- if ( in_array( $ip, $whitelist_array, true ) ) {
- wp_send_json_error( array( 'message' => __( 'IP is already whitelisted.', 'security-pack' ) ) );
- }
-
- // Add IP to whitelist.
- $whitelist_array[] = $ip;
- $new_whitelist = implode( "\n", $whitelist_array );
-
- Security_Pack::update_setting( 'ip_whitelist', $new_whitelist );
-
- // Also remove from lockouts if present.
- $ip_control = wpsp()->get_component( 'ip_control' );
- if ( $ip_control ) {
- $ip_control->unblock_ip( $ip );
- }
-
- wp_send_json_success();
- }
-
- /**
- * AJAX: Run file scan.
- */
- public function ajax_run_file_scan() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $file_integrity = new WPSP_File_Integrity();
- $results = $file_integrity->scan_core_files( true );
-
- wp_send_json_success( $results );
- }
-
- /**
- * AJAX: Run malware scan.
- */
- public function ajax_run_malware_scan() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- // Increase time limit for potentially long scans.
- // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- Required for comprehensive malware scanning.
- set_time_limit( 300 );
-
- $scanner = new WPSP_Malware_Scanner();
- $results = $scanner->scan_files();
-
- update_option( WPSP_Malware_Scanner::RESULTS_OPTION, $results );
- update_option( WPSP_Malware_Scanner::LAST_SCAN_OPTION, time() );
-
- wp_send_json_success( $results );
- }
-
- /**
- * AJAX: Reset file integrity baseline.
- */
- public function ajax_reset_file_baseline() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $file_integrity = new WPSP_File_Integrity();
- $file_integrity->reset_baseline();
-
- // Run a fresh scan to establish new baseline.
- $file_integrity->scan_core_files( true );
-
- wp_send_json_success();
- }
-
- /**
- * AJAX: Clear malware scan results.
- */
- public function ajax_clear_malware_results() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $scanner = new WPSP_Malware_Scanner();
- $scanner->clear_results();
-
- wp_send_json_success();
- }
-
- /**
- * AJAX: Download GeoIP database.
- */
- public function ajax_download_geo_db() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $geo_blocking = wpsp()->get_component( 'geo_blocking' );
- if ( ! $geo_blocking ) {
- wp_send_json_error( array( 'message' => __( 'Geo blocking not available.', 'security-pack' ) ) );
- }
-
- $result = $geo_blocking->download_database();
-
- if ( is_wp_error( $result ) ) {
- wp_send_json_error( array( 'message' => $result->get_error_message() ) );
- }
-
- wp_send_json_success();
- }
-
- /**
- * AJAX: Send test email.
- */
- public function ajax_test_email() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
-
- if ( empty( $email ) ) {
- $email = get_option( 'admin_email' );
- }
-
- if ( ! is_email( $email ) ) {
- wp_send_json_error( array( 'message' => __( 'Invalid email address.', 'security-pack' ) ) );
- }
-
- $site_name = get_bloginfo( 'name' );
- $subject = sprintf(
- /* translators: %s: Site name */
- __( '[%s] Security Pack - Test Email', 'security-pack' ),
- $site_name
- );
-
- $message = sprintf(
- /* translators: 1: Site name, 2: Site URL */
- __( "This is a test email from Security Pack.\n\nIf you received this email, your email alerts are configured correctly.\n\nSite: %1\$s\nURL: %2\$s", 'security-pack' ),
- $site_name,
- home_url()
- );
-
- $sent = wp_mail( $email, $subject, $message );
-
- if ( $sent ) {
- wp_send_json_success();
- } else {
- wp_send_json_error( array( 'message' => __( 'Failed to send email. Check your server mail configuration.', 'security-pack' ) ) );
- }
- }
-
- /**
- * AJAX: Force logout all users.
- */
- public function ajax_force_logout_all() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- // Get all users and destroy their sessions.
- $users = get_users( array( 'fields' => 'ID' ) );
- foreach ( $users as $user_id ) {
- $sessions = WP_Session_Tokens::get_instance( $user_id );
- $sessions->destroy_all();
- }
-
- // Log the action.
- WPSP_Activity_Log::log( 'force_logout', WPSP_Helper::get_client_ip(), wp_get_current_user()->user_login, __( 'All user sessions terminated', 'security-pack' ) );
-
- wp_send_json_success();
- }
-
- /**
- * AJAX: Export settings.
- */
- public function ajax_export_settings() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $settings = get_option( 'wpsp_settings', array() );
-
- wp_send_json_success( $settings );
- }
-
- /**
- * AJAX: Import settings.
- */
- public function ajax_import_settings() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON is decoded then sanitized via sanitize_settings().
- $settings_json = isset( $_POST['settings'] ) ? wp_unslash( $_POST['settings'] ) : '';
-
- if ( empty( $settings_json ) ) {
- wp_send_json_error( array( 'message' => __( 'No settings data provided.', 'security-pack' ) ) );
- }
-
- $settings = json_decode( $settings_json, true );
-
- if ( null === $settings ) {
- wp_send_json_error( array( 'message' => __( 'Invalid JSON format.', 'security-pack' ) ) );
- }
-
- // Sanitize the imported settings (individual values are sanitized here).
- $sanitized = $this->sanitize_settings( $settings );
-
- update_option( 'wpsp_settings', $sanitized );
-
- wp_send_json_success();
- }
-
- /**
- * AJAX: Export logs as CSV.
- */
- public function ajax_export_logs() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $logs = WPSP_Activity_Log::get_logs( array( 'limit' => 10000 ) );
-
- $csv_lines = array();
- $csv_lines[] = 'Time,Event,IP Address,Country,Username,Details,User Agent';
-
- foreach ( $logs as $log ) {
- $csv_lines[] = sprintf(
- '"%s","%s","%s","%s","%s","%s","%s"',
- str_replace( '"', '""', $log->created_at ),
- str_replace( '"', '""', WPSP_Activity_Log::get_event_label( $log->event_type ) ),
- str_replace( '"', '""', $log->ip_address ),
- str_replace( '"', '""', $log->country_code ? $log->country_code : '' ),
- str_replace( '"', '""', $log->username ? $log->username : '' ),
- str_replace( '"', '""', $log->details ? $log->details : '' ),
- str_replace( '"', '""', $log->user_agent ? $log->user_agent : '' )
- );
- }
-
- wp_send_json_success( array( 'csv' => implode( "\n", $csv_lines ) ) );
- }
-
- /**
- * AJAX: Unblock a single IP.
- */
- public function ajax_unblock_ip() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $ip = isset( $_POST['ip'] ) ? sanitize_text_field( wp_unslash( $_POST['ip'] ) ) : '';
-
- if ( empty( $ip ) || ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
- wp_send_json_error( array( 'message' => __( 'Invalid IP address.', 'security-pack' ) ) );
- }
-
- $ip_control = wpsp()->get_component( 'ip_control' );
- if ( $ip_control ) {
- $ip_control->unblock_ip( $ip );
- }
-
- wp_send_json_success();
- }
-
- /**
- * AJAX: Clear all lockouts.
- */
- public function ajax_clear_lockouts() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- global $wpdb;
-
- // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Admin action to clear lockouts.
- $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}wpsp_lockouts" );
-
- wp_send_json_success();
- }
-
- /**
- * AJAX: Reset all settings to defaults.
- */
- public function ajax_reset_settings() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $defaults = Security_Pack::get_default_settings();
- update_option( 'wpsp_settings', $defaults );
-
- wp_send_json_success();
- }
-
- /**
- * AJAX: Quarantine a suspicious file.
- */
- public function ajax_quarantine_file() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $file_path = isset( $_POST['file_path'] ) ? sanitize_text_field( wp_unslash( $_POST['file_path'] ) ) : '';
-
- if ( empty( $file_path ) ) {
- wp_send_json_error( array( 'message' => __( 'No file specified.', 'security-pack' ) ) );
- }
-
- $scanner = new WPSP_Malware_Scanner();
- $result = $scanner->quarantine_file( $file_path );
-
- if ( is_wp_error( $result ) ) {
- wp_send_json_error( array( 'message' => $result->get_error_message() ) );
- }
-
- wp_send_json_success( $result );
- }
-
- /**
- * AJAX: Restore a file from quarantine.
- */
- public function ajax_restore_file() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $quarantine_name = isset( $_POST['quarantine_name'] ) ? sanitize_file_name( wp_unslash( $_POST['quarantine_name'] ) ) : '';
-
- if ( empty( $quarantine_name ) ) {
- wp_send_json_error( array( 'message' => __( 'No file specified.', 'security-pack' ) ) );
- }
-
- $scanner = new WPSP_Malware_Scanner();
- $result = $scanner->restore_file( $quarantine_name );
-
- if ( is_wp_error( $result ) ) {
- wp_send_json_error( array( 'message' => $result->get_error_message() ) );
- }
-
- wp_send_json_success( $result );
- }
-
- /**
- * AJAX: Delete a quarantined file permanently.
- */
- public function ajax_delete_quarantined() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $quarantine_name = isset( $_POST['quarantine_name'] ) ? sanitize_file_name( wp_unslash( $_POST['quarantine_name'] ) ) : '';
-
- if ( empty( $quarantine_name ) ) {
- wp_send_json_error( array( 'message' => __( 'No file specified.', 'security-pack' ) ) );
- }
-
- $scanner = new WPSP_Malware_Scanner();
- $result = $scanner->delete_quarantined_file( $quarantine_name );
-
- if ( is_wp_error( $result ) ) {
- wp_send_json_error( array( 'message' => $result->get_error_message() ) );
- }
-
- wp_send_json_success( $result );
- }
-
- /**
- * AJAX: Delete WordPress info files (readme.html, license.txt).
- */
- public function ajax_delete_wp_file() {
- check_ajax_referer( 'wpsp_admin' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-pack' ) ) );
- }
-
- $file = isset( $_POST['file'] ) ? sanitize_file_name( wp_unslash( $_POST['file'] ) ) : '';
-
- // Only allow specific safe files to be deleted.
- $allowed_files = array( 'readme.html', 'license.txt' );
-
- if ( ! in_array( $file, $allowed_files, true ) ) {
- wp_send_json_error( array( 'message' => __( 'Invalid file.', 'security-pack' ) ) );
- }
-
- $file_path = ABSPATH . $file;
-
- if ( ! file_exists( $file_path ) ) {
- wp_send_json_error( array( 'message' => __( 'File not found.', 'security-pack' ) ) );
- }
-
- // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
- if ( ! unlink( $file_path ) ) {
- wp_send_json_error( array( 'message' => __( 'Failed to delete file. Check file permissions.', 'security-pack' ) ) );
- }
-
- wp_send_json_success();
- }
-}
diff --git a/security-pack/includes/class-wpsp-helper.php b/security-pack/includes/class-wpsp-helper.php
deleted file mode 100644
index 6d37305..0000000
--- a/security-pack/includes/class-wpsp-helper.php
+++ /dev/null
@@ -1,555 +0,0 @@
- 0 && $full_bytes < 16 ) {
- $bit_mask = ( ( 1 << $remaining_bits ) - 1 ) << ( 8 - $remaining_bits );
- if ( ( ord( $ip_bin[ $full_bytes ] ) & $bit_mask ) !== ( ord( $network_bin[ $full_bytes ] ) & $bit_mask ) ) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Check if an IP matches any rule in a list.
- *
- * @param string $ip IP address to check.
- * @param array $rules Array of IP addresses or CIDR ranges.
- * @return bool
- */
- public static function ip_matches_rules( $ip, $rules ) {
- if ( empty( $rules ) || ! is_array( $rules ) ) {
- return false;
- }
-
- foreach ( $rules as $rule ) {
- $rule = trim( $rule );
- if ( empty( $rule ) || strpos( $rule, '#' ) === 0 ) {
- continue; // Skip empty lines and comments.
- }
-
- if ( self::ip_in_cidr( $ip, $rule ) ) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Parse IP list from textarea.
- *
- * @param string $text Textarea content with IPs/CIDRs.
- * @return array
- */
- public static function parse_ip_list( $text ) {
- if ( empty( $text ) ) {
- return array();
- }
-
- $lines = explode( "\n", $text );
- $ips = array();
-
- foreach ( $lines as $line ) {
- $line = trim( $line );
-
- // Skip empty lines and comments.
- if ( empty( $line ) || strpos( $line, '#' ) === 0 ) {
- continue;
- }
-
- // Remove inline comments.
- if ( strpos( $line, '#' ) !== false ) {
- $line = trim( substr( $line, 0, strpos( $line, '#' ) ) );
- }
-
- // Validate IP or CIDR.
- if ( self::is_valid_ip_or_cidr( $line ) ) {
- $ips[] = $line;
- }
- }
-
- return $ips;
- }
-
- /**
- * Check if a string is a valid IP or CIDR.
- *
- * @param string $value Value to check.
- * @return bool
- */
- public static function is_valid_ip_or_cidr( $value ) {
- // Plain IP.
- if ( filter_var( $value, FILTER_VALIDATE_IP ) ) {
- return true;
- }
-
- // CIDR notation.
- if ( strpos( $value, '/' ) !== false ) {
- list( $ip, $mask ) = explode( '/', $value );
-
- if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
- return false;
- }
-
- $mask = (int) $mask;
- $is_ipv6 = filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 );
- $max_mask = $is_ipv6 ? 128 : 32;
-
- return $mask >= 0 && $mask <= $max_mask;
- }
-
- return false;
- }
-
- /**
- * Get country list for geo-blocking UI.
- *
- * @return array
- */
- public static function get_countries() {
- return array(
- 'AF' => __( 'Afghanistan', 'security-pack' ),
- 'AL' => __( 'Albania', 'security-pack' ),
- 'DZ' => __( 'Algeria', 'security-pack' ),
- 'AS' => __( 'American Samoa', 'security-pack' ),
- 'AD' => __( 'Andorra', 'security-pack' ),
- 'AO' => __( 'Angola', 'security-pack' ),
- 'AI' => __( 'Anguilla', 'security-pack' ),
- 'AQ' => __( 'Antarctica', 'security-pack' ),
- 'AG' => __( 'Antigua and Barbuda', 'security-pack' ),
- 'AR' => __( 'Argentina', 'security-pack' ),
- 'AM' => __( 'Armenia', 'security-pack' ),
- 'AW' => __( 'Aruba', 'security-pack' ),
- 'AU' => __( 'Australia', 'security-pack' ),
- 'AT' => __( 'Austria', 'security-pack' ),
- 'AZ' => __( 'Azerbaijan', 'security-pack' ),
- 'BS' => __( 'Bahamas', 'security-pack' ),
- 'BH' => __( 'Bahrain', 'security-pack' ),
- 'BD' => __( 'Bangladesh', 'security-pack' ),
- 'BB' => __( 'Barbados', 'security-pack' ),
- 'BY' => __( 'Belarus', 'security-pack' ),
- 'BE' => __( 'Belgium', 'security-pack' ),
- 'BZ' => __( 'Belize', 'security-pack' ),
- 'BJ' => __( 'Benin', 'security-pack' ),
- 'BM' => __( 'Bermuda', 'security-pack' ),
- 'BT' => __( 'Bhutan', 'security-pack' ),
- 'BO' => __( 'Bolivia', 'security-pack' ),
- 'BA' => __( 'Bosnia and Herzegovina', 'security-pack' ),
- 'BW' => __( 'Botswana', 'security-pack' ),
- 'BR' => __( 'Brazil', 'security-pack' ),
- 'BN' => __( 'Brunei', 'security-pack' ),
- 'BG' => __( 'Bulgaria', 'security-pack' ),
- 'BF' => __( 'Burkina Faso', 'security-pack' ),
- 'BI' => __( 'Burundi', 'security-pack' ),
- 'KH' => __( 'Cambodia', 'security-pack' ),
- 'CM' => __( 'Cameroon', 'security-pack' ),
- 'CA' => __( 'Canada', 'security-pack' ),
- 'CV' => __( 'Cape Verde', 'security-pack' ),
- 'KY' => __( 'Cayman Islands', 'security-pack' ),
- 'CF' => __( 'Central African Republic', 'security-pack' ),
- 'TD' => __( 'Chad', 'security-pack' ),
- 'CL' => __( 'Chile', 'security-pack' ),
- 'CN' => __( 'China', 'security-pack' ),
- 'CO' => __( 'Colombia', 'security-pack' ),
- 'KM' => __( 'Comoros', 'security-pack' ),
- 'CG' => __( 'Congo', 'security-pack' ),
- 'CD' => __( 'Congo (DRC)', 'security-pack' ),
- 'CR' => __( 'Costa Rica', 'security-pack' ),
- 'CI' => __( 'Ivory Coast', 'security-pack' ),
- 'HR' => __( 'Croatia', 'security-pack' ),
- 'CU' => __( 'Cuba', 'security-pack' ),
- 'CY' => __( 'Cyprus', 'security-pack' ),
- 'CZ' => __( 'Czech Republic', 'security-pack' ),
- 'DK' => __( 'Denmark', 'security-pack' ),
- 'DJ' => __( 'Djibouti', 'security-pack' ),
- 'DM' => __( 'Dominica', 'security-pack' ),
- 'DO' => __( 'Dominican Republic', 'security-pack' ),
- 'EC' => __( 'Ecuador', 'security-pack' ),
- 'EG' => __( 'Egypt', 'security-pack' ),
- 'SV' => __( 'El Salvador', 'security-pack' ),
- 'GQ' => __( 'Equatorial Guinea', 'security-pack' ),
- 'ER' => __( 'Eritrea', 'security-pack' ),
- 'EE' => __( 'Estonia', 'security-pack' ),
- 'ET' => __( 'Ethiopia', 'security-pack' ),
- 'FJ' => __( 'Fiji', 'security-pack' ),
- 'FI' => __( 'Finland', 'security-pack' ),
- 'FR' => __( 'France', 'security-pack' ),
- 'GA' => __( 'Gabon', 'security-pack' ),
- 'GM' => __( 'Gambia', 'security-pack' ),
- 'GE' => __( 'Georgia', 'security-pack' ),
- 'DE' => __( 'Germany', 'security-pack' ),
- 'GH' => __( 'Ghana', 'security-pack' ),
- 'GR' => __( 'Greece', 'security-pack' ),
- 'GL' => __( 'Greenland', 'security-pack' ),
- 'GD' => __( 'Grenada', 'security-pack' ),
- 'GU' => __( 'Guam', 'security-pack' ),
- 'GT' => __( 'Guatemala', 'security-pack' ),
- 'GN' => __( 'Guinea', 'security-pack' ),
- 'GW' => __( 'Guinea-Bissau', 'security-pack' ),
- 'GY' => __( 'Guyana', 'security-pack' ),
- 'HT' => __( 'Haiti', 'security-pack' ),
- 'HN' => __( 'Honduras', 'security-pack' ),
- 'HK' => __( 'Hong Kong', 'security-pack' ),
- 'HU' => __( 'Hungary', 'security-pack' ),
- 'IS' => __( 'Iceland', 'security-pack' ),
- 'IN' => __( 'India', 'security-pack' ),
- 'ID' => __( 'Indonesia', 'security-pack' ),
- 'IR' => __( 'Iran', 'security-pack' ),
- 'IQ' => __( 'Iraq', 'security-pack' ),
- 'IE' => __( 'Ireland', 'security-pack' ),
- 'IL' => __( 'Israel', 'security-pack' ),
- 'IT' => __( 'Italy', 'security-pack' ),
- 'JM' => __( 'Jamaica', 'security-pack' ),
- 'JP' => __( 'Japan', 'security-pack' ),
- 'JO' => __( 'Jordan', 'security-pack' ),
- 'KZ' => __( 'Kazakhstan', 'security-pack' ),
- 'KE' => __( 'Kenya', 'security-pack' ),
- 'KI' => __( 'Kiribati', 'security-pack' ),
- 'KP' => __( 'North Korea', 'security-pack' ),
- 'KR' => __( 'South Korea', 'security-pack' ),
- 'KW' => __( 'Kuwait', 'security-pack' ),
- 'KG' => __( 'Kyrgyzstan', 'security-pack' ),
- 'LA' => __( 'Laos', 'security-pack' ),
- 'LV' => __( 'Latvia', 'security-pack' ),
- 'LB' => __( 'Lebanon', 'security-pack' ),
- 'LS' => __( 'Lesotho', 'security-pack' ),
- 'LR' => __( 'Liberia', 'security-pack' ),
- 'LY' => __( 'Libya', 'security-pack' ),
- 'LI' => __( 'Liechtenstein', 'security-pack' ),
- 'LT' => __( 'Lithuania', 'security-pack' ),
- 'LU' => __( 'Luxembourg', 'security-pack' ),
- 'MO' => __( 'Macao', 'security-pack' ),
- 'MK' => __( 'North Macedonia', 'security-pack' ),
- 'MG' => __( 'Madagascar', 'security-pack' ),
- 'MW' => __( 'Malawi', 'security-pack' ),
- 'MY' => __( 'Malaysia', 'security-pack' ),
- 'MV' => __( 'Maldives', 'security-pack' ),
- 'ML' => __( 'Mali', 'security-pack' ),
- 'MT' => __( 'Malta', 'security-pack' ),
- 'MH' => __( 'Marshall Islands', 'security-pack' ),
- 'MR' => __( 'Mauritania', 'security-pack' ),
- 'MU' => __( 'Mauritius', 'security-pack' ),
- 'MX' => __( 'Mexico', 'security-pack' ),
- 'FM' => __( 'Micronesia', 'security-pack' ),
- 'MD' => __( 'Moldova', 'security-pack' ),
- 'MC' => __( 'Monaco', 'security-pack' ),
- 'MN' => __( 'Mongolia', 'security-pack' ),
- 'ME' => __( 'Montenegro', 'security-pack' ),
- 'MA' => __( 'Morocco', 'security-pack' ),
- 'MZ' => __( 'Mozambique', 'security-pack' ),
- 'MM' => __( 'Myanmar', 'security-pack' ),
- 'NA' => __( 'Namibia', 'security-pack' ),
- 'NR' => __( 'Nauru', 'security-pack' ),
- 'NP' => __( 'Nepal', 'security-pack' ),
- 'NL' => __( 'Netherlands', 'security-pack' ),
- 'NZ' => __( 'New Zealand', 'security-pack' ),
- 'NI' => __( 'Nicaragua', 'security-pack' ),
- 'NE' => __( 'Niger', 'security-pack' ),
- 'NG' => __( 'Nigeria', 'security-pack' ),
- 'NO' => __( 'Norway', 'security-pack' ),
- 'OM' => __( 'Oman', 'security-pack' ),
- 'PK' => __( 'Pakistan', 'security-pack' ),
- 'PW' => __( 'Palau', 'security-pack' ),
- 'PS' => __( 'Palestine', 'security-pack' ),
- 'PA' => __( 'Panama', 'security-pack' ),
- 'PG' => __( 'Papua New Guinea', 'security-pack' ),
- 'PY' => __( 'Paraguay', 'security-pack' ),
- 'PE' => __( 'Peru', 'security-pack' ),
- 'PH' => __( 'Philippines', 'security-pack' ),
- 'PL' => __( 'Poland', 'security-pack' ),
- 'PT' => __( 'Portugal', 'security-pack' ),
- 'PR' => __( 'Puerto Rico', 'security-pack' ),
- 'QA' => __( 'Qatar', 'security-pack' ),
- 'RO' => __( 'Romania', 'security-pack' ),
- 'RU' => __( 'Russia', 'security-pack' ),
- 'RW' => __( 'Rwanda', 'security-pack' ),
- 'SA' => __( 'Saudi Arabia', 'security-pack' ),
- 'SN' => __( 'Senegal', 'security-pack' ),
- 'RS' => __( 'Serbia', 'security-pack' ),
- 'SC' => __( 'Seychelles', 'security-pack' ),
- 'SL' => __( 'Sierra Leone', 'security-pack' ),
- 'SG' => __( 'Singapore', 'security-pack' ),
- 'SK' => __( 'Slovakia', 'security-pack' ),
- 'SI' => __( 'Slovenia', 'security-pack' ),
- 'SB' => __( 'Solomon Islands', 'security-pack' ),
- 'SO' => __( 'Somalia', 'security-pack' ),
- 'ZA' => __( 'South Africa', 'security-pack' ),
- 'SS' => __( 'South Sudan', 'security-pack' ),
- 'ES' => __( 'Spain', 'security-pack' ),
- 'LK' => __( 'Sri Lanka', 'security-pack' ),
- 'SD' => __( 'Sudan', 'security-pack' ),
- 'SR' => __( 'Suriname', 'security-pack' ),
- 'SZ' => __( 'Eswatini', 'security-pack' ),
- 'SE' => __( 'Sweden', 'security-pack' ),
- 'CH' => __( 'Switzerland', 'security-pack' ),
- 'SY' => __( 'Syria', 'security-pack' ),
- 'TW' => __( 'Taiwan', 'security-pack' ),
- 'TJ' => __( 'Tajikistan', 'security-pack' ),
- 'TZ' => __( 'Tanzania', 'security-pack' ),
- 'TH' => __( 'Thailand', 'security-pack' ),
- 'TL' => __( 'Timor-Leste', 'security-pack' ),
- 'TG' => __( 'Togo', 'security-pack' ),
- 'TO' => __( 'Tonga', 'security-pack' ),
- 'TT' => __( 'Trinidad and Tobago', 'security-pack' ),
- 'TN' => __( 'Tunisia', 'security-pack' ),
- 'TR' => __( 'Turkey', 'security-pack' ),
- 'TM' => __( 'Turkmenistan', 'security-pack' ),
- 'TV' => __( 'Tuvalu', 'security-pack' ),
- 'UG' => __( 'Uganda', 'security-pack' ),
- 'UA' => __( 'Ukraine', 'security-pack' ),
- 'AE' => __( 'United Arab Emirates', 'security-pack' ),
- 'GB' => __( 'United Kingdom', 'security-pack' ),
- 'US' => __( 'United States', 'security-pack' ),
- 'UY' => __( 'Uruguay', 'security-pack' ),
- 'UZ' => __( 'Uzbekistan', 'security-pack' ),
- 'VU' => __( 'Vanuatu', 'security-pack' ),
- 'VE' => __( 'Venezuela', 'security-pack' ),
- 'VN' => __( 'Vietnam', 'security-pack' ),
- 'YE' => __( 'Yemen', 'security-pack' ),
- 'ZM' => __( 'Zambia', 'security-pack' ),
- 'ZW' => __( 'Zimbabwe', 'security-pack' ),
- );
- }
-
- /**
- * Sanitize a custom login URL slug.
- *
- * @param string $slug The slug to sanitize.
- * @return string
- */
- public static function sanitize_login_slug( $slug ) {
- $slug = sanitize_title( $slug );
- $slug = preg_replace( '/[^a-z0-9\-]/', '', $slug );
-
- // Prevent common reserved slugs.
- $reserved = array( 'wp-admin', 'wp-login', 'admin', 'login', 'wp-content', 'wp-includes' );
- if ( in_array( $slug, $reserved, true ) ) {
- return '';
- }
-
- return $slug;
- }
-
- /**
- * Get the server's public IP address.
- *
- * Uses external service to determine the server's outbound IP.
- * Result is cached for 1 hour to avoid excessive external requests.
- *
- * @return string|null Server IP or null on failure.
- */
- public static function get_server_ip() {
- $cached = get_transient( 'wpsp_server_ip' );
- if ( false !== $cached ) {
- return $cached;
- }
-
- // Try multiple services for reliability.
- $services = array(
- 'https://api.ipify.org',
- 'https://ifconfig.me/ip',
- 'https://icanhazip.com',
- );
-
- $ip = null;
-
- foreach ( $services as $service ) {
- $response = wp_remote_get(
- $service,
- array(
- 'timeout' => 5,
- 'sslverify' => true,
- )
- );
-
- if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) {
- $body = trim( wp_remote_retrieve_body( $response ) );
- if ( filter_var( $body, FILTER_VALIDATE_IP ) ) {
- $ip = $body;
- break;
- }
- }
- }
-
- if ( $ip ) {
- // Cache for 1 hour.
- set_transient( 'wpsp_server_ip', $ip, HOUR_IN_SECONDS );
- }
-
- return $ip;
- }
-
- /**
- * Get country flag emoji from country code.
- *
- * Converts ISO 3166-1 alpha-2 country codes to Unicode flag emojis.
- *
- * @param string $country_code Two-letter country code (e.g., "US", "GB").
- * @return string Flag emoji or globe emoji for invalid codes.
- */
- public static function get_country_flag( $country_code ) {
- if ( empty( $country_code ) || strlen( $country_code ) !== 2 ) {
- return '🌐'; // Globe emoji for invalid codes.
- }
-
- $country_code = strtoupper( $country_code );
-
- // Convert country code to Unicode regional indicator symbols.
- // Regional indicators are U+1F1E6 (A) through U+1F1FF (Z).
- $first_letter = mb_chr( ord( $country_code[0] ) - ord( 'A' ) + 0x1F1E6, 'UTF-8' );
- $second_letter = mb_chr( ord( $country_code[1] ) - ord( 'A' ) + 0x1F1E6, 'UTF-8' );
-
- return $first_letter . $second_letter;
- }
-
- /**
- * Get countries array with flags.
- *
- * @return array Country code => "Flag Name" format.
- */
- public static function get_countries_with_flags() {
- $countries = self::get_countries();
- $countries_flags = array();
-
- foreach ( $countries as $code => $name ) {
- $flag = self::get_country_flag( $code );
- $countries_flags[ $code ] = $flag . ' ' . $name;
- }
-
- return $countries_flags;
- }
-}
diff --git a/security-pack/index.php b/security-pack/index.php
deleted file mode 100644
index 91bbd2b..0000000
--- a/security-pack/index.php
+++ /dev/null
@@ -1,6 +0,0 @@
-query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_wpsp_%'" );
-// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Cleanup during uninstall, caching not applicable.
-$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_wpsp_%'" );
-
-// Clear scheduled events.
-wp_clear_scheduled_hook( 'wpsp_daily_cleanup' );
-wp_clear_scheduled_hook( 'wpsp_daily_file_scan' );
-wp_clear_scheduled_hook( 'wpsp_weekly_malware_scan' );
-
-// Delete user meta for 2FA.
-// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Cleanup during uninstall, caching not applicable.
-$wpdb->query( "DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE '_wpsp_%'" );