Plugin Directory

Changeset 3216078


Ignore:
Timestamp:
01/02/2025 04:37:27 PM (12 months ago)
Author:
wfryan
Message:

1.1.14 - January 2, 2025

  • Improvement: General compatibility improvements and better error handling for PHP 8+
Location:
wordfence-login-security
Files:
42 added
42 deleted
22 edited
1 copied

Legend:

Unmodified
Added
Removed
  • wordfence-login-security/tags/1.1.14/classes/controller/ajax.php

    r3035804 r3216078  
    301301   
    302302    public function _ajax_activate_callback() {
    303         $userID = (int) @$_POST['user'];
     303        $userID = (int) Utility_Array::arrayGet($_POST, 'user', 0);
    304304        $user = wp_get_current_user();
    305305        if ($user->ID != $userID) {
     
    333333   
    334334    public function _ajax_deactivate_callback() {
    335         $userID = (int) @$_POST['user'];
     335        $userID = (int) Utility_Array::arrayGet($_POST, 'user', 0);
    336336        $user = wp_get_current_user();
    337337        if ($user->ID != $userID) {
     
    359359   
    360360    public function _ajax_regenerate_callback() {
    361         $userID = (int) @$_POST['user'];
     361        $userID = (int) Utility_Array::arrayGet($_POST, 'user', 0);
    362362        $user = wp_get_current_user();
    363363        if ($user->ID != $userID) {
  • wordfence-login-security/tags/1.1.14/classes/controller/settings.php

    r3049221 r3216078  
    197197            case self::OPTION_IP_TRUSTED_PROXIES:
    198198            case self::OPTION_2FA_WHITELISTED:
     199                $value = !is_string($value) ? '' : $value;
    199200                $parsed = array_filter(array_map(function($s) { return trim($s); }, preg_split('/[\r\n]/', $value)));
    200201                foreach ($parsed as $entry) {
     
    303304            case self::OPTION_IP_TRUSTED_PROXIES:
    304305            case self::OPTION_2FA_WHITELISTED:
     306                $value = !is_string($value) ? '' : $value;
    305307                $parsed = array_filter(array_map(function($s) { return trim($s); }, preg_split('/[\r\n]/', $value)));
    306308                $cleaned = array();
     
    357359                $roleValid = true;
    358360            }
    359             elseif (in_array($value, array(self::STATE_2FA_OPTIONAL, self::STATE_2FA_REQUIRED))) {
     361            else if (in_array($value, array(self::STATE_2FA_OPTIONAL, self::STATE_2FA_REQUIRED))) {
    360362                $roleValid = Controller_Permissions::shared()->allow_2fa_self($role);
    361363            }
     
    363365                $roleValid = Controller_Permissions::shared()->disallow_2fa_self($role);
    364366            }
    365             if ($roleValid)
     367           
     368            if (!in_array($value, array(self::STATE_2FA_OPTIONAL, self::STATE_2FA_REQUIRED))) {
     369                $value = self::STATE_2FA_DISABLED;
     370            }
     371           
     372            if ($roleValid) {
    366373                $settings[$this->get_required_2fa_role_key($role)] = ($value === self::STATE_2FA_REQUIRED ? time() : -1);
     374            }
     375           
     376            /**
     377             * Fires when 2FA availability/required on a role changes.
     378             *
     379             * @since 1.1.13
     380             *
     381             * @param string $role The name of the role.
     382             * @param string $state The state of 2FA on the role.
     383             */
     384            do_action('wordfence_ls_changed_2fa_required', $role, $value);
     385           
    367386            return true;
    368387        }
     388       
     389        //Settings that will dispatch actions
     390        switch ($key) {
     391            case self::OPTION_XMLRPC_ENABLED:
     392                $before = $this->get($key);
     393                $after = $value;
     394               
     395                if ($before != $after) {
     396                    /**
     397                     * Fires when the XML-RPC 2FA requirement changes.
     398                     *
     399                     * @since 1.1.13
     400                     *
     401                     * @param bool $before The previous value.
     402                     * @param bool $after The new value.
     403                     */
     404                    do_action('wordfence_ls_xml_rpc_2fa_toggled', $before, $after);
     405                }
     406                break;
     407            case self::OPTION_2FA_WHITELISTED:
     408                $before = $this->whitelisted_ips();
     409                $after = explode("\n", $value); //Already cleaned here so just re-split
     410                   
     411                if ($before != $after) {
     412                    /**
     413                     * Fires when the whitelist changes.
     414                     *
     415                     * @since 1.1.13
     416                     *
     417                     * @param string[] $before The previous value.
     418                     * @param string[] $after The new value.
     419                     */
     420                    do_action('wordfence_ls_updated_allowed_ips', $before, $after);
     421                }
     422                break;
     423            case self::OPTION_IP_SOURCE:
     424                $before = $this->get($key);
     425                $after = $value;
     426               
     427                if ($before != $after) {
     428                    /**
     429                     * Fires when the IP source changes.
     430                     *
     431                     * @since 1.1.13
     432                     *
     433                     * @param string $before The previous value.
     434                     * @param string $after The new value.
     435                     */
     436                    do_action('wordfence_ls_changed_ip_source', $before, $after);
     437                }
     438                break;
     439            case self::OPTION_IP_TRUSTED_PROXIES:
     440                $before = $this->trusted_proxies();
     441                $after = explode("\n", $value); //Already cleaned here so just re-split
     442               
     443                if (count($before) == count($after) && empty(array_diff($before, $after))) {
     444                    /**
     445                     * Fires when the trusted proxy list changes.
     446                     *
     447                     * @since 1.1.13
     448                     *
     449                     * @param string[] $before The previous value.
     450                     * @param string[] $after The new value.
     451                     */
     452                    do_action('wordfence_ls_updated_trusted_proxies', $before, $after);
     453                }
     454                break;
     455            case self::OPTION_REQUIRE_2FA_USER_GRACE_PERIOD:
     456                $before = $this->get($key);
     457                $after = $value;
     458               
     459                if ($before != $after) {
     460                    /**
     461                     * Fires when the grace period changes.
     462                     *
     463                     * @since 1.1.13
     464                     *
     465                     * @param int $before The previous value.
     466                     * @param int $after The new value.
     467                     */
     468                    do_action('wordfence_ls_changed_grace_period', $before, $after);
     469                }
     470                break;
     471            case self::OPTION_ALLOW_XML_RPC:
     472                $before = $this->get($key);
     473                $after = $value;
     474               
     475                if ($before != $after) {
     476                    /**
     477                     * Fires when the XML-RPC is enabled/disabled.
     478                     *
     479                     * @since 1.1.13
     480                     *
     481                     * @param bool $before The previous value.
     482                     * @param bool $after The new value.
     483                     */
     484                    do_action('wordfence_ls_xml_rpc_enabled_toggled', $before, $after);
     485                }
     486                break;
     487            case self::OPTION_ENABLE_AUTH_CAPTCHA:
     488                $before = $this->get($key);
     489                $after = $value;
     490               
     491                if ($before != $after) {
     492                    /**
     493                     * Fires when the login captcha is enabled/disabled.
     494                     *
     495                     * @since 1.1.13
     496                     *
     497                     * @param bool $before The previous value.
     498                     * @param bool $after The new value.
     499                     */
     500                    do_action('wordfence_ls_captcha_enabled_toggled', $before, $after);
     501                }
     502                break;
     503            case self::OPTION_RECAPTCHA_THRESHOLD:
     504                $before = $this->get($key);
     505                $after = $value;
     506               
     507                if ($before != $after) {
     508                    /**
     509                     * Fires when the reCAPTCHA threshold changes.
     510                     *
     511                     * @since 1.1.13
     512                     *
     513                     * @param float $before The previous value.
     514                     * @param float $after The new value.
     515                     */
     516                    do_action('wordfence_ls_captcha_threshold_changed', $before, $after);
     517                }
     518                break;
     519            case self::OPTION_ENABLE_WOOCOMMERCE_INTEGRATION:
     520                $before = $this->get($key);
     521                $after = $value;
     522               
     523                if ($before != $after) {
     524                    /**
     525                     * Fires when WooCommerce integration is enabled/disabled.
     526                     *
     527                     * @since 1.1.13
     528                     *
     529                     * @param bool $before The previous value.
     530                     * @param bool $after The new value.
     531                     */
     532                    do_action('wordfence_ls_woocommerce_enabled_toggled', $before, $after);
     533                }
     534                break;
     535            case self::OPTION_CAPTCHA_TEST_MODE:
     536                $before = $this->get($key);
     537                $after = $value;
     538               
     539                if ($before != $after) {
     540                    /**
     541                     * Fires when captcha test mode is enabled/disabled.
     542                     *
     543                     * @since 1.1.13
     544                     *
     545                     * @param bool $before The previous value.
     546                     * @param bool $after The new value.
     547                     */
     548                    do_action('wordfence_ls_captcha_test_mode_toggled', $before, $after);
     549                }
     550                break;
     551        }
     552       
    369553        return false;
    370554    }
     
    479663        }
    480664       
     665        if (is_null($value)) {
     666            return false;
     667        }
     668       
    481669        if (is_numeric($value)) {
    482670            return !!$value;
  • wordfence-login-security/tags/1.1.14/classes/controller/totp.php

    r2786998 r3216078  
    3939        $table = Controller_DB::shared()->secrets;
    4040        $wpdb->query($wpdb->prepare("INSERT INTO `{$table}` (`user_id`, `secret`, `recovery`, `ctime`, `vtime`, `mode`) VALUES (%d, %s, %s, UNIX_TIMESTAMP(), %d, 'authenticator')", $user->ID, Model_Compat::hex2bin($secret), implode('', array_map(function($r) { return Model_Compat::hex2bin($r); }, $recovery)), $vtime));
     41       
     42        /**
     43         * Fires when 2FA is enabled for a user.
     44         *
     45         * @since 1.1.13
     46         *
     47         * @param \WP_User $user The user.
     48         */
     49        do_action('wordfence_ls_2fa_activated', $user);
    4150    }
    4251   
  • wordfence-login-security/tags/1.1.14/classes/controller/users.php

    r3098784 r3216078  
    230230        $table = Controller_DB::shared()->secrets;
    231231        $wpdb->query($wpdb->prepare("DELETE FROM `{$table}` WHERE `user_id` = %d", $user->ID));
     232       
     233        /**
     234         * Fires when 2FA is disabled for a user.
     235         *
     236         * @since 1.1.13
     237         *
     238         * @param \WP_User $user The user.
     239         */
     240        do_action('wordfence_ls_2fa_deactivated', $user);
    232241    }
    233242
  • wordfence-login-security/tags/1.1.14/classes/controller/wordfencels.php

    r3063866 r3216078  
    238238        $_runInstallCalled = true;
    239239       
    240         if (function_exists('ignore_user_abort')) {
     240        if (function_exists('ignore_user_abort') && is_callable('ignore_user_abort')) {
    241241            @ignore_user_abort(true);
    242242        }
  • wordfence-login-security/tags/1.1.14/classes/model/crypto/jwt.php

    r2098090 r3216078  
    3939        $payload = @json_decode($json, true);
    4040        $expiration = false;
    41         if (isset($payload['_exp'])) {
     41        if (!is_array($payload)) {
     42            return false;
     43        }
     44        else if (isset($payload['_exp'])) {
    4245            $expiration = $payload['_exp'];
    4346           
  • wordfence-login-security/tags/1.1.14/classes/model/ip.php

    r2098090 r3216078  
    1616       
    1717        if (self::has_ipv6()) {
    18             return @inet_ntop($ip);
     18            return inet_ntop($ip);
    1919        }
    2020       
     
    6969    public static function inet_pton($ip) {
    7070        if (self::has_ipv6()) {
    71             $pton = @inet_pton($ip);
     71            $pton = inet_pton($ip);
    7272            if ($pton === false) {
    7373                return false;
     
    126126     */
    127127    public static function has_ipv6() {
    128         return defined('AF_INET6');
     128        return defined('AF_INET6') && is_callable('inet_ntop') && is_callable('inet_pton');
    129129    }
    130130   
  • wordfence-login-security/tags/1.1.14/classes/utility/array.php

    r2865297 r3216078  
    2626        return true;
    2727    }
    28 
     28   
     29    /**
     30     * Returns the items from $array whose keys are in $keys.
     31     *
     32     * @param array $array
     33     * @param array|string $keys
     34     * @param bool $single Return single-value as-is instead of a one-element array.
     35     * @param mixed|null $default Value to return when $single is true and nothing is found.
     36     * @return array|mixed
     37     */
     38    public static function arrayChoose($array, $keys, $single = false, $default = null) {
     39        if (!is_array($keys)) {
     40            $keys = array($keys);
     41        }
     42       
     43        $matches = array_filter($array, function($k) use ($keys) {
     44            return in_array($k, $keys);
     45        }, ARRAY_FILTER_USE_KEY);
     46        if ($single) {
     47            $key = self::arrayFirst($keys);
     48            if ($key !== null && isset($matches[$key])) {
     49                return $matches[$key];
     50            }
     51           
     52            return $default;
     53        }
     54        return $matches;
     55    }
     56   
     57    /**
     58     * Convenience function for `arrayChoose` in its single return value mode for better code readability.
     59     *
     60     * @param array $array
     61     * @param string $key
     62     * @param mixed|null $default
     63     * @return mixed
     64     */
     65    public static function arrayGet($array, $key, $default = null) {
     66        return self::arrayChoose($array, $key, true, $default);
     67    }
     68   
     69    public static function arrayFirst($array) {
     70        if (empty($array)) {
     71            return null;
     72        }
     73       
     74        $values = array_values($array);
     75        return $values[0];
     76    }
     77   
     78    public static function arrayLast($array) {
     79        if (empty($array)) {
     80            return null;
     81        }
     82       
     83        $values = array_values($array);
     84        return $values[count($values) - 1];
     85    }
    2986}
  • wordfence-login-security/tags/1.1.14/languages/wordfence-login-security.pot

    r3098784 r3216078  
    1 # Copyright (C) 2024 Wordfence
     1# Copyright (C) 2025 Wordfence
    22# This file is distributed under the same license as the Wordfence Login Security plugin.
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Wordfence Login Security 1.1.12\n"
    6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wordfence-login-security-zip-V4phf6rXp\n"
     5"Project-Id-Version: Wordfence Login Security 1.1.14\n"
     6"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wordfence-login-security-zip-yKQU9cJFC\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
    88"Language-Team: LANGUAGE <[email protected]>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2024-06-06T15:13:00+00:00\n"
     12"POT-Creation-Date: 2025-01-02T16:27:17+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.7.1\n"
     
    245245msgstr ""
    246246
    247 #: classes/controller/settings.php:202
     247#: classes/controller/settings.php:203
    248248msgid "The IP/range %s is invalid."
    249249msgstr ""
    250250
    251 #: classes/controller/settings.php:208
     251#: classes/controller/settings.php:209
    252252msgid "An invalid IP source was provided."
    253253msgstr ""
    254254
    255 #: classes/controller/settings.php:214
     255#: classes/controller/settings.php:215
    256256msgid "The grace period end time must be in the future."
    257257msgstr ""
    258258
    259 #: classes/controller/settings.php:236
     259#: classes/controller/settings.php:237
    260260msgid "Unable to validate the reCAPTCHA site key. Please check the key and try again."
    261261msgstr ""
    262262
    263 #: classes/controller/settings.php:240
     263#: classes/controller/settings.php:241
    264264msgid "An error was encountered while validating the reCAPTCHA site key: %s"
    265265msgstr ""
    266266
    267 #: classes/controller/users.php:521
     267#: classes/controller/users.php:530
    268268#: classes/controller/wordfencels.php:486
    269269msgid "2FA Status"
    270270msgstr ""
    271271
    272 #: classes/controller/users.php:525
     272#: classes/controller/users.php:534
    273273msgid "Last Login"
    274274msgstr ""
    275275
    276 #: classes/controller/users.php:527
     276#: classes/controller/users.php:536
    277277msgid "Last CAPTCHA"
    278278msgstr ""
    279279
    280 #: classes/controller/users.php:537
     280#: classes/controller/users.php:546
    281281msgid "Not Allowed"
    282282msgstr ""
    283283
    284 #: classes/controller/users.php:542
     284#: classes/controller/users.php:551
    285285#: classes/controller/wordfencels.php:490
    286286msgid "Active"
    287287msgstr ""
    288288
    289 #: classes/controller/users.php:545
     289#: classes/controller/users.php:554
    290290msgid "Inactive<small class=\"wfls-sub-status\">(Grace Period)</small>"
    291291msgstr ""
    292292
    293 #: classes/controller/users.php:548
     293#: classes/controller/users.php:557
    294294msgid "Locked Out<small class=\"wfls-sub-status\">(Grace Period Disabled)</small>"
    295295msgstr ""
    296296
    297 #: classes/controller/users.php:548
     297#: classes/controller/users.php:557
    298298msgid "Locked Out<small class=\"wfls-sub-status\">(Grace Period Exceeded)</small>"
    299299msgstr ""
    300300
    301 #: classes/controller/users.php:551
     301#: classes/controller/users.php:560
    302302#: classes/controller/wordfencels.php:490
    303303msgid "Inactive"
    304304msgstr ""
    305305
    306 #: classes/controller/users.php:653
     306#: classes/controller/users.php:662
    307307msgid "Edit two-factor authentication for %s"
    308308msgstr ""
    309309
    310 #: classes/controller/users.php:653
     310#: classes/controller/users.php:662
    311311#: views/settings/options.php:9
    312312msgid "2FA"
    313313msgstr ""
    314314
    315 #: classes/controller/users.php:664
     315#: classes/controller/users.php:673
    316316#: views/settings/user-stats.php:25
    317317msgid "2FA Active"
    318318msgstr ""
    319319
    320 #: classes/controller/users.php:665
     320#: classes/controller/users.php:674
    321321#: views/settings/user-stats.php:26
    322322msgid "2FA Inactive"
  • wordfence-login-security/tags/1.1.14/readme.txt

    r3118641 r3216078  
    22Contributors: wfryan, wfmattr, mmaunder, wfmatt
    33Tags: security, login security, 2fa, two factor authentication, captcha, xml-rpc, mfa, 2 factor
    4 Requires at least: 4.5
    5 Requires PHP: 5.5
    6 Tested up to: 6.6
    7 Stable tag: 1.1.12
     4Requires at least: 4.7
     5Requires PHP: 7.0
     6Tested up to: 6.7
     7Stable tag: 1.1.14
    88
    99Secure your website with Wordfence Login Security, providing two-factor authentication, login and registration CAPTCHA, and XML-RPC protection.
     
    5858
    5959== Changelog ==
     60
     61= 1.1.14 - January 2, 2025 =
     62* Improvement: General compatibility improvements and better error handling for PHP 8+
    6063
    6164= 1.1.12 - June 6, 2024 =
  • wordfence-login-security/tags/1.1.14/wordfence-login-security.php

    r3098784 r3216078  
    55Author: Wordfence
    66Author URI: https://www.wordfence.com/
    7 Version: 1.1.12
     7Version: 1.1.14
    88Network: true
    9 Requires at least: 4.5
    10 Requires PHP: 5.5
     9Requires at least: 4.7
     10Requires PHP: 7.0
    1111Text Domain: wordfence-login-security
    1212Domain Path: /languages
     
    3939    define('WORDFENCE_LS_FROM_CORE', ($wfCoreActive && isset($wfCoreLoading) && $wfCoreLoading));
    4040   
    41     define('WORDFENCE_LS_VERSION', '1.1.12');
    42     define('WORDFENCE_LS_BUILD_NUMBER', '1717686780');
     41    define('WORDFENCE_LS_VERSION', '1.1.14');
     42    define('WORDFENCE_LS_BUILD_NUMBER', '1735835237');
    4343
    4444    define('WORDFENCE_LS_PLUGIN_BASENAME', plugin_basename(__FILE__));
  • wordfence-login-security/trunk/classes/controller/ajax.php

    r3035804 r3216078  
    301301   
    302302    public function _ajax_activate_callback() {
    303         $userID = (int) @$_POST['user'];
     303        $userID = (int) Utility_Array::arrayGet($_POST, 'user', 0);
    304304        $user = wp_get_current_user();
    305305        if ($user->ID != $userID) {
     
    333333   
    334334    public function _ajax_deactivate_callback() {
    335         $userID = (int) @$_POST['user'];
     335        $userID = (int) Utility_Array::arrayGet($_POST, 'user', 0);
    336336        $user = wp_get_current_user();
    337337        if ($user->ID != $userID) {
     
    359359   
    360360    public function _ajax_regenerate_callback() {
    361         $userID = (int) @$_POST['user'];
     361        $userID = (int) Utility_Array::arrayGet($_POST, 'user', 0);
    362362        $user = wp_get_current_user();
    363363        if ($user->ID != $userID) {
  • wordfence-login-security/trunk/classes/controller/settings.php

    r3049221 r3216078  
    197197            case self::OPTION_IP_TRUSTED_PROXIES:
    198198            case self::OPTION_2FA_WHITELISTED:
     199                $value = !is_string($value) ? '' : $value;
    199200                $parsed = array_filter(array_map(function($s) { return trim($s); }, preg_split('/[\r\n]/', $value)));
    200201                foreach ($parsed as $entry) {
     
    303304            case self::OPTION_IP_TRUSTED_PROXIES:
    304305            case self::OPTION_2FA_WHITELISTED:
     306                $value = !is_string($value) ? '' : $value;
    305307                $parsed = array_filter(array_map(function($s) { return trim($s); }, preg_split('/[\r\n]/', $value)));
    306308                $cleaned = array();
     
    357359                $roleValid = true;
    358360            }
    359             elseif (in_array($value, array(self::STATE_2FA_OPTIONAL, self::STATE_2FA_REQUIRED))) {
     361            else if (in_array($value, array(self::STATE_2FA_OPTIONAL, self::STATE_2FA_REQUIRED))) {
    360362                $roleValid = Controller_Permissions::shared()->allow_2fa_self($role);
    361363            }
     
    363365                $roleValid = Controller_Permissions::shared()->disallow_2fa_self($role);
    364366            }
    365             if ($roleValid)
     367           
     368            if (!in_array($value, array(self::STATE_2FA_OPTIONAL, self::STATE_2FA_REQUIRED))) {
     369                $value = self::STATE_2FA_DISABLED;
     370            }
     371           
     372            if ($roleValid) {
    366373                $settings[$this->get_required_2fa_role_key($role)] = ($value === self::STATE_2FA_REQUIRED ? time() : -1);
     374            }
     375           
     376            /**
     377             * Fires when 2FA availability/required on a role changes.
     378             *
     379             * @since 1.1.13
     380             *
     381             * @param string $role The name of the role.
     382             * @param string $state The state of 2FA on the role.
     383             */
     384            do_action('wordfence_ls_changed_2fa_required', $role, $value);
     385           
    367386            return true;
    368387        }
     388       
     389        //Settings that will dispatch actions
     390        switch ($key) {
     391            case self::OPTION_XMLRPC_ENABLED:
     392                $before = $this->get($key);
     393                $after = $value;
     394               
     395                if ($before != $after) {
     396                    /**
     397                     * Fires when the XML-RPC 2FA requirement changes.
     398                     *
     399                     * @since 1.1.13
     400                     *
     401                     * @param bool $before The previous value.
     402                     * @param bool $after The new value.
     403                     */
     404                    do_action('wordfence_ls_xml_rpc_2fa_toggled', $before, $after);
     405                }
     406                break;
     407            case self::OPTION_2FA_WHITELISTED:
     408                $before = $this->whitelisted_ips();
     409                $after = explode("\n", $value); //Already cleaned here so just re-split
     410                   
     411                if ($before != $after) {
     412                    /**
     413                     * Fires when the whitelist changes.
     414                     *
     415                     * @since 1.1.13
     416                     *
     417                     * @param string[] $before The previous value.
     418                     * @param string[] $after The new value.
     419                     */
     420                    do_action('wordfence_ls_updated_allowed_ips', $before, $after);
     421                }
     422                break;
     423            case self::OPTION_IP_SOURCE:
     424                $before = $this->get($key);
     425                $after = $value;
     426               
     427                if ($before != $after) {
     428                    /**
     429                     * Fires when the IP source changes.
     430                     *
     431                     * @since 1.1.13
     432                     *
     433                     * @param string $before The previous value.
     434                     * @param string $after The new value.
     435                     */
     436                    do_action('wordfence_ls_changed_ip_source', $before, $after);
     437                }
     438                break;
     439            case self::OPTION_IP_TRUSTED_PROXIES:
     440                $before = $this->trusted_proxies();
     441                $after = explode("\n", $value); //Already cleaned here so just re-split
     442               
     443                if (count($before) == count($after) && empty(array_diff($before, $after))) {
     444                    /**
     445                     * Fires when the trusted proxy list changes.
     446                     *
     447                     * @since 1.1.13
     448                     *
     449                     * @param string[] $before The previous value.
     450                     * @param string[] $after The new value.
     451                     */
     452                    do_action('wordfence_ls_updated_trusted_proxies', $before, $after);
     453                }
     454                break;
     455            case self::OPTION_REQUIRE_2FA_USER_GRACE_PERIOD:
     456                $before = $this->get($key);
     457                $after = $value;
     458               
     459                if ($before != $after) {
     460                    /**
     461                     * Fires when the grace period changes.
     462                     *
     463                     * @since 1.1.13
     464                     *
     465                     * @param int $before The previous value.
     466                     * @param int $after The new value.
     467                     */
     468                    do_action('wordfence_ls_changed_grace_period', $before, $after);
     469                }
     470                break;
     471            case self::OPTION_ALLOW_XML_RPC:
     472                $before = $this->get($key);
     473                $after = $value;
     474               
     475                if ($before != $after) {
     476                    /**
     477                     * Fires when the XML-RPC is enabled/disabled.
     478                     *
     479                     * @since 1.1.13
     480                     *
     481                     * @param bool $before The previous value.
     482                     * @param bool $after The new value.
     483                     */
     484                    do_action('wordfence_ls_xml_rpc_enabled_toggled', $before, $after);
     485                }
     486                break;
     487            case self::OPTION_ENABLE_AUTH_CAPTCHA:
     488                $before = $this->get($key);
     489                $after = $value;
     490               
     491                if ($before != $after) {
     492                    /**
     493                     * Fires when the login captcha is enabled/disabled.
     494                     *
     495                     * @since 1.1.13
     496                     *
     497                     * @param bool $before The previous value.
     498                     * @param bool $after The new value.
     499                     */
     500                    do_action('wordfence_ls_captcha_enabled_toggled', $before, $after);
     501                }
     502                break;
     503            case self::OPTION_RECAPTCHA_THRESHOLD:
     504                $before = $this->get($key);
     505                $after = $value;
     506               
     507                if ($before != $after) {
     508                    /**
     509                     * Fires when the reCAPTCHA threshold changes.
     510                     *
     511                     * @since 1.1.13
     512                     *
     513                     * @param float $before The previous value.
     514                     * @param float $after The new value.
     515                     */
     516                    do_action('wordfence_ls_captcha_threshold_changed', $before, $after);
     517                }
     518                break;
     519            case self::OPTION_ENABLE_WOOCOMMERCE_INTEGRATION:
     520                $before = $this->get($key);
     521                $after = $value;
     522               
     523                if ($before != $after) {
     524                    /**
     525                     * Fires when WooCommerce integration is enabled/disabled.
     526                     *
     527                     * @since 1.1.13
     528                     *
     529                     * @param bool $before The previous value.
     530                     * @param bool $after The new value.
     531                     */
     532                    do_action('wordfence_ls_woocommerce_enabled_toggled', $before, $after);
     533                }
     534                break;
     535            case self::OPTION_CAPTCHA_TEST_MODE:
     536                $before = $this->get($key);
     537                $after = $value;
     538               
     539                if ($before != $after) {
     540                    /**
     541                     * Fires when captcha test mode is enabled/disabled.
     542                     *
     543                     * @since 1.1.13
     544                     *
     545                     * @param bool $before The previous value.
     546                     * @param bool $after The new value.
     547                     */
     548                    do_action('wordfence_ls_captcha_test_mode_toggled', $before, $after);
     549                }
     550                break;
     551        }
     552       
    369553        return false;
    370554    }
     
    479663        }
    480664       
     665        if (is_null($value)) {
     666            return false;
     667        }
     668       
    481669        if (is_numeric($value)) {
    482670            return !!$value;
  • wordfence-login-security/trunk/classes/controller/totp.php

    r2786998 r3216078  
    3939        $table = Controller_DB::shared()->secrets;
    4040        $wpdb->query($wpdb->prepare("INSERT INTO `{$table}` (`user_id`, `secret`, `recovery`, `ctime`, `vtime`, `mode`) VALUES (%d, %s, %s, UNIX_TIMESTAMP(), %d, 'authenticator')", $user->ID, Model_Compat::hex2bin($secret), implode('', array_map(function($r) { return Model_Compat::hex2bin($r); }, $recovery)), $vtime));
     41       
     42        /**
     43         * Fires when 2FA is enabled for a user.
     44         *
     45         * @since 1.1.13
     46         *
     47         * @param \WP_User $user The user.
     48         */
     49        do_action('wordfence_ls_2fa_activated', $user);
    4150    }
    4251   
  • wordfence-login-security/trunk/classes/controller/users.php

    r3098784 r3216078  
    230230        $table = Controller_DB::shared()->secrets;
    231231        $wpdb->query($wpdb->prepare("DELETE FROM `{$table}` WHERE `user_id` = %d", $user->ID));
     232       
     233        /**
     234         * Fires when 2FA is disabled for a user.
     235         *
     236         * @since 1.1.13
     237         *
     238         * @param \WP_User $user The user.
     239         */
     240        do_action('wordfence_ls_2fa_deactivated', $user);
    232241    }
    233242
  • wordfence-login-security/trunk/classes/controller/wordfencels.php

    r3063866 r3216078  
    238238        $_runInstallCalled = true;
    239239       
    240         if (function_exists('ignore_user_abort')) {
     240        if (function_exists('ignore_user_abort') && is_callable('ignore_user_abort')) {
    241241            @ignore_user_abort(true);
    242242        }
  • wordfence-login-security/trunk/classes/model/crypto/jwt.php

    r2098090 r3216078  
    3939        $payload = @json_decode($json, true);
    4040        $expiration = false;
    41         if (isset($payload['_exp'])) {
     41        if (!is_array($payload)) {
     42            return false;
     43        }
     44        else if (isset($payload['_exp'])) {
    4245            $expiration = $payload['_exp'];
    4346           
  • wordfence-login-security/trunk/classes/model/ip.php

    r2098090 r3216078  
    1616       
    1717        if (self::has_ipv6()) {
    18             return @inet_ntop($ip);
     18            return inet_ntop($ip);
    1919        }
    2020       
     
    6969    public static function inet_pton($ip) {
    7070        if (self::has_ipv6()) {
    71             $pton = @inet_pton($ip);
     71            $pton = inet_pton($ip);
    7272            if ($pton === false) {
    7373                return false;
     
    126126     */
    127127    public static function has_ipv6() {
    128         return defined('AF_INET6');
     128        return defined('AF_INET6') && is_callable('inet_ntop') && is_callable('inet_pton');
    129129    }
    130130   
  • wordfence-login-security/trunk/classes/utility/array.php

    r2865297 r3216078  
    2626        return true;
    2727    }
    28 
     28   
     29    /**
     30     * Returns the items from $array whose keys are in $keys.
     31     *
     32     * @param array $array
     33     * @param array|string $keys
     34     * @param bool $single Return single-value as-is instead of a one-element array.
     35     * @param mixed|null $default Value to return when $single is true and nothing is found.
     36     * @return array|mixed
     37     */
     38    public static function arrayChoose($array, $keys, $single = false, $default = null) {
     39        if (!is_array($keys)) {
     40            $keys = array($keys);
     41        }
     42       
     43        $matches = array_filter($array, function($k) use ($keys) {
     44            return in_array($k, $keys);
     45        }, ARRAY_FILTER_USE_KEY);
     46        if ($single) {
     47            $key = self::arrayFirst($keys);
     48            if ($key !== null && isset($matches[$key])) {
     49                return $matches[$key];
     50            }
     51           
     52            return $default;
     53        }
     54        return $matches;
     55    }
     56   
     57    /**
     58     * Convenience function for `arrayChoose` in its single return value mode for better code readability.
     59     *
     60     * @param array $array
     61     * @param string $key
     62     * @param mixed|null $default
     63     * @return mixed
     64     */
     65    public static function arrayGet($array, $key, $default = null) {
     66        return self::arrayChoose($array, $key, true, $default);
     67    }
     68   
     69    public static function arrayFirst($array) {
     70        if (empty($array)) {
     71            return null;
     72        }
     73       
     74        $values = array_values($array);
     75        return $values[0];
     76    }
     77   
     78    public static function arrayLast($array) {
     79        if (empty($array)) {
     80            return null;
     81        }
     82       
     83        $values = array_values($array);
     84        return $values[count($values) - 1];
     85    }
    2986}
  • wordfence-login-security/trunk/languages/wordfence-login-security.pot

    r3098784 r3216078  
    1 # Copyright (C) 2024 Wordfence
     1# Copyright (C) 2025 Wordfence
    22# This file is distributed under the same license as the Wordfence Login Security plugin.
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Wordfence Login Security 1.1.12\n"
    6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wordfence-login-security-zip-V4phf6rXp\n"
     5"Project-Id-Version: Wordfence Login Security 1.1.14\n"
     6"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wordfence-login-security-zip-yKQU9cJFC\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
    88"Language-Team: LANGUAGE <[email protected]>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2024-06-06T15:13:00+00:00\n"
     12"POT-Creation-Date: 2025-01-02T16:27:17+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.7.1\n"
     
    245245msgstr ""
    246246
    247 #: classes/controller/settings.php:202
     247#: classes/controller/settings.php:203
    248248msgid "The IP/range %s is invalid."
    249249msgstr ""
    250250
    251 #: classes/controller/settings.php:208
     251#: classes/controller/settings.php:209
    252252msgid "An invalid IP source was provided."
    253253msgstr ""
    254254
    255 #: classes/controller/settings.php:214
     255#: classes/controller/settings.php:215
    256256msgid "The grace period end time must be in the future."
    257257msgstr ""
    258258
    259 #: classes/controller/settings.php:236
     259#: classes/controller/settings.php:237
    260260msgid "Unable to validate the reCAPTCHA site key. Please check the key and try again."
    261261msgstr ""
    262262
    263 #: classes/controller/settings.php:240
     263#: classes/controller/settings.php:241
    264264msgid "An error was encountered while validating the reCAPTCHA site key: %s"
    265265msgstr ""
    266266
    267 #: classes/controller/users.php:521
     267#: classes/controller/users.php:530
    268268#: classes/controller/wordfencels.php:486
    269269msgid "2FA Status"
    270270msgstr ""
    271271
    272 #: classes/controller/users.php:525
     272#: classes/controller/users.php:534
    273273msgid "Last Login"
    274274msgstr ""
    275275
    276 #: classes/controller/users.php:527
     276#: classes/controller/users.php:536
    277277msgid "Last CAPTCHA"
    278278msgstr ""
    279279
    280 #: classes/controller/users.php:537
     280#: classes/controller/users.php:546
    281281msgid "Not Allowed"
    282282msgstr ""
    283283
    284 #: classes/controller/users.php:542
     284#: classes/controller/users.php:551
    285285#: classes/controller/wordfencels.php:490
    286286msgid "Active"
    287287msgstr ""
    288288
    289 #: classes/controller/users.php:545
     289#: classes/controller/users.php:554
    290290msgid "Inactive<small class=\"wfls-sub-status\">(Grace Period)</small>"
    291291msgstr ""
    292292
    293 #: classes/controller/users.php:548
     293#: classes/controller/users.php:557
    294294msgid "Locked Out<small class=\"wfls-sub-status\">(Grace Period Disabled)</small>"
    295295msgstr ""
    296296
    297 #: classes/controller/users.php:548
     297#: classes/controller/users.php:557
    298298msgid "Locked Out<small class=\"wfls-sub-status\">(Grace Period Exceeded)</small>"
    299299msgstr ""
    300300
    301 #: classes/controller/users.php:551
     301#: classes/controller/users.php:560
    302302#: classes/controller/wordfencels.php:490
    303303msgid "Inactive"
    304304msgstr ""
    305305
    306 #: classes/controller/users.php:653
     306#: classes/controller/users.php:662
    307307msgid "Edit two-factor authentication for %s"
    308308msgstr ""
    309309
    310 #: classes/controller/users.php:653
     310#: classes/controller/users.php:662
    311311#: views/settings/options.php:9
    312312msgid "2FA"
    313313msgstr ""
    314314
    315 #: classes/controller/users.php:664
     315#: classes/controller/users.php:673
    316316#: views/settings/user-stats.php:25
    317317msgid "2FA Active"
    318318msgstr ""
    319319
    320 #: classes/controller/users.php:665
     320#: classes/controller/users.php:674
    321321#: views/settings/user-stats.php:26
    322322msgid "2FA Inactive"
  • wordfence-login-security/trunk/readme.txt

    r3118641 r3216078  
    22Contributors: wfryan, wfmattr, mmaunder, wfmatt
    33Tags: security, login security, 2fa, two factor authentication, captcha, xml-rpc, mfa, 2 factor
    4 Requires at least: 4.5
    5 Requires PHP: 5.5
    6 Tested up to: 6.6
    7 Stable tag: 1.1.12
     4Requires at least: 4.7
     5Requires PHP: 7.0
     6Tested up to: 6.7
     7Stable tag: 1.1.14
    88
    99Secure your website with Wordfence Login Security, providing two-factor authentication, login and registration CAPTCHA, and XML-RPC protection.
     
    5858
    5959== Changelog ==
     60
     61= 1.1.14 - January 2, 2025 =
     62* Improvement: General compatibility improvements and better error handling for PHP 8+
    6063
    6164= 1.1.12 - June 6, 2024 =
  • wordfence-login-security/trunk/wordfence-login-security.php

    r3098784 r3216078  
    55Author: Wordfence
    66Author URI: https://www.wordfence.com/
    7 Version: 1.1.12
     7Version: 1.1.14
    88Network: true
    9 Requires at least: 4.5
    10 Requires PHP: 5.5
     9Requires at least: 4.7
     10Requires PHP: 7.0
    1111Text Domain: wordfence-login-security
    1212Domain Path: /languages
     
    3939    define('WORDFENCE_LS_FROM_CORE', ($wfCoreActive && isset($wfCoreLoading) && $wfCoreLoading));
    4040   
    41     define('WORDFENCE_LS_VERSION', '1.1.12');
    42     define('WORDFENCE_LS_BUILD_NUMBER', '1717686780');
     41    define('WORDFENCE_LS_VERSION', '1.1.14');
     42    define('WORDFENCE_LS_BUILD_NUMBER', '1735835237');
    4343
    4444    define('WORDFENCE_LS_PLUGIN_BASENAME', plugin_basename(__FILE__));
Note: See TracChangeset for help on using the changeset viewer.