<?php 
/**
* @version		$Id: elxis.auth.php 2578 2024-05-05 19:36:57Z IOS $
* @package		Elxis
* @subpackage	Component User / Authentication
* @copyright	Copyright (c) 2006-2024 Elxis CMS (https://www.elxis.org). All rights reserved.
* @license		Elxis Public License ( https://www.elxis.org/elxis-public-license.html )
* @author		Elxis Team ( https://www.elxis.org )
* @description 	Elxis CMS is free software. Read the license for copyright notices and details
*/

defined('_ELXIS_') or die ('Direct access to this location is not allowed');


class elxisAuthentication {


	/********************/
	/* MAGIC CONTRUCTOR */
	/********************/
	public function __construct($params) {
	}


	/******************************/
	/* AUTHENTICATE AN ELXIS USER */
	/******************************/
	public function authenticate(&$response, $options=array()) {
		$db = eFactory::getDB();

		$is_email_login = false;
		$uname = (isset($options['uname'])) ? trim($options['uname']) : '';
		$pword = (isset($options['pword'])) ? trim($options['pword']) : '';
		$otp = (isset($options['otp'])) ? trim($options['otp']) : '';
		if ($uname == '') {
			$eLang = eFactory::getLang();
			$response->errormsg = sprintf($eLang->get('FIELDNOEMPTY'), $eLang->get('USERNAME'));
			return false;
		}
		if ($pword == '') {
			$eLang = eFactory::getLang();
			$response->errormsg = sprintf($eLang->get('FIELDNOEMPTY'), $eLang->get('PASSWORD'));
			return false;
		}

		if (strlen($pword) < 6) {
			$response->errormsg = eFactory::getLang()->get('PASSTOOSHORT');
			return false;
		}
		if (strpos($uname, '@') !== false) {
			if (!filter_var($uname, FILTER_VALIDATE_EMAIL)) {
				$response->errormsg = eFactory::getLang()->get('INVALIDEMAIL');
				return false;
			}
			$is_email_login = true;
		}

		//apply elxis uname/pword security policy
		if (!$is_email_login) {
			$uname_san = trim(preg_replace('/[^a-z0-9\_\-\.+]/i', '', $uname));
			if ($uname !== $uname_san) {
				$eLang = eFactory::getLang();
				$response->errormsg = sprintf($eLang->get('FIELDNOACCCHAR'), $eLang->get('USERNAME'));
				return false;
			}
		}
		$pword_san = trim(preg_replace('/[^a-z0-9\_\-\.\!\@\#\$\&\(\)\{\}\[\]\?\<\>+]/i', '', $pword));
		if ($pword !== $pword_san) {
			$eLang = eFactory::getLang();
			$response->errormsg = sprintf($eLang->get('FIELDNOACCCHAR'), $eLang->get('PASSWORD'));
			return false;
		}

		$must_otp = false;
		if (eFactory::getElxis()->getConfig('TWOFA') != '') {
			$must_otp = true;
			if ($otp == '') {
				$response->errormsg = eFactory::getLang()->get('VCODE_WRONG');
				return false;
			}
		}

		$sql = "SELECT ".$db->quoteId('uid').", ".$db->quoteId('firstname').", ".$db->quoteId('lastname').", ".$db->quoteId('uname').","
		."\n ".$db->quoteId('pword').", ".$db->quoteId('block').", ".$db->quoteId('gid').", ".$db->quoteId('email').","
		."\n ".$db->quoteId('expiredate').", ".$db->quoteId('otp')." FROM ".$db->quoteId('#__users');
		if ($is_email_login) {
			$sql .= " WHERE ".$db->quoteId('email')." = :unml";
		} else {
			$sql .= " WHERE ".$db->quoteId('uname')." = :unml";
		}
		$stmt = $db->prepareLimit($sql, 0, 1);
		$stmt->execute(array(':unml' => $uname));
		$row = $stmt->fetch(PDO::FETCH_ASSOC);
		if (!$row) {
			$eLang = eFactory::getLang();
			$response->errormsg = $eLang->get('USERNOTFOUND').' / '.eFactory::getLang()->get('INVALIDPASS');
			return false;
		}
		$encpass = eFactory::getElxis()->obj('crypt')->getEncryptedPassword($pword);
		if ($encpass != $row['pword']) {
			$response->errormsg = eFactory::getLang()->get('USERNOTFOUND').' / '.eFactory::getLang()->get('INVALIDPASS');
			return false;
		}
		if (intval($row['block']) == 1) {
			$response->errormsg = eFactory::getLang()->get('YACCBLOCKED');
			return false;
		}
		$expiredate = trim($row['expiredate']);
		if (($expiredate != '') && ($expiredate < eFactory::getDate()->getDate())) {
			$uid = (int)$row['uid'];
			$stmt = $db->prepare("UPDATE ".$db->quoteId('#__users')." SET ".$db->quoteId('block')." = 1 WHERE ".$db->quoteId('uid')." = :userid");
			$stmt->bindParam(':userid', $uid, PDO::PARAM_INT);
			$stmt->execute();
			$response->errormsg = eFactory::getLang()->get('YACCEXPIRED');
			return false;
		}

		if ($must_otp) {
			$ok = false;
			if ((string)$row['otp'] != '') {
				$parts = explode(',', $row['otp']);
				if (count($parts) == 2) {
					if ($parts[0] == $otp) {
						$ts = (int)$parts[1];
						if (time() - $ts < 300) {//5 minutes
							$ok = true;
						} else {
							$response->errormsg = eFactory::getLang()->get('VCODE_EXPIRED');
						}
					}
				}
			}
			if (!$ok) {
				if ($response->errormsg == '') { $response->errormsg = eFactory::getLang()->get('VCODE_WRONG'); }
				return false;
			}
		}

		$response->firstname = $row['firstname'];
		$response->lastname = $row['lastname'];
		$response->email = $row['email'];
		$response->uid = (int)$row['uid'];
		$response->uname = $row['uname'];
		$response->gid = (int)$row['gid'];
		return true;
	}


