| @@ -1249,22 +1249,27 @@ | ||
| 1249 | 1249 | * @param string $password Password. |
| 1250 | 1250 | * @return WP_User|WP_Error|null |
| 1251 | 1251 | */ |
| 1252 | 1252 | public function check_force_reset_on_login( $user, $username, $password ) { |
| 1253 | - // Resolve the target user. The flag must be evaluated whether the | |
| 1254 | - // credentials matched (WP_User) or not (WP_Error). | |
| 1255 | - if ( $user instanceof WP_User ) { | |
| 1256 | - $login_user = $user; | |
| 1257 | - } else { | |
| 1258 | - $login_user = get_user_by( 'login', $username ); | |
| 1259 | - if ( ! $login_user ) { | |
| 1260 | - $login_user = get_user_by( 'email', $username ); | |
| 1261 | - } | |
| 1253 | + /* | |
| 1254 | + * Only a login that would otherwise have succeeded is turned into this | |
| 1255 | + * rejection. Wrong credentials are left exactly as WordPress reported | |
| 1256 | + * them, and they are counted like any other failed login. | |
| 1257 | + * | |
| 1258 | + * Until 2.11.12 this ran for a WP_Error too, resolving the account from | |
| 1259 | + * the username, and replaced an incorrect_password with the rejection | |
| 1260 | + * below. A rejection of Vigilant's own is not counted towards the brute | |
| 1261 | + * force lockout, so any account with a pending forced reset could be | |
| 1262 | + * guessed at without limit: measured on 17 Sep 2026 against 2.11.11 and | |
| 1263 | + * against the first build of 2.11.12, six wrong passwords in a row, none | |
| 1264 | + * of them counted and no lockout at the end. The message this function | |
| 1265 | + * exists to show belongs to whoever typed the right password. | |
| 1266 | + */ | |
| 1267 | + if ( ! ( $user instanceof WP_User ) ) { | |
| 1268 | + return $user; | |
| 1262 | 1269 | } |
| 1263 | 1270 | |
| 1264 | - if ( ! $login_user ) { | |
| 1265 | - return $user; | |
| 1266 | - } | |
| 1271 | + $login_user = $user; | |
| 1267 | 1272 | |
| 1268 | 1273 | // Check if this user has a pending forced reset. |
| 1269 | 1274 | $force_reset = get_user_meta( $login_user->ID, 'vigilante_force_reset_pending', true ); |
| 1270 | 1275 | if ( ! $force_reset ) { |
| @@ -1270,17 +1275,11 @@ | ||
| 1270 | 1275 | if ( ! $force_reset ) { |
| 1271 | 1276 | return $user; |
| 1272 | 1277 | } |
| 1273 | 1278 | |
| 1274 | - // If credentials were wrong with an error other than incorrect_password | |
| 1275 | - // (e.g. a Vigilant lockout, pending approval), don't shadow it. | |
| 1276 | - if ( is_wp_error( $user ) && ! in_array( 'incorrect_password', $user->get_error_codes(), true ) ) { | |
| 1277 | - return $user; | |
| 1278 | - } | |
| 1279 | + // Not counted towards the brute force lockout: the rejection is | |
| 1280 | + // recognised by its error code (Vigilante_Login_Security::CONTROLLED_REJECTIONS). | |
| 1279 | 1281 | |
| 1280 | - // Skip brute force counter for this controlled rejection. | |
| 1281 | - add_filter( 'vigilante_skip_failed_login_count', '__return_true' ); | |
| 1282 | - | |
| 1283 | 1282 | // Surface the controlled rejection in the activity log so the admin |
| 1284 | 1283 | // can tell apart "user fails login because they typed wrong password" |
| 1285 | 1284 | // from "user fails login because we are forcing a reset". |
| 1286 | 1285 | if ( $this->activity_log ) { |
| @@ -1390,11 +1389,8 @@ | ||
| 1390 | 1389 | return $user; |
| 1391 | 1390 | } |
| 1392 | 1391 | |
| 1393 | 1392 | if ( self::is_pending_anywhere( $user->ID ) ) { |
| 1394 | - // Mark this as a controlled rejection (not a brute force attempt) | |
| 1395 | - add_filter( 'vigilante_skip_failed_login_count', '__return_true' ); | |
| 1396 | - | |
| 1397 | 1393 | return new WP_Error( |
| 1398 | 1394 | 'pending_approval', |
| 1399 | 1395 | __( '<strong>Account pending:</strong> Your account is awaiting administrator approval. You will receive an email once approved.', 'vigilante' ) |
| 1400 | 1396 | ); |
| @@ -2142,11 +2138,8 @@ | ||
| 2142 | 2138 | array( 'user_id' => $user->ID, 'current_sessions' => $session_count, 'limit' => $max_sessions ), |
| 2143 | 2139 | 'warning' |
| 2144 | 2140 | ); |
| 2145 | 2141 | } |
| 2146 | - | |
| 2147 | - // Mark this as a controlled rejection (not a brute force attempt) | |
| 2148 | - add_filter( 'vigilante_skip_failed_login_count', '__return_true' ); | |
| 2149 | 2142 | |
| 2150 | 2143 | return new WP_Error( |
| 2151 | 2144 | 'session_limit_exceeded', |
| 2152 | 2145 | sprintf( |