2023-07-06 01:56:59 +03:00
< ? php
2023-07-07 00:34:11 +03:00
/**
* Usermeta which we use:
*
* um_user_blocked__metadata
* um_user_blocked
* um_user_blocked__timestamp
*
* um_secure_has_reset_password
* um_secure_has_reset_password__timestamp
*/
namespace um\admin ;
use WP_Session_Tokens ;
2023-07-06 01:56:59 +03:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ;
}
2023-07-07 00:34:11 +03:00
if ( ! class_exists ( 'um\admin\Secure' ) ) {
2023-07-06 01:56:59 +03:00
/**
* Class Secure
*
2023-07-07 00:34:11 +03:00
* @package um\admin
2023-07-06 01:56:59 +03:00
*
* @since 2.6.8
*/
class Secure {
/**
* Used for flushing user metas.
*
* @var bool
*/
private $need_flush_meta = false ;
/**
* Secure constructor.
*
* @since 2.6.8
*/
public function __construct () {
add_action ( 'admin_init' , array ( $this , 'admin_init' ) );
add_filter ( 'um_settings_structure' , array ( $this , 'add_settings' ) );
2023-07-07 01:46:11 +03:00
add_filter ( 'manage_users_custom_column' , array ( $this , 'add_restore_account' ), 9999 , 3 );
2023-07-07 17:28:06 +08:00
add_filter ( 'pre_get_users' , array ( $this , 'filter_users_by_date_registered' ) );
2023-07-06 01:56:59 +03:00
add_action ( 'um_settings_before_save' , array ( $this , 'check_secure_changes' ) );
add_action ( 'um_settings_save' , array ( $this , 'on_settings_save' ) );
2023-07-07 00:34:11 +03:00
add_action ( 'wp_ajax_um_secure_scan_affected_users' , array ( $this , 'ajax_scanner' ) );
}
2023-07-07 17:28:06 +08:00
/**
* Filter users by Register Date
*
* @since 2.6.8
* @param object $query WP query `pre_get_users`
*/
public function filter_users_by_date_registered ( $query ) {
global $pagenow ;
2023-08-11 11:36:53 +03:00
if ( 'users.php' === $pagenow && is_admin () ) {
2023-07-07 17:28:06 +08:00
// phpcs:disable WordPress.Security.NonceVerification
$date_from = isset ( $_GET [ 'um_secure_date_from' ] ) ? $_GET [ 'um_secure_date_from' ] : null ;
$date_to = isset ( $_GET [ 'um_secure_date_to' ] ) ? $_GET [ 'um_secure_date_to' ] : null ;
// phpcs:enable WordPress.Security.NonceVerification
2023-08-11 11:36:53 +03:00
if ( $date_from ) {
2023-10-27 13:38:49 +08:00
2023-08-11 11:36:53 +03:00
$date_query_attr = array (
2023-11-29 19:18:38 +02:00
'after' => gmdate ( get_option ( 'date_format' , 'F j, Y' ), strtotime ( '-1 day' , $date_from ) ),
'before' => gmdate ( get_option ( 'date_format' , 'F j, Y' ), strtotime ( '+1 day' , $date_from ) ),
2023-07-07 17:28:06 +08:00
);
2023-10-27 13:38:49 +08:00
2023-08-11 11:36:53 +03:00
if ( $date_to ) {
2023-11-29 19:18:38 +02:00
$date_query_attr [ 'before' ] = gmdate ( get_option ( 'date_format' , 'F j, Y' ), strtotime ( '+1 day' , $date_to ) );
2023-08-11 11:36:53 +03:00
}
2023-10-27 13:38:49 +08:00
2023-08-11 11:36:53 +03:00
$query -> set ( 'date_query' , $date_query_attr );
2023-07-07 17:28:06 +08:00
}
}
return $query ;
}
2023-07-06 01:56:59 +03:00
/**
* Handle secure actions.
*
* @since 2.6.8
*/
public function admin_init () {
2023-07-07 14:48:50 +08:00
global $wpdb ;
2023-07-06 01:56:59 +03:00
// Dismiss admin notice after the first visit to Secure settings page.
if ( isset ( $_REQUEST [ 'page' ] ) && isset ( $_REQUEST [ 'tab' ] ) &&
2023-07-07 13:48:16 +08:00
'um_options' === sanitize_key ( $_REQUEST [ 'page' ] ) && 'secure' === sanitize_key ( $_REQUEST [ 'tab' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
2023-07-06 01:56:59 +03:00
UM () -> admin () -> notices () -> dismiss ( 'secure_settings' );
}
if ( isset ( $_REQUEST [ 'um_secure_expire_all_sessions' ] ) && ! wp_doing_ajax () ) {
if ( ! wp_verify_nonce ( $_REQUEST [ '_wpnonce' ], 'um-secure-expire-session-nonce' ) || ! current_user_can ( 'manage_options' ) ) {
// This nonce is not valid or current logged-in user has no administrative rights.
wp_die ( esc_html__ ( 'Security check' , 'ultimate-member' ) );
}
2023-07-07 14:48:50 +08:00
/**
* Destroy all user sessions except the current logged-in user.
*/
2023-08-11 11:36:53 +03:00
$wpdb -> query (
$wpdb -> prepare (
" DELETE
FROM { $wpdb -> usermeta }
WHERE meta_key='session_tokens' AND
user_id != %d " ,
get_current_user_id ()
)
);
2023-07-07 14:48:50 +08:00
if ( UM () -> options () -> get ( 'display_login_form_notice' ) ) {
global $wpdb ;
$wpdb -> query (
$wpdb -> prepare (
2023-08-11 11:36:53 +03:00
" DELETE
FROM { $wpdb -> usermeta }
WHERE user_id != %d AND
( meta_key = 'um_secure_has_reset_password' OR meta_key = 'um_secure_has_reset_password__timestamp' ) " ,
2023-07-07 14:48:50 +08:00
get_current_user_id ()
)
);
2023-07-06 01:56:59 +03:00
}
wp_safe_redirect ( add_query_arg ( 'update' , 'um_secure_expire_sessions' , wp_get_referer () ) );
exit ;
}
if ( isset ( $_REQUEST [ 'um_secure_restore_account' ], $_REQUEST [ 'user_id' ] ) && ! wp_doing_ajax () ) {
$user_id = absint ( $_REQUEST [ 'user_id' ] );
if ( ! wp_verify_nonce ( $_REQUEST [ '_wpnonce' ], 'um-security-restore-account-nonce-' . $user_id ) || ! current_user_can ( 'manage_options' ) ) {
// This nonce is not valid or current logged-in user has no administrative rights.
wp_die ( esc_html__ ( 'Security check' , 'ultimate-member' ) );
}
$user = get_userdata ( $user_id );
if ( ! $user ) {
wp_die ( esc_html__ ( 'Invalid user.' , 'ultimate-member' ) );
}
2023-07-07 01:46:11 +03:00
um_fetch_user ( $user_id );
2023-07-06 01:56:59 +03:00
$metadata = get_user_meta ( $user_id , 'um_user_blocked__metadata' , true );
2023-07-07 00:45:12 +03:00
$user -> update_user_level_from_caps ();
2023-07-06 01:56:59 +03:00
// Restore Roles.
if ( isset ( $metadata [ 'roles' ] ) ) {
foreach ( $metadata [ 'roles' ] as $role ) {
$user -> add_role ( $role );
}
}
// Restore Account Status.
if ( isset ( $metadata [ 'account_status' ] ) ) {
UM () -> user () -> set_status ( $metadata [ 'account_status' ] );
}
// Delete blocked meta.
delete_user_meta ( $user_id , 'um_user_blocked__metadata' );
delete_user_meta ( $user_id , 'um_user_blocked' );
2023-07-07 00:34:11 +03:00
delete_user_meta ( $user_id , 'um_user_blocked__timestamp' );
2023-07-06 01:56:59 +03:00
// Don't need to reset a password.
2023-07-07 00:45:12 +03:00
if ( UM () -> options () -> get ( 'display_login_form_notice' ) ) {
update_user_meta ( $user_id , 'um_secure_has_reset_password' , true );
update_user_meta ( $user_id , 'um_secure_has_reset_password__timestamp' , current_time ( 'mysql' ) );
}
2023-07-06 01:56:59 +03:00
// Clear Cache.
UM () -> user () -> remove_cache ( $user_id );
2023-07-07 01:46:11 +03:00
um_reset_user ();
2023-07-06 01:56:59 +03:00
wp_safe_redirect ( add_query_arg ( 'update' , 'um_secure_restore' , wp_get_referer () ) );
exit ;
}
}
/**
* Register Secure Settings
*
* @since 2.6.8
*
* @param array $settings
* @return array
*/
public function add_settings ( $settings ) {
$nonce = wp_create_nonce ( 'um-secure-expire-session-nonce' );
$count_users = count_users ();
2023-07-07 00:34:11 +03:00
$banned_capabilities = array ();
$banned_admin_capabilities = UM () -> common () -> secure () -> get_banned_capabilities_list ();
2023-07-06 01:56:59 +03:00
foreach ( $banned_admin_capabilities as $cap ) {
$banned_capabilities [ $cap ] = $cap ;
}
2023-07-07 00:34:11 +03:00
$disabled_capabilities = UM () -> options () -> get_default ( 'banned_capabilities' );
$disabled_capabilities_text = '<strong>' . implode ( '</strong>, <strong>' , $disabled_capabilities ) . '</strong>' ;
$scanner_content = '<button class="button um-secure-scan-content">' . esc_html__ ( 'Scan Now' , 'ultimate-member' ) . '</button>' ;
$scanner_content .= '<span class="um-secure-scan-results">' ;
$scanner_content .= esc_html__ ( 'Last scan:' , 'ultimate-member' ) . ' ' ;
$scan_status = get_option ( 'um_secure_scan_status' );
$last_scanned_time = get_option ( 'um_secure_last_time_scanned' );
if ( ! empty ( $last_scanned_time ) ) {
2023-11-29 19:18:38 +02:00
$scanner_content .= human_time_diff ( strtotime ( $last_scanned_time ) ) . ' ' . esc_html__ ( 'ago' , 'ultimate-member' );
2023-07-07 00:34:11 +03:00
if ( 'started' === $scan_status ) {
$scanner_content .= ' - ' . esc_html__ ( 'Not Completed.' , 'ultimate-member' );
}
} else {
$scanner_content .= esc_html__ ( 'Not Scanned yet.' , 'ultimate-member' );
}
$scanner_content .= '</span>' ;
2023-07-06 01:56:59 +03:00
$secure_fields = array (
2023-07-07 00:34:11 +03:00
array (
'id' => 'banned_capabilities' ,
'type' => 'multi_checkbox' ,
'multi' => true ,
2023-07-07 15:06:08 +03:00
'assoc' => true ,
2023-07-07 13:48:16 +08:00
'checkbox_key' => true ,
2023-07-07 00:34:11 +03:00
'columns' => 2 ,
'options_disabled' => $disabled_capabilities ,
'options' => $banned_capabilities ,
'label' => __ ( 'Banned Administrative Capabilities' , 'ultimate-member' ),
// translators: %s are disabled default capabilities that are enabled by default.
'description' => sprintf ( __ ( 'All the above are default Administrator & Super Admin capabilities. When someone tries to inject capabilities to the Account, Profile & Register forms submission, it will be flagged with this option. The %s capabilities are locked to ensure no users will be created with these capabilities.' , 'ultimate-member' ), $disabled_capabilities_text ),
),
array (
'id' => 'secure_scan_affected_users' ,
'type' => 'info_text' ,
'label' => __ ( 'Scanner' , 'ultimate-member' ),
'value' => $scanner_content ,
'description' => __ ( 'Scan your site to check for vulnerabilities prior to Ultimate Member version 2.6.7 and get recommendations to secure your site.' , 'ultimate-member' ),
),
2023-07-06 01:56:59 +03:00
array (
'id' => 'lock_register_forms' ,
'type' => 'checkbox' ,
'label' => __ ( 'Lock All Register Forms' , 'ultimate-member' ),
'description' => __ ( 'This prevents all users from registering with Ultimate Member on your site.' , 'ultimate-member' ),
),
array (
'id' => 'display_login_form_notice' ,
'type' => 'checkbox' ,
'label' => __ ( 'Display Login form notice to reset passwords' , 'ultimate-member' ),
'description' => __ ( 'Enforces users to reset their passwords( one-time ) and prevent from entering old password.' , 'ultimate-member' ),
),
);
$count_users_exclude_me = $count_users [ 'total_users' ] - 1 ;
if ( $count_users_exclude_me > 0 ) {
$secure_fields [] = array (
'id' => 'force_reset_passwords' ,
'type' => 'info_text' ,
'label' => __ ( 'Expire All Users Sessions' , 'ultimate-member' ),
// translators: %d is the users count.
'value' => '<a class="button um_secure_force_reset_passwords" href="' . admin_url ( '?um_secure_expire_all_sessions=1&_wpnonce=' . esc_attr ( $nonce ) ) . '" onclick=\'return confirm("' . esc_js ( __ ( 'Are you sure that you want to make all users sessions expired?' , 'ultimate-member' ) ) . '");\'>' . esc_html ( sprintf ( __ ( 'Logout Users (%d)' , 'ultimate-member' ), $count_users_exclude_me ) ) . '</a>' ,
'description' => __ ( 'This will log out all users on your site and forces them to reset passwords <br/>when <strong>"Display Login form notice to reset passwords" is enabled/checked.</strong>' , 'ultimate-member' ),
);
}
$secure_fields = array_merge (
$secure_fields ,
array (
array (
2023-07-07 00:34:11 +03:00
'id' => 'secure_ban_admins_accounts' ,
'type' => 'checkbox' ,
'label' => __ ( 'Enable ban for administrative capabilities' , 'ultimate-member' ),
'description' => __ ( ' When someone tries to inject capabilities to the Account, Profile & Register forms submission, it will be banned.' , 'ultimate-member' ),
2023-07-06 01:56:59 +03:00
),
array (
'id' => 'secure_notify_admins_banned_accounts' ,
'type' => 'checkbox' ,
'label' => __ ( 'Notify Administrators' , 'ultimate-member' ),
2023-07-07 00:45:12 +03:00
'description' => __ ( 'When enabled, All administrators will be notified when someone has suspicious activities in the Account, Profile & Register forms.' , 'ultimate-member' ),
2023-07-07 00:34:11 +03:00
'conditional' => array ( 'secure_ban_admins_accounts' , '=' , 1 ),
2023-07-06 01:56:59 +03:00
),
array (
'id' => 'secure_notify_admins_banned_accounts__interval' ,
'type' => 'select' ,
'options' => array (
'instant' => __ ( 'Send Immediately' , 'ultimate-member' ),
'hourly' => __ ( 'Hourly' , 'ultimate-member' ),
'daily' => __ ( 'Daily' , 'ultimate-member' ),
),
'label' => __ ( 'Notification Schedule' , 'ultimate-member' ),
'conditional' => array ( 'secure_notify_admins_banned_accounts' , '=' , 1 ),
),
2023-07-14 12:36:07 +03:00
array (
'id' => 'secure_allowed_redirect_hosts' ,
'type' => 'textarea' ,
2023-07-18 12:06:17 +03:00
'label' => __ ( 'Allowed hosts for safe redirect (one host per line)' , 'ultimate-member' ),
'description' => __ ( 'Extend allowed hosts for frontend pages redirects' , 'ultimate-member' ),
2023-07-14 12:36:07 +03:00
),
2023-07-06 01:56:59 +03:00
)
);
$settings [ 'secure' ] = array (
'title' => __ ( 'Secure' , 'ultimate-member' ),
'fields' => $secure_fields ,
);
return $settings ;
}
/**
* Append blocked status to the `account_status` column rows.
*
* @param string $val Default column row value.
* @param string $column_name Current column name.
* @param int $user_id User ID in loop.
*
* @since 2.6.8
*
* @return string
*/
public function add_restore_account ( $val , $column_name , $user_id ) {
if ( 'account_status' === $column_name ) {
um_fetch_user ( $user_id );
$is_blocked = um_user ( 'um_user_blocked' );
$account_status = um_user ( 'account_status' );
if ( ! empty ( $is_blocked ) && in_array ( $account_status , array ( 'rejected' , 'inactive' ), true ) ) {
2023-07-07 00:34:11 +03:00
$datetime = um_user ( 'um_user_blocked__timestamp' );
2023-07-06 01:56:59 +03:00
$val .= '<div><small>' . esc_html__ ( 'Blocked Due to Suspicious Activity' , 'ultimate-member' ) . '</small></div>' ;
$nonce = wp_create_nonce ( 'um-security-restore-account-nonce-' . $user_id );
$restore_account_url = admin_url ( 'users.php?user_id=' . $user_id . '&um_secure_restore_account=1&_wpnonce=' . $nonce );
$action = ' · <a href=" ' . esc_attr ( $restore_account_url ) . ' " onclick=\'return confirm("' . esc_js ( __ ( 'Are you sure that you want to restore this account after getting flagged for suspicious activity?' , 'ultimate-member' ) ) . '");\'><small>' . esc_html__ ( 'Restore Account' , 'ultimate-member' ) . '</small></a>' ;
if ( ! empty ( $datetime ) ) {
2023-11-29 19:18:38 +02:00
$val .= '<div><small>' . human_time_diff ( strtotime ( $datetime ) ) . ' ' . __ ( 'ago' , 'ultimate-member' ) . '</small>' . $action . '</div>' ;
2023-07-06 01:56:59 +03:00
}
}
um_reset_user ();
}
return $val ;
}
/**
*
*/
public function check_secure_changes () {
2023-07-07 13:48:16 +08:00
if ( isset ( $_POST [ 'um_options' ][ 'display_login_form_notice' ] ) ) { //phpcs:ignore WordPress.Security.NonceVerification
2023-07-06 01:56:59 +03:00
$current_option_value = UM () -> options () -> get ( 'display_login_form_notice' );
if ( empty ( $current_option_value ) ) {
return ;
}
2023-07-07 13:48:16 +08:00
if ( empty ( $_POST [ 'um_options' ][ 'display_login_form_notice' ] ) ) { //phpcs:ignore WordPress.Security.NonceVerification
2023-07-06 01:56:59 +03:00
$this -> need_flush_meta = true ;
}
}
}
/**
*
*/
public function on_settings_save () {
2023-07-07 13:48:16 +08:00
if ( isset ( $_POST [ 'um_options' ][ 'display_login_form_notice' ] ) && ! empty ( $this -> need_flush_meta ) ) { //phpcs:ignore WordPress.Security.NonceVerification
2023-07-06 01:56:59 +03:00
global $wpdb ;
$wpdb -> query (
" DELETE FROM { $wpdb -> usermeta } WHERE meta_key = 'um_secure_has_reset_password' OR meta_key = 'um_secure_has_reset_password__timestamp' "
);
}
2023-07-07 15:44:28 +08:00
if ( isset ( $_POST [ 'um_options' ][ 'secure_notify_admins_banned_accounts' ] ) ) { //phpcs:ignore WordPress.Security.NonceVerification
if ( ! empty ( $_POST [ 'um_options' ][ 'secure_notify_admins_banned_accounts' ] ) ) { //phpcs:ignore WordPress.Security.NonceVerification
UM () -> options () -> update ( 'suspicious-activity_on' , 1 );
} else {
UM () -> options () -> update ( 'suspicious-activity_on' , 0 );
}
}
2023-07-06 01:56:59 +03:00
}
}
}