Making WordPress.org


Ignore:
Timestamp:
02/26/2018 07:06:12 AM (7 years ago)
Author:
dd32
Message:

2FA: Enable Email, Slack, and Backup Codes as the backup 2FA method.

See #77.

File:
1 edited

Legend:

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

    r6753 r6759  
    11<?php
    22
    3 require_once __DIR__ . '/class-wporg-two-factor-backup-codes.php';
    4 
    5 class WPORG_Two_Factor_Secondary extends WPORG_Two_Factor_Backup_Codes { // Temporarily
    6 // class WPORG_Two_Factor_Secondary extends Two_Factor_Provider { // When it's a proper wrapper.
     3class WPORG_Two_Factor_Secondary extends Two_Factor_Provider { // When it's a proper wrapper.
    74
    85    /**
     
    2421    }
    2522
    26     // protected $providers = [];
     23    public function authentication_page( $user ) {
     24        if ( ! $user ) {
     25            return;
     26        }
     27
     28        $this->send_codes_to_user( $user );
     29
     30        require_once( ABSPATH . '/wp-admin/includes/template.php' );
     31
     32        $email_enabled = isset( $this->providers['WPORG_Two_Factor_Email'] ) && $this->providers['WPORG_Two_Factor_Email']->is_available_for_user( $user );
     33        $slack_enabled = isset( $this->providers['WPORG_Two_Factor_Slack'] ) && $this->providers['WPORG_Two_Factor_Slack']->is_available_for_user( $user );
     34
     35        if ( $email_enabled && $slack_enabled ) {
     36            echo '<p>' . __( 'Enter the verification code sent to your Email, Slack, or a printed backup code.', 'wporg' ) . '</p>';
     37        } elseif ( $email_enabled ) {
     38            echo '<p>' . __( 'Enter the verification code sent to your Email, or a printed backup code.', 'wporg' ) . '</p>';
     39        } else {
     40            echo '<p>' . __( 'Enter a printed backup code.', 'wporg' ) . '</p>';
     41        }
     42        ?>
     43
     44        <p>
     45            <label for="authcode"><?php esc_html_e( 'Verification Code:', 'wporg' ); ?></label>
     46            <input type="tel" name="two-factor-backup-code" id="authcode" class="input" value="" size="20" pattern="[0-9]*" />
     47            <?php submit_button( __( 'Authenticate', 'wporg' ) ); ?>
     48        </p>
     49
     50        <?php if ( $email_enabled || $slack_enabled ) { ?>
     51            <p class="two-factor-email-resend">
     52                <input type="submit" class="button" name="two-factor-backup-resend" value="<?php esc_attr_e( 'Resend Code', 'wporg' ); ?>" />
     53            </p>
     54        <?php } ?>
     55
     56        <script type="text/javascript">
     57            setTimeout( function(){
     58                var d;
     59                try{
     60                    d = document.getElementById('authcode');
     61                    d.value = '';
     62                    d.focus();
     63                } catch(e){}
     64            }, 200);
     65        </script>
     66        <?php
     67    }
     68
     69    function is_available_for_user( $user ) { return true; }
     70
     71    protected $providers = [];
    2772
    2873    protected function __construct() {
    29         /*
    3074        $providers = [
    3175            'WPORG_Two_Factor_Email'        => __DIR__ . '/class-wporg-two-factor-email.php',
    3276            'WPORG_Two_Factor_Backup_Codes' => __DIR__ . '/class-wporg-two-factor-backup-codes.php',
    3377            'WPORG_Two_Factor_Slack'        => __DIR__ . '/class-wporg-two-factor-slack.php'
     78        ];
     79        $providers = apply_filters( 'wporg_two_factor_secondary_providers', $providers );
    3480
    35         ];
    36         */
     81        // Add some CSS for this clss.
     82        add_action( 'login_head', [ $this, 'add_styles' ] );
     83
     84        foreach ( $providers as $class => $path ) {
     85            include_once( $path );
     86
     87            if ( class_exists( $class ) ) {
     88                try {
     89                    $this->providers[ $class ] = call_user_func( array( $class, 'get_instance' ) );
     90                } catch ( Exception $e ) {
     91                    unset( $this->providers[ $class ] );
     92                }
     93            }
     94        }
     95
    3796        return parent::__construct();
    3897    }
     98
     99    // Add some specific styles for this class.
     100    public function add_styles() {
     101        if ( isset( $_GET['provider'] ) && $_GET['provider'] === __CLASS__ ) {
     102            echo '<style>
     103                body.login-action-backup_2fa .backup-methods-wrap {
     104                    display: none;
     105                }
     106                body.login-action-backup_2fa input[name="two-factor-backup-resend"] {
     107
     108                }
     109            </style>';
     110        }
     111    }
     112
     113    public function pre_process_authentication( $user ) {
     114        if ( isset( $_REQUEST['two-factor-backup-resend'] ) ) {
     115            return $this->send_codes_to_user( $user, true );
     116        }
     117
     118        return false;
     119    }
     120
     121    // Send codes to the user based on the providers available.
     122    //
     123    protected function send_codes_to_user( $user, $resend = false ) {
     124        $result = false;
     125
     126        if (
     127            isset( $this->providers['WPORG_Two_Factor_Email'] ) &&
     128            $this->providers['WPORG_Two_Factor_Email']->is_available_for_user( $user )
     129        ) {
     130            if (
     131                $resend |
     132                ! $this->providers['WPORG_Two_Factor_Email']->user_has_token( $user->ID )
     133            ) {
     134                $result = true;
     135                $this->providers['WPORG_Two_Factor_Email']->generate_and_email_token( $user );
     136            }
     137        }
     138
     139        if (
     140            isset( $this->providers['WPORG_Two_Factor_Slack'] ) &&
     141            $this->providers['WPORG_Two_Factor_Slack']->is_available_for_user( $user )
     142        ) {
     143            if (
     144                $resend ||
     145                ! $this->providers['WPORG_Two_Factor_Slack']->user_has_token( $user->ID )
     146            ) {
     147                $result = true;
     148                $this->providers['WPORG_Two_Factor_Slack']->generate_and_slack_token( $user );
     149            }
     150        }
     151
     152        return $result;
     153    }
     154
     155    function validate_authentication( $user ) {
     156        if ( empty( $_POST['two-factor-backup-code'] ) ) {
     157            return false;
     158        }
     159
     160        $backup_code = $_POST['two-factor-backup-code'];
     161
     162        $authenticated = false;
     163
     164        foreach ( $this->providers as $provider ) {
     165            if (
     166                $provider->is_available_for_user( $user ) &&
     167                $provider->validate_authentication( $user, $backup_code )
     168            ) {
     169                $authenticated = true;
     170                break;
     171            }
     172        }
     173
     174        // Also check the Primary method for the user just in case.
     175        $primary_provider = WPORG_Two_Factor_Primary::get_instance();
     176        if (
     177            ! $authenticated &&
     178            $primary_provider->is_available_for_user( $user ) &&
     179            $primary_provider->validate_authentication( $user, $backup_code )
     180        ) {
     181            $authenticated = true;
     182        }
     183
     184        if ( $authenticated ) {
     185            foreach ( $this->providers as $provider ) {
     186                if ( is_callable( [ $provider, 'delete_token' ] ) ) {
     187                    $provider->delete_token( $user->ID );
     188                }
     189            }
     190        }
     191
     192        return $authenticated;
     193    }
    39194}
Note: See TracChangeset for help on using the changeset viewer.