Plugin Directory

Changeset 3303789


Ignore:
Timestamp:
05/30/2025 08:46:48 PM (10 months ago)
Author:
wpiron
Message:

update new version

Location:
iron-security
Files:
8 added
8 edited
46 copied

Legend:

Unmodified
Added
Removed
  • iron-security/tags/2.3.4/README.txt

    r3300103 r3303789  
    55Requires at least: 4.7
    66Tested up to: 6.8
    7 Stable tag: 2.3.3
     7Stable tag: 2.3.4
    88Requires PHP: 7.0
    99License: GPLv2 or later
     
    142142== Changelog ==
    143143
     144= 2.3.4 =
     145* Update plugin
     146
    144147= 2.3.3 =
    145148* Add functionality to change default admin username
  • iron-security/tags/2.3.4/admin/class-iron-security-admin.php

    r3300103 r3303789  
    336336
    337337        return $this->login_logout_functionality->wpironsecwp_block_locked_out_users( $user, $username, $password );
     338    }
     339
     340    public function wpironis_block_locked_out_ip_early() {
     341        return $this->login_logout_functionality->wpironsecwp_block_locked_out_ip_early();
    338342    }
    339343
     
    36083612    }
    36093613
     3614    public function handle_telegram_feedback() {
     3615        check_ajax_referer('iron_security_nonce', 'nonce');
     3616
     3617        if (!current_user_can('manage_options')) {
     3618            wp_send_json_error('Insufficient permissions');
     3619            return;
     3620        }
     3621
     3622        $name = isset($_POST['name']) ? sanitize_text_field($_POST['name']) : '';
     3623        $email = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';
     3624        $message = isset($_POST['message']) ? sanitize_textarea_field($_POST['message']) : '';
     3625
     3626        if (empty($name) || empty($email) || empty($message)) {
     3627            wp_send_json_error('All fields are required');
     3628            return;
     3629        }
     3630
     3631        $bot_token = '7891702745:AAE9NIFGYVZzgmIiLZ1xVKBVtG5Wn-E-66E';
     3632        $chat_id = '-1002293858145';
     3633
     3634        $text = "*Iron Security Feedback* \n\n";
     3635        $text .= "*Name:* $name\n";
     3636        $text .= "*Email:* $email\n";
     3637        $text .= "*Message:*\n$message";
     3638
     3639        $url = "https://api.telegram.org/bot$bot_token/sendMessage";
     3640
     3641        $args = [
     3642            'body' => [
     3643                'chat_id' => $chat_id,
     3644                'text' => $text,
     3645                'parse_mode' => 'Markdown'
     3646            ]
     3647        ];
     3648
     3649        $response = wp_remote_post($url, $args);
     3650
     3651        if (is_wp_error($response)) {
     3652            error_log($response->get_error_message());
     3653            wp_send_json_error('Failed to send message: ' . $response->get_error_message());
     3654            return;
     3655        }
     3656
     3657        $body = wp_remote_retrieve_body($response);
     3658        $data = json_decode($body, true);
     3659
     3660        if (isset($data['ok']) && $data['ok'] === true) {
     3661            wp_send_json_success('Feedback sent successfully');
     3662        } else {
     3663            wp_send_json_error('Failed to send message');
     3664        }
     3665    }
     3666
    36103667    private function get_hashed_filename( $base_name ) {
    36113668        $manifest_path = plugin_dir_path( __FILE__ ) . 'js/dist/manifest.json';
  • iron-security/tags/2.3.4/admin/classes/login-logout-functionality.php

    r3291538 r3303789  
    1616        $this->version = '1.0.0';
    1717        $this->tracking_access = new SafeWP_Setup_Tracking_Access();
    18 //      $this->safe2fa         = new safe_2fa_admin();
    1918    }
    2019
     
    2423            <p class="text-center">
    2524                This section of the Iron Security Plugin offers several options to enhance the security of your
    26                 WordPress
    27                 site. These settings allow you to customize various aspects of the login and logout
     25                WordPress site. These settings allow you to customize various aspects of the login and logout
    2826                process, reducing vulnerabilities and protecting against unauthorized access.
    2927            </p>
    30             <?php
    31             settings_errors( 'wpironis_messages' ); ?>
     28            <?php settings_errors( 'wpironis_messages' ); ?>
    3229            <form method="post" action="options.php">
    3330                <?php
     
    4946                    <input type="checkbox" id="enable_session_timeout"
    5047                           name="wpironis_plugin_settings_loginlogout[enable_session_timeout]"
    51                            value="1" <?php
    52                     checked( 1, $is_enabled, true ); ?>>
     48                           value="1" <?php checked( 1, $is_enabled, true ); ?>>
    5349                    <span class="slider round"></span>
    5450                </label>
     
    5854                <input type="number" name="wpironis_plugin_settings_loginlogout[session_timeout_value]"
    5955                       id="session_timeout_value"
    60                        value="<?php
    61                        echo esc_attr( $timeoutValue ); ?>"
     56                       value="<?php echo esc_attr( $timeoutValue ); ?>"
    6257                       placeholder="Enter timeout in seconds (for example 3600 it will be 1hr)">
    6358            </div>
     
    7772                    <input type="checkbox" id="enable_slug_change"
    7873                           name="wpironis_plugin_settings_loginlogout[enable_slug_change]"
    79                            value="1" <?php
    80                     checked( 1, $is_enabled, true ); ?>>
     74                           value="1" <?php checked( 1, $is_enabled, true ); ?>>
    8175                    <span class="slider round"></span>
    8276                </label>
     
    8579                <input type="text" name="wpironis_plugin_settings_loginlogout[wpironis_custom_login_slug]"
    8680                       id="wpironis_custom-admin-slug"
    87                        value="<?php
    88                        echo isset( $slug ) ? esc_attr( $slug ) : ''; ?>"
     81                       value="<?php echo isset( $slug ) ? esc_attr( $slug ) : ''; ?>"
    8982                       placeholder="Enter custom login URL">
    9083            </div>
     
    9487                automated attacks. This simple change adds an effective layer of protection to your website.</p>
    9588        </div>
    96 
    9789        <?php
    9890    }
     
    10597                    <input type="checkbox" id="enable_limit_login_attempts"
    10698                           name="wpironis_plugin_settings_loginlogout[enable_limit_login_attempts]"
    107                            value="1" <?php
    108                     checked( 1, $is_enabled, true ); ?>>
     99                           value="1" <?php checked( 1, $is_enabled, true ); ?>>
    109100                    <span class="slider round"></span>
    110101                </label>
     
    115106                    <input type="number" name="wpironis_plugin_settings_loginlogout[wpironis_limit_login_attempts]"
    116107                           id="limit_login_attempts"
    117                            value="<?php
    118                            echo esc_attr( $attempts ); ?>"
     108                           value="<?php echo esc_attr( $attempts ); ?>"
    119109                           placeholder="Enter the number of allowed attempts (for example: 5)">
    120110                </div>
     
    123113                    <input type="number" name="wpironis_plugin_settings_loginlogout[wpironis_lockout_duration]"
    124114                           id="wpironis_lockout_duration"
    125                            value="<?php
    126                            echo esc_attr( $time ); ?>" placeholder="How long to keep user blocked? in seconds">
     115                           value="<?php echo esc_attr( $time ); ?>" placeholder="How long to keep user blocked? in seconds">
    127116                </div>
    128117            </div>
     
    141130                    <input type="checkbox" id="enable_2fa"
    142131                           name="wpironis_plugin_settings_loginlogout[enable_2fa]"
    143                            value="1" <?php
    144                     checked( 1, $is_enabled, true ); ?>>
     132                           value="1" <?php checked( 1, $is_enabled, true ); ?>>
    145133                    <span class="slider round"></span>
    146134                </label>
     
    154142                            <input type="checkbox" id="wpironis_2fa_google_auth_field"
    155143                                   name="wpironis_plugin_settings_loginlogout[wpironis_2fa_google_auth]"
    156                                    value="1" <?php
    157                             checked( 1, $googleAuth, true ); ?>>
     144                                   value="1" <?php checked( 1, $googleAuth, true ); ?>>
    158145                            <span class="slider round"></span>
    159146                        </label>
     
    178165            strtoupper( sanitize_text_field( $_SERVER['REQUEST_METHOD'] ) ) !== 'POST'
    179166        ) {
    180             // Redirect to the home URL safely
    181167            wp_redirect( esc_url( home_url() ) );
    182168            exit;
     
    184170    }
    185171
    186 
    187172    public function customLoginUrl( $customUrl ) {
    188173        global $user_login, $error;
    189174
    190175        if ( strpos( $_SERVER['REQUEST_URI'], '/' . $customUrl ) !== false ) {
    191             // Serve the login page if not logged in
    192176            if ( ! is_user_logged_in() ) {
    193177                if ( ! isset( $user_login ) ) {
     
    201185            }
    202186        }
    203         // If it's the default login URL, redirect to the custom URL
    204187        if ( strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false && ! is_user_logged_in() ) {
    205188            wp_redirect( home_url( $customUrl ) );
     
    250233                return admin_url();
    251234            }
    252 
    253235            return home_url();
    254236        }
    255 
    256237        return $redirect_to;
    257238    }
     
    261242            return (int) $timeout_value;
    262243        }
    263 
    264244        return $expireIn;
    265245    }
     
    269249        $attempts   = get_transient( $ip_address . '_wpis_attempts' ) ?: 0;
    270250        $attempts ++;
     251       
    271252        set_transient( $ip_address . '_wpis_attempts', $attempts, $options['wpironis_lockout_duration'] );
    272253        if ( $attempts >= $options['wpironis_limit_login_attempts'] ) {
     
    289270
    290271    public function wpironsecwp_block_locked_out_users( $user, $username, $password ) {
    291 
    292272        $ip_address = $this->get_user_ip();
    293 
    294         // Check if this IP is in lockout transient
     273       
    295274        if ( get_transient( $ip_address . '_wpis_lockout' ) ) {
    296 
    297             // Optionally fetch how long until lockout ends:
    298275            $lockout_duration = get_option( 'wpironis_plugin_settings_loginlogout' )['wpironis_lockout_duration'];
    299276            $lockout_time     = get_transient( $ip_address . '_wpis_lockout_time' );
    300277            $remaining_time   = $lockout_duration - ( time() - $lockout_time );
    301278
    302             // Force all sessions for this IP to log out
    303279            $this->wpisec_force_logout_by_ip( $ip_address );
    304280
    305             // -- 1) Immediately set a 403 status and kill on the login page --
    306 
    307             // Set 403 on "login_init"
    308281            add_action( 'login_init', function() {
    309282                status_header( 403 );
    310283                nocache_headers();
    311                 // Stop execution so the login form never appears
    312284                exit;
    313285            });
    314286
    315             // If WordPress tries to render the login form anyway, kill it
    316287            add_action( 'login_form', function () {
    317288                exit;
    318289            });
    319290
    320             // -- 2) Also block access to the wp-admin area --
    321 
    322291            add_action( 'admin_init', function() {
    323292                status_header( 403 );
    324293                nocache_headers();
    325                 // This prevents the admin panel from loading
    326294                exit;
    327295            });
    328 
    329             // -- 3) Optionally add your own error message on the login page (if it were to load) --
    330296
    331297            add_filter( 'login_message', function () use ( $remaining_time ) {
     
    336302            });
    337303
    338             // Return a WP_Error so WordPress sees this as a failed login
    339304            return new WP_Error(
    340305                'locked_out',
     
    343308        }
    344309
    345         // If not locked out, just return the user object
    346310        return $user;
    347311    }
    348 
    349312
    350313    /**
     
    352315     */
    353316    public function wpisec_force_logout_by_ip( $ip_address ) {
    354         $users = get_users(); // Get all users
     317        $users = get_users();
    355318
    356319        foreach ( $users as $user ) {
    357320            $sessions = WP_Session_Tokens::get_instance( $user->ID );
    358             $sessions->destroy_all(); // Log out all sessions for this user
    359         }
    360 
    361         // Destroy the current session if the locked user is logged in
     321            $sessions->destroy_all();
     322        }
     323
    362324        if ( is_user_logged_in() ) {
    363325            wp_destroy_current_session();
    364326            wp_clear_auth_cookie();
    365             wp_redirect( home_url() ); // Redirect to home page
     327            wp_redirect( home_url() );
    366328            exit;
    367329        }
     
    392354                    } else {
    393355                        error_log( '2FA code not entered' );
    394 
    395356                        return new WP_Error( 'missing_2fa_code',
    396357                            '<strong>ERROR</strong>: Please enter your 2FA code.' );
     
    401362            } else {
    402363                error_log( 'Nonce verification failed or nonce not set' );
    403 
    404364                return new WP_Error( 'invalid_nonce', '<strong>ERROR</strong>: Nonce verification failed.' );
    405365            }
     
    415375    }
    416376
    417 
    418377    public function get_user_ip() {
    419         unset($_SERVER['HTTP_X_FORWARDED_FOR'], $_SERVER['CLIENT_IP']);
    420 
    421         if (!empty($_SERVER['REMOTE_ADDR']) && self::validate_ip($_SERVER['REMOTE_ADDR'])) {
    422             return $_SERVER['REMOTE_ADDR'];
    423         }
    424     }
    425 
    426     private static function validate_ip($ip) {
    427         return filter_var($ip, FILTER_VALIDATE_IP) !== false;
     378        $remote_addr = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
     379       
     380        if (self::validate_ip($remote_addr)) {
     381            return $remote_addr;
     382        }
     383
     384        return '0.0.0.0';
     385    }
     386
     387    public static function validate_ip($ip) {
     388        if (filter_var($ip, FILTER_VALIDATE_IP) === false) {
     389            return false;
     390        }
     391        return true;
    428392    }
    429393
  • iron-security/tags/2.3.4/admin/css/iron-security-admin.css

    r3288628 r3303789  
    224224    color: #fff;
    225225    background: #0073aa;
     226}
     227
     228/* Feedback Form */
     229.iron-security-feedback-form {
     230    background: #fff;
     231    border: 1px solid #e2e4e7;
     232    border-radius: 4px;
     233    padding: 20px;
     234    margin-top: 20px;
     235    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
     236}
     237
     238.iron-security-feedback-form p {
     239    margin-bottom: 15px;
     240    color: #555;
     241}
     242
     243.iron-security-form-field {
     244    margin-bottom: 15px;
     245}
     246
     247.iron-security-form-field label {
     248    display: block;
     249    margin-bottom: 5px;
     250    font-weight: 500;
     251}
     252
     253.iron-security-form-field input,
     254.iron-security-form-field textarea {
     255    width: 100%;
     256    padding: 8px 12px;
     257    border-radius: 4px;
     258    border: 1px solid #ddd;
     259    font-size: 14px;
     260}
     261
     262.iron-security-form-field textarea {
     263    resize: vertical;
     264    min-height: 80px;
     265}
     266
     267.iron-security-feedback-status {
     268    margin-bottom: 15px;
     269    padding: 10px 15px;
     270    border-radius: 4px;
     271    font-size: 14px;
     272}
     273
     274.iron-security-feedback-status.success {
     275    background-color: #ecf9ec;
     276    color: #1e7e34;
     277    border: 1px solid #c3e6cb;
     278}
     279
     280.iron-security-feedback-status.error {
     281    background-color: #f8d7da;
     282    color: #721c24;
     283    border: 1px solid #f5c6cb;
     284}
     285
     286.iron-security-feedback-form button {
     287    margin-top: 5px;
    226288}
  • iron-security/tags/2.3.4/admin/js/components/Dashboard.jsx

    r3300103 r3303789  
    77import HttpSecurityHeadersSettings from "./HttpSecurityHeadersSettings";
    88import Support from './Support';
     9
     10const FeedbackForm = ({ settings }) => {
     11    const [name, setName] = useState('');
     12    const [email, setEmail] = useState('');
     13    const [message, setMessage] = useState('');
     14    const [isSending, setIsSending] = useState(false);
     15    const [feedbackStatus, setFeedbackStatus] = useState(null);
     16
     17    const handleSubmit = async (e) => {
     18        e.preventDefault();
     19        setIsSending(true);
     20        setFeedbackStatus(null);
     21
     22        try {
     23            const formData = new FormData();
     24            formData.append('action', 'iron_security_send_feedback');
     25            formData.append('name', name);
     26            formData.append('email', email);
     27            formData.append('message', message);
     28            formData.append('nonce', settings.nonce);
     29
     30            const response = await fetch(settings.ajaxurl, {
     31                method: 'POST',
     32                body: formData,
     33                credentials: 'same-origin'
     34            });
     35
     36            const data = await response.json();
     37
     38            if (data.success) {
     39                setFeedbackStatus({ type: 'success', message: 'Your feedback was sent successfully. Thank you!' });
     40                setName('');
     41                setEmail('');
     42                setMessage('');
     43            } else {
     44                setFeedbackStatus({ type: 'error', message: data.data || 'Failed to send feedback. Please try again.' });
     45            }
     46        } catch (error) {
     47            console.error('Error sending feedback:', error);
     48            setFeedbackStatus({ type: 'error', message: 'An error occurred while sending your feedback. Please try again.' });
     49        } finally {
     50            setIsSending(false);
     51        }
     52    };
     53
     54    return (
     55        <div className="iron-security-feedback-form iron-security-banner Standard">
     56            <div className="iron-security-banner-header">Send Us Your Feedback</div>
     57            <p>We'd love to hear your thoughts about Iron Security. Please use this form to send us your feedback, suggestions, or questions.</p>
     58           
     59            {feedbackStatus && (
     60                <div className={`iron-security-feedback-status ${feedbackStatus.type}`}>
     61                    {feedbackStatus.message}
     62                </div>
     63            )}
     64           
     65            <form onSubmit={handleSubmit}>
     66                <div className="iron-security-form-field">
     67                    <label htmlFor="feedback-name">Your Name</label>
     68                    <br/>
     69                    <input
     70                        type="text"
     71                        id="feedback-name"
     72                        value={name}
     73                        onChange={(e) => setName(e.target.value)}
     74                        required
     75                        disabled={isSending}
     76                        style={{width:"100%"}}
     77                    />
     78                </div>
     79               
     80                <div className="iron-security-form-field">
     81                    <label htmlFor="feedback-email">Your Email</label>
     82                    <br/>
     83                    <input
     84                        type="email"
     85                        id="feedback-email"
     86                        value={email}
     87                        onChange={(e) => setEmail(e.target.value)}
     88                        required
     89                        disabled={isSending}
     90                        style={{width:"100%"}}
     91                    />
     92                </div>
     93               
     94                <div className="iron-security-form-field">
     95                    <label htmlFor="feedback-message">Your Message</label>
     96                    <br/>
     97                    <textarea
     98                        id="feedback-message"
     99                        value={message}
     100                        onChange={(e) => setMessage(e.target.value)}
     101                        required
     102                        disabled={isSending}
     103                        rows="4"
     104                        style={{width:"100%"}}
     105                    ></textarea>
     106                </div>
     107               
     108                <button
     109                    type="submit"
     110                    className="button button-primary"
     111                    disabled={isSending}
     112                >
     113                    {isSending ? 'Sending...' : 'Send Feedback'}
     114                </button>
     115            </form>
     116        </div>
     117    );
     118};
    9119
    10120const Dashboard = ({settings: initialSettings}) => {
     
    202312                        <strong><a href='https://wordpress.org/plugins/quantity-discounts/' target='_blank'>Quantity Breaks</a></strong>`}
    203313                />
     314                <FeedbackForm settings={settings} />
    204315            </div>
    205316        </div>
  • iron-security/tags/2.3.4/admin/js/dist/manifest.json

    r3300103 r3303789  
    11{
    2   "dashboard.js": "dashboard.409171eb914877d3afe7.js",
    3   "vendors.js": "vendors.91782840b9e9337a9a5f.js"
     2  "dashboard.js": "dashboard.6931e43c4d8629f63bd9.js",
     3  "vendors.js": "vendors.b4116fd1b25e74ca1789.js"
    44}
  • iron-security/tags/2.3.4/includes/class-iron-security.php

    r3300103 r3303789  
    9494        $this->loader->add_action( 'wp_login_failed', $plugin_admin, 'wpironis_handle_failed_login', 10, 3 );
    9595        $this->loader->add_action( 'wp_login', $plugin_admin, 'log_successful_login', 10, 2 );
     96        $this->loader->add_action( 'init', $plugin_admin, 'wpironis_block_locked_out_ip_early', 1 );
    9697        $this->loader->add_filter( 'authenticate', $plugin_admin, 'wpironis_block_locked_out_users', 10, 3 );
    9798        $this->loader->add_filter( 'authenticate', $plugin_admin, 'wpironsecwp_block_verify_2fa', 20, 3 );
     
    295296        $this->loader->add_action( 'wp_ajax_iron_security_get_settings', $plugin_admin, 'wpironis_get_settings' );
    296297        $this->loader->add_action( 'wp_ajax_iron_security_toggle_ai_bot_blocking', $plugin_admin, 'wpironis_handle_ai_bot_blocking_toggle' );
     298        $this->loader->add_action( 'wp_ajax_iron_security_send_feedback', $plugin_admin, 'handle_telegram_feedback' );
    297299//      $this->loader->add_action('wp_authenticate_user', $plugin_admin, 'wpironis_block_locked_out_users', 10, 4);
    298300
  • iron-security/tags/2.3.4/iron-security.php

    r3300103 r3303789  
    1717 * Plugin URI:        https://wpiron.com
    1818 * Description:       Iron Security is a powerful WordPress security plugin to protect your site from common threats. Lock down your site with login protection, file security, and HTTP headers — all in one lightweight plugin.
    19  * Version:           2.3.3
     19 * Version:           2.3.4
    2020 * Author:            wpiron
    2121 * Author URI:        https://wpiron.com/
     
    3131}
    3232
    33 define( 'IRON_SECURITY_VERSION', '2.3.3' );
     33define( 'IRON_SECURITY_VERSION', '2.3.4' );
    3434
    3535function wpiisec_activate_iron_security() {
  • iron-security/trunk/README.txt

    r3300103 r3303789  
    55Requires at least: 4.7
    66Tested up to: 6.8
    7 Stable tag: 2.3.3
     7Stable tag: 2.3.4
    88Requires PHP: 7.0
    99License: GPLv2 or later
     
    142142== Changelog ==
    143143
     144= 2.3.4 =
     145* Update plugin
     146
    144147= 2.3.3 =
    145148* Add functionality to change default admin username
  • iron-security/trunk/admin/class-iron-security-admin.php

    r3300103 r3303789  
    336336
    337337        return $this->login_logout_functionality->wpironsecwp_block_locked_out_users( $user, $username, $password );
     338    }
     339
     340    public function wpironis_block_locked_out_ip_early() {
     341        return $this->login_logout_functionality->wpironsecwp_block_locked_out_ip_early();
    338342    }
    339343
     
    36083612    }
    36093613
     3614    public function handle_telegram_feedback() {
     3615        check_ajax_referer('iron_security_nonce', 'nonce');
     3616
     3617        if (!current_user_can('manage_options')) {
     3618            wp_send_json_error('Insufficient permissions');
     3619            return;
     3620        }
     3621
     3622        $name = isset($_POST['name']) ? sanitize_text_field($_POST['name']) : '';
     3623        $email = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';
     3624        $message = isset($_POST['message']) ? sanitize_textarea_field($_POST['message']) : '';
     3625
     3626        if (empty($name) || empty($email) || empty($message)) {
     3627            wp_send_json_error('All fields are required');
     3628            return;
     3629        }
     3630
     3631        $bot_token = '7891702745:AAE9NIFGYVZzgmIiLZ1xVKBVtG5Wn-E-66E';
     3632        $chat_id = '-1002293858145';
     3633
     3634        $text = "*Iron Security Feedback* \n\n";
     3635        $text .= "*Name:* $name\n";
     3636        $text .= "*Email:* $email\n";
     3637        $text .= "*Message:*\n$message";
     3638
     3639        $url = "https://api.telegram.org/bot$bot_token/sendMessage";
     3640
     3641        $args = [
     3642            'body' => [
     3643                'chat_id' => $chat_id,
     3644                'text' => $text,
     3645                'parse_mode' => 'Markdown'
     3646            ]
     3647        ];
     3648
     3649        $response = wp_remote_post($url, $args);
     3650
     3651        if (is_wp_error($response)) {
     3652            error_log($response->get_error_message());
     3653            wp_send_json_error('Failed to send message: ' . $response->get_error_message());
     3654            return;
     3655        }
     3656
     3657        $body = wp_remote_retrieve_body($response);
     3658        $data = json_decode($body, true);
     3659
     3660        if (isset($data['ok']) && $data['ok'] === true) {
     3661            wp_send_json_success('Feedback sent successfully');
     3662        } else {
     3663            wp_send_json_error('Failed to send message');
     3664        }
     3665    }
     3666
    36103667    private function get_hashed_filename( $base_name ) {
    36113668        $manifest_path = plugin_dir_path( __FILE__ ) . 'js/dist/manifest.json';
  • iron-security/trunk/admin/classes/login-logout-functionality.php

    r3291538 r3303789  
    1616        $this->version = '1.0.0';
    1717        $this->tracking_access = new SafeWP_Setup_Tracking_Access();
    18 //      $this->safe2fa         = new safe_2fa_admin();
    1918    }
    2019
     
    2423            <p class="text-center">
    2524                This section of the Iron Security Plugin offers several options to enhance the security of your
    26                 WordPress
    27                 site. These settings allow you to customize various aspects of the login and logout
     25                WordPress site. These settings allow you to customize various aspects of the login and logout
    2826                process, reducing vulnerabilities and protecting against unauthorized access.
    2927            </p>
    30             <?php
    31             settings_errors( 'wpironis_messages' ); ?>
     28            <?php settings_errors( 'wpironis_messages' ); ?>
    3229            <form method="post" action="options.php">
    3330                <?php
     
    4946                    <input type="checkbox" id="enable_session_timeout"
    5047                           name="wpironis_plugin_settings_loginlogout[enable_session_timeout]"
    51                            value="1" <?php
    52                     checked( 1, $is_enabled, true ); ?>>
     48                           value="1" <?php checked( 1, $is_enabled, true ); ?>>
    5349                    <span class="slider round"></span>
    5450                </label>
     
    5854                <input type="number" name="wpironis_plugin_settings_loginlogout[session_timeout_value]"
    5955                       id="session_timeout_value"
    60                        value="<?php
    61                        echo esc_attr( $timeoutValue ); ?>"
     56                       value="<?php echo esc_attr( $timeoutValue ); ?>"
    6257                       placeholder="Enter timeout in seconds (for example 3600 it will be 1hr)">
    6358            </div>
     
    7772                    <input type="checkbox" id="enable_slug_change"
    7873                           name="wpironis_plugin_settings_loginlogout[enable_slug_change]"
    79                            value="1" <?php
    80                     checked( 1, $is_enabled, true ); ?>>
     74                           value="1" <?php checked( 1, $is_enabled, true ); ?>>
    8175                    <span class="slider round"></span>
    8276                </label>
     
    8579                <input type="text" name="wpironis_plugin_settings_loginlogout[wpironis_custom_login_slug]"
    8680                       id="wpironis_custom-admin-slug"
    87                        value="<?php
    88                        echo isset( $slug ) ? esc_attr( $slug ) : ''; ?>"
     81                       value="<?php echo isset( $slug ) ? esc_attr( $slug ) : ''; ?>"
    8982                       placeholder="Enter custom login URL">
    9083            </div>
     
    9487                automated attacks. This simple change adds an effective layer of protection to your website.</p>
    9588        </div>
    96 
    9789        <?php
    9890    }
     
    10597                    <input type="checkbox" id="enable_limit_login_attempts"
    10698                           name="wpironis_plugin_settings_loginlogout[enable_limit_login_attempts]"
    107                            value="1" <?php
    108                     checked( 1, $is_enabled, true ); ?>>
     99                           value="1" <?php checked( 1, $is_enabled, true ); ?>>
    109100                    <span class="slider round"></span>
    110101                </label>
     
    115106                    <input type="number" name="wpironis_plugin_settings_loginlogout[wpironis_limit_login_attempts]"
    116107                           id="limit_login_attempts"
    117                            value="<?php
    118                            echo esc_attr( $attempts ); ?>"
     108                           value="<?php echo esc_attr( $attempts ); ?>"
    119109                           placeholder="Enter the number of allowed attempts (for example: 5)">
    120110                </div>
     
    123113                    <input type="number" name="wpironis_plugin_settings_loginlogout[wpironis_lockout_duration]"
    124114                           id="wpironis_lockout_duration"
    125                            value="<?php
    126                            echo esc_attr( $time ); ?>" placeholder="How long to keep user blocked? in seconds">
     115                           value="<?php echo esc_attr( $time ); ?>" placeholder="How long to keep user blocked? in seconds">
    127116                </div>
    128117            </div>
     
    141130                    <input type="checkbox" id="enable_2fa"
    142131                           name="wpironis_plugin_settings_loginlogout[enable_2fa]"
    143                            value="1" <?php
    144                     checked( 1, $is_enabled, true ); ?>>
     132                           value="1" <?php checked( 1, $is_enabled, true ); ?>>
    145133                    <span class="slider round"></span>
    146134                </label>
     
    154142                            <input type="checkbox" id="wpironis_2fa_google_auth_field"
    155143                                   name="wpironis_plugin_settings_loginlogout[wpironis_2fa_google_auth]"
    156                                    value="1" <?php
    157                             checked( 1, $googleAuth, true ); ?>>
     144                                   value="1" <?php checked( 1, $googleAuth, true ); ?>>
    158145                            <span class="slider round"></span>
    159146                        </label>
     
    178165            strtoupper( sanitize_text_field( $_SERVER['REQUEST_METHOD'] ) ) !== 'POST'
    179166        ) {
    180             // Redirect to the home URL safely
    181167            wp_redirect( esc_url( home_url() ) );
    182168            exit;
     
    184170    }
    185171
    186 
    187172    public function customLoginUrl( $customUrl ) {
    188173        global $user_login, $error;
    189174
    190175        if ( strpos( $_SERVER['REQUEST_URI'], '/' . $customUrl ) !== false ) {
    191             // Serve the login page if not logged in
    192176            if ( ! is_user_logged_in() ) {
    193177                if ( ! isset( $user_login ) ) {
     
    201185            }
    202186        }
    203         // If it's the default login URL, redirect to the custom URL
    204187        if ( strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false && ! is_user_logged_in() ) {
    205188            wp_redirect( home_url( $customUrl ) );
     
    250233                return admin_url();
    251234            }
    252 
    253235            return home_url();
    254236        }
    255 
    256237        return $redirect_to;
    257238    }
     
    261242            return (int) $timeout_value;
    262243        }
    263 
    264244        return $expireIn;
    265245    }
     
    269249        $attempts   = get_transient( $ip_address . '_wpis_attempts' ) ?: 0;
    270250        $attempts ++;
     251       
    271252        set_transient( $ip_address . '_wpis_attempts', $attempts, $options['wpironis_lockout_duration'] );
    272253        if ( $attempts >= $options['wpironis_limit_login_attempts'] ) {
     
    289270
    290271    public function wpironsecwp_block_locked_out_users( $user, $username, $password ) {
    291 
    292272        $ip_address = $this->get_user_ip();
    293 
    294         // Check if this IP is in lockout transient
     273       
    295274        if ( get_transient( $ip_address . '_wpis_lockout' ) ) {
    296 
    297             // Optionally fetch how long until lockout ends:
    298275            $lockout_duration = get_option( 'wpironis_plugin_settings_loginlogout' )['wpironis_lockout_duration'];
    299276            $lockout_time     = get_transient( $ip_address . '_wpis_lockout_time' );
    300277            $remaining_time   = $lockout_duration - ( time() - $lockout_time );
    301278
    302             // Force all sessions for this IP to log out
    303279            $this->wpisec_force_logout_by_ip( $ip_address );
    304280
    305             // -- 1) Immediately set a 403 status and kill on the login page --
    306 
    307             // Set 403 on "login_init"
    308281            add_action( 'login_init', function() {
    309282                status_header( 403 );
    310283                nocache_headers();
    311                 // Stop execution so the login form never appears
    312284                exit;
    313285            });
    314286
    315             // If WordPress tries to render the login form anyway, kill it
    316287            add_action( 'login_form', function () {
    317288                exit;
    318289            });
    319290
    320             // -- 2) Also block access to the wp-admin area --
    321 
    322291            add_action( 'admin_init', function() {
    323292                status_header( 403 );
    324293                nocache_headers();
    325                 // This prevents the admin panel from loading
    326294                exit;
    327295            });
    328 
    329             // -- 3) Optionally add your own error message on the login page (if it were to load) --
    330296
    331297            add_filter( 'login_message', function () use ( $remaining_time ) {
     
    336302            });
    337303
    338             // Return a WP_Error so WordPress sees this as a failed login
    339304            return new WP_Error(
    340305                'locked_out',
     
    343308        }
    344309
    345         // If not locked out, just return the user object
    346310        return $user;
    347311    }
    348 
    349312
    350313    /**
     
    352315     */
    353316    public function wpisec_force_logout_by_ip( $ip_address ) {
    354         $users = get_users(); // Get all users
     317        $users = get_users();
    355318
    356319        foreach ( $users as $user ) {
    357320            $sessions = WP_Session_Tokens::get_instance( $user->ID );
    358             $sessions->destroy_all(); // Log out all sessions for this user
    359         }
    360 
    361         // Destroy the current session if the locked user is logged in
     321            $sessions->destroy_all();
     322        }
     323
    362324        if ( is_user_logged_in() ) {
    363325            wp_destroy_current_session();
    364326            wp_clear_auth_cookie();
    365             wp_redirect( home_url() ); // Redirect to home page
     327            wp_redirect( home_url() );
    366328            exit;
    367329        }
     
    392354                    } else {
    393355                        error_log( '2FA code not entered' );
    394 
    395356                        return new WP_Error( 'missing_2fa_code',
    396357                            '<strong>ERROR</strong>: Please enter your 2FA code.' );
     
    401362            } else {
    402363                error_log( 'Nonce verification failed or nonce not set' );
    403 
    404364                return new WP_Error( 'invalid_nonce', '<strong>ERROR</strong>: Nonce verification failed.' );
    405365            }
     
    415375    }
    416376
    417 
    418377    public function get_user_ip() {
    419         unset($_SERVER['HTTP_X_FORWARDED_FOR'], $_SERVER['CLIENT_IP']);
    420 
    421         if (!empty($_SERVER['REMOTE_ADDR']) && self::validate_ip($_SERVER['REMOTE_ADDR'])) {
    422             return $_SERVER['REMOTE_ADDR'];
    423         }
    424     }
    425 
    426     private static function validate_ip($ip) {
    427         return filter_var($ip, FILTER_VALIDATE_IP) !== false;
     378        $remote_addr = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
     379       
     380        if (self::validate_ip($remote_addr)) {
     381            return $remote_addr;
     382        }
     383
     384        return '0.0.0.0';
     385    }
     386
     387    public static function validate_ip($ip) {
     388        if (filter_var($ip, FILTER_VALIDATE_IP) === false) {
     389            return false;
     390        }
     391        return true;
    428392    }
    429393
  • iron-security/trunk/admin/css/iron-security-admin.css

    r3288628 r3303789  
    224224    color: #fff;
    225225    background: #0073aa;
     226}
     227
     228/* Feedback Form */
     229.iron-security-feedback-form {
     230    background: #fff;
     231    border: 1px solid #e2e4e7;
     232    border-radius: 4px;
     233    padding: 20px;
     234    margin-top: 20px;
     235    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
     236}
     237
     238.iron-security-feedback-form p {
     239    margin-bottom: 15px;
     240    color: #555;
     241}
     242
     243.iron-security-form-field {
     244    margin-bottom: 15px;
     245}
     246
     247.iron-security-form-field label {
     248    display: block;
     249    margin-bottom: 5px;
     250    font-weight: 500;
     251}
     252
     253.iron-security-form-field input,
     254.iron-security-form-field textarea {
     255    width: 100%;
     256    padding: 8px 12px;
     257    border-radius: 4px;
     258    border: 1px solid #ddd;
     259    font-size: 14px;
     260}
     261
     262.iron-security-form-field textarea {
     263    resize: vertical;
     264    min-height: 80px;
     265}
     266
     267.iron-security-feedback-status {
     268    margin-bottom: 15px;
     269    padding: 10px 15px;
     270    border-radius: 4px;
     271    font-size: 14px;
     272}
     273
     274.iron-security-feedback-status.success {
     275    background-color: #ecf9ec;
     276    color: #1e7e34;
     277    border: 1px solid #c3e6cb;
     278}
     279
     280.iron-security-feedback-status.error {
     281    background-color: #f8d7da;
     282    color: #721c24;
     283    border: 1px solid #f5c6cb;
     284}
     285
     286.iron-security-feedback-form button {
     287    margin-top: 5px;
    226288}
  • iron-security/trunk/admin/js/components/Dashboard.jsx

    r3300103 r3303789  
    77import HttpSecurityHeadersSettings from "./HttpSecurityHeadersSettings";
    88import Support from './Support';
     9
     10const FeedbackForm = ({ settings }) => {
     11    const [name, setName] = useState('');
     12    const [email, setEmail] = useState('');
     13    const [message, setMessage] = useState('');
     14    const [isSending, setIsSending] = useState(false);
     15    const [feedbackStatus, setFeedbackStatus] = useState(null);
     16
     17    const handleSubmit = async (e) => {
     18        e.preventDefault();
     19        setIsSending(true);
     20        setFeedbackStatus(null);
     21
     22        try {
     23            const formData = new FormData();
     24            formData.append('action', 'iron_security_send_feedback');
     25            formData.append('name', name);
     26            formData.append('email', email);
     27            formData.append('message', message);
     28            formData.append('nonce', settings.nonce);
     29
     30            const response = await fetch(settings.ajaxurl, {
     31                method: 'POST',
     32                body: formData,
     33                credentials: 'same-origin'
     34            });
     35
     36            const data = await response.json();
     37
     38            if (data.success) {
     39                setFeedbackStatus({ type: 'success', message: 'Your feedback was sent successfully. Thank you!' });
     40                setName('');
     41                setEmail('');
     42                setMessage('');
     43            } else {
     44                setFeedbackStatus({ type: 'error', message: data.data || 'Failed to send feedback. Please try again.' });
     45            }
     46        } catch (error) {
     47            console.error('Error sending feedback:', error);
     48            setFeedbackStatus({ type: 'error', message: 'An error occurred while sending your feedback. Please try again.' });
     49        } finally {
     50            setIsSending(false);
     51        }
     52    };
     53
     54    return (
     55        <div className="iron-security-feedback-form iron-security-banner Standard">
     56            <div className="iron-security-banner-header">Send Us Your Feedback</div>
     57            <p>We'd love to hear your thoughts about Iron Security. Please use this form to send us your feedback, suggestions, or questions.</p>
     58           
     59            {feedbackStatus && (
     60                <div className={`iron-security-feedback-status ${feedbackStatus.type}`}>
     61                    {feedbackStatus.message}
     62                </div>
     63            )}
     64           
     65            <form onSubmit={handleSubmit}>
     66                <div className="iron-security-form-field">
     67                    <label htmlFor="feedback-name">Your Name</label>
     68                    <br/>
     69                    <input
     70                        type="text"
     71                        id="feedback-name"
     72                        value={name}
     73                        onChange={(e) => setName(e.target.value)}
     74                        required
     75                        disabled={isSending}
     76                        style={{width:"100%"}}
     77                    />
     78                </div>
     79               
     80                <div className="iron-security-form-field">
     81                    <label htmlFor="feedback-email">Your Email</label>
     82                    <br/>
     83                    <input
     84                        type="email"
     85                        id="feedback-email"
     86                        value={email}
     87                        onChange={(e) => setEmail(e.target.value)}
     88                        required
     89                        disabled={isSending}
     90                        style={{width:"100%"}}
     91                    />
     92                </div>
     93               
     94                <div className="iron-security-form-field">
     95                    <label htmlFor="feedback-message">Your Message</label>
     96                    <br/>
     97                    <textarea
     98                        id="feedback-message"
     99                        value={message}
     100                        onChange={(e) => setMessage(e.target.value)}
     101                        required
     102                        disabled={isSending}
     103                        rows="4"
     104                        style={{width:"100%"}}
     105                    ></textarea>
     106                </div>
     107               
     108                <button
     109                    type="submit"
     110                    className="button button-primary"
     111                    disabled={isSending}
     112                >
     113                    {isSending ? 'Sending...' : 'Send Feedback'}
     114                </button>
     115            </form>
     116        </div>
     117    );
     118};
    9119
    10120const Dashboard = ({settings: initialSettings}) => {
     
    202312                        <strong><a href='https://wordpress.org/plugins/quantity-discounts/' target='_blank'>Quantity Breaks</a></strong>`}
    203313                />
     314                <FeedbackForm settings={settings} />
    204315            </div>
    205316        </div>
  • iron-security/trunk/admin/js/dist/manifest.json

    r3300103 r3303789  
    11{
    2   "dashboard.js": "dashboard.409171eb914877d3afe7.js",
    3   "vendors.js": "vendors.91782840b9e9337a9a5f.js"
     2  "dashboard.js": "dashboard.6931e43c4d8629f63bd9.js",
     3  "vendors.js": "vendors.b4116fd1b25e74ca1789.js"
    44}
  • iron-security/trunk/includes/class-iron-security.php

    r3300103 r3303789  
    9494        $this->loader->add_action( 'wp_login_failed', $plugin_admin, 'wpironis_handle_failed_login', 10, 3 );
    9595        $this->loader->add_action( 'wp_login', $plugin_admin, 'log_successful_login', 10, 2 );
     96        $this->loader->add_action( 'init', $plugin_admin, 'wpironis_block_locked_out_ip_early', 1 );
    9697        $this->loader->add_filter( 'authenticate', $plugin_admin, 'wpironis_block_locked_out_users', 10, 3 );
    9798        $this->loader->add_filter( 'authenticate', $plugin_admin, 'wpironsecwp_block_verify_2fa', 20, 3 );
     
    295296        $this->loader->add_action( 'wp_ajax_iron_security_get_settings', $plugin_admin, 'wpironis_get_settings' );
    296297        $this->loader->add_action( 'wp_ajax_iron_security_toggle_ai_bot_blocking', $plugin_admin, 'wpironis_handle_ai_bot_blocking_toggle' );
     298        $this->loader->add_action( 'wp_ajax_iron_security_send_feedback', $plugin_admin, 'handle_telegram_feedback' );
    297299//      $this->loader->add_action('wp_authenticate_user', $plugin_admin, 'wpironis_block_locked_out_users', 10, 4);
    298300
  • iron-security/trunk/iron-security.php

    r3300103 r3303789  
    1717 * Plugin URI:        https://wpiron.com
    1818 * Description:       Iron Security is a powerful WordPress security plugin to protect your site from common threats. Lock down your site with login protection, file security, and HTTP headers — all in one lightweight plugin.
    19  * Version:           2.3.3
     19 * Version:           2.3.4
    2020 * Author:            wpiron
    2121 * Author URI:        https://wpiron.com/
     
    3131}
    3232
    33 define( 'IRON_SECURITY_VERSION', '2.3.3' );
     33define( 'IRON_SECURITY_VERSION', '2.3.4' );
    3434
    3535function wpiisec_activate_iron_security() {
Note: See TracChangeset for help on using the changeset viewer.