	/**********************************************/
	/* MAKE ONE TIME PASSWORD (VERIFICATION CODE) */
	/**********************************************/
	public function makeOTP($options=array()) {
		$db = eFactory::getDB();

		$iresponse = array('success' => false, 'errormsg' => '', 'firstname' => '', 'lastname' => '', 'uname' => '', 'gid' => '', 'email' => '', 'mobile' => '', 'otp' => '');

		$is_email_login = false;
		$uname = (isset($options['uname'])) ? trim($options['uname']) : '';
		$pword = (isset($options['pword'])) ? trim($options['pword']) : '';

		if ($uname == '') {
			$eLang = eFactory::getLang();
			$iresponse['errormsg'] = sprintf($eLang->get('FIELDNOEMPTY'), $eLang->get('USERNAME'));
			return $iresponse;
		}
		if ($pword == '') {
			$eLang = eFactory::getLang();
			$iresponse['errormsg'] = sprintf($eLang->get('FIELDNOEMPTY'), $eLang->get('PASSWORD'));
			return $iresponse;
		}

		if (strlen($pword) < 6) {
			$iresponse['errormsg'] = eFactory::getLang()->get('PASSTOOSHORT');
			return $iresponse;
		}
		if (strpos($uname, '@') !== false) {
			if (!filter_var($uname, FILTER_VALIDATE_EMAIL)) {
				$iresponse['errormsg'] = eFactory::getLang()->get('INVALIDEMAIL');
				return $iresponse;
			}
			$is_email_login = true;
		}

		//apply elxis uname/pword security policy
		if (!$is_email_login) {
			$uname_san = trim(preg_replace('/[^a-z0-9\_\-\.+]/i', '', $uname));
			if ($uname !== $uname_san) {
				$eLang = eFactory::getLang();
				$iresponse['errormsg'] = sprintf($eLang->get('FIELDNOACCCHAR'), $eLang->get('USERNAME'));
				return $iresponse;
			}
		}
		$pword_san = trim(preg_replace('/[^a-z0-9\_\-\.\!\@\#\$\&\(\)\{\}\[\]\?\<\>+]/i', '', $pword));
		if ($pword !== $pword_san) {
			$eLang = eFactory::getLang();
			$iresponse['errormsg'] = sprintf($eLang->get('FIELDNOACCCHAR'), $eLang->get('PASSWORD'));
			return $iresponse;
		}

		if (eFactory::getElxis()->getConfig('TWOFA') == '') {
			$iresponse['errormsg'] = '2 factor authentication is disabled!';
			return $iresponse;
		}

		$sql = "SELECT ".$db->quoteId('uid').", ".$db->quoteId('firstname').", ".$db->quoteId('lastname').", ".$db->quoteId('uname').","
		."\n ".$db->quoteId('pword').", ".$db->quoteId('block').", ".$db->quoteId('gid').", ".$db->quoteId('email').", ".$db->quoteId('mobile').","
		."\n ".$db->quoteId('expiredate')." FROM ".$db->quoteId('#__users');
		if ($is_email_login) {
			$sql .= " WHERE ".$db->quoteId('email')." = :unml";
		} else {
			$sql .= " WHERE ".$db->quoteId('uname')." = :unml";
		}
		$stmt = $db->prepareLimit($sql, 0, 1);
		$stmt->execute(array(':unml' => $uname));
		$row = $stmt->fetch(PDO::FETCH_ASSOC);
		if (!$row) {
			$eLang = eFactory::getLang();
			$iresponse['errormsg'] = $eLang->get('USERNOTFOUND').' / '.eFactory::getLang()->get('INVALIDPASS');
			return $iresponse;
		}
		$encpass = eFactory::getElxis()->obj('crypt')->getEncryptedPassword($pword);
		if ($encpass != $row['pword']) {
			$iresponse['errormsg'] = eFactory::getLang()->get('USERNOTFOUND').' / '.eFactory::getLang()->get('INVALIDPASS');
			return $iresponse;
		}
		if (intval($row['block']) == 1) {
			$iresponse['errormsg'] = eFactory::getLang()->get('YACCBLOCKED');
			return $iresponse;
		}
		$expiredate = trim($row['expiredate']);
		if (($expiredate != '') && ($expiredate < eFactory::getDate()->getDate())) {
			$uid = (int)$row['uid'];
			$stmt = $db->prepare("UPDATE ".$db->quoteId('#__users')." SET ".$db->quoteId('block')." = 1 WHERE ".$db->quoteId('uid')." = :userid");
			$stmt->bindParam(':userid', $uid, PDO::PARAM_INT);
			$stmt->execute();
			$iresponse['errormsg'] = eFactory::getLang()->get('YACCEXPIRED');
			return $iresponse;
		}

		$otp = rand(100000, 999999);
		$otpstr = $otp.','.time();

		$uid = (int)$row['uid'];
		$stmt = $db->prepare("UPDATE ".$db->quoteId('#__users')." SET ".$db->quoteId('otp')." = :xvc WHERE ".$db->quoteId('uid')." = :userid");
		$stmt->bindParam(':xvc', $otpstr, PDO::PARAM_STR);
		$stmt->bindParam(':userid', $uid, PDO::PARAM_INT);
		$stmt->execute();

		$iresponse['success'] = true;
		$iresponse['otp'] = $otp;
		$iresponse['firstname'] = $row['firstname'];
		$iresponse['lastname'] = $row['lastname'];
		$iresponse['uname'] = $row['uname'];
		$iresponse['gid'] = $row['gid'];
		$iresponse['email'] = $row['email'];
		$iresponse['mobile'] = $row['mobile'];

		return $iresponse;
	}


