PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.6.4
WP 2FA – Two-factor authentication for WordPress v2.6.4
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 / Methods / class-email-wizard-steps.php
wp-2fa / includes / classes / Admin / Methods Last commit date
Traits 2 years ago class-backup-codes.php 2 years ago class-email-wizard-steps.php 2 years ago class-email.php 2 years ago class-totp-wizard-steps.php 2 years ago class-totp.php 2 years ago index.php 2 years ago
class-email-wizard-steps.php
354 lines
1 <?php
2 /**
3 * Responsible for WP2FA user's Email manipulation.
4 *
5 * @package wp2fa
6 * @subpackage methods-wizard
7 * @since 2.6.0
8 * @copyright 2024 Melapress
9 * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
10 *
11 * @see https://wordpress.org/plugins/wp-2fa/
12 */
13
14 declare(strict_types=1);
15
16 namespace WP2FA\Methods\Wizards;
17
18 use WP2FA\WP2FA;
19 use WP2FA\Methods\Email;
20 use WP2FA\Admin\Helpers\WP_Helper;
21 use WP2FA\Admin\Views\Wizard_Steps;
22 use WP2FA\Admin\Helpers\User_Helper;
23 use WP2FA\Admin\Controllers\Settings;
24 use WP2FA\Admin\Methods\Traits\Methods_Wizards_Trait;
25 use WP2FA\Extensions\RoleSettings\Role_Settings_Controller;
26
27 /**
28 * Class for handling email codes.
29 *
30 * @since 2.6.0
31 *
32 * @package WP2FA
33 */
34 if ( ! class_exists( '\WP2FA\Methods\Wizards\Email_Wizard_Steps' ) ) {
35 /**
36 * Email code class, for handling email code generation and such.
37 *
38 * @since 2.6.0
39 */
40 class Email_Wizard_Steps extends Wizard_Steps {
41
42 use Methods_Wizards_Trait;
43
44 /**
45 * Keeps the main class method name, so we can call it when needed.
46 *
47 * @var string
48 *
49 * @since 2.6.0
50 */
51 private static $main_class = Email::class;
52
53 /**
54 * The default value of the method order in the wizards.
55 *
56 * @var integer
57 *
58 * @since 2.6.0
59 */
60 private static $order = 2;
61
62 /**
63 * Inits the class hooks
64 *
65 * @return void
66 *
67 * @since 2.4.0
68 */
69 public static function init() {
70 \add_filter( WP_2FA_PREFIX . 'methods_modal_options', array( __CLASS__, 'email_option' ), 10, 2 );
71 \add_action( WP_2FA_PREFIX . 'modal_methods', array( __CLASS__, 'email_modal_configure' ) );
72 \add_filter( WP_2FA_PREFIX . 'methods_re_configure', array( __CLASS__, 'email_re_configure' ), 10, 2 );
73 \add_filter( WP_2FA_PREFIX . 'methods_settings', array( __CLASS__, 'email_wizard_settings' ), 10, 4 );
74 }
75
76 /**
77 * Shows the option for email method reconfiguring (if applicable)
78 *
79 * @param array $methods - Array of methods collected.
80 * @param string $role - The name of the role to show option to.
81 *
82 * @since 2.6.0 - Parameter $methods is added, parameter $role (name) is added and array is now returned
83 *
84 * @return array
85 */
86 public static function email_re_configure( array $methods, string $role ): array {
87
88 if ( ! Email::is_enabled() ) {
89 return $methods;
90 }
91 \ob_start();
92 ?>
93 <div class="option-pill">
94 <?php echo wp_kses_post( WP2FA::contextual_reconfigure_text( WP2FA::get_wp2fa_white_label_setting( 'hotp_reconfigure_intro', true ), User_Helper::get_user_object()->ID, 'hotp' ) ); ?>
95 <div class="wp2fa-setup-actions">
96 <a class="button button-primary wp-2fa-button-primary" data-name="next_step_setting_modal_wizard" value="<?php esc_attr_e( 'I\'m Ready', 'wp-2fa' ); ?>" data-user-id="<?php echo esc_attr( User_Helper::get_user_object()->ID ); ?>" <?php echo WP_Helper::create_data_nonce( 'wp-2fa-send-setup-email' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> data-next-step="2fa-wizard-email"><?php esc_html_e( 'Change email address', 'wp-2fa' ); ?></a>
97 </div>
98 </div>
99 <?php
100 $output = ob_get_contents();
101 ob_end_clean();
102
103 $methods[ self::get_order( $role, $methods ) ] = array(
104 'name' => self::$main_class::METHOD_NAME,
105 'output' => $output,
106 );
107
108 return $methods;
109 }
110
111 /**
112 * Shows the initial email setup options based on enabled methods
113 *
114 * @param array $methods - Array of methods collected.
115 * @param string $role - The name of the role to show option to.
116 *
117 * @since 2.6.0 - Parameter $methods is added, parameter $role (name) is added and array is now returned
118 *
119 * @return array
120 */
121 public static function email_option( array $methods, string $role ): array {
122 if ( Email::is_enabled() ) {
123 \ob_start();
124 ?>
125 <div class="option-pill">
126 <label for="geek">
127 <input id="geek" name="wp_2fa_enabled_methods" type="radio" value="email">
128 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'email-option-label', true ) ); ?>
129 </label>
130 </div>
131 <?php
132 $output = ob_get_contents();
133 ob_end_clean();
134
135 $methods[ self::get_order( $role, $methods ) ] = $output;
136 }
137
138 return $methods;
139 }
140
141 /**
142 * Settings page and first time wizard settings render
143 *
144 * @param array $methods - Array with all the methods in which we have to add this one.
145 * @param boolean $setup_wizard - Is that the first time setup wizard.
146 * @param string $data_role - Additional HTML data attribute.
147 * @param mixed $role - Name of the role.
148 *
149 * @return array - The array with the methods with all the methods wizard steps.
150 *
151 * @since 2.6.0
152 */
153 public static function email_wizard_settings( array $methods, bool $setup_wizard, string $data_role, $role = null ) {
154 $name_prefix = WP_2FA_POLICY_SETTINGS_NAME;
155 $role_id = '';
156 if ( null !== $role && '' !== trim( (string) $role ) ) {
157 $name_prefix .= "[{$role}]";
158 $data_role = 'data-role="' . $role . '"';
159 $role_id = '-' . $role;
160 }
161 \ob_start();
162 ?>
163 <div id="<?php echo \esc_attr( Email::METHOD_NAME ); ?>-method-wrapper" class="method-wrapper">
164 <?php echo self::hidden_order_setting( $role ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
165 <label for="hotp<?php echo \esc_attr( $role_id ); ?>" style="margin-bottom: 0 !important;">
166 <input type="checkbox" id="hotp<?php echo \esc_attr( $role_id ); ?>" name="<?php echo \esc_attr( $name_prefix ); ?>[enable_email]" value="enable_email"
167 <?php echo $data_role; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
168 <?php if ( null !== $role && ! empty( $role ) ) { ?>
169 <?php checked( Email::POLICY_SETTINGS_NAME, Role_Settings_Controller::get_setting( $role, Email::POLICY_SETTINGS_NAME ), true ); ?>
170 <?php
171 } else {
172 $use_role_setting = null;
173 if ( null === $role || '' === trim( (string) $role ) ) {
174 $use_role_setting = \WP_2FA_PREFIX . 'no-user';
175 }
176
177 $enabled_settings = Settings::get_role_or_default_setting( Email::POLICY_SETTINGS_NAME, $use_role_setting, $role, true );
178 ?>
179 <?php checked( $enabled_settings, Email::POLICY_SETTINGS_NAME ); ?>
180 <?php } ?>
181 >
182 <?php
183 esc_html_e( 'One-time code via email (HOTP)', 'wp-2fa' );
184 esc_html_e( ' - ensure email deliverability with the free plugin ', 'wp-2fa' );
185 echo '<a href="https://wordpress.org/plugins/wp-mail-smtp/" target="_blank" rel="nofollow">WP Mail SMTP</a>.';
186 ?>
187 </label>
188 <?php
189 if ( $setup_wizard ) {
190 echo '<p class="description">' . esc_html__( 'When using this method, users will receive the one-time login code over email. Therefore, email deliverability is very important. Users using this method should whitelist the address from which the codes are sent. By default, this is the email address configured in your WordPress. You can run an email test from the plugin\'s settings to confirm email deliverability. If you have had email deliverability / reliability issues, we highly recommend you to install the free plugin ', 'wp-2fa' ) . '<a href="https://wordpress.org/plugins/wp-mail-smtp/" target="_blank" rel="nofollow">WP Mail SMTP</a><br><br>' . esc_html__( 'Allowing users to set up a secondary 2FA method is highly recommended. You can do this in the next step of the wizard. This will allow users to log in using an alternative method should they, for example lose access to their phone.', 'wp-2fa' ) . '</p>';
191 }
192 ?>
193 <?php
194 if ( null !== $role ) {
195 $enabled_settings = Role_Settings_Controller::get_setting( $role, 'enable_email' );
196 } else {
197 $enabled_settings = Settings::get_role_or_default_setting( 'enable_email', ( ( null !== $role && '' !== $role ) ? '' : false ), $role, true, true );
198 }
199 ?>
200 <?php
201 ?>
202 <?php if ( ! $setup_wizard ) { ?>
203 <div class="use-different-hotp-mail<?php echo \esc_attr( ( false === $enabled_settings ? ' disabled' : '' ) ); ?>">
204 <p class="description">
205 <?php esc_html_e( 'Allow user to specify the email address of choice', 'wp-2fa' ); ?>
206 </p>
207 <fieldset class="email-hotp-options">
208 <?php
209 $options = array(
210 'yes' => array(
211 'label' => esc_html__( 'Yes', 'wp-2fa' ),
212 'value' => 'specify-email_hotp',
213 ),
214 'no' => array(
215 'label' => esc_html__( 'No', 'wp-2fa' ),
216 'value' => '',
217 ),
218 );
219
220 foreach ( $options as $option_key => $option_settings ) {
221 ?>
222 <label for="specify-email_hotp-<?php echo \esc_attr( $option_key ); ?>">
223 <input type="radio"
224 name="<?php echo \esc_attr( $name_prefix ); ?>[specify-email_hotp]"
225 <?php echo $data_role; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
226 id="specify-email_hotp-<?php echo \esc_attr( $option_key ); ?>"
227 value="<?php echo \esc_attr( $option_settings['value'] ); ?>" class="js-nested"
228 <?php if ( null !== $role ) { ?>
229 <?php checked( Role_Settings_Controller::get_setting( $role, 'specify-email_hotp' ), $option_settings['value'] ); ?>
230 <?php
231 } else {
232
233 $use_role_setting = null;
234 if ( null === $role || '' === trim( (string) $role ) ) {
235 $use_role_setting = \WP_2FA_PREFIX . 'no-user';
236 }
237
238 checked( Settings::get_role_or_default_setting( 'specify-email_hotp', $use_role_setting, $role, true, false ), $option_settings['value'] );
239 ?>
240 <?php } ?>
241 >
242 <span><?php echo $option_settings['label']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
243 </label>
244 <?php
245 }
246 ?>
247 </fieldset>
248 </div>
249 <?php } ?>
250 </div>
251 <?php
252 $output = ob_get_contents();
253 ob_end_clean();
254
255 $methods[ self::get_order( $role, $methods ) ] = $output;
256
257 return $methods;
258 }
259
260 /**
261 * Reconfigures email form
262 *
263 * @since 2.6.0
264 *
265 * @return void
266 */
267 public static function email_modal_configure() {
268
269 if ( ! Email::is_enabled() ) {
270 return;
271 }
272 ?>
273 <div class="wizard-step" id="2fa-wizard-email">
274 <fieldset>
275 <div class="step-setting-wrapper active">
276 <div class="mb-20">
277 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'method_help_hotp_intro', true ) ); ?>
278 </div>
279 <fieldset class="radio-cells">
280 <div class="option-pill">
281 <label for="use_wp_email">
282 <input type="radio" name="wp_2fa_email_address" id="use_wp_email" value="<?php echo esc_attr( User_Helper::get_user_object()->user_email ); ?>" checked>
283 <span><?php esc_html_e( 'Use my user email (', 'wp-2fa' ); ?><small><?php echo esc_attr( User_Helper::get_user_object()->user_email ); ?></small><?php esc_html_e( ')', 'wp-2fa' ); ?></span>
284 </label>
285 </div>
286 <?php
287 if ( Settings::get_role_or_default_setting( 'specify-email_hotp', User_Helper::get_user_object() ) ) {
288 ?>
289 <div class="option-pill">
290 <label for="use_custom_email">
291 <input type="radio" name="wp_2fa_email_address" id="use_custom_email" value="use_custom_email">
292 <span><?php esc_html_e( 'Use a different email address:', 'wp-2fa' ); ?></span>
293 <?php esc_html_e( 'Email address', 'wp-2fa' ); ?>
294 <input type="email" name="custom-email-address" id="custom-email-address" class="input" value=""/>
295 </label>
296 </div>
297 <?php
298 }
299 ?>
300 </fieldset>
301 <p class="description"><?php esc_html_e( 'To complete the 2FA configuration you will be sent a one-time code over email, therefore you should have access to the mailbox of this email address. If you do not receive the email with the one-time code please check your spam folder and contact your administrator.', 'wp-2fa' ); ?></p><br>
302
303 <?php
304 $from_email = get_option( 'admin_email' );
305
306 $custom_mail = WP2FA::get_wp2fa_email_templates( 'custom_from_email_address' );
307
308 if ( isset( $custom_mail ) && ! empty( (string) $custom_mail ) ) {
309 $from_email = $custom_mail;
310 }
311 printf(
312 '<b>%1$1s</b> %2$1s %3$1s',
313 esc_html__( 'IMPORTANT: ', 'wp-2fa' ),
314 esc_html__( 'To ensure you always receive the one-time code whitelist the email address from which the codes are sent. This is ', 'wp-2fa' ),
315 esc_attr( $from_email )
316 );
317 ?>
318
319 <div class="wp2fa-setup-actions">
320 <button class="button button-primary wp-2fa-button-primary" name="next_step_setting_email_verify" value="<?php esc_attr_e( 'I\'m Ready', 'wp-2fa' ); ?>" data-trigger-setup-email data-user-id="<?php echo esc_attr( User_Helper::get_user_object()->ID ); ?>" <?php echo WP_Helper::create_data_nonce( 'wp-2fa-send-setup-email' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> type="button"><?php esc_html_e( 'I\'m Ready', 'wp-2fa' ); ?></button>
321 <a class="button button-primary wp-2fa-button-primary modal_cancel"><?php esc_attr_e( 'Cancel', 'wp-2fa' ); ?></a>
322 </div>
323 </div>
324
325 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Verify configuration', 'wp-2fa' ); ?>" id="2fa-wizard-email">
326 <div class="mb-20">
327 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'method_verification_hotp_pre', true ) ); ?>
328 </div>
329 <fieldset>
330 <label for="2fa-email-authcode">
331 <?php esc_html_e( 'Authentication Code', 'wp-2fa' ); ?>
332 <input type="tel" name="wp-2fa-email-authcode" id="wp-2fa-email-authcode" class="input" value="" size="20" pattern="[0-9]*" autocomplete="off"/>
333 <script>
334 const email_authcode = document.getElementById('wp-2fa-email-authcode');
335 email_authcode.addEventListener('input', function() {
336 this.value = this.value.trim();
337 });
338 </script>
339 </label>
340 <div class="verification-response"></div>
341 </fieldset>
342 <br />
343 <a href="#" class="button wp-2fa-button-primary" data-validate-authcode-ajax <?php echo WP_Helper::create_data_nonce( 'wp-2fa-validate-authcode' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>><?php esc_html_e( 'Validate & Save', 'wp-2fa' ); ?></a>
344 <a href="#" class="button wp-2fa-button-primary resend-email-code" data-trigger-setup-email data-user-id="<?php echo esc_attr( User_Helper::get_user_object()->ID ); ?>" <?php echo WP_Helper::create_data_nonce( 'wp-2fa-send-setup-email' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
345 <span class="resend-inner"><?php esc_html_e( 'Send me another code', 'wp-2fa' ); ?></span>
346 </a>
347 <button class="wp-2fa-button-secondary button" data-close-2fa-modal aria-label="Close this dialog window"><?php esc_html_e( 'Cancel', 'wp-2fa' ); ?></button>
348 </div>
349 </fieldset>
350 </div>
351 <?php
352 }
353 }
354 }