Compare commits
205 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63bbcd4e00 | ||
|
|
49d67d7c27 | ||
|
|
7cc4c9fedb | ||
|
|
afd110a6ed | ||
|
|
7cdf6c8d64 | ||
|
|
60621da243 | ||
|
|
96ccdda304 | ||
|
|
4073984fd7 | ||
|
|
ea31c8a64d | ||
|
|
832ee07e0e | ||
|
|
b542b140c6 | ||
|
|
ac89fc7120 | ||
|
|
150858485d | ||
|
|
e7810e2066 | ||
|
|
4879446567 | ||
|
|
43eff78088 | ||
|
|
55a2ae3801 | ||
|
|
a3b0332d13 | ||
|
|
4b1846883d | ||
|
|
778fd3ba65 | ||
|
|
00456a35e5 | ||
|
|
5958f0516b | ||
|
|
166ffedf04 | ||
|
|
36dfee1263 | ||
|
|
ec0026ecfd | ||
|
|
a721bb3f21 | ||
|
|
83de3dd719 | ||
|
|
5615decd96 | ||
|
|
0348b1ec7e | ||
|
|
1467dab58f | ||
|
|
3a8f48de35 | ||
|
|
46391c06ec | ||
|
|
7103f7dd51 | ||
|
|
9fc1dfee41 | ||
|
|
82dc76fdc6 | ||
|
|
02ae52e3df | ||
|
|
5c06683e27 | ||
|
|
2684372156 | ||
|
|
d80c6d5714 | ||
|
|
1ae5311b81 | ||
|
|
e1e7555cce | ||
|
|
4f79d7cf4b | ||
|
|
b13b1e8ac7 | ||
|
|
6a1e7cc539 | ||
|
|
2e87633ef7 | ||
|
|
8a23d0b72c | ||
|
|
735ef85088 | ||
|
|
75cf44a6d2 | ||
|
|
7e0073f4a3 | ||
|
|
c9291df345 | ||
|
|
fd5e97d48c | ||
|
|
64a9fb163a | ||
|
|
b0256ffb7d | ||
|
|
e606bdc97f | ||
|
|
b53b3a924a | ||
|
|
539ea7c8fc | ||
|
|
5e8763e160 | ||
|
|
d52f33a50c | ||
|
|
287ad84b18 | ||
|
|
3f1b792f60 | ||
|
|
d94317421d | ||
|
|
7717a82d5c | ||
|
|
ace1651ceb | ||
|
|
1f74bf059c | ||
|
|
c98e912fc5 | ||
|
|
d04a8e7bbf | ||
|
|
d4a940b723 | ||
|
|
0dd20bc29a | ||
|
|
f71ee9f1f2 | ||
|
|
dd61302445 | ||
|
|
0bee1f03de | ||
|
|
a59aaa3dc9 | ||
|
|
1debe9d939 | ||
|
|
3d2e81b457 | ||
|
|
ac759cd9a4 | ||
|
|
05c77929e4 | ||
|
|
cefd9226bd | ||
|
|
762f295d3d | ||
|
|
d3e6063027 | ||
|
|
f18c14e119 | ||
|
|
77bcd10729 | ||
|
|
6ee990af0a | ||
|
|
a3fe37b69b | ||
|
|
56388ede54 | ||
|
|
b98035bf3a | ||
|
|
95abe465ef | ||
|
|
780f607332 | ||
|
|
a11d26522a | ||
|
|
462a798cb6 | ||
|
|
7556685881 | ||
|
|
965e2dfd95 | ||
|
|
1f2cce6195 | ||
|
|
f4f84aa397 | ||
|
|
0f37dfb1eb | ||
|
|
7438786a24 | ||
|
|
041c2d176c | ||
|
|
597e765677 | ||
|
|
f757233d61 | ||
|
|
cfae3540fc | ||
|
|
9e8f32f1e8 | ||
|
|
a7b66227e6 | ||
|
|
532982784f | ||
|
|
0754be3028 | ||
|
|
166ec0575b | ||
|
|
e8ed43056c | ||
|
|
a808a3f782 | ||
|
|
686065c294 | ||
|
|
41ac713325 | ||
|
|
d1cb32b47f | ||
|
|
13b6ab0b07 | ||
|
|
215e749ba8 | ||
|
|
0b7d2358ed | ||
|
|
f3c965fe53 | ||
|
|
5b58ab4371 | ||
|
|
3ad203535a | ||
|
|
6edc6553bd | ||
|
|
3fc18f9903 | ||
|
|
506cccd7c8 | ||
|
|
6ad1ca2ba9 | ||
|
|
6d9014c29b | ||
|
|
7e168f5a0e | ||
|
|
4fcf0606c7 | ||
|
|
9d2077ddee | ||
|
|
338b855947 | ||
|
|
5d04b8c829 | ||
|
|
a0406932c3 | ||
|
|
22aa197864 | ||
|
|
d53f9b8e58 | ||
|
|
9d4205acf6 | ||
|
|
cb8b969ddd | ||
|
|
fcfd44f726 | ||
|
|
52a06bf806 | ||
|
|
20aa162fcc | ||
|
|
bb60df0709 | ||
|
|
a86c8535e0 | ||
|
|
ab82695806 | ||
|
|
c52d9bbd03 | ||
|
|
d1043b4645 | ||
|
|
9d113afc83 | ||
|
|
bbd1dca30e | ||
|
|
6d42968d1a | ||
|
|
8d66a4aec4 | ||
|
|
e071365cd6 | ||
|
|
5f05478c76 | ||
|
|
6616bd9a38 | ||
|
|
947df2079f | ||
|
|
b791cd5c3e | ||
|
|
1662745991 | ||
|
|
067c9f8c76 | ||
|
|
f396bd5184 | ||
|
|
03b5a921ff | ||
|
|
e357f7e9c3 | ||
|
|
da7309c41e | ||
|
|
257ef4c059 | ||
|
|
eda8700217 | ||
|
|
94d9c3eedf | ||
|
|
f9f1048477 | ||
|
|
a2fca3fe69 | ||
|
|
105213fd3f | ||
|
|
07f4491db6 | ||
|
|
8a30bc07f5 | ||
|
|
ddcd55a83d | ||
|
|
c3205d3672 | ||
|
|
c668c180d5 | ||
|
|
1cf5865bba | ||
|
|
6f5e49de79 | ||
|
|
a9c613e71c | ||
|
|
981d7f3d9a | ||
|
|
3445472049 | ||
|
|
bfc816a51e | ||
|
|
5afe5a8c46 | ||
|
|
eb9dded947 | ||
|
|
e958cfed84 | ||
|
|
5181602921 | ||
|
|
4bfed71ac9 | ||
|
|
69c58d21be | ||
|
|
94051dc9eb | ||
|
|
2ec039372d | ||
|
|
0c3ac31231 | ||
|
|
03257f04cb | ||
|
|
6e37b55ac6 | ||
|
|
196ef9378a | ||
|
|
9ed45ea7f8 | ||
|
|
20755bcead | ||
|
|
bde19997ba | ||
|
|
981d819fd7 | ||
|
|
c079047180 | ||
|
|
e1e7bc7b42 | ||
|
|
512a544dd1 | ||
|
|
0fb338b32d | ||
|
|
e90dae186b | ||
|
|
ca5f36d912 | ||
|
|
63d81201de | ||
|
|
0b685d569f | ||
|
|
426f204473 | ||
|
|
84599011cf | ||
|
|
6202e24b77 | ||
|
|
8deaf6a013 | ||
|
|
a491667ce5 | ||
|
|
d51556f918 | ||
|
|
233bf27afe | ||
|
|
09b3c1c45a | ||
|
|
2e6b939ec6 | ||
|
|
c1f03c1683 | ||
|
|
5731f5ffff |
5
.github/workflows/build-docs.yml
vendored
5
.github/workflows/build-docs.yml
vendored
@@ -2,7 +2,8 @@ name: build-documentation
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [published]
|
# only run for stable releases
|
||||||
|
types: [released]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_docs:
|
build_docs:
|
||||||
@@ -11,4 +12,4 @@ jobs:
|
|||||||
- env:
|
- env:
|
||||||
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
gh workflow run --repo Froxlor/Documentation build-and-deploy.yml -f type=tags ref=${{github.ref_name}}
|
gh workflow run --repo Froxlor/Documentation build-and-deploy.yml -f type=tags -f ref=${{github.ref_name}}
|
||||||
|
|||||||
112
.github/workflows/build-mariadb.yml
vendored
112
.github/workflows/build-mariadb.yml
vendored
@@ -1,5 +1,5 @@
|
|||||||
name: Froxlor-CI-MariaDB
|
name: Froxlor-CI-MariaDB
|
||||||
on: ['push', 'pull_request', 'create']
|
on: [ 'push', 'pull_request', 'create' ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
froxlor:
|
froxlor:
|
||||||
@@ -8,8 +8,8 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
php-versions: ['7.4', '8.1']
|
php-versions: [ '7.4', '8.2' ]
|
||||||
mariadb-version: [10.5, 10.4]
|
mariadb-version: [ 10.11, 10.5 ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
php-version: ${{ matrix.php-versions }}
|
php-version: ${{ matrix.php-versions }}
|
||||||
tools: composer:v2
|
tools: composer:v2
|
||||||
extensions: mbstring, xml, ctype, pdo_mysql, mysql, curl, json, zip, session, filter, posix, openssl, fileinfo, bcmath, gmp
|
extensions: mbstring, xml, ctype, pdo_mysql, mysql, curl, json, zip, session, filter, posix, openssl, fileinfo, bcmath, gmp, gnupg
|
||||||
|
|
||||||
- name: Install tools
|
- name: Install tools
|
||||||
run: sudo apt-get install -y ant
|
run: sudo apt-get install -y ant
|
||||||
@@ -49,33 +49,81 @@ jobs:
|
|||||||
- name: Run testing
|
- name: Run testing
|
||||||
run: ant quick-build
|
run: ant quick-build
|
||||||
|
|
||||||
# - name: irc push
|
nightly:
|
||||||
# uses: rectalogic/notify-irc@v1
|
name: Create nightly/testing tarball
|
||||||
# if: github.event_name == 'push'
|
runs-on: ubuntu-latest
|
||||||
# with:
|
needs: froxlor
|
||||||
# channel: "#froxlor"
|
if: ${{ github.event_name == 'push' }}
|
||||||
# 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
|
steps:
|
||||||
# uses: rectalogic/notify-irc@v1
|
- name: Checkout
|
||||||
# if: github.event_name == 'pull_request'
|
uses: actions/checkout@v3
|
||||||
# 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
|
- name: Setup PHP with PECL extension
|
||||||
# uses: rectalogic/notify-irc@v1
|
uses: shivammathur/setup-php@v2
|
||||||
# if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
with:
|
||||||
# with:
|
php-version: '7.4'
|
||||||
# channel: "#froxlor"
|
tools: composer:v2
|
||||||
# server: "irc.libera.chat"
|
extensions: mbstring, xml, ctype, pdo_mysql, mysql, curl, json, zip, session, filter, posix, openssl, fileinfo, bcmath, gmp, gnupg
|
||||||
# nickname: froxlor-ci
|
|
||||||
# message: |
|
- name: Install composer dependencies
|
||||||
# ${{ github.actor }} tagged ${{ github.repository }} ${{ github.event.ref }}
|
run: composer install --no-dev
|
||||||
|
|
||||||
|
- name: Install Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '20.x'
|
||||||
|
|
||||||
|
- name: Install npm dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Build assets
|
||||||
|
run: npm run build
|
||||||
|
working-directory: .
|
||||||
|
|
||||||
|
- name: Setting file/directory permissions
|
||||||
|
run: |
|
||||||
|
find -exec chmod ugo+r,u+w,go-w {} \;
|
||||||
|
find -type f -exec chmod ugo-x {} \;
|
||||||
|
find -type d -exec chmod ugo+x {} \;
|
||||||
|
chmod 0755 bin/froxlor-cli
|
||||||
|
|
||||||
|
- name: Remove vcs and unneeded files
|
||||||
|
run: |
|
||||||
|
rm .gitignore
|
||||||
|
rm .editorconfig
|
||||||
|
rm -rf node_modules
|
||||||
|
rm composer.json
|
||||||
|
rm composer.lock
|
||||||
|
rm package.json
|
||||||
|
rm package-lock.json
|
||||||
|
rm *.xml
|
||||||
|
rm vite.config.js
|
||||||
|
|
||||||
|
- name: Create empty index.html in built assets directory
|
||||||
|
run: |
|
||||||
|
touch templates/Froxlor/build/index.html
|
||||||
|
touch templates/Froxlor/build/assets/index.html
|
||||||
|
|
||||||
|
- name: Set outputs
|
||||||
|
id: vars
|
||||||
|
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Set nightly branding
|
||||||
|
run: |
|
||||||
|
sed -i "s/const BRANDING = '';/const BRANDING = '+nightly.${{steps.vars.outputs.sha_short}}';/" lib/Froxlor/Froxlor.php
|
||||||
|
zip -r froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip . -x "*.git*"
|
||||||
|
sha256sum froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip > froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip.sha256
|
||||||
|
mkdir dist
|
||||||
|
mv froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip dist/
|
||||||
|
mv froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip.sha256 dist/
|
||||||
|
|
||||||
|
- name: Deploy nightly to server
|
||||||
|
uses: easingthemes/ssh-deploy@v3.4.3
|
||||||
|
env:
|
||||||
|
ARGS: "-rltDzvO --chown=${{ secrets.WEB_USER }}:${{ secrets.WEB_USER }}"
|
||||||
|
SOURCE: "dist/"
|
||||||
|
SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
|
||||||
|
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
|
||||||
|
REMOTE_USER: ${{ secrets.REMOTE_USER }}
|
||||||
|
TARGET: "${{ secrets.REMOTE_TARGET }}"
|
||||||
|
|||||||
4
.github/workflows/build-mysql.yml
vendored
4
.github/workflows/build-mysql.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
php-versions: ['7.4', '8.1']
|
php-versions: ['7.4', '8.2']
|
||||||
mysql-version: [8.0, 5.7]
|
mysql-version: [8.0, 5.7]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
php-version: ${{ matrix.php-versions }}
|
php-version: ${{ matrix.php-versions }}
|
||||||
tools: composer:v2
|
tools: composer:v2
|
||||||
extensions: mbstring, xml, ctype, pdo_mysql, mysql, curl, json, zip, session, filter, posix, openssl, fileinfo, bcmath, gmp
|
extensions: mbstring, xml, ctype, pdo_mysql, mysql, curl, json, zip, session, filter, posix, openssl, fileinfo, bcmath, gmp, gnupg
|
||||||
|
|
||||||
- name: Install tools
|
- name: Install tools
|
||||||
run: sudo apt-get install -y ant
|
run: sudo apt-get install -y ant
|
||||||
|
|||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -13,6 +13,7 @@ logs/*
|
|||||||
*~
|
*~
|
||||||
.well-known
|
.well-known
|
||||||
.idea
|
.idea
|
||||||
|
.DS_Store
|
||||||
*.iml
|
*.iml
|
||||||
img/
|
img/
|
||||||
vendor/
|
vendor/
|
||||||
@@ -21,8 +22,5 @@ fonts/
|
|||||||
templates/*
|
templates/*
|
||||||
!templates/index.html
|
!templates/index.html
|
||||||
!templates/Froxlor/
|
!templates/Froxlor/
|
||||||
templates/Froxlor/assets/mix-manifest.json
|
templates/Froxlor/build/
|
||||||
templates/Froxlor/assets/css/
|
|
||||||
templates/Froxlor/assets/js/
|
|
||||||
templates/Froxlor/assets/webfonts/
|
|
||||||
!templates/misc/
|
!templates/misc/
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -34,19 +34,13 @@ You may find help in the following places:
|
|||||||
|
|
||||||
The froxlor community discord server can be found here: https://discord.froxlor.org
|
The froxlor community discord server can be found here: https://discord.froxlor.org
|
||||||
|
|
||||||
### IRC
|
|
||||||
|
|
||||||
froxlor may be found on libera.chat, channel #froxlor:
|
|
||||||
irc://irc.libera.chat/froxlor
|
|
||||||
|
|
||||||
### Forum
|
### Forum
|
||||||
|
|
||||||
The community is located on https://forum.froxlor.org/
|
The community is located on https://forum.froxlor.org/
|
||||||
|
|
||||||
### Wiki
|
### Documentation
|
||||||
|
|
||||||
More documentation may be found in the froxlor - documentation:
|
The documentation may be found at https://docs.froxlor.org/
|
||||||
https://docs.froxlor.org/
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
13
SECURITY.md
13
SECURITY.md
@@ -10,9 +10,10 @@ With that, good luck hacking us ;)
|
|||||||
|
|
||||||
## Supported versions
|
## Supported versions
|
||||||
|
|
||||||
- ️✅ **2.x** (`main` git-branch)
|
- ️✅ **2.1.x** (`main` git-branch)
|
||||||
- ❌ 0.10.x (`0.10.x` git-branch)
|
- ❌ 2.0.x (`2.0.x`-tags)
|
||||||
- ❌ 0.9.x (`0.9.x`git-branch)
|
- ❌ 0.10.x (`0.10.x`-tags)
|
||||||
|
- ❌ other git-branches
|
||||||
|
|
||||||
## Qualifying Vulnerabilities
|
## Qualifying Vulnerabilities
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ With that, good luck hacking us ;)
|
|||||||
|
|
||||||
### Vulnerabilities we accept
|
### Vulnerabilities we accept
|
||||||
|
|
||||||
Only reproducable issues on a default/clean setup from the latest stable release of a supported version will be accepted.
|
Only reproducible issues on a default/clean setup from the latest stable release of a supported version will be accepted.
|
||||||
|
|
||||||
## Non-Qualifying Vulnerabilities
|
## Non-Qualifying Vulnerabilities
|
||||||
|
|
||||||
@@ -34,6 +35,8 @@ Only reproducable issues on a default/clean setup from the latest stable release
|
|||||||
- Theoretical attacks without proof of exploitability
|
- Theoretical attacks without proof of exploitability
|
||||||
- Attacks that are the result of a third party library should be reported to the library maintainers
|
- Attacks that are the result of a third party library should be reported to the library maintainers
|
||||||
- Social engineering
|
- Social engineering
|
||||||
|
- Attacks that require disabling security features or reducing the security level of the environment
|
||||||
|
- Exploits by an admin user itself (privileged user and implicitly trusted)
|
||||||
- Reflected file download
|
- Reflected file download
|
||||||
- Physical attacks
|
- Physical attacks
|
||||||
- Weak SSL/TLS/SSH algorithms or protocols
|
- Weak SSL/TLS/SSH algorithms or protocols
|
||||||
@@ -44,4 +47,4 @@ Only reproducable issues on a default/clean setup from the latest stable release
|
|||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
If you think you have found a vulnerability in froxlor, please head over to [https://huntr.dev/repos/froxlor/froxlor](https://huntr.dev/repos/froxlor/froxlor) and use the reporting possibilities there as we are funding the prize-pot for froxlor on this platform. Also, please give us appropriate time to fix the issue and build update-packages before publishing anything into the wild. Alternatively you can send us an email to [team@froxlor.org](team@froxlor.org).
|
If you think you have found a vulnerability in froxlor, please head over to [https://github.com/Froxlor/Froxlor/security/advisories](https://github.com/Froxlor/Froxlor/security/advisories/new) and use the reporting possibilities there. Also, please give us appropriate time to fix the issue and build update-packages before publishing anything into the wild. Alternatively you can email us to [team@froxlor.org](team@froxlor.org).
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ return [
|
|||||||
'extras.directoryprotection' => lng('menue.extras.extras') . " / " . lng('menue.extras.directoryprotection'),
|
'extras.directoryprotection' => lng('menue.extras.extras') . " / " . lng('menue.extras.directoryprotection'),
|
||||||
'extras.pathoptions' => lng('menue.extras.extras') . " / " . lng('menue.extras.pathoptions'),
|
'extras.pathoptions' => lng('menue.extras.extras') . " / " . lng('menue.extras.pathoptions'),
|
||||||
'extras.logger' => lng('menue.extras.extras') . " / " . lng('menue.logger.logger'),
|
'extras.logger' => lng('menue.extras.extras') . " / " . lng('menue.logger.logger'),
|
||||||
'extras.backup' => lng('menue.extras.extras') . " / " . lng('menue.extras.backup'),
|
'extras.export' => lng('menue.extras.extras') . " / " . lng('menue.extras.export'),
|
||||||
'traffic' => lng('menue.traffic.traffic'),
|
'traffic' => lng('menue.traffic.traffic'),
|
||||||
'traffic.http' => lng('menue.traffic.traffic') . " / HTTP",
|
'traffic.http' => lng('menue.traffic.traffic') . " / HTTP",
|
||||||
'traffic.ftp' => lng('menue.traffic.traffic') . " / FTP",
|
'traffic.ftp' => lng('menue.traffic.traffic') . " / FTP",
|
||||||
@@ -337,7 +337,15 @@ return [
|
|||||||
'image_name' => 'logo_login',
|
'image_name' => 'logo_login',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingImage'
|
'save_method' => 'storeSettingImage'
|
||||||
]
|
],
|
||||||
|
'panel_menu_collapsed' => [
|
||||||
|
'label' => lng('serversettings.panel_menu_collapsed'),
|
||||||
|
'settinggroup' => 'panel',
|
||||||
|
'varname' => 'menu_collapsed',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'default' => true,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
],
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -230,13 +230,13 @@ return [
|
|||||||
'onlyif' => 1
|
'onlyif' => 1
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_backupenabled' => [
|
'system_exportenabled' => [
|
||||||
'label' => lng('serversettings.backupenabled'),
|
'label' => lng('serversettings.exportenabled'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'backupenabled',
|
'varname' => 'exportenabled',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'cronmodule' => 'froxlor/backup',
|
'cronmodule' => 'froxlor/export',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_createstdsubdom_default' => [
|
'system_createstdsubdom_default' => [
|
||||||
|
|||||||
@@ -107,7 +107,8 @@ return [
|
|||||||
'varname' => 'enabled',
|
'varname' => 'enabled',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'api_customer_default' => [
|
'api_customer_default' => [
|
||||||
'label' => lng('serversettings.api_customer_default'),
|
'label' => lng('serversettings.api_customer_default'),
|
||||||
@@ -129,7 +130,8 @@ return [
|
|||||||
'default' => 'stable',
|
'default' => 'stable',
|
||||||
'select_var' => [
|
'select_var' => [
|
||||||
'stable' => lng('serversettings.uc_stable'),
|
'stable' => lng('serversettings.uc_stable'),
|
||||||
'testing' => lng('serversettings.uc_testing')
|
'testing' => lng('serversettings.uc_testing'),
|
||||||
|
'nightly' => lng('serversettings.uc_nightly')
|
||||||
],
|
],
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
@@ -170,16 +172,6 @@ return [
|
|||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_index_file_extension' => [
|
|
||||||
'label' => lng('serversettings.index_file_extension'),
|
|
||||||
'settinggroup' => 'system',
|
|
||||||
'varname' => 'index_file_extension',
|
|
||||||
'type' => 'text',
|
|
||||||
'string_regexp' => '/^[a-zA-Z0-9]{1,6}$/',
|
|
||||||
'default' => 'html',
|
|
||||||
'save_method' => 'storeSettingField',
|
|
||||||
'advanced_mode' => true
|
|
||||||
],
|
|
||||||
'system_store_index_file_subs' => [
|
'system_store_index_file_subs' => [
|
||||||
'label' => lng('serversettings.system_store_index_file_subs'),
|
'label' => lng('serversettings.system_store_index_file_subs'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ return [
|
|||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
||||||
'default' => '/usr/bin/nice -n 5 /usr/bin/php -q',
|
'default' => '/usr/bin/nice -n 5 /usr/bin/php -q',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_crondreload' => [
|
'system_crondreload' => [
|
||||||
'label' => lng('serversettings.system_crondreload'),
|
'label' => lng('serversettings.system_crondreload'),
|
||||||
@@ -55,7 +56,8 @@ return [
|
|||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
||||||
'default' => '/etc/init.d/cron reload',
|
'default' => '/etc/init.d/cron reload',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_cron_allowautoupdate' => [
|
'system_cron_allowautoupdate' => [
|
||||||
'label' => lng('serversettings.system_cron_allowautoupdate'),
|
'label' => lng('serversettings.system_cron_allowautoupdate'),
|
||||||
@@ -63,7 +65,8 @@ return [
|
|||||||
'varname' => 'cron_allowautoupdate',
|
'varname' => 'cron_allowautoupdate',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -181,7 +181,8 @@ return [
|
|||||||
'label' => lng('serversettings.logfiles_format'),
|
'label' => lng('serversettings.logfiles_format'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'logfiles_format',
|
'varname' => 'logfiles_format',
|
||||||
'type' => 'text',
|
'type' => (strpos(Settings::Get('system.logfiles_format'), '"') !== false ? 'textarea' : 'text'),
|
||||||
|
'string_regexp' => '/^[^\0\r\n<>]*$/i',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
@@ -307,7 +308,8 @@ return [
|
|||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
||||||
'default' => '/etc/init.d/apache2 reload',
|
'default' => '/etc/init.d/apache2 reload',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_phpreload_command' => [
|
'system_phpreload_command' => [
|
||||||
'label' => lng('serversettings.phpreload_command'),
|
'label' => lng('serversettings.phpreload_command'),
|
||||||
@@ -319,7 +321,8 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'websrv_avail' => [
|
'websrv_avail' => [
|
||||||
'nginx'
|
'nginx'
|
||||||
]
|
],
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_nginx_php_backend' => [
|
'system_nginx_php_backend' => [
|
||||||
'label' => lng('serversettings.nginx_php_backend'),
|
'label' => lng('serversettings.nginx_php_backend'),
|
||||||
|
|||||||
@@ -157,7 +157,8 @@ return [
|
|||||||
'string_type' => 'file',
|
'string_type' => 'file',
|
||||||
'default' => '/root/.acme.sh/acme.sh',
|
'default' => '/root/.acme.sh/acme.sh',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_letsencryptacmeconf' => [
|
'system_letsencryptacmeconf' => [
|
||||||
'label' => lng('serversettings.letsencryptacmeconf'),
|
'label' => lng('serversettings.letsencryptacmeconf'),
|
||||||
@@ -247,7 +248,7 @@ return [
|
|||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'le_domain_dnscheck_resolver',
|
'varname' => 'le_domain_dnscheck_resolver',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^(([0-9]+ [a-z0-9\-\._]+, ?)*[0-9]+ [a-z0-9\-\._]+)?$/i',
|
'string_type' => 'validate_ip',
|
||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
|
|||||||
@@ -126,7 +126,8 @@ return [
|
|||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'phpfpm_ini_values' => [
|
'phpfpm_ini_values' => [
|
||||||
'label' => lng('phpfpm.ini_values'),
|
'label' => lng('phpfpm.ini_values'),
|
||||||
@@ -135,7 +136,8 @@ return [
|
|||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'phpfpm_ini_admin_flags' => [
|
'phpfpm_ini_admin_flags' => [
|
||||||
'label' => lng('phpfpm.ini_admin_flags'),
|
'label' => lng('phpfpm.ini_admin_flags'),
|
||||||
@@ -144,7 +146,8 @@ return [
|
|||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'phpfpm_ini_admin_values' => [
|
'phpfpm_ini_admin_values' => [
|
||||||
'label' => lng('phpfpm.ini_admin_values'),
|
'label' => lng('phpfpm.ini_admin_values'),
|
||||||
@@ -153,7 +156,8 @@ return [
|
|||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -80,7 +80,8 @@ return [
|
|||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
||||||
'default' => '/etc/init.d/bind9 reload',
|
'default' => '/etc/init.d/bind9 reload',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_nameservers' => [
|
'system_nameservers' => [
|
||||||
'label' => lng('serversettings.nameservers'),
|
'label' => lng('serversettings.nameservers'),
|
||||||
@@ -111,7 +112,8 @@ return [
|
|||||||
'string_delimiter' => ',',
|
'string_delimiter' => ',',
|
||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_powerdns_mode' => [
|
'system_powerdns_mode' => [
|
||||||
'label' => lng('serversettings.powerdns_mode'),
|
'label' => lng('serversettings.powerdns_mode'),
|
||||||
|
|||||||
@@ -137,7 +137,8 @@ return [
|
|||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
|
||||||
'default' => '/etc/init.d/dkim-filter restart',
|
'default' => '/etc/init.d/dkim-filter restart',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ return [
|
|||||||
'settinggroup' => 'spf',
|
'settinggroup' => 'spf',
|
||||||
'varname' => 'spf_entry',
|
'varname' => 'spf_entry',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'default' => '"v=spf1 a mx -all"',
|
'string_regexp' => '/^v=spf[a-z0-9:~?\s.-]+$/i',
|
||||||
|
'default' => 'v=spf1 a mx -all',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ return [
|
|||||||
'varname' => 'unix_names',
|
'varname' => 'unix_names',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => true,
|
'default' => true,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_mailpwcleartext' => [
|
'system_mailpwcleartext' => [
|
||||||
'label' => lng('serversettings.mailpwcleartext'),
|
'label' => lng('serversettings.mailpwcleartext'),
|
||||||
@@ -46,7 +47,8 @@ return [
|
|||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_passwordcryptfunc' => [
|
'system_passwordcryptfunc' => [
|
||||||
'label' => lng('serversettings.passwordcryptfunc'),
|
'label' => lng('serversettings.passwordcryptfunc'),
|
||||||
@@ -59,7 +61,8 @@ return [
|
|||||||
'getAvailablePasswordHashes'
|
'getAvailablePasswordHashes'
|
||||||
],
|
],
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_allow_error_report_admin' => [
|
'system_allow_error_report_admin' => [
|
||||||
'label' => lng('serversettings.allow_error_report_admin'),
|
'label' => lng('serversettings.allow_error_report_admin'),
|
||||||
@@ -67,7 +70,8 @@ return [
|
|||||||
'varname' => 'allow_error_report_admin',
|
'varname' => 'allow_error_report_admin',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_allow_error_report_customer' => [
|
'system_allow_error_report_customer' => [
|
||||||
'label' => lng('serversettings.allow_error_report_customer'),
|
'label' => lng('serversettings.allow_error_report_customer'),
|
||||||
@@ -75,7 +79,8 @@ return [
|
|||||||
'varname' => 'allow_error_report_customer',
|
'varname' => 'allow_error_report_customer',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_allow_customer_shell' => [
|
'system_allow_customer_shell' => [
|
||||||
'label' => lng('serversettings.allow_allow_customer_shell'),
|
'label' => lng('serversettings.allow_allow_customer_shell'),
|
||||||
@@ -84,7 +89,8 @@ return [
|
|||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_available_shells' => [
|
'system_available_shells' => [
|
||||||
'label' => lng('serversettings.available_shells'),
|
'label' => lng('serversettings.available_shells'),
|
||||||
@@ -94,7 +100,8 @@ return [
|
|||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_froxlorusergroup' => [
|
'system_froxlorusergroup' => [
|
||||||
'label' => lng('serversettings.froxlorusergroup'),
|
'label' => lng('serversettings.froxlorusergroup'),
|
||||||
@@ -108,7 +115,8 @@ return [
|
|||||||
'checkLocalGroup'
|
'checkLocalGroup'
|
||||||
],
|
],
|
||||||
'visible' => Settings::Get('system.nssextrausers'),
|
'visible' => Settings::Get('system.nssextrausers'),
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -44,24 +44,30 @@ return [
|
|||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'diskquota_repquota_path',
|
'varname' => 'diskquota_repquota_path',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
'string_type' => 'file',
|
||||||
'default' => '/usr/sbin/repquota',
|
'default' => '/usr/sbin/repquota',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_diskquota_quotatool_path' => [
|
'system_diskquota_quotatool_path' => [
|
||||||
'label' => lng('serversettings.diskquota_quotatool_path.description'),
|
'label' => lng('serversettings.diskquota_quotatool_path.description'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'diskquota_quotatool_path',
|
'varname' => 'diskquota_quotatool_path',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
'string_type' => 'file',
|
||||||
'default' => '/usr/bin/quotatool',
|
'default' => '/usr/bin/quotatool',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_diskquota_customer_partition' => [
|
'system_diskquota_customer_partition' => [
|
||||||
'label' => lng('serversettings.diskquota_customer_partition.description'),
|
'label' => lng('serversettings.diskquota_customer_partition.description'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'diskquota_customer_partition',
|
'varname' => 'diskquota_customer_partition',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
'string_type' => 'file',
|
||||||
'default' => '/dev/root',
|
'default' => '/dev/root',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ if ($action == 'delete' && function_exists('apcu_clear_cache') && $userinfo['cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!function_exists('apcu_cache_info') || !function_exists('apcu_sma_info')) {
|
if (!function_exists('apcu_cache_info') || !function_exists('apcu_sma_info')) {
|
||||||
Response::standardError(lng('error.no_apcuinfo'));
|
Response::standardError('no_apcuinfo');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
|
if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ if ($userinfo['change_serversettings'] == '1') {
|
|||||||
|
|
||||||
if (!empty($distribution)) {
|
if (!empty($distribution)) {
|
||||||
if (!file_exists($config_dir . '/' . $distribution . ".xml")) {
|
if (!file_exists($config_dir . '/' . $distribution . ".xml")) {
|
||||||
Response::dynamicError("Unknown distribution");
|
// unknown distribution -> redirect to select a valid distribution for config-templates
|
||||||
|
Settings::Set('system.distribution', '');
|
||||||
|
Response::redirectTo('admin_configfiles.php', ['reselect' => 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update setting if different
|
// update setting if different
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ use Froxlor\Api\Commands\Customers as Customers;
|
|||||||
use Froxlor\Api\Commands\Domains as Domains;
|
use Froxlor\Api\Commands\Domains as Domains;
|
||||||
use Froxlor\Bulk\DomainBulkAction;
|
use Froxlor\Bulk\DomainBulkAction;
|
||||||
use Froxlor\Cron\TaskId;
|
use Froxlor\Cron\TaskId;
|
||||||
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Customer\Customer;
|
use Froxlor\Customer\Customer;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Domain\Domain;
|
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
@@ -45,7 +45,6 @@ use Froxlor\UI\Request;
|
|||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\User;
|
use Froxlor\User;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use Froxlor\CurrentUser;
|
|
||||||
|
|
||||||
$id = (int)Request::any('id');
|
$id = (int)Request::any('id');
|
||||||
|
|
||||||
@@ -114,15 +113,11 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
} elseif ($alias_check['count'] > 0) {
|
} elseif ($alias_check['count'] > 0) {
|
||||||
Response::standardError('domains_cantdeletedomainwithaliases');
|
Response::standardError('domains_cantdeletedomainwithaliases');
|
||||||
} else {
|
} else {
|
||||||
$showcheck = false;
|
HTML::askYesNo('admin_domain_reallydelete', $filename, [
|
||||||
if (Domain::domainHasMainSubDomains($id)) {
|
|
||||||
$showcheck = true;
|
|
||||||
}
|
|
||||||
HTML::askYesNoWithCheckbox('admin_domain_reallydelete', 'remove_subbutmain_domains', $filename, [
|
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'action' => $action
|
'action' => $action
|
||||||
], $idna_convert->decode($result['domain']), $showcheck);
|
], $idna_convert->decode($result['domain']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($action == 'add') {
|
} elseif ($action == 'add') {
|
||||||
@@ -252,21 +247,6 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
$domains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']) . ' (' . $row_domain['loginname'] . ')';
|
$domains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']) . ' (' . $row_domain['loginname'] . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
$subtodomains = [
|
|
||||||
0 => lng('domains.nosubtomaindomain')
|
|
||||||
];
|
|
||||||
$result_domains_stmt = Database::prepare("
|
|
||||||
SELECT `d`.`id`, `d`.`domain`, `c`.`loginname` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c`
|
|
||||||
WHERE `d`.`aliasdomain` IS NULL AND `d`.`parentdomainid` = 0 AND `d`.`ismainbutsubto` = 0 " . $standardsubdomains . ($userinfo['customers_see_all'] ? '' : " AND `d`.`adminid` = :adminid") . "
|
|
||||||
AND `d`.`customerid`=`c`.`customerid` ORDER BY `loginname`, `domain` ASC
|
|
||||||
");
|
|
||||||
// params from above still valid
|
|
||||||
Database::pexecute($result_domains_stmt, $params);
|
|
||||||
|
|
||||||
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
||||||
$subtodomains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']) . ' (' . $row_domain['loginname'] . ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
$phpconfigs = [];
|
$phpconfigs = [];
|
||||||
$configs = Database::query("
|
$configs = Database::query("
|
||||||
SELECT c.*, fc.description as interpreter
|
SELECT c.*, fc.description as interpreter
|
||||||
@@ -469,27 +449,6 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
$domains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']);
|
$domains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$subtodomains = [
|
|
||||||
0 => lng('domains.nosubtomaindomain')
|
|
||||||
];
|
|
||||||
$result_domains_stmt = Database::prepare("
|
|
||||||
SELECT `d`.`id`, `d`.`domain` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c`
|
|
||||||
WHERE `d`.`aliasdomain` IS NULL AND `d`.`parentdomainid` = '0' AND `d`.`id` <> :id
|
|
||||||
AND `c`.`standardsubdomain`<>`d`.`id` AND `c`.`customerid`=`d`.`customerid`" . ($userinfo['customers_see_all'] ? '' : " AND `d`.`adminid` = :adminid") . "
|
|
||||||
ORDER BY `d`.`domain` ASC
|
|
||||||
");
|
|
||||||
$params = [
|
|
||||||
'id' => $result['id']
|
|
||||||
];
|
|
||||||
if ($userinfo['customers_see_all'] == '0') {
|
|
||||||
$params['adminid'] = $userinfo['adminid'];
|
|
||||||
}
|
|
||||||
Database::pexecute($result_domains_stmt, $params);
|
|
||||||
|
|
||||||
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
||||||
$subtodomains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($userinfo['ip'] == "-1") {
|
if ($userinfo['ip'] == "-1") {
|
||||||
$result_ipsandports_stmt = Database::query("
|
$result_ipsandports_stmt = Database::query("
|
||||||
SELECT `id`, `ip`, `port` FROM `" . TABLE_PANEL_IPSANDPORTS . "` WHERE `ssl`='0' ORDER BY `ip`, `port` ASC
|
SELECT `id`, `ip`, `port` FROM `" . TABLE_PANEL_IPSANDPORTS . "` WHERE `ssl`='0' ORDER BY `ip`, `port` ASC
|
||||||
@@ -676,6 +635,23 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
'alert_msg' => lng('domains.import_description')
|
'alert_msg' => lng('domains.import_description')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
} elseif ($action == 'duplicate') {
|
||||||
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
|
try {
|
||||||
|
Domains::getLocal($userinfo, $_POST)->duplicate();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
Response::redirectTo($filename, [
|
||||||
|
'page' => $page,
|
||||||
|
'searchfield' => 'd.domain_ace',
|
||||||
|
'searchtext' => Request::post('domain', "")
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
Response::redirectTo($filename, [
|
||||||
|
'page' => 'overview'
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} elseif ($page == 'domainssleditor') {
|
} elseif ($page == 'domainssleditor') {
|
||||||
require_once __DIR__ . '/ssl_editor.php';
|
require_once __DIR__ . '/ssl_editor.php';
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ use Froxlor\Api\Commands\Froxlor as Froxlor;
|
|||||||
use Froxlor\CurrentUser;
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\Language;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\Crypt;
|
use Froxlor\System\Crypt;
|
||||||
@@ -38,7 +39,6 @@ use Froxlor\UI\Panel\UI;
|
|||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use Froxlor\Language;
|
|
||||||
|
|
||||||
$id = (int)Request::any('id');
|
$id = (int)Request::any('id');
|
||||||
|
|
||||||
@@ -197,8 +197,11 @@ if ($page == 'overview') {
|
|||||||
'outstanding_tasks' => $outstanding_tasks,
|
'outstanding_tasks' => $outstanding_tasks,
|
||||||
'cron_last_runs' => $cron_last_runs
|
'cron_last_runs' => $cron_last_runs
|
||||||
]);
|
]);
|
||||||
} elseif ($page == 'change_password') {
|
} elseif ($page == 'profile') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
$languages = Language::getLanguages();
|
||||||
|
|
||||||
|
if (!empty($_POST)) {
|
||||||
|
if ($_POST['send'] == 'changepassword') {
|
||||||
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
||||||
|
|
||||||
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_ADMINS, 'adminid')) {
|
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_ADMINS, 'adminid')) {
|
||||||
@@ -241,12 +244,22 @@ if ($page == 'overview') {
|
|||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'changed password');
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'changed password');
|
||||||
Response::redirectTo($filename);
|
Response::redirectTo($filename);
|
||||||
}
|
}
|
||||||
} else {
|
} elseif ($_POST['send'] == 'changetheme') {
|
||||||
UI::view('user/change_password.html.twig');
|
if (Settings::Get('panel.allow_theme_change_admin') == 1) {
|
||||||
|
$theme = Validate::validate($_POST['theme'], 'theme');
|
||||||
|
try {
|
||||||
|
Admins::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['adminid'],
|
||||||
|
'theme' => $theme
|
||||||
|
])->update();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
} elseif ($page == 'change_language') {
|
|
||||||
$languages = Language::getLanguages();
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her theme to '" . $theme . "'");
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
}
|
||||||
|
Response::redirectTo($filename);
|
||||||
|
} elseif ($_POST['send'] == 'changelanguage') {
|
||||||
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
||||||
|
|
||||||
if (isset($languages[$def_language])) {
|
if (isset($languages[$def_language])) {
|
||||||
@@ -262,42 +275,26 @@ if ($page == 'overview') {
|
|||||||
}
|
}
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her default language to '" . $def_language . "'");
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her default language to '" . $def_language . "'");
|
||||||
Response::redirectTo($filename);
|
Response::redirectTo($filename);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// change theme
|
||||||
|
$default_theme = Settings::Get('panel.default_theme');
|
||||||
|
if ($userinfo['theme'] != '') {
|
||||||
|
$default_theme = $userinfo['theme'];
|
||||||
|
}
|
||||||
|
$themes_avail = UI::getThemes();
|
||||||
|
|
||||||
|
// change language
|
||||||
$default_lang = Settings::Get('panel.standardlanguage');
|
$default_lang = Settings::Get('panel.standardlanguage');
|
||||||
if ($userinfo['def_language'] != '') {
|
if ($userinfo['def_language'] != '') {
|
||||||
$default_lang = $userinfo['def_language'];
|
$default_lang = $userinfo['def_language'];
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('user/change_language.html.twig', [
|
UI::view('user/profile.html.twig', [
|
||||||
'languages' => $languages,
|
|
||||||
'default_lang' => $default_lang
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} elseif ($page == 'change_theme') {
|
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
|
||||||
$theme = Validate::validate($_POST['theme'], 'theme');
|
|
||||||
try {
|
|
||||||
Admins::getLocal($userinfo, [
|
|
||||||
'id' => $userinfo['adminid'],
|
|
||||||
'theme' => $theme
|
|
||||||
])->update();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her theme to '" . $theme . "'");
|
|
||||||
Response::redirectTo($filename);
|
|
||||||
} else {
|
|
||||||
$default_theme = Settings::Get('panel.default_theme');
|
|
||||||
if ($userinfo['theme'] != '') {
|
|
||||||
$default_theme = $userinfo['theme'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$themes_avail = UI::getThemes();
|
|
||||||
|
|
||||||
UI::view('user/change_theme.html.twig', [
|
|
||||||
'themes' => $themes_avail,
|
'themes' => $themes_avail,
|
||||||
'default_theme' => $default_theme
|
'default_theme' => $default_theme,
|
||||||
|
'languages' => $languages,
|
||||||
|
'default_lang' => $default_lang,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} elseif ($page == 'send_error_report' && Settings::Get('system.allow_error_report_admin') == '1') {
|
} elseif ($page == 'send_error_report' && Settings::Get('system.allow_error_report_admin') == '1') {
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ const AREA = 'admin';
|
|||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\UI\HTML;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\UI\HTML;
|
|
||||||
|
|
||||||
if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_serversettings'] == '1') {
|
if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_serversettings'] == '1') {
|
||||||
if ($_POST['send'] == 'send') {
|
if ($_POST['send'] == 'send') {
|
||||||
@@ -57,252 +57,30 @@ if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!function_exists('opcache_get_configuration')) {
|
if (!extension_loaded('Zend OPcache')) {
|
||||||
Response::standardError(lng('error.no_opcacheinfo'));
|
Response::standardError('no_opcacheinfo');
|
||||||
|
}
|
||||||
|
|
||||||
|
$ocEnabled = ini_get('opcache.enable');
|
||||||
|
if (empty($ocEnabled)) {
|
||||||
|
Response::standardError('inactive_opcacheinfo');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
|
if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
|
||||||
$time = time();
|
$time = time();
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed OPcache info");
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed OPcache info");
|
||||||
|
|
||||||
$optimizationLevels = [
|
$opcache = (new \Amnuts\Opcache\Service())->getData();
|
||||||
1 << 0 => 'CSE, STRING construction',
|
|
||||||
1 << 1 => 'Constant conversion and jumps',
|
|
||||||
1 << 2 => '++, +=, series of jumps',
|
|
||||||
1 << 3 => 'INIT_FCALL_BY_NAME -> DO_FCALL',
|
|
||||||
1 << 4 => 'CFG based optimization',
|
|
||||||
1 << 5 => 'DFA based optimization',
|
|
||||||
1 << 6 => 'CALL GRAPH optimization',
|
|
||||||
1 << 7 => 'SCCP (constant propagation)',
|
|
||||||
1 << 8 => 'TMP VAR usage',
|
|
||||||
1 << 9 => 'NOP removal',
|
|
||||||
1 << 10 => 'Merge equal constants',
|
|
||||||
1 << 11 => 'Adjust used stack',
|
|
||||||
1 << 12 => 'Remove unused variables',
|
|
||||||
1 << 13 => 'DCE (dead code elimination)',
|
|
||||||
1 << 14 => '(unsafe) Collect constants',
|
|
||||||
1 << 15 => 'Inline functions'
|
|
||||||
];
|
|
||||||
|
|
||||||
$jitModes = [
|
|
||||||
[
|
|
||||||
'flag' => 'CPU-specific optimization',
|
|
||||||
'value' => [
|
|
||||||
'Disable CPU-specific optimization',
|
|
||||||
'Enable use of AVX, if the CPU supports it'
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'flag' => 'Register allocation',
|
|
||||||
'value' => [
|
|
||||||
'Do not perform register allocation',
|
|
||||||
'Perform block-local register allocation',
|
|
||||||
'Perform global register allocation'
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'flag' => 'Trigger',
|
|
||||||
'value' => [
|
|
||||||
'Compile all functions on script load',
|
|
||||||
'Compile functions on first execution',
|
|
||||||
'Profile functions on first request and compile the hottest functions afterwards',
|
|
||||||
'Profile on the fly and compile hot functions',
|
|
||||||
'Currently unused',
|
|
||||||
'Use tracing JIT. Profile on the fly and compile traces for hot code segments'
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'flag' => 'Optimization level',
|
|
||||||
'value' => [
|
|
||||||
'No JIT',
|
|
||||||
'Minimal JIT (call standard VM handlers)',
|
|
||||||
'Inline VM handlers',
|
|
||||||
'Use type inference',
|
|
||||||
'Use call graph',
|
|
||||||
'Optimize whole script'
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
$jitModeMapping = [
|
|
||||||
'tracing' => 1254,
|
|
||||||
'on' => 1254,
|
|
||||||
'function' => 1205
|
|
||||||
];
|
|
||||||
|
|
||||||
$status = opcache_get_status(false);
|
|
||||||
$config = opcache_get_configuration();
|
|
||||||
$missingConfig = array_diff_key(ini_get_all('zend opcache', false), $config['directives']);
|
|
||||||
if (!empty($missingConfig)) {
|
|
||||||
$config['directives'] = array_merge($config['directives'], $missingConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = [];
|
|
||||||
if (!empty($status['scripts'])) {
|
|
||||||
uasort($status['scripts'], static function ($a, $b) {
|
|
||||||
return $a['hits'] <=> $b['hits'];
|
|
||||||
});
|
|
||||||
foreach ($status['scripts'] as &$file) {
|
|
||||||
$file['full_path'] = str_replace('\\', '/', $file['full_path']);
|
|
||||||
$file['readable'] = [
|
|
||||||
'hits' => number_format($file['hits']),
|
|
||||||
'memory_consumption' => bsize($file['memory_consumption'])
|
|
||||||
];
|
|
||||||
}
|
|
||||||
$files = array_values($status['scripts']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($config['directives']['opcache.file_cache_only'] || !empty($status['file_cache_only'])) {
|
|
||||||
$overview = false;
|
|
||||||
} else {
|
|
||||||
$status['opcache_statistics']['start_time'] = $status['opcache_statistics']['start_time'] ?? time();
|
|
||||||
$status['opcache_statistics']['last_restart_time'] = $status['opcache_statistics']['last_restart_time'] ?? time();
|
|
||||||
|
|
||||||
$overview = array_merge(
|
|
||||||
$status['memory_usage'],
|
|
||||||
$status['opcache_statistics'],
|
|
||||||
[
|
|
||||||
'total_memory' => $config['directives']['opcache.memory_consumption'],
|
|
||||||
'used_memory_percentage' => round(100 * (
|
|
||||||
($status['memory_usage']['used_memory'] + $status['memory_usage']['wasted_memory'])
|
|
||||||
/ $config['directives']['opcache.memory_consumption']
|
|
||||||
)),
|
|
||||||
'hit_rate_percentage' => round($status['opcache_statistics']['opcache_hit_rate']),
|
|
||||||
'used_key_percentage' => round(100 * ($status['opcache_statistics']['num_cached_keys']
|
|
||||||
/ $status['opcache_statistics']['max_cached_keys']
|
|
||||||
)),
|
|
||||||
'wasted_percentage' => round($status['memory_usage']['current_wasted_percentage'], 2),
|
|
||||||
'readable' => [
|
|
||||||
'total_memory' => bsize($config['directives']['opcache.memory_consumption']),
|
|
||||||
'used_memory' => bsize($status['memory_usage']['used_memory']),
|
|
||||||
'free_memory' => bsize($status['memory_usage']['free_memory']),
|
|
||||||
'wasted_memory' => bsize($status['memory_usage']['wasted_memory']),
|
|
||||||
'num_cached_scripts' => number_format($status['opcache_statistics']['num_cached_scripts']),
|
|
||||||
'hits' => number_format($status['opcache_statistics']['hits']),
|
|
||||||
'misses' => number_format($status['opcache_statistics']['misses']),
|
|
||||||
'blacklist_miss' => number_format($status['opcache_statistics']['blacklist_misses']),
|
|
||||||
'num_cached_keys' => number_format($status['opcache_statistics']['num_cached_keys']),
|
|
||||||
'max_cached_keys' => number_format($status['opcache_statistics']['max_cached_keys']),
|
|
||||||
'interned' => null,
|
|
||||||
'start_time' => (new DateTimeImmutable("@{$status['opcache_statistics']['start_time']}"))
|
|
||||||
->setTimezone(new DateTimeZone(date_default_timezone_get()))
|
|
||||||
->format('Y-m-d H:i:s'),
|
|
||||||
'last_restart_time' => ($status['opcache_statistics']['last_restart_time'] == 0
|
|
||||||
? 'never'
|
|
||||||
: (new DateTimeImmutable("@{$status['opcache_statistics']['last_restart_time']}"))
|
|
||||||
->setTimezone(new DateTimeZone(date_default_timezone_get()))
|
|
||||||
->format('Y-m-d H:i:s')
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$preload = [];
|
|
||||||
if (!empty($status['preload_statistics']['scripts'])) {
|
|
||||||
$preload = $status['preload_statistics']['scripts'];
|
|
||||||
sort($preload, SORT_STRING);
|
|
||||||
if ($overview) {
|
|
||||||
$overview['preload_memory'] = $status['preload_statistics']['memory_consumption'];
|
|
||||||
$overview['readable']['preload_memory'] = bsize($status['preload_statistics']['memory_consumption']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($status['interned_strings_usage'])) {
|
|
||||||
$overview['readable']['interned'] = [
|
|
||||||
'buffer_size' => bsize($status['interned_strings_usage']['buffer_size']),
|
|
||||||
'strings_used_memory' => bsize($status['interned_strings_usage']['used_memory']),
|
|
||||||
'strings_free_memory' => bsize($status['interned_strings_usage']['free_memory']),
|
|
||||||
'number_of_strings' => number_format($status['interned_strings_usage']['number_of_strings'])
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($overview && !empty($status['jit'])) {
|
|
||||||
$overview['jit_buffer_used_percentage'] = ($status['jit']['buffer_size']
|
|
||||||
? round(100 * (($status['jit']['buffer_size'] - $status['jit']['buffer_free']) / $status['jit']['buffer_size']))
|
|
||||||
: 0
|
|
||||||
);
|
|
||||||
$overview['readable'] = array_merge($overview['readable'], [
|
|
||||||
'jit_buffer_size' => bsize($status['jit']['buffer_size']),
|
|
||||||
'jit_buffer_free' => bsize($status['jit']['buffer_free'])
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$directives = [];
|
|
||||||
ksort($config['directives']);
|
|
||||||
foreach ($config['directives'] as $k => $v) {
|
|
||||||
if (in_array($k, ['opcache.max_file_size', 'opcache.memory_consumption', 'opcache.jit_buffer_size']) && $v) {
|
|
||||||
$v = bsize($v) . " ({$v})";
|
|
||||||
} elseif ($k === 'opcache.optimization_level') {
|
|
||||||
$levels = [];
|
|
||||||
foreach ($optimizationLevels as $level => $info) {
|
|
||||||
if ($level & $v) {
|
|
||||||
$levels[] = "{$info} [{$level}]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$v = $levels ?: 'none';
|
|
||||||
} elseif ($k === 'opcache.jit') {
|
|
||||||
if ($v === '1') {
|
|
||||||
$v = 'on';
|
|
||||||
}
|
|
||||||
if (isset($jitModeMapping[$v]) || is_numeric($v)) {
|
|
||||||
$levels = [];
|
|
||||||
foreach (str_split((string)($jitModeMapping[$v] ?? $v)) as $type => $level) {
|
|
||||||
$levels[] = "{$level}: {$jitModes[$type]['value'][$level]} ({$jitModes[$type]['flag']})";
|
|
||||||
}
|
|
||||||
$v = [$v, $levels];
|
|
||||||
} elseif (empty($v) || strtolower($v) === 'off') {
|
|
||||||
$v = 'Off';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$directives[] = [
|
|
||||||
'k' => $k,
|
|
||||||
'v' => $v
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$version = array_merge(
|
|
||||||
$config['version'],
|
|
||||||
[
|
|
||||||
'php' => phpversion(),
|
|
||||||
'server' => $_SERVER['SERVER_SOFTWARE'] ?: '',
|
|
||||||
'host' => (function_exists('gethostname')
|
|
||||||
? gethostname()
|
|
||||||
: (php_uname('n')
|
|
||||||
?: (empty($_SERVER['SERVER_NAME'])
|
|
||||||
? $_SERVER['HOST_NAME']
|
|
||||||
: $_SERVER['SERVER_NAME']
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
UI::view('settings/opcacheinfo.html.twig', [
|
UI::view('settings/opcacheinfo.html.twig', [
|
||||||
'opcacheinfo' => [
|
'opcacheinfo' => [
|
||||||
'version' => $version,
|
'version' => $opcache['version'],
|
||||||
'overview' => $overview,
|
'overview' => $opcache['overview'],
|
||||||
'files' => $files,
|
'files' => $opcache['files'],
|
||||||
'preload' => $preload,
|
'preload' => $opcache['preload'],
|
||||||
'directives' => $directives,
|
'directives' => $opcache['directives'],
|
||||||
'blacklist' => $config['blacklist'],
|
'blacklist' => $opcache['blacklist'],
|
||||||
'functions' => get_extension_funcs('Zend OPcache')
|
'functions' => $opcache['functions'],
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function bsize($size)
|
|
||||||
{
|
|
||||||
$i = 0;
|
|
||||||
$val = ['b', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
||||||
while (($size / 1024) > 1) {
|
|
||||||
$size /= 1024;
|
|
||||||
++$i;
|
|
||||||
}
|
|
||||||
return sprintf(
|
|
||||||
'%.2f%s%s',
|
|
||||||
$size,
|
|
||||||
'',
|
|
||||||
$val[$i]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -70,14 +70,15 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
|
|||||||
|
|
||||||
// check if the session timeout is too low #815
|
// check if the session timeout is too low #815
|
||||||
if (isset($_POST['session_sessiontimeout']) && $_POST['session_sessiontimeout'] < 60) {
|
if (isset($_POST['session_sessiontimeout']) && $_POST['session_sessiontimeout'] < 60) {
|
||||||
Response::standardError(lng('error.session_timeout'), lng('error.session_timeout_desc'));
|
Response::standardError(['session_timeout', 'session_timeout_desc']);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (Form::processForm($settings_data, $_POST, [
|
if (Form::processForm($settings_data, $_POST, [
|
||||||
'filename' => $filename,
|
'filename' => $filename,
|
||||||
'action' => $action,
|
'action' => $action,
|
||||||
'page' => $page
|
'page' => $page,
|
||||||
|
'part' => $_part,
|
||||||
], $_part, $settings_all, $settings_part, $only_enabledisable)) {
|
], $_part, $settings_all, $settings_part, $only_enabledisable)) {
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "rebuild configfiles due to changed setting");
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "rebuild configfiles due to changed setting");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
@@ -132,7 +133,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Response::standardError(lng('error.no_phpinfo'));
|
Response::standardError('error.no_phpinfo');
|
||||||
}
|
}
|
||||||
UI::view('settings/phpinfo.html.twig', [
|
UI::view('settings/phpinfo.html.twig', [
|
||||||
'phpversion' => PHP_VERSION,
|
'phpversion' => PHP_VERSION,
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ if (Settings::Get('panel.sendalternativemail') == 1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$file_templates = [
|
$file_templates = [
|
||||||
'index_html'
|
'index_html',
|
||||||
|
'unconfigured_html'
|
||||||
];
|
];
|
||||||
|
|
||||||
$languages = Language::getLanguages();
|
$languages = Language::getLanguages();
|
||||||
|
|||||||
@@ -24,20 +24,8 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
use Froxlor\Cli\ConfigDiff;
|
|
||||||
use Symfony\Component\Console\Application;
|
|
||||||
use Froxlor\Cli\RunApiCommand;
|
|
||||||
use Froxlor\Cli\ConfigServices;
|
|
||||||
use Froxlor\Cli\PhpSessionclean;
|
|
||||||
use Froxlor\Cli\SwitchServerIp;
|
|
||||||
use Froxlor\Cli\UpdateCommand;
|
|
||||||
use Froxlor\Cli\InstallCommand;
|
|
||||||
use Froxlor\Cli\MasterCron;
|
|
||||||
use Froxlor\Cli\UserCommand;
|
|
||||||
use Froxlor\Cli\ValidateAcmeWebroot;
|
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
|
use Symfony\Component\Console\Application;
|
||||||
|
|
||||||
// validate correct php version
|
// validate correct php version
|
||||||
if (version_compare("7.4.0", PHP_VERSION, ">=")) {
|
if (version_compare("7.4.0", PHP_VERSION, ">=")) {
|
||||||
@@ -53,14 +41,31 @@ require dirname(__DIR__) . '/vendor/autoload.php';
|
|||||||
require dirname(__DIR__) . '/lib/tables.inc.php';
|
require dirname(__DIR__) . '/lib/tables.inc.php';
|
||||||
|
|
||||||
$application = new Application('froxlor-cli', Froxlor::getFullVersion());
|
$application = new Application('froxlor-cli', Froxlor::getFullVersion());
|
||||||
$application->add(new RunApiCommand());
|
|
||||||
$application->add(new ConfigServices());
|
// files that are no commands
|
||||||
$application->add(new PhpSessionclean());
|
$fileIgnoreList = [
|
||||||
$application->add(new SwitchServerIp());
|
// Current non-command files
|
||||||
$application->add(new UpdateCommand());
|
'CliCommand.php',
|
||||||
$application->add(new InstallCommand());
|
'index.html',
|
||||||
$application->add(new MasterCron());
|
'install.functions.php',
|
||||||
$application->add(new UserCommand());
|
];
|
||||||
$application->add(new ValidateAcmeWebroot());
|
// directory of commands to include
|
||||||
$application->add(new ConfigDiff());
|
$cmd_files = glob(Froxlor::getInstallDir() . '/lib/Froxlor/Cli/*.php');
|
||||||
|
|
||||||
|
// include and add commands
|
||||||
|
foreach ($cmd_files as $cmdFile) {
|
||||||
|
// check ignore-list
|
||||||
|
if (!in_array(basename($cmdFile), $fileIgnoreList)) {
|
||||||
|
// include class-file
|
||||||
|
require $cmdFile;
|
||||||
|
// create class-name including namespace
|
||||||
|
$cmdClass = "\\Froxlor\\Cli\\" . substr(basename($cmdFile), 0, -4);
|
||||||
|
// check whether it exists
|
||||||
|
if (class_exists($cmdClass) && is_subclass_of($cmdClass, '\Symfony\Component\Console\Command\Command')) {
|
||||||
|
// add to cli application
|
||||||
|
$application->add(new $cmdClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$application->run();
|
$application->run();
|
||||||
|
|||||||
@@ -46,15 +46,17 @@
|
|||||||
"ext-fileinfo": "*",
|
"ext-fileinfo": "*",
|
||||||
"ext-gmp": "*",
|
"ext-gmp": "*",
|
||||||
"ext-gd": "*",
|
"ext-gd": "*",
|
||||||
|
"ext-gnupg": "*",
|
||||||
"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",
|
||||||
"twig/twig": "^3.3",
|
"twig/twig": "^3.3",
|
||||||
"erusev/parsedown": "^1.7",
|
|
||||||
"symfony/console": "^5.4",
|
"symfony/console": "^5.4",
|
||||||
"pear/net_dns2": "^1.5"
|
"pear/net_dns2": "^1.5",
|
||||||
|
"amnuts/opcache-gui": "^3.4",
|
||||||
|
"league/commonmark": "^2.4"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9",
|
"phpunit/phpunit": "^9",
|
||||||
|
|||||||
919
composer.lock
generated
919
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,7 @@ const AREA = 'customer';
|
|||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\Api\Commands\SubDomains as SubDomains;
|
use Froxlor\Api\Commands\SubDomains as SubDomains;
|
||||||
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Domain\Domain;
|
use Froxlor\Domain\Domain;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
@@ -40,7 +41,6 @@ use Froxlor\UI\Panel\UI;
|
|||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use Froxlor\CurrentUser;
|
|
||||||
|
|
||||||
// redirect if this customer page is hidden via settings
|
// redirect if this customer page is hidden via settings
|
||||||
if (Settings::IsInList('panel.customer_hide_options', 'domains')) {
|
if (Settings::IsInList('panel.customer_hide_options', 'domains')) {
|
||||||
@@ -51,7 +51,7 @@ $id = (int)Request::any('id');
|
|||||||
|
|
||||||
if ($page == 'overview' || $page == 'domains') {
|
if ($page == 'overview' || $page == 'domains') {
|
||||||
if ($action == '') {
|
if ($action == '') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_domains::domains");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_domains::domains");
|
||||||
|
|
||||||
$parentdomain_id = (int)Request::any('pid', '0');
|
$parentdomain_id = (int)Request::any('pid', '0');
|
||||||
|
|
||||||
@@ -63,20 +63,32 @@ if ($page == 'overview' || $page == 'domains') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
$actions_links = false;
|
$actions_links = [];
|
||||||
if (CurrentUser::canAddResource('subdomains')) {
|
if (CurrentUser::canAddResource('subdomains')) {
|
||||||
$actions_links = [
|
$actions_links[] = [
|
||||||
[
|
|
||||||
'href' => $linker->getLink(['section' => 'domains', 'page' => 'domains', 'action' => 'add']),
|
'href' => $linker->getLink(['section' => 'domains', 'page' => 'domains', 'action' => 'add']),
|
||||||
'label' => lng('domains.subdomain_add')
|
'label' => lng('domains.subdomain_add')
|
||||||
]
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('user/table.html.twig', [
|
$actions_links[] = [
|
||||||
|
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/domains/',
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'fa-solid fa-circle-info',
|
||||||
|
'class' => 'btn-outline-secondary'
|
||||||
|
];
|
||||||
|
|
||||||
|
$table_tpl = 'table.html.twig';
|
||||||
|
if ($collection->count() == 0) {
|
||||||
|
$table_tpl = 'table-note.html.twig';
|
||||||
|
}
|
||||||
|
UI::view('user/' . $table_tpl, [
|
||||||
'listing' => Listing::format($collection, $domain_list_data, 'domain_list'),
|
'listing' => Listing::format($collection, $domain_list_data, 'domain_list'),
|
||||||
'actions_links' => $actions_links,
|
'actions_links' => $actions_links,
|
||||||
'entity_info' => lng('domains.description')
|
'entity_info' => lng('domains.description'),
|
||||||
|
// alert-box
|
||||||
|
'type' => 'warning',
|
||||||
|
'alert_msg' => lng('domains.nodomainsassignedbyadmin')
|
||||||
]);
|
]);
|
||||||
} elseif ($action == 'delete' && $id != 0) {
|
} elseif ($action == 'delete' && $id != 0) {
|
||||||
try {
|
try {
|
||||||
@@ -130,6 +142,7 @@ if ($page == 'overview' || $page == 'domains') {
|
|||||||
AND `parentdomainid` = '0'
|
AND `parentdomainid` = '0'
|
||||||
AND `email_only` = '0'
|
AND `email_only` = '0'
|
||||||
AND `caneditdomain` = '1'
|
AND `caneditdomain` = '1'
|
||||||
|
AND `deactivated` = '0'
|
||||||
ORDER BY `domain` ASC");
|
ORDER BY `domain` ASC");
|
||||||
Database::pexecute($stmt, [
|
Database::pexecute($stmt, [
|
||||||
"customerid" => $userinfo['customerid']
|
"customerid" => $userinfo['customerid']
|
||||||
@@ -139,6 +152,14 @@ if ($page == 'overview' || $page == 'domains') {
|
|||||||
$domains[$row['domain']] = $idna_convert->decode($row['domain']);
|
$domains[$row['domain']] = $idna_convert->decode($row['domain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check of there are any domains to be used
|
||||||
|
if (count($domains) <= 0) {
|
||||||
|
// no, possible direct URL access, redirect to overview
|
||||||
|
Response::redirectTo($filename, [
|
||||||
|
'page' => $page
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$aliasdomains[0] = lng('domains.noaliasdomain');
|
$aliasdomains[0] = lng('domains.noaliasdomain');
|
||||||
$domains_stmt = Database::prepare("SELECT `d`.`id`, `d`.`domain` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c`
|
$domains_stmt = Database::prepare("SELECT `d`.`id`, `d`.`domain` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c`
|
||||||
WHERE `d`.`aliasdomain` IS NULL
|
WHERE `d`.`aliasdomain` IS NULL
|
||||||
@@ -223,7 +244,7 @@ if ($page == 'overview' || $page == 'domains') {
|
|||||||
|
|
||||||
if (isset($result['customerid']) && $result['customerid'] == $userinfo['customerid']) {
|
if (isset($result['customerid']) && $result['customerid'] == $userinfo['customerid']) {
|
||||||
|
|
||||||
if ((int) $result['caneditdomain'] == 0) {
|
if ((int)$result['caneditdomain'] == 0) {
|
||||||
Response::standardError('domaincannotbeedited', $result['domain']);
|
Response::standardError('domaincannotbeedited', $result['domain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,6 +394,23 @@ if ($page == 'overview' || $page == 'domains') {
|
|||||||
} else {
|
} else {
|
||||||
Response::standardError('domains_canteditdomain');
|
Response::standardError('domains_canteditdomain');
|
||||||
}
|
}
|
||||||
|
} elseif ($action == 'jqSpeciallogfileNote') {
|
||||||
|
$domainid = intval($_POST['id']);
|
||||||
|
$newval = intval($_POST['newval']);
|
||||||
|
try {
|
||||||
|
$json_result = SubDomains::getLocal($userinfo, [
|
||||||
|
'id' => $domainid
|
||||||
|
])->get();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
$result = json_decode($json_result, true)['data'];
|
||||||
|
if ($newval != $result['speciallogfile']) {
|
||||||
|
echo json_encode(['changed' => true, 'info' => lng('admin.speciallogwarning')]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
echo 0;
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
} elseif ($page == 'domainssleditor') {
|
} elseif ($page == 'domainssleditor') {
|
||||||
require_once __DIR__ . '/ssl_editor.php';
|
require_once __DIR__ . '/ssl_editor.php';
|
||||||
|
|||||||
@@ -27,9 +27,10 @@ const AREA = 'customer';
|
|||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\Api\Commands\EmailAccounts;
|
use Froxlor\Api\Commands\EmailAccounts;
|
||||||
|
use Froxlor\Api\Commands\EmailDomains;
|
||||||
use Froxlor\Api\Commands\EmailForwarders;
|
use Froxlor\Api\Commands\EmailForwarders;
|
||||||
use Froxlor\Api\Commands\Emails;
|
use Froxlor\Api\Commands\Emails;
|
||||||
use Froxlor\Api\Commands\EmailDomains;
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\PhpHelper;
|
use Froxlor\PhpHelper;
|
||||||
@@ -41,7 +42,6 @@ use Froxlor\UI\Panel\UI;
|
|||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\Validate\Check;
|
use Froxlor\Validate\Check;
|
||||||
use Froxlor\CurrentUser;
|
|
||||||
|
|
||||||
// redirect if this customer page is hidden via settings
|
// redirect if this customer page is hidden via settings
|
||||||
if (Settings::IsInList('panel.customer_hide_options', 'email') || $userinfo['emails'] == 0) {
|
if (Settings::IsInList('panel.customer_hide_options', 'email') || $userinfo['emails'] == 0) {
|
||||||
@@ -67,14 +67,24 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('user/table.html.twig', [
|
$actions_links = [];
|
||||||
'listing' => Listing::format($collection, $emaildomain_list_data, 'emaildomain_list'),
|
if (CurrentUser::canAddResource('emails')) {
|
||||||
'actions_links' => CurrentUser::canAddResource('emails') ? [
|
$actions_links[] = [
|
||||||
[
|
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => 'email_domain', 'action' => 'add']),
|
'href' => $linker->getLink(['section' => 'email', 'page' => 'email_domain', 'action' => 'add']),
|
||||||
'label' => lng('emails.emails_add')
|
'label' => lng('emails.emails_add')
|
||||||
]
|
];
|
||||||
] : null,
|
}
|
||||||
|
|
||||||
|
$actions_links[] = [
|
||||||
|
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/emails/',
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'fa-solid fa-circle-info',
|
||||||
|
'class' => 'btn-outline-secondary'
|
||||||
|
];
|
||||||
|
|
||||||
|
UI::view('user/table.html.twig', [
|
||||||
|
'listing' => Listing::format($collection, $emaildomain_list_data, 'emaildomain_list'),
|
||||||
|
'actions_links' => $actions_links,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// only emails for one domain -> show email address listing directly
|
// only emails for one domain -> show email address listing directly
|
||||||
@@ -84,7 +94,7 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
if ($page == 'email_domain') {
|
if ($page == 'email_domain') {
|
||||||
$email_domainid = Request::any('domainid', 0);
|
$email_domainid = Request::any('domainid', 0);
|
||||||
if ($action == '') {
|
if ($action == '') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_email::emails");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_email::emails");
|
||||||
|
|
||||||
$sql_search = [];
|
$sql_search = [];
|
||||||
if ($email_domainid > 0) {
|
if ($email_domainid > 0) {
|
||||||
@@ -127,6 +137,12 @@ if ($page == 'email_domain') {
|
|||||||
'label' => lng('emails.emails_add')
|
'label' => lng('emails.emails_add')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
$actions_links[] = [
|
||||||
|
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/emails/',
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'fa-solid fa-circle-info',
|
||||||
|
'class' => 'btn-outline-secondary'
|
||||||
|
];
|
||||||
|
|
||||||
UI::view('user/table.html.twig', [
|
UI::view('user/table.html.twig', [
|
||||||
'listing' => Listing::format($collection, $email_list_data, 'email_list'),
|
'listing' => Listing::format($collection, $email_list_data, 'email_list'),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
const AREA = 'customer';
|
const AREA = 'customer';
|
||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\Api\Commands\CustomerBackups as CustomerBackups;
|
use Froxlor\Api\Commands\DataDump as DataDump;
|
||||||
use Froxlor\Api\Commands\DirOptions as DirOptions;
|
use Froxlor\Api\Commands\DirOptions as DirOptions;
|
||||||
use Froxlor\Api\Commands\DirProtections as DirProtections;
|
use Froxlor\Api\Commands\DirProtections as DirProtections;
|
||||||
use Froxlor\Customer\Customer;
|
use Froxlor\Customer\Customer;
|
||||||
@@ -68,14 +68,22 @@ if ($page == 'overview' || $page == 'htpasswds') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('user/table.html.twig', [
|
$actions_links = [];
|
||||||
'listing' => Listing::format($collection, $htpasswd_list_data, 'htpasswd_list'),
|
$actions_links[] = [
|
||||||
'actions_links' => [
|
|
||||||
[
|
|
||||||
'href' => $linker->getLink(['section' => 'extras', 'page' => 'htpasswds', 'action' => 'add']),
|
'href' => $linker->getLink(['section' => 'extras', 'page' => 'htpasswds', 'action' => 'add']),
|
||||||
'label' => lng('extras.directoryprotection_add')
|
'label' => lng('extras.directoryprotection_add')
|
||||||
]
|
];
|
||||||
],
|
|
||||||
|
$actions_links[] = [
|
||||||
|
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/',
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'fa-solid fa-circle-info',
|
||||||
|
'class' => 'btn-outline-secondary'
|
||||||
|
];
|
||||||
|
|
||||||
|
UI::view('user/table.html.twig', [
|
||||||
|
'listing' => Listing::format($collection, $htpasswd_list_data, 'htpasswd_list'),
|
||||||
|
'actions_links' => $actions_links,
|
||||||
'entity_info' => lng('extras.description')
|
'entity_info' => lng('extras.description')
|
||||||
]);
|
]);
|
||||||
} elseif ($action == 'delete' && $id != 0) {
|
} elseif ($action == 'delete' && $id != 0) {
|
||||||
@@ -185,14 +193,22 @@ if ($page == 'overview' || $page == 'htpasswds') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('user/table.html.twig', [
|
$actions_links = [];
|
||||||
'listing' => Listing::format($collection, $htaccess_list_data, 'htaccess_list'),
|
$actions_links[] = [
|
||||||
'actions_links' => [
|
|
||||||
[
|
|
||||||
'href' => $linker->getLink(['section' => 'extras', 'page' => 'htaccess', 'action' => 'add']),
|
'href' => $linker->getLink(['section' => 'extras', 'page' => 'htaccess', 'action' => 'add']),
|
||||||
'label' => lng('extras.pathoptions_add')
|
'label' => lng('extras.pathoptions_add')
|
||||||
]
|
];
|
||||||
],
|
|
||||||
|
$actions_links[] = [
|
||||||
|
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/',
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'fa-solid fa-circle-info',
|
||||||
|
'class' => 'btn-outline-secondary'
|
||||||
|
];
|
||||||
|
|
||||||
|
UI::view('user/table.html.twig', [
|
||||||
|
'listing' => Listing::format($collection, $htaccess_list_data, 'htaccess_list'),
|
||||||
|
'actions_links' => $actions_links,
|
||||||
'entity_info' => lng('extras.description')
|
'entity_info' => lng('extras.description')
|
||||||
]);
|
]);
|
||||||
} elseif ($action == 'delete' && $id != 0) {
|
} elseif ($action == 'delete' && $id != 0) {
|
||||||
@@ -282,18 +298,18 @@ if ($page == 'overview' || $page == 'htpasswds') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($page == 'backup') {
|
} elseif ($page == 'export') {
|
||||||
// redirect if this customer sub-page is hidden via settings
|
// redirect if this customer sub-page is hidden via settings
|
||||||
if (Settings::IsInList('panel.customer_hide_options', 'extras.backup')) {
|
if (Settings::IsInList('panel.customer_hide_options', 'extras.export')) {
|
||||||
Response::redirectTo('customer_index.php');
|
Response::redirectTo('customer_index.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::Get('system.backupenabled') == 1) {
|
if (Settings::Get('system.exportenabled') == 1) {
|
||||||
if ($action == 'abort') {
|
if ($action == 'abort') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "customer_extras::backup - aborted scheduled backupjob");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "customer_extras::export - aborted scheduled data export job");
|
||||||
try {
|
try {
|
||||||
CustomerBackups::getLocal($userinfo, $_POST)->delete();
|
DataDump::getLocal($userinfo, $_POST)->delete();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
@@ -302,43 +318,53 @@ if ($page == 'overview' || $page == 'htpasswds') {
|
|||||||
'action' => ''
|
'action' => ''
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
HTML::askYesNo('extras_reallydelete_backup', $filename, [
|
HTML::askYesNo('extras_reallydelete_export', $filename, [
|
||||||
'backup_job_entry' => $id,
|
'job_entry' => $id,
|
||||||
'section' => 'extras',
|
'section' => 'extras',
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'action' => $action
|
'action' => $action
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} elseif ($action == '') {
|
} elseif ($action == '') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_extras::backup");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_extras::export");
|
||||||
|
|
||||||
// check whether there is a backup-job for this customer
|
// check whether there is a backup-job for this customer
|
||||||
try {
|
try {
|
||||||
$backup_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.backups.php';
|
$export_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.export.php';
|
||||||
$collection = (new Collection(CustomerBackups::class, $userinfo));
|
$collection = (new Collection(DataDump::class, $userinfo));
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
try {
|
try {
|
||||||
CustomerBackups::getLocal($userinfo, $_POST)->add();
|
DataDump::getLocal($userinfo, $_POST)->add();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::standardSuccess('backupscheduled');
|
Response::standardSuccess('exportscheduled');
|
||||||
} else {
|
} else {
|
||||||
$pathSelect = FileDir::makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']);
|
$pathSelect = FileDir::makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']);
|
||||||
$backup_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.backup.php';
|
$export_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.export.php';
|
||||||
|
|
||||||
|
$actions_links = [
|
||||||
|
[
|
||||||
|
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/',
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'fa-solid fa-circle-info',
|
||||||
|
'class' => 'btn-outline-secondary'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
UI::view('user/form-datatable.html.twig', [
|
UI::view('user/form-datatable.html.twig', [
|
||||||
'formaction' => $linker->getLink(['section' => 'extras']),
|
'formaction' => $linker->getLink(['section' => 'extras']),
|
||||||
'formdata' => $backup_data['backup'],
|
'formdata' => $export_data['export'],
|
||||||
'tabledata' => Listing::format($collection, $backup_list_data, 'backup_list'),
|
'actions_links' => $actions_links,
|
||||||
|
'tabledata' => Listing::format($collection, $export_list_data, 'export_list'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Response::standardError('backupfunctionnotenabled');
|
Response::standardError('exportfunctionnotenabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const AREA = 'customer';
|
|||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\Api\Commands\Ftps as Ftps;
|
use Froxlor\Api\Commands\Ftps as Ftps;
|
||||||
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
@@ -37,7 +38,6 @@ use Froxlor\UI\Listing;
|
|||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\CurrentUser;
|
|
||||||
|
|
||||||
// redirect if this customer page is hidden via settings
|
// redirect if this customer page is hidden via settings
|
||||||
if (Settings::IsInList('panel.customer_hide_options', 'ftp')) {
|
if (Settings::IsInList('panel.customer_hide_options', 'ftp')) {
|
||||||
@@ -57,15 +57,19 @@ if ($page == 'overview' || $page == 'accounts') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
$actions_links = false;
|
$actions_links = [];
|
||||||
if (CurrentUser::canAddResource('ftps')) {
|
if (CurrentUser::canAddResource('ftps')) {
|
||||||
$actions_links = [
|
$actions_links[] = [
|
||||||
[
|
|
||||||
'href' => $linker->getLink(['section' => 'ftp', 'page' => 'accounts', 'action' => 'add']),
|
'href' => $linker->getLink(['section' => 'ftp', 'page' => 'accounts', 'action' => 'add']),
|
||||||
'label' => lng('ftp.account_add')
|
'label' => lng('ftp.account_add')
|
||||||
]
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
$actions_links[] = [
|
||||||
|
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/ftp-accounts/',
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'fa-solid fa-circle-info',
|
||||||
|
'class' => 'btn-outline-secondary'
|
||||||
|
];
|
||||||
|
|
||||||
UI::view('user/table.html.twig', [
|
UI::view('user/table.html.twig', [
|
||||||
'listing' => Listing::format($collection, $ftp_list_data, 'ftp_list'),
|
'listing' => Listing::format($collection, $ftp_list_data, 'ftp_list'),
|
||||||
|
|||||||
@@ -27,21 +27,21 @@ const AREA = 'customer';
|
|||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\Api\Commands\Customers as Customers;
|
use Froxlor\Api\Commands\Customers as Customers;
|
||||||
|
use Froxlor\Cron\TaskId;
|
||||||
use Froxlor\CurrentUser;
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\Language;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\Crypt;
|
use Froxlor\System\Crypt;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use Froxlor\Language;
|
|
||||||
use Froxlor\System\Cronjob;
|
|
||||||
use Froxlor\Cron\TaskId;
|
|
||||||
|
|
||||||
if ($action == 'logout') {
|
if ($action == 'logout') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'logged out');
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, 'logged out');
|
||||||
|
|
||||||
unset($_SESSION['userinfo']);
|
unset($_SESSION['userinfo']);
|
||||||
CurrentUser::setData();
|
CurrentUser::setData();
|
||||||
@@ -66,7 +66,7 @@ if ($action == 'logout') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($page == 'overview') {
|
if ($page == 'overview') {
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_index");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_index");
|
||||||
|
|
||||||
$domain_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
$domain_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE `customerid` = :customerid
|
WHERE `customerid` = :customerid
|
||||||
@@ -114,6 +114,11 @@ if ($page == 'overview') {
|
|||||||
$userinfo['traffic_bytes'] = ($userinfo['traffic'] > -1) ? $userinfo['traffic'] * 1024 : -1;
|
$userinfo['traffic_bytes'] = ($userinfo['traffic'] > -1) ? $userinfo['traffic'] * 1024 : -1;
|
||||||
$userinfo['traffic_bytes_used'] = $userinfo['traffic_used'] * 1024;
|
$userinfo['traffic_bytes_used'] = $userinfo['traffic_used'] * 1024;
|
||||||
|
|
||||||
|
if (Settings::Get('system.mail_quota_enabled')) {
|
||||||
|
$userinfo['email_quota_bytes'] = ($userinfo['email_quota'] > -1) ? $userinfo['email_quota'] * 1024 * 1024 : -1;
|
||||||
|
$userinfo['email_quota_bytes_used'] = $userinfo['email_quota_used'] * 1024 * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
if ($usages) {
|
if ($usages) {
|
||||||
$userinfo['diskspace_bytes_used'] = $usages['webspace'] * 1024;
|
$userinfo['diskspace_bytes_used'] = $usages['webspace'] * 1024;
|
||||||
$userinfo['mailspace_used'] = $usages['mail'] * 1024;
|
$userinfo['mailspace_used'] = $usages['mail'] * 1024;
|
||||||
@@ -131,8 +136,11 @@ if ($page == 'overview') {
|
|||||||
'domains' => $domainArray,
|
'domains' => $domainArray,
|
||||||
'stdsubdomain' => $stdsubdomain
|
'stdsubdomain' => $stdsubdomain
|
||||||
]);
|
]);
|
||||||
} elseif ($page == 'change_password') {
|
} elseif ($page == 'profile') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
$languages = Language::getLanguages();
|
||||||
|
|
||||||
|
if (!empty($_POST)) {
|
||||||
|
if ($_POST['send'] == 'changepassword') {
|
||||||
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
||||||
|
|
||||||
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) {
|
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) {
|
||||||
@@ -210,12 +218,22 @@ if ($page == 'overview') {
|
|||||||
|
|
||||||
Response::redirectTo($filename);
|
Response::redirectTo($filename);
|
||||||
}
|
}
|
||||||
} else {
|
} elseif ($_POST['send'] == 'changetheme') {
|
||||||
UI::view('user/change_password.html.twig');
|
if (Settings::Get('panel.allow_theme_change_customer') == 1) {
|
||||||
|
$theme = Validate::validate($_POST['theme'], 'theme');
|
||||||
|
try {
|
||||||
|
Customers::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['customerid'],
|
||||||
|
'theme' => $theme
|
||||||
|
])->update();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
} elseif ($page == 'change_language') {
|
|
||||||
$languages = Language::getLanguages();
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default theme to '" . $theme . "'");
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
}
|
||||||
|
Response::redirectTo($filename);
|
||||||
|
} elseif ($_POST['send'] == 'changelanguage') {
|
||||||
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
||||||
if (isset($languages[$def_language])) {
|
if (isset($languages[$def_language])) {
|
||||||
try {
|
try {
|
||||||
@@ -230,42 +248,26 @@ if ($page == 'overview') {
|
|||||||
}
|
}
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default language to '" . $def_language . "'");
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default language to '" . $def_language . "'");
|
||||||
Response::redirectTo($filename);
|
Response::redirectTo($filename);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// change theme
|
||||||
|
$default_theme = Settings::Get('panel.default_theme');
|
||||||
|
if ($userinfo['theme'] != '') {
|
||||||
|
$default_theme = $userinfo['theme'];
|
||||||
|
}
|
||||||
|
$themes_avail = UI::getThemes();
|
||||||
|
|
||||||
|
// change language
|
||||||
$default_lang = Settings::Get('panel.standardlanguage');
|
$default_lang = Settings::Get('panel.standardlanguage');
|
||||||
if ($userinfo['def_language'] != '') {
|
if ($userinfo['def_language'] != '') {
|
||||||
$default_lang = $userinfo['def_language'];
|
$default_lang = $userinfo['def_language'];
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('user/change_language.html.twig', [
|
UI::view('user/profile.html.twig', [
|
||||||
'languages' => $languages,
|
|
||||||
'default_lang' => $default_lang
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} elseif ($page == 'change_theme') {
|
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
|
||||||
$theme = Validate::validate($_POST['theme'], 'theme');
|
|
||||||
try {
|
|
||||||
Customers::getLocal($userinfo, [
|
|
||||||
'id' => $userinfo['customerid'],
|
|
||||||
'theme' => $theme
|
|
||||||
])->update();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default theme to '" . $theme . "'");
|
|
||||||
Response::redirectTo($filename);
|
|
||||||
} else {
|
|
||||||
$default_theme = Settings::Get('panel.default_theme');
|
|
||||||
if ($userinfo['theme'] != '') {
|
|
||||||
$default_theme = $userinfo['theme'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$themes_avail = UI::getThemes();
|
|
||||||
|
|
||||||
UI::view('user/change_theme.html.twig', [
|
|
||||||
'themes' => $themes_avail,
|
'themes' => $themes_avail,
|
||||||
'default_theme' => $default_theme
|
'default_theme' => $default_theme,
|
||||||
|
'languages' => $languages,
|
||||||
|
'default_lang' => $default_lang,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} elseif ($page == 'send_error_report' && Settings::Get('system.allow_error_report_customer') == '1') {
|
} elseif ($page == 'send_error_report' && Settings::Get('system.allow_error_report_customer') == '1') {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ require __DIR__ . '/lib/init.php';
|
|||||||
|
|
||||||
use Froxlor\Api\Commands\Mysqls;
|
use Froxlor\Api\Commands\Mysqls;
|
||||||
use Froxlor\Api\Commands\MysqlServer;
|
use Froxlor\Api\Commands\MysqlServer;
|
||||||
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
@@ -37,7 +38,6 @@ use Froxlor\UI\Listing;
|
|||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\CurrentUser;
|
|
||||||
|
|
||||||
// redirect if this customer page is hidden via settings or no resources given
|
// redirect if this customer page is hidden via settings or no resources given
|
||||||
if (Settings::IsInList('panel.customer_hide_options', 'mysql') || $userinfo['mysqls'] == 0) {
|
if (Settings::IsInList('panel.customer_hide_options', 'mysql') || $userinfo['mysqls'] == 0) {
|
||||||
@@ -66,16 +66,21 @@ if ($page == 'overview' || $page == 'mysqls') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
$actions_links = false;
|
$actions_links = [];
|
||||||
if (CurrentUser::canAddResource('mysqls')) {
|
if (CurrentUser::canAddResource('mysqls')) {
|
||||||
$actions_links = [
|
$actions_links[] = [
|
||||||
[
|
|
||||||
'href' => $linker->getLink(['section' => 'mysql', 'page' => 'mysqls', 'action' => 'add']),
|
'href' => $linker->getLink(['section' => 'mysql', 'page' => 'mysqls', 'action' => 'add']),
|
||||||
'label' => lng('mysql.database_create')
|
'label' => lng('mysql.database_create')
|
||||||
]
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$actions_links[] = [
|
||||||
|
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/databases/',
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'fa-solid fa-circle-info',
|
||||||
|
'class' => 'btn-outline-secondary'
|
||||||
|
];
|
||||||
|
|
||||||
UI::view('user/table.html.twig', [
|
UI::view('user/table.html.twig', [
|
||||||
'listing' => Listing::format($collection, $mysql_list_data, 'mysql_list'),
|
'listing' => Listing::format($collection, $mysql_list_data, 'mysql_list'),
|
||||||
'actions_links' => $actions_links,
|
'actions_links' => $actions_links,
|
||||||
@@ -179,7 +184,7 @@ if ($page == 'overview' || $page == 'mysqls') {
|
|||||||
$result_json = MysqlServer::getLocal($userinfo)->listing();
|
$result_json = MysqlServer::getLocal($userinfo)->listing();
|
||||||
$result_decoded = json_decode($result_json, true)['data']['list'];
|
$result_decoded = json_decode($result_json, true)['data']['list'];
|
||||||
foreach ($result_decoded as $dbserver => $dbdata) {
|
foreach ($result_decoded as $dbserver => $dbdata) {
|
||||||
$mysql_servers[$dbserver] = $dbdata['caption'] . ' (' . $dbdata['host'] . (isset($dbdata['port']) && !empty($dbdata['port']) ? ':' . $dbdata['port'] : '').')';
|
$mysql_servers[$dbserver] = $dbdata['caption'] . ' (' . $dbdata['host'] . (isset($dbdata['port']) && !empty($dbdata['port']) ? ':' . $dbdata['port'] : '') . ')';
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
/* just none */
|
/* just none */
|
||||||
|
|||||||
76
index.php
76
index.php
@@ -26,6 +26,7 @@
|
|||||||
const AREA = 'login';
|
const AREA = 'login';
|
||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
|
use Froxlor\Api\FroxlorRPC;
|
||||||
use Froxlor\CurrentUser;
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Customer\Customer;
|
use Froxlor\Customer\Customer;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
@@ -37,6 +38,7 @@ use Froxlor\PhpHelper;
|
|||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Crypt;
|
use Froxlor\System\Crypt;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\User;
|
use Froxlor\User;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
@@ -72,27 +74,26 @@ if ($action == '2fa_entercode') {
|
|||||||
$code = isset($_POST['2fa_code']) ? $_POST['2fa_code'] : null;
|
$code = isset($_POST['2fa_code']) ? $_POST['2fa_code'] : null;
|
||||||
// verify entered code
|
// verify entered code
|
||||||
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
||||||
$result = ($_SESSION['secret_2fa'] == 'email' ? true : $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3));
|
|
||||||
// get user-data
|
// get user-data
|
||||||
$table = $_SESSION['uidtable_2fa'];
|
$table = $_SESSION['uidtable_2fa'];
|
||||||
$field = $_SESSION['uidfield_2fa'];
|
$field = $_SESSION['uidfield_2fa'];
|
||||||
$uid = $_SESSION['uid_2fa'];
|
$uid = $_SESSION['uid_2fa'];
|
||||||
$isadmin = $_SESSION['unfo_2fa'];
|
$isadmin = $_SESSION['unfo_2fa'];
|
||||||
|
if ($_SESSION['secret_2fa'] == 'email') {
|
||||||
|
// verify code set to user's data_2fa field
|
||||||
|
$sel_stmt = Database::prepare("SELECT `data_2fa` FROM " . $table . " WHERE `" . $field . "` = :uid");
|
||||||
|
$userinfo_code = Database::pexecute_first($sel_stmt, ['uid' => $uid]);
|
||||||
|
$result = $tfa->verifyCode($userinfo_code['data_2fa'], $code);
|
||||||
|
} else {
|
||||||
|
$result = $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3);
|
||||||
|
}
|
||||||
// either the code is valid when using authenticator-app, or we will select userdata by id and entered code
|
// either the code is valid when using authenticator-app, or we will select userdata by id and entered code
|
||||||
// which is temporarily stored for the customer when using email-2fa
|
// which is temporarily stored for the customer when using email-2fa
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$sel_param = [
|
$sel_param = [
|
||||||
'uid' => $uid
|
'uid' => $uid
|
||||||
];
|
];
|
||||||
if ($_SESSION['secret_2fa'] == 'email') {
|
|
||||||
// verify code by selecting user by id and the temp. stored code,
|
|
||||||
// so only if it's the correct code, we get the user-data
|
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid AND `data_2fa` = :code");
|
|
||||||
$sel_param['code'] = $code;
|
|
||||||
} else {
|
|
||||||
// Authenticator-verification has already happened at this point, so just get the user-data
|
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid");
|
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid");
|
||||||
}
|
|
||||||
$userinfo = Database::pexecute_first($sel_stmt, $sel_param);
|
$userinfo = Database::pexecute_first($sel_stmt, $sel_param);
|
||||||
// whoops, no (valid) user? Start again
|
// whoops, no (valid) user? Start again
|
||||||
if (empty($userinfo)) {
|
if (empty($userinfo)) {
|
||||||
@@ -325,11 +326,12 @@ if ($action == '2fa_entercode') {
|
|||||||
if ($userinfo['type_2fa'] == 1) {
|
if ($userinfo['type_2fa'] == 1) {
|
||||||
// generate code
|
// generate code
|
||||||
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
||||||
$code = $tfa->getCode($tfa->createSecret());
|
$secret = $tfa->createSecret();
|
||||||
|
$code = $tfa->getCode($secret);
|
||||||
// set code for user
|
// set code for user
|
||||||
$stmt = Database::prepare("UPDATE $table SET `data_2fa` = :d2fa WHERE `$uid` = :uid");
|
$stmt = Database::prepare("UPDATE $table SET `data_2fa` = :d2fa WHERE `$uid` = :uid");
|
||||||
Database::pexecute($stmt, [
|
Database::pexecute($stmt, [
|
||||||
"d2fa" => $code,
|
"d2fa" => $secret,
|
||||||
"uid" => $userinfo[$uid]
|
"uid" => $userinfo[$uid]
|
||||||
]);
|
]);
|
||||||
// build up & send email
|
// build up & send email
|
||||||
@@ -734,6 +736,58 @@ if ($action == 'resetpwd') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// one-time link login
|
||||||
|
if ($action == 'll') {
|
||||||
|
if (!Froxlor::hasUpdates() && !Froxlor::hasDbUpdates()) {
|
||||||
|
$loginname = Request::get('ln');
|
||||||
|
$hash = Request::get('h');
|
||||||
|
if ($loginname && $hash) {
|
||||||
|
$sel_stmt = Database::prepare("
|
||||||
|
SELECT * FROM `" . TABLE_PANEL_LOGINLINKS . "`
|
||||||
|
WHERE `loginname` = :loginname AND `hash` = :hash
|
||||||
|
");
|
||||||
|
try {
|
||||||
|
$entry = Database::pexecute_first($sel_stmt, ['loginname' => $loginname, 'hash' => $hash]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$entry = false;
|
||||||
|
}
|
||||||
|
if ($entry) {
|
||||||
|
// delete entry
|
||||||
|
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_LOGINLINKS . "` WHERE `loginname` = :loginname AND `hash` = :hash");
|
||||||
|
Database::pexecute($del_stmt, ['loginname' => $loginname, 'hash' => $hash]);
|
||||||
|
if (time() <= $entry['valid_until']) {
|
||||||
|
$valid = true;
|
||||||
|
// validate source ip if specified
|
||||||
|
if (!empty($entry['allowed_from'])) {
|
||||||
|
$valid = false;
|
||||||
|
$ip_list = explode(",", $entry['allowed_from']);
|
||||||
|
if (FroxlorRPC::validateAllowedFrom($ip_list, $_SERVER['REMOTE_ADDR'])) {
|
||||||
|
$valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($valid) {
|
||||||
|
// login user / select only non-deactivated (in case the user got deactivated after generating the link)
|
||||||
|
$userinfo_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `loginname`= :loginname AND `deactivated` = 0");
|
||||||
|
try {
|
||||||
|
$userinfo = Database::pexecute_first($userinfo_stmt, [
|
||||||
|
"loginname" => $loginname
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$userinfo = false;
|
||||||
|
}
|
||||||
|
if ($userinfo) {
|
||||||
|
$userinfo['userid'] = $userinfo['customerid'];
|
||||||
|
$userinfo['adminsession'] = 0;
|
||||||
|
finishLogin($userinfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Response::redirectTo('index.php');
|
||||||
|
}
|
||||||
|
|
||||||
function finishLogin($userinfo)
|
function finishLogin($userinfo)
|
||||||
{
|
{
|
||||||
if (isset($userinfo['userid']) && $userinfo['userid'] != '') {
|
if (isset($userinfo['userid']) && $userinfo['userid'] != '') {
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ CREATE TABLE `panel_admins` (
|
|||||||
`api_allowed` tinyint(1) NOT NULL default '1',
|
`api_allowed` tinyint(1) NOT NULL default '1',
|
||||||
PRIMARY KEY (`adminid`),
|
PRIMARY KEY (`adminid`),
|
||||||
UNIQUE KEY `loginname` (`loginname`)
|
UNIQUE KEY `loginname` (`loginname`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_customers`;
|
DROP TABLE IF EXISTS `panel_customers`;
|
||||||
@@ -278,7 +278,6 @@ CREATE TABLE `panel_domains` (
|
|||||||
`phpsettingid` INT( 11 ) UNSIGNED NOT NULL DEFAULT '1',
|
`phpsettingid` INT( 11 ) UNSIGNED NOT NULL DEFAULT '1',
|
||||||
`mod_fcgid_starter` int(4) default '-1',
|
`mod_fcgid_starter` int(4) default '-1',
|
||||||
`mod_fcgid_maxrequests` int(4) default '-1',
|
`mod_fcgid_maxrequests` int(4) default '-1',
|
||||||
`ismainbutsubto` int(11) unsigned NOT NULL default '0',
|
|
||||||
`letsencrypt` tinyint(1) NOT NULL default '0',
|
`letsencrypt` tinyint(1) NOT NULL default '0',
|
||||||
`hsts` varchar(10) NOT NULL default '0',
|
`hsts` varchar(10) NOT NULL default '0',
|
||||||
`hsts_sub` tinyint(1) NOT NULL default '0',
|
`hsts_sub` tinyint(1) NOT NULL default '0',
|
||||||
@@ -300,7 +299,7 @@ CREATE TABLE `panel_domains` (
|
|||||||
KEY `customerid` (`customerid`),
|
KEY `customerid` (`customerid`),
|
||||||
KEY `parentdomain` (`parentdomainid`),
|
KEY `parentdomain` (`parentdomainid`),
|
||||||
KEY `domain` (`domain`)
|
KEY `domain` (`domain`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_ipsandports`;
|
DROP TABLE IF EXISTS `panel_ipsandports`;
|
||||||
@@ -357,23 +356,6 @@ CREATE TABLE `panel_htpasswds` (
|
|||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_sessions`;
|
|
||||||
CREATE TABLE `panel_sessions` (
|
|
||||||
`hash` varchar(32) NOT NULL default '',
|
|
||||||
`userid` int(11) unsigned NOT NULL default '0',
|
|
||||||
`ipaddress` varchar(255) NOT NULL default '',
|
|
||||||
`useragent` varchar(255) NOT NULL default '',
|
|
||||||
`lastactivity` int(11) unsigned NOT NULL default '0',
|
|
||||||
`lastpaging` varchar(255) NOT NULL default '',
|
|
||||||
`formtoken` char(32) NOT NULL default '',
|
|
||||||
`language` varchar(64) NOT NULL default '',
|
|
||||||
`adminsession` tinyint(1) unsigned NOT NULL default '0',
|
|
||||||
`theme` varchar(255) NOT NULL default '',
|
|
||||||
PRIMARY KEY (`hash`),
|
|
||||||
KEY `userid` (`userid`)
|
|
||||||
) ENGINE=HEAP;
|
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_settings`;
|
DROP TABLE IF EXISTS `panel_settings`;
|
||||||
CREATE TABLE `panel_settings` (
|
CREATE TABLE `panel_settings` (
|
||||||
`settingid` int(11) unsigned NOT NULL auto_increment,
|
`settingid` int(11) unsigned NOT NULL auto_increment,
|
||||||
@@ -409,7 +391,7 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES
|
|||||||
('admin', 'show_version_footer', '0'),
|
('admin', 'show_version_footer', '0'),
|
||||||
('caa', 'caa_entry', ''),
|
('caa', 'caa_entry', ''),
|
||||||
('spf', 'use_spf', '0'),
|
('spf', 'use_spf', '0'),
|
||||||
('spf', 'spf_entry', '"v=spf1 a mx -all"'),
|
('spf', 'spf_entry', 'v=spf1 a mx -all'),
|
||||||
('dkim', 'dkim_algorithm', 'all'),
|
('dkim', 'dkim_algorithm', 'all'),
|
||||||
('dkim', 'dkim_keylength', '1024'),
|
('dkim', 'dkim_keylength', '1024'),
|
||||||
('dkim', 'dkim_servicetype', '0'),
|
('dkim', 'dkim_servicetype', '0'),
|
||||||
@@ -555,7 +537,7 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'defaultip', '1'),
|
('system', 'defaultip', '1'),
|
||||||
('system', 'defaultsslip', ''),
|
('system', 'defaultsslip', ''),
|
||||||
('system', 'phpappendopenbasedir', '/tmp/'),
|
('system', 'phpappendopenbasedir', '/tmp/'),
|
||||||
('system', 'deactivateddocroot', ''),
|
('system', 'deactivateddocroot', '/var/www/html/froxlor/templates/misc/deactivated/'),
|
||||||
('system', 'mailpwcleartext', '0'),
|
('system', 'mailpwcleartext', '0'),
|
||||||
('system', 'last_tasks_run', '000000'),
|
('system', 'last_tasks_run', '000000'),
|
||||||
('system', 'nameservers', ''),
|
('system', 'nameservers', ''),
|
||||||
@@ -563,7 +545,7 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'mod_fcgid', '0'),
|
('system', 'mod_fcgid', '0'),
|
||||||
('system', 'apacheconf_vhost', '/etc/apache2/sites-enabled/'),
|
('system', 'apacheconf_vhost', '/etc/apache2/sites-enabled/'),
|
||||||
('system', 'apacheconf_diroptions', '/etc/apache2/sites-enabled/'),
|
('system', 'apacheconf_diroptions', '/etc/apache2/sites-enabled/'),
|
||||||
('system', 'apacheconf_htpasswddir', '/etc/apache2/htpasswd/'),
|
('system', 'apacheconf_htpasswddir', '/etc/apache2/froxlor-htpasswd/'),
|
||||||
('system', 'webalizer_quiet', '2'),
|
('system', 'webalizer_quiet', '2'),
|
||||||
('system', 'last_archive_run', '000000'),
|
('system', 'last_archive_run', '000000'),
|
||||||
('system', 'mod_fcgid_configdir', '/var/www/php-fcgi-scripts'),
|
('system', 'mod_fcgid_configdir', '/var/www/php-fcgi-scripts'),
|
||||||
@@ -580,7 +562,6 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'mod_fcgid_wrapper', '1'),
|
('system', 'mod_fcgid_wrapper', '1'),
|
||||||
('system', 'mod_fcgid_starter', '0'),
|
('system', 'mod_fcgid_starter', '0'),
|
||||||
('system', 'mod_fcgid_peardir', '/usr/share/php/:/usr/share/php5/'),
|
('system', 'mod_fcgid_peardir', '/usr/share/php/:/usr/share/php5/'),
|
||||||
('system', 'index_file_extension', 'html'),
|
|
||||||
('system', 'mod_fcgid_maxrequests', '250'),
|
('system', 'mod_fcgid_maxrequests', '250'),
|
||||||
('system', 'ssl_key_file','/etc/ssl/froxlor_selfsigned.key'),
|
('system', 'ssl_key_file','/etc/ssl/froxlor_selfsigned.key'),
|
||||||
('system', 'ssl_ca_file', ''),
|
('system', 'ssl_ca_file', ''),
|
||||||
@@ -647,7 +628,7 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'letsencryptreuseold', 0),
|
('system', 'letsencryptreuseold', 0),
|
||||||
('system', 'leenabled', '0'),
|
('system', 'leenabled', '0'),
|
||||||
('system', 'leapiversion', '2'),
|
('system', 'leapiversion', '2'),
|
||||||
('system', 'backupenabled', '0'),
|
('system', 'exportenabled', '0'),
|
||||||
('system', 'dnsenabled', '0'),
|
('system', 'dnsenabled', '0'),
|
||||||
('system', 'dns_server', 'Bind'),
|
('system', 'dns_server', 'Bind'),
|
||||||
('system', 'apacheglobaldiropt', ''),
|
('system', 'apacheglobaldiropt', ''),
|
||||||
@@ -697,7 +678,7 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'distribution', ''),
|
('system', 'distribution', ''),
|
||||||
('system', 'update_channel', 'stable'),
|
('system', 'update_channel', 'stable'),
|
||||||
('system', 'updatecheck_data', ''),
|
('system', 'updatecheck_data', ''),
|
||||||
('system', 'update_notify_last', '2.0.23'),
|
('system', 'update_notify_last', ''),
|
||||||
('system', 'traffictool', 'goaccess'),
|
('system', 'traffictool', 'goaccess'),
|
||||||
('system', 'req_limit_per_interval', 60),
|
('system', 'req_limit_per_interval', 60),
|
||||||
('system', 'req_limit_interval', 60),
|
('system', 'req_limit_interval', 60),
|
||||||
@@ -705,7 +686,7 @@ opcache.validate_timestamps'),
|
|||||||
('api', 'customer_default', '1'),
|
('api', 'customer_default', '1'),
|
||||||
('2fa', 'enabled', '1'),
|
('2fa', 'enabled', '1'),
|
||||||
('panel', 'decimal_places', '4'),
|
('panel', 'decimal_places', '4'),
|
||||||
('panel', 'adminmail', 'admin@SERVERNAME'),
|
('panel', 'adminmail', 'ADMIN_MAIL'),
|
||||||
('panel', 'phpmyadmin_url', ''),
|
('panel', 'phpmyadmin_url', ''),
|
||||||
('panel', 'webmail_url', ''),
|
('panel', 'webmail_url', ''),
|
||||||
('panel', 'webftp_url', ''),
|
('panel', 'webftp_url', ''),
|
||||||
@@ -744,8 +725,9 @@ opcache.validate_timestamps'),
|
|||||||
('panel', 'logo_overridetheme', '0'),
|
('panel', 'logo_overridetheme', '0'),
|
||||||
('panel', 'logo_overridecustom', '0'),
|
('panel', 'logo_overridecustom', '0'),
|
||||||
('panel', 'settings_mode', '0'),
|
('panel', 'settings_mode', '0'),
|
||||||
('panel', 'version', '2.0.23'),
|
('panel', 'menu_collapsed', '1'),
|
||||||
('panel', 'db_version', '202304260');
|
('panel', 'version', '2.1.4'),
|
||||||
|
('panel', 'db_version', '202312120');
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_tasks`;
|
DROP TABLE IF EXISTS `panel_tasks`;
|
||||||
@@ -768,6 +750,7 @@ CREATE TABLE `panel_templates` (
|
|||||||
`templategroup` varchar(255) NOT NULL default '',
|
`templategroup` varchar(255) NOT NULL default '',
|
||||||
`varname` varchar(255) NOT NULL default '',
|
`varname` varchar(255) NOT NULL default '',
|
||||||
`value` longtext NOT NULL,
|
`value` longtext NOT NULL,
|
||||||
|
`file_extension` varchar(50) NOT NULL default 'html',
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
KEY adminid (adminid)
|
KEY adminid (adminid)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
@@ -914,7 +897,7 @@ INSERT INTO `cronjobs_run` (`id`, `module`, `cronfile`, `cronclass`, `interval`,
|
|||||||
(3, 'froxlor/reports', 'usage_report', '\\Froxlor\\Cron\\Traffic\\ReportsCron', '1 DAY', '1', 'cron_usage_report'),
|
(3, 'froxlor/reports', 'usage_report', '\\Froxlor\\Cron\\Traffic\\ReportsCron', '1 DAY', '1', 'cron_usage_report'),
|
||||||
(4, 'froxlor/core', 'mailboxsize', '\\Froxlor\\Cron\\System\\MailboxsizeCron', '6 HOUR', '1', 'cron_mailboxsize'),
|
(4, 'froxlor/core', 'mailboxsize', '\\Froxlor\\Cron\\System\\MailboxsizeCron', '6 HOUR', '1', 'cron_mailboxsize'),
|
||||||
(5, 'froxlor/letsencrypt', 'letsencrypt', '\\Froxlor\\Cron\\Http\\LetsEncrypt\\AcmeSh', '5 MINUTE', '0', 'cron_letsencrypt'),
|
(5, 'froxlor/letsencrypt', 'letsencrypt', '\\Froxlor\\Cron\\Http\\LetsEncrypt\\AcmeSh', '5 MINUTE', '0', 'cron_letsencrypt'),
|
||||||
(6, 'froxlor/backup', 'backup', '\\Froxlor\\Cron\\System\\BackupCron', '1 DAY', '0', 'cron_backup');
|
(6, 'froxlor/export', 'export', '\\Froxlor\\Cron\\System\\ExportCron', '1 HOUR', '0', 'cron_export');
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `ftp_quotalimits`;
|
DROP TABLE IF EXISTS `ftp_quotalimits`;
|
||||||
@@ -1052,4 +1035,14 @@ CREATE TABLE `panel_usercolumns` (
|
|||||||
KEY adminid (adminid),
|
KEY adminid (adminid),
|
||||||
KEY customerid (customerid)
|
KEY customerid (customerid)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
|
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `panel_loginlinks`;
|
||||||
|
CREATE TABLE `panel_loginlinks` (
|
||||||
|
`hash` varchar(500) NOT NULL,
|
||||||
|
`loginname` varchar(50) NOT NULL,
|
||||||
|
`valid_until` int(15) NOT NULL,
|
||||||
|
`allowed_from` text NOT NULL,
|
||||||
|
UNIQUE KEY `loginname` (`loginname`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
FROXLORSQL;
|
FROXLORSQL;
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\FileDir;
|
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Settings;
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Install\Update;
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\IPTools;
|
use Froxlor\System\IPTools;
|
||||||
|
|
||||||
|
|||||||
@@ -512,3 +512,8 @@ if (Froxlor::isFroxlorVersion('2.0.22')) {
|
|||||||
Update::showUpdateStep("Updating from 2.0.22 to 2.0.23", false);
|
Update::showUpdateStep("Updating from 2.0.22 to 2.0.23", false);
|
||||||
Froxlor::updateToVersion('2.0.23');
|
Froxlor::updateToVersion('2.0.23');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.23')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.23 to 2.0.24", false);
|
||||||
|
Froxlor::updateToVersion('2.0.24');
|
||||||
|
}
|
||||||
281
install/updates/froxlor/update_2.1.inc.php
Normal file
281
install/updates/froxlor/update_2.1.inc.php
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
|
||||||
|
if (!defined('_CRON_UPDATE')) {
|
||||||
|
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
|
||||||
|
header('Location: ../../../../index.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.24')) {
|
||||||
|
Update::showUpdateStep("Cleaning domains table");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ROW_FORMAT=DYNAMIC;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` DROP COLUMN `ismainbutsubto`;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Creating new tables and fields");
|
||||||
|
Database::query("DROP TABLE IF EXISTS `panel_loginlinks`;");
|
||||||
|
$sql = "CREATE TABLE `panel_loginlinks` (
|
||||||
|
`hash` varchar(500) NOT NULL,
|
||||||
|
`loginname` varchar(50) NOT NULL,
|
||||||
|
`valid_until` int(15) NOT NULL,
|
||||||
|
`allowed_from` text NOT NULL,
|
||||||
|
UNIQUE KEY `loginname` (`loginname`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;";
|
||||||
|
Database::query($sql);
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adding new settings");
|
||||||
|
Settings::AddNew('panel.menu_collapsed', 1);
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adjusting setting for deactivated webroot");
|
||||||
|
$current_deactivated_webroot = Settings::Get('system.deactivateddocroot');
|
||||||
|
if (empty($current_deactivated_webroot)) {
|
||||||
|
Settings::Set('system.deactivateddocroot', FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/templates/misc/deactivated/'));
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
Update::lastStepStatus(1, 'Customized setting, not changing');
|
||||||
|
}
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adjusting cronjobs");
|
||||||
|
$cfupd_stmt = Database::prepare("
|
||||||
|
UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET
|
||||||
|
`module`= 'froxlor/export',
|
||||||
|
`cronfile` = 'export',
|
||||||
|
`cronclass` = :cc,
|
||||||
|
`interval` = '1 HOUR',
|
||||||
|
`desc_lng_key` = 'cron_export'
|
||||||
|
WHERE `module` = 'froxlor/backup'
|
||||||
|
");
|
||||||
|
Database::pexecute($cfupd_stmt, [
|
||||||
|
'cc' => '\\Froxlor\\Cron\\System\\ExportCron'
|
||||||
|
]);
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adjusting system for data-export function");
|
||||||
|
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "`SET `varname` = 'exportenabled' WHERE `settinggroup`= 'system' AND `varname`= 'backupenabled'");
|
||||||
|
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "`SET `value` = REPLACE(`value`, 'extras.backup', 'extras.export') WHERE `settinggroup` = 'panel' AND `varname` = 'customer_hide_options'");
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_USERCOLUMNS . "` WHERE `section` = 'backup_list'");
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202305240');
|
||||||
|
Froxlor::updateToVersion('2.1.0-dev1');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.0-dev1')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.0-dev1 to 2.1.0-beta1", false);
|
||||||
|
Froxlor::updateToVersion('2.1.0-beta1');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.0-beta1')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.0-beta1 to 2.1.0-beta2", false);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Removing unused table");
|
||||||
|
Database::query("DROP TABLE IF EXISTS `panel_sessions`;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToVersion('2.1.0-beta2');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.0-beta2')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.0-beta2 to 2.1.0-rc1", false);
|
||||||
|
Froxlor::updateToVersion('2.1.0-rc1');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.0-rc1')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.0-rc1 to 2.1.0-rc2", false);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adjusting setting spf_entry");
|
||||||
|
$spf_entry = Settings::Get('spf.spf_entry');
|
||||||
|
if (!preg_match('/^v=spf[a-z0-9:~?\s.-]+$/i', $spf_entry)) {
|
||||||
|
Settings::Set('spf.spf_entry', 'v=spf1 a mx -all');
|
||||||
|
Update::lastStepStatus(1, 'corrected');
|
||||||
|
} else {
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Froxlor::updateToVersion('2.1.0-rc2');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202305240')) {
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adjusting file-template file extension setttings");
|
||||||
|
$current_fileextension = Settings::Get('system.index_file_extension');
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup`= 'system' AND `varname`= 'index_file_extension'");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_TEMPLATES . "` ADD `file_extension` varchar(50) NOT NULL default 'html';");
|
||||||
|
if (!empty(trim($current_fileextension)) && strtolower(trim($current_fileextension)) != 'html') {
|
||||||
|
$stmt = Database::prepare("UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET `file_extension` = :ext WHERE `templategroup` = 'files'");
|
||||||
|
Database::pexecute($stmt, ['ext' => strtolower(trim($current_fileextension))]);
|
||||||
|
}
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202311260');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.0-rc2')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.0-rc2 to 2.1.0-rc3", false);
|
||||||
|
Froxlor::updateToVersion('2.1.0-rc3');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202311260')) {
|
||||||
|
Update::showUpdateStep("Cleaning up old files");
|
||||||
|
$to_clean = array(
|
||||||
|
"install/updates/froxlor/update_2.x.inc.php",
|
||||||
|
"install/updates/preconfig/preconfig_2.x.inc.php",
|
||||||
|
"lib/Froxlor/Api/Commands/CustomerBackups.php",
|
||||||
|
"lib/Froxlor/Cli/Action",
|
||||||
|
"lib/Froxlor/Cli/Action.php",
|
||||||
|
"lib/Froxlor/Cli/CmdLineHandler.php",
|
||||||
|
"lib/Froxlor/Cli/ConfigServicesCmd.php",
|
||||||
|
"lib/Froxlor/Cli/PhpSessioncleanCmd.php",
|
||||||
|
"lib/Froxlor/Cli/SwitchServerIpCmd.php",
|
||||||
|
"lib/Froxlor/Cli/UpdateCliCmd.php",
|
||||||
|
"lib/Froxlor/Cron/System/BackupCron.php",
|
||||||
|
"lib/formfields/customer/extras/formfield.backup.php",
|
||||||
|
"lib/tablelisting/customer/tablelisting.backups.php",
|
||||||
|
"templates/Froxlor/assets/mix-manifest.json",
|
||||||
|
"templates/Froxlor/assets/css",
|
||||||
|
"templates/Froxlor/assets/webfonts",
|
||||||
|
"templates/Froxlor/assets/js/main.js",
|
||||||
|
"templates/Froxlor/assets/js/main.js.LICENSE.txt",
|
||||||
|
"templates/Froxlor/src",
|
||||||
|
"templates/Froxlor/user/change_language.html.twig",
|
||||||
|
"templates/Froxlor/user/change_password.html.twig",
|
||||||
|
"templates/Froxlor/user/change_theme.html.twig",
|
||||||
|
"tests/Backup/CustomerBackupsTest.php"
|
||||||
|
);
|
||||||
|
$disabled = explode(',', ini_get('disable_functions'));
|
||||||
|
$exec_allowed = !in_array('exec', $disabled);
|
||||||
|
$del_list = "";
|
||||||
|
foreach ($to_clean as $filedir) {
|
||||||
|
$complete_filedir = Froxlor::getInstallDir() . $filedir;
|
||||||
|
if (file_exists($complete_filedir)) {
|
||||||
|
if ($exec_allowed) {
|
||||||
|
FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir));
|
||||||
|
} else {
|
||||||
|
$del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($exec_allowed) {
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
if (empty($del_list)) {
|
||||||
|
// none of the files existed
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
Update::lastStepStatus(
|
||||||
|
1,
|
||||||
|
'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Froxlor::updateToDbVersion('202312050');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.0-rc3')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.0-rc3 to 2.1.0 stable", false);
|
||||||
|
Froxlor::updateToVersion('2.1.0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.0')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.0 to 2.1.1", false);
|
||||||
|
Froxlor::updateToVersion('2.1.1');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202312050')) {
|
||||||
|
Update::showUpdateStep("Cleaning up old files");
|
||||||
|
$to_clean = array(
|
||||||
|
"lib/configfiles/centos7.xml",
|
||||||
|
"lib/configfiles/centos8.xml",
|
||||||
|
"lib/configfiles/stretch.xml",
|
||||||
|
"lib/configfiles/xenial.xml",
|
||||||
|
"lib/configfiles/buster.xml",
|
||||||
|
"lib/configfiles/bionic.xml",
|
||||||
|
);
|
||||||
|
$disabled = explode(',', ini_get('disable_functions'));
|
||||||
|
$exec_allowed = !in_array('exec', $disabled);
|
||||||
|
$del_list = "";
|
||||||
|
foreach ($to_clean as $filedir) {
|
||||||
|
$complete_filedir = Froxlor::getInstallDir() . $filedir;
|
||||||
|
if (file_exists($complete_filedir)) {
|
||||||
|
if ($exec_allowed) {
|
||||||
|
FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir));
|
||||||
|
} else {
|
||||||
|
$del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($exec_allowed) {
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
if (empty($del_list)) {
|
||||||
|
// none of the files existed
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
Update::lastStepStatus(
|
||||||
|
1,
|
||||||
|
'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Froxlor::updateToDbVersion('202312100');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202312100')) {
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adjusting table row format of larger tables");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` ROW_FORMAT=DYNAMIC;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ROW_FORMAT=DYNAMIC;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202312120');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.1')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.1 to 2.1.2", false);
|
||||||
|
Froxlor::updateToVersion('2.1.2');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.2')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.2 to 2.1.3", false);
|
||||||
|
Froxlor::updateToVersion('2.1.3');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.3')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.3 to 2.1.4", false);
|
||||||
|
Froxlor::updateToVersion('2.1.4');
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ use Froxlor\Install\Update;
|
|||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
|
|
||||||
$preconfig = [
|
$preconfig = [
|
||||||
'title' => '2.x updates',
|
'title' => '2.0.x updates',
|
||||||
'fields' => []
|
'fields' => []
|
||||||
];
|
];
|
||||||
$return = [];
|
$return = [];
|
||||||
43
install/updates/preconfig/preconfig_2.1.inc.php
Normal file
43
install/updates/preconfig/preconfig_2.1.inc.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Config\ConfigParser;
|
||||||
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
|
||||||
|
$preconfig = [
|
||||||
|
'title' => '2.1.x updates',
|
||||||
|
'fields' => []
|
||||||
|
];
|
||||||
|
$return = [];
|
||||||
|
|
||||||
|
if (Update::versionInUpdate($current_version, '2.1.0-dev1')) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$preconfig['fields'] = $return;
|
||||||
|
return $preconfig;
|
||||||
@@ -53,7 +53,8 @@ try {
|
|||||||
if (Froxlor::isFroxlor()) {
|
if (Froxlor::isFroxlor()) {
|
||||||
|
|
||||||
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_0.10.inc.php'));
|
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_0.10.inc.php'));
|
||||||
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_2.x.inc.php'));
|
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_2.0.inc.php'));
|
||||||
|
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_2.1.inc.php'));
|
||||||
|
|
||||||
// Check Froxlor - database integrity (only happens after all updates are done, so we know the db-layout is okay)
|
// Check Froxlor - database integrity (only happens after all updates are done, so we know the db-layout is okay)
|
||||||
Update::showUpdateStep("Checking database integrity");
|
Update::showUpdateStep("Checking database integrity");
|
||||||
|
|||||||
@@ -272,7 +272,8 @@ abstract class ApiCommand extends ApiParameter
|
|||||||
$ops = [
|
$ops = [
|
||||||
'<',
|
'<',
|
||||||
'>',
|
'>',
|
||||||
'='
|
'=',
|
||||||
|
'<>'
|
||||||
];
|
];
|
||||||
$first = true;
|
$first = true;
|
||||||
foreach ($search as $field => $valoper) {
|
foreach ($search as $field => $valoper) {
|
||||||
@@ -396,6 +397,7 @@ abstract class ApiCommand extends ApiParameter
|
|||||||
|
|
||||||
$nat_fields = [
|
$nat_fields = [
|
||||||
'`c`.`loginname`',
|
'`c`.`loginname`',
|
||||||
|
'`c`.`name`',
|
||||||
'`a`.`loginname`',
|
'`a`.`loginname`',
|
||||||
'`adminname`',
|
'`adminname`',
|
||||||
'`databasename`',
|
'`databasename`',
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
AND `id`<> :stdd
|
AND `id`<> :stdd
|
||||||
");
|
");
|
||||||
$usages_stmt = Database::prepare("
|
$usages_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_DISKSPACE . "`
|
SELECT webspace, mail, mysql FROM `" . TABLE_PANEL_DISKSPACE . "`
|
||||||
WHERE `customerid` = :cid
|
WHERE `customerid` = :cid
|
||||||
ORDER BY `stamp` DESC LIMIT 1
|
ORDER BY `stamp` DESC LIMIT 1
|
||||||
");
|
");
|
||||||
@@ -109,11 +109,10 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
if ($show_usages) {
|
if ($show_usages) {
|
||||||
// get number of domains
|
// get number of domains
|
||||||
Database::pexecute($domains_stmt, [
|
$domains = Database::pexecute_first($domains_stmt, [
|
||||||
'cid' => $row['customerid'],
|
'cid' => $row['customerid'],
|
||||||
'stdd' => $row['standardsubdomain']
|
'stdd' => $row['standardsubdomain']
|
||||||
]);
|
]);
|
||||||
$domains = $domains_stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
$row['domains'] = intval($domains['domains']);
|
$row['domains'] = intval($domains['domains']);
|
||||||
// get disk-space usages for web, mysql and mail
|
// get disk-space usages for web, mysql and mail
|
||||||
$usages = Database::pexecute_first($usages_stmt, [
|
$usages = Database::pexecute_first($usages_stmt, [
|
||||||
@@ -400,6 +399,10 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
$allowed_phpconfigs = array_map('intval', $allowed_phpconfigs);
|
$allowed_phpconfigs = array_map('intval', $allowed_phpconfigs);
|
||||||
|
|
||||||
|
if (empty($allowed_phpconfigs) && $phpenabled == 1) {
|
||||||
|
Response::standardError('customerphpenabledbutnoconfig', '', true);
|
||||||
|
}
|
||||||
|
|
||||||
$allowed_mysqlserver = array();
|
$allowed_mysqlserver = array();
|
||||||
if (! empty($p_allowed_mysqlserver) && is_array($p_allowed_mysqlserver)) {
|
if (! empty($p_allowed_mysqlserver) && is_array($p_allowed_mysqlserver)) {
|
||||||
foreach ($p_allowed_mysqlserver as $allowed_ms) {
|
foreach ($p_allowed_mysqlserver as $allowed_ms) {
|
||||||
@@ -1050,7 +1053,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
$email = $this->getParam('email', true, $idna_convert->decode($result['email']));
|
$email = $this->getParam('email', true, $idna_convert->decode($result['email']));
|
||||||
$name = $this->getParam('name', true, $result['name']);
|
$name = $this->getParam('name', true, $result['name']);
|
||||||
$firstname = $this->getParam('firstname', true, $result['firstname']);
|
$firstname = $this->getParam('firstname', true, $result['firstname']);
|
||||||
$company_required = empty($result['company']) && ((!empty($name) && empty($firstname)) || (empty($name) && !empty($firstname)) || (empty($name) && empty($firstname)));
|
$company_required = (!empty($name) && empty($firstname)) || (empty($name) && !empty($firstname)) || (empty($name) && empty($firstname));
|
||||||
$company = $this->getParam('company', !$company_required, $result['company']);
|
$company = $this->getParam('company', !$company_required, $result['company']);
|
||||||
$street = $this->getParam('street', true, $result['street']);
|
$street = $this->getParam('street', true, $result['street']);
|
||||||
$zipcode = $this->getParam('zipcode', true, $result['zipcode']);
|
$zipcode = $this->getParam('zipcode', true, $result['zipcode']);
|
||||||
@@ -1110,6 +1113,9 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
if (!empty($allowed_phpconfigs)) {
|
if (!empty($allowed_phpconfigs)) {
|
||||||
$allowed_phpconfigs = array_map('intval', $allowed_phpconfigs);
|
$allowed_phpconfigs = array_map('intval', $allowed_phpconfigs);
|
||||||
}
|
}
|
||||||
|
if (empty($allowed_phpconfigs) && $phpenabled == 1) {
|
||||||
|
Response::standardError('customerphpenabledbutnoconfig', '', true);
|
||||||
|
}
|
||||||
|
|
||||||
// add permission for allowed mysql usage if customer was not allowed to use mysql prior
|
// add permission for allowed mysql usage if customer was not allowed to use mysql prior
|
||||||
if ($result['mysqls'] == 0 && ($mysqls == -1 || $mysqls > 0)) {
|
if ($result['mysqls'] == 0 && ($mysqls == -1 || $mysqls > 0)) {
|
||||||
@@ -1118,6 +1124,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
if (! empty($allowed_mysqlserver)) {
|
if (! empty($allowed_mysqlserver)) {
|
||||||
$allowed_mysqlserver = array_map('intval', $allowed_mysqlserver);
|
$allowed_mysqlserver = array_map('intval', $allowed_mysqlserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
$def_language = Validate::validate($def_language, 'default language', '', '', [], true);
|
$def_language = Validate::validate($def_language, 'default language', '', '', [], true);
|
||||||
$theme = Validate::validate($theme, 'theme', '', '', [], true);
|
$theme = Validate::validate($theme, 'theme', '', '', [], true);
|
||||||
|
|||||||
@@ -41,20 +41,22 @@ use PDO;
|
|||||||
/**
|
/**
|
||||||
* @since 0.10.0
|
* @since 0.10.0
|
||||||
*/
|
*/
|
||||||
class CustomerBackups extends ApiCommand implements ResourceEntity
|
class DataDump extends ApiCommand implements ResourceEntity
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add a new customer backup job
|
* add a new data dump job
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* path to store the backup to
|
* path to store the dumped data to
|
||||||
* @param bool $backup_dbs
|
* @param string $pgp_public_key
|
||||||
* optional whether to backup databases, default is 0 (false)
|
* optional pgp public key to encrypt the archive, default is empty
|
||||||
* @param bool $backup_mail
|
* @param bool $dump_dbs
|
||||||
* optional whether to backup mail-data, default is 0 (false)
|
* optional whether to include databases, default is 0 (false)
|
||||||
* @param bool $backup_web
|
* @param bool $dump_mail
|
||||||
* optional whether to backup web-data, default is 0 (false)
|
* optional whether to include mail-data, default is 0 (false)
|
||||||
|
* @param bool $dump_web
|
||||||
|
* optional whether to incoude web-data, default is 0 (false)
|
||||||
* @param int $customerid
|
* @param int $customerid
|
||||||
* optional, required when called as admin (if $loginname is not specified)
|
* optional, required when called as admin (if $loginname is not specified)
|
||||||
* @param string $loginname
|
* @param string $loginname
|
||||||
@@ -72,9 +74,10 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
$path = $this->getParam('path');
|
$path = $this->getParam('path');
|
||||||
|
|
||||||
// parameter
|
// parameter
|
||||||
$backup_dbs = $this->getBoolParam('backup_dbs', true, 0);
|
$pgp_public_key = $this->getParam('pgp_public_key', true, '');
|
||||||
$backup_mail = $this->getBoolParam('backup_mail', true, 0);
|
$dump_dbs = $this->getBoolParam('dump_dbs', true, 0);
|
||||||
$backup_web = $this->getBoolParam('backup_web', true, 0);
|
$dump_mail = $this->getBoolParam('dump_mail', true, 0);
|
||||||
|
$dump_web = $this->getBoolParam('dump_web', true, 0);
|
||||||
|
|
||||||
// get customer data
|
// get customer data
|
||||||
$customer = $this->getCustomerData();
|
$customer = $this->getCustomerData();
|
||||||
@@ -86,19 +89,32 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// path cannot be the customers docroot
|
// path cannot be the customers docroot
|
||||||
if ($path == FileDir::makeCorrectDir($customer['documentroot'])) {
|
if ($path == FileDir::makeCorrectDir($customer['documentroot'])) {
|
||||||
Response::standardError('backupfoldercannotbedocroot', '', true);
|
Response::standardError('dumpfoldercannotbedocroot', '', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($backup_dbs != '1') {
|
// pgp public key validation
|
||||||
$backup_dbs = '0';
|
if (!empty($pgp_public_key)) {
|
||||||
|
// check if gnupg extension is loaded
|
||||||
|
if (!extension_loaded('gnupg')) {
|
||||||
|
Response::standardError('gnupgextensionnotavailable', '', true);
|
||||||
|
}
|
||||||
|
// check if the pgp public key is a valid key
|
||||||
|
putenv('GNUPGHOME='.sys_get_temp_dir());
|
||||||
|
if (gnupg_import(gnupg_init(), $pgp_public_key) === false) {
|
||||||
|
Response::standardError('invalidpgppublickey', '', true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($backup_mail != '1') {
|
if ($dump_dbs != '1') {
|
||||||
$backup_mail = '0';
|
$dump_dbs = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($backup_web != '1') {
|
if ($dump_mail != '1') {
|
||||||
$backup_web = '0';
|
$dump_mail = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dump_web != '1') {
|
||||||
|
$dump_web = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
$task_data = [
|
$task_data = [
|
||||||
@@ -107,61 +123,63 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
'gid' => $customer['guid'],
|
'gid' => $customer['guid'],
|
||||||
'loginname' => $customer['loginname'],
|
'loginname' => $customer['loginname'],
|
||||||
'destdir' => $path,
|
'destdir' => $path,
|
||||||
'backup_dbs' => $backup_dbs,
|
'pgp_public_key' => $pgp_public_key,
|
||||||
'backup_mail' => $backup_mail,
|
'dump_dbs' => $dump_dbs,
|
||||||
'backup_web' => $backup_web
|
'dump_mail' => $dump_mail,
|
||||||
|
'dump_web' => $dump_web
|
||||||
];
|
];
|
||||||
// schedule backup job
|
|
||||||
Cronjob::inserttask(TaskId::CREATE_CUSTOMER_BACKUP, $task_data);
|
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added customer-backup job for '" . $customer['loginname'] . "'. Target directory: " . $userpath);
|
// schedule export job
|
||||||
|
Cronjob::inserttask(TaskId::CREATE_CUSTOMER_DATADUMP, $task_data);
|
||||||
|
|
||||||
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added customer data export job for '" . $customer['loginname'] . "'. Target directory: " . $userpath);
|
||||||
return $this->response($task_data);
|
return $this->response($task_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check whether backup is enabled systemwide and if accessible for customer (hide_options)
|
* check whether data dump is enabled systemwide and if accessible for customer (hide_options)
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private function validateAccess()
|
private function validateAccess()
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.backupenabled') != 1) {
|
if (Settings::Get('system.exportenabled') != 1) {
|
||||||
throw new Exception("You cannot access this resource", 405);
|
throw new Exception("You cannot access this resource", 405);
|
||||||
}
|
}
|
||||||
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras')) {
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras')) {
|
||||||
throw new Exception("You cannot access this resource", 405);
|
throw new Exception("You cannot access this resource", 405);
|
||||||
}
|
}
|
||||||
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras.backup')) {
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras.export')) {
|
||||||
throw new Exception("You cannot access this resource", 405);
|
throw new Exception("You cannot access this resource", 405);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You cannot get a planned backup.
|
* You cannot get a planned data export.
|
||||||
* Try CustomerBackups.listing()
|
* Try DataDump.listing()
|
||||||
*/
|
*/
|
||||||
public function get()
|
public function get()
|
||||||
{
|
{
|
||||||
throw new Exception('You cannot get a planned backup. Try CustomerBackups.listing()', 303);
|
throw new Exception('You cannot get a planned data export. Try DataDump.listing()', 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You cannot update a planned backup.
|
* You cannot update a planned data export.
|
||||||
* You need to delete it and re-add it.
|
* You need to delete it and re-add it.
|
||||||
*/
|
*/
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
throw new Exception('You cannot update a planned backup. You need to delete it and re-add it.', 303);
|
throw new Exception('You cannot update a planned data export. You need to delete it and re-add it.', 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* list all planned backup-jobs, if called from an admin, list all planned backup-jobs of all customers you are
|
* list all planned data export jobs, if called from an admin, list all planned data export jobs of all customers you are
|
||||||
* allowed to view, or specify id or loginname for one specific customer
|
* allowed to view, or specify id or loginname for one specific customer
|
||||||
*
|
*
|
||||||
* @param int $customerid
|
* @param int $customerid
|
||||||
* optional, admin-only, select backup-jobs of a specific customer by id
|
* optional, admin-only, select data export jobs of a specific customer by id
|
||||||
* @param string $loginname
|
* @param string $loginname
|
||||||
* optional, admin-only, select backup-jobs of a specific customer by loginname
|
* optional, admin-only, select data export jobs of a specific customer by loginname
|
||||||
* @param array $sql_search
|
* @param array $sql_search
|
||||||
* optional array with index = fieldname, and value = array with 'op' => operator (one of <, > or =),
|
* optional array with index = fieldname, and value = array with 'op' => operator (one of <, > or =),
|
||||||
* LIKE is used if left empty and 'value' => searchvalue
|
* LIKE is used if left empty and 'value' => searchvalue
|
||||||
@@ -181,9 +199,9 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
{
|
{
|
||||||
$this->validateAccess();
|
$this->validateAccess();
|
||||||
|
|
||||||
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
|
$customer_ids = $this->getAllowedCustomerIds('extras.export');
|
||||||
|
|
||||||
// check whether there is a backup-job for this customer
|
// check whether there is a data export job for this customer
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
|
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
|
||||||
Database::pexecute($sel_stmt, $query_fields, true, true);
|
Database::pexecute($sel_stmt, $query_fields, true, true);
|
||||||
@@ -194,7 +212,7 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
$result[] = $entry;
|
$result[] = $entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list customer-backups");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list customer data dump jobs");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -202,12 +220,12 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the total number of planned backups
|
* returns the total number of planned data exports
|
||||||
*
|
*
|
||||||
* @param int $customerid
|
* @param int $customerid
|
||||||
* optional, admin-only, select backup-jobs of a specific customer by id
|
* optional, admin-only, select data export jobs of a specific customer by id
|
||||||
* @param string $loginname
|
* @param string $loginname
|
||||||
* optional, admin-only, select backup-jobs of a specific customer by loginname
|
* optional, admin-only, select data export jobs of a specific customer by loginname
|
||||||
*
|
*
|
||||||
* @access admin, customer
|
* @access admin, customer
|
||||||
* @return string json-encoded response message
|
* @return string json-encoded response message
|
||||||
@@ -217,9 +235,9 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
{
|
{
|
||||||
$this->validateAccess();
|
$this->validateAccess();
|
||||||
|
|
||||||
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
|
$customer_ids = $this->getAllowedCustomerIds('extras.export');
|
||||||
|
|
||||||
// check whether there is a backup-job for this customer
|
// check whether there is a data export job for this customer
|
||||||
$result_count = 0;
|
$result_count = 0;
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'");
|
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'");
|
||||||
Database::pexecute($sel_stmt, null, true, true);
|
Database::pexecute($sel_stmt, null, true, true);
|
||||||
@@ -233,10 +251,10 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* delete a planned backup-jobs by id, if called from an admin you need to specify the customerid/loginname
|
* delete a planned data export jobs by id, if called from an admin you need to specify the customerid/loginname
|
||||||
*
|
*
|
||||||
* @param int $backup_job_entry
|
* @param int $job_entry
|
||||||
* id of backup job
|
* id of data export job
|
||||||
* @param int $customerid
|
* @param int $customerid
|
||||||
* optional, required when called as admin (if $loginname is not specified)
|
* optional, required when called as admin (if $loginname is not specified)
|
||||||
* @param string $loginname
|
* @param string $loginname
|
||||||
@@ -248,26 +266,26 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
|
|||||||
*/
|
*/
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
// get planned backups
|
// get planned exports
|
||||||
$result = $this->apiCall('CustomerBackups.listing', $this->getParamList());
|
$result = $this->apiCall('DataDump.listing', $this->getParamList());
|
||||||
|
|
||||||
$entry = $this->getParam('backup_job_entry');
|
$entry = $this->getParam('job_entry');
|
||||||
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
|
$customer_ids = $this->getAllowedCustomerIds('extras.export');
|
||||||
|
|
||||||
if ($result['count'] > 0 && $entry > 0) {
|
if ($result['count'] > 0 && $entry > 0) {
|
||||||
// prepare statement
|
// prepare statement
|
||||||
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :tid");
|
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :tid");
|
||||||
// check for the correct job
|
// check for the correct job
|
||||||
foreach ($result['list'] as $backupjob) {
|
foreach ($result['list'] as $exportjob) {
|
||||||
if ($backupjob['id'] == $entry && in_array($backupjob['data']['customerid'], $customer_ids)) {
|
if ($exportjob['id'] == $entry && in_array($exportjob['data']['customerid'], $customer_ids)) {
|
||||||
Database::pexecute($del_stmt, [
|
Database::pexecute($del_stmt, [
|
||||||
'tid' => $entry
|
'tid' => $entry
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted planned customer-backup #" . $entry);
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted planned customer data export job #" . $entry);
|
||||||
return $this->response(true);
|
return $this->response(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Exception('Backup job with id #' . $entry . ' could not be found', 404);
|
throw new Exception('Data export job with id #' . $entry . ' could not be found', 404);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
// validation
|
// validation
|
||||||
$path = FileDir::makeCorrectDir(Validate::validate($path, 'path', Validate::REGEX_DIR, '', [], true));
|
$path = FileDir::makeCorrectDir(Validate::validate($path, 'path', Validate::REGEX_DIR, '', [], true));
|
||||||
$userpath = $path;
|
$userpath = $path;
|
||||||
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
|
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);
|
||||||
|
|
||||||
if (!empty($error404path)) {
|
if (!empty($error404path)) {
|
||||||
$error404path = $this->correctErrorDocument($error404path, true);
|
$error404path = $this->correctErrorDocument($error404path, true);
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validation
|
// validation
|
||||||
$path = FileDir::makeCorrectDir(Validate::validate($path, 'path', Validate::REGEX_DIR, '', [], true));
|
$path = FileDir::makeCorrectDir(Validate::validate($path, 'path', Validate::REGEX_DIR, '', [], true));
|
||||||
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
|
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);
|
||||||
$username = Validate::validate($username, 'username', '/^[a-zA-Z0-9][a-zA-Z0-9\-_]+\$?$/', '', [], true);
|
$username = Validate::validate($username, 'username', '/^[a-zA-Z0-9][a-zA-Z0-9\-_]+\$?$/', '', [], true);
|
||||||
$authname = Validate::validate($authname, 'directory_authname', '/^[a-zA-Z0-9][a-zA-Z0-9\-_ ]+\$?$/', '', [], true);
|
$authname = Validate::validate($authname, 'directory_authname', '/^[a-zA-Z0-9][a-zA-Z0-9\-_ ]+\$?$/', '', [], true);
|
||||||
$password = Validate::validate($password, 'password', '', '', [], true);
|
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||||
|
|||||||
@@ -302,6 +302,8 @@ class DomainZones extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
} elseif ($type == 'SSHFP' && !empty($content)) {
|
} elseif ($type == 'SSHFP' && !empty($content)) {
|
||||||
$content = $content;
|
$content = $content;
|
||||||
|
} elseif ($type == 'TLSA' && !empty($content)) {
|
||||||
|
$content = $content;
|
||||||
} elseif ($type == 'TXT' && !empty($content)) {
|
} elseif ($type == 'TXT' && !empty($content)) {
|
||||||
// check that TXT content is enclosed in " "
|
// check that TXT content is enclosed in " "
|
||||||
$content = Dns::encloseTXTContent($content);
|
$content = Dns::encloseTXTContent($content);
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT
|
SELECT
|
||||||
`d`.*, `c`.`loginname`, `c`.`deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`, `c`.`adminid` as customeradmin,
|
`d`.*, `c`.`loginname`, `c`.`deactivated` as `customer_deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`, `c`.`adminid` as customeradmin,
|
||||||
`ad`.`id` AS `aliasdomainid`, `ad`.`domain` AS `aliasdomain`
|
`ad`.`id` AS `aliasdomainid`, `ad`.`domain` AS `aliasdomain`
|
||||||
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
||||||
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
|
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
|
||||||
@@ -110,7 +110,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
*
|
*
|
||||||
* @param number $domain_id
|
* @param number $domain_id
|
||||||
* @param bool $ssl_only
|
* @param bool $ssl_only
|
||||||
* optional, return only ssl enabled ip's, default false
|
* optional, return only ssl enabled ips, default false
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function getIpsForDomain($domain_id = 0, $ssl_only = false)
|
private function getIpsForDomain($domain_id = 0, $ssl_only = false)
|
||||||
@@ -190,9 +190,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* 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
|
||||||
* optional, domain-id of a domain that the new domain should be an alias of, default 0 (none)
|
* optional, domain-id of a domain that the new domain should be an alias of, default 0 (none)
|
||||||
* @param int $issubof
|
|
||||||
* optional, domain-id of a domain this domain is a subdomain of (required for webserver-cronjob to
|
|
||||||
* generate the correct order), default 0 (none)
|
|
||||||
* @param string $registration_date
|
* @param string $registration_date
|
||||||
* optional, date of domain registration in form of YYYY-MM-DD, default empty (none)
|
* optional, date of domain registration in form of YYYY-MM-DD, default empty (none)
|
||||||
* @param string $termination_date
|
* @param string $termination_date
|
||||||
@@ -210,7 +207,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* @param string $ssl_specialsettings
|
* @param string $ssl_specialsettings
|
||||||
* optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty
|
* optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty
|
||||||
* @param bool $include_specialsettings
|
* @param bool $include_specialsettings
|
||||||
* optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false
|
* optional, whether to include non-ssl specialsettings in the generated ssl-vhost, default false
|
||||||
* @param bool $notryfiles
|
* @param bool $notryfiles
|
||||||
* optional, [nginx only] do not generate the default try-files directive, default 0 (false)
|
* optional, [nginx only] do not generate the default try-files directive, default 0 (false)
|
||||||
* @param bool $writeaccesslog
|
* @param bool $writeaccesslog
|
||||||
@@ -219,7 +216,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, Enable writing an error-log file for this domain, default 1 (true)
|
* optional, Enable writing an error-log file for this domain, default 1 (true)
|
||||||
* @param string $documentroot
|
* @param string $documentroot
|
||||||
* optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be
|
* optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be
|
||||||
* aware, if path starts with / it it considered a full path, not relative to customer-docroot. Also
|
* aware, if path starts with / it is considered a full path, not relative to customer-docroot. Also
|
||||||
* specifying a URL is possible here (redirect), default empty (autogenerated)
|
* specifying a URL is possible here (redirect), default empty (autogenerated)
|
||||||
* @param bool $phpenabled
|
* @param bool $phpenabled
|
||||||
* optional, whether php is enabled for this domain, default 0 (false)
|
* optional, whether php is enabled for this domain, default 0 (false)
|
||||||
@@ -244,7 +241,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, do NOT set the systems default ssl ip addresses if none are given via $ssl_ipandport
|
* optional, do NOT set the systems default ssl ip addresses if none are given via $ssl_ipandport
|
||||||
* parameter
|
* parameter
|
||||||
* @param bool $sslenabled
|
* @param bool $sslenabled
|
||||||
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
* optional, whether SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
||||||
* 1 (true)
|
* 1 (true)
|
||||||
* @param bool $http2
|
* @param bool $http2
|
||||||
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
|
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
|
||||||
@@ -252,9 +249,9 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* @param int $hsts_maxage
|
* @param int $hsts_maxage
|
||||||
* optional max-age value for HSTS header
|
* optional max-age value for HSTS header
|
||||||
* @param bool $hsts_sub
|
* @param bool $hsts_sub
|
||||||
* optional whether or not to add subdomains to the HSTS header
|
* optional whether to add subdomains to the HSTS header
|
||||||
* @param bool $hsts_preload
|
* @param bool $hsts_preload
|
||||||
* optional whether or not to preload HSTS header value
|
* optional whether to preload HSTS header value
|
||||||
* @param bool $ocsp_stapling
|
* @param bool $ocsp_stapling
|
||||||
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
|
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
|
||||||
* @param bool $honorcipherorder
|
* @param bool $honorcipherorder
|
||||||
@@ -263,7 +260,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional whether to enable or disable TLS sessiontickets (RFC 5077) for this domain. default 1
|
* optional whether to enable or disable TLS sessiontickets (RFC 5077) for this domain. default 1
|
||||||
* (true), requires SSL
|
* (true), requires SSL
|
||||||
* @param bool $override_tls
|
* @param bool $override_tls
|
||||||
* optional whether or not to override system-tls settings like protocol, ssl-ciphers and if applicable
|
* optional whether to override system-tls settings like protocol, ssl-ciphers and if applicable
|
||||||
* tls-1.3 ciphers, requires change_serversettings flag for the admin, default false
|
* tls-1.3 ciphers, requires change_serversettings flag for the admin, default false
|
||||||
* @param array $ssl_protocols
|
* @param array $ssl_protocols
|
||||||
* optional list of allowed/used ssl/tls protocols, see system.ssl_protocols setting, only used/required
|
* optional list of allowed/used ssl/tls protocols, see system.ssl_protocols setting, only used/required
|
||||||
@@ -298,7 +295,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$serveraliasoption = $this->getParam('selectserveralias', true, Settings::Get('system.domaindefaultalias'));
|
$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);
|
|
||||||
$registration_date = $this->getParam('registration_date', true, '');
|
$registration_date = $this->getParam('registration_date', true, '');
|
||||||
$termination_date = $this->getParam('termination_date', true, '');
|
$termination_date = $this->getParam('termination_date', true, '');
|
||||||
$caneditdomain = $this->getBoolParam('caneditdomain', true, 0);
|
$caneditdomain = $this->getBoolParam('caneditdomain', true, 0);
|
||||||
@@ -320,9 +316,9 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
|
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
|
||||||
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, 0);
|
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, 0);
|
||||||
$letsencrypt = $this->getBoolParam('letsencrypt', true, 0);
|
$letsencrypt = $this->getBoolParam('letsencrypt', true, 0);
|
||||||
|
$sslenabled = $this->getBoolParam('sslenabled', true, 1);
|
||||||
$dont_use_default_ssl_ipandport_if_empty = $this->getBoolParam('dont_use_default_ssl_ipandport_if_empty', true, 0);
|
$dont_use_default_ssl_ipandport_if_empty = $this->getBoolParam('dont_use_default_ssl_ipandport_if_empty', true, 0);
|
||||||
$p_ssl_ipandports = $this->getParam('ssl_ipandport', true, $dont_use_default_ssl_ipandport_if_empty ? [] : explode(',', Settings::Get('system.defaultsslip')));
|
$p_ssl_ipandports = $this->getParam('ssl_ipandport', true, $dont_use_default_ssl_ipandport_if_empty ? [] : explode(',', Settings::Get('system.defaultsslip')));
|
||||||
$sslenabled = $this->getBoolParam('sslenabled', true, 1);
|
|
||||||
$http2 = $this->getBoolParam('http2', true, 0);
|
$http2 = $this->getBoolParam('http2', true, 0);
|
||||||
$hsts_maxage = $this->getParam('hsts_maxage', true, 0);
|
$hsts_maxage = $this->getParam('hsts_maxage', true, 0);
|
||||||
$hsts_sub = $this->getBoolParam('hsts_sub', true, 0);
|
$hsts_sub = $this->getBoolParam('hsts_sub', true, 0);
|
||||||
@@ -353,6 +349,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
if (substr($p_domain, 0, 4) == 'xn--') {
|
if (substr($p_domain, 0, 4) == 'xn--') {
|
||||||
Response::standardError('domain_nopunycode', '', true);
|
Response::standardError('domain_nopunycode', '', true);
|
||||||
|
} elseif (Validate::validate_ip2($p_domain, true, '', true, true)) {
|
||||||
|
Response::standardError('domain_noipaddress', '', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
@@ -548,6 +546,10 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$ssl_specialsettings = Validate::validate(str_replace("\r\n", "\n", $ssl_specialsettings), 'ssl_specialsettings', '/^[^\0]*$/', '', [], true);
|
$ssl_specialsettings = Validate::validate(str_replace("\r\n", "\n", $ssl_specialsettings), 'ssl_specialsettings', '/^[^\0]*$/', '', [], true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Settings::Get('system.use_ssl') == "1" && $sslenabled == 1 && empty($ssl_ipandports)) {
|
||||||
|
// enabled ssl for the domain but no ssl ip/port is selected
|
||||||
|
Response::standardError('nosslippportgiven', '', true);
|
||||||
|
}
|
||||||
if (Settings::Get('system.use_ssl') == "0" || empty($ssl_ipandports)) {
|
if (Settings::Get('system.use_ssl') == "0" || empty($ssl_ipandports)) {
|
||||||
$ssl_redirect = 0;
|
$ssl_redirect = 0;
|
||||||
$letsencrypt = 0;
|
$letsencrypt = 0;
|
||||||
@@ -665,10 +667,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$serveraliasoption = '0';
|
$serveraliasoption = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($issubof <= 0) {
|
|
||||||
$issubof = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
if ($domain == '') {
|
if ($domain == '') {
|
||||||
Response::standardError([
|
Response::standardError([
|
||||||
@@ -723,7 +721,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
'phpsettingid' => $phpsettingid,
|
'phpsettingid' => $phpsettingid,
|
||||||
'mod_fcgid_starter' => $mod_fcgid_starter,
|
'mod_fcgid_starter' => $mod_fcgid_starter,
|
||||||
'mod_fcgid_maxrequests' => $mod_fcgid_maxrequests,
|
'mod_fcgid_maxrequests' => $mod_fcgid_maxrequests,
|
||||||
'ismainbutsubto' => $issubof,
|
|
||||||
'letsencrypt' => $letsencrypt,
|
'letsencrypt' => $letsencrypt,
|
||||||
'http2' => $http2,
|
'http2' => $http2,
|
||||||
'hsts' => $hsts_maxage,
|
'hsts' => $hsts_maxage,
|
||||||
@@ -777,7 +774,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`phpsettingid` = :phpsettingid,
|
`phpsettingid` = :phpsettingid,
|
||||||
`mod_fcgid_starter` = :mod_fcgid_starter,
|
`mod_fcgid_starter` = :mod_fcgid_starter,
|
||||||
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
||||||
`ismainbutsubto` = :ismainbutsubto,
|
|
||||||
`letsencrypt` = :letsencrypt,
|
`letsencrypt` = :letsencrypt,
|
||||||
`http2` = :http2,
|
`http2` = :http2,
|
||||||
`hsts` = :hsts,
|
`hsts` = :hsts,
|
||||||
@@ -1069,9 +1065,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* default 0 (false)
|
* default 0 (false)
|
||||||
* @param int $alias
|
* @param int $alias
|
||||||
* optional, domain-id of a domain that the new domain should be an alias of, default 0 (none)
|
* optional, domain-id of a domain that the new domain should be an alias of, default 0 (none)
|
||||||
* @param int $issubof
|
|
||||||
* optional, domain-id of a domain this domain is a subdomain of (required for webserver-cronjob to
|
|
||||||
* generate the correct order), default 0 (none)
|
|
||||||
* @param string $registration_date
|
* @param string $registration_date
|
||||||
* optional, date of domain registration in form of YYYY-MM-DD, default empty (none)
|
* optional, date of domain registration in form of YYYY-MM-DD, default empty (none)
|
||||||
* @param string $termination_date
|
* @param string $termination_date
|
||||||
@@ -1089,7 +1082,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* @param string $ssl_specialsettings
|
* @param string $ssl_specialsettings
|
||||||
* optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty
|
* optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty
|
||||||
* @param bool $include_specialsettings
|
* @param bool $include_specialsettings
|
||||||
* optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false
|
* optional, whether to include non-ssl specialsettings in the generated ssl-vhost, default false
|
||||||
* @param bool $specialsettingsforsubdomains
|
* @param bool $specialsettingsforsubdomains
|
||||||
* optional, whether to apply specialsettings to all subdomains of this domain, default is read from
|
* optional, whether to apply specialsettings to all subdomains of this domain, default is read from
|
||||||
* setting system.apply_specialsettings_default
|
* setting system.apply_specialsettings_default
|
||||||
@@ -1101,7 +1094,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, Enable writing an error-log file for this domain, default 1 (true)
|
* optional, Enable writing an error-log file for this domain, default 1 (true)
|
||||||
* @param string $documentroot
|
* @param string $documentroot
|
||||||
* optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be
|
* optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be
|
||||||
* aware, if path starts with / it it considered a full path, not relative to customer-docroot. Also
|
* aware, if path starts with / it is considered a full path, not relative to customer-docroot. Also
|
||||||
* specifying a URL is possible here (redirect), default empty (autogenerated)
|
* specifying a URL is possible here (redirect), default empty (autogenerated)
|
||||||
* @param bool $phpenabled
|
* @param bool $phpenabled
|
||||||
* optional, whether php is enabled for this domain, default 0 (false)
|
* optional, whether php is enabled for this domain, default 0 (false)
|
||||||
@@ -1130,7 +1123,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, if set to true and no $ssl_ipandport value is given, the ip's get removed, otherwise, the
|
* optional, if set to true and no $ssl_ipandport value is given, the ip's get removed, otherwise, the
|
||||||
* currently set value is used, default false
|
* currently set value is used, default false
|
||||||
* @param bool $sslenabled
|
* @param bool $sslenabled
|
||||||
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
* optional, whether SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
||||||
* 1 (true)
|
* 1 (true)
|
||||||
* @param bool $http2
|
* @param bool $http2
|
||||||
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
|
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
|
||||||
@@ -1138,9 +1131,9 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* @param int $hsts_maxage
|
* @param int $hsts_maxage
|
||||||
* optional max-age value for HSTS header
|
* optional max-age value for HSTS header
|
||||||
* @param bool $hsts_sub
|
* @param bool $hsts_sub
|
||||||
* optional whether or not to add subdomains to the HSTS header
|
* optional whether to add subdomains to the HSTS header
|
||||||
* @param bool $hsts_preload
|
* @param bool $hsts_preload
|
||||||
* optional whether or not to preload HSTS header value
|
* optional whether to preload HSTS header value
|
||||||
* @param bool $ocsp_stapling
|
* @param bool $ocsp_stapling
|
||||||
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
|
* optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL
|
||||||
* @param bool $honorcipherorder
|
* @param bool $honorcipherorder
|
||||||
@@ -1150,6 +1143,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* (true), requires SSL
|
* (true), requires SSL
|
||||||
* @param string $description
|
* @param string $description
|
||||||
* optional custom description (currently not used/shown in the frontend), default empty
|
* optional custom description (currently not used/shown in the frontend), default empty
|
||||||
|
* @param bool $deactivated
|
||||||
|
* optional, if 1 (true) the domain can be deactivated/suspended
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
@@ -1191,7 +1186,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$speciallogfile = $this->getBoolParam('speciallogfile', true, $result['speciallogfile']);
|
$speciallogfile = $this->getBoolParam('speciallogfile', true, $result['speciallogfile']);
|
||||||
$speciallogverified = $this->getBoolParam('speciallogverified', true, 0);
|
$speciallogverified = $this->getBoolParam('speciallogverified', true, 0);
|
||||||
$aliasdomain = intval($this->getParam('alias', true, $result['aliasdomain']));
|
$aliasdomain = intval($this->getParam('alias', true, $result['aliasdomain']));
|
||||||
$issubof = $this->getParam('issubof', true, $result['ismainbutsubto']);
|
|
||||||
$registration_date = $this->getParam('registration_date', true, $result['registration_date']);
|
$registration_date = $this->getParam('registration_date', true, $result['registration_date']);
|
||||||
$termination_date = $this->getParam('termination_date', true, $result['termination_date']);
|
$termination_date = $this->getParam('termination_date', true, $result['termination_date']);
|
||||||
$caneditdomain = $this->getBoolParam('caneditdomain', true, $result['caneditdomain']);
|
$caneditdomain = $this->getBoolParam('caneditdomain', true, $result['caneditdomain']);
|
||||||
@@ -1219,7 +1213,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$p_ssl_ipandports = $this->getParam('ssl_ipandport', true, $remove_ssl_ipandport ? [
|
$p_ssl_ipandports = $this->getParam('ssl_ipandport', true, $remove_ssl_ipandport ? [
|
||||||
-1
|
-1
|
||||||
] : null);
|
] : null);
|
||||||
$sslenabled = $this->getBoolParam('sslenabled', true, $result['ssl_enabled']);
|
$sslenabled = $remove_ssl_ipandport ? false : $this->getBoolParam('sslenabled', true, $result['ssl_enabled']);
|
||||||
$http2 = $this->getBoolParam('http2', true, $result['http2']);
|
$http2 = $this->getBoolParam('http2', true, $result['http2']);
|
||||||
$hsts_maxage = $this->getParam('hsts_maxage', true, $result['hsts']);
|
$hsts_maxage = $this->getParam('hsts_maxage', true, $result['hsts']);
|
||||||
$hsts_sub = $this->getBoolParam('hsts_sub', true, $result['hsts_sub']);
|
$hsts_sub = $this->getBoolParam('hsts_sub', true, $result['hsts_sub']);
|
||||||
@@ -1246,6 +1240,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$tlsv13_cipher_list = $result['tlsv13_cipher_list'];
|
$tlsv13_cipher_list = $result['tlsv13_cipher_list'];
|
||||||
}
|
}
|
||||||
$description = $this->getParam('description', true, $result['description']);
|
$description = $this->getParam('description', true, $result['description']);
|
||||||
|
$deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']);
|
||||||
|
|
||||||
// count subdomain usage of source-domain
|
// count subdomain usage of source-domain
|
||||||
$subdomains_stmt = Database::prepare("
|
$subdomains_stmt = Database::prepare("
|
||||||
@@ -1528,6 +1523,10 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
if ($remove_ssl_ipandport || (!empty($p_ssl_ipandports) && $p_ssl_ipandports[0] == -1)) {
|
if ($remove_ssl_ipandport || (!empty($p_ssl_ipandports) && $p_ssl_ipandports[0] == -1)) {
|
||||||
$ssl_ipandports = [];
|
$ssl_ipandports = [];
|
||||||
}
|
}
|
||||||
|
if (Settings::Get('system.use_ssl') == "1" && $sslenabled && empty($ssl_ipandports)) {
|
||||||
|
// enabled ssl for the domain but no ssl ip/port is selected
|
||||||
|
Response::standardError('nosslippportgiven', '', true);
|
||||||
|
}
|
||||||
if (Settings::Get('system.use_ssl') == "0" || empty($ssl_ipandports)) {
|
if (Settings::Get('system.use_ssl') == "0" || empty($ssl_ipandports)) {
|
||||||
$ssl_redirect = 0;
|
$ssl_redirect = 0;
|
||||||
$letsencrypt = 0;
|
$letsencrypt = 0;
|
||||||
@@ -1564,7 +1563,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Temporarily deactivate ssl_redirect until Let's Encrypt certificate was generated
|
// Temporarily deactivate ssl_redirect until Let's Encrypt certificate was generated
|
||||||
if ($ssl_redirect > 0 && $letsencrypt == 1 && $result['letsencrypt'] != $letsencrypt) {
|
if (($result['letsencrypt'] != $letsencrypt || $result['ssl_redirect'] != $ssl_redirect) && $ssl_redirect > 0 && $letsencrypt == 1) {
|
||||||
$ssl_redirect = 2;
|
$ssl_redirect = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1640,10 +1639,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
Response::standardError('domainisaliasorothercustomer', '', true);
|
Response::standardError('domainisaliasorothercustomer', '', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($issubof <= 0) {
|
|
||||||
$issubof = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($serveraliasoption != '1' && $serveraliasoption != '2') {
|
if ($serveraliasoption != '1' && $serveraliasoption != '2') {
|
||||||
$serveraliasoption = '0';
|
$serveraliasoption = '0';
|
||||||
}
|
}
|
||||||
@@ -1657,6 +1652,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
|| $iswildcarddomain != $result['iswildcarddomain']
|
|| $iswildcarddomain != $result['iswildcarddomain']
|
||||||
|| $phpenabled != $result['phpenabled']
|
|| $phpenabled != $result['phpenabled']
|
||||||
|| $openbasedir != $result['openbasedir']
|
|| $openbasedir != $result['openbasedir']
|
||||||
|
|| $openbasedir_path != $result['openbasedir_path']
|
||||||
|| $phpsettingid != $result['phpsettingid']
|
|| $phpsettingid != $result['phpsettingid']
|
||||||
|| $mod_fcgid_starter != $result['mod_fcgid_starter']
|
|| $mod_fcgid_starter != $result['mod_fcgid_starter']
|
||||||
|| $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests']
|
|| $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests']
|
||||||
@@ -1666,7 +1662,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
|| $writeaccesslog != $result['writeaccesslog']
|
|| $writeaccesslog != $result['writeaccesslog']
|
||||||
|| $writeerrorlog != $result['writeerrorlog']
|
|| $writeerrorlog != $result['writeerrorlog']
|
||||||
|| $aliasdomain != $result['aliasdomain']
|
|| $aliasdomain != $result['aliasdomain']
|
||||||
|| $issubof != $result['ismainbutsubto']
|
|
||||||
|| $email_only != $result['email_only']
|
|| $email_only != $result['email_only']
|
||||||
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|
||||||
|| $letsencrypt != $result['letsencrypt']
|
|| $letsencrypt != $result['letsencrypt']
|
||||||
@@ -1675,6 +1670,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
|| $hsts_sub != $result['hsts_sub']
|
|| $hsts_sub != $result['hsts_sub']
|
||||||
|| $hsts_preload != $result['hsts_preload']
|
|| $hsts_preload != $result['hsts_preload']
|
||||||
|| $ocsp_stapling != $result['ocsp_stapling']
|
|| $ocsp_stapling != $result['ocsp_stapling']
|
||||||
|
|| $sslenabled != $result['ssl_enabled']
|
||||||
) {
|
) {
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
@@ -1823,7 +1819,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$update_data['wwwserveralias'] = $wwwserveralias;
|
$update_data['wwwserveralias'] = $wwwserveralias;
|
||||||
$update_data['iswildcarddomain'] = $iswildcarddomain;
|
$update_data['iswildcarddomain'] = $iswildcarddomain;
|
||||||
$update_data['phpenabled'] = $phpenabled;
|
$update_data['phpenabled'] = $phpenabled;
|
||||||
$update_data['openbasedir'] = $openbasedir;;
|
$update_data['openbasedir'] = $openbasedir;
|
||||||
$update_data['openbasedir_path'] = $openbasedir_path;
|
$update_data['openbasedir_path'] = $openbasedir_path;
|
||||||
$update_data['speciallogfile'] = $speciallogfile;
|
$update_data['speciallogfile'] = $speciallogfile;
|
||||||
$update_data['phpsettingid'] = $phpsettingid;
|
$update_data['phpsettingid'] = $phpsettingid;
|
||||||
@@ -1837,7 +1833,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$update_data['writeerrorlog'] = $writeerrorlog;
|
$update_data['writeerrorlog'] = $writeerrorlog;
|
||||||
$update_data['registration_date'] = $registration_date;
|
$update_data['registration_date'] = $registration_date;
|
||||||
$update_data['termination_date'] = $termination_date;
|
$update_data['termination_date'] = $termination_date;
|
||||||
$update_data['ismainbutsubto'] = $issubof;
|
|
||||||
$update_data['letsencrypt'] = $letsencrypt;
|
$update_data['letsencrypt'] = $letsencrypt;
|
||||||
$update_data['http2'] = $http2;
|
$update_data['http2'] = $http2;
|
||||||
$update_data['hsts'] = $hsts_maxage;
|
$update_data['hsts'] = $hsts_maxage;
|
||||||
@@ -1852,6 +1847,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$update_data['honorcipherorder'] = $honorcipherorder;
|
$update_data['honorcipherorder'] = $honorcipherorder;
|
||||||
$update_data['sessiontickets'] = $sessiontickets;
|
$update_data['sessiontickets'] = $sessiontickets;
|
||||||
$update_data['description'] = $description;
|
$update_data['description'] = $description;
|
||||||
|
$update_data['deactivated'] = $deactivated;
|
||||||
$update_data['id'] = $id;
|
$update_data['id'] = $id;
|
||||||
|
|
||||||
$update_stmt = Database::prepare("
|
$update_stmt = Database::prepare("
|
||||||
@@ -1885,7 +1881,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`writeerrorlog` = :writeerrorlog,
|
`writeerrorlog` = :writeerrorlog,
|
||||||
`registration_date` = :registration_date,
|
`registration_date` = :registration_date,
|
||||||
`termination_date` = :termination_date,
|
`termination_date` = :termination_date,
|
||||||
`ismainbutsubto` = :ismainbutsubto,
|
|
||||||
`letsencrypt` = :letsencrypt,
|
`letsencrypt` = :letsencrypt,
|
||||||
`http2` = :http2,
|
`http2` = :http2,
|
||||||
`hsts` = :hsts,
|
`hsts` = :hsts,
|
||||||
@@ -1899,11 +1894,36 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`ssl_enabled` = :sslenabled,
|
`ssl_enabled` = :sslenabled,
|
||||||
`ssl_honorcipherorder` = :honorcipherorder,
|
`ssl_honorcipherorder` = :honorcipherorder,
|
||||||
`ssl_sessiontickets` = :sessiontickets,
|
`ssl_sessiontickets` = :sessiontickets,
|
||||||
`description` = :description
|
`description` = :description,
|
||||||
|
`deactivated` = :deactivated
|
||||||
WHERE `id` = :id
|
WHERE `id` = :id
|
||||||
");
|
");
|
||||||
Database::pexecute($update_stmt, $update_data, true, true);
|
Database::pexecute($update_stmt, $update_data, true, true);
|
||||||
|
|
||||||
|
// activate/deactivate domain-based services
|
||||||
|
if ($deactivated != $result['deactivated']) {
|
||||||
|
// deactivate email accounts
|
||||||
|
$yesno = ($deactivated ? 'N' : 'Y');
|
||||||
|
$pop3 = ($deactivated ? '0' : (int)$customer['pop3']);
|
||||||
|
$imap = ($deactivated ? '0' : (int)$customer['imap']);
|
||||||
|
|
||||||
|
$upd_stmt = Database::prepare("
|
||||||
|
UPDATE `" . TABLE_MAIL_USERS . "`
|
||||||
|
SET `postfix`= :yesno, `pop3` = :pop3, `imap` = :imap
|
||||||
|
WHERE `customerid` = :customerid AND `domainid` = :domainid
|
||||||
|
");
|
||||||
|
Database::pexecute($upd_stmt, [
|
||||||
|
'yesno' => $yesno,
|
||||||
|
'pop3' => $pop3,
|
||||||
|
'imap' => $imap,
|
||||||
|
'customerid' => $customerid,
|
||||||
|
'domainid' => $id
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " domain '" . $result['domain'] . "'");
|
||||||
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
}
|
||||||
|
|
||||||
$_update_data['customerid'] = $customerid;
|
$_update_data['customerid'] = $customerid;
|
||||||
$_update_data['adminid'] = $adminid;
|
$_update_data['adminid'] = $adminid;
|
||||||
$_update_data['phpenabled'] = $phpenabled;
|
$_update_data['phpenabled'] = $phpenabled;
|
||||||
@@ -1921,6 +1941,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$_update_data['honorcipherorder'] = $honorcipherorder;
|
$_update_data['honorcipherorder'] = $honorcipherorder;
|
||||||
$_update_data['sessiontickets'] = $sessiontickets;
|
$_update_data['sessiontickets'] = $sessiontickets;
|
||||||
$_update_data['parentdomainid'] = $id;
|
$_update_data['parentdomainid'] = $id;
|
||||||
|
$_update_data['deactivated'] = $deactivated;
|
||||||
|
|
||||||
// if php config is to be set for all subdomains, check here
|
// if php config is to be set for all subdomains, check here
|
||||||
$update_phpconfig = '';
|
$update_phpconfig = '';
|
||||||
@@ -1953,7 +1974,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`ssl_cipher_list` = :ssl_cipher_list,
|
`ssl_cipher_list` = :ssl_cipher_list,
|
||||||
`tlsv13_cipher_list` = :tlsv13_cipher_list,
|
`tlsv13_cipher_list` = :tlsv13_cipher_list,
|
||||||
`ssl_honorcipherorder` = :honorcipherorder,
|
`ssl_honorcipherorder` = :honorcipherorder,
|
||||||
`ssl_sessiontickets` = :sessiontickets
|
`ssl_sessiontickets` = :sessiontickets,
|
||||||
|
`deactivated` = :deactivated
|
||||||
" . $update_phpconfig . $upd_specialsettings . $updatechildren . $update_sslredirect . "
|
" . $update_phpconfig . $upd_specialsettings . $updatechildren . $update_sslredirect . "
|
||||||
WHERE `parentdomainid` = :parentdomainid
|
WHERE `parentdomainid` = :parentdomainid
|
||||||
");
|
");
|
||||||
@@ -2073,9 +2095,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, the domain-id
|
* optional, the domain-id
|
||||||
* @param string $domainname
|
* @param string $domainname
|
||||||
* optional, the domainname
|
* optional, the domainname
|
||||||
* @param bool $delete_mainsubdomains
|
|
||||||
* optional, remove also domains that are subdomains of this domain but added as main domains; default
|
|
||||||
* false
|
|
||||||
* @param bool $is_stdsubdomain
|
* @param bool $is_stdsubdomain
|
||||||
* optional, default false, specify whether it's a std-subdomain you are deleting as it does not count
|
* optional, default false, specify whether it's a std-subdomain you are deleting as it does not count
|
||||||
* as subdomain-resource
|
* as subdomain-resource
|
||||||
@@ -2091,7 +2110,6 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$dn_optional = $id > 0;
|
$dn_optional = $id > 0;
|
||||||
$domainname = $this->getParam('domainname', $dn_optional, '');
|
$domainname = $this->getParam('domainname', $dn_optional, '');
|
||||||
$is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0);
|
$is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0);
|
||||||
$remove_subbutmain_domains = $this->getParam('delete_mainsubdomains', true, 0);
|
|
||||||
|
|
||||||
$result = $this->apiCall('Domains.get', [
|
$result = $this->apiCall('Domains.get', [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
@@ -2099,15 +2117,10 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
]);
|
]);
|
||||||
$id = $result['id'];
|
$id = $result['id'];
|
||||||
|
|
||||||
// check for deletion of main-domains which are logically subdomains, #329
|
|
||||||
$rsd_sql = '';
|
|
||||||
if ($remove_subbutmain_domains) {
|
|
||||||
$rsd_sql .= " OR `ismainbutsubto` = :id";
|
|
||||||
}
|
|
||||||
|
|
||||||
$subresult_stmt = Database::prepare("
|
$subresult_stmt = Database::prepare("
|
||||||
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "`
|
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE (`id` = :id OR `parentdomainid` = :id " . $rsd_sql . ")");
|
WHERE (`id` = :id OR `parentdomainid` = :id)
|
||||||
|
");
|
||||||
Database::pexecute($subresult_stmt, [
|
Database::pexecute($subresult_stmt, [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
@@ -2129,23 +2142,10 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] deleted domain/s from mail-tables");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] deleted domain/s from mail-tables");
|
||||||
}
|
}
|
||||||
|
|
||||||
// if mainbutsubto-domains are not to be deleted, re-assign the (ismainbutsubto value of the main
|
|
||||||
// domain which is being deleted) as their new ismainbutsubto value
|
|
||||||
if ($remove_subbutmain_domains !== 1) {
|
|
||||||
$upd_stmt = Database::prepare("
|
|
||||||
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
|
|
||||||
`ismainbutsubto` = :newIsMainButSubtoValue
|
|
||||||
WHERE `ismainbutsubto` = :deletedMainDomainId
|
|
||||||
");
|
|
||||||
Database::pexecute($upd_stmt, [
|
|
||||||
'newIsMainButSubtoValue' => $result['ismainbutsubto'],
|
|
||||||
'deletedMainDomainId' => $id
|
|
||||||
], true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$del_stmt = Database::prepare("
|
$del_stmt = Database::prepare("
|
||||||
DELETE FROM `" . TABLE_PANEL_DOMAINS . "`
|
DELETE FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE `id` = :id OR `parentdomainid` = :id " . $rsd_sql);
|
WHERE `id` = :id OR `parentdomainid` = :id
|
||||||
|
");
|
||||||
Database::pexecute($del_stmt, [
|
Database::pexecute($del_stmt, [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
@@ -2230,4 +2230,118 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* duplicate domain entry by either id or domainname. All parameters from Domains.add() can be used
|
||||||
|
* to overwrite source entity values if necessary.
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* optional, the domain-id
|
||||||
|
* @param string $domainname
|
||||||
|
* optional, the domainname
|
||||||
|
* @param string $domain
|
||||||
|
* required, name of the new domain to be added
|
||||||
|
*
|
||||||
|
* @access admin
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function duplicate()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin()) {
|
||||||
|
// parameters
|
||||||
|
$id = $this->getParam('id', true, 0);
|
||||||
|
$dn_optional = $id > 0;
|
||||||
|
$domainname = $this->getParam('domainname', $dn_optional, '');
|
||||||
|
$p_domain = $this->getParam('domain');
|
||||||
|
|
||||||
|
// get requested domain
|
||||||
|
$result = $this->apiCall('Domains.get', [
|
||||||
|
'id' => $id,
|
||||||
|
'domainname' => $domainname,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// clear some defaults
|
||||||
|
unset($result['domain_ace']);
|
||||||
|
unset($result['adminid']);
|
||||||
|
unset($result['documentroot']);
|
||||||
|
unset($result['registration_date']);
|
||||||
|
unset($result['termination_date']);
|
||||||
|
unset($result['zonefile']);
|
||||||
|
// clear auto-generated values
|
||||||
|
unset($result['bindserial']);
|
||||||
|
unset($result['dkim_privkey']);
|
||||||
|
unset($result['dkim_pubkey']);
|
||||||
|
// clear api-call generated fields
|
||||||
|
unset($result['domain_hascert']);
|
||||||
|
|
||||||
|
// set correct ip/port information
|
||||||
|
$domain_ips = $result['ipsandports'];
|
||||||
|
unset($result['ipsandports']);
|
||||||
|
$result['ipandport'] = [];
|
||||||
|
$result['ssl_ipandport'] = [];
|
||||||
|
foreach ($domain_ips as $dip) {
|
||||||
|
if ($dip['ssl'] == 1) {
|
||||||
|
$result['ssl_ipandport'][] = $dip['id'];
|
||||||
|
} else {
|
||||||
|
$result['ipandport'][] = $dip['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether we are changing the customer/owner
|
||||||
|
if ($this->getParam('customerid', true, 0) == 0 && $this->getParam('loginname', true, '') == '') {
|
||||||
|
$customerid = $result['customerid'];
|
||||||
|
} else {
|
||||||
|
$customer = $this->getCustomerData();
|
||||||
|
$customerid = $customer['customerid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for alias-domain and whether it belongs to the target user
|
||||||
|
if (!empty($result['aliasdomain']) && $customerid == $result['customerid']) {
|
||||||
|
// duplicate alias entry
|
||||||
|
$result['alias'] = $result['aliasdomain'];
|
||||||
|
}
|
||||||
|
unset($result['aliasdomain']);
|
||||||
|
|
||||||
|
// validate possible fpm configs and whether the customer is allowed to use them
|
||||||
|
if ($customerid != $result['customerid']) {
|
||||||
|
$allowed_phpconfigs = json_decode($customer['allowed_phpconfigs'] ?? '[]', true);
|
||||||
|
if (empty($allowed_phpconfigs)) {
|
||||||
|
// system defaults
|
||||||
|
unset($result['phpsettingid']);
|
||||||
|
} elseif (!in_array($result['phpsettingid'], $allowed_phpconfigs)) {
|
||||||
|
// use the first customer allowed config
|
||||||
|
$result['phpsettingid'] = array_shift($allowed_phpconfigs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate serveralias values
|
||||||
|
$result['selectserveralias'] = 2;
|
||||||
|
if ((int)$result['wwwserveralias'] == 1) {
|
||||||
|
$result['selectserveralias'] = 1;
|
||||||
|
} elseif ((int)$result['iswildcarddomain'] == 1) {
|
||||||
|
$result['selectserveralias'] = 0;
|
||||||
|
}
|
||||||
|
unset($result['wwwserveralias']);
|
||||||
|
unset($result['iswildcarddomain']);
|
||||||
|
|
||||||
|
// translate sslenabled flag
|
||||||
|
$result['sslenabled'] = $result['ssl_enabled'];
|
||||||
|
unset($result['ssl_enabled']);
|
||||||
|
|
||||||
|
$additional_params = $this->getParamList();
|
||||||
|
// unset unneeded params from this call
|
||||||
|
unset($additional_params['id']);
|
||||||
|
unset($additional_params['domainname']);
|
||||||
|
unset($additional_params['domain']);
|
||||||
|
|
||||||
|
// set new values and merge with optional add() parameters
|
||||||
|
$new_domain = array_merge($result, $additional_params);
|
||||||
|
$new_domain['domain'] = $p_domain;
|
||||||
|
|
||||||
|
$result_new = $this->apiCall('Domains.add', $new_domain);
|
||||||
|
return $this->response($result_new);
|
||||||
|
}
|
||||||
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,9 +95,13 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
$customer = $this->getCustomerData('email_accounts');
|
$customer = $this->getCustomerData('email_accounts');
|
||||||
|
|
||||||
// check for imap||pop3 == 1, see #1298
|
// check for imap||pop3 == 1, see #1298
|
||||||
|
// d00p, 6.5.2023 @revert this - if a customer has resources which allow email accounts
|
||||||
|
// it implicitly allowed SMTP, e.g. sending of emails which also requires an account to exist
|
||||||
|
/*
|
||||||
if ($customer['imap'] != '1' && $customer['pop3'] != '1') {
|
if ($customer['imap'] != '1' && $customer['pop3'] != '1') {
|
||||||
Response::standardError('notallowedtouseaccounts', '', true);
|
Response::standardError('notallowedtouseaccounts', '', true);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
if (!empty($emailaddr)) {
|
if (!empty($emailaddr)) {
|
||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
|
|||||||
@@ -88,9 +88,12 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
$domain_check = $this->apiCall('SubDomains.get', [
|
$domain_check = $this->apiCall('SubDomains.get', [
|
||||||
'domainname' => $domain
|
'domainname' => $domain
|
||||||
], true);
|
], true);
|
||||||
if ($domain_check['isemaildomain'] == 0) {
|
if ((int)$domain_check['isemaildomain'] == 0) {
|
||||||
Response::standardError('maindomainnonexist', $domain, true);
|
Response::standardError('maindomainnonexist', $domain, true);
|
||||||
}
|
}
|
||||||
|
if ((int)$domain_check['deactivated'] == 1) {
|
||||||
|
Response::standardError('maindomaindeactivated', $domain, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (Settings::Get('catchall.catchall_enabled') != '1') {
|
if (Settings::Get('catchall.catchall_enabled') != '1') {
|
||||||
$iscatchall = 0;
|
$iscatchall = 0;
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validation
|
// validation
|
||||||
$description = Validate::validate($description, 'description', Validate::REGEX_DESC_TEXT, '', [], true);
|
$description = Validate::validate($description, 'description', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$reload_cmd = Validate::validate($reload_cmd, 'reload_cmd', '/^[a-z0-9\/\._\- ]+$/i', '', [], true);
|
$reload_cmd = Validate::validate($reload_cmd, 'reload_cmd', '/^[a-z0-9\/\._\-@ ]+$/i', '', [], true);
|
||||||
$sel_stmt = Database::prepare("SELECT `id` FROM `".TABLE_PANEL_FPMDAEMONS."` WHERE `reload_cmd` = :rc");
|
$sel_stmt = Database::prepare("SELECT `id` FROM `".TABLE_PANEL_FPMDAEMONS."` WHERE `reload_cmd` = :rc");
|
||||||
$dupcheck = Database::pexecute_first($sel_stmt, ['rc' => $reload_cmd]);
|
$dupcheck = Database::pexecute_first($sel_stmt, ['rc' => $reload_cmd]);
|
||||||
if ($dupcheck && $dupcheck['id']) {
|
if ($dupcheck && $dupcheck['id']) {
|
||||||
@@ -327,7 +327,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validation
|
// validation
|
||||||
$description = Validate::validate($description, 'description', Validate::REGEX_DESC_TEXT, '', [], true);
|
$description = Validate::validate($description, 'description', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$reload_cmd = Validate::validate($reload_cmd, 'reload_cmd', '/^[a-z0-9\/\._\- ]+$/i', '', [], true);
|
$reload_cmd = Validate::validate($reload_cmd, 'reload_cmd', '/^[a-z0-9\/\._\-@ ]+$/i', '', [], true);
|
||||||
$sel_stmt = Database::prepare("SELECT `id` FROM `".TABLE_PANEL_FPMDAEMONS."` WHERE `reload_cmd` = :rc");
|
$sel_stmt = Database::prepare("SELECT `id` FROM `".TABLE_PANEL_FPMDAEMONS."` WHERE `reload_cmd` = :rc");
|
||||||
$dupcheck = Database::pexecute_first($sel_stmt, ['rc' => $reload_cmd]);
|
$dupcheck = Database::pexecute_first($sel_stmt, ['rc' => $reload_cmd]);
|
||||||
if ($dupcheck && $dupcheck['id'] != $id) {
|
if ($dupcheck && $dupcheck['id'] != $id) {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ use Froxlor\Settings;
|
|||||||
use Froxlor\SImExporter;
|
use Froxlor\SImExporter;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\Crypt;
|
use Froxlor\System\Crypt;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
use PDO;
|
use PDO;
|
||||||
use RecursiveDirectoryIterator;
|
use RecursiveDirectoryIterator;
|
||||||
use RecursiveIteratorIterator;
|
use RecursiveIteratorIterator;
|
||||||
@@ -81,7 +82,7 @@ class Froxlor extends ApiCommand
|
|||||||
if ($aucheck == 1) {
|
if ($aucheck == 1) {
|
||||||
// anzeige über version-status mit ggfls. formular
|
// anzeige über version-status mit ggfls. formular
|
||||||
// zum update schritt #1 -> download
|
// zum update schritt #1 -> download
|
||||||
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') == 'testing' ? 'testing ' : ''), AutoUpdate::getFromResult('version'), $this->version]);
|
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') != 'stable' ? Settings::Get('system.update_channel').' ' : ''), AutoUpdate::getFromResult('version'), $this->version]);
|
||||||
$response = [
|
$response = [
|
||||||
'isnewerversion' => (int) !AutoUpdate::getFromResult('has_latest'),
|
'isnewerversion' => (int) !AutoUpdate::getFromResult('has_latest'),
|
||||||
'version' => $this->version,
|
'version' => $this->version,
|
||||||
@@ -90,7 +91,7 @@ class Froxlor extends ApiCommand
|
|||||||
'additional_info' => AutoUpdate::getFromResult('info'),
|
'additional_info' => AutoUpdate::getFromResult('info'),
|
||||||
'aucheck' => $aucheck
|
'aucheck' => $aucheck
|
||||||
];
|
];
|
||||||
} else if ($aucheck < 0 || $aucheck > 1) {
|
} elseif ($aucheck < 0 || $aucheck > 1) {
|
||||||
// errors
|
// errors
|
||||||
if ($aucheck < 0) {
|
if ($aucheck < 0) {
|
||||||
$errmsg = AutoUpdate::getLastError();
|
$errmsg = AutoUpdate::getLastError();
|
||||||
@@ -258,17 +259,91 @@ class Froxlor extends ApiCommand
|
|||||||
* returns a random password based on froxlor settings for min-length, included characters, etc.
|
* returns a random password based on froxlor settings for min-length, included characters, etc.
|
||||||
*
|
*
|
||||||
* @param int $length
|
* @param int $length
|
||||||
* optional length of password, defaults to 10
|
* optional length of password, defaults to 0 (panel.password_min_length)
|
||||||
*
|
*
|
||||||
* @access admin, customer
|
* @access admin, customer
|
||||||
* @return string
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function generatePassword()
|
public function generatePassword(): string
|
||||||
{
|
{
|
||||||
$length = $this->getParam('length', true, 10);
|
$length = $this->getParam('length', true, 0);
|
||||||
return $this->response(Crypt::generatePassword($length));
|
return $this->response(Crypt::generatePassword($length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a one-time login link URL for a given user
|
||||||
|
*
|
||||||
|
* @param int $customerid optional, required if $loginname is not specified, user to create link for
|
||||||
|
* @param string $loginname optional, required if $customerid is not specified, user to create link for
|
||||||
|
* @param int $valid_time optional, value in seconds how long the link will be valid, default is 10 seconds, valid values are numbers from 10 to 120
|
||||||
|
* @param string $allowed_from optional, comma separated list of ip addresses or networks to allow login from via this link
|
||||||
|
*
|
||||||
|
* @access admin
|
||||||
|
* @return string json-encoded array [base => domain, uri => relative link]
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function generateLoginLink()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin()) {
|
||||||
|
$customer = $this->getCustomerData();
|
||||||
|
|
||||||
|
// cannot create link for deactivated users
|
||||||
|
if ((int)$customer['deactivated'] == 1) {
|
||||||
|
throw new Exception("Cannot generate link for deactivated user", 406);
|
||||||
|
}
|
||||||
|
|
||||||
|
$valid_time = (int)$this->getParam('valid_time', true, 10);
|
||||||
|
$allowed_from = $this->getParam('allowed_from', true, '');
|
||||||
|
|
||||||
|
$valid_time = Validate::validate($valid_time, 'valid time', '/^(1[0-1][0-9]|120|[1-9][0-9])$/', 'invalid_validtime', [10], true);
|
||||||
|
|
||||||
|
// validate allowed_from
|
||||||
|
if (!empty($allowed_from)) {
|
||||||
|
$ip_list = array_map('trim', explode(",", $allowed_from));
|
||||||
|
$_check_list = $ip_list;
|
||||||
|
foreach ($_check_list as $idx => $ip) {
|
||||||
|
if (Validate::validate_ip2($ip, true, 'invalidip', true, true, true) == false) {
|
||||||
|
throw new Exception('Invalid ip address', 406);
|
||||||
|
}
|
||||||
|
// check for cidr
|
||||||
|
if (strpos($ip, '/') !== false) {
|
||||||
|
$ipparts = explode("/", $ip);
|
||||||
|
// shorten IP
|
||||||
|
$ip = inet_ntop(inet_pton($ipparts[0]));
|
||||||
|
// re-add cidr
|
||||||
|
$ip .= '/' . $ipparts[1];
|
||||||
|
} else {
|
||||||
|
// shorten IP
|
||||||
|
$ip = inet_ntop(inet_pton($ip));
|
||||||
|
}
|
||||||
|
$ip_list[$idx] = $ip;
|
||||||
|
}
|
||||||
|
$allowed_from = implode(",", array_unique($ip_list));
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash = hash('sha256', openssl_random_pseudo_bytes(64 * 64));
|
||||||
|
|
||||||
|
$ins_stmt = Database::prepare("
|
||||||
|
INSERT INTO `" . TABLE_PANEL_LOGINLINKS . "`
|
||||||
|
SET `hash` = :hash, `loginname` = :loginname, `valid_until` = :validuntil, `allowed_from` = :allowedfrom
|
||||||
|
ON DUPLICATE KEY UPDATE `hash` = :hash, `valid_until` = :validuntil, `allowed_from` = :allowedfrom
|
||||||
|
");
|
||||||
|
Database::pexecute($ins_stmt, [
|
||||||
|
'hash' => $hash,
|
||||||
|
'loginname' => $customer['loginname'],
|
||||||
|
'validuntil' => time() + $valid_time,
|
||||||
|
'allowedfrom' => $allowed_from
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->response([
|
||||||
|
'base' => 'https://' . Settings::Get('system.hostname') . '/' . (Settings::Get('system.froxlordirectlyviahostname') != 1 ? basename(\Froxlor\Froxlor::getInstallDir()) . '/' : ''),
|
||||||
|
'uri' => 'index.php?action=ll&ln=' . $customer['loginname'] . '&h=' . $hash
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* can be used to remotely run the integritiy checks froxlor implements
|
* can be used to remotely run the integritiy checks froxlor implements
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
* optional whether to add additional usernames to the group
|
* optional whether to add additional usernames to the group
|
||||||
* @param bool $is_defaultuser
|
* @param bool $is_defaultuser
|
||||||
* optional whether this is the standard default ftp user which is being added so no usage is decreased
|
* optional whether this is the standard default ftp user which is being added so no usage is decreased
|
||||||
|
* @param bool $login_enabled
|
||||||
|
* optional whether to allow login (default) or not
|
||||||
*
|
*
|
||||||
* @access admin, customer
|
* @access admin, customer
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
@@ -84,6 +86,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
$is_defaultuser = $this->getBoolParam('is_defaultuser', true, 0);
|
$is_defaultuser = $this->getBoolParam('is_defaultuser', true, 0);
|
||||||
|
$login_enabled = $this->getBoolParam('login_enabled', true, 1);
|
||||||
|
|
||||||
if (($this->getUserDetail('ftps_used') < $this->getUserDetail('ftps') || $this->getUserDetail('ftps') == '-1') || $this->isAdmin() && $is_defaultuser == 1) {
|
if (($this->getUserDetail('ftps_used') < $this->getUserDetail('ftps') || $this->getUserDetail('ftps') == '-1') || $this->isAdmin() && $is_defaultuser == 1) {
|
||||||
// required parameters
|
// required parameters
|
||||||
@@ -171,18 +174,19 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
} elseif ($username == $password) {
|
} elseif ($username == $password) {
|
||||||
Response::standardError('passwordshouldnotbeusername', '', true);
|
Response::standardError('passwordshouldnotbeusername', '', true);
|
||||||
} else {
|
} else {
|
||||||
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
|
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);
|
||||||
$cryptPassword = Crypt::makeCryptPassword($password, false, true);
|
$cryptPassword = Crypt::makeCryptPassword($password, false, true);
|
||||||
|
|
||||||
$stmt = Database::prepare("INSERT INTO `" . TABLE_FTP_USERS . "`
|
$stmt = Database::prepare("INSERT INTO `" . TABLE_FTP_USERS . "`
|
||||||
(`customerid`, `username`, `description`, `password`, `homedir`, `login_enabled`, `uid`, `gid`, `shell`)
|
(`customerid`, `username`, `description`, `password`, `homedir`, `login_enabled`, `uid`, `gid`, `shell`)
|
||||||
VALUES (:customerid, :username, :description, :password, :homedir, 'y', :guid, :guid, :shell)");
|
VALUES (:customerid, :username, :description, :password, :homedir, :loginenabled, :guid, :guid, :shell)");
|
||||||
$params = [
|
$params = [
|
||||||
"customerid" => $customer['customerid'],
|
"customerid" => $customer['customerid'],
|
||||||
"username" => $username,
|
"username" => $username,
|
||||||
"description" => $description,
|
"description" => $description,
|
||||||
"password" => $cryptPassword,
|
"password" => $cryptPassword,
|
||||||
"homedir" => $path,
|
"homedir" => $path,
|
||||||
|
"loginenabled" => $login_enabled ? 'Y' : 'N',
|
||||||
"guid" => $customer['guid'],
|
"guid" => $customer['guid'],
|
||||||
"shell" => $shell
|
"shell" => $shell
|
||||||
];
|
];
|
||||||
@@ -389,6 +393,8 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
* optional, description for ftp-user
|
* optional, description for ftp-user
|
||||||
* @param string $shell
|
* @param string $shell
|
||||||
* optional, default /bin/false (not changeable when deactivated)
|
* optional, default /bin/false (not changeable when deactivated)
|
||||||
|
* @param bool $login_enabled
|
||||||
|
* optional whether to allow login (default) or not
|
||||||
* @param int $customerid
|
* @param int $customerid
|
||||||
* optional, required when called as admin (if $loginname is not specified)
|
* optional, required when called as admin (if $loginname is not specified)
|
||||||
* @param string $loginname
|
* @param string $loginname
|
||||||
@@ -419,6 +425,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
$password = $this->getParam('ftp_password', true, '');
|
$password = $this->getParam('ftp_password', true, '');
|
||||||
$description = $this->getParam('ftp_description', true, $result['description']);
|
$description = $this->getParam('ftp_description', true, $result['description']);
|
||||||
$shell = $this->getParam('shell', true, $result['shell']);
|
$shell = $this->getParam('shell', true, $result['shell']);
|
||||||
|
$login_enabled = $this->getBoolParam('login_enabled', true, ($result['login_enabled'] == 'Y' ? 1 : 0));
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$password = Validate::validate($password, 'password', '', '', [], true);
|
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||||
@@ -430,6 +437,10 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
$shell = "/bin/false";
|
$shell = "/bin/false";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($login_enabled != 1) {
|
||||||
|
$login_enabled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// get needed customer info to reduce the ftp-user-counter by one
|
// get needed customer info to reduce the ftp-user-counter by one
|
||||||
$customer = $this->getCustomerData();
|
$customer = $this->getCustomerData();
|
||||||
|
|
||||||
@@ -458,7 +469,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// path update?
|
// path update?
|
||||||
if ($path != '') {
|
if ($path != '') {
|
||||||
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
|
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);
|
||||||
|
|
||||||
if ($path != $result['homedir']) {
|
if ($path != $result['homedir']) {
|
||||||
$stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "`
|
$stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "`
|
||||||
@@ -480,13 +491,14 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
$stmt = Database::prepare("
|
$stmt = Database::prepare("
|
||||||
UPDATE `" . TABLE_FTP_USERS . "`
|
UPDATE `" . TABLE_FTP_USERS . "`
|
||||||
SET `description` = :desc, `shell` = :shell
|
SET `description` = :desc, `shell` = :shell, `login_enabled` = :loginenabled
|
||||||
WHERE `customerid` = :customerid
|
WHERE `customerid` = :customerid
|
||||||
AND `id` = :id
|
AND `id` = :id
|
||||||
");
|
");
|
||||||
Database::pexecute($stmt, [
|
Database::pexecute($stmt, [
|
||||||
"desc" => $description,
|
"desc" => $description,
|
||||||
"shell" => $shell,
|
"shell" => $shell,
|
||||||
|
"loginenabled" => $login_enabled ? 'Y' : 'N',
|
||||||
"customerid" => $customer['customerid'],
|
"customerid" => $customer['customerid'],
|
||||||
"id" => $id
|
"id" => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validation
|
// validation
|
||||||
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_CONF_TEXT);
|
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT);
|
||||||
|
|
||||||
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
||||||
$value_arr['email_quota'] = -1;
|
$value_arr['email_quota'] = -1;
|
||||||
@@ -383,7 +383,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validation
|
// validation
|
||||||
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_CONF_TEXT);
|
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT);
|
||||||
|
|
||||||
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
||||||
$value_arr['email_quota'] = -1;
|
$value_arr['email_quota'] = -1;
|
||||||
|
|||||||
@@ -176,8 +176,9 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
if ((int)Settings::Get('system.use_ssl') == 1) {
|
if ((int)Settings::Get('system.use_ssl') == 1) {
|
||||||
$ssl = (bool)$this->getBoolParam('ssl', true, 0);
|
$ssl = (bool)$this->getBoolParam('ssl', true, 0);
|
||||||
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', !$ssl, ''), 'ssl_cert_file', '', '', [], true);
|
$cert_optional = !($ssl && empty(Settings::Get('system.ssl_cert_file')));
|
||||||
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', !$ssl, ''), 'ssl_key_file', '', '', [], true);
|
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', $cert_optional, ''), 'ssl_cert_file', '', '', [], true);
|
||||||
|
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', $cert_optional, ''), 'ssl_key_file', '', '', [], true);
|
||||||
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, ''), 'ssl_ca_file', '', '', [], true);
|
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, ''), 'ssl_ca_file', '', '', [], true);
|
||||||
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, ''), 'ssl_cert_chainfile', '', '', [], true);
|
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, ''), 'ssl_cert_chainfile', '', '', [], true);
|
||||||
$sslss = $this->getParam('ssl_specialsettings', true, '');
|
$sslss = $this->getParam('ssl_specialsettings', true, '');
|
||||||
@@ -415,8 +416,9 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
if ((int)Settings::Get('system.use_ssl') == 1) {
|
if ((int)Settings::Get('system.use_ssl') == 1) {
|
||||||
$ssl = (bool)$this->getBoolParam('ssl', true, $result['ssl']);
|
$ssl = (bool)$this->getBoolParam('ssl', true, $result['ssl']);
|
||||||
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', !$ssl, $result['ssl_cert_file']), 'ssl_cert_file', '', '', [], true);
|
$cert_optional = !($ssl && empty(Settings::Get('system.ssl_cert_file')));
|
||||||
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', !$ssl, $result['ssl_key_file']), 'ssl_key_file', '', '', [], true);
|
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', $cert_optional, $result['ssl_cert_file']), 'ssl_cert_file', '', '', [], true);
|
||||||
|
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', $cert_optional, $result['ssl_key_file']), 'ssl_key_file', '', '', [], true);
|
||||||
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, $result['ssl_ca_file']), 'ssl_ca_file', '', '', [], true);
|
$ssl_ca_file = Validate::validate($this->getParam('ssl_ca_file', true, $result['ssl_ca_file']), 'ssl_ca_file', '', '', [], true);
|
||||||
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, $result['ssl_cert_chainfile']), 'ssl_cert_chainfile', '', '', [], true);
|
$ssl_cert_chainfile = Validate::validate($this->getParam('ssl_cert_chainfile', true, $result['ssl_cert_chainfile']), 'ssl_cert_chainfile', '', '', [], true);
|
||||||
$sslss = $this->getParam('ssl_specialsettings', true, $result['ssl_specialsettings']);
|
$sslss = $this->getParam('ssl_specialsettings', true, $result['ssl_specialsettings']);
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, php-settings-id, if empty the $domain value is used
|
* optional, php-settings-id, if empty the $domain value is used
|
||||||
* @param int $redirectcode
|
* @param int $redirectcode
|
||||||
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
|
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
|
||||||
|
* @param int $speciallogfile
|
||||||
|
* optional, whether to create an exclusive web-logfile for this domain (1) or not (0) or inherit value from parentdomain (2, default)
|
||||||
* @param bool $sslenabled
|
* @param bool $sslenabled
|
||||||
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
||||||
* 1 (true)
|
* 1 (true)
|
||||||
@@ -107,6 +109,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
|
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, 0);
|
$phpsettingid = $this->getParam('phpsettingid', true, 0);
|
||||||
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
|
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
|
||||||
|
$speciallogfile = intval($this->getParam('speciallogfile', true, 2));
|
||||||
$isemaildomain = $this->getParam('isemaildomain', true, 0);
|
$isemaildomain = $this->getParam('isemaildomain', true, 0);
|
||||||
if (Settings::Get('system.use_ssl')) {
|
if (Settings::Get('system.use_ssl')) {
|
||||||
$sslenabled = $this->getBoolParam('sslenabled', true, 1);
|
$sslenabled = $this->getBoolParam('sslenabled', true, 1);
|
||||||
@@ -229,6 +232,9 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
} elseif ($completedomain_check && strtolower($completedomain_check['domain']) == strtolower($completedomain)) {
|
} elseif ($completedomain_check && strtolower($completedomain_check['domain']) == strtolower($completedomain)) {
|
||||||
// the domain does already exist as main-domain
|
// the domain does already exist as main-domain
|
||||||
Response::standardError('domainexistalready', $completedomain, true);
|
Response::standardError('domainexistalready', $completedomain, true);
|
||||||
|
} elseif ((int)$domain_check['deactivated'] == 1) {
|
||||||
|
// main domain is deactivated
|
||||||
|
Response::standardError('maindomaindeactivated', $domain, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if allowed, check for 'is email domain'-flag
|
// if allowed, check for 'is email domain'-flag
|
||||||
@@ -273,6 +279,11 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$ssl_redirect = 2;
|
$ssl_redirect = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate speciallogfile value
|
||||||
|
if ($speciallogfile < 0 || $speciallogfile > 2) {
|
||||||
|
$speciallogfile = 2; // inherit from parent-domain
|
||||||
|
}
|
||||||
|
|
||||||
// get the phpsettingid from parentdomain, #107
|
// get the phpsettingid from parentdomain, #107
|
||||||
$phpsid_stmt = Database::prepare("
|
$phpsid_stmt = Database::prepare("
|
||||||
SELECT `phpsettingid` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `id` = :id
|
SELECT `phpsettingid` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `id` = :id
|
||||||
@@ -351,7 +362,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
"openbasedir" => $domain_check['openbasedir'],
|
"openbasedir" => $domain_check['openbasedir'],
|
||||||
"openbasedir_path" => $openbasedir_path,
|
"openbasedir_path" => $openbasedir_path,
|
||||||
"phpenabled" => $domain_check['phpenabled'],
|
"phpenabled" => $domain_check['phpenabled'],
|
||||||
"speciallogfile" => $domain_check['speciallogfile'],
|
"speciallogfile" => $speciallogfile == 2 ? $domain_check['speciallogfile'] : $speciallogfile,
|
||||||
"specialsettings" => $domain_check['specialsettings'],
|
"specialsettings" => $domain_check['specialsettings'],
|
||||||
"ssl_specialsettings" => $domain_check['ssl_specialsettings'],
|
"ssl_specialsettings" => $domain_check['ssl_specialsettings'],
|
||||||
"include_specialsettings" => $domain_check['include_specialsettings'],
|
"include_specialsettings" => $domain_check['include_specialsettings'],
|
||||||
@@ -553,9 +564,9 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
// If path is empty or '/' and 'Use domain name as default value for DocumentRoot path' is enabled in settings,
|
// If path is empty or '/' and 'Use domain name as default value for DocumentRoot path' is enabled in settings,
|
||||||
// set default path to subdomain or domain name
|
// set default path to subdomain or domain name
|
||||||
if ((($path == '') || ($path == '/')) && Settings::Get('system.documentroot_use_default_value') == 1) {
|
if ((($path == '') || ($path == '/')) && Settings::Get('system.documentroot_use_default_value') == 1) {
|
||||||
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $completedomain);
|
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $completedomain, $customer['documentroot']);
|
||||||
} else {
|
} else {
|
||||||
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
|
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no it's not, create a redirect
|
// no it's not, create a redirect
|
||||||
@@ -588,6 +599,11 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, php-settings-id, if empty the $domain value is used
|
* optional, php-settings-id, if empty the $domain value is used
|
||||||
* @param int $redirectcode
|
* @param int $redirectcode
|
||||||
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
|
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
|
||||||
|
* @param bool $speciallogfile
|
||||||
|
* optional, whether to create an exclusive web-logfile for this domain
|
||||||
|
* @param bool $speciallogverified
|
||||||
|
* optional, when setting $speciallogfile to false, this needs to be set to true to confirm the action,
|
||||||
|
* default 0 (false)
|
||||||
* @param bool $sslenabled
|
* @param bool $sslenabled
|
||||||
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
|
||||||
* 1 (true)
|
* 1 (true)
|
||||||
@@ -645,6 +661,8 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$openbasedir_path = $this->getParam('openbasedir_path', true, $result['openbasedir_path']);
|
$openbasedir_path = $this->getParam('openbasedir_path', true, $result['openbasedir_path']);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
||||||
$redirectcode = $this->getParam('redirectcode', true, Domain::getDomainRedirectId($id));
|
$redirectcode = $this->getParam('redirectcode', true, Domain::getDomainRedirectId($id));
|
||||||
|
$speciallogfile = $this->getBoolParam('speciallogfile', true, $result['speciallogfile']);
|
||||||
|
$speciallogverified = $this->getBoolParam('speciallogverified', true, 0);
|
||||||
if (Settings::Get('system.use_ssl')) {
|
if (Settings::Get('system.use_ssl')) {
|
||||||
$sslenabled = $this->getBoolParam('sslenabled', true, $result['ssl_enabled']);
|
$sslenabled = $this->getBoolParam('sslenabled', true, $result['ssl_enabled']);
|
||||||
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, $result['ssl_redirect']);
|
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, $result['ssl_redirect']);
|
||||||
@@ -754,6 +772,10 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$ssl_redirect = 2;
|
$ssl_redirect = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($speciallogfile != $result['speciallogfile'] && $speciallogverified != '1') {
|
||||||
|
$speciallogfile = $result['speciallogfile'];
|
||||||
|
}
|
||||||
|
|
||||||
// is-email-domain flag changed - remove mail accounts and mail-addresses
|
// is-email-domain flag changed - remove mail accounts and mail-addresses
|
||||||
if (($result['isemaildomain'] == '1') && $isemaildomain == '0') {
|
if (($result['isemaildomain'] == '1') && $isemaildomain == '0') {
|
||||||
$params = [
|
$params = [
|
||||||
@@ -786,7 +808,21 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
Domain::updateRedirectOfDomain($id, $redirectcode);
|
Domain::updateRedirectOfDomain($id, $redirectcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($path != $result['documentroot'] || $isemaildomain != $result['isemaildomain'] || $wwwserveralias != $result['wwwserveralias'] || $iswildcarddomain != $result['iswildcarddomain'] || $aliasdomain != (int)$result['aliasdomain'] || $openbasedir_path != $result['openbasedir_path'] || $ssl_redirect != $result['ssl_redirect'] || $letsencrypt != $result['letsencrypt'] || $hsts_maxage != $result['hsts'] || $hsts_sub != $result['hsts_sub'] || $hsts_preload != $result['hsts_preload'] || $phpsettingid != $result['phpsettingid'] || $http2 != $result['http2']) {
|
if ($path != $result['documentroot']
|
||||||
|
|| $isemaildomain != $result['isemaildomain']
|
||||||
|
|| $wwwserveralias != $result['wwwserveralias']
|
||||||
|
|| $iswildcarddomain != $result['iswildcarddomain']
|
||||||
|
|| $aliasdomain != (int)$result['aliasdomain']
|
||||||
|
|| $openbasedir_path != $result['openbasedir_path']
|
||||||
|
|| $ssl_redirect != $result['ssl_redirect']
|
||||||
|
|| $letsencrypt != $result['letsencrypt']
|
||||||
|
|| $hsts_maxage != $result['hsts']
|
||||||
|
|| $hsts_sub != $result['hsts_sub']
|
||||||
|
|| $hsts_preload != $result['hsts_preload']
|
||||||
|
|| $phpsettingid != $result['phpsettingid']
|
||||||
|
|| $http2 != $result['http2']
|
||||||
|
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|
||||||
|
) {
|
||||||
$stmt = Database::prepare("
|
$stmt = Database::prepare("
|
||||||
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
|
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
|
||||||
`documentroot` = :documentroot,
|
`documentroot` = :documentroot,
|
||||||
@@ -802,7 +838,8 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
`hsts` = :hsts,
|
`hsts` = :hsts,
|
||||||
`hsts_sub` = :hsts_sub,
|
`hsts_sub` = :hsts_sub,
|
||||||
`hsts_preload` = :hsts_preload,
|
`hsts_preload` = :hsts_preload,
|
||||||
`phpsettingid` = :phpsettingid
|
`phpsettingid` = :phpsettingid,
|
||||||
|
`speciallogfile` = :speciallogfile
|
||||||
WHERE `customerid`= :customerid AND `id`= :id
|
WHERE `customerid`= :customerid AND `id`= :id
|
||||||
");
|
");
|
||||||
$params = [
|
$params = [
|
||||||
@@ -820,6 +857,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
"hsts_sub" => $hsts_sub,
|
"hsts_sub" => $hsts_sub,
|
||||||
"hsts_preload" => $hsts_preload,
|
"hsts_preload" => $hsts_preload,
|
||||||
"phpsettingid" => $phpsettingid,
|
"phpsettingid" => $phpsettingid,
|
||||||
|
"speciallogfile" => $speciallogfile,
|
||||||
"customerid" => $customer['customerid'],
|
"customerid" => $customer['customerid'],
|
||||||
"id" => $id
|
"id" => $id
|
||||||
];
|
];
|
||||||
@@ -865,7 +903,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lists all subdomain entries
|
* lists all customer domain/subdomain entries
|
||||||
*
|
*
|
||||||
* @param bool $with_ips
|
* @param bool $with_ips
|
||||||
* optional, default true
|
* optional, default true
|
||||||
@@ -910,17 +948,12 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$custom_list_result = $_custom_list_result['list'];
|
$custom_list_result = $_custom_list_result['list'];
|
||||||
}
|
}
|
||||||
$customer_ids = [];
|
$customer_ids = [];
|
||||||
$customer_stdsubs = [];
|
|
||||||
foreach ($custom_list_result as $customer) {
|
foreach ($custom_list_result as $customer) {
|
||||||
$customer_ids[] = $customer['customerid'];
|
$customer_ids[] = $customer['customerid'];
|
||||||
$customer_stdsubs[$customer['customerid']] = $customer['standardsubdomain'];
|
|
||||||
}
|
}
|
||||||
if (empty($customer_ids)) {
|
if (empty($customer_ids)) {
|
||||||
throw new Exception("Required resource unsatisfied.", 405);
|
throw new Exception("Required resource unsatisfied.", 405);
|
||||||
}
|
}
|
||||||
if (empty($customer_stdsubs)) {
|
|
||||||
throw new Exception("Required resource unsatisfied.", 405);
|
|
||||||
}
|
|
||||||
|
|
||||||
$select_fields = [
|
$select_fields = [
|
||||||
'`d`.*'
|
'`d`.*'
|
||||||
@@ -932,9 +965,6 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$customer_ids = [
|
$customer_ids = [
|
||||||
$this->getUserDetail('customerid')
|
$this->getUserDetail('customerid')
|
||||||
];
|
];
|
||||||
$customer_stdsubs = [
|
|
||||||
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
|
|
||||||
];
|
|
||||||
|
|
||||||
$select_fields = [
|
$select_fields = [
|
||||||
'`d`.`id`',
|
'`d`.`id`',
|
||||||
@@ -949,7 +979,8 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
'`d`.`parentdomainid`',
|
'`d`.`parentdomainid`',
|
||||||
'`d`.`letsencrypt`',
|
'`d`.`letsencrypt`',
|
||||||
'`d`.`registration_date`',
|
'`d`.`registration_date`',
|
||||||
'`d`.`termination_date`'
|
'`d`.`termination_date`',
|
||||||
|
'`d`.`deactivated`'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
@@ -963,7 +994,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON `pd`.`id`=`d`.`parentdomainid`
|
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON `pd`.`id`=`d`.`parentdomainid`
|
||||||
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
||||||
AND `d`.`email_only` = '0'
|
AND `d`.`email_only` = '0'
|
||||||
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit());
|
" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit());
|
||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
Database::pexecute($domains_stmt, $query_fields, true, true);
|
Database::pexecute($domains_stmt, $query_fields, true, true);
|
||||||
@@ -1047,10 +1078,8 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$custom_list_result = $_custom_list_result['list'];
|
$custom_list_result = $_custom_list_result['list'];
|
||||||
}
|
}
|
||||||
$customer_ids = [];
|
$customer_ids = [];
|
||||||
$customer_stdsubs = [];
|
|
||||||
foreach ($custom_list_result as $customer) {
|
foreach ($custom_list_result as $customer) {
|
||||||
$customer_ids[] = $customer['customerid'];
|
$customer_ids[] = $customer['customerid'];
|
||||||
$customer_stdsubs[$customer['customerid']] = $customer['standardsubdomain'];
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Settings::IsInList('panel.customer_hide_options', 'domains')) {
|
if (Settings::IsInList('panel.customer_hide_options', 'domains')) {
|
||||||
@@ -1059,22 +1088,20 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$customer_ids = [
|
$customer_ids = [
|
||||||
$this->getUserDetail('customerid')
|
$this->getUserDetail('customerid')
|
||||||
];
|
];
|
||||||
$customer_stdsubs = [
|
|
||||||
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
if (!empty($customer_ids)) {
|
||||||
// prepare select statement
|
// prepare select statement
|
||||||
$domains_stmt = Database::prepare("
|
$domains_stmt = Database::prepare("
|
||||||
SELECT COUNT(*) as num_subdom
|
SELECT COUNT(*) as num_subdom
|
||||||
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
||||||
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
||||||
AND `d`.`email_only` = '0'
|
AND `d`.`email_only` = '0'
|
||||||
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")
|
|
||||||
");
|
");
|
||||||
$result = Database::pexecute_first($domains_stmt, null, true, true);
|
$result = Database::pexecute_first($domains_stmt, null, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
return $this->response($result['num_subdom']);
|
return $this->response($result['num_subdom']);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return $this->response(0);
|
return $this->response(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,11 +112,11 @@ class FroxlorRPC
|
|||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private static function validateAllowedFrom(array $allowed_from, string $remote_addr): bool
|
public static function validateAllowedFrom(array $allowed_from, string $remote_addr): bool
|
||||||
{
|
{
|
||||||
// shorten IP for comparison
|
// shorten IP for comparison
|
||||||
$remote_addr = inet_ntop(inet_pton($remote_addr));
|
$remote_addr = inet_ntop(inet_pton($remote_addr));
|
||||||
// check for diret matches
|
// check for direct matches
|
||||||
if (in_array($remote_addr, $allowed_from)) {
|
if (in_array($remote_addr, $allowed_from)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,19 +25,18 @@
|
|||||||
|
|
||||||
namespace Froxlor\Cli;
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
use PDO;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\Database\Database;
|
use PDO;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
class CliCommand extends Command
|
class CliCommand extends Command
|
||||||
{
|
{
|
||||||
|
|
||||||
protected function validateRequirements(InputInterface $input, OutputInterface $output, bool $ignore_has_updates = false): int
|
protected function validateRequirements(OutputInterface $output, bool $ignore_has_updates = false): int
|
||||||
{
|
{
|
||||||
if (!file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) {
|
if (!file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) {
|
||||||
$output->writeln("<error>Could not find froxlor's userdata.inc.php file. You should use this script only with an installed froxlor system.</>");
|
$output->writeln("<error>Could not find froxlor's userdata.inc.php file. You should use this script only with an installed froxlor system.</>");
|
||||||
@@ -116,9 +115,11 @@ class CliCommand extends Command
|
|||||||
return $userinfo;
|
return $userinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function runUpdate(OutputInterface $output): int
|
protected function runUpdate(OutputInterface $output, bool $manual = false): int
|
||||||
{
|
{
|
||||||
|
if (!$manual) {
|
||||||
$output->writeln('<comment>Automatic update is activated and we are going to proceed without any notices</>');
|
$output->writeln('<comment>Automatic update is activated and we are going to proceed without any notices</>');
|
||||||
|
}
|
||||||
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
|
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
|
||||||
define('_CRON_UPDATE', 1);
|
define('_CRON_UPDATE', 1);
|
||||||
ob_start([
|
ob_start([
|
||||||
@@ -127,11 +128,11 @@ class CliCommand extends Command
|
|||||||
]);
|
]);
|
||||||
include_once Froxlor::getInstallDir() . '/install/updatesql.php';
|
include_once Froxlor::getInstallDir() . '/install/updatesql.php';
|
||||||
ob_end_flush();
|
ob_end_flush();
|
||||||
$output->writeln('<info>Automatic update done - you should check your settings to be sure everything is fine</>');
|
$output->writeln('<info>' . ($manual ? 'Database' : 'Automatic') . ' update done - you should check your settings to be sure everything is fine</>');
|
||||||
return self::SUCCESS;
|
return self::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function cleanUpdateOutput($buffer)
|
private function cleanUpdateOutput($buffer): string
|
||||||
{
|
{
|
||||||
return strip_tags(preg_replace("/<br\W*?\/>/", "\n", $buffer));
|
return strip_tags(preg_replace("/<br\W*?\/>/", "\n", $buffer));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ final class ConfigDiff extends CliCommand
|
|||||||
->addOption('diff-params', '', InputOption::VALUE_REQUIRED, 'Additional parameters for `diff`, e.g. --diff-params="--color=always"');
|
->addOption('diff-params', '', InputOption::VALUE_REQUIRED, 'Additional parameters for `diff`, e.g. --diff-params="--color=always"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
require Froxlor::getInstallDir() . '/lib/functions.php';
|
require Froxlor::getInstallDir() . '/lib/functions.php';
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
namespace Froxlor\Cli;
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
use Froxlor\Config\ConfigParser;
|
use Froxlor\Config\ConfigParser;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
@@ -40,9 +41,8 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
|||||||
|
|
||||||
final class ConfigServices extends CliCommand
|
final class ConfigServices extends CliCommand
|
||||||
{
|
{
|
||||||
|
|
||||||
private $yes_to_all_supported = [
|
private $yes_to_all_supported = [
|
||||||
/* 'bookworm', */
|
'bookworm',
|
||||||
'bionic',
|
'bionic',
|
||||||
'bullseye',
|
'bullseye',
|
||||||
'buster',
|
'buster',
|
||||||
@@ -62,11 +62,9 @@ final class ConfigServices extends CliCommand
|
|||||||
->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Install packages without asking questions (Debian/Ubuntu only currently)');
|
->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Install packages without asking questions (Debian/Ubuntu only currently)');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$result = self::SUCCESS;
|
$result = $this->validateRequirements($output);
|
||||||
|
|
||||||
$result = $this->validateRequirements($input, $output);
|
|
||||||
|
|
||||||
require Froxlor::getInstallDir() . '/lib/functions.php';
|
require Froxlor::getInstallDir() . '/lib/functions.php';
|
||||||
|
|
||||||
@@ -93,7 +91,7 @@ final class ConfigServices extends CliCommand
|
|||||||
if ($result == self::SUCCESS) {
|
if ($result == self::SUCCESS) {
|
||||||
$io = new SymfonyStyle($input, $output);
|
$io = new SymfonyStyle($input, $output);
|
||||||
if ($input->getOption('create')) {
|
if ($input->getOption('create')) {
|
||||||
$result = $this->createConfig($input, $output, $io);
|
$result = $this->createConfig($output, $io);
|
||||||
} elseif ($input->getOption('apply')) {
|
} elseif ($input->getOption('apply')) {
|
||||||
$result = $this->applyConfig($input, $output, $io);
|
$result = $this->applyConfig($input, $output, $io);
|
||||||
} elseif ($input->getOption('list') || $input->getOption('daemon')) {
|
} elseif ($input->getOption('list') || $input->getOption('daemon')) {
|
||||||
@@ -158,7 +156,10 @@ final class ConfigServices extends CliCommand
|
|||||||
fclose($fp);
|
fclose($fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createConfig(InputInterface $input, OutputInterface $output, SymfonyStyle $io)
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function createConfig(OutputInterface $output, SymfonyStyle $io): int
|
||||||
{
|
{
|
||||||
$_daemons_config = [
|
$_daemons_config = [
|
||||||
'distro' => ""
|
'distro' => ""
|
||||||
@@ -285,7 +286,10 @@ final class ConfigServices extends CliCommand
|
|||||||
return self::SUCCESS;
|
return self::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function applyConfig(InputInterface $input, OutputInterface $output, SymfonyStyle $io)
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function applyConfig(InputInterface $input, OutputInterface $output, SymfonyStyle $io): int
|
||||||
{
|
{
|
||||||
$applyFile = $input->getOption('apply');
|
$applyFile = $input->getOption('apply');
|
||||||
|
|
||||||
@@ -398,7 +402,7 @@ final class ConfigServices extends CliCommand
|
|||||||
case "file":
|
case "file":
|
||||||
if (array_key_exists('content', $action)) {
|
if (array_key_exists('content', $action)) {
|
||||||
$output->writeln('<comment>Creating file "' . $action['name'] . '"</>');
|
$output->writeln('<comment>Creating file "' . $action['name'] . '"</>');
|
||||||
file_put_contents($action['name'], trim(strtr($action['content'], $replace_arr)));
|
file_put_contents($action['name'], trim(strtr($action['content'], $replace_arr)) . PHP_EOL);
|
||||||
} elseif (array_key_exists('subcommands', $action)) {
|
} elseif (array_key_exists('subcommands', $action)) {
|
||||||
foreach ($action['subcommands'] as $fileaction) {
|
foreach ($action['subcommands'] as $fileaction) {
|
||||||
if (array_key_exists('execute', $fileaction) && $fileaction['execute'] == "pre") {
|
if (array_key_exists('execute', $fileaction) && $fileaction['execute'] == "pre") {
|
||||||
@@ -407,7 +411,7 @@ final class ConfigServices extends CliCommand
|
|||||||
exec(strtr($fileaction['content'], $replace_arr));
|
exec(strtr($fileaction['content'], $replace_arr));
|
||||||
} elseif ($fileaction['type'] == 'file') {
|
} elseif ($fileaction['type'] == 'file') {
|
||||||
$output->writeln('<comment>Creating file "' . $fileaction['name'] . '"</>');
|
$output->writeln('<comment>Creating file "' . $fileaction['name'] . '"</>');
|
||||||
file_put_contents($fileaction['name'], trim(strtr($fileaction['content'], $replace_arr)));
|
file_put_contents($fileaction['name'], trim(strtr($fileaction['content'], $replace_arr)) . PHP_EOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -429,7 +433,10 @@ final class ConfigServices extends CliCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getReplacerArray()
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function getReplacerArray(): array
|
||||||
{
|
{
|
||||||
$customer_tmpdir = '/tmp/';
|
$customer_tmpdir = '/tmp/';
|
||||||
if (Settings::Get('system.mod_fcgid') == '1' && Settings::Get('system.mod_fcgid_tmpdir') != '') {
|
if (Settings::Get('system.mod_fcgid') == '1' && Settings::Get('system.mod_fcgid_tmpdir') != '') {
|
||||||
@@ -438,7 +445,7 @@ final class ConfigServices extends CliCommand
|
|||||||
$customer_tmpdir = Settings::Get('phpfpm.tmpdir');
|
$customer_tmpdir = Settings::Get('phpfpm.tmpdir');
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to convert namserver hosts to ip's
|
// try to convert nameserver hosts to ip's
|
||||||
$ns_ips = "";
|
$ns_ips = "";
|
||||||
$known_ns_ips = [];
|
$known_ns_ips = [];
|
||||||
if (Settings::Get('system.nameservers') != '') {
|
if (Settings::Get('system.nameservers') != '') {
|
||||||
@@ -484,12 +491,12 @@ final class ConfigServices extends CliCommand
|
|||||||
Database::needSqlData();
|
Database::needSqlData();
|
||||||
$sql = Database::getSqlData();
|
$sql = Database::getSqlData();
|
||||||
|
|
||||||
$replace_arr = [
|
return [
|
||||||
'<SQL_UNPRIVILEGED_USER>' => $sql['user'],
|
'<SQL_UNPRIVILEGED_USER>' => $sql['user'],
|
||||||
'<SQL_UNPRIVILEGED_PASSWORD>' => $sql['passwd'],
|
'<SQL_UNPRIVILEGED_PASSWORD>' => $sql['passwd'],
|
||||||
'<SQL_DB>' => $sql['db'],
|
'<SQL_DB>' => $sql['db'],
|
||||||
'<SQL_HOST>' => $sql['host'],
|
'<SQL_HOST>' => $sql['host'],
|
||||||
'<SQL_SOCKET>' => isset($sql['socket']) ? $sql['socket'] : null,
|
'<SQL_SOCKET>' => $sql['socket'] ?? null,
|
||||||
'<SERVERNAME>' => Settings::Get('system.hostname'),
|
'<SERVERNAME>' => Settings::Get('system.hostname'),
|
||||||
'<SERVERIP>' => Settings::Get('system.ipaddress'),
|
'<SERVERIP>' => Settings::Get('system.ipaddress'),
|
||||||
'<NAMESERVERS>' => Settings::Get('system.nameservers'),
|
'<NAMESERVERS>' => Settings::Get('system.nameservers'),
|
||||||
@@ -507,7 +514,7 @@ final class ConfigServices extends CliCommand
|
|||||||
'<WEBSERVER_GROUP>' => Settings::Get('system.httpgroup'),
|
'<WEBSERVER_GROUP>' => Settings::Get('system.httpgroup'),
|
||||||
'<SSL_CERT_FILE>' => Settings::Get('system.ssl_cert_file'),
|
'<SSL_CERT_FILE>' => Settings::Get('system.ssl_cert_file'),
|
||||||
'<SSL_KEY_FILE>' => Settings::Get('system.ssl_key_file'),
|
'<SSL_KEY_FILE>' => Settings::Get('system.ssl_key_file'),
|
||||||
|
'<ADMIN_MAIL>' => Settings::Get('panel.adminmail'),
|
||||||
];
|
];
|
||||||
return $replace_arr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,13 +26,13 @@
|
|||||||
namespace Froxlor\Cli;
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\Config\ConfigParser;
|
use Froxlor\Config\ConfigParser;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Install\Install;
|
use Froxlor\Install\Install;
|
||||||
use Froxlor\Install\Install\Core;
|
use Froxlor\Install\Install\Core;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
@@ -53,7 +53,10 @@ final class InstallCommand extends Command
|
|||||||
->addOption('create-userdata-from-str', 'c', InputOption::VALUE_REQUIRED, 'Creates lib/userdata.inc.php file from string created by web-install process');
|
->addOption('create-userdata-from-str', 'c', InputOption::VALUE_REQUIRED, 'Creates lib/userdata.inc.php file from string created by web-install process');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$result = self::SUCCESS;
|
$result = self::SUCCESS;
|
||||||
|
|
||||||
@@ -137,10 +140,12 @@ final class InstallCommand extends Command
|
|||||||
$decoded_input = [];
|
$decoded_input = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->showStep(0, $extended, $decoded_input);
|
return $this->showStep(0, $extended, $decoded_input);
|
||||||
return $result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
private function showStep(int $step = 0, bool $extended = false, array $decoded_input = []): int
|
private function showStep(int $step = 0, bool $extended = false, array $decoded_input = []): int
|
||||||
{
|
{
|
||||||
$result = self::SUCCESS;
|
$result = self::SUCCESS;
|
||||||
@@ -206,7 +211,7 @@ final class InstallCommand extends Command
|
|||||||
$ask_field = false;
|
$ask_field = false;
|
||||||
}
|
}
|
||||||
$fielddata['value'] = $this->formfielddata[$fieldname] ?? ($fielddata['value'] ?? null);
|
$fielddata['value'] = $this->formfielddata[$fieldname] ?? ($fielddata['value'] ?? null);
|
||||||
$fielddata['label'] = strip_tags(str_replace("<br>", " ", $fielddata['label']));
|
$fielddata['label'] = $this->cliTextFormat($fielddata['label'], " ");
|
||||||
if ($ask_field) {
|
if ($ask_field) {
|
||||||
if ($fielddata['type'] == 'password') {
|
if ($fielddata['type'] == 'password') {
|
||||||
$this->formfielddata[$fieldname] = $this->io->askHidden($fielddata['label'], function ($value) use ($fielddata) {
|
$this->formfielddata[$fieldname] = $this->io->askHidden($fielddata['label'], function ($value) use ($fielddata) {
|
||||||
@@ -262,15 +267,17 @@ final class InstallCommand extends Command
|
|||||||
case 4:
|
case 4:
|
||||||
$section = $inst->formfield['install']['sections']['step' . $step] ?? [];
|
$section = $inst->formfield['install']['sections']['step' . $step] ?? [];
|
||||||
$this->io->section($section['title']);
|
$this->io->section($section['title']);
|
||||||
$this->io->note($section['description']);
|
$this->io->note($this->cliTextFormat($section['description']));
|
||||||
$cmdfield = $section['fields']['system'];
|
$cmdfield = $section['fields']['system'];
|
||||||
$this->io->success([
|
$this->io->success([
|
||||||
$cmdfield['label'],
|
$cmdfield['label'],
|
||||||
$cmdfield['value']
|
$cmdfield['value']
|
||||||
]);
|
]);
|
||||||
|
if (!isset($decoded_input['manual_config']) || (bool)$decoded_input['manual_config'] === false) {
|
||||||
if (!empty($decoded_input) || $this->io->confirm('Execute command now?', false)) {
|
if (!empty($decoded_input) || $this->io->confirm('Execute command now?', false)) {
|
||||||
passthru($cmdfield['value']);
|
passthru($cmdfield['value']);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
@@ -300,7 +307,7 @@ final class InstallCommand extends Command
|
|||||||
$json_output = [];
|
$json_output = [];
|
||||||
foreach ($fields['install']['sections'] as $section => $section_fields) {
|
foreach ($fields['install']['sections'] as $section => $section_fields) {
|
||||||
foreach ($section_fields['fields'] as $name => $field) {
|
foreach ($section_fields['fields'] as $name => $field) {
|
||||||
if ($name == 'system' || $name == 'manual_config' || $name == 'target_servername') {
|
if ($name == 'system' || $name == 'target_servername') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($field['type'] == 'text' || $field['type'] == 'email') {
|
if ($field['type'] == 'text' || $field['type'] == 'email') {
|
||||||
@@ -313,7 +320,7 @@ final class InstallCommand extends Command
|
|||||||
$fieldval = '******';
|
$fieldval = '******';
|
||||||
} elseif ($field['type'] == 'select') {
|
} elseif ($field['type'] == 'select') {
|
||||||
$fieldval = implode("|", array_keys($field['select_var']));
|
$fieldval = implode("|", array_keys($field['select_var']));
|
||||||
} else if ($field['type'] == 'checkbox') {
|
} elseif ($field['type'] == 'checkbox') {
|
||||||
$fieldval = "1|0";
|
$fieldval = "1|0";
|
||||||
} else {
|
} else {
|
||||||
$fieldval = "?";
|
$fieldval = "?";
|
||||||
@@ -341,4 +348,10 @@ final class InstallCommand extends Command
|
|||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function cliTextFormat(string $text, string $nl_char = "\n"): string
|
||||||
|
{
|
||||||
|
$text = str_replace(['<br>', '<br/>', '<br />'], [$nl_char, $nl_char, $nl_char], $text);
|
||||||
|
return strip_tags($text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,19 +25,20 @@
|
|||||||
|
|
||||||
namespace Froxlor\Cli;
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
use PDO;
|
use Exception;
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\FileDir;
|
|
||||||
use Froxlor\Settings;
|
|
||||||
use Froxlor\FroxlorLogger;
|
|
||||||
use Froxlor\Database\Database;
|
|
||||||
use Froxlor\System\Cronjob;
|
|
||||||
use Froxlor\Cron\TaskId;
|
|
||||||
use Froxlor\Cron\CronConfig;
|
use Froxlor\Cron\CronConfig;
|
||||||
use Froxlor\Cron\System\Extrausers;
|
use Froxlor\Cron\System\Extrausers;
|
||||||
|
use Froxlor\Cron\TaskId;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
use Froxlor\System\Cronjob;
|
||||||
|
use PDO;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
final class MasterCron extends CliCommand
|
final class MasterCron extends CliCommand
|
||||||
@@ -52,15 +53,17 @@ final class MasterCron extends CliCommand
|
|||||||
$this->setDescription('Regulary perform tasks created by froxlor');
|
$this->setDescription('Regulary perform tasks created by froxlor');
|
||||||
$this->addArgument('job', InputArgument::IS_ARRAY, 'Job(s) to run');
|
$this->addArgument('job', InputArgument::IS_ARRAY, 'Job(s) to run');
|
||||||
$this->addOption('run-task', 'r', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Run a specific task [1 = re-generate configs, 4 = re-generate dns zones, 10 = re-set quotas, 99 = re-create cron.d-file]')
|
$this->addOption('run-task', 'r', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Run a specific task [1 = re-generate configs, 4 = re-generate dns zones, 10 = re-set quotas, 99 = re-create cron.d-file]')
|
||||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces re-generating of config-files (webserver, nameserver, etc.)')
|
->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces given job or, if none given, forces re-generating of config-files (webserver, nameserver, etc.)')
|
||||||
->addOption('debug', 'd', InputOption::VALUE_NONE, 'Output debug information about what is going on to STDOUT.')
|
->addOption('debug', 'd', InputOption::VALUE_NONE, 'Output debug information about what is going on to STDOUT.')
|
||||||
->addOption('no-fork', 'N', InputOption::VALUE_NONE, 'Do not fork to background (traffic cron only).');
|
->addOption('no-fork', 'N', InputOption::VALUE_NONE, 'Do not fork to background (traffic cron only).');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$result = self::SUCCESS;
|
$result = $this->validateRequirements($output);
|
||||||
$result = $this->validateRequirements($input, $output);
|
|
||||||
|
|
||||||
if ($result != self::SUCCESS) {
|
if ($result != self::SUCCESS) {
|
||||||
// requirements failed, exit
|
// requirements failed, exit
|
||||||
@@ -71,12 +74,13 @@ final class MasterCron extends CliCommand
|
|||||||
|
|
||||||
// handle force option
|
// handle force option
|
||||||
if ($input->getOption('force')) {
|
if ($input->getOption('force')) {
|
||||||
// rebuild all config files
|
if (empty($jobs) || in_array('tasks', $jobs)) {
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_DNS);
|
Cronjob::inserttask(TaskId::REBUILD_DNS);
|
||||||
Cronjob::inserttask(TaskId::CREATE_QUOTA);
|
Cronjob::inserttask(TaskId::CREATE_QUOTA);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_CRON);
|
Cronjob::inserttask(TaskId::REBUILD_CRON);
|
||||||
array_push($jobs, 'tasks');
|
$jobs[] = 'tasks';
|
||||||
|
}
|
||||||
define('CRON_IS_FORCED', 1);
|
define('CRON_IS_FORCED', 1);
|
||||||
}
|
}
|
||||||
// handle debug option
|
// handle debug option
|
||||||
@@ -91,9 +95,9 @@ final class MasterCron extends CliCommand
|
|||||||
if ($input->getOption('run-task')) {
|
if ($input->getOption('run-task')) {
|
||||||
$tasks_to_run = $input->getOption('run-task');
|
$tasks_to_run = $input->getOption('run-task');
|
||||||
foreach ($tasks_to_run as $ttr) {
|
foreach ($tasks_to_run as $ttr) {
|
||||||
if (in_array($ttr, [1, 4, 10, 99])) {
|
if (in_array($ttr, [TaskId::REBUILD_VHOST, TaskId::REBUILD_DNS, TaskId::CREATE_QUOTA, TaskId::REBUILD_CRON])) {
|
||||||
Cronjob::inserttask($ttr);
|
Cronjob::inserttask($ttr);
|
||||||
array_push($jobs, 'tasks');
|
$jobs[] = 'tasks';
|
||||||
} else {
|
} else {
|
||||||
$output->writeln('<comment>Unknown task number "' . $ttr . '"</>');
|
$output->writeln('<comment>Unknown task number "' . $ttr . '"</>');
|
||||||
}
|
}
|
||||||
@@ -139,12 +143,12 @@ final class MasterCron extends CliCommand
|
|||||||
$cronfile::run();
|
$cronfile::run();
|
||||||
}
|
}
|
||||||
// free the lockfile
|
// free the lockfile
|
||||||
$this->unlockJob($job);
|
$this->unlockJob();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// regenerate nss-extrausers files / invalidate nscd cache (if used)
|
// regenerate nss-extrausers files / invalidate nscd cache (if used)
|
||||||
$this->refreshUsers((int) $tasks_cnt['jobcnt']);
|
$this->refreshUsers((int)$tasks_cnt['jobcnt']);
|
||||||
|
|
||||||
// we have to check the system's last guid with every cron run
|
// we have to check the system's last guid with every cron run
|
||||||
// in case the admin installed new software which added a new user
|
// in case the admin installed new software which added a new user
|
||||||
@@ -156,40 +160,25 @@ final class MasterCron extends CliCommand
|
|||||||
CronConfig::checkCrondConfigurationFile();
|
CronConfig::checkCrondConfigurationFile();
|
||||||
|
|
||||||
// check for old/compatibility cronjob file
|
// check for old/compatibility cronjob file
|
||||||
if (file_exists(Froxlor::getInstallDir().'/scripts/froxlor_master_cronjob.php')) {
|
if (file_exists(Froxlor::getInstallDir() . '/scripts/froxlor_master_cronjob.php')) {
|
||||||
@unlink(Froxlor::getInstallDir().'/scripts/froxlor_master_cronjob.php');
|
@unlink(Froxlor::getInstallDir() . '/scripts/froxlor_master_cronjob.php');
|
||||||
@rmdir(Froxlor::getInstallDir().'/scripts');
|
@rmdir(Froxlor::getInstallDir() . '/scripts');
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset cronlog-flag if set to "once"
|
// reset cronlog-flag if set to "once"
|
||||||
if ((int) Settings::Get('logger.log_cron') == 1) {
|
if ((int)Settings::Get('logger.log_cron') == 1) {
|
||||||
FroxlorLogger::getInstanceOf()->setCronLog(0);
|
FroxlorLogger::getInstanceOf()->setCronLog(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clean up possible old login-links
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_LOGINLINKS . "` WHERE `valid_until` < UNIX_TIMESTAMP()");
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function refreshUsers(int $jobcount = 0)
|
/**
|
||||||
{
|
* @throws Exception
|
||||||
if ($jobcount > 0) {
|
*/
|
||||||
if (Settings::Get('system.nssextrausers') == 1) {
|
|
||||||
Extrausers::generateFiles($this->cronLog);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear NSCD cache if using fcgid or fpm, #1570 - not needed for nss-extrausers
|
|
||||||
if ((Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1) && Settings::Get('system.nssextrausers') == 0) {
|
|
||||||
$false_val = false;
|
|
||||||
FileDir::safe_exec('nscd -i passwd 1> /dev/null', $false_val, [
|
|
||||||
'>'
|
|
||||||
]);
|
|
||||||
FileDir::safe_exec('nscd -i group 1> /dev/null', $false_val, [
|
|
||||||
'>'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function validateOwnership(OutputInterface $output)
|
private function validateOwnership(OutputInterface $output)
|
||||||
{
|
{
|
||||||
// when using fcgid or fpm for froxlor-vhost itself, we have to check
|
// when using fcgid or fpm for froxlor-vhost itself, we have to check
|
||||||
@@ -216,21 +205,6 @@ final class MasterCron extends CliCommand
|
|||||||
$output->writeln('OK');
|
$output->writeln('OK');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getCronModule(string $cronname, OutputInterface $output)
|
|
||||||
{
|
|
||||||
$upd_stmt = Database::prepare("
|
|
||||||
SELECT `cronclass` FROM `" . TABLE_PANEL_CRONRUNS . "` WHERE `cronfile` = :cron;
|
|
||||||
");
|
|
||||||
$cron = Database::pexecute_first($upd_stmt, [
|
|
||||||
'cron' => $cronname
|
|
||||||
]);
|
|
||||||
if ($cron) {
|
|
||||||
return $cron['cronclass'];
|
|
||||||
}
|
|
||||||
$output->writeln("<error>Requested cronjob '" . $cronname . "' could not be found.</>");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function lockJob(string $job, OutputInterface $output): bool
|
private function lockJob(string $job, OutputInterface $output): bool
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -243,12 +217,12 @@ final class MasterCron extends CliCommand
|
|||||||
system("kill -CHLD " . (int)$jobinfo['pid'] . " 1> /dev/null 2> /dev/null", $check_pid_return);
|
system("kill -CHLD " . (int)$jobinfo['pid'] . " 1> /dev/null 2> /dev/null", $check_pid_return);
|
||||||
if ($check_pid_return == 1) {
|
if ($check_pid_return == 1) {
|
||||||
// Process does not seem to run, most likely it has died
|
// Process does not seem to run, most likely it has died
|
||||||
$this->unlockJob($job);
|
$this->unlockJob();
|
||||||
} else {
|
} else {
|
||||||
// cronjob still running, output info and stop
|
// cronjob still running, output info and stop
|
||||||
$output->writeln([
|
$output->writeln([
|
||||||
'<comment>Job "' . $jobinfo['job'] . '" is currently running.',
|
'<comment>Job "' . $jobinfo['job'] . '" is currently running.',
|
||||||
'Started: ' . date('d.m.Y H:i', (int) $jobinfo['startts']),
|
'Started: ' . date('d.m.Y H:i', (int)$jobinfo['startts']),
|
||||||
'PID: ' . $jobinfo['pid'] . '</>'
|
'PID: ' . $jobinfo['pid'] . '</>'
|
||||||
]);
|
]);
|
||||||
return false;
|
return false;
|
||||||
@@ -264,8 +238,48 @@ final class MasterCron extends CliCommand
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function unlockJob(string $job): bool
|
private function unlockJob(): bool
|
||||||
{
|
{
|
||||||
return @unlink($this->lockFile);
|
return @unlink($this->lockFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getCronModule(string $cronname, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$upd_stmt = Database::prepare("
|
||||||
|
SELECT `cronclass` FROM `" . TABLE_PANEL_CRONRUNS . "` WHERE `cronfile` = :cron;
|
||||||
|
");
|
||||||
|
$cron = Database::pexecute_first($upd_stmt, [
|
||||||
|
'cron' => $cronname
|
||||||
|
]);
|
||||||
|
if ($cron) {
|
||||||
|
return $cron['cronclass'];
|
||||||
|
}
|
||||||
|
$output->writeln("<error>Requested cronjob '" . $cronname . "' could not be found.</>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function refreshUsers(int $jobcount = 0)
|
||||||
|
{
|
||||||
|
if ($jobcount > 0) {
|
||||||
|
if (Settings::Get('system.nssextrausers') == 1) {
|
||||||
|
Extrausers::generateFiles($this->cronLog);
|
||||||
|
// reload crond as shell users might use crontab and the user is only known to crond if reloaded
|
||||||
|
FileDir::safe_exec(escapeshellcmd(Settings::Get('system.crondreload')));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear NSCD cache if using fcgid or fpm, #1570 - not needed for nss-extrausers
|
||||||
|
if ((Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1) && Settings::Get('system.nssextrausers') == 0) {
|
||||||
|
$false_val = false;
|
||||||
|
FileDir::safe_exec('nscd -i passwd 1> /dev/null', $false_val, [
|
||||||
|
'>'
|
||||||
|
]);
|
||||||
|
FileDir::safe_exec('nscd -i group 1> /dev/null', $false_val, [
|
||||||
|
'>'
|
||||||
|
]);
|
||||||
|
// reload crond as shell users might use crontab and the user is only known to crond if reloaded
|
||||||
|
FileDir::safe_exec(escapeshellcmd(Settings::Get('system.crondreload')));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ final class PhpSessionclean extends CliCommand
|
|||||||
$this->addArgument('max-lifetime', InputArgument::OPTIONAL, 'The number of seconds after which data will be seen as "garbage" and potentially cleaned up. Defaults to "1440"');
|
$this->addArgument('max-lifetime', InputArgument::OPTIONAL, 'The number of seconds after which data will be seen as "garbage" and potentially cleaned up. Defaults to "1440"');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$result = $this->validateRequirements($input, $output);
|
$result = $this->validateRequirements($output);
|
||||||
|
|
||||||
if ($result == self::SUCCESS) {
|
if ($result == self::SUCCESS) {
|
||||||
if ((int)Settings::Get('phpfpm.enabled') == 1) {
|
if ((int)Settings::Get('phpfpm.enabled') == 1) {
|
||||||
@@ -89,7 +89,7 @@ final class PhpSessionclean extends CliCommand
|
|||||||
|
|
||||||
if (count($paths_to_clean) > 0) {
|
if (count($paths_to_clean) > 0) {
|
||||||
foreach ($paths_to_clean as $ptc) {
|
foreach ($paths_to_clean as $ptc) {
|
||||||
// find all files older then maxlifetime and delete them
|
// find all files older than maxlifetime and delete them
|
||||||
FileDir::safe_exec("find -O3 \"" . $ptc . "\" -ignore_readdir_race -depth -mindepth 1 -name 'sess_*' -type f -cmin \"+" . $maxlifetime . "\" -delete");
|
FileDir::safe_exec("find -O3 \"" . $ptc . "\" -ignore_readdir_race -depth -mindepth 1 -name 'sess_*' -type f -cmin \"+" . $maxlifetime . "\" -delete");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,14 +26,12 @@
|
|||||||
namespace Froxlor\Cli;
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use PDO;
|
use Froxlor\Froxlor;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
use Froxlor\Database\Database;
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
|
|
||||||
final class RunApiCommand extends CliCommand
|
final class RunApiCommand extends CliCommand
|
||||||
{
|
{
|
||||||
@@ -48,11 +46,9 @@ final class RunApiCommand extends CliCommand
|
|||||||
$this->addOption('show-params', 's', InputOption::VALUE_NONE, 'Show possible parameters for given api-command (given command will *not* be called)');
|
$this->addOption('show-params', 's', InputOption::VALUE_NONE, 'Show possible parameters for given api-command (given command will *not* be called)');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$result = self::SUCCESS;
|
$result = $this->validateRequirements($output);
|
||||||
|
|
||||||
$result = $this->validateRequirements($input, $output);
|
|
||||||
|
|
||||||
require Froxlor::getInstallDir() . '/lib/functions.php';
|
require Froxlor::getInstallDir() . '/lib/functions.php';
|
||||||
|
|
||||||
@@ -110,6 +106,9 @@ final class RunApiCommand extends CliCommand
|
|||||||
return self::SUCCESS;
|
return self::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
private function validateCommand(string $command): array
|
private function validateCommand(string $command): array
|
||||||
{
|
{
|
||||||
$command = explode(".", $command);
|
$command = explode(".", $command);
|
||||||
|
|||||||
@@ -43,11 +43,9 @@ final class SwitchServerIp extends CliCommand
|
|||||||
->addOption('list', 'l', InputOption::VALUE_NONE, 'List all IP addresses currently added for this server in froxlor');
|
->addOption('list', 'l', InputOption::VALUE_NONE, 'List all IP addresses currently added for this server in froxlor');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$result = self::SUCCESS;
|
$result = $this->validateRequirements($output);
|
||||||
|
|
||||||
$result = $this->validateRequirements($input, $output);
|
|
||||||
|
|
||||||
if ($result == self::SUCCESS && $input->getOption('list') == false && $input->getOption('switch') == false) {
|
if ($result == self::SUCCESS && $input->getOption('list') == false && $input->getOption('switch') == false) {
|
||||||
$output->writeln('<error>Either --list or --switch option must be provided. Nothing to do, exiting.</>');
|
$output->writeln('<error>Either --list or --switch option must be provided. Nothing to do, exiting.</>');
|
||||||
@@ -83,6 +81,7 @@ final class SwitchServerIp extends CliCommand
|
|||||||
$ip_list = $input->getOption('switch');
|
$ip_list = $input->getOption('switch');
|
||||||
|
|
||||||
$has_error = false;
|
$has_error = false;
|
||||||
|
$ips_to_switch = [];
|
||||||
foreach ($ip_list as $ips_combo) {
|
foreach ($ip_list as $ips_combo) {
|
||||||
$ip_pair = explode(",", $ips_combo);
|
$ip_pair = explode(",", $ips_combo);
|
||||||
if (count($ip_pair) != 2) {
|
if (count($ip_pair) != 2) {
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ namespace Froxlor\Cli;
|
|||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Settings;
|
|
||||||
use Froxlor\Install\Update;
|
|
||||||
use Froxlor\Install\AutoUpdate;
|
use Froxlor\Install\AutoUpdate;
|
||||||
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Mailer;
|
use Froxlor\System\Mailer;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
@@ -44,6 +44,7 @@ final class UpdateCommand extends CliCommand
|
|||||||
$this->setName('froxlor:update');
|
$this->setName('froxlor:update');
|
||||||
$this->setDescription('Check for newer version and update froxlor');
|
$this->setDescription('Check for newer version and update froxlor');
|
||||||
$this->addOption('check-only', 'c', InputOption::VALUE_NONE, 'Only check for newer version and exit')
|
$this->addOption('check-only', 'c', InputOption::VALUE_NONE, 'Only check for newer version and exit')
|
||||||
|
->addOption('database', 'd', InputOption::VALUE_NONE, 'Only run database updates in case updates are done via apt or manually.')
|
||||||
->addOption('mail-notify', 'm', InputOption::VALUE_NONE, 'Additionally inform administrator via email if a newer version was found')
|
->addOption('mail-notify', 'm', InputOption::VALUE_NONE, 'Additionally inform administrator via email if a newer version was found')
|
||||||
->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for download, extract and database-update, just do it (if not --check-only is set)')
|
->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for download, extract and database-update, just do it (if not --check-only is set)')
|
||||||
->addOption('integer-return', 'i', InputOption::VALUE_NONE, 'Return integer whether a new version is available or not (implies --check-only). Useful for programmatic use.');
|
->addOption('integer-return', 'i', InputOption::VALUE_NONE, 'Return integer whether a new version is available or not (implies --check-only). Useful for programmatic use.');
|
||||||
@@ -53,7 +54,35 @@ final class UpdateCommand extends CliCommand
|
|||||||
{
|
{
|
||||||
$result = self::SUCCESS;
|
$result = self::SUCCESS;
|
||||||
|
|
||||||
$result = $this->validateRequirements($input, $output);
|
// database update only
|
||||||
|
if ($input->getOption('database')) {
|
||||||
|
$result = $this->validateRequirements($output, true);
|
||||||
|
if ($result == self::SUCCESS) {
|
||||||
|
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
||||||
|
$output->writeln('<info>' . lng('updates.dbupdate_required') . '</>');
|
||||||
|
if ($input->getOption('check-only')) {
|
||||||
|
$output->writeln('<comment>Doing nothing because of "check-only" flag.</>');
|
||||||
|
} else {
|
||||||
|
$yestoall = $input->getOption('yes-to-all') !== false;
|
||||||
|
$helper = $this->getHelper('question');
|
||||||
|
$question = new ConfirmationQuestion('Update database? [no] ', false, '/^(y|j)/i');
|
||||||
|
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||||
|
$result = $this->runUpdate($output, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
$output->writeln('<info>' . lng('update.noupdatesavail', (Settings::Get('system.update_channel') == 'testing' ? lng('serversettings.uc_testing') . ' ' : '')) . '</>');
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->validateRequirements($output);
|
||||||
|
|
||||||
|
if ($result != self::SUCCESS) {
|
||||||
|
// requirements failed, exit
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
require Froxlor::getInstallDir() . '/lib/functions.php';
|
require Froxlor::getInstallDir() . '/lib/functions.php';
|
||||||
|
|
||||||
@@ -71,7 +100,7 @@ final class UpdateCommand extends CliCommand
|
|||||||
}
|
}
|
||||||
// there is a new version
|
// there is a new version
|
||||||
if ($input->getOption('check-only')) {
|
if ($input->getOption('check-only')) {
|
||||||
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') == 'testing' ? 'testing ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
|
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') != 'stable' ? Settings::Get('system.update_channel').' ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
|
||||||
} else {
|
} else {
|
||||||
$text = lng('admin.newerversionavailable') . ' ' . lng('admin.newerversiondetails', [AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
|
$text = lng('admin.newerversionavailable') . ' ' . lng('admin.newerversiondetails', [AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
|
||||||
}
|
}
|
||||||
@@ -146,7 +175,7 @@ final class UpdateCommand extends CliCommand
|
|||||||
$result = self::SUCCESS;
|
$result = self::SUCCESS;
|
||||||
$question = new ConfirmationQuestion('Update database? [no] ', false, '/^(y|j)/i');
|
$question = new ConfirmationQuestion('Update database? [no] ', false, '/^(y|j)/i');
|
||||||
if ($yestoall || $helper->ask($input, $output, $question)) {
|
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||||
$result = $this->updateDatabase();
|
$result = $this->runUpdate($output, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$errmsg = 'error.autoupdate_' . $auex;
|
$errmsg = 'error.autoupdate_' . $auex;
|
||||||
@@ -170,7 +199,7 @@ final class UpdateCommand extends CliCommand
|
|||||||
if ($input->getOption('mail-notify')) {
|
if ($input->getOption('mail-notify')) {
|
||||||
$last_check_version = Settings::Get('system.update_notify_last');
|
$last_check_version = Settings::Get('system.update_notify_last');
|
||||||
if (Update::versionInUpdate($last_check_version, AutoUpdate::getFromResult('version'))) {
|
if (Update::versionInUpdate($last_check_version, AutoUpdate::getFromResult('version'))) {
|
||||||
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') == 'testing' ? 'testing ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
|
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') != 'stable' ? Settings::Get('system.update_channel').' ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
|
||||||
$mail = new Mailer(true);
|
$mail = new Mailer(true);
|
||||||
$mail->Body = $text;
|
$mail->Body = $text;
|
||||||
$mail->Subject = "[froxlor] " . lng('update.notify_subject');
|
$mail->Subject = "[froxlor] " . lng('update.notify_subject');
|
||||||
@@ -182,22 +211,4 @@ final class UpdateCommand extends CliCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function updateDatabase()
|
|
||||||
{
|
|
||||||
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
|
|
||||||
define('_CRON_UPDATE', 1);
|
|
||||||
ob_start([
|
|
||||||
$this,
|
|
||||||
'cleanUpdateOutput'
|
|
||||||
]);
|
|
||||||
include_once Froxlor::getInstallDir() . '/install/updatesql.php';
|
|
||||||
ob_end_flush();
|
|
||||||
return self::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function cleanUpdateOutput($buffer)
|
|
||||||
{
|
|
||||||
return strip_tags(preg_replace("/<br\W*?\/>/", "\n", $buffer));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,15 +26,15 @@
|
|||||||
namespace Froxlor\Cli;
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Froxlor\Api\Commands\Admins;
|
||||||
|
use Froxlor\Api\Commands\Customers;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\System\Crypt;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
use Froxlor\Api\Commands\Admins;
|
|
||||||
use Froxlor\Api\Commands\Customers;
|
|
||||||
use Froxlor\System\Crypt;
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
|
|
||||||
final class UserCommand extends CliCommand
|
final class UserCommand extends CliCommand
|
||||||
{
|
{
|
||||||
@@ -50,11 +50,11 @@ final class UserCommand extends CliCommand
|
|||||||
->addOption('show-info', 's', InputOption::VALUE_NONE, 'Output information details of given user');
|
->addOption('show-info', 's', InputOption::VALUE_NONE, 'Output information details of given user');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$result = self::SUCCESS;
|
$result = self::SUCCESS;
|
||||||
|
|
||||||
$result = $this->validateRequirements($input, $output);
|
$result = $this->validateRequirements($output);
|
||||||
|
|
||||||
require Froxlor::getInstallDir() . '/lib/functions.php';
|
require Froxlor::getInstallDir() . '/lib/functions.php';
|
||||||
|
|
||||||
|
|||||||
@@ -48,15 +48,16 @@ final class ValidateAcmeWebroot extends CliCommand
|
|||||||
$this->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for confirmation, update files if necessary');
|
$this->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for confirmation, update files if necessary');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$result = self::SUCCESS;
|
$result = $this->validateRequirements($output, true);
|
||||||
|
|
||||||
$result = $this->validateRequirements($input, $output, true);
|
|
||||||
|
|
||||||
$io = new SymfonyStyle($input, $output);
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
|
||||||
if ((int) Settings::Get('system.leenabled') == 0) {
|
if ((int)Settings::Get('system.leenabled') == 0) {
|
||||||
$io->info("Let's Encrypt not activated in froxlor settings.");
|
$io->info("Let's Encrypt not activated in froxlor settings.");
|
||||||
$result = self::INVALID;
|
$result = self::INVALID;
|
||||||
}
|
}
|
||||||
@@ -94,7 +95,7 @@ final class ValidateAcmeWebroot extends CliCommand
|
|||||||
$acmesh_challenge_dir = $recommended;
|
$acmesh_challenge_dir = $recommended;
|
||||||
// need to update the corresponding acme-alias config-file
|
// need to update the corresponding acme-alias config-file
|
||||||
$acme_alias_file = Settings::Get('system.letsencryptacmeconf');
|
$acme_alias_file = Settings::Get('system.letsencryptacmeconf');
|
||||||
$sed_params = "s@".$former_value."@" . $acmesh_challenge_dir . "@";
|
$sed_params = "s@" . $former_value . "@" . $acmesh_challenge_dir . "@";
|
||||||
FileDir::safe_exec('sed -i -e "' . $sed_params . '" ' . escapeshellarg($acme_alias_file));
|
FileDir::safe_exec('sed -i -e "' . $sed_params . '" ' . escapeshellarg($acme_alias_file));
|
||||||
$count_changes++;
|
$count_changes++;
|
||||||
}
|
}
|
||||||
@@ -138,8 +139,6 @@ final class ValidateAcmeWebroot extends CliCommand
|
|||||||
$io->info("Domain '" . $domain . "' Le_Webroot value is correct");
|
$io->info("Domain '" . $domain . "' Le_Webroot value is correct");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ class ConfigDisplay
|
|||||||
'<SQL_UNPRIVILEGED_PASSWORD>' => 'FROXLOR_MYSQL_PASSWORD',
|
'<SQL_UNPRIVILEGED_PASSWORD>' => 'FROXLOR_MYSQL_PASSWORD',
|
||||||
'<SQL_DB>' => $sql['db'],
|
'<SQL_DB>' => $sql['db'],
|
||||||
'<SQL_HOST>' => $sql['host'],
|
'<SQL_HOST>' => $sql['host'],
|
||||||
'<SQL_SOCKET>' => isset($sql['socket']) ? $sql['socket'] : null,
|
'<SQL_SOCKET>' => $sql['socket'] ?? null,
|
||||||
'<SERVERNAME>' => Settings::Get('system.hostname'),
|
'<SERVERNAME>' => Settings::Get('system.hostname'),
|
||||||
'<SERVERIP>' => Settings::Get('system.ipaddress'),
|
'<SERVERIP>' => Settings::Get('system.ipaddress'),
|
||||||
'<NAMESERVERS>' => Settings::Get('system.nameservers'),
|
'<NAMESERVERS>' => Settings::Get('system.nameservers'),
|
||||||
@@ -127,12 +127,15 @@ class ConfigDisplay
|
|||||||
'<VIRTUAL_GID_MAPS>' => Settings::Get('system.vmail_gid'),
|
'<VIRTUAL_GID_MAPS>' => Settings::Get('system.vmail_gid'),
|
||||||
'<SSLPROTOCOLS>' => (Settings::Get('system.use_ssl') == '1') ? 'imaps pop3s' : '',
|
'<SSLPROTOCOLS>' => (Settings::Get('system.use_ssl') == '1') ? 'imaps pop3s' : '',
|
||||||
'<CUSTOMER_TMP>' => FileDir::makeCorrectDir($customer_tmpdir),
|
'<CUSTOMER_TMP>' => FileDir::makeCorrectDir($customer_tmpdir),
|
||||||
'<BASE_PATH>' => FileDir::makeCorrectDir(Froxlor::getInstallDir()),
|
'<BASE_PATH>' => Froxlor::getInstallDir(),
|
||||||
'<BIND_CONFIG_PATH>' => FileDir::makeCorrectDir(Settings::Get('system.bindconf_directory')),
|
'<BIND_CONFIG_PATH>' => FileDir::makeCorrectDir(Settings::Get('system.bindconf_directory')),
|
||||||
'<WEBSERVER_RELOAD_CMD>' => Settings::Get('system.apachereload_command'),
|
'<WEBSERVER_RELOAD_CMD>' => Settings::Get('system.apachereload_command'),
|
||||||
'<CUSTOMER_LOGS>' => FileDir::makeCorrectDir(Settings::Get('system.logfiles_directory')),
|
'<CUSTOMER_LOGS>' => FileDir::makeCorrectDir(Settings::Get('system.logfiles_directory')),
|
||||||
'<FPM_IPCDIR>' => FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir')),
|
'<FPM_IPCDIR>' => FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir')),
|
||||||
'<WEBSERVER_GROUP>' => Settings::Get('system.httpgroup')
|
'<WEBSERVER_GROUP>' => Settings::Get('system.httpgroup'),
|
||||||
|
'<SSL_CERT_FILE>' => Settings::Get('system.ssl_cert_file'),
|
||||||
|
'<SSL_KEY_FILE>' => Settings::Get('system.ssl_key_file'),
|
||||||
|
'<ADMIN_MAIL>' => Settings::Get('panel.adminmail'),
|
||||||
];
|
];
|
||||||
|
|
||||||
$commands_pre = "";
|
$commands_pre = "";
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ class Bind extends DnsBase
|
|||||||
$this->bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n";
|
$this->bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n";
|
||||||
|
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
if ($domain['ismainbutsubto'] > 0) {
|
if ($domain['is_child']) {
|
||||||
// domains with ismainbutsubto>0 are handled by recursion within walkDomainList()
|
// domains that are subdomains to other main domains are handled by recursion within walkDomainList()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$this->walkDomainList($domain, $domains);
|
$this->walkDomainList($domain, $domains);
|
||||||
@@ -114,7 +114,7 @@ class Bind extends DnsBase
|
|||||||
$isFroxlorHostname = true;
|
$isFroxlorHostname = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($domain['ismainbutsubto'] == 0) {
|
if (!$domain['is_child']) {
|
||||||
$zoneContent = (string)Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
|
$zoneContent = (string)Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
|
||||||
$domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone';
|
$domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone';
|
||||||
$zonefile_name = FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']);
|
$zonefile_name = FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
namespace Froxlor\Cron\Dns;
|
namespace Froxlor\Cron\Dns;
|
||||||
|
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\Domain\Domain;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\PhpHelper;
|
use Froxlor\PhpHelper;
|
||||||
@@ -210,7 +211,6 @@ abstract class DnsBase
|
|||||||
`d`.`dkim`,
|
`d`.`dkim`,
|
||||||
`d`.`dkim_id`,
|
`d`.`dkim_id`,
|
||||||
`d`.`dkim_pubkey`,
|
`d`.`dkim_pubkey`,
|
||||||
`d`.`ismainbutsubto`,
|
|
||||||
`c`.`loginname`,
|
`c`.`loginname`,
|
||||||
`c`.`guid`
|
`c`.`guid`
|
||||||
FROM
|
FROM
|
||||||
@@ -219,7 +219,7 @@ abstract class DnsBase
|
|||||||
WHERE
|
WHERE
|
||||||
`d`.`isbinddomain` = '1'
|
`d`.`isbinddomain` = '1'
|
||||||
ORDER BY
|
ORDER BY
|
||||||
`d`.`domain` ASC
|
LENGTH(`d`.`domain`), `d`.`domain` ASC
|
||||||
");
|
");
|
||||||
|
|
||||||
$domains = [];
|
$domains = [];
|
||||||
@@ -241,11 +241,10 @@ abstract class DnsBase
|
|||||||
'bindserial' => date('Ymd') . '00',
|
'bindserial' => date('Ymd') . '00',
|
||||||
'dkim' => '0',
|
'dkim' => '0',
|
||||||
'iswildcarddomain' => '1',
|
'iswildcarddomain' => '1',
|
||||||
'ismainbutsubto' => '0',
|
|
||||||
'zonefile' => '',
|
'zonefile' => '',
|
||||||
'froxlorhost' => '1'
|
'froxlorhost' => '1'
|
||||||
];
|
];
|
||||||
$domains['none'] = $hostname_arr;
|
$domains[0] = $hostname_arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($domains)) {
|
if (empty($domains)) {
|
||||||
@@ -257,18 +256,23 @@ abstract class DnsBase
|
|||||||
if (!isset($domains[$key]['children'])) {
|
if (!isset($domains[$key]['children'])) {
|
||||||
$domains[$key]['children'] = [];
|
$domains[$key]['children'] = [];
|
||||||
}
|
}
|
||||||
if ($domains[$key]['ismainbutsubto'] > 0) {
|
if (!isset($domains[$key]['is_child'])) {
|
||||||
if (isset($domains[$domains[$key]['ismainbutsubto']])) {
|
$domains[$key]['is_child'] = false;
|
||||||
$domains[$domains[$key]['ismainbutsubto']]['children'][] = $domains[$key]['id'];
|
}
|
||||||
} else {
|
$children = Domain::getMainSubdomainIds($key);
|
||||||
$domains[$key]['ismainbutsubto'] = 0;
|
if (count($children) > 0) {
|
||||||
|
foreach ($children as $child) {
|
||||||
|
if (isset($domains[$child])) {
|
||||||
|
$domains[$key]['children'][] = $domains[$child]['id'];
|
||||||
|
$domains[$child]['is_child'] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, str_pad('domId', 9, ' ') . str_pad('domain', 40, ' ') . 'ismainbutsubto ' . str_pad('parent domain', 40, ' ') . "list of child domain ids");
|
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, str_pad('domId', 9, ' ') . str_pad('domain', 40, ' ') . "list of child domain ids");
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
$logLine = str_pad($domain['id'], 9, ' ') . str_pad($domain['domain'], 40, ' ') . str_pad($domain['ismainbutsubto'], 15, ' ') . str_pad(((isset($domains[$domain['ismainbutsubto']])) ? $domains[$domain['ismainbutsubto']]['domain'] : '-'), 40, ' ') . join(', ', $domain['children']);
|
$logLine = str_pad($domain['id'], 9, ' ') . str_pad($domain['domain'], 40, ' ') . join(', ', $domain['children']);
|
||||||
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, $logLine);
|
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, $logLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ class PowerDNS extends DnsBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
if ($domain['ismainbutsubto'] > 0) {
|
if ($domain['is_child']) {
|
||||||
// domains with ismainbutsubto>0 are handled by recursion within walkDomainList()
|
// domains that are subdomains to other main domains are handled by recursion within walkDomainList()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$this->walkDomainList($domain, $domains);
|
$this->walkDomainList($domain, $domains);
|
||||||
@@ -108,7 +108,7 @@ class PowerDNS extends DnsBase
|
|||||||
$isFroxlorHostname = true;
|
$isFroxlorHostname = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($domain['ismainbutsubto'] == 0) {
|
if (!$domain['is_child']) {
|
||||||
$zoneContent = Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
|
$zoneContent = Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname);
|
||||||
if (count($subzones)) {
|
if (count($subzones)) {
|
||||||
foreach ($subzones as $subzone) {
|
foreach ($subzones as $subzone) {
|
||||||
|
|||||||
57
lib/Froxlor/Cron/Forkable.php
Normal file
57
lib/Froxlor/Cron/Forkable.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Cron;
|
||||||
|
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
|
||||||
|
trait Forkable
|
||||||
|
{
|
||||||
|
public static function runFork($closure, array $attributes = [], int $concurrentChildren = 3)
|
||||||
|
{
|
||||||
|
$childrenPids = [];
|
||||||
|
|
||||||
|
// We only fork if pcntl_fork is available and nofork flag is not set
|
||||||
|
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
|
||||||
|
foreach ($attributes as $closureAttributes) {
|
||||||
|
// We close the database - connection before we fork, so we don't share resources with the child
|
||||||
|
Database::needRoot(false); // this forces the connection to be set to null
|
||||||
|
$pid = pcntl_fork();
|
||||||
|
|
||||||
|
if ($pid == -1) {
|
||||||
|
exit("Error forking...\n");
|
||||||
|
} elseif ($pid == 0) {
|
||||||
|
// re-create db
|
||||||
|
Database::needRoot(false);
|
||||||
|
$closure($closureAttributes);
|
||||||
|
exit();
|
||||||
|
} else {
|
||||||
|
$childrenPids[] = $pid;
|
||||||
|
while (count($childrenPids) >= $concurrentChildren) {
|
||||||
|
foreach ($childrenPids as $key => $pid) {
|
||||||
|
$res = pcntl_waitpid($pid, $status, WNOHANG);
|
||||||
|
// If the process has already exited
|
||||||
|
if ($res == -1 || $res > 0) {
|
||||||
|
unset($childrenPids[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (pcntl_waitpid(0, $status) != -1);
|
||||||
|
} else {
|
||||||
|
if (!defined('CRON_NOFORK_FLAG')) {
|
||||||
|
if (extension_loaded('pcntl')) {
|
||||||
|
$msg = "PHP compiled with pcntl but pcntl_fork function is not available.";
|
||||||
|
} else {
|
||||||
|
$msg = "PHP compiled without pcntl.";
|
||||||
|
}
|
||||||
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, $msg . " Not forking " . self::class . ", this may take a long time!");
|
||||||
|
}
|
||||||
|
foreach ($attributes as $closureAttributes) {
|
||||||
|
$closure($closureAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -129,7 +129,7 @@ class Apache extends HttpConfigBase
|
|||||||
if ($row_ipsandports['ssl'] == '0' && Settings::Get('system.le_froxlor_redirect') == '1') {
|
if ($row_ipsandports['ssl'] == '0' && Settings::Get('system.le_froxlor_redirect') == '1') {
|
||||||
$is_redirect = true;
|
$is_redirect = true;
|
||||||
// check whether froxlor uses Let's Encrypt and not cert is being generated yet
|
// check whether froxlor uses Let's Encrypt and not cert is being generated yet
|
||||||
// or a renew is ongoing - disable redirect
|
// or a renewal is ongoing - disable redirect
|
||||||
if (Settings::Get('system.le_froxlor_enabled') && ($this->froxlorVhostHasLetsEncryptCert() == false || $this->froxlorVhostLetsEncryptNeedsRenew())) {
|
if (Settings::Get('system.le_froxlor_enabled') && ($this->froxlorVhostHasLetsEncryptCert() == false || $this->froxlorVhostLetsEncryptNeedsRenew())) {
|
||||||
$this->virtualhosts_data[$vhosts_filename] .= '# temp. disabled ssl-redirect due to Let\'s Encrypt certificate generation.' . PHP_EOL;
|
$this->virtualhosts_data[$vhosts_filename] .= '# temp. disabled ssl-redirect due to Let\'s Encrypt certificate generation.' . PHP_EOL;
|
||||||
$is_redirect = false;
|
$is_redirect = false;
|
||||||
@@ -515,13 +515,7 @@ class Apache extends HttpConfigBase
|
|||||||
*/
|
*/
|
||||||
private function createStandardDirectoryEntry()
|
private function createStandardDirectoryEntry()
|
||||||
{
|
{
|
||||||
$vhosts_folder = '';
|
$vhosts_filename = $this->getCustomVhostFilename('05_froxlor_dirfix_nofcgid.conf');
|
||||||
if (is_dir(Settings::Get('system.apacheconf_vhost'))) {
|
|
||||||
$vhosts_folder = FileDir::makeCorrectDir(Settings::Get('system.apacheconf_vhost'));
|
|
||||||
} else {
|
|
||||||
$vhosts_folder = FileDir::makeCorrectDir(dirname(Settings::Get('system.apacheconf_vhost')));
|
|
||||||
}
|
|
||||||
$vhosts_filename = FileDir::makeCorrectFile($vhosts_folder . '/05_froxlor_dirfix_nofcgid.conf');
|
|
||||||
|
|
||||||
if (!isset($this->virtualhosts_data[$vhosts_filename])) {
|
if (!isset($this->virtualhosts_data[$vhosts_filename])) {
|
||||||
$this->virtualhosts_data[$vhosts_filename] = '';
|
$this->virtualhosts_data[$vhosts_filename] = '';
|
||||||
@@ -545,7 +539,7 @@ class Apache extends HttpConfigBase
|
|||||||
}
|
}
|
||||||
$this->virtualhosts_data[$vhosts_filename] .= ' </Directory>' . "\n";
|
$this->virtualhosts_data[$vhosts_filename] .= ' </Directory>' . "\n";
|
||||||
|
|
||||||
$ocsp_cache_filename = FileDir::makeCorrectFile($vhosts_folder . '/03_froxlor_ocsp_cache.conf');
|
$ocsp_cache_filename = $this->getCustomVhostFilename('03_froxlor_ocsp_cache.conf');
|
||||||
if (Settings::Get('system.use_ssl') == '1' && Settings::Get('system.apache24') == 1) {
|
if (Settings::Get('system.use_ssl') == '1' && Settings::Get('system.apache24') == 1) {
|
||||||
$this->virtualhosts_data[$ocsp_cache_filename] = 'SSLStaplingCache ' . Settings::Get('system.apache24_ocsp_cache_path') . "\n";
|
$this->virtualhosts_data[$ocsp_cache_filename] = 'SSLStaplingCache ' . Settings::Get('system.apache24_ocsp_cache_path') . "\n";
|
||||||
} else {
|
} else {
|
||||||
@@ -562,14 +556,7 @@ class Apache extends HttpConfigBase
|
|||||||
private function createStandardErrorHandler()
|
private function createStandardErrorHandler()
|
||||||
{
|
{
|
||||||
if (Settings::Get('defaultwebsrverrhandler.enabled') == '1' && (Settings::Get('defaultwebsrverrhandler.err401') != '' || Settings::Get('defaultwebsrverrhandler.err403') != '' || Settings::Get('defaultwebsrverrhandler.err404') != '' || Settings::Get('defaultwebsrverrhandler.err500') != '')) {
|
if (Settings::Get('defaultwebsrverrhandler.enabled') == '1' && (Settings::Get('defaultwebsrverrhandler.err401') != '' || Settings::Get('defaultwebsrverrhandler.err403') != '' || Settings::Get('defaultwebsrverrhandler.err404') != '' || Settings::Get('defaultwebsrverrhandler.err500') != '')) {
|
||||||
$vhosts_folder = '';
|
$vhosts_filename = $this->getCustomVhostFilename('05_froxlor_default_errorhandler.conf');
|
||||||
if (is_dir(Settings::Get('system.apacheconf_vhost'))) {
|
|
||||||
$vhosts_folder = FileDir::makeCorrectDir(Settings::Get('system.apacheconf_vhost'));
|
|
||||||
} else {
|
|
||||||
$vhosts_folder = FileDir::makeCorrectDir(dirname(Settings::Get('system.apacheconf_vhost')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$vhosts_filename = FileDir::makeCorrectFile($vhosts_folder . '/05_froxlor_default_errorhandler.conf');
|
|
||||||
|
|
||||||
if (!isset($this->virtualhosts_data[$vhosts_filename])) {
|
if (!isset($this->virtualhosts_data[$vhosts_filename])) {
|
||||||
$this->virtualhosts_data[$vhosts_filename] = '';
|
$this->virtualhosts_data[$vhosts_filename] = '';
|
||||||
@@ -630,29 +617,6 @@ class Apache extends HttpConfigBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the filename for the virtualhost
|
|
||||||
*/
|
|
||||||
protected function getVhostFilename($domain, $ssl_vhost = false)
|
|
||||||
{
|
|
||||||
if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) {
|
|
||||||
$vhost_no = '35';
|
|
||||||
} elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) {
|
|
||||||
$vhost_no = '30';
|
|
||||||
} else {
|
|
||||||
// number of dots in a domain specifies it's position (and depth of subdomain) starting at 29 going downwards on higher depth
|
|
||||||
$vhost_no = (string)(30 - substr_count($domain['domain'], ".") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ssl_vhost === true) {
|
|
||||||
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_ssl_vhost_' . $domain['domain'] . '.conf');
|
|
||||||
} else {
|
|
||||||
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_normal_vhost_' . $domain['domain'] . '.conf');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $vhost_filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We compose the virtualhost entry for one domain
|
* We compose the virtualhost entry for one domain
|
||||||
*/
|
*/
|
||||||
@@ -1278,7 +1242,7 @@ class Apache extends HttpConfigBase
|
|||||||
// >=apache-2.4 enabled?
|
// >=apache-2.4 enabled?
|
||||||
if (Settings::Get('system.apache24') == '1') {
|
if (Settings::Get('system.apache24') == '1') {
|
||||||
$mypath_dir = new Directory($row_diroptions['path']);
|
$mypath_dir = new Directory($row_diroptions['path']);
|
||||||
// only create the require all granted if there is not active directory-protection
|
// only create the' require all granted' if there is no active directory-protection
|
||||||
// for this path, as this would be the first require and therefore grant all access
|
// for this path, as this would be the first require and therefore grant all access
|
||||||
if ($mypath_dir->isUserProtected() == false) {
|
if ($mypath_dir->isUserProtected() == false) {
|
||||||
$this->diroptions_data[$diroptions_filename] .= ' Require all granted' . "\n";
|
$this->diroptions_data[$diroptions_filename] .= ' Require all granted' . "\n";
|
||||||
|
|||||||
@@ -43,23 +43,29 @@ class DomainSSL
|
|||||||
* domain-array as reference so we can set the corresponding array-indices
|
* domain-array as reference so we can set the corresponding array-indices
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function setDomainSSLFilesArray(array &$domain = null)
|
public function setDomainSSLFilesArray(array &$domain = null)
|
||||||
{
|
{
|
||||||
// check if the domain itself has a certificate defined
|
// check if the domain itself has a certificate defined
|
||||||
$dom_certs_stmt = Database::prepare("
|
$dom_certs_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = :domid
|
SELECT s.*, d.domain
|
||||||
|
FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` s
|
||||||
|
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON d.id = s.domainid
|
||||||
|
WHERE s.`domainid` = :domid
|
||||||
");
|
");
|
||||||
$dom_certs = Database::pexecute_first($dom_certs_stmt, [
|
$dom_certs = Database::pexecute_first($dom_certs_stmt, [
|
||||||
'domid' => $domain['id']
|
'domid' => $domain['id']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$parent_certificate = false;
|
||||||
if (!is_array($dom_certs) || !isset($dom_certs['ssl_cert_file']) || $dom_certs['ssl_cert_file'] == '') {
|
if (!is_array($dom_certs) || !isset($dom_certs['ssl_cert_file']) || $dom_certs['ssl_cert_file'] == '') {
|
||||||
// maybe its parent?
|
// maybe its parent?
|
||||||
if (isset($domain['parentdomainid']) && $domain['parentdomainid'] != 0) {
|
if (isset($domain['parentdomainid']) && $domain['parentdomainid'] != 0) {
|
||||||
$dom_certs = Database::pexecute_first($dom_certs_stmt, [
|
$dom_certs = Database::pexecute_first($dom_certs_stmt, [
|
||||||
'domid' => $domain['parentdomainid']
|
'domid' => $domain['parentdomainid']
|
||||||
]);
|
]);
|
||||||
|
$parent_certificate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +79,8 @@ class DomainSSL
|
|||||||
}
|
}
|
||||||
// make correct files for the certificates
|
// make correct files for the certificates
|
||||||
$ssl_files = [
|
$ssl_files = [
|
||||||
'ssl_cert_file' => FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '.crt'),
|
'ssl_cert_file' => FileDir::makeCorrectFile($sslcertpath . '/' . ($parent_certificate ? $dom_certs['domain'] : $domain['domain']) . '.crt'),
|
||||||
'ssl_key_file' => FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '.key')
|
'ssl_key_file' => FileDir::makeCorrectFile($sslcertpath . '/' . ($parent_certificate ? $dom_certs['domain'] : $domain['domain']) . '.key')
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!$this->validateCertificate($dom_certs)) {
|
if (!$this->validateCertificate($dom_certs)) {
|
||||||
@@ -93,19 +99,19 @@ class DomainSSL
|
|||||||
$ssl_files['ssl_cert_chainfile'] = '';
|
$ssl_files['ssl_cert_chainfile'] = '';
|
||||||
// set them if they are != empty
|
// set them if they are != empty
|
||||||
if ($dom_certs['ssl_ca_file'] != '') {
|
if ($dom_certs['ssl_ca_file'] != '') {
|
||||||
$ssl_files['ssl_ca_file'] = FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '_CA.pem');
|
$ssl_files['ssl_ca_file'] = FileDir::makeCorrectFile($sslcertpath . '/' . ($parent_certificate ? $dom_certs['domain'] : $domain['domain']) . '_CA.pem');
|
||||||
}
|
}
|
||||||
if ($dom_certs['ssl_cert_chainfile'] != '') {
|
if ($dom_certs['ssl_cert_chainfile'] != '') {
|
||||||
if (Settings::Get('system.webserver') == 'nginx') {
|
if (Settings::Get('system.webserver') == 'nginx') {
|
||||||
// put ca.crt in my.crt, as nginx does not support a separate chain file.
|
// put ca.crt in my.crt, as nginx does not support a separate chain file.
|
||||||
$dom_certs['ssl_cert_file'] = trim($dom_certs['ssl_cert_file']) . "\n" . trim($dom_certs['ssl_cert_chainfile']) . "\n";
|
$dom_certs['ssl_cert_file'] = trim($dom_certs['ssl_cert_file']) . "\n" . trim($dom_certs['ssl_cert_chainfile']) . "\n";
|
||||||
} else {
|
} else {
|
||||||
$ssl_files['ssl_cert_chainfile'] = FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '_chain.pem');
|
$ssl_files['ssl_cert_chainfile'] = FileDir::makeCorrectFile($sslcertpath . '/' . ($parent_certificate ? $dom_certs['domain'] : $domain['domain']) . '_chain.pem');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// will only be generated to be used externally, froxlor does not need this
|
// will only be generated to be used externally, froxlor does not need this
|
||||||
if ($dom_certs['ssl_fullchain_file'] != '') {
|
if ($dom_certs['ssl_fullchain_file'] != '') {
|
||||||
$ssl_files['ssl_fullchain_file'] = FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '_fullchain.pem');
|
$ssl_files['ssl_fullchain_file'] = FileDir::makeCorrectFile($sslcertpath . '/' . ($parent_certificate ? $dom_certs['domain'] : $domain['domain']) . '_fullchain.pem');
|
||||||
}
|
}
|
||||||
// create them on the filesystem
|
// create them on the filesystem
|
||||||
foreach ($ssl_files as $type => $filename) {
|
foreach ($ssl_files as $type => $filename) {
|
||||||
@@ -131,7 +137,7 @@ class DomainSSL
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function validateCertificate($dom_certs = [])
|
private function validateCertificate($dom_certs = []): bool
|
||||||
{
|
{
|
||||||
return openssl_x509_check_private_key($dom_certs['ssl_cert_file'], $dom_certs['ssl_key_file']);
|
return openssl_x509_check_private_key($dom_certs['ssl_cert_file'], $dom_certs['ssl_key_file']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace Froxlor\Cron\Http;
|
|||||||
use Froxlor\Cron\Http\LetsEncrypt\AcmeSh;
|
use Froxlor\Cron\Http\LetsEncrypt\AcmeSh;
|
||||||
use Froxlor\Cron\Http\Php\Fpm;
|
use Froxlor\Cron\Http\Php\Fpm;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\Domain\Domain;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
@@ -187,4 +188,27 @@ class HttpConfigBase
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the filename for the virtualhost
|
||||||
|
*/
|
||||||
|
protected function getVhostFilename(array $domain, bool $ssl_vhost = false, bool $filename_only = false)
|
||||||
|
{
|
||||||
|
// number of dots in a domain specifies its position (and depth of subdomain) starting at 35 going downwards on higher depth
|
||||||
|
$vhost_no = (string)(35 - substr_count($domain['domain'], ".") + 1);
|
||||||
|
$filename = $vhost_no . '_froxlor_' . ($ssl_vhost ? 'ssl' : 'normal') . '_vhost_' . $domain['domain'] . '.conf';
|
||||||
|
if ($filename_only) {
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
return FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCustomVhostFilename(string $name)
|
||||||
|
{
|
||||||
|
$vhosts_folder = FileDir::makeCorrectDir(dirname(Settings::Get('system.apacheconf_vhost')));
|
||||||
|
if (is_dir(Settings::Get('system.apacheconf_vhost'))) {
|
||||||
|
$vhosts_folder = FileDir::makeCorrectDir(Settings::Get('system.apacheconf_vhost'));
|
||||||
|
}
|
||||||
|
return FileDir::makeCorrectFile($vhosts_folder . '/' . $name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
namespace Froxlor\Cron\Http\LetsEncrypt;
|
namespace Froxlor\Cron\Http\LetsEncrypt;
|
||||||
|
|
||||||
use Froxlor\Cron\FroxlorCron;
|
use Froxlor\Cron\FroxlorCron;
|
||||||
|
use Froxlor\Cron\TaskId;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Domain\Domain;
|
use Froxlor\Domain\Domain;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
@@ -83,7 +84,7 @@ class AcmeSh extends FroxlorCron
|
|||||||
$renew_domains = self::renewDomains(true);
|
$renew_domains = self::renewDomains(true);
|
||||||
if ($issue_froxlor || !empty($issue_domains) || !empty($renew_froxlor) || $renew_domains) {
|
if ($issue_froxlor || !empty($issue_domains) || !empty($renew_froxlor) || $renew_domains) {
|
||||||
// insert task to generate certificates and vhost-configs
|
// insert task to generate certificates and vhost-configs
|
||||||
Cronjob::inserttask(1);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -203,7 +204,7 @@ class AcmeSh extends FroxlorCron
|
|||||||
// 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) {
|
||||||
Cronjob::inserttask(1);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
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 {
|
||||||
@@ -556,6 +557,10 @@ EOC;
|
|||||||
Settings::Set('system.le_froxlor_enabled', 0);
|
Settings::Set('system.le_froxlor_enabled', 0);
|
||||||
}
|
}
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Let's Encrypt deactivated for domain " . $domain);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Let's Encrypt deactivated for domain " . $domain);
|
||||||
|
if (!defined('CRON_IS_FORCED') && !defined('CRON_DEBUG_FLAG')) {
|
||||||
|
// email info to admin that lets encrypt has been disabled for this domain
|
||||||
|
Cronjob::notifyMailToAdmin("Let's Encrypt has been deactivated for domain '" . $domain . "' due to failed dns validation (wrong or no IP address)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -586,13 +591,22 @@ EOC;
|
|||||||
$acmesh_cmd .= " --debug";
|
$acmesh_cmd .= " --debug";
|
||||||
}
|
}
|
||||||
|
|
||||||
$acme_result = FileDir::safe_exec($acmesh_cmd);
|
$exit_code = null;
|
||||||
|
$acme_result = FileDir::safe_exec($acmesh_cmd, $exit_code);
|
||||||
// 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));
|
||||||
|
|
||||||
|
if ($exit_code != 0) {
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, "Non-successful exit-code returned :(");
|
||||||
|
if (!defined('CRON_IS_FORCED') && !defined('CRON_DEBUG_FLAG')) {
|
||||||
|
Cronjob::notifyMailToAdmin("Let's Encrypt certificate could not be obtained for: " . implode(", ", $domains) . "\n\n" . implode("\n", $acme_result));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, "Successful exit-code returned - storing certificate");
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -336,24 +336,9 @@ class Lighttpd extends HttpConfigBase
|
|||||||
$_pos = strrpos($_tmp_path, '/');
|
$_pos = strrpos($_tmp_path, '/');
|
||||||
$_inc_path = substr($_tmp_path, $_pos + 1);
|
$_inc_path = substr($_tmp_path, $_pos + 1);
|
||||||
|
|
||||||
// maindomain
|
$filename = self::getVhostFilename($domain, ($ssl == '1'), true);
|
||||||
if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) {
|
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/vhosts/' . $filename);
|
||||||
$vhost_no = '50';
|
$included_vhosts[] = $_inc_path . '/vhosts/' . $filename;
|
||||||
} elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) {
|
|
||||||
// sub-but-main-domain
|
|
||||||
$vhost_no = '51';
|
|
||||||
} else {
|
|
||||||
// subdomains
|
|
||||||
// number of dots in a domain specifies it's position (and depth of subdomain) starting at 89 going downwards on higher depth
|
|
||||||
$vhost_no = (string)(90 - substr_count($domain['domain'], ".") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ssl == '1') {
|
|
||||||
$vhost_no = (int)$vhost_no += 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/vhosts/' . $vhost_no . '_' . $domain['domain'] . '.conf');
|
|
||||||
$included_vhosts[] = $_inc_path . '/vhosts/' . $vhost_no . '_' . $domain['domain'] . '.conf';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($this->lighttpd_data[$vhost_filename])) {
|
if (!isset($this->lighttpd_data[$vhost_filename])) {
|
||||||
|
|||||||
@@ -467,26 +467,6 @@ class Nginx extends HttpConfigBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getVhostFilename($domain, $ssl_vhost = false)
|
|
||||||
{
|
|
||||||
if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) {
|
|
||||||
$vhost_no = '35';
|
|
||||||
} elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) {
|
|
||||||
$vhost_no = '30';
|
|
||||||
} else {
|
|
||||||
// number of dots in a domain specifies it's position (and depth of subdomain) starting at 29 going downwards on higher depth
|
|
||||||
$vhost_no = (string)(30 - substr_count($domain['domain'], ".") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ssl_vhost === true) {
|
|
||||||
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_ssl_vhost_' . $domain['domain'] . '.conf');
|
|
||||||
} else {
|
|
||||||
$vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_normal_vhost_' . $domain['domain'] . '.conf');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $vhost_filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getVhostContent($domain, $ssl_vhost = false)
|
protected function getVhostContent($domain, $ssl_vhost = false)
|
||||||
{
|
{
|
||||||
if ($ssl_vhost === true && $domain['ssl'] != '1' && $domain['ssl_redirect'] != '1') {
|
if ($ssl_vhost === true && $domain['ssl'] != '1' && $domain['ssl_redirect'] != '1') {
|
||||||
@@ -883,7 +863,7 @@ class Nginx extends HttpConfigBase
|
|||||||
// remove comments
|
// remove comments
|
||||||
$vhost = implode("\n", preg_replace('/^(\s+)?#(.*)$/', '', explode("\n", $vhost)));
|
$vhost = implode("\n", preg_replace('/^(\s+)?#(.*)$/', '', explode("\n", $vhost)));
|
||||||
// Break blocks into lines
|
// Break blocks into lines
|
||||||
$vhost = preg_replace("/^(\s+)location(.+)\{(.+)\}$/misU", "location $2 {\n $3 \n}", $vhost);
|
$vhost = preg_replace("/^(\s+)?location(.+)\{(.+)\}$/misU", "location $2 {\n $3 \n}", $vhost);
|
||||||
// Break into array items
|
// Break into array items
|
||||||
$vhost = explode("\n", preg_replace('/[ \t]+/', ' ', trim(preg_replace('/\t+/', '', $vhost))));
|
$vhost = explode("\n", preg_replace('/[ \t]+/', ' ', trim(preg_replace('/\t+/', '', $vhost))));
|
||||||
// Remove empty lines
|
// Remove empty lines
|
||||||
@@ -1181,14 +1161,7 @@ class Nginx extends HttpConfigBase
|
|||||||
private function createStandardErrorHandler()
|
private function createStandardErrorHandler()
|
||||||
{
|
{
|
||||||
if (Settings::Get('defaultwebsrverrhandler.enabled') == '1' && (Settings::Get('defaultwebsrverrhandler.err401') != '' || Settings::Get('defaultwebsrverrhandler.err403') != '' || Settings::Get('defaultwebsrverrhandler.err404') != '' || Settings::Get('defaultwebsrverrhandler.err500') != '')) {
|
if (Settings::Get('defaultwebsrverrhandler.enabled') == '1' && (Settings::Get('defaultwebsrverrhandler.err401') != '' || Settings::Get('defaultwebsrverrhandler.err403') != '' || Settings::Get('defaultwebsrverrhandler.err404') != '' || Settings::Get('defaultwebsrverrhandler.err500') != '')) {
|
||||||
$vhosts_folder = '';
|
$vhosts_filename = $this->getCustomVhostFilename('05_froxlor_default_errorhandler.conf');
|
||||||
if (is_dir(Settings::Get('system.apacheconf_vhost'))) {
|
|
||||||
$vhosts_folder = FileDir::makeCorrectDir(Settings::Get('system.apacheconf_vhost'));
|
|
||||||
} else {
|
|
||||||
$vhosts_folder = FileDir::makeCorrectDir(dirname(Settings::Get('system.apacheconf_vhost')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$vhosts_filename = FileDir::makeCorrectFile($vhosts_folder . '/05_froxlor_default_errorhandler.conf');
|
|
||||||
|
|
||||||
if (!isset($this->nginx_data[$vhosts_filename])) {
|
if (!isset($this->nginx_data[$vhosts_filename])) {
|
||||||
$this->nginx_data[$vhosts_filename] = '';
|
$this->nginx_data[$vhosts_filename] = '';
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ pm.max_children = 1
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now check if 'sendmail_path' has not beed set in the custom-php.ini
|
// now check if 'sendmail_path' has not been set in the custom-php.ini
|
||||||
// if not we use our fallback-default as usual
|
// if not we use our fallback-default as usual
|
||||||
if (strpos($fpm_config, 'php_admin_value[sendmail_path]') === false) {
|
if (strpos($fpm_config, 'php_admin_value[sendmail_path]') === false) {
|
||||||
$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";
|
||||||
|
|||||||
@@ -25,70 +25,37 @@
|
|||||||
|
|
||||||
namespace Froxlor\Cron\System;
|
namespace Froxlor\Cron\System;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\Cron\Forkable;
|
||||||
use Froxlor\Cron\FroxlorCron;
|
use Froxlor\Cron\FroxlorCron;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
|
|
||||||
class BackupCron extends FroxlorCron
|
class ExportCron extends FroxlorCron
|
||||||
{
|
{
|
||||||
|
use Forkable;
|
||||||
|
|
||||||
public static function run()
|
public static function run()
|
||||||
{
|
{
|
||||||
// Check Traffic-Lock
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'ExportCron: started - creating customer data export');
|
||||||
if (function_exists('pcntl_fork')) {
|
|
||||||
$BackupLock = FileDir::makeCorrectFile(dirname(self::getLockfile()) . "/froxlor_cron_backup.lock");
|
|
||||||
if (file_exists($BackupLock) && is_numeric($BackupPid = file_get_contents($BackupLock))) {
|
|
||||||
if (function_exists('posix_kill')) {
|
|
||||||
$BackupPidStatus = @posix_kill($BackupPid, 0);
|
|
||||||
} else {
|
|
||||||
system("kill -CHLD " . $BackupPid . " 1> /dev/null 2> /dev/null", $BackupPidStatus);
|
|
||||||
$BackupPidStatus = !$BackupPidStatus;
|
|
||||||
}
|
|
||||||
if ($BackupPidStatus) {
|
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Backup run already in progress');
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Create Backup Log and Fork
|
|
||||||
// We close the database - connection before we fork, so we don't share resources with the child
|
|
||||||
Database::needRoot(false); // this forces the connection to be set to null
|
|
||||||
$BackupPid = pcntl_fork();
|
|
||||||
// Parent
|
|
||||||
if ($BackupPid) {
|
|
||||||
file_put_contents($BackupLock, $BackupPid);
|
|
||||||
// unnecessary to recreate database connection here
|
|
||||||
return 0;
|
|
||||||
} elseif ($BackupPid == 0) {
|
|
||||||
// Child
|
|
||||||
posix_setsid();
|
|
||||||
// re-create db
|
|
||||||
Database::needRoot(false);
|
|
||||||
} else {
|
|
||||||
// Fork failed
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (extension_loaded('pcntl')) {
|
|
||||||
$msg = "PHP compiled with pcntl but pcntl_fork function is not available.";
|
|
||||||
} else {
|
|
||||||
$msg = "PHP compiled without pcntl.";
|
|
||||||
}
|
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, $msg . " Not forking backup-cron, this may take a long time!");
|
|
||||||
}
|
|
||||||
|
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'BackupCron: started - creating customer backup');
|
|
||||||
|
|
||||||
$result_tasks_stmt = Database::query("
|
$result_tasks_stmt = Database::query("
|
||||||
SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20' ORDER BY `id` ASC
|
SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20' ORDER BY `id` ASC
|
||||||
");
|
");
|
||||||
|
|
||||||
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :id");
|
|
||||||
|
|
||||||
$cronlog = FroxlorLogger::getInstanceOf();
|
|
||||||
$all_jobs = $result_tasks_stmt->fetchAll();
|
$all_jobs = $result_tasks_stmt->fetchAll();
|
||||||
foreach ($all_jobs as $row) {
|
|
||||||
|
if (!empty($all_jobs)) {
|
||||||
|
self::runFork([self::class, 'handle'], $all_jobs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function handle(array $row)
|
||||||
|
{
|
||||||
|
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :id");
|
||||||
|
$cronlog = FroxlorLogger::getInstanceOf();
|
||||||
|
|
||||||
if ($row['data'] != '') {
|
if ($row['data'] != '') {
|
||||||
$row['data'] = json_decode($row['data'], true);
|
$row['data'] = json_decode($row['data'], true);
|
||||||
}
|
}
|
||||||
@@ -100,11 +67,11 @@ class BackupCron extends FroxlorCron
|
|||||||
|
|
||||||
// create folder if not exists
|
// create folder if not exists
|
||||||
if (!file_exists($row['data']['destdir']) && $row['data']['destdir'] != '/' && $row['data']['destdir'] != Settings::Get('system.documentroot_prefix') && $row['data']['destdir'] != $customerdocroot) {
|
if (!file_exists($row['data']['destdir']) && $row['data']['destdir'] != '/' && $row['data']['destdir'] != Settings::Get('system.documentroot_prefix') && $row['data']['destdir'] != $customerdocroot) {
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Creating backup-destination path for customer: ' . escapeshellarg($row['data']['destdir']));
|
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating data export destination path for customer: ' . escapeshellarg($row['data']['destdir']));
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg($row['data']['destdir']));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($row['data']['destdir']));
|
||||||
}
|
}
|
||||||
|
|
||||||
self::createCustomerBackup($row['data'], $customerdocroot, $cronlog);
|
self::createCustomerExport($row['data'], $customerdocroot, $cronlog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,33 +81,28 @@ class BackupCron extends FroxlorCron
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (function_exists('pcntl_fork')) {
|
|
||||||
@unlink($BackupLock);
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* depending on the give choice, the customers web-data, email-data and databases are being backup'ed
|
* depending on the give choice, the customers web-data, email-data and databases are being exported
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*
|
*
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private static function createCustomerBackup($data = null, $customerdocroot = null, &$cronlog = null)
|
private static function createCustomerExport($data = null, $customerdocroot = null, &$cronlog = null)
|
||||||
{
|
{
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating Backup for user "' . $data['loginname'] . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Creating data export for user "' . $data['loginname'] . '"');
|
||||||
|
|
||||||
// create tmp folder
|
// create tmp folder
|
||||||
$tmpdir = FileDir::makeCorrectDir($data['destdir'] . '/.tmp/');
|
$tmpdir = FileDir::makeCorrectDir($data['destdir'] . '/.tmp/');
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating tmp-folder "' . $tmpdir . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating tmp-folder "' . $tmpdir . '"');
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg($tmpdir));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg($tmpdir));
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
|
||||||
$create_backup_tar_data = "";
|
$create_export_tar_data = "";
|
||||||
|
|
||||||
// MySQL databases
|
// MySQL databases
|
||||||
if ($data['backup_dbs'] == 1) {
|
if ($data['dump_dbs'] == 1) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating mysql-folder "' . FileDir::makeCorrectDir($tmpdir . '/mysql') . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating mysql-folder "' . FileDir::makeCorrectDir($tmpdir . '/mysql') . '"');
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
|
||||||
@@ -152,7 +114,7 @@ class BackupCron extends FroxlorCron
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$has_dbs = false;
|
$has_dbs = false;
|
||||||
$current_dbserver = null;
|
$current_dbserver = -1;
|
||||||
while ($row = $sel_stmt->fetch()) {
|
while ($row = $sel_stmt->fetch()) {
|
||||||
// Get sql_root data for the specific database-server the database resides on
|
// Get sql_root data for the specific database-server the database resides on
|
||||||
if ($current_dbserver != $row['dbserver']) {
|
if ($current_dbserver != $row['dbserver']) {
|
||||||
@@ -180,16 +142,18 @@ class BackupCron extends FroxlorCron
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($has_dbs) {
|
if ($has_dbs) {
|
||||||
$create_backup_tar_data .= './mysql ';
|
$create_export_tar_data .= './mysql ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file_exists($mysqlcnf_file)) {
|
||||||
unlink($mysqlcnf_file);
|
unlink($mysqlcnf_file);
|
||||||
|
}
|
||||||
|
|
||||||
unset($sql_root);
|
unset($sql_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// E-mail data
|
// E-mail data
|
||||||
if ($data['backup_mail'] == 1) {
|
if ($data['dump_mail'] == 1) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating mail-folder "' . FileDir::makeCorrectDir($tmpdir . '/mail') . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating mail-folder "' . FileDir::makeCorrectDir($tmpdir . '/mail') . '"');
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mail')));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mail')));
|
||||||
|
|
||||||
@@ -209,28 +173,41 @@ class BackupCron extends FroxlorCron
|
|||||||
if (!empty($tar_file_list)) {
|
if (!empty($tar_file_list)) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfvz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfvz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
||||||
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
|
||||||
$create_backup_tar_data .= './mail ';
|
$create_export_tar_data .= './mail ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web data
|
// Web data
|
||||||
if ($data['backup_web'] == 1) {
|
if ($data['dump_web'] == 1) {
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating web-folder "' . FileDir::makeCorrectDir($tmpdir . '/web') . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating web-folder "' . FileDir::makeCorrectDir($tmpdir . '/web') . '"');
|
||||||
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/web')));
|
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/web')));
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(FileDir::makeCorrectDir($tmpdir), 0, -1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(FileDir::makeCorrectDir($tmpdir), 0, -1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
|
||||||
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(FileDir::makeCorrectFile($tmpdir), 0, -1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
|
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(FileDir::makeCorrectFile($tmpdir), 0, -1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
|
||||||
$create_backup_tar_data .= './web ';
|
$create_export_tar_data .= './web ';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($create_backup_tar_data)) {
|
if (!empty($create_export_tar_data)) {
|
||||||
$backup_file = FileDir::makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-backup_' . date('YmdHi', time()) . '.tar.gz');
|
// set owner to customer
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating backup-file "' . $backup_file . '"');
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> chown -R ' . (int)$data['uid'] . ':' . (int)$data['gid'] . ' ' . escapeshellarg($tmpdir));
|
||||||
// pack all archives in tmp-dir to one
|
FileDir::safe_exec('chown -R ' . (int)$data['uid'] . ':' . (int)$data['gid'] . ' ' . escapeshellarg($tmpdir));
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg($backup_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_backup_tar_data));
|
// create tar-file
|
||||||
FileDir::safe_exec('tar cfz ' . escapeshellarg($backup_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_backup_tar_data));
|
$export_file = FileDir::makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-export_' . date('YmdHi', time()) . '.tar.gz' . (!empty($data['pgp_public_key']) ? '.gpg' : ''));
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating export-file "' . $export_file . '"');
|
||||||
|
if (!empty($data['pgp_public_key'])) {
|
||||||
|
// pack all archives in tmp-dir to one archive and encrypt it with gpg
|
||||||
|
$recipient_file = FileDir::makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-recipients.gpg');
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating recipient-file "' . $recipient_file . '"');
|
||||||
|
file_put_contents($recipient_file, $data['pgp_public_key']);
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz - -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data) . ' | gpg --encrypt --recipient-file ' . escapeshellarg($recipient_file) . ' --output ' . escapeshellarg($export_file) . ' --trust-model always --batch --yes');
|
||||||
|
FileDir::safe_exec('tar cfz - -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data) . ' | gpg --encrypt --recipient-file ' . escapeshellarg($recipient_file) . ' --output ' . escapeshellarg($export_file) . ' --trust-model always --batch --yes', $return_value, ['|']);
|
||||||
|
} else {
|
||||||
|
// pack all archives in tmp-dir to one archive
|
||||||
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg($export_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data));
|
||||||
|
FileDir::safe_exec('tar cfz ' . escapeshellarg($export_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data));
|
||||||
|
}
|
||||||
// move to destination directory
|
// move to destination directory
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mv ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($data['destdir']));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mv ' . escapeshellarg($export_file) . ' ' . escapeshellarg($data['destdir']));
|
||||||
FileDir::safe_exec('mv ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($data['destdir']));
|
FileDir::safe_exec('mv ' . escapeshellarg($export_file) . ' ' . escapeshellarg($data['destdir']));
|
||||||
// remove tmp-files
|
// remove tmp-files
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> rm -rf ' . escapeshellarg($tmpdir));
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> rm -rf ' . escapeshellarg($tmpdir));
|
||||||
FileDir::safe_exec('rm -rf ' . escapeshellarg($tmpdir));
|
FileDir::safe_exec('rm -rf ' . escapeshellarg($tmpdir));
|
||||||
@@ -46,7 +46,7 @@ class TasksCron extends FroxlorCron
|
|||||||
* LOOK INTO TASKS TABLE TO SEE IF THERE ARE ANY UNDONE JOBS
|
* LOOK INTO TASKS TABLE TO SEE IF THERE ARE ANY UNDONE JOBS
|
||||||
*/
|
*/
|
||||||
self::$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "TasksCron: Searching for tasks to do");
|
self::$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "TasksCron: Searching for tasks to do");
|
||||||
// no type 99 (regenerate cron.d-file) and no type 20 (customer backup)
|
// no type 99 (regenerate cron.d-file) and no type 20 (customer data export)
|
||||||
// order by type descending to re-create bind and then webserver at the end
|
// order by type descending to re-create bind and then webserver at the end
|
||||||
$result_tasks_stmt = Database::query("
|
$result_tasks_stmt = Database::query("
|
||||||
SELECT `id`, `type`, `data` FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` <> '99' AND `type` <> '20' ORDER BY `type` DESC, `id` ASC
|
SELECT `id`, `type`, `data` FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` <> '99' AND `type` <> '20' ORDER BY `type` DESC, `id` ASC
|
||||||
|
|||||||
@@ -82,9 +82,9 @@ final class TaskId
|
|||||||
const DELETE_DOMAIN_SSL = 12;
|
const DELETE_DOMAIN_SSL = 12;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TYPE=20 COSTUMERBACKUP
|
* TYPE=20 CUSTUMER DATA DUMP
|
||||||
*/
|
*/
|
||||||
const CREATE_CUSTOMER_BACKUP = 20;
|
const CREATE_CUSTOMER_DATADUMP = 20;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TYPE=99 REGENERATE CRON
|
* TYPE=99 REGENERATE CRON
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace Froxlor\Cron\Traffic;
|
|||||||
* @author Froxlor team <team@froxlor.org> (2010-)
|
* @author Froxlor team <team@froxlor.org> (2010-)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Froxlor\Cron\Forkable;
|
||||||
use Froxlor\Cron\FroxlorCron;
|
use Froxlor\Cron\FroxlorCron;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
@@ -42,51 +43,15 @@ use PDO;
|
|||||||
|
|
||||||
class TrafficCron extends FroxlorCron
|
class TrafficCron extends FroxlorCron
|
||||||
{
|
{
|
||||||
|
use Forkable;
|
||||||
|
|
||||||
public static function run()
|
public static function run()
|
||||||
{
|
{
|
||||||
// Check Traffic-Lock
|
self::runFork([self::class, 'handle'], [true]);
|
||||||
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
|
|
||||||
$TrafficLock = FileDir::makeCorrectFile("/var/run/froxlor_cron_traffic.lock");
|
|
||||||
if (file_exists($TrafficLock) && is_numeric($TrafficPid = file_get_contents($TrafficLock))) {
|
|
||||||
if (function_exists('posix_kill')) {
|
|
||||||
$TrafficPidStatus = @posix_kill($TrafficPid, 0);
|
|
||||||
} else {
|
|
||||||
system("kill -CHLD " . $TrafficPid . " 1> /dev/null 2> /dev/null", $TrafficPidStatus);
|
|
||||||
$TrafficPidStatus = !$TrafficPidStatus;
|
|
||||||
}
|
|
||||||
if ($TrafficPidStatus) {
|
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Traffic Run already in progress');
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Create Traffic Log and Fork
|
|
||||||
// We close the database - connection before we fork, so we don't share resources with the child
|
|
||||||
Database::needRoot(false); // this forces the connection to be set to null
|
|
||||||
$TrafficPid = pcntl_fork();
|
|
||||||
// Parent
|
|
||||||
if ($TrafficPid) {
|
|
||||||
file_put_contents($TrafficLock, $TrafficPid);
|
|
||||||
// unnecessary to recreate database connection here
|
|
||||||
return 0;
|
|
||||||
} elseif ($TrafficPid == 0) {
|
|
||||||
// Child
|
|
||||||
posix_setsid();
|
|
||||||
// re-create db
|
|
||||||
Database::needRoot(false);
|
|
||||||
} else {
|
|
||||||
// Fork failed
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} elseif (!defined('CRON_NOFORK_FLAG')) {
|
|
||||||
if (extension_loaded('pcntl')) {
|
|
||||||
$msg = "PHP compiled with pcntl but pcntl_fork function is not available.";
|
|
||||||
} else {
|
|
||||||
$msg = "PHP compiled without pcntl.";
|
|
||||||
}
|
|
||||||
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, $msg . " Not forking traffic-cron, this may take a long time!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function handle()
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* TRAFFIC AND DISKUSAGE MEASURE
|
* TRAFFIC AND DISKUSAGE MEASURE
|
||||||
*/
|
*/
|
||||||
@@ -198,14 +163,14 @@ class TrafficCron extends FroxlorCron
|
|||||||
|
|
||||||
if (isset($domainlist[$row['customerid']]) && is_array($domainlist[$row['customerid']]) && count($domainlist[$row['customerid']]) != 0) {
|
if (isset($domainlist[$row['customerid']]) && is_array($domainlist[$row['customerid']]) && count($domainlist[$row['customerid']]) != 0) {
|
||||||
// Examining which caption to use for default webalizer stats...
|
// Examining which caption to use for default webalizer stats...
|
||||||
if ($row['standardsubdomain'] != '0') {
|
if ($row['standardsubdomain'] != '0' && isset($domainlist[$row['customerid']][$row['standardsubdomain']])) {
|
||||||
// ... of course we'd prefer to use the standardsubdomain ...
|
// ... of course we'd prefer to use the standardsubdomain ...
|
||||||
$caption = $domainlist[$row['customerid']][$row['standardsubdomain']];
|
$caption = $domainlist[$row['customerid']][$row['standardsubdomain']];
|
||||||
} else {
|
} else {
|
||||||
// ... but if there is no standardsubdomain, we have to use the loginname ...
|
// ... but if there is no standardsubdomain, we have to use the loginname ...
|
||||||
$caption = $row['loginname'];
|
$caption = $row['loginname'];
|
||||||
|
|
||||||
// ... which results in non-usable links to files in the stats, so lets have a look if we find a domain which is not speciallogfiledomain
|
// ... which results in non-usable links to files in the stats, so let's have a look if we find a domain which is not speciallogfiledomain
|
||||||
foreach ($domainlist[$row['customerid']] as $domainid => $domain) {
|
foreach ($domainlist[$row['customerid']] as $domainid => $domain) {
|
||||||
if (!isset($speciallogfile_domainlist[$row['customerid']]) || !isset($speciallogfile_domainlist[$row['customerid']][$domainid])) {
|
if (!isset($speciallogfile_domainlist[$row['customerid']]) || !isset($speciallogfile_domainlist[$row['customerid']][$domainid])) {
|
||||||
$caption = $domain;
|
$caption = $domain;
|
||||||
@@ -228,6 +193,8 @@ class TrafficCron extends FroxlorCron
|
|||||||
} else {
|
} else {
|
||||||
$httptraffic += floatval(self::callWebalizerGetTraffic($row['loginname'] . '-' . $domain, $row['documentroot'] . '/webalizer/' . $domain . '/', $domain, $domainlist[$row['customerid']]));
|
$httptraffic += floatval(self::callWebalizerGetTraffic($row['loginname'] . '-' . $domain, $row['documentroot'] . '/webalizer/' . $domain . '/', $domain, $domainlist[$row['customerid']]));
|
||||||
}
|
}
|
||||||
|
// kind of a keep-alive-call as this unsets the link which leads to a new connection to the database
|
||||||
|
Database::needRoot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,6 +212,8 @@ class TrafficCron extends FroxlorCron
|
|||||||
} else {
|
} else {
|
||||||
$httptraffic += floatval(self::callWebalizerGetTraffic($row['loginname'], $row['documentroot'] . '/webalizer/', $caption, $domainlist[$row['customerid']]));
|
$httptraffic += floatval(self::callWebalizerGetTraffic($row['loginname'], $row['documentroot'] . '/webalizer/', $caption, $domainlist[$row['customerid']]));
|
||||||
}
|
}
|
||||||
|
// kind of a keep-alive-call as this unsets the link which leads to a new connection to the database
|
||||||
|
Database::needRoot();
|
||||||
|
|
||||||
// make the stuff readable for the customer, #258
|
// make the stuff readable for the customer, #258
|
||||||
Statistics::makeChownWithNewStats($row);
|
Statistics::makeChownWithNewStats($row);
|
||||||
@@ -611,11 +580,6 @@ class TrafficCron extends FroxlorCron
|
|||||||
}
|
}
|
||||||
|
|
||||||
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = UNIX_TIMESTAMP() WHERE `settinggroup` = 'system' AND `varname` = 'last_traffic_run'");
|
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = UNIX_TIMESTAMP() WHERE `settinggroup` = 'system' AND `varname` = 'last_traffic_run'");
|
||||||
|
|
||||||
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
|
|
||||||
@unlink($TrafficLock);
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -658,7 +622,7 @@ class TrafficCron extends FroxlorCron
|
|||||||
$format = Settings::Get('system.logfiles_type') == '2' ? 'VCOMBINED' : 'COMBINED';
|
$format = Settings::Get('system.logfiles_type') == '2' ? 'VCOMBINED' : 'COMBINED';
|
||||||
$monthyear = $monthyear_arr['month'] . '/' . $monthyear_arr['year'];
|
$monthyear = $monthyear_arr['month'] . '/' . $monthyear_arr['year'];
|
||||||
$return_value = false;
|
$return_value = false;
|
||||||
FileDir::safe_exec("grep '" . $monthyear . "' " . escapeshellarg($logfile) . " | goaccess " . $keep_params . " --db-path=" . escapeshellarg($outputdir) . " -o " . escapeshellarg($outputdir . '.tmp.json') . " -o " . escapeshellarg($outputdir . 'index.html') . " --html-report-title=" . escapeshellarg($caption) . " --log-format=" . $format . " - ", $return_value, ['|']);
|
FileDir::safe_exec("grep '" . $monthyear . "' " . escapeshellarg($logfile) . " | goaccess " . $keep_params . " --db-path=" . escapeshellarg($outputdir) . " -o " . escapeshellarg($outputdir . '.tmp.json') . " -o " . escapeshellarg($outputdir . 'index.html') . " --html-report-title=" . escapeshellarg($caption) . " --log-format=" . $format . " --no-parsing-spinner --no-progress - ", $return_value, ['|']);
|
||||||
|
|
||||||
if (file_exists($outputdir . '.tmp.json')) {
|
if (file_exists($outputdir . '.tmp.json')) {
|
||||||
// need jq here because of potentially LARGE json files
|
// need jq here because of potentially LARGE json files
|
||||||
@@ -827,6 +791,8 @@ class TrafficCron extends FroxlorCron
|
|||||||
// 'real' domains and no subdomains which are aliases in the
|
// 'real' domains and no subdomains which are aliases in the
|
||||||
// model-config-file.
|
// model-config-file.
|
||||||
$returnval += self::awstatsDoSingleDomain($singledomain, $outputdir, $current_stamp);
|
$returnval += self::awstatsDoSingleDomain($singledomain, $outputdir, $current_stamp);
|
||||||
|
// kind of a keep-alive-call as this unsets the link which leads to a new connection to the database
|
||||||
|
Database::needRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,10 +25,13 @@
|
|||||||
|
|
||||||
namespace Froxlor;
|
namespace Froxlor;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
use Froxlor\Api\Commands\Customers;
|
use Froxlor\Api\Commands\Customers;
|
||||||
use Froxlor\Api\Commands\SubDomains;
|
use Froxlor\Api\Commands\SubDomains;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\UI\Collection;
|
use Froxlor\UI\Collection;
|
||||||
|
use Froxlor\UI\Response;
|
||||||
|
use RobThree\Auth\TwoFactorAuthException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to manage the current user / session
|
* Class to manage the current user / session
|
||||||
@@ -144,22 +147,95 @@ class CurrentUser
|
|||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT COUNT(`id`) as emaildomains
|
SELECT COUNT(`id`) as emaildomains
|
||||||
FROM `" . TABLE_PANEL_DOMAINS . "`
|
FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE `customerid`= :cid AND `isemaildomain` = '1'
|
WHERE `customerid`= :cid AND `isemaildomain` = '1' AND `deactivated` = '0'
|
||||||
");
|
");
|
||||||
$result = Database::pexecute_first($result_stmt, [
|
$result = Database::pexecute_first($result_stmt, [
|
||||||
"cid" => $_SESSION['userinfo']['customerid']
|
"cid" => $_SESSION['userinfo']['customerid']
|
||||||
]);
|
]);
|
||||||
$addition = $result['emaildomains'] != 0;
|
$addition = $result['emaildomains'] != 0;
|
||||||
} elseif ($resource == 'subdomains') {
|
} elseif ($resource == 'subdomains') {
|
||||||
$parentDomainCollection = (new Collection(SubDomains::class, $_SESSION['userinfo'],
|
if (Settings::IsInList('panel.customer_hide_options', 'domains')) {
|
||||||
['sql_search' => ['d.parentdomainid' => 0]]));
|
$addition = false;
|
||||||
|
} else {
|
||||||
|
$parentDomainCollection = (new Collection(
|
||||||
|
SubDomains::class,
|
||||||
|
$_SESSION['userinfo'],
|
||||||
|
['sql_search' => [
|
||||||
|
'd.parentdomainid' => 0,
|
||||||
|
'd.deactivated' => 0,
|
||||||
|
'd.id' => ['op' => '<>', 'value' => $_SESSION['userinfo']['standardsubdomain']]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
));
|
||||||
$addition = $parentDomainCollection->count() != 0;
|
$addition = $parentDomainCollection->count() != 0;
|
||||||
|
}
|
||||||
} elseif ($resource == 'domains') {
|
} elseif ($resource == 'domains') {
|
||||||
$customerCollection = (new Collection(Customers::class, $_SESSION['userinfo']));
|
$customerCollection = (new Collection(Customers::class, $_SESSION['userinfo']));
|
||||||
$addition = $customerCollection != 0;
|
$addition = $customerCollection->count() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($_SESSION['userinfo'][$resource . '_used'] < $_SESSION['userinfo'][$resource] || $_SESSION['userinfo'][$resource] == '-1') && $addition;
|
return ($_SESSION['userinfo'][$resource . '_used'] < $_SESSION['userinfo'][$resource] || $_SESSION['userinfo'][$resource] == '-1') && $addition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws TwoFactorAuthException
|
||||||
|
*/
|
||||||
|
public static function sendOtpEmail()
|
||||||
|
{
|
||||||
|
global $mail;
|
||||||
|
|
||||||
|
if (self::getField('type_2fa') == 1) {
|
||||||
|
// generate code
|
||||||
|
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
||||||
|
$secret = $tfa->createSecret();
|
||||||
|
$code = $tfa->getCode($secret);
|
||||||
|
// set code for user
|
||||||
|
$table = TABLE_PANEL_CUSTOMERS;
|
||||||
|
$uid = 'customerid';
|
||||||
|
if (self::isAdmin()) {
|
||||||
|
$table = TABLE_PANEL_ADMINS;
|
||||||
|
$uid = 'adminid';
|
||||||
|
}
|
||||||
|
$stmt = Database::prepare("UPDATE $table SET `data_2fa` = :d2fa WHERE `$uid` = :uid");
|
||||||
|
Database::pexecute($stmt, [
|
||||||
|
"d2fa" => $secret,
|
||||||
|
"uid" => self::getField($uid)
|
||||||
|
]);
|
||||||
|
// build up & send email
|
||||||
|
$_mailerror = false;
|
||||||
|
$mailerr_msg = "";
|
||||||
|
$replace_arr = [
|
||||||
|
'CODE' => $code
|
||||||
|
];
|
||||||
|
$mail_body = html_entity_decode(PhpHelper::replaceVariables(lng('mails.2fa.mailbody'), $replace_arr));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$mail->Subject = lng('mails.2fa.subject');
|
||||||
|
$mail->AltBody = $mail_body;
|
||||||
|
$mail->MsgHTML(str_replace("\n", "<br />", $mail_body));
|
||||||
|
$mail->AddAddress(self::getField('email'), User::getCorrectUserSalutation(self::getData()));
|
||||||
|
$mail->Send();
|
||||||
|
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
||||||
|
$mailerr_msg = $e->errorMessage();
|
||||||
|
$_mailerror = true;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$mailerr_msg = $e->getMessage();
|
||||||
|
$_mailerror = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_mailerror) {
|
||||||
|
$rstlog = FroxlorLogger::getInstanceOf([
|
||||||
|
'loginname' => '2fa code-sending'
|
||||||
|
]);
|
||||||
|
$rstlog->logAction(FroxlorLogger::ADM_ACTION, LOG_ERR, "Error sending mail: " . $mailerr_msg);
|
||||||
|
Response::redirectTo('index.php', [
|
||||||
|
'showmessage' => '4',
|
||||||
|
'customermail' => self::getField('email')
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$mail->ClearAddresses();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,51 +235,30 @@ class Domain
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check whether a domain has subdomains added as full-domains
|
* get ids of domains that are main domains but a subdomain of another main domain (for DNS)
|
||||||
* #329
|
|
||||||
*
|
*
|
||||||
* @param int $id domain-id
|
* @param int $id main-domain to check
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return array
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function domainHasMainSubDomains(int $id): bool
|
public static function getMainSubdomainIds(int $id): array
|
||||||
{
|
{
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT COUNT(`id`) as `mainsubs` FROM `" . TABLE_PANEL_DOMAINS . "`
|
SELECT id
|
||||||
WHERE `ismainbutsubto` = :id");
|
FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
$result = Database::pexecute_first($result_stmt, [
|
WHERE
|
||||||
'id' => $id
|
isbinddomain = 1 AND
|
||||||
]);
|
domain LIKE CONCAT('%.', ( SELECT d.domain FROM `" . TABLE_PANEL_DOMAINS . "` AS d WHERE d.id = :id ))
|
||||||
|
");
|
||||||
if ($result && isset($result['mainsubs'])) {
|
|
||||||
return $result['mainsubs'] > 0;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check whether a subof-domain exists
|
|
||||||
* #329
|
|
||||||
*
|
|
||||||
* @param int $id subof-domain-id
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public static function domainMainToSubExists(int $id): bool
|
|
||||||
{
|
|
||||||
$result_stmt = Database::prepare("
|
|
||||||
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `id` = :id");
|
|
||||||
Database::pexecute($result_stmt, [
|
Database::pexecute($result_stmt, [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
|
$result = [];
|
||||||
|
while ($entry = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
if ($result && isset($result['id'])) {
|
$result[] = $entry['id'];
|
||||||
return $result['id'] > 0;
|
|
||||||
}
|
}
|
||||||
return false;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -345,8 +324,11 @@ class Domain
|
|||||||
FroxlorLogger $log
|
FroxlorLogger $log
|
||||||
) {
|
) {
|
||||||
if ($aliasDestinationDomainID > 0) {
|
if ($aliasDestinationDomainID > 0) {
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO,
|
$log->logAction(
|
||||||
"LetsEncrypt CSR triggered for domain ID " . $aliasDestinationDomainID);
|
FroxlorLogger::ADM_ACTION,
|
||||||
|
LOG_INFO,
|
||||||
|
"LetsEncrypt CSR triggered for domain ID " . $aliasDestinationDomainID
|
||||||
|
);
|
||||||
$upd_stmt = Database::prepare("UPDATE
|
$upd_stmt = Database::prepare("UPDATE
|
||||||
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
||||||
SET
|
SET
|
||||||
@@ -370,15 +352,20 @@ class Domain
|
|||||||
$acmesh = AcmeSh::getAcmeSh();
|
$acmesh = AcmeSh::getAcmeSh();
|
||||||
if (file_exists($acmesh)) {
|
if (file_exists($acmesh)) {
|
||||||
$certificate_folder = AcmeSh::getWorkingDirFromEnv($domainname);
|
$certificate_folder = AcmeSh::getWorkingDirFromEnv($domainname);
|
||||||
if (file_exists($certificate_folder)) {
|
$certificate_ecc_folder = AcmeSh::getWorkingDirFromEnv($domainname, true);
|
||||||
|
if (file_exists($certificate_folder) || file_exists($certificate_ecc_folder)) {
|
||||||
$params = " --remove -d " . $domainname;
|
$params = " --remove -d " . $domainname;
|
||||||
if (Settings::Get('system.leecc') > 0) {
|
if (file_exists($certificate_ecc_folder)) {
|
||||||
$params .= " --ecc";
|
$params .= " --ecc";
|
||||||
}
|
}
|
||||||
// run remove command
|
// run remove command
|
||||||
FileDir::safe_exec($acmesh . $params);
|
FileDir::safe_exec($acmesh . $params);
|
||||||
// remove certificates directory
|
// remove certificates directory
|
||||||
|
if (file_exists($certificate_folder)) {
|
||||||
FileDir::safe_exec('rm -rf ' . $certificate_folder);
|
FileDir::safe_exec('rm -rf ' . $certificate_folder);
|
||||||
|
} elseif (file_exists($certificate_ecc_folder)) {
|
||||||
|
FileDir::safe_exec('rm -rf ' . $certificate_ecc_folder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -43,9 +43,6 @@ class IpAddr
|
|||||||
|
|
||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
if (!isset($system_ipaddress_array[$row['ip']]) && !in_array($row['ip'], $system_ipaddress_array)) {
|
if (!isset($system_ipaddress_array[$row['ip']]) && !in_array($row['ip'], $system_ipaddress_array)) {
|
||||||
if (filter_var($row['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
|
||||||
$row['ip'] = '[' . $row['ip'] . ']';
|
|
||||||
}
|
|
||||||
$system_ipaddress_array[$row['ip']] = $row['ip'];
|
$system_ipaddress_array[$row['ip']] = $row['ip'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,10 @@
|
|||||||
namespace Froxlor;
|
namespace Froxlor;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use PDO;
|
|
||||||
use RecursiveCallbackFilterIterator;
|
|
||||||
use Froxlor\Customer\Customer;
|
use Froxlor\Customer\Customer;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
|
use PDO;
|
||||||
|
use RecursiveCallbackFilterIterator;
|
||||||
|
|
||||||
class FileDir
|
class FileDir
|
||||||
{
|
{
|
||||||
@@ -55,7 +55,8 @@ class FileDir
|
|||||||
int $gid,
|
int $gid,
|
||||||
bool $placeindex = false,
|
bool $placeindex = false,
|
||||||
bool $allow_notwithinhomedir = false
|
bool $allow_notwithinhomedir = false
|
||||||
): bool {
|
): bool
|
||||||
|
{
|
||||||
if ($homeDir != '' && $dirToCreate != '') {
|
if ($homeDir != '' && $dirToCreate != '') {
|
||||||
$homeDir = self::makeCorrectDir($homeDir);
|
$homeDir = self::makeCorrectDir($homeDir);
|
||||||
$dirToCreate = self::makeCorrectDir($dirToCreate);
|
$dirToCreate = self::makeCorrectDir($dirToCreate);
|
||||||
@@ -107,15 +108,16 @@ class FileDir
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function which returns a correct dirname, means to add slashes at the beginning and at the end if there weren't
|
* Returns a correct/secure dirname, means to add slashes at the beginning and at the end if there weren't
|
||||||
* some
|
* some. If $fixes_homedir is specified,
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* @param string $dir the path to correct
|
* @param string $dir the path to correct
|
||||||
*
|
*
|
||||||
* @return string the corrected path
|
* @return string the corrected path
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function makeCorrectDir(string $dir): string
|
public static function makeCorrectDir(string $dir, string $fixed_homedir = ""): string
|
||||||
{
|
{
|
||||||
if (strlen($dir) > 0) {
|
if (strlen($dir) > 0) {
|
||||||
$dir = trim($dir);
|
$dir = trim($dir);
|
||||||
@@ -125,6 +127,30 @@ class FileDir
|
|||||||
if (substr($dir, 0, 1) != '/') {
|
if (substr($dir, 0, 1) != '/') {
|
||||||
$dir = '/' . $dir;
|
$dir = '/' . $dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if given, check that the target path is within the $fixed_homedir
|
||||||
|
// by checking each folder for being a symlink and whether it targets
|
||||||
|
// the customers homedir or points outside of it
|
||||||
|
if (!empty($fixed_homedir)) {
|
||||||
|
$to_check = explode("/", substr($dir, strlen($fixed_homedir) + 1), -1);
|
||||||
|
$check_dir = substr($fixed_homedir, 0, -1);
|
||||||
|
// Symlink check
|
||||||
|
foreach ($to_check as $sub_dir) {
|
||||||
|
$check_dir .= '/' . $sub_dir;
|
||||||
|
if (is_link($check_dir)) {
|
||||||
|
$original_target = $check_dir;
|
||||||
|
$check_dir = readlink($check_dir);
|
||||||
|
if (substr($check_dir, 0, strlen($fixed_homedir)) != $fixed_homedir) {
|
||||||
|
throw new Exception("Found symlink pointing outside of customer home directory: " . substr($original_target, strlen($fixed_homedir)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check for the path to be within the given homedir
|
||||||
|
if (substr($dir, 0, strlen($fixed_homedir)) != $fixed_homedir) {
|
||||||
|
throw new Exception("Target path not within the required customer home directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return self::makeSecurePath($dir);
|
return self::makeSecurePath($dir);
|
||||||
}
|
}
|
||||||
throw new Exception("Cannot validate directory in " . __FUNCTION__ . " which is very dangerous.");
|
throw new Exception("Cannot validate directory in " . __FUNCTION__ . " which is very dangerous.");
|
||||||
@@ -219,7 +245,7 @@ class FileDir
|
|||||||
}
|
}
|
||||||
|
|
||||||
// execute the command and return output
|
// execute the command and return output
|
||||||
$return = '';
|
$return = [];
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
if ($return_value == false) {
|
if ($return_value == false) {
|
||||||
@@ -231,6 +257,41 @@ class FileDir
|
|||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read unconfigured-domain template from database if exists or fallback to default
|
||||||
|
*
|
||||||
|
* @param string $servername
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function getUnknownDomainTemplate(string $servername = "")
|
||||||
|
{
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT * FROM `" . TABLE_PANEL_TEMPLATES . "` WHERE `templategroup` = 'files' AND `varname` = 'unconfigured_html'
|
||||||
|
");
|
||||||
|
Database::pexecute($result_stmt);
|
||||||
|
if (Database::num_rows() > 0) {
|
||||||
|
$template = $result_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$replace_arr = [
|
||||||
|
'SERVERNAME' => $servername,
|
||||||
|
];
|
||||||
|
$tpl_content = PhpHelper::replaceVariables($template['value'], $replace_arr);
|
||||||
|
$tpl_ext = $template['file_extension'];
|
||||||
|
} else {
|
||||||
|
$tpl_ext = 'html';
|
||||||
|
$unconfiguredPath = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/templates/misc/unconfigured/index.html');
|
||||||
|
if (file_exists($unconfiguredPath)) {
|
||||||
|
$tpl_content = file_get_contents($unconfiguredPath);
|
||||||
|
} else {
|
||||||
|
$tpl_content = lng('admin.templates.unconfigured_content_fallback');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$redirect_file = FileDir::makeCorrectFile(Froxlor::getInstallDir().'/notice.'.$tpl_ext);
|
||||||
|
file_put_contents($redirect_file, $tpl_content);
|
||||||
|
return basename($redirect_file);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* store the default index-file in a given destination folder
|
* store the default index-file in a given destination folder
|
||||||
*
|
*
|
||||||
@@ -247,10 +308,11 @@ class FileDir
|
|||||||
string $destination,
|
string $destination,
|
||||||
$logger = null,
|
$logger = null,
|
||||||
bool $force = false
|
bool $force = false
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
if ($force || (int)Settings::Get('system.store_index_file_subs') == 1) {
|
if ($force || (int)Settings::Get('system.store_index_file_subs') == 1) {
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT `t`.`value`, `c`.`email` AS `customer_email`, `a`.`email` AS `admin_email`, `c`.`loginname` AS `customer_login`, `a`.`loginname` AS `admin_login`
|
SELECT `t`.`value`, `t`.`file_extension`, `c`.`email` AS `customer_email`, `a`.`email` AS `admin_email`, `c`.`loginname` AS `customer_login`, `a`.`loginname` AS `admin_login`
|
||||||
FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c` INNER JOIN `" . TABLE_PANEL_ADMINS . "` AS `a`
|
FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c` INNER JOIN `" . TABLE_PANEL_ADMINS . "` AS `a`
|
||||||
ON `c`.`adminid` = `a`.`adminid`
|
ON `c`.`adminid` = `a`.`adminid`
|
||||||
INNER JOIN `" . TABLE_PANEL_TEMPLATES . "` AS `t`
|
INNER JOIN `" . TABLE_PANEL_TEMPLATES . "` AS `t`
|
||||||
@@ -273,7 +335,7 @@ class FileDir
|
|||||||
|
|
||||||
// replaceVariables
|
// replaceVariables
|
||||||
$htmlcontent = PhpHelper::replaceVariables($template['value'], $replace_arr);
|
$htmlcontent = PhpHelper::replaceVariables($template['value'], $replace_arr);
|
||||||
$indexhtmlpath = self::makeCorrectFile($destination . '/index.' . Settings::Get('system.index_file_extension'));
|
$indexhtmlpath = self::makeCorrectFile($destination . '/index.' . $template['file_extension']);
|
||||||
$index_html_handler = fopen($indexhtmlpath, 'w');
|
$index_html_handler = fopen($indexhtmlpath, 'w');
|
||||||
fwrite($index_html_handler, $htmlcontent);
|
fwrite($index_html_handler, $htmlcontent);
|
||||||
fclose($index_html_handler);
|
fclose($index_html_handler);
|
||||||
@@ -281,7 +343,7 @@ class FileDir
|
|||||||
$logger->logAction(
|
$logger->logAction(
|
||||||
FroxlorLogger::CRON_ACTION,
|
FroxlorLogger::CRON_ACTION,
|
||||||
LOG_NOTICE,
|
LOG_NOTICE,
|
||||||
'Creating \'index.' . Settings::Get('system.index_file_extension') . '\' for Customer \'' . $template['customer_login'] . '\' based on template in directory ' . escapeshellarg($indexhtmlpath)
|
'Creating \'index.' . $template['file_extension'] . '\' for Customer \'' . $template['customer_login'] . '\' based on template in directory ' . escapeshellarg($indexhtmlpath)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -31,14 +31,16 @@ final class Froxlor
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Main version variable
|
// Main version variable
|
||||||
const VERSION = '2.0.23';
|
const VERSION = '2.1.4';
|
||||||
|
|
||||||
// Database version (YYYYMMDDC where C is a daily counter)
|
// Database version (YYYYMMDDC where C is a daily counter)
|
||||||
const DBVERSION = '202304260';
|
const DBVERSION = '202312120';
|
||||||
|
|
||||||
// Distribution branding-tag (used for Debian etc.)
|
// Distribution branding-tag (used for Debian etc.)
|
||||||
const BRANDING = '';
|
const BRANDING = '';
|
||||||
|
|
||||||
|
const DOCS_URL = 'https://docs.froxlor.org/v2.1/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return path to where froxlor is installed, e.g.
|
* return path to where froxlor is installed, e.g.
|
||||||
* /var/www/froxlor/
|
* /var/www/froxlor/
|
||||||
|
|||||||
@@ -104,18 +104,16 @@ class FroxlorLogger
|
|||||||
self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG));
|
self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG));
|
||||||
break;
|
break;
|
||||||
case 'file':
|
case 'file':
|
||||||
|
$setings_logfile = Settings::Get('logger.logfile');
|
||||||
|
if (empty($setings_logfile)) {
|
||||||
|
Settings::Set('logger.logfile', 'froxlor.log');
|
||||||
|
}
|
||||||
$logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/' . Settings::Get('logger.logfile'));
|
$logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/' . Settings::Get('logger.logfile'));
|
||||||
// is_writable needs an existing file to check if it's actually writable
|
// is_writable needs an existing file to check if it's actually writable
|
||||||
@touch($logger_logfile);
|
if (!@touch($logger_logfile) || !is_writable($logger_logfile)) {
|
||||||
if (empty($logger_logfile) || !is_writable($logger_logfile)) {
|
|
||||||
Settings::Set('logger.logfile', 'froxlor.log');
|
|
||||||
$logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/froxlor.log');
|
|
||||||
@touch($logger_logfile);
|
|
||||||
if (empty($logger_logfile) || !is_writable($logger_logfile)) {
|
|
||||||
// not writable in our own directory? Skip
|
// not writable in our own directory? Skip
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self::$ml->pushHandler(new StreamHandler($logger_logfile, Logger::DEBUG));
|
self::$ml->pushHandler(new StreamHandler($logger_logfile, Logger::DEBUG));
|
||||||
break;
|
break;
|
||||||
case 'mysql':
|
case 'mysql':
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class IdnaWrapper
|
|||||||
*/
|
*/
|
||||||
public function encode(string $to_encode): string
|
public function encode(string $to_encode): string
|
||||||
{
|
{
|
||||||
$to_encode = $this->isUtf8($to_encode) ? $to_encode : utf8_encode($to_encode);
|
$to_encode = $this->isUtf8($to_encode) ? $to_encode : mb_convert_encoding($to_encode, 'UTF-8');
|
||||||
try {
|
try {
|
||||||
return $this->idna_converter->encode($to_encode);
|
return $this->idna_converter->encode($to_encode);
|
||||||
} catch (InvalidArgumentException $iae) {
|
} catch (InvalidArgumentException $iae) {
|
||||||
|
|||||||
@@ -68,6 +68,12 @@ class AutoUpdate
|
|||||||
$channel = '';
|
$channel = '';
|
||||||
if (Settings::Get('system.update_channel') == 'testing') {
|
if (Settings::Get('system.update_channel') == 'testing') {
|
||||||
$channel = '/testing';
|
$channel = '/testing';
|
||||||
|
} elseif (Settings::Get('system.update_channel') == 'nightly') {
|
||||||
|
if (empty(Froxlor::BRANDING)) {
|
||||||
|
$channel = '/nightly.0000000';
|
||||||
|
} else {
|
||||||
|
$channel = '/' . substr(Froxlor::BRANDING, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$latestversion = HttpClient::urlGet(self::UPDATE_URI . Froxlor::VERSION . $channel, true, 3);
|
$latestversion = HttpClient::urlGet(self::UPDATE_URI . Froxlor::VERSION . $channel, true, 3);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
@@ -81,7 +87,7 @@ class AutoUpdate
|
|||||||
if (!empty(self::$latestversion['error']) && self::$latestversion['error']) {
|
if (!empty(self::$latestversion['error']) && self::$latestversion['error']) {
|
||||||
$result = -1;
|
$result = -1;
|
||||||
self::$lasterror = self::$latestversion['message'];
|
self::$lasterror = self::$latestversion['message'];
|
||||||
} else if (isset(self::$latestversion['has_latest']) && self::$latestversion['has_latest'] == false) {
|
} elseif (isset(self::$latestversion['has_latest']) && self::$latestversion['has_latest'] == false) {
|
||||||
$result = 1;
|
$result = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,6 +151,8 @@ class AutoUpdate
|
|||||||
$zip->close();
|
$zip->close();
|
||||||
// success - remove unused archive
|
// success - remove unused archive
|
||||||
@unlink($localArchive);
|
@unlink($localArchive);
|
||||||
|
// reset cached version check
|
||||||
|
Settings::Set('system.updatecheck_data', '');
|
||||||
// wait a bit before we redirect to be sure
|
// wait a bit before we redirect to be sure
|
||||||
sleep(3);
|
sleep(3);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -26,13 +26,14 @@
|
|||||||
namespace Froxlor\Install;
|
namespace Froxlor\Install;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use PDO;
|
use Froxlor\Config\ConfigParser;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Install\Install\Core;
|
use Froxlor\Install\Install\Core;
|
||||||
|
use Froxlor\System\IPTools;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\Config\ConfigParser;
|
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use Froxlor\System\IPTools;
|
use PDO;
|
||||||
|
|
||||||
class Install
|
class Install
|
||||||
{
|
{
|
||||||
@@ -41,25 +42,27 @@ class Install
|
|||||||
public $maxSteps;
|
public $maxSteps;
|
||||||
public $phpVersion;
|
public $phpVersion;
|
||||||
public $formfield;
|
public $formfield;
|
||||||
public string $requiredVersion = '7.4.0';
|
|
||||||
public array $requiredExtensions = ['session', 'ctype', 'xml', 'filter', 'posix', 'mbstring', 'curl', 'gmp', 'json', 'gd'];
|
|
||||||
public array $suggestedExtensions = ['bcmath', 'zip'];
|
|
||||||
public array $suggestions = [];
|
public array $suggestions = [];
|
||||||
public array $criticals = [];
|
public array $criticals = [];
|
||||||
public array $loadedExtensions;
|
public array $loadedExtensions;
|
||||||
public array $supportedOS = [];
|
public array $supportedOS = [];
|
||||||
public array $webserverBackend = [
|
public array $webserverBackend = [
|
||||||
'php-fpm' => 'PHP-FPM',
|
'php-fpm' => 'PHP-FPM',
|
||||||
'fcgid' => 'FCGID',
|
'fcgid' => 'FCGID (apache2 only)',
|
||||||
'mod_php' => 'mod_php (not recommended)',
|
'mod_php' => 'mod_php (not recommended)',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(array $cliData = [])
|
public function __construct(array $cliData = [])
|
||||||
{
|
{
|
||||||
|
// set actual php version and extensions
|
||||||
|
$this->phpVersion = phpversion();
|
||||||
|
$this->loadedExtensions = get_loaded_extensions();
|
||||||
|
|
||||||
// get all supported OS
|
// get all supported OS
|
||||||
// show list of available distro's
|
// show list of available distro's
|
||||||
$distros = glob(dirname(__DIR__, 3) . '/lib/configfiles/*.xml');
|
$distros = glob(dirname(__DIR__, 3) . '/lib/configfiles/*.xml');
|
||||||
$distributions_select[''] = '-';
|
$distributions_select[''] = '-';
|
||||||
|
if (in_array('xml', $this->loadedExtensions)) {
|
||||||
// read in all the distros
|
// read in all the distros
|
||||||
foreach ($distros as $distribution) {
|
foreach ($distros as $distribution) {
|
||||||
// get configparser object
|
// get configparser object
|
||||||
@@ -69,6 +72,7 @@ class Install
|
|||||||
}
|
}
|
||||||
// sort by distribution name
|
// sort by distribution name
|
||||||
asort($this->supportedOS);
|
asort($this->supportedOS);
|
||||||
|
}
|
||||||
|
|
||||||
// guess distribution and webserver to preselect in formfield
|
// guess distribution and webserver to preselect in formfield
|
||||||
$webserverBackend = $this->webserverBackend;
|
$webserverBackend = $this->webserverBackend;
|
||||||
@@ -84,10 +88,6 @@ class Install
|
|||||||
$this->extendedView = $cliData['extended'] ?? Request::any('extended', 0);
|
$this->extendedView = $cliData['extended'] ?? Request::any('extended', 0);
|
||||||
$this->maxSteps = count($this->formfield['install']['sections']);
|
$this->maxSteps = count($this->formfield['install']['sections']);
|
||||||
|
|
||||||
// set actual php version and extensions
|
|
||||||
$this->phpVersion = phpversion();
|
|
||||||
$this->loadedExtensions = get_loaded_extensions();
|
|
||||||
|
|
||||||
if (empty($cliData)) {
|
if (empty($cliData)) {
|
||||||
// set global variables
|
// set global variables
|
||||||
UI::twig()->addGlobal('install_mode', true);
|
UI::twig()->addGlobal('install_mode', true);
|
||||||
@@ -99,7 +99,7 @@ class Install
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for url manipulation or wrong step
|
// check for url manipulation or wrong step
|
||||||
if ((isset($_SESSION['installation']['stepCompleted']) && ($this->currentStep + 1) > ($_SESSION['installation']['stepCompleted'] ?? 0))
|
if ((isset($_SESSION['installation']['stepCompleted']) && $this->currentStep > $_SESSION['installation']['stepCompleted'])
|
||||||
|| (!isset($_SESSION['installation']['stepCompleted']) && $this->currentStep > 0)
|
|| (!isset($_SESSION['installation']['stepCompleted']) && $this->currentStep > 0)
|
||||||
) {
|
) {
|
||||||
$this->currentStep = isset($_SESSION['installation']['stepCompleted']) ? $_SESSION['installation']['stepCompleted'] + 1 : 1;
|
$this->currentStep = isset($_SESSION['installation']['stepCompleted']) ? $_SESSION['installation']['stepCompleted'] + 1 : 1;
|
||||||
@@ -136,6 +136,7 @@ class Install
|
|||||||
'section' => $this->formfield['install']['sections']['step' . $this->currentStep] ?? [],
|
'section' => $this->formfield['install']['sections']['step' . $this->currentStep] ?? [],
|
||||||
'error' => $error ?? null,
|
'error' => $error ?? null,
|
||||||
'extended' => $this->extendedView,
|
'extended' => $this->extendedView,
|
||||||
|
'csrf_token' => Froxlor::genSessionId(20),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// output view
|
// output view
|
||||||
@@ -151,16 +152,14 @@ class Install
|
|||||||
if ($this->currentStep <= $this->maxSteps) {
|
if ($this->currentStep <= $this->maxSteps) {
|
||||||
// Validate user data
|
// Validate user data
|
||||||
$validatedData = $this->validateRequest($formfield['sections']['step' . $this->currentStep]['fields']);
|
$validatedData = $this->validateRequest($formfield['sections']['step' . $this->currentStep]['fields']);
|
||||||
// Check database connection (
|
|
||||||
if ($this->currentStep == 1) {
|
if ($this->currentStep == 1) {
|
||||||
|
// Check database connection
|
||||||
$this->checkDatabase($validatedData);
|
$this->checkDatabase($validatedData);
|
||||||
}
|
} elseif ($this->currentStep == 2) {
|
||||||
// Check validity of admin user data
|
// Check validity of admin user data
|
||||||
elseif ($this->currentStep == 2) {
|
|
||||||
$this->checkAdminUser($validatedData);
|
$this->checkAdminUser($validatedData);
|
||||||
}
|
} elseif ($this->currentStep == 3) {
|
||||||
// Check validity of system data
|
// Check validity of system data
|
||||||
elseif ($this->currentStep == 3) {
|
|
||||||
$this->checkSystem($validatedData);
|
$this->checkSystem($validatedData);
|
||||||
}
|
}
|
||||||
$validatedData['stepCompleted'] = ($this->currentStep < $this->maxSteps) ? $this->currentStep : ($this->maxSteps - 1);
|
$validatedData['stepCompleted'] = ($this->currentStep < $this->maxSteps) ? $this->currentStep : ($this->maxSteps - 1);
|
||||||
@@ -192,7 +191,7 @@ class Install
|
|||||||
private function checkInstallStateFinished(): bool
|
private function checkInstallStateFinished(): bool
|
||||||
{
|
{
|
||||||
$core = new Core($_SESSION['installation']);
|
$core = new Core($_SESSION['installation']);
|
||||||
if (isset($_SESSION['installation']['manual_config']) && (int) $_SESSION['installation']['manual_config'] == 1) {
|
if (isset($_SESSION['installation']['manual_config']) && (int)$_SESSION['installation']['manual_config'] == 1) {
|
||||||
$core->createUserdataConf();
|
$core->createUserdataConf();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -200,7 +199,7 @@ class Install
|
|||||||
$stmt = $pdo->prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'panel' AND `varname` = 'is_configured'");
|
$stmt = $pdo->prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'panel' AND `varname` = 'is_configured'");
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
if ($result && (int) $result['value'] == 1) {
|
if ($result && (int)$result['value'] == 1) {
|
||||||
$core->createUserdataConf();
|
$core->createUserdataConf();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -223,7 +222,7 @@ class Install
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for required extensions
|
// check for required extensions
|
||||||
foreach ($this->requiredExtensions as $requiredExtension) {
|
foreach (Requirements::REQUIRED_EXTENSIONS as $requiredExtension) {
|
||||||
if (in_array($requiredExtension, $this->loadedExtensions)) {
|
if (in_array($requiredExtension, $this->loadedExtensions)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -231,7 +230,7 @@ class Install
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for suggested extensions
|
// check for suggested extensions
|
||||||
foreach ($this->suggestedExtensions as $suggestedExtension) {
|
foreach (Requirements::SUGGESTED_EXTENSIONS as $suggestedExtension) {
|
||||||
if (in_array($suggestedExtension, $this->loadedExtensions)) {
|
if (in_array($suggestedExtension, $this->loadedExtensions)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -250,11 +249,11 @@ class Install
|
|||||||
*/
|
*/
|
||||||
private function getInformationText(): string
|
private function getInformationText(): string
|
||||||
{
|
{
|
||||||
if (version_compare($this->requiredVersion, PHP_VERSION, "<")) {
|
if (version_compare(Requirements::REQUIRED_VERSION, PHP_VERSION, "<")) {
|
||||||
$text = lng('install.phpinfosuccess', [$this->phpVersion]);
|
$text = lng('install.phpinfosuccess', [$this->phpVersion]);
|
||||||
} else {
|
} else {
|
||||||
$text = lng('install.phpinfowarn', [$this->requiredVersion]);
|
$text = lng('install.phpinfowarn', [Requirements::REQUIRED_VERSION]);
|
||||||
$this->criticals[] = lng('install.phpinfoupdate', [$this->phpVersion, $this->requiredVersion]);
|
$this->criticals[] = lng('install.phpinfoupdate', [$this->phpVersion, Requirements::REQUIRED_VERSION]);
|
||||||
}
|
}
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
@@ -302,9 +301,9 @@ class Install
|
|||||||
throw new Exception(lng('install.errors.nov4andnov6ip'));
|
throw new Exception(lng('install.errors.nov4andnov6ip'));
|
||||||
} elseif (!empty($serveripv4) && (!Validate::validate_ip2($serveripv4, true, '', false, true) || IPTools::is_ipv6($serveripv4))) {
|
} elseif (!empty($serveripv4) && (!Validate::validate_ip2($serveripv4, true, '', false, true) || IPTools::is_ipv6($serveripv4))) {
|
||||||
throw new Exception(lng('error.invalidip', [$serveripv4]));
|
throw new Exception(lng('error.invalidip', [$serveripv4]));
|
||||||
} elseif (!empty($serveripv6) && (!Validate::validate_ip2($serveripv6, true, '', false, true) || IPTools::is_ipv6($serveripv6) == false)) {
|
} elseif (!empty($serveripv6) && (!Validate::validate_ip2($serveripv6, true, '', false, true) || !IPTools::is_ipv6($serveripv6))) {
|
||||||
throw new Exception(lng('error.invalidip', [$serveripv6]));
|
throw new Exception(lng('error.invalidip', [$serveripv6]));
|
||||||
} elseif (!Validate::validateDomain($servername) && !Validate::validateLocalHostname($servername)) {
|
} elseif (!Validate::validateDomain($servername)) {
|
||||||
throw new Exception(lng('install.errors.servernameneedstobevalid'));
|
throw new Exception(lng('install.errors.servernameneedstobevalid'));
|
||||||
} elseif (posix_getpwnam($httpuser) === false) {
|
} elseif (posix_getpwnam($httpuser) === false) {
|
||||||
throw new Exception(lng('install.errors.websrvuserdoesnotexist'));
|
throw new Exception(lng('install.errors.websrvuserdoesnotexist'));
|
||||||
@@ -323,6 +322,8 @@ class Install
|
|||||||
$email = $validatedData['admin_email'] ?? '';
|
$email = $validatedData['admin_email'] ?? '';
|
||||||
$password = $validatedData['admin_pass'] ?? '';
|
$password = $validatedData['admin_pass'] ?? '';
|
||||||
$password_confirm = $validatedData['admin_pass_confirm'] ?? '';
|
$password_confirm = $validatedData['admin_pass_confirm'] ?? '';
|
||||||
|
$useadminmailassender = $validatedData['use_admin_email_as_sender'] ?? '1';
|
||||||
|
$senderemail = $validatedData['sender_email'] ?? '';
|
||||||
|
|
||||||
if (!preg_match('/^[^\r\n\t\f\0]*$/D', $name)) {
|
if (!preg_match('/^[^\r\n\t\f\0]*$/D', $name)) {
|
||||||
throw new Exception(lng('error.stringformaterror', ['admin_name']));
|
throw new Exception(lng('error.stringformaterror', ['admin_name']));
|
||||||
@@ -330,6 +331,8 @@ class Install
|
|||||||
throw new Exception(lng('error.loginnameiswrong', [$loginname]));
|
throw new Exception(lng('error.loginnameiswrong', [$loginname]));
|
||||||
} elseif (empty(trim($email)) || !Validate::validateEmail($email)) {
|
} elseif (empty(trim($email)) || !Validate::validateEmail($email)) {
|
||||||
throw new Exception(lng('error.emailiswrong', [$email]));
|
throw new Exception(lng('error.emailiswrong', [$email]));
|
||||||
|
} elseif ((int)$useadminmailassender == 0 && !empty(trim($senderemail)) && !Validate::validateEmail($senderemail)) {
|
||||||
|
throw new Exception(lng('error.emailiswrong', [$senderemail]));
|
||||||
} elseif (empty($password) || $password != $password_confirm) {
|
} elseif (empty($password) || $password != $password_confirm) {
|
||||||
throw new Exception(lng('error.newpasswordconfirmerror'));
|
throw new Exception(lng('error.newpasswordconfirmerror'));
|
||||||
} elseif ($password == $loginname) {
|
} elseif ($password == $loginname) {
|
||||||
@@ -410,7 +413,7 @@ class Install
|
|||||||
} else {
|
} else {
|
||||||
$osrf = explode("\n", file_get_contents('/etc/os-release'));
|
$osrf = explode("\n", file_get_contents('/etc/os-release'));
|
||||||
foreach ($osrf as $line) {
|
foreach ($osrf as $line) {
|
||||||
$osrfline = explode("\n", $line);
|
$osrfline = explode("=", $line);
|
||||||
if ($osrfline[0] == 'VERSION_CODENAME') {
|
if ($osrfline[0] == 'VERSION_CODENAME') {
|
||||||
$os_dist['VERSION_CODENAME'] = $osrfline[1];
|
$os_dist['VERSION_CODENAME'] = $osrfline[1];
|
||||||
} else if ($osrfline[0] == 'ID') {
|
} else if ($osrfline[0] == 'ID') {
|
||||||
|
|||||||
@@ -301,8 +301,8 @@ class Core
|
|||||||
/* continue */
|
/* continue */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (version_compare($db_root->getAttribute(PDO::ATTR_SERVER_VERSION), '10.0.0', '>=')) {
|
if (version_compare($db_root->getAttribute(PDO::ATTR_SERVER_VERSION), '8.0.11', '>=')) {
|
||||||
// mariadb compatibility
|
// mariadb & mysql8
|
||||||
// create user
|
// create user
|
||||||
$stmt = $db_root->prepare("CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED BY :password");
|
$stmt = $db_root->prepare("CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED BY :password");
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
@@ -314,19 +314,6 @@ class Core
|
|||||||
"username" => $username,
|
"username" => $username,
|
||||||
"host" => $access_host
|
"host" => $access_host
|
||||||
]);
|
]);
|
||||||
} elseif (version_compare($db_root->getAttribute(PDO::ATTR_SERVER_VERSION), '8.0.11', '>=')) {
|
|
||||||
// mysql8 compatibility
|
|
||||||
// create user
|
|
||||||
$stmt = $db_root->prepare("CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED WITH mysql_native_password BY :password");
|
|
||||||
$stmt->execute([
|
|
||||||
"password" => $password
|
|
||||||
]);
|
|
||||||
// grant privileges
|
|
||||||
$stmt = $db_root->prepare("GRANT ALL ON `" . $database . "`.* TO :username@:host");
|
|
||||||
$stmt->execute([
|
|
||||||
"username" => $username,
|
|
||||||
"host" => $access_host
|
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
// grant privileges
|
// grant privileges
|
||||||
$stmt = $db_root->prepare("GRANT ALL PRIVILEGES ON `" . $database . "`.* TO :username@:host IDENTIFIED BY :password");
|
$stmt = $db_root->prepare("GRANT ALL PRIVILEGES ON `" . $database . "`.* TO :username@:host IDENTIFIED BY :password");
|
||||||
@@ -378,7 +365,14 @@ class Core
|
|||||||
|
|
||||||
$mainip = !empty($this->validatedData['serveripv6']) ? $this->validatedData['serveripv6'] : $this->validatedData['serveripv4'];
|
$mainip = !empty($this->validatedData['serveripv6']) ? $this->validatedData['serveripv6'] : $this->validatedData['serveripv4'];
|
||||||
|
|
||||||
$this->updateSetting($upd_stmt, 'admin@' . $this->validatedData['servername'], 'panel', 'adminmail');
|
if ($this->validatedData['use_admin_email_as_sender'] == '1') {
|
||||||
|
$adminmail_value = $this->validatedData['admin_email'];
|
||||||
|
} elseif ($this->validatedData['use_admin_email_as_sender'] == '0' && !empty($this->validatedData['sender_email'])) {
|
||||||
|
$adminmail_value = $this->validatedData['sender_email'];
|
||||||
|
} else {
|
||||||
|
$adminmail_value = 'admin@' . $this->validatedData['servername'];
|
||||||
|
}
|
||||||
|
$this->updateSetting($upd_stmt, $adminmail_value, 'panel', 'adminmail');
|
||||||
$this->updateSetting($upd_stmt, $mainip, 'system', 'ipaddress');
|
$this->updateSetting($upd_stmt, $mainip, 'system', 'ipaddress');
|
||||||
if ($this->validatedData['use_ssl']) {
|
if ($this->validatedData['use_ssl']) {
|
||||||
$this->updateSetting($upd_stmt, 1, 'system', 'use_ssl');
|
$this->updateSetting($upd_stmt, 1, 'system', 'use_ssl');
|
||||||
@@ -421,6 +415,7 @@ class Core
|
|||||||
|
|
||||||
$this->updateSetting($upd_stmt, $this->validatedData['activate_newsfeed'], 'admin', 'show_news_feed');
|
$this->updateSetting($upd_stmt, $this->validatedData['activate_newsfeed'], 'admin', 'show_news_feed');
|
||||||
$this->updateSetting($upd_stmt, dirname(__FILE__, 5), 'system', 'letsencryptchallengepath');
|
$this->updateSetting($upd_stmt, dirname(__FILE__, 5), 'system', 'letsencryptchallengepath');
|
||||||
|
$this->updateSetting($upd_stmt, dirname(__FILE__, 5) . '/templates/misc/deactivated/', 'system', 'deactivateddocroot');
|
||||||
|
|
||||||
// insert the lastcronrun to be the installation date
|
// insert the lastcronrun to be the installation date
|
||||||
$this->updateSetting($upd_stmt, time(), 'system', 'lastcronrun');
|
$this->updateSetting($upd_stmt, time(), 'system', 'lastcronrun');
|
||||||
@@ -575,7 +570,7 @@ class Core
|
|||||||
'password' => password_hash($this->validatedData['admin_pass'], PASSWORD_DEFAULT),
|
'password' => password_hash($this->validatedData['admin_pass'], PASSWORD_DEFAULT),
|
||||||
'adminname' => $this->validatedData['admin_name'],
|
'adminname' => $this->validatedData['admin_name'],
|
||||||
'email' => $this->validatedData['admin_email'],
|
'email' => $this->validatedData['admin_email'],
|
||||||
'deflang' => 'en' // TODO: set lanuage
|
'deflang' => 'en' // TODO: set language
|
||||||
];
|
];
|
||||||
$ins_stmt = $db_user->prepare("
|
$ins_stmt = $db_user->prepare("
|
||||||
INSERT INTO `" . TABLE_PANEL_ADMINS . "` SET
|
INSERT INTO `" . TABLE_PANEL_ADMINS . "` SET
|
||||||
|
|||||||
10
lib/Froxlor/Install/Requirements.php
Normal file
10
lib/Froxlor/Install/Requirements.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Froxlor\Install;
|
||||||
|
|
||||||
|
class Requirements
|
||||||
|
{
|
||||||
|
const REQUIRED_VERSION = '7.4.0';
|
||||||
|
const REQUIRED_EXTENSIONS = ['session', 'ctype', 'xml', 'filter', 'posix', 'mbstring', 'pdo_mysql', 'curl', 'gmp', 'json', 'gd'];
|
||||||
|
const SUGGESTED_EXTENSIONS = ['bcmath', 'zip', 'gnupg'];
|
||||||
|
}
|
||||||
@@ -220,8 +220,11 @@ class PhpHelper
|
|||||||
if (is_dir($data_dirname)) {
|
if (is_dir($data_dirname)) {
|
||||||
$data_dirhandle = opendir($data_dirname);
|
$data_dirhandle = opendir($data_dirname);
|
||||||
while (false !== ($data_filename = readdir($data_dirhandle))) {
|
while (false !== ($data_filename = readdir($data_dirhandle))) {
|
||||||
if ($data_filename != '.' && $data_filename != '..' && $data_filename != '' && substr($data_filename,
|
if ($data_filename != '.'
|
||||||
-4) == '.php') {
|
&& $data_filename != '..'
|
||||||
|
&& $data_filename != ''
|
||||||
|
&& substr($data_filename, -4) == '.php'
|
||||||
|
) {
|
||||||
$data_files[] = $data_dirname . $data_filename;
|
$data_files[] = $data_dirname . $data_filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -458,6 +461,10 @@ class PhpHelper
|
|||||||
'directory_password',
|
'directory_password',
|
||||||
'ftp_password',
|
'ftp_password',
|
||||||
'mysql_password',
|
'mysql_password',
|
||||||
|
'mysql_root_pass',
|
||||||
|
'mysql_unprivileged_pass',
|
||||||
|
'admin_pass',
|
||||||
|
'admin_pass_confirm',
|
||||||
];
|
];
|
||||||
if (!empty($global)) {
|
if (!empty($global)) {
|
||||||
$tmp = $global;
|
$tmp = $global;
|
||||||
@@ -557,4 +564,17 @@ class PhpHelper
|
|||||||
}
|
}
|
||||||
return $tab . $str;
|
return $tab . $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function array_merge_recursive_distinct(array &$array1, array &$array2)
|
||||||
|
{
|
||||||
|
$merged = $array1;
|
||||||
|
foreach ($array2 as $key => &$value) {
|
||||||
|
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
|
||||||
|
$merged[$key] = self::array_merge_recursive_distinct($merged[$key], $value);
|
||||||
|
} else {
|
||||||
|
$merged[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $merged;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class SImExporter
|
|||||||
public static function export()
|
public static function export()
|
||||||
{
|
{
|
||||||
$settings_definitions = [];
|
$settings_definitions = [];
|
||||||
foreach (PhpHelper::loadConfigArrayDir('./actions/admin/settings/')['groups'] as $group) {
|
foreach (PhpHelper::loadConfigArrayDir(Froxlor::getInstallDir() . '/actions/admin/settings/')['groups'] as $group) {
|
||||||
foreach ($group['fields'] as $field) {
|
foreach ($group['fields'] as $field) {
|
||||||
$settings_definitions[$field['settinggroup']][$field['varname']] = $field;
|
$settings_definitions[$field['settinggroup']][$field['varname']] = $field;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,8 @@ class Settings
|
|||||||
{
|
{
|
||||||
// set defaults
|
// set defaults
|
||||||
self::$conf = [
|
self::$conf = [
|
||||||
'enable_webupdate' => false
|
'enable_webupdate' => false,
|
||||||
|
'disable_otp_security_check' => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
$configfile = Froxlor::getInstallDir() . '/lib/config.inc.php';
|
$configfile = Froxlor::getInstallDir() . '/lib/config.inc.php';
|
||||||
|
|||||||
@@ -211,10 +211,10 @@ class Cronjob
|
|||||||
'type' => TaskId::DELETE_DOMAIN_SSL,
|
'type' => TaskId::DELETE_DOMAIN_SSL,
|
||||||
'data' => $data
|
'data' => $data
|
||||||
]);
|
]);
|
||||||
} elseif ($type == TaskId::CREATE_CUSTOMER_BACKUP && isset($params[0]) && is_array($params[0])) {
|
} elseif ($type == TaskId::CREATE_CUSTOMER_DATADUMP && isset($params[0]) && is_array($params[0])) {
|
||||||
$data = json_encode($params[0]);
|
$data = json_encode($params[0]);
|
||||||
Database::pexecute($ins_stmt, [
|
Database::pexecute($ins_stmt, [
|
||||||
'type' => TaskId::CREATE_CUSTOMER_BACKUP,
|
'type' => TaskId::CREATE_CUSTOMER_DATADUMP,
|
||||||
'data' => $data
|
'data' => $data
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -310,44 +310,39 @@ class Cronjob
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cronjob function to end a cronjob in a critical condition
|
* Send notification to system admin via email
|
||||||
* but not without sending a notification mail to the admin
|
|
||||||
*
|
*
|
||||||
* @param string $message
|
* @param string $message
|
||||||
* @param string $subject
|
* @param string $subject
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function dieWithMail(string $message, string $subject = "[froxlor] Cronjob error")
|
public static function notifyMailToAdmin(string $message, string $subject = "[froxlor] Important notice")
|
||||||
{
|
{
|
||||||
if (Settings::Get('system.send_cron_errors') == '1') {
|
$mail = new Mailer(true);
|
||||||
$_mail = new Mailer(true);
|
$mailerror = false;
|
||||||
$_mailerror = false;
|
|
||||||
$mailerr_msg = "";
|
$mailerr_msg = "";
|
||||||
try {
|
try {
|
||||||
$_mail->Subject = $subject;
|
$mail->Subject = $subject;
|
||||||
$_mail->AltBody = $message;
|
$mail->AltBody = $message;
|
||||||
$_mail->MsgHTML(nl2br($message));
|
$mail->MsgHTML(nl2br($message));
|
||||||
$_mail->AddAddress(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname'));
|
$mail->AddAddress(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname'));
|
||||||
$_mail->Send();
|
$mail->Send();
|
||||||
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
||||||
$mailerr_msg = $e->errorMessage();
|
$mailerr_msg = $e->errorMessage();
|
||||||
$_mailerror = true;
|
$mailerror = true;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$mailerr_msg = $e->getMessage();
|
$mailerr_msg = $e->getMessage();
|
||||||
$_mailerror = true;
|
$mailerror = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$_mail->ClearAddresses();
|
$mail->ClearAddresses();
|
||||||
|
|
||||||
if ($_mailerror) {
|
if ($mailerror) {
|
||||||
echo 'Error sending mail: ' . $mailerr_msg . "\n";
|
echo 'Error sending mail: ' . $mailerr_msg . "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
die($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $cronname
|
* @param string $cronname
|
||||||
* @return void
|
* @return void
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user