WordPress.org

Making WordPress.org


Ignore:
Timestamp:
02/25/2018 04:46:39 AM (3 years ago)
Author:
obenland
Message:

2FA: First pass at new user edit UI.

Needs more work around changing devices, backup codes, and (possibly) application passwords.

See #77.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-two-factor/wporg-two-factor.php

    r6735 r6737  
    1414    public function __construct() {
    1515        add_filter( 'two_factor_providers', [ $this, 'two_factor_providers' ] );
     16
     17        remove_action( 'edit_user_profile', [ 'Two_Factor_Core', 'user_two_factor_options' ] );
     18        remove_action( 'show_user_profile', [ 'Two_Factor_Core', 'user_two_factor_options' ] );
     19
     20        if ( ! is_admin() ) {
     21            add_action( 'edit_user_profile', [ $this, 'user_two_factor_options' ] );
     22            add_action( 'show_user_profile', [ $this, 'user_two_factor_options' ] );
     23        }
     24
     25        add_action( 'wp_ajax_two-factor-totp-verify-code',[ $this, 'ajax_verify_code' ] );
     26        add_action( 'wp_ajax_two-factor-disable',[ $this, 'ajax_disable' ] );
    1627    }
    1728
     
    3142        return $wporg_providers;
    3243    }
     44
     45    /**
     46     * Displays the UI to set up and remove 2FA.
     47     *
     48     * @param \WP_User $user User object.
     49     */
     50    public function user_two_factor_options( $user ) {
     51        wp_enqueue_script( 'two-factor-edit', plugins_url( 'js/profile-edit.js' , __FILE__ ), [ 'jquery' ], 1, true );
     52
     53        $key       = get_user_meta( $user->ID, Two_Factor_Totp::SECRET_META_KEY, true );
     54        $is_active = !! $key;
     55        ?>
     56
     57        <h2 class="entry-title"><?php esc_html_e( 'Two Factor Authentication', 'wporg' ); ?></h2>
     58        <?php Two_Factor_Totp::admin_notices(); ?>
     59        <fieldset id="two-factor-active" class="bbp-form two-factor" <?php if ( ! $is_active ) { echo 'style="display:none;"'; } ?>>
     60            <legend><?php esc_html_e( 'Two Factor Authentication', 'wporg' ); ?></legend>
     61            <div><?php echo wp_kses_post( __( '<strong>Status:</strong> Two Factor Authentication is currently <span>ACTIVE</span>.', 'wporg' ) ); ?></div>
     62            <div><?php esc_html_e( 'While enabled, logging in to WordPress.org requires you to enter a unique passcode, generated by an app on your mobile device, in addition to your username and password.', 'wporg' ); ?></div>
     63            <div><?php esc_html_e( 'Switching to a new device? Follow these steps to avoid losing access to your account.', 'wporg' ); ?></div>
     64            <div><button type="cancel" class="button button-secondary alignright"><?php esc_html_e( 'Disable Two Factor Authentication', 'wporg' ); ?></button></div>
     65        </fieldset>
     66        <?php
     67        if ( empty( $key ) ) {
     68            $key = Two_Factor_Totp::generate_key();
     69        }
     70
     71        wp_nonce_field( 'user_two_factor_totp_options', '_nonce_user_two_factor_totp_options' );
     72        ?>
     73        <fieldset id="two-factor-start" class="bbp-form two-factor" <?php if ( $is_active ) { echo 'style="display:none;"'; } ?>>
     74            <legend><?php esc_html_e( 'Two Factor Authentication', 'wporg' ); ?></legend>
     75            <div><?php esc_html_e( 'Two-Step Authentication adds an extra layer of security to your account. Once enabled, logging in to WordPress.org will require you to enter a unique passcode generated by an app on your mobile device, in addition to your username and password.', 'wporg' ); ?></div>
     76            <div><button type="button" id="two-factor-start-toggle" class="button button-primary"><?php esc_html_e( 'Get Started', 'wporg' ); ?></button></div>
     77        </fieldset>
     78
     79        <fieldset id="two-factor-qr-code" class="bbp-form two-factor" style="display: none;">
     80            <legend><?php esc_html_e( 'Two Factor Authentication', 'wporg' ); ?></legend>
     81            <div>
     82                <p><?php esc_html_e( 'Scan this QR code with your mobile app.', 'wporg' ); ?></p>
     83                <p><button type="button" class="button-link"><?php esc_html_e( 'Can&#8217;t scan the code?', 'wporg' ); ?></button></p>
     84                <img src="<?php echo esc_url( Two_Factor_Totp::get_google_qr_code( 'wordpress.org:' . $user->user_login, $key, 'wordpress.org' ) ); ?>" id="two-factor-totp-qrcode" />
     85                <p><?php esc_html_e( 'Then enter the authentication code provided by the app:', 'wporg' ); ?></p>
     86                <p>
     87                    <label class="screen-reader-text" for="two-factor-totp-authcode"><?php esc_html_e( 'Authentication Code:', 'wporg' ); ?></label>
     88                    <input type="hidden" name="two-factor-totp-key" value="<?php echo esc_attr( $key ) ?>" />
     89                    <input type="tel" name="two-factor-totp-authcode" class="input" value="" size="20" pattern="[0-9]*" placeholder="<?php esc_attr_e( 'e.g. 123456', 'wporg' ); ?>" />
     90                </p>
     91                <button type="cancel" class="button button-secondary alignleft"><?php esc_html_e( 'Cancel', 'wporg' ); ?></button>
     92                <button type="submit" class="button button-primary alignright"><?php esc_html_e( 'Enable', 'wporg' ); ?></button>
     93            </div>
     94        </fieldset>
     95
     96        <fieldset id="two-factor-key-code" class="bbp-form two-factor" style="display: none;">
     97            <legend><?php esc_html_e( 'Two Factor Authentication', 'wporg' ); ?></legend>
     98            <div>
     99                <p><?php esc_html_e( 'Enter this time code into your mobile app.', 'wporg' ); ?></p>
     100                <p><button type="button" class="button-link"><?php esc_html_e( 'Prefer to scan the code?', 'wporg' ); ?></button></p>
     101                <p class="key"><strong><?php echo esc_html( $key ); ?></strong></p>
     102                <p><?php esc_html_e( 'Then enter the authentication code provided by the app:', 'wporg' ); ?></p>
     103                <p>
     104                    <label class="screen-reader-text" for="two-factor-totp-authcode"><?php esc_html_e( 'Authentication Code:', 'wporg' ); ?></label>
     105                    <input type="hidden" name="two-factor-totp-key" value="<?php echo esc_attr( $key ) ?>" />
     106                    <input type="tel" name="two-factor-totp-authcode" class="input" value="" size="20" pattern="[0-9]*" placeholder="<?php esc_attr_e( 'e.g. 123456', 'wporg' ); ?>" />
     107                </p>
     108                <button type="cancel" class="button button-secondary alignleft"><?php esc_html_e( 'Cancel', 'wporg' ); ?></button>
     109                <button type="submit" class="button button-primary alignright"><?php esc_html_e( 'Enable', 'wporg' ); ?></button>
     110            </div>
     111        </fieldset>
     112
     113        <style>
     114            #bbpress-forums fieldset.two-factor:not(#two-factor-start) > div {
     115                margin-left: 20%;
     116                width: 60% !important;
     117            }
     118            #bbpress-forums .two-factor button.button-link {
     119                color: #4ca6cf;
     120                padding: 0;
     121            }
     122            #bbpress-forums .two-factor .key {
     123                padding: 2rem 0;
     124            }
     125        </style>
     126
     127        <?php
     128    }
     129
     130    /**
     131     * AJAX handler to verify a user's 2FA code.
     132     */
     133    public function ajax_verify_code() {
     134        check_ajax_referer( 'user_two_factor_totp_options', '_nonce_user_two_factor_totp_options' );
     135
     136        $user_id = absint( $_POST['user_id'] );
     137        if ( ! current_user_can( 'edit_user', $user_id ) ) {
     138            wp_send_json_error( __( 'You do not have permission to edit this user.' ) );
     139        }
     140
     141        if ( empty( $_POST['authcode'] ) ) {
     142            wp_send_json_error( __( 'Please enter a valid authorization code.' ) );
     143        }
     144
     145        if ( Two_Factor_Totp::is_valid_authcode( $_POST['key'], $_POST['authcode'] ) ) {
     146            if ( ! update_user_meta( $user_id, Two_Factor_Totp::SECRET_META_KEY, $_POST['key'] ) ) {
     147                wp_send_json_error( __( 'Unable to save Two Factor Authentication code. Please try again.', 'wporg' ) );
     148            }
     149
     150            wp_send_json_success();
     151        }
     152
     153        wp_send_json_error( __( 'The authentication code you entered was not valid. Please try again.', 'wporg' ) );
     154    }
     155
     156    /**
     157     * AJAX handler to disable 2FA.
     158     */
     159    public function ajax_disable() {
     160        check_ajax_referer( 'user_two_factor_totp_options', '_nonce_user_two_factor_totp_options' );
     161
     162        $user_id = absint( $_POST['user_id'] );
     163        if ( ! current_user_can( 'edit_user', $user_id ) ) {
     164            wp_send_json_error( __( 'You do not have permission to edit this user.' ) );
     165        };
     166
     167        if ( ! delete_user_meta( $user_id, Two_Factor_Totp::SECRET_META_KEY ) ) {
     168            wp_send_json_error( __( 'Unable to remove Two Factor Authentication code. Please try again.', 'wporg' ) );
     169        }
     170
     171        if ( ! update_user_meta( $user_id, Two_Factor_Core::ENABLED_PROVIDERS_USER_META_KEY, [] ) ) {
     172            wp_send_json_error( __( 'Unable to remove Two Factor Authentication code. Please try again.', 'wporg' ) );
     173        }
     174
     175        wp_send_json_success( __( 'Two Factor authentication disabled. Your account is now less secure.', 'wporg' ) );
     176    }
    33177}
    34178new WPORG_Two_Factor();
Note: See TracChangeset for help on using the changeset viewer.