You are here

class TfaTotpSetup in TFA Basic plugins 7

Class TfaTotpSetup

Hierarchy

Expanded class hierarchy of TfaTotpSetup

File

includes/tfa_totp.inc, line 173
classes for tfa_totp

View source
class TfaTotpSetup extends TfaTotp implements TfaSetupPluginInterface {

  /**
   * @var string Un-encrypted seed.
   */
  protected $seed;

  /**
   * @var string
   */
  protected $namePrefix;

  /**
   * @copydoc TfaBasePlugin::__construct()
   */
  public function __construct(array $context) {
    parent::__construct($context);

    // Generate seed.
    $this->seed = $this
      ->createSeed();
    $this->namePrefix = variable_get('tfa_basic_name_prefix', variable_get('site_name', 'Drupal'));
  }

  /**
   * @copydoc TfaSetupPluginInterface::getSetupForm()
   */
  public function getSetupForm(array $form, array &$form_state) {
    $items = array(
      l('Google Authenticator (Android/iPhone/BlackBerry)', 'https://support.google.com/accounts/answer/1066447?hl=en', array(
        'attributes' => array(
          'target' => '_blank',
        ),
      )),
      l('Authy (Android/iPhone)', 'https://www.authy.com/app/', array(
        'attributes' => array(
          'target' => '_blank',
        ),
      )),
      l('Authenticator (Windows Phone)', 'http://www.windowsphone.com/en-us/store/app/authenticator/021dd79f-0598-e011-986b-78e7d1fa76f8', array(
        'attributes' => array(
          'target' => '_blank',
        ),
      )),
      l('FreeOTP (Android)', 'https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp', array(
        'attributes' => array(
          'target' => '_blank',
        ),
      )),
      l('GAuth Authenticator (Firefox OS, desktop, others)', 'https://github.com/gbraad/gauth', array(
        'attributes' => array(
          'target' => '_blank',
        ),
      )),
    );
    $form['apps'] = array(
      '#type' => 'markup',
      '#markup' => theme('item_list', array(
        'items' => $items,
        'title' => t('Install authentication code application on your mobile or desktop device:'),
      )),
    );
    $form['info'] = array(
      '#type' => 'markup',
      '#markup' => t('<p>The two-factor authentication application will be used during this setup and for generating codes during regular authentication. If the application supports it, scan the QR code below to get the setup code otherwise you can manually enter the text code.</p>'),
    );
    $form['seed'] = array(
      '#type' => 'textfield',
      '#value' => $this->seed,
      '#disabled' => TRUE,
      '#allow_focus' => TRUE,
      '#description' => t('Enter this code into your two-factor authentication app or scan the QR code below.'),
    );

    // QR image of seed.
    if (file_exists(drupal_get_path('module', 'tfa_basic') . '/includes/qrcodejs/qrcode.min.js')) {
      $form['qr_image_wrapper']['qr_image'] = array(
        '#markup' => '<div id="tfa-qrcode"></div>',
      );
      $qrdata = 'otpauth://totp/' . $this
        ->accountName() . '?secret=' . $this->seed;
      $form['qr_image_wrapper']['qr_image']['#attached']['library'][] = array(
        'tfa_basic',
        'qrcodejs',
      );
      $form['qr_image_wrapper']['qr_image']['#attached']['js'][] = array(
        'data' => 'jQuery(document).ready(function () { new QRCode(document.getElementById("tfa-qrcode"), "' . $qrdata . '");});',
        'type' => 'inline',
        'scope' => 'footer',
        'weight' => 5,
      );
    }
    else {
      $form['qr_image'] = array(
        '#markup' => '<img src="' . $this
          ->getQrCodeUrl($this->seed) . '" alt="QR code for TFA setup">',
      );
    }

    // Include code entry form.
    $form = $this
      ->getForm($form, $form_state);
    $form['actions']['login']['#value'] = t('Verify and save');

    // Alter code description.
    $form['code']['#description'] = t('A verification code will be generated after you scan the above QR code or manually enter the setup code. The verification code is six digits long.');
    return $form;
  }

  /**
   * @copydoc TfaSetupPluginInterface::validateSetupForm()
   */
  public function validateSetupForm(array $form, array &$form_state) {
    if (!$this
      ->validate($form_state['values']['code'])) {
      $this->errorMessages['code'] = t('Invalid application code. Please try again.');
      return FALSE;
    }
    else {
      return TRUE;
    }
  }

  /**
   * @copydoc TfaBasePlugin::validate()
   */
  protected function validate($code) {
    return $this->ga
      ->verifyCode($this->seed, $code, $this->timeSkew);
  }

  /**
   * @copydoc TfaSetupPluginInterface::submitSetupForm()
   */
  public function submitSetupForm(array $form, array &$form_state) {

    // Write seed for user.
    $this
      ->storeSeed($this->seed);
    return TRUE;
  }

