summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2005-04-24 11:43:08 +0000
committerDries Buytaert <dries@buytaert.net>2005-04-24 11:43:08 +0000
commite2b256dcf63e01de58a47f7b8358ac918eaf3b91 (patch)
tree47a95f58a9a1de49c94fc9bf9589452861048cfb
parent45c5344f15ad1dd812eaa0fda677a72ab077d755 (diff)
downloadbrdo-e2b256dcf63e01de58a47f7b8358ac918eaf3b91.tar.gz
brdo-e2b256dcf63e01de58a47f7b8358ac918eaf3b91.tar.bz2
- Patch #18719 by Jose: reworked the 'request new password' functionality.
-rw-r--r--CHANGELOG.txt2
-rw-r--r--database/database.mysql1
-rw-r--r--database/database.pgsql1
-rw-r--r--database/updates.inc14
-rw-r--r--modules/contact.module8
-rw-r--r--modules/contact/contact.module8
-rw-r--r--modules/user.module91
-rw-r--r--modules/user/user.module91
8 files changed, 158 insertions, 58 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index fcc39bccd..a0e7575a3 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -2,6 +2,8 @@ Drupal x.x.x, xxxx-xx-xx (Development version)
------------------------
- added free tagging support (folksonomies).
+- added a site-wide contact form.
+- reworked the 'request new password' functionality.
- profiles:
* added a block to display author information along with posts.
* added support for private profile fields.
diff --git a/database/database.mysql b/database/database.mysql
index 2e2e8ad55..d0279f4c5 100644
--- a/database/database.mysql
+++ b/database/database.mysql
@@ -705,6 +705,7 @@ CREATE TABLE users (
signature varchar(255) NOT NULL default '',
created int(11) NOT NULL default '0',
changed int(11) NOT NULL default '0',
+ login int(11) NOT NULL default '0',
status tinyint(4) NOT NULL default '0',
timezone varchar(8) default NULL,
language varchar(12) NOT NULL default '',
diff --git a/database/database.pgsql b/database/database.pgsql
index 1fa3d1634..b635751b4 100644
--- a/database/database.pgsql
+++ b/database/database.pgsql
@@ -702,6 +702,7 @@ CREATE TABLE users (
signature varchar(255) NOT NULL default '',
created integer NOT NULL default '0',
changed integer NOT NULL default '0',
+ login integer NOT NULL default '0',
status smallint NOT NULL default '0',
timezone varchar(8) default NULL,
language varchar(12) NOT NULL default '',
diff --git a/database/updates.inc b/database/updates.inc
index aef73c8c2..6874bd72c 100644
--- a/database/updates.inc
+++ b/database/updates.inc
@@ -109,7 +109,7 @@ $sql_updates = array(
"2005-04-10" => "update_130",
"2005-04-11" => "update_131",
"2005-04-14" => "update_132",
- "2005-04-20" => "update_133"
+ "2005-04-24" => "update_133"
);
function update_32() {
@@ -2407,14 +2407,24 @@ function update_132() {
}
function update_133() {
- $ret[] = update_sql("CREATE TABLE contact (
+ $ret[] = update_sql("CREATE TABLE {contact} (
subject varchar(255) NOT NULL default '',
recipients longtext NOT NULL default '',
reply longtext NOT NULL default ''
)");
+ if ($GLOBALS['db_type'] == 'mysql') {
+ $ret[] = update_sql("ALTER TABLE {users} ADD login int(11) NOT NULL default '0'");
+ }
+ elseif ($GLOBALS['db_type'] == 'pgsql') {
+ $ret[] = update_sql("ALTER TABLE {users} ADD login integer");
+ $ret[] = update_sql("ALTER TABLE {users} ALTER COLUMN login SET NOT NULL");
+ $ret[] = update_sql("ALTER TABLE {users} ALTER COLUMN login SET DEFAULT '0'");
+ }
+
return $ret;
}
+
function update_sql($sql) {
$edit = $_POST["edit"];
$result = db_query($sql);
diff --git a/modules/contact.module b/modules/contact.module
index 71d88cdb8..7f9646bb4 100644
--- a/modules/contact.module
+++ b/modules/contact.module
@@ -224,7 +224,7 @@ function contact_mail_page() {
if (isset($_POST['edit'])) {
$edit = $_POST['edit'];
}
-
+
if ($edit) {
// Validate the fields:
if (!$edit['name']) {
@@ -236,11 +236,11 @@ function contact_mail_page() {
if (!$edit['message']) {
form_set_error('message', t('You must enter a message.'));
}
-
+
if (!form_get_errors()) {
// Prepare the sender:
$from = $edit['mail'];
-
+
// Compose the body:
$message[] = t("%name sent a message using the contact form at %form:", array('%name' => $edit['name'], '%form' => url($_GET['q'], NULL, NULL, TRUE)));
$message[] = $edit['message'];
@@ -282,7 +282,7 @@ function contact_mail_page() {
$edit['name'] = $user->name;
$edit['mail'] = $user->mail;
}
-
+
$result = db_query('SELECT subject FROM contact ORDER BY subject');
while ($subject = db_fetch_object($result)) {
$subjects[$subject->subject] = $subject->subject;
diff --git a/modules/contact/contact.module b/modules/contact/contact.module
index 71d88cdb8..7f9646bb4 100644
--- a/modules/contact/contact.module
+++ b/modules/contact/contact.module
@@ -224,7 +224,7 @@ function contact_mail_page() {
if (isset($_POST['edit'])) {
$edit = $_POST['edit'];
}
-
+
if ($edit) {
// Validate the fields:
if (!$edit['name']) {
@@ -236,11 +236,11 @@ function contact_mail_page() {
if (!$edit['message']) {
form_set_error('message', t('You must enter a message.'));
}
-
+
if (!form_get_errors()) {
// Prepare the sender:
$from = $edit['mail'];
-
+
// Compose the body:
$message[] = t("%name sent a message using the contact form at %form:", array('%name' => $edit['name'], '%form' => url($_GET['q'], NULL, NULL, TRUE)));
$message[] = $edit['message'];
@@ -282,7 +282,7 @@ function contact_mail_page() {
$edit['name'] = $user->name;
$edit['mail'] = $user->mail;
}
-
+
$result = db_query('SELECT subject FROM contact ORDER BY subject');
while ($subject = db_fetch_object($result)) {
$subjects[$subject->subject] = $subject->subject;
diff --git a/modules/user.module b/modules/user.module
index a2d994816..329715990 100644
--- a/modules/user.module
+++ b/modules/user.module
@@ -392,7 +392,7 @@ function user_fields() {
}
else {
// Make sure we return the default fields at least
- $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'changed', 'status', 'timezone', 'language', 'init', 'data');
+ $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'changed', 'login', 'status', 'timezone', 'language', 'init', 'data');
}
}
@@ -644,6 +644,8 @@ function user_menu($may_cache) {
'callback' => 'user_page', 'access' => $user->uid == 0 && variable_get('user_register', 1), 'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'user/password', 'title' => t('request new password'),
'callback' => 'user_pass', 'access' => $user->uid == 0, 'type' => MENU_LOCAL_TASK);
+ $items[] = array('path' => 'user/reset', 'title' => t('reset password'),
+ 'callback' => 'user_pass_reset', 'access' => $user->uid == 0, 'type' => MENU_CALLBACK);
$items[] = array('path' => 'user/help', 'title' => t('help'),
'callback' => 'user_help_page', 'type' => MENU_CALLBACK);
@@ -809,7 +811,7 @@ function user_login($edit = array(), $msg = '') {
watchdog('user', t('Session opened for %name.', array('%name' => theme('placeholder', $user->name))));
// Update the user table timestamp noting user has logged in.
- db_query("UPDATE {users} SET changed = '%d' WHERE uid = '%s'", time(), $user->uid);
+ db_query("UPDATE {users} SET login = '%d' WHERE uid = '%s'", time(), $user->uid);
user_module_invoke('login', $edit, $user);
@@ -922,31 +924,27 @@ function user_pass() {
}
if ($account) {
$from = variable_get('site_mail', ini_get('sendmail_from'));
- $pass = user_password();
- // Save new password:
- user_save($account, array('pass' => $pass));
-
- // Mail new password:
- $variables = array('%username' => $account->name, '%site' => variable_get('site_name', 'drupal'), '%password' => $pass, '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $account->mail, '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE));
+ // Mail one time login URL and instructions.
+ $variables = array('%username' => $account->name, '%site' => variable_get('site_name', 'drupal'), '%login_url' => user_pass_reset_url($account), '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $account->mail, '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE));
$subject = _user_mail_text('pass_subject', $variables);
$body = _user_mail_text('pass_body', $variables);
$headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from";
$mail_success = user_mail($account->mail, $subject, $body, $headers);
if ($mail_success) {
- watchdog('user', t('Password mailed to %name at %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', $account->mail))));
- drupal_set_message(t('Your password and further instructions have been sent to your e-mail address.'));
+ watchdog('user', t('Password reset instructions mailed to %name at %email.', array('%name' => '<em>'. $account->name .'</em>', '%email' => '<em>'. $account->mail .'</em>')));
+ drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
}
else {
- watchdog('user', t('Error mailing password to %name at %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', $account->mail))), WATCHDOG_ERROR);
+ watchdog('user', t('Error mailing password reset instructions to %name at %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', $account->mail))), WATCHDOG_ERROR);
drupal_set_message(t('Unable to send mail. Please contact the site admin.'));
}
drupal_goto('user');
}
else {
if ($edit) {
- drupal_set_message(t('You must provider either a username or e-mail address.'), 'error');
+ drupal_set_message(t('You must provide either a username or e-mail address.'), 'error');
}
// Display form:
$output = '<p>'. t('Enter your username <strong><em>or</em></strong> your e-mail address.') .'</p>';
@@ -957,6 +955,50 @@ function user_pass() {
}
}
+/**
+ * Menu callback; process one time login URL, and redirects to the user page on success.
+ */
+function user_pass_reset($uid, $timestamp, $hashed_pass) {
+ global $user;
+ // Time out, in seconds, until login URL expires. 24 hours = 86400 seconds.
+ $timeout = 86400;
+ $current = time();
+ // Some redundant checks for extra security ?
+ if ($timestamp < $current && is_numeric($uid) && $account = user_load(array('uid' => $uid, 'status' => 1)) ) {
+ // No time out for first time login.
+ if ($account->login && $current - $timestamp > $timeout) {
+ drupal_set_message(t('You have tried to use a one time login URL which has expired. Please request a new one using the form below.'));
+ drupal_goto('user/password');
+ }
+ if ($account->uid && !$user->uid && !empty($account) && $timestamp > $account->login && $timestamp < $current &&
+ $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
+ watchdog('user', t('One time login URL used for %name with timestamp %timestamp.', array('%name' => "<em>$account->name</em>", '%timestamp' => $timestamp)));
+ // Update the user table noting user has logged in.
+ // And this also makes this hashed password a one-time-only login.
+ db_query("UPDATE {users} SET login = '%d' WHERE uid = %d", time(), $account->uid);
+ // Now we can set the new user.
+ $user = $account;
+ // And proceed with normal login, going to user page.
+ user_module_invoke('login', $edit, $user);
+ drupal_set_message(t("You have used a one-time login, which won't be valid anymore."));
+ drupal_set_message(t('Please change your password.'));
+ drupal_goto('user/'. $user->uid .'/edit');
+ }
+ }
+ // Deny access, no more clues.
+ // Everything will be in the watchdog's URL for the administrator to check.
+ drupal_access_denied();
+}
+
+function user_pass_reset_url($account){
+ $timestamp = time();
+ return url("user/reset/$account->uid/$timestamp/".user_pass_rehash($account->pass, $timestamp, $account->login), NULL, NULL, TRUE);
+}
+
+function user_pass_rehash($password, $timestamp, $login){
+ return md5($timestamp . $password . $login);
+}
+
function user_register($edit = array()) {
global $user, $base_url;
@@ -977,7 +1019,7 @@ function user_register($edit = array()) {
$account = user_save('', array_merge(array('name' => $edit['name'], 'pass' => $pass, 'init' => $edit['mail'], 'mail' => $edit['mail'], 'roles' => array(_user_authenticated_id()), 'status' => (variable_get('user_register', 1) == 1 ? 1 : 0)), $edit));
watchdog('user', t('New user: %name %email.', array('%name' => theme('placeholder', $edit['name']), '%email' => theme('placeholder', '<'. $edit['mail'] .'>'))), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit'));
- $variables = array('%username' => $edit['name'], '%site' => variable_get('site_name', 'drupal'), '%password' => $pass, '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $edit['mail'], '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE));
+ $variables = array('%username' => $edit['name'], '%site' => variable_get('site_name', 'drupal'), '%password' => $pass, '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $edit['mail'], '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE), '%login_url' => user_pass_reset_url($account));
// The first user may login immediately, and receives a customized welcome e-mail.
if ($account->uid == 1) {
@@ -1256,15 +1298,15 @@ function _user_mail_text($messageid, $variables = array()) {
case 'welcome_subject':
return t('Account details for %username at %site', $variables);
case 'welcome_body':
- return t("%username,\n\nThank you for registering at %site. You may now log in to %login_uri using the following username and password:\n\nusername: %username\npassword: %password\n\nAfter logging in, you may wish to change your password at %edit_uri\n\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://www.drupal.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
+ return t("%username,\n\nThank you for registering at %site. You may now log in to %login_uri using the following username and password:\n\nusername: %username\npassword: %password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n%login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to %edit_uri so you can change your password.\n\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://www.drop.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
case 'approval_subject':
return t('Account details for %username at %site (pending admin approval)', $variables);
case 'approval_body':
- return t("%username,\n\nThank you for registering at %site. Your application for an account is currently pending approval. Once it has been granted, you may log in to %login_uri using the following username and password:\n\nusername: %username\npassword: %password\n\nAfter logging in, you may wish to change your password at %edit_uri\n\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://www.drupal.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
+ return t("%username,\n\nThank you for registering at %site. Your application for an account is currently pending approval. Once it has been granted, you may log in to %login_uri using the following username and password:\n\nusername: %username\npassword: %password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n%login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you may wish to change your password at %edit_uri\n\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://www.drop.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
case 'pass_subject':
return t('Replacement login information for %username at %site', $variables);
case 'pass_body':
- return t("%username,\n\nHere is your new password for %site. You may now login to %login_uri using the following username and password:\n\nusername: %username\npassword: %password\n\nAfter logging in, you may wish to change your password at %edit_uri", $variables);
+ return t("%username,\n\nA request to reset the password for your account has been made at %site.\n\nYou may now log in to %uri_brief clicking on this link or copying and pasting it in your browser:\n\n%login_url\n\nThis is a one-time login, so it can be used only once. It expires after one day and nothing will happen if it's not used.\n\nAfter logging in, you will be redirected to %edit_uri so you can change your password.", $variables);
}
}
}
@@ -1276,12 +1318,12 @@ function user_configure_settings() {
$output = form_group(t('User registration settings'), $group);
// User e-mail settings.
- $group = form_textfield(t('Subject of welcome e-mail'), 'user_mail_welcome_subject', _user_mail_text('welcome_subject'), 70, 180, t('Customize the subject of your welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri.');
- $group .= form_textarea(t('Body of welcome e-mail'), 'user_mail_welcome_body', _user_mail_text('welcome_body'), 70, 10, t('Customize the body of the welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri.');
- $group .= form_textfield(t('Subject of welcome e-mail (awaiting admin approval)'), 'user_mail_approval_subject', _user_mail_text('approval_subject'), 70, 180, t('Customize the subject of your awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri.');
- $group .= form_textarea(t('Body of welcome e-mail (awaiting admin approval)'), 'user_mail_approval_body', _user_mail_text('approval_body'), 70, 10, t('Customize the body of the awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri.');
- $group .= form_textfield(t('Subject of password recovery e-mail'), 'user_mail_pass_subject', _user_mail_text('pass_subject'), 70, 180, t('Customize the Subject of your forgotten password e-mail.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri.');
- $group .= form_textarea(t('Body of password recovery e-mail'), 'user_mail_pass_body', _user_mail_text('pass_body'), 70, 10, t('Customize the body of the forgotten password e-mail.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri.');
+ $group = form_textfield(t('Subject of welcome e-mail'), 'user_mail_welcome_subject', _user_mail_text('welcome_subject'), 70, 180, t('Customize the subject of your welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri, %login_url.');
+ $group .= form_textarea(t('Body of welcome e-mail'), 'user_mail_welcome_body', _user_mail_text('welcome_body'), 70, 10, t('Customize the body of the welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri, %login_url.');
+ $group .= form_textfield(t('Subject of welcome e-mail (awaiting admin approval)'), 'user_mail_approval_subject', _user_mail_text('approval_subject'), 70, 180, t('Customize the subject of your awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri, %login_url.');
+ $group .= form_textarea(t('Body of welcome e-mail (awaiting admin approval)'), 'user_mail_approval_body', _user_mail_text('approval_body'), 70, 10, t('Customize the body of the awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri, %login_url.');
+ $group .= form_textfield(t('Subject of password recovery e-mail'), 'user_mail_pass_subject', _user_mail_text('pass_subject'), 70, 180, t('Customize the Subject of your forgotten password e-mail.') .' '. t('Available variables are:') .' %username, %site, %login_url, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri.');
+ $group .= form_textarea(t('Body of password recovery e-mail'), 'user_mail_pass_body', _user_mail_text('pass_body'), 70, 10, t('Customize the body of the forgotten password e-mail.') .' '. t('Available variables are:') .' %username, %site, %login_url, %uri, %uri_brief, %mailto, %login_uri, %edit_uri.');
$output .= form_group(t('User email settings'), $group);
// Picture settings.
@@ -1626,10 +1668,10 @@ function user_admin_account() {
array('data' => t('Username'), 'field' => 'u.name'),
array('data' => t('Status'), 'field' => 'u.status'),
array('data' => t('Roles')),
- array('data' => t('Last access'), 'field' => 'u.changed', 'sort' => 'desc'),
+ array('data' => t('Last access'), 'field' => 'u.login', 'sort' => 'desc'),
t('Operations')
);
- $sql = 'SELECT u.uid, u.name, u.status, u.changed FROM {users} u WHERE uid != 0';
+ $sql = 'SELECT u.uid, u.name, u.status, u.login, u.changed FROM {users} u WHERE uid != 0';
$sql .= tablesort_sql($header);
$result = pager_query($sql, 50);
@@ -1644,6 +1686,7 @@ function user_admin_account() {
}
$rows[] = array($account->uid, format_name($account), $status[$account->status], implode(', ', $roles), format_date($account->changed, 'small'), l(t('edit'), "user/$account->uid/edit", array(), $destination));
+
}
$pager = theme('pager', NULL, 50, 0, tablesort_pager());
diff --git a/modules/user/user.module b/modules/user/user.module
index a2d994816..329715990 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -392,7 +392,7 @@ function user_fields() {
}
else {
// Make sure we return the default fields at least
- $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'changed', 'status', 'timezone', 'language', 'init', 'data');
+ $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'changed', 'login', 'status', 'timezone', 'language', 'init', 'data');
}
}
@@ -644,6 +644,8 @@ function user_menu($may_cache) {
'callback' => 'user_page', 'access' => $user->uid == 0 && variable_get('user_register', 1), 'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'user/password', 'title' => t('request new password'),
'callback' => 'user_pass', 'access' => $user->uid == 0, 'type' => MENU_LOCAL_TASK);
+ $items[] = array('path' => 'user/reset', 'title' => t('reset password'),
+ 'callback' => 'user_pass_reset', 'access' => $user->uid == 0, 'type' => MENU_CALLBACK);
$items[] = array('path' => 'user/help', 'title' => t('help'),
'callback' => 'user_help_page', 'type' => MENU_CALLBACK);
@@ -809,7 +811,7 @@ function user_login($edit = array(), $msg = '') {
watchdog('user', t('Session opened for %name.', array('%name' => theme('placeholder', $user->name))));
// Update the user table timestamp noting user has logged in.
- db_query("UPDATE {users} SET changed = '%d' WHERE uid = '%s'", time(), $user->uid);
+ db_query("UPDATE {users} SET login = '%d' WHERE uid = '%s'", time(), $user->uid);
user_module_invoke('login', $edit, $user);
@@ -922,31 +924,27 @@ function user_pass() {
}
if ($account) {
$from = variable_get('site_mail', ini_get('sendmail_from'));
- $pass = user_password();
- // Save new password:
- user_save($account, array('pass' => $pass));
-
- // Mail new password:
- $variables = array('%username' => $account->name, '%site' => variable_get('site_name', 'drupal'), '%password' => $pass, '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $account->mail, '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE));
+ // Mail one time login URL and instructions.
+ $variables = array('%username' => $account->name, '%site' => variable_get('site_name', 'drupal'), '%login_url' => user_pass_reset_url($account), '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $account->mail, '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE));
$subject = _user_mail_text('pass_subject', $variables);
$body = _user_mail_text('pass_body', $variables);
$headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from";
$mail_success = user_mail($account->mail, $subject, $body, $headers);
if ($mail_success) {
- watchdog('user', t('Password mailed to %name at %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', $account->mail))));
- drupal_set_message(t('Your password and further instructions have been sent to your e-mail address.'));
+ watchdog('user', t('Password reset instructions mailed to %name at %email.', array('%name' => '<em>'. $account->name .'</em>', '%email' => '<em>'. $account->mail .'</em>')));
+ drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
}
else {
- watchdog('user', t('Error mailing password to %name at %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', $account->mail))), WATCHDOG_ERROR);
+ watchdog('user', t('Error mailing password reset instructions to %name at %email.', array('%name' => theme('placeholder', $account->name), '%email' => theme('placeholder', $account->mail))), WATCHDOG_ERROR);
drupal_set_message(t('Unable to send mail. Please contact the site admin.'));
}
drupal_goto('user');
}
else {
if ($edit) {
- drupal_set_message(t('You must provider either a username or e-mail address.'), 'error');
+ drupal_set_message(t('You must provide either a username or e-mail address.'), 'error');
}
// Display form:
$output = '<p>'. t('Enter your username <strong><em>or</em></strong> your e-mail address.') .'</p>';
@@ -957,6 +955,50 @@ function user_pass() {
}
}
+/**
+ * Menu callback; process one time login URL, and redirects to the user page on success.
+ */
+function user_pass_reset($uid, $timestamp, $hashed_pass) {
+ global $user;
+ // Time out, in seconds, until login URL expires. 24 hours = 86400 seconds.
+ $timeout = 86400;
+ $current = time();
+ // Some redundant checks for extra security ?
+ if ($timestamp < $current && is_numeric($uid) && $account = user_load(array('uid' => $uid, 'status' => 1)) ) {
+ // No time out for first time login.
+ if ($account->login && $current - $timestamp > $timeout) {
+ drupal_set_message(t('You have tried to use a one time login URL which has expired. Please request a new one using the form below.'));
+ drupal_goto('user/password');
+ }
+ if ($account->uid && !$user->uid && !empty($account) && $timestamp > $account->login && $timestamp < $current &&
+ $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
+ watchdog('user', t('One time login URL used for %name with timestamp %timestamp.', array('%name' => "<em>$account->name</em>", '%timestamp' => $timestamp)));
+ // Update the user table noting user has logged in.
+ // And this also makes this hashed password a one-time-only login.
+ db_query("UPDATE {users} SET login = '%d' WHERE uid = %d", time(), $account->uid);
+ // Now we can set the new user.
+ $user = $account;
+ // And proceed with normal login, going to user page.
+ user_module_invoke('login', $edit, $user);
+ drupal_set_message(t("You have used a one-time login, which won't be valid anymore."));
+ drupal_set_message(t('Please change your password.'));
+ drupal_goto('user/'. $user->uid .'/edit');
+ }
+ }
+ // Deny access, no more clues.
+ // Everything will be in the watchdog's URL for the administrator to check.
+ drupal_access_denied();
+}
+
+function user_pass_reset_url($account){
+ $timestamp = time();
+ return url("user/reset/$account->uid/$timestamp/".user_pass_rehash($account->pass, $timestamp, $account->login), NULL, NULL, TRUE);
+}
+
+function user_pass_rehash($password, $timestamp, $login){
+ return md5($timestamp . $password . $login);
+}
+
function user_register($edit = array()) {
global $user, $base_url;
@@ -977,7 +1019,7 @@ function user_register($edit = array()) {
$account = user_save('', array_merge(array('name' => $edit['name'], 'pass' => $pass, 'init' => $edit['mail'], 'mail' => $edit['mail'], 'roles' => array(_user_authenticated_id()), 'status' => (variable_get('user_register', 1) == 1 ? 1 : 0)), $edit));
watchdog('user', t('New user: %name %email.', array('%name' => theme('placeholder', $edit['name']), '%email' => theme('placeholder', '<'. $edit['mail'] .'>'))), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit'));
- $variables = array('%username' => $edit['name'], '%site' => variable_get('site_name', 'drupal'), '%password' => $pass, '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $edit['mail'], '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE));
+ $variables = array('%username' => $edit['name'], '%site' => variable_get('site_name', 'drupal'), '%password' => $pass, '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $edit['mail'], '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE), '%login_url' => user_pass_reset_url($account));
// The first user may login immediately, and receives a customized welcome e-mail.
if ($account->uid == 1) {
@@ -1256,15 +1298,15 @@ function _user_mail_text($messageid, $variables = array()) {
case 'welcome_subject':
return t('Account details for %username at %site', $variables);
case 'welcome_body':
- return t("%username,\n\nThank you for registering at %site. You may now log in to %login_uri using the following username and password:\n\nusername: %username\npassword: %password\n\nAfter logging in, you may wish to change your password at %edit_uri\n\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://www.drupal.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
+ return t("%username,\n\nThank you for registering at %site. You may now log in to %login_uri using the following username and password:\n\nusername: %username\npassword: %password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n%login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to %edit_uri so you can change your password.\n\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://www.drop.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
case 'approval_subject':
return t('Account details for %username at %site (pending admin approval)', $variables);
case 'approval_body':
- return t("%username,\n\nThank you for registering at %site. Your application for an account is currently pending approval. Once it has been granted, you may log in to %login_uri using the following username and password:\n\nusername: %username\npassword: %password\n\nAfter logging in, you may wish to change your password at %edit_uri\n\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://www.drupal.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
+ return t("%username,\n\nThank you for registering at %site. Your application for an account is currently pending approval. Once it has been granted, you may log in to %login_uri using the following username and password:\n\nusername: %username\npassword: %password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n%login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you may wish to change your password at %edit_uri\n\nYour new %site membership also enables to you to login to other Drupal powered websites (e.g. http://www.drop.org/) without registering. Just use the following Drupal ID and password:\n\nDrupal ID: %username@%uri_brief\npassword: %password\n\n\n-- %site team", $variables);
case 'pass_subject':
return t('Replacement login information for %username at %site', $variables);
case 'pass_body':
- return t("%username,\n\nHere is your new password for %site. You may now login to %login_uri using the following username and password:\n\nusername: %username\npassword: %password\n\nAfter logging in, you may wish to change your password at %edit_uri", $variables);
+ return t("%username,\n\nA request to reset the password for your account has been made at %site.\n\nYou may now log in to %uri_brief clicking on this link or copying and pasting it in your browser:\n\n%login_url\n\nThis is a one-time login, so it can be used only once. It expires after one day and nothing will happen if it's not used.\n\nAfter logging in, you will be redirected to %edit_uri so you can change your password.", $variables);
}
}
}
@@ -1276,12 +1318,12 @@ function user_configure_settings() {
$output = form_group(t('User registration settings'), $group);
// User e-mail settings.
- $group = form_textfield(t('Subject of welcome e-mail'), 'user_mail_welcome_subject', _user_mail_text('welcome_subject'), 70, 180, t('Customize the subject of your welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri.');
- $group .= form_textarea(t('Body of welcome e-mail'), 'user_mail_welcome_body', _user_mail_text('welcome_body'), 70, 10, t('Customize the body of the welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri.');
- $group .= form_textfield(t('Subject of welcome e-mail (awaiting admin approval)'), 'user_mail_approval_subject', _user_mail_text('approval_subject'), 70, 180, t('Customize the subject of your awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri.');
- $group .= form_textarea(t('Body of welcome e-mail (awaiting admin approval)'), 'user_mail_approval_body', _user_mail_text('approval_body'), 70, 10, t('Customize the body of the awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri.');
- $group .= form_textfield(t('Subject of password recovery e-mail'), 'user_mail_pass_subject', _user_mail_text('pass_subject'), 70, 180, t('Customize the Subject of your forgotten password e-mail.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri.');
- $group .= form_textarea(t('Body of password recovery e-mail'), 'user_mail_pass_body', _user_mail_text('pass_body'), 70, 10, t('Customize the body of the forgotten password e-mail.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri.');
+ $group = form_textfield(t('Subject of welcome e-mail'), 'user_mail_welcome_subject', _user_mail_text('welcome_subject'), 70, 180, t('Customize the subject of your welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri, %login_url.');
+ $group .= form_textarea(t('Body of welcome e-mail'), 'user_mail_welcome_body', _user_mail_text('welcome_body'), 70, 10, t('Customize the body of the welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri, %login_url.');
+ $group .= form_textfield(t('Subject of welcome e-mail (awaiting admin approval)'), 'user_mail_approval_subject', _user_mail_text('approval_subject'), 70, 180, t('Customize the subject of your awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri, %login_url.');
+ $group .= form_textarea(t('Body of welcome e-mail (awaiting admin approval)'), 'user_mail_approval_body', _user_mail_text('approval_body'), 70, 10, t('Customize the body of the awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' %username, %site, %password, %uri, %uri_brief, %mailto, %login_uri, %edit_uri, %login_url.');
+ $group .= form_textfield(t('Subject of password recovery e-mail'), 'user_mail_pass_subject', _user_mail_text('pass_subject'), 70, 180, t('Customize the Subject of your forgotten password e-mail.') .' '. t('Available variables are:') .' %username, %site, %login_url, %uri, %uri_brief, %mailto, %date, %login_uri, %edit_uri.');
+ $group .= form_textarea(t('Body of password recovery e-mail'), 'user_mail_pass_body', _user_mail_text('pass_body'), 70, 10, t('Customize the body of the forgotten password e-mail.') .' '. t('Available variables are:') .' %username, %site, %login_url, %uri, %uri_brief, %mailto, %login_uri, %edit_uri.');
$output .= form_group(t('User email settings'), $group);
// Picture settings.
@@ -1626,10 +1668,10 @@ function user_admin_account() {
array('data' => t('Username'), 'field' => 'u.name'),
array('data' => t('Status'), 'field' => 'u.status'),
array('data' => t('Roles')),
- array('data' => t('Last access'), 'field' => 'u.changed', 'sort' => 'desc'),
+ array('data' => t('Last access'), 'field' => 'u.login', 'sort' => 'desc'),
t('Operations')
);
- $sql = 'SELECT u.uid, u.name, u.status, u.changed FROM {users} u WHERE uid != 0';
+ $sql = 'SELECT u.uid, u.name, u.status, u.login, u.changed FROM {users} u WHERE uid != 0';
$sql .= tablesort_sql($header);
$result = pager_query($sql, 50);
@@ -1644,6 +1686,7 @@ function user_admin_account() {
}
$rows[] = array($account->uid, format_name($account), $status[$account->status], implode(', ', $roles), format_date($account->changed, 'small'), l(t('edit'), "user/$account->uid/edit", array(), $destination));
+
}
$pager = theme('pager', NULL, 50, 0, tablesort_pager());