Project

General

Profile

Paste
Download (9.29 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / recovery_pass / recovery_pass.module @ 7dbec6b0

1
<?php
2
/**
3
 * @file
4
 * Alters default Drupal password recovery process by overriding default submit.
5
 */
6

    
7
/**
8
 * Implements hook_help().
9
 */
10
function recovery_pass_help($path, $arg) {
11
  $output = '';
12
  switch ($path) {
13
    case 'admin/help#recovery_pass':
14
      $output = file_get_contents(drupal_get_path('module', 'recovery_pass') . '/README.txt');
15
  }
16
  return $output;
17
}
18

    
19
/**
20
 * Implements hook_ctools_plugin_api().
21
 */
22
function recovery_pass_ctools_plugin_api($owner, $api) {
23
  if ($owner == 'services' && $api == 'services') {
24
    return array(
25
      'version' => 3,
26
      'file' => 'recovery_pass.services.inc'
27
    );
28
  }
29
}
30

    
31
/**
32
 * Implements hook_menu().
33
 */
34
function recovery_pass_menu() {
35
  $items = array();
36

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

    
49
/**
50
 * Implements hook_form_FORM_ID_alter().
51
 */
52
function recovery_pass_form_user_pass_alter(&$form, &$form_state, $form_id) {
53
  // Overrides default submit handler for user_pass form.
54
  $form['#submit'] = array_diff($form['#submit'], array('user_pass_submit'));
55
  array_unshift($form['#submit'], 'recovery_pass_forgot_password_submit');
56
}
57

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

    
65
  // Generate random password.
66
  $random_password = user_password();
67
  // Store Old Hash Password Temporarily.
68
  if (!_recovery_pass_store_old_pass($user)) {
69
    watchdog('recovery_pass', 'Error saving old password for user @id', array('@id' => $user->uid), WATCHDOG_NOTICE, 'link');
70
  }
71
  // Save new password.
72
  user_save($user, array('pass' => $random_password), 'account');
73

    
74
  // Retrive email body and subject.
75
  $message = _recovery_pass_mail_text('email_text', $language, TRUE, $user);
76
  if ($message) {
77
    // Replace [user_new_password] placeholder with new password.
78
    $message = str_replace("[user_new_password]", $random_password, $message);
79
  }
80
  $subject = _recovery_pass_mail_text('email_subject', $language, TRUE, $user);
81
  if (module_exists("htmlmail")) {
82
    // For html mail convert new lines to br.
83
    $message = nl2br($message);
84
  }
85
  $params = array(
86
    'body' => $message,
87
    'subject' => $subject,
88
  );
89
  $to = $user->mail;
90
  $from = variable_get('site_mail');
91
  if (drupal_mail('recovery_pass', 'recovery_pass', $to, language_default(), $params, $from, TRUE)) {
92
    drupal_set_message(t("Further instructions have been sent to your registered Email-id."), 'status', FALSE);
93
  }
94
  else {
95
    drupal_set_message(t("Error Sending Recovery Mail. Please contact site administrator."), 'error', FALSE);
96
  }
97
  $form_state['redirect'] = variable_get('recovery_pass_fpass_redirect', 'user');
98
}
99

    
100
/**
101
 * Temporarily stores old password in custom table for error message in future.
102
 */
103
function _recovery_pass_store_old_pass($user) {
104
  // Update or Insert using db_merge() the old password.
105
  $result = db_merge('recovery_pass')
106
    ->key(array('uid' => $user->uid))
107
    ->fields(array(
108
        'uid' => (int) $user->uid,
109
        'old_pass' => $user->pass,
110
        'changed' => time(),
111
    ))
112
    ->execute();
113
  if ($result) {
114
    // Successfully saved old password.
115
    return TRUE;
116
  }
117
  return FALSE;
118
}
119

    
120
/**
121
 * Implements hook_mail().
122
 */
123
function recovery_pass_mail($key, &$message, $params) {
124
  switch ($key) {
125
    case 'recovery_pass':
126
      // Mail parameters used for recovery mail.
127
      $message['subject'] = $params['subject'];
128
      $message['body'][] = $params['body'];
129
      if (module_exists("htmlmail")) {
130
        // For html mail.
131
        $message['headers']['Content-Type'] = 'text/html; charset=UTF-8; format=flowed';
132
      }
133
      break;
134
  }
135
}
136

    
137
/**
138
 * Returns a mail string for a variable name.
139
 *
140
 * Used by recovery_pass_mail() and the settings forms to retrieve strings.
141
 */
142
function _recovery_pass_mail_text($key, $language = NULL, $replace = TRUE, $user = array()) {
143
  $langcode = !empty($language) ? $language->language : NULL;
144
  $text = '';
145

    
146
  if ($admin_setting = variable_get('recovery_pass_' . $key, FALSE)) {
147
    // An admin setting overrides the default string.
148
    $text = $admin_setting;
149
  }
150
  else {
151
    // No override, return default string.
152
    switch ($key) {
153
      case 'email_subject':
154
        $text = t('Replacement login information for [user:name] at [site:name]', array(), array('langcode' => $langcode));
155
        break;
156

    
157
      case 'email_text':
158
        $text = t("[user:name],
159

    
160
A request to reset the password for your account has been made at [site:name].
161

    
162
Your new password is [user_new_password].
163

    
164

    
165
--  [site:name] team", array(), array('langcode' => $langcode));
166
        break;
167

    
168
      case 'old_pass_warning':
169
        $text = t('You are using <strong>old password</strong>, your password was reset recently. New Password was sent to your registered email id.');
170
        break;
171
    }
172
  }
173

    
174
  if ($replace) {
175
    // Token Replace the text.
176
    return token_replace($text, array('user' => $user));
177
  }
178

    
179
  return $text;
180
}
181

    
182
/**
183
 * Implements hook_form_alter().
184
 */
185
function recovery_pass_form_alter(&$form, &$form_state, $form_id) {
186
  if (variable_get('recovery_pass_old_pass_show', 1)) {
187
    switch ($form_id) {
188
      case 'user_login_block':
189
      case 'user_login':
190
        // Extending default drupal login validators.
191
        $insert = 'recovery_pass_user_login_validate';
192
        $form['#validate'] = _recovery_pass_insert_array($form['#validate'], 1, $insert);
193
        break;
194
    }
195
  }
196
}
197

    
198
/**
199
 * To insert our validator at index 1 between the default validators.
200
 */
201
function _recovery_pass_insert_array($array, $index, $val) {
202
  // Because this will be used one more time.
203
  $size = count($array);
204
  if (!is_int($index) || $index < 0 || $index > $size) {
205
    return -1;
206
  }
207
  else {
208
    $temp   = array_slice($array, 0, $index);
209
    $temp[] = $val;
210
    return array_merge($temp, array_slice($array, $index, $size));
211
  }
212
}
213

    
214
/**
215
 * Custom Submit handler for user login form.
216
 *
217
 * Incase user tries to login using old pass then error msg is shown that pass
218
 * has been reset, till user tries any other pass.
219
 */
220
function recovery_pass_user_login_validate($form, &$form_state) {
221
  $input_password = trim($form_state['values']['pass']);
222
  if (!empty($form_state['values']['name']) && !empty($input_password)) {
223
    $account = db_query("SELECT uid,pass FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
224
    // Check uid exists in recovery_pass table.
225
    $result = db_select('recovery_pass', 'r')
226
      ->fields('r', array('uid', 'old_pass'))
227
      ->condition('uid', (int) $account->uid)
228
      ->execute()
229
      ->fetchAssoc();
230
    if ($result) {
231
      // If uid exists in table.
232
      $old_password = $result['old_pass'];
233
      // Match input password with password stored in recovery_pass table.
234
      if (_recovery_pass_match_old_password($input_password, $old_password)) {
235
        drupal_set_message(_recovery_pass_mail_text('old_pass_warning'), 'warning', FALSE);
236
      }
237
      else {
238
        // Irrespective of the input password delete the entry.
239
        $entry_deleted = db_delete('recovery_pass')
240
          ->condition('uid', $result['uid'])
241
          ->execute();
242
        if (!$entry_deleted) {
243
          watchdog('recovery_pass', 'Error deleting entry from recovery_table for user @id', array('@id' => $result['uid']), WATCHDOG_NOTICE, 'link');
244
        }
245
      }
246
    }
247
  }
248
}
249

    
250
/**
251
 * Matches old password stored in recovery_pass table with user input password.
252
 */
253
function _recovery_pass_match_old_password($password, $old_password) {
254
  // Allow alternate password hashing schemes.
255
  require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
256
  if (substr($old_password, 0, 2) == 'U$') {
257
    // This may be an updated password from user_update_7000(). Such hashes
258
    // have 'U' added as the first character and need an extra md5().
259
    $stored_hash = substr($old_password, 1);
260
    $password = md5($password);
261
  }
262
  else {
263
    $stored_hash = $old_password;
264
  }
265

    
266
  $type = substr($stored_hash, 0, 3);
267
  switch ($type) {
268
    case '$S$':
269
      // A normal Drupal 7 password using sha512.
270
      $hash = _password_crypt('sha512', $password, $stored_hash);
271
      break;
272

    
273
    case '$H$':
274
      // phpBB3 uses "$H$" for the same thing as "$P$".
275
    case '$P$':
276
      // A phpass password generated using md5.  This is an
277
      // imported password or from an earlier Drupal version.
278
      $hash = _password_crypt('md5', $password, $stored_hash);
279
      break;
280

    
281
    default:
282
      return FALSE;
283
  }
284
  return ($hash && $stored_hash == $hash);
285
}
286

    
287
/**
288
 * Implements hook_cron().
289
 */
290
function recovery_pass_cron() {
291
  $expiry_period = strtotime("-" . variable_get('recovery_pass_expiry_period', '1') . " week");
292
  // Delete all records more created than one week ago.
293
  $entry_deleted = db_delete('recovery_pass')
294
    ->condition('changed', $expiry_period, '<')
295
    ->execute();
296

    
297
  if ($entry_deleted) {
298
    watchdog('recovery_pass', 'Error deleting entry from recovery_table at cron time.', array(), WATCHDOG_NOTICE, 'link');
299
  }
300
}