Viewing 4 replies - 1 through 4 (of 4 total)
  • Hi @kurtnuimage,

    It seems the woocommerce_process_login_errors is not an action but a filter. The code in your hooked callback (add_wc_process_login_errors) may not be correct.

    Furthermore it seems you can also use the WordPress Core login_errors filter.

    +++ To prevent any confusion, I’m not SolidWP +++

    • This reply was modified 8 months, 4 weeks ago by nlpro.
    Thread Starter nukurt

    (@kurtnuimage)

    Hi @nlpro

    Thanks for the response, you are right it is actually a filter instead. That is actually something i noticed as well.

    The problem with using the woocommerce_process_login_errors filter is that it seems to fire before Solid Security, so using the filter means that login attempts no longer seem to be logged into the wp_itsec_logs table.

    I know you’re not Solid Security so i understand if you don’t know, but i guess i need to know at which point Solid Security writes to the database, so i can use a filter after this point and return my error message.

    Plugin Support Brent Wilson

    (@bwbama)

    Hello,

    Apologies for the delay here!

    This code is untested so please try this on a staging/development site before pushing it live. This should help get you pointed in the right direction:

    <?php
    /**
    * WooCommerce: show Solid Security "attempts remaining" after a real failed login.
    * Place in wp-content/mu-plugins/attempts-remaining.php (preferred) or your theme’s functions.php
    */

    add_action( 'wp_login_failed', function ( $username, $error ) {
    // Only show on WooCommerce flows where notices are displayed.
    if ( ! function_exists( 'wc_add_notice' ) ) {
    return;
    }

    // Solid Security classes must be available.
    if ( ! class_exists( 'ITSEC_Modules' ) || ! class_exists( 'ITSEC_Lib' ) ) {
    return;
    }

    $settings = ITSEC_Modules::get_settings( 'brute-force' );
    $host_limit = isset( $settings['max_attempts_host'] ) ? (int) $settings['max_attempts_host'] : 0;
    $user_limit = isset( $settings['max_attempts_user'] ) ? (int) $settings['max_attempts_user'] : 0;
    $period_min = isset( $settings['check_period'] ) ? (int) $settings['check_period'] : 0;

    // If both limits are effectively disabled, skip.
    if ( $host_limit <= 0 && $user_limit <= 0 ) {
    return;
    }

    global $wpdb;
    $table = $wpdb->base_prefix . 'itsec_logs';
    $since = gmdate( 'Y-m-d H:i:s', time() - ( $period_min * 60 ) );

    // Use Solid Security’s IP helper so proxies/CDN are respected (configure Proxy Detection in Security > Settings > Global).
    $ip = ITSEC_Lib::get_ip();

    // Count failures for this host (IP) in the window.
    $host_used = 0;
    if ( $host_limit > 0 ) {
    $host_used = (int) $wpdb->get_var(
    $wpdb->prepare(
    "SELECT COUNT(*)
    FROM {$table}
    WHERE module = %s
    AND code LIKE 'invalid-login%%'
    AND remote_ip = %s
    AND init_timestamp > %s",
    'brute_force', $ip, $since
    )
    );
    }
    $host_remaining = ( $host_limit > 0 ) ? max( 0, $host_limit - $host_used ) : PHP_INT_MAX;

    // Count failures for this specific user (if it exists) in the window.
    $user_remaining = PHP_INT_MAX;
    if ( $user_limit > 0 ) {
    $user = get_user_by( is_email( $username ) ? 'email' : 'login', $username );
    if ( $user instanceof WP_User ) {
    $user_used = (int) $wpdb->get_var(
    $wpdb->prepare(
    "SELECT COUNT(*)
    FROM {$table}
    WHERE module = %s
    AND code = %s
    AND init_timestamp > %s",
    'brute_force',
    'invalid-login::user-' . $user->ID,
    $since
    )
    );
    $user_remaining = max( 0, $user_limit - $user_used );
    }
    }

    $remaining = min( $host_remaining, $user_remaining );

    // If at least one limit is active, show a notice.
    if ( PHP_INT_MAX !== $remaining ) {
    /* translators: 1: number remaining, 2: "s" plural suffix (or empty), 3: minutes in window */
    $message = sprintf(
    __( 'Heads up: You have %1$d login attempt%2$s remaining before a temporary lockout (resets after %3$d minutes).', 'your-textdomain' ),
    $remaining,
    ( 1 === (int) $remaining ) ? '' : 's',
    $period_min
    );

    // Use a neutral notice; switch to 'error' if you want it red.
    wc_add_notice( $message, 'notice' );
    }
    }, 10, 2 );

    Let me know if you run into any issues!

    Thread Starter nukurt

    (@kurtnuimage)

    Hi @bwbama,

    This code seems to work great thank you!

    The one minor adjustment i made was to not show the notice if the IP is found in the authorized IP list, but this is done now.

    Thanks for the help!

Viewing 4 replies - 1 through 4 (of 4 total)

The topic ‘Login attempts remaining’ is closed to new replies.