Your IP : 216.73.216.215


Current Path : /home/flapst5/ekmtoronto.com/wp-content/plugins/wp-defender/src/controller/
Upload File :
Current File : /home/flapst5/ekmtoronto.com/wp-content/plugins/wp-defender/src/controller/class-setup-wizard.php

<?php
/**
 * Handles setup wizard.
 *
 * @package WP_Defender\Controller
 */

namespace WP_Defender\Controller;

use WP_Defender\Event;
use Calotes\Component\Request;
use Calotes\Component\Response;
use WP_Defender\Component\Feature_Modal;
use WP_Defender\Controller\Data_Tracking;
use WP_Defender\Controller\Security_Tweaks;
use WP_Defender\Component\Config\Config_Hub_Helper;
use WP_Defender\Component\Security_Tweaks\Security_Key;
use WP_Defender\Component\Audit;
use WP_Defender\Model\Setting\Audit_Logging as Model_Audit_Logging;

/**
 * Handles setup wizard.
 */
class Setup_Wizard extends Event {
	/**
	 * Legacy site option key for skipped setup wizard bubble state.
	 *
	 * @var string
	 */
	public const RESUME_NOTICE_OPTION = 'wd_setup_wizard_resume_notice';

	/**
	 * The slug identifier for this controller.
	 *
	 * @var string
	 */
	public $slug = 'wdf-setup-wizard';

	/**
	 * The old key for the remind later in Onboarding. This is from V5.x. We can delete it in the future versions.
	 *
	 * @var string
	 */
	public const REMINDER_KEY = 'wp_defender_onboard_antibot_reminder';

	/**
	 * Initializes the model and service, registers routes, and sets up scheduled events if the model is active.
	 */
	public function __construct() {
		$this->register_routes();
	}

	/**
	 * Provides data for the frontend.
	 *
	 * @return array An array of data for the frontend.
	 */
	public function data_frontend(): array {
		return array_merge(
			array(
				'custom_nonce'   => wp_create_nonce( 'wpdef_setup_wizard' ),
				// Saved wizard selections, so the wizard can resume from server state after a refresh.
				'onboardingData' => get_site_option( 'wd_onboarding_data', array() ),
			),
			$this->dump_routes_and_nonces()
		);
	}

	/**
	 * Deletes any legacy resume setup wizard bubble state.
	 *
	 * @return void
	 */
	private static function clear_resume_notice_option(): void {
		delete_site_option( self::RESUME_NOTICE_OPTION );
	}

	/**
	 * Persist a single wizard step's selection to the database.
	 *
	 * Each step is merged into the canonical `wd_onboarding_data` site option so the
	 * wizard can resume from server state after a refresh or on another device. The
	 * actual module side effects are still applied atomically in finish_setup_wizard().
	 *
	 * @param  Request $request  The request object containing the step data.
	 *
	 * @return Response
	 * @defender_route
	 */
	public function save_step( Request $request ): Response {
		if ( ! $this->check_permission() ) {
			return new Response(
				false,
				array(
					'message' => esc_html__( 'Invalid', 'wpdef' ),
				)
			);
		}

		$payload = $request->get_data();
		$step    = isset( $payload['step'] ) ? sanitize_text_field( $payload['step'] ) : '';
		$data    = isset( $payload['data'] ) && is_array( $payload['data'] ) ? $payload['data'] : array();

		$allowed_steps = array( 'local-firewall', 'hardening', 'audit-logging' );
		if ( ! in_array( $step, $allowed_steps, true ) ) {
			return new Response(
				false,
				array(
					'message' => esc_html__( 'Invalid step.', 'wpdef' ),
				)
			);
		}

		$saved = get_site_option( 'wd_onboarding_data', array() );
		if ( ! is_array( $saved ) ) {
			$saved = array();
		}

		switch ( $step ) {
			case 'local-firewall':
				$saved['local_firewall'] = isset( $data['local_firewall'] );
				break;
			case 'hardening':
				$hardening          = isset( $data['hardening'] ) && is_array( $data['hardening'] )
					? $data['hardening']
					: array();
				$saved['hardening'] = array_map(
					static function ( $value ) {
						return filter_var( $value, FILTER_VALIDATE_BOOLEAN );
					},
					$hardening
				);
				break;
			case 'audit-logging':
				$saved['audit_logging'] = isset( $data['audit_logging'] );
				break;
		}

		$saved['current_screen'] = $step;
		update_site_option( 'wd_onboarding_data', $saved );

		return new Response(
			true,
			array(
				'message' => esc_html__( 'Step saved.', 'wpdef' ),
			)
		);
	}

