Compare commits
112 Commits
2.0.13
...
upgrade-2.
| Author | SHA1 | Date | |
|---|---|---|---|
| d7a3568506 | |||
| 10c13bc5b1 | |||
| dcb3f6f568 | |||
| 7566def0d1 | |||
| 3630f82817 | |||
| 9ddd2e9154 | |||
| 53afe4ebd1 | |||
| 4f69e8ee0e | |||
| 32f5b0d5e9 | |||
| 53a6485a6e | |||
| f2643ac887 | |||
| e37687a85d | |||
| ccbc3286a5 | |||
| 929a562324 | |||
| 3704cf6621 | |||
| 10238a1466 | |||
| 9002ddf4a2 | |||
| 8a2de5a44a | |||
| 96c0af18dd | |||
| 5bb228ce78 | |||
| 804128280c | |||
| 5b8e918f75 | |||
| 0e3e83d184 | |||
| 8ced61c6aa | |||
| 29a2ab7567 | |||
|
|
166ec0575b | ||
|
|
215e749ba8 | ||
|
|
506cccd7c8 | ||
|
|
6d9014c29b | ||
|
|
10555bff76 | ||
|
|
37aa7af4da | ||
|
|
4b75369597 | ||
|
|
9d0e463906 | ||
|
|
a7198f58ce | ||
|
|
47be4b2847 | ||
|
|
b0fae4bd14 | ||
|
|
4711a41436 | ||
|
|
faa71ceaef | ||
|
|
2d30394150 | ||
|
|
99c1182af8 | ||
|
|
d9abe58dd2 | ||
|
|
23034b8ad2 | ||
|
|
1cae5638d3 | ||
|
|
ce9a5f97a3 | ||
|
|
c38b90deef | ||
|
|
13daa7d6fa | ||
|
|
b0e43d332d | ||
|
|
75c8754fb4 | ||
|
|
e0fa64f897 | ||
|
|
ed72fd1766 | ||
|
|
826ae36647 | ||
|
|
9ddf24539e | ||
|
|
3940c1429d | ||
|
|
c236d9eaab | ||
|
|
688994e40c | ||
|
|
9facaee809 | ||
|
|
a7dd5f4685 | ||
|
|
da810ea953 | ||
|
|
51b6e067e8 | ||
|
|
34cf6698bc | ||
|
|
4642160724 | ||
|
|
78a259ef3b | ||
|
|
68cf4ab69a | ||
|
|
d5661d492d | ||
|
|
6900898ae1 | ||
|
|
d90fb7fa68 | ||
|
|
4ea8629fcc | ||
|
|
9d4ff8698d | ||
|
|
b164038846 | ||
|
|
5c46960734 | ||
|
|
a7f4f0c737 | ||
|
|
b64dd501dd | ||
|
|
1679675aa1 | ||
|
|
640466f301 | ||
|
|
9c9771a371 | ||
|
|
1922b3ce65 | ||
|
|
83e819908a | ||
|
|
0924aa644b | ||
|
|
7711ce1d66 | ||
|
|
7dae63e586 | ||
|
|
1bcaa45492 | ||
|
|
66cb114f0d | ||
|
|
1c5d60dcfd | ||
|
|
b6da6356fc | ||
|
|
c09670cc45 | ||
|
|
464f5b7bed | ||
|
|
c799235c24 | ||
|
|
a2860e70a5 | ||
|
|
95a96d46a6 | ||
|
|
81f3dbda31 | ||
|
|
4eb4191843 | ||
|
|
ca433d8a61 | ||
|
|
8f4dfe1514 | ||
|
|
ee42f5168e | ||
|
|
fc8ca57f8c | ||
|
|
7e4bba2d55 | ||
|
|
7e635f9be4 | ||
|
|
e9406a20f2 | ||
|
|
de7729cec8 | ||
|
|
d60e48849b | ||
|
|
908df5a7bb | ||
|
|
c1952afb94 | ||
|
|
7a22e8f4dd | ||
|
|
3ac0da2cdd | ||
|
|
eb816c4cc6 | ||
|
|
64d8bf4fba | ||
|
|
ae6ee95973 | ||
|
|
e9051dc30a | ||
|
|
b6c7c53c3a | ||
|
|
f36bc61fc7 | ||
|
|
c56e0b9dac | ||
|
|
1deb08bf75 |
53
.drone.yml
Normal file
53
.drone.yml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
kind: pipeline
|
||||||
|
name: deploy-froxlor
|
||||||
|
type: docker
|
||||||
|
|
||||||
|
platform:
|
||||||
|
os: linux
|
||||||
|
arch: arm64
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- upgrade-2.0
|
||||||
|
event:
|
||||||
|
include:
|
||||||
|
- push
|
||||||
|
|
||||||
|
environment:
|
||||||
|
DEPLOY_HOST: rechner.maketank.net
|
||||||
|
DEPLOY_DIR: ~/froxlor-test
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: deploy
|
||||||
|
image: cr.wks/drone/drone-rsync:latest
|
||||||
|
settings:
|
||||||
|
hosts: ["rechner02.maketank.net"]
|
||||||
|
source: ./
|
||||||
|
target: ~/froxlor-test
|
||||||
|
user: www-data
|
||||||
|
exclude: ['vendor', '.git*', '*drone.yml', '.settings', '.buildpath', '.editorconfig', '.project', '.travis.yml', 'node_modules']
|
||||||
|
args: '-v --delete'
|
||||||
|
log_level: quiet
|
||||||
|
key:
|
||||||
|
from_secret: ssh-www-data-maketank-rsa
|
||||||
|
command_timeout: 10m
|
||||||
|
- name: compose
|
||||||
|
image: appleboy/drone-ssh
|
||||||
|
settings:
|
||||||
|
host:
|
||||||
|
- rechner02.maketank.net
|
||||||
|
username: www-data
|
||||||
|
key:
|
||||||
|
from_secret: ssh-www-data-maketank-rsa
|
||||||
|
script:
|
||||||
|
- cd ~/froxlor-test && composer install --no-dev
|
||||||
|
- name: npm
|
||||||
|
image: appleboy/drone-ssh
|
||||||
|
settings:
|
||||||
|
host:
|
||||||
|
- rechner02.maketank.net
|
||||||
|
username: www-data
|
||||||
|
key:
|
||||||
|
from_secret: ssh-www-data-maketank-rsa
|
||||||
|
script:
|
||||||
|
- cd ~/froxlor-test && npm install && npm run build
|
||||||
2
.github/workflows/build-docs.yml
vendored
2
.github/workflows/build-docs.yml
vendored
@@ -11,4 +11,4 @@ jobs:
|
|||||||
- env:
|
- env:
|
||||||
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
gh workflow run --repo Froxlor/Documentation build-and-deploy -f type=tags ref=${{github.ref_name}}
|
gh workflow run --repo Froxlor/Documentation build-and-deploy.yml -f type=tags ref=${{github.ref_name}}
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -18,7 +18,6 @@ img/
|
|||||||
vendor/
|
vendor/
|
||||||
node_modules/
|
node_modules/
|
||||||
fonts/
|
fonts/
|
||||||
templates/*
|
|
||||||
!templates/index.html
|
!templates/index.html
|
||||||
!templates/Froxlor/
|
!templates/Froxlor/
|
||||||
templates/Froxlor/assets/mix-manifest.json
|
templates/Froxlor/assets/mix-manifest.json
|
||||||
|
|||||||
@@ -138,6 +138,26 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
|
'system_req_limit_per_interval' => [
|
||||||
|
'label' => lng('serversettings.req_limit_per_interval'),
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'req_limit_per_interval',
|
||||||
|
'type' => 'number',
|
||||||
|
'min' => 30,
|
||||||
|
'default' => 60,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'advanced_mode' => true
|
||||||
|
],
|
||||||
|
'system_req_limit_interval' => [
|
||||||
|
'label' => lng('serversettings.req_limit_interval'),
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'req_limit_interval',
|
||||||
|
'type' => 'number',
|
||||||
|
'min' => 5,
|
||||||
|
'default' => 60,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'advanced_mode' => true
|
||||||
|
],
|
||||||
'customer_accountprefix' => [
|
'customer_accountprefix' => [
|
||||||
'label' => lng('serversettings.accountprefix'),
|
'label' => lng('serversettings.accountprefix'),
|
||||||
'settinggroup' => 'customer',
|
'settinggroup' => 'customer',
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ return [
|
|||||||
'string_regexp' => '/^(([a-z0-9\-\._]+, ?)*[a-z0-9\-\._]+)?$/i',
|
'string_regexp' => '/^(([a-z0-9\-\._]+, ?)*[a-z0-9\-\._]+)?$/i',
|
||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingClearCertificates',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin
|
|||||||
$result['switched_user'] = CurrentUser::getData();
|
$result['switched_user'] = CurrentUser::getData();
|
||||||
$result['adminsession'] = 1;
|
$result['adminsession'] = 1;
|
||||||
$result['userid'] = $result['adminid'];
|
$result['userid'] = $result['adminid'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
|
|
||||||
$log->logAction(
|
$log->logAction(
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ require __DIR__ . '/lib/init.php';
|
|||||||
|
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\Http\HttpClient;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\Install\AutoUpdate;
|
use Froxlor\Install\AutoUpdate;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
@@ -132,7 +132,7 @@ elseif ($page == 'getdownload') {
|
|||||||
elseif ($page == 'extract') {
|
elseif ($page == 'extract') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
$toExtract = isset($_POST['archive']) ? $_POST['archive'] : null;
|
$toExtract = isset($_POST['archive']) ? $_POST['archive'] : null;
|
||||||
$localArchive = Froxlor::getInstallDir() . '/updates/' . $toExtract;
|
$localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract);
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Extracting " . $localArchive . " to " . Froxlor::getInstallDir());
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Extracting " . $localArchive . " to " . Froxlor::getInstallDir());
|
||||||
$result = AutoUpdate::extractZip($localArchive);
|
$result = AutoUpdate::extractZip($localArchive);
|
||||||
if ($result > 0) {
|
if ($result > 0) {
|
||||||
@@ -146,7 +146,7 @@ elseif ($page == 'extract') {
|
|||||||
Response::redirectTo('admin_updates.php');
|
Response::redirectTo('admin_updates.php');
|
||||||
} else {
|
} else {
|
||||||
$toExtract = isset($_GET['archive']) ? $_GET['archive'] : null;
|
$toExtract = isset($_GET['archive']) ? $_GET['archive'] : null;
|
||||||
$localArchive = Froxlor::getInstallDir() . '/updates/' . $toExtract;
|
$localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_exists($localArchive)) {
|
if (!file_exists($localArchive)) {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use Froxlor\Settings;
|
|||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
|
|
||||||
if ($userinfo['change_serversettings'] == '1') {
|
if ($userinfo['change_serversettings'] == '1') {
|
||||||
if ($action == 'setconfigured') {
|
if ($action == 'setconfigured') {
|
||||||
@@ -91,6 +92,7 @@ if ($userinfo['change_serversettings'] == '1') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($distribution != "" && isset($_POST['finish'])) {
|
if ($distribution != "" && isset($_POST['finish'])) {
|
||||||
|
$valid_keys = ['http', 'dns', 'smtp', 'mail', 'ftp', 'system', 'distro'];
|
||||||
unset($_POST['finish']);
|
unset($_POST['finish']);
|
||||||
unset($_POST['csrf_token']);
|
unset($_POST['csrf_token']);
|
||||||
$params = $_POST;
|
$params = $_POST;
|
||||||
@@ -99,6 +101,20 @@ if ($userinfo['change_serversettings'] == '1') {
|
|||||||
foreach ($_POST['system'] as $sysdaemon) {
|
foreach ($_POST['system'] as $sysdaemon) {
|
||||||
$params['system'][] = $sysdaemon;
|
$params['system'][] = $sysdaemon;
|
||||||
}
|
}
|
||||||
|
// validate params
|
||||||
|
foreach ($params as $key => $value) {
|
||||||
|
if (!in_array($key, $valid_keys)) {
|
||||||
|
unset($params[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!is_array($value)) {
|
||||||
|
$params[$key] = Validate::validate($value, $key);
|
||||||
|
} else {
|
||||||
|
foreach ($value as $subkey => $subvalue) {
|
||||||
|
$params[$key][$subkey] = Validate::validate($subvalue, $key.'.'.$subkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
$params_content = json_encode($params);
|
$params_content = json_encode($params);
|
||||||
$params_filename = FileDir::makeCorrectFile(Froxlor::getInstallDir() . 'install/' . Froxlor::genSessionId() . '.json');
|
$params_filename = FileDir::makeCorrectFile(Froxlor::getInstallDir() . 'install/' . Froxlor::genSessionId() . '.json');
|
||||||
file_put_contents($params_filename, $params_content);
|
file_put_contents($params_filename, $params_content);
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
|
|||||||
$result['switched_user'] = CurrentUser::getData();
|
$result['switched_user'] = CurrentUser::getData();
|
||||||
$result['adminsession'] = 0;
|
$result['adminsession'] = 0;
|
||||||
$result['userid'] = $result['customerid'];
|
$result['userid'] = $result['customerid'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
|
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "switched user and is now '" . $destination_user . "'");
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "switched user and is now '" . $destination_user . "'");
|
||||||
|
|||||||
@@ -282,6 +282,12 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$openbasedir = [
|
||||||
|
0 => lng('domain.docroot'),
|
||||||
|
1 => lng('domain.homedir'),
|
||||||
|
2 => lng('domain.docparent')
|
||||||
|
];
|
||||||
|
|
||||||
// create serveralias options
|
// create serveralias options
|
||||||
$serveraliasoptions = [
|
$serveraliasoptions = [
|
||||||
0 => lng('domains.serveraliasoption_wildcard'),
|
0 => lng('domains.serveraliasoption_wildcard'),
|
||||||
@@ -545,6 +551,12 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
$result['temporary_ssl_redirect'] = $result['ssl_redirect'];
|
$result['temporary_ssl_redirect'] = $result['ssl_redirect'];
|
||||||
$result['ssl_redirect'] = ($result['ssl_redirect'] == 0 ? 0 : 1);
|
$result['ssl_redirect'] = ($result['ssl_redirect'] == 0 ? 0 : 1);
|
||||||
|
|
||||||
|
$openbasedir = [
|
||||||
|
0 => lng('domain.docroot'),
|
||||||
|
1 => lng('domain.homedir'),
|
||||||
|
2 => lng('domain.docparent')
|
||||||
|
];
|
||||||
|
|
||||||
$serveraliasoptions = [
|
$serveraliasoptions = [
|
||||||
0 => lng('domains.serveraliasoption_wildcard'),
|
0 => lng('domains.serveraliasoption_wildcard'),
|
||||||
1 => lng('domains.serveraliasoption_www'),
|
1 => lng('domains.serveraliasoption_www'),
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ if ($action == 'logout') {
|
|||||||
if (is_array(CurrentUser::getField('switched_user'))) {
|
if (is_array(CurrentUser::getField('switched_user'))) {
|
||||||
$result = CurrentUser::getData();
|
$result = CurrentUser::getData();
|
||||||
$result = $result['switched_user'];
|
$result = $result['switched_user'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
||||||
$redirect = "admin_" . $target . ".php";
|
$redirect = "admin_" . $target . ".php";
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Froxlor\Cli\ConfigDiff;
|
||||||
use Symfony\Component\Console\Application;
|
use Symfony\Component\Console\Application;
|
||||||
use Froxlor\Cli\RunApiCommand;
|
use Froxlor\Cli\RunApiCommand;
|
||||||
use Froxlor\Cli\ConfigServices;
|
use Froxlor\Cli\ConfigServices;
|
||||||
@@ -61,4 +62,5 @@ $application->add(new InstallCommand());
|
|||||||
$application->add(new MasterCron());
|
$application->add(new MasterCron());
|
||||||
$application->add(new UserCommand());
|
$application->add(new UserCommand());
|
||||||
$application->add(new ValidateAcmeWebroot());
|
$application->add(new ValidateAcmeWebroot());
|
||||||
|
$application->add(new ConfigDiff());
|
||||||
$application->run();
|
$application->run();
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"ext-fileinfo": "*",
|
"ext-fileinfo": "*",
|
||||||
"ext-gmp": "*",
|
"ext-gmp": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
"phpmailer/phpmailer": "~6.0",
|
"phpmailer/phpmailer": "~6.0",
|
||||||
"monolog/monolog": "^1.24",
|
"monolog/monolog": "^1.24",
|
||||||
"robthree/twofactorauth": "^1.6",
|
"robthree/twofactorauth": "^1.6",
|
||||||
|
|||||||
175
composer.lock
generated
175
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "41e7a3bc0e13b47c4f245334b113c3be",
|
"content-hash": "2de39e6b85579ce1f0c2f7a16d57ede3",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "erusev/parsedown",
|
"name": "erusev/parsedown",
|
||||||
@@ -251,16 +251,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpmailer/phpmailer",
|
"name": "phpmailer/phpmailer",
|
||||||
"version": "v6.7.1",
|
"version": "v6.8.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||||
"reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55"
|
"reference": "df16b615e371d81fb79e506277faea67a1be18f1"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/49cd7ea3d2563f028d7811f06864a53b1f15ff55",
|
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/df16b615e371d81fb79e506277faea67a1be18f1",
|
||||||
"reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55",
|
"reference": "df16b615e371d81fb79e506277faea67a1be18f1",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -319,7 +319,7 @@
|
|||||||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
|
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
|
||||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.7.1"
|
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -327,7 +327,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-12-08T13:30:06+00:00"
|
"time": "2023-03-06T14:43:22+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/container",
|
"name": "psr/container",
|
||||||
@@ -499,16 +499,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
"version": "v5.4.19",
|
"version": "v5.4.22",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/console.git",
|
"url": "https://github.com/symfony/console.git",
|
||||||
"reference": "dccb8d251a9017d5994c988b034d3e18aaabf740"
|
"reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/console/zipball/dccb8d251a9017d5994c988b034d3e18aaabf740",
|
"url": "https://api.github.com/repos/symfony/console/zipball/3cd51fd2e6c461ca678f84d419461281bd87a0a8",
|
||||||
"reference": "dccb8d251a9017d5994c988b034d3e18aaabf740",
|
"reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -573,12 +573,12 @@
|
|||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"cli",
|
"cli",
|
||||||
"command line",
|
"command-line",
|
||||||
"console",
|
"console",
|
||||||
"terminal"
|
"terminal"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/console/tree/v5.4.19"
|
"source": "https://github.com/symfony/console/tree/v5.4.22"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -594,7 +594,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-01-01T08:32:19+00:00"
|
"time": "2023-03-25T09:27:28+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/deprecation-contracts",
|
"name": "symfony/deprecation-contracts",
|
||||||
@@ -1399,16 +1399,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/string",
|
"name": "symfony/string",
|
||||||
"version": "v5.4.19",
|
"version": "v5.4.22",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/string.git",
|
"url": "https://github.com/symfony/string.git",
|
||||||
"reference": "0a01071610fd861cc160dfb7e2682ceec66064cb"
|
"reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/string/zipball/0a01071610fd861cc160dfb7e2682ceec66064cb",
|
"url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62",
|
||||||
"reference": "0a01071610fd861cc160dfb7e2682ceec66064cb",
|
"reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1465,7 +1465,7 @@
|
|||||||
"utf8"
|
"utf8"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/string/tree/v5.4.19"
|
"source": "https://github.com/symfony/string/tree/v5.4.22"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1481,7 +1481,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-01-01T08:32:19+00:00"
|
"time": "2023-03-14T06:11:53+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/twig",
|
"name": "twig/twig",
|
||||||
@@ -1718,16 +1718,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "voku/portable-utf8",
|
"name": "voku/portable-utf8",
|
||||||
"version": "6.0.12",
|
"version": "6.0.13",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/voku/portable-utf8.git",
|
"url": "https://github.com/voku/portable-utf8.git",
|
||||||
"reference": "db0583727bb17666bbd2ba238c85babb973fd165"
|
"reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/voku/portable-utf8/zipball/db0583727bb17666bbd2ba238c85babb973fd165",
|
"url": "https://api.github.com/repos/voku/portable-utf8/zipball/b8ce36bf26593e5c2e81b1850ef0ffb299d2043f",
|
||||||
"reference": "db0583727bb17666bbd2ba238c85babb973fd165",
|
"reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1793,7 +1793,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/voku/portable-utf8/issues",
|
"issues": "https://github.com/voku/portable-utf8/issues",
|
||||||
"source": "https://github.com/voku/portable-utf8/tree/6.0.12"
|
"source": "https://github.com/voku/portable-utf8/tree/6.0.13"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1817,7 +1817,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-01-11T12:26:16+00:00"
|
"time": "2023-03-08T08:35:38+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
@@ -2030,16 +2030,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "myclabs/deep-copy",
|
"name": "myclabs/deep-copy",
|
||||||
"version": "1.11.0",
|
"version": "1.11.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||||
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
|
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
|
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||||
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
|
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2077,7 +2077,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
|
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2085,20 +2085,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-03-03T13:19:32+00:00"
|
"time": "2023-03-08T13:26:56+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/php-parser",
|
"name": "nikic/php-parser",
|
||||||
"version": "v4.15.3",
|
"version": "v4.15.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||||
"reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039"
|
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039",
|
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
|
||||||
"reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039",
|
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2139,22 +2139,22 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3"
|
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4"
|
||||||
},
|
},
|
||||||
"time": "2023-01-16T22:05:37+00:00"
|
"time": "2023-03-05T19:49:14+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pdepend/pdepend",
|
"name": "pdepend/pdepend",
|
||||||
"version": "2.12.1",
|
"version": "2.13.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pdepend/pdepend.git",
|
"url": "https://github.com/pdepend/pdepend.git",
|
||||||
"reference": "7a892d56ceafd804b4a2ecc85184640937ce9e84"
|
"reference": "31be7cd4f305f3f7b52af99c1cb13fc938d1cfad"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/7a892d56ceafd804b4a2ecc85184640937ce9e84",
|
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/31be7cd4f305f3f7b52af99c1cb13fc938d1cfad",
|
||||||
"reference": "7a892d56ceafd804b4a2ecc85184640937ce9e84",
|
"reference": "31be7cd4f305f3f7b52af99c1cb13fc938d1cfad",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2190,7 +2190,7 @@
|
|||||||
"description": "Official version of pdepend to be handled with Composer",
|
"description": "Official version of pdepend to be handled with Composer",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pdepend/pdepend/issues",
|
"issues": "https://github.com/pdepend/pdepend/issues",
|
||||||
"source": "https://github.com/pdepend/pdepend/tree/2.12.1"
|
"source": "https://github.com/pdepend/pdepend/tree/2.13.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2198,7 +2198,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-09-08T19:30:37+00:00"
|
"time": "2023-02-28T20:56:15+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/manifest",
|
"name": "phar-io/manifest",
|
||||||
@@ -2520,16 +2520,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan",
|
"name": "phpstan/phpstan",
|
||||||
"version": "1.10.3",
|
"version": "1.10.14",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpstan.git",
|
"url": "https://github.com/phpstan/phpstan.git",
|
||||||
"reference": "5419375b5891add97dc74be71e6c1c34baaddf64"
|
"reference": "d232901b09e67538e5c86a724be841bea5768a7c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/5419375b5891add97dc74be71e6c1c34baaddf64",
|
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/d232901b09e67538e5c86a724be841bea5768a7c",
|
||||||
"reference": "5419375b5891add97dc74be71e6c1c34baaddf64",
|
"reference": "d232901b09e67538e5c86a724be841bea5768a7c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2558,8 +2558,11 @@
|
|||||||
"static analysis"
|
"static analysis"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
|
"docs": "https://phpstan.org/user-guide/getting-started",
|
||||||
|
"forum": "https://github.com/phpstan/phpstan/discussions",
|
||||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||||
"source": "https://github.com/phpstan/phpstan/tree/1.10.3"
|
"security": "https://github.com/phpstan/phpstan/security/policy",
|
||||||
|
"source": "https://github.com/phpstan/phpstan-src"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2575,20 +2578,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-02-25T14:47:13+00:00"
|
"time": "2023-04-19T13:47:27+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "9.2.25",
|
"version": "9.2.26",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||||
"reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954"
|
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e2b40518197a8c0d4b08bc34dfff1c99c508954",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
|
||||||
"reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954",
|
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2610,8 +2613,8 @@
|
|||||||
"phpunit/phpunit": "^9.3"
|
"phpunit/phpunit": "^9.3"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-pcov": "*",
|
"ext-pcov": "PHP extension that provides line coverage",
|
||||||
"ext-xdebug": "*"
|
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
@@ -2644,7 +2647,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.25"
|
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2652,7 +2655,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-02-25T05:32:00+00:00"
|
"time": "2023-03-06T12:58:08+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-file-iterator",
|
"name": "phpunit/php-file-iterator",
|
||||||
@@ -2897,16 +2900,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "9.6.3",
|
"version": "9.6.7",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555"
|
"reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7b1615e3e887d6c719121c6d4a44b0ab9645555",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c993f0d3b0489ffc42ee2fe0bd645af1538a63b2",
|
||||||
"reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555",
|
"reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2939,8 +2942,8 @@
|
|||||||
"sebastian/version": "^3.0.2"
|
"sebastian/version": "^3.0.2"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-soap": "*",
|
"ext-soap": "To be able to generate mocks based on WSDL files",
|
||||||
"ext-xdebug": "*"
|
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
|
||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
"phpunit"
|
"phpunit"
|
||||||
@@ -2979,7 +2982,8 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.3"
|
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||||
|
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.7"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2995,7 +2999,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-02-04T13:37:15+00:00"
|
"time": "2023-04-14T08:58:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/cli-parser",
|
"name": "sebastian/cli-parser",
|
||||||
@@ -4082,16 +4086,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/config",
|
"name": "symfony/config",
|
||||||
"version": "v5.4.19",
|
"version": "v5.4.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/config.git",
|
"url": "https://github.com/symfony/config.git",
|
||||||
"reference": "9bd60843443cda9638efdca7c41eb82ed0026179"
|
"reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/config/zipball/9bd60843443cda9638efdca7c41eb82ed0026179",
|
"url": "https://api.github.com/repos/symfony/config/zipball/2a6b1111d038adfa15d52c0871e540f3b352d1e4",
|
||||||
"reference": "9bd60843443cda9638efdca7c41eb82ed0026179",
|
"reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -4141,7 +4145,7 @@
|
|||||||
"description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
|
"description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/config/tree/v5.4.19"
|
"source": "https://github.com/symfony/config/tree/v5.4.21"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -4157,20 +4161,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-01-08T13:23:55+00:00"
|
"time": "2023-02-14T08:03:56+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/dependency-injection",
|
"name": "symfony/dependency-injection",
|
||||||
"version": "v5.4.20",
|
"version": "v5.4.22",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/dependency-injection.git",
|
"url": "https://github.com/symfony/dependency-injection.git",
|
||||||
"reference": "8185ed0df129005a26715902f1a53bad0fe67102"
|
"reference": "e1b7c1432efb4ad1dd89d62906187271e2601ed9"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8185ed0df129005a26715902f1a53bad0fe67102",
|
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e1b7c1432efb4ad1dd89d62906187271e2601ed9",
|
||||||
"reference": "8185ed0df129005a26715902f1a53bad0fe67102",
|
"reference": "e1b7c1432efb4ad1dd89d62906187271e2601ed9",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -4230,7 +4234,7 @@
|
|||||||
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
|
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/dependency-injection/tree/v5.4.20"
|
"source": "https://github.com/symfony/dependency-injection/tree/v5.4.22"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -4246,20 +4250,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-01-27T11:08:11+00:00"
|
"time": "2023-03-10T10:02:45+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/filesystem",
|
"name": "symfony/filesystem",
|
||||||
"version": "v5.4.19",
|
"version": "v5.4.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/filesystem.git",
|
"url": "https://github.com/symfony/filesystem.git",
|
||||||
"reference": "648bfaca6a494f3e22378123bcee2894045dc9d8"
|
"reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/648bfaca6a494f3e22378123bcee2894045dc9d8",
|
"url": "https://api.github.com/repos/symfony/filesystem/zipball/e75960b1bbfd2b8c9e483e0d74811d555ca3de9f",
|
||||||
"reference": "648bfaca6a494f3e22378123bcee2894045dc9d8",
|
"reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -4294,7 +4298,7 @@
|
|||||||
"description": "Provides basic utilities for the filesystem",
|
"description": "Provides basic utilities for the filesystem",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/filesystem/tree/v5.4.19"
|
"source": "https://github.com/symfony/filesystem/tree/v5.4.21"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -4310,7 +4314,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-01-14T19:14:44+00:00"
|
"time": "2023-02-14T08:03:56+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-php81",
|
"name": "symfony/polyfill-php81",
|
||||||
@@ -4462,7 +4466,8 @@
|
|||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"ext-fileinfo": "*",
|
"ext-fileinfo": "*",
|
||||||
"ext-gmp": "*"
|
"ext-gmp": "*",
|
||||||
|
"ext-gd": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": {
|
"platform-dev": {
|
||||||
"ext-pcntl": "*"
|
"ext-pcntl": "*"
|
||||||
|
|||||||
@@ -299,6 +299,30 @@ if ($page == 'email_domain') {
|
|||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
]);
|
]);
|
||||||
|
} elseif ($action == 'togglegreylist' && $id != 0) {
|
||||||
|
try {
|
||||||
|
$json_result = Emails::getLocal($userinfo, [
|
||||||
|
'id' => $id
|
||||||
|
])->get();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
$result = json_decode($json_result, true)['data'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
Emails::getLocal($userinfo, [
|
||||||
|
'id' => $id,
|
||||||
|
'disablegreylist' => ($result['disablegreylist'] == '1' ? 0 : 1)
|
||||||
|
])->updateGreylist();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
Response::redirectTo($filename, [
|
||||||
|
'page' => $page,
|
||||||
|
'domainid' => $email_domainid,
|
||||||
|
'action' => 'edit',
|
||||||
|
'id' => $id,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
} elseif ($page == 'accounts') {
|
} elseif ($page == 'accounts') {
|
||||||
$email_domainid = Request::any('domainid', 0);
|
$email_domainid = Request::any('domainid', 0);
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ if ($page == 'overview' || $page == 'accounts') {
|
|||||||
if (Settings::Get('customer.ftpatdomain') == '1') {
|
if (Settings::Get('customer.ftpatdomain') == '1') {
|
||||||
$domainlist = [];
|
$domainlist = [];
|
||||||
$result_domains_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
$result_domains_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE `customerid`= :customerid");
|
WHERE `customerid`= :customerid ORDER BY `domain` ASC");
|
||||||
Database::pexecute($result_domains_stmt, [
|
Database::pexecute($result_domains_stmt, [
|
||||||
"customerid" => $userinfo['customerid']
|
"customerid" => $userinfo['customerid']
|
||||||
]);
|
]);
|
||||||
@@ -127,7 +127,6 @@ if ($page == 'overview' || $page == 'accounts') {
|
|||||||
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$domainlist[$row_domain['domain']] = $idna_convert->decode($row_domain['domain']);
|
$domainlist[$row_domain['domain']] = $idna_convert->decode($row_domain['domain']);
|
||||||
}
|
}
|
||||||
sort($domainlist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::Get('system.allow_customer_shell') == '1') {
|
if (Settings::Get('system.allow_customer_shell') == '1') {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ if ($action == 'logout') {
|
|||||||
if (is_array(CurrentUser::getField('switched_user'))) {
|
if (is_array(CurrentUser::getField('switched_user'))) {
|
||||||
$result = CurrentUser::getData();
|
$result = CurrentUser::getData();
|
||||||
$result = $result['switched_user'];
|
$result = $result['switched_user'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
||||||
$redirect = "admin_" . $target . ".php";
|
$redirect = "admin_" . $target . ".php";
|
||||||
|
|||||||
101
index.php
101
index.php
@@ -40,7 +40,6 @@ use Froxlor\UI\Panel\UI;
|
|||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\User;
|
use Froxlor\User;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use Froxlor\Language;
|
|
||||||
|
|
||||||
if ($action == '') {
|
if ($action == '') {
|
||||||
$action = 'login';
|
$action = 'login';
|
||||||
@@ -53,9 +52,15 @@ if ($action == '2fa_entercode') {
|
|||||||
Response::redirectTo('index.php');
|
Response::redirectTo('index.php');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
$smessage = isset($_GET['showmessage']) ? (int)$_GET['showmessage'] : 0;
|
||||||
|
$message = "";
|
||||||
|
if ($smessage > 0) {
|
||||||
|
$message = lng('error.2fa_wrongcode');
|
||||||
|
}
|
||||||
// show template to enter code
|
// show template to enter code
|
||||||
UI::view('login/enter2fa.html.twig', [
|
UI::view('login/enter2fa.html.twig', [
|
||||||
'pagetitle' => lng('login.2fa')
|
'pagetitle' => lng('login.2fa'),
|
||||||
|
'message' => $message
|
||||||
]);
|
]);
|
||||||
} elseif ($action == '2fa_verify') {
|
} elseif ($action == '2fa_verify') {
|
||||||
// verify code from 2fa code-enter form
|
// verify code from 2fa code-enter form
|
||||||
@@ -68,25 +73,25 @@ if ($action == '2fa_entercode') {
|
|||||||
// verify entered code
|
// verify entered code
|
||||||
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
||||||
$result = ($_SESSION['secret_2fa'] == 'email' ? true : $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3));
|
$result = ($_SESSION['secret_2fa'] == 'email' ? true : $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3));
|
||||||
|
// get user-data
|
||||||
|
$table = $_SESSION['uidtable_2fa'];
|
||||||
|
$field = $_SESSION['uidfield_2fa'];
|
||||||
|
$uid = $_SESSION['uid_2fa'];
|
||||||
|
$isadmin = $_SESSION['unfo_2fa'];
|
||||||
// either the code is valid when using authenticator-app, or we will select userdata by id and entered code
|
// either the code is valid when using authenticator-app, or we will select userdata by id and entered code
|
||||||
// which is temporarily stored for the customer when using email-2fa
|
// which is temporarily stored for the customer when using email-2fa
|
||||||
if ($result) {
|
if ($result) {
|
||||||
// get user-data
|
|
||||||
$table = $_SESSION['uidtable_2fa'];
|
|
||||||
$field = $_SESSION['uidfield_2fa'];
|
|
||||||
$uid = $_SESSION['uid_2fa'];
|
|
||||||
$isadmin = $_SESSION['unfo_2fa'];
|
|
||||||
$sel_param = [
|
$sel_param = [
|
||||||
'uid' => $uid
|
'uid' => $uid
|
||||||
];
|
];
|
||||||
if ($_SESSION['secret_2fa'] == 'email') {
|
if ($_SESSION['secret_2fa'] == 'email') {
|
||||||
// verify code by selecting user by id and the temp. stored code,
|
// verify code by selecting user by id and the temp. stored code,
|
||||||
// so only if it's the correct code, we get the user-data
|
// so only if it's the correct code, we get the user-data
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM $table WHERE `" . $field . "` = :uid AND `data_2fa` = :code");
|
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid AND `data_2fa` = :code");
|
||||||
$sel_param['code'] = $code;
|
$sel_param['code'] = $code;
|
||||||
} else {
|
} else {
|
||||||
// Authenticator-verification has already happened at this point, so just get the user-data
|
// Authenticator-verification has already happened at this point, so just get the user-data
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM $table WHERE `" . $field . "` = :uid");
|
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid");
|
||||||
}
|
}
|
||||||
$userinfo = Database::pexecute_first($sel_stmt, $sel_param);
|
$userinfo = Database::pexecute_first($sel_stmt, $sel_param);
|
||||||
// whoops, no (valid) user? Start again
|
// whoops, no (valid) user? Start again
|
||||||
@@ -108,19 +113,54 @@ if ($action == '2fa_entercode') {
|
|||||||
|
|
||||||
// when using email-2fa, remove the one-time-code
|
// when using email-2fa, remove the one-time-code
|
||||||
if ($userinfo['type_2fa'] == '1') {
|
if ($userinfo['type_2fa'] == '1') {
|
||||||
$del_stmt = Database::prepare("UPDATE $table SET `data_2fa` = '' WHERE `" . $field . "` = :uid");
|
$del_stmt = Database::prepare("UPDATE " . $table . " SET `data_2fa` = '' WHERE `" . $field . "` = :uid");
|
||||||
$userinfo = Database::pexecute_first($del_stmt, [
|
$userinfo = Database::pexecute_first($del_stmt, [
|
||||||
'uid' => $uid
|
'uid' => $uid
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
// wrong 2fa code - treat like "wrong password"
|
||||||
|
$stmt = Database::prepare("
|
||||||
|
UPDATE " . $table . "
|
||||||
|
SET `lastlogin_fail`= :lastlogin_fail, `loginfail_count`=`loginfail_count`+1
|
||||||
|
WHERE `" . $field . "`= :uid
|
||||||
|
");
|
||||||
|
Database::pexecute($stmt, [
|
||||||
|
"lastlogin_fail" => time(),
|
||||||
|
"uid" => $uid
|
||||||
|
]);
|
||||||
|
|
||||||
|
// get data for processing further
|
||||||
|
$stmt = Database::prepare("
|
||||||
|
SELECT `loginname`, `loginfail_count`, `lastlogin_fail` FROM " . $table . "
|
||||||
|
WHERE `" . $field . "`= :uid
|
||||||
|
");
|
||||||
|
$fail_user = Database::pexecute_first($stmt, [
|
||||||
|
"uid" => $uid
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($fail_user['loginfail_count'] >= Settings::Get('login.maxloginattempts') && $fail_user['lastlogin_fail'] > (time() - Settings::Get('login.deactivatetime'))) {
|
||||||
|
// Log failed login
|
||||||
|
$rstlog = FroxlorLogger::getInstanceOf([
|
||||||
|
'loginname' => $_SERVER['REMOTE_ADDR']
|
||||||
|
]);
|
||||||
|
$rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "User '" . $fail_user['loginname'] . "' entered wrong 2fa code too often.");
|
||||||
|
unset($fail_user);
|
||||||
|
Response::redirectTo('index.php', [
|
||||||
|
'showmessage' => '3'
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
unset($fail_user);
|
||||||
|
// back to form
|
||||||
Response::redirectTo('index.php', [
|
Response::redirectTo('index.php', [
|
||||||
'showmessage' => '2'
|
'action' => '2fa_entercode',
|
||||||
|
'showmessage' => '1'
|
||||||
]);
|
]);
|
||||||
exit();
|
exit();
|
||||||
} elseif ($action == 'login') {
|
} elseif ($action == 'login') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (!empty($_POST)) {
|
||||||
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
||||||
$password = Validate::validate($_POST['password'], 'password');
|
$password = Validate::validate($_POST['password'], 'password');
|
||||||
|
|
||||||
@@ -390,13 +430,18 @@ if ($action == '2fa_entercode') {
|
|||||||
}
|
}
|
||||||
$lastqrystr = "";
|
$lastqrystr = "";
|
||||||
if (isset($_REQUEST['qrystr']) && $_REQUEST['qrystr'] != "") {
|
if (isset($_REQUEST['qrystr']) && $_REQUEST['qrystr'] != "") {
|
||||||
$lastqrystr = htmlspecialchars($_REQUEST['qrystr'], ENT_QUOTES);
|
$lastqrystr = urlencode($_REQUEST['qrystr']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($lastscript)) {
|
||||||
|
$_SESSION['lastscript'] = $lastscript;
|
||||||
|
}
|
||||||
|
if (!empty($lastqrystr)) {
|
||||||
|
$_SESSION['lastqrystr'] = $lastqrystr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('login/login.html.twig', [
|
UI::view('login/login.html.twig', [
|
||||||
'pagetitle' => 'Login',
|
'pagetitle' => 'Login',
|
||||||
'lastscript' => $lastscript,
|
|
||||||
'lastqrystr' => $lastqrystr,
|
|
||||||
'upd_in_progress' => $update_in_progress,
|
'upd_in_progress' => $update_in_progress,
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
'successmsg' => $successmessage
|
'successmsg' => $successmessage
|
||||||
@@ -408,7 +453,7 @@ if ($action == 'forgotpwd') {
|
|||||||
$adminchecked = false;
|
$adminchecked = false;
|
||||||
$message = '';
|
$message = '';
|
||||||
|
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (!empty($_POST)) {
|
||||||
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
||||||
$email = Validate::validateEmail($_POST['loginemail']);
|
$email = Validate::validateEmail($_POST['loginemail']);
|
||||||
$result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "`
|
$result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "`
|
||||||
@@ -592,7 +637,7 @@ if ($action == 'forgotpwd') {
|
|||||||
|
|
||||||
UI::view('login/fpwd.html.twig', [
|
UI::view('login/fpwd.html.twig', [
|
||||||
'pagetitle' => lng('login.presend'),
|
'pagetitle' => lng('login.presend'),
|
||||||
'action' => $action,
|
'formaction' => 'index.php?action=' . $action,
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -615,7 +660,7 @@ if ($action == 'resetpwd') {
|
|||||||
$check = substr($activationcode, 40, 10);
|
$check = substr($activationcode, 40, 10);
|
||||||
|
|
||||||
if (substr(md5($third . $timestamp), 0, 10) == $check && $timestamp >= time() - 86400) {
|
if (substr(md5($third . $timestamp), 0, 10) == $check && $timestamp >= time() - 86400) {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (!empty($_POST)) {
|
||||||
$stmt = Database::prepare("SELECT `userid`, `admin` FROM `" . TABLE_PANEL_ACTIVATION . "`
|
$stmt = Database::prepare("SELECT `userid`, `admin` FROM `" . TABLE_PANEL_ACTIVATION . "`
|
||||||
WHERE `activationcode` = :activationcode");
|
WHERE `activationcode` = :activationcode");
|
||||||
$result = Database::pexecute_first($stmt, [
|
$result = Database::pexecute_first($stmt, [
|
||||||
@@ -692,6 +737,7 @@ if ($action == 'resetpwd') {
|
|||||||
function finishLogin($userinfo)
|
function finishLogin($userinfo)
|
||||||
{
|
{
|
||||||
if (isset($userinfo['userid']) && $userinfo['userid'] != '') {
|
if (isset($userinfo['userid']) && $userinfo['userid'] != '') {
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($userinfo);
|
CurrentUser::setData($userinfo);
|
||||||
|
|
||||||
$language = $userinfo['def_language'] ?? Settings::Get('panel.standardlanguage');
|
$language = $userinfo['def_language'] ?? Settings::Get('panel.standardlanguage');
|
||||||
@@ -705,29 +751,34 @@ function finishLogin($userinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
$qryparams = [];
|
$qryparams = [];
|
||||||
if (isset($_POST['qrystr']) && $_POST['qrystr'] != "") {
|
if (!empty($_SESSION['lastqrystr'])) {
|
||||||
parse_str(urldecode($_POST['qrystr']), $qryparams);
|
parse_str(urldecode($_SESSION['lastqrystr']), $qryparams);
|
||||||
|
unset($_SESSION['lastqrystr']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($userinfo['adminsession'] == '1') {
|
if ($userinfo['adminsession'] == '1') {
|
||||||
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
||||||
Response::redirectTo('admin_updates.php?page=overview');
|
Response::redirectTo('admin_updates.php?page=overview');
|
||||||
} else {
|
} else {
|
||||||
if (isset($_POST['script']) && $_POST['script'] != "") {
|
if (!empty($_SESSION['lastscript'])) {
|
||||||
if (preg_match("/customer\_/", $_POST['script']) === 1) {
|
$lastscript = $_SESSION['lastscript'];
|
||||||
|
unset($_SESSION['lastscript']);
|
||||||
|
if (preg_match("/customer\_/", $lastscript) === 1) {
|
||||||
Response::redirectTo('admin_customers.php', [
|
Response::redirectTo('admin_customers.php', [
|
||||||
"page" => "customers"
|
"page" => "customers"
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
Response::redirectTo($_POST['script'], $qryparams);
|
Response::redirectTo($lastscript, $qryparams);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Response::redirectTo('admin_index.php', $qryparams);
|
Response::redirectTo('admin_index.php', $qryparams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isset($_POST['script']) && $_POST['script'] != "") {
|
if (!empty($_SESSION['lastscript'])) {
|
||||||
Response::redirectTo($_POST['script'], $qryparams);
|
$lastscript = $_SESSION['lastscript'];
|
||||||
|
unset($_SESSION['lastscript']);
|
||||||
|
Response::redirectTo($lastscript, $qryparams);
|
||||||
} else {
|
} else {
|
||||||
Response::redirectTo('customer_index.php', $qryparams);
|
Response::redirectTo('customer_index.php', $qryparams);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -697,8 +697,10 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'distribution', ''),
|
('system', 'distribution', ''),
|
||||||
('system', 'update_channel', 'stable'),
|
('system', 'update_channel', 'stable'),
|
||||||
('system', 'updatecheck_data', ''),
|
('system', 'updatecheck_data', ''),
|
||||||
('system', 'update_notify_last', '2.0.13'),
|
('system', 'update_notify_last', '2.0.24'),
|
||||||
('system', 'traffictool', 'goaccess'),
|
('system', 'traffictool', 'goaccess'),
|
||||||
|
('system', 'req_limit_per_interval', 60),
|
||||||
|
('system', 'req_limit_interval', 60),
|
||||||
('api', 'enabled', '0'),
|
('api', 'enabled', '0'),
|
||||||
('api', 'customer_default', '1'),
|
('api', 'customer_default', '1'),
|
||||||
('2fa', 'enabled', '1'),
|
('2fa', 'enabled', '1'),
|
||||||
@@ -742,8 +744,8 @@ opcache.validate_timestamps'),
|
|||||||
('panel', 'logo_overridetheme', '0'),
|
('panel', 'logo_overridetheme', '0'),
|
||||||
('panel', 'logo_overridecustom', '0'),
|
('panel', 'logo_overridecustom', '0'),
|
||||||
('panel', 'settings_mode', '0'),
|
('panel', 'settings_mode', '0'),
|
||||||
('panel', 'version', '2.0.13'),
|
('panel', 'version', '2.0.24'),
|
||||||
('panel', 'db_version', '202302030');
|
('panel', 'db_version', '202304260');
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_tasks`;
|
DROP TABLE IF EXISTS `panel_tasks`;
|
||||||
@@ -983,7 +985,9 @@ CREATE TABLE IF NOT EXISTS `domain_ssl_settings` (
|
|||||||
`ssl_cert_chainfile` mediumtext,
|
`ssl_cert_chainfile` mediumtext,
|
||||||
`ssl_csr_file` mediumtext,
|
`ssl_csr_file` mediumtext,
|
||||||
`ssl_fullchain_file` mediumtext,
|
`ssl_fullchain_file` mediumtext,
|
||||||
`expirationdate` datetime DEFAULT NULL,
|
`validfromdate` datetime DEFAULT NULL,
|
||||||
|
`validtodate` datetime DEFAULT NULL,
|
||||||
|
`issuer` varchar(255) NOT NULL default '',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY (`domainid`)
|
UNIQUE KEY (`domainid`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Froxlor\Http\RateLimiter;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\Install\Install;
|
use Froxlor\Install\Install;
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ require dirname(__DIR__) . '/lib/tables.inc.php';
|
|||||||
// init twig
|
// init twig
|
||||||
UI::initTwig(true);
|
UI::initTwig(true);
|
||||||
UI::sendHeaders();
|
UI::sendHeaders();
|
||||||
|
RateLimiter::run(true);
|
||||||
|
|
||||||
$installer = new Install();
|
$installer = new Install();
|
||||||
$installer->handle();
|
$installer->handle();
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\FileDir;
|
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Settings;
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Install\Update;
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
|
||||||
if (!defined('_CRON_UPDATE')) {
|
if (!defined('_CRON_UPDATE')) {
|
||||||
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
|
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
|
||||||
@@ -82,7 +82,7 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` DROP COLUMN `domains_see_all`;");
|
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` DROP COLUMN `domains_see_all`;");
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
Update::showUpdateStep("Checking for multiple mysql-servers to allow acccess to customers for existing databases");
|
Update::showUpdateStep("Checking for multiple mysql-servers to allow access to customers for existing databases");
|
||||||
$dbservers_stmt = Database::query("
|
$dbservers_stmt = Database::query("
|
||||||
SELECT `customerid`,
|
SELECT `customerid`,
|
||||||
GROUP_CONCAT(DISTINCT `dbserver` SEPARATOR ',') as allowed_mysqlserver
|
GROUP_CONCAT(DISTINCT `dbserver` SEPARATOR ',') as allowed_mysqlserver
|
||||||
@@ -93,7 +93,8 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
if (isset($dbserver['allowed_mysqlserver']) && !empty($dbserver['allowed_mysqlserver'])) {
|
if (isset($dbserver['allowed_mysqlserver']) && !empty($dbserver['allowed_mysqlserver'])) {
|
||||||
$allowed_mysqlserver = json_encode(explode(",", $dbserver['allowed_mysqlserver']));
|
$allowed_mysqlserver = json_encode(explode(",", $dbserver['allowed_mysqlserver']));
|
||||||
Database::pexecute($upd_stmt, ['allowed_mysql_server' => $allowed_mysqlserver, 'customerid' => $dbserver['customerid']]);
|
Database::pexecute($upd_stmt,
|
||||||
|
['allowed_mysql_server' => $allowed_mysqlserver, 'customerid' => $dbserver['customerid']]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
@@ -140,14 +141,15 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
// none of the files existed
|
// none of the files existed
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
} else {
|
} else {
|
||||||
Update::lastStepStatus(1, 'manual commands needed', 'Please run the following commands manually:<br><pre>' . $del_list . '</pre>');
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Update::showUpdateStep("Adding new settings");
|
Update::showUpdateStep("Adding new settings");
|
||||||
$panel_settings_mode = isset($_POST['panel_settings_mode']) ? (int)$_POST['panel_settings_mode'] : 0;
|
$panel_settings_mode = isset($_POST['panel_settings_mode']) ? (int)$_POST['panel_settings_mode'] : 0;
|
||||||
Settings::AddNew("panel.settings_mode", $panel_settings_mode);
|
Settings::AddNew("panel.settings_mode", $panel_settings_mode);
|
||||||
$system_distribution = isset($_POST['system_distribution']) ? $_POST['system_distribution'] : '';
|
$system_distribution = isset($_POST['system_distribution']) ? $_POST['system_distribution'] : 'bullseye';
|
||||||
Settings::AddNew("system.distribution", $system_distribution);
|
Settings::AddNew("system.distribution", $system_distribution);
|
||||||
Settings::AddNew("system.update_channel", 'stable');
|
Settings::AddNew("system.update_channel", 'stable');
|
||||||
Settings::AddNew("system.updatecheck_data", '');
|
Settings::AddNew("system.updatecheck_data", '');
|
||||||
@@ -224,7 +226,8 @@ EOF;
|
|||||||
} else {
|
} else {
|
||||||
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
||||||
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
||||||
Update::lastStepStatus(1, 'manual commands needed', 'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
||||||
}
|
}
|
||||||
|
|
||||||
Froxlor::updateToDbVersion('202212060');
|
Froxlor::updateToDbVersion('202212060');
|
||||||
@@ -283,7 +286,8 @@ EOF;
|
|||||||
} else {
|
} else {
|
||||||
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
||||||
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
||||||
Update::lastStepStatus(1, 'manual commands needed', 'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Froxlor::updateToVersion('2.0.4');
|
Froxlor::updateToVersion('2.0.4');
|
||||||
@@ -323,7 +327,7 @@ if (Froxlor::isDatabaseVersion('202212060')) {
|
|||||||
$system_letsencryptchallengepath_upd = isset($_POST['system_letsencryptchallengepath_upd']) ? $_POST['system_letsencryptchallengepath_upd'] : $acmesh_challenge_dir;
|
$system_letsencryptchallengepath_upd = isset($_POST['system_letsencryptchallengepath_upd']) ? $_POST['system_letsencryptchallengepath_upd'] : $acmesh_challenge_dir;
|
||||||
if ($acmesh_challenge_dir != $system_letsencryptchallengepath_upd) {
|
if ($acmesh_challenge_dir != $system_letsencryptchallengepath_upd) {
|
||||||
Settings::Set('system.letsencryptchallengepath', $system_letsencryptchallengepath_upd);
|
Settings::Set('system.letsencryptchallengepath', $system_letsencryptchallengepath_upd);
|
||||||
if ((int) Settings::Get('system.leenabled') == 1) {
|
if ((int)Settings::Get('system.leenabled') == 1) {
|
||||||
// create JSON string for --apply
|
// create JSON string for --apply
|
||||||
$dist = Settings::Get('system.distribution');
|
$dist = Settings::Get('system.distribution');
|
||||||
$webserver = Settings::Get('system.webserver');
|
$webserver = Settings::Get('system.webserver');
|
||||||
@@ -405,3 +409,111 @@ if (Froxlor::isFroxlorVersion('2.0.12')) {
|
|||||||
Update::showUpdateStep("Updating from 2.0.12 to 2.0.13", false);
|
Update::showUpdateStep("Updating from 2.0.12 to 2.0.13", false);
|
||||||
Froxlor::updateToVersion('2.0.13');
|
Froxlor::updateToVersion('2.0.13');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202302030')) {
|
||||||
|
Update::showUpdateStep("Correcting language mapping of templates created pre 2.0.x");
|
||||||
|
// languages from 0.10.x
|
||||||
|
$language_mapping_comp = [
|
||||||
|
'de' => 'Deutsch',
|
||||||
|
'en' => 'English',
|
||||||
|
'fr' => 'Français',
|
||||||
|
'pt' => 'Português',
|
||||||
|
'it' => 'Italiano',
|
||||||
|
'nl' => 'Nederlands',
|
||||||
|
'se' => 'Svenska',
|
||||||
|
'cz' => 'Česká republika'
|
||||||
|
];
|
||||||
|
$upd_tpl_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET `language` = :iso WHERE `language` = :lng");
|
||||||
|
foreach ($language_mapping_comp as $iso => $lang) {
|
||||||
|
Database::pexecute($upd_tpl_stmt, ['iso' => $iso, 'lng' => $lang]);
|
||||||
|
}
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Enhancing ssl data table");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` CHANGE `expirationdate` `validtodate` datetime DEFAULT NULL;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` ADD `validfromdate` datetime DEFAULT NULL AFTER `ssl_fullchain_file`;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` ADD `issuer` varchar(255) NOT NULL default '' AFTER `validtodate`;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Filling new ssl data fields with existing certificate data");
|
||||||
|
$crt_upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` SET `validfromdate` = :validfromdate, `issuer` = :issuer WHERE `id` = :id");
|
||||||
|
$crt_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`");
|
||||||
|
Database::pexecute($crt_stmt);
|
||||||
|
while ($cert = $crt_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$cert_content = openssl_x509_parse($cert['ssl_cert_file']);
|
||||||
|
if (is_array($cert_content)) {
|
||||||
|
$validfromdate = empty($cert_content['validFrom_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validFrom_time_t']);
|
||||||
|
$issuer = $cert_content['issuer']['O'] ?? "";
|
||||||
|
Database::pexecute($crt_upd_stmt, ['validfromdate' => $validfromdate, 'issuer' => $issuer, 'id' => $cert['id']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear possible user customized columns
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_USERCOLUMNS . "` WHERE `section` = 'sslcertificates_list'");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202303150');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.13')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.13 to 2.0.14", false);
|
||||||
|
Froxlor::updateToVersion('2.0.14');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.14')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.14 to 2.0.15", false);
|
||||||
|
Froxlor::updateToVersion('2.0.15');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202303150')) {
|
||||||
|
Update::showUpdateStep("Adding new request rate limit settings");
|
||||||
|
Settings::AddNew("system.req_limit_per_interval", "60");
|
||||||
|
Settings::AddNew("system.req_limit_interval", "60");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202304260');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.15')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.15 to 2.0.16", false);
|
||||||
|
Froxlor::updateToVersion('2.0.16');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.16')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.16 to 2.0.17", false);
|
||||||
|
Froxlor::updateToVersion('2.0.17');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.17')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.17 to 2.0.18", false);
|
||||||
|
Froxlor::updateToVersion('2.0.18');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.18')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.18 to 2.0.19", false);
|
||||||
|
Froxlor::updateToVersion('2.0.19');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.19')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.19 to 2.0.20", false);
|
||||||
|
Froxlor::updateToVersion('2.0.20');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.20')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.20 to 2.0.21", false);
|
||||||
|
Froxlor::updateToVersion('2.0.21');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.21')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.21 to 2.0.22", false);
|
||||||
|
Froxlor::updateToVersion('2.0.22');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.22')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.22 to 2.0.23", false);
|
||||||
|
Froxlor::updateToVersion('2.0.23');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.23')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.23 to 2.0.24", false);
|
||||||
|
Froxlor::updateToVersion('2.0.24');
|
||||||
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
|||||||
$config_dir = FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/lib/configfiles/');
|
$config_dir = FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/lib/configfiles/');
|
||||||
// show list of available distro's
|
// show list of available distro's
|
||||||
$distros = glob($config_dir . '*.xml');
|
$distros = glob($config_dir . '*.xml');
|
||||||
$distributions_select[''] = '-';
|
// selection is required $distributions_select[''] = '-';
|
||||||
// read in all the distros
|
// read in all the distros
|
||||||
foreach ($distros as $_distribution) {
|
foreach ($distros as $_distribution) {
|
||||||
// get configparser object
|
// get configparser object
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
namespace Froxlor\Api;
|
namespace Froxlor\Api;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Froxlor\Http\RateLimiter;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use voku\helper\AntiXSS;
|
use voku\helper\AntiXSS;
|
||||||
|
|
||||||
@@ -52,6 +53,8 @@ class Api
|
|||||||
if (Settings::Get('api.enabled') != 1) {
|
if (Settings::Get('api.enabled') != 1) {
|
||||||
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
|
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RateLimiter::run();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ abstract class ApiParameter
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param array $params
|
* @param array|null $params
|
||||||
* optional, array of parameters (var=>value) for the command
|
* optional, array of parameters (var=>value) for the command
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function __construct($params = null)
|
public function __construct(array $params = null)
|
||||||
{
|
{
|
||||||
if (!is_null($params)) {
|
if (!is_null($params)) {
|
||||||
$params = $this->trimArray($params);
|
$params = $this->trimArray($params);
|
||||||
@@ -57,7 +57,7 @@ abstract class ApiParameter
|
|||||||
*
|
*
|
||||||
* @param array $input
|
* @param array $input
|
||||||
*
|
*
|
||||||
* @return array
|
* @return string|array
|
||||||
*/
|
*/
|
||||||
private function trimArray($input)
|
private function trimArray($input)
|
||||||
{
|
{
|
||||||
@@ -79,9 +79,9 @@ abstract class ApiParameter
|
|||||||
/**
|
/**
|
||||||
* get specific parameter which also has and unlimited-field
|
* get specific parameter which also has and unlimited-field
|
||||||
*
|
*
|
||||||
* @param string $param
|
* @param string|null $param
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param string $ul_field
|
* @param string|null $ul_field
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param bool $optional
|
* @param bool $optional
|
||||||
* default: false
|
* default: false
|
||||||
@@ -91,7 +91,7 @@ abstract class ApiParameter
|
|||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function getUlParam($param = null, $ul_field = null, $optional = false, $default = 0)
|
protected function getUlParam(string $param = null, string $ul_field = null, bool $optional = false, $default = 0)
|
||||||
{
|
{
|
||||||
$param_value = (int)$this->getParam($param, $optional, $default);
|
$param_value = (int)$this->getParam($param, $optional, $default);
|
||||||
$ul_field_value = $this->getBoolParam($ul_field, true, 0);
|
$ul_field_value = $this->getBoolParam($ul_field, true, 0);
|
||||||
@@ -102,11 +102,11 @@ abstract class ApiParameter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get specific parameter from the parameterlist;
|
* get specific parameter from the parameter list;
|
||||||
* check for existence and != empty if needed.
|
* check for existence and != empty if needed.
|
||||||
* Maybe more in the future
|
* Maybe more in the future
|
||||||
*
|
*
|
||||||
* @param string $param
|
* @param string|null $param
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param bool $optional
|
* @param bool $optional
|
||||||
* default: false
|
* default: false
|
||||||
@@ -116,7 +116,7 @@ abstract class ApiParameter
|
|||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function getParam($param = null, $optional = false, $default = '')
|
protected function getParam(string $param = null, bool $optional = false, $default = '')
|
||||||
{
|
{
|
||||||
// does it exist?
|
// does it exist?
|
||||||
if (!isset($this->cmd_params[$param])) {
|
if (!isset($this->cmd_params[$param])) {
|
||||||
@@ -128,7 +128,7 @@ abstract class ApiParameter
|
|||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
// is it empty? - test really on string, as value 0 is being seen as empty by php
|
// is it empty? - test really on string, as value 0 is being seen as empty by php
|
||||||
if ($this->cmd_params[$param] === "") {
|
if (!is_array($this->cmd_params[$param]) && trim($this->cmd_params[$param]) === "") {
|
||||||
if ($optional === false) {
|
if ($optional === false) {
|
||||||
// get module + function for better error-messages
|
// get module + function for better error-messages
|
||||||
$inmod = $this->getModFunctionString();
|
$inmod = $this->getModFunctionString();
|
||||||
@@ -142,7 +142,7 @@ abstract class ApiParameter
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* returns "module::function()" for better error-messages (missing parameter etc.)
|
* returns "module::function()" for better error-messages (missing parameter etc.)
|
||||||
* makes debugging a whole lot more comfortable
|
* makes debugging a lot more comfortable
|
||||||
*
|
*
|
||||||
* @param int $level
|
* @param int $level
|
||||||
* depth of backtrace, default 2
|
* depth of backtrace, default 2
|
||||||
@@ -152,7 +152,7 @@ abstract class ApiParameter
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function getModFunctionString($level = 1, $max_level = 5, $trace = null)
|
private function getModFunctionString(int $level = 1, int $max_level = 5, $trace = null)
|
||||||
{
|
{
|
||||||
// which class called us
|
// which class called us
|
||||||
$_class = get_called_class();
|
$_class = get_called_class();
|
||||||
@@ -174,7 +174,7 @@ abstract class ApiParameter
|
|||||||
/**
|
/**
|
||||||
* getParam wrapper for boolean parameter
|
* getParam wrapper for boolean parameter
|
||||||
*
|
*
|
||||||
* @param string $param
|
* @param string|null $param
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param bool $optional
|
* @param bool $optional
|
||||||
* default: false
|
* default: false
|
||||||
@@ -183,7 +183,7 @@ abstract class ApiParameter
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function getBoolParam($param = null, $optional = false, $default = false)
|
protected function getBoolParam(string $param = null, bool $optional = false, $default = false)
|
||||||
{
|
{
|
||||||
$_default = '0';
|
$_default = '0';
|
||||||
if ($default) {
|
if ($default) {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list admins");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list admins");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT *
|
SELECT *
|
||||||
@@ -407,7 +407,7 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get admin '" . $result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get admin '" . $result['loginname'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
||||||
@@ -584,6 +584,18 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
$theme = Settings::Get('panel.default_theme');
|
$theme = Settings::Get('panel.default_theme');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (empty(trim($name))) {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'admin.name'
|
||||||
|
], '', true);
|
||||||
|
}
|
||||||
|
if (empty(trim($email))) {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'admin.email'
|
||||||
|
], '', true);
|
||||||
|
}
|
||||||
if (!Validate::validateEmail($email)) {
|
if (!Validate::validateEmail($email)) {
|
||||||
Response::standardError('emailiswrong', $email, true);
|
Response::standardError('emailiswrong', $email, true);
|
||||||
} else {
|
} else {
|
||||||
@@ -705,7 +717,7 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
WHERE `adminid` = :adminid
|
WHERE `adminid` = :adminid
|
||||||
");
|
");
|
||||||
Database::pexecute($upd_stmt, $upd_data, true, true);
|
Database::pexecute($upd_stmt, $upd_data, true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] edited admin '" . $result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] edited admin '" . $result['loginname'] . "'");
|
||||||
|
|
||||||
// get all admin-data for return-array
|
// get all admin-data for return-array
|
||||||
$result = $this->apiCall('Admins.get', [
|
$result = $this->apiCall('Admins.get', [
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
if (!$has_cert) {
|
if (!$has_cert) {
|
||||||
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, true);
|
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ssl-certificate for '" . $domain['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ssl-certificate for '" . $domain['domain'] . "'");
|
||||||
$result = $this->apiCall('Certificates.get', [
|
$result = $this->apiCall('Certificates.get', [
|
||||||
'id' => $domain['id']
|
'id' => $domain['id']
|
||||||
]);
|
]);
|
||||||
@@ -127,7 +127,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
$do_verify = true;
|
$do_verify = true;
|
||||||
$expirationdate = null;
|
$validtodate = null;
|
||||||
|
$validtodate = null;
|
||||||
|
$issuer = "";
|
||||||
// no cert-file given -> forget everything
|
// no cert-file given -> forget everything
|
||||||
if ($ssl_cert_file == '') {
|
if ($ssl_cert_file == '') {
|
||||||
$ssl_key_file = '';
|
$ssl_key_file = '';
|
||||||
@@ -168,7 +170,10 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
} else {
|
} else {
|
||||||
Response::standardError('sslcertificateinvalidcert', '', true);
|
Response::standardError('sslcertificateinvalidcert', '', true);
|
||||||
}
|
}
|
||||||
$expirationdate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']);
|
// get data from certificate to store in the table
|
||||||
|
$validfromdate = empty($cert_content['validFrom_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validFrom_time_t']);
|
||||||
|
$validtodate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']);
|
||||||
|
$issuer = $cert_content['issuer']['O'] ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add/Update database entry
|
// Add/Update database entry
|
||||||
@@ -183,7 +188,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
`ssl_key_file` = :ssl_key_file,
|
`ssl_key_file` = :ssl_key_file,
|
||||||
`ssl_ca_file` = :ssl_ca_file,
|
`ssl_ca_file` = :ssl_ca_file,
|
||||||
`ssl_cert_chainfile` = :ssl_cert_chainfile,
|
`ssl_cert_chainfile` = :ssl_cert_chainfile,
|
||||||
`expirationdate` = :expirationdate
|
`validfromdate` = :validfromdate,
|
||||||
|
`validtodate` = :validtodate,
|
||||||
|
`issuer` = :issuer
|
||||||
" . $qrywhere . " `domainid`= :domainid
|
" . $qrywhere . " `domainid`= :domainid
|
||||||
");
|
");
|
||||||
$params = [
|
$params = [
|
||||||
@@ -191,7 +198,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
"ssl_key_file" => $ssl_key_file,
|
"ssl_key_file" => $ssl_key_file,
|
||||||
"ssl_ca_file" => $ssl_ca_file,
|
"ssl_ca_file" => $ssl_ca_file,
|
||||||
"ssl_cert_chainfile" => $ssl_cert_chainfile,
|
"ssl_cert_chainfile" => $ssl_cert_chainfile,
|
||||||
"expirationdate" => $expirationdate,
|
"validfromdate" => $validfromdate,
|
||||||
|
"validtodate" => $validtodate,
|
||||||
|
"issuer" => $issuer,
|
||||||
"domainid" => $domainid
|
"domainid" => $domainid
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
@@ -239,7 +248,7 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
$ssl_ca_file = $this->getParam('ssl_ca_file', true, '');
|
$ssl_ca_file = $this->getParam('ssl_ca_file', true, '');
|
||||||
$ssl_cert_chainfile = $this->getParam('ssl_cert_chainfile', true, '');
|
$ssl_cert_chainfile = $this->getParam('ssl_cert_chainfile', true, '');
|
||||||
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, false);
|
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, false);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ssl-certificate for '" . $domain['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ssl-certificate for '" . $domain['domain'] . "'");
|
||||||
$result = $this->apiCall('Certificates.get', [
|
$result = $this->apiCall('Certificates.get', [
|
||||||
'id' => $domain['id']
|
'id' => $domain['id']
|
||||||
]);
|
]);
|
||||||
@@ -299,27 +308,23 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set data from certificate
|
// Set data from certificate
|
||||||
|
$cert['isvalid'] = false;
|
||||||
|
$cert['san'] = null;
|
||||||
$cert_data = openssl_x509_parse($cert['ssl_cert_file']);
|
$cert_data = openssl_x509_parse($cert['ssl_cert_file']);
|
||||||
if ($cert_data) {
|
if ($cert_data) {
|
||||||
$cert['validfromdate'] = date('Y-m-d H:i:s', $cert_data['validFrom_time_t']);
|
|
||||||
$cert['validtodate'] = date('Y-m-d H:i:s', $cert_data['validTo_time_t']);
|
|
||||||
$cert['isvalid'] = (bool)$cert_data['validTo_time_t'] > time();
|
$cert['isvalid'] = (bool)$cert_data['validTo_time_t'] > time();
|
||||||
$cert['issuer'] = $cert_data['issuer']['O'] ?? null;
|
// Set subject alt names from certificate
|
||||||
}
|
if (isset($cert_data['extensions']['subjectAltName']) && !empty($cert_data['extensions']['subjectAltName'])) {
|
||||||
|
$SANs = explode(",", $cert_data['extensions']['subjectAltName']);
|
||||||
// Set subject alt names from certificate
|
$SANs = array_map('trim', $SANs);
|
||||||
$cert['san'] = null;
|
foreach ($SANs as $san) {
|
||||||
if (isset($cert_data['extensions']['subjectAltName']) && !empty($cert_data['extensions']['subjectAltName'])) {
|
$san = str_replace("DNS:", "", $san);
|
||||||
$SANs = explode(",", $cert_data['extensions']['subjectAltName']);
|
if ($san != $cert_data['subject']['CN'] && strpos($san, "othername:") === false) {
|
||||||
$SANs = array_map('trim', $SANs);
|
$cert['san'][] = $san;
|
||||||
foreach ($SANs as $san) {
|
}
|
||||||
$san = str_replace("DNS:", "", $san);
|
|
||||||
if ($san != $cert_data['subject']['CN'] && strpos($san, "othername:") === false) {
|
|
||||||
$cert['san'][] = $san;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[] = $cert;
|
$result[] = $cert;
|
||||||
}
|
}
|
||||||
return $this->response([
|
return $this->response([
|
||||||
@@ -465,7 +470,7 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
if ($chk['letsencrypt'] == '1') {
|
if ($chk['letsencrypt'] == '1') {
|
||||||
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $chk['domain']);
|
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $chk['domain']);
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] removed ssl-certificate for '" . $chk['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] removed ssl-certificate for '" . $chk['domain'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("Unable to determine SSL certificate. Maybe no access?", 406);
|
throw new Exception("Unable to determine SSL certificate. Maybe no access?", 406);
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// insert task to re-generate the cron.d-file
|
// insert task to re-generate the cron.d-file
|
||||||
Cronjob::inserttask(TaskId::REBUILD_CRON);
|
Cronjob::inserttask(TaskId::REBUILD_CRON);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
||||||
$result = $this->apiCall('Cronjobs.get', [
|
$result = $this->apiCall('Cronjobs.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -177,7 +177,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list cronjobs");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list cronjobs");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
$result[] = $entry;
|
$result[] = $entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list customer-backups");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list customer-backups");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
|
|||||||
@@ -895,7 +895,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
$result['dbspace_used'] = 0;
|
$result['dbspace_used'] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get customer '" . $result['loginname'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get customer '" . $result['loginname'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
||||||
@@ -1327,7 +1327,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
'vu' => $valid_until
|
'vu' => $valid_until
|
||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1538,7 +1538,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
Database::query($admin_update_query);
|
Database::query($admin_update_query);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited user '" . $result['loginname'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited user '" . $result['loginname'] . "'");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* move customer to another admin/reseller; #1166
|
* move customer to another admin/reseller; #1166
|
||||||
@@ -1911,7 +1911,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
// now, recalculate the resource-usage for the old and the new admin
|
// now, recalculate the resource-usage for the old and the new admin
|
||||||
User::updateCounters(false);
|
User::updateCounters(false);
|
||||||
|
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] moved user '" . $c_result['loginname'] . "' from admin/reseller '" . $c_result['adminname'] . " to admin/reseller '" . $a_result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] moved user '" . $c_result['loginname'] . "' from admin/reseller '" . $c_result['adminname'] . " to admin/reseller '" . $a_result['loginname'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Customers.get', [
|
$result = $this->apiCall('Customers.get', [
|
||||||
'id' => $c_result['customerid']
|
'id' => $c_result['customerid']
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$id = Database::lastInsertId();
|
$id = Database::lastInsertId();
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-option for '" . $userpath . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added directory-option for '" . $userpath . "'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
|
||||||
$result = $this->apiCall('DirOptions.get', [
|
$result = $this->apiCall('DirOptions.get', [
|
||||||
@@ -247,7 +247,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
$params['id'] = $id;
|
$params['id'] = $id;
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory options for '" . $result['path'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get directory options for '" . $result['path'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = "id #" . $id;
|
$key = "id #" . $id;
|
||||||
@@ -331,7 +331,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id
|
"id" => $id
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited directory options for '" . str_replace($customer['documentroot'], '/', $result['path']) . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited directory options for '" . str_replace($customer['documentroot'], '/', $result['path']) . "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->apiCall('DirOptions.get', [
|
$result = $this->apiCall('DirOptions.get', [
|
||||||
@@ -379,7 +379,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-options");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list directory-options");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -478,7 +478,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
"customerid" => $customer_data['customerid'],
|
"customerid" => $customer_data['customerid'],
|
||||||
"id" => $id
|
"id" => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$id = Database::lastInsertId();
|
$id = Database::lastInsertId();
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-protection for '" . $username . " (" . $path . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added directory-protection for '" . $username . " (" . $path . ")'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
|
||||||
$result = $this->apiCall('DirProtections.get', [
|
$result = $this->apiCall('DirProtections.get', [
|
||||||
@@ -196,7 +196,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
$params['idun'] = ($id <= 0 ? $username : $id);
|
$params['idun'] = ($id <= 0 ? $username : $id);
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory protection for '" . $result['path'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get directory protection for '" . $result['path'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
||||||
@@ -279,7 +279,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'");
|
||||||
$result = $this->apiCall('DirProtections.get', [
|
$result = $this->apiCall('DirProtections.get', [
|
||||||
'id' => $result['id']
|
'id' => $result['id']
|
||||||
]);
|
]);
|
||||||
@@ -325,7 +325,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-protections");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list directory-protections");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -413,7 +413,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id
|
"id" => $id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -413,7 +413,7 @@ class DomainZones extends ApiCommand implements ResourceEntity
|
|||||||
$zone = Dns::createDomainZone($id);
|
$zone = Dns::createDomainZone($id);
|
||||||
$zonefile = (string)$zone;
|
$zonefile = (string)$zone;
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get dns-zone for '" . $result['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get dns-zone for '" . $result['domain'] . "'");
|
||||||
return $this->response(explode("\n", $zonefile));
|
return $this->response(explode("\n", $zonefile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -225,6 +225,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, whether php is enabled for this domain, default 0 (false)
|
* optional, whether php is enabled for this domain, default 0 (false)
|
||||||
* @param bool $openbasedir
|
* @param bool $openbasedir
|
||||||
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
||||||
|
* @param int $openbasedir_path
|
||||||
|
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
||||||
* @param int $mod_fcgid_starter
|
* @param int $mod_fcgid_starter
|
||||||
@@ -312,6 +314,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$documentroot = $this->getParam('documentroot', true, '');
|
$documentroot = $this->getParam('documentroot', true, '');
|
||||||
$phpenabled = $this->getBoolParam('phpenabled', true, 0);
|
$phpenabled = $this->getBoolParam('phpenabled', true, 0);
|
||||||
$openbasedir = $this->getBoolParam('openbasedir', true, 0);
|
$openbasedir = $this->getBoolParam('openbasedir', true, 0);
|
||||||
|
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, 1);
|
$phpsettingid = $this->getParam('phpsettingid', true, 1);
|
||||||
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, -1);
|
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, -1);
|
||||||
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
|
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
|
||||||
@@ -530,6 +533,10 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$mod_fcgid_maxrequests = '-1';
|
$mod_fcgid_maxrequests = '-1';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
|
||||||
|
$openbasedir_path = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check non-ssl IP
|
// check non-ssl IP
|
||||||
$ipandports = $this->validateIpAddresses($p_ipandports);
|
$ipandports = $this->validateIpAddresses($p_ipandports);
|
||||||
// check ssl IP
|
// check ssl IP
|
||||||
@@ -701,6 +708,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
'caneditdomain' => $caneditdomain,
|
'caneditdomain' => $caneditdomain,
|
||||||
'phpenabled' => $phpenabled,
|
'phpenabled' => $phpenabled,
|
||||||
'openbasedir' => $openbasedir,
|
'openbasedir' => $openbasedir,
|
||||||
|
'openbasedir_path' => $openbasedir_path,
|
||||||
'speciallogfile' => $speciallogfile,
|
'speciallogfile' => $speciallogfile,
|
||||||
'specialsettings' => $specialsettings,
|
'specialsettings' => $specialsettings,
|
||||||
'ssl_specialsettings' => $ssl_specialsettings,
|
'ssl_specialsettings' => $ssl_specialsettings,
|
||||||
@@ -754,6 +762,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`caneditdomain` = :caneditdomain,
|
`caneditdomain` = :caneditdomain,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`speciallogfile` = :speciallogfile,
|
`speciallogfile` = :speciallogfile,
|
||||||
`specialsettings` = :specialsettings,
|
`specialsettings` = :specialsettings,
|
||||||
`ssl_specialsettings` = :ssl_specialsettings,
|
`ssl_specialsettings` = :ssl_specialsettings,
|
||||||
@@ -889,7 +898,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
||||||
}
|
}
|
||||||
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get domain '" . $result['domain'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get domain '" . $result['domain'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
||||||
@@ -1101,6 +1110,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* from setting system.apply_phpconfigs_default
|
* from setting system.apply_phpconfigs_default
|
||||||
* @param bool $openbasedir
|
* @param bool $openbasedir
|
||||||
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
||||||
|
* @param int $openbasedir_path
|
||||||
|
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
||||||
* @param int $mod_fcgid_starter
|
* @param int $mod_fcgid_starter
|
||||||
@@ -1198,6 +1209,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$phpenabled = $this->getBoolParam('phpenabled', true, $result['phpenabled']);
|
$phpenabled = $this->getBoolParam('phpenabled', true, $result['phpenabled']);
|
||||||
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, Settings::Get('system.apply_phpconfigs_default'));
|
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, Settings::Get('system.apply_phpconfigs_default'));
|
||||||
$openbasedir = $this->getBoolParam('openbasedir', true, $result['openbasedir']);
|
$openbasedir = $this->getBoolParam('openbasedir', true, $result['openbasedir']);
|
||||||
|
$openbasedir_path = $this->getParam('openbasedir_path', true, $result['openbasedir_path']);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
||||||
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, $result['mod_fcgid_starter']);
|
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, $result['mod_fcgid_starter']);
|
||||||
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, $result['mod_fcgid_maxrequests']);
|
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, $result['mod_fcgid_maxrequests']);
|
||||||
@@ -1489,6 +1501,11 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$mod_fcgid_maxrequests = $result['mod_fcgid_maxrequests'];
|
$mod_fcgid_maxrequests = $result['mod_fcgid_maxrequests'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check changes of openbasedir-path variable
|
||||||
|
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
|
||||||
|
$openbasedir_path = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check non-ssl IP
|
// check non-ssl IP
|
||||||
$ipandports = $this->validateIpAddresses($p_ipandports, false, $result['id']);
|
$ipandports = $this->validateIpAddresses($p_ipandports, false, $result['id']);
|
||||||
// check ssl IP
|
// check ssl IP
|
||||||
@@ -1634,7 +1651,31 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
||||||
$iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0';
|
$iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0';
|
||||||
|
|
||||||
if ($documentroot != $result['documentroot'] || $ssl_redirect != $result['ssl_redirect'] || $wwwserveralias != $result['wwwserveralias'] || $iswildcarddomain != $result['iswildcarddomain'] || $phpenabled != $result['phpenabled'] || $openbasedir != $result['openbasedir'] || $phpsettingid != $result['phpsettingid'] || $mod_fcgid_starter != $result['mod_fcgid_starter'] || $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests'] || $specialsettings != $result['specialsettings'] || $ssl_specialsettings != $result['ssl_specialsettings'] || $notryfiles != $result['notryfiles'] || $writeaccesslog != $result['writeaccesslog'] || $writeerrorlog != $result['writeerrorlog'] || $aliasdomain != $result['aliasdomain'] || $issubof != $result['ismainbutsubto'] || $email_only != $result['email_only'] || ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1') || $letsencrypt != $result['letsencrypt'] || $http2 != $result['http2'] || $hsts_maxage != $result['hsts'] || $hsts_sub != $result['hsts_sub'] || $hsts_preload != $result['hsts_preload'] || $ocsp_stapling != $result['ocsp_stapling']) {
|
if ($documentroot != $result['documentroot']
|
||||||
|
|| $ssl_redirect != $result['ssl_redirect']
|
||||||
|
|| $wwwserveralias != $result['wwwserveralias']
|
||||||
|
|| $iswildcarddomain != $result['iswildcarddomain']
|
||||||
|
|| $phpenabled != $result['phpenabled']
|
||||||
|
|| $openbasedir != $result['openbasedir']
|
||||||
|
|| $phpsettingid != $result['phpsettingid']
|
||||||
|
|| $mod_fcgid_starter != $result['mod_fcgid_starter']
|
||||||
|
|| $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests']
|
||||||
|
|| $specialsettings != $result['specialsettings']
|
||||||
|
|| $ssl_specialsettings != $result['ssl_specialsettings']
|
||||||
|
|| $notryfiles != $result['notryfiles']
|
||||||
|
|| $writeaccesslog != $result['writeaccesslog']
|
||||||
|
|| $writeerrorlog != $result['writeerrorlog']
|
||||||
|
|| $aliasdomain != $result['aliasdomain']
|
||||||
|
|| $issubof != $result['ismainbutsubto']
|
||||||
|
|| $email_only != $result['email_only']
|
||||||
|
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|
||||||
|
|| $letsencrypt != $result['letsencrypt']
|
||||||
|
|| $http2 != $result['http2']
|
||||||
|
|| $hsts_maxage != $result['hsts']
|
||||||
|
|| $hsts_sub != $result['hsts_sub']
|
||||||
|
|| $hsts_preload != $result['hsts_preload']
|
||||||
|
|| $ocsp_stapling != $result['ocsp_stapling']
|
||||||
|
) {
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1760,7 +1801,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
Database::pexecute($upd_stmt, [
|
Database::pexecute($upd_stmt, [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] removed specialsettings on all subdomains of domain #" . $id);
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] removed specialsettings on all subdomains of domain #" . $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
||||||
@@ -1782,7 +1823,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$update_data['wwwserveralias'] = $wwwserveralias;
|
$update_data['wwwserveralias'] = $wwwserveralias;
|
||||||
$update_data['iswildcarddomain'] = $iswildcarddomain;
|
$update_data['iswildcarddomain'] = $iswildcarddomain;
|
||||||
$update_data['phpenabled'] = $phpenabled;
|
$update_data['phpenabled'] = $phpenabled;
|
||||||
$update_data['openbasedir'] = $openbasedir;
|
$update_data['openbasedir'] = $openbasedir;;
|
||||||
|
$update_data['openbasedir_path'] = $openbasedir_path;
|
||||||
$update_data['speciallogfile'] = $speciallogfile;
|
$update_data['speciallogfile'] = $speciallogfile;
|
||||||
$update_data['phpsettingid'] = $phpsettingid;
|
$update_data['phpsettingid'] = $phpsettingid;
|
||||||
$update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
$update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
||||||
@@ -1830,6 +1872,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`iswildcarddomain` = :iswildcarddomain,
|
`iswildcarddomain` = :iswildcarddomain,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`speciallogfile` = :speciallogfile,
|
`speciallogfile` = :speciallogfile,
|
||||||
`phpsettingid` = :phpsettingid,
|
`phpsettingid` = :phpsettingid,
|
||||||
`mod_fcgid_starter` = :mod_fcgid_starter,
|
`mod_fcgid_starter` = :mod_fcgid_starter,
|
||||||
@@ -1865,6 +1908,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$_update_data['adminid'] = $adminid;
|
$_update_data['adminid'] = $adminid;
|
||||||
$_update_data['phpenabled'] = $phpenabled;
|
$_update_data['phpenabled'] = $phpenabled;
|
||||||
$_update_data['openbasedir'] = $openbasedir;
|
$_update_data['openbasedir'] = $openbasedir;
|
||||||
|
$_update_data['openbasedir_path'] = $openbasedir_path;
|
||||||
$_update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
$_update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
||||||
$_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests;
|
$_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests;
|
||||||
$_update_data['notryfiles'] = $notryfiles;
|
$_update_data['notryfiles'] = $notryfiles;
|
||||||
@@ -1898,6 +1942,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`adminid` = :adminid,
|
`adminid` = :adminid,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`mod_fcgid_starter` = :mod_fcgid_starter,
|
`mod_fcgid_starter` = :mod_fcgid_starter,
|
||||||
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
||||||
`notryfiles` = :notryfiles,
|
`notryfiles` = :notryfiles,
|
||||||
@@ -1914,6 +1959,18 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
");
|
");
|
||||||
Database::pexecute($_update_stmt, $_update_data, true, true);
|
Database::pexecute($_update_stmt, $_update_data, true, true);
|
||||||
|
|
||||||
|
// get current ip<>domain entries
|
||||||
|
$ip_sel_stmt = Database::prepare("
|
||||||
|
SELECT id_ipandports FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
||||||
|
");
|
||||||
|
Database::pexecute($ip_sel_stmt, [
|
||||||
|
'id' => $id
|
||||||
|
], true, true);
|
||||||
|
$current_ips = [];
|
||||||
|
while ($cIP = $ip_sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$current_ips[] = $cIP['id_ipandports'];
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup domain <-> ip mapping
|
// Cleanup domain <-> ip mapping
|
||||||
$del_stmt = Database::prepare("
|
$del_stmt = Database::prepare("
|
||||||
DELETE FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
DELETE FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
||||||
@@ -1941,6 +1998,12 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check ip changes
|
||||||
|
$all_new_ips = array_merge($ipandports, $ssl_ipandports);
|
||||||
|
if (count(array_diff($current_ips, $all_new_ips)) != 0 || count(array_diff($all_new_ips, $current_ips)) != 0) {
|
||||||
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup domain <-> ip mapping for subdomains
|
// Cleanup domain <-> ip mapping for subdomains
|
||||||
$domainidsresult_stmt = Database::prepare("
|
$domainidsresult_stmt = Database::prepare("
|
||||||
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `parentdomainid` = :id
|
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `parentdomainid` = :id
|
||||||
@@ -2158,7 +2221,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
// remove domain from acme.sh / lets encrypt if used
|
// remove domain from acme.sh / lets encrypt if used
|
||||||
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $result['domain']);
|
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $result['domain']);
|
||||||
|
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] deleted domain/subdomains (#" . $result['id'] . ")");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted domain/subdomains (#" . $result['id'] . ")");
|
||||||
User::updateCounters();
|
User::updateCounters();
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
// Using nameserver, insert a task which rebuilds the server config
|
// Using nameserver, insert a task which rebuilds the server config
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
* @param string $alternative_email
|
* @param string $alternative_email
|
||||||
* optional email address to send account information to, default is the account that is being created
|
* optional email address to send account information to, default is the account that is being created
|
||||||
* @param int $email_quota
|
* @param int $email_quota
|
||||||
* optional quota if enabled in MB, default 0
|
* optional quota if enabled in MB, default setting: system.mail_quota
|
||||||
* @param bool $sendinfomail
|
* @param bool $sendinfomail
|
||||||
* optional, sends the welcome message to the new account (needed for creation, without the user won't
|
* optional, sends the welcome message to the new account (needed for creation, without the user won't
|
||||||
* be able to login before any mail is received), default 1 (true)
|
* be able to login before any mail is received), default 1 (true)
|
||||||
@@ -85,7 +85,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
||||||
$email_password = $this->getParam('email_password');
|
$email_password = $this->getParam('email_password');
|
||||||
$alternative_email = $this->getParam('alternative_email', true, '');
|
$alternative_email = $this->getParam('alternative_email', true, '');
|
||||||
$quota = $this->getParam('email_quota', true, 0);
|
$quota = $this->getParam('email_quota', true, Settings::Get('system.mail_quota') ?? 0);
|
||||||
$sendinfomail = $this->getBoolParam('sendinfomail', true, 1);
|
$sendinfomail = $this->getBoolParam('sendinfomail', true, 1);
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
@@ -99,6 +99,11 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
Response::standardError('notallowedtouseaccounts', '', true);
|
Response::standardError('notallowedtouseaccounts', '', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($emailaddr)) {
|
||||||
|
$idna_convert = new IdnaWrapper();
|
||||||
|
$emailaddr = $idna_convert->encode($emailaddr);
|
||||||
|
}
|
||||||
|
|
||||||
// get email address
|
// get email address
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
@@ -306,7 +311,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email account for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email account for '" . $result['email_full'] . "'");
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
]);
|
]);
|
||||||
@@ -357,6 +362,11 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
$ea_optional = $id > 0;
|
$ea_optional = $id > 0;
|
||||||
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
||||||
|
|
||||||
|
if (!empty($emailaddr)) {
|
||||||
|
$idna_convert = new IdnaWrapper();
|
||||||
|
$emailaddr = $idna_convert->encode($emailaddr);
|
||||||
|
}
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
@@ -450,7 +460,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
Admins::increaseUsage($customer['adminid'], 'email_quota_used', '', ($quota - $result['quota']));
|
Admins::increaseUsage($customer['adminid'], 'email_quota_used', '', ($quota - $result['quota']));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated email account '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated email account '" . $result['email_full'] . "'");
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
]);
|
]);
|
||||||
@@ -556,7 +566,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
Customers::decreaseUsage($customer['customerid'], 'email_accounts_used');
|
Customers::decreaseUsage($customer['customerid'], 'email_accounts_used');
|
||||||
Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $quota);
|
Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $quota);
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email account for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted email account for '" . $result['email_full'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class EmailDomains extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE,
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO,
|
||||||
"[API] list email-domains");
|
"[API] list email-domains");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
|
|||||||
@@ -77,6 +77,11 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
|
|||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
$destination = $idna_convert->encode($destination);
|
$destination = $idna_convert->encode($destination);
|
||||||
|
|
||||||
|
if (!empty($emailaddr)) {
|
||||||
|
$idna_convert = new IdnaWrapper();
|
||||||
|
$emailaddr = $idna_convert->encode($emailaddr);
|
||||||
|
}
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'emailaddr' => $emailaddr
|
'emailaddr' => $emailaddr
|
||||||
@@ -116,7 +121,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
|
|||||||
// update customer usage
|
// update customer usage
|
||||||
Customers::increaseUsage($customer['customerid'], 'email_forwarders_used');
|
Customers::increaseUsage($customer['customerid'], 'email_forwarders_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email forwarder for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email forwarder for '" . $result['email_full'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
@@ -293,7 +298,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
|
|||||||
// update customer usage
|
// update customer usage
|
||||||
Customers::decreaseUsage($customer['customerid'], 'email_forwarders_used');
|
Customers::decreaseUsage($customer['customerid'], 'email_forwarders_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email forwarder for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted email forwarder for '" . $result['email_full'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
$iscatchall = $this->getBoolParam('iscatchall', true, 0);
|
$iscatchall = $this->getBoolParam('iscatchall', true, 0);
|
||||||
|
$disablegreylist = $this->getBoolParam('disablegreylist', true, 0);
|
||||||
$description = $this->getParam('description', true, '');
|
$description = $this->getParam('description', true, '');
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
@@ -118,7 +119,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// duplicate check
|
// duplicate check
|
||||||
$stmt = Database::prepare("
|
$stmt = Database::prepare("
|
||||||
SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid` FROM `" . TABLE_MAIL_VIRTUAL . "`
|
SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid`, `disablegreylist` FROM `" . TABLE_MAIL_VIRTUAL . "`
|
||||||
WHERE (`email` = :email OR `email_full` = :emailfull )
|
WHERE (`email` = :email OR `email_full` = :emailfull )
|
||||||
AND `customerid`= :cid
|
AND `customerid`= :cid
|
||||||
");
|
");
|
||||||
@@ -144,7 +145,8 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
`email_full` = :email_full,
|
`email_full` = :email_full,
|
||||||
`iscatchall` = :iscatchall,
|
`iscatchall` = :iscatchall,
|
||||||
`domainid` = :domainid,
|
`domainid` = :domainid,
|
||||||
`description` = :description
|
`description` = :description,
|
||||||
|
`disablegreylist` = :disablegreylist
|
||||||
");
|
");
|
||||||
$params = [
|
$params = [
|
||||||
"cid" => $customer['customerid'],
|
"cid" => $customer['customerid'],
|
||||||
@@ -152,14 +154,15 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
"email_full" => $email_full,
|
"email_full" => $email_full,
|
||||||
"iscatchall" => $iscatchall,
|
"iscatchall" => $iscatchall,
|
||||||
"domainid" => $domain_check['id'],
|
"domainid" => $domain_check['id'],
|
||||||
"description" => $description
|
"description" => $description,
|
||||||
|
"disablegreylist" => $disablegreylist
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
|
|
||||||
// update customer usage
|
// update customer usage
|
||||||
Customers::increaseUsage($customer['customerid'], 'emails_used');
|
Customers::increaseUsage($customer['customerid'], 'emails_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email address '" . $email_full . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email address '" . $email_full . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $email_full
|
'emailaddr' => $email_full
|
||||||
@@ -191,15 +194,15 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
$customer_ids = $this->getAllowedCustomerIds('email');
|
$customer_ids = $this->getAllowedCustomerIds('email');
|
||||||
$params['idea'] = ($id <= 0 ? $emailaddr : $id);
|
$params['idea'] = ($id <= 0 ? $emailaddr : $id);
|
||||||
|
|
||||||
$result_stmt = Database::prepare("SELECT v.`id`, v.`email`, v.`email_full`, v.`iscatchall`, v.`destination`, v.`customerid`, v.`popaccountid`, v.`domainid`, v.`description`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
|
$result_stmt = Database::prepare("SELECT v.`id`, v.`email`, v.`email_full`, v.`iscatchall`, v.`disablegreylist`, v.`destination`, v.`customerid`, v.`popaccountid`, v.`domainid`, v.`description`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
|
||||||
FROM `" . TABLE_MAIL_VIRTUAL . "` v
|
FROM `" . TABLE_MAIL_VIRTUAL . "` v
|
||||||
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
|
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
|
||||||
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
|
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
|
||||||
AND (v.`id`= :idea OR (v.`email` = :idea OR v.`email_full` = :idea))
|
AND " . (is_numeric($params['idea']) ? "v.`id`= :idea" : "(v.`email` = :idea OR v.`email_full` = :idea)")
|
||||||
");
|
);
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get email address '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get email address '" . $result['email_full'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'");
|
$key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'");
|
||||||
@@ -294,7 +297,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id
|
"id" => $id
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
@@ -302,6 +305,81 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toggle greylist flag of given email address either by id or email-address
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* optional, the email-address-id
|
||||||
|
* @param string $emailaddr
|
||||||
|
* optional, the email-address
|
||||||
|
* @param int $customerid
|
||||||
|
* optional, required when called as admin (if $loginname is not specified)
|
||||||
|
* @param string $loginname
|
||||||
|
* optional, required when called as admin (if $customerid is not specified)
|
||||||
|
* @param boolean $greylist
|
||||||
|
* optional
|
||||||
|
* @param string $description
|
||||||
|
* optional custom description (currently not used/shown in the frontend), default empty
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function updateGreylist()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
|
||||||
|
throw new Exception("You cannot access this resource", 405);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if enabling catchall is not allowed by settings, we do not need
|
||||||
|
// to run update()
|
||||||
|
/** if (Settings::Get('catchall.catchall_enabled') != '1') {
|
||||||
|
Response::standardError([
|
||||||
|
'operationnotpermitted',
|
||||||
|
'featureisdisabled'
|
||||||
|
], 'catchall', true);
|
||||||
|
} */
|
||||||
|
|
||||||
|
$id = $this->getParam('id', true, 0);
|
||||||
|
$ea_optional = $id > 0;
|
||||||
|
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
||||||
|
|
||||||
|
$result = $this->apiCall('Emails.get', [
|
||||||
|
'id' => $id,
|
||||||
|
'emailaddr' => $emailaddr
|
||||||
|
]);
|
||||||
|
$id = $result['id'];
|
||||||
|
$email = $result['email'];
|
||||||
|
|
||||||
|
|
||||||
|
// parameters
|
||||||
|
$disablegreylist = $this->getBoolParam('disablegreylist', true, $result['disablegreylist']);
|
||||||
|
$description = $this->getParam('description', true, $result['description']);
|
||||||
|
|
||||||
|
// get needed customer info to reduce the email-address-counter by one
|
||||||
|
$customer = $this->getCustomerData();
|
||||||
|
|
||||||
|
// check for catchall-flag
|
||||||
|
$stmt = Database::prepare("
|
||||||
|
UPDATE `" . TABLE_MAIL_VIRTUAL . "`
|
||||||
|
SET `email` = :email , `disablegreylist` = :grflag, `description` = :description
|
||||||
|
WHERE `customerid`= :cid AND `id`= :id
|
||||||
|
");
|
||||||
|
$params = [
|
||||||
|
"email" => $email,
|
||||||
|
"grflag" => $disablegreylist,
|
||||||
|
"description" => $description,
|
||||||
|
"cid" => $customer['customerid'],
|
||||||
|
"id" => $id
|
||||||
|
];
|
||||||
|
Database::pexecute($stmt, $params, true, true);
|
||||||
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] toggled greylist-flag for email address '" . $result['email_full'] . "'");
|
||||||
|
|
||||||
|
$result = $this->apiCall('Emails.get', [
|
||||||
|
'emailaddr' => $result['email_full']
|
||||||
|
]);
|
||||||
|
return $this->response($result);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* list all email addresses, if called from an admin, list all email addresses of all customers you are allowed to
|
* list all email addresses, if called from an admin, list all email addresses of all customers you are allowed to
|
||||||
* view, or specify id or loginname for one specific customer
|
* view, or specify id or loginname for one specific customer
|
||||||
@@ -331,7 +409,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
$result = [];
|
$result = [];
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT m.`id`, m.`domainid`, m.`email`, m.`email_full`, m.`iscatchall`, m.`destination`, m.`popaccountid`, d.`domain`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
|
SELECT m.`id`, m.`domainid`, m.`email`, m.`email_full`, m.`iscatchall`, m.`disablegreylist`, m.`destination`, m.`popaccountid`, d.`domain`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
|
||||||
FROM `" . TABLE_MAIL_VIRTUAL . "` m
|
FROM `" . TABLE_MAIL_VIRTUAL . "` m
|
||||||
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`)
|
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`)
|
||||||
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`)
|
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`)
|
||||||
@@ -340,7 +418,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list email-addresses");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list email-addresses");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -445,7 +523,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
], true, true);
|
], true, true);
|
||||||
Customers::decreaseUsage($customer['customerid'], 'emails_used');
|
Customers::decreaseUsage($customer['customerid'], 'emails_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email address '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted email address '" . $result['email_full'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list fpm-daemons");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list fpm-daemons");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "`" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "`" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
||||||
@@ -258,7 +258,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
$id = Database::lastInsertId();
|
$id = Database::lastInsertId();
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
||||||
$result = $this->apiCall('FpmDaemons.get', [
|
$result = $this->apiCall('FpmDaemons.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -384,7 +384,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
Database::pexecute($upd_stmt, $upd_data, true, true);
|
Database::pexecute($upd_stmt, $upd_data, true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
||||||
$result = $this->apiCall('FpmDaemons.get', [
|
$result = $this->apiCall('FpmDaemons.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -433,7 +433,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class Froxlor extends ApiCommand
|
|||||||
|
|
||||||
if (empty($uc_data) || empty($response) || $uc_data['ts'] + self::UPDATE_CHECK_INTERVAL < time() || $uc_data['channel'] != Settings::Get('system.update_channel') || $force_ucheck) {
|
if (empty($uc_data) || empty($response) || $uc_data['ts'] + self::UPDATE_CHECK_INTERVAL < time() || $uc_data['channel'] != Settings::Get('system.update_channel') || $force_ucheck) {
|
||||||
// log our actions
|
// log our actions
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] checking for updates");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] checking for updates");
|
||||||
|
|
||||||
// check for new version
|
// check for new version
|
||||||
$aucheck = AutoUpdate::checkVersion();
|
$aucheck = AutoUpdate::checkVersion();
|
||||||
@@ -142,7 +142,7 @@ class Froxlor extends ApiCommand
|
|||||||
{
|
{
|
||||||
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
|
||||||
$json_str = $this->getParam('json_str');
|
$json_str = $this->getParam('json_str');
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "User " . $this->getUserDetail('loginname') . " imported settings");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "User " . $this->getUserDetail('loginname') . " imported settings");
|
||||||
try {
|
try {
|
||||||
SImExporter::import($json_str);
|
SImExporter::import($json_str);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
Customers::increaseUsage($customer['customerid'], 'ftp_lastaccountnumber');
|
Customers::increaseUsage($customer['customerid'], 'ftp_lastaccountnumber');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ftp-account '" . $username . " (" . $path . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ftp-account '" . $username . " (" . $path . ")'");
|
||||||
Cronjob::inserttask(TaskId::CREATE_FTP);
|
Cronjob::inserttask(TaskId::CREATE_FTP);
|
||||||
|
|
||||||
if ($sendinfomail == 1) {
|
if ($sendinfomail == 1) {
|
||||||
@@ -302,7 +302,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
$this->mailer()->clearAddresses();
|
$this->mailer()->clearAddresses();
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] added ftp-user '" . $username . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ftp-user '" . $username . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Ftps.get', [
|
$result = $this->apiCall('Ftps.get', [
|
||||||
'username' => $username
|
'username' => $username
|
||||||
@@ -367,7 +367,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
$params['idun'] = ($id <= 0 ? $username : $id);
|
$params['idun'] = ($id <= 0 ? $username : $id);
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get ftp-user '" . $result['username'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get ftp-user '" . $result['username'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
||||||
@@ -453,7 +453,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id,
|
"id" => $id,
|
||||||
"password" => $cryptPassword
|
"password" => $cryptPassword
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ftp-account password for '" . $result['username'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-account password for '" . $result['username'] . "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// path update?
|
// path update?
|
||||||
@@ -471,7 +471,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
"customerid" => $customer['customerid'],
|
"customerid" => $customer['customerid'],
|
||||||
"id" => $id
|
"id" => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ftp-account homdir for '" . $result['username'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-account homdir for '" . $result['username'] . "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// it's the task for "new ftp" but that will
|
// it's the task for "new ftp" but that will
|
||||||
@@ -533,7 +533,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list ftp-users");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list ftp-users");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list hosting-plans");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list hosting-plans");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT p.*, a.loginname as adminname
|
SELECT p.*, a.loginname as adminname
|
||||||
@@ -200,8 +200,8 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, 0);
|
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, 0);
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$name = Validate::validate(trim($name), 'name', '', '', [], true);
|
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT);
|
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_CONF_TEXT);
|
||||||
|
|
||||||
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
||||||
$value_arr['email_quota'] = -1;
|
$value_arr['email_quota'] = -1;
|
||||||
@@ -227,7 +227,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
'valuearr' => json_encode($value_arr)
|
'valuearr' => json_encode($value_arr)
|
||||||
];
|
];
|
||||||
Database::pexecute($ins_stmt, $ins_data, true, true);
|
Database::pexecute($ins_stmt, $ins_data, true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added hosting-plan '" . $name . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] added hosting-plan '" . $name . "'");
|
||||||
$result = $this->apiCall('HostingPlans.get', [
|
$result = $this->apiCall('HostingPlans.get', [
|
||||||
'planname' => $name
|
'planname' => $name
|
||||||
]);
|
]);
|
||||||
@@ -264,7 +264,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get hosting-plan '" . $result['name'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get hosting-plan '" . $result['name'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "planname '" . $planname . "'");
|
$key = ($id > 0 ? "id #" . $id : "planname '" . $planname . "'");
|
||||||
@@ -382,8 +382,8 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, $result['logviewenabled']);
|
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, $result['logviewenabled']);
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$name = Validate::validate(trim($name), 'name', '', '', [], true);
|
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT);
|
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_CONF_TEXT);
|
||||||
|
|
||||||
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
||||||
$value_arr['email_quota'] = -1;
|
$value_arr['email_quota'] = -1;
|
||||||
@@ -414,7 +414,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
'id' => $id
|
'id' => $id
|
||||||
];
|
];
|
||||||
Database::pexecute($upd_stmt, $update_data, true, true);
|
Database::pexecute($upd_stmt, $update_data, true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] updated hosting-plan '" . $result['name'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] updated hosting-plan '" . $result['name'] . "'");
|
||||||
return $this->response($update_data);
|
return $this->response($update_data);
|
||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin() && ($this->getUserDetail('change_serversettings') || !empty($this->getUserDetail('ip')))) {
|
if ($this->isAdmin() && ($this->getUserDetail('change_serversettings') || !empty($this->getUserDetail('ip')))) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list ips and ports");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list ips and ports");
|
||||||
$ip_where = "";
|
$ip_where = "";
|
||||||
$append_where = false;
|
$append_where = false;
|
||||||
if (!empty($this->getUserDetail('ip')) && $this->getUserDetail('ip') != -1) {
|
if (!empty($this->getUserDetail('ip')) && $this->getUserDetail('ip') != -1) {
|
||||||
@@ -175,9 +175,9 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
$docroot = Validate::validate($this->getParam('docroot', true, ''), 'docroot', Validate::REGEX_DIR, '', [], true);
|
$docroot = Validate::validate($this->getParam('docroot', true, ''), 'docroot', Validate::REGEX_DIR, '', [], true);
|
||||||
|
|
||||||
if ((int)Settings::Get('system.use_ssl') == 1) {
|
if ((int)Settings::Get('system.use_ssl') == 1) {
|
||||||
$ssl = !empty($this->getBoolParam('ssl', true, 0)) ? intval($this->getBoolParam('ssl', true, 0)) : 0;
|
$ssl = (bool)$this->getBoolParam('ssl', true, 0);
|
||||||
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', $ssl, ''), 'ssl_cert_file', '', '', [], true);
|
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', !$ssl, ''), 'ssl_cert_file', '', '', [], true);
|
||||||
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', $ssl, ''), 'ssl_key_file', '', '', [], true);
|
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', !$ssl, ''), 'ssl_key_file', '', '', [], true);
|
||||||
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, ''), 'ssl_ca_file', '', '', [], true);
|
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, ''), 'ssl_ca_file', '', '', [], true);
|
||||||
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, ''), 'ssl_cert_chainfile', '', '', [], true);
|
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, ''), 'ssl_cert_chainfile', '', '', [], true);
|
||||||
$sslss = $this->getParam('ssl_specialsettings', true, '');
|
$sslss = $this->getParam('ssl_specialsettings', true, '');
|
||||||
@@ -335,7 +335,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
'id' => $id
|
'id' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get ip " . $result['ip'] . " " . $result['port']);
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get ip " . $result['ip'] . " " . $result['port']);
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("IP/port with id #" . $id . " could not be found", 404);
|
throw new Exception("IP/port with id #" . $id . " could not be found", 404);
|
||||||
@@ -414,9 +414,9 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
$docroot = Validate::validate($this->getParam('docroot', true, $result['docroot']), 'docroot', Validate::REGEX_DIR, '', [], true);
|
$docroot = Validate::validate($this->getParam('docroot', true, $result['docroot']), 'docroot', Validate::REGEX_DIR, '', [], true);
|
||||||
|
|
||||||
if ((int)Settings::Get('system.use_ssl') == 1) {
|
if ((int)Settings::Get('system.use_ssl') == 1) {
|
||||||
$ssl = $this->getBoolParam('ssl', true, $result['ssl']);
|
$ssl = (bool)$this->getBoolParam('ssl', true, $result['ssl']);
|
||||||
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', $ssl, $result['ssl_cert_file']), 'ssl_cert_file', '', '', [], true);
|
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', !$ssl, $result['ssl_cert_file']), 'ssl_cert_file', '', '', [], true);
|
||||||
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', $ssl, $result['ssl_key_file']), 'ssl_key_file', '', '', [], true);
|
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', !$ssl, $result['ssl_key_file']), 'ssl_key_file', '', '', [], true);
|
||||||
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, $result['ssl_ca_file']), 'ssl_ca_file', '', '', [], true);
|
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, $result['ssl_ca_file']), 'ssl_ca_file', '', '', [], true);
|
||||||
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, $result['ssl_cert_chainfile']), 'ssl_cert_chainfile', '', '', [], true);
|
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, $result['ssl_cert_chainfile']), 'ssl_cert_chainfile', '', '', [], true);
|
||||||
$sslss = $this->getParam('ssl_specialsettings', true, $result['ssl_specialsettings']);
|
$sslss = $this->getParam('ssl_specialsettings', true, $result['ssl_specialsettings']);
|
||||||
|
|||||||
@@ -26,14 +26,15 @@
|
|||||||
namespace Froxlor\Api\Commands;
|
namespace Froxlor\Api\Commands;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use PDO;
|
|
||||||
use PDOException;
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\PhpHelper;
|
|
||||||
use Froxlor\Api\ApiCommand;
|
use Froxlor\Api\ApiCommand;
|
||||||
use Froxlor\Api\ResourceEntity;
|
use Froxlor\Api\ResourceEntity;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\PhpHelper;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
|
|
||||||
class MysqlServer extends ApiCommand implements ResourceEntity
|
class MysqlServer extends ApiCommand implements ResourceEntity
|
||||||
{
|
{
|
||||||
@@ -73,8 +74,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional, test connection with given credentials, default is true (yes)
|
* optional, test connection with given credentials, default is true (yes)
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function add()
|
public function add()
|
||||||
{
|
{
|
||||||
@@ -112,7 +113,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
);
|
);
|
||||||
if (!empty($mysql_ca)) {
|
if (!empty($mysql_ca)) {
|
||||||
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
||||||
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool) $mysql_verifycert;
|
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool)$mysql_verifycert;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
||||||
@@ -167,6 +168,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
$this->addDatabaseFromCustomerAllowedList($newdbserver);
|
$this->addDatabaseFromCustomerAllowedList($newdbserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added new database server '" . $description . "' (" . $mysql_host . ")");
|
||||||
|
|
||||||
return $this->response(['dbserver' => $newdbserver]);
|
return $this->response(['dbserver' => $newdbserver]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,16 +182,16 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional the number of the mysql server (either id or dbserver must be set)
|
* optional the number of the mysql server (either id or dbserver must be set)
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
$this->validateAccess();
|
$this->validateAccess();
|
||||||
|
|
||||||
$id = (int) $this->getParam('id', true, -1);
|
$id = (int)$this->getParam('id', true, -1);
|
||||||
$dn_optional = $id >= 0;
|
$dn_optional = $id >= 0;
|
||||||
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
|
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
|
||||||
$dbserver = $id >= 0 ? $id : $dbserver;
|
$dbserver = $id >= 0 ? $id : $dbserver;
|
||||||
|
|
||||||
if ($dbserver == 0) {
|
if ($dbserver == 0) {
|
||||||
@@ -212,8 +215,12 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
// when removing, remove from list of allowed_mysqlservers from any customers
|
// when removing, remove from list of allowed_mysqlservers from any customers
|
||||||
$this->removeDatabaseFromCustomerAllowedList($dbserver);
|
$this->removeDatabaseFromCustomerAllowedList($dbserver);
|
||||||
|
|
||||||
|
$description = $sql_root[$dbserver]['caption'] ?? "unknown";
|
||||||
|
$mysql_host = $sql_root[$dbserver]['host'] ?? "unknown";
|
||||||
unset($sql_root[$dbserver]);
|
unset($sql_root[$dbserver]);
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] removed database server '" . $description . "' (" . $mysql_host . ")");
|
||||||
|
|
||||||
$this->generateNewUserData($sql, $sql_root);
|
$this->generateNewUserData($sql, $sql_root);
|
||||||
return $this->response(['true']);
|
return $this->response(['true']);
|
||||||
}
|
}
|
||||||
@@ -287,14 +294,14 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional the number of the mysql server (either id or dbserver must be set)
|
* optional the number of the mysql server (either id or dbserver must be set)
|
||||||
*
|
*
|
||||||
* @access admin, customer
|
* @access admin, customer
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function get()
|
public function get()
|
||||||
{
|
{
|
||||||
$id = (int) $this->getParam('id', true, -1);
|
$id = (int)$this->getParam('id', true, -1);
|
||||||
$dn_optional = $id >= 0;
|
$dn_optional = $id >= 0;
|
||||||
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
|
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
|
||||||
$dbserver = $id >= 0 ? $id : $dbserver;
|
$dbserver = $id >= 0 ? $id : $dbserver;
|
||||||
|
|
||||||
$sql_root = [];
|
$sql_root = [];
|
||||||
@@ -317,6 +324,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
unset($sql_root[$dbserver]['password']);
|
unset($sql_root[$dbserver]['password']);
|
||||||
$sql_root[$dbserver]['id'] = $dbserver;
|
$sql_root[$dbserver]['id'] = $dbserver;
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get database-server '" . $sql_root[$dbserver]['caption'] . "'");
|
||||||
return $this->response($sql_root[$dbserver]);
|
return $this->response($sql_root[$dbserver]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,16 +355,16 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional, test connection with given credentials, default is true (yes)
|
* optional, test connection with given credentials, default is true (yes)
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
$this->validateAccess();
|
$this->validateAccess();
|
||||||
|
|
||||||
$id = (int) $this->getParam('id', true, -1);
|
$id = (int)$this->getParam('id', true, -1);
|
||||||
$dn_optional = $id >= 0;
|
$dn_optional = $id >= 0;
|
||||||
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
|
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
|
||||||
$dbserver = $id >= 0 ? $id : $dbserver;
|
$dbserver = $id >= 0 ? $id : $dbserver;
|
||||||
|
|
||||||
$sql_root = [];
|
$sql_root = [];
|
||||||
@@ -417,7 +425,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
);
|
);
|
||||||
if (!empty($mysql_ca)) {
|
if (!empty($mysql_ca)) {
|
||||||
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
||||||
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool) $mysql_verifycert;
|
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool)$mysql_verifycert;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
||||||
@@ -448,6 +456,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
$this->addDatabaseFromCustomerAllowedList($dbserver);
|
$this->addDatabaseFromCustomerAllowedList($dbserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] edited database server '" . $description . "' (" . $mysql_host . ")");
|
||||||
|
|
||||||
return $this->response(['true']);
|
return $this->response(['true']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +482,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
WHERE `dbserver` = :dbserver
|
WHERE `dbserver` = :dbserver
|
||||||
");
|
");
|
||||||
$result = Database::pexecute_first($result_stmt, ['dbserver' => $dbserver], true, true);
|
$result = Database::pexecute_first($result_stmt, ['dbserver' => $dbserver], true, true);
|
||||||
return (int) $result['num_dbs'];
|
return (int)$result['num_dbs'];
|
||||||
} else {
|
} else {
|
||||||
$dbserver = $this->getParam('mysql_server');
|
$dbserver = $this->getParam('mysql_server');
|
||||||
$customer_ids = $this->getAllowedCustomerIds();
|
$customer_ids = $this->getAllowedCustomerIds();
|
||||||
@@ -516,7 +526,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
`allowed_mysqlserver` = :am WHERE `customerid` = :cid
|
`allowed_mysqlserver` = :am WHERE `customerid` = :cid
|
||||||
");
|
");
|
||||||
while ($customer = $sel_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($customer = $sel_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$allowed_mysqls = json_decode(($customer['allowed_mysqlserver'] ?? '[]'), true);
|
$allowed_mysqls = json_decode(($customer['allowed_mysqlserver'] ?: '[]'), true);
|
||||||
if (!in_array($dbserver, $allowed_mysqls)) {
|
if (!in_array($dbserver, $allowed_mysqls)) {
|
||||||
$allowed_mysqls[] = $dbserver;
|
$allowed_mysqls[] = $dbserver;
|
||||||
$allowed_mysqls = json_encode($allowed_mysqls);
|
$allowed_mysqls = json_encode($allowed_mysqls);
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
$this->mailer()->clearAddresses();
|
$this->mailer()->clearAddresses();
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] added mysql-database '" . $username . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added mysql-database '" . $username . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Mysqls.get', [
|
$result = $this->apiCall('Mysqls.get', [
|
||||||
'dbname' => $username,
|
'dbname' => $username,
|
||||||
@@ -299,7 +299,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
$mbdata = $mbdata_stmt->fetch(PDO::FETCH_ASSOC);
|
$mbdata = $mbdata_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
Database::needRoot(false);
|
Database::needRoot(false);
|
||||||
$result['size'] = $mbdata['MB'] ?? 0;
|
$result['size'] = $mbdata['MB'] ?? 0;
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get database '" . $result['databasename'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get database '" . $result['databasename'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "dbname '" . $dbname . "'");
|
$key = ($id > 0 ? "id #" . $id : "dbname '" . $dbname . "'");
|
||||||
@@ -388,7 +388,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] updated mysql-database '" . $result['databasename'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated mysql-database '" . $result['databasename'] . "'");
|
||||||
$result = $this->apiCall('Mysqls.get', [
|
$result = $this->apiCall('Mysqls.get', [
|
||||||
'dbname' => $result['databasename']
|
'dbname' => $result['databasename']
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list php-configs");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list php-configs");
|
||||||
|
|
||||||
$with_subdomains = $this->getBoolParam('with_subdomains', true, false);
|
$with_subdomains = $this->getBoolParam('with_subdomains', true, false);
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
@@ -392,7 +392,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
$ins_data['id'] = Database::lastInsertId();
|
$ins_data['id'] = Database::lastInsertId();
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('PhpSettings.get', [
|
$result = $this->apiCall('PhpSettings.get', [
|
||||||
'id' => $ins_data['id']
|
'id' => $ins_data['id']
|
||||||
@@ -629,7 +629,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
Database::pexecute($upd_stmt, $upd_data, true, true);
|
Database::pexecute($upd_stmt, $upd_data, true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('PhpSettings.get', [
|
$result = $this->apiCall('PhpSettings.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
@@ -686,7 +686,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, overwrites path value with an URL to generate a redirect, alternatively use the path
|
* optional, overwrites path value with an URL to generate a redirect, alternatively use the path
|
||||||
* parameter also for URLs
|
* parameter also for URLs
|
||||||
* @param int $openbasedir_path
|
* @param int $openbasedir_path
|
||||||
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
* optional, either 0 for domains-docroot [default], 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, php-settings-id, if empty the $domain value is used
|
* optional, php-settings-id, if empty the $domain value is used
|
||||||
* @param int $redirectcode
|
* @param int $redirectcode
|
||||||
@@ -104,7 +104,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$aliasdomain = $this->getParam('alias', true, 0);
|
$aliasdomain = $this->getParam('alias', true, 0);
|
||||||
$path = $this->getParam('path', true, '');
|
$path = $this->getParam('path', true, '');
|
||||||
$url = $this->getParam('url', true, '');
|
$url = $this->getParam('url', true, '');
|
||||||
$openbasedir_path = $this->getParam('openbasedir_path', true, 1);
|
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, 0);
|
$phpsettingid = $this->getParam('phpsettingid', true, 0);
|
||||||
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
|
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
|
||||||
$isemaildomain = $this->getParam('isemaildomain', true, 0);
|
$isemaildomain = $this->getParam('isemaildomain', true, 0);
|
||||||
@@ -486,7 +486,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
||||||
}
|
}
|
||||||
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get subdomain '" . $result['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get subdomain '" . $result['domain'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
||||||
@@ -856,7 +856,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_DNS);
|
Cronjob::inserttask(TaskId::REBUILD_DNS);
|
||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'");
|
||||||
}
|
}
|
||||||
$result = $this->apiCall('SubDomains.get', [
|
$result = $this->apiCall('SubDomains.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class SysLog extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list log-entries");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list log-entries");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ class Traffic extends ApiCommand implements ResourceEntity
|
|||||||
$row['mail'] *= 1024;
|
$row['mail'] *= 1024;
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list traffic");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list traffic");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class CliCommand extends Command
|
|||||||
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
|
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
|
||||||
define('_CRON_UPDATE', 1);
|
define('_CRON_UPDATE', 1);
|
||||||
ob_start([
|
ob_start([
|
||||||
'this',
|
$this,
|
||||||
'cleanUpdateOutput'
|
'cleanUpdateOutput'
|
||||||
]);
|
]);
|
||||||
include_once Froxlor::getInstallDir() . '/install/updatesql.php';
|
include_once Froxlor::getInstallDir() . '/install/updatesql.php';
|
||||||
|
|||||||
178
lib/Froxlor/Cli/ConfigDiff.php
Normal file
178
lib/Froxlor/Cli/ConfigDiff.php
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
|
use Froxlor\Config\ConfigParser;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
final class ConfigDiff extends CliCommand
|
||||||
|
{
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this->setName('froxlor:config-diff')
|
||||||
|
->setDescription('Shows differences in config templates between OS versions')
|
||||||
|
->addArgument('from', InputArgument::OPTIONAL, 'OS version to compare against')
|
||||||
|
->addArgument('to', InputArgument::OPTIONAL, 'OS version to compare from')
|
||||||
|
->addOption('list', 'l', InputOption::VALUE_NONE, 'List all possible OS versions')
|
||||||
|
->addOption('diff-params', '', InputOption::VALUE_REQUIRED, 'Additional parameters for `diff`, e.g. --diff-params="--color=always"');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
require Froxlor::getInstallDir() . '/lib/functions.php';
|
||||||
|
|
||||||
|
$parsers = $versions = [];
|
||||||
|
foreach (glob(Froxlor::getInstallDir() . '/lib/configfiles/*.xml') as $config) {
|
||||||
|
$name = str_replace(".xml", "", strtolower(basename($config)));
|
||||||
|
$parser = new ConfigParser($config);
|
||||||
|
$versions[$name] = $parser->getCompleteDistroName();
|
||||||
|
$parsers[$name] = $parser;
|
||||||
|
}
|
||||||
|
asort($versions);
|
||||||
|
|
||||||
|
if ($input->getOption('list') === true) {
|
||||||
|
$output->writeln('The following OS version templates are available:');
|
||||||
|
foreach ($versions as $k => $v) {
|
||||||
|
$output->writeln(str_pad($k, 20) . $v);
|
||||||
|
}
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$input->hasArgument('from') || !array_key_exists($input->getArgument('from'), $versions)) {
|
||||||
|
$output->writeln('<error>Missing or invalid "from" argument.</error>');
|
||||||
|
$output->writeln('Available versions: ' . implode(', ', array_keys($versions)));
|
||||||
|
return self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$input->hasArgument('to') || !array_key_exists($input->getArgument('to'), $versions)) {
|
||||||
|
$output->writeln('<error>Missing or invalid "to" argument.</error>');
|
||||||
|
$output->writeln('Available versions: ' . implode(', ', array_keys($versions)));
|
||||||
|
return self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure diff is installed
|
||||||
|
$check_diff_installed = FileDir::safe_exec('which diff');
|
||||||
|
if (count($check_diff_installed) === 0) {
|
||||||
|
$output->writeln('<error>Unable to find "diff" installation on your system.</error>');
|
||||||
|
return self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parser_from = $parsers[$input->getArgument('from')];
|
||||||
|
$parser_to = $parsers[$input->getArgument('to')];
|
||||||
|
$tmp_from = tempnam(sys_get_temp_dir(), 'froxlor_config_diff_from');
|
||||||
|
$tmp_to = tempnam(sys_get_temp_dir(), 'froxlor_config_diff_to');
|
||||||
|
$files = [];
|
||||||
|
$titles_by_key = [];
|
||||||
|
|
||||||
|
// Aggregate content for each config file
|
||||||
|
foreach ([[$parser_from, 'from'], [$parser_to, 'to']] as $todo) {
|
||||||
|
foreach ($todo[0]->getServices() as $service_type => $service) {
|
||||||
|
foreach ($service->getDaemons() as $daemon_name => $daemon) {
|
||||||
|
foreach ($daemon->getConfig() as $instruction) {
|
||||||
|
if ($instruction['type'] !== 'file') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($instruction['subcommands'])) {
|
||||||
|
foreach ($instruction['subcommands'] as $subinstruction) {
|
||||||
|
if ($subinstruction['type'] !== 'file') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $subinstruction['content'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$content = $instruction['content'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($content)) {
|
||||||
|
throw new \Exception("Cannot find content for {$instruction['name']}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = "{$service_type}_{$daemon_name}_{$instruction['name']}";
|
||||||
|
$titles_by_key[$key] = "{$service->title} : {$daemon->title} : {$instruction['name']}";
|
||||||
|
if (!isset($files[$key])) {
|
||||||
|
$files[$key] = ['from' => '', 'to' => ''];
|
||||||
|
}
|
||||||
|
$files[$key][$todo[1]] = $this->filterContent($content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ksort($files);
|
||||||
|
|
||||||
|
$diff_params = '';
|
||||||
|
if ($input->hasOption('diff-params') && trim($input->getOption('diff-params')) !== '') {
|
||||||
|
$diff_params = trim($input->getOption('diff-params'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run diff on each file and output, if anything changed
|
||||||
|
foreach ($files as $file_key => $content) {
|
||||||
|
file_put_contents($tmp_from, $content['from']);
|
||||||
|
file_put_contents($tmp_to, $content['to']);
|
||||||
|
$diff_output = FileDir::safe_exec("{$check_diff_installed[0]} {$diff_params} {$tmp_from} {$tmp_to}");
|
||||||
|
|
||||||
|
if (count($diff_output) === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->writeln('<info># ' . $titles_by_key[$file_key] . '</info>');
|
||||||
|
$output->writeln(implode("\n", $diff_output) . "\n");
|
||||||
|
unset($diff_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove tmp files again
|
||||||
|
unlink($tmp_from);
|
||||||
|
unlink($tmp_to);
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function filterContent(string $content): string
|
||||||
|
{
|
||||||
|
$new_content = '';
|
||||||
|
|
||||||
|
foreach (explode("\n", $content) as $n) {
|
||||||
|
$n = trim($n);
|
||||||
|
if (!$n) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_starts_with($n, '#')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_content .= $n . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $new_content;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -80,7 +80,7 @@ final class InstallCommand extends Command
|
|||||||
$_SERVER['SERVER_NAME'] = $host[0] ?? '';
|
$_SERVER['SERVER_NAME'] = $host[0] ?? '';
|
||||||
$ips = [];
|
$ips = [];
|
||||||
exec('hostname -I', $ips);
|
exec('hostname -I', $ips);
|
||||||
$ips = explode(" ", $ips[0]);
|
$ips = explode(" ", $ips[0] ?? "");
|
||||||
// ipv4 address?
|
// ipv4 address?
|
||||||
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ($ips[0] ?? '') : '';
|
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ($ips[0] ?? '') : '';
|
||||||
if (empty($_SERVER['SERVER_ADDR'])) {
|
if (empty($_SERVER['SERVER_ADDR'])) {
|
||||||
|
|||||||
@@ -62,6 +62,11 @@ final class MasterCron extends CliCommand
|
|||||||
$result = self::SUCCESS;
|
$result = self::SUCCESS;
|
||||||
$result = $this->validateRequirements($input, $output);
|
$result = $this->validateRequirements($input, $output);
|
||||||
|
|
||||||
|
if ($result != self::SUCCESS) {
|
||||||
|
// requirements failed, exit
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
$jobs = $input->getArgument('job');
|
$jobs = $input->getArgument('job');
|
||||||
|
|
||||||
// handle force option
|
// handle force option
|
||||||
@@ -111,8 +116,8 @@ final class MasterCron extends CliCommand
|
|||||||
]);
|
]);
|
||||||
$this->cronLog->setCronDebugFlag(defined('CRON_DEBUG_FLAG'));
|
$this->cronLog->setCronDebugFlag(defined('CRON_DEBUG_FLAG'));
|
||||||
|
|
||||||
// check whether there are actual tasks to perform by 'tasks'-cron so
|
// check whether there are actual tasks to perform by 'tasks'-cron, so
|
||||||
// we dont regenerate files unnecessarily
|
// we don't regenerate files unnecessarily
|
||||||
$tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`");
|
$tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`");
|
||||||
$tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC);
|
$tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ final class ValidateAcmeWebroot extends CliCommand
|
|||||||
'domain' => Settings::Get('system.hostname')
|
'domain' => Settings::Get('system.hostname')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$upd_stmt = Database::prepare("UPDATE domain_ssl_settings SET expirationdate=NULL WHERE `domainid` = :did");
|
$upd_stmt = Database::prepare("UPDATE domain_ssl_settings SET `validtodate`=NULL WHERE `domainid` = :did");
|
||||||
$acmesh_dir = dirname(Settings::Get('system.acmeshpath'));
|
$acmesh_dir = dirname(Settings::Get('system.acmeshpath'));
|
||||||
$acmesh_challenge_dir = rtrim(FileDir::makeCorrectDir(Settings::Get('system.letsencryptchallengepath')), "/");
|
$acmesh_challenge_dir = rtrim(FileDir::makeCorrectDir(Settings::Get('system.letsencryptchallengepath')), "/");
|
||||||
$recommended = rtrim(FileDir::makeCorrectDir(Froxlor::getInstallDir()), "/");
|
$recommended = rtrim(FileDir::makeCorrectDir(Froxlor::getInstallDir()), "/");
|
||||||
|
|||||||
@@ -132,18 +132,16 @@ abstract class DnsBase
|
|||||||
");
|
");
|
||||||
|
|
||||||
while ($domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$privkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . Settings::Get('dkim.privkeysuffix'));
|
$privkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/mx.' . $domain['domain'] . '.' . Settings::Get('dkim.privkeysuffix'));
|
||||||
$pubkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . '.public');
|
$pubkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/mx.' . $domain['domain'] . '.public');
|
||||||
|
|
||||||
if ($domain['dkim_privkey'] == '' || $domain['dkim_pubkey'] == '') {
|
if ($domain['dkim_privkey'] == '' || $domain['dkim_pubkey'] == '') {
|
||||||
$max_dkim_id_stmt = Database::query("SELECT MAX(`dkim_id`) as `max_dkim_id` FROM `" . TABLE_PANEL_DOMAINS . "`");
|
$max_dkim_id_stmt = Database::query("SELECT MAX(`dkim_id`) as `max_dkim_id` FROM `" . TABLE_PANEL_DOMAINS . "`");
|
||||||
$max_dkim_id = $max_dkim_id_stmt->fetch(PDO::FETCH_ASSOC);
|
$max_dkim_id = $max_dkim_id_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$domain['dkim_id'] = (int)$max_dkim_id['max_dkim_id'] + 1;
|
$domain['dkim_id'] = (int)$max_dkim_id['max_dkim_id'] + 1;
|
||||||
$privkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . Settings::Get('dkim.privkeysuffix'));
|
|
||||||
FileDir::safe_exec('openssl genrsa -out ' . escapeshellarg($privkey_filename) . ' ' . Settings::Get('dkim.dkim_keylength'));
|
FileDir::safe_exec('openssl genrsa -out ' . escapeshellarg($privkey_filename) . ' ' . Settings::Get('dkim.dkim_keylength'));
|
||||||
$domain['dkim_privkey'] = file_get_contents($privkey_filename);
|
$domain['dkim_privkey'] = file_get_contents($privkey_filename);
|
||||||
FileDir::safe_exec("chmod 0640 " . escapeshellarg($privkey_filename));
|
FileDir::safe_exec("chmod 0640 " . escapeshellarg($privkey_filename));
|
||||||
$pubkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . '.public');
|
|
||||||
FileDir::safe_exec('openssl rsa -in ' . escapeshellarg($privkey_filename) . ' -pubout -outform pem -out ' . escapeshellarg($pubkey_filename));
|
FileDir::safe_exec('openssl rsa -in ' . escapeshellarg($privkey_filename) . ' -pubout -outform pem -out ' . escapeshellarg($pubkey_filename));
|
||||||
$domain['dkim_pubkey'] = file_get_contents($pubkey_filename);
|
$domain['dkim_pubkey'] = file_get_contents($pubkey_filename);
|
||||||
FileDir::safe_exec("chmod 0664 " . escapeshellarg($pubkey_filename));
|
FileDir::safe_exec("chmod 0664 " . escapeshellarg($pubkey_filename));
|
||||||
@@ -217,7 +215,7 @@ abstract class DnsBase
|
|||||||
`" . TABLE_PANEL_DOMAINS . "` `d`
|
`" . TABLE_PANEL_DOMAINS . "` `d`
|
||||||
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
|
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
|
||||||
WHERE
|
WHERE
|
||||||
`d`.`isbinddomain` = '1'
|
`d`.`isbinddomain` = '1' aND `d`.`deactivated` = '0'
|
||||||
ORDER BY
|
ORDER BY
|
||||||
`d`.`domain` ASC
|
`d`.`domain` ASC
|
||||||
");
|
");
|
||||||
|
|||||||
@@ -126,6 +126,9 @@ class ApacheFcgi extends Apache
|
|||||||
|
|
||||||
// mod_proxy stuff for apache-2.4
|
// mod_proxy stuff for apache-2.4
|
||||||
if (Settings::Get('system.apache24') == '1' && Settings::Get('phpfpm.use_mod_proxy') == '1') {
|
if (Settings::Get('system.apache24') == '1' && Settings::Get('phpfpm.use_mod_proxy') == '1') {
|
||||||
|
|
||||||
|
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
||||||
|
|
||||||
$filesmatch = $phpconfig['fpm_settings']['limit_extensions'];
|
$filesmatch = $phpconfig['fpm_settings']['limit_extensions'];
|
||||||
$extensions = explode(" ", $filesmatch);
|
$extensions = explode(" ", $filesmatch);
|
||||||
$filesmatch = "";
|
$filesmatch = "";
|
||||||
@@ -141,23 +144,19 @@ class ApacheFcgi extends Apache
|
|||||||
$php_options_text .= ' </FilesMatch>' . "\n";
|
$php_options_text .= ' </FilesMatch>' . "\n";
|
||||||
|
|
||||||
$mypath_dir = new Directory($domain['documentroot']);
|
$mypath_dir = new Directory($domain['documentroot']);
|
||||||
|
// only create the "require all granted" directive if there is no active directory-protection
|
||||||
// only create the require all granted if there is not active directory-protection
|
|
||||||
// for this path, as this would be the first require and therefore grant all access
|
// for this path, as this would be the first require and therefore grant all access
|
||||||
if ($mypath_dir->isUserProtected() == false) {
|
if ($mypath_dir->isUserProtected() == false) {
|
||||||
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
|
||||||
if ($phpconfig['pass_authorizationheader'] == '1') {
|
if ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
$php_options_text .= ' CGIPassAuth On' . "\n";
|
$php_options_text .= ' CGIPassAuth On' . "\n";
|
||||||
}
|
}
|
||||||
$php_options_text .= ' Require all granted' . "\n";
|
$php_options_text .= ' Require all granted' . "\n";
|
||||||
$php_options_text .= ' AllowOverride All' . "\n";
|
$php_options_text .= ' AllowOverride All' . "\n";
|
||||||
$php_options_text .= ' </Directory>' . "\n";
|
|
||||||
} elseif ($phpconfig['pass_authorizationheader'] == '1') {
|
} elseif ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
// allow Pass of Authorization header
|
// allow Pass of Authorization header
|
||||||
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
|
|
||||||
$php_options_text .= ' CGIPassAuth On' . "\n";
|
$php_options_text .= ' CGIPassAuth On' . "\n";
|
||||||
$php_options_text .= ' </Directory>' . "\n";
|
|
||||||
}
|
}
|
||||||
|
$php_options_text .= ' </Directory>' . "\n";
|
||||||
} else {
|
} else {
|
||||||
$addheader = "";
|
$addheader = "";
|
||||||
if ($phpconfig['pass_authorizationheader'] == '1') {
|
if ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
@@ -196,6 +195,9 @@ class ApacheFcgi extends Apache
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$php_options_text .= ' FcgidIdleTimeout ' . Settings::Get('system.mod_fcgid_idle_timeout') . "\n";
|
$php_options_text .= ' FcgidIdleTimeout ' . Settings::Get('system.mod_fcgid_idle_timeout') . "\n";
|
||||||
|
if ($phpconfig['pass_authorizationheader'] == '1') {
|
||||||
|
$php_options_text .= ' FcgidPassHeader Authorization' . "\n";
|
||||||
|
}
|
||||||
if ((int)Settings::Get('system.mod_fcgid_wrapper') == 0) {
|
if ((int)Settings::Get('system.mod_fcgid_wrapper') == 0) {
|
||||||
$php_options_text .= ' SuexecUserGroup "' . $domain['loginname'] . '" "' . $domain['loginname'] . '"' . "\n";
|
$php_options_text .= ' SuexecUserGroup "' . $domain['loginname'] . '" "' . $domain['loginname'] . '"' . "\n";
|
||||||
$php_options_text .= ' ScriptAlias /php/ ' . $php->getInterface()->getConfigDir() . "\n";
|
$php_options_text .= ' ScriptAlias /php/ ' . $php->getInterface()->getConfigDir() . "\n";
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ class HttpConfigBase
|
|||||||
$froxlor_ssl_settings_stmt = Database::prepare("
|
$froxlor_ssl_settings_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
||||||
WHERE `domainid` = '0' AND
|
WHERE `domainid` = '0' AND
|
||||||
(`expirationdate` < DATE_ADD(NOW(), INTERVAL 30 DAY) OR `expirationdate` IS NULL)
|
(`validtodate` < DATE_ADD(NOW(), INTERVAL 30 DAY) OR `validtodate` IS NULL)
|
||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
if ($froxlor_ssl && !empty($froxlor_ssl['ssl_cert_file'])) {
|
if ($froxlor_ssl && !empty($froxlor_ssl['ssl_cert_file'])) {
|
||||||
|
|||||||
@@ -114,7 +114,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
`ssl_cert_chainfile` = :chain,
|
`ssl_cert_chainfile` = :chain,
|
||||||
`ssl_csr_file` = :csr,
|
`ssl_csr_file` = :csr,
|
||||||
`ssl_fullchain_file` = :fullchain,
|
`ssl_fullchain_file` = :fullchain,
|
||||||
`expirationdate` = :expirationdate
|
`validfromdate` = :validfromdate,
|
||||||
|
`validtodate` = :validtodate,
|
||||||
|
`issuer` = :issuer
|
||||||
");
|
");
|
||||||
|
|
||||||
// prepare domain update sql
|
// prepare domain update sql
|
||||||
@@ -136,7 +138,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
'lepublickey' => Settings::Get('system.lepublickey'),
|
'lepublickey' => Settings::Get('system.lepublickey'),
|
||||||
'leregistered' => Settings::Get('system.leregistered'),
|
'leregistered' => Settings::Get('system.leregistered'),
|
||||||
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
||||||
'expirationdate' => null,
|
'validfromdate' => null,
|
||||||
|
'validtodate' => null,
|
||||||
|
'issuer' => "",
|
||||||
'ssl_cert_file' => null,
|
'ssl_cert_file' => null,
|
||||||
'ssl_key_file' => null,
|
'ssl_key_file' => null,
|
||||||
'ssl_ca_file' => null,
|
'ssl_ca_file' => null,
|
||||||
@@ -171,7 +175,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
'lepublickey' => Settings::Get('system.lepublickey'),
|
'lepublickey' => Settings::Get('system.lepublickey'),
|
||||||
'leregistered' => Settings::Get('system.leregistered'),
|
'leregistered' => Settings::Get('system.leregistered'),
|
||||||
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
||||||
'expirationdate' => is_array($renew_froxlor) ? $renew_froxlor['expirationdate'] : date('Y-m-d H:i:s', 0),
|
'validfromdate' => is_array($renew_froxlor) ? $renew_froxlor['validfromdate'] : date('Y-m-d H:i:s', 0),
|
||||||
|
'validtodate' => is_array($renew_froxlor) ? $renew_froxlor['validtodate'] : date('Y-m-d H:i:s', 0),
|
||||||
|
'issuer' => is_array($renew_froxlor) ? $renew_froxlor['issuer'] : "",
|
||||||
'ssl_cert_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_cert_file'] : null,
|
'ssl_cert_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_cert_file'] : null,
|
||||||
'ssl_key_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_key_file'] : null,
|
'ssl_key_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_key_file'] : null,
|
||||||
'ssl_ca_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_ca_file'] : null,
|
'ssl_ca_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_ca_file'] : null,
|
||||||
@@ -187,7 +193,7 @@ class AcmeSh extends FroxlorCron
|
|||||||
'loginname' => $domain['loginname'],
|
'loginname' => $domain['loginname'],
|
||||||
'adminsession' => 0
|
'adminsession' => 0
|
||||||
]);
|
]);
|
||||||
if (defined('CRON_IS_FORCED') || self::checkFsFilesAreNewer($domain['domain'], $domain['expirationdate'])) {
|
if (defined('CRON_IS_FORCED') || self::checkFsFilesAreNewer($domain['domain'], $domain['validtodate'])) {
|
||||||
self::certToDb($domain, $cronlog, []);
|
self::certToDb($domain, $cronlog, []);
|
||||||
$changedetected = 1;
|
$changedetected = 1;
|
||||||
}
|
}
|
||||||
@@ -221,16 +227,21 @@ class AcmeSh extends FroxlorCron
|
|||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
// also check for possible existing certificate
|
// also check for possible existing certificate
|
||||||
if (!$froxlor_ssl && !self::checkFsFilesAreNewer(Settings::Get('system.hostname'), date('Y-m-d H:i:s'))) {
|
if (($froxlor_ssl && empty($froxlor_ssl['validtodate']))
|
||||||
|
|| (!$froxlor_ssl && !self::checkFsFilesAreNewer(Settings::Get('system.hostname'), date('Y-m-d H:i:s')))
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function checkFsFilesAreNewer($domain, $cert_date = 0)
|
private static function checkFsFilesAreNewer($domain, $cert_date = 0): bool
|
||||||
{
|
{
|
||||||
$certificate_folder = self::getWorkingDirFromEnv(strtolower($domain));
|
$certificate_folder = self::getCertificateFolder(strtolower($domain));
|
||||||
|
if (empty($certificate_folder)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$ssl_file = FileDir::makeCorrectFile($certificate_folder . '/' . strtolower($domain) . '.cer');
|
$ssl_file = FileDir::makeCorrectFile($certificate_folder . '/' . strtolower($domain) . '.cer');
|
||||||
|
|
||||||
if (is_dir($certificate_folder) && file_exists($ssl_file) && is_readable($ssl_file)) {
|
if (is_dir($certificate_folder) && file_exists($ssl_file) && is_readable($ssl_file)) {
|
||||||
@@ -242,9 +253,13 @@ class AcmeSh extends FroxlorCron
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getWorkingDirFromEnv($domain = "", $forced_noecc = false)
|
public static function getWorkingDirFromEnv($domain = "", $forced_ecc = false): string
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.leecc') > 0 && !$forced_noecc) {
|
// first try without _ecc either if it's enabled currently or not as
|
||||||
|
// it might have been at some point so there is a chance we have certificates
|
||||||
|
// with and without _ecc - the method getCertificateFolder() will check both
|
||||||
|
// possibilities
|
||||||
|
if ($forced_ecc) {
|
||||||
$domain .= "_ecc";
|
$domain .= "_ecc";
|
||||||
}
|
}
|
||||||
$env_file = FileDir::makeCorrectFile(dirname(self::getAcmeSh()) . '/acme.sh.env');
|
$env_file = FileDir::makeCorrectFile(dirname(self::getAcmeSh()) . '/acme.sh.env');
|
||||||
@@ -254,7 +269,7 @@ class AcmeSh extends FroxlorCron
|
|||||||
cut -d'"' -f2
|
cut -d'"' -f2
|
||||||
EOC;
|
EOC;
|
||||||
exec('grep "LE_WORKING_DIR" ' . escapeshellarg($env_file) . ' | ' . $cut, $output);
|
exec('grep "LE_WORKING_DIR" ' . escapeshellarg($env_file) . ' | ' . $cut, $output);
|
||||||
if (is_array($output) && !empty($output) && isset($output[0]) && !empty($output[0])) {
|
if (is_array($output) && !empty($output) && !empty($output[0])) {
|
||||||
return FileDir::makeCorrectDir($output[0] . "/" . $domain);
|
return FileDir::makeCorrectDir($output[0] . "/" . $domain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,7 +294,9 @@ EOC;
|
|||||||
SELECT
|
SELECT
|
||||||
domssl.`id`,
|
domssl.`id`,
|
||||||
domssl.`domainid`,
|
domssl.`domainid`,
|
||||||
domssl.`expirationdate`,
|
domssl.`validfromdate`,
|
||||||
|
domssl.`validtodate`,
|
||||||
|
domssl.`issuer`,
|
||||||
domssl.`ssl_cert_file`,
|
domssl.`ssl_cert_file`,
|
||||||
domssl.`ssl_key_file`,
|
domssl.`ssl_key_file`,
|
||||||
domssl.`ssl_ca_file`,
|
domssl.`ssl_ca_file`,
|
||||||
@@ -306,7 +323,7 @@ EOC;
|
|||||||
AND dom.`letsencrypt` = 1
|
AND dom.`letsencrypt` = 1
|
||||||
AND dom.`aliasdomain` IS NULL
|
AND dom.`aliasdomain` IS NULL
|
||||||
AND dom.`iswildcarddomain` = 0
|
AND dom.`iswildcarddomain` = 0
|
||||||
AND domssl.`expirationdate` IS NULL
|
AND domssl.`validtodate` IS NULL
|
||||||
");
|
");
|
||||||
$customer_ssl = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
|
$customer_ssl = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
if ($customer_ssl) {
|
if ($customer_ssl) {
|
||||||
@@ -330,7 +347,7 @@ EOC;
|
|||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
// also check for possible existing certificate
|
// also check for possible existing certificate
|
||||||
if ($froxlor_ssl && self::checkFsFilesAreNewer(Settings::Get('system.hostname'), $froxlor_ssl['expirationdate'])) {
|
if ($froxlor_ssl && self::checkFsFilesAreNewer(Settings::Get('system.hostname'), $froxlor_ssl['validtodate'])) {
|
||||||
return $froxlor_ssl;
|
return $froxlor_ssl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -346,7 +363,9 @@ EOC;
|
|||||||
SELECT
|
SELECT
|
||||||
domssl.`id`,
|
domssl.`id`,
|
||||||
domssl.`domainid`,
|
domssl.`domainid`,
|
||||||
domssl.`expirationdate`,
|
domssl.`validfromdate`,
|
||||||
|
domssl.`validtodate`,
|
||||||
|
domssl.`issuer`,
|
||||||
domssl.`ssl_cert_file`,
|
domssl.`ssl_cert_file`,
|
||||||
domssl.`ssl_key_file`,
|
domssl.`ssl_key_file`,
|
||||||
dom.`domain`,
|
dom.`domain`,
|
||||||
@@ -370,7 +389,7 @@ EOC;
|
|||||||
if ($renew_certs) {
|
if ($renew_certs) {
|
||||||
if ($check) {
|
if ($check) {
|
||||||
foreach ($renew_certs as $cert) {
|
foreach ($renew_certs as $cert) {
|
||||||
if (self::checkFsFilesAreNewer($cert['domain'], $cert['expirationdate'])) {
|
if (self::checkFsFilesAreNewer($cert['domain'], $cert['validtodate'])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -453,7 +472,7 @@ EOC;
|
|||||||
// Only issue let's encrypt certificate if no broken ssl_redirect is enabled
|
// Only issue let's encrypt certificate if no broken ssl_redirect is enabled
|
||||||
if ($certrow['ssl_redirect'] != 2) {
|
if ($certrow['ssl_redirect'] != 2) {
|
||||||
$do_force = false;
|
$do_force = false;
|
||||||
if (!empty($certrow['ssl_cert_file']) && empty($certrow['expirationdate'])) {
|
if (!empty($certrow['ssl_cert_file']) && empty($certrow['validtodate'])) {
|
||||||
// domain changed (SAN or similar)
|
// domain changed (SAN or similar)
|
||||||
$do_force = true;
|
$do_force = true;
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']);
|
||||||
@@ -594,7 +613,9 @@ EOC;
|
|||||||
'chain' => $return['chain'],
|
'chain' => $return['chain'],
|
||||||
'csr' => $return['csr'],
|
'csr' => $return['csr'],
|
||||||
'fullchain' => $return['fullchain'],
|
'fullchain' => $return['fullchain'],
|
||||||
'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t'])
|
'validfromdate' => date('Y-m-d H:i:s', $newcert['validFrom_time_t']),
|
||||||
|
'validtodate' => date('Y-m-d H:i:s', $newcert['validTo_time_t']),
|
||||||
|
'issuer' => $newcert['issuer']['O'] ?? ""
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($certrow['ssl_redirect'] == 3) {
|
if ($certrow['ssl_redirect'] == 3) {
|
||||||
@@ -621,35 +642,21 @@ EOC;
|
|||||||
*/
|
*/
|
||||||
private static function readCertificateToVar($domain, &$return, &$cronlog)
|
private static function readCertificateToVar($domain, &$return, &$cronlog)
|
||||||
{
|
{
|
||||||
$certificate_folder = self::getWorkingDirFromEnv($domain);
|
$certificate_folder = self::getCertificateFolder($domain);
|
||||||
$certificate_folder_noecc = null;
|
|
||||||
if (Settings::Get('system.leecc') > 0) {
|
|
||||||
$certificate_folder_noecc = self::getWorkingDirFromEnv($domain, true);
|
|
||||||
}
|
|
||||||
$certificate_folder = FileDir::makeCorrectDir($certificate_folder);
|
|
||||||
|
|
||||||
if (is_dir($certificate_folder) || is_dir($certificate_folder_noecc)) {
|
if (!empty($certificate_folder)) {
|
||||||
foreach (
|
$certificate_files = [
|
||||||
[
|
'crt' => $domain . '.cer',
|
||||||
'crt' => $domain . '.cer',
|
'key' => $domain . '.key',
|
||||||
'key' => $domain . '.key',
|
'chain' => 'ca.cer',
|
||||||
'chain' => 'ca.cer',
|
'fullchain' => 'fullchain.cer',
|
||||||
'fullchain' => 'fullchain.cer',
|
'csr' => $domain . '.csr'
|
||||||
'csr' => $domain . '.csr'
|
];
|
||||||
] as $index => $sslfile
|
foreach ($certificate_files as $index => $sslfile) {
|
||||||
) {
|
|
||||||
$ssl_file = FileDir::makeCorrectFile($certificate_folder . '/' . $sslfile);
|
$ssl_file = FileDir::makeCorrectFile($certificate_folder . '/' . $sslfile);
|
||||||
if (file_exists($ssl_file)) {
|
if (file_exists($ssl_file)) {
|
||||||
$return[$index] = file_get_contents($ssl_file);
|
$return[$index] = file_get_contents($ssl_file);
|
||||||
} else {
|
} else {
|
||||||
if (!empty($certificate_folder_noecc)) {
|
|
||||||
$ssl_file_fb = FileDir::makeCorrectFile($certificate_folder_noecc . '/' . $sslfile);
|
|
||||||
if (file_exists($ssl_file_fb)) {
|
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "ECC certificates activated but found only non-ecc file");
|
|
||||||
$return[$index] = file_get_contents($ssl_file_fb);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find file '" . $sslfile . "' in '" . $certificate_folder . "'");
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find file '" . $sslfile . "' in '" . $certificate_folder . "'");
|
||||||
$return[$index] = null;
|
$return[$index] = null;
|
||||||
}
|
}
|
||||||
@@ -658,4 +665,18 @@ EOC;
|
|||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find certificate-folder '" . $certificate_folder . "'");
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find certificate-folder '" . $certificate_folder . "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function getCertificateFolder(string $domain): string
|
||||||
|
{
|
||||||
|
$certificate_folder = self::getWorkingDirFromEnv(strtolower($domain));
|
||||||
|
if (file_exists($certificate_folder)) {
|
||||||
|
return $certificate_folder;
|
||||||
|
}
|
||||||
|
$certificate_folder_ecc = self::getWorkingDirFromEnv($domain, true);
|
||||||
|
if (file_exists($certificate_folder_ecc)) {
|
||||||
|
return $certificate_folder_ecc;
|
||||||
|
}
|
||||||
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not find certificate-folder for domain '" . $domain . "'");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ class Nginx extends HttpConfigBase
|
|||||||
$this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n";
|
$this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n";
|
||||||
|
|
||||||
// protect bin/
|
// protect bin/
|
||||||
$this->nginx_data[$vhost_filename] .= "\t" . 'location ~ ' . rtrim($relpath, "/") . '/(bin|cache|logs|tests|vendor) {' . "\n";
|
$this->nginx_data[$vhost_filename] .= "\t" . 'location ~ ^' . rtrim($relpath, "/") . '/(bin|cache|logs|tests|vendor) {' . "\n";
|
||||||
$this->nginx_data[$vhost_filename] .= "\t" . ' deny all;' . "\n";
|
$this->nginx_data[$vhost_filename] .= "\t" . ' deny all;' . "\n";
|
||||||
$this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n";
|
$this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n";
|
||||||
}
|
}
|
||||||
@@ -883,13 +883,7 @@ class Nginx extends HttpConfigBase
|
|||||||
// remove comments
|
// remove comments
|
||||||
$vhost = implode("\n", preg_replace('/^(\s+)?#(.*)$/', '', explode("\n", $vhost)));
|
$vhost = implode("\n", preg_replace('/^(\s+)?#(.*)$/', '', explode("\n", $vhost)));
|
||||||
// Break blocks into lines
|
// Break blocks into lines
|
||||||
$vhost = str_replace([
|
$vhost = preg_replace("/^(\s+)?location(.+)\{(.+)\}$/misU", "location $2 {\n $3 \n}", $vhost);
|
||||||
"{",
|
|
||||||
"}"
|
|
||||||
], [
|
|
||||||
" {\n",
|
|
||||||
"\n}"
|
|
||||||
], $vhost);
|
|
||||||
// Break into array items
|
// Break into array items
|
||||||
$vhost = explode("\n", preg_replace('/[ \t]+/', ' ', trim(preg_replace('/\t+/', '', $vhost))));
|
$vhost = explode("\n", preg_replace('/[ \t]+/', ' ', trim(preg_replace('/\t+/', '', $vhost))));
|
||||||
// Remove empty lines
|
// Remove empty lines
|
||||||
@@ -1040,6 +1034,11 @@ class Nginx extends HttpConfigBase
|
|||||||
$path_options .= "\t\t" . 'auth_basic_user_file ' . FileDir::makeCorrectFile($single['usrf']) . ';' . "\n";
|
$path_options .= "\t\t" . 'auth_basic_user_file ' . FileDir::makeCorrectFile($single['usrf']) . ';' . "\n";
|
||||||
if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') {
|
if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') {
|
||||||
$path_options .= "\t\t" . 'index index.php index.html index.htm;' . "\n";
|
$path_options .= "\t\t" . 'index index.php index.html index.htm;' . "\n";
|
||||||
|
if ($domain['notryfiles'] != 1) {
|
||||||
|
$path_options .= "\t\t" . 'location ~ ^(.+?\.php)(/.*)?$ {' . "\n";
|
||||||
|
$path_options .= "\t\t\t" . 'try_files ' . $domain['nonexistinguri'] . ' @php;' . "\n";
|
||||||
|
$path_options .= "\t\t" . '}' . "\n\n";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$path_options .= "\t\t" . 'index index.html index.htm;' . "\n";
|
$path_options .= "\t\t" . 'index index.html index.htm;' . "\n";
|
||||||
}
|
}
|
||||||
@@ -1166,7 +1165,6 @@ class Nginx extends HttpConfigBase
|
|||||||
$phpopts .= "\t\tinclude " . Settings::Get('nginx.fastcgiparams') . ";\n";
|
$phpopts .= "\t\tinclude " . Settings::Get('nginx.fastcgiparams') . ";\n";
|
||||||
$phpopts .= "\t\tfastcgi_param SCRIPT_FILENAME \$request_filename;\n";
|
$phpopts .= "\t\tfastcgi_param SCRIPT_FILENAME \$request_filename;\n";
|
||||||
$phpopts .= "\t\tfastcgi_param PATH_INFO \$fastcgi_path_info;\n";
|
$phpopts .= "\t\tfastcgi_param PATH_INFO \$fastcgi_path_info;\n";
|
||||||
$phpopts .= "\t\ttry_files \$fastcgi_script_name =404;\n";
|
|
||||||
$phpopts .= "\t\tfastcgi_pass " . Settings::Get('system.nginx_php_backend') . ";\n";
|
$phpopts .= "\t\tfastcgi_pass " . Settings::Get('system.nginx_php_backend') . ";\n";
|
||||||
$phpopts .= "\t\tfastcgi_index index.php;\n";
|
$phpopts .= "\t\tfastcgi_index index.php;\n";
|
||||||
if ($domain['ssl'] == '1' && $ssl_vhost) {
|
if ($domain['ssl'] == '1' && $ssl_vhost) {
|
||||||
|
|||||||
@@ -342,8 +342,17 @@ pm.max_children = 1
|
|||||||
public function getSocketFile($createifnotexists = true)
|
public function getSocketFile($createifnotexists = true)
|
||||||
{
|
{
|
||||||
$socketdir = FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir'));
|
$socketdir = FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir'));
|
||||||
// add fpm-config-id to filename so it's unique for the fpm-daemon and doesn't interfere with running configs when reuilding
|
// add fpm-config-id to filename, so it's unique for the fpm-daemon and doesn't interfere with running configs when reuilding
|
||||||
$socket = strtolower(FileDir::makeCorrectFile($socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['loginname'] . '-' . $this->domain['domain'] . '-php-fpm.socket'));
|
$socket_filename = $socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['loginname'] . '-' . $this->domain['domain'] . '-php-fpm.socket';
|
||||||
|
if (strlen($socket_filename) > 100) {
|
||||||
|
// respect the unix socket-length limitation
|
||||||
|
$socket_filename = $socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['loginname'] . '-' . $this->domain['id'] . '-php-fpm.socket';
|
||||||
|
if (strlen($socket_filename) > 100) {
|
||||||
|
// even a long loginname it seems
|
||||||
|
$socket_filename = $socketdir . '/' . $this->domain['fpm_config_id'] . '-' . $this->domain['guid'] . '-' . $this->domain['id'] . '-php-fpm.socket';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$socket = strtolower(FileDir::makeCorrectFile($socket_filename));
|
||||||
|
|
||||||
if (!is_dir($socketdir) && $createifnotexists) {
|
if (!is_dir($socketdir) && $createifnotexists) {
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg($socketdir));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($socketdir));
|
||||||
|
|||||||
@@ -25,10 +25,10 @@
|
|||||||
|
|
||||||
namespace Froxlor;
|
namespace Froxlor;
|
||||||
|
|
||||||
use Froxlor\Database\Database;
|
|
||||||
use Froxlor\UI\Collection;
|
|
||||||
use Froxlor\Api\Commands\Customers;
|
use Froxlor\Api\Commands\Customers;
|
||||||
use Froxlor\Api\Commands\SubDomains;
|
use Froxlor\Api\Commands\SubDomains;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\UI\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to manage the current user / session
|
* Class to manage the current user / session
|
||||||
@@ -151,9 +151,13 @@ class CurrentUser
|
|||||||
]);
|
]);
|
||||||
$addition = $result['emaildomains'] != 0;
|
$addition = $result['emaildomains'] != 0;
|
||||||
} elseif ($resource == 'subdomains') {
|
} elseif ($resource == 'subdomains') {
|
||||||
$parentDomainCollection = (new Collection(SubDomains::class, $_SESSION['userinfo'],
|
if (Settings::IsInList('panel.customer_hide_options', 'domains')) {
|
||||||
['sql_search' => ['d.parentdomainid' => 0]]));
|
$addition = false;
|
||||||
$addition = $parentDomainCollection != 0;
|
} else {
|
||||||
|
$parentDomainCollection = (new Collection(SubDomains::class, $_SESSION['userinfo'],
|
||||||
|
['sql_search' => ['d.parentdomainid' => 0]]));
|
||||||
|
$addition = $parentDomainCollection->count() != 0;
|
||||||
|
}
|
||||||
} elseif ($resource == 'domains') {
|
} elseif ($resource == 'domains') {
|
||||||
$customerCollection = (new Collection(Customers::class, $_SESSION['userinfo']));
|
$customerCollection = (new Collection(Customers::class, $_SESSION['userinfo']));
|
||||||
$addition = $customerCollection != 0;
|
$addition = $customerCollection != 0;
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
* @author Froxlor team <team@froxlor.org>
|
* @author Froxlor team <team@froxlor.org>
|
||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Froxlor\Dns;
|
namespace Froxlor\Dns;
|
||||||
|
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
@@ -183,7 +182,10 @@ class Dns
|
|||||||
}
|
}
|
||||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||||
// check for DKIM content later
|
// check for DKIM content later
|
||||||
self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey.' . $sub_record, 'TXT', $required_entries);
|
//self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey.' . $sub_record, 'TXT', $required_entries);
|
||||||
|
self::addRequiredEntry('mx._domainkey.' . $sub_record, 'TXT', $required_entries);
|
||||||
|
//Also add dmarc
|
||||||
|
self::addRequiredEntry('_dmarc' . $sub_record, 'TXT', $required_entries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,7 +222,10 @@ class Dns
|
|||||||
}
|
}
|
||||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||||
// check for DKIM content later
|
// check for DKIM content later
|
||||||
self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey', 'TXT', $required_entries);
|
//self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey', 'TXT', $required_entries);
|
||||||
|
self::addRequiredEntry('mx._domainkey', 'TXT', $required_entries);
|
||||||
|
//Also add dmarc
|
||||||
|
self::addRequiredEntry('_dmarc', 'TXT', $required_entries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,8 +284,7 @@ class Dns
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$zonerecords[] = new DnsEntry($entry['record'], $entry['type'], $entry['content'], $entry['prio'],
|
$zonerecords[] = new DnsEntry($entry['record'], $entry['type'], $entry['content'], $entry['prio'] ?? 0, $entry['ttl']);
|
||||||
$entry['ttl']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add missing required entries
|
// add missing required entries
|
||||||
@@ -379,10 +383,13 @@ class Dns
|
|||||||
if (array_key_exists("TXT", $required_entries)) {
|
if (array_key_exists("TXT", $required_entries)) {
|
||||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||||
$dkim_entries = self::generateDkimEntries($domain);
|
$dkim_entries = self::generateDkimEntries($domain);
|
||||||
|
$dmarc_entries = self::generateDmarcEntries($domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($required_entries as $type => $records) {
|
foreach ($required_entries as $type => $records) {
|
||||||
if ($type == 'TXT') {
|
if ($type == 'TXT') {
|
||||||
|
//$dkim_record = 'dkim' . $domain['dkim_id'] . '._domainkey';
|
||||||
|
$dkim_record = 'mx._domainkey';
|
||||||
foreach ($records as $record) {
|
foreach ($records as $record) {
|
||||||
if ($record == '@SPF@') {
|
if ($record == '@SPF@') {
|
||||||
// spf for main-domain
|
// spf for main-domain
|
||||||
@@ -393,9 +400,8 @@ class Dns
|
|||||||
$txt_content = Settings::Get('spf.spf_entry');
|
$txt_content = Settings::Get('spf.spf_entry');
|
||||||
$sub_record = substr($record, 6);
|
$sub_record = substr($record, 6);
|
||||||
$zonerecords[] = new DnsEntry($sub_record, 'TXT', self::encloseTXTContent($txt_content));
|
$zonerecords[] = new DnsEntry($sub_record, 'TXT', self::encloseTXTContent($txt_content));
|
||||||
} elseif (!empty($dkim_entries)) {
|
} elseif (!empty($dkim_entries) && $record == $dkim_record ) {
|
||||||
// DKIM entries
|
// DKIM entries
|
||||||
$dkim_record = 'dkim' . $domain['dkim_id'] . '._domainkey';
|
|
||||||
if ($record == $dkim_record) {
|
if ($record == $dkim_record) {
|
||||||
// dkim for main-domain
|
// dkim for main-domain
|
||||||
// check for multiline entry
|
// check for multiline entry
|
||||||
@@ -413,7 +419,10 @@ class Dns
|
|||||||
}
|
}
|
||||||
$zonerecords[] = new DnsEntry($record, 'TXT', self::encloseTXTContent($dkim_entries[0], $multiline));
|
$zonerecords[] = new DnsEntry($record, 'TXT', self::encloseTXTContent($dkim_entries[0], $multiline));
|
||||||
}
|
}
|
||||||
|
} elseif ($record == '_dmarc' && !empty($dmarc_entries) && $domain['isemaildomain'] == '1') {
|
||||||
|
$zonerecords[] = new DnsEntry($record, 'TXT', self::encloseTXTContent($dmarc_entries[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -524,7 +533,7 @@ class Dns
|
|||||||
* @param array $domain
|
* @param array $domain
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private static function generateDkimEntries(array $domain): array
|
/** private static function generateDkimEntries(array $domain): array
|
||||||
{
|
{
|
||||||
$zone_dkim = [];
|
$zone_dkim = [];
|
||||||
|
|
||||||
@@ -570,43 +579,61 @@ class Dns
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $zone_dkim;
|
return $zone_dkim;
|
||||||
}
|
} */
|
||||||
|
private static function generateDkimEntries(array $domain): array
|
||||||
|
{
|
||||||
|
$zone_dkim = [];
|
||||||
|
if (Settings::Get('dkim.use_dkim') == '1' && $domain['dkim'] == '1' && $domain['dkim_pubkey'] != '') {
|
||||||
|
// start
|
||||||
|
$dkim_txt = 'v=DKIM1;k=rsa;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAosq0CmLqEzJJxIHkQwG1Xwk6CSyHHWSDXL9BHCKzY9lJXH7a23PogVlLvUBYaAgBtFOpsKuUCBl+/g6rOqgVXKg0OpYdpgTxZyz1i4NcubGFLifQGnF8ZKpIEDqIzmLI6SbH+9DKwYA319sXAR6feZI4g5bWqF07t/kzA5LN+2V5QnDQ3th++GPRl5rmWF6uoidIRD85UZVEX4s3J1hce0k6tRb2aEozCJaSXHUwyarmbbX/5rky467QQ+45Uy0q9CNaMMu1IX5eybhLRxYXK1k0TfIRJv4FH1UFLlq2QoGC7d+KvLrUabhzQ5wbdZkWuVgLFZ7CL2NegfzO6YeEcQIDAQAB';
|
||||||
|
$zone_dkim[] = $dkim_txt;
|
||||||
|
}
|
||||||
|
return $zone_dkim;
|
||||||
|
}
|
||||||
|
private static function generateDmarcEntries(array $domain): array
|
||||||
|
{
|
||||||
|
$zone_dmarc = [];
|
||||||
|
if (Settings::Get('dkim.use_dkim') == '1' && $domain['dkim'] == '1' ){
|
||||||
|
$dmarc_txt = 'v=DMARC1; p=reject; ruf=mailto:dmarc@'. $domain['domain'] . '; rua=mailto:dmarc@'. $domain['domain'] . '; fo=1; adkim=r; aspf=r; pct=100; rf=afrf; ri=345600;';
|
||||||
|
$zone_dmarc[] = $dmarc_txt;
|
||||||
|
}
|
||||||
|
return $zone_dmarc;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @param string $txt_content
|
* @param string $txt_content
|
||||||
* @param bool $isMultiLine
|
* @param bool $isMultiLine
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function encloseTXTContent(string $txt_content, bool $isMultiLine = false): string
|
public static function encloseTXTContent(string $txt_content, bool $isMultiLine = false): string
|
||||||
{
|
{
|
||||||
// check that TXT content is enclosed in " "
|
// check that TXT content is enclosed in " "
|
||||||
if (!$isMultiLine && Settings::Get('system.dns_server') != 'PowerDNS') {
|
if (! $isMultiLine && Settings::Get('system.dns_server') != 'PowerDNS') {
|
||||||
if (substr($txt_content, 0, 1) != '"') {
|
if (substr($txt_content, 0, 1) != '"') {
|
||||||
$txt_content = '"' . $txt_content;
|
$txt_content = '"' . $txt_content;
|
||||||
}
|
}
|
||||||
if (substr($txt_content, -1) != '"') {
|
if (substr($txt_content, - 1) != '"') {
|
||||||
$txt_content .= '"';
|
$txt_content .= '"';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Settings::Get('system.dns_server') == 'PowerDNS') {
|
if (Settings::Get('system.dns_server') == 'PowerDNS') {
|
||||||
// no quotation for PowerDNS
|
// no quotation for PowerDNS
|
||||||
if (substr($txt_content, 0, 1) == '"') {
|
if (substr($txt_content, 0, 1) == '"') {
|
||||||
$txt_content = substr($txt_content, 1);
|
$txt_content = substr($txt_content, 1);
|
||||||
}
|
}
|
||||||
if (substr($txt_content, -1) == '"') {
|
if (substr($txt_content, - 1) == '"') {
|
||||||
$txt_content = substr($txt_content, 0, -1);
|
$txt_content = substr($txt_content, 0, - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $txt_content;
|
return $txt_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $email
|
* @param string $email
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private static function escapeSoaAdminMail(string $email): string
|
private static function escapeSoaAdminMail(string $email): string
|
||||||
{
|
{
|
||||||
$mail_parts = explode("@", $email);
|
$mail_parts = explode("@", $email);
|
||||||
return str_replace(".", "\.", $mail_parts[0]) . "." . $mail_parts[1] . ".";
|
return str_replace(".", "\.", $mail_parts[0]) . "." . $mail_parts[1] . ".";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,18 +37,18 @@ class PowerDNS
|
|||||||
/**
|
/**
|
||||||
* remove all records and entries of a given domain
|
* remove all records and entries of a given domain
|
||||||
*
|
*
|
||||||
* @param array|null $domain
|
* @param string|null $domain
|
||||||
*/
|
*/
|
||||||
public static function cleanDomainZone(array $domain = null)
|
public static function cleanDomainZone(string $domain = null)
|
||||||
{
|
{
|
||||||
if (is_array($domain) && isset($domain['domain'])) {
|
if (!empty($domain)) {
|
||||||
$pdns_domains_stmt = self::getDB()->prepare("SELECT `id`, `name` FROM `domains` WHERE `name` = :domain");
|
$pdns_domains_stmt = self::getDB()->prepare("SELECT `id`, `name` FROM `domains` WHERE `name` = :domain");
|
||||||
$del_rec_stmt = self::getDB()->prepare("DELETE FROM `records` WHERE `domain_id` = :did");
|
$del_rec_stmt = self::getDB()->prepare("DELETE FROM `records` WHERE `domain_id` = :did");
|
||||||
$del_meta_stmt = self::getDB()->prepare("DELETE FROM `domainmetadata` WHERE `domain_id` = :did");
|
$del_meta_stmt = self::getDB()->prepare("DELETE FROM `domainmetadata` WHERE `domain_id` = :did");
|
||||||
$del_dom_stmt = self::getDB()->prepare("DELETE FROM `domains` WHERE `id` = :did");
|
$del_dom_stmt = self::getDB()->prepare("DELETE FROM `domains` WHERE `id` = :did");
|
||||||
|
|
||||||
$pdns_domains_stmt->execute([
|
$pdns_domains_stmt->execute([
|
||||||
'domain' => $domain['domain']
|
'domain' => $domain
|
||||||
]);
|
]);
|
||||||
$pdns_domain = $pdns_domains_stmt->fetch(PDO::FETCH_ASSOC);
|
$pdns_domain = $pdns_domains_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ class Domain
|
|||||||
$upd_stmt = Database::prepare("UPDATE
|
$upd_stmt = Database::prepare("UPDATE
|
||||||
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
||||||
SET
|
SET
|
||||||
`expirationdate` = null
|
`validtodate` = null
|
||||||
WHERE
|
WHERE
|
||||||
domainid = :domainid
|
domainid = :domainid
|
||||||
");
|
");
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ class IpAddr
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function getSslIpPortCombinations(): array
|
public static function getSslIpPortCombinations(): array
|
||||||
{
|
{
|
||||||
@@ -75,7 +76,7 @@ class IpAddr
|
|||||||
$additional_conditions_params = [];
|
$additional_conditions_params = [];
|
||||||
$additional_conditions_array = [];
|
$additional_conditions_array = [];
|
||||||
|
|
||||||
if ($userinfo['ip'] != '-1') {
|
if (!empty($userinfo) && $userinfo['ip'] != '-1') {
|
||||||
$admin_ip_stmt = Database::prepare("
|
$admin_ip_stmt = Database::prepare("
|
||||||
SELECT `id`, `ip`, `port` FROM `" . TABLE_PANEL_IPSANDPORTS . "` WHERE `id` = IN (:ipid)
|
SELECT `id`, `ip`, `port` FROM `" . TABLE_PANEL_IPSANDPORTS . "` WHERE `id` = IN (:ipid)
|
||||||
");
|
");
|
||||||
|
|||||||
@@ -447,7 +447,8 @@ class FileDir
|
|||||||
$field = [
|
$field = [
|
||||||
'type' => 'select',
|
'type' => 'select',
|
||||||
'select_var' => $_field,
|
'select_var' => $_field,
|
||||||
'selected' => $value
|
'selected' => $value,
|
||||||
|
'value' => $value
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
$field = [
|
$field = [
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ final class Froxlor
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Main version variable
|
// Main version variable
|
||||||
const VERSION = '2.0.13';
|
const VERSION = '2.0.24';
|
||||||
|
|
||||||
// Database version (YYYYMMDDC where C is a daily counter)
|
// Database version (YYYYMMDDC where C is a daily counter)
|
||||||
const DBVERSION = '202302030';
|
const DBVERSION = '202304260';
|
||||||
|
|
||||||
// Distribution branding-tag (used for Debian etc.)
|
// Distribution branding-tag (used for Debian etc.)
|
||||||
const BRANDING = '';
|
const BRANDING = '';
|
||||||
|
|||||||
55
lib/Froxlor/Http/RateLimiter.php
Normal file
55
lib/Froxlor/Http/RateLimiter.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Http;
|
||||||
|
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
use Froxlor\UI\Panel\UI;
|
||||||
|
|
||||||
|
class RateLimiter
|
||||||
|
{
|
||||||
|
private static int $limit_per_interval = 60;
|
||||||
|
private static int $reset_time = 0;
|
||||||
|
|
||||||
|
public static function run(bool $install_mode = false)
|
||||||
|
{
|
||||||
|
// default interval = 60 sec
|
||||||
|
self::$reset_time = time() + 60;
|
||||||
|
|
||||||
|
if (!$install_mode) {
|
||||||
|
self::$limit_per_interval = Settings::Get('system.req_limit_per_interval') ?? 60;
|
||||||
|
self::$reset_time = time() + Settings::Get('system.req_limit_interval') ?? 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the remaining requests and reset time from the headers
|
||||||
|
$remaining = isset($_SESSION['HTTP_X_RATELIMIT_REMAINING']) ? (int)$_SESSION['HTTP_X_RATELIMIT_REMAINING'] : self::$limit_per_interval;
|
||||||
|
$reset = isset($_SESSION['HTTP_X_RATELIMIT_RESET']) ? (int)$_SESSION['HTTP_X_RATELIMIT_RESET'] : self::$reset_time;
|
||||||
|
|
||||||
|
// check if reset time is due
|
||||||
|
if (time() > $reset) {
|
||||||
|
$remaining = self::$limit_per_interval;
|
||||||
|
$reset = self::$reset_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've hit the limit, return an error
|
||||||
|
if ($remaining <= 0) {
|
||||||
|
header('HTTP/1.1 429 Too Many Requests');
|
||||||
|
header("Retry-After: $reset");
|
||||||
|
UI::twig()->addGlobal('install_mode', '1');
|
||||||
|
echo UI::twig()->render('Froxlor/misc/ratelimithint.html.twig', [
|
||||||
|
'retry' => $reset,
|
||||||
|
'installdir' => Froxlor::getInstallDir()
|
||||||
|
]);
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrement the remaining requests and update the headers
|
||||||
|
$remaining--;
|
||||||
|
$_SESSION['HTTP_X_RATELIMIT_REMAINING'] = $remaining;
|
||||||
|
$_SESSION['HTTP_X_RATELIMIT_RESET'] = $reset;
|
||||||
|
|
||||||
|
header("X-RateLimit-Limit: " . self::$limit_per_interval);
|
||||||
|
header("X-RateLimit-Remaining: " . $remaining);
|
||||||
|
header("X-RateLimit-Reset: " . $reset);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ class Install
|
|||||||
public $phpVersion;
|
public $phpVersion;
|
||||||
public $formfield;
|
public $formfield;
|
||||||
public string $requiredVersion = '7.4.0';
|
public string $requiredVersion = '7.4.0';
|
||||||
public array $requiredExtensions = ['session', 'ctype', 'xml', 'filter', 'posix', 'mbstring', 'curl', 'gmp', 'json'];
|
public array $requiredExtensions = ['session', 'ctype', 'xml', 'filter', 'posix', 'mbstring', 'curl', 'gmp', 'json', 'gd'];
|
||||||
public array $suggestedExtensions = ['bcmath', 'zip'];
|
public array $suggestedExtensions = ['bcmath', 'zip'];
|
||||||
public array $suggestions = [];
|
public array $suggestions = [];
|
||||||
public array $criticals = [];
|
public array $criticals = [];
|
||||||
|
|||||||
@@ -448,7 +448,11 @@ class Core
|
|||||||
$reload = "service php" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "-fpm restart";
|
$reload = "service php" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "-fpm restart";
|
||||||
$config_dir = "/etc/php/" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "/fpm/pool.d/";
|
$config_dir = "/etc/php/" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "/fpm/pool.d/";
|
||||||
// fcgid
|
// fcgid
|
||||||
$binary = "/usr/bin/php" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "-cgi";
|
if ($this->validatedData['distribution'] == 'bookworm') {
|
||||||
|
$binary = "/usr/bin/php-cgi" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;
|
||||||
|
} else {
|
||||||
|
$binary = "/usr/bin/php" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "-cgi";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$db_user->query("UPDATE `" . TABLE_PANEL_FPMDAEMONS . "` SET `reload_cmd` = '" . $reload . "', `config_dir` = '" . $config_dir . "' WHERE `id` ='1';");
|
$db_user->query("UPDATE `" . TABLE_PANEL_FPMDAEMONS . "` SET `reload_cmd` = '" . $reload . "', `config_dir` = '" . $config_dir . "' WHERE `id` ='1';");
|
||||||
$db_user->query("UPDATE `" . TABLE_PANEL_PHPCONFIGS . "` SET `binary` = '" . $binary . "';");
|
$db_user->query("UPDATE `" . TABLE_PANEL_PHPCONFIGS . "` SET `binary` = '" . $binary . "';");
|
||||||
|
|||||||
@@ -68,10 +68,10 @@ class MailLogParser
|
|||||||
// Parse MDA traffic
|
// Parse MDA traffic
|
||||||
if (Settings::Get("system.mdaserver") == "dovecot") {
|
if (Settings::Get("system.mdaserver") == "dovecot") {
|
||||||
$this->parseDovecotLog(Settings::Get("system.mdalog"));
|
$this->parseDovecotLog(Settings::Get("system.mdalog"));
|
||||||
$this->parsePostfixLog(Settings::Get("system.mdalog") . ".1");
|
$this->parseDovecotLog(Settings::Get("system.mdalog") . ".1");
|
||||||
} elseif (Settings::Get("system.mdaserver") == "courier") {
|
} elseif (Settings::Get("system.mdaserver") == "courier") {
|
||||||
$this->parseCourierLog(Settings::Get("system.mdalog"));
|
$this->parseCourierLog(Settings::Get("system.mdalog"));
|
||||||
$this->parsePostfixLog(Settings::Get("system.mdalog") . ".1");
|
$this->parseCourierLog(Settings::Get("system.mdalog") . ".1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ class PhpHelper
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function sizeReadable(
|
public static function sizeReadable(
|
||||||
int $size,
|
$size,
|
||||||
?string $max = '',
|
?string $max = '',
|
||||||
string $system = 'si',
|
string $system = 'si',
|
||||||
string $retstring = '%01.2f %s'
|
string $retstring = '%01.2f %s'
|
||||||
@@ -449,7 +449,15 @@ class PhpHelper
|
|||||||
'ssl_specialsettings',
|
'ssl_specialsettings',
|
||||||
'default_vhostconf_domain',
|
'default_vhostconf_domain',
|
||||||
'ssl_default_vhostconf_domain',
|
'ssl_default_vhostconf_domain',
|
||||||
'filecontent'
|
'filecontent',
|
||||||
|
'admin_password',
|
||||||
|
'password',
|
||||||
|
'new_customer_password',
|
||||||
|
'privileged_password',
|
||||||
|
'email_password',
|
||||||
|
'directory_password',
|
||||||
|
'ftp_password',
|
||||||
|
'mysql_password',
|
||||||
];
|
];
|
||||||
if (!empty($global)) {
|
if (!empty($global)) {
|
||||||
$tmp = $global;
|
$tmp = $global;
|
||||||
@@ -519,7 +527,12 @@ class PhpHelper
|
|||||||
} elseif (is_int($value)) {
|
} elseif (is_int($value)) {
|
||||||
$str .= self::tabPrefix($depth, "'{$key}' => $value,\n");
|
$str .= self::tabPrefix($depth, "'{$key}' => $value,\n");
|
||||||
} else {
|
} else {
|
||||||
$str .= self::tabPrefix($depth, "'{$key}' => '{$value}',\n");
|
if ($key == 'password') {
|
||||||
|
// special case for passwords (nowdoc)
|
||||||
|
$str .= self::tabPrefix($depth, "'{$key}' => <<<'EOT'\n{$value}\nEOT,\n");
|
||||||
|
} else {
|
||||||
|
$str .= self::tabPrefix($depth, "'{$key}' => '{$value}',\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$str .= self::parseArrayToString($value, $key, ($depth + 1));
|
$str .= self::parseArrayToString($value, $key, ($depth + 1));
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace Froxlor;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\UI\Form;
|
use Froxlor\UI\Form;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
use PDO;
|
use PDO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -159,6 +160,9 @@ class SImExporter
|
|||||||
// re-format the array-key for Form::processForm
|
// re-format the array-key for Form::processForm
|
||||||
foreach ($_data as $key => $value) {
|
foreach ($_data as $key => $value) {
|
||||||
$index_split = explode('.', $key, 3);
|
$index_split = explode('.', $key, 3);
|
||||||
|
if (!isset($current_settings[$index_split[0]][$index_split[1]])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (isset($index_split[2]) && $index_split[2] === 'image_data' && !empty($_data[$index_split[0] . '.' . $index_split[1]])) {
|
if (isset($index_split[2]) && $index_split[2] === 'image_data' && !empty($_data[$index_split[0] . '.' . $index_split[1]])) {
|
||||||
$image_data[$key] = $value;
|
$image_data[$key] = $value;
|
||||||
} else {
|
} else {
|
||||||
@@ -190,42 +194,27 @@ class SImExporter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$img_data = base64_decode($value);
|
if (Validate::validateBase64Image($value)) {
|
||||||
$img_filename = Froxlor::getInstallDir() . '/' . str_replace('../', '',
|
$img_data = base64_decode($value);
|
||||||
explode('?', $_data[$index_split[0] . '.' . $index_split[1]], 2)[0]);
|
$img_filename = explode('?', $_data[$index_split[0] . '.' . $index_split[1]], 2)[0];
|
||||||
|
|
||||||
file_put_contents($img_filename, $img_data);
|
$spl = explode('.', $img_filename);
|
||||||
|
$file_extension = strtolower(array_pop($spl));
|
||||||
|
unset($spl);
|
||||||
|
|
||||||
if (function_exists('finfo_open')) {
|
if (!in_array($file_extension, [
|
||||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
'jpeg',
|
||||||
$mimetype = finfo_file($finfo, $img_filename);
|
'jpg',
|
||||||
finfo_close($finfo);
|
'png',
|
||||||
} else {
|
'gif'
|
||||||
$mimetype = mime_content_type($img_filename);
|
])) {
|
||||||
|
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
|
||||||
|
}
|
||||||
|
$img_filename = 'img/' . bin2hex(random_bytes(16)) . '.' . $file_extension;
|
||||||
|
file_put_contents(Froxlor::getInstallDir() . '/' . $img_filename, $img_data);
|
||||||
|
$img_index = $index_split[0].'.'.$index_split[1];
|
||||||
|
Settings::Set($img_index, $img_filename . '?v=' . time());
|
||||||
}
|
}
|
||||||
if (empty($mimetype)) {
|
|
||||||
$mimetype = 'application/octet-stream';
|
|
||||||
}
|
|
||||||
if (!in_array($mimetype, ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'])) {
|
|
||||||
@unlink($img_filename);
|
|
||||||
throw new Exception("Uploaded file is not a valid image");
|
|
||||||
}
|
|
||||||
|
|
||||||
$spl = explode('.', $img_filename);
|
|
||||||
$file_extension = strtolower(array_pop($spl));
|
|
||||||
unset($spl);
|
|
||||||
|
|
||||||
if (!in_array($file_extension, [
|
|
||||||
'jpeg',
|
|
||||||
'jpg',
|
|
||||||
'png',
|
|
||||||
'gif'
|
|
||||||
])) {
|
|
||||||
@unlink($img_filename);
|
|
||||||
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::Set($index, $value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// all good
|
// all good
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ use Froxlor\PhpHelper;
|
|||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\IPTools;
|
use Froxlor\System\IPTools;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
use PDO;
|
use PDO;
|
||||||
|
|
||||||
class Store
|
class Store
|
||||||
@@ -45,10 +46,21 @@ class Store
|
|||||||
{
|
{
|
||||||
$returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue);
|
$returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue);
|
||||||
|
|
||||||
if ($returnvalue !== false && is_array($fielddata) && isset($fielddata['settinggroup']) && $fielddata['settinggroup'] == 'system' && isset($fielddata['varname']) && $fielddata['varname'] == 'le_froxlor_enabled' && $newfieldvalue == '0') {
|
if ($returnvalue !== false
|
||||||
Database::query("
|
&& is_array($fielddata)
|
||||||
DELETE FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = '0'
|
&& isset($fielddata['settinggroup'])
|
||||||
");
|
&& $fielddata['settinggroup'] == 'system'
|
||||||
|
&& isset($fielddata['varname'])
|
||||||
|
) {
|
||||||
|
if ($fielddata['varname'] == 'le_froxlor_enabled' && $newfieldvalue == '0') {
|
||||||
|
Database::query("
|
||||||
|
DELETE FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = '0'
|
||||||
|
");
|
||||||
|
} elseif ($fielddata['varname'] == 'froxloraliases' && $newfieldvalue != $fielddata['value']) {
|
||||||
|
Database::query("
|
||||||
|
UPDATE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` SET `validtodate`= NULL WHERE `domainid` = '0'
|
||||||
|
");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $returnvalue;
|
return $returnvalue;
|
||||||
@@ -415,40 +427,30 @@ class Store
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure mime-type matches an image
|
// Make sure mime-type matches an image
|
||||||
if (function_exists('finfo_open')) {
|
$image_content = file_get_contents($_FILES[$fieldname]['tmp_name']);
|
||||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
$value = base64_encode($image_content);
|
||||||
$mimetype = finfo_file($finfo, $_FILES[$fieldname]['tmp_name']);
|
if (Validate::validateBase64Image($value)) {
|
||||||
finfo_close($finfo);
|
$img_filename = $_FILES[$fieldname]['name'];
|
||||||
} else {
|
|
||||||
$mimetype = mime_content_type($_FILES[$fieldname]['tmp_name']);
|
|
||||||
}
|
|
||||||
if (empty($mimetype)) {
|
|
||||||
$mimetype = 'application/octet-stream';
|
|
||||||
}
|
|
||||||
if (!in_array($mimetype, ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'])) {
|
|
||||||
throw new \Exception("Uploaded file is not a valid image");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine file extension
|
$spl = explode('.', $img_filename);
|
||||||
$spl = explode('.', $_FILES[$fieldname]['name']);
|
$file_extension = strtolower(array_pop($spl));
|
||||||
$file_extension = strtolower(array_pop($spl));
|
unset($spl);
|
||||||
unset($spl);
|
|
||||||
|
|
||||||
if (!in_array($file_extension, [
|
if (!in_array($file_extension, [
|
||||||
'jpeg',
|
'jpeg',
|
||||||
'jpg',
|
'jpg',
|
||||||
'png',
|
'png',
|
||||||
'gif'
|
'gif'
|
||||||
])) {
|
])) {
|
||||||
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
|
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
|
||||||
|
}
|
||||||
|
$filename = bin2hex(random_bytes(16)) . '.' . $file_extension;
|
||||||
|
// Move file
|
||||||
|
if (!move_uploaded_file($_FILES[$fieldname]['tmp_name'], $path . $filename)) {
|
||||||
|
throw new Exception("Unable to save image to img folder");
|
||||||
|
}
|
||||||
|
$save_to = 'img/' . $filename . '?v=' . time();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move file
|
|
||||||
if (!move_uploaded_file($_FILES[$fieldname]['tmp_name'], $path . $fielddata['image_name'] . '.' . $file_extension)) {
|
|
||||||
throw new Exception("Unable to save image to img folder");
|
|
||||||
}
|
|
||||||
|
|
||||||
$save_to = 'img/' . $fielddata['image_name'] . '.' . $file_extension . '?v=' . time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete file?
|
// Delete file?
|
||||||
|
|||||||
@@ -87,26 +87,38 @@ class UI
|
|||||||
|
|
||||||
return $isHttps && (strcasecmp('on', $isHttps) == 0 || strcasecmp('https', $isHttps) == 0);
|
return $isHttps && (strcasecmp('on', $isHttps) == 0 || strcasecmp('https', $isHttps) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the cookie host from HTTP_HOST, stripping the port.
|
||||||
|
*/
|
||||||
|
public static function getCookieHost(): ?string
|
||||||
|
{
|
||||||
|
if (empty($_SERVER['HTTP_HOST']))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
$colonPosition = strrpos($_SERVER['HTTP_HOST'], ':');
|
||||||
|
// There's no port in the host
|
||||||
|
if ($colonPosition === false)
|
||||||
|
return $_SERVER['HTTP_HOST'];
|
||||||
|
|
||||||
|
$closingSquareBracketPosition = strrpos($_SERVER['HTTP_HOST'], ']');
|
||||||
|
// The host is an IPv4 address or hostname with port
|
||||||
|
if ($closingSquareBracketPosition === false)
|
||||||
|
return substr($_SERVER['HTTP_HOST'], 0, $colonPosition);
|
||||||
|
|
||||||
|
// The host is an IPv6 address with port
|
||||||
|
return substr($_SERVER['HTTP_HOST'], 0, $closingSquareBracketPosition + 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* send various security related headers
|
* send various security related headers
|
||||||
*/
|
*/
|
||||||
public static function sendHeaders()
|
public static function sendHeaders()
|
||||||
{
|
{
|
||||||
if (empty($_SERVER['HTTP_HOST'])) {
|
|
||||||
if (!self::$install_mode) {
|
|
||||||
// fallback to set hostname in settings
|
|
||||||
$_SERVER['HTTP_HOST'] = Settings::Get('system.hostname');
|
|
||||||
} else {
|
|
||||||
// bad request
|
|
||||||
http_response_code(400);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
session_set_cookie_params([
|
session_set_cookie_params([
|
||||||
'lifetime' => self::$install_mode ? 7200 : 600, // will be renewed based on settings in lib/init.php
|
'lifetime' => self::$install_mode ? 7200 : 600, // will be renewed based on settings in lib/init.php
|
||||||
'path' => '/',
|
'path' => '/',
|
||||||
'domain' => explode(':', $_SERVER['HTTP_HOST'])[0],
|
'domain' => self::getCookieHost(),
|
||||||
'secure' => self::requestIsHttps(),
|
'secure' => self::requestIsHttps(),
|
||||||
'httponly' => true,
|
'httponly' => true,
|
||||||
'samesite' => 'Strict'
|
'samesite' => 'Strict'
|
||||||
@@ -278,7 +290,8 @@ class UI
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function validateThemeTemplate(string $name, string $theme = "") {
|
public static function validateThemeTemplate(string $name, string $theme = "")
|
||||||
|
{
|
||||||
if (empty(trim($theme))) {
|
if (empty(trim($theme))) {
|
||||||
$theme = self::getTheme();
|
$theme = self::getTheme();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,16 +52,16 @@ class Check
|
|||||||
];
|
];
|
||||||
|
|
||||||
$check_array = [
|
$check_array = [
|
||||||
'system_mod_fcgid_enabled' => [
|
'system_mod_fcgid' => [
|
||||||
'other_post_field' => 'system_phpfpm_enabled',
|
'other_post_field' => 'phpfpm_enabled',
|
||||||
'other_enabled' => 'phpfpm.enabled',
|
'other_enabled' => 'phpfpm.enabled',
|
||||||
'other_enabled_lng' => 'phpfpmstillenabled',
|
'other_enabled_lng' => 'phpfpmstillenabled',
|
||||||
'deactivate' => [
|
'deactivate' => [
|
||||||
'phpfpm.enabled_ownvhost' => 0
|
'phpfpm.enabled_ownvhost' => 0
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_phpfpm_enabled' => [
|
'phpfpm_enabled' => [
|
||||||
'other_post_field' => 'system_mod_fcgid_enabled',
|
'other_post_field' => 'system_mod_fcgid',
|
||||||
'other_enabled' => 'system.mod_fcgid',
|
'other_enabled' => 'system.mod_fcgid',
|
||||||
'other_enabled_lng' => 'fcgidstillenabled',
|
'other_enabled_lng' => 'fcgidstillenabled',
|
||||||
'deactivate' => [
|
'deactivate' => [
|
||||||
@@ -291,7 +291,7 @@ class Check
|
|||||||
*/
|
*/
|
||||||
public static function checkLocalGroup($fieldname, $fielddata, $newfieldvalue, $allnewfieldvalues)
|
public static function checkLocalGroup($fieldname, $fielddata, $newfieldvalue, $allnewfieldvalues)
|
||||||
{
|
{
|
||||||
if (empty($newfieldvalue) || $fielddata == $newfieldvalue) {
|
if (empty($newfieldvalue) || $fielddata['value'] == $newfieldvalue) {
|
||||||
$returnvalue = [
|
$returnvalue = [
|
||||||
self::FORMFIELDS_PLAUSIBILITY_CHECK_OK
|
self::FORMFIELDS_PLAUSIBILITY_CHECK_OK
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ class Validate
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if an emailaddress is in correct format or not
|
* Returns if an email-address is in correct format or not
|
||||||
*
|
*
|
||||||
* @param string $email The email address to check
|
* @param string $email The email address to check
|
||||||
*
|
*
|
||||||
@@ -334,4 +334,40 @@ class Validate
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validates whether a given base64 string decodes to an image
|
||||||
|
*
|
||||||
|
* @param string $base64string
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function validateBase64Image(string $base64string) {
|
||||||
|
|
||||||
|
if (!extension_loaded('gd')) {
|
||||||
|
Response::standardError('phpgdextensionnotavailable', null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the base64 string
|
||||||
|
$data = base64_decode($base64string);
|
||||||
|
|
||||||
|
// Create an image from the decoded data
|
||||||
|
$image = @imagecreatefromstring($data);
|
||||||
|
|
||||||
|
// Check if the image was created successfully
|
||||||
|
if (!$image) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the MIME type of the image
|
||||||
|
$mime = image_type_to_mime_type(getimagesizefromstring($data)[2]);
|
||||||
|
|
||||||
|
// Check if the MIME type is a valid image MIME type
|
||||||
|
if (strpos($mime, 'image/') !== 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If everything is okay, return true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2600,7 +2600,6 @@ ServerName "<SERVERNAME> FTP Server"
|
|||||||
ServerType standalone
|
ServerType standalone
|
||||||
DeferWelcome off
|
DeferWelcome off
|
||||||
|
|
||||||
MultilineRFC2228 on
|
|
||||||
DefaultServer on
|
DefaultServer on
|
||||||
ShowSymlinks on
|
ShowSymlinks on
|
||||||
|
|
||||||
@@ -2939,7 +2938,6 @@ SQLNamedQuery get-quota-limit SELECT "ftp_users.username AS name, ftp_quotalimit
|
|||||||
SQLNamedQuery get-quota-tally SELECT "name, quota_type, bytes_in_used,bytes_out_used, bytes_xfer_used, files_in_used, files_out_used,files_xfer_used FROM ftp_quotatallies WHERE name = '%{0}' AND quota_type = '%{1}'"
|
SQLNamedQuery get-quota-tally SELECT "name, quota_type, bytes_in_used,bytes_out_used, bytes_xfer_used, files_in_used, files_out_used,files_xfer_used FROM ftp_quotatallies WHERE name = '%{0}' AND quota_type = '%{1}'"
|
||||||
SQLNamedQuery update-quota-tally UPDATE "bytes_in_used = bytes_in_used + %{0}, bytes_out_used = bytes_out_used + %{1}, bytes_xfer_used = bytes_xfer_used + %{2}, files_in_used = files_in_used + %{3}, files_out_used= files_out_used + %{4}, files_xfer_used = files_xfer_used + %{5} WHERE name= '%{6}' AND quota_type = '%{7}'" ftp_quotatallies
|
SQLNamedQuery update-quota-tally UPDATE "bytes_in_used = bytes_in_used + %{0}, bytes_out_used = bytes_out_used + %{1}, bytes_xfer_used = bytes_xfer_used + %{2}, files_in_used = files_in_used + %{3}, files_out_used= files_out_used + %{4}, files_xfer_used = files_xfer_used + %{5} WHERE name= '%{6}' AND quota_type = '%{7}'" ftp_quotatallies
|
||||||
SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4},%{5}, %{6}, %{7}" ftp_quotatallies
|
SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4},%{5}, %{6}, %{7}" ftp_quotatallies
|
||||||
|
|
||||||
</IfModule>
|
</IfModule>
|
||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
@@ -2955,7 +2953,7 @@ TLSRSACertificateFile /etc/ssl/certs/proftpd.crt
|
|||||||
TLSRSACertificateKeyFile /etc/ssl/private/proftpd.key
|
TLSRSACertificateKeyFile /etc/ssl/private/proftpd.key
|
||||||
TLSECCertificateFile /etc/ssl/certs/proftpd_ec.crt
|
TLSECCertificateFile /etc/ssl/certs/proftpd_ec.crt
|
||||||
TLSECCertificateKeyFile /etc/ssl/private/proftpd_ec.key
|
TLSECCertificateKeyFile /etc/ssl/private/proftpd_ec.key
|
||||||
TLSOptions NoCertRequest NoSessionReuseRequired
|
TLSOptions NoSessionReuseRequired
|
||||||
TLSVerifyClient off
|
TLSVerifyClient off
|
||||||
|
|
||||||
# Are clients required to use FTP over TLS when talking to this server?
|
# Are clients required to use FTP over TLS when talking to this server?
|
||||||
@@ -3317,7 +3315,7 @@ aliases: files
|
|||||||
<command><![CDATA[mkdir -p {{settings.system.mod_fcgid_configdir}}]]></command>
|
<command><![CDATA[mkdir -p {{settings.system.mod_fcgid_configdir}}]]></command>
|
||||||
<command><![CDATA[mkdir -p {{settings.system.mod_fcgid_tmpdir}}]]></command>
|
<command><![CDATA[mkdir -p {{settings.system.mod_fcgid_tmpdir}}]]></command>
|
||||||
<command><![CDATA[chmod 1777 {{settings.system.mod_fcgid_tmpdir}}]]></command>
|
<command><![CDATA[chmod 1777 {{settings.system.mod_fcgid_tmpdir}}]]></command>
|
||||||
<command><![CDATA[a2dismod php8.1]]></command>
|
<command><![CDATA[a2dismod php8.2]]></command>
|
||||||
</commands>
|
</commands>
|
||||||
<!-- instead of just restarting apache, we let the cronjob do all the
|
<!-- instead of just restarting apache, we let the cronjob do all the
|
||||||
dirty work -->
|
dirty work -->
|
||||||
@@ -3350,7 +3348,7 @@ aliases: files
|
|||||||
</visibility>
|
</visibility>
|
||||||
<visibility mode="true">{{settings.phpfpm.enabled_ownvhost}}
|
<visibility mode="true">{{settings.phpfpm.enabled_ownvhost}}
|
||||||
</visibility>
|
</visibility>
|
||||||
<command><![CDATA[a2dismod php8.1]]></command>
|
<command><![CDATA[a2dismod php8.2]]></command>
|
||||||
</commands>
|
</commands>
|
||||||
<!-- instead of just restarting apache, we let the cronjob do all the
|
<!-- instead of just restarting apache, we let the cronjob do all the
|
||||||
dirty work -->
|
dirty work -->
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ return [
|
|||||||
'customers' => [
|
'customers' => [
|
||||||
'label' => lng('admin.customers'),
|
'label' => lng('admin.customers'),
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['customers'],
|
'value' => empty($result['customers']) ? '0' : $result['customers'],
|
||||||
'maxlength' => 9,
|
'maxlength' => 9,
|
||||||
'mandatory' => true
|
'mandatory' => true
|
||||||
],
|
],
|
||||||
@@ -146,7 +146,7 @@ return [
|
|||||||
'domains' => [
|
'domains' => [
|
||||||
'label' => lng('admin.domains'),
|
'label' => lng('admin.domains'),
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['domains'],
|
'value' => empty($result['domains']) ? '0' : $result['domains'],
|
||||||
'maxlength' => 9,
|
'maxlength' => 9,
|
||||||
'mandatory' => true
|
'mandatory' => true
|
||||||
],
|
],
|
||||||
@@ -159,49 +159,49 @@ return [
|
|||||||
'diskspace' => [
|
'diskspace' => [
|
||||||
'label' => lng('customer.diskspace') . ' (' . lng('customer.mib') . ')',
|
'label' => lng('customer.diskspace') . ' (' . lng('customer.mib') . ')',
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['diskspace'],
|
'value' => empty($result['diskspace']) ? '0' : $result['diskspace'],
|
||||||
'maxlength' => 6,
|
'maxlength' => 6,
|
||||||
'mandatory' => true
|
'mandatory' => true
|
||||||
],
|
],
|
||||||
'traffic' => [
|
'traffic' => [
|
||||||
'label' => lng('customer.traffic') . ' (' . lng('customer.gib') . ')',
|
'label' => lng('customer.traffic') . ' (' . lng('customer.gib') . ')',
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['traffic'],
|
'value' => empty($result['traffic']) ? '0' : $result['traffic'],
|
||||||
'maxlength' => 4,
|
'maxlength' => 4,
|
||||||
'mandatory' => true
|
'mandatory' => true
|
||||||
],
|
],
|
||||||
'subdomains' => [
|
'subdomains' => [
|
||||||
'label' => lng('customer.subdomains'),
|
'label' => lng('customer.subdomains'),
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['subdomains'],
|
'value' => empty($result['subdomains']) ? '0' : $result['subdomains'],
|
||||||
'maxlength' => 9,
|
'maxlength' => 9,
|
||||||
'mandatory' => true
|
'mandatory' => true
|
||||||
],
|
],
|
||||||
'emails' => [
|
'emails' => [
|
||||||
'label' => lng('customer.emails'),
|
'label' => lng('customer.emails'),
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['emails'],
|
'value' => empty($result['emails']) ? '0' : $result['emails'],
|
||||||
'maxlength' => 9,
|
'maxlength' => 9,
|
||||||
'mandatory' => true
|
'mandatory' => true
|
||||||
],
|
],
|
||||||
'email_accounts' => [
|
'email_accounts' => [
|
||||||
'label' => lng('customer.accounts'),
|
'label' => lng('customer.accounts'),
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['email_accounts'],
|
'value' => empty($result['email_accounts']) ? '0' : $result['email_accounts'],
|
||||||
'maxlength' => 9,
|
'maxlength' => 9,
|
||||||
'mandatory' => true
|
'mandatory' => true
|
||||||
],
|
],
|
||||||
'email_forwarders' => [
|
'email_forwarders' => [
|
||||||
'label' => lng('customer.forwarders'),
|
'label' => lng('customer.forwarders'),
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['email_forwarders'],
|
'value' => empty($result['email_forwarders']) ? '0' : $result['email_forwarders'],
|
||||||
'maxlength' => 9,
|
'maxlength' => 9,
|
||||||
'mandatory' => true
|
'mandatory' => true
|
||||||
],
|
],
|
||||||
'email_quota' => [
|
'email_quota' => [
|
||||||
'label' => lng('customer.email_quota') . ' (' . lng('customer.mib') . ')',
|
'label' => lng('customer.email_quota') . ' (' . lng('customer.mib') . ')',
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['email_quota'],
|
'value' => empty($result['email_quota']) ? '0' : $result['email_quota'],
|
||||||
'maxlength' => 9,
|
'maxlength' => 9,
|
||||||
'visible' => Settings::Get('system.mail_quota_enabled') == '1',
|
'visible' => Settings::Get('system.mail_quota_enabled') == '1',
|
||||||
'mandatory' => true
|
'mandatory' => true
|
||||||
@@ -209,13 +209,13 @@ return [
|
|||||||
'ftps' => [
|
'ftps' => [
|
||||||
'label' => lng('customer.ftps'),
|
'label' => lng('customer.ftps'),
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['ftps'],
|
'value' => empty($result['ftps']) ? '0' : $result['ftps'],
|
||||||
'maxlength' => 9
|
'maxlength' => 9
|
||||||
],
|
],
|
||||||
'mysqls' => [
|
'mysqls' => [
|
||||||
'label' => lng('customer.mysqls'),
|
'label' => lng('customer.mysqls'),
|
||||||
'type' => 'textul',
|
'type' => 'textul',
|
||||||
'value' => $result['mysqls'],
|
'value' => empty($result['mysqls']) ? '0' : $result['mysqls'],
|
||||||
'maxlength' => 9,
|
'maxlength' => 9,
|
||||||
'mandatory' => true
|
'mandatory' => true
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -364,6 +364,12 @@ return [
|
|||||||
'value' => '1',
|
'value' => '1',
|
||||||
'checked' => true
|
'checked' => true
|
||||||
],
|
],
|
||||||
|
'openbasedir_path' => [
|
||||||
|
'label' => lng('domain.openbasedirpath'),
|
||||||
|
'type' => 'select',
|
||||||
|
'select_var' => $openbasedir,
|
||||||
|
'selected' => 0
|
||||||
|
],
|
||||||
'phpenabled' => [
|
'phpenabled' => [
|
||||||
'label' => lng('admin.phpenabled'),
|
'label' => lng('admin.phpenabled'),
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
|
|||||||
@@ -390,6 +390,12 @@ return [
|
|||||||
'value' => '1',
|
'value' => '1',
|
||||||
'checked' => $result['openbasedir']
|
'checked' => $result['openbasedir']
|
||||||
],
|
],
|
||||||
|
'openbasedir_path' => [
|
||||||
|
'label' => lng('domain.openbasedirpath'),
|
||||||
|
'type' => 'select',
|
||||||
|
'select_var' => $openbasedir,
|
||||||
|
'selected' => $result['openbasedir_path']
|
||||||
|
],
|
||||||
'phpenabled' => [
|
'phpenabled' => [
|
||||||
'label' => lng('admin.phpenabled'),
|
'label' => lng('admin.phpenabled'),
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ return [
|
|||||||
'value' => '5s'
|
'value' => '5s'
|
||||||
],
|
],
|
||||||
'phpfpm_pass_authorizationheader' => [
|
'phpfpm_pass_authorizationheader' => [
|
||||||
'visible' => Settings::Get('phpfpm.enabled') == 1 && Settings::Get('system.webserver') == "apache2",
|
'visible' => Settings::Get('system.webserver') == "apache2",
|
||||||
'label' => lng('admin.phpsettings.pass_authorizationheader'),
|
'label' => lng('admin.phpsettings.pass_authorizationheader'),
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'value' => '1',
|
'value' => '1',
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ return [
|
|||||||
'value' => $result['fpm_reqslow']
|
'value' => $result['fpm_reqslow']
|
||||||
],
|
],
|
||||||
'phpfpm_pass_authorizationheader' => [
|
'phpfpm_pass_authorizationheader' => [
|
||||||
'visible' => Settings::Get('phpfpm.enabled') == 1 && Settings::Get('system.webserver') == "apache2",
|
'visible' => Settings::Get('system.webserver') == "apache2",
|
||||||
'label' => lng('admin.phpsettings.pass_authorizationheader'),
|
'label' => lng('admin.phpsettings.pass_authorizationheader'),
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'value' => '1',
|
'value' => '1',
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ return [
|
|||||||
'label' => lng('panel.path'),
|
'label' => lng('panel.path'),
|
||||||
'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescriptionSubdomain').(Settings::Get('system.documentroot_use_default_value') == 1 ? lng('panel.pathDescriptionEx') : '') : null),
|
'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescriptionSubdomain').(Settings::Get('system.documentroot_use_default_value') == 1 ? lng('panel.pathDescriptionEx') : '') : null),
|
||||||
'type' => $pathSelect['type'],
|
'type' => $pathSelect['type'],
|
||||||
'select_var' => $pathSelect['value'],
|
'select_var' => $pathSelect['select_var'] ?? '',
|
||||||
'selected' => $pathSelect['value'],
|
'selected' => $pathSelect['value'],
|
||||||
'value' => $pathSelect['value'],
|
'value' => $pathSelect['value'],
|
||||||
'note' => $pathSelect['note'] ?? '',
|
'note' => $pathSelect['note'] ?? '',
|
||||||
|
|||||||
@@ -43,13 +43,16 @@ return [
|
|||||||
'email_password' => [
|
'email_password' => [
|
||||||
'label' => lng('login.password'),
|
'label' => lng('login.password'),
|
||||||
'type' => 'password',
|
'type' => 'password',
|
||||||
'autocomplete' => 'off'
|
'autocomplete' => 'off',
|
||||||
],
|
'next_to' => [
|
||||||
'email_password_suggestion' => [
|
'email_password_suggestion' => [
|
||||||
'label' => lng('customer.generated_pwd'),
|
'next_to_prefix' => lng('customer.generated_pwd') . ':',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'visible' => (Settings::Get('panel.password_regex') == ''),
|
'visible' => (Settings::Get('panel.password_regex') == ''),
|
||||||
'value' => Crypt::generatePassword()
|
'value' => Crypt::generatePassword(),
|
||||||
|
'readonly' => true
|
||||||
|
]
|
||||||
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -52,7 +52,13 @@ return [
|
|||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'value' => '1',
|
'value' => '1',
|
||||||
'checked' => false
|
'checked' => false
|
||||||
]
|
],
|
||||||
|
'disablegreylist' => [
|
||||||
|
'label' => lng('emails.disablegreylist'),
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'value' => '1',
|
||||||
|
'checked' => false
|
||||||
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ return [
|
|||||||
'autocomplete' => 'off',
|
'autocomplete' => 'off',
|
||||||
'mandatory' => true,
|
'mandatory' => true,
|
||||||
'next_to' => [
|
'next_to' => [
|
||||||
'admin_password_suggestion' => [
|
'email_password_suggestion' => [
|
||||||
'next_to_prefix' => lng('customer.generated_pwd') . ':',
|
'next_to_prefix' => lng('customer.generated_pwd') . ':',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'visible' => (Settings::Get('panel.password_regex') == ''),
|
'visible' => (Settings::Get('panel.password_regex') == ''),
|
||||||
|
|||||||
@@ -102,6 +102,19 @@ return [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
'mail_disablegreylist' => [
|
||||||
|
'label' => lng('emails.greylist'),
|
||||||
|
'type' => 'label',
|
||||||
|
'value' => ((int)$result['disablegreylist'] == 0 ? lng('panel.no') : lng('panel.yes')),
|
||||||
|
'next_to' => [
|
||||||
|
'add_link' => [
|
||||||
|
'type' => 'link',
|
||||||
|
'href' => $filename . '?page=' . $page . '&domainid=' . $result['domainid'] . '&action=togglegreylist&id=' . $result['id'],
|
||||||
|
'label' => '<i class="fa-solid fa-arrow-right-arrow-left"></i> ' . lng('panel.toggle'),
|
||||||
|
'classes' => 'btn btn-sm btn-secondary'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
'mail_fwds' => [
|
'mail_fwds' => [
|
||||||
'label' => lng('emails.forwarders') . ' (' . $forwarders_count . ')',
|
'label' => lng('emails.forwarders') . ' (' . $forwarders_count . ')',
|
||||||
'type' => 'itemlist',
|
'type' => 'itemlist',
|
||||||
|
|||||||
@@ -25,6 +25,13 @@
|
|||||||
|
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
|
|
||||||
|
$httpuser = '';
|
||||||
|
$httpgroup = '';
|
||||||
|
if (extension_loaded('posix')) {
|
||||||
|
$httpuser = posix_getpwuid(posix_getuid())['name'] ?? '';
|
||||||
|
$httpgroup = posix_getgrgid(posix_getgid())['name'] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'install' => [
|
'install' => [
|
||||||
'title' => 'install',
|
'title' => 'install',
|
||||||
@@ -194,7 +201,7 @@ return [
|
|||||||
'placeholder' => lng('admin.webserver_user'),
|
'placeholder' => lng('admin.webserver_user'),
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'mandatory' => true,
|
'mandatory' => true,
|
||||||
'value' => old('httpuser', posix_getpwuid(posix_getuid())['name'] ?? '', 'installation'),
|
'value' => old('httpuser', $httpuser, 'installation'),
|
||||||
'advanced' => true,
|
'advanced' => true,
|
||||||
],
|
],
|
||||||
'httpgroup' => [
|
'httpgroup' => [
|
||||||
@@ -202,7 +209,7 @@ return [
|
|||||||
'placeholder' => lng('admin.webserver_group'),
|
'placeholder' => lng('admin.webserver_group'),
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'mandatory' => true,
|
'mandatory' => true,
|
||||||
'value' => old('httpgroup', posix_getgrgid(posix_getgid())['name'] ?? '', 'installation'),
|
'value' => old('httpgroup', $httpgroup, 'installation'),
|
||||||
'advanced' => true,
|
'advanced' => true,
|
||||||
],
|
],
|
||||||
'activate_newsfeed' => [
|
'activate_newsfeed' => [
|
||||||
|
|||||||
19
lib/init.php
19
lib/init.php
@@ -52,6 +52,7 @@ require dirname(__DIR__) . '/vendor/autoload.php';
|
|||||||
use Froxlor\CurrentUser;
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\Http\RateLimiter;
|
||||||
use Froxlor\Idna\IdnaWrapper;
|
use Froxlor\Idna\IdnaWrapper;
|
||||||
use Froxlor\Language;
|
use Froxlor\Language;
|
||||||
use Froxlor\PhpHelper;
|
use Froxlor\PhpHelper;
|
||||||
@@ -121,6 +122,7 @@ if (!isset($sql) || !is_array($sql)) {
|
|||||||
|
|
||||||
// send ssl-related headers (later than the others because we need a working database-connection and installation)
|
// send ssl-related headers (later than the others because we need a working database-connection and installation)
|
||||||
UI::sendSslHeaders();
|
UI::sendSslHeaders();
|
||||||
|
RateLimiter::run();
|
||||||
|
|
||||||
// create a new idna converter
|
// create a new idna converter
|
||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
@@ -179,8 +181,10 @@ if (@file_exists('templates/' . $theme . '/config.json')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for existence of variant in theme
|
// check for existence of variant in theme
|
||||||
if (is_array($_themeoptions) && (!array_key_exists('variants', $_themeoptions) || !array_key_exists($themevariant,
|
if (is_array($_themeoptions) && (!array_key_exists('variants', $_themeoptions) || !array_key_exists(
|
||||||
$_themeoptions['variants']))) {
|
$themevariant,
|
||||||
|
$_themeoptions['variants']
|
||||||
|
))) {
|
||||||
$themevariant = "default";
|
$themevariant = "default";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,12 +218,11 @@ UI::twig()->addGlobal('header_logo', $header_logo);
|
|||||||
if (!CurrentUser::hasSession() && AREA != 'login') {
|
if (!CurrentUser::hasSession() && AREA != 'login') {
|
||||||
unset($_SESSION['userinfo']);
|
unset($_SESSION['userinfo']);
|
||||||
CurrentUser::setData();
|
CurrentUser::setData();
|
||||||
session_destroy();
|
$_SESSION = [
|
||||||
$params = [
|
"lastscript" => basename($_SERVER["SCRIPT_NAME"]),
|
||||||
"script" => basename($_SERVER["SCRIPT_NAME"]),
|
"lastqrystr" => $_SERVER["QUERY_STRING"]
|
||||||
"qrystr" => $_SERVER["QUERY_STRING"]
|
|
||||||
];
|
];
|
||||||
Response::redirectTo('index.php', $params);
|
Response::redirectTo('index.php');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +335,7 @@ if (CurrentUser::hasSession()) {
|
|||||||
$cookie_params = [
|
$cookie_params = [
|
||||||
'expires' => time() + Settings::Get('session.sessiontimeout'),
|
'expires' => time() + Settings::Get('session.sessiontimeout'),
|
||||||
'path' => '/',
|
'path' => '/',
|
||||||
'domain' => explode(':', $_SERVER['HTTP_HOST'])[0],
|
'domain' => UI::getCookieHost(),
|
||||||
'secure' => UI::requestIsHttps(),
|
'secure' => UI::requestIsHttps(),
|
||||||
'httponly' => true,
|
'httponly' => true,
|
||||||
'samesite' => 'Strict'
|
'samesite' => 'Strict'
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ return [
|
|||||||
'url' => 'customer_email.php?page=emails',
|
'url' => 'customer_email.php?page=emails',
|
||||||
'label' => lng('menue.email.emails'),
|
'label' => lng('menue.email.emails'),
|
||||||
'required_resources' => 'emails',
|
'required_resources' => 'emails',
|
||||||
'add_shortlink' => CurrentUser::canAddResource('emails') ? 'customer_email.php?page=emails&action=add' : null,
|
'add_shortlink' => !CurrentUser::isAdmin() && CurrentUser::canAddResource('emails') ? 'customer_email.php?page=email_domain&action=add' : null,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'url' => Settings::Get('panel.webmail_url'),
|
'url' => Settings::Get('panel.webmail_url'),
|
||||||
@@ -60,7 +60,7 @@ return [
|
|||||||
'url' => 'customer_mysql.php?page=mysqls',
|
'url' => 'customer_mysql.php?page=mysqls',
|
||||||
'label' => lng('menue.mysql.databases'),
|
'label' => lng('menue.mysql.databases'),
|
||||||
'required_resources' => 'mysqls',
|
'required_resources' => 'mysqls',
|
||||||
'add_shortlink' => CurrentUser::canAddResource('mysqls')? 'customer_mysql.php?page=mysqls&action=add' : null,
|
'add_shortlink' => !CurrentUser::isAdmin() && CurrentUser::canAddResource('mysqls')? 'customer_mysql.php?page=mysqls&action=add' : null,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'url' => Settings::Get('panel.phpmyadmin_url'),
|
'url' => Settings::Get('panel.phpmyadmin_url'),
|
||||||
@@ -81,7 +81,7 @@ return [
|
|||||||
[
|
[
|
||||||
'url' => 'customer_domains.php?page=domains',
|
'url' => 'customer_domains.php?page=domains',
|
||||||
'label' => lng('menue.domains.settings'),
|
'label' => lng('menue.domains.settings'),
|
||||||
'add_shortlink' => CurrentUser::canAddResource('subdomains') ? 'customer_domains.php?page=domains&action=add' : null,
|
'add_shortlink' => !CurrentUser::isAdmin() && CurrentUser::canAddResource('subdomains') ? 'customer_domains.php?page=domains&action=add' : null,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'url' => 'customer_domains.php?page=sslcertificates',
|
'url' => 'customer_domains.php?page=sslcertificates',
|
||||||
@@ -98,7 +98,7 @@ return [
|
|||||||
[
|
[
|
||||||
'url' => 'customer_ftp.php?page=accounts',
|
'url' => 'customer_ftp.php?page=accounts',
|
||||||
'label' => lng('menue.ftp.accounts'),
|
'label' => lng('menue.ftp.accounts'),
|
||||||
'add_shortlink' => CurrentUser::canAddResource('ftps') ? 'customer_ftp.php?page=accounts&action=add' : null,
|
'add_shortlink' => !CurrentUser::isAdmin() && CurrentUser::canAddResource('ftps') ? 'customer_ftp.php?page=accounts&action=add' : null,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'url' => Settings::Get('panel.webftp_url'),
|
'url' => Settings::Get('panel.webftp_url'),
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ return [
|
|||||||
'callback' => [Text::class, 'boolean'],
|
'callback' => [Text::class, 'boolean'],
|
||||||
'visible' => Settings::Get('catchall.catchall_enabled') == '1'
|
'visible' => Settings::Get('catchall.catchall_enabled') == '1'
|
||||||
],
|
],
|
||||||
|
'm.disablegreylist' => [
|
||||||
|
'label' => lng('emails.greylist'),
|
||||||
|
'field' => 'disablegreylist',
|
||||||
|
'callback' => [Text::class, 'boolean'],
|
||||||
|
'#visible' => Settings::Get('greylist.greylist_enabled') == '1'
|
||||||
|
],
|
||||||
'u.quota' => [
|
'u.quota' => [
|
||||||
'label' => lng('emails.quota'),
|
'label' => lng('emails.quota'),
|
||||||
'field' => 'quota',
|
'field' => 'quota',
|
||||||
@@ -66,6 +72,7 @@ return [
|
|||||||
'm.destination',
|
'm.destination',
|
||||||
'm.popaccountid',
|
'm.popaccountid',
|
||||||
'm.iscatchall',
|
'm.iscatchall',
|
||||||
|
'm.disablegreylist',
|
||||||
'u.quota'
|
'u.quota'
|
||||||
]),
|
]),
|
||||||
'actions' => [
|
'actions' => [
|
||||||
|
|||||||
@@ -45,30 +45,27 @@ return [
|
|||||||
'callback' => [SSLCertificate::class, 'domainWithSan'],
|
'callback' => [SSLCertificate::class, 'domainWithSan'],
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
],
|
],
|
||||||
'c.issuer' => [
|
's.issuer' => [
|
||||||
'label' => lng('ssl_certificates.issuer'),
|
'label' => lng('ssl_certificates.issuer'),
|
||||||
'field' => 'issuer',
|
'field' => 'issuer',
|
||||||
'searchable' => false,
|
|
||||||
],
|
],
|
||||||
'c.validfromdate' => [
|
's.validfromdate' => [
|
||||||
'label' => lng('ssl_certificates.valid_from'),
|
'label' => lng('ssl_certificates.valid_from'),
|
||||||
'field' => 'validfromdate',
|
'field' => 'validfromdate',
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
'sortable' => false,
|
|
||||||
],
|
],
|
||||||
'c.validtodate' => [
|
's.validtodate' => [
|
||||||
'label' => lng('ssl_certificates.valid_until'),
|
'label' => lng('ssl_certificates.valid_until'),
|
||||||
'field' => 'validtodate',
|
'field' => 'validtodate',
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
'sortable' => false,
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'visible_columns' => Listing::getVisibleColumnsForListing('sslcertificates_list', [
|
'visible_columns' => Listing::getVisibleColumnsForListing('sslcertificates_list', [
|
||||||
'd.domain',
|
'd.domain',
|
||||||
'c.domain',
|
'c.domain',
|
||||||
'c.issuer',
|
's.issuer',
|
||||||
'c.validfromdate',
|
's.validfromdate',
|
||||||
'c.validtodate',
|
's.validtodate',
|
||||||
]),
|
]),
|
||||||
'actions' => [
|
'actions' => [
|
||||||
'edit' => [
|
'edit' => [
|
||||||
|
|||||||
2406
lng/ca.lng.php
Normal file
2406
lng/ca.lng.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@ return [
|
|||||||
'nl' => 'Niederländisch',
|
'nl' => 'Niederländisch',
|
||||||
'pt' => 'Portugiesisch',
|
'pt' => 'Portugiesisch',
|
||||||
'se' => 'Schwedisch',
|
'se' => 'Schwedisch',
|
||||||
|
'es' => 'Spanisch',
|
||||||
],
|
],
|
||||||
'2fa' => [
|
'2fa' => [
|
||||||
'2fa' => '2FA Optionen',
|
'2fa' => '2FA Optionen',
|
||||||
@@ -297,7 +298,7 @@ return [
|
|||||||
'request_terminate_timeout' => 'request_terminate_timeout',
|
'request_terminate_timeout' => 'request_terminate_timeout',
|
||||||
'request_slowlog_timeout' => 'request_slowlog_timeout',
|
'request_slowlog_timeout' => 'request_slowlog_timeout',
|
||||||
'activephpconfigs' => 'In Verwendung für PHP-Konfiguration(en)',
|
'activephpconfigs' => 'In Verwendung für PHP-Konfiguration(en)',
|
||||||
'pass_authorizationheader' => 'Füge "-pass-header Authorization" / "CGIPassAuth On" in Vhosts ein',
|
'pass_authorizationheader' => 'Übergeben von HTTP AUTH BASIC/DIGEST-Headern von Apache an PHP',
|
||||||
],
|
],
|
||||||
'misc' => 'Sonstiges',
|
'misc' => 'Sonstiges',
|
||||||
'fpmsettings' => [
|
'fpmsettings' => [
|
||||||
@@ -723,6 +724,8 @@ return [
|
|||||||
'back_to_overview' => 'Zurück zur Domain-Übersicht',
|
'back_to_overview' => 'Zurück zur Domain-Übersicht',
|
||||||
'accounts' => 'Konten',
|
'accounts' => 'Konten',
|
||||||
'emails' => 'Adressen',
|
'emails' => 'Adressen',
|
||||||
|
'disablegreylist' => 'Greylisting deaktivieren?',
|
||||||
|
'greylist' => 'Greylisting aus?'
|
||||||
],
|
],
|
||||||
'error' => [
|
'error' => [
|
||||||
'error' => 'Fehlermeldung',
|
'error' => 'Fehlermeldung',
|
||||||
@@ -924,6 +927,8 @@ return [
|
|||||||
'mysqlserverstillhasdbs' => 'Datenbank-Server kann für den Kunden nicht entfernt werden, da sich dort noch Datenbanken befinden.',
|
'mysqlserverstillhasdbs' => 'Datenbank-Server kann für den Kunden nicht entfernt werden, da sich dort noch Datenbanken befinden.',
|
||||||
'domaincannotbeedited' => 'Keine Berechtigung, um die Domain %s zu bearbeiten',
|
'domaincannotbeedited' => 'Keine Berechtigung, um die Domain %s zu bearbeiten',
|
||||||
'invalidcronjobintervalvalue' => 'Cronjob Intervall muss einer der folgenden Werte sein: %s',
|
'invalidcronjobintervalvalue' => 'Cronjob Intervall muss einer der folgenden Werte sein: %s',
|
||||||
|
'phpgdextensionnotavailable' => 'Die PHP GD Extension ist nicht verfügbar. Bild-Daten können nicht validiert werden.',
|
||||||
|
'2fa_wrongcode' => 'Der angegebene Code ist nicht korrekt',
|
||||||
],
|
],
|
||||||
'extras' => [
|
'extras' => [
|
||||||
'description' => 'Hier können Sie zusätzliche Extras einrichten, wie zum Beispiel einen Verzeichnisschutz.<br />Die Änderungen sind erst nach einer kurzen Zeit wirksam.',
|
'description' => 'Hier können Sie zusätzliche Extras einrichten, wie zum Beispiel einen Verzeichnisschutz.<br />Die Änderungen sind erst nach einer kurzen Zeit wirksam.',
|
||||||
@@ -2070,6 +2075,14 @@ Vielen Dank, Ihr Administrator',
|
|||||||
'toolselect' => 'Traffic Analyzer',
|
'toolselect' => 'Traffic Analyzer',
|
||||||
],
|
],
|
||||||
'requires_reconfiguration' => 'Änderungen an dieser Einstellungen benötigen unter Umständen eine erneute Konfiguration der folgenden Dienste:<br><strong>%s</strong>',
|
'requires_reconfiguration' => 'Änderungen an dieser Einstellungen benötigen unter Umständen eine erneute Konfiguration der folgenden Dienste:<br><strong>%s</strong>',
|
||||||
|
'req_limit_per_interval' => [
|
||||||
|
'title' => 'Anzahl der HTTP-Anfragen pro Intervall',
|
||||||
|
'description' => 'Erlaubte Anzahl von HTTP-Anfragen pro Intervall (siehe unten) auf froxlor, Standard ist "60"',
|
||||||
|
],
|
||||||
|
'req_limit_interval' => [
|
||||||
|
'title' => 'Rate-Limit-Intervall',
|
||||||
|
'description' => 'Zeit in Sekunden für die maximale Anzahl von HTTP-Anfragen, Standard ist "60".',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'spf' => [
|
'spf' => [
|
||||||
'use_spf' => 'Aktiviere SPF für Domains?',
|
'use_spf' => 'Aktiviere SPF für Domains?',
|
||||||
@@ -2177,6 +2190,7 @@ Vielen Dank, Ihr Administrator',
|
|||||||
'description' => 'Aktualisierung der froxlor Datenbank',
|
'description' => 'Aktualisierung der froxlor Datenbank',
|
||||||
'uc_newinfo' => 'Eine neuere %sVersion ist verfügbar: "%s" (Aktuell installierte Version: %s)',
|
'uc_newinfo' => 'Eine neuere %sVersion ist verfügbar: "%s" (Aktuell installierte Version: %s)',
|
||||||
'notify_subject' => 'Neues Update verfügbar',
|
'notify_subject' => 'Neues Update verfügbar',
|
||||||
|
'dbupdate_required' => 'Froxlor-Dateien wurden aktualisiert, Datenbank-Aktualisierung notwendig',
|
||||||
],
|
],
|
||||||
'usersettings' => [
|
'usersettings' => [
|
||||||
'custom_notes' => [
|
'custom_notes' => [
|
||||||
@@ -2231,8 +2245,8 @@ Vielen Dank, Ihr Administrator',
|
|||||||
'install' => [
|
'install' => [
|
||||||
'top' => 'Abschluss',
|
'top' => 'Abschluss',
|
||||||
'title' => 'Ein letzter Schritt...',
|
'title' => 'Ein letzter Schritt...',
|
||||||
'description' => 'Der untenstehende Befehl lädt, installiert und konfiguriert die benötigten Dienste auf dem System aufgrund der Angaben die während des Installationsprozessen gesammelt wurden.',
|
'description' => 'Der untenstehende Befehl lädt, installiert und konfiguriert die benötigten Dienste auf dem System aufgrund der Angaben die während des Installationsprozessen gesammelt wurden.<br><br><span class="text-danger">Führe die gezeigten Befehle als <b>root</b> in der Shell/Konsole des Servers aus.</span>',
|
||||||
'runcmd' => 'Folgenden Befehl als root-Benutzer in der Shell auf dem Server ausführen:',
|
'runcmd' => 'Folgende Befehle ausführen, um die Installation abzuschließen:',
|
||||||
'manual_config' => 'Ich werden die Dienste manuell konfigurieren, direkt zum Login umleiten',
|
'manual_config' => 'Ich werden die Dienste manuell konfigurieren, direkt zum Login umleiten',
|
||||||
'waitforconfig' => 'Warte auf Abschluss der Dienstkonfiguration...',
|
'waitforconfig' => 'Warte auf Abschluss der Dienstkonfiguration...',
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ return [
|
|||||||
'nl' => 'Dutch',
|
'nl' => 'Dutch',
|
||||||
'pt' => 'Portuguese',
|
'pt' => 'Portuguese',
|
||||||
'se' => 'Swedish',
|
'se' => 'Swedish',
|
||||||
|
'es' => 'Spanish',
|
||||||
|
'ca' => 'Catalan',
|
||||||
],
|
],
|
||||||
'2fa' => [
|
'2fa' => [
|
||||||
'2fa' => '2FA options',
|
'2fa' => '2FA options',
|
||||||
@@ -302,7 +304,7 @@ return [
|
|||||||
'request_terminate_timeout' => 'Request terminate-timeout',
|
'request_terminate_timeout' => 'Request terminate-timeout',
|
||||||
'request_slowlog_timeout' => 'Request slowlog-timeout',
|
'request_slowlog_timeout' => 'Request slowlog-timeout',
|
||||||
'activephpconfigs' => 'In use for php-config(s)',
|
'activephpconfigs' => 'In use for php-config(s)',
|
||||||
'pass_authorizationheader' => 'Add "-pass-header Authorization" / "CGIPassAuth On" to vhosts',
|
'pass_authorizationheader' => 'Passing HTTP AUTH BASIC/DIGEST headers from Apache to PHP',
|
||||||
],
|
],
|
||||||
'misc' => 'Miscellaneous',
|
'misc' => 'Miscellaneous',
|
||||||
'fpmsettings' => [
|
'fpmsettings' => [
|
||||||
@@ -951,7 +953,7 @@ return [
|
|||||||
'autoupdate_1' => 'PHP setting allow_url_fopen is disabled. Autoupdate needs this setting to be enabled in php.ini',
|
'autoupdate_1' => 'PHP setting allow_url_fopen is disabled. Autoupdate needs this setting to be enabled in php.ini',
|
||||||
'autoupdate_2' => 'PHP zip extension not found, please ensure it is installed and activated',
|
'autoupdate_2' => 'PHP zip extension not found, please ensure it is installed and activated',
|
||||||
'autoupdate_4' => 'The froxlor archive could not be stored to the disk :(',
|
'autoupdate_4' => 'The froxlor archive could not be stored to the disk :(',
|
||||||
'autoupdate_5' => 'version.froxlor.org returned inacceptable values :(',
|
'autoupdate_5' => 'version.froxlor.org returned unacceptable values :(',
|
||||||
'autoupdate_6' => 'Whoops, there was no (valid) version given to download :(',
|
'autoupdate_6' => 'Whoops, there was no (valid) version given to download :(',
|
||||||
'autoupdate_7' => 'The downloaded archive could not be found :(',
|
'autoupdate_7' => 'The downloaded archive could not be found :(',
|
||||||
'autoupdate_8' => 'The archive could not be extracted :(',
|
'autoupdate_8' => 'The archive could not be extracted :(',
|
||||||
@@ -993,6 +995,8 @@ return [
|
|||||||
'mysqlserverstillhasdbs' => 'Cannot remove database server from customers allow-list as there are still databases on it.',
|
'mysqlserverstillhasdbs' => 'Cannot remove database server from customers allow-list as there are still databases on it.',
|
||||||
'domaincannotbeedited' => 'You are not permitted to edit the domain %s',
|
'domaincannotbeedited' => 'You are not permitted to edit the domain %s',
|
||||||
'invalidcronjobintervalvalue' => 'Cronjob interval must be one of: %s',
|
'invalidcronjobintervalvalue' => 'Cronjob interval must be one of: %s',
|
||||||
|
'phpgdextensionnotavailable' => 'The PHP GD extension is not available. Unable to validate image-data',
|
||||||
|
'2fa_wrongcode' => 'The code entered is not valid',
|
||||||
],
|
],
|
||||||
'extras' => [
|
'extras' => [
|
||||||
'description' => 'Here you can add some extras, for example directory protection.<br />The system will need some time to apply the new settings after every change.',
|
'description' => 'Here you can add some extras, for example directory protection.<br />The system will need some time to apply the new settings after every change.',
|
||||||
@@ -1191,7 +1195,7 @@ Yours sincerely, your administrator',
|
|||||||
'database_edit' => 'Edit database',
|
'database_edit' => 'Edit database',
|
||||||
'size' => 'Size',
|
'size' => 'Size',
|
||||||
'privileged_user' => 'Privileged database user',
|
'privileged_user' => 'Privileged database user',
|
||||||
'privileged_passwd' => 'Password for priviliged user',
|
'privileged_passwd' => 'Password for privileged user',
|
||||||
'unprivileged_passwd' => 'Password for unprivileged user',
|
'unprivileged_passwd' => 'Password for unprivileged user',
|
||||||
'mysql_ssl_ca_file' => 'SSL server certificate',
|
'mysql_ssl_ca_file' => 'SSL server certificate',
|
||||||
'mysql_ssl_verify_server_certificate' => 'Verify SSL server certificate'
|
'mysql_ssl_verify_server_certificate' => 'Verify SSL server certificate'
|
||||||
@@ -1260,7 +1264,7 @@ Yours sincerely, your administrator',
|
|||||||
'reset' => 'Discard changes',
|
'reset' => 'Discard changes',
|
||||||
'pathDescription' => 'If the directory doesn\'t exist, it will be created automatically.',
|
'pathDescription' => 'If the directory doesn\'t exist, it will be created automatically.',
|
||||||
'pathDescriptionEx' => '<br /><br /><span class="text-danger">Please note:</span> The path <code>/</code> is not allowed due to administrative settings, it will automatically be set to <code>/chosen.subdomain.tld/</code> if not set to another directory.',
|
'pathDescriptionEx' => '<br /><br /><span class="text-danger">Please note:</span> The path <code>/</code> is not allowed due to administrative settings, it will automatically be set to <code>/chosen.subdomain.tld/</code> if not set to another directory.',
|
||||||
'pathDescriptionSubdomain' => 'If the directory doesn\'t exist, it will be created automatically.<br /><br />If you want a redirect to another domain than this entry has to start with http:// or https://.<br /><br />If the URL ends with / it is considered a folder, if not, it is treated as file.',
|
'pathDescriptionSubdomain' => 'If the directory doesn\'t exist, it will be created automatically.<br /><br />If you want a redirect to another domain then this entry has to start with http:// or https://.<br /><br />If the URL ends with / it is considered a folder, if not, it is treated as file.',
|
||||||
'back' => 'Back',
|
'back' => 'Back',
|
||||||
'reseller' => 'reseller',
|
'reseller' => 'reseller',
|
||||||
'admin' => 'admin',
|
'admin' => 'admin',
|
||||||
@@ -2194,6 +2198,14 @@ Yours sincerely, your administrator',
|
|||||||
'goaccess' => 'goacccess'
|
'goaccess' => 'goacccess'
|
||||||
],
|
],
|
||||||
'requires_reconfiguration' => 'Changing this settings might require a reconfiguration of the following services:<br><strong>%s</strong>',
|
'requires_reconfiguration' => 'Changing this settings might require a reconfiguration of the following services:<br><strong>%s</strong>',
|
||||||
|
'req_limit_per_interval' => [
|
||||||
|
'title' => 'Number of HTTP requests per interval',
|
||||||
|
'description' => 'Limit the number of HTTP requests per interval (see below) to froxlor, default is "60"',
|
||||||
|
],
|
||||||
|
'req_limit_interval' => [
|
||||||
|
'title' => 'Rate-limit interval',
|
||||||
|
'description' => 'Specify the time in seconds for the number of HTTP requests, default is "60"',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'spf' => [
|
'spf' => [
|
||||||
'use_spf' => 'Activate SPF for domains?',
|
'use_spf' => 'Activate SPF for domains?',
|
||||||
@@ -2308,6 +2320,7 @@ Yours sincerely, your administrator',
|
|||||||
'description' => 'Running database updates for your froxlor installation',
|
'description' => 'Running database updates for your froxlor installation',
|
||||||
'uc_newinfo' => 'There is a newer %sversion available: "%s" (Your current version is: %s)',
|
'uc_newinfo' => 'There is a newer %sversion available: "%s" (Your current version is: %s)',
|
||||||
'notify_subject' => 'New update available',
|
'notify_subject' => 'New update available',
|
||||||
|
'dbupdate_required' => 'Froxlor files have been updated, database update required',
|
||||||
],
|
],
|
||||||
'usersettings' => [
|
'usersettings' => [
|
||||||
'custom_notes' => [
|
'custom_notes' => [
|
||||||
@@ -2363,8 +2376,8 @@ Yours sincerely, your administrator',
|
|||||||
'install' => [
|
'install' => [
|
||||||
'top' => 'Finish setup',
|
'top' => 'Finish setup',
|
||||||
'title' => 'One last step...',
|
'title' => 'One last step...',
|
||||||
'description' => 'The command below will download, install and configure required services on your system according to the data you have given in this installation process.',
|
'description' => 'The command below will download, install and configure required services on your system according to the data you have given in this installation process.<br><br><span class="text-danger">Be sure to run the following command as <b>root</b> on the server\'s shell/terminal.</span>',
|
||||||
'runcmd' => 'Run the following command as root-user in your shell on this server:',
|
'runcmd' => 'Run the following command to finish the installation:',
|
||||||
'manual_config' => 'I will manually configure the services, just take me to the login',
|
'manual_config' => 'I will manually configure the services, just take me to the login',
|
||||||
'waitforconfig' => 'Waiting for services to be configured...',
|
'waitforconfig' => 'Waiting for services to be configured...',
|
||||||
],
|
],
|
||||||
|
|||||||
2405
lng/es.lng.php
Normal file
2405
lng/es.lng.php
Normal file
File diff suppressed because it is too large
Load Diff
55
notice.html
Normal file
55
notice.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="robots" content="noindex, nofollow">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>froxlor - Domain not configured</title>
|
||||||
|
<style>
|
||||||
|
:root{--primary:#1872a2;--fonts:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}
|
||||||
|
body{display:flex;flex-direction:column;background:#f8f9fa;color:#4b5563;align-items:center;justify-content:center;font-family:var(--fonts)}
|
||||||
|
main{background:#fff;margin:10% auto 12px;max-width:540px;padding:2rem;box-shadow:4px 8px 16px 0 rgba(0,0,0,.07);border-radius:.375rem}
|
||||||
|
main h2{margin:0}
|
||||||
|
main p{margin-bottom:1.5rem}
|
||||||
|
main p:last-child{margin-bottom:0}
|
||||||
|
main ul{list-style:none;margin-left:-40px}
|
||||||
|
main li{display:flex;align-items:center;margin-bottom:1rem}
|
||||||
|
main .icon{min-width:24px;width:24px;stroke:var(--primary);margin-right:.75rem}
|
||||||
|
code{background:#eee;padding:.1rem .25rem;border-radius:4px;color:rgba(0,0,0,.75)}
|
||||||
|
hr{margin:2rem 0;border:none;border-bottom:solid 1px rgba(0,0,0,.1)}
|
||||||
|
a,a:active,a:visited{color:var(--primary);text-decoration:none}
|
||||||
|
a:hover{text-decoration:underline}
|
||||||
|
footer{display:flex;align-items:center;margin-top:.5rem}
|
||||||
|
footer .logo{margin-right:.35rem}
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root{--primary:#29a2d6}
|
||||||
|
body{background:#212529;color:#f8f9fa}
|
||||||
|
main{background:#343a40}
|
||||||
|
hr{border-color:rgba(0,0,0,.2)}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<h2>Domain not configured</h2>
|
||||||
|
<p>
|
||||||
|
This domain requires configuration via the froxlor server management panel, as it is currently not assigned to any customer.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
|
||||||
|
</svg>
|
||||||
|
<span>Please ask your provider/hoster if you have any questions.</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<img class="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAAAQCAYAAAC1MDndAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAy1JREFUeNrs1muIVlUUBuBnvqZkoswudKErZFOG0kWt6WpN0wWCDMOsgX4UmVS/KovKhIKYLhRBJvV1o/5VlJCmYEmUFYijaBYhSRQVBVE0ZnRBJ/vzfnA4nDN+wTh/pgWHc/baa6+z97v3et/d0Ww24SQ8ij5MNL7tN6zBvdjWiZOxDpP8b3JA5qAXPQ0MtAnOm9jZBvqbsQHbsGsMFrQLv+KPUc47CQONlFXZPsNfJd/buBrDFfHDWIDDcAZmohsPjwFAD+EQnL8Xcl/WqOGc+/FJyXcxVuHJivjX8Hx2cwGeweO4fIxOkL10Wg9o1HSsxUcl30V5P1JxnFuxp+M53I67cQ5mYwZexj2YlnarJBdl3BE4FfPxdfofSOwNhX+uwgXxf1Uz/024DpNxFHrwRIEiPs74XnyIq3A8Xion6qxIvj0TX1vyb8x7CJ/jrELfjrx/zgmS0p2bCWzHzejAQTgmO35J+OpInIcv8GLKeROuzcI24lAsRH/yzcGJFfMfDIB/B/ipeD8bNojX8W1hPR+gCxPwTzsAdaGRgTeGrAZLJXd4zc59l1Jr2dzC91S8g+PSXhFwGgGxO4s6Bd9gaQRkAHdhSQHso/FCzRweS56ezLmB1bgCb+DBCg67rwaLSud+uDAAvVLRfw1OqCO18JEKbusvgNMqA/F153sCpgegT+O7Iwt8NwrZwKsh5irbUuDMFoXMquhv2eKRSKiOg54OUFXSt3SEfPvi4Dz77IEAW/8uH+vdpf6dkXGF+F9GyNtRkXe4or8tqwNoWrigbDeFTEfDZhbKckuBy9blu0XkC1Pi++PK+Objy5q80/NeXSDl9wrgnDkaAIlyzCj5zh1FCb00JL07Jd2LKfgBx+LWXE6XJP6pcMiUiMg8/FmRd3GEYHNiZ+H6wgZP/i+T7MzPJo5wkjYU2t01cWfjp6hH2WZn0adVbM7KALAS3weYftwZIVgTIHtxS8YtD6kOYX2Uqi8iIKCsD6CDhXnNi+iI+vXhwD3g83tHs9l8K5JZZbfh2UL7x0jyeLFljVzUhtoc0DWOwBnCoga25s6wrHDhG8+2I1j0YOu/AwBUU7aBHvM/ZwAAAABJRU5ErkJggg==" alt="froxlor"/>
|
||||||
|
<small>© 2009-<span id="year"></span> by <a href="https://froxlor.org" rel="external">the froxlor team</a></small>
|
||||||
|
</footer>
|
||||||
|
<script>
|
||||||
|
document.getElementById("year").innerHTML = new Date().getFullYear();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
13833
package-lock.json
generated
13833
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
templates/Froxlor/assets/css/dark.css
Normal file
17
templates/Froxlor/assets/css/dark.css
Normal file
File diff suppressed because one or more lines are too long
17
templates/Froxlor/assets/css/main.css
Normal file
17
templates/Froxlor/assets/css/main.css
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user