Compare commits
415 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1347b877a5 | ||
|
|
a862307bce | ||
|
|
2f03eee9aa | ||
|
|
f4183b020b | ||
|
|
9a3d88e8c9 | ||
|
|
c9460fd58f | ||
|
|
6ef532b470 | ||
|
|
5909401cdd | ||
|
|
809e8ef45b | ||
|
|
0a091a99e8 | ||
|
|
e299fbe665 | ||
|
|
67e8b622d8 | ||
|
|
ce509273d4 | ||
|
|
bcf588a2e4 | ||
|
|
f08d540e66 | ||
|
|
e06db3d8c5 | ||
|
|
c5c04ebe9c | ||
|
|
c9faa38f6c | ||
|
|
c188f047dc | ||
|
|
775d50306c | ||
|
|
3821144c3b | ||
|
|
a1da70c221 | ||
|
|
bb2db0fed0 | ||
|
|
9680f24640 | ||
|
|
c732fbd81b | ||
|
|
7980b8d14d | ||
|
|
13e88f5b47 | ||
|
|
031596301b | ||
|
|
b34ab45746 | ||
|
|
dbf83c6f24 | ||
|
|
4cb974839c | ||
|
|
1fa714ef2c | ||
|
|
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 | ||
|
|
10555bff76 | ||
|
|
338b855947 | ||
|
|
5d04b8c829 | ||
|
|
37aa7af4da | ||
|
|
4b75369597 | ||
|
|
9d0e463906 | ||
|
|
a0406932c3 | ||
|
|
a7198f58ce | ||
|
|
22aa197864 | ||
|
|
d53f9b8e58 | ||
|
|
47be4b2847 | ||
|
|
b0fae4bd14 | ||
|
|
9d4205acf6 | ||
|
|
4711a41436 | ||
|
|
cb8b969ddd | ||
|
|
faa71ceaef | ||
|
|
fcfd44f726 | ||
|
|
2d30394150 | ||
|
|
52a06bf806 | ||
|
|
20aa162fcc | ||
|
|
bb60df0709 | ||
|
|
a86c8535e0 | ||
|
|
ab82695806 | ||
|
|
99c1182af8 | ||
|
|
c52d9bbd03 | ||
|
|
d1043b4645 | ||
|
|
9d113afc83 | ||
|
|
bbd1dca30e | ||
|
|
6d42968d1a | ||
|
|
8d66a4aec4 | ||
|
|
e071365cd6 | ||
|
|
5f05478c76 | ||
|
|
6616bd9a38 | ||
|
|
d9abe58dd2 | ||
|
|
947df2079f | ||
|
|
23034b8ad2 | ||
|
|
b791cd5c3e | ||
|
|
1662745991 | ||
|
|
1cae5638d3 | ||
|
|
ce9a5f97a3 | ||
|
|
067c9f8c76 | ||
|
|
f396bd5184 | ||
|
|
c38b90deef | ||
|
|
13daa7d6fa | ||
|
|
b0e43d332d | ||
|
|
03b5a921ff | ||
|
|
75c8754fb4 | ||
|
|
e357f7e9c3 | ||
|
|
da7309c41e | ||
|
|
257ef4c059 | ||
|
|
eda8700217 | ||
|
|
94d9c3eedf | ||
|
|
f9f1048477 | ||
|
|
a2fca3fe69 | ||
|
|
105213fd3f | ||
|
|
07f4491db6 | ||
|
|
e0fa64f897 | ||
|
|
ed72fd1766 | ||
|
|
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 | ||
|
|
826ae36647 | ||
|
|
9ddf24539e | ||
|
|
c079047180 | ||
|
|
e1e7bc7b42 | ||
|
|
3940c1429d | ||
|
|
c236d9eaab | ||
|
|
512a544dd1 | ||
|
|
688994e40c | ||
|
|
0fb338b32d | ||
|
|
9facaee809 | ||
|
|
e90dae186b | ||
|
|
a7dd5f4685 | ||
|
|
ca5f36d912 | ||
|
|
63d81201de | ||
|
|
0b685d569f | ||
|
|
426f204473 | ||
|
|
84599011cf | ||
|
|
6202e24b77 | ||
|
|
8deaf6a013 | ||
|
|
a491667ce5 | ||
|
|
da810ea953 | ||
|
|
d51556f918 | ||
|
|
51b6e067e8 | ||
|
|
233bf27afe | ||
|
|
09b3c1c45a | ||
|
|
2e6b939ec6 | ||
|
|
c1f03c1683 | ||
|
|
5731f5ffff | ||
|
|
34cf6698bc | ||
|
|
4642160724 | ||
|
|
78a259ef3b | ||
|
|
68cf4ab69a | ||
|
|
d5661d492d | ||
|
|
6900898ae1 | ||
|
|
d90fb7fa68 | ||
|
|
4ea8629fcc | ||
|
|
9d4ff8698d | ||
|
|
b164038846 | ||
|
|
5c46960734 | ||
|
|
a7f4f0c737 | ||
|
|
b64dd501dd | ||
|
|
1679675aa1 | ||
|
|
640466f301 | ||
|
|
9c9771a371 | ||
|
|
1922b3ce65 | ||
|
|
83e819908a | ||
|
|
0924aa644b | ||
|
|
7711ce1d66 | ||
|
|
7dae63e586 | ||
|
|
1bcaa45492 | ||
|
|
66cb114f0d | ||
|
|
1c5d60dcfd | ||
|
|
b6da6356fc | ||
|
|
c09670cc45 | ||
|
|
464f5b7bed | ||
|
|
c799235c24 | ||
|
|
a2860e70a5 | ||
|
|
95a96d46a6 | ||
|
|
81f3dbda31 | ||
|
|
4eb4191843 | ||
|
|
ca433d8a61 | ||
|
|
8f4dfe1514 | ||
|
|
ee42f5168e | ||
|
|
fc8ca57f8c | ||
|
|
7e4bba2d55 | ||
|
|
7e635f9be4 | ||
|
|
e9406a20f2 | ||
|
|
de7729cec8 | ||
|
|
d60e48849b | ||
|
|
908df5a7bb | ||
|
|
c1952afb94 | ||
|
|
7a22e8f4dd | ||
|
|
3ac0da2cdd | ||
|
|
eb816c4cc6 | ||
|
|
64d8bf4fba | ||
|
|
ae6ee95973 | ||
|
|
e9051dc30a | ||
|
|
b6c7c53c3a | ||
|
|
f36bc61fc7 | ||
|
|
c56e0b9dac | ||
|
|
1deb08bf75 | ||
|
|
b30d7a8252 | ||
|
|
b03e11c18d | ||
|
|
bf7d22a794 | ||
|
|
fb57a8a3b5 | ||
|
|
0d625797b0 | ||
|
|
6777fbf229 | ||
|
|
23f1f79eff | ||
|
|
a5af104d53 | ||
|
|
38d94698ce | ||
|
|
5ba28ef599 | ||
|
|
a3486cc5b3 | ||
|
|
5ab322ab1d | ||
|
|
4f26bdd535 | ||
|
|
88f76e4355 | ||
|
|
a464d8cb19 | ||
|
|
0f596dce8b | ||
|
|
60270b20b3 | ||
|
|
4003a8d2b6 | ||
|
|
89843d6f37 | ||
|
|
256a52a5da | ||
|
|
c9b2bfe53c | ||
|
|
98cb36327e | ||
|
|
7d23e4882d | ||
|
|
1cc3a1d066 | ||
|
|
de0f7d2f01 | ||
|
|
aa48ffca2b | ||
|
|
802168cb5b | ||
|
|
6ace2e9f3d | ||
|
|
0bff360d22 | ||
|
|
e300acf109 | ||
|
|
14d8e12cdc | ||
|
|
d29411dba6 | ||
|
|
464663877c | ||
|
|
c3f769d48b | ||
|
|
f97536ed02 | ||
|
|
7686effc8c | ||
|
|
ee8385467b | ||
|
|
0a51d97684 | ||
|
|
67fc762eef | ||
|
|
8378795f5d | ||
|
|
98e6f1df4a | ||
|
|
674e35e5c5 | ||
|
|
b24ca44e6f | ||
|
|
e0f7fcd2ef | ||
|
|
c5bece64ce | ||
|
|
0034681412 | ||
|
|
bd5b99dc1c | ||
|
|
2feb802094 | ||
|
|
7b08a71c59 | ||
|
|
2a84e9c120 | ||
|
|
d854e8e991 | ||
|
|
0a363910d6 | ||
|
|
b23d5cd909 | ||
|
|
3b753aa69d | ||
|
|
492cd288bc | ||
|
|
47938c5082 | ||
|
|
97c4c9a366 | ||
|
|
d090e48544 | ||
|
|
314e4407a0 | ||
|
|
ed50e03957 | ||
|
|
dff7530cc5 | ||
|
|
19423c9644 | ||
|
|
42b3f1e59d | ||
|
|
1b77632fa8 | ||
|
|
867b7b1390 | ||
|
|
4c6ebde58c | ||
|
|
1e013d9e9a | ||
|
|
c56bc651b9 | ||
|
|
6cbdf45a7c | ||
|
|
715667e227 | ||
|
|
41de161555 | ||
|
|
1f1ea370c0 | ||
|
|
090cfc26f2 | ||
|
|
529890b5d2 | ||
|
|
d4a6ab146d | ||
|
|
e3f02879cf | ||
|
|
b52d6df777 | ||
|
|
9e671100ae | ||
|
|
7e801ea502 | ||
|
|
b68522f7d5 | ||
|
|
86852942e0 | ||
|
|
ea88d53e39 | ||
|
|
61f6a474e4 | ||
|
|
ec05c84f4d | ||
|
|
9e13c077e9 | ||
|
|
da8d315e77 | ||
|
|
82af9af1e1 | ||
|
|
cb67e3ae63 | ||
|
|
82d15c4dc2 | ||
|
|
6d048e2cee | ||
|
|
87bd80eea1 | ||
|
|
80e442e396 | ||
|
|
489ad375bd | ||
|
|
c420196e73 | ||
|
|
cc6d8d5f8b |
14
.github/workflows/build-apidocs.yml
vendored
14
.github/workflows/build-apidocs.yml
vendored
@@ -1,14 +0,0 @@
|
|||||||
name: build-docs
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_docs:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
gh workflow run --repo Froxlor/Documentation build-docs -f ref=${{github.ref_name}}
|
|
||||||
15
.github/workflows/build-docs.yml
vendored
Normal file
15
.github/workflows/build-docs.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: build-documentation
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
# only run for stable releases
|
||||||
|
types: [released]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_docs:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
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' && github.ref == 'refs/heads/main' }}
|
||||||
# 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/
|
||||||
|
|||||||
12
README.md
12
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
|
||||||
|
|
||||||
@@ -57,7 +51,7 @@ May be found in [COPYING](COPYING)
|
|||||||
### Tarball
|
### Tarball
|
||||||
https://files.froxlor.org/releases/froxlor-latest.tar.gz [MD5](https://files.froxlor.org/releases/froxlor-latest.tar.gz.md5) [SHA1](https://files.froxlor.org/releases/froxlor-latest.tar.gz.sha1)
|
https://files.froxlor.org/releases/froxlor-latest.tar.gz [MD5](https://files.froxlor.org/releases/froxlor-latest.tar.gz.md5) [SHA1](https://files.froxlor.org/releases/froxlor-latest.tar.gz.sha1)
|
||||||
|
|
||||||
### Debian / Ubutnu repository
|
### Debian / Ubuntu repository
|
||||||
|
|
||||||
[HowTo](https://docs.froxlor.org/latest/general/installation/apt-package.html)
|
[HowTo](https://docs.froxlor.org/latest/general/installation/apt-package.html)
|
||||||
|
|
||||||
|
|||||||
14
SECURITY.md
14
SECURITY.md
@@ -10,9 +10,11 @@ With that, good luck hacking us ;)
|
|||||||
|
|
||||||
## Supported versions
|
## Supported versions
|
||||||
|
|
||||||
- ️✅ **2.x** (`main` git-branch)
|
- ️✅ **2.2.x** (`main` git-branch)
|
||||||
- ❌ 0.10.x (`0.10.x` git-branch)
|
- ️✅ **2.1.x** (`v2.1` git-branch)
|
||||||
- ❌ 0.9.x (`0.9.x`git-branch)
|
- ❌ 2.0.x (`2.0.x`-tags)
|
||||||
|
- ❌ 0.10.x (`0.10.x`-tags)
|
||||||
|
- ❌ other git-branches
|
||||||
|
|
||||||
## Qualifying Vulnerabilities
|
## Qualifying Vulnerabilities
|
||||||
|
|
||||||
@@ -26,7 +28,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 +36,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 +48,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,11 +265,12 @@ 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",
|
||||||
'traffic.mail' => lng('menue.traffic.traffic') . " / Mail"
|
'traffic.mail' => lng('menue.traffic.traffic') . " / Mail",
|
||||||
|
'misc.documentation' => lng('admin.documentation'),
|
||||||
],
|
],
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
@@ -336,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',
|
||||||
|
],
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ return [
|
|||||||
'varname' => 'sessiontimeout',
|
'varname' => 'sessiontimeout',
|
||||||
'type' => 'number',
|
'type' => 'number',
|
||||||
'min' => 60,
|
'min' => 60,
|
||||||
|
'max' => 31536000,
|
||||||
'default' => 600,
|
'default' => 600,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
@@ -138,6 +139,26 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
|
'system_req_limit_per_interval' => [
|
||||||
|
'label' => lng('serversettings.req_limit_per_interval'),
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'req_limit_per_interval',
|
||||||
|
'type' => 'number',
|
||||||
|
'min' => 30,
|
||||||
|
'default' => 60,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'advanced_mode' => true
|
||||||
|
],
|
||||||
|
'system_req_limit_interval' => [
|
||||||
|
'label' => lng('serversettings.req_limit_interval'),
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'req_limit_interval',
|
||||||
|
'type' => 'number',
|
||||||
|
'min' => 5,
|
||||||
|
'default' => 60,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'advanced_mode' => true
|
||||||
|
],
|
||||||
'customer_accountprefix' => [
|
'customer_accountprefix' => [
|
||||||
'label' => lng('serversettings.accountprefix'),
|
'label' => lng('serversettings.accountprefix'),
|
||||||
'settinggroup' => 'customer',
|
'settinggroup' => 'customer',
|
||||||
@@ -210,13 +231,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,9 +107,22 @@ return [
|
|||||||
'varname' => 'enabled',
|
'varname' => 'enabled',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
|
'save_method' => 'storeSettingField',
|
||||||
|
'required_otp' => true
|
||||||
|
],
|
||||||
|
'api_customer_default' => [
|
||||||
|
'label' => lng('serversettings.api_customer_default'),
|
||||||
|
'settinggroup' => 'api',
|
||||||
|
'varname' => 'customer_default',
|
||||||
|
'type' => 'select',
|
||||||
|
'default' => 1,
|
||||||
|
'select_var' => [
|
||||||
|
1 => lng('panel.yes'),
|
||||||
|
0 => lng('panel.no')
|
||||||
|
],
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'update_channel' => [
|
'system_update_channel' => [
|
||||||
'label' => lng('serversettings.update_channel'),
|
'label' => lng('serversettings.update_channel'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'update_channel',
|
'varname' => 'update_channel',
|
||||||
@@ -117,12 +130,13 @@ 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
|
||||||
],
|
],
|
||||||
'system_validatedomain' => [
|
'system_validate_domain' => [
|
||||||
'label' => lng('serversettings.validate_domain'),
|
'label' => lng('serversettings.validate_domain'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'validate_domain',
|
'varname' => 'validate_domain',
|
||||||
@@ -158,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',
|
||||||
@@ -307,7 +311,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'hide_incompatible_settings' => [
|
'system_hide_incompatible_settings' => [
|
||||||
'label' => lng('serversettings.hide_incompatible_settings'),
|
'label' => lng('serversettings.hide_incompatible_settings'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'hide_incompatible_settings',
|
'varname' => 'hide_incompatible_settings',
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ return [
|
|||||||
'string_regexp' => '/^(([a-z0-9\-\._]+, ?)*[a-z0-9\-\._]+)?$/i',
|
'string_regexp' => '/^(([a-z0-9\-\._]+, ?)*[a-z0-9\-\._]+)?$/i',
|
||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingClearCertificates',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
/**
|
/**
|
||||||
@@ -154,7 +154,7 @@ return [
|
|||||||
/**
|
/**
|
||||||
* FCGID
|
* FCGID
|
||||||
*/
|
*/
|
||||||
'system_mod_fcgid_enabled_ownvhost' => [
|
'system_mod_fcgid_ownvhost' => [
|
||||||
'label' => lng('serversettings.mod_fcgid_ownvhost'),
|
'label' => lng('serversettings.mod_fcgid_ownvhost'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'mod_fcgid_ownvhost',
|
'varname' => 'mod_fcgid_ownvhost',
|
||||||
@@ -224,7 +224,7 @@ return [
|
|||||||
/**
|
/**
|
||||||
* php-fpm
|
* php-fpm
|
||||||
*/
|
*/
|
||||||
'system_phpfpm_enabled_ownvhost' => [
|
'phpfpm_enabled_ownvhost' => [
|
||||||
'label' => lng('phpfpm.ownvhost'),
|
'label' => lng('phpfpm.ownvhost'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'enabled_ownvhost',
|
'varname' => 'enabled_ownvhost',
|
||||||
@@ -237,7 +237,7 @@ return [
|
|||||||
]),
|
]),
|
||||||
'requires_reconf' => ['system:php-fpm']
|
'requires_reconf' => ['system:php-fpm']
|
||||||
],
|
],
|
||||||
'system_phpfpm_httpuser' => [
|
'phpfpm_vhost_httpuser' => [
|
||||||
'label' => lng('phpfpm.vhost_httpuser'),
|
'label' => lng('phpfpm.vhost_httpuser'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'vhost_httpuser',
|
'varname' => 'vhost_httpuser',
|
||||||
@@ -250,7 +250,7 @@ return [
|
|||||||
]),
|
]),
|
||||||
'requires_reconf' => ['system:php-fpm']
|
'requires_reconf' => ['system:php-fpm']
|
||||||
],
|
],
|
||||||
'system_phpfpm_httpgroup' => [
|
'phpfpm_vhost_httpgroup' => [
|
||||||
'label' => lng('phpfpm.vhost_httpgroup'),
|
'label' => lng('phpfpm.vhost_httpgroup'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'vhost_httpgroup',
|
'varname' => 'vhost_httpgroup',
|
||||||
@@ -263,7 +263,7 @@ return [
|
|||||||
]),
|
]),
|
||||||
'requires_reconf' => ['system:php-fpm']
|
'requires_reconf' => ['system:php-fpm']
|
||||||
],
|
],
|
||||||
'system_phpfpm_defaultini_ownvhost' => [
|
'phpfpm_vhost_defaultini' => [
|
||||||
'label' => lng('serversettings.mod_fcgid.defaultini_ownvhost'),
|
'label' => lng('serversettings.mod_fcgid.defaultini_ownvhost'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'vhost_defaultini',
|
'varname' => 'vhost_defaultini',
|
||||||
|
|||||||
@@ -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
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ return [
|
|||||||
'apache2'
|
'apache2'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_apache_itksupport' => [
|
'system_apacheitksupport' => [
|
||||||
'label' => lng('serversettings.apache_itksupport'),
|
'label' => lng('serversettings.apache_itksupport'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'apacheitksupport',
|
'varname' => 'apacheitksupport',
|
||||||
@@ -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',
|
||||||
@@ -229,7 +230,7 @@ return [
|
|||||||
'nginx'
|
'nginx'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_customersslpath' => [
|
'system_customer_ssl_path' => [
|
||||||
'label' => lng('serversettings.customerssl_directory'),
|
'label' => lng('serversettings.customerssl_directory'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'customer_ssl_path',
|
'varname' => 'customer_ssl_path',
|
||||||
@@ -287,7 +288,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_apache_globaldiropt' => [
|
'system_apacheglobaldiropt' => [
|
||||||
'label' => lng('serversettings.apache_globaldiropt'),
|
'label' => lng('serversettings.apache_globaldiropt'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'apacheglobaldiropt',
|
'varname' => 'apacheglobaldiropt',
|
||||||
@@ -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'),
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ return [
|
|||||||
'title' => lng('admin.sslsettings'),
|
'title' => lng('admin.sslsettings'),
|
||||||
'icon' => 'fa-solid fa-shield',
|
'icon' => 'fa-solid fa-shield',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'system_ssl_enabled' => [
|
'system_use_ssl' => [
|
||||||
'label' => lng('serversettings.ssl.use_ssl'),
|
'label' => lng('serversettings.ssl.use_ssl'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'use_ssl',
|
'varname' => 'use_ssl',
|
||||||
@@ -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'),
|
||||||
@@ -241,6 +242,16 @@ return [
|
|||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => true,
|
'default' => true,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
|
],
|
||||||
|
'system_le_domain_dnscheck_resolver' => [
|
||||||
|
'label' => lng('serversettings.le_domain_dnscheck_resolver'),
|
||||||
|
'settinggroup' => 'system',
|
||||||
|
'varname' => 'le_domain_dnscheck_resolver',
|
||||||
|
'type' => 'text',
|
||||||
|
'string_type' => 'validate_ip',
|
||||||
|
'string_emptyallowed' => true,
|
||||||
|
'default' => '',
|
||||||
|
'save_method' => 'storeSettingField'
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ return [
|
|||||||
'lighttpd'
|
'lighttpd'
|
||||||
],
|
],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'system_mod_fcgid_enabled' => [
|
'system_mod_fcgid' => [
|
||||||
'label' => lng('serversettings.mod_fcgid'),
|
'label' => lng('serversettings.mod_fcgid'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'mod_fcgid',
|
'varname' => 'mod_fcgid',
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ return [
|
|||||||
'title' => lng('admin.phpfpm_settings'),
|
'title' => lng('admin.phpfpm_settings'),
|
||||||
'icon' => 'fa-brands fa-php',
|
'icon' => 'fa-brands fa-php',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'system_phpfpm_enabled' => [
|
'phpfpm_enabled' => [
|
||||||
'label' => lng('serversettings.phpfpm'),
|
'label' => lng('serversettings.phpfpm'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'enabled',
|
'varname' => 'enabled',
|
||||||
@@ -45,7 +45,7 @@ return [
|
|||||||
'overview_option' => true,
|
'overview_option' => true,
|
||||||
'requires_reconf' => ['http', 'system:php-fpm']
|
'requires_reconf' => ['http', 'system:php-fpm']
|
||||||
],
|
],
|
||||||
'system_phpfpm_defaultini' => [
|
'phpfpm_defaultini' => [
|
||||||
'label' => lng('serversettings.mod_fcgid.defaultini'),
|
'label' => lng('serversettings.mod_fcgid.defaultini'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'defaultini',
|
'varname' => 'defaultini',
|
||||||
@@ -57,7 +57,7 @@ return [
|
|||||||
],
|
],
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_phpfpm_aliasconfigdir' => [
|
'phpfpm_aliasconfigdir' => [
|
||||||
'label' => lng('serversettings.phpfpm_settings.aliasconfigdir'),
|
'label' => lng('serversettings.phpfpm_settings.aliasconfigdir'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'aliasconfigdir',
|
'varname' => 'aliasconfigdir',
|
||||||
@@ -67,7 +67,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_tmpdir' => [
|
'phpfpm_tmpdir' => [
|
||||||
'label' => lng('serversettings.mod_fcgid.tmpdir'),
|
'label' => lng('serversettings.mod_fcgid.tmpdir'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'tmpdir',
|
'varname' => 'tmpdir',
|
||||||
@@ -76,7 +76,7 @@ return [
|
|||||||
'default' => '/var/customers/tmp/',
|
'default' => '/var/customers/tmp/',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_phpfpm_peardir' => [
|
'phpfpm_peardir' => [
|
||||||
'label' => lng('serversettings.mod_fcgid.peardir'),
|
'label' => lng('serversettings.mod_fcgid.peardir'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'peardir',
|
'varname' => 'peardir',
|
||||||
@@ -88,7 +88,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_envpath' => [
|
'phpfpm_envpath' => [
|
||||||
'label' => lng('serversettings.phpfpm_settings.envpath'),
|
'label' => lng('serversettings.phpfpm_settings.envpath'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'envpath',
|
'varname' => 'envpath',
|
||||||
@@ -100,7 +100,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_fastcgi_ipcdir' => [
|
'phpfpm_fastcgi_ipcdir' => [
|
||||||
'label' => lng('serversettings.phpfpm_settings.ipcdir'),
|
'label' => lng('serversettings.phpfpm_settings.ipcdir'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'fastcgi_ipcdir',
|
'varname' => 'fastcgi_ipcdir',
|
||||||
@@ -110,7 +110,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_use_mod_proxy' => [
|
'phpfpm_use_mod_proxy' => [
|
||||||
'label' => lng('phpfpm.use_mod_proxy'),
|
'label' => lng('phpfpm.use_mod_proxy'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'use_mod_proxy',
|
'varname' => 'use_mod_proxy',
|
||||||
@@ -119,41 +119,45 @@ return [
|
|||||||
'visible' => Settings::Get('system.apache24'),
|
'visible' => Settings::Get('system.apache24'),
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_phpfpm_ini_flags' => [
|
'phpfpm_ini_flags' => [
|
||||||
'label' => lng('phpfpm.ini_flags'),
|
'label' => lng('phpfpm.ini_flags'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'ini_flags',
|
'varname' => 'ini_flags',
|
||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_ini_values' => [
|
'phpfpm_ini_values' => [
|
||||||
'label' => lng('phpfpm.ini_values'),
|
'label' => lng('phpfpm.ini_values'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'ini_values',
|
'varname' => 'ini_values',
|
||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_ini_admin_flags' => [
|
'phpfpm_ini_admin_flags' => [
|
||||||
'label' => lng('phpfpm.ini_admin_flags'),
|
'label' => lng('phpfpm.ini_admin_flags'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'ini_admin_flags',
|
'varname' => 'ini_admin_flags',
|
||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
],
|
],
|
||||||
'system_phpfpm_ini_admin_values' => [
|
'phpfpm_ini_admin_values' => [
|
||||||
'label' => lng('phpfpm.ini_admin_values'),
|
'label' => lng('phpfpm.ini_admin_values'),
|
||||||
'settinggroup' => 'phpfpm',
|
'settinggroup' => 'phpfpm',
|
||||||
'varname' => 'ini_admin_values',
|
'varname' => 'ini_admin_values',
|
||||||
'type' => 'textarea',
|
'type' => 'textarea',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true,
|
||||||
|
'required_otp' => true
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ return [
|
|||||||
'title' => lng('admin.perl_settings'),
|
'title' => lng('admin.perl_settings'),
|
||||||
'icon' => 'fa-solid fa-code',
|
'icon' => 'fa-solid fa-code',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'perl_path' => [
|
'system_perl_path' => [
|
||||||
'label' => lng('serversettings.perl_path'),
|
'label' => lng('serversettings.perl_path'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'perl_path',
|
'varname' => 'perl_path',
|
||||||
@@ -40,7 +40,7 @@ return [
|
|||||||
'lighttpd'
|
'lighttpd'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_perl_suexecworkaround' => [
|
'perl_suexecworkaround' => [
|
||||||
'label' => lng('serversettings.perl.suexecworkaround'),
|
'label' => lng('serversettings.perl.suexecworkaround'),
|
||||||
'settinggroup' => 'perl',
|
'settinggroup' => 'perl',
|
||||||
'varname' => 'suexecworkaround',
|
'varname' => 'suexecworkaround',
|
||||||
@@ -51,7 +51,7 @@ return [
|
|||||||
'apache2'
|
'apache2'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'system_perl_suexeccgipath' => [
|
'perl_suexecpath' => [
|
||||||
'label' => lng('serversettings.perl.suexeccgipath'),
|
'label' => lng('serversettings.perl.suexeccgipath'),
|
||||||
'settinggroup' => 'perl',
|
'settinggroup' => 'perl',
|
||||||
'varname' => 'suexecpath',
|
'varname' => 'suexecpath',
|
||||||
@@ -63,7 +63,7 @@ return [
|
|||||||
'apache2'
|
'apache2'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'perl_server' => [
|
'serversettings_perl_server' => [
|
||||||
'label' => lng('serversettings.perl_server'),
|
'label' => lng('serversettings.perl_server'),
|
||||||
'settinggroup' => 'serversettings',
|
'settinggroup' => 'serversettings',
|
||||||
'varname' => 'perl_server',
|
'varname' => 'perl_server',
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ return [
|
|||||||
'default' => 100,
|
'default' => 100,
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'system_catchall_enabled' => [
|
'catchall_catchall_enabled' => [
|
||||||
'label' => lng('serversettings.catchall_enabled'),
|
'label' => lng('serversettings.catchall_enabled'),
|
||||||
'settinggroup' => 'catchall',
|
'settinggroup' => 'catchall',
|
||||||
'varname' => 'catchall_enabled',
|
'varname' => 'catchall_enabled',
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ return [
|
|||||||
'title' => lng('admin.ftpserversettings'),
|
'title' => lng('admin.ftpserversettings'),
|
||||||
'icon' => 'fa-solid fa-arrow-right-arrow-left',
|
'icon' => 'fa-solid fa-arrow-right-arrow-left',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'ftpserver' => [
|
'system_ftpserver' => [
|
||||||
'label' => lng('admin.ftpserver'),
|
'label' => lng('admin.ftpserver'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'ftpserver',
|
'varname' => 'ftpserver',
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ return [
|
|||||||
'title' => lng('admin.nameserversettings'),
|
'title' => lng('admin.nameserversettings'),
|
||||||
'icon' => 'fa-solid fa-globe',
|
'icon' => 'fa-solid fa-globe',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'nameserver_enable' => [
|
'system_bind_enable' => [
|
||||||
'label' => lng('serversettings.bindenable'),
|
'label' => lng('serversettings.bindenable'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'bind_enable',
|
'varname' => 'bind_enable',
|
||||||
@@ -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'),
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ return [
|
|||||||
'title' => lng('admin.dkimsettings'),
|
'title' => lng('admin.dkimsettings'),
|
||||||
'icon' => 'fa-solid fa-fingerprint',
|
'icon' => 'fa-solid fa-fingerprint',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'dkim_enabled' => [
|
'dkim_use_dkim' => [
|
||||||
'label' => lng('dkim.use_dkim'),
|
'label' => lng('dkim.use_dkim'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'use_dkim',
|
'varname' => 'use_dkim',
|
||||||
@@ -40,7 +40,7 @@ return [
|
|||||||
'save_method' => 'storeSettingFieldInsertBindTask',
|
'save_method' => 'storeSettingFieldInsertBindTask',
|
||||||
'overview_option' => true
|
'overview_option' => true
|
||||||
],
|
],
|
||||||
'dkim_prefix' => [
|
'dkim_dkim_prefix' => [
|
||||||
'label' => lng('dkim.dkim_prefix'),
|
'label' => lng('dkim.dkim_prefix'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_prefix',
|
'varname' => 'dkim_prefix',
|
||||||
@@ -59,7 +59,7 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'dkim_domains' => [
|
'dkim_dkim_domains' => [
|
||||||
'label' => lng('dkim.dkim_domains'),
|
'label' => lng('dkim.dkim_domains'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_domains',
|
'varname' => 'dkim_domains',
|
||||||
@@ -68,7 +68,7 @@ return [
|
|||||||
'default' => 'domains',
|
'default' => 'domains',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'dkim_dkimkeys' => [
|
'dkim_dkim_dkimkeys' => [
|
||||||
'label' => lng('dkim.dkim_dkimkeys'),
|
'label' => lng('dkim.dkim_dkimkeys'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_dkimkeys',
|
'varname' => 'dkim_dkimkeys',
|
||||||
@@ -77,7 +77,7 @@ return [
|
|||||||
'default' => 'dkim-keys.conf',
|
'default' => 'dkim-keys.conf',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
],
|
],
|
||||||
'dkim_algorithm' => [
|
'dkim_dkim_algorithm' => [
|
||||||
'label' => lng('dkim.dkim_algorithm'),
|
'label' => lng('dkim.dkim_algorithm'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_algorithm',
|
'varname' => 'dkim_algorithm',
|
||||||
@@ -92,7 +92,7 @@ return [
|
|||||||
'save_method' => 'storeSettingFieldInsertBindTask',
|
'save_method' => 'storeSettingFieldInsertBindTask',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'dkim_servicetype' => [
|
'dkim_dkim_servicetype' => [
|
||||||
'label' => lng('dkim.dkim_servicetype'),
|
'label' => lng('dkim.dkim_servicetype'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_servicetype',
|
'varname' => 'dkim_servicetype',
|
||||||
@@ -105,7 +105,7 @@ return [
|
|||||||
'save_method' => 'storeSettingFieldInsertBindTask',
|
'save_method' => 'storeSettingFieldInsertBindTask',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'dkim_keylength' => [
|
'dkim_dkim_keylength' => [
|
||||||
'label' => [
|
'label' => [
|
||||||
'title' => lng('dkim.dkim_keylength.title'),
|
'title' => lng('dkim.dkim_keylength.title'),
|
||||||
'description' => lng('dkim.dkim_keylength.description', [Settings::Get('dkim.dkim_prefix')])
|
'description' => lng('dkim.dkim_keylength.description', [Settings::Get('dkim.dkim_prefix')])
|
||||||
@@ -120,7 +120,7 @@ return [
|
|||||||
],
|
],
|
||||||
'save_method' => 'storeSettingFieldInsertBindTask'
|
'save_method' => 'storeSettingFieldInsertBindTask'
|
||||||
],
|
],
|
||||||
'dkim_notes' => [
|
'dkim_dkim_notes' => [
|
||||||
'label' => lng('dkim.dkim_notes'),
|
'label' => lng('dkim.dkim_notes'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkim_notes',
|
'varname' => 'dkim_notes',
|
||||||
@@ -130,14 +130,15 @@ return [
|
|||||||
'save_method' => 'storeSettingFieldInsertBindTask',
|
'save_method' => 'storeSettingFieldInsertBindTask',
|
||||||
'advanced_mode' => true
|
'advanced_mode' => true
|
||||||
],
|
],
|
||||||
'dkimrestart_command' => [
|
'dkim_dkimrestart_command' => [
|
||||||
'label' => lng('dkim.dkimrestart_command'),
|
'label' => lng('dkim.dkimrestart_command'),
|
||||||
'settinggroup' => 'dkim',
|
'settinggroup' => 'dkim',
|
||||||
'varname' => 'dkimrestart_command',
|
'varname' => 'dkimrestart_command',
|
||||||
'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
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ return [
|
|||||||
'title' => lng('admin.spfsettings'),
|
'title' => lng('admin.spfsettings'),
|
||||||
'icon' => 'fa-solid fa-clipboard-check',
|
'icon' => 'fa-solid fa-clipboard-check',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'use_spf' => [
|
'spf_use_spf' => [
|
||||||
'label' => lng('spf.use_spf'),
|
'label' => lng('spf.use_spf'),
|
||||||
'settinggroup' => 'spf',
|
'settinggroup' => 'spf',
|
||||||
'varname' => 'use_spf',
|
'varname' => 'use_spf',
|
||||||
@@ -38,12 +38,13 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'overview_option' => true
|
'overview_option' => true
|
||||||
],
|
],
|
||||||
'spf_entry' => [
|
'spf_spf_entry' => [
|
||||||
'label' => lng('spf.spf_entry'),
|
'label' => lng('spf.spf_entry'),
|
||||||
'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
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ return [
|
|||||||
'icon' => 'fa-solid fa-sliders',
|
'icon' => 'fa-solid fa-sliders',
|
||||||
'advanced_mode' => true,
|
'advanced_mode' => true,
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'diskquota_enabled' => [
|
'system_diskquota_enabled' => [
|
||||||
'label' => lng('serversettings.diskquota_enabled'),
|
'label' => lng('serversettings.diskquota_enabled'),
|
||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'diskquota_enabled',
|
'varname' => 'diskquota_enabled',
|
||||||
@@ -39,29 +39,35 @@ return [
|
|||||||
'save_method' => 'storeSettingField',
|
'save_method' => 'storeSettingField',
|
||||||
'overview_option' => true
|
'overview_option' => true
|
||||||
],
|
],
|
||||||
'diskquota_repquota_path' => [
|
'system_diskquota_repquota_path' => [
|
||||||
'label' => lng('serversettings.diskquota_repquota_path.description'),
|
'label' => lng('serversettings.diskquota_repquota_path.description'),
|
||||||
'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
|
||||||
],
|
],
|
||||||
'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
|
||||||
],
|
],
|
||||||
'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
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin
|
|||||||
$result['switched_user'] = CurrentUser::getData();
|
$result['switched_user'] = CurrentUser::getData();
|
||||||
$result['adminsession'] = 1;
|
$result['adminsession'] = 1;
|
||||||
$result['userid'] = $result['adminid'];
|
$result['userid'] = $result['adminid'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
|
|
||||||
$log->logAction(
|
$log->logAction(
|
||||||
|
|||||||
@@ -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') {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ require __DIR__ . '/lib/init.php';
|
|||||||
|
|
||||||
use Froxlor\Froxlor;
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\Http\HttpClient;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\Install\AutoUpdate;
|
use Froxlor\Install\AutoUpdate;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
@@ -132,7 +132,7 @@ elseif ($page == 'getdownload') {
|
|||||||
elseif ($page == 'extract') {
|
elseif ($page == 'extract') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||||
$toExtract = isset($_POST['archive']) ? $_POST['archive'] : null;
|
$toExtract = isset($_POST['archive']) ? $_POST['archive'] : null;
|
||||||
$localArchive = Froxlor::getInstallDir() . '/updates/' . $toExtract;
|
$localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract);
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Extracting " . $localArchive . " to " . Froxlor::getInstallDir());
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Extracting " . $localArchive . " to " . Froxlor::getInstallDir());
|
||||||
$result = AutoUpdate::extractZip($localArchive);
|
$result = AutoUpdate::extractZip($localArchive);
|
||||||
if ($result > 0) {
|
if ($result > 0) {
|
||||||
@@ -146,7 +146,7 @@ elseif ($page == 'extract') {
|
|||||||
Response::redirectTo('admin_updates.php');
|
Response::redirectTo('admin_updates.php');
|
||||||
} else {
|
} else {
|
||||||
$toExtract = isset($_GET['archive']) ? $_GET['archive'] : null;
|
$toExtract = isset($_GET['archive']) ? $_GET['archive'] : null;
|
||||||
$localArchive = Froxlor::getInstallDir() . '/updates/' . $toExtract;
|
$localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_exists($localArchive)) {
|
if (!file_exists($localArchive)) {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use Froxlor\Settings;
|
|||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\UI\Request;
|
use Froxlor\UI\Request;
|
||||||
use Froxlor\UI\Response;
|
use Froxlor\UI\Response;
|
||||||
|
use Froxlor\Validate\Validate;
|
||||||
|
|
||||||
if ($userinfo['change_serversettings'] == '1') {
|
if ($userinfo['change_serversettings'] == '1') {
|
||||||
if ($action == 'setconfigured') {
|
if ($action == 'setconfigured') {
|
||||||
@@ -59,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
|
||||||
@@ -91,13 +94,29 @@ if ($userinfo['change_serversettings'] == '1') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($distribution != "" && isset($_POST['finish'])) {
|
if ($distribution != "" && isset($_POST['finish'])) {
|
||||||
|
$valid_keys = ['http', 'dns', 'smtp', 'mail', 'ftp', 'system', 'distro'];
|
||||||
unset($_POST['finish']);
|
unset($_POST['finish']);
|
||||||
|
unset($_POST['csrf_token']);
|
||||||
$params = $_POST;
|
$params = $_POST;
|
||||||
$params['distro'] = $distribution;
|
$params['distro'] = $distribution;
|
||||||
$params['system'] = [];
|
$params['system'] = [];
|
||||||
foreach ($_POST['system'] as $sysdaemon) {
|
foreach ($_POST['system'] as $sysdaemon) {
|
||||||
$params['system'][] = $sysdaemon;
|
$params['system'][] = $sysdaemon;
|
||||||
}
|
}
|
||||||
|
// validate params
|
||||||
|
foreach ($params as $key => $value) {
|
||||||
|
if (!in_array($key, $valid_keys)) {
|
||||||
|
unset($params[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!is_array($value)) {
|
||||||
|
$params[$key] = Validate::validate($value, $key);
|
||||||
|
} else {
|
||||||
|
foreach ($value as $subkey => $subvalue) {
|
||||||
|
$params[$key][$subkey] = Validate::validate($subvalue, $key.'.'.$subkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
$params_content = json_encode($params);
|
$params_content = json_encode($params);
|
||||||
$params_filename = FileDir::makeCorrectFile(Froxlor::getInstallDir() . 'install/' . Froxlor::genSessionId() . '.json');
|
$params_filename = FileDir::makeCorrectFile(Froxlor::getInstallDir() . 'install/' . Froxlor::genSessionId() . '.json');
|
||||||
file_put_contents($params_filename, $params_content);
|
file_put_contents($params_filename, $params_content);
|
||||||
@@ -121,8 +140,6 @@ if ($userinfo['change_serversettings'] == '1') {
|
|||||||
'distribution' => $distribution
|
'distribution' => $distribution
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// @fixme check set distribution from settings
|
|
||||||
|
|
||||||
$cfg_formfield = [
|
$cfg_formfield = [
|
||||||
'config' => [
|
'config' => [
|
||||||
'title' => lng('admin.configfiles.serverconfiguration'),
|
'title' => lng('admin.configfiles.serverconfiguration'),
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
|
|||||||
$result['switched_user'] = CurrentUser::getData();
|
$result['switched_user'] = CurrentUser::getData();
|
||||||
$result['adminsession'] = 0;
|
$result['adminsession'] = 0;
|
||||||
$result['userid'] = $result['customerid'];
|
$result['userid'] = $result['customerid'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
|
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "switched user and is now '" . $destination_user . "'");
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "switched user and is now '" . $destination_user . "'");
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -282,6 +262,12 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$openbasedir = [
|
||||||
|
0 => lng('domain.docroot'),
|
||||||
|
1 => lng('domain.homedir'),
|
||||||
|
2 => lng('domain.docparent')
|
||||||
|
];
|
||||||
|
|
||||||
// create serveralias options
|
// create serveralias options
|
||||||
$serveraliasoptions = [
|
$serveraliasoptions = [
|
||||||
0 => lng('domains.serveraliasoption_wildcard'),
|
0 => lng('domains.serveraliasoption_wildcard'),
|
||||||
@@ -463,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
|
||||||
@@ -545,6 +510,12 @@ if ($page == 'domains' || $page == 'overview') {
|
|||||||
$result['temporary_ssl_redirect'] = $result['ssl_redirect'];
|
$result['temporary_ssl_redirect'] = $result['ssl_redirect'];
|
||||||
$result['ssl_redirect'] = ($result['ssl_redirect'] == 0 ? 0 : 1);
|
$result['ssl_redirect'] = ($result['ssl_redirect'] == 0 ? 0 : 1);
|
||||||
|
|
||||||
|
$openbasedir = [
|
||||||
|
0 => lng('domain.docroot'),
|
||||||
|
1 => lng('domain.homedir'),
|
||||||
|
2 => lng('domain.docparent')
|
||||||
|
];
|
||||||
|
|
||||||
$serveraliasoptions = [
|
$serveraliasoptions = [
|
||||||
0 => lng('domains.serveraliasoption_wildcard'),
|
0 => lng('domains.serveraliasoption_wildcard'),
|
||||||
1 => lng('domains.serveraliasoption_www'),
|
1 => lng('domains.serveraliasoption_www'),
|
||||||
@@ -664,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';
|
||||||
|
|||||||
168
admin_index.php
168
admin_index.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');
|
||||||
|
|
||||||
@@ -53,6 +53,7 @@ if ($action == 'logout') {
|
|||||||
if (is_array(CurrentUser::getField('switched_user'))) {
|
if (is_array(CurrentUser::getField('switched_user'))) {
|
||||||
$result = CurrentUser::getData();
|
$result = CurrentUser::getData();
|
||||||
$result = $result['switched_user'];
|
$result = $result['switched_user'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
||||||
$redirect = "admin_" . $target . ".php";
|
$redirect = "admin_" . $target . ".php";
|
||||||
@@ -196,107 +197,104 @@ 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();
|
||||||
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
|
||||||
|
|
||||||
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_ADMINS, 'adminid')) {
|
if (!empty($_POST)) {
|
||||||
Response::standardError('oldpasswordnotcorrect');
|
if ($_POST['send'] == 'changepassword') {
|
||||||
}
|
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
||||||
|
|
||||||
try {
|
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_ADMINS, 'adminid')) {
|
||||||
$new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
|
Response::standardError('oldpasswordnotcorrect');
|
||||||
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
|
}
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($old_password == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.old_password'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.new_password'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password_confirm == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.new_password_confirm'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password != $new_password_confirm) {
|
|
||||||
Response::standardError('newpasswordconfirmerror');
|
|
||||||
} else {
|
|
||||||
try {
|
try {
|
||||||
Admins::getLocal($userinfo, [
|
$new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
|
||||||
'id' => $userinfo['adminid'],
|
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
|
||||||
'admin_password' => $new_password
|
|
||||||
])->update();
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'changed password');
|
|
||||||
|
if ($old_password == '') {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'changepassword.old_password'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password == '') {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'changepassword.new_password'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password_confirm == '') {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'changepassword.new_password_confirm'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password != $new_password_confirm) {
|
||||||
|
Response::standardError('newpasswordconfirmerror');
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Admins::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['adminid'],
|
||||||
|
'admin_password' => $new_password
|
||||||
|
])->update();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'changed password');
|
||||||
|
Response::redirectTo($filename);
|
||||||
|
}
|
||||||
|
} elseif ($_POST['send'] == 'changetheme') {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her theme to '" . $theme . "'");
|
||||||
|
}
|
||||||
|
Response::redirectTo($filename);
|
||||||
|
} elseif ($_POST['send'] == 'changelanguage') {
|
||||||
|
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
||||||
|
|
||||||
|
if (isset($languages[$def_language])) {
|
||||||
|
try {
|
||||||
|
Admins::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['adminid'],
|
||||||
|
'def_language' => $def_language
|
||||||
|
])->update();
|
||||||
|
CurrentUser::setField('language', $def_language);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her default language to '" . $def_language . "'");
|
||||||
Response::redirectTo($filename);
|
Response::redirectTo($filename);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UI::view('user/change_password.html.twig');
|
// change theme
|
||||||
}
|
$default_theme = Settings::Get('panel.default_theme');
|
||||||
} elseif ($page == 'change_language') {
|
if ($userinfo['theme'] != '') {
|
||||||
$languages = Language::getLanguages();
|
$default_theme = $userinfo['theme'];
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
|
||||||
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
|
||||||
|
|
||||||
if (isset($languages[$def_language])) {
|
|
||||||
try {
|
|
||||||
Admins::getLocal($userinfo, [
|
|
||||||
'id' => $userinfo['adminid'],
|
|
||||||
'def_language' => $def_language
|
|
||||||
])->update();
|
|
||||||
CurrentUser::setField('language', $def_language);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her default language to '" . $def_language . "'");
|
$themes_avail = UI::getThemes();
|
||||||
Response::redirectTo($filename);
|
|
||||||
} else {
|
// 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') {
|
||||||
|
|||||||
@@ -142,8 +142,10 @@ if (($page == 'ipsandports' || $page == 'overview') && $userinfo['change_servers
|
|||||||
}
|
}
|
||||||
} elseif ($action == 'jqCheckIP') {
|
} elseif ($action == 'jqCheckIP') {
|
||||||
$ip = $_POST['ip'] ?? "";
|
$ip = $_POST['ip'] ?? "";
|
||||||
if ((filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) || filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE) == false) {
|
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
|
||||||
// returns notice if private network detected so we can display it
|
echo json_encode('<div id="ipnote" class="invalid-feedback">'.lng('error.invalidip', [$ip]).'</div>');
|
||||||
|
} elseif (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE)) {
|
||||||
|
// returns notice if private network detected, so we can display it
|
||||||
echo json_encode(lng('admin.ipsandports.ipnote'));
|
echo json_encode(lng('admin.ipsandports.ipnote'));
|
||||||
} else {
|
} else {
|
||||||
echo 0;
|
echo 0;
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -253,6 +254,9 @@ if ($action == '') {
|
|||||||
if (isset($_POST['prepare']) && $_POST['prepare'] == 'prepare') {
|
if (isset($_POST['prepare']) && $_POST['prepare'] == 'prepare') {
|
||||||
// email templates
|
// email templates
|
||||||
$language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
|
$language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
|
||||||
|
if (!array_key_exists($language, $languages)) {
|
||||||
|
Response::standardError('templatelanguageinvalid');
|
||||||
|
}
|
||||||
$template = Validate::validate($_POST['template'], 'template');
|
$template = Validate::validate($_POST['template'], 'template');
|
||||||
|
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
@@ -288,6 +292,9 @@ if ($action == '') {
|
|||||||
} elseif (isset($_POST['send']) && $_POST['send'] == 'send' && !isset($_POST['filesend'])) {
|
} elseif (isset($_POST['send']) && $_POST['send'] == 'send' && !isset($_POST['filesend'])) {
|
||||||
// email templates
|
// email templates
|
||||||
$language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
|
$language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
|
||||||
|
if (!array_key_exists($language, $languages)) {
|
||||||
|
Response::standardError('templatelanguageinvalid');
|
||||||
|
}
|
||||||
$template = Validate::validate($_POST['template'], 'template');
|
$template = Validate::validate($_POST['template'], 'template');
|
||||||
$subject = Validate::validate($_POST['subject'], 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate');
|
$subject = Validate::validate($_POST['subject'], 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate');
|
||||||
$mailbody = Validate::validate($_POST['mailbody'], 'mailbody', '/^[^\0]+$/', 'nomailbodycreate');
|
$mailbody = Validate::validate($_POST['mailbody'], 'mailbody', '/^[^\0]+$/', 'nomailbodycreate');
|
||||||
|
|||||||
@@ -24,18 +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 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\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, ">=")) {
|
||||||
@@ -51,12 +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());
|
];
|
||||||
|
// directory of commands to include
|
||||||
|
$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();
|
||||||
|
|||||||
@@ -45,15 +45,19 @@
|
|||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"ext-fileinfo": "*",
|
"ext-fileinfo": "*",
|
||||||
"ext-gmp": "*",
|
"ext-gmp": "*",
|
||||||
|
"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",
|
||||||
},
|
"amnuts/opcache-gui": "^3.4",
|
||||||
|
"league/commonmark": "^2.4"
|
||||||
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9",
|
"phpunit/phpunit": "^9",
|
||||||
"ext-pcntl": "*",
|
"ext-pcntl": "*",
|
||||||
|
|||||||
1421
composer.lock
generated
1421
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';
|
||||||
|
|||||||
@@ -26,9 +26,11 @@
|
|||||||
const AREA = 'customer';
|
const AREA = 'customer';
|
||||||
require __DIR__ . '/lib/init.php';
|
require __DIR__ . '/lib/init.php';
|
||||||
|
|
||||||
use Froxlor\Api\Commands\EmailAccounts as EmailAccounts;
|
use Froxlor\Api\Commands\EmailAccounts;
|
||||||
use Froxlor\Api\Commands\EmailForwarders as EmailForwarders;
|
use Froxlor\Api\Commands\EmailDomains;
|
||||||
use Froxlor\Api\Commands\Emails as Emails;
|
use Froxlor\Api\Commands\EmailForwarders;
|
||||||
|
use Froxlor\Api\Commands\Emails;
|
||||||
|
use Froxlor\CurrentUser;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\PhpHelper;
|
use Froxlor\PhpHelper;
|
||||||
@@ -40,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) {
|
||||||
@@ -50,13 +51,60 @@ if (Settings::IsInList('panel.customer_hide_options', 'email') || $userinfo['ema
|
|||||||
$id = (int)Request::any('id');
|
$id = (int)Request::any('id');
|
||||||
|
|
||||||
if ($page == 'overview' || $page == 'emails') {
|
if ($page == 'overview' || $page == 'emails') {
|
||||||
if ($action == '') {
|
$result_stmt = Database::prepare("
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_email::emails");
|
SELECT COUNT(DISTINCT `domainid`) as maildomains FROM `" . TABLE_MAIL_VIRTUAL . "` WHERE `customerid`= :cid
|
||||||
|
");
|
||||||
|
$domain_count = Database::pexecute_first($result_stmt, [
|
||||||
|
"cid" => $userinfo['customerid']
|
||||||
|
]);
|
||||||
|
if ($domain_count['maildomains'] && $domain_count['maildomains'] > 1) {
|
||||||
|
try {
|
||||||
|
$emaildomain_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.emails_overview.php';
|
||||||
|
$collection = (new Collection(EmailDomains::class, $userinfo))
|
||||||
|
->withPagination($emaildomain_list_data['emaildomain_list']['columns'],
|
||||||
|
$emaildomain_list_data['emaildomain_list']['default_sorting']);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions_links = [];
|
||||||
|
if (CurrentUser::canAddResource('emails')) {
|
||||||
|
$actions_links[] = [
|
||||||
|
'href' => $linker->getLink(['section' => 'email', 'page' => 'email_domain', 'action' => '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', [
|
||||||
|
'listing' => Listing::format($collection, $emaildomain_list_data, 'emaildomain_list'),
|
||||||
|
'actions_links' => $actions_links,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
// only emails for one domain -> show email address listing directly
|
||||||
|
$page = 'email_domain';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($page == 'email_domain') {
|
||||||
|
$email_domainid = Request::any('domainid', 0);
|
||||||
|
if ($action == '') {
|
||||||
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_email::emails");
|
||||||
|
|
||||||
|
$sql_search = [];
|
||||||
|
if ($email_domainid > 0) {
|
||||||
|
$sql_search = ['sql_search' => ['m.domainid' => ['op' => '=', 'value' => $email_domainid]]];
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
$email_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.emails.php';
|
$email_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.emails.php';
|
||||||
$collection = (new Collection(Emails::class, $userinfo))
|
$collection = (new Collection(Emails::class, $userinfo, $sql_search))
|
||||||
->withPagination($email_list_data['email_list']['columns'], $email_list_data['email_list']['default_sorting']);
|
->withPagination($email_list_data['email_list']['columns'],
|
||||||
|
$email_list_data['email_list']['default_sorting']);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
@@ -71,15 +119,30 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
]);
|
]);
|
||||||
$emaildomains_count = $result2['emaildomains'];
|
$emaildomains_count = $result2['emaildomains'];
|
||||||
|
|
||||||
$actions_links = false;
|
$actions_links = [];
|
||||||
if (CurrentUser::canAddResource('emails')) {
|
if ($email_domainid > 0) {
|
||||||
$actions_links = [
|
$actions_links[] = [
|
||||||
[
|
'class' => 'btn-outline-primary',
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => $page, 'action' => 'add']),
|
'href' => $linker->getLink([
|
||||||
'label' => lng('emails.emails_add')
|
'section' => 'email',
|
||||||
]
|
'page' => 'emails',
|
||||||
|
]),
|
||||||
|
'label' => lng('emails.back_to_overview'),
|
||||||
|
'icon' => 'fa-solid fa-reply'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
if (CurrentUser::canAddResource('emails')) {
|
||||||
|
$actions_links[] = [
|
||||||
|
'href' => $linker->getLink(['section' => 'email', 'page' => 'email_domain', 'action' => 'add', 'domainid' => $email_domainid]),
|
||||||
|
'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'),
|
||||||
@@ -145,7 +208,11 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
"cid" => $userinfo['customerid']
|
"cid" => $userinfo['customerid']
|
||||||
]);
|
]);
|
||||||
$domains = [];
|
$domains = [];
|
||||||
|
$selected_domain = "";
|
||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
if ($email_domainid == $row['id']) {
|
||||||
|
$selected_domain = $row['domain'];
|
||||||
|
}
|
||||||
$domains[$row['domain']] = $idna_convert->decode($row['domain']);
|
$domains[$row['domain']] = $idna_convert->decode($row['domain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,11 +311,13 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} elseif ($page == 'accounts') {
|
} elseif ($page == 'accounts') {
|
||||||
|
$email_domainid = Request::any('domainid', 0);
|
||||||
if ($action == 'add' && $id != 0) {
|
if ($action == 'add' && $id != 0) {
|
||||||
if ($userinfo['email_accounts'] == '-1' || ($userinfo['email_accounts_used'] < $userinfo['email_accounts'])) {
|
if ($userinfo['email_accounts'] == '-1' || ($userinfo['email_accounts_used'] < $userinfo['email_accounts'])) {
|
||||||
try {
|
try {
|
||||||
@@ -267,7 +336,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -292,7 +362,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink([
|
'href' => $linker->getLink([
|
||||||
'section' => 'email',
|
'section' => 'email',
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]),
|
]),
|
||||||
@@ -301,7 +372,11 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => 'emails']),
|
'href' => $linker->getLink([
|
||||||
|
'section' => 'email',
|
||||||
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid
|
||||||
|
]),
|
||||||
'label' => lng('menue.email.emails'),
|
'label' => lng('menue.email.emails'),
|
||||||
'icon' => 'fa-solid fa-envelope'
|
'icon' => 'fa-solid fa-envelope'
|
||||||
]
|
]
|
||||||
@@ -332,7 +407,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -350,7 +426,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink([
|
'href' => $linker->getLink([
|
||||||
'section' => 'email',
|
'section' => 'email',
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]),
|
]),
|
||||||
@@ -359,7 +436,11 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => 'emails']),
|
'href' => $linker->getLink([
|
||||||
|
'section' => 'email',
|
||||||
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid
|
||||||
|
]),
|
||||||
'label' => lng('menue.email.emails'),
|
'label' => lng('menue.email.emails'),
|
||||||
'icon' => 'fa-solid fa-envelope'
|
'icon' => 'fa-solid fa-envelope'
|
||||||
]
|
]
|
||||||
@@ -385,7 +466,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -403,7 +485,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink([
|
'href' => $linker->getLink([
|
||||||
'section' => 'email',
|
'section' => 'email',
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]),
|
]),
|
||||||
@@ -412,7 +495,11 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => 'emails']),
|
'href' => $linker->getLink([
|
||||||
|
'section' => 'email',
|
||||||
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid
|
||||||
|
]),
|
||||||
'label' => lng('menue.email.emails'),
|
'label' => lng('menue.email.emails'),
|
||||||
'icon' => 'fa-solid fa-envelope'
|
'icon' => 'fa-solid fa-envelope'
|
||||||
]
|
]
|
||||||
@@ -438,7 +525,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -446,12 +534,14 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
HTML::askYesNoWithCheckbox('email_reallydelete_account', 'admin_customer_alsoremovemail', $filename, [
|
HTML::askYesNoWithCheckbox('email_reallydelete_account', 'admin_customer_alsoremovemail', $filename, [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => $action
|
'action' => $action
|
||||||
], $idna_convert->decode($result['email_full']));
|
], $idna_convert->decode($result['email_full']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($page == 'forwarders') {
|
} elseif ($page == 'forwarders') {
|
||||||
|
$email_domainid = Request::any('domainid', 0);
|
||||||
if ($action == 'add' && $id != 0) {
|
if ($action == 'add' && $id != 0) {
|
||||||
if ($userinfo['email_forwarders_used'] < $userinfo['email_forwarders'] || $userinfo['email_forwarders'] == '-1') {
|
if ($userinfo['email_forwarders_used'] < $userinfo['email_forwarders'] || $userinfo['email_forwarders'] == '-1') {
|
||||||
try {
|
try {
|
||||||
@@ -471,7 +561,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -489,7 +580,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink([
|
'href' => $linker->getLink([
|
||||||
'section' => 'email',
|
'section' => 'email',
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]),
|
]),
|
||||||
@@ -498,7 +590,11 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'class' => 'btn-secondary',
|
'class' => 'btn-secondary',
|
||||||
'href' => $linker->getLink(['section' => 'email', 'page' => 'emails']),
|
'href' => $linker->getLink([
|
||||||
|
'section' => 'email',
|
||||||
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid
|
||||||
|
]),
|
||||||
'label' => lng('menue.email.emails'),
|
'label' => lng('menue.email.emails'),
|
||||||
'icon' => 'fa-solid fa-envelope'
|
'icon' => 'fa-solid fa-envelope'
|
||||||
]
|
]
|
||||||
@@ -540,7 +636,8 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
Response::redirectTo($filename, [
|
Response::redirectTo($filename, [
|
||||||
'page' => 'emails',
|
'page' => 'email_domain',
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => 'edit',
|
'action' => 'edit',
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -549,6 +646,7 @@ if ($page == 'overview' || $page == 'emails') {
|
|||||||
'id' => $id,
|
'id' => $id,
|
||||||
'forwarderid' => $forwarderid,
|
'forwarderid' => $forwarderid,
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
|
'domainid' => $email_domainid,
|
||||||
'action' => $action
|
'action' => $action
|
||||||
], $idna_convert->decode($result['email_full']) . ' -> ' . $idna_convert->decode($forwarder));
|
], $idna_convert->decode($result['email_full']) . ' -> ' . $idna_convert->decode($forwarder));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$actions_links = [];
|
||||||
|
$actions_links[] = [
|
||||||
|
'href' => $linker->getLink(['section' => 'extras', 'page' => 'htpasswds', 'action' => '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', [
|
UI::view('user/table.html.twig', [
|
||||||
'listing' => Listing::format($collection, $htpasswd_list_data, 'htpasswd_list'),
|
'listing' => Listing::format($collection, $htpasswd_list_data, 'htpasswd_list'),
|
||||||
'actions_links' => [
|
'actions_links' => $actions_links,
|
||||||
[
|
|
||||||
'href' => $linker->getLink(['section' => 'extras', 'page' => 'htpasswds', 'action' => 'add']),
|
|
||||||
'label' => lng('extras.directoryprotection_add')
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$actions_links = [];
|
||||||
|
$actions_links[] = [
|
||||||
|
'href' => $linker->getLink(['section' => 'extras', 'page' => 'htaccess', 'action' => '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', [
|
UI::view('user/table.html.twig', [
|
||||||
'listing' => Listing::format($collection, $htaccess_list_data, 'htaccess_list'),
|
'listing' => Listing::format($collection, $htaccess_list_data, 'htaccess_list'),
|
||||||
'actions_links' => [
|
'actions_links' => $actions_links,
|
||||||
[
|
|
||||||
'href' => $linker->getLink(['section' => 'extras', 'page' => 'htaccess', 'action' => 'add']),
|
|
||||||
'label' => lng('extras.pathoptions_add')
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'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,10 +38,9 @@ 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') || $userinfo['ftps'] == 0) {
|
if (Settings::IsInList('panel.customer_hide_options', 'ftp')) {
|
||||||
Response::redirectTo('customer_index.php');
|
Response::redirectTo('customer_index.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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'),
|
||||||
@@ -119,7 +123,7 @@ if ($page == 'overview' || $page == 'accounts') {
|
|||||||
if (Settings::Get('customer.ftpatdomain') == '1') {
|
if (Settings::Get('customer.ftpatdomain') == '1') {
|
||||||
$domainlist = [];
|
$domainlist = [];
|
||||||
$result_domains_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
$result_domains_stmt = Database::prepare("SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "`
|
||||||
WHERE `customerid`= :customerid");
|
WHERE `customerid`= :customerid ORDER BY `domain` ASC");
|
||||||
Database::pexecute($result_domains_stmt, [
|
Database::pexecute($result_domains_stmt, [
|
||||||
"customerid" => $userinfo['customerid']
|
"customerid" => $userinfo['customerid']
|
||||||
]);
|
]);
|
||||||
@@ -127,7 +131,6 @@ if ($page == 'overview' || $page == 'accounts') {
|
|||||||
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$domainlist[$row_domain['domain']] = $idna_convert->decode($row_domain['domain']);
|
$domainlist[$row_domain['domain']] = $idna_convert->decode($row_domain['domain']);
|
||||||
}
|
}
|
||||||
sort($domainlist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::Get('system.allow_customer_shell') == '1') {
|
if (Settings::Get('system.allow_customer_shell') == '1') {
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -52,6 +52,7 @@ if ($action == 'logout') {
|
|||||||
if (is_array(CurrentUser::getField('switched_user'))) {
|
if (is_array(CurrentUser::getField('switched_user'))) {
|
||||||
$result = CurrentUser::getData();
|
$result = CurrentUser::getData();
|
||||||
$result = $result['switched_user'];
|
$result = $result['switched_user'];
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($result);
|
CurrentUser::setData($result);
|
||||||
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
|
||||||
$redirect = "admin_" . $target . ".php";
|
$redirect = "admin_" . $target . ".php";
|
||||||
@@ -65,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
|
||||||
@@ -113,12 +114,21 @@ 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['dbspace_used'] = $usages['mysql'] * 1024;
|
||||||
$userinfo['total_bytes_used'] = ($usages['webspace'] + $usages['mail'] + $usages['mysql']) * 1024;
|
$userinfo['total_bytes_used'] = ($usages['webspace'] + $usages['mail'] + $usages['mysql']) * 1024;
|
||||||
} else {
|
} else {
|
||||||
$userinfo['diskspace_bytes_used'] = 0;
|
$userinfo['diskspace_bytes_used'] = 0;
|
||||||
$userinfo['total_bytes_used'] = 0;
|
$userinfo['total_bytes_used'] = 0;
|
||||||
|
$userinfo['mailspace_used'] = 0;
|
||||||
|
$userinfo['dbspace_used'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::twig()->addGlobal('userinfo', $userinfo);
|
UI::twig()->addGlobal('userinfo', $userinfo);
|
||||||
@@ -126,141 +136,138 @@ 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();
|
||||||
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
|
||||||
|
|
||||||
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) {
|
if (!empty($_POST)) {
|
||||||
Response::standardError('oldpasswordnotcorrect');
|
if ($_POST['send'] == 'changepassword') {
|
||||||
}
|
$old_password = Validate::validate($_POST['old_password'], 'old password');
|
||||||
|
|
||||||
try {
|
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) {
|
||||||
$new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
|
Response::standardError('oldpasswordnotcorrect');
|
||||||
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
|
}
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($old_password == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.old_password'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.new_password'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password_confirm == '') {
|
|
||||||
Response::standardError([
|
|
||||||
'stringisempty',
|
|
||||||
'changepassword.new_password_confirm'
|
|
||||||
]);
|
|
||||||
} elseif ($new_password != $new_password_confirm) {
|
|
||||||
Response::standardError('newpasswordconfirmerror');
|
|
||||||
} else {
|
|
||||||
// Update user password
|
|
||||||
try {
|
try {
|
||||||
Customers::getLocal($userinfo, [
|
$new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
|
||||||
'id' => $userinfo['customerid'],
|
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
|
||||||
'new_customer_password' => $new_password
|
|
||||||
])->update();
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed password');
|
|
||||||
|
|
||||||
// Update ftp password
|
if ($old_password == '') {
|
||||||
if (isset($_POST['change_main_ftp']) && $_POST['change_main_ftp'] == 'true') {
|
Response::standardError([
|
||||||
$cryptPassword = Crypt::makeCryptPassword($new_password);
|
'stringisempty',
|
||||||
$stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "`
|
'changepassword.old_password'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password == '') {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'changepassword.new_password'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password_confirm == '') {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'changepassword.new_password_confirm'
|
||||||
|
]);
|
||||||
|
} elseif ($new_password != $new_password_confirm) {
|
||||||
|
Response::standardError('newpasswordconfirmerror');
|
||||||
|
} else {
|
||||||
|
// Update user password
|
||||||
|
try {
|
||||||
|
Customers::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['customerid'],
|
||||||
|
'new_customer_password' => $new_password
|
||||||
|
])->update();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed password');
|
||||||
|
|
||||||
|
// Update ftp password
|
||||||
|
if (isset($_POST['change_main_ftp']) && $_POST['change_main_ftp'] == 'true') {
|
||||||
|
$cryptPassword = Crypt::makeCryptPassword($new_password);
|
||||||
|
$stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "`
|
||||||
SET `password` = :password
|
SET `password` = :password
|
||||||
WHERE `customerid` = :customerid
|
WHERE `customerid` = :customerid
|
||||||
AND `username` = :username");
|
AND `username` = :username");
|
||||||
$params = [
|
$params = [
|
||||||
"password" => $cryptPassword,
|
"password" => $cryptPassword,
|
||||||
"customerid" => $userinfo['customerid'],
|
"customerid" => $userinfo['customerid'],
|
||||||
"username" => $userinfo['loginname']
|
"username" => $userinfo['loginname']
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params);
|
Database::pexecute($stmt, $params);
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed main ftp password');
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed main ftp password');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update statistics password
|
// Update statistics password
|
||||||
if (isset($_POST['change_stats']) && $_POST['change_stats'] == 'true') {
|
if (isset($_POST['change_stats']) && $_POST['change_stats'] == 'true') {
|
||||||
$new_stats_password = Crypt::makeCryptPassword($new_password, true);
|
$new_stats_password = Crypt::makeCryptPassword($new_password, true);
|
||||||
|
|
||||||
$stmt = Database::prepare("UPDATE `" . TABLE_PANEL_HTPASSWDS . "`
|
$stmt = Database::prepare("UPDATE `" . TABLE_PANEL_HTPASSWDS . "`
|
||||||
SET `password` = :password
|
SET `password` = :password
|
||||||
WHERE `customerid` = :customerid
|
WHERE `customerid` = :customerid
|
||||||
AND `username` = :username");
|
AND `username` = :username");
|
||||||
$params = [
|
$params = [
|
||||||
"password" => $new_stats_password,
|
"password" => $new_stats_password,
|
||||||
"customerid" => $userinfo['customerid'],
|
"customerid" => $userinfo['customerid'],
|
||||||
"username" => $userinfo['loginname']
|
"username" => $userinfo['loginname']
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params);
|
Database::pexecute($stmt, $params);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Response::redirectTo($filename);
|
||||||
|
}
|
||||||
|
} elseif ($_POST['send'] == 'changetheme') {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default theme to '" . $theme . "'");
|
||||||
|
}
|
||||||
|
Response::redirectTo($filename);
|
||||||
|
} elseif ($_POST['send'] == 'changelanguage') {
|
||||||
|
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
||||||
|
if (isset($languages[$def_language])) {
|
||||||
|
try {
|
||||||
|
Customers::getLocal($userinfo, [
|
||||||
|
'id' => $userinfo['customerid'],
|
||||||
|
'def_language' => $def_language
|
||||||
|
])->update();
|
||||||
|
CurrentUser::setField('language', $def_language);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Response::dynamicError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default language to '" . $def_language . "'");
|
||||||
Response::redirectTo($filename);
|
Response::redirectTo($filename);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UI::view('user/change_password.html.twig');
|
// change theme
|
||||||
}
|
$default_theme = Settings::Get('panel.default_theme');
|
||||||
} elseif ($page == 'change_language') {
|
if ($userinfo['theme'] != '') {
|
||||||
$languages = Language::getLanguages();
|
$default_theme = $userinfo['theme'];
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
|
||||||
$def_language = Validate::validate($_POST['def_language'], 'default language');
|
|
||||||
if (isset($languages[$def_language])) {
|
|
||||||
try {
|
|
||||||
Customers::getLocal($userinfo, [
|
|
||||||
'id' => $userinfo['customerid'],
|
|
||||||
'def_language' => $def_language
|
|
||||||
])->update();
|
|
||||||
CurrentUser::setField('language', $def_language);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Response::dynamicError($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default language to '" . $def_language . "'");
|
$themes_avail = UI::getThemes();
|
||||||
Response::redirectTo($filename);
|
|
||||||
} else {
|
// 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 */
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ if ($action == 'add_record' && !empty($_POST)) {
|
|||||||
try {
|
try {
|
||||||
$dns_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/tablelisting.dns.php';
|
$dns_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/tablelisting.dns.php';
|
||||||
$collection = (new Collection(DomainZones::class, $userinfo, ['id' => $domain_id]))
|
$collection = (new Collection(DomainZones::class, $userinfo, ['id' => $domain_id]))
|
||||||
->withPagination($dns_list_data['dns_list']['columns'], $dns_list_data['dns_list']['default_sorting']);
|
->withPagination($dns_list_data['dns_list']['columns'], $dns_list_data['dns_list']['default_sorting'], ['domain_id='.$domain_id]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::dynamicError($e->getMessage());
|
Response::dynamicError($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use Froxlor\Froxlor;
|
|||||||
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\Database\Database;
|
||||||
|
|
||||||
// This file is being included in admin_domains and customer_domains
|
// This file is being included in admin_domains and customer_domains
|
||||||
// and therefore does not need to require lib/init.php
|
// and therefore does not need to require lib/init.php
|
||||||
|
|||||||
181
index.php
181
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,10 +38,10 @@ 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;
|
||||||
use Froxlor\Language;
|
|
||||||
|
|
||||||
if ($action == '') {
|
if ($action == '') {
|
||||||
$action = 'login';
|
$action = 'login';
|
||||||
@@ -53,9 +54,15 @@ if ($action == '2fa_entercode') {
|
|||||||
Response::redirectTo('index.php');
|
Response::redirectTo('index.php');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
$smessage = isset($_GET['showmessage']) ? (int)$_GET['showmessage'] : 0;
|
||||||
|
$message = "";
|
||||||
|
if ($smessage > 0) {
|
||||||
|
$message = lng('error.2fa_wrongcode');
|
||||||
|
}
|
||||||
// show template to enter code
|
// show template to enter code
|
||||||
UI::view('login/enter2fa.html.twig', [
|
UI::view('login/enter2fa.html.twig', [
|
||||||
'pagetitle' => lng('login.2fa')
|
'pagetitle' => lng('login.2fa'),
|
||||||
|
'message' => $message
|
||||||
]);
|
]);
|
||||||
} elseif ($action == '2fa_verify') {
|
} elseif ($action == '2fa_verify') {
|
||||||
// verify code from 2fa code-enter form
|
// verify code from 2fa code-enter form
|
||||||
@@ -67,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
|
||||||
|
$table = $_SESSION['uidtable_2fa'];
|
||||||
|
$field = $_SESSION['uidfield_2fa'];
|
||||||
|
$uid = $_SESSION['uid_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) {
|
||||||
// get user-data
|
|
||||||
$table = $_SESSION['uidtable_2fa'];
|
|
||||||
$field = $_SESSION['uidfield_2fa'];
|
|
||||||
$uid = $_SESSION['uid_2fa'];
|
|
||||||
$isadmin = $_SESSION['unfo_2fa'];
|
|
||||||
$sel_param = [
|
$sel_param = [
|
||||||
'uid' => $uid
|
'uid' => $uid
|
||||||
];
|
];
|
||||||
if ($_SESSION['secret_2fa'] == 'email') {
|
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid");
|
||||||
// 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");
|
|
||||||
}
|
|
||||||
$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)) {
|
||||||
@@ -108,19 +114,54 @@ if ($action == '2fa_entercode') {
|
|||||||
|
|
||||||
// when using email-2fa, remove the one-time-code
|
// when using email-2fa, remove the one-time-code
|
||||||
if ($userinfo['type_2fa'] == '1') {
|
if ($userinfo['type_2fa'] == '1') {
|
||||||
$del_stmt = Database::prepare("UPDATE $table SET `data_2fa` = '' WHERE `" . $field . "` = :uid");
|
$del_stmt = Database::prepare("UPDATE " . $table . " SET `data_2fa` = '' WHERE `" . $field . "` = :uid");
|
||||||
$userinfo = Database::pexecute_first($del_stmt, [
|
$userinfo = Database::pexecute_first($del_stmt, [
|
||||||
'uid' => $uid
|
'uid' => $uid
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
// wrong 2fa code - treat like "wrong password"
|
||||||
|
$stmt = Database::prepare("
|
||||||
|
UPDATE " . $table . "
|
||||||
|
SET `lastlogin_fail`= :lastlogin_fail, `loginfail_count`=`loginfail_count`+1
|
||||||
|
WHERE `" . $field . "`= :uid
|
||||||
|
");
|
||||||
|
Database::pexecute($stmt, [
|
||||||
|
"lastlogin_fail" => time(),
|
||||||
|
"uid" => $uid
|
||||||
|
]);
|
||||||
|
|
||||||
|
// get data for processing further
|
||||||
|
$stmt = Database::prepare("
|
||||||
|
SELECT `loginname`, `loginfail_count`, `lastlogin_fail` FROM " . $table . "
|
||||||
|
WHERE `" . $field . "`= :uid
|
||||||
|
");
|
||||||
|
$fail_user = Database::pexecute_first($stmt, [
|
||||||
|
"uid" => $uid
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($fail_user['loginfail_count'] >= Settings::Get('login.maxloginattempts') && $fail_user['lastlogin_fail'] > (time() - Settings::Get('login.deactivatetime'))) {
|
||||||
|
// Log failed login
|
||||||
|
$rstlog = FroxlorLogger::getInstanceOf([
|
||||||
|
'loginname' => $_SERVER['REMOTE_ADDR']
|
||||||
|
]);
|
||||||
|
$rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "User '" . $fail_user['loginname'] . "' entered wrong 2fa code too often.");
|
||||||
|
unset($fail_user);
|
||||||
|
Response::redirectTo('index.php', [
|
||||||
|
'showmessage' => '3'
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
unset($fail_user);
|
||||||
|
// back to form
|
||||||
Response::redirectTo('index.php', [
|
Response::redirectTo('index.php', [
|
||||||
'showmessage' => '2'
|
'action' => '2fa_entercode',
|
||||||
|
'showmessage' => '1'
|
||||||
]);
|
]);
|
||||||
exit();
|
exit();
|
||||||
} elseif ($action == 'login') {
|
} elseif ($action == 'login') {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (!empty($_POST)) {
|
||||||
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
||||||
$password = Validate::validate($_POST['password'], 'password');
|
$password = Validate::validate($_POST['password'], 'password');
|
||||||
|
|
||||||
@@ -207,7 +248,7 @@ if ($action == '2fa_entercode') {
|
|||||||
$rstlog = FroxlorLogger::getInstanceOf([
|
$rstlog = FroxlorLogger::getInstanceOf([
|
||||||
'loginname' => $_SERVER['REMOTE_ADDR']
|
'loginname' => $_SERVER['REMOTE_ADDR']
|
||||||
]);
|
]);
|
||||||
$rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "Unknown user '" . $loginname . "' tried to login.");
|
$rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "Unknown user tried to login.");
|
||||||
|
|
||||||
Response::redirectTo('index.php', [
|
Response::redirectTo('index.php', [
|
||||||
'showmessage' => '2'
|
'showmessage' => '2'
|
||||||
@@ -264,7 +305,7 @@ if ($action == '2fa_entercode') {
|
|||||||
$rstlog = FroxlorLogger::getInstanceOf([
|
$rstlog = FroxlorLogger::getInstanceOf([
|
||||||
'loginname' => $_SERVER['REMOTE_ADDR']
|
'loginname' => $_SERVER['REMOTE_ADDR']
|
||||||
]);
|
]);
|
||||||
$rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "User '" . $loginname . "' tried to login with wrong password.");
|
$rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "User tried to login with wrong password.");
|
||||||
|
|
||||||
unset($userinfo);
|
unset($userinfo);
|
||||||
Response::redirectTo('index.php', [
|
Response::redirectTo('index.php', [
|
||||||
@@ -285,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
|
||||||
@@ -390,13 +432,18 @@ if ($action == '2fa_entercode') {
|
|||||||
}
|
}
|
||||||
$lastqrystr = "";
|
$lastqrystr = "";
|
||||||
if (isset($_REQUEST['qrystr']) && $_REQUEST['qrystr'] != "") {
|
if (isset($_REQUEST['qrystr']) && $_REQUEST['qrystr'] != "") {
|
||||||
$lastqrystr = htmlspecialchars($_REQUEST['qrystr'], ENT_QUOTES);
|
$lastqrystr = urlencode($_REQUEST['qrystr']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($lastscript)) {
|
||||||
|
$_SESSION['lastscript'] = $lastscript;
|
||||||
|
}
|
||||||
|
if (!empty($lastqrystr)) {
|
||||||
|
$_SESSION['lastqrystr'] = $lastqrystr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::view('login/login.html.twig', [
|
UI::view('login/login.html.twig', [
|
||||||
'pagetitle' => 'Login',
|
'pagetitle' => 'Login',
|
||||||
'lastscript' => $lastscript,
|
|
||||||
'lastqrystr' => $lastqrystr,
|
|
||||||
'upd_in_progress' => $update_in_progress,
|
'upd_in_progress' => $update_in_progress,
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
'successmsg' => $successmessage
|
'successmsg' => $successmessage
|
||||||
@@ -408,7 +455,7 @@ if ($action == 'forgotpwd') {
|
|||||||
$adminchecked = false;
|
$adminchecked = false;
|
||||||
$message = '';
|
$message = '';
|
||||||
|
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (!empty($_POST)) {
|
||||||
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
$loginname = Validate::validate($_POST['loginname'], 'loginname');
|
||||||
$email = Validate::validateEmail($_POST['loginemail']);
|
$email = Validate::validateEmail($_POST['loginemail']);
|
||||||
$result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "`
|
$result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "`
|
||||||
@@ -577,7 +624,7 @@ if ($action == 'forgotpwd') {
|
|||||||
$rstlog = FroxlorLogger::getInstanceOf([
|
$rstlog = FroxlorLogger::getInstanceOf([
|
||||||
'loginname' => 'password_reset'
|
'loginname' => 'password_reset'
|
||||||
]);
|
]);
|
||||||
$rstlog->logAction(FroxlorLogger::USR_ACTION, LOG_WARNING, "User '" . $loginname . "' requested to set a new password, but was not found in database!");
|
$rstlog->logAction(FroxlorLogger::USR_ACTION, LOG_WARNING, "Unknown user requested to set a new password, but was not found in database!");
|
||||||
$message = lng('login.usernotfound');
|
$message = lng('login.usernotfound');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,7 +639,7 @@ if ($action == 'forgotpwd') {
|
|||||||
|
|
||||||
UI::view('login/fpwd.html.twig', [
|
UI::view('login/fpwd.html.twig', [
|
||||||
'pagetitle' => lng('login.presend'),
|
'pagetitle' => lng('login.presend'),
|
||||||
'action' => $action,
|
'formaction' => 'index.php?action=' . $action,
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -615,7 +662,7 @@ if ($action == 'resetpwd') {
|
|||||||
$check = substr($activationcode, 40, 10);
|
$check = substr($activationcode, 40, 10);
|
||||||
|
|
||||||
if (substr(md5($third . $timestamp), 0, 10) == $check && $timestamp >= time() - 86400) {
|
if (substr(md5($third . $timestamp), 0, 10) == $check && $timestamp >= time() - 86400) {
|
||||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
if (!empty($_POST)) {
|
||||||
$stmt = Database::prepare("SELECT `userid`, `admin` FROM `" . TABLE_PANEL_ACTIVATION . "`
|
$stmt = Database::prepare("SELECT `userid`, `admin` FROM `" . TABLE_PANEL_ACTIVATION . "`
|
||||||
WHERE `activationcode` = :activationcode");
|
WHERE `activationcode` = :activationcode");
|
||||||
$result = Database::pexecute_first($stmt, [
|
$result = Database::pexecute_first($stmt, [
|
||||||
@@ -689,9 +736,62 @@ 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'] != '') {
|
||||||
|
session_regenerate_id(true);
|
||||||
CurrentUser::setData($userinfo);
|
CurrentUser::setData($userinfo);
|
||||||
|
|
||||||
$language = $userinfo['def_language'] ?? Settings::Get('panel.standardlanguage');
|
$language = $userinfo['def_language'] ?? Settings::Get('panel.standardlanguage');
|
||||||
@@ -705,29 +805,34 @@ function finishLogin($userinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
$qryparams = [];
|
$qryparams = [];
|
||||||
if (isset($_POST['qrystr']) && $_POST['qrystr'] != "") {
|
if (!empty($_SESSION['lastqrystr'])) {
|
||||||
parse_str(urldecode($_POST['qrystr']), $qryparams);
|
parse_str(urldecode($_SESSION['lastqrystr']), $qryparams);
|
||||||
|
unset($_SESSION['lastqrystr']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($userinfo['adminsession'] == '1') {
|
if ($userinfo['adminsession'] == '1') {
|
||||||
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
||||||
Response::redirectTo('admin_updates.php?page=overview');
|
Response::redirectTo('admin_updates.php?page=overview');
|
||||||
} else {
|
} else {
|
||||||
if (isset($_POST['script']) && $_POST['script'] != "") {
|
if (!empty($_SESSION['lastscript'])) {
|
||||||
if (preg_match("/customer\_/", $_POST['script']) === 1) {
|
$lastscript = $_SESSION['lastscript'];
|
||||||
|
unset($_SESSION['lastscript']);
|
||||||
|
if (preg_match("/customer\_/", $lastscript) === 1) {
|
||||||
Response::redirectTo('admin_customers.php', [
|
Response::redirectTo('admin_customers.php', [
|
||||||
"page" => "customers"
|
"page" => "customers"
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
Response::redirectTo($_POST['script'], $qryparams);
|
Response::redirectTo($lastscript, $qryparams);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Response::redirectTo('admin_index.php', $qryparams);
|
Response::redirectTo('admin_index.php', $qryparams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isset($_POST['script']) && $_POST['script'] != "") {
|
if (!empty($_SESSION['lastscript'])) {
|
||||||
Response::redirectTo($_POST['script'], $qryparams);
|
$lastscript = $_SESSION['lastscript'];
|
||||||
|
unset($_SESSION['lastscript']);
|
||||||
|
Response::redirectTo($lastscript, $qryparams);
|
||||||
} else {
|
} else {
|
||||||
Response::redirectTo('customer_index.php', $qryparams);
|
Response::redirectTo('customer_index.php', $qryparams);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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', ''),
|
||||||
@@ -642,12 +623,12 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'leprivatekey', 'unset'),
|
('system', 'leprivatekey', 'unset'),
|
||||||
('system', 'lepublickey', 'unset'),
|
('system', 'lepublickey', 'unset'),
|
||||||
('system', 'letsencryptca', 'letsencrypt'),
|
('system', 'letsencryptca', 'letsencrypt'),
|
||||||
('system', 'letsencryptchallengepath', '/var/www/froxlor'),
|
('system', 'letsencryptchallengepath', '/var/www/html/froxlor'),
|
||||||
('system', 'letsencryptkeysize', '4096'),
|
('system', 'letsencryptkeysize', '4096'),
|
||||||
('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', ''),
|
||||||
@@ -670,6 +651,7 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'leaccount', ''),
|
('system', 'leaccount', ''),
|
||||||
('system', 'nssextrausers', '1'),
|
('system', 'nssextrausers', '1'),
|
||||||
('system', 'le_domain_dnscheck', '1'),
|
('system', 'le_domain_dnscheck', '1'),
|
||||||
|
('system', 'le_domain_dnscheck_resolver', '1.1.1.1'),
|
||||||
('system', 'ssl_protocols', 'TLSv1.2'),
|
('system', 'ssl_protocols', 'TLSv1.2'),
|
||||||
('system', 'tlsv13_cipher_list', ''),
|
('system', 'tlsv13_cipher_list', ''),
|
||||||
('system', 'honorcipherorder', '0'),
|
('system', 'honorcipherorder', '0'),
|
||||||
@@ -696,12 +678,15 @@ 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.6'),
|
('system', 'update_notify_last', ''),
|
||||||
('system', 'traffictool', 'goaccess'),
|
('system', 'traffictool', 'goaccess'),
|
||||||
|
('system', 'req_limit_per_interval', 60),
|
||||||
|
('system', 'req_limit_interval', 60),
|
||||||
('api', 'enabled', '0'),
|
('api', 'enabled', '0'),
|
||||||
|
('api', 'customer_default', '1'),
|
||||||
('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', ''),
|
||||||
@@ -740,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.6'),
|
('panel', 'menu_collapsed', '1'),
|
||||||
('panel', 'db_version', '202212060');
|
('panel', 'version', '2.1.9'),
|
||||||
|
('panel', 'db_version', '202312120');
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_tasks`;
|
DROP TABLE IF EXISTS `panel_tasks`;
|
||||||
@@ -764,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;
|
||||||
@@ -910,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`;
|
||||||
@@ -981,7 +968,9 @@ CREATE TABLE IF NOT EXISTS `domain_ssl_settings` (
|
|||||||
`ssl_cert_chainfile` mediumtext,
|
`ssl_cert_chainfile` mediumtext,
|
||||||
`ssl_csr_file` mediumtext,
|
`ssl_csr_file` mediumtext,
|
||||||
`ssl_fullchain_file` mediumtext,
|
`ssl_fullchain_file` mediumtext,
|
||||||
`expirationdate` datetime DEFAULT NULL,
|
`validfromdate` datetime DEFAULT NULL,
|
||||||
|
`validtodate` datetime DEFAULT NULL,
|
||||||
|
`issuer` varchar(255) NOT NULL default '',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY (`domainid`)
|
UNIQUE KEY (`domainid`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
@@ -1046,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,6 +23,7 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Froxlor\Http\RateLimiter;
|
||||||
use Froxlor\UI\Panel\UI;
|
use Froxlor\UI\Panel\UI;
|
||||||
use Froxlor\Install\Install;
|
use Froxlor\Install\Install;
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ require dirname(__DIR__) . '/lib/tables.inc.php';
|
|||||||
// init twig
|
// init twig
|
||||||
UI::initTwig(true);
|
UI::initTwig(true);
|
||||||
UI::sendHeaders();
|
UI::sendHeaders();
|
||||||
|
RateLimiter::run(true);
|
||||||
|
|
||||||
$installer = new Install();
|
$installer = new Install();
|
||||||
$installer->handle();
|
$installer->handle();
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\FileDir;
|
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Settings;
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Install\Update;
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
use Froxlor\System\IPTools;
|
use Froxlor\System\IPTools;
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\FileDir;
|
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\Settings;
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
use Froxlor\Install\Update;
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
|
||||||
if (!defined('_CRON_UPDATE')) {
|
if (!defined('_CRON_UPDATE')) {
|
||||||
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
|
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
|
||||||
@@ -38,10 +38,9 @@ if (!defined('_CRON_UPDATE')) {
|
|||||||
|
|
||||||
// last 0.10.x release
|
// last 0.10.x release
|
||||||
if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
||||||
|
|
||||||
$update_to = '2.0.0-beta1';
|
$update_to = '2.0.0-beta1';
|
||||||
|
|
||||||
Update::showUpdateStep("Updating from 0.10.38.3 to ".$update_to, false);
|
Update::showUpdateStep("Updating from 0.10.38.3 to " . $update_to, false);
|
||||||
|
|
||||||
Update::showUpdateStep("Removing unused table");
|
Update::showUpdateStep("Removing unused table");
|
||||||
Database::query("DROP TABLE IF EXISTS `panel_sessions`;");
|
Database::query("DROP TABLE IF EXISTS `panel_sessions`;");
|
||||||
@@ -83,7 +82,7 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` DROP COLUMN `domains_see_all`;");
|
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` DROP COLUMN `domains_see_all`;");
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
Update::showUpdateStep("Checking for multiple mysql-servers to allow acccess to customers for existing databases");
|
Update::showUpdateStep("Checking for multiple mysql-servers to allow access to customers for existing databases");
|
||||||
$dbservers_stmt = Database::query("
|
$dbservers_stmt = Database::query("
|
||||||
SELECT `customerid`,
|
SELECT `customerid`,
|
||||||
GROUP_CONCAT(DISTINCT `dbserver` SEPARATOR ',') as allowed_mysqlserver
|
GROUP_CONCAT(DISTINCT `dbserver` SEPARATOR ',') as allowed_mysqlserver
|
||||||
@@ -94,7 +93,8 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
if (isset($dbserver['allowed_mysqlserver']) && !empty($dbserver['allowed_mysqlserver'])) {
|
if (isset($dbserver['allowed_mysqlserver']) && !empty($dbserver['allowed_mysqlserver'])) {
|
||||||
$allowed_mysqlserver = json_encode(explode(",", $dbserver['allowed_mysqlserver']));
|
$allowed_mysqlserver = json_encode(explode(",", $dbserver['allowed_mysqlserver']));
|
||||||
Database::pexecute($upd_stmt, ['allowed_mysql_server' => $allowed_mysqlserver, 'customerid' => $dbserver['customerid']]);
|
Database::pexecute($upd_stmt,
|
||||||
|
['allowed_mysql_server' => $allowed_mysqlserver, 'customerid' => $dbserver['customerid']]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
@@ -141,14 +141,15 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
// none of the files existed
|
// none of the files existed
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
} else {
|
} else {
|
||||||
Update::lastStepStatus(1, 'manual commands needed', 'Please run the following commands manually:<br><pre>' . $del_list . '</pre>');
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Update::showUpdateStep("Adding new settings");
|
Update::showUpdateStep("Adding new settings");
|
||||||
$panel_settings_mode = isset($_POST['panel_settings_mode']) ? (int) $_POST['panel_settings_mode'] : 0;
|
$panel_settings_mode = isset($_POST['panel_settings_mode']) ? (int)$_POST['panel_settings_mode'] : 0;
|
||||||
Settings::AddNew("panel.settings_mode", $panel_settings_mode);
|
Settings::AddNew("panel.settings_mode", $panel_settings_mode);
|
||||||
$system_distribution = isset($_POST['system_distribution']) ? $_POST['system_distribution'] : '';
|
$system_distribution = isset($_POST['system_distribution']) ? $_POST['system_distribution'] : 'bullseye';
|
||||||
Settings::AddNew("system.distribution", $system_distribution);
|
Settings::AddNew("system.distribution", $system_distribution);
|
||||||
Settings::AddNew("system.update_channel", 'stable');
|
Settings::AddNew("system.update_channel", 'stable');
|
||||||
Settings::AddNew("system.updatecheck_data", '');
|
Settings::AddNew("system.updatecheck_data", '');
|
||||||
@@ -193,7 +194,6 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Froxlor::isDatabaseVersion('202112310')) {
|
if (Froxlor::isDatabaseVersion('202112310')) {
|
||||||
|
|
||||||
Update::showUpdateStep("Adjusting traffic tool settings");
|
Update::showUpdateStep("Adjusting traffic tool settings");
|
||||||
$traffic_tool = Settings::Get('system.awstats_enabled') == 1 ? 'awstats' : 'webalizer';
|
$traffic_tool = Settings::Get('system.awstats_enabled') == 1 ? 'awstats' : 'webalizer';
|
||||||
Settings::AddNew("system.traffictool", $traffic_tool);
|
Settings::AddNew("system.traffictool", $traffic_tool);
|
||||||
@@ -204,20 +204,31 @@ if (Froxlor::isDatabaseVersion('202112310')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Froxlor::isDatabaseVersion('202211030')) {
|
if (Froxlor::isDatabaseVersion('202211030')) {
|
||||||
|
|
||||||
Update::showUpdateStep("Creating backward compatibility for cronjob");
|
Update::showUpdateStep("Creating backward compatibility for cronjob");
|
||||||
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
|
$disabled = explode(',', ini_get('disable_functions'));
|
||||||
mkdir($complete_filedir, 0750, true);
|
$exec_allowed = !in_array('exec', $disabled);
|
||||||
$newCronBin = Froxlor::getInstallDir().'/bin/froxlor-cli';
|
// check whether old files could be deleted in previous updates and if not,
|
||||||
$compCron = <<<EOF
|
// user should run cron to regenerate cron.d-file manually as he will run
|
||||||
|
// the other commands manually only after the update so this file would be deleted too
|
||||||
|
if ($exec_allowed) {
|
||||||
|
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
|
||||||
|
mkdir($complete_filedir, 0750, true);
|
||||||
|
$newCronBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
|
||||||
|
$compCron = <<<EOF
|
||||||
<?php
|
<?php
|
||||||
chmod('$newCronBin', 0755);
|
chmod('$newCronBin', 0755);
|
||||||
// re-create cron.d configuration file
|
// re-create cron.d configuration file
|
||||||
exec('$newCronBin froxlor:cron -r 99');
|
exec('$newCronBin froxlor:cron -r 99');
|
||||||
exit;
|
exit;
|
||||||
EOF;
|
EOF;
|
||||||
file_put_contents($complete_filedir.'/froxlor_master_cronjob.php', $compCron);
|
file_put_contents($complete_filedir . '/froxlor_master_cronjob.php', $compCron);
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
||||||
|
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
||||||
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
||||||
|
}
|
||||||
|
|
||||||
Froxlor::updateToDbVersion('202212060');
|
Froxlor::updateToDbVersion('202212060');
|
||||||
}
|
}
|
||||||
@@ -257,20 +268,28 @@ if (Froxlor::isFroxlorVersion('2.0.3')) {
|
|||||||
|
|
||||||
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
|
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
|
||||||
// check if compat. cronjob still exists (most likely didn't run successfully b/c of error from former 2.0 release)
|
// check if compat. cronjob still exists (most likely didn't run successfully b/c of error from former 2.0 release)
|
||||||
if (@file_exists($complete_filedir.'/froxlor_master_cronjob.php')) {
|
if (@file_exists($complete_filedir . '/froxlor_master_cronjob.php')) {
|
||||||
Update::showUpdateStep("Adjusting backward compatibility for cronjob");
|
Update::showUpdateStep("Adjusting backward compatibility for cronjob");
|
||||||
$newCronBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
|
$disabled = explode(',', ini_get('disable_functions'));
|
||||||
$compCron = <<<EOF
|
$exec_allowed = !in_array('exec', $disabled);
|
||||||
|
if ($exec_allowed) {
|
||||||
|
$newCronBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
|
||||||
|
$compCron = <<<EOF
|
||||||
<?php
|
<?php
|
||||||
chmod('$newCronBin', 0755);
|
chmod('$newCronBin', 0755);
|
||||||
// re-create cron.d configuration file
|
// re-create cron.d configuration file
|
||||||
exec('$newCronBin froxlor:cron -r 99');
|
exec('$newCronBin froxlor:cron -r 99');
|
||||||
exit;
|
exit;
|
||||||
EOF;
|
EOF;
|
||||||
file_put_contents($complete_filedir . '/froxlor_master_cronjob.php', $compCron);
|
file_put_contents($complete_filedir . '/froxlor_master_cronjob.php', $compCron);
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHP_EOL;
|
||||||
|
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
||||||
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Froxlor::updateToVersion('2.0.4');
|
Froxlor::updateToVersion('2.0.4');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,3 +310,210 @@ if (Froxlor::isFroxlorVersion('2.0.5')) {
|
|||||||
|
|
||||||
Froxlor::updateToVersion('2.0.6');
|
Froxlor::updateToVersion('2.0.6');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.6')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.6 to 2.0.7", false);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Correcting allowed_mysqlserver for customers");
|
||||||
|
Database::query("UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `allowed_mysqlserver` = '[0]' WHERE `allowed_mysqlserver` = ''");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToVersion('2.0.7');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202212060')) {
|
||||||
|
Update::showUpdateStep("Validating acme.sh challenge path");
|
||||||
|
$acmesh_challenge_dir = Settings::Get('system.letsencryptchallengepath');
|
||||||
|
$system_letsencryptchallengepath_upd = isset($_POST['system_letsencryptchallengepath_upd']) ? $_POST['system_letsencryptchallengepath_upd'] : $acmesh_challenge_dir;
|
||||||
|
if ($acmesh_challenge_dir != $system_letsencryptchallengepath_upd) {
|
||||||
|
Settings::Set('system.letsencryptchallengepath', $system_letsencryptchallengepath_upd);
|
||||||
|
if ((int)Settings::Get('system.leenabled') == 1) {
|
||||||
|
// create JSON string for --apply
|
||||||
|
$dist = Settings::Get('system.distribution');
|
||||||
|
$webserver = Settings::Get('system.webserver');
|
||||||
|
if ($webserver == 'apache2') {
|
||||||
|
$webserver = 'apache22';
|
||||||
|
if (Settings::Get('system.apache24')) {
|
||||||
|
$webserver = 'apache24';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$apply_json = '{"http":"' . $webserver . '","dns":"x","smtp":"x","mail":"x","ftp":"x","distro":"' . $dist . '","system":[]}';
|
||||||
|
Update::lastStepStatus(1, 'manual commands needed',
|
||||||
|
"Please reconfigure webserver service using <pre>bin/froxlor-cli froxlor:config-services --apply='" . $apply_json . "'</pre>" .
|
||||||
|
'<br>or adjust the path manually in <pre>' . Settings::Get('system.letsencryptacmeconf') . '</pre>' .
|
||||||
|
'<br><br>In case you already have certificates issued, run the following command to validate and correct the webroot used for renewal:<br>' .
|
||||||
|
'<pre>bin/froxlor-cli froxlor:validate-acme-webroot</pre><br>'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202301120');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.7')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.7 to 2.0.8", false);
|
||||||
|
|
||||||
|
// adjust file-logging to be set to froxlor/logs/
|
||||||
|
$logtypes = explode(',', Settings::Get('logger.logtypes'));
|
||||||
|
if (in_array('file', $logtypes)) {
|
||||||
|
Update::showUpdateStep("Adjusting froxlor logfile for system-logging to be stored in logs/froxlor.log");
|
||||||
|
Settings::Set('logger.logfile', 'froxlor.log');
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Froxlor::updateToVersion('2.0.8');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202301120')) {
|
||||||
|
Update::showUpdateStep("Adding new setting for DNS resolver when using Let's Encrypt");
|
||||||
|
$system_le_domain_dnscheck_resolver = isset($_POST['system_le_domain_dnscheck_resolver']) ? $_POST['system_le_domain_dnscheck_resolver'] : '1.1.1.1';
|
||||||
|
Settings::AddNew("system.le_domain_dnscheck_resolver", $system_le_domain_dnscheck_resolver);
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202301180');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.8')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.8 to 2.0.9", false);
|
||||||
|
Froxlor::updateToVersion('2.0.9');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.9')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.9 to 2.0.10", false);
|
||||||
|
Froxlor::updateToVersion('2.0.10');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202301180')) {
|
||||||
|
Update::showUpdateStep("Adding new setting for 'Allow API access' default value for new customers");
|
||||||
|
Settings::AddNew("api.customer_default", "1");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202302030');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.10')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.10 to 2.0.11", false);
|
||||||
|
Froxlor::updateToVersion('2.0.11');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.11')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.11 to 2.0.12", false);
|
||||||
|
Froxlor::updateToVersion('2.0.12');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.12')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.12 to 2.0.13", false);
|
||||||
|
Froxlor::updateToVersion('2.0.13');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202302030')) {
|
||||||
|
Update::showUpdateStep("Correcting language mapping of templates created pre 2.0.x");
|
||||||
|
// languages from 0.10.x
|
||||||
|
$language_mapping_comp = [
|
||||||
|
'de' => 'Deutsch',
|
||||||
|
'en' => 'English',
|
||||||
|
'fr' => 'Français',
|
||||||
|
'pt' => 'Português',
|
||||||
|
'it' => 'Italiano',
|
||||||
|
'nl' => 'Nederlands',
|
||||||
|
'se' => 'Svenska',
|
||||||
|
'cz' => 'Česká republika'
|
||||||
|
];
|
||||||
|
$upd_tpl_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET `language` = :iso WHERE `language` = :lng");
|
||||||
|
foreach ($language_mapping_comp as $iso => $lang) {
|
||||||
|
Database::pexecute($upd_tpl_stmt, ['iso' => $iso, 'lng' => $lang]);
|
||||||
|
}
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Enhancing ssl data table");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` CHANGE `expirationdate` `validtodate` datetime DEFAULT NULL;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` ADD `validfromdate` datetime DEFAULT NULL AFTER `ssl_fullchain_file`;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` ADD `issuer` varchar(255) NOT NULL default '' AFTER `validtodate`;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Filling new ssl data fields with existing certificate data");
|
||||||
|
$crt_upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` SET `validfromdate` = :validfromdate, `issuer` = :issuer WHERE `id` = :id");
|
||||||
|
$crt_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`");
|
||||||
|
Database::pexecute($crt_stmt);
|
||||||
|
while ($cert = $crt_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$cert_content = openssl_x509_parse($cert['ssl_cert_file']);
|
||||||
|
if (is_array($cert_content)) {
|
||||||
|
$validfromdate = empty($cert_content['validFrom_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validFrom_time_t']);
|
||||||
|
$issuer = $cert_content['issuer']['O'] ?? "";
|
||||||
|
Database::pexecute($crt_upd_stmt, ['validfromdate' => $validfromdate, 'issuer' => $issuer, 'id' => $cert['id']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear possible user customized columns
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_USERCOLUMNS . "` WHERE `section` = 'sslcertificates_list'");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202303150');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.13')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.13 to 2.0.14", false);
|
||||||
|
Froxlor::updateToVersion('2.0.14');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.14')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.14 to 2.0.15", false);
|
||||||
|
Froxlor::updateToVersion('2.0.15');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202303150')) {
|
||||||
|
Update::showUpdateStep("Adding new request rate limit settings");
|
||||||
|
Settings::AddNew("system.req_limit_per_interval", "60");
|
||||||
|
Settings::AddNew("system.req_limit_interval", "60");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202304260');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.15')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.15 to 2.0.16", false);
|
||||||
|
Froxlor::updateToVersion('2.0.16');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.16')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.16 to 2.0.17", false);
|
||||||
|
Froxlor::updateToVersion('2.0.17');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.17')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.17 to 2.0.18", false);
|
||||||
|
Froxlor::updateToVersion('2.0.18');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.18')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.18 to 2.0.19", false);
|
||||||
|
Froxlor::updateToVersion('2.0.19');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.19')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.19 to 2.0.20", false);
|
||||||
|
Froxlor::updateToVersion('2.0.20');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.20')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.20 to 2.0.21", false);
|
||||||
|
Froxlor::updateToVersion('2.0.21');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.21')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.21 to 2.0.22", false);
|
||||||
|
Froxlor::updateToVersion('2.0.22');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.22')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.22 to 2.0.23", false);
|
||||||
|
Froxlor::updateToVersion('2.0.23');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.0.23')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.0.23 to 2.0.24", false);
|
||||||
|
Froxlor::updateToVersion('2.0.24');
|
||||||
|
}
|
||||||
306
install/updates/froxlor/update_2.1.inc.php
Normal file
306
install/updates/froxlor/update_2.1.inc.php
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
<?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');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.4')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.4 to 2.1.5", false);
|
||||||
|
Froxlor::updateToVersion('2.1.5');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.5')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.5 to 2.1.6", false);
|
||||||
|
Froxlor::updateToVersion('2.1.6');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.6')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.6 to 2.1.7", false);
|
||||||
|
Froxlor::updateToVersion('2.1.7');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.7')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.7 to 2.1.8", false);
|
||||||
|
Froxlor::updateToVersion('2.1.8');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.8')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.8 to 2.1.9", false);
|
||||||
|
Froxlor::updateToVersion('2.1.9');
|
||||||
|
}
|
||||||
@@ -34,9 +34,14 @@ $return = [];
|
|||||||
if (Update::versionInUpdate($current_db_version, '202004140')) {
|
if (Update::versionInUpdate($current_db_version, '202004140')) {
|
||||||
$has_preconfig = true;
|
$has_preconfig = true;
|
||||||
$description = 'Froxlor can now optionally validate the dns entries of domains that request Lets Encrypt certificates to reduce dns-related problems (e.g. freshly registered domain or updated a-record).';
|
$description = 'Froxlor can now optionally validate the dns entries of domains that request Lets Encrypt certificates to reduce dns-related problems (e.g. freshly registered domain or updated a-record).';
|
||||||
$return['system_le_domain_dnscheck_note'] = ['type' => 'infotext', 'value' => $description];
|
|
||||||
$question = '<strong>Validate DNS of domains when using Lets Encrypt ';
|
$question = '<strong>Validate DNS of domains when using Lets Encrypt ';
|
||||||
$return['system_le_domain_dnscheck'] = ['type' => 'checkbox', 'value' => 1, 'checked' => 1, 'label' => $question];
|
$return['system_le_domain_dnscheck'] = [
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'value' => 1,
|
||||||
|
'checked' => 1,
|
||||||
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$preconfig['fields'] = $return;
|
$preconfig['fields'] = $return;
|
||||||
|
|||||||
@@ -27,16 +27,16 @@ use Froxlor\Froxlor;
|
|||||||
use Froxlor\FileDir;
|
use Froxlor\FileDir;
|
||||||
use Froxlor\Config\ConfigParser;
|
use Froxlor\Config\ConfigParser;
|
||||||
use Froxlor\Install\Update;
|
use Froxlor\Install\Update;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
|
||||||
$preconfig = [
|
$preconfig = [
|
||||||
'title' => '2.x updates',
|
'title' => '2.0.x updates',
|
||||||
'fields' => []
|
'fields' => []
|
||||||
];
|
];
|
||||||
$return = [];
|
$return = [];
|
||||||
|
|
||||||
if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
||||||
$description = 'We have rearranged the settings and split them into basic and advanced categories. This makes it easier for users who do not need all the detailed or very specific settings and options and gives a better overview of the basic/mostly used settings.';
|
$description = 'We have rearranged the settings and split them into basic and advanced categories. This makes it easier for users who do not need all the detailed or very specific settings and options and gives a better overview of the basic/mostly used settings.';
|
||||||
$return['panel_settings_mode_note'] = ['type' => 'infotext', 'value' => $description];
|
|
||||||
$question = '<strong>Chose settings mode (you can change that at any time)</strong>';
|
$question = '<strong>Chose settings mode (you can change that at any time)</strong>';
|
||||||
$return['panel_settings_mode'] = [
|
$return['panel_settings_mode'] = [
|
||||||
'type' => 'select',
|
'type' => 'select',
|
||||||
@@ -45,16 +45,16 @@ if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
|||||||
1 => 'Advanced'
|
1 => 'Advanced'
|
||||||
],
|
],
|
||||||
'selected' => 1,
|
'selected' => 1,
|
||||||
'label' => $question
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description
|
||||||
];
|
];
|
||||||
|
|
||||||
$description = 'The configuration page now can preselect a distribution, please select your current distribution';
|
$description = 'The configuration page now can preselect a distribution, please select your current distribution';
|
||||||
$return['system_distribution_note'] = ['type' => 'infotext', 'value' => $description];
|
|
||||||
$question = '<strong>Select distribution</strong>';
|
$question = '<strong>Select distribution</strong>';
|
||||||
$config_dir = FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/lib/configfiles/');
|
$config_dir = FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/lib/configfiles/');
|
||||||
// show list of available distro's
|
// show list of available distro's
|
||||||
$distros = glob($config_dir . '*.xml');
|
$distros = glob($config_dir . '*.xml');
|
||||||
$distributions_select[''] = '-';
|
// selection is required $distributions_select[''] = '-';
|
||||||
// read in all the distros
|
// read in all the distros
|
||||||
foreach ($distros as $_distribution) {
|
foreach ($distros as $_distribution) {
|
||||||
// get configparser object
|
// get configparser object
|
||||||
@@ -68,9 +68,44 @@ if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
|||||||
'type' => 'select',
|
'type' => 'select',
|
||||||
'select_var' => $distributions_select,
|
'select_var' => $distributions_select,
|
||||||
'selected' => '',
|
'selected' => '',
|
||||||
'label' => $question
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Update::versionInUpdate($current_db_version, '202301120')) {
|
||||||
|
$acmesh_challenge_dir = rtrim(FileDir::makeCorrectDir(Settings::Get('system.letsencryptchallengepath')), "/");
|
||||||
|
$recommended = rtrim(FileDir::makeCorrectDir(Froxlor::getInstallDir()), "/");
|
||||||
|
if ((int) Settings::Get('system.leenabled') == 1 && $acmesh_challenge_dir != $recommended) {
|
||||||
|
$has_preconfig = true;
|
||||||
|
$description = 'ACME challenge docroot from settings differs from the current installation directory.';
|
||||||
|
$question = '<strong>Validate Let\'s Encrypt challenge path (recommended value: ' . $recommended . ')</strong>';
|
||||||
|
$return['system_letsencryptchallengepath_upd'] = [
|
||||||
|
'type' => 'text',
|
||||||
|
'value' => $recommended,
|
||||||
|
'placeholder' => $acmesh_challenge_dir,
|
||||||
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description,
|
||||||
|
'mandatory' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Update::versionInUpdate($current_db_version, '202301180')) {
|
||||||
|
if ((int) Settings::Get('system.leenabled') == 1) {
|
||||||
|
$has_preconfig = true;
|
||||||
|
$description = 'Froxlor now supports to set an external DNS resolver for the Let\'s Encrypt pre-check.';
|
||||||
|
$question = '<strong>Specify a DNS resolver IP (recommended value: 1.1.1.1 or similar)</strong>';
|
||||||
|
$return['system_le_domain_dnscheck_resolver'] = [
|
||||||
|
'type' => 'text',
|
||||||
|
'pattern' => '^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$|^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$|^\s*$',
|
||||||
|
'value' => '1.1.1.1',
|
||||||
|
'placeholder' => '1.1.1.1',
|
||||||
|
'label' => $question,
|
||||||
|
'prior_infotext' => $description,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$preconfig['fields'] = $return;
|
$preconfig['fields'] = $return;
|
||||||
return $preconfig;
|
return $preconfig;
|
||||||
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");
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ class Ajax
|
|||||||
$content = preg_replace("/[\r\n]+/", " ", strip_tags($item->description));
|
$content = preg_replace("/[\r\n]+/", " ", strip_tags($item->description));
|
||||||
$content = substr($content, 0, 150) . "...";
|
$content = substr($content, 0, 150) . "...";
|
||||||
|
|
||||||
$items .= UI::twig()->render($this->theme . '/user/newsfeeditem.html.twig', [
|
$items .= UI::twig()->render(UI::validateThemeTemplate('/user/newsfeeditem.html.twig', $this->theme), [
|
||||||
'link' => $link,
|
'link' => $link,
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'date' => $date,
|
'date' => $date,
|
||||||
@@ -201,7 +201,7 @@ class Ajax
|
|||||||
$result['last_update_check'] = $uc_data['ts'];
|
$result['last_update_check'] = $uc_data['ts'];
|
||||||
$result['channel'] = Settings::Get('system.update_channel');
|
$result['channel'] = Settings::Get('system.update_channel');
|
||||||
|
|
||||||
$result_rendered = UI::twig()->render($this->theme . '/misc/version_top.html.twig', $result);
|
$result_rendered = UI::twig()->render(UI::validateThemeTemplate('/misc/version_top.html.twig', $this->theme), $result);
|
||||||
return $this->jsonResponse($result_rendered);
|
return $this->jsonResponse($result_rendered);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// don't display anything if just not allowed due to permissions
|
// don't display anything if just not allowed due to permissions
|
||||||
@@ -237,11 +237,11 @@ class Ajax
|
|||||||
private function updateTablelisting()
|
private function updateTablelisting()
|
||||||
{
|
{
|
||||||
$columns = [];
|
$columns = [];
|
||||||
foreach ((Request::any('columns') ?? []) as $value) {
|
foreach ((Request::post('columns') ?? []) as $value) {
|
||||||
$columns[] = $value;
|
$columns[] = $value;
|
||||||
}
|
}
|
||||||
if (!empty($columns)) {
|
if (!empty($columns)) {
|
||||||
Listing::storeColumnListingForUser([Request::any('listing') => $columns]);
|
$columns = Listing::storeColumnListingForUser([Request::get('listing') => $columns]);
|
||||||
return $this->jsonResponse($columns);
|
return $this->jsonResponse($columns);
|
||||||
}
|
}
|
||||||
return $this->errorResponse('At least one column must be selected', 406);
|
return $this->errorResponse('At least one column must be selected', 406);
|
||||||
@@ -249,7 +249,7 @@ class Ajax
|
|||||||
|
|
||||||
private function resetTablelisting()
|
private function resetTablelisting()
|
||||||
{
|
{
|
||||||
Listing::deleteColumnListingForUser([Request::any('listing') => []]);
|
Listing::deleteColumnListingForUser([Request::get('listing') => []]);
|
||||||
return $this->jsonResponse([]);
|
return $this->jsonResponse([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace Froxlor\Ajax;
|
|||||||
use Froxlor\Api\Commands\Admins;
|
use Froxlor\Api\Commands\Admins;
|
||||||
use Froxlor\Api\Commands\Customers;
|
use Froxlor\Api\Commands\Customers;
|
||||||
use Froxlor\Api\Commands\Domains;
|
use Froxlor\Api\Commands\Domains;
|
||||||
|
use Froxlor\Api\Commands\EmailDomains;
|
||||||
use Froxlor\Api\Commands\Emails;
|
use Froxlor\Api\Commands\Emails;
|
||||||
use Froxlor\Api\Commands\FpmDaemons;
|
use Froxlor\Api\Commands\FpmDaemons;
|
||||||
use Froxlor\Api\Commands\Ftps;
|
use Froxlor\Api\Commands\Ftps;
|
||||||
@@ -267,7 +268,20 @@ class GlobalSearch
|
|||||||
'result_format' => [
|
'result_format' => [
|
||||||
'title' => ['self', 'getFieldFromResult'],
|
'title' => ['self', 'getFieldFromResult'],
|
||||||
'title_args' => 'email',
|
'title_args' => 'email',
|
||||||
'href' => 'customer_email.php?page=emails&searchfield=m.email&searchtext='
|
'href' => 'customer_email.php?page=email_domain&domainid={domainid}&searchfield=m.email&searchtext='
|
||||||
|
]
|
||||||
|
],
|
||||||
|
// email-domains
|
||||||
|
'email_domains' => [
|
||||||
|
'class' => EmailDomains::class,
|
||||||
|
'searchfields' => [
|
||||||
|
'd.domain',
|
||||||
|
],
|
||||||
|
'result_key' => 'domain',
|
||||||
|
'result_format' => [
|
||||||
|
'title' => ['self', 'getFieldFromResult'],
|
||||||
|
'title_args' => 'domain',
|
||||||
|
'href' => 'customer_email.php?page=emails&searchfield=d.domain&searchtext='
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
// databases
|
// databases
|
||||||
@@ -326,6 +340,14 @@ class GlobalSearch
|
|||||||
if (!isset($result[$entity])) {
|
if (!isset($result[$entity])) {
|
||||||
$result[$entity] = [];
|
$result[$entity] = [];
|
||||||
}
|
}
|
||||||
|
// replacer from result in href
|
||||||
|
$href_replacer = [];
|
||||||
|
if (preg_match_all('/\{([a-z]+)\}/', $edata['result_format']['href'], $href_replacer) !== false) {
|
||||||
|
foreach ($href_replacer[1] as $href_field) {
|
||||||
|
$href_field_value = self::getFieldFromResult($cresult, $href_field);
|
||||||
|
$edata['result_format']['href'] = str_replace('{'.$href_field.'}', $href_field_value, $edata['result_format']['href']);
|
||||||
|
}
|
||||||
|
}
|
||||||
$result[$entity][] = [
|
$result[$entity][] = [
|
||||||
'title' => call_user_func($edata['result_format']['title'], $cresult, ($edata['result_format']['title_args'] ?? null)),
|
'title' => call_user_func($edata['result_format']['title'], $cresult, ($edata['result_format']['title_args'] ?? null)),
|
||||||
'href' => $edata['result_format']['href'] . $cresult[$edata['result_key']]
|
'href' => $edata['result_format']['href'] . $cresult[$edata['result_key']]
|
||||||
@@ -335,7 +357,7 @@ class GlobalSearch
|
|||||||
}
|
}
|
||||||
} // foreach entity
|
} // foreach entity
|
||||||
|
|
||||||
} // foreach splitted search-term
|
} // foreach split search-term
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
namespace Froxlor\Api;
|
namespace Froxlor\Api;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Froxlor\Http\RateLimiter;
|
||||||
use Froxlor\Settings;
|
use Froxlor\Settings;
|
||||||
use voku\helper\AntiXSS;
|
use voku\helper\AntiXSS;
|
||||||
|
|
||||||
@@ -52,6 +53,8 @@ class Api
|
|||||||
if (Settings::Get('api.enabled') != 1) {
|
if (Settings::Get('api.enabled') != 1) {
|
||||||
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
|
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RateLimiter::run();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,6 +120,6 @@ class Api
|
|||||||
|
|
||||||
private function stripcslashesDeep($value)
|
private function stripcslashesDeep($value)
|
||||||
{
|
{
|
||||||
return is_array($value) ? array_map([$this, 'stripcslashesDeep'], $value) : stripcslashes($value);
|
return is_array($value) ? array_map([$this, 'stripcslashesDeep'], $value) : (!empty($value) ? stripcslashes($value) : $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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`',
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ abstract class ApiParameter
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param array $params
|
* @param array|null $params
|
||||||
* optional, array of parameters (var=>value) for the command
|
* optional, array of parameters (var=>value) for the command
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function __construct($params = null)
|
public function __construct(array $params = null)
|
||||||
{
|
{
|
||||||
if (!is_null($params)) {
|
if (!is_null($params)) {
|
||||||
$params = $this->trimArray($params);
|
$params = $this->trimArray($params);
|
||||||
@@ -57,7 +57,7 @@ abstract class ApiParameter
|
|||||||
*
|
*
|
||||||
* @param array $input
|
* @param array $input
|
||||||
*
|
*
|
||||||
* @return array
|
* @return string|array
|
||||||
*/
|
*/
|
||||||
private function trimArray($input)
|
private function trimArray($input)
|
||||||
{
|
{
|
||||||
@@ -79,9 +79,9 @@ abstract class ApiParameter
|
|||||||
/**
|
/**
|
||||||
* get specific parameter which also has and unlimited-field
|
* get specific parameter which also has and unlimited-field
|
||||||
*
|
*
|
||||||
* @param string $param
|
* @param string|null $param
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param string $ul_field
|
* @param string|null $ul_field
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param bool $optional
|
* @param bool $optional
|
||||||
* default: false
|
* default: false
|
||||||
@@ -91,7 +91,7 @@ abstract class ApiParameter
|
|||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function getUlParam($param = null, $ul_field = null, $optional = false, $default = 0)
|
protected function getUlParam(string $param = null, string $ul_field = null, bool $optional = false, $default = 0)
|
||||||
{
|
{
|
||||||
$param_value = (int)$this->getParam($param, $optional, $default);
|
$param_value = (int)$this->getParam($param, $optional, $default);
|
||||||
$ul_field_value = $this->getBoolParam($ul_field, true, 0);
|
$ul_field_value = $this->getBoolParam($ul_field, true, 0);
|
||||||
@@ -102,11 +102,11 @@ abstract class ApiParameter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get specific parameter from the parameterlist;
|
* get specific parameter from the parameter list;
|
||||||
* check for existence and != empty if needed.
|
* check for existence and != empty if needed.
|
||||||
* Maybe more in the future
|
* Maybe more in the future
|
||||||
*
|
*
|
||||||
* @param string $param
|
* @param string|null $param
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param bool $optional
|
* @param bool $optional
|
||||||
* default: false
|
* default: false
|
||||||
@@ -116,7 +116,7 @@ abstract class ApiParameter
|
|||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function getParam($param = null, $optional = false, $default = '')
|
protected function getParam(string $param = null, bool $optional = false, $default = '')
|
||||||
{
|
{
|
||||||
// does it exist?
|
// does it exist?
|
||||||
if (!isset($this->cmd_params[$param])) {
|
if (!isset($this->cmd_params[$param])) {
|
||||||
@@ -128,7 +128,7 @@ abstract class ApiParameter
|
|||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
// is it empty? - test really on string, as value 0 is being seen as empty by php
|
// is it empty? - test really on string, as value 0 is being seen as empty by php
|
||||||
if ($this->cmd_params[$param] === "") {
|
if (!is_array($this->cmd_params[$param]) && trim($this->cmd_params[$param]) === "") {
|
||||||
if ($optional === false) {
|
if ($optional === false) {
|
||||||
// get module + function for better error-messages
|
// get module + function for better error-messages
|
||||||
$inmod = $this->getModFunctionString();
|
$inmod = $this->getModFunctionString();
|
||||||
@@ -142,7 +142,7 @@ abstract class ApiParameter
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* returns "module::function()" for better error-messages (missing parameter etc.)
|
* returns "module::function()" for better error-messages (missing parameter etc.)
|
||||||
* makes debugging a whole lot more comfortable
|
* makes debugging a lot more comfortable
|
||||||
*
|
*
|
||||||
* @param int $level
|
* @param int $level
|
||||||
* depth of backtrace, default 2
|
* depth of backtrace, default 2
|
||||||
@@ -152,7 +152,7 @@ abstract class ApiParameter
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function getModFunctionString($level = 1, $max_level = 5, $trace = null)
|
private function getModFunctionString(int $level = 1, int $max_level = 5, $trace = null)
|
||||||
{
|
{
|
||||||
// which class called us
|
// which class called us
|
||||||
$_class = get_called_class();
|
$_class = get_called_class();
|
||||||
@@ -174,7 +174,7 @@ abstract class ApiParameter
|
|||||||
/**
|
/**
|
||||||
* getParam wrapper for boolean parameter
|
* getParam wrapper for boolean parameter
|
||||||
*
|
*
|
||||||
* @param string $param
|
* @param string|null $param
|
||||||
* parameter to get out of the request-parameter list
|
* parameter to get out of the request-parameter list
|
||||||
* @param bool $optional
|
* @param bool $optional
|
||||||
* default: false
|
* default: false
|
||||||
@@ -183,7 +183,7 @@ abstract class ApiParameter
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function getBoolParam($param = null, $optional = false, $default = false)
|
protected function getBoolParam(string $param = null, bool $optional = false, $default = false)
|
||||||
{
|
{
|
||||||
$_default = '0';
|
$_default = '0';
|
||||||
if ($default) {
|
if ($default) {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list admins");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list admins");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT *
|
SELECT *
|
||||||
@@ -407,7 +407,7 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get admin '" . $result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get admin '" . $result['loginname'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
||||||
@@ -584,6 +584,18 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
$theme = Settings::Get('panel.default_theme');
|
$theme = Settings::Get('panel.default_theme');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (empty(trim($name))) {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'admin.name'
|
||||||
|
], '', true);
|
||||||
|
}
|
||||||
|
if (empty(trim($email))) {
|
||||||
|
Response::standardError([
|
||||||
|
'stringisempty',
|
||||||
|
'admin.email'
|
||||||
|
], '', true);
|
||||||
|
}
|
||||||
if (!Validate::validateEmail($email)) {
|
if (!Validate::validateEmail($email)) {
|
||||||
Response::standardError('emailiswrong', $email, true);
|
Response::standardError('emailiswrong', $email, true);
|
||||||
} else {
|
} else {
|
||||||
@@ -705,7 +717,7 @@ class Admins extends ApiCommand implements ResourceEntity
|
|||||||
WHERE `adminid` = :adminid
|
WHERE `adminid` = :adminid
|
||||||
");
|
");
|
||||||
Database::pexecute($upd_stmt, $upd_data, true, true);
|
Database::pexecute($upd_stmt, $upd_data, true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] edited admin '" . $result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] edited admin '" . $result['loginname'] . "'");
|
||||||
|
|
||||||
// get all admin-data for return-array
|
// get all admin-data for return-array
|
||||||
$result = $this->apiCall('Admins.get', [
|
$result = $this->apiCall('Admins.get', [
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
if (!$has_cert) {
|
if (!$has_cert) {
|
||||||
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, true);
|
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ssl-certificate for '" . $domain['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ssl-certificate for '" . $domain['domain'] . "'");
|
||||||
$result = $this->apiCall('Certificates.get', [
|
$result = $this->apiCall('Certificates.get', [
|
||||||
'id' => $domain['id']
|
'id' => $domain['id']
|
||||||
]);
|
]);
|
||||||
@@ -127,7 +127,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
$do_verify = true;
|
$do_verify = true;
|
||||||
$expirationdate = null;
|
$validtodate = null;
|
||||||
|
$validtodate = null;
|
||||||
|
$issuer = "";
|
||||||
// no cert-file given -> forget everything
|
// no cert-file given -> forget everything
|
||||||
if ($ssl_cert_file == '') {
|
if ($ssl_cert_file == '') {
|
||||||
$ssl_key_file = '';
|
$ssl_key_file = '';
|
||||||
@@ -168,7 +170,10 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
} else {
|
} else {
|
||||||
Response::standardError('sslcertificateinvalidcert', '', true);
|
Response::standardError('sslcertificateinvalidcert', '', true);
|
||||||
}
|
}
|
||||||
$expirationdate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']);
|
// get data from certificate to store in the table
|
||||||
|
$validfromdate = empty($cert_content['validFrom_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validFrom_time_t']);
|
||||||
|
$validtodate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']);
|
||||||
|
$issuer = $cert_content['issuer']['O'] ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add/Update database entry
|
// Add/Update database entry
|
||||||
@@ -183,7 +188,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
`ssl_key_file` = :ssl_key_file,
|
`ssl_key_file` = :ssl_key_file,
|
||||||
`ssl_ca_file` = :ssl_ca_file,
|
`ssl_ca_file` = :ssl_ca_file,
|
||||||
`ssl_cert_chainfile` = :ssl_cert_chainfile,
|
`ssl_cert_chainfile` = :ssl_cert_chainfile,
|
||||||
`expirationdate` = :expirationdate
|
`validfromdate` = :validfromdate,
|
||||||
|
`validtodate` = :validtodate,
|
||||||
|
`issuer` = :issuer
|
||||||
" . $qrywhere . " `domainid`= :domainid
|
" . $qrywhere . " `domainid`= :domainid
|
||||||
");
|
");
|
||||||
$params = [
|
$params = [
|
||||||
@@ -191,7 +198,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
"ssl_key_file" => $ssl_key_file,
|
"ssl_key_file" => $ssl_key_file,
|
||||||
"ssl_ca_file" => $ssl_ca_file,
|
"ssl_ca_file" => $ssl_ca_file,
|
||||||
"ssl_cert_chainfile" => $ssl_cert_chainfile,
|
"ssl_cert_chainfile" => $ssl_cert_chainfile,
|
||||||
"expirationdate" => $expirationdate,
|
"validfromdate" => $validfromdate,
|
||||||
|
"validtodate" => $validtodate,
|
||||||
|
"issuer" => $issuer,
|
||||||
"domainid" => $domainid
|
"domainid" => $domainid
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
@@ -239,7 +248,7 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
$ssl_ca_file = $this->getParam('ssl_ca_file', true, '');
|
$ssl_ca_file = $this->getParam('ssl_ca_file', true, '');
|
||||||
$ssl_cert_chainfile = $this->getParam('ssl_cert_chainfile', true, '');
|
$ssl_cert_chainfile = $this->getParam('ssl_cert_chainfile', true, '');
|
||||||
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, false);
|
$this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, false);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ssl-certificate for '" . $domain['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ssl-certificate for '" . $domain['domain'] . "'");
|
||||||
$result = $this->apiCall('Certificates.get', [
|
$result = $this->apiCall('Certificates.get', [
|
||||||
'id' => $domain['id']
|
'id' => $domain['id']
|
||||||
]);
|
]);
|
||||||
@@ -299,27 +308,23 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set data from certificate
|
// Set data from certificate
|
||||||
|
$cert['isvalid'] = false;
|
||||||
|
$cert['san'] = null;
|
||||||
$cert_data = openssl_x509_parse($cert['ssl_cert_file']);
|
$cert_data = openssl_x509_parse($cert['ssl_cert_file']);
|
||||||
if ($cert_data) {
|
if ($cert_data) {
|
||||||
$cert['validfromdate'] = date('Y-m-d H:i:s', $cert_data['validFrom_time_t']);
|
|
||||||
$cert['validtodate'] = date('Y-m-d H:i:s', $cert_data['validTo_time_t']);
|
|
||||||
$cert['isvalid'] = (bool)$cert_data['validTo_time_t'] > time();
|
$cert['isvalid'] = (bool)$cert_data['validTo_time_t'] > time();
|
||||||
$cert['issuer'] = $cert_data['issuer']['O'] ?? null;
|
// Set subject alt names from certificate
|
||||||
}
|
if (isset($cert_data['extensions']['subjectAltName']) && !empty($cert_data['extensions']['subjectAltName'])) {
|
||||||
|
$SANs = explode(",", $cert_data['extensions']['subjectAltName']);
|
||||||
// Set subject alt names from certificate
|
$SANs = array_map('trim', $SANs);
|
||||||
$cert['san'] = null;
|
foreach ($SANs as $san) {
|
||||||
if (isset($cert_data['extensions']['subjectAltName']) && !empty($cert_data['extensions']['subjectAltName'])) {
|
$san = str_replace("DNS:", "", $san);
|
||||||
$SANs = explode(",", $cert_data['extensions']['subjectAltName']);
|
if ($san != $cert_data['subject']['CN'] && strpos($san, "othername:") === false) {
|
||||||
$SANs = array_map('trim', $SANs);
|
$cert['san'][] = $san;
|
||||||
foreach ($SANs as $san) {
|
}
|
||||||
$san = str_replace("DNS:", "", $san);
|
|
||||||
if ($san != $cert_data['subject']['CN'] && strpos($san, "othername:") === false) {
|
|
||||||
$cert['san'][] = $san;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[] = $cert;
|
$result[] = $cert;
|
||||||
}
|
}
|
||||||
return $this->response([
|
return $this->response([
|
||||||
@@ -465,7 +470,7 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
if ($chk['letsencrypt'] == '1') {
|
if ($chk['letsencrypt'] == '1') {
|
||||||
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $chk['domain']);
|
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $chk['domain']);
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] removed ssl-certificate for '" . $chk['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] removed ssl-certificate for '" . $chk['domain'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("Unable to determine SSL certificate. Maybe no access?", 406);
|
throw new Exception("Unable to determine SSL certificate. Maybe no access?", 406);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ use Froxlor\Cron\TaskId;
|
|||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
use Froxlor\FroxlorLogger;
|
use Froxlor\FroxlorLogger;
|
||||||
use Froxlor\System\Cronjob;
|
use Froxlor\System\Cronjob;
|
||||||
|
use Froxlor\UI\Response;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
use PDO;
|
use PDO;
|
||||||
|
|
||||||
@@ -41,6 +42,14 @@ use PDO;
|
|||||||
class Cronjobs extends ApiCommand implements ResourceEntity
|
class Cronjobs extends ApiCommand implements ResourceEntity
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private array $allowed_intervals = [
|
||||||
|
'MINUTE',
|
||||||
|
'HOUR',
|
||||||
|
'DAY',
|
||||||
|
'WEEK',
|
||||||
|
'MONTH'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You cannot add new cronjobs yet.
|
* You cannot add new cronjobs yet.
|
||||||
*/
|
*/
|
||||||
@@ -118,6 +127,10 @@ class Cronjobs extends ApiCommand implements ResourceEntity
|
|||||||
$interval_value = Validate::validate($interval_value, 'interval_value', '/^([0-9]+)$/Di', 'stringisempty', [], true);
|
$interval_value = Validate::validate($interval_value, 'interval_value', '/^([0-9]+)$/Di', 'stringisempty', [], true);
|
||||||
$interval_interval = Validate::validate($interval_interval, 'interval_interval', '', '', [], true);
|
$interval_interval = Validate::validate($interval_interval, 'interval_interval', '', '', [], true);
|
||||||
|
|
||||||
|
if (!in_array(strtoupper($interval_interval), $this->allowed_intervals)) {
|
||||||
|
Response::standardError('invalidcronjobintervalvalue', implode(", ", $this->allowed_intervals), true);
|
||||||
|
}
|
||||||
|
|
||||||
// put together interval value
|
// put together interval value
|
||||||
$interval = $interval_value . ' ' . strtoupper($interval_interval);
|
$interval = $interval_value . ' ' . strtoupper($interval_interval);
|
||||||
|
|
||||||
@@ -134,7 +147,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// insert task to re-generate the cron.d-file
|
// insert task to re-generate the cron.d-file
|
||||||
Cronjob::inserttask(TaskId::REBUILD_CRON);
|
Cronjob::inserttask(TaskId::REBUILD_CRON);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
||||||
$result = $this->apiCall('Cronjobs.get', [
|
$result = $this->apiCall('Cronjobs.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -164,7 +177,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list cronjobs");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list cronjobs");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
||||||
|
|||||||
@@ -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, [
|
||||||
@@ -298,7 +297,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
$fax = $this->getParam('fax', true, '');
|
$fax = $this->getParam('fax', true, '');
|
||||||
$customernumber = $this->getParam('customernumber', true, '');
|
$customernumber = $this->getParam('customernumber', true, '');
|
||||||
$def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage'));
|
$def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage'));
|
||||||
$api_allowed = $this->getBoolParam('api_allowed', true, Settings::Get('api.enabled'));
|
$api_allowed = $this->getBoolParam('api_allowed', true, (Settings::Get('api.enabled') && Settings::Get('api.customer_default')));
|
||||||
$gender = (int)$this->getParam('gender', true, 0);
|
$gender = (int)$this->getParam('gender', true, 0);
|
||||||
$custom_notes = $this->getParam('custom_notes', true, '');
|
$custom_notes = $this->getParam('custom_notes', true, '');
|
||||||
$custom_notes_show = $this->getBoolParam('custom_notes_show', true, 0);
|
$custom_notes_show = $this->getBoolParam('custom_notes_show', true, 0);
|
||||||
@@ -400,6 +399,13 @@ 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) {
|
||||||
|
// only required if not using mod_php
|
||||||
|
if ((int)Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 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) {
|
||||||
@@ -895,7 +901,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
$result['dbspace_used'] = 0;
|
$result['dbspace_used'] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get customer '" . $result['loginname'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get customer '" . $result['loginname'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
$key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'");
|
||||||
@@ -1050,7 +1056,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 +1116,12 @@ 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) {
|
||||||
|
// only required if not using mod_php
|
||||||
|
if ((int)Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 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 +1130,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);
|
||||||
@@ -1327,7 +1340,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
'vu' => $valid_until
|
'vu' => $valid_until
|
||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1538,7 +1551,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
Database::query($admin_update_query);
|
Database::query($admin_update_query);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited user '" . $result['loginname'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited user '" . $result['loginname'] . "'");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* move customer to another admin/reseller; #1166
|
* move customer to another admin/reseller; #1166
|
||||||
@@ -1911,7 +1924,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
// now, recalculate the resource-usage for the old and the new admin
|
// now, recalculate the resource-usage for the old and the new admin
|
||||||
User::updateCounters(false);
|
User::updateCounters(false);
|
||||||
|
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] moved user '" . $c_result['loginname'] . "' from admin/reseller '" . $c_result['adminname'] . " to admin/reseller '" . $a_result['loginname'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] moved user '" . $c_result['loginname'] . "' from admin/reseller '" . $c_result['adminname'] . " to admin/reseller '" . $a_result['loginname'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Customers.get', [
|
$result = $this->apiCall('Customers.get', [
|
||||||
'id' => $c_result['customerid']
|
'id' => $c_result['customerid']
|
||||||
|
|||||||
@@ -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_NOTICE, "[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);
|
||||||
@@ -144,7 +144,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$id = Database::lastInsertId();
|
$id = Database::lastInsertId();
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-option for '" . $userpath . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added directory-option for '" . $userpath . "'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
|
||||||
$result = $this->apiCall('DirOptions.get', [
|
$result = $this->apiCall('DirOptions.get', [
|
||||||
@@ -157,16 +157,15 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
* this functions validates a given value as ErrorDocument
|
* this functions validates a given value as ErrorDocument
|
||||||
* refs #267
|
* refs #267
|
||||||
*
|
*
|
||||||
* @param
|
* @param string $errdoc
|
||||||
* string error-document-string
|
|
||||||
* @param bool $throw_exception
|
* @param bool $throw_exception
|
||||||
*
|
*
|
||||||
* @return string error-document-string
|
* @return string error-document-string
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private function correctErrorDocument($errdoc = null, $throw_exception = false)
|
private function correctErrorDocument(string $errdoc, $throw_exception = false)
|
||||||
{
|
{
|
||||||
if ($errdoc !== null && $errdoc != '') {
|
if (trim($errdoc) != '') {
|
||||||
// not a URL
|
// not a URL
|
||||||
if ((strtoupper(substr($errdoc, 0, 5)) != 'HTTP:' && strtoupper(substr($errdoc, 0, 6)) != 'HTTPS:') || !Validate::validateUrl($errdoc)) {
|
if ((strtoupper(substr($errdoc, 0, 5)) != 'HTTP:' && strtoupper(substr($errdoc, 0, 6)) != 'HTTPS:') || !Validate::validateUrl($errdoc)) {
|
||||||
// a file
|
// a file
|
||||||
@@ -176,14 +175,14 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
if (!substr($errdoc, 0, 1) == '/') {
|
if (!substr($errdoc, 0, 1) == '/') {
|
||||||
$errdoc = '/' . $errdoc;
|
$errdoc = '/' . $errdoc;
|
||||||
}
|
}
|
||||||
} else {
|
} elseif (preg_match('/^"([^\r\n\t\f\0"]+)"$/', $errdoc)) {
|
||||||
// a string (check for ending ")
|
// a string (check for ending ")
|
||||||
// string won't work for lighty
|
// string won't work for lighty
|
||||||
if (Settings::Get('system.webserver') == 'lighttpd') {
|
if (Settings::Get('system.webserver') == 'lighttpd') {
|
||||||
Response::standardError('stringerrordocumentnotvalidforlighty', '', $throw_exception);
|
Response::standardError('stringerrordocumentnotvalidforlighty', '', $throw_exception);
|
||||||
} elseif (substr($errdoc, -1) != '"') {
|
|
||||||
$errdoc .= '"';
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Response::standardError('invaliderrordocumentvalue', '', $throw_exception);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Settings::Get('system.webserver') == 'lighttpd') {
|
if (Settings::Get('system.webserver') == 'lighttpd') {
|
||||||
@@ -191,7 +190,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $errdoc;
|
return trim($errdoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,7 +247,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
$params['id'] = $id;
|
$params['id'] = $id;
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory options for '" . $result['path'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get directory options for '" . $result['path'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = "id #" . $id;
|
$key = "id #" . $id;
|
||||||
@@ -332,7 +331,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id
|
"id" => $id
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited directory options for '" . str_replace($customer['documentroot'], '/', $result['path']) . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited directory options for '" . str_replace($customer['documentroot'], '/', $result['path']) . "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->apiCall('DirOptions.get', [
|
$result = $this->apiCall('DirOptions.get', [
|
||||||
@@ -380,7 +379,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-options");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list directory-options");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -479,7 +478,7 @@ class DirOptions extends ApiCommand implements ResourceEntity
|
|||||||
"customerid" => $customer_data['customerid'],
|
"customerid" => $customer_data['customerid'],
|
||||||
"id" => $id
|
"id" => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,10 +84,11 @@ 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);
|
||||||
Validate::validate($password, 'password', '', '', [], true);
|
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||||
|
$password = Crypt::validatePassword($password, true);
|
||||||
|
|
||||||
// check for duplicate usernames for the path
|
// check for duplicate usernames for the path
|
||||||
$username_path_check_stmt = Database::prepare("
|
$username_path_check_stmt = Database::prepare("
|
||||||
@@ -128,7 +129,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$id = Database::lastInsertId();
|
$id = Database::lastInsertId();
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-protection for '" . $username . " (" . $path . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added directory-protection for '" . $username . " (" . $path . ")'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
|
||||||
$result = $this->apiCall('DirProtections.get', [
|
$result = $this->apiCall('DirProtections.get', [
|
||||||
@@ -195,7 +196,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
$params['idun'] = ($id <= 0 ? $username : $id);
|
$params['idun'] = ($id <= 0 ? $username : $id);
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory protection for '" . $result['path'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get directory protection for '" . $result['path'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
||||||
@@ -244,7 +245,8 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validation
|
// validation
|
||||||
$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);
|
||||||
Validate::validate($password, 'password', '', '', [], true);
|
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||||
|
$password = Crypt::validatePassword($password, true);
|
||||||
|
|
||||||
$upd_query = "";
|
$upd_query = "";
|
||||||
$upd_params = [
|
$upd_params = [
|
||||||
@@ -277,7 +279,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'");
|
||||||
$result = $this->apiCall('DirProtections.get', [
|
$result = $this->apiCall('DirProtections.get', [
|
||||||
'id' => $result['id']
|
'id' => $result['id']
|
||||||
]);
|
]);
|
||||||
@@ -323,7 +325,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-protections");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list directory-protections");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -411,7 +413,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id
|
"id" => $id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'");
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -413,7 +415,7 @@ class DomainZones extends ApiCommand implements ResourceEntity
|
|||||||
$zone = Dns::createDomainZone($id);
|
$zone = Dns::createDomainZone($id);
|
||||||
$zonefile = (string)$zone;
|
$zonefile = (string)$zone;
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get dns-zone for '" . $result['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get dns-zone for '" . $result['domain'] . "'");
|
||||||
return $this->response(explode("\n", $zonefile));
|
return $this->response(explode("\n", $zonefile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,12 +216,14 @@ 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)
|
||||||
* @param bool $openbasedir
|
* @param bool $openbasedir
|
||||||
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
||||||
|
* @param int $openbasedir_path
|
||||||
|
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
||||||
* @param int $mod_fcgid_starter
|
* @param int $mod_fcgid_starter
|
||||||
@@ -242,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
|
||||||
@@ -250,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
|
||||||
@@ -261,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
|
||||||
@@ -296,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);
|
||||||
@@ -312,14 +310,15 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$documentroot = $this->getParam('documentroot', true, '');
|
$documentroot = $this->getParam('documentroot', true, '');
|
||||||
$phpenabled = $this->getBoolParam('phpenabled', true, 0);
|
$phpenabled = $this->getBoolParam('phpenabled', true, 0);
|
||||||
$openbasedir = $this->getBoolParam('openbasedir', true, 0);
|
$openbasedir = $this->getBoolParam('openbasedir', true, 0);
|
||||||
|
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, 1);
|
$phpsettingid = $this->getParam('phpsettingid', true, 1);
|
||||||
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, -1);
|
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, -1);
|
||||||
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
|
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
|
||||||
$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);
|
||||||
@@ -350,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();
|
||||||
@@ -404,20 +405,25 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$documentroot = $_documentroot;
|
$documentroot = $_documentroot;
|
||||||
}
|
}
|
||||||
|
|
||||||
$registration_date = Validate::validate($registration_date, 'registration_date', Validate::REGEX_YYYY_MM_DD, '', [
|
if (!is_null($registration_date)) {
|
||||||
'0000-00-00',
|
$registration_date = Validate::validate($registration_date, 'registration_date',
|
||||||
'0',
|
Validate::REGEX_YYYY_MM_DD, '', [
|
||||||
''
|
'0000-00-00',
|
||||||
], true);
|
'0',
|
||||||
|
''
|
||||||
|
], true);
|
||||||
|
}
|
||||||
if ($registration_date == '0000-00-00' || empty($registration_date)) {
|
if ($registration_date == '0000-00-00' || empty($registration_date)) {
|
||||||
$registration_date = null;
|
$registration_date = null;
|
||||||
}
|
}
|
||||||
|
if (!is_null($termination_date)) {
|
||||||
$termination_date = Validate::validate($termination_date, 'termination_date', Validate::REGEX_YYYY_MM_DD, '', [
|
$termination_date = Validate::validate($termination_date, 'termination_date',
|
||||||
'0000-00-00',
|
Validate::REGEX_YYYY_MM_DD, '', [
|
||||||
'0',
|
'0000-00-00',
|
||||||
''
|
'0',
|
||||||
], true);
|
''
|
||||||
|
], true);
|
||||||
|
}
|
||||||
if ($termination_date == '0000-00-00' || empty($termination_date)) {
|
if ($termination_date == '0000-00-00' || empty($termination_date)) {
|
||||||
$termination_date = null;
|
$termination_date = null;
|
||||||
}
|
}
|
||||||
@@ -513,7 +519,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$mod_fcgid_maxrequests = '-1';
|
$mod_fcgid_maxrequests = '-1';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$phpenabled = '1';
|
// set default to whether the customer has php enabled or not
|
||||||
|
$phpenabled = $customer['phpenabled'];
|
||||||
$openbasedir = '1';
|
$openbasedir = '1';
|
||||||
|
|
||||||
if ((int)Settings::Get('phpfpm.enabled') == 1) {
|
if ((int)Settings::Get('phpfpm.enabled') == 1) {
|
||||||
@@ -525,6 +532,10 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$mod_fcgid_maxrequests = '-1';
|
$mod_fcgid_maxrequests = '-1';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
|
||||||
|
$openbasedir_path = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check non-ssl IP
|
// check non-ssl IP
|
||||||
$ipandports = $this->validateIpAddresses($p_ipandports);
|
$ipandports = $this->validateIpAddresses($p_ipandports);
|
||||||
// check ssl IP
|
// check ssl IP
|
||||||
@@ -536,6 +547,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;
|
||||||
@@ -559,7 +574,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
||||||
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
||||||
$domain_ips = PhpHelper::gethostbynamel6($domain);
|
$domain_ips = PhpHelper::gethostbynamel6($domain, true, Settings::Get('system.le_domain_dnscheck_resolver'));
|
||||||
$selected_ips = $this->getIpsFromIdArray($ssl_ipandports);
|
$selected_ips = $this->getIpsFromIdArray($ssl_ipandports);
|
||||||
if ($domain_ips == false || count(array_intersect($selected_ips, $domain_ips)) <= 0) {
|
if ($domain_ips == false || count(array_intersect($selected_ips, $domain_ips)) <= 0) {
|
||||||
Response::standardError('invaliddnsforletsencrypt', '', true);
|
Response::standardError('invaliddnsforletsencrypt', '', true);
|
||||||
@@ -653,10 +668,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([
|
||||||
@@ -696,6 +707,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
'caneditdomain' => $caneditdomain,
|
'caneditdomain' => $caneditdomain,
|
||||||
'phpenabled' => $phpenabled,
|
'phpenabled' => $phpenabled,
|
||||||
'openbasedir' => $openbasedir,
|
'openbasedir' => $openbasedir,
|
||||||
|
'openbasedir_path' => $openbasedir_path,
|
||||||
'speciallogfile' => $speciallogfile,
|
'speciallogfile' => $speciallogfile,
|
||||||
'specialsettings' => $specialsettings,
|
'specialsettings' => $specialsettings,
|
||||||
'ssl_specialsettings' => $ssl_specialsettings,
|
'ssl_specialsettings' => $ssl_specialsettings,
|
||||||
@@ -710,7 +722,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,
|
||||||
@@ -749,6 +760,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`caneditdomain` = :caneditdomain,
|
`caneditdomain` = :caneditdomain,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`speciallogfile` = :speciallogfile,
|
`speciallogfile` = :speciallogfile,
|
||||||
`specialsettings` = :specialsettings,
|
`specialsettings` = :specialsettings,
|
||||||
`ssl_specialsettings` = :ssl_specialsettings,
|
`ssl_specialsettings` = :ssl_specialsettings,
|
||||||
@@ -763,7 +775,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,
|
||||||
@@ -884,7 +895,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
||||||
}
|
}
|
||||||
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get domain '" . $result['domain'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get domain '" . $result['domain'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
||||||
@@ -1055,9 +1066,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
|
||||||
@@ -1075,7 +1083,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
|
||||||
@@ -1087,7 +1095,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)
|
||||||
@@ -1096,6 +1104,8 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
* from setting system.apply_phpconfigs_default
|
* from setting system.apply_phpconfigs_default
|
||||||
* @param bool $openbasedir
|
* @param bool $openbasedir
|
||||||
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
|
||||||
|
* @param int $openbasedir_path
|
||||||
|
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
* optional, specify php-configuration that is being used by id, default 1 (system-default)
|
||||||
* @param int $mod_fcgid_starter
|
* @param int $mod_fcgid_starter
|
||||||
@@ -1114,7 +1124,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
|
||||||
@@ -1122,9 +1132,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
|
||||||
@@ -1134,6 +1144,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
|
||||||
@@ -1175,7 +1187,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']);
|
||||||
@@ -1193,6 +1204,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$phpenabled = $this->getBoolParam('phpenabled', true, $result['phpenabled']);
|
$phpenabled = $this->getBoolParam('phpenabled', true, $result['phpenabled']);
|
||||||
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, Settings::Get('system.apply_phpconfigs_default'));
|
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, Settings::Get('system.apply_phpconfigs_default'));
|
||||||
$openbasedir = $this->getBoolParam('openbasedir', true, $result['openbasedir']);
|
$openbasedir = $this->getBoolParam('openbasedir', true, $result['openbasedir']);
|
||||||
|
$openbasedir_path = $this->getParam('openbasedir_path', true, $result['openbasedir_path']);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
|
||||||
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, $result['mod_fcgid_starter']);
|
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, $result['mod_fcgid_starter']);
|
||||||
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, $result['mod_fcgid_maxrequests']);
|
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, $result['mod_fcgid_maxrequests']);
|
||||||
@@ -1202,7 +1214,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']);
|
||||||
@@ -1229,6 +1241,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("
|
||||||
@@ -1322,19 +1335,25 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$adminid = $result['adminid'];
|
$adminid = $result['adminid'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$registration_date = Validate::validate($registration_date, 'registration_date', Validate::REGEX_YYYY_MM_DD, '', [
|
if (!is_null($registration_date)) {
|
||||||
'0000-00-00',
|
$registration_date = Validate::validate($registration_date, 'registration_date',
|
||||||
'0',
|
Validate::REGEX_YYYY_MM_DD, '', [
|
||||||
''
|
'0000-00-00',
|
||||||
], true);
|
'0',
|
||||||
|
''
|
||||||
|
], true);
|
||||||
|
}
|
||||||
if ($registration_date == '0000-00-00' || empty($registration_date)) {
|
if ($registration_date == '0000-00-00' || empty($registration_date)) {
|
||||||
$registration_date = null;
|
$registration_date = null;
|
||||||
}
|
}
|
||||||
$termination_date = Validate::validate($termination_date, 'termination_date', Validate::REGEX_YYYY_MM_DD, '', [
|
if (!is_null($termination_date)) {
|
||||||
'0000-00-00',
|
$termination_date = Validate::validate($termination_date, 'termination_date',
|
||||||
'0',
|
Validate::REGEX_YYYY_MM_DD, '', [
|
||||||
''
|
'0000-00-00',
|
||||||
], true);
|
'0',
|
||||||
|
''
|
||||||
|
], true);
|
||||||
|
}
|
||||||
if ($termination_date == '0000-00-00' || empty($termination_date)) {
|
if ($termination_date == '0000-00-00' || empty($termination_date)) {
|
||||||
$termination_date = null;
|
$termination_date = null;
|
||||||
}
|
}
|
||||||
@@ -1478,6 +1497,11 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$mod_fcgid_maxrequests = $result['mod_fcgid_maxrequests'];
|
$mod_fcgid_maxrequests = $result['mod_fcgid_maxrequests'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check changes of openbasedir-path variable
|
||||||
|
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
|
||||||
|
$openbasedir_path = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check non-ssl IP
|
// check non-ssl IP
|
||||||
$ipandports = $this->validateIpAddresses($p_ipandports, false, $result['id']);
|
$ipandports = $this->validateIpAddresses($p_ipandports, false, $result['id']);
|
||||||
// check ssl IP
|
// check ssl IP
|
||||||
@@ -1500,13 +1524,16 @@ 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') == "0" || empty($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) || !$sslenabled) {
|
||||||
$ssl_redirect = 0;
|
$ssl_redirect = 0;
|
||||||
$letsencrypt = 0;
|
$letsencrypt = 0;
|
||||||
$http2 = 0;
|
$http2 = 0;
|
||||||
// we need this for the json_encode
|
// act like $remove_ssl_ipandport
|
||||||
// if ssl is disabled or no ssl-ip/port exists
|
$ssl_ipandports = [];
|
||||||
$ssl_ipandports[] = -1;
|
|
||||||
|
|
||||||
// HSTS
|
// HSTS
|
||||||
$hsts_maxage = 0;
|
$hsts_maxage = 0;
|
||||||
@@ -1523,7 +1550,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
||||||
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
||||||
$domain_ips = PhpHelper::gethostbynamel6($result['domain']);
|
$domain_ips = PhpHelper::gethostbynamel6($result['domain'], true, Settings::Get('system.le_domain_dnscheck_resolver'));
|
||||||
$selected_ips = $this->getIpsFromIdArray($ssl_ipandports);
|
$selected_ips = $this->getIpsFromIdArray($ssl_ipandports);
|
||||||
if ($domain_ips == false || count(array_intersect($selected_ips, $domain_ips)) <= 0) {
|
if ($domain_ips == false || count(array_intersect($selected_ips, $domain_ips)) <= 0) {
|
||||||
Response::standardError('invaliddnsforletsencrypt', '', true);
|
Response::standardError('invaliddnsforletsencrypt', '', true);
|
||||||
@@ -1536,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1612,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';
|
||||||
}
|
}
|
||||||
@@ -1623,7 +1646,32 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
||||||
$iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0';
|
$iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0';
|
||||||
|
|
||||||
if ($documentroot != $result['documentroot'] || $ssl_redirect != $result['ssl_redirect'] || $wwwserveralias != $result['wwwserveralias'] || $iswildcarddomain != $result['iswildcarddomain'] || $phpenabled != $result['phpenabled'] || $openbasedir != $result['openbasedir'] || $phpsettingid != $result['phpsettingid'] || $mod_fcgid_starter != $result['mod_fcgid_starter'] || $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests'] || $specialsettings != $result['specialsettings'] || $ssl_specialsettings != $result['ssl_specialsettings'] || $notryfiles != $result['notryfiles'] || $writeaccesslog != $result['writeaccesslog'] || $writeerrorlog != $result['writeerrorlog'] || $aliasdomain != $result['aliasdomain'] || $issubof != $result['ismainbutsubto'] || $email_only != $result['email_only'] || ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1') || $letsencrypt != $result['letsencrypt'] || $http2 != $result['http2'] || $hsts_maxage != $result['hsts'] || $hsts_sub != $result['hsts_sub'] || $hsts_preload != $result['hsts_preload'] || $ocsp_stapling != $result['ocsp_stapling']) {
|
if ($documentroot != $result['documentroot']
|
||||||
|
|| $ssl_redirect != $result['ssl_redirect']
|
||||||
|
|| $wwwserveralias != $result['wwwserveralias']
|
||||||
|
|| $iswildcarddomain != $result['iswildcarddomain']
|
||||||
|
|| $phpenabled != $result['phpenabled']
|
||||||
|
|| $openbasedir != $result['openbasedir']
|
||||||
|
|| $openbasedir_path != $result['openbasedir_path']
|
||||||
|
|| $phpsettingid != $result['phpsettingid']
|
||||||
|
|| $mod_fcgid_starter != $result['mod_fcgid_starter']
|
||||||
|
|| $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests']
|
||||||
|
|| $specialsettings != $result['specialsettings']
|
||||||
|
|| $ssl_specialsettings != $result['ssl_specialsettings']
|
||||||
|
|| $notryfiles != $result['notryfiles']
|
||||||
|
|| $writeaccesslog != $result['writeaccesslog']
|
||||||
|
|| $writeerrorlog != $result['writeerrorlog']
|
||||||
|
|| $aliasdomain != $result['aliasdomain']
|
||||||
|
|| $email_only != $result['email_only']
|
||||||
|
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|
||||||
|
|| $letsencrypt != $result['letsencrypt']
|
||||||
|
|| $http2 != $result['http2']
|
||||||
|
|| $hsts_maxage != $result['hsts']
|
||||||
|
|| $hsts_sub != $result['hsts_sub']
|
||||||
|
|| $hsts_preload != $result['hsts_preload']
|
||||||
|
|| $ocsp_stapling != $result['ocsp_stapling']
|
||||||
|
|| $sslenabled != $result['ssl_enabled']
|
||||||
|
) {
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1749,7 +1797,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
Database::pexecute($upd_stmt, [
|
Database::pexecute($upd_stmt, [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] removed specialsettings on all subdomains of domain #" . $id);
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] removed specialsettings on all subdomains of domain #" . $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
|
||||||
@@ -1772,6 +1820,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
$update_data['iswildcarddomain'] = $iswildcarddomain;
|
$update_data['iswildcarddomain'] = $iswildcarddomain;
|
||||||
$update_data['phpenabled'] = $phpenabled;
|
$update_data['phpenabled'] = $phpenabled;
|
||||||
$update_data['openbasedir'] = $openbasedir;
|
$update_data['openbasedir'] = $openbasedir;
|
||||||
|
$update_data['openbasedir_path'] = $openbasedir_path;
|
||||||
$update_data['speciallogfile'] = $speciallogfile;
|
$update_data['speciallogfile'] = $speciallogfile;
|
||||||
$update_data['phpsettingid'] = $phpsettingid;
|
$update_data['phpsettingid'] = $phpsettingid;
|
||||||
$update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
$update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
||||||
@@ -1784,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;
|
||||||
@@ -1799,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("
|
||||||
@@ -1819,6 +1868,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`iswildcarddomain` = :iswildcarddomain,
|
`iswildcarddomain` = :iswildcarddomain,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`speciallogfile` = :speciallogfile,
|
`speciallogfile` = :speciallogfile,
|
||||||
`phpsettingid` = :phpsettingid,
|
`phpsettingid` = :phpsettingid,
|
||||||
`mod_fcgid_starter` = :mod_fcgid_starter,
|
`mod_fcgid_starter` = :mod_fcgid_starter,
|
||||||
@@ -1831,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,
|
||||||
@@ -1845,15 +1894,41 @@ 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;
|
||||||
$_update_data['openbasedir'] = $openbasedir;
|
$_update_data['openbasedir'] = $openbasedir;
|
||||||
|
$_update_data['openbasedir_path'] = $openbasedir_path;
|
||||||
$_update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
$_update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
|
||||||
$_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests;
|
$_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests;
|
||||||
$_update_data['notryfiles'] = $notryfiles;
|
$_update_data['notryfiles'] = $notryfiles;
|
||||||
@@ -1866,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 = '';
|
||||||
@@ -1887,6 +1963,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
`adminid` = :adminid,
|
`adminid` = :adminid,
|
||||||
`phpenabled` = :phpenabled,
|
`phpenabled` = :phpenabled,
|
||||||
`openbasedir` = :openbasedir,
|
`openbasedir` = :openbasedir,
|
||||||
|
`openbasedir_path` = :openbasedir_path,
|
||||||
`mod_fcgid_starter` = :mod_fcgid_starter,
|
`mod_fcgid_starter` = :mod_fcgid_starter,
|
||||||
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
|
||||||
`notryfiles` = :notryfiles,
|
`notryfiles` = :notryfiles,
|
||||||
@@ -1897,12 +1974,25 @@ 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
|
||||||
");
|
");
|
||||||
Database::pexecute($_update_stmt, $_update_data, true, true);
|
Database::pexecute($_update_stmt, $_update_data, true, true);
|
||||||
|
|
||||||
|
// get current ip<>domain entries
|
||||||
|
$ip_sel_stmt = Database::prepare("
|
||||||
|
SELECT id_ipandports FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
||||||
|
");
|
||||||
|
Database::pexecute($ip_sel_stmt, [
|
||||||
|
'id' => $id
|
||||||
|
], true, true);
|
||||||
|
$current_ips = [];
|
||||||
|
while ($cIP = $ip_sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$current_ips[] = $cIP['id_ipandports'];
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup domain <-> ip mapping
|
// Cleanup domain <-> ip mapping
|
||||||
$del_stmt = Database::prepare("
|
$del_stmt = Database::prepare("
|
||||||
DELETE FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
DELETE FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
|
||||||
@@ -1930,6 +2020,12 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check ip changes
|
||||||
|
$all_new_ips = array_merge($ipandports, $ssl_ipandports);
|
||||||
|
if (count(array_diff($current_ips, $all_new_ips)) != 0 || count(array_diff($all_new_ips, $current_ips)) != 0) {
|
||||||
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup domain <-> ip mapping for subdomains
|
// Cleanup domain <-> ip mapping for subdomains
|
||||||
$domainidsresult_stmt = Database::prepare("
|
$domainidsresult_stmt = Database::prepare("
|
||||||
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `parentdomainid` = :id
|
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `parentdomainid` = :id
|
||||||
@@ -1974,12 +2070,11 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
if ($result['wwwserveralias'] != $wwwserveralias || $result['letsencrypt'] != $letsencrypt) {
|
if ($result['wwwserveralias'] != $wwwserveralias || $result['letsencrypt'] != $letsencrypt) {
|
||||||
// or when wwwserveralias or letsencrypt was changed
|
// or when wwwserveralias or letsencrypt was changed
|
||||||
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $this->logger());
|
|
||||||
if ((int)$aliasdomain === 0) {
|
if ((int)$aliasdomain === 0) {
|
||||||
// in case the wwwserveralias is set on a main domain, $aliasdomain is 0
|
// in case the wwwserveralias is set on a main domain, $aliasdomain is 0
|
||||||
// --> the call just above to triggerLetsEncryptCSRForAliasDestinationDomain
|
|
||||||
// is a noop...let's repeat it with the domain id of the main domain
|
|
||||||
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($id, $this->logger());
|
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($id, $this->logger());
|
||||||
|
} else {
|
||||||
|
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $this->logger());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2000,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
|
||||||
@@ -2018,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,
|
||||||
@@ -2026,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);
|
||||||
@@ -2056,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);
|
||||||
@@ -2138,7 +2211,9 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
'domainid' => $id
|
'domainid' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger());
|
if ((int)$result['aliasdomain'] !== 0) {
|
||||||
|
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger());
|
||||||
|
}
|
||||||
|
|
||||||
// remove domains DNS from powerDNS if used, #581
|
// remove domains DNS from powerDNS if used, #581
|
||||||
Cronjob::inserttask(TaskId::DELETE_DOMAIN_PDNS, $result['domain']);
|
Cronjob::inserttask(TaskId::DELETE_DOMAIN_PDNS, $result['domain']);
|
||||||
@@ -2146,7 +2221,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
|||||||
// remove domain from acme.sh / lets encrypt if used
|
// remove domain from acme.sh / lets encrypt if used
|
||||||
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $result['domain']);
|
Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $result['domain']);
|
||||||
|
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] deleted domain/subdomains (#" . $result['id'] . ")");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted domain/subdomains (#" . $result['id'] . ")");
|
||||||
User::updateCounters();
|
User::updateCounters();
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
// Using nameserver, insert a task which rebuilds the server config
|
// Using nameserver, insert a task which rebuilds the server config
|
||||||
@@ -2155,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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
* @param string $alternative_email
|
* @param string $alternative_email
|
||||||
* optional email address to send account information to, default is the account that is being created
|
* optional email address to send account information to, default is the account that is being created
|
||||||
* @param int $email_quota
|
* @param int $email_quota
|
||||||
* optional quota if enabled in MB, default 0
|
* optional quota if enabled in MB, default setting: system.mail_quota
|
||||||
* @param bool $sendinfomail
|
* @param bool $sendinfomail
|
||||||
* optional, sends the welcome message to the new account (needed for creation, without the user won't
|
* optional, sends the welcome message to the new account (needed for creation, without the user won't
|
||||||
* be able to login before any mail is received), default 1 (true)
|
* be able to login before any mail is received), default 1 (true)
|
||||||
@@ -85,7 +85,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
||||||
$email_password = $this->getParam('email_password');
|
$email_password = $this->getParam('email_password');
|
||||||
$alternative_email = $this->getParam('alternative_email', true, '');
|
$alternative_email = $this->getParam('alternative_email', true, '');
|
||||||
$quota = $this->getParam('email_quota', true, 0);
|
$quota = $this->getParam('email_quota', true, Settings::Get('system.mail_quota') ?? 0);
|
||||||
$sendinfomail = $this->getBoolParam('sendinfomail', true, 1);
|
$sendinfomail = $this->getBoolParam('sendinfomail', true, 1);
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
@@ -95,9 +95,18 @@ 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)) {
|
||||||
|
$idna_convert = new IdnaWrapper();
|
||||||
|
$emailaddr = $idna_convert->encode($emailaddr);
|
||||||
|
}
|
||||||
|
|
||||||
// get email address
|
// get email address
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
@@ -148,10 +157,10 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
// prefix hash-algo
|
// prefix hash-algo
|
||||||
switch (Settings::Get('system.passwordcryptfunc')) {
|
switch (Settings::Get('system.passwordcryptfunc')) {
|
||||||
case PASSWORD_ARGON2I:
|
case 'argon2i':
|
||||||
$cpPrefix = '{ARGON2I}';
|
$cpPrefix = '{ARGON2I}';
|
||||||
break;
|
break;
|
||||||
case PASSWORD_ARGON2ID:
|
case 'argon2id':
|
||||||
$cpPrefix = '{ARGON2ID}';
|
$cpPrefix = '{ARGON2ID}';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -306,7 +315,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email account for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email account for '" . $result['email_full'] . "'");
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
]);
|
]);
|
||||||
@@ -357,6 +366,11 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
$ea_optional = $id > 0;
|
$ea_optional = $id > 0;
|
||||||
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
||||||
|
|
||||||
|
if (!empty($emailaddr)) {
|
||||||
|
$idna_convert = new IdnaWrapper();
|
||||||
|
$emailaddr = $idna_convert->encode($emailaddr);
|
||||||
|
}
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
@@ -390,10 +404,10 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
$password = Crypt::validatePassword($password, true);
|
$password = Crypt::validatePassword($password, true);
|
||||||
// prefix hash-algo
|
// prefix hash-algo
|
||||||
switch (Settings::Get('system.passwordcryptfunc')) {
|
switch (Settings::Get('system.passwordcryptfunc')) {
|
||||||
case PASSWORD_ARGON2I:
|
case 'argon2i':
|
||||||
$cpPrefix = '{ARGON2I}';
|
$cpPrefix = '{ARGON2I}';
|
||||||
break;
|
break;
|
||||||
case PASSWORD_ARGON2ID:
|
case 'argon2id':
|
||||||
$cpPrefix = '{ARGON2ID}';
|
$cpPrefix = '{ARGON2ID}';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -450,7 +464,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
Admins::increaseUsage($customer['adminid'], 'email_quota_used', '', ($quota - $result['quota']));
|
Admins::increaseUsage($customer['adminid'], 'email_quota_used', '', ($quota - $result['quota']));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated email account '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated email account '" . $result['email_full'] . "'");
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
]);
|
]);
|
||||||
@@ -556,7 +570,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
|
|||||||
Customers::decreaseUsage($customer['customerid'], 'email_accounts_used');
|
Customers::decreaseUsage($customer['customerid'], 'email_accounts_used');
|
||||||
Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $quota);
|
Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $quota);
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email account for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted email account for '" . $result['email_full'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
188
lib/Froxlor/Api/Commands/EmailDomains.php
Normal file
188
lib/Froxlor/Api/Commands/EmailDomains.php
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Api\Commands;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Froxlor\Api\ApiCommand;
|
||||||
|
use Froxlor\Api\ResourceEntity;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class EmailDomains extends ApiCommand implements ResourceEntity
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* list all domains with email addresses connected to it.
|
||||||
|
* If called from an admin, list all domains with email addresses
|
||||||
|
* connected to it from all customers you are allowed to view, or
|
||||||
|
* specify id or loginname for one specific customer
|
||||||
|
*
|
||||||
|
* @param int $customerid
|
||||||
|
* optional, admin-only, select email addresses of a specific customer by id
|
||||||
|
* @param string $loginname
|
||||||
|
* optional, admin-only, select email addresses of a specific customer by loginname
|
||||||
|
* @param array $sql_search
|
||||||
|
* optional array with index = fieldname, and value = array with 'op' => operator (one of <, > or =),
|
||||||
|
* LIKE is used if left empty and 'value' => searchvalue
|
||||||
|
* @param int $sql_limit
|
||||||
|
* optional specify number of results to be returned
|
||||||
|
* @param int $sql_offset
|
||||||
|
* optional specify offset for resultset
|
||||||
|
* @param array $sql_orderby
|
||||||
|
* optional array with index = fieldname and value = ASC|DESC to order the resultset by one or more
|
||||||
|
* fields
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array count|list
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function listing()
|
||||||
|
{
|
||||||
|
$customer_ids = $this->getAllowedCustomerIds('email');
|
||||||
|
$result = [];
|
||||||
|
$query_fields = [];
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT DISTINCT d.domain, e.domainid,
|
||||||
|
COUNT(e.email) as addresses,
|
||||||
|
IFNULL(SUM(CASE WHEN e.popaccountid > 0 THEN 1 ELSE 0 END), 0) as accounts,
|
||||||
|
IFNULL(SUM(
|
||||||
|
CASE
|
||||||
|
WHEN LENGTH(REPLACE(e.destination, CONCAT(e.email_full, ' '), '')) - LENGTH(REPLACE(REPLACE(e.destination, CONCAT(e.email_full, ' '), ''), ' ', '')) > 0
|
||||||
|
THEN LENGTH(REPLACE(e.destination, CONCAT(e.email_full, ' '), '')) - LENGTH(REPLACE(REPLACE(e.destination, CONCAT(e.email_full, ' '), ''), ' ', ''))
|
||||||
|
WHEN e.destination <> e.email_full THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END
|
||||||
|
), 0) as forwarder
|
||||||
|
FROM `" . TABLE_MAIL_VIRTUAL . "` e
|
||||||
|
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON d.id = e.domainid
|
||||||
|
WHERE e.customerid IN (" . implode(", ", $customer_ids) . ") AND d.domain IS NOT NULL " .
|
||||||
|
$this->getSearchWhere($query_fields,
|
||||||
|
true) . " GROUP BY e.domainid " . $this->getOrderBy() . $this->getLimit());
|
||||||
|
Database::pexecute($result_stmt, $query_fields, true, true);
|
||||||
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$result[] = $row;
|
||||||
|
}
|
||||||
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO,
|
||||||
|
"[API] list email-domains");
|
||||||
|
return $this->response([
|
||||||
|
'count' => count($result),
|
||||||
|
'list' => $result
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the total number of accessible domains with email addresses connected to
|
||||||
|
*
|
||||||
|
* @param int $customerid
|
||||||
|
* optional, admin-only, select email addresses of a specific customer by id
|
||||||
|
* @param string $loginname
|
||||||
|
* optional, admin-only, select email addresses of a specific customer by loginname
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded response message
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function listingCount()
|
||||||
|
{
|
||||||
|
$customer_ids = $this->getAllowedCustomerIds('email');
|
||||||
|
$result_stmt = Database::prepare("
|
||||||
|
SELECT COUNT(DISTINCT d.domain) as num_emaildomains
|
||||||
|
FROM `" . TABLE_MAIL_VIRTUAL . "` e
|
||||||
|
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON d.id = e.domainid
|
||||||
|
WHERE e.customerid IN (" . implode(", ", $customer_ids) . ") AND d.domain IS NOT NULL
|
||||||
|
");
|
||||||
|
$result = Database::pexecute_first($result_stmt, null, true, true);
|
||||||
|
if ($result) {
|
||||||
|
return $this->response($result['num_emaildomains']);
|
||||||
|
}
|
||||||
|
return $this->response(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You cannot directly access email-domains
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function get()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
|
||||||
|
throw new Exception("You cannot access this resource", 405);
|
||||||
|
}
|
||||||
|
throw new Exception('You cannot directly access this resource.', 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You cannot directly add email-domains
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
|
||||||
|
throw new Exception("You cannot access this resource", 405);
|
||||||
|
}
|
||||||
|
throw new Exception('You cannot directly add this resource.', 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toggle catchall flag of given email address either by id or email-address
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
|
||||||
|
throw new Exception("You cannot access this resource", 405);
|
||||||
|
}
|
||||||
|
throw new Exception('You cannot directly update this resource.', 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You cannot directly delete email-domains
|
||||||
|
*
|
||||||
|
* @access admin, customer
|
||||||
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
|
||||||
|
throw new Exception("You cannot access this resource", 405);
|
||||||
|
}
|
||||||
|
throw new Exception('You cannot directly delete this resource.', 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -77,6 +77,11 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
|
|||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
$destination = $idna_convert->encode($destination);
|
$destination = $idna_convert->encode($destination);
|
||||||
|
|
||||||
|
if (!empty($emailaddr)) {
|
||||||
|
$idna_convert = new IdnaWrapper();
|
||||||
|
$emailaddr = $idna_convert->encode($emailaddr);
|
||||||
|
}
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'emailaddr' => $emailaddr
|
'emailaddr' => $emailaddr
|
||||||
@@ -116,7 +121,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
|
|||||||
// update customer usage
|
// update customer usage
|
||||||
Customers::increaseUsage($customer['customerid'], 'email_forwarders_used');
|
Customers::increaseUsage($customer['customerid'], 'email_forwarders_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email forwarder for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email forwarder for '" . $result['email_full'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
@@ -293,7 +298,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity
|
|||||||
// update customer usage
|
// update customer usage
|
||||||
Customers::decreaseUsage($customer['customerid'], 'email_forwarders_used');
|
Customers::decreaseUsage($customer['customerid'], 'email_forwarders_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email forwarder for '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted email forwarder for '" . $result['email_full'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -159,7 +162,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
// update customer usage
|
// update customer usage
|
||||||
Customers::increaseUsage($customer['customerid'], 'emails_used');
|
Customers::increaseUsage($customer['customerid'], 'emails_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email address '" . $email_full . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email address '" . $email_full . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $email_full
|
'emailaddr' => $email_full
|
||||||
@@ -195,11 +198,11 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
FROM `" . TABLE_MAIL_VIRTUAL . "` v
|
FROM `" . TABLE_MAIL_VIRTUAL . "` v
|
||||||
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
|
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
|
||||||
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
|
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
|
||||||
AND (v.`id`= :idea OR (v.`email` = :idea OR v.`email_full` = :idea))
|
AND " . (is_numeric($params['idea']) ? "v.`id`= :idea" : "(v.`email` = :idea OR v.`email_full` = :idea)")
|
||||||
");
|
);
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get email address '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get email address '" . $result['email_full'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'");
|
$key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'");
|
||||||
@@ -294,7 +297,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id
|
"id" => $id
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Emails.get', [
|
$result = $this->apiCall('Emails.get', [
|
||||||
'emailaddr' => $result['email_full']
|
'emailaddr' => $result['email_full']
|
||||||
@@ -340,7 +343,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list email-addresses");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list email-addresses");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
@@ -445,7 +448,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
|||||||
], true, true);
|
], true, true);
|
||||||
Customers::decreaseUsage($customer['customerid'], 'emails_used');
|
Customers::decreaseUsage($customer['customerid'], 'emails_used');
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email address '" . $result['email_full'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted email address '" . $result['email_full'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list fpm-daemons");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list fpm-daemons");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "`" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "`" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit());
|
||||||
@@ -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']) {
|
||||||
@@ -258,7 +258,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
$id = Database::lastInsertId();
|
$id = Database::lastInsertId();
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
||||||
$result = $this->apiCall('FpmDaemons.get', [
|
$result = $this->apiCall('FpmDaemons.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -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) {
|
||||||
@@ -384,7 +384,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
Database::pexecute($upd_stmt, $upd_data, true, true);
|
Database::pexecute($upd_stmt, $upd_data, true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
||||||
$result = $this->apiCall('FpmDaemons.get', [
|
$result = $this->apiCall('FpmDaemons.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
@@ -433,7 +433,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
|
|||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -72,7 +73,7 @@ class Froxlor extends ApiCommand
|
|||||||
|
|
||||||
if (empty($uc_data) || empty($response) || $uc_data['ts'] + self::UPDATE_CHECK_INTERVAL < time() || $uc_data['channel'] != Settings::Get('system.update_channel') || $force_ucheck) {
|
if (empty($uc_data) || empty($response) || $uc_data['ts'] + self::UPDATE_CHECK_INTERVAL < time() || $uc_data['channel'] != Settings::Get('system.update_channel') || $force_ucheck) {
|
||||||
// log our actions
|
// log our actions
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] checking for updates");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] checking for updates");
|
||||||
|
|
||||||
// check for new version
|
// check for new version
|
||||||
$aucheck = AutoUpdate::checkVersion();
|
$aucheck = AutoUpdate::checkVersion();
|
||||||
@@ -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();
|
||||||
@@ -142,7 +143,7 @@ class Froxlor extends ApiCommand
|
|||||||
{
|
{
|
||||||
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
|
if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) {
|
||||||
$json_str = $this->getParam('json_str');
|
$json_str = $this->getParam('json_str');
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "User " . $this->getUserDetail('loginname') . " imported settings");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "User " . $this->getUserDetail('loginname') . " imported settings");
|
||||||
try {
|
try {
|
||||||
SImExporter::import($json_str);
|
SImExporter::import($json_str);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
@@ -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
|
||||||
];
|
];
|
||||||
@@ -257,7 +261,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
Customers::increaseUsage($customer['customerid'], 'ftp_lastaccountnumber');
|
Customers::increaseUsage($customer['customerid'], 'ftp_lastaccountnumber');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ftp-account '" . $username . " (" . $path . ")'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ftp-account '" . $username . " (" . $path . ")'");
|
||||||
Cronjob::inserttask(TaskId::CREATE_FTP);
|
Cronjob::inserttask(TaskId::CREATE_FTP);
|
||||||
|
|
||||||
if ($sendinfomail == 1) {
|
if ($sendinfomail == 1) {
|
||||||
@@ -302,7 +306,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
$this->mailer()->clearAddresses();
|
$this->mailer()->clearAddresses();
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] added ftp-user '" . $username . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ftp-user '" . $username . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Ftps.get', [
|
$result = $this->apiCall('Ftps.get', [
|
||||||
'username' => $username
|
'username' => $username
|
||||||
@@ -367,7 +371,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
$params['idun'] = ($id <= 0 ? $username : $id);
|
$params['idun'] = ($id <= 0 ? $username : $id);
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get ftp-user '" . $result['username'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get ftp-user '" . $result['username'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
$key = ($id > 0 ? "id #" . $id : "username '" . $username . "'");
|
||||||
@@ -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();
|
||||||
|
|
||||||
@@ -453,12 +464,12 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
"id" => $id,
|
"id" => $id,
|
||||||
"password" => $cryptPassword
|
"password" => $cryptPassword
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ftp-account password for '" . $result['username'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-account password for '" . $result['username'] . "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// path update?
|
// path update?
|
||||||
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 . "`
|
||||||
@@ -471,7 +482,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
"customerid" => $customer['customerid'],
|
"customerid" => $customer['customerid'],
|
||||||
"id" => $id
|
"id" => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ftp-account homdir for '" . $result['username'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-account homdir for '" . $result['username'] . "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// it's the task for "new ftp" but that will
|
// it's the task for "new ftp" but that will
|
||||||
@@ -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);
|
||||||
@@ -533,7 +545,7 @@ class Ftps extends ApiCommand implements ResourceEntity
|
|||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list ftp-users");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list ftp-users");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list hosting-plans");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list hosting-plans");
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
$result_stmt = Database::prepare("
|
$result_stmt = Database::prepare("
|
||||||
SELECT p.*, a.loginname as adminname
|
SELECT p.*, a.loginname as adminname
|
||||||
@@ -200,7 +200,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, 0);
|
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, 0);
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$name = Validate::validate(trim($name), 'name', '', '', [], true);
|
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT);
|
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT);
|
||||||
|
|
||||||
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
||||||
@@ -227,7 +227,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
'valuearr' => json_encode($value_arr)
|
'valuearr' => json_encode($value_arr)
|
||||||
];
|
];
|
||||||
Database::pexecute($ins_stmt, $ins_data, true, true);
|
Database::pexecute($ins_stmt, $ins_data, true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added hosting-plan '" . $name . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] added hosting-plan '" . $name . "'");
|
||||||
$result = $this->apiCall('HostingPlans.get', [
|
$result = $this->apiCall('HostingPlans.get', [
|
||||||
'planname' => $name
|
'planname' => $name
|
||||||
]);
|
]);
|
||||||
@@ -264,7 +264,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
$result = Database::pexecute_first($result_stmt, $params, true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get hosting-plan '" . $result['name'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get hosting-plan '" . $result['name'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "planname '" . $planname . "'");
|
$key = ($id > 0 ? "id #" . $id : "planname '" . $planname . "'");
|
||||||
@@ -382,7 +382,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, $result['logviewenabled']);
|
$value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, $result['logviewenabled']);
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$name = Validate::validate(trim($name), 'name', '', '', [], true);
|
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
|
||||||
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT);
|
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT);
|
||||||
|
|
||||||
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
if (Settings::Get('system.mail_quota_enabled') != '1') {
|
||||||
@@ -414,7 +414,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
|
|||||||
'id' => $id
|
'id' => $id
|
||||||
];
|
];
|
||||||
Database::pexecute($upd_stmt, $update_data, true, true);
|
Database::pexecute($upd_stmt, $update_data, true, true);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] updated hosting-plan '" . $result['name'] . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] updated hosting-plan '" . $result['name'] . "'");
|
||||||
return $this->response($update_data);
|
return $this->response($update_data);
|
||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin() && ($this->getUserDetail('change_serversettings') || !empty($this->getUserDetail('ip')))) {
|
if ($this->isAdmin() && ($this->getUserDetail('change_serversettings') || !empty($this->getUserDetail('ip')))) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list ips and ports");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list ips and ports");
|
||||||
$ip_where = "";
|
$ip_where = "";
|
||||||
$append_where = false;
|
$append_where = false;
|
||||||
if (!empty($this->getUserDetail('ip')) && $this->getUserDetail('ip') != -1) {
|
if (!empty($this->getUserDetail('ip')) && $this->getUserDetail('ip') != -1) {
|
||||||
@@ -175,9 +175,10 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
$docroot = Validate::validate($this->getParam('docroot', true, ''), 'docroot', Validate::REGEX_DIR, '', [], true);
|
$docroot = Validate::validate($this->getParam('docroot', true, ''), 'docroot', Validate::REGEX_DIR, '', [], true);
|
||||||
|
|
||||||
if ((int)Settings::Get('system.use_ssl') == 1) {
|
if ((int)Settings::Get('system.use_ssl') == 1) {
|
||||||
$ssl = !empty($this->getBoolParam('ssl', true, 0)) ? intval($this->getBoolParam('ssl', true, 0)) : 0;
|
$ssl = (bool)$this->getBoolParam('ssl', true, 0);
|
||||||
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', $ssl, ''), 'ssl_cert_file', '', '', [], true);
|
$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, '');
|
||||||
@@ -335,7 +336,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
'id' => $id
|
'id' => $id
|
||||||
], true, true);
|
], true, true);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get ip " . $result['ip'] . " " . $result['port']);
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get ip " . $result['ip'] . " " . $result['port']);
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("IP/port with id #" . $id . " could not be found", 404);
|
throw new Exception("IP/port with id #" . $id . " could not be found", 404);
|
||||||
@@ -414,9 +415,10 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
|
|||||||
$docroot = Validate::validate($this->getParam('docroot', true, $result['docroot']), 'docroot', Validate::REGEX_DIR, '', [], true);
|
$docroot = Validate::validate($this->getParam('docroot', true, $result['docroot']), 'docroot', Validate::REGEX_DIR, '', [], true);
|
||||||
|
|
||||||
if ((int)Settings::Get('system.use_ssl') == 1) {
|
if ((int)Settings::Get('system.use_ssl') == 1) {
|
||||||
$ssl = $this->getBoolParam('ssl', true, $result['ssl']);
|
$ssl = (bool)$this->getBoolParam('ssl', true, $result['ssl']);
|
||||||
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', $ssl, $result['ssl_cert_file']), 'ssl_cert_file', '', '', [], true);
|
$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']);
|
||||||
|
|||||||
@@ -26,14 +26,15 @@
|
|||||||
namespace Froxlor\Api\Commands;
|
namespace Froxlor\Api\Commands;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use PDO;
|
|
||||||
use PDOException;
|
|
||||||
use Froxlor\Froxlor;
|
|
||||||
use Froxlor\PhpHelper;
|
|
||||||
use Froxlor\Api\ApiCommand;
|
use Froxlor\Api\ApiCommand;
|
||||||
use Froxlor\Api\ResourceEntity;
|
use Froxlor\Api\ResourceEntity;
|
||||||
use Froxlor\Database\Database;
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\FroxlorLogger;
|
||||||
|
use Froxlor\PhpHelper;
|
||||||
use Froxlor\Validate\Validate;
|
use Froxlor\Validate\Validate;
|
||||||
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
|
|
||||||
class MysqlServer extends ApiCommand implements ResourceEntity
|
class MysqlServer extends ApiCommand implements ResourceEntity
|
||||||
{
|
{
|
||||||
@@ -73,8 +74,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional, test connection with given credentials, default is true (yes)
|
* optional, test connection with given credentials, default is true (yes)
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function add()
|
public function add()
|
||||||
{
|
{
|
||||||
@@ -112,7 +113,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
);
|
);
|
||||||
if (!empty($mysql_ca)) {
|
if (!empty($mysql_ca)) {
|
||||||
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
||||||
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool) $mysql_verifycert;
|
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool)$mysql_verifycert;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
||||||
@@ -167,6 +168,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
$this->addDatabaseFromCustomerAllowedList($newdbserver);
|
$this->addDatabaseFromCustomerAllowedList($newdbserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added new database server '" . $description . "' (" . $mysql_host . ")");
|
||||||
|
|
||||||
return $this->response(['dbserver' => $newdbserver]);
|
return $this->response(['dbserver' => $newdbserver]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,16 +182,16 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional the number of the mysql server (either id or dbserver must be set)
|
* optional the number of the mysql server (either id or dbserver must be set)
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
$this->validateAccess();
|
$this->validateAccess();
|
||||||
|
|
||||||
$id = (int) $this->getParam('id', true, -1);
|
$id = (int)$this->getParam('id', true, -1);
|
||||||
$dn_optional = $id >= 0;
|
$dn_optional = $id >= 0;
|
||||||
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
|
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
|
||||||
$dbserver = $id >= 0 ? $id : $dbserver;
|
$dbserver = $id >= 0 ? $id : $dbserver;
|
||||||
|
|
||||||
if ($dbserver == 0) {
|
if ($dbserver == 0) {
|
||||||
@@ -212,8 +215,12 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
// when removing, remove from list of allowed_mysqlservers from any customers
|
// when removing, remove from list of allowed_mysqlservers from any customers
|
||||||
$this->removeDatabaseFromCustomerAllowedList($dbserver);
|
$this->removeDatabaseFromCustomerAllowedList($dbserver);
|
||||||
|
|
||||||
|
$description = $sql_root[$dbserver]['caption'] ?? "unknown";
|
||||||
|
$mysql_host = $sql_root[$dbserver]['host'] ?? "unknown";
|
||||||
unset($sql_root[$dbserver]);
|
unset($sql_root[$dbserver]);
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] removed database server '" . $description . "' (" . $mysql_host . ")");
|
||||||
|
|
||||||
$this->generateNewUserData($sql, $sql_root);
|
$this->generateNewUserData($sql, $sql_root);
|
||||||
return $this->response(['true']);
|
return $this->response(['true']);
|
||||||
}
|
}
|
||||||
@@ -287,14 +294,14 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional the number of the mysql server (either id or dbserver must be set)
|
* optional the number of the mysql server (either id or dbserver must be set)
|
||||||
*
|
*
|
||||||
* @access admin, customer
|
* @access admin, customer
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function get()
|
public function get()
|
||||||
{
|
{
|
||||||
$id = (int) $this->getParam('id', true, -1);
|
$id = (int)$this->getParam('id', true, -1);
|
||||||
$dn_optional = $id >= 0;
|
$dn_optional = $id >= 0;
|
||||||
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
|
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
|
||||||
$dbserver = $id >= 0 ? $id : $dbserver;
|
$dbserver = $id >= 0 ? $id : $dbserver;
|
||||||
|
|
||||||
$sql_root = [];
|
$sql_root = [];
|
||||||
@@ -317,6 +324,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
unset($sql_root[$dbserver]['password']);
|
unset($sql_root[$dbserver]['password']);
|
||||||
$sql_root[$dbserver]['id'] = $dbserver;
|
$sql_root[$dbserver]['id'] = $dbserver;
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get database-server '" . $sql_root[$dbserver]['caption'] . "'");
|
||||||
return $this->response($sql_root[$dbserver]);
|
return $this->response($sql_root[$dbserver]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,16 +355,16 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
* optional, test connection with given credentials, default is true (yes)
|
* optional, test connection with given credentials, default is true (yes)
|
||||||
*
|
*
|
||||||
* @access admin
|
* @access admin
|
||||||
* @throws Exception
|
|
||||||
* @return string json-encoded array
|
* @return string json-encoded array
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
$this->validateAccess();
|
$this->validateAccess();
|
||||||
|
|
||||||
$id = (int) $this->getParam('id', true, -1);
|
$id = (int)$this->getParam('id', true, -1);
|
||||||
$dn_optional = $id >= 0;
|
$dn_optional = $id >= 0;
|
||||||
$dbserver = (int) $this->getParam('dbserver', $dn_optional, -1);
|
$dbserver = (int)$this->getParam('dbserver', $dn_optional, -1);
|
||||||
$dbserver = $id >= 0 ? $id : $dbserver;
|
$dbserver = $id >= 0 ? $id : $dbserver;
|
||||||
|
|
||||||
$sql_root = [];
|
$sql_root = [];
|
||||||
@@ -417,7 +425,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
);
|
);
|
||||||
if (!empty($mysql_ca)) {
|
if (!empty($mysql_ca)) {
|
||||||
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
$options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca;
|
||||||
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool) $mysql_verifycert;
|
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool)$mysql_verifycert;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
$dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";";
|
||||||
@@ -448,6 +456,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
$this->addDatabaseFromCustomerAllowedList($dbserver);
|
$this->addDatabaseFromCustomerAllowedList($dbserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] edited database server '" . $description . "' (" . $mysql_host . ")");
|
||||||
|
|
||||||
return $this->response(['true']);
|
return $this->response(['true']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +482,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
WHERE `dbserver` = :dbserver
|
WHERE `dbserver` = :dbserver
|
||||||
");
|
");
|
||||||
$result = Database::pexecute_first($result_stmt, ['dbserver' => $dbserver], true, true);
|
$result = Database::pexecute_first($result_stmt, ['dbserver' => $dbserver], true, true);
|
||||||
return (int) $result['num_dbs'];
|
return (int)$result['num_dbs'];
|
||||||
} else {
|
} else {
|
||||||
$dbserver = $this->getParam('mysql_server');
|
$dbserver = $this->getParam('mysql_server');
|
||||||
$customer_ids = $this->getAllowedCustomerIds();
|
$customer_ids = $this->getAllowedCustomerIds();
|
||||||
@@ -516,7 +526,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
|
|||||||
`allowed_mysqlserver` = :am WHERE `customerid` = :cid
|
`allowed_mysqlserver` = :am WHERE `customerid` = :cid
|
||||||
");
|
");
|
||||||
while ($customer = $sel_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($customer = $sel_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$allowed_mysqls = json_decode(($customer['allowed_mysqlserver'] ?? '[]'), true);
|
$allowed_mysqls = json_decode(($customer['allowed_mysqlserver'] ?: '[]'), true);
|
||||||
if (!in_array($dbserver, $allowed_mysqls)) {
|
if (!in_array($dbserver, $allowed_mysqls)) {
|
||||||
$allowed_mysqls[] = $dbserver;
|
$allowed_mysqls[] = $dbserver;
|
||||||
$allowed_mysqls = json_encode($allowed_mysqls);
|
$allowed_mysqls = json_encode($allowed_mysqls);
|
||||||
|
|||||||
@@ -73,12 +73,12 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
$password = $this->getParam('mysql_password');
|
$password = $this->getParam('mysql_password');
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
$dbserver = $this->getParam('mysql_server', true, 0);
|
|
||||||
$databasedescription = $this->getParam('description', true, '');
|
$databasedescription = $this->getParam('description', true, '');
|
||||||
$databasename = $this->getParam('custom_suffix', true, '');
|
$databasename = $this->getParam('custom_suffix', true, '');
|
||||||
$sendinfomail = $this->getBoolParam('sendinfomail', true, 0);
|
$sendinfomail = $this->getBoolParam('sendinfomail', true, 0);
|
||||||
// get needed customer info to reduce the mysql-usage-counter by one
|
// get needed customer info to reduce the mysql-usage-counter by one
|
||||||
$customer = $this->getCustomerData('mysqls');
|
$customer = $this->getCustomerData('mysqls');
|
||||||
|
$dbserver = $this->getParam('mysql_server', true, $this->getDefaultMySqlServer($customer));
|
||||||
|
|
||||||
// validation
|
// validation
|
||||||
$password = Validate::validate($password, 'password', '', '', [], true);
|
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||||
@@ -199,7 +199,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
|
|
||||||
$this->mailer()->clearAddresses();
|
$this->mailer()->clearAddresses();
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] added mysql-database '" . $username . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added mysql-database '" . $username . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('Mysqls.get', [
|
$result = $this->apiCall('Mysqls.get', [
|
||||||
'dbname' => $username,
|
'dbname' => $username,
|
||||||
@@ -299,7 +299,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
$mbdata = $mbdata_stmt->fetch(PDO::FETCH_ASSOC);
|
$mbdata = $mbdata_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
Database::needRoot(false);
|
Database::needRoot(false);
|
||||||
$result['size'] = $mbdata['MB'] ?? 0;
|
$result['size'] = $mbdata['MB'] ?? 0;
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get database '" . $result['databasename'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get database '" . $result['databasename'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "dbname '" . $dbname . "'");
|
$key = ($id > 0 ? "id #" . $id : "dbname '" . $dbname . "'");
|
||||||
@@ -388,7 +388,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
|
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] updated mysql-database '" . $result['databasename'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated mysql-database '" . $result['databasename'] . "'");
|
||||||
$result = $this->apiCall('Mysqls.get', [
|
$result = $this->apiCall('Mysqls.get', [
|
||||||
'dbname' => $result['databasename']
|
'dbname' => $result['databasename']
|
||||||
]);
|
]);
|
||||||
@@ -558,4 +558,13 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
|||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted database '" . $result['databasename'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted database '" . $result['databasename'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getDefaultMySqlServer(array $customer) {
|
||||||
|
$allowed_mysqlservers = json_decode($customer['allowed_mysqlserver'] ?? '[]', true);
|
||||||
|
asort($allowed_mysqlservers, SORT_NUMERIC);
|
||||||
|
if (count($allowed_mysqlservers) == 1 && $allowed_mysqlservers[0] != 0) {
|
||||||
|
return (int) $allowed_mysqlservers[0];
|
||||||
|
}
|
||||||
|
return (int) array_shift($allowed_mysqlservers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
public function listing()
|
public function listing()
|
||||||
{
|
{
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list php-configs");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list php-configs");
|
||||||
|
|
||||||
$with_subdomains = $this->getBoolParam('with_subdomains', true, false);
|
$with_subdomains = $this->getBoolParam('with_subdomains', true, false);
|
||||||
$query_fields = [];
|
$query_fields = [];
|
||||||
@@ -222,8 +222,8 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
* optional request terminate timeout if FPM is used, default is '60s'
|
* optional request terminate timeout if FPM is used, default is '60s'
|
||||||
* @param string $phpfpm_reqslowtimeout
|
* @param string $phpfpm_reqslowtimeout
|
||||||
* optional request slowlog timeout if FPM is used, default is '5s'
|
* optional request slowlog timeout if FPM is used, default is '5s'
|
||||||
* @param bool $phpfpm_pass_authorizationheader
|
* @param bool $pass_authorizationheader
|
||||||
* optional whether to pass authorization header to webserver if FPM is used, default is 0 (false)
|
* optional whether to pass authorization header to webserver if FPM/FCGID is used, default is 0 (false)
|
||||||
* @param bool $override_fpmconfig
|
* @param bool $override_fpmconfig
|
||||||
* optional whether to override fpm-daemon-config value for the following settings if FPM is used,
|
* optional whether to override fpm-daemon-config value for the following settings if FPM is used,
|
||||||
* default is 0 (false)
|
* default is 0 (false)
|
||||||
@@ -276,7 +276,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
$fpm_enableslowlog = $this->getBoolParam('phpfpm_enable_slowlog', true, 0);
|
$fpm_enableslowlog = $this->getBoolParam('phpfpm_enable_slowlog', true, 0);
|
||||||
$fpm_reqtermtimeout = $this->getParam('phpfpm_reqtermtimeout', true, "60s");
|
$fpm_reqtermtimeout = $this->getParam('phpfpm_reqtermtimeout', true, "60s");
|
||||||
$fpm_reqslowtimeout = $this->getParam('phpfpm_reqslowtimeout', true, "5s");
|
$fpm_reqslowtimeout = $this->getParam('phpfpm_reqslowtimeout', true, "5s");
|
||||||
$fpm_pass_authorizationheader = $this->getBoolParam('phpfpm_pass_authorizationheader', true, 0);
|
$pass_authorizationheader = $this->getBoolParam('pass_authorizationheader', true, 0);
|
||||||
|
|
||||||
$override_fpmconfig = $this->getBoolParam('override_fpmconfig', true, 0);
|
$override_fpmconfig = $this->getBoolParam('override_fpmconfig', true, 0);
|
||||||
$def_fpmconfig = $this->apiCall('FpmDaemons.get', [
|
$def_fpmconfig = $this->apiCall('FpmDaemons.get', [
|
||||||
@@ -312,7 +312,6 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
$fpm_enableslowlog = 0;
|
$fpm_enableslowlog = 0;
|
||||||
$fpm_reqtermtimeout = 0;
|
$fpm_reqtermtimeout = 0;
|
||||||
$fpm_reqslowtimeout = 0;
|
$fpm_reqslowtimeout = 0;
|
||||||
$fpm_pass_authorizationheader = 0;
|
|
||||||
$override_fpmconfig = 0;
|
$override_fpmconfig = 0;
|
||||||
} elseif (Settings::Get('phpfpm.enabled') == 1) {
|
} elseif (Settings::Get('phpfpm.enabled') == 1) {
|
||||||
$fpm_reqtermtimeout = Validate::validate($fpm_reqtermtimeout, 'phpfpm_reqtermtimeout', '/^([0-9]+)(|s|m|h|d)$/', '', [], true);
|
$fpm_reqtermtimeout = Validate::validate($fpm_reqtermtimeout, 'phpfpm_reqtermtimeout', '/^([0-9]+)(|s|m|h|d)$/', '', [], true);
|
||||||
@@ -377,7 +376,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
'fpmreqslow' => $fpm_reqslowtimeout,
|
'fpmreqslow' => $fpm_reqslowtimeout,
|
||||||
'phpsettings' => $phpsettings,
|
'phpsettings' => $phpsettings,
|
||||||
'fpmsettingid' => $fpm_config_id,
|
'fpmsettingid' => $fpm_config_id,
|
||||||
'fpmpassauth' => $fpm_pass_authorizationheader,
|
'fpmpassauth' => $pass_authorizationheader,
|
||||||
'ofc' => $override_fpmconfig,
|
'ofc' => $override_fpmconfig,
|
||||||
'pm' => $pmanager,
|
'pm' => $pmanager,
|
||||||
'max_children' => $max_children,
|
'max_children' => $max_children,
|
||||||
@@ -392,7 +391,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
$ins_data['id'] = Database::lastInsertId();
|
$ins_data['id'] = Database::lastInsertId();
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('PhpSettings.get', [
|
$result = $this->apiCall('PhpSettings.get', [
|
||||||
'id' => $ins_data['id']
|
'id' => $ins_data['id']
|
||||||
@@ -464,7 +463,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
* optional request terminate timeout if FPM is used, default is '60s'
|
* optional request terminate timeout if FPM is used, default is '60s'
|
||||||
* @param string $phpfpm_reqslowtimeout
|
* @param string $phpfpm_reqslowtimeout
|
||||||
* optional request slowlog timeout if FPM is used, default is '5s'
|
* optional request slowlog timeout if FPM is used, default is '5s'
|
||||||
* @param bool $phpfpm_pass_authorizationheader
|
* @param bool $pass_authorizationheader
|
||||||
* optional whether to pass authorization header to webserver if FPM is used, default is 0 (false)
|
* optional whether to pass authorization header to webserver if FPM is used, default is 0 (false)
|
||||||
* @param bool $override_fpmconfig
|
* @param bool $override_fpmconfig
|
||||||
* optional whether to override fpm-daemon-config value for the following settings if FPM is used,
|
* optional whether to override fpm-daemon-config value for the following settings if FPM is used,
|
||||||
@@ -516,7 +515,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
$fpm_enableslowlog = $this->getBoolParam('phpfpm_enable_slowlog', true, $result['fpm_slowlog']);
|
$fpm_enableslowlog = $this->getBoolParam('phpfpm_enable_slowlog', true, $result['fpm_slowlog']);
|
||||||
$fpm_reqtermtimeout = $this->getParam('phpfpm_reqtermtimeout', true, $result['fpm_reqterm']);
|
$fpm_reqtermtimeout = $this->getParam('phpfpm_reqtermtimeout', true, $result['fpm_reqterm']);
|
||||||
$fpm_reqslowtimeout = $this->getParam('phpfpm_reqslowtimeout', true, $result['fpm_reqslow']);
|
$fpm_reqslowtimeout = $this->getParam('phpfpm_reqslowtimeout', true, $result['fpm_reqslow']);
|
||||||
$fpm_pass_authorizationheader = $this->getBoolParam('phpfpm_pass_authorizationheader', true, $result['pass_authorizationheader']);
|
$pass_authorizationheader = $this->getBoolParam('pass_authorizationheader', true, $result['pass_authorizationheader']);
|
||||||
$override_fpmconfig = $this->getBoolParam('override_fpmconfig', true, $result['override_fpmconfig']);
|
$override_fpmconfig = $this->getBoolParam('override_fpmconfig', true, $result['override_fpmconfig']);
|
||||||
$pmanager = $this->getParam('pm', true, $result['pm']);
|
$pmanager = $this->getParam('pm', true, $result['pm']);
|
||||||
$max_children = $this->getParam('max_children', true, $result['max_children']);
|
$max_children = $this->getParam('max_children', true, $result['max_children']);
|
||||||
@@ -548,7 +547,6 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
$fpm_enableslowlog = 0;
|
$fpm_enableslowlog = 0;
|
||||||
$fpm_reqtermtimeout = 0;
|
$fpm_reqtermtimeout = 0;
|
||||||
$fpm_reqslowtimeout = 0;
|
$fpm_reqslowtimeout = 0;
|
||||||
$fpm_pass_authorizationheader = 0;
|
|
||||||
$override_fpmconfig = 0;
|
$override_fpmconfig = 0;
|
||||||
} elseif (Settings::Get('phpfpm.enabled') == 1) {
|
} elseif (Settings::Get('phpfpm.enabled') == 1) {
|
||||||
$fpm_reqtermtimeout = Validate::validate($fpm_reqtermtimeout, 'phpfpm_reqtermtimeout', '/^([0-9]+)(|s|m|h|d)$/', '', [], true);
|
$fpm_reqtermtimeout = Validate::validate($fpm_reqtermtimeout, 'phpfpm_reqtermtimeout', '/^([0-9]+)(|s|m|h|d)$/', '', [], true);
|
||||||
@@ -614,7 +612,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
'fpmreqslow' => $fpm_reqslowtimeout,
|
'fpmreqslow' => $fpm_reqslowtimeout,
|
||||||
'phpsettings' => $phpsettings,
|
'phpsettings' => $phpsettings,
|
||||||
'fpmsettingid' => $fpm_config_id,
|
'fpmsettingid' => $fpm_config_id,
|
||||||
'fpmpassauth' => $fpm_pass_authorizationheader,
|
'fpmpassauth' => $pass_authorizationheader,
|
||||||
'ofc' => $override_fpmconfig,
|
'ofc' => $override_fpmconfig,
|
||||||
'pm' => $pmanager,
|
'pm' => $pmanager,
|
||||||
'max_children' => $max_children,
|
'max_children' => $max_children,
|
||||||
@@ -629,7 +627,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
Database::pexecute($upd_stmt, $upd_data, true, true);
|
Database::pexecute($upd_stmt, $upd_data, true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
|
||||||
|
|
||||||
$result = $this->apiCall('PhpSettings.get', [
|
$result = $this->apiCall('PhpSettings.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
@@ -686,7 +684,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity
|
|||||||
], true, true);
|
], true, true);
|
||||||
|
|
||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
throw new Exception("Not allowed to execute given command.", 403);
|
throw new Exception("Not allowed to execute given command.", 403);
|
||||||
|
|||||||
@@ -62,11 +62,13 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
* optional, overwrites path value with an URL to generate a redirect, alternatively use the path
|
* optional, overwrites path value with an URL to generate a redirect, alternatively use the path
|
||||||
* parameter also for URLs
|
* parameter also for URLs
|
||||||
* @param int $openbasedir_path
|
* @param int $openbasedir_path
|
||||||
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
* optional, either 0 for domains-docroot [default], 1 for customers-homedir or 2 for parent-directory of domains-docroot
|
||||||
* @param int $phpsettingid
|
* @param int $phpsettingid
|
||||||
* optional, php-settings-id, if empty the $domain value is used
|
* optional, php-settings-id, if empty the $domain value is used
|
||||||
* @param int $redirectcode
|
* @param int $redirectcode
|
||||||
* 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)
|
||||||
@@ -104,9 +106,10 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$aliasdomain = $this->getParam('alias', true, 0);
|
$aliasdomain = $this->getParam('alias', true, 0);
|
||||||
$path = $this->getParam('path', true, '');
|
$path = $this->getParam('path', true, '');
|
||||||
$url = $this->getParam('url', true, '');
|
$url = $this->getParam('url', true, '');
|
||||||
$openbasedir_path = $this->getParam('openbasedir_path', true, 1);
|
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
|
||||||
$phpsettingid = $this->getParam('phpsettingid', true, 0);
|
$phpsettingid = $this->getParam('phpsettingid', true, 0);
|
||||||
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
|
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
|
||||||
|
$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
|
||||||
@@ -262,7 +268,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
||||||
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
||||||
$our_ips = Domain::getIpsOfDomain($domain_check['id']);
|
$our_ips = Domain::getIpsOfDomain($domain_check['id']);
|
||||||
$domain_ips = PhpHelper::gethostbynamel6($completedomain);
|
$domain_ips = PhpHelper::gethostbynamel6($completedomain, true, Settings::Get('system.le_domain_dnscheck_resolver'));
|
||||||
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
||||||
Response::standardError('invaliddnsforletsencrypt', '', true);
|
Response::standardError('invaliddnsforletsencrypt', '', true);
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
@@ -285,21 +296,24 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
// assign default config
|
// assign default config
|
||||||
$phpsid_result['phpsettingid'] = 1;
|
$phpsid_result['phpsettingid'] = 1;
|
||||||
}
|
}
|
||||||
// check whether the customer has chosen its own php-config
|
|
||||||
if ($phpsettingid > 0 && $phpsettingid != $phpsid_result['phpsettingid']) {
|
|
||||||
$phpsid_result['phpsettingid'] = intval($phpsettingid);
|
|
||||||
}
|
|
||||||
|
|
||||||
$allowed_phpconfigs = $customer['allowed_phpconfigs'];
|
if ($domain_check['phpenabled'] == 1) {
|
||||||
if (!empty($allowed_phpconfigs)) {
|
// check whether the customer has chosen its own php-config
|
||||||
$allowed_phpconfigs = json_decode($allowed_phpconfigs, true);
|
if ($phpsettingid > 0 && $phpsettingid != $phpsid_result['phpsettingid']) {
|
||||||
} else {
|
$phpsid_result['phpsettingid'] = intval($phpsettingid);
|
||||||
$allowed_phpconfigs = [];
|
}
|
||||||
}
|
|
||||||
// only with fcgid/fpm enabled will it be possible to select a php-setting
|
$allowed_phpconfigs = $customer['allowed_phpconfigs'];
|
||||||
if ((int)Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1) {
|
if (!empty($allowed_phpconfigs)) {
|
||||||
if (!in_array($phpsid_result['phpsettingid'], $allowed_phpconfigs)) {
|
$allowed_phpconfigs = json_decode($allowed_phpconfigs, true);
|
||||||
Response::standardError('notallowedphpconfigused', '', true);
|
} else {
|
||||||
|
$allowed_phpconfigs = [];
|
||||||
|
}
|
||||||
|
// only with fcgid/fpm enabled will it be possible to select a php-setting
|
||||||
|
if ((int)Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1) {
|
||||||
|
if (!in_array($phpsid_result['phpsettingid'], $allowed_phpconfigs)) {
|
||||||
|
Response::standardError('notallowedphpconfigused', '', true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,7 +365,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'],
|
||||||
@@ -486,7 +500,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
$result['ipsandports'] = $this->getIpsForDomain($result['id']);
|
||||||
}
|
}
|
||||||
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
$result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']);
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get subdomain '" . $result['domain'] . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get subdomain '" . $result['domain'] . "'");
|
||||||
return $this->response($result);
|
return $this->response($result);
|
||||||
}
|
}
|
||||||
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
$key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'");
|
||||||
@@ -553,9 +567,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 +602,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 +664,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']);
|
||||||
@@ -738,7 +759,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
// validate dns if lets encrypt is enabled to check whether we can use it at all
|
||||||
if ($result['letsencrypt'] != $letsencrypt && $letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
if ($result['letsencrypt'] != $letsencrypt && $letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
|
||||||
$our_ips = Domain::getIpsOfDomain($result['parentdomainid']);
|
$our_ips = Domain::getIpsOfDomain($result['parentdomainid']);
|
||||||
$domain_ips = PhpHelper::gethostbynamel6($result['domain']);
|
$domain_ips = PhpHelper::gethostbynamel6($result['domain'], true, Settings::Get('system.le_domain_dnscheck_resolver'));
|
||||||
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
|
||||||
Response::standardError('invaliddnsforletsencrypt', '', true);
|
Response::standardError('invaliddnsforletsencrypt', '', true);
|
||||||
}
|
}
|
||||||
@@ -754,6 +775,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 = [
|
||||||
@@ -775,7 +800,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$allowed_phpconfigs = [];
|
$allowed_phpconfigs = [];
|
||||||
}
|
}
|
||||||
// only with fcgid/fpm enabled will it be possible to select a php-setting
|
// only with fcgid/fpm enabled will it be possible to select a php-setting
|
||||||
if ((int)Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1) {
|
if ((int)$result['phpenabled'] == 1 && ((int)Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1)) {
|
||||||
if (!in_array($phpsettingid, $allowed_phpconfigs)) {
|
if (!in_array($phpsettingid, $allowed_phpconfigs)) {
|
||||||
Response::standardError('notallowedphpconfigused', '', true);
|
Response::standardError('notallowedphpconfigused', '', true);
|
||||||
}
|
}
|
||||||
@@ -786,7 +811,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 +841,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 +860,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
|
||||||
];
|
];
|
||||||
@@ -856,7 +897,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
Cronjob::inserttask(TaskId::REBUILD_DNS);
|
Cronjob::inserttask(TaskId::REBUILD_DNS);
|
||||||
$idna_convert = new IdnaWrapper();
|
$idna_convert = new IdnaWrapper();
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'");
|
||||||
}
|
}
|
||||||
$result = $this->apiCall('SubDomains.get', [
|
$result = $this->apiCall('SubDomains.get', [
|
||||||
'id' => $id
|
'id' => $id
|
||||||
@@ -865,7 +906,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 +951,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 +968,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 +982,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 +997,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 +1081,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,21 +1091,19 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
$customer_ids = [
|
$customer_ids = [
|
||||||
$this->getUserDetail('customerid')
|
$this->getUserDetail('customerid')
|
||||||
];
|
];
|
||||||
$customer_stdsubs = [
|
|
||||||
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
// prepare select statement
|
if (!empty($customer_ids)) {
|
||||||
$domains_stmt = Database::prepare("
|
// prepare select statement
|
||||||
SELECT COUNT(*) as num_subdom
|
$domains_stmt = Database::prepare("
|
||||||
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
SELECT COUNT(*) as num_subdom
|
||||||
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
|
||||||
AND `d`.`email_only` = '0'
|
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
|
||||||
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")
|
AND `d`.`email_only` = '0'
|
||||||
");
|
");
|
||||||
$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);
|
||||||
}
|
}
|
||||||
@@ -1133,7 +1163,9 @@ class SubDomains extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger());
|
if ((int)$result['aliasdomain'] !== 0) {
|
||||||
|
Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger());
|
||||||
|
}
|
||||||
|
|
||||||
// delete domain from table
|
// delete domain from table
|
||||||
$stmt = Database::prepare("
|
$stmt = Database::prepare("
|
||||||
|
|||||||
@@ -90,9 +90,11 @@ class SysLog extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
Database::pexecute($result_stmt, $query_fields, true, true);
|
Database::pexecute($result_stmt, $query_fields, true, true);
|
||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
// clean log-text
|
||||||
|
$row['text'] = preg_replace("/[^\w @#\"':.()\[\]+\-_\/\\\!]/i", "_", $row['text']);
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list log-entries");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list log-entries");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ class Traffic extends ApiCommand implements ResourceEntity
|
|||||||
$row['mail'] *= 1024;
|
$row['mail'] *= 1024;
|
||||||
$result[] = $row;
|
$result[] = $row;
|
||||||
}
|
}
|
||||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list traffic");
|
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list traffic");
|
||||||
return $this->response([
|
return $this->response([
|
||||||
'count' => count($result),
|
'count' => count($result),
|
||||||
'list' => $result
|
'list' => $result
|
||||||
|
|||||||
@@ -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): 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.</>");
|
||||||
@@ -51,7 +50,7 @@ class CliCommand extends Command
|
|||||||
$output->writeln("<error>" . $e->getMessage() . "</>");
|
$output->writeln("<error>" . $e->getMessage() . "</>");
|
||||||
return self::INVALID;
|
return self::INVALID;
|
||||||
}
|
}
|
||||||
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
if (!$ignore_has_updates && (Froxlor::hasUpdates() || Froxlor::hasDbUpdates())) {
|
||||||
if ((int)Settings::Get('system.cron_allowautoupdate') == 1) {
|
if ((int)Settings::Get('system.cron_allowautoupdate') == 1) {
|
||||||
return $this->runUpdate($output);
|
return $this->runUpdate($output);
|
||||||
} else {
|
} else {
|
||||||
@@ -116,22 +115,24 @@ class CliCommand extends Command
|
|||||||
return $userinfo;
|
return $userinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function runUpdate(OutputInterface $output): int
|
protected function runUpdate(OutputInterface $output, bool $manual = false): int
|
||||||
{
|
{
|
||||||
$output->writeln('<comment>Automatic update is activated and we are going to proceed without any notices</>');
|
if (!$manual) {
|
||||||
|
$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([
|
||||||
'this',
|
$this,
|
||||||
'cleanUpdateOutput'
|
'cleanUpdateOutput'
|
||||||
]);
|
]);
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|||||||
181
lib/Froxlor/Cli/ConfigDiff.php
Normal file
181
lib/Froxlor/Cli/ConfigDiff.php
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
|
use Froxlor\Config\ConfigParser;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
final class ConfigDiff extends CliCommand
|
||||||
|
{
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this->setName('froxlor:config-diff')
|
||||||
|
->setDescription('Shows differences in config templates between OS versions')
|
||||||
|
->addArgument('from', InputArgument::OPTIONAL, 'OS version to compare against')
|
||||||
|
->addArgument('to', InputArgument::OPTIONAL, 'OS version to compare from')
|
||||||
|
->addOption('list', 'l', InputOption::VALUE_NONE, 'List all possible OS versions')
|
||||||
|
->addOption('diff-params', '', InputOption::VALUE_REQUIRED, 'Additional parameters for `diff`, e.g. --diff-params="--color=always"');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
require Froxlor::getInstallDir() . '/lib/functions.php';
|
||||||
|
|
||||||
|
$parsers = $versions = [];
|
||||||
|
foreach (glob(Froxlor::getInstallDir() . '/lib/configfiles/*.xml') as $config) {
|
||||||
|
$name = str_replace(".xml", "", strtolower(basename($config)));
|
||||||
|
$parser = new ConfigParser($config);
|
||||||
|
$versions[$name] = $parser->getCompleteDistroName();
|
||||||
|
$parsers[$name] = $parser;
|
||||||
|
}
|
||||||
|
asort($versions);
|
||||||
|
|
||||||
|
if ($input->getOption('list') === true) {
|
||||||
|
$output->writeln('The following OS version templates are available:');
|
||||||
|
foreach ($versions as $k => $v) {
|
||||||
|
$output->writeln(str_pad($k, 20) . $v);
|
||||||
|
}
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$input->hasArgument('from') || !array_key_exists($input->getArgument('from'), $versions)) {
|
||||||
|
$output->writeln('<error>Missing or invalid "from" argument.</error>');
|
||||||
|
$output->writeln('Available versions: ' . implode(', ', array_keys($versions)));
|
||||||
|
return self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$input->hasArgument('to') || !array_key_exists($input->getArgument('to'), $versions)) {
|
||||||
|
$output->writeln('<error>Missing or invalid "to" argument.</error>');
|
||||||
|
$output->writeln('Available versions: ' . implode(', ', array_keys($versions)));
|
||||||
|
return self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure diff is installed
|
||||||
|
$check_diff_installed = FileDir::safe_exec('which diff');
|
||||||
|
if (count($check_diff_installed) === 0) {
|
||||||
|
$output->writeln('<error>Unable to find "diff" installation on your system.</error>');
|
||||||
|
return self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parser_from = $parsers[$input->getArgument('from')];
|
||||||
|
$parser_to = $parsers[$input->getArgument('to')];
|
||||||
|
$tmp_from = tempnam(sys_get_temp_dir(), 'froxlor_config_diff_from');
|
||||||
|
$tmp_to = tempnam(sys_get_temp_dir(), 'froxlor_config_diff_to');
|
||||||
|
$files = [];
|
||||||
|
$titles_by_key = [];
|
||||||
|
|
||||||
|
// Aggregate content for each config file
|
||||||
|
foreach ([[$parser_from, 'from'], [$parser_to, 'to']] as $todo) {
|
||||||
|
foreach ($todo[0]->getServices() as $service_type => $service) {
|
||||||
|
foreach ($service->getDaemons() as $daemon_name => $daemon) {
|
||||||
|
foreach ($daemon->getConfig() as $instruction) {
|
||||||
|
if ($instruction['type'] !== 'file') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($instruction['subcommands'])) {
|
||||||
|
foreach ($instruction['subcommands'] as $subinstruction) {
|
||||||
|
if ($subinstruction['type'] !== 'file') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $subinstruction['content'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$content = $instruction['content'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($content)) {
|
||||||
|
throw new \Exception("Cannot find content for {$instruction['name']}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = "{$service_type}_{$daemon_name}_{$instruction['name']}";
|
||||||
|
$titles_by_key[$key] = "{$service->title} : {$daemon->title} : {$instruction['name']}";
|
||||||
|
if (!isset($files[$key])) {
|
||||||
|
$files[$key] = ['from' => '', 'to' => ''];
|
||||||
|
}
|
||||||
|
$files[$key][$todo[1]] = $this->filterContent($content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ksort($files);
|
||||||
|
|
||||||
|
$diff_params = '';
|
||||||
|
if ($input->hasOption('diff-params') && trim($input->getOption('diff-params')) !== '') {
|
||||||
|
$diff_params = trim($input->getOption('diff-params'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run diff on each file and output, if anything changed
|
||||||
|
foreach ($files as $file_key => $content) {
|
||||||
|
file_put_contents($tmp_from, $content['from']);
|
||||||
|
file_put_contents($tmp_to, $content['to']);
|
||||||
|
$diff_output = FileDir::safe_exec("{$check_diff_installed[0]} {$diff_params} {$tmp_from} {$tmp_to}");
|
||||||
|
|
||||||
|
if (count($diff_output) === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->writeln('<info># ' . $titles_by_key[$file_key] . '</info>');
|
||||||
|
$output->writeln(implode("\n", $diff_output) . "\n");
|
||||||
|
unset($diff_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove tmp files again
|
||||||
|
unlink($tmp_from);
|
||||||
|
unlink($tmp_to);
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function filterContent(string $content): string
|
||||||
|
{
|
||||||
|
$new_content = '';
|
||||||
|
|
||||||
|
foreach (explode("\n", $content) as $n) {
|
||||||
|
$n = trim($n);
|
||||||
|
if (!$n) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_starts_with($n, '#')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_content .= $n . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $new_content;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
@@ -80,7 +83,7 @@ final class InstallCommand extends Command
|
|||||||
$_SERVER['SERVER_NAME'] = $host[0] ?? '';
|
$_SERVER['SERVER_NAME'] = $host[0] ?? '';
|
||||||
$ips = [];
|
$ips = [];
|
||||||
exec('hostname -I', $ips);
|
exec('hostname -I', $ips);
|
||||||
$ips = explode(" ", $ips[0]);
|
$ips = explode(" ", $ips[0] ?? "");
|
||||||
// ipv4 address?
|
// ipv4 address?
|
||||||
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ($ips[0] ?? '') : '';
|
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ($ips[0] ?? '') : '';
|
||||||
if (empty($_SERVER['SERVER_ADDR'])) {
|
if (empty($_SERVER['SERVER_ADDR'])) {
|
||||||
@@ -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) {
|
||||||
@@ -246,7 +251,10 @@ final class InstallCommand extends Command
|
|||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->io->error($e->getMessage());
|
$this->io->error($e->getMessage());
|
||||||
return $this->showStep($step, $extended, $decoded_input);
|
if ($this->io->confirm('Retry?', empty($decoded_input))) {
|
||||||
|
return $this->showStep($step, $extended, $decoded_input);
|
||||||
|
}
|
||||||
|
return self::FAILURE;
|
||||||
}
|
}
|
||||||
if ($step == 3) {
|
if ($step == 3) {
|
||||||
// do actual install with data from $this->formfielddata
|
// do actual install with data from $this->formfielddata
|
||||||
@@ -259,14 +267,16 @@ 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 (!empty($decoded_input) || $this->io->confirm('Execute command now?', false)) {
|
if (!isset($decoded_input['manual_config']) || (bool)$decoded_input['manual_config'] === false) {
|
||||||
passthru($cmdfield['value']);
|
if (!empty($decoded_input) || $this->io->confirm('Execute command now?', false)) {
|
||||||
|
passthru($cmdfield['value']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -297,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') {
|
if ($name == 'system' || $name == 'target_servername') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($field['type'] == 'text' || $field['type'] == 'email') {
|
if ($field['type'] == 'text' || $field['type'] == 'email') {
|
||||||
@@ -310,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 = "?";
|
||||||
@@ -338,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,26 +53,34 @@ 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) {
|
||||||
|
// requirements failed, exit
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
$jobs = $input->getArgument('job');
|
$jobs = $input->getArgument('job');
|
||||||
|
|
||||||
// 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
|
||||||
@@ -86,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 . '"</>');
|
||||||
}
|
}
|
||||||
@@ -111,8 +120,8 @@ final class MasterCron extends CliCommand
|
|||||||
]);
|
]);
|
||||||
$this->cronLog->setCronDebugFlag(defined('CRON_DEBUG_FLAG'));
|
$this->cronLog->setCronDebugFlag(defined('CRON_DEBUG_FLAG'));
|
||||||
|
|
||||||
// check whether there are actual tasks to perform by 'tasks'-cron so
|
// check whether there are actual tasks to perform by 'tasks'-cron, so
|
||||||
// we dont regenerate files unnecessarily
|
// we don't regenerate files unnecessarily
|
||||||
$tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`");
|
$tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`");
|
||||||
$tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC);
|
$tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
@@ -134,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
|
||||||
@@ -151,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
|
||||||
@@ -211,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
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -238,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;
|
||||||
@@ -259,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]);
|
||||||
}
|
}
|
||||||
@@ -81,7 +110,7 @@ final class UpdateCommand extends CliCommand
|
|||||||
$newversionavail = true;
|
$newversionavail = true;
|
||||||
$output->writeln('<comment>' . $text . '</>');
|
$output->writeln('<comment>' . $text . '</>');
|
||||||
$result = self::SUCCESS;
|
$result = self::SUCCESS;
|
||||||
} else if ($aucheck < 0 || $aucheck > 1) {
|
} elseif ($aucheck < 0 || $aucheck > 1) {
|
||||||
if ($input->getOption('integer-return')) {
|
if ($input->getOption('integer-return')) {
|
||||||
$output->write(-1);
|
$output->write(-1);
|
||||||
return self::INVALID;
|
return self::INVALID;
|
||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
164
lib/Froxlor/Cli/ValidateAcmeWebroot.php
Normal file
164
lib/Froxlor/Cli/ValidateAcmeWebroot.php
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Froxlor project.
|
||||||
|
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you can also view it online at
|
||||||
|
* https://files.froxlor.org/misc/COPYING.txt
|
||||||
|
*
|
||||||
|
* @copyright the authors
|
||||||
|
* @author Froxlor team <team@froxlor.org>
|
||||||
|
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Froxlor\Cli;
|
||||||
|
|
||||||
|
use Froxlor\Cron\TaskId;
|
||||||
|
use Froxlor\Database\Database;
|
||||||
|
use Froxlor\FileDir;
|
||||||
|
use Froxlor\Froxlor;
|
||||||
|
use Froxlor\Settings;
|
||||||
|
use Froxlor\System\Cronjob;
|
||||||
|
use PDO;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
final class ValidateAcmeWebroot extends CliCommand
|
||||||
|
{
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('froxlor:validate-acme-webroot');
|
||||||
|
$this->setDescription('Validates the Le_Webroot value is correct for froxlor managed domains with Let\'s Encrypt certificate.');
|
||||||
|
$this->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for confirmation, update files if necessary');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$result = $this->validateRequirements($output, true);
|
||||||
|
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
|
||||||
|
if ((int)Settings::Get('system.leenabled') == 0) {
|
||||||
|
$io->info("Let's Encrypt not activated in froxlor settings.");
|
||||||
|
$result = self::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result == self::SUCCESS) {
|
||||||
|
$yestoall = $input->getOption('yes-to-all') !== false;
|
||||||
|
$helper = $this->getHelper('question');
|
||||||
|
$count_changes = 0;
|
||||||
|
// get all Let's Encrypt enabled domains
|
||||||
|
$sel_stmt = Database::prepare("SELECT id, domain FROM panel_domains WHERE `letsencrypt` = '1' AND aliasdomain IS NULL ORDER BY id ASC");
|
||||||
|
Database::pexecute($sel_stmt);
|
||||||
|
$domains = $sel_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
// check for froxlor-vhost
|
||||||
|
if (Settings::Get('system.le_froxlor_enabled') == '1') {
|
||||||
|
$domains[] = [
|
||||||
|
'id' => 0,
|
||||||
|
'domain' => Settings::Get('system.hostname')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$upd_stmt = Database::prepare("UPDATE domain_ssl_settings SET `validtodate`=NULL WHERE `domainid` = :did");
|
||||||
|
$acmesh_dir = dirname(Settings::Get('system.acmeshpath'));
|
||||||
|
$acmesh_challenge_dir = rtrim(FileDir::makeCorrectDir(Settings::Get('system.letsencryptchallengepath')), "/");
|
||||||
|
$recommended = rtrim(FileDir::makeCorrectDir(Froxlor::getInstallDir()), "/");
|
||||||
|
|
||||||
|
if ($acmesh_challenge_dir != $recommended) {
|
||||||
|
$io->warning([
|
||||||
|
"ACME challenge docroot from settings differs from the current installation directory.",
|
||||||
|
"Settings: '" . $acmesh_challenge_dir . "'",
|
||||||
|
"Default/recommended value: '" . $recommended . "'",
|
||||||
|
]);
|
||||||
|
$question = new ConfirmationQuestion('Fix ACME challenge docroot setting? [yes] ', true, '/^(y|j)/i');
|
||||||
|
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||||
|
Settings::Set('system.letsencryptchallengepath', $recommended);
|
||||||
|
$former_value = $acmesh_challenge_dir;
|
||||||
|
$acmesh_challenge_dir = $recommended;
|
||||||
|
// need to update the corresponding acme-alias config-file
|
||||||
|
$acme_alias_file = Settings::Get('system.letsencryptacmeconf');
|
||||||
|
$sed_params = "s@" . $former_value . "@" . $acmesh_challenge_dir . "@";
|
||||||
|
FileDir::safe_exec('sed -i -e "' . $sed_params . '" ' . escapeshellarg($acme_alias_file));
|
||||||
|
$count_changes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($domains as $domain_arr) {
|
||||||
|
$domain = $domain_arr['domain'];
|
||||||
|
$acme_domain_conf = FileDir::makeCorrectFile($acmesh_dir . '/' . $domain . '/' . $domain . '.conf');
|
||||||
|
if (file_exists($acme_domain_conf)) {
|
||||||
|
$io->text("Getting info from " . $acme_domain_conf);
|
||||||
|
$conf_content = file_get_contents($acme_domain_conf);
|
||||||
|
} else {
|
||||||
|
$acme_domain_conf = FileDir::makeCorrectFile($acmesh_dir . '/' . $domain . '_ecc/' . $domain . '.conf');
|
||||||
|
if (file_exists($acme_domain_conf)) {
|
||||||
|
$io->text("Getting info from " . $acme_domain_conf);
|
||||||
|
$conf_content = file_get_contents($acme_domain_conf);
|
||||||
|
} else {
|
||||||
|
$io->info("No domain configuration file found in '" . $acmesh_dir . "'");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($conf_content)) {
|
||||||
|
$lines = explode("\n", $conf_content);
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
$val_key = explode("=", $line);
|
||||||
|
if ($val_key[0] == 'Le_Webroot') {
|
||||||
|
$domain_webroot = trim(trim($val_key[1], "'"), '"');
|
||||||
|
if ($domain_webroot != $acmesh_challenge_dir) {
|
||||||
|
$io->warning("Domain '" . $domain . "' has old/wrong Le_Webroot setting: '" . $domain_webroot . ' <> ' . $acmesh_challenge_dir . "'");
|
||||||
|
$question = new ConfirmationQuestion('Fix Le_Webroot? [yes] ', true, '/^(y|j)/i');
|
||||||
|
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||||
|
$sed_params = "s@Le_Webroot=.*@Le_Webroot='" . $acmesh_challenge_dir . "'@";
|
||||||
|
FileDir::safe_exec('sed -i -e "' . $sed_params . '" ' . escapeshellarg($acme_domain_conf));
|
||||||
|
Database::pexecute($upd_stmt, ['did' => $domain_arr['id']]);
|
||||||
|
$io->success("Correction of Le_Webroot successful");
|
||||||
|
$count_changes++;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$io->info("Domain '" . $domain . "' Le_Webroot value is correct");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($count_changes > 0) {
|
||||||
|
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
||||||
|
$io->info("Changes detected but froxlor has been updated. Inserting task to rebuild vhosts after update.");
|
||||||
|
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||||
|
} else {
|
||||||
|
$question = new ConfirmationQuestion('Changes detected. Force cronjob to refresh certificates? [yes] ', true, '/^(y|j)/i');
|
||||||
|
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||||
|
passthru(FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -f -d');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$io->success("No changes necessary.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 = "";
|
||||||
@@ -148,7 +151,7 @@ class ConfigDisplay
|
|||||||
if ($lasttype != '' && $lasttype != $_action['type']) {
|
if ($lasttype != '' && $lasttype != $_action['type']) {
|
||||||
$commands = trim($commands);
|
$commands = trim($commands);
|
||||||
$numbrows = count(explode("\n", $commands));
|
$numbrows = count(explode("\n", $commands));
|
||||||
$configpage .= UI::twig()->render(self::$theme . '/settings/conf/command.html.twig', [
|
$configpage .= UI::twig()->render(UI::validateThemeTemplate('/settings/conf/command.html.twig', self::$theme), [
|
||||||
'commands' => $commands,
|
'commands' => $commands,
|
||||||
'numbrows' => $numbrows
|
'numbrows' => $numbrows
|
||||||
]);
|
]);
|
||||||
@@ -182,7 +185,7 @@ class ConfigDisplay
|
|||||||
$commands = trim($commands_pre);
|
$commands = trim($commands_pre);
|
||||||
if ($commands != "") {
|
if ($commands != "") {
|
||||||
$numbrows = count(explode("\n", $commands));
|
$numbrows = count(explode("\n", $commands));
|
||||||
$commands_pre = UI::twig()->render(self::$theme . '/settings/conf/command.html.twig', [
|
$commands_pre = UI::twig()->render(UI::validateThemeTemplate('/settings/conf/command.html.twig', self::$theme), [
|
||||||
'commands' => $commands,
|
'commands' => $commands,
|
||||||
'numbrows' => $numbrows
|
'numbrows' => $numbrows
|
||||||
]);
|
]);
|
||||||
@@ -190,12 +193,12 @@ class ConfigDisplay
|
|||||||
$commands = trim($commands_post);
|
$commands = trim($commands_post);
|
||||||
if ($commands != "") {
|
if ($commands != "") {
|
||||||
$numbrows = count(explode("\n", $commands));
|
$numbrows = count(explode("\n", $commands));
|
||||||
$commands_post = UI::twig()->render(self::$theme . '/settings/conf/command.html.twig', [
|
$commands_post = UI::twig()->render(UI::validateThemeTemplate('/settings/conf/command.html.twig', self::$theme), [
|
||||||
'commands' => $commands,
|
'commands' => $commands,
|
||||||
'numbrows' => $numbrows
|
'numbrows' => $numbrows
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$configpage .= UI::twig()->render(self::$theme . '/settings/conf/fileblock.html.twig', [
|
$configpage .= UI::twig()->render(UI::validateThemeTemplate('/settings/conf/fileblock.html.twig', self::$theme), [
|
||||||
'realname' => $realname,
|
'realname' => $realname,
|
||||||
'commands_pre' => $commands_pre,
|
'commands_pre' => $commands_pre,
|
||||||
'commands_file' => $commands_file,
|
'commands_file' => $commands_file,
|
||||||
@@ -210,7 +213,7 @@ class ConfigDisplay
|
|||||||
$commands = trim($commands);
|
$commands = trim($commands);
|
||||||
if ($commands != '') {
|
if ($commands != '') {
|
||||||
$numbrows = count(explode("\n", $commands));
|
$numbrows = count(explode("\n", $commands));
|
||||||
$configpage .= UI::twig()->render(self::$theme . '/settings/conf/command.html.twig', [
|
$configpage .= UI::twig()->render(UI::validateThemeTemplate('/settings/conf/command.html.twig', self::$theme), [
|
||||||
'commands' => $commands,
|
'commands' => $commands,
|
||||||
'numbrows' => $numbrows
|
'numbrows' => $numbrows
|
||||||
]);
|
]);
|
||||||
@@ -233,7 +236,7 @@ class ConfigDisplay
|
|||||||
$file_content = htmlspecialchars($file_content);
|
$file_content = htmlspecialchars($file_content);
|
||||||
$numbrows = count(explode("\n", $file_content));
|
$numbrows = count(explode("\n", $file_content));
|
||||||
//eval("\$files=\"" . \Froxlor\UI\Template::getTemplate("configfiles/configfiles_file") . "\";");
|
//eval("\$files=\"" . \Froxlor\UI\Template::getTemplate("configfiles/configfiles_file") . "\";");
|
||||||
$files = UI::twig()->render(self::$theme . '/settings/conf/file.html.twig', [
|
$files = UI::twig()->render(UI::validateThemeTemplate('/settings/conf/file.html.twig', self::$theme), [
|
||||||
'distro_editor' => self::$editor,
|
'distro_editor' => self::$editor,
|
||||||
'realname' => $realname,
|
'realname' => $realname,
|
||||||
'numbrows' => $numbrows,
|
'numbrows' => $numbrows,
|
||||||
|
|||||||
@@ -55,18 +55,17 @@ class Bind extends DnsBase
|
|||||||
$domains = $this->getDomainList();
|
$domains = $this->getDomainList();
|
||||||
|
|
||||||
if (empty($domains)) {
|
if (empty($domains)) {
|
||||||
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'No domains found for nameserver-config, skipping...');
|
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'No domains found for nameserver-config, not creating any zones...');
|
||||||
return;
|
$this->bindconf_file = '';
|
||||||
}
|
} else {
|
||||||
|
$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) {
|
||||||
|
if ($domain['is_child']) {
|
||||||
foreach ($domains as $domain) {
|
// domains that are subdomains to other main domains are handled by recursion within walkDomainList()
|
||||||
if ($domain['ismainbutsubto'] > 0) {
|
continue;
|
||||||
// domains with ismainbutsubto>0 are handled by recursion within walkDomainList()
|
}
|
||||||
continue;
|
$this->walkDomainList($domain, $domains);
|
||||||
}
|
}
|
||||||
$this->walkDomainList($domain, $domains);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$bindconf_file_handler = fopen(FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/froxlor_bind.conf'), 'w');
|
$bindconf_file_handler = fopen(FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/froxlor_bind.conf'), 'w');
|
||||||
@@ -114,7 +113,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user