<?php
// +---------------------------------------------------------------------------------------+
// | TenderSystem                                                                          |
// +---------------------------------------------------------------------------------------+
// | The contents of this file are subject to the TenderSystem Public License Version 1.1  |
// | ("License"); you may not use this file except in compliance with the License. You may |
// | obtain a copy of the License at http://www.tendersystem.com/tpl/                      |
// |                                                                                       |
// | Software distributed under the License is distributed on an "AS IS" basis, WITHOUT    |
// | WARRANTY OF ANY KIND, either express or implied. See the License for the specific     |
// | language governing rights and limitations under the License.                          |
// |                                                                                       |
// | All copies of the Covered Code must include the "Powered by TenderSystem" logo and    |
// | ValueCard copyright notice on every user interface screen and in every outgoing       |
// | email in the same form as they appear in the distribution.                            |
// |                                                                                       |
// | The Original Code is: TenderSystem                                                    |
// | The Initial Developer of the Original Code is ValueCard (Pty) Limited.                |
// | Portions created by ValueCard are Copyright (C) 2002 ValueCard (Pty) Limited.         |
// | All Rights Reserved.                                                                  |
// | Contributor(s): __________________.                                                   |
// +---------------------------------------------------------------------------------------+

/**
* password class
* @package TenderSystem
* @subpackage Password
* @copyright Copyright &copy; 2002, ValueCard (Pty) Ltd
* @license http://www.tendersystem.com/tpl/ TenderSystem Public License
* @version 
*/

// Security - ensure that file never called directly
// not required if global variables are off or API is hosted on a non-public server
if (eregi(basename(__FILE__),$_SERVER['PHP_SELF'])) {
    die ("You can't access this file directly...");
}

