You are here

recovery_pass.module in Recovery Password (Email New Password) 7

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

Alters default Drupal password recovery process by overriding default submit.

File

recovery_pass.module
View source
<?php

/**
 * @file
 * Alters default Drupal password recovery process by overriding default submit.
 */

/**
 * Implements hook_help().
 */
function recovery_pass_help($path, $arg) {
  $output = '';
  switch ($path) {
    case 'admin/help#recovery_pass':
      $output = file_get_contents(drupal_get_path('module', 'recovery_pass') . '/README.txt');
  }
  return $output;
}

/**
 * Implements hook_ctools_plugin_api().
 */
function recovery_pass_ctools_plugin_api($owner, $api) {
  if ($owner == 'services' && $api == 'services') {
    return array(
      'version' => 3,
      'file' => 'recovery_pass.services.inc',
    );
  }
}

/**
 * Implements hook_menu().
 */
function recovery_pass_menu() {
  $items = array();

  // Menu item for module configurations.
  $items['admin/config/people/recovery-pass'] = array(
    'title' => 'Recovery Password Configuration',
    'description' => 'Configure email message to be sent to user for password recovery.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'recovery_pass_config_form',
    ),
    'access arguments' => array(
      'administer users',
    ),
    'file' => 'recovery_pass.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function recovery_pass_form_user_pass_alter(&$form, &$form_state, $form_id) {

  // Overrides default submit handler for user_pass form.
  $form['#submit'] = array_diff($form['#submit'], array(
    'user_pass_submit',
  ));
  array_unshift($form['#submit'], 'recovery_pass_forgot_password_submit');
}

/**
 * Custom submit handler to send password in recovery mail.
 */
function recovery_pass_forgot_password_submit($form, &$form_state) {
  global $language;
  $user = $form_state['values']['account'];

  // Generate random password.
  $random_password = user_password();

  // Store Old Hash Password Temporarily.
  if (!_recovery_pass_store_old_pass($user)) {
    watchdog('recovery_pass', 'Error saving old password for user @id', array(
      '@id' => $user->uid,
    ), WATCHDOG_NOTICE, 'link');
  }

  // Save new password.
  user_save($user, array(
    'pass' => $random_password,
  ), 'account');

  // Retrive email body and subject.
  $message = _recovery_pass_mail_text('email_text', $language, TRUE, $user);
  if ($message) {

    // Replace [user_new_password] placeholder with new password.
    $message = str_replace("[user_new_password]", $random_password, $message);
  }
  $subject = _recovery_pass_mail_text('email_subject', $language, TRUE, $user);
  if (module_exists("htmlmail")) {

    // For html mail convert new lines to br.
    $message = nl2br($message);
  }
  $params = array(
    'body' => $message,
    'subject' => $subject,
  );
  $to = $user->mail;
  $from = variable_get('site_mail');
  if (drupal_mail('recovery_pass', 'recovery_pass', $to, language_default(), $params, $from, TRUE)) {
    drupal_set_message(t("Further instructions have been sent to your registered Email-id."), 'status', FALSE);
  }
  else {
    drupal_set_message(t("Error Sending Recovery Mail. Please contact site administrator."), 'error', FALSE);
  }
  $form_state['redirect'] = variable_get('recovery_pass_fpass_redirect', 'user');
}

/**
 * Temporarily stores old password in custom table for error message in future.
 */
function _recovery_pass_store_old_pass($user) {

  // Update or Insert using db_merge() the old password.
  $result = db_merge('recovery_pass')
    ->key(array(
    'uid' => $user->uid,
  ))
    ->fields(array(
    'uid' => (int) $user->uid,
    'old_pass' => $user->pass,
    'changed' => time(),
  ))
    ->execute();
  if ($result) {

    // Successfully saved old password.
    return TRUE;
  }
  return FALSE;
}

/**
 * Implements hook_mail().
 */
function recovery_pass_mail($key, &$message, $params) {
  switch ($key) {
    case 'recovery_pass':

      // Mail parameters used for recovery mail.
      $message['subject'] = $params['subject'];
      $message['body'][] = $params['body'];
      if (module_exists("htmlmail")) {

        // For html mail.
        $message['headers']['Content-Type'] = 'text/html; charset=UTF-8; format=flowed';
      }
      break;
  }
}

/**
 * Returns a mail string for a variable name.
 *
 * Used by recovery_pass_mail() and the settings forms to retrieve strings.
 */
function _recovery_pass_mail_text($key, $language = NULL, $replace = TRUE, $user = array()) {
  $langcode = !empty($language) ? $language->language : NULL;
  $text = '';
  if ($admin_setting = variable_get('recovery_pass_' . $key, FALSE)) {

    // An admin setting overrides the default string.
    $text = $admin_setting;
  }
  else {

    // No override, return default string.
    switch ($key) {
      case 'email_subject':
        $text = t('Replacement login information for [user:name] at [site:name]', array(), array(
          'langcode' => $langcode,
        ));
        break;
      case 'email_text':
        $text = t("[user:name],\n\nA request to reset the password for your account has been made at [site:name].\n\nYour new password is [user_new_password].\n\n\n--  [site:name] team", array(), array(
          'langcode' => $langcode,
        ));
        break;
      case 'old_pass_warning':
        $text = t('You are using <strong>old password</strong>, your password was reset recently. New Password was sent to your registered email id.');
        break;
    }
  }
  if ($replace) {

    // Token Replace the text.
    return token_replace($text, array(
      'user' => $user,
    ));
  }
  return $text;
}

