File: /home/wbwebdes/domains/support.wb-webdesign.com/private_html/admin/elevator.php
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
use RobThree\Auth\TwoFactorAuth;
define('IN_SCRIPT',1);
define('HESK_PATH','../');
/* Get all the required files and functions */
require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
require(HESK_PATH . 'inc/admin_functions.inc.php');
require(HESK_PATH . 'inc/mfa_functions.inc.php');
hesk_load_database_functions();
hesk_session_start();
hesk_dbConnect();
hesk_isLoggedIn();
$mfa_enrollment = intval($_SESSION['mfa_enrollment']);
$skip_email = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (hesk_POST('a') === 'backup_email') {
// Force email verification instead of authenticator code
$mfa_enrollment = 1;
$force_send_email = true;
// Let's limit the "Send another email" to max 3
if (isset($_SESSION['mfa_emails_sent'])) {
if ($_SESSION['mfa_emails_sent'] >= 3) {
hesk_forceLogout($hesklang['bf_int']);
}
$_SESSION['mfa_emails_sent']++;
} else {
$_SESSION['mfa_emails_sent'] = 1;
}
} elseif (hesk_POST('a') === 'verify') {
$skip_email = true;
$mfa_method = intval(hesk_POST('mfa-method'));
if ($mfa_method === 0) {
$pass = hesk_input( hesk_POST('verification-code') );
if ( ! $pass) {
$error = $hesklang['enter_pass'];
} elseif (strlen($pass) > 64) {
$error = $hesklang['pass_len'];
} else {
hesk_limitInternalBfAttempts();
if (hesk_password_verify($pass, fetch_current_user_password())) {
handle_successful_elevation();
} else {
$error = $hesklang['wrong_pass'];
}
}
hesk_process_messages($error, 'NOREDIRECT');
} else {
hesk_limitInternalBfAttempts();
if (($mfa_method === 1 && is_mfa_email_code_valid($_SESSION['id'], hesk_POST('verification-code'))) ||
($mfa_method === 2 && is_mfa_app_code_valid($_SESSION['id'], hesk_POST('verification-code')))) {
handle_successful_elevation();
} else {
// Verification failed
hesk_process_messages($hesklang['mfa_invalid_verification_code'], 'NOREDIRECT');
}
}
} elseif (hesk_POST('a') === 'do_backup_code_verification') {
$skip_email = true;
hesk_limitInternalBfAttempts();
if (verify_mfa_backup_code($_SESSION['id'], hesk_POST('backup-code'))) {
handle_successful_elevation();
} else {
// Verification failed
hesk_process_messages($hesklang['mfa_invalid_backup_code'], 'NOREDIRECT');
}
} else {
// Invalid action, something strange is going on... Let's force logout
hesk_forceLogout($hesklang['invalid_action']);
}
}
$message = ''; //$hesklang['elevator_intro'] . '<br><br>';
if ($mfa_enrollment === 0) {
$mfa_verify_option = 0;
$message .= $hesklang['elevator_enter_password'];
} elseif ($mfa_enrollment === 1) {
// Email
$mfa_verify_option = 1;
// Unless the "Send another email" link was clicked, don't send a new email until the old one is valid
if (! $skip_email && empty($force_send_email) && isset($_SESSION['skip_mfa_emails_until']) && $_SESSION['skip_mfa_emails_until'] > date('Y-m-d H:i:s')) {
$skip_email = true;
}
// Don't send a new email each time a verification fails
if (! $skip_email) {
$verification_code = generate_mfa_code();
hash_and_store_mfa_verification_code($_SESSION['id'], $verification_code);
send_mfa_email($_SESSION['name'], $_SESSION['email'], $verification_code);
hesk_process_messages($hesklang['mfa_sent'], 'NOREDIRECT', 'INFO');
// Don't send a new email until the old one is valid (with 15 min buffer) unless explicitly asked to
$skip_mfa_emails_until = new DateTime();
$skip_mfa_emails_until->add(new DateInterval('PT15M'));
$_SESSION['skip_mfa_emails_until'] = $skip_mfa_emails_until->format('Y-m-d H:i:s');
}
$message .= $hesklang['mfa_verification_needed_email'];
} elseif ($mfa_enrollment === 2) {
// Authenticator App
$message .= $hesklang['mfa_verification_needed_auth_app'];
$mfa_verify_option = 2;
}
/* Print header */
require_once(HESK_PATH . 'inc/header.inc.php');
/* Print main manage users page */
require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
?>
<div class="main__content profile">
<section class="mfa__head">
<h2>
<?php echo $hesklang['elevator_header']; ?>
</h2>
</section>
<article class="profile__wrapper mfa">
<?php hesk_handle_messages(); ?>
<div id="mfa-verify">
<p><?php echo $message; ?></p>
<form id="verify-form" class="form" action="elevator.php" method="post">
<div class="form-group">
<?php if ($mfa_verify_option === 0): ?>
<label><?php echo $hesklang['pass']; ?></label>
<div class="input-group">
<input name="verification-code" id="regInputPassword" type="password" class="form-control">
<div class="input-group-append--icon passwordIsHidden">
<svg class="icon icon-eye-close">
<use xlink:href="<?php echo HESK_PATH; ?>img/sprite.svg#icon-eye-close"></use>
</svg>
</div>
</div>
<?php else: ?>
<label><?php echo $hesklang['mfa_code']; ?></label>
<input name="verification-code" id="verify-input" type="text" class="form-control" maxlength="6" placeholder="000000" autocomplete="off">
<?php endif; ?>
</div>
<button id="verify-submit" style="margin-top: 10px;" type="submit" class="btn btn-full" ripple="ripple"><?php echo $hesklang['mfa_verify']; ?></button>
<input type="hidden" name="mfa-method" value="<?php echo $mfa_verify_option; ?>">
<input type="hidden" name="a" value="verify">
</form>
<?php if ($mfa_verify_option === 1): ?>
<form action="elevator.php" class="form" id="send-another-email-form" method="post" name="send-another-email-form" novalidate>
<button class="btn btn-link" type="submit">
<?php echo $hesklang['mfa_send_another_email']; ?>
</button>
<input type="hidden" name="a" value="backup_email">
</form>
<?php endif; ?>
<?php if ($mfa_verify_option !== 0): ?>
<br>
<a href="javascript:hesk_toggleLayerDisplay('verify-another-way');hesk_toggleLayerDisplay('mfa-verify')">
<?php echo $hesklang['mfa_verify_another_way']; ?>
</a>
<?php endif; ?>
</div>
<?php if ($mfa_verify_option !== 0): ?>
<div id="verify-another-way" style="display: none">
<ul>
<?php if ($mfa_verify_option === 2): ?>
<li>
<div class="flex">
<div class="mfa-alt-icon" aria-hidden="true">
<svg class="icon icon-mail">
<use xlink:href="<?php echo HESK_PATH; ?>img/sprite.svg#icon-mail"></use>
</svg>
</div>
<div class="mfa-alt-text">
<form action="elevator.php" class="form" id="email-backup-form" method="post" name="email-backup-form" novalidate>
<button class="btn btn-link" type="submit">
<?php echo sprintf($hesklang['mfa_verify_another_way_email'], hesk_maskEmailAddress($_SESSION['email'])); ?>
</button>
<input type="hidden" name="a" value="backup_email">
</form>
</div>
</div>
</li>
<?php endif; ?>
<li>
<div class="flex">
<div class="mfa-alt-icon" aria-hidden="true">
<svg class="icon icon-lock">
<use xlink:href="<?php echo HESK_PATH; ?>img/sprite.svg#icon-lock"></use>
</svg>
</div>
<div class="mfa-alt-text">
<a href="javascript:hesk_toggleLayerDisplay('backup-code-field')"><?php echo $hesklang['mfa_verify_another_way_code']; ?></a>
<div id="backup-code-field" style="display: none">
<form action="elevator.php" class="form" id="backup-form" method="post" name="backup-form" novalidate>
<div class="form-group">
<label for="backupCode"><?php echo $hesklang['mfa_backup_code']; ?></label>
<input type="text" class="form-control" id="backupCode" name="backup-code" minlength="8" maxlength="9" autocomplete="off">
</div>
<div class="form__submit mfa">
<button class="btn btn-full" ripple="ripple" type="submit" id="backup-code-submit">
<?php echo $hesklang['s']; ?>
</button>
</div>
<input type="hidden" name="a" value="do_backup_code_verification">
</form>
</div>
</div>
</div>
</li>
</ul>
<p style="text-align: center">
<a href="javascript:hesk_toggleLayerDisplay('verify-another-way');hesk_toggleLayerDisplay('mfa-verify')">
<?php echo $hesklang['back']; ?>
</a>
</p>
</div>
<?php endif; ?>
</article>
</div>
<script>
$('#verify-form').preventDoubleSubmission();
$('#backup-form').preventDoubleSubmission();
$('#verify-input').keyup(function() {
if (this.value.length === 6) {
$('#verify-form').submit();
}
});
$('#backupCode').keyup(function() {
if (this.value.length === 8 || this.value.length === 9) {
$('#backup-form').submit();
}
});
$('#verify-form').submit(function() {
$('#verify-submit').attr('disabled', 'disabled')
.addClass('disabled');
});
$('#backup-form').submit(function() {
$('#backup-code-submit').attr('disabled', 'disabled')
.addClass('disabled');
});
</script>
<?php
require_once(HESK_PATH . 'inc/footer.inc.php');
function fetch_current_user_password() {
global $hesk_settings, $hesklang;
$res = hesk_dbQuery("SELECT `pass` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `id` = ".intval($_SESSION['id'])." LIMIT 1");
if (hesk_dbNumRows($res) != 1) {
hesk_forceLogout($hesklang['wrong_user']);
}
$row = hesk_dbFetchAssoc($res);
return $row['pass'];
}
function handle_successful_elevation() {
global $hesk_settings;
hesk_session_regenerate_id();
hesk_cleanBfAttempts();
delete_mfa_codes($_SESSION['id']);
hesk_cleanSessionVars('mfa_emails_sent');
hesk_cleanSessionVars('skip_mfa_emails_until');
$current_time = new DateTime();
$interval_amount = $hesk_settings['elevator_duration'];
if (in_array(substr($interval_amount, -1), array('M', 'H'))) {
$interval_amount = 'T'.$interval_amount;
}
$elevation_expiration = $current_time->add(new DateInterval("P{$interval_amount}"));
$_SESSION['elevated'] = $elevation_expiration;
$elevator_target = hesk_SESSION('elevator_target', 'admin_main.php');
unset($_SESSION['elevator_target']);
header('Location: ' . $elevator_target);
exit();
}
exit();