Initial
This commit is contained in:
23
web/inc/2fa/check.php
Normal file
23
web/inc/2fa/check.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
require_once __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
if (isset($argv[1]) && isset($argv[2])) {
|
||||
$secret = $argv[1];
|
||||
$token = $argv[2];
|
||||
} elseif (isset($_GET["secret"]) && isset($_GET["token"])) {
|
||||
$secret = htmlspecialchars($_GET["secret"]);
|
||||
$token = htmlspecialchars($_GET["token"]);
|
||||
} else {
|
||||
echo "ERROR: Secret or Token is not set as argument!";
|
||||
exit();
|
||||
}
|
||||
|
||||
$tfa = new TwoFactorAuth("Hestia Control Panel");
|
||||
|
||||
// Verify code
|
||||
$result = $tfa->verifyCode($secret, $token);
|
||||
|
||||
if ($result) {
|
||||
echo "ok";
|
||||
}
|
||||
10
web/inc/2fa/secret.php
Normal file
10
web/inc/2fa/secret.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
require_once __DIR__ . "/../vendor/autoload.php";
|
||||
$tfa = new TwoFactorAuth("Hestia Control Panel");
|
||||
|
||||
$secret = $tfa->createSecret(160); // Though the default is an 80 bits secret (for backwards compatibility reasons) we recommend creating 160+ bits secrets (see RFC 4226 - Algorithm Requirements)
|
||||
$qrcode = $tfa->getQRCodeImageAsDataUri(gethostname(), $secret);
|
||||
|
||||
echo $secret . "-" . $qrcode;
|
||||
7
web/inc/composer.json
Normal file
7
web/inc/composer.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"require": {
|
||||
"phpmailer/phpmailer": "6.8.0",
|
||||
"hestiacp/phpquoteshellarg": "1.0.2",
|
||||
"robthree/twofactorauth": "2.0.0"
|
||||
}
|
||||
}
|
||||
218
web/inc/composer.lock
generated
Normal file
218
web/inc/composer.lock
generated
Normal file
@@ -0,0 +1,218 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "bd5fba3223573f480531e48f5e3ce14e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "hestiacp/phpquoteshellarg",
|
||||
"version": "v1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/hestiacp/phpquoteshellarg.git",
|
||||
"reference": "7fd1a3a648cdc39a3fe2aab78a1a3a0267f92f49"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/hestiacp/phpquoteshellarg/zipball/7fd1a3a648cdc39a3fe2aab78a1a3a0267f92f49",
|
||||
"reference": "7fd1a3a648cdc39a3fe2aab78a1a3a0267f92f49",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/Hestiacp/quoteshellarg/quoteshellarg.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Unlicense"
|
||||
],
|
||||
"description": "Improved escape shell arguments for support of special charactars",
|
||||
"homepage": "https://github.com/hestiacp",
|
||||
"keywords": [
|
||||
"escapeshellarg",
|
||||
"quoteshellarg"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/hestiacp/phpquoteshellarg/tree/v1.0.2"
|
||||
},
|
||||
"time": "2023-07-23T09:16:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"version": "v6.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||
"reference": "df16b615e371d81fb79e506277faea67a1be18f1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/df16b615e371d81fb79e506277faea67a1be18f1",
|
||||
"reference": "df16b615e371d81fb79e506277faea67a1be18f1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-filter": "*",
|
||||
"ext-hash": "*",
|
||||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
|
||||
"doctrine/annotations": "^1.2.6 || ^1.13.3",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3.2",
|
||||
"phpcompatibility/php-compatibility": "^9.3.5",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"squizlabs/php_codesniffer": "^3.7.1",
|
||||
"yoast/phpunit-polyfills": "^1.0.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
|
||||
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
|
||||
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
|
||||
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
|
||||
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
|
||||
"psr/log": "For optional PSR-3 debug logging",
|
||||
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
|
||||
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PHPMailer\\PHPMailer\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-only"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marcus Bointon",
|
||||
"email": "phpmailer@synchromedia.co.uk"
|
||||
},
|
||||
{
|
||||
"name": "Jim Jagielski",
|
||||
"email": "jimjag@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Andy Prevost",
|
||||
"email": "codeworxtech@users.sourceforge.net"
|
||||
},
|
||||
{
|
||||
"name": "Brent R. Matzelle"
|
||||
}
|
||||
],
|
||||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
|
||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Synchro",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-06T14:43:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "robthree/twofactorauth",
|
||||
"version": "v2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobThree/TwoFactorAuth.git",
|
||||
"reference": "27cd1e1392d19f178398e892f59062003c8998a4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/27cd1e1392d19f178398e892f59062003c8998a4",
|
||||
"reference": "27cd1e1392d19f178398e892f59062003c8998a4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.13",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpunit": "^9"
|
||||
},
|
||||
"suggest": {
|
||||
"bacon/bacon-qr-code": "Needed for BaconQrCodeProvider provider",
|
||||
"endroid/qr-code": "Needed for EndroidQrCodeProvider"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"RobThree\\Auth\\": "lib"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Rob Janssen",
|
||||
"homepage": "http://robiii.me",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Nicolas CARPi",
|
||||
"homepage": "https://github.com/NicolasCARPi",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Will Power",
|
||||
"homepage": "https://github.com/willpower232",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Two Factor Authentication",
|
||||
"homepage": "https://github.com/RobThree/TwoFactorAuth",
|
||||
"keywords": [
|
||||
"Authentication",
|
||||
"MFA",
|
||||
"Multi Factor Authentication",
|
||||
"Two Factor Authentication",
|
||||
"authenticator",
|
||||
"authy",
|
||||
"php",
|
||||
"tfa"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/RobThree/TwoFactorAuth/issues",
|
||||
"source": "https://github.com/RobThree/TwoFactorAuth"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://paypal.me/robiii",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/RobThree",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-25T11:33:28+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
||||
178
web/inc/helpers.php
Normal file
178
web/inc/helpers.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
use function Hestiacp\quoteshellarg\quoteshellarg;
|
||||
|
||||
# Return codes
|
||||
const E_ARGS = 1;
|
||||
const E_INVALID = 2;
|
||||
const E_NOTEXIST = 3;
|
||||
const E_EXISTS = 4;
|
||||
const E_SUSPENDED = 5;
|
||||
const E_UNSUSPENDED = 6;
|
||||
const E_INUSE = 7;
|
||||
const E_LIMIT = 8;
|
||||
const E_PASSWORD = 9;
|
||||
const E_FORBIDEN = 10;
|
||||
const E_FORBIDDEN = 10;
|
||||
const E_DISABLED = 11;
|
||||
const E_PARSING = 12;
|
||||
const E_DISK = 13;
|
||||
const E_LA = 14;
|
||||
const E_CONNECT = 15;
|
||||
const E_FTP = 16;
|
||||
const E_DB = 17;
|
||||
const E_RRD = 18;
|
||||
const E_UPDATE = 19;
|
||||
const E_RESTART = 20;
|
||||
const E_API_DISABLED = 21;
|
||||
|
||||
/**
|
||||
* Looks for a code equivalent to "exit_code" to use in http_code.
|
||||
*
|
||||
* @param int $exit_code
|
||||
* @param int $default
|
||||
* @return int
|
||||
*/
|
||||
function exit_code_to_http_code(int $exit_code, int $default = 400): int {
|
||||
switch ($exit_code) {
|
||||
case 0:
|
||||
return 200;
|
||||
case E_ARGS:
|
||||
// return 500;
|
||||
return 400;
|
||||
case E_INVALID:
|
||||
return 422;
|
||||
// case E_NOTEXIST:
|
||||
// return 404;
|
||||
// case E_EXISTS:
|
||||
// return 302;
|
||||
case E_PASSWORD:
|
||||
return 401;
|
||||
case E_SUSPENDED:
|
||||
case E_UNSUSPENDED:
|
||||
case E_FORBIDEN:
|
||||
case E_FORBIDDEN:
|
||||
case E_API_DISABLED:
|
||||
return 401;
|
||||
// return 403;
|
||||
case E_DISABLED:
|
||||
return 400;
|
||||
// return 503;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
function check_local_ip($addr) {
|
||||
if (in_array($addr, [$_SERVER["SERVER_ADDR"], "127.0.0.1"])) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_real_user_ip() {
|
||||
$ip = $_SERVER["REMOTE_ADDR"];
|
||||
if (isset($_SERVER["HTTP_CLIENT_IP"]) && !check_local_ip($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
if (filter_var($_SERVER["HTTP_CLIENT_IP"], FILTER_VALIDATE_IP)) {
|
||||
$ip = $_SERVER["HTTP_CLIENT_IP"];
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
isset($_SERVER["HTTP_X_FORWARDED_FOR"]) &&
|
||||
!check_local_ip($_SERVER["HTTP_X_FORWARDED_FOR"])
|
||||
) {
|
||||
if (filter_var($_SERVER["HTTP_X_FORWARDED_FOR"], FILTER_VALIDATE_IP)) {
|
||||
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SERVER["HTTP_FORWARDED_FOR"]) && !check_local_ip($_SERVER["HTTP_FORWARDED_FOR"])) {
|
||||
if (filter_var($_SERVER["HTTP_FORWARDED_FOR"], FILTER_VALIDATE_IP)) {
|
||||
$ip = $_SERVER["HTTP_FORWARDED_FOR"];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SERVER["HTTP_X_FORWARDED"]) && !check_local_ip($_SERVER["HTTP_X_FORWARDED"])) {
|
||||
if (filter_var($_SERVER["HTTP_X_FORWARDED"], FILTER_VALIDATE_IP)) {
|
||||
$ip = $_SERVER["HTTP_X_FORWARDED"];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SERVER["HTTP_FORWARDED"]) && !check_local_ip($_SERVER["HTTP_FORWARDED"])) {
|
||||
if (filter_var($_SERVER["HTTP_FORWARDED"], FILTER_VALIDATE_IP)) {
|
||||
$ip = $_SERVER["HTTP_FORWARDED"];
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
isset($_SERVER["HTTP_CF_CONNECTING_IP"]) &&
|
||||
!check_local_ip($_SERVER["HTTP_CF_CONNECTING_IP"])
|
||||
) {
|
||||
if (filter_var($_SERVER["HTTP_CF_CONNECTING_IP"], FILTER_VALIDATE_IP)) {
|
||||
$ip = $_SERVER["HTTP_CF_CONNECTING_IP"];
|
||||
}
|
||||
}
|
||||
return $ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a history log using 'v-log-action' script.
|
||||
*
|
||||
* @param string $message The message for log.
|
||||
* @param string $category A category for log. Ex: Auth, Firewall, API...
|
||||
* @param string $level Info|Warning|Error.
|
||||
* @param string $user A username for save in the user history ou 'system' to save in Hestia history.
|
||||
* @return int The script result code.
|
||||
*/
|
||||
function hst_add_history_log($message, $category = "System", $level = "Info", $user = "system") {
|
||||
//$message = ucfirst($message);
|
||||
//$message = str_replace("'", "`", $message);
|
||||
$category = ucfirst(strtolower($category));
|
||||
$level = ucfirst(strtolower($level));
|
||||
|
||||
$command_args =
|
||||
quoteshellarg($user) .
|
||||
" " .
|
||||
quoteshellarg($level) .
|
||||
" " .
|
||||
quoteshellarg($category) .
|
||||
" " .
|
||||
quoteshellarg($message);
|
||||
exec(HESTIA_CMD . "v-log-action " . $command_args, $output, $return_var);
|
||||
unset($output);
|
||||
|
||||
return $return_var;
|
||||
}
|
||||
|
||||
function get_hostname() {
|
||||
$badValues = [
|
||||
false,
|
||||
null,
|
||||
0,
|
||||
"",
|
||||
"localhost",
|
||||
"127.0.0.1",
|
||||
"::1",
|
||||
"0000:0000:0000:0000:0000:0000:0000:0001",
|
||||
];
|
||||
$ret = gethostname();
|
||||
if (in_array($ret, $badValues, true)) {
|
||||
throw new Exception("gethostname() failed");
|
||||
}
|
||||
$ret2 = gethostbyname($ret);
|
||||
if (in_array($ret2, $badValues, true)) {
|
||||
return $ret;
|
||||
}
|
||||
$ret3 = gethostbyaddr($ret2);
|
||||
if (in_array($ret3, $badValues, true)) {
|
||||
return $ret2;
|
||||
}
|
||||
return $ret3;
|
||||
}
|
||||
|
||||
function display_title($tab) {
|
||||
$array1 = ["{{page}}", "{{hostname}}", "{{ip}}", "{{appname}}"];
|
||||
$array2 = [$tab, get_hostname(), $_SERVER["REMOTE_ADDR"], $_SESSION["APP_NAME"]];
|
||||
return str_replace($array1, $array2, $_SESSION["TITLE"]);
|
||||
}
|
||||
85
web/inc/i18n.php
Normal file
85
web/inc/i18n.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
// Functions for internationalization
|
||||
// I18N support information here
|
||||
|
||||
putenv("LANGUAGE=" . detect_user_language());
|
||||
setlocale(LC_ALL, "C.UTF-8");
|
||||
|
||||
$domain = "hestiacp";
|
||||
$localedir = "/usr/local/hestia/web/locale";
|
||||
bindtextdomain($domain, $localedir);
|
||||
textdomain($domain);
|
||||
|
||||
/**
|
||||
* Detects user language from Accept-Language HTTP header.
|
||||
* @param string Fallback language (default: 'en')
|
||||
* @return string Language code (such as 'en' and 'ja')
|
||||
*/
|
||||
function detect_user_language() {
|
||||
if (!empty($_SESSION["language"])) {
|
||||
return $_SESSION["language"];
|
||||
} elseif (!empty($_SESSION["LANGUAGE"])) {
|
||||
return $_SESSION["LANGUAGE"];
|
||||
} else {
|
||||
return "en";
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Translate ISO2 to "Language"
|
||||
* nl = Dutch, de = German
|
||||
* @param string iso2 code
|
||||
* @return string Language
|
||||
*/
|
||||
function translate_json($string) {
|
||||
$json = file_get_contents($_SERVER["DOCUMENT_ROOT"] . "/locale/languages.json");
|
||||
$json_a = json_decode($json, true);
|
||||
return $json_a[$string][0] . " (" . $json_a[$string . "_locale"][0] . ")";
|
||||
}
|
||||
/**
|
||||
* Support translation strings that contains html
|
||||
*/
|
||||
function htmlify_trans($string, $closingTag) {
|
||||
$arguments = func_get_args();
|
||||
return preg_replace_callback(
|
||||
"/{(.*?)}/", // Ungreedy (*?)
|
||||
function ($matches) use ($arguments, $closingTag) {
|
||||
static $i = 1;
|
||||
$i++;
|
||||
return $arguments[$i] . $matches[1] . $closingTag;
|
||||
},
|
||||
$string,
|
||||
);
|
||||
}
|
||||
|
||||
function get_email_template($file, $language) {
|
||||
if (
|
||||
file_exists(
|
||||
$_SERVER["HESTIA"] . "/data/templates/email/" . $language . "/" . $file . ".html",
|
||||
)
|
||||
) {
|
||||
return file_get_contents(
|
||||
$_SERVER["HESTIA"] . "/data/templates/email/" . $language . "/" . $file . ".html",
|
||||
);
|
||||
}
|
||||
if (file_exists($_SERVER["HESTIA"] . "/data/templates/email/" . $file . ".html")) {
|
||||
return file_get_contents($_SERVER["HESTIA"] . "/data/templates/email/" . $file . ".html");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function translate_email($string, $replace) {
|
||||
$array1 = $array2 = [];
|
||||
foreach ($replace as $key => $value) {
|
||||
$array1[] = "{{" . $key . "}}";
|
||||
$array2[] = $value;
|
||||
}
|
||||
return str_replace($array1, $array2, $string);
|
||||
}
|
||||
/**
|
||||
* Detects user language .
|
||||
* @param string Fallback language (default: 'en')
|
||||
* @return string Language code (such as 'en' and 'ja')
|
||||
*/
|
||||
|
||||
function detect_login_language() {
|
||||
}
|
||||
43
web/inc/mail-wrapper.php
Executable file
43
web/inc/mail-wrapper.php
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/local/hestia/php/bin/php
|
||||
<?php
|
||||
if (empty($argv[1])) {
|
||||
echo "ERROR: not enough arguments\n";
|
||||
echo "USAGE: mail-wrapper.php -s SUBJECT EMAIL [NOTIFY]\n";
|
||||
exit(3);
|
||||
}
|
||||
|
||||
$options = getopt("s:f:");
|
||||
|
||||
if (!empty($argv[4]) && $argv[4] == "no") {
|
||||
exit();
|
||||
}
|
||||
|
||||
define("NO_AUTH_REQUIRED", true);
|
||||
|
||||
include "/usr/local/hestia/web/inc/main.php";
|
||||
|
||||
// Set system language
|
||||
exec(HESTIA_CMD . "v-list-sys-config json", $output, $return_var);
|
||||
$data = json_decode(implode("", $output), true);
|
||||
if (!empty($data["config"]["LANGUAGE"])) {
|
||||
$_SESSION["language"] = $data["config"]["LANGUAGE"];
|
||||
} else {
|
||||
$_SESSION["language"] = "en";
|
||||
}
|
||||
|
||||
//define vars
|
||||
//make hostname detection a bit more feature proof
|
||||
$hostname = get_hostname();
|
||||
$from = !empty($_SESSION["FROM_EMAIL"]) ? $_SESSION["FROM_EMAIL"] : "noreply@" . $hostname;
|
||||
$from_name = !empty($_SESSION["FROM_NAME"]) ? $_SESSION["FROM_NAME"] : $_SESSION["APP_NAME"];
|
||||
$to = $argv[3] . "\n";
|
||||
$subject = $argv[2] . "\n";
|
||||
$mailtext = file_get_contents("php://stdin");
|
||||
|
||||
// Send email
|
||||
if (!empty($to) && !empty($subject)) {
|
||||
send_email($to, $subject, $mailtext, $from, $from_name);
|
||||
}
|
||||
|
||||
session_destroy();
|
||||
|
||||
578
web/inc/main.php
Normal file
578
web/inc/main.php
Normal file
@@ -0,0 +1,578 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\SMTP;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
use function Hestiacp\quoteshellarg\quoteshellarg;
|
||||
|
||||
try {
|
||||
require_once "vendor/autoload.php";
|
||||
} catch (Throwable $ex) {
|
||||
$errstr =
|
||||
"Unable to load required libraries. Please run v-add-sys-dependencies in command line. Error: " .
|
||||
$ex->getMessage();
|
||||
trigger_error($errstr);
|
||||
echo $errstr;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
define("HESTIA_DIR_BIN", "/usr/local/hestia/bin/");
|
||||
define("HESTIA_CMD", "/usr/bin/sudo /usr/local/hestia/bin/");
|
||||
define("DEFAULT_PHP_VERSION", "php-" . exec('php -r "echo substr(phpversion(),0,3);"'));
|
||||
|
||||
// Load Hestia Config directly
|
||||
load_hestia_config();
|
||||
require_once dirname(__FILE__) . "/prevent_csrf.php";
|
||||
require_once dirname(__FILE__) . "/helpers.php";
|
||||
$root_directory = dirname(__FILE__) . "/../../";
|
||||
|
||||
function destroy_sessions() {
|
||||
unset($_SESSION);
|
||||
session_unset();
|
||||
session_destroy();
|
||||
session_start();
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
|
||||
// Saving user IPs to the session for preventing session hijacking
|
||||
$user_combined_ip = "";
|
||||
if (isset($_SERVER["REMOTE_ADDR"])) {
|
||||
$user_combined_ip = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
if (isset($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$user_combined_ip .= "|" . $_SERVER["HTTP_CLIENT_IP"];
|
||||
}
|
||||
if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
$user_combined_ip .= "|" . $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
}
|
||||
if (isset($_SERVER["HTTP_FORWARDED_FOR"])) {
|
||||
$user_combined_ip .= "|" . $_SERVER["HTTP_FORWARDED_FOR"];
|
||||
}
|
||||
if (isset($_SERVER["HTTP_X_FORWARDED"])) {
|
||||
$user_combined_ip .= "|" . $_SERVER["HTTP_X_FORWARDED"];
|
||||
}
|
||||
if (isset($_SERVER["HTTP_FORWARDED"])) {
|
||||
$user_combined_ip .= "|" . $_SERVER["HTTP_FORWARDED"];
|
||||
}
|
||||
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
|
||||
if (!empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
|
||||
$user_combined_ip = $_SERVER["HTTP_CF_CONNECTING_IP"];
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($_SESSION["user_combined_ip"])) {
|
||||
$_SESSION["user_combined_ip"] = $user_combined_ip;
|
||||
}
|
||||
|
||||
// Checking user to use session from the same IP he has been logged in
|
||||
if (
|
||||
$_SESSION["user_combined_ip"] != $user_combined_ip &&
|
||||
isset($_SESSION["user"]) &&
|
||||
$_SESSION["DISABLE_IP_CHECK"] != "yes"
|
||||
) {
|
||||
$v_user = quoteshellarg($_SESSION["user"]);
|
||||
$v_session_id = quoteshellarg($_SESSION["token"]);
|
||||
exec(HESTIA_CMD . "v-log-user-logout " . $v_user . " " . $v_session_id, $output, $return_var);
|
||||
destroy_sessions();
|
||||
header("Location: /login/");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check system settings
|
||||
if (!isset($_SESSION["VERSION"]) && !defined("NO_AUTH_REQUIRED")) {
|
||||
destroy_sessions();
|
||||
header("Location: /login/");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check user session
|
||||
if (!isset($_SESSION["user"]) && !defined("NO_AUTH_REQUIRED")) {
|
||||
destroy_sessions();
|
||||
header("Location: /login/");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Generate CSRF Token
|
||||
if (isset($_SESSION["user"])) {
|
||||
if (!isset($_SESSION["token"])) {
|
||||
$token = bin2hex(random_bytes(16));
|
||||
$_SESSION["token"] = $token;
|
||||
}
|
||||
}
|
||||
|
||||
if ($_SESSION["RELEASE_BRANCH"] == "release" && $_SESSION["DEBUG_MODE"] == "false") {
|
||||
define("JS_LATEST_UPDATE", "v=" . $_SESSION["VERSION"]);
|
||||
} else {
|
||||
define("JS_LATEST_UPDATE", "r=" . time());
|
||||
}
|
||||
|
||||
if (!defined("NO_AUTH_REQUIRED")) {
|
||||
if (empty($_SESSION["LAST_ACTIVITY"]) || empty($_SESSION["INACTIVE_SESSION_TIMEOUT"])) {
|
||||
destroy_sessions();
|
||||
header("Location: /login/");
|
||||
} elseif ($_SESSION["INACTIVE_SESSION_TIMEOUT"] * 60 + $_SESSION["LAST_ACTIVITY"] < time()) {
|
||||
$v_user = quoteshellarg($_SESSION["user"]);
|
||||
$v_session_id = quoteshellarg($_SESSION["token"]);
|
||||
exec(
|
||||
HESTIA_CMD . "v-log-user-logout " . $v_user . " " . $v_session_id,
|
||||
$output,
|
||||
$return_var,
|
||||
);
|
||||
destroy_sessions();
|
||||
header("Location: /login/");
|
||||
exit();
|
||||
} else {
|
||||
$_SESSION["LAST_ACTIVITY"] = time();
|
||||
}
|
||||
}
|
||||
|
||||
function ipUsed() {
|
||||
[$http_host, $port] = explode(":", $_SERVER["HTTP_HOST"] . ":");
|
||||
if (filter_var($http_host, FILTER_VALIDATE_IP)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SESSION["user"])) {
|
||||
$user = quoteshellarg($_SESSION["user"]);
|
||||
$user_plain = htmlentities($_SESSION["user"]);
|
||||
}
|
||||
|
||||
if (isset($_SESSION["look"]) && $_SESSION["look"] != "" && $_SESSION["userContext"] === "admin") {
|
||||
$user = quoteshellarg($_SESSION["look"]);
|
||||
$user_plain = htmlentities($_SESSION["look"]);
|
||||
}
|
||||
if (empty($user_plain)) {
|
||||
$user_plain = "";
|
||||
}
|
||||
if (empty($_SESSION["look"])) {
|
||||
$_SESSION["look"] = "";
|
||||
}
|
||||
|
||||
require_once dirname(__FILE__) . "/i18n.php";
|
||||
|
||||
function check_error($return_var) {
|
||||
if ($return_var > 0) {
|
||||
header("Location: /error/");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
function check_return_code($return_var, $output) {
|
||||
if ($return_var != 0) {
|
||||
$error = implode("<br>", $output);
|
||||
if (empty($error)) {
|
||||
$error = sprintf(_("Error code: %s"), $return_var);
|
||||
}
|
||||
$_SESSION["error_msg"] = $error;
|
||||
}
|
||||
}
|
||||
function check_return_code_redirect($return_var, $output, $location) {
|
||||
if ($return_var != 0) {
|
||||
$error = implode("<br>", $output);
|
||||
if (empty($error)) {
|
||||
$error = sprintf(_("Error code: %s"), $return_var);
|
||||
}
|
||||
$_SESSION["error_msg"] = $error;
|
||||
header("Location:" . $location);
|
||||
}
|
||||
}
|
||||
|
||||
function render_page($user, $TAB, $page) {
|
||||
$__template_dir = dirname(__DIR__) . "/templates/";
|
||||
|
||||
// Extract global variables
|
||||
// I think those variables should be passed via arguments
|
||||
extract($GLOBALS, EXTR_SKIP);
|
||||
|
||||
// Header
|
||||
include $__template_dir . "header.php";
|
||||
|
||||
// Panel
|
||||
$panel = top_panel(empty($_SESSION["look"]) ? $_SESSION["user"] : $_SESSION["look"], $TAB);
|
||||
|
||||
// Policies controller
|
||||
@include_once dirname(__DIR__) . "/inc/policies.php";
|
||||
|
||||
// Body
|
||||
include $__template_dir . "pages/" . $page . ".php";
|
||||
|
||||
// Footer
|
||||
include $__template_dir . "footer.php";
|
||||
}
|
||||
|
||||
// Match $_SESSION['token'] against $_GET['token'] or $_POST['token']
|
||||
// Usage: verify_csrf($_POST) or verify_csrf($_GET); Use verify_csrf($_POST,true) to return on failure instead of redirect
|
||||
function verify_csrf($method, $return = false) {
|
||||
if (
|
||||
$method["token"] !== $_SESSION["token"] ||
|
||||
empty($method["token"]) ||
|
||||
empty($_SESSION["token"])
|
||||
) {
|
||||
if ($return === true) {
|
||||
return false;
|
||||
} else {
|
||||
header("Location: /login/");
|
||||
die();
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function show_alert_message($data) {
|
||||
$msgIcon = "";
|
||||
$msgText = "";
|
||||
$msgClass = "";
|
||||
if (!empty($data["error_msg"])) {
|
||||
$msgIcon = "fa-circle-exclamation";
|
||||
$msgText = htmlentities($data["error_msg"]);
|
||||
$msgClass = "inline-alert-danger";
|
||||
} elseif (!empty($data["ok_msg"])) {
|
||||
$msgIcon = "fa-circle-check";
|
||||
$msgText = $data["ok_msg"];
|
||||
$msgClass = "inline-alert-success";
|
||||
}
|
||||
|
||||
if (!empty($msgText)) {
|
||||
printf(
|
||||
'<div class="inline-alert %s u-mb20" role="alert"><i class="fas %s"></i><p>%s</p></div>',
|
||||
$msgClass,
|
||||
$msgIcon,
|
||||
$msgText,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function top_panel($user, $TAB) {
|
||||
$command = HESTIA_CMD . "v-list-user " . $user . " 'json'";
|
||||
exec($command, $output, $return_var);
|
||||
if ($return_var > 0) {
|
||||
destroy_sessions();
|
||||
$_SESSION["error_msg"] = _("You are logged out, please log in again.");
|
||||
header("Location: /login/");
|
||||
exit();
|
||||
}
|
||||
$panel = json_decode(implode("", $output), true);
|
||||
unset($output);
|
||||
|
||||
// Log out active sessions for suspended users
|
||||
if ($panel[$user]["SUSPENDED"] === "yes" && $_SESSION["POLICY_USER_VIEW_SUSPENDED"] !== "yes") {
|
||||
if (empty($_SESSION["look"])) {
|
||||
destroy_sessions();
|
||||
$_SESSION["error_msg"] = _("You are logged out, please log in again.");
|
||||
header("Location: /login/");
|
||||
}
|
||||
}
|
||||
|
||||
// Reset user permissions if changed while logged in
|
||||
if ($panel[$user]["ROLE"] !== $_SESSION["userContext"] && !isset($_SESSION["look"])) {
|
||||
unset($_SESSION["userContext"]);
|
||||
$_SESSION["userContext"] = $panel[$user]["ROLE"];
|
||||
}
|
||||
|
||||
// Load user's selected theme and do not change it when impersonting user
|
||||
if (isset($panel[$user]["THEME"]) && !isset($_SESSION["look"])) {
|
||||
$_SESSION["userTheme"] = $panel[$user]["THEME"];
|
||||
}
|
||||
|
||||
// Unset userTheme override variable if POLICY_USER_CHANGE_THEME is set to no
|
||||
if ($_SESSION["POLICY_USER_CHANGE_THEME"] === "no") {
|
||||
unset($_SESSION["userTheme"]);
|
||||
}
|
||||
|
||||
// Set preferred sort order
|
||||
if (!isset($_SESSION["look"])) {
|
||||
$_SESSION["userSortOrder"] = $panel[$user]["PREF_UI_SORT"];
|
||||
}
|
||||
|
||||
// Set home location URLs
|
||||
if ($_SESSION["userContext"] === "admin" && empty($_SESSION["look"])) {
|
||||
// Display users list for administrators unless they are impersonating a user account
|
||||
$home_url = "/list/user/";
|
||||
} else {
|
||||
// Set home location URL based on available package features from account
|
||||
if ($panel[$user]["WEB_DOMAINS"] != "0") {
|
||||
$home_url = "/list/web/";
|
||||
} elseif ($panel[$user]["DNS_DOMAINS"] != "0") {
|
||||
$home_url = "/list/dns/";
|
||||
} elseif ($panel[$user]["MAIL_DOMAINS"] != "0") {
|
||||
$home_url = "/list/mail/";
|
||||
} elseif ($panel[$user]["DATABASES"] != "0") {
|
||||
$home_url = "/list/db/";
|
||||
} elseif ($panel[$user]["CRON_JOBS"] != "0") {
|
||||
$home_url = "/list/cron/";
|
||||
} elseif ($panel[$user]["BACKUPS"] != "0") {
|
||||
$home_url = "/list/backups/";
|
||||
}
|
||||
}
|
||||
|
||||
include dirname(__FILE__) . "/../templates/includes/panel.php";
|
||||
return $panel;
|
||||
}
|
||||
|
||||
function translate_date($date) {
|
||||
$date = new DateTime($date);
|
||||
return $date->format("d") . " " . _($date->format("M")) . " " . $date->format("Y");
|
||||
}
|
||||
|
||||
function humanize_time($usage) {
|
||||
if ($usage > 60) {
|
||||
$usage = $usage / 60;
|
||||
if ($usage > 24) {
|
||||
$usage = $usage / 24;
|
||||
$usage = number_format($usage);
|
||||
return sprintf(ngettext("%d day", "%d days", $usage), $usage);
|
||||
} else {
|
||||
$usage = round($usage);
|
||||
return sprintf(ngettext("%d hour", "%d hours", $usage), $usage);
|
||||
}
|
||||
} else {
|
||||
$usage = round($usage);
|
||||
return sprintf(ngettext("%d minute", "%d minutes", $usage), $usage);
|
||||
}
|
||||
}
|
||||
|
||||
function humanize_usage_size($usage, $round = 2) {
|
||||
if ($usage == "unlimited") {
|
||||
return "∞";
|
||||
}
|
||||
$display_usage = $usage;
|
||||
if ($usage > 1024) {
|
||||
$usage = $usage / 1024;
|
||||
if ($usage > 1024) {
|
||||
$usage = $usage / 1024;
|
||||
if ($usage > 1024) {
|
||||
$usage = $usage / 1024;
|
||||
$display_usage = number_format($usage, $round);
|
||||
} else {
|
||||
if ($usage > 999) {
|
||||
$usage = $usage / 1024;
|
||||
}
|
||||
$display_usage = number_format($usage, $round);
|
||||
}
|
||||
} else {
|
||||
if ($usage > 999) {
|
||||
$usage = $usage / 1024;
|
||||
}
|
||||
$display_usage = number_format($usage, $round);
|
||||
}
|
||||
} else {
|
||||
if ($usage > 999) {
|
||||
$usage = $usage / 1024;
|
||||
}
|
||||
$display_usage = number_format($usage, $round);
|
||||
}
|
||||
return $display_usage;
|
||||
}
|
||||
|
||||
function humanize_usage_measure($usage) {
|
||||
if ($usage == "unlimited") {
|
||||
return;
|
||||
}
|
||||
|
||||
$measure = "kb";
|
||||
if ($usage > 1024) {
|
||||
$usage = $usage / 1024;
|
||||
if ($usage > 1024) {
|
||||
$usage = $usage / 1024;
|
||||
$measure = $usage < 1024 ? "tb" : "pb";
|
||||
if ($usage > 999) {
|
||||
$usage = $usage / 1024;
|
||||
$measure = "pb";
|
||||
}
|
||||
} else {
|
||||
$measure = $usage < 1024 ? "gb" : "tb";
|
||||
if ($usage > 999) {
|
||||
$usage = $usage / 1024;
|
||||
$measure = "tb";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$measure = $usage < 1024 ? "mb" : "gb";
|
||||
if ($usage > 999) {
|
||||
$measure = "gb";
|
||||
}
|
||||
}
|
||||
return $measure;
|
||||
}
|
||||
|
||||
function get_percentage($used, $total) {
|
||||
if ($total = "unlimited") {
|
||||
//return 0 if unlimited
|
||||
return 0;
|
||||
}
|
||||
if (!isset($total)) {
|
||||
$total = 0;
|
||||
}
|
||||
if (!isset($used)) {
|
||||
$used = 0;
|
||||
}
|
||||
if ($total == 0) {
|
||||
$percent = 0;
|
||||
} else {
|
||||
$percent = $used / $total;
|
||||
$percent = $percent * 100;
|
||||
$percent = number_format($percent, 0, "", "");
|
||||
if ($percent < 0) {
|
||||
$percent = 0;
|
||||
} elseif ($percent > 100) {
|
||||
$percent = 100;
|
||||
}
|
||||
}
|
||||
return $percent;
|
||||
}
|
||||
|
||||
function send_email($to, $subject, $mailtext, $from, $from_name, $to_name = "") {
|
||||
$mail = new PHPMailer();
|
||||
|
||||
if (isset($_SESSION["USE_SERVER_SMTP"]) && $_SESSION["USE_SERVER_SMTP"] == "true") {
|
||||
if (!empty($_SESSION["SERVER_SMTP_ADDR"]) && $_SESSION["SERVER_SMTP_ADDR"] != "") {
|
||||
if (filter_var($_SESSION["SERVER_SMTP_ADDR"], FILTER_VALIDATE_EMAIL)) {
|
||||
$from = $_SESSION["SERVER_SMTP_ADDR"];
|
||||
}
|
||||
}
|
||||
|
||||
$mail->IsSMTP();
|
||||
$mail->Mailer = "smtp";
|
||||
$mail->SMTPDebug = 0;
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->SMTPSecure = $_SESSION["SERVER_SMTP_SECURITY"];
|
||||
$mail->Port = $_SESSION["SERVER_SMTP_PORT"];
|
||||
$mail->Host = $_SESSION["SERVER_SMTP_HOST"];
|
||||
$mail->Username = $_SESSION["SERVER_SMTP_USER"];
|
||||
$mail->Password = $_SESSION["SERVER_SMTP_PASSWD"];
|
||||
}
|
||||
|
||||
$mail->IsHTML(true);
|
||||
$mail->ClearReplyTos();
|
||||
if (empty($to_name)) {
|
||||
$mail->AddAddress($to);
|
||||
} else {
|
||||
$mail->AddAddress($to, $to_name);
|
||||
}
|
||||
$mail->SetFrom($from, $from_name);
|
||||
|
||||
$mail->CharSet = "utf-8";
|
||||
$mail->Subject = $subject;
|
||||
$content = $mailtext;
|
||||
$content = nl2br($content);
|
||||
$mail->MsgHTML($content);
|
||||
$mail->Send();
|
||||
}
|
||||
|
||||
function list_timezones() {
|
||||
foreach (
|
||||
["AKST", "AKDT", "PST", "PDT", "MST", "MDT", "CST", "CDT", "EST", "EDT", "AST", "ADT"]
|
||||
as $timezone
|
||||
) {
|
||||
$tz = new DateTimeZone($timezone);
|
||||
$timezone_offsets[$timezone] = $tz->getOffset(new DateTime());
|
||||
}
|
||||
|
||||
foreach (DateTimeZone::listIdentifiers() as $timezone) {
|
||||
$tz = new DateTimeZone($timezone);
|
||||
$timezone_offsets[$timezone] = $tz->getOffset(new DateTime());
|
||||
}
|
||||
|
||||
foreach ($timezone_offsets as $timezone => $offset) {
|
||||
$offset_prefix = $offset < 0 ? "-" : "+";
|
||||
$offset_formatted = gmdate("H:i", abs($offset));
|
||||
$pretty_offset = "UTC{$offset_prefix}{$offset_formatted}";
|
||||
$c = new DateTime(gmdate("Y-M-d H:i:s"), new DateTimeZone("UTC"));
|
||||
$c->setTimezone(new DateTimeZone($timezone));
|
||||
$current_time = $c->format("H:i:s");
|
||||
$timezone_list[$timezone] = "$timezone [ $current_time ] {$pretty_offset}";
|
||||
#$timezone_list[$timezone] = "$timezone ${pretty_offset}";
|
||||
}
|
||||
return $timezone_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that tells is it MySQL installed on the system, or it is MariaDB.
|
||||
*
|
||||
* Explanation:
|
||||
* $_SESSION['DB_SYSTEM'] has 'mysql' value even if MariaDB is installed, so you can't figure out is it really MySQL or it's MariaDB.
|
||||
* So, this function will make it clear.
|
||||
*
|
||||
* If MySQL is installed, function will return 'mysql' as a string.
|
||||
* If MariaDB is installed, function will return 'mariadb' as a string.
|
||||
*
|
||||
* Hint: if you want to check if PostgreSQL is installed - check value of $_SESSION['DB_SYSTEM']
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function is_it_mysql_or_mariadb() {
|
||||
exec(HESTIA_CMD . "v-list-sys-services json", $output, $return_var);
|
||||
$data = json_decode(implode("", $output), true);
|
||||
unset($output);
|
||||
$mysqltype = "mysql";
|
||||
if (isset($data["mariadb"])) {
|
||||
$mysqltype = "mariadb";
|
||||
}
|
||||
return $mysqltype;
|
||||
}
|
||||
|
||||
function load_hestia_config() {
|
||||
// Check system configuration
|
||||
exec(HESTIA_CMD . "v-list-sys-config json", $output, $return_var);
|
||||
$data = json_decode(implode("", $output), true);
|
||||
$sys_arr = $data["config"];
|
||||
foreach ($sys_arr as $key => $value) {
|
||||
$_SESSION[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of all web domains from all users grouped by Backend Template used and owner
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function backendtpl_with_webdomains() {
|
||||
exec(HESTIA_CMD . "v-list-users json", $output, $return_var);
|
||||
$users = json_decode(implode("", $output), true);
|
||||
unset($output);
|
||||
|
||||
$backend_list = [];
|
||||
foreach ($users as $user => $user_details) {
|
||||
exec(
|
||||
HESTIA_CMD . "v-list-web-domains " . quoteshellarg($user) . " json",
|
||||
$output,
|
||||
$return_var,
|
||||
);
|
||||
$domains = json_decode(implode("", $output), true);
|
||||
unset($output);
|
||||
foreach ($domains as $domain => $domain_details) {
|
||||
if (!empty($domain_details["BACKEND"])) {
|
||||
$backend = $domain_details["BACKEND"];
|
||||
$backend_list[$backend][$user][] = $domain;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $backend_list;
|
||||
}
|
||||
/**
|
||||
* Check if password is valid
|
||||
*
|
||||
* @return int; 1 / 0
|
||||
*/
|
||||
function validate_password($password) {
|
||||
return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(.){8,}$/', $password);
|
||||
}
|
||||
|
||||
function unset_alerts() {
|
||||
if (!empty($_SESSION["unset_alerts"])) {
|
||||
if (!empty($_SESSION["error_msg"])) {
|
||||
unset($_SESSION["error_msg"]);
|
||||
}
|
||||
if (!empty($_SESSION["ok_msg"])) {
|
||||
unset($_SESSION["ok_msg"]);
|
||||
}
|
||||
unset($_SESSION["unset_alerts"]);
|
||||
}
|
||||
}
|
||||
register_shutdown_function("unset_alerts");
|
||||
20
web/inc/policies.php
Normal file
20
web/inc/policies.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
if (
|
||||
($_SESSION["userContext"] === "user" &&
|
||||
$panel[$user]["SUSPENDED"] === "yes" &&
|
||||
$_SESSION["POLICY_USER_VIEW_SUSPENDED"] === "yes") ||
|
||||
($_SESSION["userContext"] === "admin" &&
|
||||
$_SESSION["look"] === "admin" &&
|
||||
$_SESSION["POLICY_SYSTEM_PROTECTED_ADMIN"] === "yes")
|
||||
) {
|
||||
$read_only = "true";
|
||||
} else {
|
||||
$read_only = "";
|
||||
}
|
||||
|
||||
if ($read_only === "true") {
|
||||
$display_mode = "disabled";
|
||||
} else {
|
||||
$display_mode = "";
|
||||
}
|
||||
151
web/inc/prevent_csrf.php
Normal file
151
web/inc/prevent_csrf.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
$check_csrf = true;
|
||||
|
||||
if (
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web/inc/mail-wrapper.php" ||
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia//web/inc/mail-wrapper.php"
|
||||
) {
|
||||
$check_csrf = false;
|
||||
} // execute only from CLI
|
||||
if (
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web/reset/mail/index.php" ||
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web//reset/mail/index.php"
|
||||
) {
|
||||
$check_csrf = false;
|
||||
} // Localhost only
|
||||
if (
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web/api/index.php" ||
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web//api/index.php"
|
||||
) {
|
||||
$check_csrf = false;
|
||||
} // Own check
|
||||
if (substr($_SERVER["SCRIPT_FILENAME"], 0, 22) == "/usr/local/hestia/bin/") {
|
||||
$check_csrf = false;
|
||||
}
|
||||
|
||||
function checkStrictness($level) {
|
||||
if ($level >= $_SESSION["POLICY_CSRF_STRICTNESS"]) {
|
||||
return true;
|
||||
} else {
|
||||
http_response_code(400);
|
||||
echo "<h1>Potential CSRF use detected</h1>\n" .
|
||||
"<p>Please disable any plugins/add-ons inside your browser or contact your system administrator. If you are the system administrator you can run v-change-sys-config-value 'POLICY_CSRF_STRICTNESS' '0' as root to disable this check.<p>" .
|
||||
"<p>If you followed a bookmark or an static link please <a href='/'>navigate to root</a>";
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
function prevent_post_csrf() {
|
||||
if (!empty($_SERVER["REQUEST_METHOD"])) {
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
if (!empty($_SERVER["HTTP_HOST"])) {
|
||||
$hostname = preg_replace(
|
||||
"/(\[?[^]]*\]?):([0-9]{1,5})$/",
|
||||
"$1",
|
||||
$_SERVER["HTTP_HOST"],
|
||||
);
|
||||
$port_is_defined = preg_match("/\[?[^]]*\]?:[0-9]{1,5}$/", $_SERVER["HTTP_HOST"]);
|
||||
if ($port_is_defined) {
|
||||
$port = preg_replace(
|
||||
"/(\[?[^]]*\]?):([0-9]{1,5})$/",
|
||||
"$2",
|
||||
$_SERVER["HTTP_HOST"],
|
||||
);
|
||||
} else {
|
||||
$port = 443;
|
||||
}
|
||||
} else {
|
||||
$hostname = gethostname();
|
||||
$port = 443;
|
||||
}
|
||||
if (isset($_SERVER["HTTP_ORIGIN"])) {
|
||||
$origin_host = parse_url($_SERVER["HTTP_ORIGIN"], PHP_URL_HOST);
|
||||
if (
|
||||
strcmp($origin_host, gethostname()) === 0 &&
|
||||
in_array($port, ["443", $_SERVER["SERVER_PORT"]])
|
||||
) {
|
||||
return checkStrictness(2);
|
||||
} else {
|
||||
if (
|
||||
strcmp($origin_host, $hostname) === 0 &&
|
||||
in_array($port, ["443", $_SERVER["SERVER_PORT"]])
|
||||
) {
|
||||
return checkStrictness(1);
|
||||
} else {
|
||||
return checkStrictness(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function prevent_get_csrf() {
|
||||
if (!empty($_SERVER["REQUEST_METHOD"])) {
|
||||
if ($_SERVER["REQUEST_METHOD"] === "GET") {
|
||||
if (!empty($_SERVER["HTTP_HOST"])) {
|
||||
$hostname = preg_replace(
|
||||
"/(\[?[^]]*\]?):([0-9]{1,5})$/",
|
||||
"$1",
|
||||
$_SERVER["HTTP_HOST"],
|
||||
);
|
||||
$port_is_defined = preg_match("/\[?[^]]*\]?:[0-9]{1,5}$/", $_SERVER["HTTP_HOST"]);
|
||||
if ($port_is_defined) {
|
||||
$port = preg_replace(
|
||||
"/(\[?[^]]*\]?):([0-9]{1,5})$/",
|
||||
"$2",
|
||||
$_SERVER["HTTP_HOST"],
|
||||
);
|
||||
} else {
|
||||
$port = 443;
|
||||
}
|
||||
} else {
|
||||
$hostname = gethostname();
|
||||
$port = 443;
|
||||
}
|
||||
|
||||
//list of possible entries route and these should never be blocked
|
||||
if (
|
||||
in_array($_SERVER["DOCUMENT_URI"], [
|
||||
"/list/user/index.php",
|
||||
"/login/index.php",
|
||||
"/list/web/index.php",
|
||||
"/list/dns/index.php",
|
||||
"/list/mail/index.php",
|
||||
"/list/db/index.php",
|
||||
"/list/cron/index.php",
|
||||
"/list/backup/index.php",
|
||||
"/reset/index.php",
|
||||
])
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (isset($_SERVER["HTTP_REFERER"])) {
|
||||
$referrer_host = parse_url($_SERVER["HTTP_REFERER"], PHP_URL_HOST);
|
||||
if (
|
||||
strcmp($referrer_host, gethostname()) === 0 &&
|
||||
in_array($port, ["443", $_SERVER["SERVER_PORT"]])
|
||||
) {
|
||||
return checkStrictness(2);
|
||||
} else {
|
||||
if (
|
||||
strcmp($referrer_host, $hostname) === 0 &&
|
||||
in_array($port, ["443", $_SERVER["SERVER_PORT"]])
|
||||
) {
|
||||
return checkStrictness(1);
|
||||
} else {
|
||||
return checkStrictness(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return checkStrictness(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($check_csrf == true) {
|
||||
prevent_post_csrf();
|
||||
prevent_get_csrf();
|
||||
}
|
||||
31
web/inc/secure_login.php
Normal file
31
web/inc/secure_login.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
$login_url_skip = 0;
|
||||
if (
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web/reset/mail/index.php" ||
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web//reset/mail/index.php" ||
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web/reset/mail/set-ar.php" ||
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web//reset/mail/set-ar.php" ||
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web/reset/mail/get-ar.php" ||
|
||||
$_SERVER["SCRIPT_FILENAME"] == "/usr/local/hestia/web//reset/mail/get-ar.php" ||
|
||||
substr($_SERVER["SCRIPT_FILENAME"], 0, 21) == "/usr/local/hestia/bin/"
|
||||
) {
|
||||
$login_url_skip = 1;
|
||||
}
|
||||
|
||||
if ($login_url_skip == 0) {
|
||||
if (!isset($login_url_loaded)) {
|
||||
$login_url_loaded = 1;
|
||||
if (file_exists("/usr/local/hestia/web/inc/login_url.php")) {
|
||||
require_once "/usr/local/hestia/web/inc/login_url.php";
|
||||
if (isset($_GET[$login_url])) {
|
||||
setcookie($login_url, "1", time() + 31536000, "/", $_SERVER["HTTP_HOST"], true);
|
||||
header("Location: /login/");
|
||||
exit();
|
||||
}
|
||||
if (!isset($_COOKIE[$login_url])) {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user