better_passwords.module in Better Passwords 8
Same filename and directory in other branches
The better passwords module file.
File
better_passwords.moduleView source
<?php
/**
* @file
* The better passwords module file.
*/
use ZxcvbnPhp\Zxcvbn;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Form\FormStateInterface;
/**
* Implements hook_element_info_alter().
*/
function better_passwords_element_info_alter(array &$info) {
if (isset($info['password_confirm'])) {
$info['password_confirm']['#after_build'][] = 'better_passwords_after_build';
}
}
/**
* After build function for password_confirm elements.
*
* @param array $element
* The element being altered after build.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form_state object returned with the element.
*/
function better_passwords_after_build(array $element, FormStateInterface $form_state) {
$config = \Drupal::config('better_passwords.settings');
// Hide the password fields if Better Passwords is generating passwords.
if (($generate = $config
->get('auto_generate')) && \Drupal::currentUser()
->isAuthenticated() && $form_state
->getFormObject()
->getFormId() == 'user_register_form') {
$element['#required'] = $element['pass1']['#required'] = $element['pass2']['#required'] = FALSE;
if ($generate == 1) {
$element['pass1']['#states']['visible']['#auto-generate-password'] = $element['pass2']['#states']['visible']['#auto-generate-password'] = [
'checked' => FALSE,
];
$element['auto_generate_password'] = [
'#type' => 'checkbox',
'#title' => t('Auto-generate password'),
'#checked' => TRUE,
'#attributes' => [
'id' => 'auto-generate-password',
],
'#parents' => $element['#parents'],
'#array_parents' => $element['#array_parents'],
];
}
else {
$element['pass1']['#access'] = $element['pass2']['#access'] = FALSE;
}
}
// Better Password validate should come before other validate functions.
array_unshift($element['#element_validate'], 'better_passwords_validate');
return $element;
}
/**
* Element validate function for password_confirm elements.
*
* @param array $element
* The element being validated.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form_state object returned with the element.
*/
function better_passwords_validate(array $element, FormStateInterface $form_state) {
$config = \Drupal::config('better_passwords.settings');
$minLength = $config
->get('length');
$minStrength = $config
->get('strength');
$autoGenerate = $config
->get('auto_generate');
$value = $element['pass1']['#value'];
if ($value === "") {
if ($autoGenerate && \Drupal::currentUser()
->isAuthenticated() && $form_state
->getFormObject()
->getFormId() == 'user_register_form') {
$genpass = user_password(64);
$form_state
->setValueForElement($element, [
'pass1' => $genpass,
'pass2' => $genpass,
]);
}
return TRUE;
}
if (strlen($value) < $minLength) {
$form_state
->setError($element, t('Passwords must be at least @num characters.', [
'@num' => $minLength,
]));
return;
}
elseif (!empty($minStrength)) {
$userdata = [
$form_state
->get('name'),
$form_state
->get('mail'),
];
$z = new Zxcvbn();
$strength = $z
->passwordStrength($value, $userdata);
if ($strength['score'] < $minStrength) {
$matches = [];
foreach ($strength['sequence'] as $obj) {
if (!empty($obj->pattern)) {
$str = substr($value, $obj->begin, $obj->end + 1 - $obj->begin);
switch ($obj->pattern) {
case 'date':
$matches[] = t('%str is a date', [
'%str' => $str,
]);
break;
case 'dictionary':
$matches[] = t('%str matches @dict dictionary (#@num)', [
'%str' => $str,
'@dict' => $obj->dictionaryName,
'@num' => $obj->rank,
]);
break;
case 'digit':
$matches[] = t('%str is numeric', [
'%str' => $str,
]);
break;
case 'repeat':
$matches[] = t('%str is repetitive', [
'%str' => $str,
]);
break;
case 'sequence':
$matches[] = t('%str is sequential', [
'%str' => $str,
]);
break;
case 'spatial':
$matches[] = t('%str is adjacent on the keyboard', [
'%str' => $str,
]);
break;
case 'year':
$matches[] = t('%str is a year', [
'%str' => $str,
]);
break;
}
}
}
$error = new FormattableMarkup(t('Please choose a stronger password. Current strength: @score. Minimum: @min.', [
'@score' => $strength['score'],
'@min' => $minStrength,
]) . '<ul><li>' . implode('</li><li>', $matches) . '</li></ul>', []);
$form_state
->setErrorByName('pass1', $error);
}
else {
\Drupal::messenger()
->addMessage(t('Password strength: @score. Minimum: @min.', [
'@score' => $strength['score'],
'@min' => $minStrength,
]));
}
}
}
Functions
Name | Description |
---|---|
better_passwords_after_build | After build function for password_confirm elements. |
better_passwords_element_info_alter | Implements hook_element_info_alter(). |
better_passwords_validate | Element validate function for password_confirm elements. |