<?php

declare(strict_types=1);

/**
 * This file is part of LEPTON Core, released under the GNU GPL
 * Please see LICENSE and COPYING files in your package for details, specially for terms and warranties.
 * 
 * NOTICE:LEPTON CMS Package has several different licenses.
 * Please see the individual license in the header of each single file or info.php of modules and templates.
 *
 * @author          LEPTON Project
 * @copyright       2010-2026 LEPTON Project
 * @link            https://lepton-cms.org
 * @license         https://gnu.org/licenses/gpl.html
 * @license_terms   please see LICENSE and COPYING files in your package
 *
 */

class LEPTON_tfa
{
	public bool $key_new = false;	
	public string $pin = '-1';
	public string $pin_encode = '-1';
	public int $user_id = -99;
	public int $iCodeExpires = 3600; // 60 minutes as default if there is no entry in the L*ini

	public object|null $oTwig = null;
	public object|null $oAC = null;
	public object|null $database = null;
	public object|null $mailer = null;
	public static $instance;
	
//    public static $instance;
	
    /**
     *  Return the instance of this class.
     *
    */
    public static function getInstance()
    {
        if (null === static::$instance)
        {
            static::$instance = new static();
            static::$instance->initialize();
        }
        return static::$instance;
    }
	
	public function initialize( int $user_id = -99)
	{	
		$this->oTwig = lib_twig_box::getInstance();
		$this->oAC = account::getInstance();
		$this->database = LEPTON_database::getInstance();
		$this->mailer = LEPTON_mailer::getInstance();
		
		$temp_value = $this->database->get_one("SELECT pin FROM ".TABLE_PREFIX."users WHERE user_id = ".$user_id);
		
		if($temp_value == -1)
		{
			$this->key_new = true;
		} 
		else 
		{
			$this->key_new = false;
		}
		
		// read code expires from ini_file
		$ini_file_name = LEPTON_PATH."/config/lepton.ini.php";			
       	$config = parse_ini_string(";" . file_get_contents($ini_file_name), true);
        if ($config['custom_vars']['tfa_code_expires'] != '')
		{
			// override default text with value from ini file
			$this->iCodeExpires = intval($config['custom_vars']['tfa_code_expires']);
		}
			
		$this->user_id = $user_id;
		$createPin = random_int(100000, 999999);
		$this->pin = "".$createPin."";
		$this->pin_encode = password_hash($this->pin, PASSWORD_DEFAULT); 	// for use in TFA = mail only 	
	}

	public function set_fe_pin($id = '') 
	{		
		if ( $id == 'create') 
		{						
			if(isset($_SESSION['USER_ID']) && isset($_SESSION['LEPTOKENS']))
			{					
				$token = $_SESSION['LEPTOKENS'][0];
				$redirect = $_GET['redirect']?? LEPTON_URL;

				$page_values = array(
					'oTFA'			=> $this,
					'ACTION_URL'	=> LEPTON_URL."/account/tfa.php",
					'token'			=> $token,
					'redirect'		=> $redirect,
					'post_login'	=> $_POST,
					'pin'			=> $this->pin,
					'new'			=> $this->key_new,
				);
								
				echo $this->oTwig->render("tfa_form.lte",$page_values);				
			} 
		}
		
		elseif ( $id == 'save') 
		{
			if(isset($_POST['save']) && strlen($_POST['save']) == 6 )
			{		
				$this->pin_encode = password_hash($_POST['save'], PASSWORD_DEFAULT); 	// for use in TFA = local
				
				// save pin
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `pin` = '".$this->pin_encode."' WHERE user_id = ".$this->user_id);

				// modify pin_set
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `pin_set` = 1 WHERE user_id = ".$this->user_id);
				
				// modify unix time
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `unix_time` = ".time()."  WHERE user_id = ".$this->user_id);				

				header('Location: '.$_POST['redirect'].' ');
				exit();
				
			} 
		}
		else 
		{
			header('Location: '.LEPTON_URL.'/account/logout.php');
		}
	}	

	public function display_fe_pin( $id )	
	{
		global $TEXT;
		
		if ( $id == 'display' || $id == 'resend')
		{
			if(TFA == "mail")
			{			
				// modify pin_set
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `pin` = '".$this->pin_encode."' WHERE user_id = ".$this->user_id);
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `pin_set` = 1 WHERE user_id = ".$this->user_id);			
				
				// modify unix time
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `unix_time` = ".time()."  WHERE user_id = ".$this->user_id);				
				
				self::send_mail($this->user_id);			
			}	
			$page_values = array(
				'oTFA'			=> $this,
				'ACTION_URL'	=> LEPTON_URL."/account/tfa.php",
				'post_login'	=> $_POST,
				'redirect'		=> $_POST['redirect'] ?? LEPTON_URL,
				'TFA'			=> TFA,				
				'token'			=> $_SESSION['LEPTOKENS'][0],
				'new'			=> false,
			);
			
			echo $this->oTwig->render("tfa_form.lte",$page_values);		
		} 
		elseif ( $id == 'forward') 
		{			
			if(isset($_POST['token']) && strlen($_POST['pin']) == 6 )
			{			
				// check if code has expired
				$unix = $this->database->get_one("SELECT unix_time FROM ".TABLE_PREFIX."users WHERE user_id = ".$this->user_id);				
				if($unix + $this->iCodeExpires < time())
				{
					LEPTON_frontend::displayFEMessage('error',$TEXT['TFA_EXPIRED'],$_POST['redirect'],-1);
					exit();				
				}
				else
				{						
					// get PIN from database
					$dbKey = $this->database->get_one("SELECT pin FROM ".TABLE_PREFIX."users WHERE user_id = ".$this->user_id);
					$postKey = $_POST['pin'];		
					$forward = strip_tags($_REQUEST['redirect'] ?? LEPTON_URL);

					// validate PIN
					if(password_verify ($postKey, $dbKey) === true)
					{
						// prevent logout
						$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `pin_set` = 2 WHERE user_id = ".$this->user_id);
					
						header('Location: '.$forward);					
					} 
					else
					{					
						header('Location: '.LEPTON_URL.'/account/logout.php');
					}					
				}				
			}
			else
			{
				header('Location: '.LEPTON_URL.'/account/logout.php');
			}			
		} 
		else 
		{				
			header('Location: '.LEPTON_URL.'/account/logout.php');
		}
	}
	
