PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / trunk
Defender Security – Malware Scanner, Login Security & Firewall vtrunk
6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 3.1.1 All 140 releases
defender-security / src / controller / class-setup-wizard.php

class-setup-wizard.php in Defender Security – Malware Scanner, Login Security & Firewall trunk, at src/controller/class-setup-wizard.php

342 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles setup wizard.
4 *
5 * @package WP_Defender\Controller
6 */
7
8 namespace WP_Defender\Controller;
9
10 use WP_Defender\Event;
11 use Calotes\Component\Request;
12 use Calotes\Component\Response;
13 use WP_Defender\Component\Feature_Modal;
14 use WP_Defender\Controller\Data_Tracking;
15 use WP_Defender\Controller\Security_Tweaks;
16 use WP_Defender\Component\Config\Config_Hub_Helper;
17 use WP_Defender\Component\Security_Tweaks\Security_Key;
18
19 /**
20 * Handles setup wizard.
21 */
22 class Setup_Wizard extends Event {
23 /**
24 * Legacy site option key for skipped setup wizard bubble state.
25 *
26 * @var string
27 */
28 public const RESUME_NOTICE_OPTION = 'wd_setup_wizard_resume_notice';
29
30 /**
31 * The slug identifier for this controller.
32 *
33 * @var string
34 */
35 public $slug = 'wdf-setup-wizard';
36
37 /**
38 * The old key for the remind later in Onboarding. This is from V5.x. We can delete it in the future versions.
39 *
40 * @var string
41 */
42 public const REMINDER_KEY = 'wp_defender_onboard_antibot_reminder';
43
44 /**
45 * Initializes the model and service, registers routes, and sets up scheduled events if the model is active.
46 */
47 public function __construct() {
48 $this->register_routes();
49 }
50
51 /**
52 * Provides data for the frontend.
53 *
54 * @return array An array of data for the frontend.
55 */
56 public function data_frontend(): array {
57 return array_merge(
58 array(
59 'custom_nonce' => wp_create_nonce( 'wpdef_setup_wizard' ),
60 // Saved wizard selections, so the wizard can resume from server state after a refresh.
61 'onboardingData' => get_site_option( 'wd_onboarding_data', array() ),
62 ),
63 $this->dump_routes_and_nonces()
64 );
65 }
66
67 /**
68 * Deletes any legacy resume setup wizard bubble state.
69 *
70 * @return void
71 */
72 private static function clear_resume_notice_option(): void {
73 delete_site_option( self::RESUME_NOTICE_OPTION );
74 }
75
76 /**
77 * Persist a single wizard step's selection to the database.
78 *
79 * Each step is merged into the canonical `wd_onboarding_data` site option so the
80 * wizard can resume from server state after a refresh or on another device. The
81 * actual module side effects are still applied atomically in finish_setup_wizard().
82 *
83 * @param Request $request The request object containing the step data.
84 *
85 * @return Response
86 * @defender_route
87 */
88 public function save_step( Request $request ): Response {
89 if ( ! $this->check_permission() ) {
90 return new Response(
91 false,
92 array(
93 'message' => esc_html__( 'Invalid', 'defender-security' ),
94 )
95 );
96 }
97
98 $payload = $request->get_data();
99 $step = isset( $payload['step'] ) ? sanitize_text_field( $payload['step'] ) : '';
100 $data = isset( $payload['data'] ) && is_array( $payload['data'] ) ? $payload['data'] : array();
101
102 $allowed_steps = array( 'local-firewall', 'hardening', 'audit-logging' );
103 if ( ! in_array( $step, $allowed_steps, true ) ) {
104 return new Response(
105 false,
106 array(
107 'message' => esc_html__( 'Invalid step.', 'defender-security' ),
108 )
109 );
110 }
111
112 $saved = get_site_option( 'wd_onboarding_data', array() );
113 if ( ! is_array( $saved ) ) {
114 $saved = array();
115 }
116
117 switch ( $step ) {
118 case 'local-firewall':
119 $saved['local_firewall'] = isset( $data['local_firewall'] );
120 break;
121 case 'hardening':
122 $hardening = isset( $data['hardening'] ) && is_array( $data['hardening'] )
123 ? $data['hardening']
124 : array();
125 $saved['hardening'] = array_map(
126 static function ( $value ) {
127 return filter_var( $value, FILTER_VALIDATE_BOOLEAN );
128 },
129 $hardening
130 );
131 break;
132 }
133
134 $saved['current_screen'] = $step;
135 update_site_option( 'wd_onboarding_data', $saved );
136
137 return new Response(
138 true,
139 array(
140 'message' => esc_html__( 'Step saved.', 'defender-security' ),
141 )
142 );
143 }
144
145 /**
146 * Finish the setup wizard.
147 *
148 * @param Request $request The request object containing the data.
149 *
150 * @return Response
151 * @defender_route
152 */
153 public function finish_setup_wizard( Request $request ): Response {
154 if ( ! $this->check_permission() ) {
155 return new Response(
156 false,
157 array(
158 'message' => esc_html__( 'Invalid', 'defender-security' ),
159 )
160 );
161 }
162
163 // Merge any per-step selections already saved with the final payload (request wins).
164 $saved = get_site_option( 'wd_onboarding_data', array() );
165 $saved = is_array( $saved ) ? $saved : array();
166 $settings = array_merge( $saved, $request->get_data() );
167 $settings['last_scan'] = time();
168 update_site_option( 'wd_onboarding_data', $settings );
169
170 $firewall_state = (bool) $settings['local_firewall'];
171 if ( $firewall_state ) {
172 wd_di()->get( \WP_Defender\Controller\Firewall::class )->preset_firewall( true );
173 }
174
175 if ( isset( $settings['hardening'] ) && is_array( $settings['hardening'] ) ) {
176 $toggle_to_slug = array(
177 'disable_xmlrpc' => 'disable-xml-rpc',
178 'hide_error_reporting' => 'hide-error',
179 'update_security_keys' => 'security-key',
180 'prevent_enum_users' => 'prevent-enum-users',
181 'disable_trackbacks_pingbacks' => 'disable-trackback',
182 'disable_file_editor' => 'disable-file-editor',
183 );
184 $hardening_state = $settings['hardening'];
185 $resolved_slugs = array();
186
187 foreach ( $toggle_to_slug as $toggle_key => $slug ) {
188 if ( ! array_key_exists( $toggle_key, $hardening_state ) ) {
189 continue;
190 }
191
192 if ( filter_var( $hardening_state[ $toggle_key ], FILTER_VALIDATE_BOOLEAN ) ) {
193 $resolved_slugs[] = $slug;
194 }
195 }
196
197 $security_key_slug = 'security-key';
198 $auto_regen_enabled = in_array( $security_key_slug, $resolved_slugs, true );
199
200 // Only save the autogenerate flag — don't resolve the tweak (that would regenerate keys immediately).
201 $resolved_slugs = array_values( array_filter( $resolved_slugs, fn( $s ) => $s !== $security_key_slug ) );
202
203 $security_key = wd_di()->get( Security_Key::class );
204 $security_key->set_is_autogenrate_keys( $auto_regen_enabled );
205 if ( $auto_regen_enabled ) {
206 $security_key->cron_schedule();
207 } else {
208 $security_key->cron_unschedule();
209 }
210
211 // Activate all other selected hardening tweaks.
212 if ( is_array( $resolved_slugs ) && array() !== $resolved_slugs ) {
213 $security_tweaks = wd_di()->get( Security_Tweaks::class );
214 $security_tweaks->security_tweaks_auto_action( $resolved_slugs, 'resolve' );
215 }
216 }
217
218 update_site_option( 'wp_defender_shown_activator', true );
219 delete_site_option( 'wp_defender_is_free_activated' );
220 self::clear_resume_notice_option();
221 // Skip Welcome modal.
222 Feature_Modal::delete_modal_key();
223
224 return new Response(
225 true,
226 array(
227 'message' => esc_html__( 'Setup wizard completed successfully.', 'defender-security' ),
228 )
229 );
230 }
231
232
233 /**
234 * Close setup wizard session.
235 *
236 * @return Response
237 * @defender_route
238 */
239 public function skip(): Response {
240 if ( ! $this->check_permission() ) {
241 return new Response(
242 false,
243 array(
244 'message' => esc_html__( 'Invalid', 'defender-security' ),
245 )
246 );
247 }
248
249 update_site_option( 'wp_defender_shown_activator', true );
250 delete_site_option( 'wp_defender_is_free_activated' );
251 delete_site_option( 'wp_defender_onboarding_step' );
252 self::clear_resume_notice_option();
253 Data_Tracking::delete_modal_key();
254 // Skip Welcome modal.
255 Feature_Modal::delete_modal_key();
256
257 return new Response(
258 true,
259 array(
260 'message' => esc_html__( 'Setup wizard skipped successfully.', 'defender-security' ),
261 )
262 );
263 }
264
265 /**
266 * Clears skip state so the setup wizard can be opened again.
267 *
268 * @return Response
269 * @defender_route
270 */
271 public function resume_setup_wizard(): Response {
272 if ( ! $this->check_permission() ) {
273 return new Response(
274 false,
275 array(
276 'message' => esc_html__( 'Invalid', 'defender-security' ),
277 )
278 );
279 }
280
281 self::clear_resume_notice_option();
282 delete_site_option( 'wp_defender_shown_activator' );
283 delete_site_option( 'wp_defender_onboarding_step' );
284
285 return new Response(
286 true,
287 array(
288 'message' => esc_html__( 'Setup wizard resume state cleared successfully.', 'defender-security' ),
289 )
290 );
291 }
292
293 /**
294 * Converts the current object state to an array.
295 *
296 * @return array The array representation of the object.
297 */
298 public function to_array(): array {
299 return array();
300 }
301
302 /**
303 * Import the data of other source into this, it can be when HUB trigger the import, or user apply a preset.
304 *
305 * @param array $data Data from other source.
306 *
307 * @return null|void
308 */
309 public function import_data( array $data ) {
310 }
311
312 /**
313 * Remove all settings, configs generated in this container runtime.
314 *
315 * @return void
316 */
317 public function remove_settings() {
318 delete_site_option( 'wd_onboarding_data' );
319 self::clear_resume_notice_option();
320 // From V5.x. We can delete it in the future versions.
321 delete_site_option( self::REMINDER_KEY );
322 delete_site_option( 'wp_defender_onboarding_step' );
323 }
324
325 /**
326 * Remove all data.
327 *
328 * @return void
329 */
330 public function remove_data() {
331 }
332
333 /**
334 * Export strings.
335 *
336 * @return array
337 */
338 public function export_strings(): array {
339 return array();
340 }
341 }
342