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 | } |