PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.2.1
WP 2FA – Two-factor authentication for WordPress v2.2.1
4.1.0 4.0.0 1.7.1 2.0.0 2.0.1 2.1.0 2.2.0 2.2.1 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.8.0 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0 3.0.1 3.1.0 3.1.1 3.1.1.2 trunk 1.2.0 1.3.0 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.1 1.6.2 1.7.0
wp-2fa / includes / classes / Admin / SettingsPages / class-settings-page-email.php
wp-2fa / includes / classes / Admin / SettingsPages Last commit date
class-settings-page-email.php 4 years ago class-settings-page-general.php 4 years ago class-settings-page-policies.php 4 years ago class-settings-page-white-label.php 4 years ago
class-settings-page-email.php
430 lines
1 <?php
2 /**
3 * Email settings class.
4 *
5 * @package wp2fa
6 * @subpackage settings-pages
7 * @copyright 2021 WP White Security
8 * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
9 * @link https://wordpress.org/plugins/wp-2fa/
10 */
11
12 namespace WP2FA\Admin\SettingsPages;
13
14 use WP2FA\Email_Template;
15 use \WP2FA\WP2FA as WP2FA;
16 use WP2FA\Admin\Controllers\Settings;
17 use WP2FA\Utils\Settings_Utils as Settings_Utils;
18
19 /**
20 * Email settings tab
21 */
22 if ( ! class_exists( '\WP2FA\Admin\SettingsPages\Settings_Page_Email' ) ) {
23 /**
24 * Settings_Page_Email - Class for handling email settings
25 *
26 * @since 2.0.0
27 */
28 class Settings_Page_Email {
29
30 /**
31 * Render the settings
32 *
33 * @return void
34 *
35 * @since 2.0.0
36 */
37 public function render() {
38 settings_fields( WP_2FA_EMAIL_SETTINGS_NAME );
39 $this->email_from_settings();
40 $this->email_settings();
41 submit_button( esc_html__( 'Save email settings and templates', 'wp-2fa' ) );
42 }
43
44 /**
45 * Handle saving email options to the network main site options.
46 *
47 * @return void
48 *
49 * @since 2.0.0
50 *
51 * @SuppressWarnings(PHPMD.ExitExpressions)
52 */
53 public function update_wp2fa_network_options() {
54 if ( isset( $_POST['email_from_setting'] ) ) { // phpcs:ignore
55 $options = $this->validate_and_sanitize( wp_unslash( $_POST ) ); // phpcs:ignore
56
57 if ( isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_display_name'] ) && empty( $_POST['custom_from_display_name'] ) || isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_email_address'] ) && empty( $_POST['custom_from_email_address'] ) ) { // phpcs:ignore
58 // redirect back to our options page.
59 wp_safe_redirect(
60 add_query_arg(
61 array(
62 'page' => 'wp-2fa-settings',
63 'wp_2fa_network_settings_updated' => 'false',
64 'tab' => 'email-settings',
65 ),
66 network_admin_url( 'admin.php' )
67 )
68 );
69 exit;
70 }
71
72 Settings_Utils::update_option( WP_2FA_EMAIL_SETTINGS_NAME, $options );
73 }
74
75 // redirect back to our options page.
76 wp_safe_redirect(
77 add_query_arg(
78 array(
79 'page' => 'wp-2fa-settings',
80 'wp_2fa_network_settings_updated' => 'true',
81 'tab' => 'email-settings',
82 ),
83 network_admin_url( 'admin.php' )
84 )
85 );
86 exit;
87 }
88
89 /**
90 * Email settings
91 *
92 * @return void
93 *
94 * @since 2.0.0
95 */
96 private function email_from_settings() {
97 ?>
98 <h3><?php esc_html_e( 'Which email address should the plugin use as a from address?', 'wp-2fa' ); ?></h3>
99 <p class="description">
100 <?php esc_html_e( 'Use these settings to customize the "from" name and email address for all correspondence sent from our plugin.', 'wp-2fa' ); ?>
101 </p>
102 <table class="form-table">
103 <tbody>
104 <tr>
105 <th><label for="2fa-method"><?php esc_html_e( 'From email & name', 'wp-2fa' ); ?></label>
106 </th>
107 <td>
108 <fieldset class="contains-hidden-inputs">
109 <label for="use-defaults">
110 <input type="radio" name="email_from_setting" id="use-defaults" value="use-defaults"
111 <?php checked( WP2FA::get_wp2fa_email_templates( 'email_from_setting' ), 'use-defaults' ); ?>
112 >
113 <span><?php esc_html_e( 'Use the email address from the WordPress general settings.', 'wp-2fa' ); ?></span>
114 </label>
115
116 <br/>
117 <label for="use-custom-email">
118 <input type="radio" name="email_from_setting" id="use-custom-email" value="use-custom-email"
119 <?php checked( WP2FA::get_wp2fa_email_templates( 'email_from_setting' ), 'use-custom-email' ); ?>
120 data-unhide-when-checked=".custom-from-inputs">
121 <span><?php esc_html_e( 'Use another email address', 'wp-2fa' ); ?></span>
122 </label>
123 <fieldset class="hidden custom-from-inputs">
124 <br/>
125 <span><?php esc_html_e( 'Email Address:', 'wp-2fa' ); ?></span> <input type="text" id="custom_from_email_address" name="custom_from_email_address" value="<?php echo esc_attr( WP2FA::get_wp2fa_email_templates( 'custom_from_email_address' ) ); ?>"><br><br>
126 <span><?php esc_html_e( 'Display Name:', 'wp-2fa' ); ?></span> <input type="text" id="custom_from_display_name" name="custom_from_display_name" value="<?php echo esc_attr( WP2FA::get_wp2fa_email_templates( 'custom_from_display_name' ) ); ?>">
127 </fieldset>
128
129 </fieldset>
130 </td>
131 </tr>
132 </tbody>
133 </table>
134
135 <br>
136 <hr>
137
138 <h3><?php esc_html_e( 'Email delivery test', 'wp-2fa' ); ?></h3>
139 <p class="description">
140 <?php esc_html_e( 'The plugin sends emails with one-time codes, blocked account notifications and more. Use the button below to confirm the plugin can successfully send emails.', 'wp-2fa' ); ?>
141 </p>
142 <p>
143 <button type="button" name="test_email_config_test"
144 class="button js-button-test-email-trigger"
145 data-email-id="config_test"
146 data-nonce="<?php echo esc_attr( wp_create_nonce( 'wp-2fa-email-test-config_test' ) ); ?>">
147 <?php esc_html_e( 'Test email delivery', 'wp-2fa' ); ?>
148 </button>
149 </p>
150
151 <br>
152 <hr>
153
154 <?php
155 }
156
157 /**
158 * Creates the email notification definitions.
159 *
160 * @return Email_Template[]
161 *
162 * @since 2.0.0
163 */
164 public function get_email_notification_definitions() {
165 $result = array(
166 new Email_Template(
167 'login_code',
168 esc_html__( 'Login code email', 'wp-2fa' ),
169 esc_html__( 'This is the email sent to a user when a login code is required.', 'wp-2fa' )
170 ),
171 new Email_Template(
172 'account_locked',
173 esc_html__( 'User account locked email', 'wp-2fa' ),
174 esc_html__( 'This is the email sent to a user upon grace period expiry.', 'wp-2fa' )
175 ),
176 new Email_Template(
177 'account_unlocked',
178 esc_html__( 'User account unlocked email', 'wp-2fa' ),
179 esc_html__( 'This is the email sent to a user when the user\'s account has been unlocked.', 'wp-2fa' )
180 ),
181 );
182
183 /**
184 * Add an option for external providers to implement their own email template settings for the settings tab.
185 *
186 * @param array $result - The array with all the email templates.
187 *
188 * @since 2.0.0
189 */
190 $result = apply_filters( WP_2FA_PREFIX . 'email_notification_definitions', $result );
191
192 if ( count( $result ) > 3 ) {
193 $result[0]->set_can_be_toggled( false );
194 $result[1]->set_can_be_toggled( false );
195 $result[2]->set_email_content_id( 'user_account_locked' );
196 $result[3]->set_email_content_id( 'user_account_unlocked' );
197 } else {
198 $result[0]->set_can_be_toggled( false );
199 $result[1]->set_email_content_id( 'user_account_locked' );
200 $result[2]->set_email_content_id( 'user_account_unlocked' );
201 }
202 return $result;
203 }
204
205 /**
206 * Validate email templates before saving
207 *
208 * @since 2.0.0
209 *
210 * @SuppressWarnings(PHPMD.ExitExpressions)
211 */
212 public function validate_and_sanitize() {
213
214 // Bail if user doesn't have permissions to be here.
215 if ( ! current_user_can( 'manage_options' ) ) {
216 return;
217 }
218
219 if ( empty( $_POST ) || ! isset( $_POST['_wpnonce'] ) || empty( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], WP_2FA_PREFIX . 'email_settings-options' ) && ! wp_verify_nonce( $_POST['_wpnonce'], WP_2FA_PREFIX . 'settings-options' ) || ! wp_verify_nonce( $_POST['_wpnonce'], WP_2FA_PREFIX . 'email_settings-options' ) && ! wp_verify_nonce( $_POST['_wpnonce'], WP_2FA_PREFIX . 'settings-options' ) ) { // phpcs:ignore
220 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
221 }
222
223 $output = array();
224
225 if ( isset( $_POST['email_from_setting'] ) && 'use-defaults' === $_POST['email_from_setting'] || isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] ) {
226 $output['email_from_setting'] = sanitize_text_field( wp_unslash( $_POST['email_from_setting'] ) );
227 }
228
229 if ( isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_email_address'] ) && empty( $_POST['custom_from_email_address'] ) ) {
230 add_settings_error(
231 WP_2FA_SETTINGS_NAME,
232 esc_attr( 'email_from_settings_error' ),
233 esc_html__( 'Please provide an email address', 'wp-2fa' ),
234 'error'
235 );
236 $output['custom_from_email_address'] = '';
237 }
238
239 if ( isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_display_name'] ) && empty( $_POST['custom_from_display_name'] ) ) {
240 add_settings_error(
241 WP_2FA_SETTINGS_NAME,
242 esc_attr( 'display_name_settings_error' ),
243 esc_html__( 'Please provide a display name.', 'wp-2fa' ),
244 'error'
245 );
246 $output['custom_from_email_address'] = '';
247 }
248
249 if ( isset( $_POST['custom_from_email_address'] ) && ! empty( $_POST['custom_from_email_address'] ) ) {
250 if ( ! filter_var( wp_unslash( $_POST['custom_from_email_address'] ), FILTER_VALIDATE_EMAIL ) ) {
251 add_settings_error(
252 WP_2FA_SETTINGS_NAME,
253 esc_attr( 'email_invalid_settings_error' ),
254 esc_html__( 'Please provide a valid email address. Your email address has not been updated.', 'wp-2fa' ),
255 'error'
256 );
257 }
258 $output['custom_from_email_address'] = sanitize_email( wp_unslash( $_POST['custom_from_email_address'] ) );
259 }
260
261 if ( isset( $_POST['custom_from_display_name'] ) && ! empty( $_POST['custom_from_display_name'] ) ) {
262 // Check if the string contains HTML/tags.
263 preg_match( "/<\/?\w+((\s+\w+(\s*=\s*(?:\".*?\"|'.*?'|[^'\">\s]+))?)+\s*|\s*)\/?>/", sanitize_text_field( wp_unslash( $_POST['custom_from_display_name'] ) ), $matches );
264 if ( count( $matches ) > 0 ) {
265 add_settings_error(
266 WP_2FA_SETTINGS_NAME,
267 esc_attr( 'display_name_invalid_settings_error' ),
268 esc_html__( 'Please only use alphanumeric text. Your display name has not been updated.', 'wp-2fa' ),
269 'error'
270 );
271 } else {
272 $output['custom_from_display_name'] = sanitize_text_field( wp_unslash( $_POST['custom_from_display_name'] ) );
273 }
274 }
275
276 if ( isset( $_POST['login_code_email_subject'] ) ) {
277 $output['login_code_email_subject'] = wp_kses_post( wp_unslash( $_POST['login_code_email_subject'] ) );
278 }
279
280 if ( isset( $_POST['login_code_email_body'] ) ) {
281 $output['login_code_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['login_code_email_body'] ) ) );
282 }
283
284 if ( isset( $_POST['user_account_locked_email_subject'] ) ) {
285 $output['user_account_locked_email_subject'] = wp_kses_post( wp_unslash( $_POST['user_account_locked_email_subject'] ) );
286 }
287
288 if ( isset( $_POST['user_account_locked_email_body'] ) ) {
289 $output['user_account_locked_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['user_account_locked_email_body'] ) ) );
290 }
291
292 if ( isset( $_POST['user_account_unlocked_email_subject'] ) ) {
293 $output['user_account_unlocked_email_subject'] = wp_kses_post( wp_unslash( $_POST['user_account_unlocked_email_subject'] ) );
294 }
295
296 if ( isset( $_POST['user_account_unlocked_email_body'] ) ) {
297 $output['user_account_unlocked_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['user_account_unlocked_email_body'] ) ) );
298 }
299
300 $output['send_account_locked_email'] = '';
301 if ( isset( $_POST['send_account_locked_email'] ) && 'enable_account_locked_email' === $_POST['send_account_locked_email'] ) {
302 $output['send_account_locked_email'] = sanitize_text_field( wp_unslash( $_POST['send_account_locked_email'] ) );
303 }
304
305 $output['send_account_unlocked_email'] = '';
306 if ( isset( $_POST['send_account_unlocked_email'] ) && 'enable_account_unlocked_email' === $_POST['send_account_unlocked_email'] ) {
307 $output['send_account_unlocked_email'] = sanitize_text_field( wp_unslash( $_POST['send_account_unlocked_email'] ) );
308 }
309
310 /**
311 * Filter the values we are about to store in the plugin settings.
312 *
313 * @param array $output - The output array with all the data we will store in the settings.
314 *
315 * @since 2.0.0
316 */
317 $output = apply_filters( WP_2FA_PREFIX . 'filter_output_email_template_content', $output );
318
319 // Remove duplicates from settings errors. We do this as this sanitization callback is actually fired twice, so we end up with duplicates when saving the settings for the FIRST TIME only. The issue is not present once the settings are in the DB as the sanitization wont fire again. For details on this core issue - https://core.trac.wordpress.org/ticket/21989.
320 global $wp_settings_errors;
321 if ( isset( $wp_settings_errors ) ) {
322 $errors = array_map( 'unserialize', array_unique( array_map( 'serialize', $wp_settings_errors ) ) );
323 $wp_settings_errors = $errors; // phpcs:ignore
324 }
325
326 if ( isset( $output ) ) {
327 return $output;
328 } else {
329 return;
330 }
331 }
332
333 /**
334 * Email settings
335 *
336 * @return void
337 *
338 * @since 2.0.0
339 */
340 private function email_settings() {
341 $custom_user_page_id = Settings::check_setting_in_all_roles( 'custom-user-page-id' );
342 $email_template_definitions = $this->get_email_notification_definitions();
343 ?>
344 <h1><?php esc_html_e( 'Email Templates', 'wp-2fa' ); ?></h1>
345 <?php foreach ( $email_template_definitions as $email_template ) : ?>
346 <?php $template_id = $email_template->get_id(); ?>
347 <h3><?php echo esc_html( $email_template->get_title() ); ?></h3>
348 <p class="description"><?php echo $email_template->get_description(); // phpcs:ignore ?></p>warning
349 <table class="form-table">
350 <tbody>
351 <?php if ( $email_template->can_be_toggled() ) : ?>
352 <tr>
353 <th><label for="send_<?php echo esc_attr( $template_id ); ?>_email"><?php esc_html_e( 'Send this email', 'wp-2fa' ); ?></label></th>
354 <td>
355 <fieldset>
356 <input type="checkbox" id="send_<?php echo esc_attr( $template_id ); ?>_email" name="send_<?php echo esc_attr( $template_id ); ?>_email" value="enable_<?php echo esc_attr( $template_id ); ?>_email"
357 <?php checked( 'enable_' . $template_id . '_email', WP2FA::get_wp2fa_email_templates( 'send_' . $template_id . '_email' ) ); ?>
358 >
359 <label for="send_<?php echo esc_attr( $template_id ); ?>_email"><?php esc_html_e( 'Uncheck to disable this message.', 'wp-2fa' ); ?></label>
360 </fieldset>
361 </td>
362 </tr>
363 <?php endif; ?>
364 <?php $template_id = $email_template->get_email_content_id(); ?>
365 <tr>
366 <th><label for="<?php echo esc_attr( $template_id ); ?>_email_subject"><?php esc_html_e( 'Email subject', 'wp-2fa' ); ?></label></th>
367 <td>
368 <fieldset>
369 <input type="text" id="<?php echo esc_attr( $template_id ); ?>_email_subject" name="<?php echo esc_attr( $template_id ); ?>_email_subject" class="large-text" value="<?php echo esc_attr( WP2FA::get_wp2fa_email_templates( $template_id . '_email_subject' ) ); ?>">
370 </fieldset>
371 </td>
372 </tr>
373 <tr>
374 <th>
375 <label for="<?php echo esc_attr( $template_id ); ?>_email_body"><?php esc_html_e( 'Email body', 'wp-2fa' ); ?></label>
376 </br>
377 <label for="<?php echo esc_attr( $template_id ); ?>_email_tags" style="font-weight: 400;"><?php esc_html_e( 'Available template tags:', 'wp-2fa' ); ?></label>
378 </br>
379 </br>
380 <span style="font-weight: 400;">
381 {site_url}</br>
382 {site_name}</br>
383 {grace_period}</br>
384 {user_login_name}</br>
385 {user_first_name}</br>
386 {user_last_name}</br>
387 {user_display_name}</br>
388 {login_code}</br>
389 {user_ip_address}
390 <?php
391 if ( ! empty( $custom_user_page_id ) ) {
392 echo '</br>{2fa_settings_page_url}';
393 }
394 ?>
395 </span>
396 </th>
397 <td>
398 <fieldset>
399 <?php
400 $message = WP2FA::get_wp2fa_email_templates( $template_id . '_email_body' );
401 $content = $message;
402 $editor_id = $template_id . '_email_body';
403 $settings = array(
404 'media_buttons' => false,
405 'editor_height' => 200,
406 );
407 wp_editor( $content, $editor_id, $settings );
408 ?>
409 </fieldset>
410 <p>
411 <button type="button" name="test_email_<?php echo esc_attr( $template_id ); ?>"
412 class="button js-button-test-email-trigger"
413 data-email-id="<?php echo esc_attr( $template_id ); ?>"
414 data-nonce="<?php echo esc_attr( wp_create_nonce( 'wp-2fa-email-test-' . $template_id ) ); ?>">
415 <?php esc_html_e( 'Send test email', 'wp-2fa' ); ?>
416 </button>
417 </p>
418 </td>
419 </tr>
420 </tbody>
421 </table>
422
423 <br>
424 <hr>
425 <?php endforeach; ?>
426 <?php
427 }
428 }
429 }
430