You are here

password_field.module in Password Field 7

Same filename and directory in other branches
  1. 8 password_field.module

Password Field Module

Functions for storing and displaying password fields

File

password_field.module
View source
<?php

/**
 * @file
 * Password Field Module
 *
 * Functions for storing and displaying password fields
 */

/**
 * Implements hook_field_info().
 */
function password_field_field_info() {
  return array(
    'password_field' => array(
      'label' => t('Password'),
      'description' => t('A password'),
      'default_widget' => 'password_field_widget',
      'default_formatter' => 'password_field_formatter',
      'property_type' => 'password_field',
    ),
  );
}

/**
 * Implements hook_permission().
 */
function password_field_permission() {
  return array(
    'view unencrypted passwords' => array(
      'title' => t('View unencrypted passwords'),
      'description' => t('Allow access to unencrypted password field formatter.'),
    ),
  );
}

/**
 * Implements hook_field_formatter_info().
 */
function password_field_field_formatter_info() {
  return array(
    'password_field_formatter' => array(
      'label' => t('Password field formatter'),
      'field types' => array(
        'password_field',
      ),
    ),
    'unencrypted_field_formatter' => array(
      'label' => t('Unencrypted password field formatter'),
      'field types' => array(
        'password_field',
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_view().
 */
function password_field_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  switch ($display['type']) {
    case 'password_field_formatter':
      foreach ($items as $delta => $item) {
        if (!empty($item['password_field'])) {
          $pw_out = '••••••••••••••••';
          $element[$delta]['#markup'] = '<span>' . $pw_out . '</span>';
        }
      }
      break;
    case 'unencrypted_field_formatter':
      foreach ($items as $delta => $item) {
        if (!empty($item['password_field']) && user_access('view unencrypted passwords')) {
          $pw_out = password_field_decrypt($item['password_field']);
          $element[$delta]['#markup'] = '<span>' . $pw_out . '</span>';
        }
      }
      break;
  }
  return $element;
}

/**
 * Implements hook_field_widget_form().
 */
function password_field_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $field_name = $field['field_name'];
  $field_type = $field['type'];
  $default_pw = $instance['default_value'][0][$field_type][$field_type];
  if ($instance['widget']['type'] === 'password_field') {
    $dsc_key = '#description';
    $default_dsc = t('Password will remain unchanged if left blank.');
    $description = empty($element[$dsc_key]) ? $default_dsc : $element[$dsc_key];
    $weight = isset($element['#weight']) ? $element['#weight'] : 0;
    $element['password_field'] = array(
      '#type' => 'password',
      '#title' => filter_xss($element['#title']),
      '#description' => filter_xss($description),
      '#default_value' => $default_pw,
      '#required' => $element['#required'],
      '#weight' => $weight,
      '#delta' => $delta,
      '#element_validate' => array(
        '_password_field_encrypt',
      ),
    );
  }
  return $element;
}

/**
 * Implements hook_field_widget_error().
 */
function password_field_widget_error($element, $error, $form, &$form_state) {
  switch ($error['error']) {
    case 'password_field_invalid':
      form_error($element, $error['message']);
      break;
  }
}

/**
 * Implements hook_field_is_empty().
 */
function password_field_field_is_empty($item, $field) {
  if (empty($item['password_field'])) {
    return TRUE;
  }
}

/**
 * Implements hook_field_widget_info().
 */
function password_field_field_widget_info() {
  return array(
    'password_field' => array(
      'label' => t('Password'),
      'field types' => array(
        'password_field',
      ),
    ),
  );
}

/**
 * Get field instance details.
 *
 * Given an element and form state, load details of the field instance
 * and the entity type it is attached to.
 */
function _password_field_get_instance_details($element, $form_state) {

  // Parse the element name to determine field name, language, and delta.
  $pattern = '/^([^\\[]+)\\[([^\\[]+)]\\[([^\\[]+)\\]/';
  if (!preg_match($pattern, $element['#name'], $matches)) {
    return;
  }
  list($full_match, $field_name, $langcode, $delta) = $matches;

  // Get the entity type and the entity itself.
  $field_instance = $form_state['field'][$field_name][$langcode]['instance'];
  $entity_type = $field_instance['entity_type'];
  return array(
    'field_name' => $field_name,
    'langcode' => $langcode,
    'delta' => $delta,
    'entity_type' => $entity_type,
  );
}

/**
 * Load field value.
 *
 * Given an element and form state, load the current value of the field
 * instance.
 */
function _password_field_load_current_value($element, $form_state) {

  // Get field details.
  $field_details = _password_field_get_instance_details($element, $form_state);
  $entity_type = $field_details['entity_type'];

  // If there is no entity, then there can't be a value.
  if (empty($form_state[$entity_type])) {
    return;
  }
  $entity = $form_state[$entity_type];
  $field_name = $field_details['field_name'];
  $delta = $field_details['delta'];

  // Load the field instance from DB and get the value.
  $pwfield = field_get_items($entity_type, $entity, $field_name);
  $pwvalue = isset($pwfield[$delta]['password_field']) ? $pwfield[$delta]['password_field'] : NULL;
  return $pwvalue;
}

/**
 * Encrypt the password.
 */
function _password_field_encrypt($element, &$form_state) {

  // If no value to encrypt, get out of here.
  if (!isset($element['#value'])) {
    return;
  }

  // If password value exists, but is empty, load old value and store that. This
  // means that if the field is left blank, then the value will be unchanged.
  if (empty($element['#value']) && !empty($form_state['field'])) {
    $pwvalue = _password_field_load_current_value($element, $form_state);
    form_set_value($element, array(
      'password_field' => $pwvalue,
    ), $form_state);
    return;
  }

  // If a new password value has been entered, encrypt it before saving.
  if (!empty($element['#value'])) {
    define('ENCRYPT_METHOD', 'AES-256-CBC');
    $str = $element['#value'];
    $key = md5(drupal_get_hash_salt());

    // Generate the Initialization Vector.
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(ENCRYPT_METHOD));

    // Encrypt the password.
    $encrypted = openssl_encrypt($str, ENCRYPT_METHOD, $key, 0, $iv);

    // Save the IV with the data for the decrypt.
    $value = trim(base64_encode($encrypted . '::' . $iv));
    form_set_value($element, array(
      'password_field' => $value,
    ), $form_state);
  }
}

/**
 * Decrypt a password string.
 */
function password_field_decrypt($str) {
  $key = md5(drupal_get_hash_salt());

  // Get the IV and the encrypted data.
  list($encrypted_data, $iv) = explode('::', base64_decode($str), 2);
  return trim(openssl_decrypt($encrypted_data, ENCRYPT_METHOD, $key, 0, $iv));
}