PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.2.3
Defender Security – Malware Scanner, Login Security & Firewall v6.2.3
6.3.0 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 All 141 releases
defender-security / src / component / class-notification-base.php

class-notification-base.php in Defender Security – Malware Scanner, Login Security & Firewall 6.2.3, at src/component/class-notification-base.php

552 lines 15.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Abstract base for the Notification component.
4 *
5 * Contains all shared functionality used by both the pro and free versions.
6 *
7 * @package WP_Defender\Component
8 */
9
10 namespace WP_Defender\Component;
11
12 use Exception;
13 use WP_User_Query;
14 use WP_Defender\Component;
15 use WP_Defender\Traits\IO;
16 use WP_Defender\Traits\User;
17 use WP_Defender\Model\Setting\Scan as Scan_Settings;
18 use WP_Defender\Model\Notification\Audit_Report;
19 use WP_Defender\Model\Notification\Malware_Report;
20 use WP_Defender\Model\Notification\Tweak_Reminder;
21 use WP_Defender\Model\Notification\Firewall_Report;
22 use WP_Defender\Model\Notification\Malware_Notification;
23 use WP_Defender\Model\Notification\Firewall_Notification;
24 use WP_Defender\Controller\Notification as Controller_Notification;
25
26 /**
27 * Abstract base for the Notification component.
28 */
29 abstract class Notification_Base extends Component {
30
31 use User;
32 use IO;
33
34 /**
35 * Scan settings model.
36 *
37 * @var Scan_Settings
38 */
39 public $scan_settings;
40
41 /**
42 * Retrieves a pool of users based on specified criteria.
43 *
44 * @param array $exclude User IDs to exclude.
45 * @param string $role Role to filter users by.
46 * @param string $username Search term for username.
47 * @param string $order_by Property to sort by.
48 * @param string $order Sort order (ASC or DESC).
49 * @param int $limit Number of users to retrieve.
50 * @param int $paged Page number for pagination.
51 *
52 * @return array Array of user data including display name, email, role, avatar, and ID.
53 */
54 public function get_users_pool(
55 $exclude = array(),
56 $role = '',
57 $username = '',
58 $order_by = 'ID',
59 $order = 'ASC',
60 $limit = 15,
61 $paged = 1
62 ): array {
63 $params = array(
64 'site_id' => 0,
65 'role' => $role,
66 'orderby' => $order_by,
67 'order' => $order,
68 'number' => $limit,
69 'paged' => $paged,
70 'exclude' => $exclude,
71 );
72
73 if ( '' !== $username ) {
74 $params['search'] = strtolower( $username );
75 $params['search_columns'] = array(
76 'user_login',
77 'user_email',
78 'user_nicename',
79 'display_name',
80 );
81 }
82 $user_query = new WP_User_Query( $params );
83
84 $pools = array();
85 foreach ( $user_query->get_results() as $user ) {
86 $pools[] = array(
87 'name' => $this->get_user_display( $user ),
88 'email' => $this->get_current_user_email( $user ),
89 'role' => $this->get_current_user_role( $user ),
90 'avatar' => get_avatar_url( $this->get_current_user_email( $user ) ),
91 'id' => $user->ID,
92 'status' => \WP_Defender\Model\Notification::USER_SUBSCRIBE_NA,
93 );
94 }
95
96 return $pools;
97 }
98
99 /**
100 * Dispatches notifications based on the module slug and additional arguments.
101 *
102 * @param string $slug Module slug to identify the notification handler.
103 * @param object $args Additional arguments for the notification.
104 */
105 public function dispatch_notification( $slug, $args ) {
106 if ( ! is_object( $args ) ) {
107 return;
108 }
109 $module = $this->find_module_by_slug( $slug );
110 if ( is_object( $module ) ) {
111 if ( 'malware-notification' === $module->slug ) {
112 // For a manual scan, always notify the triggering user regardless of notification status.
113 $is_manual_with_user = ! $args->is_automation && (int) get_transient( 'defender_scan_triggered_by_' . $args->id ) > 0;
114 if ( $is_manual_with_user || $module->check_options() ) {
115 $module->send( $args );
116 }
117 } elseif ( 'firewall-notification' === $module->slug && $module->check_options( $args ) ) {
118 $module->send( $args );
119 }
120 }
121 }
122
123 /**
124 * Finds a notification module by its slug.
125 *
126 * @param string $slug The slug of the module.
127 *
128 * @return mixed Returns the module object if found.
129 */
130 public function find_module_by_slug( $slug ) {
131 switch ( $slug ) {
132 case Tweak_Reminder::SLUG:
133 return wd_di()->get( Tweak_Reminder::class );
134 case Malware_Notification::SLUG:
135 return wd_di()->get( Malware_Notification::class );
136 case Firewall_Notification::SLUG:
137 return wd_di()->get( Firewall_Notification::class );
138 case Malware_Report::SLUG:
139 return wd_di()->get( Malware_Report::class );
140 case Firewall_Report::SLUG:
141 return wd_di()->get( Firewall_Report::class );
142 case Audit_Report::SLUG:
143 return wd_di()->get( Audit_Report::class );
144 default:
145 return false;
146 }
147 }
148
149 /**
150 * Send a verification email to users.
151 *
152 * @param \WP_Defender\Model\Notification $model Notification model containing recipient details.
153 *
154 * @throws Exception Emits Exception in case of an error.
155 */
156 public function send_subscription_confirm_email( \WP_Defender\Model\Notification $model ) {
157 foreach ( $model->in_house_recipients as &$subscriber ) {
158 if ( ! isset( $subscriber['status'] ) || '' === $subscriber['status'] ) {
159 continue;
160 }
161 if ( \WP_Defender\Model\Notification::USER_SUBSCRIBE_NA !== $subscriber['status'] ) {
162 continue;
163 }
164 $ret = $this->send_email( $subscriber, $model->export() );
165
166 if ( $ret ) {
167 $subscriber['status'] = \WP_Defender\Model\Notification::USER_SUBSCRIBE_WAITING;
168 }
169 }
170 foreach ( $model->out_house_recipients as &$subscriber ) {
171 if ( ! isset( $subscriber['status'] ) || '' === $subscriber['status'] ) {
172 continue;
173 }
174 if ( \WP_Defender\Model\Notification::USER_SUBSCRIBE_NA !== $subscriber['status'] ) {
175 continue;
176 }
177 $ret = $this->send_email( $subscriber, $model->export() );
178
179 if ( $ret ) {
180 $subscriber['status'] = \WP_Defender\Model\Notification::USER_SUBSCRIBE_WAITING;
181 }
182 }
183
184 $model->save();
185 }
186
187 /**
188 * Sends an email to a subscriber.
189 *
190 * @param array $subscriber Subscriber information.
191 * @param array $data Notification slug, title, type.
192 *
193 * @return bool Returns true if the email was sent successfully.
194 */
195 public function send_email( $subscriber, $data ) {
196 $headers = wd_di()->get( Mail::class )->get_headers(
197 defender_noreply_email( 'wd_confirm_noreply_email' ),
198 'subscription'
199 );
200 $email = $subscriber['email'];
201 $name = $subscriber['name'] ?? '';
202 $inhouse = false;
203 if ( isset( $subscriber['id'] ) ) {
204 $inhouse = true;
205 }
206 $url = $this->create_subscribe_url( $data['slug'], $email, $inhouse );
207 $subject = sprintf( /* translators: %s: Model title. */ 'Subscribe to %s', $data['title'] );
208 $notification = wd_di()->get( Controller_Notification::class );
209 $content_body = $notification->render_partial(
210 'email/confirm',
211 array(
212 'subject' => $subject,
213 'email' => $email,
214 'notification_name' => $data['title'],
215 'url' => $url,
216 'site_url' => network_site_url(),
217 'name' => $name,
218 ),
219 false
220 );
221 $content = $notification->render_partial(
222 'email/index',
223 array(
224 'title' => $data['title'],
225 'content_body' => $content_body,
226 'unsubscribe_link' => '',
227 ),
228 false
229 );
230
231 return wp_mail( $email, $subject, $content, $headers );
232 }
233
234 /**
235 * Sends a single invite email listing all notification modules the recipient was added to.
236 *
237 * @param array $subscriber Subscriber info with 'email', 'name', and optionally 'id' for in-house.
238 * @param array $modules Array of notification model objects.
239 *
240 * @return bool True if the email was sent successfully.
241 */
242 public function send_invite_all_email( array $subscriber, array $modules ): bool {
243 $email = $subscriber['email'];
244 $name = $subscriber['name'] ?? '';
245 $inhouse = isset( $subscriber['id'] );
246
247 $module_list = array();
248 $slugs = array();
249 foreach ( $modules as $module ) {
250 $module_list[] = array( 'title' => $module->title );
251 $slugs[] = $module->slug;
252 }
253
254 if ( array() === $module_list ) {
255 return false;
256 }
257
258 $url = $this->create_subscribe_all_url( $slugs, $email, $inhouse );
259 $headers = wd_di()->get( Mail::class )->get_headers(
260 defender_noreply_email( 'wd_confirm_noreply_email' ),
261 'subscription'
262 );
263 $subject = esc_html__( 'Confirm your subscriptions', 'defender-security' );
264 $notification = wd_di()->get( Controller_Notification::class );
265 $content_body = $notification->render_partial(
266 'email/confirm-all',
267 array(
268 'name' => $name,
269 'email' => $email,
270 'site_url' => network_site_url(),
271 'modules' => $module_list,
272 'url' => $url,
273 ),
274 false
275 );
276 $content = $notification->render_partial(
277 'email/index',
278 array(
279 'title' => esc_html__( 'Confirm your subscriptions', 'defender-security' ),
280 'content_body' => $content_body,
281 'unsubscribe_link' => '',
282 ),
283 false
284 );
285
286 return wp_mail( $email, $subject, $content, $headers );
287 }
288
289 /**
290 * Sends a subscription confirmation email to a user.
291 *
292 * @param string $email Email address of the subscriber.
293 * @param object $m Notification model object.
294 * @param string $name Name of the subscriber.
295 */
296 public function send_subscribed_email( $email, $m, $name ) {
297 $headers = wd_di()->get( Mail::class )->get_headers(
298 defender_noreply_email( 'wd_subscribe_noreply_email' ),
299 'subscribe_confimed'
300 );
301 $notification = wd_di()->get( Controller_Notification::class );
302 $subject = esc_html__( 'Confirmed', 'defender-security' );
303 $content_body = $notification->render_partial(
304 'email/subscribed',
305 array(
306 'subject' => esc_html__( 'Subscription Confirmed', 'defender-security' ),
307 'notification_name' => $m->title,
308 'url' => $this->create_unsubscribe_url( $m->slug, $email ),
309 'name' => $name,
310 )
311 );
312 $content = $notification->render_partial(
313 'email/index',
314 array(
315 'title' => preg_replace( '/ - (Notification|Alert)$/', '', $m->title ),
316 'content_body' => $content_body,
317 'unsubscribe_link' => '',
318 ),
319 false
320 );
321
322 wp_mail( $email, $subject, $content, $headers );
323 }
324
325 /**
326 * Sends a single subscription confirmation email for multiple modules.
327 *
328 * @param string $email Email address of the subscriber.
329 * @param array $modules Array of notification model objects.
330 * @param string $name Name of the subscriber.
331 */
332 public function send_subscribed_all_email( $email, array $modules, $name ) {
333 $module_list = array();
334 foreach ( $modules as $module ) {
335 $module_list[] = array(
336 'title' => $module->title,
337 'url' => $this->create_unsubscribe_url( $module->slug, $email ),
338 );
339 }
340
341 if ( array() === $module_list ) {
342 return;
343 }
344
345 $headers = wd_di()->get( Mail::class )->get_headers(
346 defender_noreply_email( 'wd_subscribe_noreply_email' ),
347 'subscribe_confimed'
348 );
349 $notification = wd_di()->get( Controller_Notification::class );
350 $subject = esc_html__( 'Confirmed', 'defender-security' );
351 $content_body = $notification->render_partial(
352 'email/subscribed-all',
353 array(
354 'subject' => esc_html__( 'Subscriptions Confirmed', 'defender-security' ),
355 'modules' => $module_list,
356 'name' => $name,
357 ),
358 false
359 );
360 $content = $notification->render_partial(
361 'email/index',
362 array(
363 'title' => esc_html__( 'Subscriptions Confirmed', 'defender-security' ),
364 'content_body' => $content_body,
365 'unsubscribe_link' => '',
366 ),
367 false
368 );
369
370 wp_mail( $email, $subject, $content, $headers );
371 }
372
373 /**
374 * Sends an unsubscribe email to a user.
375 *
376 * @param object $m Notification model object.
377 * @param string $email Email address of the subscriber.
378 * @param bool $inhouse Indicates if the user is an in-house user.
379 * @param string $name Name of the subscriber.
380 */
381 public function send_unsubscribe_email( $m, $email, $inhouse, $name ) {
382 $subject = esc_html__( 'Unsubscribed', 'defender-security' );
383 $url = $this->create_subscribe_url( $m->slug, $email, $inhouse );
384 $notification = wd_di()->get( Controller_Notification::class );
385 $content_body = $notification->render_partial(
386 'email/unsubscribe',
387 array(
388 'subject' => esc_html__( 'Unsubscribed', 'defender-security' ),
389 'notification_name' => $m->title,
390 'url' => $url,
391 'name' => $name,
392 ),
393 false
394 );
395 $title = preg_replace( '/ - (Notification|Alert)$/', '', $m->title );
396 $title = preg_replace( '/ - Reporting$/', '', $title );
397 $content = $notification->render_partial(
398 'email/index',
399 array(
400 'title' => $title,
401 'content_body' => $content_body,
402 'unsubscribe_link' => '',
403 ),
404 false
405 );
406 $headers = wd_di()->get( Mail::class )->get_headers(
407 defender_noreply_email( 'wd_unsubscribe_noreply_email' ),
408 'unsubscription'
409 );
410
411 wp_mail( $email, $subject, $content, $headers );
412 }
413
414 /**
415 * Create a URL for unsubscribing from notifications.
416 *
417 * @param string $slug Notification slug.
418 * @param string $email Email address of the subscriber.
419 *
420 * @return string Unsubscribe URL.
421 */
422 public function create_unsubscribe_url( $slug, $email ): string {
423 return add_query_arg(
424 array(
425 'action' => Controller_Notification::SLUG_UNSUBSCRIBE,
426 'hash' => hash( 'sha256', $email . AUTH_SALT ),
427 'slug' => $slug,
428 ),
429 admin_url( 'admin-ajax.php' )
430 );
431 }
432
433 /**
434 * Create a URL for subscribing to notifications.
435 *
436 * @param string $slug Notification slug.
437 * @param string $email Email address of the subscriber.
438 * @param bool $inhouse Indicates if the user is an in-house user.
439 *
440 * @return string Subscribe URL.
441 */
442 public function create_subscribe_url( $slug, $email, $inhouse ): string {
443 return add_query_arg(
444 array(
445 'action' => Controller_Notification::SLUG_SUBSCRIBE,
446 'hash' => hash( 'sha256', $email . AUTH_SALT ),
447 'uid' => $slug,
448 'inhouse' => $inhouse,
449 ),
450 admin_url( 'admin-ajax.php' )
451 );
452 }
453
454 /**
455 * Create a URL for subscribing to multiple notifications.
456 *
457 * @param array $slugs Notification slugs.
458 * @param string $email Email address of the subscriber.
459 * @param bool $inhouse Indicates if the user is an in-house user.
460 *
461 * @return string Subscribe URL.
462 */
463 public function create_subscribe_all_url( array $slugs, $email, $inhouse ): string {
464 return add_query_arg(
465 array(
466 'action' => Controller_Notification::SLUG_SUBSCRIBE,
467 'hash' => hash( 'sha256', $email . AUTH_SALT ),
468 'uids' => implode( ',', array_map( 'sanitize_key', $slugs ) ),
469 'inhouse' => $inhouse,
470 ),
471 admin_url( 'admin-ajax.php' )
472 );
473 }
474
475 /**
476 * Counts the number of active modules.
477 *
478 * @return int Number of active modules.
479 */
480 public function count_active(): int {
481 $count = 0;
482 foreach ( $this->get_modules() as $module ) {
483 if ( \WP_Defender\Model\Notification::STATUS_ACTIVE === $module['status'] ) {
484 ++$count;
485 }
486 }
487
488 return $count;
489 }
490
491 /**
492 * Get available user roles with user count.
493 *
494 * @return array Return user roles with user count.
495 */
496 public function get_user_roles(): array {
497 $user_roles = count_users();
498
499 if ( isset( $user_roles['avail_roles'] ) ) {
500 foreach ( $user_roles['avail_roles'] as $key => $value ) {
501 if ( 0 === $value ) {
502 unset( $user_roles['avail_roles'][ $key ] );
503 }
504 }
505 }
506
507 return $user_roles;
508 }
509
510 /**
511 * Get all modules as array of arrays.
512 *
513 * @return array
514 */
515 abstract public function get_modules(): array;
516
517 /**
518 * Get all modules as array of objects.
519 *
520 * @return array
521 */
522 abstract public function get_modules_as_objects(): array;
523
524 /**
525 * Return the time that the next report will be triggered.
526 *
527 * @return string|null
528 */
529 abstract public function get_next_run();
530
531 /**
532 * Get inactive modules.
533 *
534 * @return array
535 */
536 abstract public function get_inactive_modules(): array;
537
538 /**
539 * Get active pro report modules as arrays.
540 *
541 * @return array
542 */
543 abstract public function get_active_pro_reports(): array;
544
545 /**
546 * Get active pro report modules as objects.
547 *
548 * @return array
549 */
550 abstract public function get_active_pro_reports_as_objects(): array;
551 }
552