<?php /********************************************************************************* * * TimeTrex is a Workforce Management program developed by * TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License version 3 as published by * the Free Software Foundation with the addition of the following permission * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED * WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * 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 Affero General Public License for more * details. * * * You should have received a copy of the GNU Affero General Public License along * with this program; if not, see http://www.gnu.org/licenses or write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. * * * You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite * #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com. * * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License version 3. * * * In accordance with Section 7(b) of the GNU Affero General Public License * version 3, these Appropriate Legal Notices must retain the display of the * "Powered by TimeTrex" logo. If the display of the logo is not reasonably * feasible for technical reasons, the Appropriate Legal Notices must display * the words "Powered by TimeTrex". * ********************************************************************************/ require_once( '../../../includes/global.inc.php' ); forceNoCacheHeaders(); //Send headers to disable caching. TTi18n::chooseBestLocale(); extract( FormVariables::GetVariables( [ 'action', 'email', 'key', 'email_sent', 'password', 'password2', ] ) ); $rl = TTNew( 'RateLimit' ); /** @var RateLimit $rl */ $rl->setID( 'client_contact_password_reset_' . Misc::getRemoteIPAddress() ); $rl->setAllowedCalls( 10 ); $rl->setTimeFrame( 900 ); //15 minutes $validator = new Validator(); //All HTML special chars are encoded prior to getting here, which makes things like "&" be saved as "&", corrupting passwords. $password = FormVariables::reverseSanitize( $password ); $password2 = FormVariables::reverseSanitize( $password2 ); $action = Misc::findSubmitButton(); Debug::Text( 'Action: ' . $action, __FILE__, __LINE__, __METHOD__, 10 ); switch ( $action ) { case 'change_password': Debug::Text( 'Change Password: ' . $key, __FILE__, __LINE__, __METHOD__, 10 ); if ( $rl->check() == false ) { Debug::Text( 'Excessive change password attempts... Preventing resets from: ' . Misc::getRemoteIPAddress() . ' for up to 15 minutes...', __FILE__, __LINE__, __METHOD__, 10 ); sleep( 5 ); //Excessive password attempts, sleep longer. $action = 'reset_password'; } else { $cclf = TTnew( 'ClientContactListFactory' ); /** @var ClientContactListFactory $cclf */ $cclf->getByPasswordResetKey( $key ); if ( $cclf->getRecordCount() == 1 ) { Debug::Text( 'FOUND Password reset key! ', __FILE__, __LINE__, __METHOD__, 10 ); $cc_obj = $cclf->getCurrent(); if ( $cc_obj->checkPasswordResetKey( $key ) == true ) { $user_name = $cc_obj->getUserName(); //Make sure passwords match if ( $password == $password2 ) { //Change password $cc_obj->setPassword( $password ); //Password reset key is cleared when password is changed. if ( $cc_obj->isValid() ) { $cc_obj->Save(); Debug::Text( 'Password Change succesful!', __FILE__, __LINE__, __METHOD__, 10 ); $rl->delete(); //Clear password reset rate limit upon successful reset. //Redirect::Page( URLBuilder::getURL( array('password_reset' => 1 ), 'Login.php' ) ); Redirect::Page( 'https://www.timetrex.com/store?step=login' ); } } else { $validator->isTrue( 'password', false, 'Passwords do not match' ); } } else { Debug::Text( 'DID NOT FIND Valid Password reset key! ', __FILE__, __LINE__, __METHOD__, 10 ); $action = 'reset_password'; } } else { Debug::Text( 'DID NOT FIND Password reset key! ', __FILE__, __LINE__, __METHOD__, 10 ); $action = 'reset_password'; } Debug::text( 'Change Password Failed! Attempt: ' . $rl->getAttempts(), __FILE__, __LINE__, __METHOD__, 10 ); sleep( ( $rl->getAttempts() * 0.5 ) ); //If email is incorrect, sleep for some time to slow down brute force attacks. } break; case 'password_reset': //Debug::setVerbosity( 11 ); Debug::Text( 'Key: ' . $key, __FILE__, __LINE__, __METHOD__, 10 ); if ( $rl->check() == false ) { Debug::Text( 'Excessive reset password attempts... Preventing resets from: ' . Misc::getRemoteIPAddress() . ' for up to 15 minutes...', __FILE__, __LINE__, __METHOD__, 10 ); sleep( 5 ); //Excessive password attempts, sleep longer. $action = 'reset_password'; } else { $cclf = TTnew( 'ClientContactListFactory' ); /** @var ClientContactListFactory $cclf */ $cclf->getByPasswordResetKey( $key ); if ( $cclf->getRecordCount() == 1 ) { Debug::Text( 'FOUND Password reset key! ', __FILE__, __LINE__, __METHOD__, 10 ); $cc_obj = $cclf->getCurrent(); if ( $cc_obj->checkPasswordResetKey( $key ) == true ) { $user_name = $cc_obj->getUserName(); $rl->delete(); //Clear password reset rate limit upon successful reset. } else { Debug::Text( 'DID NOT FIND Valid Password reset key! ', __FILE__, __LINE__, __METHOD__, 10 ); $action = 'reset_password'; } } else { Debug::Text( 'DID NOT FIND Password reset key! ', __FILE__, __LINE__, __METHOD__, 10 ); $action = 'reset_password'; } Debug::text( 'Reset Password Failed! Attempt: ' . $rl->getAttempts(), __FILE__, __LINE__, __METHOD__, 10 ); sleep( ( $rl->getAttempts() * 0.5 ) ); //If email is incorrect, sleep for some time to slow down brute force attacks. } break; case 'reset_password': //Debug::setVerbosity( 11 ); Debug::Text( 'Email: ' . $email, __FILE__, __LINE__, __METHOD__, 10 ); if ( $rl->check() == false ) { Debug::Text( 'Excessive reset password attempts... Preventing resets from: ' . Misc::getRemoteIPAddress() . ' for up to 15 minutes...', __FILE__, __LINE__, __METHOD__, 10 ); sleep( 5 ); //Excessive password attempts, sleep longer. $validator->isTrue( 'email', false, TTi18n::getText( 'Email address was not found in our database (z)' ) ); } else { $cclf = TTnew( 'ClientContactListFactory' ); /** @var ClientContactListFactory $cclf */ //$cclf->getByHomeEmailOrWorkEmail( $email ); $cclf->getByUserName( $email ); if ( $cclf->getRecordCount() == 1 ) { $cc_obj = $cclf->getCurrent(); $cc_obj->sendPasswordResetEmail(); Debug::Text( 'Found USER! ', __FILE__, __LINE__, __METHOD__, 10 ); $rl->delete(); //Clear password reset rate limit upon successful login. Redirect::Page( URLBuilder::getURL( [ 'email_sent' => 1, 'email' => $email ], Environment::getBaseURL() . 'html5/client/ForgotPassword.php' ) ); } else { //Error Debug::Text( 'DID NOT FIND USER! ', __FILE__, __LINE__, __METHOD__, 10 ); $validator->isTrue( 'email', false, 'Email address was not found in our database' ); } Debug::text( 'Reset Password Failed! Attempt: ' . $rl->getAttempts(), __FILE__, __LINE__, __METHOD__, 10 ); sleep( ( $rl->getAttempts() * 0.5 ) ); //If email is incorrect, sleep for some time to slow down brute force attacks. } break; default: break; } $BASE_URL = '../'; $META_TITLE = TTi18n::getText( 'Password Reset' ); require( '../../../includes/Header.inc.php' ); ?> <div id="contentContainer" class="content-container"> <div class="container"> <div class="row"> <div class="col-12"> <div id="contentBox-ForgotPassword"> <div class="textTitle2"><?php echo TTi18n::getText( 'Password Reset' ) ?></div> <?php if ( $action == 'password_reset' || $action == 'change_password' ) { ?> <?php if ( !$validator->isValid() ) { ?> <div class="alert alert-danger alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button> <?php echo TTi18n::getText( 'Incorrect Input!' ); ?> <script language=JavaScript> var form_modified = true; </script> <br> <?php echo $validator->geterrors(); ?> </div> <?php } ?> <form method="post" name="password_reset" class="form-horizontal" action=""> <div class="form-group row"> <label class="col-sm-3 col-xs-12 control-label"><?php echo TTi18n::getText( 'Email:' ) ?> </label> <div class="col-sm-9 col-xs-12"> <p class="form-control-static"><?php echo $user_name; ?></p> </div> </div> <div class="form-group row"> <label for="password" class="col-xs-12 col-sm-3 control-label"><?php echo TTi18n::getText( 'New Password:' ) ?> </label> <div class="col-xs-12 col-sm-9"> <input type="password" id="password" class="form-control" name="password" autocomplete="new-password"> </div> </div> <div class="form-group row"> <label for="password2" class="col-xs-12 col-sm-3 control-label"><?php echo TTi18n::getText( 'New Password (confirm):' ) ?> </label> <div class="col-xs-12 col-sm-9"> <input type="password" id="password2" class="form-control" name="password2" autocomplete="new-password"> </div> </div> <input type="hidden" name="key" value="<?php echo $key; ?>"> <input type="submit" class="button btn btn-default" name="action:change_password" value="<?php echo TTi18n::getText( 'Change Password' ) ?>"> </form> <?php } else { if ( $email_sent == 1 ) { ?> <div id="rowWarning" class="text-center"> <?php echo TTi18n::getText( 'An email has been sent to' ) . ' <b>' . $email . '</b> ' . TTi18n::getText( 'with instructions on how to change your password.' ); ?> </div> </div> <?php } else { ?> <?php if ( !$validator->isValid() ) { ?> <div class="alert alert-danger alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button> <?php echo TTi18n::getText( 'Incorrect Input!' ); ?> <script language=JavaScript> var form_modified = true; </script> <br> <?php echo $validator->geterrors(); ?> </div> <?php } ?> <form method="post" name="password_reset" class="form-horizontal" action=""> <div class="form-group row"> <label for="email" class="col-xs-12 col-sm-3 control-label"><?php echo TTi18n::getText( 'Email Address:' ); ?> </label> <div class="col-xs-12 col-sm-9"> <input type="text" id="email" class="form-control" name="email" value="<?php echo $email; ?>"> </div> </div> <input type="submit" class="button btn btn-default" name="action:reset_password" value="<?php echo TTi18n::getText( 'Reset Password' ); ?>"> </form> </div> <?php } } ?> </div> </div> </div> </div> </div> <?php require( '../../../includes/Footer.inc.php' ); ?>