Index: typo3/sysext/felogin/ext_emconf.php
===================================================================
--- typo3/sysext/felogin/ext_emconf.php (revision 5890)
+++ typo3/sysext/felogin/ext_emconf.php (working copy)
@@ -29,7 +29,7 @@
'clearCacheOnLoad' => 1,
'lockType' => '',
'author_company' => '',
- 'version' => '1.1.0',
+ 'version' => '1.2.0',
'constraints' => array(
'depends' => array(
'php' => '5.1.0-0.0.0',
Index: typo3/sysext/felogin/ext_tables.php
===================================================================
--- typo3/sysext/felogin/ext_tables.php (revision 5890)
+++ typo3/sysext/felogin/ext_tables.php (working copy)
@@ -17,11 +17,11 @@
--div--;LLL:EXT:cms/locallang_tca.xml:pages.tabs.access, starttime, endtime';
// Adds the redirect-field to the fe_group- and fe_users-table
-$tempColumns = Array (
- "felogin_redirectPid" => Array (
+$tempColumns = array (
+ "felogin_redirectPid" => array (
"exclude" => 1,
"label" => "LLL:EXT:felogin/locallang_db.xml:felogin_redirectPid",
- "config" => Array (
+ "config" => array (
"type" => "group",
"internal_type" => "db",
"allowed" => "pages",
@@ -30,6 +30,13 @@
"maxitems" => 1,
)
),
+ 'felogin_forgotHash' => array (
+ 'exclude' => 1,
+ 'label' => 'LLL:EXT:felogin/locallang_db.xml:felogin_forgotHash',
+ 'config' => array (
+ 'type' => 'passthrough',
+ )
+ ),
);
t3lib_div::loadTCA("fe_groups");
Index: typo3/sysext/felogin/ext_tables.sql
===================================================================
--- typo3/sysext/felogin/ext_tables.sql (revision 5890)
+++ typo3/sysext/felogin/ext_tables.sql (working copy)
@@ -11,7 +11,8 @@
# Table structure for table 'fe_users'
#
CREATE TABLE fe_users (
- felogin_redirectPid tinytext
+ felogin_redirectPid tinytext,
+ felogin_forgotHash varchar(80) default ''
);
Index: typo3/sysext/felogin/ext_typoscript_setup.txt
===================================================================
--- typo3/sysext/felogin/ext_typoscript_setup.txt (revision 5890)
+++ typo3/sysext/felogin/ext_typoscript_setup.txt (working copy)
@@ -6,6 +6,9 @@
#Template File
templateFile = EXT:felogin/template.html
+ #baseURL for the link generation
+ feloginBaseURL =
+
#wrapContentInBaseClass
wrapContentInBaseClass = 1
@@ -24,7 +27,11 @@
showForgotPasswordLink =
showPermaLogin =
+ # time in hours how long the link for forget password is valid
+ forgotLinkHashValidTime = 12
+ newPasswordMinLength = 6
+
welcomeHeader_stdWrap {
wrap =
|
}
@@ -60,6 +67,14 @@
wrap = |
}
+ changePasswordHeader_stdWrap {
+ wrap = |
+ }
+ changePasswordMessage_stdWrap {
+ wrap = |
+ }
+
+
# stdWrap for fe_users fields used in Messages
userfields {
username {
@@ -86,7 +101,7 @@
# Allowed Referrer-Redirect-Domains:
domains =
-
+ dateFormat = Y-m-d H:i
}
plugin.tx_felogin_pi1._CSS_DEFAULT_STYLE (
Index: typo3/sysext/felogin/pi1/class.tx_felogin_pi1.php
===================================================================
--- typo3/sysext/felogin/pi1/class.tx_felogin_pi1.php (revision 5890)
+++ typo3/sysext/felogin/pi1/class.tx_felogin_pi1.php (working copy)
@@ -108,6 +108,8 @@
$content='';
if ($this->piVars['forgot']) {
$content .= $this->showForgot();
+ } elseif ($this->piVars['forgothash']) {
+ $content .= $this->changePassword();
} else {
if($this->userIsLoggedIn && !$this->logintype) {
$content .= $this->showLogout();
@@ -139,65 +141,230 @@
protected function showForgot() {
$subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_FORGOT###');
$subpartArray = $linkpartArray = array();
+ $postData = t3lib_div::_POST($this->prefixId);
- if ($this->piVars['forgot_email']) {
- if (t3lib_div::validEmail($this->piVars['forgot_email'])) {
- // look for user record and send the password
+ if ($postData['forgot_email']) {
+
+ // get hashes for compare
+ $postedHash = $postData['forgot_hash'];
+ $hashData = $GLOBALS['TSFE']->fe_user->getKey('ses', 'forgot_hash');
+
+
+ if ($postedHash === $hashData['forgot_hash']) {
+ $row = FALSE;
+
+ // look for user record
+ $data = $GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['forgot_email'], 'fe_users');
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
- 'uid, username, password',
+ 'uid, username, password, email',
'fe_users',
- 'email='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['forgot_email'], 'fe_users').' AND pid IN ('.$GLOBALS['TYPO3_DB']->cleanIntList($this->spid).') '.$this->cObj->enableFields('fe_users')
+ '(email=' . $data .' OR username=' . $data . ') AND pid IN ('.$GLOBALS['TYPO3_DB']->cleanIntList($this->spid).') '.$this->cObj->enableFields('fe_users')
);
if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
$row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
- $msg = sprintf($this->pi_getLL('ll_forgot_email_password', '', 0), $this->piVars['forgot_email'], $row['username'], $row['password']);
- } else {
- $msg = sprintf($this->pi_getLL('ll_forgot_email_nopassword', '', 0), $this->piVars['forgot_email']);
}
-
- // Generate new password with md5 and save it in user record
- if ($GLOBALS['TYPO3_DB']->sql_num_rows($res) && t3lib_extMgm::isLoaded('kb_md5fepw')) {
- $newPass = $this->generatePassword(8);
- $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
- 'fe_users',
- 'uid=' . $row['uid'],
- array('password' => md5($newPass))
- );
- $msg = sprintf($this->pi_getLL('ll_forgot_email_password', '', 0),$this->piVars['forgot_email'], $row['username'], $newPass);
+ if ($row) {
+ // generate an email with the hashed link
+ $error = $this->generateAndSendHash($row);
}
-
- $this->cObj->sendNotifyEmail($msg, $this->piVars['forgot_email'], '', $this->conf['email_from'], $this->conf['email_fromName'], $this->conf['replyTo']);
- $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap(sprintf($this->pi_getLL('ll_forgot_message_emailSent', '', 1), '' . htmlspecialchars($this->piVars['forgot_email']) .''), $this->conf['forgotMessage_stdWrap.']);
+ // generate message
+ if ($error) {
+ $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap($error, $this->conf['forgotMessage_stdWrap.']);
+ } else {
+ $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap($this->pi_getLL('ll_forgot_reset_message_emailSent', '', 1), $this->conf['forgotMessage_stdWrap.']);
+ }
$subpartArray['###FORGOT_FORM###'] = '';
} else {
//wrong email
- $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_message', $this->conf['forgotMessage_stdWrap.']);
+ $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_reset_message', $this->conf['forgotMessage_stdWrap.']);
$markerArray['###BACKLINK_LOGIN###'] = '';
}
} else {
- $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_message', $this->conf['forgotMessage_stdWrap.']);
+ $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('forgot_reset_message', $this->conf['forgotMessage_stdWrap.']);
$markerArray['###BACKLINK_LOGIN###'] = '';
}
$markerArray['###BACKLINK_LOGIN###'] = $this->getPageLink($this->pi_getLL('ll_forgot_header_backToLogin', '', 1), array());
$markerArray['###STATUS_HEADER###'] = $this->getDisplayText('forgot_header', $this->conf['forgotHeader_stdWrap.']);
- $markerArray['###LEGEND###'] = $this->pi_getLL('send_password', '', 1);
+ $markerArray['###LEGEND###'] = $this->pi_getLL('reset_password', '', 1);
$markerArray['###ACTION_URI###'] = $this->getPageLink('', array($this->prefixId . '[forgot]'=>1), true);
$markerArray['###EMAIL_LABEL###'] = $this->pi_getLL('your_email', '', 1);
$markerArray['###FORGOT_PASSWORD_ENTEREMAIL###'] = $this->pi_getLL('forgot_password_enterEmail', '', 1);
$markerArray['###FORGOT_EMAIL###'] = $this->prefixId.'[forgot_email]';
- $markerArray['###SEND_PASSWORD###'] = $this->pi_getLL('send_password', '', 1);
+ $markerArray['###SEND_PASSWORD###'] = $this->pi_getLL('reset_password', '', 1);
+
+ $markerArray['###DATA_LABEL###'] = $this->pi_getLL('ll_enter_your_data', '', 1);
+
+
+
$markerArray = array_merge($markerArray, $this->getUserFieldMarkers());
+ // generate hash
+ $hash = md5($this->generatePassword(3));
+ $markerArray['###FORGOTHASH###'] = $hash;
+ // set hash in feuser session
+ $GLOBALS['TSFE']->fe_user->setKey('ses', 'forgot_hash', array('forgot_hash' => $hash));
+
+
return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
}
/**
+ * This function checks the hash from link and checks the validity. If it's valid it shows the form for
+ * changing the password and process the change of password after submit, if not valid it returns the error message
+ *
+ * @return string The content.
+ */
+ protected function changePassword() {
+
+ $subpartArray = $linkpartArray = array();
+ $done = false;
+
+ $minLength = intval($this->conf['newPasswordMinLength']) ? intval($this->conf['newPasswordMinLength']) : 6;
+
+ $subpart = $this->cObj->getSubpart($this->template, '###TEMPLATE_CHANGEPASSWORD###');
+
+ $markerArray['###STATUS_HEADER###'] = $this->getDisplayText('change_password_header', $this->conf['changePasswordHeader_stdWrap.']);
+ $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText('change_password_message', $this->conf['changePasswordMessage_stdWrap.']), $minLength);
+
+ $markerArray['###BACKLINK_LOGIN###'] = '';
+ $uid = $this->piVars['user'];
+ $piHash = $this->piVars['forgothash'];
+
+ $hash = explode('|', $piHash);
+ if (intval($uid) == 0) {
+ $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('change_password_notvalid_message', $this->conf['changePasswordMessage_stdWrap.']);
+ $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
+ } else {
+ $user = $this->pi_getRecord('fe_users', intval($uid));
+ $userHash = $user['felogin_forgotHash'];
+ $compareHash = explode('|', $userHash);
+
+ if (!$compareHash || !$compareHash[1] || $compareHash[0] < time() || $hash[0] != $compareHash[0] || md5($hash[1]) != $compareHash[1]) {
+ $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('change_password_notvalid_message',$this->conf['changePasswordMessage_stdWrap.']);
+ $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
+ } else {
+ // all is fine, continue with new password
+ $postData = t3lib_div::_POST($this->prefixId);
+
+ if ($postData['changepasswordsubmit']) {
+ if (strlen($postData['password1']) < $minLength) {
+ $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText('change_password_tooshort_message', $this->conf['changePasswordMessage_stdWrap.']), $minLength);
+ } elseif ($postData['password1'] != $postData['password2']) {
+ $markerArray['###STATUS_MESSAGE###'] = sprintf($this->getDisplayText('change_password_notequal_message', $this->conf['changePasswordMessage_stdWrap.']), $minLength);
+ } else {
+ $newPass = $postData['password1'];
+
+ if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['password_changed']) {
+ $_params = array(
+ 'user' => $user,
+ 'newPassword' => $newPass,
+ );
+ foreach($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['password_changed'] as $_funcRef) {
+ if ($_funcRef) {
+ t3lib_div::callUserFunction($_funcRef, $_params, $this);
+ }
+ }
+ $newPass = $_params['newPassword'];
+ }
+
+ // save new password and clear DB-hash
+ $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
+ 'fe_users',
+ 'uid=' . $user['uid'],
+ array('password' => $newPass, 'felogin_forgotHash' => '')
+ );
+ $markerArray['###STATUS_MESSAGE###'] = $this->getDisplayText('change_password_done_message', $this->conf['changePasswordMessage_stdWrap.']);
+ $done = true;
+ $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
+ $markerArray['###BACKLINK_LOGIN###'] = $this->getPageLink($this->pi_getLL('ll_forgot_header_backToLogin', '', 1), array());
+ }
+ }
+
+ if (!$done) {
+ // Change password form
+ $markerArray['###ACTION_URI###'] = $this->pi_getPageLink($GLOBALS['TSFE']->id, '', array(
+ $this->prefixId . '[user]' => $user['uid'],
+ $this->prefixId . '[forgothash]' => $piHash
+ ));
+ $markerArray['###LEGEND###'] = $this->pi_getLL('change_password', '', 1);
+ $markerArray['###NEWPASSWORD1_LABEL###'] = $this->pi_getLL('newpassword_label1', '', 1);
+ $markerArray['###NEWPASSWORD2_LABEL###'] = $this->pi_getLL('newpassword_label2', '', 1);
+ $markerArray['###NEWPASSWORD1###'] = $this->prefixId . '[password1]';
+ $markerArray['###NEWPASSWORD2###'] = $this->prefixId . '[password2]';
+ $markerArray['###STORAGE_PID###'] = $this->spid;
+ $markerArray['###SEND_PASSWORD###'] = $this->pi_getLL('change_password', '', 1);
+ $markerArray['###FORGOTHASH###'] = $piHash;
+ }
+ }
+ }
+
+ return $this->cObj->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
+ }
+
+ /**
+ * generates a hashed link and send it with email
+ *
+ * @param array $user contains user data
+ * @return string Empty string with success, error message with no success
+ */
+ protected function generateAndSendHash($user) {
+ $hours = intval($this->conf['forgotLinkHashValidTime']) > 0 ? intval($this->conf['forgotLinkHashValidTime']) : 24;
+ $validEnd = time() + 3600 * $hours;
+ $validEndString = date($this->conf['dateFormat'], $validEnd);
+
+ $hash = md5(rand());
+ $randHash = $validEnd . '|' . $hash;
+ $randHashDB = $validEnd . '|' . md5($hash);
+
+ //write hash to DB
+ $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery('fe_users', 'uid=' . $user['uid'], array('felogin_forgotHash' => $randHashDB));
+
+ // send hashlink to user
+ $this->conf['linkPrefix'] = -1;
+ $isAbsRelPrefix = !empty($GLOBALS['TSFE']->absRefPrefix);
+ $isBaseURL = !empty($GLOBALS['TSFE']->baseUrl);
+ $isFeloginBaseURL = !empty($this->conf['feloginBaseURL']);
+
+ if ($isFeloginBaseURL) {
+ // first priority
+ $this->conf['linkPrefix'] = $this->conf['feloginBaseURL'];
+ } else {
+ if ($isBaseURL) {
+ // 3rd priority
+ $this->conf['linkPrefix'] = $GLOBALS['TSFE']->baseUrl;
+ }
+ }
+
+ if ($this->conf['linkPrefix'] == -1 && !$isAbsRelPrefix) {
+ // no preix is set, return the error
+ return $this->pi_getLL('ll_change_password_nolinkprefix_message');
+ }
+
+ $link = ($isAbsRelPrefix ? '' : $this->conf['linkPrefix']) . $this->pi_getPageLink($GLOBALS['TSFE']->id, '', array(
+ $this->prefixId . '[user]' => $user['uid'],
+ $this->prefixId . '[forgothash]' => $randHash
+ ));
+
+ $msg = sprintf($this->pi_getLL('ll_forgot_validate_reset_password', '', 0), $user['username'], $link, $validEndString);
+
+ // no RDCT - Links for security reasons
+ $oldSetting = $GLOBALS['TSFE']->config['config']['notification_email_urlmode'];
+ $GLOBALS['TSFE']->config['config']['notification_email_urlmode'] = 0;
+ // send the email
+ $this->cObj->sendNotifyEmail($msg, $user['email'], '', $this->conf['email_from'], $this->conf['email_fromName'], $this->conf['replyTo']);
+ // restore settings
+ $GLOBALS['TSFE']->config['config']['notification_email_urlmode'] = $oldSetting;
+
+ return '';
+ }
+
+ /**
* Shows logout form
*
* @return string The content.
Index: typo3/sysext/felogin/pi1/locallang.xml
===================================================================
--- typo3/sysext/felogin/pi1/locallang.xml (revision 5890)
+++ typo3/sysext/felogin/pi1/locallang.xml (working copy)
@@ -16,18 +16,29 @@
+Another possibility is that cookies might be disabled in your web browser.
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: typo3/sysext/felogin/template.html
===================================================================
--- typo3/sysext/felogin/template.html (revision 5890)
+++ typo3/sysext/felogin/template.html (working copy)
@@ -144,10 +144,13 @@