| @@ -1393,9 +1393,9 @@ | ||
| 1393 | 1393 | $count, |
| 1394 | 1394 | 'vigilante' |
| 1395 | 1395 | ) ), |
| 1396 | 1396 | absint( $count ), |
| 1397 | - '<a href="' . esc_url( admin_url( 'admin.php?page=vigilante&tab=users' ) ) . '">' . esc_html__( 'Review in Vigilant', 'vigilante' ) . '</a>' | |
| 1397 | + '<a href="' . esc_url( admin_url( 'admin.php?page=vigilante&tab=users#vigilante-section-users-pending' ) ) . '">' . esc_html__( 'Review in Vigilant', 'vigilante' ) . '</a>' | |
| 1398 | 1398 | ); |
| 1399 | 1399 | ?> |
| 1400 | 1400 | </p> |
| 1401 | 1401 | </div> |
| @@ -1427,8 +1427,14 @@ | ||
| 1427 | 1427 | * @param int $approved_by Admin user ID who approved. |
| 1428 | 1428 | * @return bool |
| 1429 | 1429 | */ |
| 1430 | 1430 | public function approve_user( $user_id, $approved_by = 0 ) { |
| 1431 | + // Same reasoning as reject_user(): approving an account that never asked | |
| 1432 | + // for approval is a no-op that reports success and writes misleading meta. | |
| 1433 | + if ( ! get_user_meta( $user_id, 'vigilante_pending_approval', true ) ) { | |
| 1434 | + return false; | |
| 1435 | + } | |
| 1436 | + | |
| 1431 | 1437 | $user = get_userdata( $user_id ); |
| 1432 | 1438 | if ( ! $user ) { |
| 1433 | 1439 | return false; |
| 1434 | 1440 | } |
| @@ -1474,8 +1480,16 @@ | ||
| 1474 | 1480 | if ( ! $user ) { |
| 1475 | 1481 | return false; |
| 1476 | 1482 | } |
| 1477 | 1483 | |
| 1484 | + // Only an account actually waiting for approval may be rejected. Without | |
| 1485 | + // this the handler deletes any user id it is given, and wp_delete_user() | |
| 1486 | + // with no reassignment takes their posts with them, skipping the dialog | |
| 1487 | + // core always shows. Deleting a member is the Users screen's job. | |
| 1488 | + if ( ! get_user_meta( $user_id, 'vigilante_pending_approval', true ) ) { | |
| 1489 | + return false; | |
| 1490 | + } | |
| 1491 | + | |
| 1478 | 1492 | // Log before deletion |
| 1479 | 1493 | if ( $this->activity_log ) { |
| 1480 | 1494 | $admin = $rejected_by ? get_userdata( $rejected_by ) : null; |
| 1481 | 1495 | $this->activity_log->log( |
| @@ -1519,9 +1533,9 @@ | ||
| 1519 | 1533 | __( '[%s] New user registration pending approval', 'vigilante' ), |
| 1520 | 1534 | $site_name |
| 1521 | 1535 | ); |
| 1522 | 1536 | |
| 1523 | - $approve_url = admin_url( 'admin.php?page=vigilante&tab=users' ); | |
| 1537 | + $approve_url = admin_url( 'admin.php?page=vigilante&tab=users#vigilante-section-users-pending' ); | |
| 1524 | 1538 | |
| 1525 | 1539 | $body = Vigilante_Email_Template::p( __( 'A new user has registered and is awaiting your approval.', 'vigilante' ) ); |
| 1526 | 1540 | $body .= Vigilante_Email_Template::data_table( array( |
| 1527 | 1541 | __( 'Username', 'vigilante' ) => $user->user_login, |
| @@ -2037,9 +2051,15 @@ | ||
| 2037 | 2051 | |
| 2038 | 2052 | // Honor both affected_roles AND the per-user exclusion list, and |
| 2039 | 2053 | // clear stale flags if the user no longer matches the rules. |
| 2040 | 2054 | if ( ! $this->is_password_expiration_applicable( $user_id ) ) { |
| 2041 | - if ( get_user_meta( $user_id, 'vigilante_must_change_password', true ) ) { | |
| 2055 | + // Only on a single site, for the same reason as in | |
| 2056 | + // force_password_change_redirect(): on a network the flag belongs to | |
| 2057 | + // the account, and this site's policy says nothing about the site | |
| 2058 | + // that set it. The 2.11.8 fix only covered that method, and this | |
| 2059 | + // notice cleared the flag anyway on the next admin page; found by | |
| 2060 | + // the cross review of 2.11.8. | |
| 2061 | + if ( ! is_multisite() && get_user_meta( $user_id, 'vigilante_must_change_password', true ) ) { | |
| 2042 | 2062 | delete_user_meta( $user_id, 'vigilante_must_change_password' ); |
| 2043 | 2063 | } |
| 2044 | 2064 | return; |
| 2045 | 2065 | } |
| @@ -2132,9 +2152,16 @@ | ||
| 2132 | 2152 | // excluded list after the flag was set. Without this check the flag |
| 2133 | 2153 | // outlives the configuration change and locks the user in a redirect |
| 2134 | 2154 | // loop into profile.php. |
| 2135 | 2155 | if ( ! $this->is_password_expiration_applicable( $user_id ) ) { |
| 2136 | - delete_user_meta( $user_id, 'vigilante_must_change_password' ); | |
| 2156 | + // On a network the flag is a user meta that every site shares, and the | |
| 2157 | + // policy just checked is only this site's: another site may have set | |
| 2158 | + // it, and clearing it here let a user skip that site's forced change | |
| 2159 | + // by visiting any other dashboard. It is only cleared on a single | |
| 2160 | + // site (2.11.8); on a network the user is just not redirected here. | |
| 2161 | + if ( ! is_multisite() ) { | |
| 2162 | + delete_user_meta( $user_id, 'vigilante_must_change_password' ); | |
| 2163 | + } | |
| 2137 | 2164 | return; |
| 2138 | 2165 | } |
| 2139 | 2166 | |
| 2140 | 2167 | wp_safe_redirect( admin_url( 'profile.php#password' ) ); |
| @@ -2679,20 +2706,22 @@ | ||
| 2679 | 2706 | wp_safe_redirect( add_query_arg( 'vigilante_message', 'invalid', wp_login_url() ) ); |
| 2680 | 2707 | exit; |
| 2681 | 2708 | } |
| 2682 | 2709 | |
| 2683 | - $stored_hash = get_user_meta( $user_id, 'vigilante_verification_token', true ); | |
| 2684 | - $expires = get_user_meta( $user_id, 'vigilante_verification_expires', true ); | |
| 2710 | + $stored_hash = (string) get_user_meta( $user_id, 'vigilante_verification_token', true ); | |
| 2711 | + $expires = (int) get_user_meta( $user_id, 'vigilante_verification_expires', true ); | |
| 2685 | 2712 | |
| 2686 | - // Check expiration | |
| 2687 | - if ( time() > $expires ) { | |
| 2688 | - wp_safe_redirect( add_query_arg( 'vigilante_message', 'expired', wp_login_url() ) ); | |
| 2713 | + // The token first. Checking the expiry before it answered "expired" for | |
| 2714 | + // any account with no verification pending and "invalid" for one waiting, | |
| 2715 | + // so a wrong link revealed which user ids were waiting (2.11.8). Only the | |
| 2716 | + // holder of the right token learns that it expired. | |
| 2717 | + if ( '' === $stored_hash || ! hash_equals( $stored_hash, wp_hash( $token ) ) ) { | |
| 2718 | + wp_safe_redirect( add_query_arg( 'vigilante_message', 'invalid', wp_login_url() ) ); | |
| 2689 | 2719 | exit; |
| 2690 | 2720 | } |
| 2691 | 2721 | |
| 2692 | - // Verify token | |
| 2693 | - if ( ! hash_equals( $stored_hash, wp_hash( $token ) ) ) { | |
| 2694 | - wp_safe_redirect( add_query_arg( 'vigilante_message', 'invalid', wp_login_url() ) ); | |
| 2722 | + if ( time() > $expires ) { | |
| 2723 | + wp_safe_redirect( add_query_arg( 'vigilante_message', 'expired', wp_login_url() ) ); | |
| 2695 | 2724 | exit; |
| 2696 | 2725 | } |
| 2697 | 2726 | |
| 2698 | 2727 | // Mark as verified |