	public function set_be_pin( $id ) 
	{
		if ( $id == 'create') 
		{
			$page_values = array(
				'oTFA'			=> $this,
				'ACTION_URL'	=> ADMIN_URL."/login/tfa.php",
				'token'			=> $_SESSION['LEPTOKENS'][0],
				'post_login'	=> $_POST,
				'pin'			=> $this->pin,
				'new'			=> $this->key_new,
			);

			echo $this->oTwig->render("@theme/tfa_form.lte",$page_values);
		}

		if ( $id == 'save') 
		{			
			if(isset($_POST['save']) && strlen($_POST['save']) == 6 )
			{				
				$this->pin_encode = password_hash($_POST['save'], PASSWORD_DEFAULT); 	// for use in TFA = local
			
				// save PIN
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `pin` = '".$this->pin_encode."' WHERE user_id = ".$this->user_id);

				// modify pin_set
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `pin_set` = 1 WHERE user_id = ".$this->user_id);
				
				// modify unix time
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `unix_time` = ".time()."  WHERE user_id = ".$this->user_id);				
				
				header('Location: '.ADMIN_URL.'/logout/index.php');
				exit();			
			} 
			else 
			{
				header('Location: '.ADMIN_URL.'/logout/index.php');
			}
		}
	}
	
	public function display_be_pin( $id )	
	{	
		global $TEXT;	
		
		if ( $id == 'display' || $id == 'resend')
		{
			if(TFA == "mail")
			{		
				// modify pin_set
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `pin` = '".$this->pin_encode."' WHERE user_id = ".$this->user_id);
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `pin_set` = 1 WHERE user_id = ".$this->user_id);
				
				// modify unix time
				$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `unix_time` = ".time()."  WHERE user_id = ".$this->user_id);				
				
				self::send_mail($this->user_id);
			}
		
			$page_values = array(
				'oTFA'			=> $this,
				'ACTION_URL'	=> ADMIN_URL."/login/tfa.php",
				'token'			=> $_SESSION['LEPTOKENS'][0],
				'TFA'			=> TFA,
				'new'			=> false,
			);

			echo $this->oTwig->render("@theme/tfa_form.lte",$page_values);					
		} 

		elseif ( $id == 'forward') 
		{			
			if(isset($_POST['token']) && strlen($_POST['pin']) == 6 )
			{							
				// get PIN from database
				$dbKey = $this->database->get_one("SELECT pin FROM ".TABLE_PREFIX."users WHERE user_id = ".$this->user_id);
				$postKey = $_POST['pin'];

				// check if code has expired
				$unix = $this->database->get_one("SELECT unix_time FROM ".TABLE_PREFIX."users WHERE user_id = ".$this->user_id);				
				if($unix + $this->iCodeExpires < time())
				{
					LEPTON_frontend::displayFEMessage('error',$TEXT['TFA_EXPIRED'],$_POST['redirect'],-1);
					exit();
				}
				else
				{
					// validate PIN
					if(password_verify ($postKey, $dbKey) === true)
					{
						// modify pin_set
						$this->database->simple_query("UPDATE ".TABLE_PREFIX."users SET `pin_set` = 2 WHERE user_id = ".$this->user_id);	
						
						header('Location: '.ADMIN_URL.'/start/index.php?leptoken='.$_POST['token']);				
					} 
					else
					{
						header('Location: '.ADMIN_URL.'/logout/index.php');
					}					
				}			
			} 
		} 
		else 
		{
			header('Location: '.ADMIN_URL.'/logout/index.php');
		}		
	}

	
	public function send_mail( $id = -99 )
	{
		global $TEXT;
		
		$sFrom = SERVER_EMAIL;
		$sSendTo = $this->database->get_one("SELECT email FROM ".TABLE_PREFIX."users WHERE user_id = ".$this->user_id);
		$sSubject = $TEXT['TFA_SUBJECT'];
		
		// data for twig template engine	
		$data = array(
			'oTFA'		=> $this
		);
	
		//	get the template-engine	
		$sMessage = $this->oTwig->render('tfa_mail.lte', $data);			
		
		if (!$this->mailer->sendmail( $sFrom, $sSendTo, $sSubject, $sMessage)) 
		{		
			$message = "Failure send mail";	
			echo(LEPTON_tools::display($message,'pre','ui red message'));	
		}
	}
}
