* Copyright © 2014 Strangecode, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/*
* reset.php
*
* Facilitate password resets.
*
* @author Quinn Comendant
* @version 1.0
* @since 13 Sep 2014 12:44:26
*/
/********************************************************************
* CONFIG
********************************************************************/
require_once dirname(__FILE__) . '/_config.inc.php';
/********************************************************************
* MAIN
********************************************************************/
// If boomerang is set remember which page we came from so we can go back there.
if (getFormData('boomerang', false) && isset($_SERVER['HTTP_REFERER'])) {
$app->setBoomerangURL($_SERVER['HTTP_REFERER'], 'signup');
$app->setBoomerangURL($_SERVER['HTTP_REFERER'], 'previoussignup');
}
$app->sslOn();
if (getFormData('c')) {
//
// Reset code provided, let's see about resetting that password.
//
$nav->add(_("Reset your password"));
$main_template = 'reset_form.inc.html';
// Code validation occurs on GET and POST.
if (!$user_id = validatePasswordReset(getFormData('c'))) {
$app->dieURL('/reset.php');
}
if ('POST' == $_SERVER['REQUEST_METHOD']) {
$app->requireValidCSRFToken();
if ($fv->notEmpty('userpass', sprintf(_("%s cannot be blank."), _("Password")))) {
if (getFormData('complexity') < 20) {
$fv->addError('userpass', sprintf(_("Please choose a more complex password. Make it longer or add numbers and punctuation."), null), MSG_ERR, __FILE__, __LINE__);
}
}
if (!$fv->anyErrors()) {
// Set user password.
$auth->setPassword($user_id, getFormData('userpass'));
$user = User::get(array('user_id' => $user_id));
$app->raiseMsg(sprintf(_("Thanks %s, you have successfully changed your password. Go ahead and try it now. (Remember, your username is ‘%s’.)"), $user['first_name'], $user['username']), MSG_SUCCESS, __FILE__, __LINE__);
$app->dieURL('/login.php');
}
}
} else {
//
// No code provided, we assume they need one sent to them.
//
$nav->add(_("Doh, I forgot my credentials!"));
$main_template = 'forgot_form.inc.html';
if ('POST' == $_SERVER['REQUEST_METHOD']) {
$app->requireValidCSRFToken();
$user = User::get(array('email' => getFormData('email')));
if ($fv->notEmpty('email', sprintf(_("%s cannot be blank."), _("Email")))) {
$fv->stringLength('email', 0, 255, sprintf(_("%s must be %d-to-%d characters in length."), _("Email address"), 0, 255));
$fv->validateEmail('email');
if (false === $user) {
$fv->addError('email', sprintf(_("We couldn’t find an account with the email address %s."), getFormData('email')), MSG_ERR, __FILE__, __LINE__);
}
}
if (!$fv->anyErrors()) {
// Send email reset link.
if (requestPasswordReset($user)) {
$app->raiseMsg(sprintf(_("A password reset link was sent to %s. It will expire in one hour."), getFormData('email')), MSG_SUCCESS, __FILE__, __LINE__);
$app->dieURL('/login.php');
} else {
$app->raiseMsg(sprintf(_("Oops, something went wrong. Please try that again."), null), MSG_ERR, __FILE__, __LINE__);
}
}
}
}
/********************************************************************
* OUTPUT
********************************************************************/
$frm = resetForm(getFormData());
// Templates.
include 'header.inc.html';
include $main_template;
include 'footer.inc.html';
/********************************************************************
* FUNCTIONS
********************************************************************/
/*
* Reset form values to default, optionally merging posted form data.
*
* @access public
* @param bool $merge Merge existing values from $_REQUEST?
* @param array $new New values to merge with default values.
* @return array Initialized array of form values.
* @author Quinn Comendant
* @version 1.0
* @since 08 Nov 2014 20:14:22
*/
function resetForm($merge=false, $new=array())
{
$frm = array(
'email' => '',
'password' => '',
);
return $merge ? array_merge($frm, getFormData(), $new) : array_merge($frm, $new);
}
/*
*
*
* @access public
* @param
* @return
* @author Quinn Comendant
* @version 1.0
* @since 16 Nov 2014 17:45:40
*/
function requestPasswordReset($user)
{
$app =& App::getInstance();
// Reset code is the user_id + timestamp in hex, using the user's modified_datetime as part of the salt, which causes the code to become invalid after the user is modified.
$reset_code = addSignature(sprintf('%s-%s', $user['user_id'], dechex(time())), $user['modified_datetime'] . 'pybjojreoveulaw');
$email = new Email(array(
'to' => sprintf('%s %s <%s>', $user['first_name'], $user['last_name'], $user['email']),
'from' => sprintf('%s <%s>', $app->getParam('site_name'), $app->getParam('site_email')),
'subject' => _("Reset your password"),
));
$email->setTemplate('password_reset.inc.eml');
$email->replace(array(
'first_name' => $user['first_name'],
'username' => $user['username'],
'reset_url' => sprintf('%s/reset.php?c=%s', $app->getParam('site_url'), $reset_code),
));
return $email->send();
}
/*
*
*
* @access public
* @param
* @return
* @author Quinn Comendant
* @version 1.0
* @since 16 Nov 2014 17:45:40
*/
function validatePasswordReset($code)
{
$app =& App::getInstance();
// We can't trust this data until the signature is verified.
list($user_id, $time) = explode('-', removeSignature($code));
$user = User::get(array('user_id' => $user_id));
// Reset code is the user_id + timestamp in hex, using the user's modified_datetime as part of the salt, which causes the code to become invalid after the user is modified.
if (!$user || !verifySignature($code, $user['modified_datetime'] . 'pybjojreoveulaw')) {
// Reset code invalid.
$app->raiseMsg(_("Sorry, that password reset link is not valid."), MSG_ERR, __FILE__, __LINE__);
$app->logMsg(sprintf('Invalid reset code: %s', $code), LOG_NOTICE, __FILE__, __LINE__);
return false;
}
if (hexdec($time) < time() - 3600) {
// Reset code has expired (>= 1 hour ago).
$app->raiseMsg(_("Sorry, that password reset link has expired. Try again?"), MSG_ERR, __FILE__, __LINE__);
$app->logMsg(sprintf('Expired reset code %s (from %s)', $code, date('Y-m-d', hexdec($time))), LOG_NOTICE, __FILE__, __LINE__);
return false;
}
return $user_id;
}