/**
 * Implements hook_form_alter().
 */
function recovery_pass_form_alter(&$form, &$form_state, $form_id) {
  if (variable_get('recovery_pass_old_pass_show', 1)) {
    switch ($form_id) {
      case 'user_login_block':
      case 'user_login':

        // Extending default drupal login validators.
        $insert = 'recovery_pass_user_login_validate';
        $form['#validate'] = _recovery_pass_insert_array($form['#validate'], 1, $insert);
        break;
    }
  }
}

/**
 * To insert our validator at index 1 between the default validators.
 */
function _recovery_pass_insert_array($array, $index, $val) {

  // Because this will be used one more time.
  $size = count($array);
  if (!is_int($index) || $index < 0 || $index > $size) {
    return -1;
  }
  else {
    $temp = array_slice($array, 0, $index);
    $temp[] = $val;
    return array_merge($temp, array_slice($array, $index, $size));
  }
}

/**
 * Custom Submit handler for user login form.
 *
 * Incase user tries to login using old pass then error msg is shown that pass
 * has been reset, till user tries any other pass.
 */
function recovery_pass_user_login_validate($form, &$form_state) {
  $input_password = trim($form_state['values']['pass']);
  if (!empty($form_state['values']['name']) && !empty($input_password)) {
    $account = db_query("SELECT uid,pass FROM {users} WHERE name = :name AND status = 1", array(
      ':name' => $form_state['values']['name'],
    ))
      ->fetchObject();

    // Check uid exists in recovery_pass table.
    $result = db_select('recovery_pass', 'r')
      ->fields('r', array(
      'uid',
      'old_pass',
    ))
      ->condition('uid', (int) $account->uid)
      ->execute()
      ->fetchAssoc();
    if ($result) {

      // If uid exists in table.
      $old_password = $result['old_pass'];

      // Match input password with password stored in recovery_pass table.
      if (_recovery_pass_match_old_password($input_password, $old_password)) {
        drupal_set_message(_recovery_pass_mail_text('old_pass_warning'), 'warning', FALSE);
      }
      else {

        // Irrespective of the input password delete the entry.
        $entry_deleted = db_delete('recovery_pass')
          ->condition('uid', $result['uid'])
          ->execute();
        if (!$entry_deleted) {
          watchdog('recovery_pass', 'Error deleting entry from recovery_table for user @id', array(
            '@id' => $result['uid'],
          ), WATCHDOG_NOTICE, 'link');
        }
      }
    }
  }
}

/**
 * Matches old password stored in recovery_pass table with user input password.
 */
function _recovery_pass_match_old_password($password, $old_password) {

  // Allow alternate password hashing schemes.
  require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
  if (substr($old_password, 0, 2) == 'U$') {

    // This may be an updated password from user_update_7000(). Such hashes
    // have 'U' added as the first character and need an extra md5().
    $stored_hash = substr($old_password, 1);
    $password = md5($password);
  }
  else {
    $stored_hash = $old_password;
  }
  $type = substr($stored_hash, 0, 3);
  switch ($type) {
    case '$S$':

      // A normal Drupal 7 password using sha512.
      $hash = _password_crypt('sha512', $password, $stored_hash);
      break;
    case '$H$':

    // phpBB3 uses "$H$" for the same thing as "$P$".
    case '$P$':

      // A phpass password generated using md5.  This is an
      // imported password or from an earlier Drupal version.
      $hash = _password_crypt('md5', $password, $stored_hash);
      break;
    default:
      return FALSE;
  }
  return $hash && $stored_hash == $hash;
}

/**
 * Implements hook_cron().
 */
function recovery_pass_cron() {
  $expiry_period = strtotime("-" . variable_get('recovery_pass_expiry_period', '1') . " week");

  // Delete all records more created than one week ago.
  $entry_deleted = db_delete('recovery_pass')
    ->condition('changed', $expiry_period, '<')
    ->execute();
  if ($entry_deleted) {
    watchdog('recovery_pass', 'Error deleting entry from recovery_table at cron time.', array(), WATCHDOG_NOTICE, 'link');
  }
}

Functions

Namesort descending Description
recovery_pass_cron Implements hook_cron().
recovery_pass_ctools_plugin_api Implements hook_ctools_plugin_api().
recovery_pass_forgot_password_submit Custom submit handler to send password in recovery mail.
recovery_pass_form_alter Implements hook_form_alter().
recovery_pass_form_user_pass_alter Implements hook_form_FORM_ID_alter().
recovery_pass_help Implements hook_help().
recovery_pass_mail Implements hook_mail().
recovery_pass_menu Implements hook_menu().
recovery_pass_user_login_validate Custom Submit handler for user login form.
_recovery_pass_insert_array To insert our validator at index 1 between the default validators.
_recovery_pass_mail_text Returns a mail string for a variable name.
_recovery_pass_match_old_password Matches old password stored in recovery_pass table with user input password.
_recovery_pass_store_old_pass Temporarily stores old password in custom table for error message in future.