<?php
/*
** Copyright (C) 2001-2025 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** 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 <https://www.gnu.org/licenses/>.
**/


require_once __DIR__.'/include/classes/user/CWebUser.php';
require_once __DIR__.'/include/config.inc.php';

// Clear 'Session terminated, re-login, please' message.
CMessageHelper::clear();

// VAR	TYPE	OPTIONAL	FLAGS	VALIDATION	EXCEPTION
$fields = [
	'enter' =>				[T_ZBX_STR, O_OPT, P_SYS,	null,	null],
	'request' =>			[T_ZBX_STR, O_OPT, null,	null,	null],
	'totp_secret' =>		[T_ZBX_STR, O_OPT, null,	null,	null],
	'hash_function' =>		[T_ZBX_STR, O_OPT, null,	null,	null],
	'verification_code' =>	[T_ZBX_INT, O_OPT, null,	null,	null],
	'qr_code_url' =>		[T_ZBX_STR, O_OPT, null,	null,	null],
	'duo_code' =>			[T_ZBX_STR, O_OPT, null,	null,	null],
	'state' =>				[T_ZBX_STR, O_OPT, null,	null,	null]
];
check_fields($fields);

$page['scripts'] = ['qrcode.js'];

$redirect_to = (new CUrl('index.php'))->setArgument('form', 'default');
$request = getRequest('request', '');

if ($request != '' && !CHtmlUrlValidator::validateSameSite($request)) {
	$request = '';
}

if ($request != '') {
	$redirect_to->setArgument('request', $request);
}

try {
	$session_data = json_decode(base64_decode(CCookieHelper::get(ZBX_SESSION_NAME)), true);

	// If no session data or MFA is not required - redirect to the main login page.
	if (!$session_data || !array_key_exists('confirmid', $session_data)) {
		redirect($redirect_to->toString());
	}

	$session_data_sign = CSessionHelper::get('sign');
	$session_data_sign_check = CEncryptHelper::sign(json_encode(array_diff_key($session_data, array_flip(['sign']))));

	if (!$session_data_sign || !CEncryptHelper::checkSign($session_data_sign, $session_data_sign_check)) {
		throw new Exception(_('Session initialization error.'));
	}

	if ($request != '') {
		CSessionHelper::set('request', $request);
	}

	$duo_redirect_uri = ((new CUrl($_SERVER['REQUEST_URI']))
		->removeArgument('state')
		->removeArgument('duo_code'))
		->setArgument('request', $request)
		->toString();

	$full_duo_redirect_url = implode('', [HTTPS ? 'https://' : 'http://', $_SERVER['HTTP_HOST'], $duo_redirect_uri]);

	$confirm_data = [
		'sessionid' => CSessionHelper::get('confirmid'),
		'redirect_uri' => implode('', [HTTPS ? 'https://' : 'http://', $_SERVER['HTTP_HOST'], $duo_redirect_uri])
	];

	$error = null;

	if (!CSessionHelper::has('state') && !hasRequest('enter')) {
		$data = CUser::getConfirmData($confirm_data);

		if ($data['mfa']['type'] == MFA_TYPE_TOTP) {
			session_write_close();
			echo (new CView('mfa.login', $data))->getOutput();
			exit;
		}

		if ($data['mfa']['type'] == MFA_TYPE_DUO) {
			CSessionHelper::set('state', $data['state']);
			CSessionHelper::set('username', $data['username']);
			CSessionHelper::set('sessionid', $data['sessionid']);

			redirect($data['prompt_uri']);
		}
	}
	else {
		$data['mfa_response_data'] = [
			'verification_code' => getRequest('verification_code', ''),
			'totp_secret' => getRequest('totp_secret'),
			'duo_code' => getRequest('duo_code'),
			'duo_state' => getRequest('state'),
			'state' => CSessionHelper::get('state'),
			'username' => CSessionHelper::get('username')
		];

		$confirm = CUser::confirm($confirm_data + $data);

		if ($confirm) {
			CWebUser::checkAuthentication($confirm['sessionid']);
			CSessionHelper::set('sessionid', CWebUser::$data['sessionid']);
			CSessionHelper::unset(['state', 'username', 'confirmid']);

			API::getWrapper()->auth = [
				'type' => CJsonRpc::AUTH_TYPE_FRONTEND,
				'auth' => CWebUser::$data['sessionid']
			];

			$redirect = array_filter([$request, CWebUser::$data['url'], CMenuHelper::getFirstUrl()]);
			redirect(reset($redirect));
		}
	}
}
catch (Exception $e) {
	$error['error']['message'] = $e->getMessage();

	CMessageHelper::clear();

	if ($e->getCode() == ZBX_API_ERROR_PARAMETERS) {
		$data['qr_code_url'] = getRequest('qr_code_url');
		$data['totp_secret'] = getRequest('totp_secret');
		$data['mfa']['hash_function'] = getRequest('hash_function');

		session_write_close();
		echo (new CView('mfa.login', $data + $error))->getOutput();
		exit;
	}
}

echo (new CView('general.warning', [
	'header' => _('You are not logged in'),
	'messages' => $error,
	'buttons' => [
		(new CButton('login', _('Login')))
			->setAttribute('data-url', $redirect_to->getUrl())
			->onClick('document.location = this.dataset.url;')
	],
	'theme' => getUserTheme(CWebUser::$data)
]))->getOutput();

session_write_close();