verify_2fa_user_access(); $user = wp_get_current_user(); $site_name = wp_strip_all_tags( get_bloginfo( 'name' ) ); if ( empty( $site_name ) ) { $site_name = 'WordPress'; } $secret = AIO_TOTP::generate_secret(); $otpauth_uri = AIO_TOTP::get_otpauth_uri( $site_name, $user->user_login, $secret ); // Store pending secret server-side (encrypted) for 15 minutes — never trust secret from POST on verify set_transient( 'aio_2fa_pending_' . $user->ID, AIO_Crypto::encrypt( $secret ), 15 * MINUTE_IN_SECONDS ); wp_send_json_success( [ 'secret' => $secret, 'otpauth_uri' => $otpauth_uri, ] ); } public function aio_verify_2fa_ajax() { $this->verify_2fa_user_access(); $user_id = get_current_user_id(); $code = isset( $_POST['code'] ) ? sanitize_text_field( wp_unslash( $_POST['code'] ) ) : ''; $encrypted_tmp = get_transient( 'aio_2fa_pending_' . $user_id ); $secret = ! empty( $encrypted_tmp ) ? AIO_Crypto::decrypt( $encrypted_tmp ) : ''; if ( empty( $code ) || empty( $secret ) ) { wp_send_json_error( __( '2FA setup session expired or missing code. Please click Setup 2FA again.', 'aio-tools' ) ); } $matched_slice = null; $is_valid = AIO_TOTP::verify_code( $secret, $code, 1, $matched_slice ); if ( $is_valid ) { $backup = AIO_TOTP::generate_backup_codes( 8 ); update_user_meta( $user_id, '_aio_2fa_secret', AIO_Crypto::encrypt( $secret ) ); update_user_meta( $user_id, '_aio_2fa_enabled', 1 ); update_user_meta( $user_id, '_aio_2fa_last_slice', (int) $matched_slice ); update_user_meta( $user_id, '_aio_2fa_backup_codes', $backup['hashes'] ); delete_transient( 'aio_2fa_pending_' . $user_id ); wp_send_json_success( [ 'message' => __( '2FA successfully activated! Please save your recovery codes below.', 'aio-tools' ), 'backup_codes' => $backup['plain'], ] ); } else { wp_send_json_error( __( 'Invalid 6-digit code! Please check your authenticator app and try again.', 'aio-tools' ) ); } } public function aio_regenerate_2fa_backup_ajax() { $this->verify_2fa_user_access(); $user_id = get_current_user_id(); if ( ! get_user_meta( $user_id, '_aio_2fa_enabled', true ) ) { wp_send_json_error( __( '2FA is not enabled on your account.', 'aio-tools' ) ); } $backup = AIO_TOTP::generate_backup_codes( 8 ); update_user_meta( $user_id, '_aio_2fa_backup_codes', $backup['hashes'] ); wp_send_json_success( [ 'message' => __( 'New recovery codes generated! Previous recovery codes have been invalidated.', 'aio-tools' ), 'backup_codes' => $backup['plain'], ] ); } public function aio_disable_2fa_ajax() { $this->verify_2fa_user_access(); $target_user_id = get_current_user_id(); if ( ! empty( $_POST['target_user_id'] ) && current_user_can( 'manage_options' ) ) { $target_user_id = absint( $_POST['target_user_id'] ); } delete_user_meta( $target_user_id, '_aio_2fa_enabled' ); delete_user_meta( $target_user_id, '_aio_2fa_secret' ); delete_user_meta( $target_user_id, '_aio_2fa_backup_codes' ); delete_user_meta( $target_user_id, '_aio_2fa_last_slice' ); delete_transient( 'aio_2fa_pending_' . $target_user_id ); wp_send_json_success( __( 'Successfully disabled!', 'aio-tools' ) ); } public function aio_unblock_ip_ajax() { check_ajax_referer( 'aio-settings-nonce', 'security' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( __( 'Unauthorized', 'aio-tools' ) ); } $ip = isset( $_POST['ip'] ) ? sanitize_text_field( wp_unslash( $_POST['ip'] ) ) : ''; if ( empty( $ip ) ) { wp_send_json_error( __( 'Invalid IP', 'aio-tools' ) ); } global $wpdb; $lockouts_table = $wpdb->prefix . 'aio_lockouts'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->delete( $lockouts_table, [ 'ip_address' => $ip ], [ '%s' ] ); delete_transient( 'aio_lockout_' . md5( $ip ) ); delete_transient( 'aio_login_attempts_' . md5( $ip ) ); wp_send_json_success( __( 'IP has been unblocked successfully!', 'aio-tools' ) ); } public function aio_block_ip_ajax() { check_ajax_referer( 'aio-settings-nonce', 'security' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( __( 'Unauthorized', 'aio-tools' ) ); } $ip = isset( $_POST['ip'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['ip'] ) ) ) : ''; $duration = isset( $_POST['duration'] ) ? sanitize_text_field( wp_unslash( $_POST['duration'] ) ) : 'permanent'; $reason = isset( $_POST['reason'] ) ? sanitize_text_field( wp_unslash( $_POST['reason'] ) ) : __( 'Manual Admin Block', 'aio-tools' ); if ( empty( $ip ) || false === filter_var( $ip, FILTER_VALIDATE_IP ) ) { wp_send_json_error( __( 'Please enter a valid IPv4 or IPv6 address.', 'aio-tools' ) ); } if ( function_exists( 'aio_get_client_ip' ) && $ip === aio_get_client_ip() ) { wp_send_json_error( __( 'You cannot block your own current IP address.', 'aio-tools' ) ); } $expires_at = '2099-12-31 23:59:59'; if ( is_numeric( $duration ) && (int) $duration > 0 ) { $expires_at = wp_date( 'Y-m-d H:i:s', time() + ( (int) $duration * MINUTE_IN_SECONDS ) ); } global $wpdb; $lockouts_table = $wpdb->prefix . 'aio_lockouts'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->delete( $lockouts_table, [ 'ip_address' => $ip ], [ '%s' ] ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $wpdb->insert( $lockouts_table, [ 'ip_address' => substr( $ip, 0, 45 ), 'reason' => substr( $reason ?: 'Manual Admin Block', 0, 255 ), 'blocked_at' => current_time( 'mysql' ), 'expires_at' => $expires_at, ], [ '%s', '%s', '%s', '%s' ] ); wp_send_json_success( [ 'message' => __( 'IP address blocked successfully.', 'aio-tools' ), 'ip_address' => $ip, 'reason' => $reason ?: 'Manual Admin Block', 'blocked_at' => current_time( 'mysql' ), 'expires_at' => $expires_at, ] ); } public function aio_unlink_social_ajax() { $nonce = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : ''; if ( ! wp_verify_nonce( $nonce, 'aio-profile-security-nonce' ) && ! wp_verify_nonce( $nonce, 'aio-settings-nonce' ) ) { wp_send_json_error( __( 'Security check failed.', 'aio-tools' ) ); } if ( ! is_user_logged_in() ) { wp_send_json_error( __( 'Unauthorized', 'aio-tools' ) ); } $provider = isset( $_POST['provider'] ) ? sanitize_key( wp_unslash( $_POST['provider'] ) ) : ''; if ( ! in_array( $provider, [ 'google', 'facebook' ], true ) ) { wp_send_json_error( __( 'Invalid social provider.', 'aio-tools' ) ); } delete_user_meta( get_current_user_id(), 'aio_social_' . $provider . '_id' ); wp_send_json_success( __( 'Social account unlinked successfully.', 'aio-tools' ) ); } /** * Render 2FA setup & Social Account unlinking on WordPress User Profile (profile.php). */ public function render_user_profile_security_section( $user ) { $can_use_2fa = aio_is_module_active( 'opt-module-security' ) && ( user_can( $user, 'manage_options' ) || user_can( $user, 'edit_posts' ) || user_can( $user, 'manage_woocommerce' ) ); $social_active = aio_is_module_active( 'opt-module-social-login' ); $google_id = get_user_meta( $user->ID, 'aio_social_google_id', true ); $facebook_id = get_user_meta( $user->ID, 'aio_social_facebook_id', true ); if ( ! $can_use_2fa && ! $social_active && empty( $google_id ) && empty( $facebook_id ) ) { return; } $is_2fa_enabled = (bool) get_user_meta( $user->ID, '_aio_2fa_enabled', true ); $profile_nonce = wp_create_nonce( 'aio-profile-security-nonce' ); ?>

ID, '_aio_2fa_enabled', true ); if ( ! $is_2fa_enabled ) { return; } $profile_nonce = wp_create_nonce( 'aio-profile-security-nonce' ); ?>