Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
156846a845 | ||
|
|
abe00b79a7 | ||
|
|
26ab659c6a | ||
|
|
b0273c68d2 | ||
|
|
720cf9d74f | ||
|
|
35cd567c48 | ||
|
|
2332d5be7b | ||
|
|
14cdc3801a | ||
|
|
d85efe480e | ||
|
|
4f2ceaa3ab | ||
|
|
3b6792d548 | ||
|
|
36de6e09d4 | ||
|
|
300c410b18 | ||
|
|
282d7d9101 | ||
|
|
48f6601003 | ||
|
|
c4c4279171 | ||
|
|
b88f9c1f18 | ||
|
|
0dac045dc9 | ||
|
|
80b5f97367 | ||
|
|
7a8b39fad0 | ||
|
|
9f5978e875 | ||
|
|
155fd757bf | ||
|
|
518ec202ab | ||
|
|
871083d613 | ||
|
|
79f0c8d28f | ||
|
|
dfbb4127e2 | ||
|
|
b9b2f00f30 | ||
|
|
6923f9d926 | ||
|
|
cacbf7fec7 | ||
|
|
73991e855c | ||
|
|
0208812013 | ||
|
|
48bd2561f7 | ||
|
|
af12c4102b | ||
|
|
d2efa3ecc4 | ||
|
|
acb04566f5 | ||
|
|
abb98ae960 | ||
|
|
0d202a7e4d | ||
|
|
c69ef20b17 | ||
|
|
5872d0682a | ||
|
|
c4fa8feb8c | ||
|
|
61a50cc657 | ||
|
|
3df3261ac0 | ||
|
|
f2636e14f0 | ||
|
|
a23f22f561 |
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,6 +1,6 @@
|
|||||||
# Bug report vs. support request
|
# Bug report vs. support request
|
||||||
If you're unsure of whether your problem is a bug or a configuration error
|
If you're unsure of whether your problem is a bug or a configuration error
|
||||||
* contact us via IRC in #froxlor on freenode
|
* contact us via IRC in #froxlor on irc.libera.chat
|
||||||
* or post a thread in our forum at https://forum.froxlor.org
|
* or post a thread in our forum at https://forum.froxlor.org
|
||||||
|
|
||||||
As a rule of thumb: before reporting an issue
|
As a rule of thumb: before reporting an issue
|
||||||
|
|||||||
80
.github/workflows/build.yml
vendored
Normal file
80
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
name: Froxlor-CI
|
||||||
|
on: ['push', 'pull_request', 'create']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
froxlor:
|
||||||
|
name: Froxlor (PHP ${{ matrix.php-versions }}, MariaDB ${{ matrix.mariadb-version }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
php-versions: ['7.3', '7.4', '8.0']
|
||||||
|
mariadb-version: [10.5, 10.4, 10.3]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup PHP, with composer and extensions
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: ${{ matrix.php-versions }}
|
||||||
|
tools: composer:v2
|
||||||
|
extensions: mbstring, xml, ctype, pdo_mysql, mysql, curl, json, zip, session, filter, posix, openssl, fileinfo, bcmath
|
||||||
|
|
||||||
|
- name: Install tools
|
||||||
|
run: sudo apt-get install -y ant
|
||||||
|
|
||||||
|
- name: Adjust firewall
|
||||||
|
run: |
|
||||||
|
sudo ufw allow out 3306/tcp
|
||||||
|
sudo ufw allow in 3306/tcp
|
||||||
|
|
||||||
|
- name: Setup MariaDB
|
||||||
|
uses: getong/mariadb-action@v1.1
|
||||||
|
with:
|
||||||
|
mariadb version: ${{ matrix.mariadb-version }}
|
||||||
|
mysql database: 'froxlor010'
|
||||||
|
mysql root password: 'fr0xl0r.TravisCI'
|
||||||
|
|
||||||
|
- name: Wait for database
|
||||||
|
run: sleep 15
|
||||||
|
|
||||||
|
- name: Setup databases
|
||||||
|
run: |
|
||||||
|
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "CREATE USER 'froxlor010'@'%' IDENTIFIED BY 'fr0xl0r.TravisCI';"
|
||||||
|
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "GRANT ALL ON froxlor010.* TO 'froxlor010'@'%';"
|
||||||
|
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI froxlor010 < install/froxlor.sql
|
||||||
|
|
||||||
|
- name: Run testing
|
||||||
|
run: ant quick-build
|
||||||
|
|
||||||
|
# - name: irc push
|
||||||
|
# uses: rectalogic/notify-irc@v1
|
||||||
|
# if: github.event_name == 'push'
|
||||||
|
# with:
|
||||||
|
# channel: "#froxlor"
|
||||||
|
# server: "irc.libera.chat"
|
||||||
|
# nickname: froxlor-ci
|
||||||
|
# message: |
|
||||||
|
# ${{ github.actor }} pushed ${{ github.event.ref }} ${{ github.event.compare }}
|
||||||
|
# ${{ join(github.event.commits.*.message) }}
|
||||||
|
|
||||||
|
# - name: irc pull request
|
||||||
|
# uses: rectalogic/notify-irc@v1
|
||||||
|
# if: github.event_name == 'pull_request'
|
||||||
|
# with:
|
||||||
|
# channel: "#froxlor"
|
||||||
|
# server: "irc.libera.chat"
|
||||||
|
# nickname: froxlor-ci
|
||||||
|
# message: |
|
||||||
|
# ${{ github.actor }} opened PR ${{ github.event.pull_request.html_url }}
|
||||||
|
|
||||||
|
# - name: irc tag created
|
||||||
|
# uses: rectalogic/notify-irc@v1
|
||||||
|
# if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||||
|
# with:
|
||||||
|
# channel: "#froxlor"
|
||||||
|
# server: "irc.libera.chat"
|
||||||
|
# nickname: froxlor-ci
|
||||||
|
# message: |
|
||||||
|
# ${{ github.actor }} tagged ${{ github.repository }} ${{ github.event.ref }}
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -12,9 +12,10 @@ logs/*
|
|||||||
.well-known
|
.well-known
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
img/
|
||||||
|
|
||||||
!templates/Froxlor/
|
!templates/Froxlor/
|
||||||
!templates/Sparkle/
|
!templates/Sparkle/
|
||||||
!templates/misc/
|
!templates/misc/
|
||||||
templates/Froxlor/assets/img/logo_custom.png
|
templates/Sparkle/assets/css/custom.css
|
||||||
vendor/
|
vendor/
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ script:
|
|||||||
- ant phpunit-no-coverage
|
- ant phpunit-no-coverage
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
irc: "chat.freenode.net#froxlor"
|
irc: "irc.libera.chat#froxlor"
|
||||||
webhooks:
|
webhooks:
|
||||||
urls:
|
urls:
|
||||||
- https://webhooks.gitter.im/e/bdf91d1c3f745e51f796
|
- https://webhooks.gitter.im/e/bdf91d1c3f745e51f796
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[](https://travis-ci.com/Froxlor/Froxlor)
|
[](https://github.com/Froxlor/Froxlor/actions/workflows/build.yml)
|
||||||
[](https://gitter.im/Froxlor/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
[](https://gitter.im/Froxlor/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
|
|
||||||
# Froxlor
|
# Froxlor
|
||||||
@@ -28,8 +28,8 @@ You may find help in the following places:
|
|||||||
|
|
||||||
### IRC
|
### IRC
|
||||||
|
|
||||||
froxlor may be found on freenode.net, channel #froxlor:
|
froxlor may be found on libera.chat, channel #froxlor:
|
||||||
irc://chat.freenode.net/froxlor
|
irc://irc.libera.chat/froxlor
|
||||||
|
|
||||||
### Forum
|
### Forum
|
||||||
|
|
||||||
|
|||||||
@@ -296,6 +296,24 @@ return array(
|
|||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
),
|
),
|
||||||
|
'panel_logo_image_header' => array(
|
||||||
|
'label' => $lng['serversettings']['logo_image_header'],
|
||||||
|
'settinggroup' => 'panel',
|
||||||
|
'varname' => 'logo_image_header',
|
||||||
|
'type' => 'image',
|
||||||
|
'image_name' => 'logo_header',
|
||||||
|
'default' => '',
|
||||||
|
'save_method' => 'storeSettingImage'
|
||||||
|
),
|
||||||
|
'panel_logo_image_login' => array(
|
||||||
|
'label' => $lng['serversettings']['logo_image_login'],
|
||||||
|
'settinggroup' => 'panel',
|
||||||
|
'varname' => 'logo_image_login',
|
||||||
|
'type' => 'image',
|
||||||
|
'image_name' => 'logo_login',
|
||||||
|
'default' => '',
|
||||||
|
'save_method' => 'storeSettingImage'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -270,6 +270,20 @@ return array(
|
|||||||
'default' => true,
|
'default' => true,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
),
|
),
|
||||||
|
'system_domaindefaultalias' => array(
|
||||||
|
'label' => $lng['admin']['domaindefaultalias'],
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'domaindefaultalias',
|
||||||
|
'type' => 'option',
|
||||||
|
'default' => '0',
|
||||||
|
'option_mode' => 'one',
|
||||||
|
'option_options' => array(
|
||||||
|
'0' => $lng['domains']['serveraliasoption_wildcard'],
|
||||||
|
'1' => $lng['domains']['serveraliasoption_www'],
|
||||||
|
'2' => $lng['domains']['serveraliasoption_none']
|
||||||
|
),
|
||||||
|
'save_method' => 'storeSettingField'
|
||||||
|
),
|
||||||
'hide_incompatible_settings' => array(
|
'hide_incompatible_settings' => array(
|
||||||
'label' => $lng['serversettings']['hide_incompatible_settings'],
|
'label' => $lng['serversettings']['hide_incompatible_settings'],
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
|
|||||||
@@ -142,6 +142,9 @@ return array(
|
|||||||
'default' => '/etc/apache2/conf-enabled/acme.conf',
|
'default' => '/etc/apache2/conf-enabled/acme.conf',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
),
|
),
|
||||||
|
/**
|
||||||
|
* currently the only option anyway
|
||||||
|
*
|
||||||
'system_leapiversion' => array(
|
'system_leapiversion' => array(
|
||||||
'label' => $lng['serversettings']['leapiversion'],
|
'label' => $lng['serversettings']['leapiversion'],
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
@@ -154,16 +157,18 @@ return array(
|
|||||||
),
|
),
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
),
|
),
|
||||||
|
*/
|
||||||
'system_letsencryptca' => array(
|
'system_letsencryptca' => array(
|
||||||
'label' => $lng['serversettings']['letsencryptca'],
|
'label' => $lng['serversettings']['letsencryptca'],
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'letsencryptca',
|
'varname' => 'letsencryptca',
|
||||||
'type' => 'option',
|
'type' => 'option',
|
||||||
'default' => 'production',
|
'default' => 'letsencrypt',
|
||||||
'option_mode' => 'one',
|
'option_mode' => 'one',
|
||||||
'option_options' => array(
|
'option_options' => array(
|
||||||
'testing' => 'https://acme-staging-v0' . \Froxlor\Settings::Get('system.leapiversion') . '.api.letsencrypt.org (Test)',
|
'letsencrypt_test' => 'Let\'s Encrypt (Test / Staging)',
|
||||||
'production' => 'https://acme-v0' . \Froxlor\Settings::Get('system.leapiversion') . '.api.letsencrypt.org (Live)'
|
'letsencrypt' => 'Let\'s Encrypt (Live)',
|
||||||
|
'zerossl' => 'ZeroSSL (Live)'
|
||||||
),
|
),
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -290,9 +290,9 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
|
|
||||||
// create serveralias options
|
// create serveralias options
|
||||||
$serveraliasoptions = "";
|
$serveraliasoptions = "";
|
||||||
$serveraliasoptions .= \Froxlor\UI\HTML::makeoption($lng['domains']['serveraliasoption_wildcard'], '0', '0', true, true);
|
$serveraliasoptions .= \Froxlor\UI\HTML::makeoption($lng['domains']['serveraliasoption_wildcard'], '0', Settings::Get('system.domaindefaultalias'), true, true);
|
||||||
$serveraliasoptions .= \Froxlor\UI\HTML::makeoption($lng['domains']['serveraliasoption_www'], '1', '0', true, true);
|
$serveraliasoptions .= \Froxlor\UI\HTML::makeoption($lng['domains']['serveraliasoption_www'], '1', Settings::Get('system.domaindefaultalias'), true, true);
|
||||||
$serveraliasoptions .= \Froxlor\UI\HTML::makeoption($lng['domains']['serveraliasoption_none'], '2', '0', true, true);
|
$serveraliasoptions .= \Froxlor\UI\HTML::makeoption($lng['domains']['serveraliasoption_none'], '2', Settings::Get('system.domaindefaultalias'), true, true);
|
||||||
|
|
||||||
$subcanemaildomain = \Froxlor\UI\HTML::makeoption($lng['admin']['subcanemaildomain']['never'], '0', '0', true, true);
|
$subcanemaildomain = \Froxlor\UI\HTML::makeoption($lng['admin']['subcanemaildomain']['never'], '0', '0', true, true);
|
||||||
$subcanemaildomain .= \Froxlor\UI\HTML::makeoption($lng['admin']['subcanemaildomain']['choosableno'], '1', '0', true, true);
|
$subcanemaildomain .= \Froxlor\UI\HTML::makeoption($lng['admin']['subcanemaildomain']['choosableno'], '1', '0', true, true);
|
||||||
|
|||||||
23
build.xml
23
build.xml
@@ -6,21 +6,20 @@
|
|||||||
<property name="pdepend" value="${basedir}/vendor/bin/pdepend" />
|
<property name="pdepend" value="${basedir}/vendor/bin/pdepend" />
|
||||||
<property name="phpcpd" value="${basedir}/vendor/bin/phpcpd" />
|
<property name="phpcpd" value="${basedir}/vendor/bin/phpcpd" />
|
||||||
<property name="phpcs" value="${basedir}/vendor/bin/phpcs" />
|
<property name="phpcs" value="${basedir}/vendor/bin/phpcs" />
|
||||||
<property name="phpdox" value="${basedir}/vendor/bin/phpdox" />
|
|
||||||
<property name="phploc" value="${basedir}/vendor/bin/phploc" />
|
<property name="phploc" value="${basedir}/vendor/bin/phploc" />
|
||||||
<property name="phpmd" value="${basedir}/vendor/bin/phpmd" />
|
<property name="phpmd" value="${basedir}/vendor/bin/phpmd" />
|
||||||
<property name="phpunit" value="${basedir}/vendor/bin/phpunit" />
|
<property name="phpunit" value="${basedir}/vendor/bin/phpunit" />
|
||||||
|
|
||||||
<target name="full-build"
|
<target name="full-build"
|
||||||
depends="prepare,composer,static-analysis,phpunit,phpdox,-check-failure"
|
depends="prepare,composer,static-analysis,phpunit,-check-failure"
|
||||||
description="Performs static analysis, runs the tests, and generates project documentation" />
|
description="Performs static analysis, runs the tests, and generates project documentation" />
|
||||||
|
|
||||||
<target name="full-build-parallel"
|
<target name="full-build-parallel"
|
||||||
depends="prepare,composer,static-analysis-parallel,phpunit,phpdox,-check-failure"
|
depends="prepare,composer,static-analysis-parallel,phpunit,-check-failure"
|
||||||
description="Performs static analysis (executing the tools in parallel), runs the tests, and generates project documentation" />
|
description="Performs static analysis (executing the tools in parallel), runs the tests, and generates project documentation" />
|
||||||
|
|
||||||
<target name="quick-build"
|
<target name="quick-build"
|
||||||
depends="prepare,composer,lint,phpunit-no-coverage"
|
depends="prepare,composer,lint,phpunit-no-coverage,-check-failure"
|
||||||
description="Performs a lint check and runs the tests (without generating code coverage reports)" />
|
description="Performs a lint check and runs the tests (without generating code coverage reports)" />
|
||||||
|
|
||||||
<target name="static-analysis"
|
<target name="static-analysis"
|
||||||
@@ -49,7 +48,6 @@
|
|||||||
<delete dir="${basedir}/build/coverage" />
|
<delete dir="${basedir}/build/coverage" />
|
||||||
<delete dir="${basedir}/build/logs" />
|
<delete dir="${basedir}/build/logs" />
|
||||||
<delete dir="${basedir}/build/pdepend" />
|
<delete dir="${basedir}/build/pdepend" />
|
||||||
<delete dir="${basedir}/build/phpdox" />
|
|
||||||
<property name="clean.done" value="true" />
|
<property name="clean.done" value="true" />
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
@@ -59,7 +57,6 @@
|
|||||||
<mkdir dir="${basedir}/build/coverage" />
|
<mkdir dir="${basedir}/build/coverage" />
|
||||||
<mkdir dir="${basedir}/build/logs" />
|
<mkdir dir="${basedir}/build/logs" />
|
||||||
<mkdir dir="${basedir}/build/pdepend" />
|
<mkdir dir="${basedir}/build/pdepend" />
|
||||||
<mkdir dir="${basedir}/build/phpdox" />
|
|
||||||
|
|
||||||
<property name="prepare.done" value="true" />
|
<property name="prepare.done" value="true" />
|
||||||
</target>
|
</target>
|
||||||
@@ -257,7 +254,7 @@
|
|||||||
<target name="phpunit-no-coverage" unless="phpunit.done"
|
<target name="phpunit-no-coverage" unless="phpunit.done"
|
||||||
depends="composer"
|
depends="composer"
|
||||||
description="Run unit tests with PHPUnit (without generating code coverage reports)">
|
description="Run unit tests with PHPUnit (without generating code coverage reports)">
|
||||||
<exec executable="${phpunit}" failonerror="true"
|
<exec executable="${phpunit}" failonerror="true" resultproperty="result.phpunit"
|
||||||
taskname="phpunit">
|
taskname="phpunit">
|
||||||
<arg value="--configuration" />
|
<arg value="--configuration" />
|
||||||
<arg path="${basedir}/phpunit.xml" />
|
<arg path="${basedir}/phpunit.xml" />
|
||||||
@@ -269,18 +266,6 @@
|
|||||||
<property name="phpunit.done" value="true" />
|
<property name="phpunit.done" value="true" />
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="phpdox" unless="phpdox.done"
|
|
||||||
depends="phploc-ci,phpcs-ci,phpcompat-ci,phpmd-ci"
|
|
||||||
description="Generate project documentation using phpDox">
|
|
||||||
<exec executable="${phpdox}" dir="${basedir}/build"
|
|
||||||
taskname="phpdox">
|
|
||||||
<arg value="--file" />
|
|
||||||
<arg path="${basedir}/phpdox.xml" />
|
|
||||||
</exec>
|
|
||||||
|
|
||||||
<property name="phpdox.done" value="true" />
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="-check-failure">
|
<target name="-check-failure">
|
||||||
<fail message="PHPUnit did not finish successfully">
|
<fail message="PHPUnit did not finish successfully">
|
||||||
<condition>
|
<condition>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"issues": "https://github.com/Froxlor/Froxlor/issues",
|
"issues": "https://github.com/Froxlor/Froxlor/issues",
|
||||||
"forum": "https://forum.froxlor.org/",
|
"forum": "https://forum.froxlor.org/",
|
||||||
"wiki": "https://github.com/Froxlor/Froxlor/wiki",
|
"wiki": "https://github.com/Froxlor/Froxlor/wiki",
|
||||||
"irc": "irc://chat.freenode.net/froxlor",
|
"irc": "irc://irc.libera.chat/froxlor",
|
||||||
"source": "https://github.com/Froxlor/Froxlor",
|
"source": "https://github.com/Froxlor/Froxlor",
|
||||||
"docs": "https://github.com/Froxlor/Froxlor/wiki"
|
"docs": "https://github.com/Froxlor/Froxlor/wiki"
|
||||||
},
|
},
|
||||||
@@ -43,23 +43,24 @@
|
|||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
|
"ext-fileinfo": "*",
|
||||||
"phpmailer/phpmailer": "~6.0",
|
"phpmailer/phpmailer": "~6.0",
|
||||||
"monolog/monolog": "^1.24",
|
"monolog/monolog": "^1.24",
|
||||||
"robthree/twofactorauth": "^1.6",
|
"robthree/twofactorauth": "^1.6",
|
||||||
"froxlor/idna-convert-legacy": "^2.1",
|
"froxlor/idna-convert-legacy": "^2.1",
|
||||||
"voku/anti-xss": "^4.1"
|
"voku/anti-xss": "^4.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "8.4.1",
|
"phpunit/phpunit": "^9",
|
||||||
"php": ">=7.3",
|
"php": ">=7.3",
|
||||||
"ext-pcntl": "*",
|
"ext-pcntl": "*",
|
||||||
"phpcompatibility/php-compatibility": "*",
|
"phpcompatibility/php-compatibility": "*",
|
||||||
"squizlabs/php_codesniffer": "*",
|
"squizlabs/php_codesniffer": "*",
|
||||||
"pdepend/pdepend": "^2.5",
|
"pdepend/pdepend": "^2.9",
|
||||||
"sebastian/phpcpd": "^4.1",
|
"sebastian/phpcpd": "^6.0",
|
||||||
"theseer/phpdox": "^0.12.0",
|
"phploc/phploc": "^7.0",
|
||||||
"phploc/phploc": "^5.0",
|
"phpmd/phpmd": "^2.10",
|
||||||
"phpmd/phpmd": "^2.6"
|
"phpunit/php-timer" : "^5"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-bcmath": "*",
|
"ext-bcmath": "*",
|
||||||
|
|||||||
1687
composer.lock
generated
1687
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -628,7 +628,7 @@ opcache.interned_strings_buffer'),
|
|||||||
('system', 'apacheitksupport', '0'),
|
('system', 'apacheitksupport', '0'),
|
||||||
('system', 'leprivatekey', 'unset'),
|
('system', 'leprivatekey', 'unset'),
|
||||||
('system', 'lepublickey', 'unset'),
|
('system', 'lepublickey', 'unset'),
|
||||||
('system', 'letsencryptca', 'production'),
|
('system', 'letsencryptca', 'letsencrypt'),
|
||||||
('system', 'letsencryptcountrycode', 'DE'),
|
('system', 'letsencryptcountrycode', 'DE'),
|
||||||
('system', 'letsencryptstate', 'Hessen'),
|
('system', 'letsencryptstate', 'Hessen'),
|
||||||
('system', 'letsencryptchallengepath', '/var/www/froxlor'),
|
('system', 'letsencryptchallengepath', '/var/www/froxlor'),
|
||||||
@@ -677,6 +677,7 @@ opcache.interned_strings_buffer'),
|
|||||||
('system', 'hide_incompatible_settings', '0'),
|
('system', 'hide_incompatible_settings', '0'),
|
||||||
('system', 'include_default_vhostconf', '0'),
|
('system', 'include_default_vhostconf', '0'),
|
||||||
('system', 'soaemail', ''),
|
('system', 'soaemail', ''),
|
||||||
|
('system', 'domaindefaultalias', '0'),
|
||||||
('api', 'enabled', '0'),
|
('api', 'enabled', '0'),
|
||||||
('2fa', 'enabled', '1'),
|
('2fa', 'enabled', '1'),
|
||||||
('panel', 'decimal_places', '4'),
|
('panel', 'decimal_places', '4'),
|
||||||
@@ -714,8 +715,10 @@ opcache.interned_strings_buffer'),
|
|||||||
('panel', 'imprint_url', ''),
|
('panel', 'imprint_url', ''),
|
||||||
('panel', 'terms_url', ''),
|
('panel', 'terms_url', ''),
|
||||||
('panel', 'privacy_url', ''),
|
('panel', 'privacy_url', ''),
|
||||||
('panel', 'version', '0.10.26'),
|
('panel', 'logo_image_header', ''),
|
||||||
('panel', 'db_version', '202103240');
|
('panel', 'logo_image_login', ''),
|
||||||
|
('panel', 'version', '0.10.27'),
|
||||||
|
('panel', 'db_version', '202107070');
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_tasks`;
|
DROP TABLE IF EXISTS `panel_tasks`;
|
||||||
|
|||||||
@@ -784,7 +784,7 @@ class FroxlorInstall
|
|||||||
}
|
}
|
||||||
// language selection
|
// language selection
|
||||||
$language_options = '';
|
$language_options = '';
|
||||||
foreach ($this->_languages as $language_name => $language_file) {
|
foreach ($this->_languages as $language_file => $language_name) {
|
||||||
$language_options .= \Froxlor\UI\HTML::makeoption($language_name, $language_file, $this->_activelng, true, true);
|
$language_options .= \Froxlor\UI\HTML::makeoption($language_name, $language_file, $this->_activelng, true, true);
|
||||||
}
|
}
|
||||||
// get language-form-template
|
// get language-form-template
|
||||||
@@ -867,19 +867,24 @@ class FroxlorInstall
|
|||||||
}
|
}
|
||||||
|
|
||||||
// show list of available distro's
|
// show list of available distro's
|
||||||
|
$distributions_select_data = [];
|
||||||
$distros = glob(\Froxlor\FileDir::makeCorrectDir(\Froxlor\Froxlor::getInstallDir() . '/lib/configfiles/') . '*.xml');
|
$distros = glob(\Froxlor\FileDir::makeCorrectDir(\Froxlor\Froxlor::getInstallDir() . '/lib/configfiles/') . '*.xml');
|
||||||
foreach ($distros as $_distribution) {
|
foreach ($distros as $_distribution) {
|
||||||
$dist = new \Froxlor\Config\ConfigParser($_distribution);
|
$dist = new \Froxlor\Config\ConfigParser($_distribution);
|
||||||
$dist_display = $dist->distributionName . " " . $dist->distributionCodename . " (" . $dist->distributionVersion . ")";
|
$dist_display = $dist->distributionName . " " . $dist->distributionCodename . " (" . $dist->distributionVersion . ")";
|
||||||
|
if (!array_key_exists($dist_display, $distributions_select_data)) {
|
||||||
|
$distributions_select_data[$dist_display] = '';
|
||||||
|
}
|
||||||
$distributions_select_data[$dist_display] .= str_replace(".xml", "", strtolower(basename($_distribution)));
|
$distributions_select_data[$dist_display] .= str_replace(".xml", "", strtolower(basename($_distribution)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort by distribution name
|
// sort by distribution name
|
||||||
ksort($distributions_select_data);
|
ksort($distributions_select_data);
|
||||||
|
|
||||||
|
$distributions_select = '';
|
||||||
foreach ($distributions_select_data as $dist_display => $dist_index) {
|
foreach ($distributions_select_data as $dist_display => $dist_index) {
|
||||||
// create select-box-option
|
// create select-box-option
|
||||||
$distributions_select .= \Froxlor\UI\HTML::makeoption($dist_display, $dist_index, $this->_data['distribution']);
|
$distributions_select .= \Froxlor\UI\HTML::makeoption($dist_display, $dist_index, $this->_data['distribution'] ?? '');
|
||||||
// $this->_data['distribution']
|
// $this->_data['distribution']
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -994,7 +999,6 @@ class FroxlorInstall
|
|||||||
*/
|
*/
|
||||||
private function _getSectionItemSelectbox($fieldname = null, $options = null, $style = "")
|
private function _getSectionItemSelectbox($fieldname = null, $options = null, $style = "")
|
||||||
{
|
{
|
||||||
$groupname = $this->_lng['install'][$groupname];
|
|
||||||
$fieldlabel = $this->_lng['install'][$fieldname];
|
$fieldlabel = $this->_lng['install'][$fieldname];
|
||||||
|
|
||||||
$sectionitem = "";
|
$sectionitem = "";
|
||||||
|
|||||||
@@ -803,3 +803,67 @@ if (\Froxlor\Froxlor::isFroxlorVersion('0.10.25')) {
|
|||||||
showUpdateStep("Updating from 0.10.25 to 0.10.26", false);
|
showUpdateStep("Updating from 0.10.25 to 0.10.26", false);
|
||||||
\Froxlor\Froxlor::updateToVersion('0.10.26');
|
\Froxlor\Froxlor::updateToVersion('0.10.26');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (\Froxlor\Froxlor::isDatabaseVersion('202103240')) {
|
||||||
|
|
||||||
|
showUpdateStep("Adding setting for default serveralias value for new domains", true);
|
||||||
|
Settings::AddNew("system.domaindefaultalias", '0');
|
||||||
|
lastStepStatus(0);
|
||||||
|
|
||||||
|
\Froxlor\Froxlor::updateToDbVersion('202106160');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\Froxlor\Froxlor::isDatabaseVersion('202106160')) {
|
||||||
|
|
||||||
|
showUpdateStep("Adjusting Let's Encrypt endpoint configuration to support ZeroSSL", true);
|
||||||
|
if (Settings::Get('system.letsencryptca') == 'testing') {
|
||||||
|
Settings::Set("system.letsencryptca", 'letsencrypt_test');
|
||||||
|
} else {
|
||||||
|
Settings::Set("system.letsencryptca", 'letsencrypt');
|
||||||
|
}
|
||||||
|
lastStepStatus(0);
|
||||||
|
|
||||||
|
\Froxlor\Froxlor::updateToDbVersion('202106270');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\Froxlor\Froxlor::isDatabaseVersion('202106270')) {
|
||||||
|
showUpdateStep("Adding custom logo image settings", true);
|
||||||
|
Settings::AddNew("panel.logo_image_header", '');
|
||||||
|
Settings::AddNew("panel.logo_image_login", '');
|
||||||
|
lastStepStatus(0);
|
||||||
|
|
||||||
|
// Migrating old custom logo over, if exists
|
||||||
|
$custom_logo_file_old = \Froxlor\Froxlor::getInstallDir() . '/templates/Sparkle/assets/img/logo_custom.png';
|
||||||
|
if (file_exists($custom_logo_file_old)) {
|
||||||
|
showUpdateStep("Migrating existing custom logo to new settings", true);
|
||||||
|
|
||||||
|
$path = \Froxlor\Froxlor::getInstallDir().'/img/';
|
||||||
|
if (!is_dir($path) && !mkdir($path, 0775)) {
|
||||||
|
throw new \Exception("img directory does not exist and cannot be created");
|
||||||
|
}
|
||||||
|
if (!is_writable($path)) {
|
||||||
|
if (!chmod($path, '0775')) {
|
||||||
|
throw new \Exception("Cannot write to img directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save as new custom logo header
|
||||||
|
$save_to = 'logo_header.png';
|
||||||
|
copy($custom_logo_file_old, $path.$save_to);
|
||||||
|
Settings::Set("panel.logo_image_header", "img/{$save_to}?v=".time());
|
||||||
|
|
||||||
|
// Save as new custom logo login
|
||||||
|
$save_to = 'logo_login.png';
|
||||||
|
copy($custom_logo_file_old, $path.$save_to);
|
||||||
|
Settings::Set("panel.logo_image_login", "img/{$save_to}?v=".time());
|
||||||
|
|
||||||
|
lastStepStatus(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
\Froxlor\Froxlor::updateToDbVersion('202107070');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.26')) {
|
||||||
|
showUpdateStep("Updating from 0.10.26 to 0.10.27", false);
|
||||||
|
\Froxlor\Froxlor::updateToVersion('0.10.27');
|
||||||
|
}
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
|
|||||||
* @param bool $email_only
|
* @param bool $email_only
|
||||||
* optional, restrict domain to email usage, default 0 (false)
|
* optional, restrict domain to email usage, default 0 (false)
|
||||||
* @param int $selectserveralias
|
* @param int $selectserveralias
|
||||||
* optional, 0 = wildcard, 1 = www-alias, 2 = none, default 0
|
* optional, 0 = wildcard, 1 = www-alias, 2 = none, default [system.domaindefaultalias]
|
||||||
* @param bool $speciallogfile
|
* @param bool $speciallogfile
|
||||||
* optional, whether to create an exclusive web-logfile for this domain, default 0 (false)
|
* optional, whether to create an exclusive web-logfile for this domain, default 0 (false)
|
||||||
* @param int $alias
|
* @param int $alias
|
||||||
@@ -309,7 +309,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
|
|||||||
$subcanemaildomain = $this->getParam('subcanemaildomain', true, 0);
|
$subcanemaildomain = $this->getParam('subcanemaildomain', true, 0);
|
||||||
$isemaildomain = $this->getBoolParam('isemaildomain', true, 0);
|
$isemaildomain = $this->getBoolParam('isemaildomain', true, 0);
|
||||||
$email_only = $this->getBoolParam('email_only', true, 0);
|
$email_only = $this->getBoolParam('email_only', true, 0);
|
||||||
$serveraliasoption = $this->getParam('selectserveralias', true, 0);
|
$serveraliasoption = $this->getParam('selectserveralias', true, Settings::Get('system.domaindefaultalias'));
|
||||||
$speciallogfile = $this->getBoolParam('speciallogfile', true, 0);
|
$speciallogfile = $this->getBoolParam('speciallogfile', true, 0);
|
||||||
$aliasdomain = intval($this->getParam('alias', true, 0));
|
$aliasdomain = intval($this->getParam('alias', true, 0));
|
||||||
$issubof = $this->getParam('issubof', true, 0);
|
$issubof = $this->getParam('issubof', true, 0);
|
||||||
|
|||||||
@@ -28,63 +28,69 @@ use Froxlor\FileDir;
|
|||||||
class AcmeSh extends \Froxlor\Cron\FroxlorCron
|
class AcmeSh extends \Froxlor\Cron\FroxlorCron
|
||||||
{
|
{
|
||||||
|
|
||||||
private static $apiserver = "";
|
const ACME_PROVIDER = [
|
||||||
|
'letsencrypt' => "https://acme-v02.api.letsencrypt.org/directory",
|
||||||
|
'letsencrypt_test' => "https://acme-staging-v02.api.letsencrypt.org/directory",
|
||||||
|
'zerossl' => "https://acme.zerossl.com/v2/DV90"
|
||||||
|
];
|
||||||
|
|
||||||
private static $acmesh = "/root/.acme.sh/acme.sh";
|
private static $apiserver = "";
|
||||||
|
|
||||||
/**
|
private static $acmesh = "/root/.acme.sh/acme.sh";
|
||||||
*
|
|
||||||
* @var \PDOStatement
|
|
||||||
*/
|
|
||||||
private static $updcert_stmt = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @var \PDOStatement
|
* @var \PDOStatement
|
||||||
*/
|
*/
|
||||||
private static $upddom_stmt = null;
|
private static $updcert_stmt = null;
|
||||||
|
|
||||||
public static $no_inserttask = false;
|
/**
|
||||||
|
*
|
||||||
|
* @var \PDOStatement
|
||||||
|
*/
|
||||||
|
private static $upddom_stmt = null;
|
||||||
|
|
||||||
/**
|
public static $no_inserttask = false;
|
||||||
* run the task
|
|
||||||
*
|
|
||||||
* @param boolean $internal
|
|
||||||
* @return number
|
|
||||||
*/
|
|
||||||
public static function run($internal = false)
|
|
||||||
{
|
|
||||||
// usually, this is action is called from within the tasks-jobs
|
|
||||||
if (! defined('CRON_IS_FORCED') && ! defined('CRON_DEBUG_FLAG') && $internal == false) {
|
|
||||||
// Let's Encrypt cronjob is combined with regeneration of webserver configuration files.
|
|
||||||
// For debugging purposes you can use the --debug switch and the --force switch to run the cron manually.
|
|
||||||
// check whether we MIGHT need to run although there is no task to regenerate config-files
|
|
||||||
$issue_froxlor = self::issueFroxlorVhost();
|
|
||||||
$issue_domains = self::issueDomains();
|
|
||||||
$renew_froxlor = self::renewFroxlorVhost();
|
|
||||||
$renew_domains = self::renewDomains(true);
|
|
||||||
if ($issue_froxlor || !empty($issue_domains) || !empty($renew_froxlor) || $renew_domains) {
|
|
||||||
// insert task to generate certificates and vhost-configs
|
|
||||||
\Froxlor\System\Cronjob::inserttask(1);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set server according to settings
|
/**
|
||||||
self::$apiserver = 'https://acme-' . (Settings::Get('system.letsencryptca') == 'testing' ? 'staging-' : '') . 'v0' . \Froxlor\Settings::Get('system.leapiversion') . '.api.letsencrypt.org/directory';
|
* run the task
|
||||||
|
*
|
||||||
|
* @param boolean $internal
|
||||||
|
* @return number
|
||||||
|
*/
|
||||||
|
public static function run($internal = false)
|
||||||
|
{
|
||||||
|
// usually, this is action is called from within the tasks-jobs
|
||||||
|
if (! defined('CRON_IS_FORCED') && ! defined('CRON_DEBUG_FLAG') && $internal == false) {
|
||||||
|
// Let's Encrypt cronjob is combined with regeneration of webserver configuration files.
|
||||||
|
// For debugging purposes you can use the --debug switch and the --force switch to run the cron manually.
|
||||||
|
// check whether we MIGHT need to run although there is no task to regenerate config-files
|
||||||
|
$issue_froxlor = self::issueFroxlorVhost();
|
||||||
|
$issue_domains = self::issueDomains();
|
||||||
|
$renew_froxlor = self::renewFroxlorVhost();
|
||||||
|
$renew_domains = self::renewDomains(true);
|
||||||
|
if ($issue_froxlor || ! empty($issue_domains) || ! empty($renew_froxlor) || $renew_domains) {
|
||||||
|
// insert task to generate certificates and vhost-configs
|
||||||
|
\Froxlor\System\Cronjob::inserttask(1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// validate acme.sh installation
|
// set server according to settings
|
||||||
if (! self::checkInstall()) {
|
self::$apiserver = self::ACME_PROVIDER[Settings::Get('system.letsencryptca')];
|
||||||
return - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self::checkUpgrade();
|
// validate acme.sh installation
|
||||||
|
if (! self::checkInstall()) {
|
||||||
|
return - 1;
|
||||||
|
}
|
||||||
|
|
||||||
// flag for re-generation of vhost files
|
self::checkUpgrade();
|
||||||
$changedetected = 0;
|
|
||||||
|
|
||||||
// prepare update sql
|
// flag for re-generation of vhost files
|
||||||
self::$updcert_stmt = Database::prepare("
|
$changedetected = 0;
|
||||||
|
|
||||||
|
// prepare update sql
|
||||||
|
self::$updcert_stmt = Database::prepare("
|
||||||
REPLACE INTO
|
REPLACE INTO
|
||||||
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
||||||
SET
|
SET
|
||||||
@@ -99,99 +105,99 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron
|
|||||||
`expirationdate` = :expirationdate
|
`expirationdate` = :expirationdate
|
||||||
");
|
");
|
||||||
|
|
||||||
// prepare domain update sql
|
// prepare domain update sql
|
||||||
self::$upddom_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `ssl_redirect` = '1' WHERE `id` = :domainid");
|
self::$upddom_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `ssl_redirect` = '1' WHERE `id` = :domainid");
|
||||||
|
|
||||||
// check whether there are certificates to issue
|
// check whether there are certificates to issue
|
||||||
$issue_froxlor = self::issueFroxlorVhost();
|
$issue_froxlor = self::issueFroxlorVhost();
|
||||||
$issue_domains = self::issueDomains();
|
$issue_domains = self::issueDomains();
|
||||||
|
|
||||||
// first - generate LE for system-vhost if enabled
|
// first - generate LE for system-vhost if enabled
|
||||||
if ($issue_froxlor) {
|
if ($issue_froxlor) {
|
||||||
// build row
|
// build row
|
||||||
$certrow = array(
|
$certrow = array(
|
||||||
'loginname' => 'froxlor.panel',
|
'loginname' => 'froxlor.panel',
|
||||||
'domain' => Settings::Get('system.hostname'),
|
'domain' => Settings::Get('system.hostname'),
|
||||||
'domainid' => 0,
|
'domainid' => 0,
|
||||||
'documentroot' => \Froxlor\Froxlor::getInstallDir(),
|
'documentroot' => \Froxlor\Froxlor::getInstallDir(),
|
||||||
'leprivatekey' => Settings::Get('system.leprivatekey'),
|
'leprivatekey' => Settings::Get('system.leprivatekey'),
|
||||||
'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,
|
'expirationdate' => null,
|
||||||
'ssl_cert_file' => null,
|
'ssl_cert_file' => null,
|
||||||
'ssl_key_file' => null,
|
'ssl_key_file' => null,
|
||||||
'ssl_ca_file' => null,
|
'ssl_ca_file' => null,
|
||||||
'ssl_csr_file' => null,
|
'ssl_csr_file' => null,
|
||||||
'id' => null
|
'id' => null
|
||||||
);
|
);
|
||||||
|
|
||||||
// add to queue
|
// add to queue
|
||||||
$issue_domains[] = $certrow;
|
$issue_domains[] = $certrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($issue_domains)) {
|
if (count($issue_domains)) {
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Requesting " . count($issue_domains) . " new Let's Encrypt certificates");
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Requesting " . count($issue_domains) . " new Let's Encrypt certificates");
|
||||||
self::runIssueFor($issue_domains);
|
self::runIssueFor($issue_domains);
|
||||||
$changedetected = 1;
|
$changedetected = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// compare file-system certificates with the ones in our database
|
// compare file-system certificates with the ones in our database
|
||||||
// and update if needed
|
// and update if needed
|
||||||
$renew_froxlor = self::renewFroxlorVhost();
|
$renew_froxlor = self::renewFroxlorVhost();
|
||||||
$renew_domains = self::renewDomains();
|
$renew_domains = self::renewDomains();
|
||||||
|
|
||||||
if ($renew_froxlor) {
|
if ($renew_froxlor) {
|
||||||
// build row
|
// build row
|
||||||
$certrow = array(
|
$certrow = array(
|
||||||
'loginname' => 'froxlor.panel',
|
'loginname' => 'froxlor.panel',
|
||||||
'domain' => Settings::Get('system.hostname'),
|
'domain' => Settings::Get('system.hostname'),
|
||||||
'domainid' => 0,
|
'domainid' => 0,
|
||||||
'documentroot' => \Froxlor\Froxlor::getInstallDir(),
|
'documentroot' => \Froxlor\Froxlor::getInstallDir(),
|
||||||
'leprivatekey' => Settings::Get('system.leprivatekey'),
|
'leprivatekey' => Settings::Get('system.leprivatekey'),
|
||||||
'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),
|
'expirationdate' => is_array($renew_froxlor) ? $renew_froxlor['expirationdate'] : date('Y-m-d H:i:s', 0),
|
||||||
'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,
|
||||||
'ssl_csr_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_csr_file'] : null,
|
'ssl_csr_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_csr_file'] : null,
|
||||||
'id' => is_array($renew_froxlor) ? $renew_froxlor['id'] : null
|
'id' => is_array($renew_froxlor) ? $renew_froxlor['id'] : null
|
||||||
);
|
);
|
||||||
$renew_domains[] = $certrow;
|
$renew_domains[] = $certrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($renew_domains as $domain) {
|
foreach ($renew_domains as $domain) {
|
||||||
$cronlog = FroxlorLogger::getInstanceOf(array(
|
$cronlog = FroxlorLogger::getInstanceOf(array(
|
||||||
'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['expirationdate'])) {
|
||||||
self::certToDb($domain, $cronlog, array());
|
self::certToDb($domain, $cronlog, array());
|
||||||
$changedetected = 1;
|
$changedetected = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a change in a certificate, we need to update the webserver - configs
|
// If we have a change in a certificate, we need to update the webserver - configs
|
||||||
// This is easiest done by just creating a new task ;)
|
// This is easiest done by just creating a new task ;)
|
||||||
if ($changedetected) {
|
if ($changedetected) {
|
||||||
if (self::$no_inserttask == false) {
|
if (self::$no_inserttask == false) {
|
||||||
\Froxlor\System\Cronjob::inserttask(1);
|
\Froxlor\System\Cronjob::inserttask(1);
|
||||||
}
|
}
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Let's Encrypt certificates have been updated");
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Let's Encrypt certificates have been updated");
|
||||||
} else {
|
} else {
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "No new certificates or certificate updates found");
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "No new certificates or certificate updates found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* issue certificates for a list of domains
|
* issue certificates for a list of domains
|
||||||
*/
|
*/
|
||||||
private static function runIssueFor($certrows = array())
|
private static function runIssueFor($certrows = array())
|
||||||
{
|
{
|
||||||
// prepare aliasdomain-check
|
// prepare aliasdomain-check
|
||||||
$aliasdomains_stmt = Database::prepare("
|
$aliasdomains_stmt = Database::prepare("
|
||||||
SELECT
|
SELECT
|
||||||
dom.`id` as domainid,
|
dom.`id` as domainid,
|
||||||
dom.`domain`,
|
dom.`domain`,
|
||||||
@@ -202,216 +208,216 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron
|
|||||||
AND dom.`letsencrypt` = 1
|
AND dom.`letsencrypt` = 1
|
||||||
AND dom.`iswildcarddomain` = 0
|
AND dom.`iswildcarddomain` = 0
|
||||||
");
|
");
|
||||||
// iterate through all domains
|
// iterate through all domains
|
||||||
foreach ($certrows as $certrow) {
|
foreach ($certrows as $certrow) {
|
||||||
// set logger to corresponding loginname for the log to appear in the users system-log
|
// set logger to corresponding loginname for the log to appear in the users system-log
|
||||||
$cronlog = FroxlorLogger::getInstanceOf(array(
|
$cronlog = FroxlorLogger::getInstanceOf(array(
|
||||||
'loginname' => $certrow['loginname'],
|
'loginname' => $certrow['loginname'],
|
||||||
'adminsession' => 0
|
'adminsession' => 0
|
||||||
));
|
));
|
||||||
// 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['expirationdate'])) {
|
||||||
// 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']);
|
||||||
} else {
|
} else {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Creating certificate for " . $certrow['domain']);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Creating certificate for " . $certrow['domain']);
|
||||||
}
|
}
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding common-name: " . $certrow['domain']);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding common-name: " . $certrow['domain']);
|
||||||
$domains = array(
|
$domains = array(
|
||||||
strtolower($certrow['domain'])
|
strtolower($certrow['domain'])
|
||||||
);
|
);
|
||||||
// add www.<domain> to SAN list
|
// add www.<domain> to SAN list
|
||||||
if ($certrow['wwwserveralias'] == 1) {
|
if ($certrow['wwwserveralias'] == 1) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $certrow['domain']);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $certrow['domain']);
|
||||||
$domains[] = strtolower('www.' . $certrow['domain']);
|
$domains[] = strtolower('www.' . $certrow['domain']);
|
||||||
}
|
}
|
||||||
if ($certrow['domainid'] == 0) {
|
if ($certrow['domainid'] == 0) {
|
||||||
$froxlor_aliases = Settings::Get('system.froxloraliases');
|
$froxlor_aliases = Settings::Get('system.froxloraliases');
|
||||||
if (! empty($froxlor_aliases)) {
|
if (! empty($froxlor_aliases)) {
|
||||||
$froxlor_aliases = explode(",", $froxlor_aliases);
|
$froxlor_aliases = explode(",", $froxlor_aliases);
|
||||||
foreach ($froxlor_aliases as $falias) {
|
foreach ($froxlor_aliases as $falias) {
|
||||||
if (\Froxlor\Validate\Validate::validateDomain(trim($falias))) {
|
if (\Froxlor\Validate\Validate::validateDomain(trim($falias))) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . strtolower(trim($falias)));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . strtolower(trim($falias)));
|
||||||
$domains[] = strtolower(trim($falias));
|
$domains[] = strtolower(trim($falias));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// add alias domains (and possibly www.<aliasdomain>) to SAN list
|
// add alias domains (and possibly www.<aliasdomain>) to SAN list
|
||||||
Database::pexecute($aliasdomains_stmt, array(
|
Database::pexecute($aliasdomains_stmt, array(
|
||||||
'id' => $certrow['domainid']
|
'id' => $certrow['domainid']
|
||||||
));
|
));
|
||||||
$aliasdomains = $aliasdomains_stmt->fetchAll(\PDO::FETCH_ASSOC);
|
$aliasdomains = $aliasdomains_stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||||
foreach ($aliasdomains as $aliasdomain) {
|
foreach ($aliasdomains as $aliasdomain) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . $aliasdomain['domain']);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . $aliasdomain['domain']);
|
||||||
$domains[] = strtolower($aliasdomain['domain']);
|
$domains[] = strtolower($aliasdomain['domain']);
|
||||||
if ($aliasdomain['wwwserveralias'] == 1) {
|
if ($aliasdomain['wwwserveralias'] == 1) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $aliasdomain['domain']);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $aliasdomain['domain']);
|
||||||
$domains[] = strtolower('www.' . $aliasdomain['domain']);
|
$domains[] = strtolower('www.' . $aliasdomain['domain']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self::validateDns($domains, $certrow['domainid'], $cronlog);
|
self::validateDns($domains, $certrow['domainid'], $cronlog);
|
||||||
|
|
||||||
self::runAcmeSh($certrow, $domains, $cronlog, $do_force);
|
self::runAcmeSh($certrow, $domains, $cronlog, $do_force);
|
||||||
} else {
|
} else {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $certrow['domain'] . " due to an enabled ssl_redirect");
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $certrow['domain'] . " due to an enabled ssl_redirect");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* validate dns (A / AAAA record) of domain against known system ips
|
* validate dns (A / AAAA record) of domain against known system ips
|
||||||
*
|
*
|
||||||
* @param array $domains
|
* @param array $domains
|
||||||
* @param int $domain_id
|
* @param int $domain_id
|
||||||
* @param FroxlorLogger $cronlog
|
* @param FroxlorLogger $cronlog
|
||||||
*/
|
*/
|
||||||
private static function validateDns(array &$domains, $domain_id, &$cronlog)
|
private static function validateDns(array &$domains, $domain_id, &$cronlog)
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.le_domain_dnscheck') == '1' && ! empty($domains)) {
|
if (Settings::Get('system.le_domain_dnscheck') == '1' && ! empty($domains)) {
|
||||||
$loop_domains = $domains;
|
$loop_domains = $domains;
|
||||||
// ips according to our system
|
// ips according to our system
|
||||||
$our_ips = Domain::getIpsOfDomain($domain_id);
|
$our_ips = Domain::getIpsOfDomain($domain_id);
|
||||||
foreach ($loop_domains as $idx => $domain) {
|
foreach ($loop_domains as $idx => $domain) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Validating DNS of " . $domain);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Validating DNS of " . $domain);
|
||||||
// ips accordint to NS
|
// ips accordint to NS
|
||||||
$domain_ips = PhpHelper::gethostbynamel6($domain);
|
$domain_ips = PhpHelper::gethostbynamel6($domain);
|
||||||
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
||||||
// no common ips...
|
// no common ips...
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $domain . " due to no system known IP address via DNS check");
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $domain . " due to no system known IP address via DNS check");
|
||||||
unset($domains[$idx]);
|
unset($domains[$idx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function runAcmeSh(array $certrow, array $domains, &$cronlog = null, $force = false)
|
private static function runAcmeSh(array $certrow, array $domains, &$cronlog = null, $force = false)
|
||||||
{
|
{
|
||||||
if (! empty($domains)) {
|
if (! empty($domains)) {
|
||||||
|
|
||||||
$acmesh_cmd = self::$acmesh . " --server " . self::$apiserver . " --issue -d " . implode(" -d ", $domains);
|
$acmesh_cmd = self::$acmesh . " --server " . self::$apiserver . " --issue -d " . implode(" -d ", $domains);
|
||||||
// challenge path
|
// challenge path
|
||||||
$acmesh_cmd .= " -w " . Settings::Get('system.letsencryptchallengepath');
|
$acmesh_cmd .= " -w " . Settings::Get('system.letsencryptchallengepath');
|
||||||
if (Settings::Get('system.leecc') > 0) {
|
if (Settings::Get('system.leecc') > 0) {
|
||||||
// ecc certificate
|
// ecc certificate
|
||||||
$acmesh_cmd .= " --keylength ec-" . Settings::Get('system.leecc');
|
$acmesh_cmd .= " --keylength ec-" . Settings::Get('system.leecc');
|
||||||
} else {
|
} else {
|
||||||
$acmesh_cmd .= " --keylength " . Settings::Get('system.letsencryptkeysize');
|
$acmesh_cmd .= " --keylength " . Settings::Get('system.letsencryptkeysize');
|
||||||
}
|
}
|
||||||
if (Settings::Get('system.letsencryptreuseold') != '1') {
|
if (Settings::Get('system.letsencryptreuseold') != '1') {
|
||||||
$acmesh_cmd .= " --always-force-new-domain-key";
|
$acmesh_cmd .= " --always-force-new-domain-key";
|
||||||
}
|
}
|
||||||
if (Settings::Get('system.letsencryptca') == 'testing') {
|
if (Settings::Get('system.letsencryptca') == 'letsencrypt_test') {
|
||||||
$acmesh_cmd .= " --staging";
|
$acmesh_cmd .= " --staging";
|
||||||
}
|
}
|
||||||
if ($force) {
|
if ($force) {
|
||||||
$acmesh_cmd .= " --force";
|
$acmesh_cmd .= " --force";
|
||||||
}
|
}
|
||||||
if (defined('CRON_DEBUG_FLAG')) {
|
if (defined('CRON_DEBUG_FLAG')) {
|
||||||
$acmesh_cmd .= " --debug";
|
$acmesh_cmd .= " --debug";
|
||||||
}
|
}
|
||||||
|
|
||||||
$acme_result = \Froxlor\FileDir::safe_exec($acmesh_cmd);
|
$acme_result = \Froxlor\FileDir::safe_exec($acmesh_cmd);
|
||||||
// debug output of acme.sh run
|
// debug output of acme.sh run
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, implode("\n", $acme_result));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, implode("\n", $acme_result));
|
||||||
|
|
||||||
self::certToDb($certrow, $cronlog, $acme_result);
|
self::certToDb($certrow, $cronlog, $acme_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function certToDb($certrow, &$cronlog, $acme_result)
|
private static function certToDb($certrow, &$cronlog, $acme_result)
|
||||||
{
|
{
|
||||||
$return = array();
|
$return = array();
|
||||||
self::readCertificateToVar(strtolower($certrow['domain']), $return, $cronlog);
|
self::readCertificateToVar(strtolower($certrow['domain']), $return, $cronlog);
|
||||||
|
|
||||||
if (! empty($return['crt'])) {
|
if (! empty($return['crt'])) {
|
||||||
|
|
||||||
$newcert = openssl_x509_parse($return['crt']);
|
$newcert = openssl_x509_parse($return['crt']);
|
||||||
|
|
||||||
if ($newcert) {
|
if ($newcert) {
|
||||||
// Store the new data
|
// Store the new data
|
||||||
Database::pexecute(self::$updcert_stmt, array(
|
Database::pexecute(self::$updcert_stmt, array(
|
||||||
'id' => $certrow['id'],
|
'id' => $certrow['id'],
|
||||||
'domainid' => $certrow['domainid'],
|
'domainid' => $certrow['domainid'],
|
||||||
'crt' => $return['crt'],
|
'crt' => $return['crt'],
|
||||||
'key' => $return['key'],
|
'key' => $return['key'],
|
||||||
'ca' => $return['chain'],
|
'ca' => $return['chain'],
|
||||||
'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'])
|
'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t'])
|
||||||
));
|
));
|
||||||
|
|
||||||
if ($certrow['ssl_redirect'] == 3) {
|
if ($certrow['ssl_redirect'] == 3) {
|
||||||
Database::pexecute(self::$upddom_stmt, array(
|
Database::pexecute(self::$upddom_stmt, array(
|
||||||
'domainid' => $certrow['domainid']
|
'domainid' => $certrow['domainid']
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Updated Let's Encrypt certificate for " . $certrow['domain']);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Updated Let's Encrypt certificate for " . $certrow['domain']);
|
||||||
} else {
|
} else {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Got non-successful Let's Encrypt response for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Got non-successful Let's Encrypt response for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not get Let's Encrypt certificate for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not get Let's Encrypt certificate for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check whether we need to issue a new certificate for froxlor itself
|
* check whether we need to issue a new certificate for froxlor itself
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
private static function issueFroxlorVhost()
|
private static function issueFroxlorVhost()
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.le_froxlor_enabled') == '1') {
|
if (Settings::Get('system.le_froxlor_enabled') == '1') {
|
||||||
// let's encrypt is enabled, now check whether we have a certificate
|
// let's encrypt is enabled, now check whether we have a certificate
|
||||||
$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'
|
WHERE `domainid` = '0'
|
||||||
");
|
");
|
||||||
$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 && ! self::checkFsFilesAreNewer(Settings::Get('system.hostname'), date('Y-m-d H:i:s'))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check whether we need to renew-check the certificate for froxlor itself
|
* check whether we need to renew-check the certificate for froxlor itself
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
private static function renewFroxlorVhost()
|
private static function renewFroxlorVhost()
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.le_froxlor_enabled') == '1') {
|
if (Settings::Get('system.le_froxlor_enabled') == '1') {
|
||||||
// let's encrypt is enabled, now check whether we have a certificate
|
// let's encrypt is enabled, now check whether we have a certificate
|
||||||
$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'
|
WHERE `domainid` = '0'
|
||||||
");
|
");
|
||||||
$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['expirationdate'])) {
|
||||||
return $froxlor_ssl;
|
return $froxlor_ssl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a list of domains that have a lets encrypt certificate (possible renew)
|
* get a list of domains that have a lets encrypt certificate (possible renew)
|
||||||
*/
|
*/
|
||||||
private static function renewDomains($check = false)
|
private static function renewDomains($check = false)
|
||||||
{
|
{
|
||||||
$certificates_stmt = Database::query("
|
$certificates_stmt = Database::query("
|
||||||
SELECT
|
SELECT
|
||||||
domssl.`id`,
|
domssl.`id`,
|
||||||
domssl.`domainid`,
|
domssl.`domainid`,
|
||||||
@@ -435,27 +441,27 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron
|
|||||||
AND dom.`aliasdomain` IS NULL
|
AND dom.`aliasdomain` IS NULL
|
||||||
AND dom.`iswildcarddomain` = 0
|
AND dom.`iswildcarddomain` = 0
|
||||||
");
|
");
|
||||||
$renew_certs = $certificates_stmt->fetchAll(\PDO::FETCH_ASSOC);
|
$renew_certs = $certificates_stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||||
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['expirationdate'])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return $renew_certs;
|
return $renew_certs;
|
||||||
}
|
}
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a list of domains that require a new certificate (issue)
|
* get a list of domains that require a new certificate (issue)
|
||||||
*/
|
*/
|
||||||
private static function issueDomains()
|
private static function issueDomains()
|
||||||
{
|
{
|
||||||
$certificates_stmt = Database::query("
|
$certificates_stmt = Database::query("
|
||||||
SELECT
|
SELECT
|
||||||
domssl.`id`,
|
domssl.`id`,
|
||||||
domssl.`domainid`,
|
domssl.`domainid`,
|
||||||
@@ -488,125 +494,125 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron
|
|||||||
AND dom.`iswildcarddomain` = 0
|
AND dom.`iswildcarddomain` = 0
|
||||||
AND domssl.`expirationdate` IS NULL
|
AND domssl.`expirationdate` IS NULL
|
||||||
");
|
");
|
||||||
$customer_ssl = $certificates_stmt->fetchAll(\PDO::FETCH_ASSOC);
|
$customer_ssl = $certificates_stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||||
if ($customer_ssl) {
|
if ($customer_ssl) {
|
||||||
return $customer_ssl;
|
return $customer_ssl;
|
||||||
}
|
}
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function checkFsFilesAreNewer($domain, $cert_date = 0)
|
private static function checkFsFilesAreNewer($domain, $cert_date = 0)
|
||||||
{
|
{
|
||||||
$certificate_folder = self::getWorkingDirFromEnv(strtolower($domain));
|
$certificate_folder = self::getWorkingDirFromEnv(strtolower($domain));
|
||||||
$ssl_file = \Froxlor\FileDir::makeCorrectFile($certificate_folder . '/' . strtolower($domain) . '.cer');
|
$ssl_file = \Froxlor\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)) {
|
||||||
$cert_data = openssl_x509_parse(file_get_contents($ssl_file));
|
$cert_data = openssl_x509_parse(file_get_contents($ssl_file));
|
||||||
if ($cert_data && $cert_data['validTo_time_t'] > strtotime($cert_date)) {
|
if ($cert_data && $cert_data['validTo_time_t'] > strtotime($cert_date)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getWorkingDirFromEnv($domain = "", $forced_noecc = false)
|
public static function getWorkingDirFromEnv($domain = "", $forced_noecc = false)
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.leecc') > 0 && ! $forced_noecc) {
|
if (Settings::Get('system.leecc') > 0 && ! $forced_noecc) {
|
||||||
$domain .= "_ecc";
|
$domain .= "_ecc";
|
||||||
}
|
}
|
||||||
$env_file = FileDir::makeCorrectFile(dirname(self::$acmesh) . '/acme.sh.env');
|
$env_file = FileDir::makeCorrectFile(dirname(self::$acmesh) . '/acme.sh.env');
|
||||||
if (file_exists($env_file)) {
|
if (file_exists($env_file)) {
|
||||||
$output = [];
|
$output = [];
|
||||||
$cut = <<<EOC
|
$cut = <<<EOC
|
||||||
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) && isset($output[0]) && ! empty($output[0])) {
|
||||||
return FileDir::makeCorrectDir($output[0] . "/" . $domain);
|
return FileDir::makeCorrectDir($output[0] . "/" . $domain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FileDir::makeCorrectDir(dirname(self::$acmesh) . "/" . $domain);
|
return FileDir::makeCorrectDir(dirname(self::$acmesh) . "/" . $domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAcmeSh()
|
public static function getAcmeSh()
|
||||||
{
|
{
|
||||||
return self::$acmesh;
|
return self::$acmesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get certificate files from filesystem and store in $return array
|
* get certificate files from filesystem and store in $return array
|
||||||
*
|
*
|
||||||
* @param string $domain
|
* @param string $domain
|
||||||
* @param array $return
|
* @param array $return
|
||||||
* @param object $cronlog
|
* @param object $cronlog
|
||||||
*/
|
*/
|
||||||
private static function readCertificateToVar($domain, &$return, &$cronlog)
|
private static function readCertificateToVar($domain, &$return, &$cronlog)
|
||||||
{
|
{
|
||||||
$certificate_folder = self::getWorkingDirFromEnv($domain);
|
$certificate_folder = self::getWorkingDirFromEnv($domain);
|
||||||
$certificate_folder_noecc = null;
|
$certificate_folder_noecc = null;
|
||||||
if (Settings::Get('system.leecc') > 0) {
|
if (Settings::Get('system.leecc') > 0) {
|
||||||
$certificate_folder_noecc = self::getWorkingDirFromEnv($domain, true);
|
$certificate_folder_noecc = self::getWorkingDirFromEnv($domain, true);
|
||||||
}
|
}
|
||||||
$certificate_folder = \Froxlor\FileDir::makeCorrectDir($certificate_folder);
|
$certificate_folder = \Froxlor\FileDir::makeCorrectDir($certificate_folder);
|
||||||
|
|
||||||
if (is_dir($certificate_folder) || is_dir($certificate_folder_noecc)) {
|
if (is_dir($certificate_folder) || is_dir($certificate_folder_noecc)) {
|
||||||
foreach ([
|
foreach ([
|
||||||
'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) {
|
] as $index => $sslfile) {
|
||||||
$ssl_file = \Froxlor\FileDir::makeCorrectFile($certificate_folder . '/' . $sslfile);
|
$ssl_file = \Froxlor\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)) {
|
if (! empty($certificate_folder_noecc)) {
|
||||||
$ssl_file_fb = \Froxlor\FileDir::makeCorrectFile($certificate_folder_noecc . '/' . $sslfile);
|
$ssl_file_fb = \Froxlor\FileDir::makeCorrectFile($certificate_folder_noecc . '/' . $sslfile);
|
||||||
if (file_exists($ssl_file_fb)) {
|
if (file_exists($ssl_file_fb)) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "ECC certificates activated but found only non-ecc file");
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "ECC certificates activated but found only non-ecc file");
|
||||||
$return[$index] = file_get_contents($ssl_file_fb);
|
$return[$index] = file_get_contents($ssl_file_fb);
|
||||||
continue;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$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 . "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* install acme.sh if not found yet
|
* install acme.sh if not found yet
|
||||||
*/
|
*/
|
||||||
private static function checkInstall($tries = 0)
|
private static function checkInstall($tries = 0)
|
||||||
{
|
{
|
||||||
if (! file_exists(self::$acmesh) && $tries > 0) {
|
if (! file_exists(self::$acmesh) && $tries > 0) {
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Download/installation of acme.sh seems to have failed. Re-run cronjob to try again or install manually to '" . self::$acmesh . "'");
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Download/installation of acme.sh seems to have failed. Re-run cronjob to try again or install manually to '" . self::$acmesh . "'");
|
||||||
echo PHP_EOL . "Download/installation of acme.sh seems to have failed. Re-run cronjob to try again or install manually to '" . self::$acmesh . "'" . PHP_EOL;
|
echo PHP_EOL . "Download/installation of acme.sh seems to have failed. Re-run cronjob to try again or install manually to '" . self::$acmesh . "'" . PHP_EOL;
|
||||||
return false;
|
return false;
|
||||||
} else if (! file_exists(self::$acmesh)) {
|
} else if (! file_exists(self::$acmesh)) {
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Could not find acme.sh - installing it to /root/.acme.sh/");
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Could not find acme.sh - installing it to /root/.acme.sh/");
|
||||||
$return = false;
|
$return = false;
|
||||||
\Froxlor\FileDir::safe_exec("wget -O - https://get.acme.sh | sh", $return, array(
|
\Froxlor\FileDir::safe_exec("wget -O - https://get.acme.sh | sh", $return, array(
|
||||||
'|'
|
'|'
|
||||||
));
|
));
|
||||||
// check whether the installation worked
|
// check whether the installation worked
|
||||||
return self::checkInstall(++ $tries);
|
return self::checkInstall(++ $tries);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* run upgrade
|
* run upgrade
|
||||||
*/
|
*/
|
||||||
private static function checkUpgrade()
|
private static function checkUpgrade()
|
||||||
{
|
{
|
||||||
$acmesh_result = \Froxlor\FileDir::safe_exec(self::$acmesh . " --upgrade --auto-upgrade 0");
|
$acmesh_result = \Froxlor\FileDir::safe_exec(self::$acmesh . " --upgrade --auto-upgrade 0");
|
||||||
// check for activated cron
|
// check for activated cron
|
||||||
$acmesh_result2 = \Froxlor\FileDir::safe_exec(self::$acmesh . " --install-cronjob");
|
$acmesh_result2 = \Froxlor\FileDir::safe_exec(self::$acmesh . " --install-cronjob");
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Checking for LetsEncrypt client upgrades before renewing certificates:\n" . implode("\n", $acmesh_result) . "\n" . implode("\n", $acmesh_result2));
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Checking for LetsEncrypt client upgrades before renewing certificates:\n" . implode("\n", $acmesh_result) . "\n" . implode("\n", $acmesh_result2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ class Fpm
|
|||||||
$openbasedir .= $_phpappendopenbasedir;
|
$openbasedir .= $_phpappendopenbasedir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$fpm_config .= 'php_admin_value[session.save_path] = ' . \Froxlor\FileDir::makeCorrectDir(Settings::Get('phpfpm.tmpdir') . '/' . $this->domain['loginname'] . '/') . "\n";
|
|
||||||
$fpm_config .= 'php_admin_value[upload_tmp_dir] = ' . \Froxlor\FileDir::makeCorrectDir(Settings::Get('phpfpm.tmpdir') . '/' . $this->domain['loginname'] . '/') . "\n";
|
$fpm_config .= 'php_admin_value[upload_tmp_dir] = ' . \Froxlor\FileDir::makeCorrectDir(Settings::Get('phpfpm.tmpdir') . '/' . $this->domain['loginname'] . '/') . "\n";
|
||||||
|
|
||||||
$admin = $this->getAdminData($this->domain['adminid']);
|
$admin = $this->getAdminData($this->domain['adminid']);
|
||||||
@@ -261,6 +261,11 @@ class Fpm
|
|||||||
$fpm_config .= 'php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f ' . $this->domain['email'] . "\n";
|
$fpm_config .= 'php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f ' . $this->domain['email'] . "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for session.save_path, whether it has been specified by the user, if not, set a default
|
||||||
|
if (strpos($fpm_config, 'php_value[session.save_path]') === false && strpos($fpm_config, 'php_admin_value[session.save_path]') === false) {
|
||||||
|
$fpm_config .= 'php_admin_value[session.save_path] = ' . $this->getTempDir() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
// append custom phpfpm configuration
|
// append custom phpfpm configuration
|
||||||
if (! empty($fpm_custom_config)) {
|
if (! empty($fpm_custom_config)) {
|
||||||
$fpm_config .= "\n; Custom Configuration\n";
|
$fpm_config .= "\n; Custom Configuration\n";
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class Dns
|
|||||||
$domain = $domain_id;
|
$domain = $domain_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($domain['isbinddomain'] != '1') {
|
if (!isset($domain['isbinddomain']) || $domain['isbinddomain'] != '1') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,12 +190,26 @@ class Dns
|
|||||||
'@',
|
'@',
|
||||||
'www',
|
'www',
|
||||||
'*'
|
'*'
|
||||||
] as $crceord) {
|
] as $crecord) {
|
||||||
if ($entry['type'] == 'CNAME' && $entry['record'] == '@' && (array_key_exists(md5($crceord), $required_entries['A']) || array_key_exists(md5($crceord), $required_entries['AAAA']))) {
|
if ($entry['type'] == 'CNAME' && $entry['record'] == '@' && (array_key_exists(md5($crecord), $required_entries['A']) || array_key_exists(md5($crecord), $required_entries['AAAA']))) {
|
||||||
unset($required_entries['A'][md5($crceord)]);
|
unset($required_entries['A'][md5($crecord)]);
|
||||||
unset($required_entries['AAAA'][md5($crceord)]);
|
unset($required_entries['AAAA'][md5($crecord)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// also allow overriding of auto-generated values (imap,pop3,mail,smtp) if enabled in the settings
|
||||||
|
if (Settings::Get('system.dns_createmailentry')) {
|
||||||
|
foreach (array(
|
||||||
|
'imap',
|
||||||
|
'pop3',
|
||||||
|
'mail',
|
||||||
|
'smtp'
|
||||||
|
) as $crecord) {
|
||||||
|
if ($entry['type'] == 'CNAME' && $entry['record'] == $crecord && (array_key_exists(md5($crecord), $required_entries['A']) || array_key_exists(md5($crecord), $required_entries['AAAA']))) {
|
||||||
|
unset($required_entries['A'][md5($crecord)]);
|
||||||
|
unset($required_entries['AAAA'][md5($crecord)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
$zonerecords[] = new DnsEntry($entry['record'], $entry['type'], $entry['content'], $entry['prio'], $entry['ttl']);
|
$zonerecords[] = new DnsEntry($entry['record'], $entry['type'], $entry['content'], $entry['prio'], $entry['ttl']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ final class Froxlor
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Main version variable
|
// Main version variable
|
||||||
const VERSION = '0.10.26';
|
const VERSION = '0.10.27';
|
||||||
|
|
||||||
// Database version (YYYYMMDDC where C is a daily counter)
|
// Database version (YYYYMMDDC where C is a daily counter)
|
||||||
const DBVERSION = '202103240';
|
const DBVERSION = '202107070';
|
||||||
|
|
||||||
// Distribution branding-tag (used for Debian etc.)
|
// Distribution branding-tag (used for Debian etc.)
|
||||||
const BRANDING = '';
|
const BRANDING = '';
|
||||||
|
|||||||
@@ -60,6 +60,13 @@ class SImExporter
|
|||||||
|
|
||||||
public static function export()
|
public static function export()
|
||||||
{
|
{
|
||||||
|
$settings_definitions = [];
|
||||||
|
foreach (\Froxlor\PhpHelper::loadConfigArrayDir('./actions/admin/settings/')['groups'] AS $group) {
|
||||||
|
foreach ($group['fields'] AS $field) {
|
||||||
|
$settings_definitions[$field['settinggroup']][$field['varname']] = $field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$result_stmt = Database::query("
|
$result_stmt = Database::query("
|
||||||
SELECT * FROM `" . TABLE_PANEL_SETTINGS . "` ORDER BY `settingid` ASC
|
SELECT * FROM `" . TABLE_PANEL_SETTINGS . "` ORDER BY `settingid` ASC
|
||||||
");
|
");
|
||||||
@@ -69,13 +76,26 @@ class SImExporter
|
|||||||
if (! in_array($index, self::$no_export)) {
|
if (! in_array($index, self::$no_export)) {
|
||||||
$_data[$index] = $row['value'];
|
$_data[$index] = $row['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists($row['settinggroup'], $settings_definitions) && array_key_exists($row['varname'], $settings_definitions[$row['settinggroup']])) {
|
||||||
|
// Export image file
|
||||||
|
if ($settings_definitions[$row['settinggroup']][$row['varname']]['type'] === "image") {
|
||||||
|
if ($row['value'] === "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$_data[$index.'.image_data'] = base64_encode(file_get_contents(explode('?', $row['value'], 2)[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add checksum for validation
|
// add checksum for validation
|
||||||
$_data['_sha'] = sha1(var_export($_data, true));
|
$_data['_sha'] = sha1(var_export($_data, true));
|
||||||
$_export = json_encode($_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
$_export = json_encode($_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||||
if (! $_export) {
|
if (! $_export) {
|
||||||
throw new \Exception("Error exporting settings: " . json_last_error_msg());
|
throw new \Exception("Error exporting settings: " . json_last_error_msg());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $_export;
|
return $_export;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +140,26 @@ class SImExporter
|
|||||||
}
|
}
|
||||||
// store new data
|
// store new data
|
||||||
foreach ($_data as $index => $value) {
|
foreach ($_data as $index => $value) {
|
||||||
|
$index_split = explode('.', $index, 3);
|
||||||
|
|
||||||
|
// Catch image_data and save it
|
||||||
|
if (isset($index_split[2]) && $index_split[2] === 'image_data' && !empty($_data[$index_split[0].'.'.$index_split[1]])) {
|
||||||
|
$path = \Froxlor\Froxlor::getInstallDir().'/img/';
|
||||||
|
if (!is_dir($path) && !mkdir($path, '0775')) {
|
||||||
|
throw new \Exception("img directory does not exist and cannot be created");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we can write to the upload directory
|
||||||
|
if (!is_writable($path)) {
|
||||||
|
if (!chmod($path, '0775')) {
|
||||||
|
throw new \Exception("Cannot write to img directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents(\Froxlor\Froxlor::getInstallDir() . '/' . explode('?', $_data[$index_split[0].'.'.$index_split[1]], 2)[0], base64_decode($value));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Settings::Set($index, $value);
|
Settings::Set($index, $value);
|
||||||
}
|
}
|
||||||
// save to DB
|
// save to DB
|
||||||
|
|||||||
@@ -367,4 +367,67 @@ class Store
|
|||||||
|
|
||||||
return $returnvalue;
|
return $returnvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function storeSettingImage($fieldname, $fielddata)
|
||||||
|
{
|
||||||
|
if (isset($fielddata['settinggroup'], $fielddata['varname']) && is_array($fielddata) && $fielddata['settinggroup'] !== '' && $fielddata['varname'] !== '') {
|
||||||
|
$save_to = null;
|
||||||
|
$path = \Froxlor\Froxlor::getInstallDir().'/img/';
|
||||||
|
|
||||||
|
// New file?
|
||||||
|
if (isset($_FILES[$fieldname]) && $_FILES[$fieldname]['tmp_name']) {
|
||||||
|
// Make sure upload directory exists
|
||||||
|
if (!is_dir($path) && !mkdir($path, '0775')) {
|
||||||
|
throw new \Exception("img directory does not exist and cannot be created");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we can write to the upload directory
|
||||||
|
if (!is_writable($path)) {
|
||||||
|
if (!chmod($path, '0775')) {
|
||||||
|
throw new \Exception("Cannot write to img directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure mime-type matches an image
|
||||||
|
if (!in_array(mime_content_type($_FILES[$fieldname]['tmp_name']), ['image/jpeg','image/jpg','image/png','image/gif'])) {
|
||||||
|
throw new \Exception("Uploaded file not a valid image");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine file extension
|
||||||
|
$spl = explode('.', $_FILES[$fieldname]['name']);
|
||||||
|
$file_extension = strtolower(array_pop($spl));
|
||||||
|
unset($spl);
|
||||||
|
|
||||||
|
// 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?
|
||||||
|
if ($fielddata['value'] !== "" && array_key_exists($fieldname.'_delete', $_POST) && $_POST[$fieldname.'_delete']) {
|
||||||
|
@unlink(\Froxlor\Froxlor::getInstallDir() . '/' . explode('?', $fielddata['value'], 2)[0]);
|
||||||
|
$save_to = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing changed
|
||||||
|
if ($save_to === null) {
|
||||||
|
return array(
|
||||||
|
$fielddata['settinggroup'] . '.' . $fielddata['varname'] => $fielddata['value']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings::Set($fielddata['settinggroup'] . '.' . $fielddata['varname'], $save_to) === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$fielddata['settinggroup'] . '.' . $fielddata['varname'] => $save_to
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ class Data
|
|||||||
return $newfieldvalue;
|
return $newfieldvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getFormFieldDataImage($fieldname, $fielddata, $input)
|
||||||
|
{
|
||||||
|
// We always make the system think we have new data to trigger the save function where we actually check everything
|
||||||
|
return time();
|
||||||
|
}
|
||||||
|
|
||||||
public static function manipulateFormFieldDataDate($fieldname, $fielddata, $newfieldvalue)
|
public static function manipulateFormFieldDataDate($fieldname, $fielddata, $newfieldvalue)
|
||||||
{
|
{
|
||||||
if (isset($fielddata['date_timestamp']) && $fielddata['date_timestamp'] === true) {
|
if (isset($fielddata['date_timestamp']) && $fielddata['date_timestamp'] === true) {
|
||||||
|
|||||||
@@ -89,6 +89,15 @@ class Fields
|
|||||||
return $returnvalue;
|
return $returnvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getFormFieldOutputImage($fieldname, $fielddata, $do_show = true)
|
||||||
|
{
|
||||||
|
global $lng;
|
||||||
|
$label = $fielddata['label'];
|
||||||
|
$value = htmlentities($fielddata['value']);
|
||||||
|
eval("\$returnvalue = \"" . \Froxlor\UI\Template::getTemplate("formfields/image", true) . "\";");
|
||||||
|
return $returnvalue;
|
||||||
|
}
|
||||||
|
|
||||||
public static function getFormFieldOutputDate($fieldname, $fielddata, $do_show = true)
|
public static function getFormFieldOutputDate($fieldname, $fielddata, $do_show = true)
|
||||||
{
|
{
|
||||||
if (isset($fielddata['date_timestamp']) && $fielddata['date_timestamp'] === true) {
|
if (isset($fielddata['date_timestamp']) && $fielddata['date_timestamp'] === true) {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -74,7 +74,7 @@ Alias "/.well-known/acme-challenge" "{{settings.system.letsencryptchallengepath}
|
|||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
</file>
|
</file>
|
||||||
<command><![CDATA[/etc/init.d/apache2 restart]]></command>
|
<command><![CDATA[service apache2 restart]]></command>
|
||||||
</daemon>
|
</daemon>
|
||||||
<!-- HTTP Lighttpd -->
|
<!-- HTTP Lighttpd -->
|
||||||
<daemon name="lighttpd" title="LigHTTPd">
|
<daemon name="lighttpd" title="LigHTTPd">
|
||||||
@@ -138,7 +138,7 @@ include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
|
|||||||
</command>
|
</command>
|
||||||
<command><![CDATA[lighty-disable-mod cgi]]></command>
|
<command><![CDATA[lighty-disable-mod cgi]]></command>
|
||||||
<command><![CDATA[lighty-disable-mod fastcgi]]></command>
|
<command><![CDATA[lighty-disable-mod fastcgi]]></command>
|
||||||
<command><![CDATA[/etc/init.d/lighttpd restart]]></command>
|
<command><![CDATA[service lighttpd restart]]></command>
|
||||||
</daemon>
|
</daemon>
|
||||||
<!-- HTTP Nginx -->
|
<!-- HTTP Nginx -->
|
||||||
<daemon name="nginx" title="nginx">
|
<daemon name="nginx" title="nginx">
|
||||||
@@ -354,7 +354,6 @@ exit "$RETVAL"
|
|||||||
</visibility>
|
</visibility>
|
||||||
<content><![CDATA[/etc/init.d/php-fcgi restart]]></content>
|
<content><![CDATA[/etc/init.d/php-fcgi restart]]></content>
|
||||||
</command>
|
</command>
|
||||||
<command><![CDATA[/etc/init.d/nginx restart]]></command>
|
|
||||||
</daemon>
|
</daemon>
|
||||||
</service>
|
</service>
|
||||||
<!--DNS -->
|
<!--DNS -->
|
||||||
@@ -366,7 +365,7 @@ exit "$RETVAL"
|
|||||||
<command><![CDATA[touch {{settings.system.bindconf_directory}}froxlor_bind.conf]]></command>
|
<command><![CDATA[touch {{settings.system.bindconf_directory}}froxlor_bind.conf]]></command>
|
||||||
<command><![CDATA[chown bind:0 {{settings.system.bindconf_directory}}froxlor_bind.conf]]></command>
|
<command><![CDATA[chown bind:0 {{settings.system.bindconf_directory}}froxlor_bind.conf]]></command>
|
||||||
<command><![CDATA[chmod 0644 {{settings.system.bindconf_directory}}froxlor_bind.conf]]></command>
|
<command><![CDATA[chmod 0644 {{settings.system.bindconf_directory}}froxlor_bind.conf]]></command>
|
||||||
<command><![CDATA[/etc/init.d/bind9 restart]]></command>
|
<command><![CDATA[service bind9 restart]]></command>
|
||||||
</daemon>
|
</daemon>
|
||||||
<daemon name="powerdns" title="PowerDNS (standalone)">
|
<daemon name="powerdns" title="PowerDNS (standalone)">
|
||||||
<install><![CDATA[apt-get install pdns-server pdns-backend-mysql]]></install>
|
<install><![CDATA[apt-get install pdns-server pdns-backend-mysql]]></install>
|
||||||
@@ -908,7 +907,7 @@ gmysql-password=
|
|||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
</file>
|
</file>
|
||||||
<command><![CDATA[/etc/init.d/pdns restart]]></command>
|
<command><![CDATA[service pdns restart]]></command>
|
||||||
</daemon>
|
</daemon>
|
||||||
<daemon name="powerdns_bind"
|
<daemon name="powerdns_bind"
|
||||||
title="PowerDNS via bind-backend">
|
title="PowerDNS via bind-backend">
|
||||||
@@ -1455,7 +1454,7 @@ bind-check-interval=180
|
|||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
</file>
|
</file>
|
||||||
<command><![CDATA[/etc/init.d/pdns restart]]></command>
|
<command><![CDATA[service pdns restart]]></command>
|
||||||
</daemon>
|
</daemon>
|
||||||
</service>
|
</service>
|
||||||
<!-- SMTP services -->
|
<!-- SMTP services -->
|
||||||
@@ -1578,7 +1577,7 @@ root: root@<SERVERNAME>
|
|||||||
</files>
|
</files>
|
||||||
<commands index="3">
|
<commands index="3">
|
||||||
<command><![CDATA[newaliases]]></command>
|
<command><![CDATA[newaliases]]></command>
|
||||||
<command><![CDATA[/etc/init.d/postfix restart]]></command>
|
<command><![CDATA[service postfix restart]]></command>
|
||||||
</commands>
|
</commands>
|
||||||
</general>
|
</general>
|
||||||
<!-- postfix with dovecot -->
|
<!-- postfix with dovecot -->
|
||||||
@@ -3299,7 +3298,7 @@ plugin {
|
|||||||
</file>
|
</file>
|
||||||
</files>
|
</files>
|
||||||
<commands index="1">
|
<commands index="1">
|
||||||
<command><![CDATA[/etc/init.d/dovecot restart]]></command>
|
<command><![CDATA[service dovecot restart]]></command>
|
||||||
</commands>
|
</commands>
|
||||||
</general>
|
</general>
|
||||||
<!-- Dovecot with postfix -->
|
<!-- Dovecot with postfix -->
|
||||||
@@ -3722,7 +3721,7 @@ TLSVerifyClient off
|
|||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
</file>
|
</file>
|
||||||
<command><![CDATA[/etc/init.d/proftpd restart]]></command>
|
<command><![CDATA[service proftpd restart]]></command>
|
||||||
</daemon>
|
</daemon>
|
||||||
<!-- Pureftpd -->
|
<!-- Pureftpd -->
|
||||||
<daemon name="pureftpd" title="PureFTPd">
|
<daemon name="pureftpd" title="PureFTPd">
|
||||||
@@ -3948,7 +3947,7 @@ UPLOADGID=
|
|||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
</file>
|
</file>
|
||||||
<command><![CDATA[/etc/init.d/pure-ftpd-mysql restart]]></command>
|
<command><![CDATA[service pure-ftpd-mysql restart]]></command>
|
||||||
</daemon>
|
</daemon>
|
||||||
</service>
|
</service>
|
||||||
<!-- System tools/services -->
|
<!-- System tools/services -->
|
||||||
@@ -4088,7 +4087,7 @@ aliases: files
|
|||||||
<commands index="5">
|
<commands index="5">
|
||||||
<visibility mode="equals" value="apache2">{{settings.system.webserver}}
|
<visibility mode="equals" value="apache2">{{settings.system.webserver}}
|
||||||
</visibility>
|
</visibility>
|
||||||
<command><![CDATA[/etc/init.d/apache2 restart]]></command>
|
<command><![CDATA[service apache2 restart]]></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 -->
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<froxlor>
|
<froxlor>
|
||||||
<distribution name="Debian" codename="Stretch"
|
<distribution name="Debian" codename="Stretch"
|
||||||
version="9.x" defaulteditor="/bin/nano">
|
version="9.x" defaulteditor="/bin/nano" deprecated="true">
|
||||||
<services>
|
<services>
|
||||||
<!-- HTTP -->
|
<!-- HTTP -->
|
||||||
<service type="http" title="{{lng.admin.configfiles.http}}">
|
<service type="http" title="{{lng.admin.configfiles.http}}">
|
||||||
|
|||||||
@@ -380,11 +380,8 @@ if (! array_key_exists('variants', $_themeoptions) || ! array_key_exists($themev
|
|||||||
|
|
||||||
// check for custom header-graphic
|
// check for custom header-graphic
|
||||||
$hl_path = 'templates/' . $theme . '/assets/img';
|
$hl_path = 'templates/' . $theme . '/assets/img';
|
||||||
$header_logo = $hl_path . '/logo.png';
|
$header_logo = Settings::Get('panel.logo_image_header') ?: $hl_path . '/logo.png';
|
||||||
|
$header_logo_login = Settings::Get('panel.logo_image_login') ?: $hl_path . '/logo.png';
|
||||||
if (file_exists($hl_path . '/logo_custom.png')) {
|
|
||||||
$header_logo = $hl_path . '/logo_custom.png';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redirects to index.php (login page) if no session exists
|
* Redirects to index.php (login page) if no session exists
|
||||||
|
|||||||
@@ -1832,15 +1832,15 @@ $lng['opcacheinfo']['false'] = '<i>false</i>';
|
|||||||
|
|
||||||
// Added for let's encrypt
|
// Added for let's encrypt
|
||||||
$lng['admin']['letsencrypt']['title'] = 'Use Let\'s Encrypt';
|
$lng['admin']['letsencrypt']['title'] = 'Use Let\'s Encrypt';
|
||||||
$lng['admin']['letsencrypt']['description'] = 'Get a free certificate from <a href="https://letsencrypt.org">Let\'s Encrypt</a>. The certificate will be created and renewed automatically.<br><strong class="red">ATTENTION:</strong> If wildcards are enabled, this option will automatically be disabled. This feature is still in beta.';
|
$lng['admin']['letsencrypt']['description'] = 'Get a free certificate from <a href="https://letsencrypt.org">Let\'s Encrypt</a>. The certificate will be created and renewed automatically.<br><strong class="red">ATTENTION:</strong> If wildcards are enabled, this option will automatically be disabled.';
|
||||||
$lng['customer']['letsencrypt']['title'] = 'Use Let\'s Encrypt';
|
$lng['customer']['letsencrypt']['title'] = 'Use Let\'s Encrypt';
|
||||||
$lng['customer']['letsencrypt']['description'] = 'Get a free certificate from <a href="https://letsencrypt.org">Let\'s Encrypt</a>. The certificate will be created and renewed automatically.<br><strong class="red">ATTENTION:</strong> This feature is still in beta.';
|
$lng['customer']['letsencrypt']['description'] = 'Get a free certificate from <a href="https://letsencrypt.org">Let\'s Encrypt</a>. The certificate will be created and renewed automatically.';
|
||||||
$lng['error']['sslredirectonlypossiblewithsslipport'] = 'Using Let\'s Encrypt is only possible when the domain has at least one ssl-enabled IP/port combination assigned.';
|
$lng['error']['sslredirectonlypossiblewithsslipport'] = 'Using Let\'s Encrypt is only possible when the domain has at least one ssl-enabled IP/port combination assigned.';
|
||||||
$lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt cannot handle wildcard-domains using ACME in froxlor (requires dns-challenge), sorry. Please set the ServerAlias to WWW or disable it completely';
|
$lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt cannot handle wildcard-domains using ACME in froxlor (requires dns-challenge), sorry. Please set the ServerAlias to WWW or disable it completely';
|
||||||
$lng['panel']['letsencrypt'] = 'Using Let\'s encrypt';
|
$lng['panel']['letsencrypt'] = 'Using Let\'s encrypt';
|
||||||
$lng['crondesc']['cron_letsencrypt'] = 'updating Let\'s Encrypt certificates';
|
$lng['crondesc']['cron_letsencrypt'] = 'updating Let\'s Encrypt certificates';
|
||||||
$lng['serversettings']['letsencryptca']['title'] = "Let's Encrypt environment";
|
$lng['serversettings']['letsencryptca']['title'] = "ACME environment";
|
||||||
$lng['serversettings']['letsencryptca']['description'] = "Environment to be used for Let's Encrypt certificates.";
|
$lng['serversettings']['letsencryptca']['description'] = "Environment to be used for Let's Encrypt / ZeroSSL certificates.";
|
||||||
$lng['serversettings']['letsencryptcountrycode']['title'] = "Let's Encrypt country code";
|
$lng['serversettings']['letsencryptcountrycode']['title'] = "Let's Encrypt country code";
|
||||||
$lng['serversettings']['letsencryptcountrycode']['description'] = "2 letter country code used to generate Let's Encrypt certificates.";
|
$lng['serversettings']['letsencryptcountrycode']['description'] = "2 letter country code used to generate Let's Encrypt certificates.";
|
||||||
$lng['serversettings']['letsencryptstate']['title'] = "Let's Encrypt state";
|
$lng['serversettings']['letsencryptstate']['title'] = "Let's Encrypt state";
|
||||||
@@ -2116,3 +2116,10 @@ $lng['serversettings']['terms_url']['description'] = 'Specify an URL to your ter
|
|||||||
$lng['privacy'] = 'Privacy policy';
|
$lng['privacy'] = 'Privacy policy';
|
||||||
$lng['serversettings']['privacy_url']['title'] = 'URL to privacy policy';
|
$lng['serversettings']['privacy_url']['title'] = 'URL to privacy policy';
|
||||||
$lng['serversettings']['privacy_url']['description'] = 'Specify an URL to your privacy policy site / imprint site. The link will be visible on the login screen and on the footer when logged in.';
|
$lng['serversettings']['privacy_url']['description'] = 'Specify an URL to your privacy policy site / imprint site. The link will be visible on the login screen and on the footer when logged in.';
|
||||||
|
$lng['admin']['domaindefaultalias'] = 'Default ServerAlias value for new domains';
|
||||||
|
|
||||||
|
$lng['serversettings']['logo_image_header']['title'] = 'Logo Image (Header)';
|
||||||
|
$lng['serversettings']['logo_image_header']['description'] = 'Upload your own logo image to be shown in the header after login (recommended height 30px)';
|
||||||
|
$lng['serversettings']['logo_image_login']['title'] = 'Logo Image (Login)';
|
||||||
|
$lng['serversettings']['logo_image_login']['description'] = 'Upload your own logo image to be shown during login';
|
||||||
|
$lng['panel']['image_field_delete'] = 'Delete the existing current image';
|
||||||
|
|||||||
@@ -1490,8 +1490,8 @@ $lng['error']['sslredirectonlypossiblewithsslipport'] = 'Die Nutzung von Let\'s
|
|||||||
$lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt kann mittels ACME Wildcard-Domains nur via DNS validieren, sorry. Bitte den ServerAlias auf WWW setzen oder deaktivieren';
|
$lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt kann mittels ACME Wildcard-Domains nur via DNS validieren, sorry. Bitte den ServerAlias auf WWW setzen oder deaktivieren';
|
||||||
$lng['panel']['letsencrypt'] = 'Benutzt Let\'s encrypt';
|
$lng['panel']['letsencrypt'] = 'Benutzt Let\'s encrypt';
|
||||||
$lng['crondesc']['cron_letsencrypt'] = 'Aktualisierung der Let\'s Encrypt Zertifikate';
|
$lng['crondesc']['cron_letsencrypt'] = 'Aktualisierung der Let\'s Encrypt Zertifikate';
|
||||||
$lng['serversettings']['letsencryptca']['title'] = "Let's Encrypt Umgebung";
|
$lng['serversettings']['letsencryptca']['title'] = "ACME Umgebung";
|
||||||
$lng['serversettings']['letsencryptca']['description'] = "Let's Encrypt - Umgebung, welche genutzt wird um Zertifikate zu bestellen.";
|
$lng['serversettings']['letsencryptca']['description'] = "Umgebung, welche genutzt wird um Zertifikate zu bestellen.";
|
||||||
$lng['serversettings']['letsencryptcountrycode']['title'] = "Let's Encrypt Ländercode";
|
$lng['serversettings']['letsencryptcountrycode']['title'] = "Let's Encrypt Ländercode";
|
||||||
$lng['serversettings']['letsencryptcountrycode']['description'] = "2 - stelliger Ländercode, welcher benutzt wird um Let's Encrypt - Zertifikate zu bestellen.";
|
$lng['serversettings']['letsencryptcountrycode']['description'] = "2 - stelliger Ländercode, welcher benutzt wird um Let's Encrypt - Zertifikate zu bestellen.";
|
||||||
$lng['serversettings']['letsencryptstate']['title'] = "Let's Encrypt Bundesland";
|
$lng['serversettings']['letsencryptstate']['title'] = "Let's Encrypt Bundesland";
|
||||||
@@ -1762,3 +1762,10 @@ $lng['serversettings']['terms_url']['description'] = 'Die URL zur AGB-Seite. Der
|
|||||||
$lng['privacy'] = 'Datenschutzerklärung';
|
$lng['privacy'] = 'Datenschutzerklärung';
|
||||||
$lng['serversettings']['privacy_url']['title'] = 'URL zur Datenschutzerklärung';
|
$lng['serversettings']['privacy_url']['title'] = 'URL zur Datenschutzerklärung';
|
||||||
$lng['serversettings']['privacy_url']['description'] = 'Die URL zur Datenschutzerklärungs-Seite. Der Link ist auf der Login-Seite und wenn eingeloggt, in der Fußzeile sichtbar.';
|
$lng['serversettings']['privacy_url']['description'] = 'Die URL zur Datenschutzerklärungs-Seite. Der Link ist auf der Login-Seite und wenn eingeloggt, in der Fußzeile sichtbar.';
|
||||||
|
$lng['admin']['domaindefaultalias'] = 'Standard ServerAlias-Angabe für neue Domains';
|
||||||
|
|
||||||
|
$lng['serversettings']['logo_image_header']['title'] = 'Logo Bild (Header)';
|
||||||
|
$lng['serversettings']['logo_image_header']['description'] = 'Das hochgeladene Bild wird als Logo oben links nach dem Login angezeigt (empfohlene Höhe sind 30px)';
|
||||||
|
$lng['serversettings']['logo_image_login']['title'] = 'Logo Bild (Login)';
|
||||||
|
$lng['serversettings']['logo_image_login']['description'] = 'Das hochgeladene Bild wird als Logo während des Logins angezeigt';
|
||||||
|
$lng['panel']['image_field_delete'] = 'Das momentan vorhandene Bild löschen';
|
||||||
|
|||||||
79
phpunit.xml
79
phpunit.xml
@@ -1,45 +1,38 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<phpunit backupGlobals="false" backupStaticAttributes="false"
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" backupStaticAttributes="false" colors="false" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" bootstrap="tests/bootstrap.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||||
colors="false" convertErrorsToExceptions="true"
|
<coverage processUncoveredFiles="true">
|
||||||
convertNoticesToExceptions="true" convertWarningsToExceptions="true"
|
<include>
|
||||||
processIsolation="false" stopOnFailure="false"
|
<directory suffix=".php">./lib/Froxlor</directory>
|
||||||
bootstrap="tests/bootstrap.php">
|
</include>
|
||||||
|
<report>
|
||||||
<testsuites>
|
<clover outputFile="build/logs/clover.xml"/>
|
||||||
<testsuite name="froxlor">
|
<crap4j outputFile="build/logs/crap4j.xml"/>
|
||||||
<!-- we need to specify the order of the tests for dependency-reasons -->
|
<html outputDirectory="build/coverage" lowUpperBound="35" highLowerBound="70"/>
|
||||||
<directory>tests/Global</directory>
|
</report>
|
||||||
<directory>tests/Admins</directory>
|
</coverage>
|
||||||
<directory>tests/Customers</directory>
|
<testsuites>
|
||||||
<directory>tests/IpsAndPorts</directory>
|
<testsuite name="froxlor">
|
||||||
<directory>tests/Domains</directory>
|
<!-- we need to specify the order of the tests for dependency-reasons -->
|
||||||
<directory>tests/Cronjobs</directory>
|
<directory>tests/Global</directory>
|
||||||
<directory>tests/SubDomains</directory>
|
<directory>tests/Admins</directory>
|
||||||
<directory>tests/Certificates</directory>
|
<directory>tests/Customers</directory>
|
||||||
<directory>tests/Ftps</directory>
|
<directory>tests/IpsAndPorts</directory>
|
||||||
<directory>tests/Emails</directory>
|
<directory>tests/Domains</directory>
|
||||||
<directory>tests/Extras</directory>
|
<directory>tests/Cronjobs</directory>
|
||||||
<directory>tests/Backup</directory>
|
<directory>tests/SubDomains</directory>
|
||||||
<directory>tests/DomainZones</directory>
|
<directory>tests/Certificates</directory>
|
||||||
<directory>tests/Mysqls</directory>
|
<directory>tests/Ftps</directory>
|
||||||
<directory>tests/PhpAndFpm</directory>
|
<directory>tests/Emails</directory>
|
||||||
<directory>tests/Traffic</directory>
|
<directory>tests/Extras</directory>
|
||||||
<directory>tests/Froxlor</directory>
|
<directory>tests/Backup</directory>
|
||||||
</testsuite>
|
<directory>tests/DomainZones</directory>
|
||||||
</testsuites>
|
<directory>tests/Mysqls</directory>
|
||||||
|
<directory>tests/PhpAndFpm</directory>
|
||||||
<logging>
|
<directory>tests/Traffic</directory>
|
||||||
<log type="coverage-html" target="build/coverage"
|
<directory>tests/Froxlor</directory>
|
||||||
lowUpperBound="35" highLowerBound="70" />
|
</testsuite>
|
||||||
<log type="coverage-clover" target="build/logs/clover.xml" />
|
</testsuites>
|
||||||
<log type="coverage-crap4j" target="build/logs/crap4j.xml" />
|
<logging>
|
||||||
<log type="junit" target="build/logs/junit.xml" />
|
<junit outputFile="build/logs/junit.xml"/>
|
||||||
</logging>
|
</logging>
|
||||||
|
|
||||||
<filter>
|
|
||||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
|
||||||
<directory suffix=".php">./lib/Froxlor</directory>
|
|
||||||
</whitelist>
|
|
||||||
</filter>
|
|
||||||
|
|
||||||
</phpunit>
|
</phpunit>
|
||||||
|
|||||||
2
robots.txt
Normal file
2
robots.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /
|
||||||
2
templates/Sparkle/2fa/entercode.tpl
vendored
2
templates/Sparkle/2fa/entercode.tpl
vendored
@@ -1,7 +1,7 @@
|
|||||||
$header
|
$header
|
||||||
<article class="login bradius">
|
<article class="login bradius">
|
||||||
<header class="dark">
|
<header class="dark">
|
||||||
<img src="{$header_logo}" alt="Froxlor Server Management Panel" />
|
<img src="{$header_logo_login}" alt="Froxlor Server Management Panel" />
|
||||||
</header>
|
</header>
|
||||||
<section class="loginsec">
|
<section class="loginsec">
|
||||||
<form method="post" action="{$filename}" enctype="application/x-www-form-urlencoded">
|
<form method="post" action="{$filename}" enctype="application/x-www-form-urlencoded">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
$header
|
$header
|
||||||
<form method="post" action="$filename" enctype="application/x-www-form-urlencoded">
|
<form method="post" action="$filename" enctype="multipart/form-data">
|
||||||
<input type="hidden" name="send" value="send" />
|
<input type="hidden" name="send" value="send" />
|
||||||
<input type="hidden" name="s" value="$s" />
|
<input type="hidden" name="s" value="$s" />
|
||||||
<input type="hidden" name="page" value="$page" />
|
<input type="hidden" name="page" value="$page" />
|
||||||
|
|||||||
1
templates/Sparkle/assets/css/custom.example.css
vendored
Normal file
1
templates/Sparkle/assets/css/custom.example.css
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/* To include your custom CSS for this theme, please rename this file to "custom.css" and place your CSS in it */
|
||||||
12
templates/Sparkle/assets/css/main.css
vendored
12
templates/Sparkle/assets/css/main.css
vendored
@@ -77,7 +77,11 @@ strong {
|
|||||||
}
|
}
|
||||||
|
|
||||||
header img {
|
header img {
|
||||||
padding: 10px 0 10px 10px;
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.login header img {
|
||||||
|
margin: 0 auto;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
img.small {
|
img.small {
|
||||||
@@ -1745,3 +1749,9 @@ td.size-50 {
|
|||||||
.footer-link:last-child:after {
|
.footer-link:last-child:after {
|
||||||
content: "";
|
content: "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field-image-preview {
|
||||||
|
max-width: 300px;
|
||||||
|
max-height: 500px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|||||||
3
templates/Sparkle/config.json
vendored
3
templates/Sparkle/config.json
vendored
@@ -2,7 +2,8 @@
|
|||||||
"variants": {
|
"variants": {
|
||||||
"default": {
|
"default": {
|
||||||
"css": [
|
"css": [
|
||||||
"main.css"
|
"main.css",
|
||||||
|
"custom.css"
|
||||||
],
|
],
|
||||||
"js": [
|
"js": [
|
||||||
"main.js",
|
"main.js",
|
||||||
|
|||||||
11
templates/Sparkle/formfields/image.tpl
vendored
Normal file
11
templates/Sparkle/formfields/image.tpl
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<tr>
|
||||||
|
<td>{$label}</td>
|
||||||
|
<td>
|
||||||
|
<if $value>
|
||||||
|
<img src="/{$value}" alt="Current Image" class="field-image-preview"><br>
|
||||||
|
<input type="checkbox" value="1" name="{$fieldname}_delete" /> {$lng['panel']['image_field_delete']}
|
||||||
|
<br><br>
|
||||||
|
</if>
|
||||||
|
<input <if $do_show == 0>disabled="disabled"</if> type="file" class="file" name="{$fieldname}" accept="image/jpeg, image/jpg, image/png, image/gif" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
2
templates/Sparkle/login/fpwd.tpl
vendored
2
templates/Sparkle/login/fpwd.tpl
vendored
@@ -1,7 +1,7 @@
|
|||||||
$header
|
$header
|
||||||
<article class="login bradius">
|
<article class="login bradius">
|
||||||
<header class="dark">
|
<header class="dark">
|
||||||
<img src="{$header_logo}" alt="Froxlor Server Management Panel" />
|
<img src="{$header_logo_login}" alt="Froxlor Server Management Panel" />
|
||||||
</header>
|
</header>
|
||||||
<if $message != ''>
|
<if $message != ''>
|
||||||
<div class="errorcontainer bradius">
|
<div class="errorcontainer bradius">
|
||||||
|
|||||||
2
templates/Sparkle/login/login.tpl
vendored
2
templates/Sparkle/login/login.tpl
vendored
@@ -1,7 +1,7 @@
|
|||||||
$header
|
$header
|
||||||
<article class="login bradius">
|
<article class="login bradius">
|
||||||
<header class="dark">
|
<header class="dark">
|
||||||
<img src="{$header_logo}" alt="Froxlor Server Management Panel" />
|
<img src="{$header_logo_login}" alt="Froxlor Server Management Panel" />
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<if $update_in_progress !== ''>
|
<if $update_in_progress !== ''>
|
||||||
|
|||||||
2
templates/Sparkle/login/login_ftp.tpl
vendored
2
templates/Sparkle/login/login_ftp.tpl
vendored
@@ -1,6 +1,6 @@
|
|||||||
<article class="login bradius">
|
<article class="login bradius">
|
||||||
<header class="dark">
|
<header class="dark">
|
||||||
<img src="{$header_logo}" alt="{t}Froxlor Server Management Panel{/t}" />
|
<img src="{$header_logo_login}" alt="{t}Froxlor Server Management Panel{/t}" />
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{if isset($successmessage)}
|
{if isset($successmessage)}
|
||||||
|
|||||||
2
templates/Sparkle/login/rpwd.tpl
vendored
2
templates/Sparkle/login/rpwd.tpl
vendored
@@ -1,7 +1,7 @@
|
|||||||
$header
|
$header
|
||||||
<article class="login bradius">
|
<article class="login bradius">
|
||||||
<header class="dark">
|
<header class="dark">
|
||||||
<img src="{$header_logo}" alt="Froxlor Server Management Panel" />
|
<img src="{$header_logo_login}" alt="Froxlor Server Management Panel" />
|
||||||
</header>
|
</header>
|
||||||
<if $message != ''>
|
<if $message != ''>
|
||||||
<div class="errorcontainer bradius">
|
<div class="errorcontainer bradius">
|
||||||
|
|||||||
Reference in New Issue
Block a user