  /**
   * Get a URL to a Google Chart QR image for a seed.
   *
   * @param string $seed
   * @return string URL
   */
  protected function getQrCodeUrl($seed) {

    // Note, this URL is over https but does leak the seed and account
    // email address to Google. See README.txt for local QR code generation
    // using qrcode.js.
    return $this->ga
      ->getQRCodeGoogleUrl($this
      ->accountName(), $seed);
  }

  /**
   * Create OTP seed for account.
   *
   * @return string Seed.
   */
  protected function createSeed() {
    return $this->ga
      ->createSecret(24);
  }

  /**
   * Save seed for account.
   *
   * @param string $seed Seed.
   */
  protected function storeSeed($seed) {

    // Encrypt seed for storage.
    $encrypted = $this
      ->encrypt($seed);

    // Data is binary so store base64 encoded.
    $record = array(
      'uid' => $this->context['uid'],
      'seed' => base64_encode($encrypted),
      'created' => REQUEST_TIME,
    );
    $existing = $this
      ->getSeed();
    if (!empty($existing)) {

      // Update existing seed.
      drupal_write_record('tfa_totp_seed', $record, 'uid');
    }
    else {
      drupal_write_record('tfa_totp_seed', $record);
    }
  }

  /**
   * Get account name for QR image.
   *
   * @return string URL encoded string.
   */
  protected function accountName() {
    $account = user_load($this->context['uid']);
    return urlencode($this->namePrefix . '-' . $account->name);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
TfaBasePlugin::$code protected property TFA code.
TfaBasePlugin::$codeLength protected property Code Length.
TfaBasePlugin::$context protected property Context of current TFA process.
TfaBasePlugin::$encryptionKey protected property Encryption key.
TfaBasePlugin::$errorMessages protected property Error messages.
TfaBasePlugin::$isValid protected property Code is valid.
TfaBasePlugin::CRYPT_VERSION constant
TfaBasePlugin::decrypt protected function Decrypt a encrypted string.
TfaBasePlugin::decryptLegacyDataWithMcrypt protected function Decrypt using the deprecated Mcrypt extension.
TfaBasePlugin::decryptLegacyDataWithOpenSSL protected function Use OpenSSL to decrypt data that was originally encrypted with Mcrypt.
TfaBasePlugin::encrypt protected function Encrypt a plaintext string.
TfaBasePlugin::encryptWithMcrypt protected function Encrypt using the deprecated Mcrypt extension.
TfaBasePlugin::generate protected function Generate a random string of characters of length $this->codeLength.
TfaBasePlugin::getErrorMessages public function Get error messages suitable for form_set_error().
TfaBasePlugin::submitForm public function Submit form. 1
TfaBasePlugin::timingSafeEquals private function A timing safe equals comparison.
TfaTotp::$alreadyAccepted protected property
TfaTotp::$ga protected property
TfaTotp::$timeSkew protected property
TfaTotp::alreadyAcceptedCode protected function Whether code has recently been accepted.
TfaTotp::deleteSeed public function Delete users seeds.
TfaTotp::getForm public function @copydoc TfaValidationPluginInterface::getForm() Overrides TfaValidationPluginInterface::getForm
TfaTotp::getSeed protected function Get seed for this account.
TfaTotp::ready public function @copydoc TfaBasePlugin::ready() Overrides TfaBasePlugin::ready
TfaTotp::storeAcceptedCode protected function
TfaTotp::validateForm public function @copydoc TfaValidationPluginInterface::validateForm() Overrides TfaValidationPluginInterface::validateForm
TfaTotpSetup::$namePrefix protected property
TfaTotpSetup::$seed protected property
TfaTotpSetup::accountName protected function Get account name for QR image.
TfaTotpSetup::createSeed protected function Create OTP seed for account.
TfaTotpSetup::getQrCodeUrl protected function Get a URL to a Google Chart QR image for a seed.
TfaTotpSetup::getSetupForm public function @copydoc TfaSetupPluginInterface::getSetupForm() Overrides TfaSetupPluginInterface::getSetupForm
TfaTotpSetup::storeSeed protected function Save seed for account.
TfaTotpSetup::submitSetupForm public function @copydoc TfaSetupPluginInterface::submitSetupForm() Overrides TfaSetupPluginInterface::submitSetupForm
TfaTotpSetup::validate protected function @copydoc TfaBasePlugin::validate() Overrides TfaTotp::validate
TfaTotpSetup::validateSetupForm public function @copydoc TfaSetupPluginInterface::validateSetupForm() Overrides TfaSetupPluginInterface::validateSetupForm
TfaTotpSetup::__construct public function @copydoc TfaBasePlugin::__construct() Overrides TfaTotp::__construct