Plugin Directory

Changeset 3378867


Ignore:
Timestamp:
10/15/2025 11:59:42 AM (5 months ago)
Author:
chrmrtns
Message:

Release version 2.7.3 - Critical bug fixes

CRITICAL FIX: Magic link token validation

  • Fixed database table name mismatches causing immediate token expired errors
  • Token validation was querying non-existent kla_login_tokens table
  • Updated 10 SQL queries to use correct chrmrtns_kla_* table prefix
  • Tokens stored in chrmrtns_kla_login_tokens but lookups used kla_login_tokens

CRITICAL FIX: 2FA grace period redirect

  • Fixed malformed URL when grace period expires
  • Changed from wp_login_url with query string to add_query_arg()
  • Prevents incorrect URL encoding of query parameters

Additional fixes:

  • Removed unused variable in backup code validation
  • Fixed all database queries to use correct table names

Impact: Users experiencing immediate token expiration on magic links should now login successfully

Location:
keyless-auth
Files:
33 added
4 edited

Legend:

Unmodified
Added
Removed
  • keyless-auth/trunk/includes/class-chrmrtns-kla-2fa-core.php

    r3372203 r3378867  
    725725            if (time() > $grace_end) {
    726726                wp_logout();
    727                 wp_redirect(wp_login_url('?chrmrtns_kla_2fa_required=1'));
     727                wp_redirect(add_query_arg('chrmrtns_kla_2fa_required', '1', wp_login_url()));
    728728                exit;
    729729            }
  • keyless-auth/trunk/includes/class-chrmrtns-kla-database.php

    r3378019 r3378867  
    298298
    299299        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $where_clause and $order_by are properly sanitized above
    300         $sql = "SELECT * FROM {$wpdb->prefix}kla_login_logs
     300        $sql = "SELECT * FROM {$wpdb->prefix}chrmrtns_kla_login_logs
    301301                WHERE $where_clause
    302302                ORDER BY $order_by
     
    397397
    398398        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $sql is hardcoded with proper placeholders, no dynamic content
    399         $sql = "SELECT * FROM {$wpdb->prefix}kla_login_tokens
     399        $sql = "SELECT * FROM {$wpdb->prefix}chrmrtns_kla_login_tokens
    400400                WHERE user_id = %d
    401401                AND token_hash = %s
     
    425425        // Increment attempt count for failed attempts
    426426        $wpdb->query($wpdb->prepare(
    427             "UPDATE {$wpdb->prefix}kla_login_tokens
     427            "UPDATE {$wpdb->prefix}chrmrtns_kla_login_tokens
    428428             SET attempt_count = attempt_count + 1
    429429             WHERE user_id = %d AND token_hash = %s",
     
    449449
    450450        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $where_clause is safely constructed above
    451         $sql = "DELETE FROM {$wpdb->prefix}kla_login_tokens WHERE $where_clause"; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
     451        $sql = "DELETE FROM {$wpdb->prefix}chrmrtns_kla_login_tokens WHERE $where_clause"; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    452452
    453453        if (!empty($where_values)) {
     
    468468        // Total logins
    469469        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Statistics query for custom table
    470         $stats['total_logins'] = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}kla_login_logs WHERE status = 'success'");
     470        $stats['total_logins'] = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}chrmrtns_kla_login_logs WHERE status = 'success'");
    471471
    472472        // Logins this month
    473473        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Statistics query for custom table
    474474        $stats['logins_this_month'] = $wpdb->get_var(
    475             "SELECT COUNT(*) FROM {$wpdb->prefix}kla_login_logs
     475            "SELECT COUNT(*) FROM {$wpdb->prefix}chrmrtns_kla_login_logs
    476476             WHERE status = 'success'
    477477             AND login_time >= DATE_FORMAT(NOW(), '%Y-%m-01')"
     
    480480        // Failed attempts
    481481        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Statistics query for custom table
    482         $stats['failed_attempts'] = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}kla_login_logs WHERE status = 'failed'");
     482        $stats['failed_attempts'] = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}chrmrtns_kla_login_logs WHERE status = 'failed'");
    483483
    484484        // Total emails sent
    485485        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Statistics query for custom table
    486         $stats['emails_sent'] = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}kla_mail_logs WHERE status = 'sent'");
     486        $stats['emails_sent'] = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}chrmrtns_kla_mail_logs WHERE status = 'sent'");
    487487
    488488        // Active tokens
    489489        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Statistics query for custom table
    490         $stats['active_tokens'] = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}kla_login_tokens WHERE expires_at > NOW() AND is_used = 0");
     490        $stats['active_tokens'] = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}chrmrtns_kla_login_tokens WHERE expires_at > NOW() AND is_used = 0");
    491491
    492492        return $stats;
     
    504504        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Maintenance cleanup of old logs
    505505        $login_deleted = $wpdb->query($wpdb->prepare(
    506             "DELETE FROM {$wpdb->prefix}kla_login_logs WHERE login_time < %s",
     506            "DELETE FROM {$wpdb->prefix}chrmrtns_kla_login_logs WHERE login_time < %s",
    507507            $date_threshold
    508508        ));
     
    511511        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Maintenance cleanup of old logs
    512512        $mail_deleted = $wpdb->query($wpdb->prepare(
    513             "DELETE FROM {$wpdb->prefix}kla_mail_logs WHERE sent_time < %s",
     513            "DELETE FROM {$wpdb->prefix}chrmrtns_kla_mail_logs WHERE sent_time < %s",
    514514            $date_threshold
    515515        ));
     
    585585        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Querying custom devices table
    586586        $existing = $wpdb->get_row($wpdb->prepare(
    587             "SELECT id FROM {$wpdb->prefix}kla_user_devices WHERE user_id = %d AND device_fingerprint = %s",
     587            "SELECT id FROM {$wpdb->prefix}chrmrtns_kla_user_devices WHERE user_id = %d AND device_fingerprint = %s",
    588588            $user_id, $device_fingerprint
    589589        ));
     
    659659        $result = $wpdb->get_row($wpdb->prepare(
    660660            "SELECT totp_secret, totp_enabled, totp_backup_codes, totp_last_used, totp_failed_attempts, totp_locked_until
    661              FROM {$wpdb->prefix}kla_user_devices
     661             FROM {$wpdb->prefix}chrmrtns_kla_user_devices
    662662             WHERE user_id = %d AND totp_enabled = 1
    663663             LIMIT 1",
     
    697697            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Updating custom devices table
    698698            $wpdb->query($wpdb->prepare(
    699                 "UPDATE {$wpdb->prefix}kla_user_devices
     699                "UPDATE {$wpdb->prefix}chrmrtns_kla_user_devices
    700700                 SET totp_failed_attempts = totp_failed_attempts + 1,
    701701                     totp_locked_until = CASE
     
    763763        $base_query = "SELECT u.ID, u.user_login, u.user_email, u.display_name, d.totp_enabled, d.totp_last_used, d.totp_failed_attempts, d.totp_locked_until
    764764                       FROM {$wpdb->users} u
    765                        INNER JOIN {$wpdb->prefix}kla_user_devices d ON u.ID = d.user_id AND d.totp_enabled = 1";
     765                       INNER JOIN {$wpdb->prefix}chrmrtns_kla_user_devices d ON u.ID = d.user_id AND d.totp_enabled = 1";
    766766
    767767        if (!empty($search)) {
  • keyless-auth/trunk/keyless-auth.php

    r3378019 r3378867  
    44* Plugin URI: https://github.com/chrmrtns/keyless-auth
    55* Description: Enhanced passwordless authentication allowing users to login securely without passwords via email magic links. Fork of Passwordless Login by Cozmoslabs with additional security features.
    6 * Version: 2.7.2
     6* Version: 2.7.3
    77* Author: Chris Martens
    88* Author URI: https://github.com/chrmrtns
     
    3838
    3939// Define plugin constants
    40 define('CHRMRTNS_KLA_VERSION', '2.7.2');
     40define('CHRMRTNS_KLA_VERSION', '2.7.3');
    4141define('CHRMRTNS_KLA_PLUGIN_DIR', plugin_dir_path(__FILE__));
    4242define('CHRMRTNS_KLA_PLUGIN_URL', plugin_dir_url(__FILE__));
  • keyless-auth/trunk/readme.txt

    r3378019 r3378867  
    66Requires at least: 3.9
    77Tested up to: 6.8
    8 Stable tag: 2.7.2
     8Stable tag: 2.7.3
    99License: GPLv2 or later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    305305
    306306== Changelog ==
     307= 2.7.3 =
     308* CRITICAL FIX: Magic link token validation - Fixed database table name mismatches causing "token expired" errors
     309* CRITICAL FIX: 2FA grace period redirect - Fixed malformed URL when grace period expires (proper use of add_query_arg)
     310* FIX: Database queries now correctly reference chrmrtns_kla_* tables instead of kla_* tables (10 query fixes)
     311* FIX: Removed unused variable $code_hash in backup code validation function
     312* TECHNICAL: Token validation was querying non-existent kla_login_tokens table instead of chrmrtns_kla_login_tokens
     313* TECHNICAL: Fixed inconsistency between table creation (chrmrtns_kla_*) and queries (kla_*)
     314* IMPACT: Users experiencing immediate token expiration on magic links should now login successfully
     315
    307316= 2.7.2 =
    308317* FIX: Database table naming - Renamed all tables from kla_* to chrmrtns_kla_* for unique namespace and collision prevention
Note: See TracChangeset for help on using the changeset viewer.