	/**********************/
	/* DISPLAY LOGIN FORM */
	/**********************/
	public function loginForm() {
		$eLang = eFactory::getLang();
		$elxis = eFactory::getElxis();
		$eDoc = eFactory::getDocument();

		elxisLoader::loadFile('includes/libraries/elxis/form5.class.php');

		$action = $elxis->makeURL('user:login/elxis.html', '', true, false);
		$return = base64_encode($elxis->makeURL('user:/'));

		$form = new elxis5Form(array('idprefix' => 'ulog', 'labelclass' => 'elx5_labelblock', 'sideclass' => 'elx5_zero'));
		$form->openForm(array('name' => 'fmuserlogin', 'method' => 'post', 'action' => $action, 'id' => 'fmuserlogin'));
		$form->openFieldset($eLang->get('LOGIN'));
		$form->addNote($eLang->get('LOGINOWNACC'), 'elx5_sminfo elx5_dspace');
		$form->addText('uname', '', $eLang->get('USERNAME').' / '.$eLang->get('EMAIL'), array('required' => 'required', 'dir' => 'ltr', 'autocomplete' => 'off', 'placeholder' => $eLang->get('USERNAME').' / '.$eLang->get('EMAIL')));
		$form->addPassword('pword', '', $eLang->get('PASSWORD'), array('required' => 'required', 'maxlength' => 60, 'autocomplete' => 'off'));
		$options = array();
		$options[] = $form->makeOption(1, $eLang->get('REMEMBER_ME'));
		$form->addCheckbox('remember', '', null, $options);
		$form->addHidden('return', $return);
		$form->addHidden('auth_method', 'elxis');
		if ($elxis->getConfig('TWOFA') != '') {
			$form->addHidden('makeotp', '1');
		}
		$form->addToken('fmuserlogin');
		$form->addHTML('<div class="elx5_dspace">');
		$form->addButton('sbmlog', $eLang->get('LOGIN'), 'submit');
		$form->addHTML('</div>');
		$form->closeFieldset();
		$form->closeForm();
		unset($form);
	}


	/***********************/
	/* EXECUTE CUSTOM TASK */
	/***********************/
	public function runTask($etask) {
		if (ob_get_length() > 0) { @ob_end_clean(); }
		header('content-type:text/plain; charset=utf-8');
		echo 'Invalid request';
		exit;
	}


	/***************************************/
	/* CUSTOM ACTIONS TO PERFORM ON LOGOUT */
	/***************************************/
	public function logout() {
	}

}

?>