class TfaTotp in TFA Basic plugins 7
Class TfaTotp
Hierarchy
- class \TfaBasePlugin
- class \TfaTotp implements TfaValidationPluginInterface
Expanded class hierarchy of TfaTotp
1 string reference to 'TfaTotp'
- tfa_basic_tfa_api in ./
tfa_basic.module - Implements hook_tfa_api().
File
- includes/
tfa_totp.inc, line 10 - classes for tfa_totp
View source
class TfaTotp extends TfaBasePlugin implements TfaValidationPluginInterface {
/**
* @var PHPGangsta_GoogleAuthenticator
*/
protected $ga;
/**
* @var int
*/
protected $timeSkew;
/**
* @var bool
*/
protected $alreadyAccepted;
/**
* @copydoc TfaBasePlugin::__construct()
*/
public function __construct(array $context) {
parent::__construct($context);
$this->ga = new PHPGangsta_GoogleAuthenticator();
// Allow codes within tolerance range of 3 * 30 second units.
$this->timeSkew = variable_get('tfa_basic_time_skew', 3);
// Recommended: set variable tfa_totp_secret_key in settings.php.
$this->encryptionKey = variable_get('tfa_basic_secret_key', drupal_get_private_key());
$this->alreadyAccepted = FALSE;
}
/**
* @copydoc TfaBasePlugin::ready()
*/
public function ready() {
return $this
->getSeed() !== FALSE;
}
/**
* @copydoc TfaValidationPluginInterface::getForm()
*/
public function getForm(array $form, array &$form_state) {
$form['code'] = array(
'#type' => 'textfield',
'#title' => t('Application verification code'),
'#description' => t('Verification code is application generated and !length digits long.', array(
'!length' => $this->codeLength,
)),
'#required' => TRUE,
'#attributes' => array(
'autocomplete' => 'off',
),
);
if (module_exists('elements')) {
$form['code']['#type'] = 'numberfield';
}
$form['actions']['#type'] = 'actions';
$form['actions']['login'] = array(
'#type' => 'submit',
'#value' => t('Verify'),
);
return $form;
}
/**
* @copydoc TfaValidationPluginInterface::validateForm()
*/
public function validateForm(array $form, array &$form_state) {
if (!$this
->validate($form_state['values']['code'])) {
$this->errorMessages['code'] = t('Invalid application code. Please try again.');
if ($this->alreadyAccepted) {
$this->errorMessages['code'] = t('Invalid code, it was recently used for a login. Please wait for the application to generate a new code.');
}
return FALSE;
}
else {
// Store accepted code to prevent replay attacks.
$this
->storeAcceptedCode($form_state['values']['code']);
return TRUE;
}
}
/**
* @copydoc TfaBasePlugin::validate()
*/
protected function validate($code) {
// Strip whitespace.
$code = preg_replace('/\\s+/', '', $code);
if ($this
->alreadyAcceptedCode($code)) {
$this->isValid = FALSE;
}
else {
// Get OTP seed.
$seed = $this
->getSeed();
$this->isValid = $seed && $this->ga
->verifyCode($seed, $code, $this->timeSkew);
}
return $this->isValid;
}
/**
* @param string $code
*/
protected function storeAcceptedCode($code) {
$code = preg_replace('/\\s+/', '', $code);
$hash = hash('sha1', drupal_get_hash_salt() . $code);
db_insert('tfa_accepted_code')
->fields(array(
'uid' => $this->context['uid'],
'code_hash' => $hash,
'time_accepted' => REQUEST_TIME,
))
->execute();
}
/**
* Whether code has recently been accepted.
*
* @param string $code
* @return bool
*/
protected function alreadyAcceptedCode($code) {
$hash = hash('sha1', drupal_get_hash_salt() . $code);
$result = db_query("SELECT code_hash FROM {tfa_accepted_code} WHERE uid = :uid AND code_hash = :code", array(
':uid' => $this->context['uid'],
':code' => $hash,
))
->fetchAssoc();
if (!empty($result)) {
$this->alreadyAccepted = TRUE;
return TRUE;
}
return FALSE;
}
/**
* Get seed for this account.
*
* @return string Decrypted account OTP seed or FALSE if none exists.
*/
protected function getSeed() {
// Lookup seed for account and decrypt.
$result = db_query("SELECT seed FROM {tfa_totp_seed} WHERE uid = :uid", array(
':uid' => $this->context['uid'],
))
->fetchAssoc();
if (!empty($result)) {
$encrypted = base64_decode($result['seed']);
$seed = $this
->decrypt($encrypted);
if (!empty($seed)) {
return $seed;
}
}
return FALSE;
}
/**
* Delete users seeds.
*
* @return int
*/
public function deleteSeed() {
$query = db_delete('tfa_totp_seed')
->condition('uid', $this->context['uid']);
return $query
->execute();
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
TfaBasePlugin:: |
protected | property | TFA code. | |
TfaBasePlugin:: |
protected | property | Code Length. | |
TfaBasePlugin:: |
protected | property | Context of current TFA process. | |
TfaBasePlugin:: |
protected | property | Encryption key. | |
TfaBasePlugin:: |
protected | property | Error messages. | |
TfaBasePlugin:: |
protected | property | Code is valid. | |
TfaBasePlugin:: |
constant | |||
TfaBasePlugin:: |
protected | function | Decrypt a encrypted string. | |
TfaBasePlugin:: |
protected | function | Decrypt using the deprecated Mcrypt extension. | |
TfaBasePlugin:: |
protected | function | Use OpenSSL to decrypt data that was originally encrypted with Mcrypt. | |
TfaBasePlugin:: |
protected | function | Encrypt a plaintext string. | |
TfaBasePlugin:: |
protected | function | Encrypt using the deprecated Mcrypt extension. | |
TfaBasePlugin:: |
protected | function | Generate a random string of characters of length $this->codeLength. | |
TfaBasePlugin:: |
public | function | Get error messages suitable for form_set_error(). | |
TfaBasePlugin:: |
public | function | Submit form. | 1 |
TfaBasePlugin:: |
private | function | A timing safe equals comparison. | |
TfaTotp:: |
protected | property | ||
TfaTotp:: |
protected | property | ||
TfaTotp:: |
protected | property | ||
TfaTotp:: |
protected | function | Whether code has recently been accepted. | |
TfaTotp:: |
public | function | Delete users seeds. | |
TfaTotp:: |
public | function |
@copydoc TfaValidationPluginInterface::getForm() Overrides TfaValidationPluginInterface:: |
|
TfaTotp:: |
protected | function | Get seed for this account. | |
TfaTotp:: |
public | function |
@copydoc TfaBasePlugin::ready() Overrides TfaBasePlugin:: |
|
TfaTotp:: |
protected | function | ||
TfaTotp:: |
protected | function |
@copydoc TfaBasePlugin::validate() Overrides TfaBasePlugin:: |
1 |
TfaTotp:: |
public | function |
@copydoc TfaValidationPluginInterface::validateForm() Overrides TfaValidationPluginInterface:: |
|
TfaTotp:: |
public | function |
@copydoc TfaBasePlugin::__construct() Overrides TfaBasePlugin:: |
1 |