Plugin Directory

Changeset 3289923


Ignore:
Timestamp:
05/08/2025 02:09:01 PM (8 months ago)
Author:
hamdisaidani
Message:

v1.1.2 – Security fix: block access to wp-login.php when Fortress is active

Location:
fortress-login-pro/trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • fortress-login-pro/trunk/fortress-login-pro.php

    r3289880 r3289923  
    33 * Plugin Name: Fortress Login Pro – Secure, Hide & Rename Login URL
    44 * Description: Secure and rotate your WordPress login slug. Block brute force attacks, track attempts, and auto-rotate slugs via email.
    5  * Version: 1.1.1
     5 * Version: 1.1.2
    66 * Author: hamdisaidani
    77 * License: GPL2+
     
    1212
    1313// Define plugin constants
    14 define('FORTLOPR_VERSION', '1.1.1');
     14define('FORTLOPR_VERSION', '1.1.2');
    1515define('FORTLOPR_PLUGIN_DIR', plugin_dir_path(__FILE__));
    1616define('FORTLOPR_PLUGIN_URL', plugin_dir_url(__FILE__));
  • fortress-login-pro/trunk/includes/filters-hooks.php

    r3289752 r3289923  
    99// Include the logger to track unauthorized access attempts
    1010require_once plugin_dir_path(__FILE__) . '/../core/logger.php';
     11
     12// Start session for tracking state if not already started
     13if (!isset($_SESSION) && !headers_sent()) {
     14    session_start();
     15}
     16
     17// Emergency flush of rewrite rules to fix password reset URL issues
     18function fortlopr_emergency_flush_rules() {
     19    // Only do this once per session to avoid performance issues
     20    if (!isset($_SESSION['fortress_emergency_flush_done'])) {
     21        // Force flush rewrite rules when we have active custom login slug
     22        $active_slug = get_option('fortress_active_slug', 'wp-login.php');
     23        if ($active_slug !== 'wp-login.php') {
     24            flush_rewrite_rules(true);
     25            // Mark as done for this session
     26            $_SESSION['fortress_emergency_flush_done'] = true;
     27        }
     28    }
     29}
     30// Run emergency flush
     31fortlopr_emergency_flush_rules();
    1132
    1233/**
     
    462483        add_action('template_redirect', 'fortlopr_handle_login_template', 5);
    463484       
    464         // Optional: Redirect wp-login.php to custom slug
    465         add_action('login_init', 'fortlopr_redirect_wp_login', 5);
    466        
    467485        // Block access to login-like paths
    468486        add_action('template_redirect', 'fortlopr_block_login_like_paths', 4);
     
    470488}
    471489add_action('wp', 'fortlopr_init_login_handlers');
     490
     491/**
     492 * Add direct hook for wp-login.php redirection
     493 * This needs to be outside the normal handlers to catch direct access to wp-login.php
     494 */
     495function fortlopr_setup_login_redirect() {
     496    $active_slug = get_option('fortress_active_slug', 'wp-login.php');
     497   
     498    // Only add redirect if using a custom slug
     499    if ($active_slug !== 'wp-login.php') {
     500        add_action('login_init', 'fortlopr_redirect_wp_login', 5);
     501    }
     502}
     503add_action('init', 'fortlopr_setup_login_redirect', 5);
    472504
    473505/**
     
    497529        add_rewrite_rule(
    498530            '^' . $slug . '/?$',
     531            'index.php?fortress_login=1&fortress_slug_type=active',
     532            'top'
     533        );
     534       
     535        // Add rewrite rule for active slug with wp-login.php
     536        add_rewrite_rule(
     537            '^' . $slug . '/wp-login\.php',
    499538            'index.php?fortress_login=1&fortress_slug_type=active',
    500539            'top'
     
    512551                add_rewrite_rule(
    513552                    '^' . $pending_slug . '/?$',
     553                    'index.php?fortress_login=1&fortress_slug_type=pending',
     554                    'top'
     555                );
     556               
     557                // Add rewrite rule for pending slug with wp-login.php
     558                add_rewrite_rule(
     559                    '^' . $pending_slug . '/wp-login\.php',
    514560                    'index.php?fortress_login=1&fortress_slug_type=pending',
    515561                    'top'
     
    604650    // Exit early if not a login request
    605651    if (!get_query_var('fortress_login')) {
     652        // Special handling for combined URLs (slug/wp-login.php?checkemail=confirm)
     653        $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
     654        $active_slug = get_option('fortress_active_slug', 'wp-login.php');
     655       
     656        // If this is a checkemail=confirm on a combined path, process it
     657        if (strpos($request_uri, trim($active_slug, '/') . '/wp-login.php') === 1 &&
     658            isset($_GET['checkemail']) &&
     659            sanitize_text_field(wp_unslash($_GET['checkemail'])) === 'confirm') {
     660           
     661            // Include the login form to handle the reset confirmation
     662            include_once(ABSPATH . 'wp-login.php');
     663            exit;
     664        }
     665       
    606666        return;
    607667    }
    608    
    609     global $pagenow, $user_login, $error;
    610668   
    611669    // Store which slug was used (active or pending)
     
    852910    }
    853911   
     912    // Allow any wp-login.php path with password reset functionality
     913    if (strpos($request_path, 'wp-login.php') !== false) {
     914        // Allow password reset confirmation on all paths
     915        if (isset($_GET['checkemail']) && sanitize_text_field(wp_unslash($_GET['checkemail'])) === 'confirm') {
     916            return;
     917        }
     918       
     919        // Allow password reset related actions too
     920        if (isset($_GET['action']) && in_array(sanitize_text_field(wp_unslash($_GET['action'])), array('lostpassword', 'rp', 'resetpass'), true)) {
     921            return;
     922        }
     923    }
     924   
     925    // Also skip if this is a combination of custom slug and wp-login.php with allowed params
     926    if (strpos($request_path, trim($active_slug, '/') . '/wp-login.php') === 0) {
     927        // These checks are redundant with the one above, but kept for compatibility
     928        if (isset($_GET['checkemail']) && sanitize_text_field(wp_unslash($_GET['checkemail'])) === 'confirm') {
     929            return;
     930        }
     931       
     932        if (isset($_GET['action']) && in_array(sanitize_text_field(wp_unslash($_GET['action'])), array('lostpassword', 'rp', 'resetpass'), true)) {
     933            return;
     934        }
     935    }
     936   
    854937    // Also skip if this is the pending slug path (only if pending status is valid)
    855938    $pending_is_valid = !empty($pending_slug) && ($pending_status === 'pending' || $pending_status === 'confirmed');
     
    912995            return;
    913996        }
     997       
     998        // Allow password reset related actions
     999        if (isset($_GET['action']) && in_array(sanitize_text_field(wp_unslash($_GET['action'])), array('lostpassword', 'rp', 'resetpass'), true)) {
     1000            return;
     1001        }
     1002       
     1003        // Allow password reset confirmation screen
     1004        if (isset($_GET['checkemail']) && sanitize_text_field(wp_unslash($_GET['checkemail'])) === 'confirm') {
     1005            return;
     1006        }
    9141007    }
    9151008   
     
    9651058    }
    9661059   
     1060    // Also allow password reset confirmation
     1061    if (isset($_GET['checkemail']) && sanitize_text_field(wp_unslash($_GET['checkemail'])) === 'confirm') {
     1062        return;
     1063    }
     1064   
    9671065    // Skip if $_SERVER['REQUEST_URI'] contains AJAX or admin actions
    9681066    if (isset($_SERVER['REQUEST_URI'])) {
     
    9761074    $active_slug = get_option('fortress_active_slug', 'wp-login.php');
    9771075   
    978     // Only redirect if using custom slug
     1076    // Only block if using custom slug
    9791077    if ($active_slug !== 'wp-login.php') {
    980         // Redirect to custom login URL
    981         wp_safe_redirect(home_url($active_slug));
     1078        // Log the unauthorized access attempt
     1079        if (!function_exists('fortlopr_log_access_attempt')) {
     1080            require_once plugin_dir_path(__FILE__) . '/../core/logger.php';
     1081        }
     1082       
     1083        // Prepare URL for logging
     1084        $host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : '';
     1085        $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
     1086        $url_attempted = esc_url_raw('http://' . $host . $request_uri);
     1087       
     1088        // Log the access attempt if it passes our filters
     1089        if (fortlopr_should_log_access($url_attempted)) {
     1090            fortlopr_log_access_attempt([
     1091                'ip_address'     => isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : 'Unknown',
     1092                'user_agent'     => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : 'Unknown',
     1093                'referrer'       => isset($_SERVER['HTTP_REFERER']) ? esc_url_raw(wp_unslash($_SERVER['HTTP_REFERER'])) : 'Direct',
     1094                'url_attempted'  => $url_attempted,
     1095                'timestamp'      => current_time('mysql'),
     1096            ]);
     1097        }
     1098       
     1099        // Show access denied page instead of redirecting
     1100        status_header(403);
     1101        include plugin_dir_path(__FILE__) . '/../templates/access-denied-page.php';
    9821102        exit;
    9831103    }
     
    10321152        if (strpos($path, 'action=confirm_admin_email') !== false) {
    10331153            return $url;
     1154        }
     1155       
     1156        // Special handling for password reset confirmation
     1157        if (strpos($path, 'checkemail=confirm') !== false) {
     1158            // Keep the original URL with the custom slug added
     1159            return home_url('/' . trim($active_slug, '/') . $path);
    10341160        }
    10351161       
  • fortress-login-pro/trunk/readme.txt

    r3289880 r3289923  
    55Tested up to: 6.8 
    66Requires PHP: 7.2 
    7 Stable tag: 1.1.1 
     7Stable tag: 1.1.2 
    88License: GPLv2 or later 
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html 
     
    2121### 🔐 Key Features
    2222
    23 - **Custom Login URL:** Hide `wp-login.php` and set your own private login path
    24 - **Auto-Rotate Slugs:** Automatically change your login URL on a custom schedule
    25 - **Dual-Slug Rotation Safety:** Keep the old URL live until the new one is used (fail-safe)
    26 - **Slug Generator:** Choose readable word combos or full-random slugs (with number support)
    27 - **Access Logs & Charts:** See IPs, timestamps, referrers, and user-agents by login attempt
    28 - **Export Logs:** Download access history or slug changes in CSV or JSON
    29 - **Slug History Panel:** Restore, archive, or delete old slugs anytime
    30 - **SMTP Configuration:** Set up outgoing email for login slug alerts and rotation notices
    31 - **Test Email & Rotation:** Built-in checks before activating rotation so you don’t get locked out
    32 - **Clean UI:** Fast, modern dashboard with zero bloat or upsell traps
     23- **Custom Login URL:** Hide `wp-login.php` and set your own private login path 
     24- **Auto-Rotate Slugs:** Automatically change your login URL on a custom schedule 
     25- **Dual-Slug Rotation Safety:** Keep the old URL live until the new one is used (fail-safe) 
     26- **Slug Generator:** Choose readable word combos or full-random slugs (with number support) 
     27- **Access Logs & Charts:** See IPs, timestamps, referrers, and user-agents by login attempt 
     28- **Export Logs:** Download access history or slug changes in CSV or JSON 
     29- **Slug History Panel:** Restore, archive, or delete old slugs anytime 
     30- **SMTP Configuration:** Set up outgoing email for login slug alerts and rotation notices 
     31- **Test Email & Rotation:** Built-in checks before activating rotation so you don’t get locked out 
     32- **Clean UI:** Fast, modern dashboard with zero bloat or upsell traps 
    3333
    3434### ✅ Works With
     
    5252== Installation ==
    5353
    54 1. Upload the plugin to `/wp-content/plugins/`
    55 2. Activate via **Plugins → Installed Plugins**
    56 3. Go to **Fortress Login Pro** in your dashboard
    57 4. Choose a login slug (manual or generated), then click **Save**
    58 5. Bookmark or email yourself the new URL — your old login path is now hidden
     541. Upload the plugin to `/wp-content/plugins/` 
     552. Activate via **Plugins → Installed Plugins** 
     563. Go to **Fortress Login Pro** in your dashboard 
     574. Choose a login slug (manual or generated), then click **Save** 
     585. Bookmark or email yourself the new URL — your old login path is now hidden 
    5959
    6060---
     
    98983. Slug history view with restore/delete options 
    99994. SMTP configuration and test email panel 
    100 5. Access Denied page template
     1005. Access Denied page template 
    101101
    102102---
     
    104104== Changelog ==
    105105
     106= 1.1.2 =
     107* Security Fix: Blocked direct access to wp-login.php when custom slug is active
     108
    106109= 1.1.1 =
    107 * Fixed bug where Copy and Generate buttons were incorrectly disabled by SMTP status
    108 * Improved empty-state UI for Analytics Overview chart
     110* Fixed bug where Copy and Generate buttons were incorrectly disabled by SMTP status 
     111* Improved empty-state UI for Analytics Overview chart 
    109112
    110113= 1.1.0 =
    111 * Added dual-slug auto-rotation (fail-safe)
    112 * Added slug generator: readable vs random + number toggle
    113 * Enhanced UI with slug strength meter, rotation timers, and status badges
    114 * Improved SMTP configuration with test email verification
    115 * Added slug history metadata (source, usage, status)
     114* Added dual-slug auto-rotation (fail-safe) 
     115* Added slug generator: readable vs random + number toggle 
     116* Enhanced UI with slug strength meter, rotation timers, and status badges 
     117* Improved SMTP configuration with test email verification 
     118* Added slug history metadata (source, usage, status) 
    116119
    117120= 1.0.0 =
    118 * Initial release
     121* Initial release 
    119122
    120123---
     
    122125== Upgrade Notice ==
    123126
    124 1.1.1 includes a UI bug fix and a visual enhancement. Recommended for all users.
     1271.1.2 includes a critical security fix. It is highly recommended for all users.
    125128
    126129---
  • fortress-login-pro/trunk/templates/access-denied-page.php

    r3289880 r3289923  
    55 *
    66 * @package FortressLoginPro
    7  * @version 1.1.1
     7 * @version 1.1.2
    88 */
    99
  • fortress-login-pro/trunk/templates/email-template.php

    r3289880 r3289923  
    55 *
    66 * @package FortressLoginPro
    7  * @version 1.1.1
     7 * @version 1.1.2
    88 */
    99
  • fortress-login-pro/trunk/templates/test-email-template.php

    r3289880 r3289923  
    55 *
    66 * @package FortressLoginPro
    7  * @version 1.1.1
     7 * @version 1.1.2
    88 */
    99
Note: See TracChangeset for help on using the changeset viewer.