	/**
	 * Finish the setup wizard.
	 *
	 * @param  Request $request  The request object containing the data.
	 *
	 * @return Response
	 * @defender_route
	 */
	public function finish_setup_wizard( Request $request ): Response {
		if ( ! $this->check_permission() ) {
			return new Response(
				false,
				array(
					'message' => esc_html__( 'Invalid', 'wpdef' ),
				)
			);
		}

		// Merge any per-step selections already saved with the final payload (request wins).
		$saved                 = get_site_option( 'wd_onboarding_data', array() );
		$saved                 = is_array( $saved ) ? $saved : array();
		$settings              = array_merge( $saved, $request->get_data() );
		$settings['last_scan'] = time();
		update_site_option( 'wd_onboarding_data', $settings );

		$firewall_state = (bool) $settings['local_firewall'];
		if ( $firewall_state ) {
			wd_di()->get( \WP_Defender\Controller\Firewall::class )->preset_firewall( true );
		}
		if ( isset( $settings['audit_logging'] ) ) {
			$this->apply_audit_logging( filter_var( $settings['audit_logging'], FILTER_VALIDATE_BOOLEAN ) );
		}

		if ( isset( $settings['hardening'] ) && is_array( $settings['hardening'] ) ) {
			$toggle_to_slug  = array(
				'disable_xmlrpc'               => 'disable-xml-rpc',
				'hide_error_reporting'         => 'hide-error',
				'update_security_keys'         => 'security-key',
				'prevent_enum_users'           => 'prevent-enum-users',
				'disable_trackbacks_pingbacks' => 'disable-trackback',
				'disable_file_editor'          => 'disable-file-editor',
			);
			$hardening_state = $settings['hardening'];
			$resolved_slugs  = array();

			foreach ( $toggle_to_slug as $toggle_key => $slug ) {
				if ( ! array_key_exists( $toggle_key, $hardening_state ) ) {
					continue;
				}

				if ( filter_var( $hardening_state[ $toggle_key ], FILTER_VALIDATE_BOOLEAN ) ) {
					$resolved_slugs[] = $slug;
				}
			}

			$security_key_slug  = 'security-key';
			$auto_regen_enabled = in_array( $security_key_slug, $resolved_slugs, true );

			// Only save the autogenerate flag — don't resolve the tweak (that would regenerate keys immediately).
			$resolved_slugs = array_values( array_filter( $resolved_slugs, fn( $s ) => $s !== $security_key_slug ) );

			$security_key = wd_di()->get( Security_Key::class );
			$security_key->set_is_autogenrate_keys( $auto_regen_enabled );
			if ( $auto_regen_enabled ) {
				$security_key->cron_schedule();
			} else {
				$security_key->cron_unschedule();
			}

			// Activate all other selected hardening tweaks.
			if ( is_array( $resolved_slugs ) && array() !== $resolved_slugs ) {
				$security_tweaks = wd_di()->get( Security_Tweaks::class );
				$security_tweaks->security_tweaks_auto_action( $resolved_slugs, 'resolve' );
			}
		}

		update_site_option( 'wp_defender_shown_activator', true );
		delete_site_option( 'wp_defender_is_free_activated' );
		self::clear_resume_notice_option();
		// Skip Welcome modal.
		Feature_Modal::delete_modal_key();

		return new Response(
			true,
			array(
				'message' => esc_html__( 'Setup wizard completed successfully.', 'wpdef' ),
			)
		);
	}

	/**
	 * Apply Audit Logging state from onboarding wizard.
	 *
	 * @param  bool $enabled  Whether Audit Logging is enabled.
	 *
	 * @return void
	 */
	private function apply_audit_logging( bool $enabled ): void {
		$model = wd_di()->get( Model_Audit_Logging::class );
		if ( false === $enabled && $enabled !== $model->is_active() ) {
			( new Audit() )->flush();
		}

		$model->enabled = $enabled;
		if ( $model->validate() ) {
			$model->save();
		}

		Config_Hub_Helper::set_clear_active_flag();
	}

	/**
	 * Close setup wizard session.
	 *
	 * @return Response
	 * @defender_route
	 */
	public function skip(): Response {
		if ( ! $this->check_permission() ) {
			return new Response(
				false,
				array(
					'message' => esc_html__( 'Invalid', 'wpdef' ),
				)
			);
		}

		update_site_option( 'wp_defender_shown_activator', true );
		delete_site_option( 'wp_defender_is_free_activated' );
		delete_site_option( 'wp_defender_onboarding_step' );
		self::clear_resume_notice_option();
		Data_Tracking::delete_modal_key();
		// Skip Welcome modal.
		Feature_Modal::delete_modal_key();

		return new Response(
			true,
			array(
				'message' => esc_html__( 'Setup wizard skipped successfully.', 'wpdef' ),
			)
		);
	}

	/**
	 * Clears skip state so the setup wizard can be opened again.
	 *
	 * @return Response
	 * @defender_route
	 */
	public function resume_setup_wizard(): Response {
		if ( ! $this->check_permission() ) {
			return new Response(
				false,
				array(
					'message' => esc_html__( 'Invalid', 'wpdef' ),
				)
			);
		}

		self::clear_resume_notice_option();
		delete_site_option( 'wp_defender_shown_activator' );
		delete_site_option( 'wp_defender_onboarding_step' );

		return new Response(
			true,
			array(
				'message' => esc_html__( 'Setup wizard resume state cleared successfully.', 'wpdef' ),
			)
		);
	}

	/**
	 * Converts the current object state to an array.
	 *
	 * @return array The array representation of the object.
	 */
	public function to_array(): array {
		return array();
	}

	/**
	 * Import the data of other source into this, it can be when HUB trigger the import, or user apply a preset.
	 *
	 * @param  array $data  Data from other source.
	 *
	 * @return null|void
	 */
	public function import_data( array $data ) {
	}

	/**
	 * Remove all settings, configs generated in this container runtime.
	 *
	 * @return void
	 */
	public function remove_settings() {
		delete_site_option( 'wd_onboarding_data' );
		self::clear_resume_notice_option();
		// From V5.x. We can delete it in the future versions.
		delete_site_option( self::REMINDER_KEY );
		delete_site_option( 'wp_defender_onboarding_step' );
	}

	/**
	 * Remove all data.
	 *
	 * @return void
	 */
	public function remove_data() {
	}

	/**
	 * Export strings.
	 *
	 * @return array
	 */
	public function export_strings(): array {
		return array();
	}
}