Class password {
	// user paramaters
	var $user;
	var $error;

	/**
	 * Validates that a password is okay to be reseted
	 * 
	 * @param array params Parameters
	 * @param mixed cfg The Config settings of tendersystem
	 * @param [ADOConnection] conn The connection to the database
	 *
	 * @param boolean TRUE on success Or FALSE on failure  
	 */
	function validate_reset($params,$user,$cfg,$conn) {
		// set that password not to be stored in database
		$cfg['smtp']['blob'] = "security";
		// set paramaters
		$this->user = $params;
		// check if params exist
		if(!$this->user['username']) {
			// missing username parameter
			$this->error[] = "94";
		}
		if(!$this->user['email']) {
			// missing email parameter
			$this->error[] = "92";
		}
		if(!$this->user['server_ip']) {
			// missing server ip address parameter
			$this->error[] = "118";
		}
		// errors 
		if(!empty($this->error)) {
			// Error in password class
			$this->error[] = "195";
			// response
			return FALSE;
		}
		$new_user = new user;
		// get the user id
		$usersid = $new_user->get_id_by_username($this->user['username'],$cfg,$conn);
		if(!$usersid) {
			// Username and/or Email address invalid
			$this->error[] = "196";
			// response
			return FALSE;
		}
		// get user information
		$this->user = $new_user->get_info($usersid,$cfg,$conn);
		if($this->user['email'] != $params['email']) {
			// Username and/or Email address invalid
			$this->error[] = "196";
			// response
			return FALSE;
		}
		// expire time 
		$expirestamp = ts_time($cfg) + $cfg['password']['expire'];
		$new_database = new database;
		// database table name 
		$table_name = "~password_reset";
		// setup data for insert 
		$insert = array(
			'id'			=> $new_database->get_next_id("~password_reset",$cfg,$conn),
			'user_id'		=> $this->user['id'],
			'authentication'=> md5(uniqid(rand())),
			'ip_address' 	=> $params['server_ip'],
			'status' 		=> "1",
			'created_by' 	=> "0"
		);
		// set created_by
		if($user) {
			$insert['created_by'] = $user['id'];
		}
		$new_database->setTime("expire",$insert,$expirestamp,$cfg);
		$new_database->setTime("created",$insert,"",$cfg);
		$new_database->parse_sql($table_name,$cfg);
		// execute 
		$conn->AutoExecute($table_name,$insert,"INSERT");
		// error handling
		if ($conn->ErrorMsg()) {
			// instantiate the error class and log
			$new_error = new error;
			$error_text = "SQL error in file ".__file__." on line ".__line__." Error:".$conn->ErrorMsg();
			$new_error->log("SQL","critical",$error_text,$cfg);
			// Error occurred while inserting into Database 
			$this->error[] = "1064";
			// response
			return FALSE;
		}
		// include language file 
		require($cfg['file'].'modules/password/language/'.$this->user['language'].'/password.php');
		// include email body template
		$html = $subject = FALSE;
		require($cfg['file'].'modules/password/templates/password_reset.php');
		// set message paramaters
		$message['classification'] = "password_reset";
		$message['body'] = $html;
		$message['name'] = $message['reference'] = $this->user['name']." ".$this->user['surname'];
		$message['email'] = $this->user['email'];
		$message['subject'] = $subject;
		// instantiate object
		$new_message = new message;
		// send the email
		$message_id = $new_message->send_email_message($message,$this->user['id'],$insert['created_by'],$cfg,$conn);
		// error handling
		if (!$message_id) {
			// Message errors 
			$this->error = $new_message->error;
			// Error sending email
			$this->error[] = "202";
			// response
			return FALSE;
		}
		// response
		return TRUE;
	}
	
	/**
	 * Validates that a password is should be reseted
	 * 
	 * @param array params Parameters
	 * @param mixed cfg The Config settings of tendersystem
	 * @param [ADOConnection] conn The connection to the database
	 *
	 * @param boolean TRUE on success Or FALSE on failure  
	 */
	function validate_confirm($params,$cfg,$conn) {
		// set paramaters
		$this->user = $params;
		// check if params exist 
		if(!$this->user['language']) {
			// Missing language
			$this->error[] = "101";
		}
		if(!$this->user['id']) {
			// Missing password_reset id
			$this->error[] = "208";
		}
		if(!$this->user['user_id']) {
			// Missing user id
			$this->error[] = "209";
		}
		if(!$this->user['authentication']) {
			// Missing authentication string
			$this->error[] = "210";
		}
		// errors 
		if(!empty($this->error)) {
			// Error in password class
			$this->error[] = "195";
			// reponse
			return FALSE;
		}
		// time now
		$date_now = date("Y-m-d",ts_time($cfg));
		$time_now = date("H:i:s",ts_time($cfg));
		// query password reset to determine if correct id, userid and authentication string
		$sqlstr = "SELECT * ";
		$sqlstr.= "FROM ~password_reset ";
		$sqlstr.= "WHERE id = '".$this->user['id']."' " ;
		$sqlstr.= "AND user_id = '".$this->user['user_id']."' " ;
		$sqlstr.= "AND authentication = '".$this->user['authentication']."' " ;
		$sqlstr.= "AND (expire_date > '".$date_now."' ";
		$sqlstr.= "OR (expire_date = '".$date_now."' ";
		$sqlstr.= "AND expire_time > '".$time_now."')) ";
		$new_database = new database;
		$new_database->parse_sql($sqlstr,$cfg);
		// execute sql
		$all = $conn->GetAll($sqlstr);
		// error handling
		if ($conn->ErrorMsg()) {
			// instantiate the error class and log
			$new_error = new error;
			$error_text = "SQL error in file ".__file__." on line ".__line__." Error:".$conn->ErrorMsg();
			$new_error->log("SQL","critical",$error_text,$cfg);
			// An error occurred while querying the database 
			$this->error[] = "1065";
			// Error in password class
			$this->error[] = "195";
			// response
			return FALSE;
       	} elseif (!$all) {
       		// Not Valid Confimation string 
			$this->error[] = "211";
			// response
			return FALSE;
       	} elseif (count($all) > 1) {
			// Duplicate password_reset confirmations in database
			$this->error[] = "212";
			// response
			return FALSE;
       	}
       	$row = $all[0];
		// remember status must = 1
		if($row['status'] != "1"){ 
			// Password_reset already confirm
			$this->error[] = "213";
			// response
			return FALSE;
		}
		$new_database = new database;
		$table_name = "~password_reset";
		$timestamp = ts_time($cfg);
		$update = array(
			'status'	 	=> "0",
			'expire_date'	=>	$row['expire_date'],
			'expire_time'	=>	$row['expire_time'],
			'deleted_by' 	=>  $row['user_id']
		);
		$where = "id = '".$this->user['id']."' ";
		$new_database->setTime("deleted",$update,"",$cfg);
		$new_database->parse_sql($table_name,$cfg);
		// execute sql
		$conn->AutoExecute($table_name,$update,"UPDATE",$where);
		// error handling
		if ($conn->ErrorMsg()) {
			// instantiate the error class and log
			$new_error = new error;
			$error_text = "SQL error in file ".__file__." on line ".__line__." Error:".$conn->ErrorMsg();
			$new_error->log("SQL","critical",$error_text,$cfg);
			// An error occurred while updating the database
			$this->error[] = "1066";
			// response
			return FALSE;
       	}
		// then you send the password via email
		$this->user['password_key'] = $this->generate_password();
		// reset user password
		$reset_password = $this->reset_password($cfg,$conn);
		if(!$reset_password) {
			// response error set in reset_password
			return FALSE;
		}
		// email it to the user
		$new_users = new user;
		$users_info = $new_users->get_info($row['user_id'],$cfg,$conn); 
		$this->user['name'] = $users_info['name'];
		$this->user['username'] = $users_info['username'];
		// include language file
		require($cfg['file'].'modules/password/language/'.$users_info['language'].'/password.php');
		// include email body template
		$html = FALSE;
		require($cfg['file'].'modules/password/templates/password_confirmation.php');
		// set message paramaters
		$message['classification'] = "password";
		$message['subject'] = $lang['subject_confirm'];
		$message['body'] = $html;
		$message['name'] = $message['reference'] = $users_info['name']." ".$users_info['surname'];
		$message['email'] = $users_info['email'];
		// instantiate object
		$new_message = new message;
		// don't send to backup
		$cfg['smtp']['backup']['status'] = FALSE;
		// set that password not to be stored in database
		$cfg['smtp']['blob'] = "security";
		// send the email
		if (!$new_message->send_email_message($message,$users_info['id'],$users_info['id'],$cfg,$conn)) {
			// Message errors 
			$this->error = $new_message->error;
			// Error sending email
			$this->error[] = "202";
			return FALSE;
		}
		// response
		return TRUE;
	}

	/**
	 * Send_message to user with password
	 * 
	 * @param array params Parameters
	 * @param mixed cfg The Config settings of tendersystem
	 * @param [ADOConnection] conn The connection to the database
	 *
	 * @param boolean TRUE on success Or FALSE on failure  
	 */
	function send_password($params,$usersid,$cfg,$conn) {
		// set paramaters
		$this->user = $params;
		// check if params exist 
		if(!$this->user['language']) {
			// Missing language
			$this->error[] = "101";
		}
		if(!$this->user['id']) {
			// Missing user id
			$this->error[] = "209";
		}
		// errors 
		if(!empty($this->error)) {
			// Error in password class
			$this->error[] = "195";
			// reponse
			return FALSE;
		}
		// then you send the password via email
		$this->user['password_key'] = $this->generate_password();
		$this->user['user_id'] = $this->user['id'];
		// reset user password
		$reset_password = $this->reset_password($cfg,$conn);
		if(!$reset_password) {
			// response error set in reset_password
			return FALSE;
		}
		// email it to the user
		// include language file
		require($cfg['file'].'modules/password/language/'.$this->user['language'].'/password.php');
		// include email body template
		$html = FALSE;
		require($cfg['file'].'modules/password/templates/new_user.php');
		// set message paramaters
		$message['classification'] = "password";
		$message['subject'] = $lang['subject_welcome'];
		$message['body'] = $html;
		$message['name'] = $message['reference'] = $this->user['name']." ".$this->user['surname'];
		$message['email'] = $this->user['email'];
		// instantiate object
		$new_message = new message;
		// do not email to backup
		$cfg['smtp']['backup']['status'] = FALSE;
		// set that password not to be stored in database
		$cfg['smtp']['blob'] = "security";
		// send the email
		$message_id = $new_message->send_email_message($message,$this->user['id'],$usersid,$cfg,$conn);
		if (!$message_id) {
			// Message errors 
			$this->error = $new_message->error;
			// Error sending email
			$this->error[] = "202";
			return FALSE;
		}
		// response
		return TRUE;
	}
	
	/**
	 * Sets the user status to 2
	 * 
	 * @param mixed cfg The Config settings of tendersystem
	 * @param [ADOConnection] conn The connection to the database
	 *
	 * @param boolean TRUE on success Or FALSE on failure  
	 */
	function reset_password($cfg,$conn) {
		if(!$this->user['user_id']) {
			// Error with user id
			$this->error[] = "209";
		}
		if(!$this->user['password_key']) {
			// Error with password
			$this->error[] = "95";
		}
		// errors 
		if(!empty($this->error)) {
			// Error in password class
			$this->error[] = "195";
			// response
			return FALSE;
		}
		$new_user = new user;
		// response
		return $new_user->update_password($this->hash_password($this->user['password_key'],$cfg),$this->user['user_id'],'2',$cfg,$conn);
	} 
	
	/**
	 * Generates a password
	 * 
	 * @return string password  
	 * 
	 */
	function generate_password() {
		// keep the array list words under 6 characters to prevent to long passwords
        $word_arr_one = array("blue", "green", "gold", "lime", "red", "orange", "dove", "grant", 
            "yellow", "silver", "grey", "purple", "watch", "radio", "chair", "table", "cup", "phone");
        $word_arr_two = array("walk", "talk", "time", "door", "sit", "book", "news", 
            "tall", "tank", "drum", "hill", "size", "table", "help", "tender",
            "hand", "cook", "main", "pack", "page", "hello" , "system");
		// determine how many variables are in string
		$count_one = sizeof($word_arr_one) - 1;
       	$count_two = sizeof($word_arr_two) - 1;
		// get randum number for the arrays
		mt_srand($this->make_seed());
		$random_one = mt_rand(0,$count_one);
		mt_srand($this->make_seed());
		$random_two = mt_rand(0,$count_two);
		// generate passwords
		$password_one = $word_arr_one[$random_one];
		$password_two = $word_arr_two[$random_two];
		mt_srand($this->make_seed());
		$password_number_one = mt_rand(1,9);
		mt_srand($this->make_seed());
		$password_number_two = mt_rand(1,9);
		// randomly select array numer
        $pwd = $password_one.$password_number_one.$password_number_two.$password_two;
		// set password
		return $pwd;
	}
	
	/**
	 * Hashes the password
	 * 
	 * @param string password 
	 * @param mixed cfg The Config settings of tendersystem
	 * 
	 */
	function hash_password($password,$cfg) {
		 // set hash function
		 $hash_function = $cfg['password']['hash'];
		 // check if function exists
		 if(!function_exists($hash_function)) {
		 	// set to default
		 	$hash_function = "md5";
		 }
		 // check password scheme
		 if($cfg['password']['scheme'] == "2") {
		 	// hash(pre_salt + password + post_salt)
		 	$hashed_pwd = $hash_function($cfg['password']['salt']['pre'].$password.$cfg['password']['salt']['post']);
		 } elseif($cfg['password']['scheme'] == "3") {
		 	$hash_1 = $hash_function($cfg['password']['salt']['pre']);
		 	$hash_2 = $hash_function($password);
		 	$hash_3 = $hash_function($cfg['password']['salt']['post']);
		 	$hashed_pwd = $hash_function($hash_1.$hash_2.$hash_3);
		 } else {
		 	$hashed_pwd = $hash_function($password);
		 }
        // set password
		return $hashed_pwd;
	}
	
	/**
	 * seed for the password random number
	 * 
	 */
	function make_seed() {
	   list($usec, $sec) = explode(' ', microtime());
	   return (float) $sec + ((float) $usec * 100000);
	}
	
	/**
	 * checks if a user id matches a password
	 * 
	 * @param integer usersid The Id of the user
	 * @param string password The Hashed Password
	 * @param mixed cfg The Config settings of tendersystem
	 * @param [ADOConnection] conn The connection to the database
	 *
	 * @param boolean TRUE on success Or FALSE on failure  
	 */
	function validate_hashed_password($usersid,$password,$cfg,$conn) {
		// check if params exist
		if(!$usersid) {
			// missing user id
			$this->error[] = "209";
		}
		if(!$password) {
			// missing password
			$this->error[] = "9";
		}
		// errors 
		if(!empty($this->error)) {
			// Error in password class
			$this->error[] = "195";
			// response
			return FALSE;
		}
		$new_user = new user;
		$password_database = $new_user->get_password($usersid,$cfg,$conn);
		if($password_database === $password) {
			return TRUE;	
		}
		return FALSE;
	}
	
	/**
	 * Changes a users password
	 * 
	 * @param array user The user information
	 * @param mixed cfg The Config settings of tendersystem
	 * @param [ADOConnection] conn The connection to the database
	 *
	 * @param boolean TRUE on success Or FALSE on failure  
	 */
	function change_password($user,$cfg,$conn) {
		// set the paramaters
		$this->user = $user;
		// if no session present return error message
		if (!$this->user['id']) {
			// no user id present
			$this->error[] = "22";
		}
		if (!$this->user['new_password']) {
			// no new password present
			$this->error[] = "4";
			return FALSE;
		}
		if (!empty($this->error)) {
			// error in session class 
			$this->error[] = "195";
			// response
			return FALSE;
		}
		$new_user = new user;
		// response
		return $new_user->update_password($this->user['new_password'],$this->user['id'],'1',$cfg,$conn);
	}
}
?>