Compare commits

..

25 Commits

Author SHA1 Message Date
d7a3568506 reject policy dmarc 2025-09-29 19:06:10 +02:00
10c13bc5b1 not generating disabled zones 2025-09-26 13:01:26 +02:00
dcb3f6f568 DKIM stuff with our own selector 2025-09-25 11:16:48 +02:00
7566def0d1 TODO: This is a dkim hack 2025-09-25 09:40:40 +02:00
3630f82817 greylisting 2.0 2025-09-24 16:45:43 +02:00
9ddd2e9154 styles 2025-09-03 12:10:46 +02:00
53afe4ebd1 new files
Some checks failed
continuous-integration/drone/push Build is failing
2024-01-30 17:12:26 +01:00
4f69e8ee0e new css 2024-01-30 17:12:16 +01:00
32f5b0d5e9 new Theme
Some checks failed
continuous-integration/drone/push Build is failing
2024-01-30 16:52:34 +01:00
53a6485a6e Maketank Theme migration
Some checks failed
continuous-integration/drone/push Build is failing
2024-01-30 13:52:59 +01:00
f2643ac887 env test 3
Some checks failed
continuous-integration/drone/push Build is failing
2023-12-13 12:46:20 +01:00
e37687a85d env test 3
Some checks failed
continuous-integration/drone/push Build is failing
2023-12-13 12:44:29 +01:00
ccbc3286a5 env test 2
Some checks failed
continuous-integration/drone/push Build is failing
2023-12-13 12:39:58 +01:00
929a562324 env test 2
Some checks failed
continuous-integration/drone/push Build is failing
2023-12-13 12:36:50 +01:00
3704cf6621 env test 2
Some checks failed
continuous-integration/drone/push Build is failing
2023-12-13 12:35:09 +01:00
10238a1466 env test
All checks were successful
continuous-integration/drone/push Build is passing
2023-12-12 14:04:03 +01:00
9002ddf4a2 env test
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2023-12-12 14:03:10 +01:00
8a2de5a44a env test
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2023-12-12 13:59:34 +01:00
96c0af18dd npm and compose
Some checks failed
continuous-integration/drone/push Build is failing
2023-12-12 13:50:23 +01:00
5bb228ce78 npm and compose
Some checks failed
continuous-integration/drone/push Build is failing
2023-12-12 13:48:08 +01:00
804128280c npm and compose 2023-12-12 13:47:32 +01:00
5b8e918f75 ssh test
All checks were successful
continuous-integration/drone/push Build is passing
2023-12-12 13:45:23 +01:00
0e3e83d184 ssh test
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-12-12 10:51:21 +01:00
8ced61c6aa bogus edit for pipeline trigger
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-12-11 15:31:39 +01:00
29a2ab7567 2.0 upgrade test first
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-12-07 12:39:20 +01:00
462 changed files with 28404 additions and 12517 deletions

53
.drone.yml Normal file
View File

@@ -0,0 +1,53 @@
kind: pipeline
name: deploy-froxlor
type: docker
platform:
os: linux
arch: arm64
trigger:
branch:
- upgrade-2.0
event:
include:
- push
environment:
DEPLOY_HOST: rechner.maketank.net
DEPLOY_DIR: ~/froxlor-test
steps:
- name: deploy
image: cr.wks/drone/drone-rsync:latest
settings:
hosts: ["rechner02.maketank.net"]
source: ./
target: ~/froxlor-test
user: www-data
exclude: ['vendor', '.git*', '*drone.yml', '.settings', '.buildpath', '.editorconfig', '.project', '.travis.yml', 'node_modules']
args: '-v --delete'
log_level: quiet
key:
from_secret: ssh-www-data-maketank-rsa
command_timeout: 10m
- name: compose
image: appleboy/drone-ssh
settings:
host:
- rechner02.maketank.net
username: www-data
key:
from_secret: ssh-www-data-maketank-rsa
script:
- cd ~/froxlor-test && composer install --no-dev
- name: npm
image: appleboy/drone-ssh
settings:
host:
- rechner02.maketank.net
username: www-data
key:
from_secret: ssh-www-data-maketank-rsa
script:
- cd ~/froxlor-test && npm install && npm run build

View File

@@ -2,8 +2,7 @@ name: build-documentation
on: on:
release: release:
# only run for stable releases types: [published]
types: [released]
jobs: jobs:
build_docs: build_docs:
@@ -12,4 +11,4 @@ jobs:
- env: - env:
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
run: | run: |
gh workflow run --repo Froxlor/Documentation build-and-deploy.yml -f type=tags -f ref=${{github.ref_name}} gh workflow run --repo Froxlor/Documentation build-and-deploy.yml -f type=tags ref=${{github.ref_name}}

View File

@@ -8,18 +8,18 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
php-versions: [ '7.4', '8.2' ] php-versions: ['7.4', '8.1']
mariadb-version: [ 10.11, 10.5 ] mariadb-version: [10.5, 10.4]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Setup PHP, with composer and extensions - name: Setup PHP, with composer and extensions
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@v2
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, gnupg extensions: mbstring, xml, ctype, pdo_mysql, mysql, curl, json, zip, session, filter, posix, openssl, fileinfo, bcmath, gmp
- name: Install tools - name: Install tools
run: sudo apt-get install -y ant run: sudo apt-get install -y ant
@@ -49,81 +49,33 @@ jobs:
- name: Run testing - name: Run testing
run: ant quick-build run: ant quick-build
nightly: # - name: irc push
name: Create nightly/testing tarball # uses: rectalogic/notify-irc@v1
runs-on: ubuntu-latest # if: github.event_name == 'push'
needs: froxlor # with:
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} # channel: "#froxlor"
# server: "irc.libera.chat"
# nickname: froxlor-ci
# message: |
# ${{ github.actor }} pushed ${{ github.event.ref }} ${{ github.event.compare }}
# ${{ join(github.event.commits.*.message) }}
steps: # - name: irc pull request
- name: Checkout # uses: rectalogic/notify-irc@v1
uses: actions/checkout@v4 # if: github.event_name == 'pull_request'
# with:
# channel: "#froxlor"
# server: "irc.libera.chat"
# nickname: froxlor-ci
# message: |
# ${{ github.actor }} opened PR ${{ github.event.pull_request.html_url }}
- name: Setup PHP with PECL extension # - name: irc tag created
uses: shivammathur/setup-php@v2 # uses: rectalogic/notify-irc@v1
with: # if: github.event_name == 'create' && github.event.ref_type == 'tag'
php-version: '7.4' # with:
tools: composer:v2 # channel: "#froxlor"
extensions: mbstring, xml, ctype, pdo_mysql, mysql, curl, json, zip, session, filter, posix, openssl, fileinfo, bcmath, gmp, gnupg # server: "irc.libera.chat"
# nickname: froxlor-ci
- name: Install composer dependencies # message: |
run: composer install --no-dev # ${{ github.actor }} tagged ${{ github.repository }} ${{ github.event.ref }}
- name: Install Node.js
uses: actions/setup-node@v4
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@main
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 }}"

View File

@@ -8,18 +8,18 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
php-versions: ['7.4', '8.2'] php-versions: ['7.4', '8.1']
mysql-version: [8.0, 5.7] mysql-version: [8.0, 5.7]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Setup PHP, with composer and extensions - name: Setup PHP, with composer and extensions
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@v2
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, gnupg extensions: mbstring, xml, ctype, pdo_mysql, mysql, curl, json, zip, session, filter, posix, openssl, fileinfo, bcmath, gmp
- name: Install tools - name: Install tools
run: sudo apt-get install -y ant run: sudo apt-get install -y ant
@@ -39,7 +39,16 @@ jobs:
- name: Wait for database - name: Wait for database
run: sleep 15 run: sleep 15
- name: Setup database - name: Setup database (8.0)
if: matrix.mysql-version == '8.0'
run: |
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "CREATE USER 'froxlor010'@'%' IDENTIFIED WITH mysql_native_password BY 'fr0xl0r.TravisCI';"
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "GRANT ALL ON froxlor010.* TO 'froxlor010'@'%';"
php -r "echo include('install/froxlor.sql.php');" > /tmp/froxlor.sql
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI froxlor010 < /tmp/froxlor.sql
- name: Setup database (5.7)
if: matrix.mysql-version == '5.7'
run: | run: |
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "CREATE USER 'froxlor010'@'%' IDENTIFIED BY 'fr0xl0r.TravisCI';" mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "CREATE USER 'froxlor010'@'%' IDENTIFIED BY 'fr0xl0r.TravisCI';"
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "GRANT ALL ON froxlor010.* TO 'froxlor010'@'%';" mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "GRANT ALL ON froxlor010.* TO 'froxlor010'@'%';"

7
.gitignore vendored
View File

@@ -13,14 +13,15 @@ logs/*
*~ *~
.well-known .well-known
.idea .idea
.DS_Store
*.iml *.iml
img/ img/
vendor/ vendor/
node_modules/ node_modules/
fonts/ fonts/
templates/*
!templates/index.html !templates/index.html
!templates/Froxlor/ !templates/Froxlor/
templates/Froxlor/build/ templates/Froxlor/assets/mix-manifest.json
templates/Froxlor/assets/css/
templates/Froxlor/assets/js/
templates/Froxlor/assets/webfonts/
!templates/misc/ !templates/misc/

View File

@@ -33,7 +33,6 @@ use Froxlor\FroxlorLogger;
use Froxlor\FroxlorTwoFactorAuth; use Froxlor\FroxlorTwoFactorAuth;
use Froxlor\Settings; use Froxlor\Settings;
use Froxlor\UI\Panel\UI; use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request;
use Froxlor\UI\Response; use Froxlor\UI\Response;
use Froxlor\PhpHelper; use Froxlor\PhpHelper;
use Froxlor\User; use Froxlor\User;
@@ -64,7 +63,7 @@ if ($action == 'delete') {
]); ]);
Response::standardSuccess('2fa.2fa_removed'); Response::standardSuccess('2fa.2fa_removed');
} elseif ($action == 'preadd') { } elseif ($action == 'preadd') {
$type = Request::post('type_2fa', '0'); $type = isset($_POST['type_2fa']) ? $_POST['type_2fa'] : '0';
$data = ""; $data = "";
if ($type > 0) { if ($type > 0) {
@@ -108,9 +107,9 @@ if ($action == 'delete') {
Response::dynamicError('Select one of the possible values for 2FA'); Response::dynamicError('Select one of the possible values for 2FA');
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
$type = Request::post('type_2fa', '0'); $type = isset($_POST['type_2fa']) ? $_POST['type_2fa'] : '0';
$data = Request::post('data_2fa', ''); $data = isset($_POST['data_2fa']) ? $_POST['data_2fa'] : '';
$code = Request::post('codevalidation', ''); $code = isset($_POST['codevalidation']) ? $_POST['codevalidation'] : '';
// validate // validate
$result = $tfa->verifyCode($data, $code, 3); $result = $tfa->verifyCode($data, $code, 3);

View File

@@ -34,13 +34,19 @@ 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/
### Documentation ### Wiki
The documentation may be found at https://docs.froxlor.org/ More documentation may be found in the froxlor - documentation:
https://docs.froxlor.org/
## License ## License
@@ -58,17 +64,17 @@ https://files.froxlor.org/releases/froxlor-latest.tar.gz [MD5](https://files.fro
#### Debian #### Debian
``` ```
apt -y install apt-transport-https lsb-release ca-certificates curl gnupg apt-get -y install apt-transport-https lsb-release ca-certificates curl
curl -sSLo /usr/share/keyrings/deb.froxlor.org-froxlor.gpg https://deb.froxlor.org/froxlor.gpg curl -sSLo /usr/share/keyrings/deb.froxlor.org-froxlor.gpg https://deb.froxlor.org/froxlor.gpg
sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.froxlor.org-froxlor.gpg] https://deb.froxlor.org/debian $(lsb_release -sc) main" > /etc/apt/sources.list.d/froxlor.list' echo sh -c '"deb [signed-by=/usr/share/keyrings/deb.froxlor.org-froxlor.gpg] https://deb.froxlor.org/debian $(lsb_release -sc) main" > /etc/apt/sources.list.d/froxlor.list'
``` ```
#### Ubuntu #### Ubuntu
``` ```
apt -y install apt-transport-https lsb-release ca-certificates curl gnupg apt-get -y install apt-transport-https lsb-release ca-certificates curl
curl -sSLo /usr/share/keyrings/deb.froxlor.org-froxlor.gpg https://deb.froxlor.org/froxlor.gpg curl -sSLo /usr/share/keyrings/deb.froxlor.org-froxlor.gpg https://deb.froxlor.org/froxlor.gpg
sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.froxlor.org-froxlor.gpg] https://deb.froxlor.org/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/froxlor.list' echo sh -c '"deb [signed-by=/usr/share/keyrings/deb.froxlor.org-froxlor.gpg] https://deb.froxlor.org/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/froxlor.list'
``` ```
## Contributing ## Contributing

View File

@@ -10,11 +10,9 @@ With that, good luck hacking us ;)
## Supported versions ## Supported versions
- ️✅ **2.2.x** (`main` git-branch) - ️✅ **2.x** (`main` git-branch)
- ️✅ **2.1.x** (`v2.1` git-branch) - ❌ 0.10.x (`0.10.x` git-branch)
-2.0.x (`2.0.x`-tags) -0.9.x (`0.9.x`git-branch)
- ❌ 0.10.x (`0.10.x`-tags)
- ❌ other git-branches
## Qualifying Vulnerabilities ## Qualifying Vulnerabilities
@@ -28,7 +26,7 @@ With that, good luck hacking us ;)
### Vulnerabilities we accept ### Vulnerabilities we accept
Only reproducible issues on a default/clean setup from the latest stable release of a supported version will be accepted. Only reproducable issues on a default/clean setup from the latest stable release of a supported version will be accepted.
## Non-Qualifying Vulnerabilities ## Non-Qualifying Vulnerabilities
@@ -36,8 +34,6 @@ Only reproducible 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
@@ -48,4 +44,4 @@ Only reproducible 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://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). 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).

View File

@@ -265,7 +265,7 @@ return [
'extras.directoryprotection' => lng('menue.extras.extras') . " / " . lng('menue.extras.directoryprotection'), 'extras.directoryprotection' => lng('menue.extras.extras') . " / " . lng('menue.extras.directoryprotection'),
'extras.pathoptions' => lng('menue.extras.extras') . " / " . lng('menue.extras.pathoptions'), 'extras.pathoptions' => lng('menue.extras.extras') . " / " . lng('menue.extras.pathoptions'),
'extras.logger' => lng('menue.extras.extras') . " / " . lng('menue.logger.logger'), 'extras.logger' => lng('menue.extras.extras') . " / " . lng('menue.logger.logger'),
'extras.export' => lng('menue.extras.extras') . " / " . lng('menue.extras.export'), 'extras.backup' => lng('menue.extras.extras') . " / " . lng('menue.extras.backup'),
'traffic' => lng('menue.traffic.traffic'), 'traffic' => lng('menue.traffic.traffic'),
'traffic.http' => lng('menue.traffic.traffic') . " / HTTP", 'traffic.http' => lng('menue.traffic.traffic') . " / HTTP",
'traffic.ftp' => lng('menue.traffic.traffic') . " / FTP", 'traffic.ftp' => lng('menue.traffic.traffic') . " / FTP",
@@ -337,15 +337,7 @@ 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',
],
] ]
] ]
] ]

View File

@@ -35,7 +35,6 @@ 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'
], ],
@@ -231,13 +230,13 @@ return [
'onlyif' => 1 'onlyif' => 1
] ]
], ],
'system_exportenabled' => [ 'system_backupenabled' => [
'label' => lng('serversettings.exportenabled'), 'label' => lng('serversettings.backupenabled'),
'settinggroup' => 'system', 'settinggroup' => 'system',
'varname' => 'exportenabled', 'varname' => 'backupenabled',
'type' => 'checkbox', 'type' => 'checkbox',
'default' => false, 'default' => false,
'cronmodule' => 'froxlor/export', 'cronmodule' => 'froxlor/backup',
'save_method' => 'storeSettingField' 'save_method' => 'storeSettingField'
], ],
'system_createstdsubdom_default' => [ 'system_createstdsubdom_default' => [

View File

@@ -107,8 +107,7 @@ return [
'varname' => 'enabled', 'varname' => 'enabled',
'type' => 'checkbox', 'type' => 'checkbox',
'default' => false, 'default' => false,
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField'
'required_otp' => true
], ],
'api_customer_default' => [ 'api_customer_default' => [
'label' => lng('serversettings.api_customer_default'), 'label' => lng('serversettings.api_customer_default'),
@@ -130,8 +129,7 @@ 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
@@ -172,6 +170,16 @@ 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',
@@ -180,6 +188,18 @@ return [
'default' => true, 'default' => true,
'save_method' => 'storeSettingField' 'save_method' => 'storeSettingField'
], ],
'system_httpuser' => [
'settinggroup' => 'system',
'varname' => 'httpuser',
'type' => 'hidden',
'default' => 'www-data'
],
'system_httpgroup' => [
'settinggroup' => 'system',
'varname' => 'httpgroup',
'type' => 'hidden',
'default' => 'www-data'
],
'system_report_enable' => [ 'system_report_enable' => [
'label' => lng('serversettings.report.report'), 'label' => lng('serversettings.report.report'),
'settinggroup' => 'system', 'settinggroup' => 'system',

View File

@@ -176,7 +176,6 @@ return [
'varname' => 'mod_fcgid_httpuser', 'varname' => 'mod_fcgid_httpuser',
'type' => 'text', 'type' => 'text',
'default' => 'froxlorlocal', 'default' => 'froxlorlocal',
'string_emptyallowed' => false,
'save_method' => 'storeSettingWebserverFcgidFpmUser', 'save_method' => 'storeSettingWebserverFcgidFpmUser',
'websrv_avail' => [ 'websrv_avail' => [
'apache2' 'apache2'
@@ -194,7 +193,6 @@ return [
'type' => 'text', 'type' => 'text',
'default' => 'froxlorlocal', 'default' => 'froxlorlocal',
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField',
'string_emptyallowed' => false,
'websrv_avail' => [ 'websrv_avail' => [
'apache2' 'apache2'
], ],
@@ -245,7 +243,6 @@ return [
'varname' => 'vhost_httpuser', 'varname' => 'vhost_httpuser',
'type' => 'text', 'type' => 'text',
'default' => 'froxlorlocal', 'default' => 'froxlorlocal',
'string_emptyallowed' => false,
'save_method' => 'storeSettingWebserverFcgidFpmUser', 'save_method' => 'storeSettingWebserverFcgidFpmUser',
'visible' => Settings::Get('phpfpm.enabled') && call_user_func([ 'visible' => Settings::Get('phpfpm.enabled') && call_user_func([
'\Froxlor\Settings\FroxlorVhostSettings', '\Froxlor\Settings\FroxlorVhostSettings',
@@ -259,7 +256,6 @@ return [
'varname' => 'vhost_httpgroup', 'varname' => 'vhost_httpgroup',
'type' => 'text', 'type' => 'text',
'default' => 'froxlorlocal', 'default' => 'froxlorlocal',
'string_emptyallowed' => false,
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField',
'visible' => Settings::Get('phpfpm.enabled') && call_user_func([ 'visible' => Settings::Get('phpfpm.enabled') && call_user_func([
'\Froxlor\Settings\FroxlorVhostSettings', '\Froxlor\Settings\FroxlorVhostSettings',

View File

@@ -46,8 +46,7 @@ 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'),
@@ -56,8 +55,7 @@ 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'),
@@ -65,8 +63,7 @@ return [
'varname' => 'cron_allowautoupdate', 'varname' => 'cron_allowautoupdate',
'type' => 'checkbox', 'type' => 'checkbox',
'default' => false, 'default' => false,
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField'
'required_otp' => true
] ]
] ]
] ]

View File

@@ -181,8 +181,7 @@ return [
'label' => lng('serversettings.logfiles_format'), 'label' => lng('serversettings.logfiles_format'),
'settinggroup' => 'system', 'settinggroup' => 'system',
'varname' => 'logfiles_format', 'varname' => 'logfiles_format',
'type' => (strpos(Settings::Get('system.logfiles_format'), '"') !== false ? 'textarea' : 'text'), 'type' => 'text',
'string_regexp' => '/^[^\0\r\n<>]*$/i',
'default' => '', 'default' => '',
'string_emptyallowed' => true, 'string_emptyallowed' => true,
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField',
@@ -308,8 +307,7 @@ 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'),
@@ -321,8 +319,7 @@ 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'),

View File

@@ -157,8 +157,7 @@ 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'),
@@ -248,40 +247,11 @@ return [
'settinggroup' => 'system', 'settinggroup' => 'system',
'varname' => 'le_domain_dnscheck_resolver', 'varname' => 'le_domain_dnscheck_resolver',
'type' => 'text', 'type' => 'text',
'string_type' => 'validate_ip', 'string_regexp' => '/^(([0-9]+ [a-z0-9\-\._]+, ?)*[0-9]+ [a-z0-9\-\._]+)?$/i',
'string_emptyallowed' => true, 'string_emptyallowed' => true,
'default' => '', 'default' => '',
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField'
'advanced_mode' => true ]
],
'system_le_renew_services' => [
'label' => lng('serversettings.le_renew_services'),
'settinggroup' => 'system',
'varname' => 'le_renew_services',
'type' => 'select',
'default' => '',
'select_mode' => 'multiple',
'option_emptyallowed' => true,
'select_var' => [
'' => lng('panel.none_value'),
'postfix' => 'postfix (smtp)',
'dovecot' => 'dovecot (imap/pop3)',
'proftpd' => 'proftpd (ftp)',
],
'save_method' => 'storeSettingField',
'advanced_mode' => true
],
'system_le_renew_hook' => [
'label' => lng('serversettings.le_renew_hook'),
'settinggroup' => 'system',
'varname' => 'le_renew_hook',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
'default' => 'systemctl restart postfix dovecot proftpd',
'save_method' => 'storeSettingField',
'advanced_mode' => true,
'required_otp' => true
],
] ]
] ]
] ]

View File

@@ -126,8 +126,7 @@ return [
'type' => 'textarea', 'type' => 'textarea',
'default' => '', 'default' => '',
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField',
'advanced_mode' => true, 'advanced_mode' => true
'required_otp' => true
], ],
'phpfpm_ini_values' => [ 'phpfpm_ini_values' => [
'label' => lng('phpfpm.ini_values'), 'label' => lng('phpfpm.ini_values'),
@@ -136,8 +135,7 @@ return [
'type' => 'textarea', 'type' => 'textarea',
'default' => '', 'default' => '',
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField',
'advanced_mode' => true, 'advanced_mode' => true
'required_otp' => true
], ],
'phpfpm_ini_admin_flags' => [ 'phpfpm_ini_admin_flags' => [
'label' => lng('phpfpm.ini_admin_flags'), 'label' => lng('phpfpm.ini_admin_flags'),
@@ -146,8 +144,7 @@ return [
'type' => 'textarea', 'type' => 'textarea',
'default' => '', 'default' => '',
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField',
'advanced_mode' => true, 'advanced_mode' => true
'required_otp' => true
], ],
'phpfpm_ini_admin_values' => [ 'phpfpm_ini_admin_values' => [
'label' => lng('phpfpm.ini_admin_values'), 'label' => lng('phpfpm.ini_admin_values'),
@@ -156,8 +153,7 @@ return [
'type' => 'textarea', 'type' => 'textarea',
'default' => '', 'default' => '',
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField',
'advanced_mode' => true, 'advanced_mode' => true
'required_otp' => true
] ]
] ]
] ]

View File

@@ -80,8 +80,7 @@ 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'),
@@ -112,8 +111,7 @@ 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'),

View File

@@ -1,111 +0,0 @@
<?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
*/
return [
'groups' => [
'antispam' => [
'title' => lng('admin.antispam_settings'),
'icon' => 'fa-solid fa-clipboard-check',
'fields' => [
'antispam_activated' => [
'label' => lng('antispam.activated'),
'settinggroup' => 'antispam',
'varname' => 'activated',
'type' => 'checkbox',
'default' => true,
'overview_option' => true,
'save_method' => 'storeSettingFieldInsertAntispamTask',
],
'antispam_config_file' => [
'label' => lng('antispam.config_file'),
'settinggroup' => 'antispam',
'varname' => 'config_file',
'type' => 'text',
'string_type' => 'file',
'default' => '/etc/rspamd/local.d/froxlor_settings.conf',
'save_method' => 'storeSettingFieldInsertAntispamTask',
'requires_reconf' => ['antispam']
],
'antispam_reload_command' => [
'label' => lng('antispam.reload_command'),
'settinggroup' => 'antispam',
'varname' => 'reload_command',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
'default' => 'service rspamd restart',
'save_method' => 'storeSettingField',
'required_otp' => true
],
'antispam_dkim_keylength' => [
'label' => lng('antispam.dkim_keylength'),
'settinggroup' => 'antispam',
'varname' => 'dkim_keylength',
'type' => 'select',
'default' => '1024',
'select_var' => [
'1024' => '1024 Bit',
'2048' => '2048 Bit'
],
'save_method' => 'storeSettingFieldInsertBindTask',
'advanced_mode' => true,
],
'spf_use_spf' => [
'label' => lng('spf.use_spf'),
'settinggroup' => 'spf',
'varname' => 'use_spf',
'type' => 'checkbox',
'default' => false,
'save_method' => 'storeSettingField',
],
'spf_spf_entry' => [
'label' => lng('spf.spf_entry'),
'settinggroup' => 'spf',
'varname' => 'spf_entry',
'type' => 'text',
'string_regexp' => '/^v=spf[a-z0-9:~?\s.-]+$/i',
'default' => 'v=spf1 a mx -all',
'save_method' => 'storeSettingField'
],
'dmarc_use_dmarc' => [
'label' => lng('dmarc.use_dmarc'),
'settinggroup' => 'dmarc',
'varname' => 'use_dmarc',
'type' => 'checkbox',
'default' => false,
'save_method' => 'storeSettingField',
],
'dmarc_dmarc_entry' => [
'label' => lng('dmarc.dmarc_entry'),
'settinggroup' => 'dmarc',
'varname' => 'dmarc_entry',
'type' => 'text',
'string_regexp' => '/^v=dmarc1(.+)$/i',
'default' => 'v=DMARC1; p=none;',
'save_method' => 'storeSettingField'
]
]
]
]
];

View File

@@ -0,0 +1,145 @@
<?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\Settings;
return [
'groups' => [
'dkim' => [
'title' => lng('admin.dkimsettings'),
'icon' => 'fa-solid fa-fingerprint',
'fields' => [
'dkim_use_dkim' => [
'label' => lng('dkim.use_dkim'),
'settinggroup' => 'dkim',
'varname' => 'use_dkim',
'type' => 'checkbox',
'default' => false,
'save_method' => 'storeSettingFieldInsertBindTask',
'overview_option' => true
],
'dkim_dkim_prefix' => [
'label' => lng('dkim.dkim_prefix'),
'settinggroup' => 'dkim',
'varname' => 'dkim_prefix',
'type' => 'text',
'string_type' => 'dir',
'default' => '/etc/postfix/dkim/',
'save_method' => 'storeSettingField'
],
'dkim_privkeysuffix' => [
'label' => lng('dkim.privkeysuffix'),
'settinggroup' => 'dkim',
'varname' => 'privkeysuffix',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\._]+$/i',
'default' => '.priv',
'save_method' => 'storeSettingField',
'advanced_mode' => true
],
'dkim_dkim_domains' => [
'label' => lng('dkim.dkim_domains'),
'settinggroup' => 'dkim',
'varname' => 'dkim_domains',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\._]+$/i',
'default' => 'domains',
'save_method' => 'storeSettingField'
],
'dkim_dkim_dkimkeys' => [
'label' => lng('dkim.dkim_dkimkeys'),
'settinggroup' => 'dkim',
'varname' => 'dkim_dkimkeys',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\._]+$/i',
'default' => 'dkim-keys.conf',
'save_method' => 'storeSettingField'
],
'dkim_dkim_algorithm' => [
'label' => lng('dkim.dkim_algorithm'),
'settinggroup' => 'dkim',
'varname' => 'dkim_algorithm',
'type' => 'select',
'default' => 'all',
'select_mode' => 'multiple',
'select_var' => [
'all' => 'All',
'sha1' => 'SHA1',
'sha256' => 'SHA256'
],
'save_method' => 'storeSettingFieldInsertBindTask',
'advanced_mode' => true
],
'dkim_dkim_servicetype' => [
'label' => lng('dkim.dkim_servicetype'),
'settinggroup' => 'dkim',
'varname' => 'dkim_servicetype',
'type' => 'select',
'default' => '0',
'select_var' => [
'0' => 'All',
'1' => 'E-Mail'
],
'save_method' => 'storeSettingFieldInsertBindTask',
'advanced_mode' => true
],
'dkim_dkim_keylength' => [
'label' => [
'title' => lng('dkim.dkim_keylength.title'),
'description' => lng('dkim.dkim_keylength.description', [Settings::Get('dkim.dkim_prefix')])
],
'settinggroup' => 'dkim',
'varname' => 'dkim_keylength',
'type' => 'select',
'default' => '1024',
'select_var' => [
'1024' => '1024 Bit',
'2048' => '2048 Bit'
],
'save_method' => 'storeSettingFieldInsertBindTask'
],
'dkim_dkim_notes' => [
'label' => lng('dkim.dkim_notes'),
'settinggroup' => 'dkim',
'varname' => 'dkim_notes',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\._]+$/i',
'default' => '',
'save_method' => 'storeSettingFieldInsertBindTask',
'advanced_mode' => true
],
'dkim_dkimrestart_command' => [
'label' => lng('dkim.dkimrestart_command'),
'settinggroup' => 'dkim',
'varname' => 'dkimrestart_command',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
'default' => '/etc/init.d/dkim-filter restart',
'save_method' => 'storeSettingField'
]
]
]
]
];

View File

@@ -23,21 +23,30 @@
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2 * @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/ */
use Froxlor\Froxlor; return [
use Froxlor\FileDir; 'groups' => [
use Froxlor\Config\ConfigParser; 'spf' => [
use Froxlor\Install\Update; 'title' => lng('admin.spfsettings'),
use Froxlor\Settings; 'icon' => 'fa-solid fa-clipboard-check',
'fields' => [
$preconfig = [ 'spf_use_spf' => [
'title' => '2.1.x updates', 'label' => lng('spf.use_spf'),
'fields' => [] 'settinggroup' => 'spf',
'varname' => 'use_spf',
'type' => 'checkbox',
'default' => false,
'save_method' => 'storeSettingField',
'overview_option' => true
],
'spf_spf_entry' => [
'label' => lng('spf.spf_entry'),
'settinggroup' => 'spf',
'varname' => 'spf_entry',
'type' => 'text',
'default' => '"v=spf1 a mx -all"',
'save_method' => 'storeSettingField'
]
]
]
]
]; ];
$return = [];
if (Update::versionInUpdate($current_version, '2.1.0-dev1')) {
}
$preconfig['fields'] = $return;
return $preconfig;

View File

@@ -37,8 +37,7 @@ 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'),
@@ -47,8 +46,7 @@ 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'),
@@ -61,8 +59,7 @@ 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'),
@@ -70,8 +67,7 @@ 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'),
@@ -79,8 +75,7 @@ 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'),
@@ -89,8 +84,7 @@ 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'),
@@ -100,8 +94,7 @@ 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'),
@@ -115,8 +108,7 @@ return [
'checkLocalGroup' 'checkLocalGroup'
], ],
'visible' => Settings::Get('system.nssextrausers'), 'visible' => Settings::Get('system.nssextrausers'),
'advanced_mode' => true, 'advanced_mode' => true
'required_otp' => true
], ],
] ]
] ]

View File

@@ -44,30 +44,24 @@ return [
'settinggroup' => 'system', 'settinggroup' => 'system',
'varname' => 'diskquota_repquota_path', 'varname' => 'diskquota_repquota_path',
'type' => 'text', 'type' => 'text',
'string_type' => 'file',
'default' => '/usr/sbin/repquota', 'default' => '/usr/sbin/repquota',
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField'
'required_otp' => true
], ],
'system_diskquota_quotatool_path' => [ 'system_diskquota_quotatool_path' => [
'label' => lng('serversettings.diskquota_quotatool_path.description'), 'label' => lng('serversettings.diskquota_quotatool_path.description'),
'settinggroup' => 'system', 'settinggroup' => 'system',
'varname' => 'diskquota_quotatool_path', 'varname' => 'diskquota_quotatool_path',
'type' => 'text', 'type' => 'text',
'string_type' => 'file',
'default' => '/usr/bin/quotatool', 'default' => '/usr/bin/quotatool',
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField'
'required_otp' => true
], ],
'system_diskquota_customer_partition' => [ 'system_diskquota_customer_partition' => [
'label' => lng('serversettings.diskquota_customer_partition.description'), 'label' => lng('serversettings.diskquota_customer_partition.description'),
'settinggroup' => 'system', 'settinggroup' => 'system',
'varname' => 'diskquota_customer_partition', 'varname' => 'diskquota_customer_partition',
'type' => 'text', 'type' => 'text',
'string_type' => 'file',
'default' => '/dev/root', 'default' => '/dev/root',
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField'
'required_otp' => true
] ]
] ]
] ]

View File

@@ -106,7 +106,7 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin
Response::standardError('youcantdeleteyourself'); Response::standardError('youcantdeleteyourself');
} }
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
Admins::getLocal($userinfo, [ Admins::getLocal($userinfo, [
'id' => $id 'id' => $id
])->delete(); ])->delete();
@@ -122,9 +122,9 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin
} }
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Admins::getLocal($userinfo, Request::postAll())->add(); Admins::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -159,9 +159,9 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if ($result['loginname'] != '') { if ($result['loginname'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Admins::getLocal($userinfo, Request::postAll())->update(); Admins::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }

View File

@@ -33,7 +33,6 @@
use Froxlor\FroxlorLogger; use Froxlor\FroxlorLogger;
use Froxlor\UI\Panel\UI; use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request;
use Froxlor\UI\Response; use Froxlor\UI\Response;
use Froxlor\UI\HTML; use Froxlor\UI\HTML;
@@ -43,7 +42,7 @@ require __DIR__ . '/lib/init.php';
$horizontal_bar_size = 950; // 1280px window width $horizontal_bar_size = 950; // 1280px window width
if ($action == 'delete' && function_exists('apcu_clear_cache') && $userinfo['change_serversettings'] == '1') { if ($action == 'delete' && function_exists('apcu_clear_cache') && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') { if ($_POST['send'] == 'send') {
apcu_clear_cache(); apcu_clear_cache();
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "cleared APCu cache"); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "cleared APCu cache");
header('Location: ' . $linker->getLink([ header('Location: ' . $linker->getLink([
@@ -63,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('no_apcuinfo'); Response::standardError(lng('error.no_apcuinfo'));
} }
if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') { if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
@@ -118,7 +117,7 @@ if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
'uptime' => duration($cache['start_time']) 'uptime' => duration($cache['start_time'])
]; ];
$overview['mem_used_percentage'] = number_format(($overview['mem_used'] / $overview['mem_size']) * 100, 1); $overview['mem_used_percentage'] = number_format(($overview['mem_used'] / $overview['mem_avail']) * 100, 1);
$overview['num_hits_percentage'] = number_format(($overview['num_hits'] / $overview['num_hits_and_misses']) * 100, $overview['num_hits_percentage'] = number_format(($overview['num_hits'] / $overview['num_hits_and_misses']) * 100,
1); 1);
$overview['num_misses_percentage'] = number_format(($overview['num_misses'] / $overview['num_hits_and_misses']) * 100, $overview['num_misses_percentage'] = number_format(($overview['num_misses'] / $overview['num_hits_and_misses']) * 100,

View File

@@ -32,7 +32,6 @@ 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;
use Froxlor\UI\Request;
use Froxlor\UI\Response; use Froxlor\UI\Response;
if ($page != 'error') { if ($page != 'error') {
@@ -111,7 +110,7 @@ if ($page == 'overview') {
} // download the new archive } // download the new archive
elseif ($page == 'getdownload') { elseif ($page == 'getdownload') {
// retrieve the new version from the form // retrieve the new version from the form
$newversion = Request::post('newversion'); $newversion = isset($_POST['newversion']) ? $_POST['newversion'] : null;
$result = 6; $result = 6;
// valid? // valid?
@@ -131,8 +130,8 @@ elseif ($page == 'getdownload') {
]); ]);
} // extract and install new version } // extract and install new version
elseif ($page == 'extract') { elseif ($page == 'extract') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$toExtract = Request::post('archive'); $toExtract = isset($_POST['archive']) ? $_POST['archive'] : null;
$localArchive = FileDir::makeCorrectFile(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);
@@ -146,7 +145,7 @@ elseif ($page == 'extract') {
// redirect to update-page // redirect to update-page
Response::redirectTo('admin_updates.php'); Response::redirectTo('admin_updates.php');
} else { } else {
$toExtract = Request::get('archive'); $toExtract = isset($_GET['archive']) ? $_GET['archive'] : null;
$localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract); $localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract);
} }
@@ -193,7 +192,7 @@ elseif ($page == 'extract') {
} // display error } // display error
elseif ($page == 'error') { elseif ($page == 'error') {
// retrieve error-number via url-parameter // retrieve error-number via url-parameter
$errno = Request::get('errno', 0); $errno = isset($_GET['errno']) ? (int)$_GET['errno'] : 0;
// 2 = no Zlib // 2 = no Zlib
// 3 = custom version detected // 3 = custom version detected

View File

@@ -60,9 +60,7 @@ 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")) {
// unknown distribution -> redirect to select a valid distribution for config-templates Response::dynamicError("Unknown distribution");
Settings::Set('system.distribution', '');
Response::redirectTo('admin_configfiles.php', ['reselect' => 1]);
} }
// update setting if different // update setting if different
@@ -93,14 +91,14 @@ if ($userinfo['change_serversettings'] == '1') {
asort($distributions_select); asort($distributions_select);
} }
if ($distribution != "" && !empty(Request::post('finish'))) { if ($distribution != "" && isset($_POST['finish'])) {
$valid_keys = ['http', 'dns', 'smtp', 'mail', 'antispam', 'ftp', 'system', 'distro']; $valid_keys = ['http', 'dns', 'smtp', 'mail', 'ftp', 'system', 'distro'];
unset($_POST['finish']); unset($_POST['finish']);
unset($_POST['csrf_token']); unset($_POST['csrf_token']);
$params = Request::postAll(); $params = $_POST;
$params['distro'] = $distribution; $params['distro'] = $distribution;
$params['system'] = []; $params['system'] = [];
foreach (Request::post('system', []) as $sysdaemon) { foreach ($_POST['system'] as $sysdaemon) {
$params['system'][] = $sysdaemon; $params['system'][] = $sysdaemon;
} }
// validate params // validate params

View File

@@ -68,9 +68,9 @@ if (($page == 'cronjobs' || $page == 'overview') && $userinfo['change_serversett
} }
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if ($result['cronfile'] != '') { if ($result['cronfile'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Cronjobs::getLocal($userinfo, Request::postAll())->update(); Cronjobs::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }

View File

@@ -98,7 +98,7 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
$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 . "'");
$target = Request::get('target', 'index'); $target = (isset($_GET['target']) ? $_GET['target'] : 'index');
$redirect = "customer_" . $target . ".php"; $redirect = "customer_" . $target . ".php";
if (!file_exists(Froxlor::getInstallDir() . "/" . $redirect)) { if (!file_exists(Froxlor::getInstallDir() . "/" . $redirect)) {
$redirect = "customer_index.php"; $redirect = "customer_index.php";
@@ -119,7 +119,7 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
} }
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
$json_result = Customers::getLocal($userinfo, [ $json_result = Customers::getLocal($userinfo, [
'id' => $id 'id' => $id
@@ -147,11 +147,11 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
} }
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
$json_result = Customers::getLocal($userinfo, [ $json_result = Customers::getLocal($userinfo, [
'id' => $id, 'id' => $id,
'delete_userfiles' => Request::post('delete_userfiles', 0) 'delete_userfiles' => (isset($_POST['delete_userfiles']) ? (int)$_POST['delete_userfiles'] : 0)
])->delete(); ])->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
@@ -167,9 +167,9 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
], $result['loginname']); ], $result['loginname']);
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Customers::getLocal($userinfo, Request::postAll())->add(); Customers::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -243,9 +243,9 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if ($result['loginname'] != '') { if ($result['loginname'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Customers::getLocal($userinfo, Request::postAll())->update(); Customers::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }

View File

@@ -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,6 +45,7 @@ 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');
@@ -100,9 +101,9 @@ if ($page == 'domains' || $page == 'overview') {
]); ]);
if ($result['domain'] != '') { if ($result['domain'] != '') {
if (Request::post('send') == 'send' && $alias_check['count'] == 0) { if (isset($_POST['send']) && $_POST['send'] == 'send' && $alias_check['count'] == 0) {
try { try {
Domains::getLocal($userinfo, Request::postAll())->delete(); Domains::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -113,17 +114,21 @@ 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 {
HTML::askYesNoWithCheckbox('admin_domain_reallydelete', 'admin_customer_alsoremovemail', $filename, [ $showcheck = false;
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'])); ], $idna_convert->decode($result['domain']), $showcheck);
} }
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Domains::getLocal($userinfo, Request::postAll())->add(); Domains::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -247,6 +252,21 @@ 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
@@ -355,13 +375,13 @@ if ($page == 'domains' || $page == 'overview') {
$usedips[] = $ipsresultrow['id_ipandports']; $usedips[] = $ipsresultrow['id_ipandports'];
} }
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
// remove ssl ip/ports if set is empty // remove ssl ip/ports if set is empty
if (empty(Request::post('ssl_ipandport'))) { if (!isset($_POST['ssl_ipandport']) || empty($_POST['ssl_ipandport'])) {
$_POST['remove_ssl_ipandport'] = true; $_POST['remove_ssl_ipandport'] = true;
} }
Domains::getLocal($userinfo, Request::postAll())->update(); Domains::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -449,6 +469,27 @@ 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
@@ -572,13 +613,13 @@ if ($page == 'domains' || $page == 'overview') {
} }
} }
} elseif ($action == 'jqGetCustomerPHPConfigs') { } elseif ($action == 'jqGetCustomerPHPConfigs') {
$customerid = intval(Request::post('customerid')); $customerid = intval($_POST['customerid']);
$allowed_phpconfigs = Customer::getCustomerDetail($customerid, 'allowed_phpconfigs'); $allowed_phpconfigs = Customer::getCustomerDetail($customerid, 'allowed_phpconfigs');
echo !empty($allowed_phpconfigs) ? $allowed_phpconfigs : json_encode([]); echo !empty($allowed_phpconfigs) ? $allowed_phpconfigs : json_encode([]);
exit(); exit();
} elseif ($action == 'jqSpeciallogfileNote') { } elseif ($action == 'jqSpeciallogfileNote') {
$domainid = intval(Request::post('id')); $domainid = intval($_POST['id']);
$newval = intval(Request::post('newval')); $newval = intval($_POST['newval']);
try { try {
$json_result = Domains::getLocal($userinfo, [ $json_result = Domains::getLocal($userinfo, [
'id' => $domainid 'id' => $domainid
@@ -594,9 +635,9 @@ if ($page == 'domains' || $page == 'overview') {
echo 0; echo 0;
exit(); exit();
} elseif ($action == 'import') { } elseif ($action == 'import') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$separator = Validate::validate(Request::post('separator'), 'separator'); $separator = Validate::validate($_POST['separator'], 'separator');
$offset = (int)Validate::validate(Request::post('offset'), 'offset', "/[0-9]/i"); $offset = (int)Validate::validate($_POST['offset'], 'offset', "/[0-9]/i");
$file_name = $_FILES['file']['tmp_name']; $file_name = $_FILES['file']['tmp_name'];
@@ -635,23 +676,6 @@ if ($page == 'domains' || $page == 'overview') {
'alert_msg' => lng('domains.import_description') 'alert_msg' => lng('domains.import_description')
]); ]);
} }
} elseif ($action == 'duplicate') {
if (Request::post('send') == 'send') {
try {
Domains::getLocal($userinfo, Request::postAll())->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';

View File

@@ -31,7 +31,6 @@ 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;
@@ -39,6 +38,7 @@ 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');
@@ -55,7 +55,7 @@ if ($action == 'logout') {
$result = $result['switched_user']; $result = $result['switched_user'];
session_regenerate_id(true); session_regenerate_id(true);
CurrentUser::setData($result); CurrentUser::setData($result);
$target = Request::get('target', 'index'); $target = (isset($_GET['target']) ? $_GET['target'] : 'index');
$redirect = "admin_" . $target . ".php"; $redirect = "admin_" . $target . ".php";
if (!file_exists(\Froxlor\Froxlor::getInstallDir() . "/" . $redirect)) { if (!file_exists(\Froxlor\Froxlor::getInstallDir() . "/" . $redirect)) {
$redirect = "admin_index.php"; $redirect = "admin_index.php";
@@ -111,7 +111,7 @@ if ($page == 'overview') {
$overview['number_domains'] = $number_domains['number_domains']; $overview['number_domains'] = $number_domains['number_domains'];
if (Request::get('lookfornewversion') == 'yes' || (isset($lookfornewversion) && $lookfornewversion == 'yes')) { if ((isset($_GET['lookfornewversion']) && $_GET['lookfornewversion'] == 'yes') || (isset($lookfornewversion) && $lookfornewversion == 'yes')) {
try { try {
$json_result = Froxlor::getLocal($userinfo)->checkUpdate(); $json_result = Froxlor::getLocal($userinfo)->checkUpdate();
} catch (Exception $e) { } catch (Exception $e) {
@@ -197,20 +197,17 @@ 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 == 'profile') { } elseif ($page == 'change_password') {
$languages = Language::getLanguages(); if (isset($_POST['send']) && $_POST['send'] == 'send') {
$old_password = Validate::validate($_POST['old_password'], 'old password');
if (!empty($_POST)) {
if (Request::post('send') == 'changepassword') {
$old_password = Validate::validate(Request::post('old_password'), 'old password');
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_ADMINS, 'adminid')) { if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_ADMINS, 'adminid')) {
Response::standardError('oldpasswordnotcorrect'); Response::standardError('oldpasswordnotcorrect');
} }
try { try {
$new_password = Crypt::validatePassword(Request::post('new_password'), 'new password'); $new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
$new_password_confirm = Crypt::validatePassword(Request::post('new_password_confirm'), 'new password confirm'); $new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -244,23 +241,13 @@ if ($page == 'overview') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'changed password'); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'changed password');
Response::redirectTo($filename); Response::redirectTo($filename);
} }
} elseif (Request::post('send') == 'changetheme') { } else {
if (Settings::Get('panel.allow_theme_change_admin') == 1) { UI::view('user/change_password.html.twig');
$theme = Validate::validate(Request::post('theme'), 'theme');
try {
Admins::getLocal($userinfo, [
'id' => $userinfo['adminid'],
'theme' => $theme
])->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
} }
} elseif ($page == 'change_language') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her theme to '" . $theme . "'"); $languages = Language::getLanguages();
} if (isset($_POST['send']) && $_POST['send'] == 'send') {
Response::redirectTo($filename); $def_language = Validate::validate($_POST['def_language'], 'default language');
} elseif (Request::post('send') == 'changelanguage') {
$def_language = Validate::validate(Request::post('def_language'), 'default language');
if (isset($languages[$def_language])) { if (isset($languages[$def_language])) {
try { try {
@@ -275,26 +262,42 @@ if ($page == 'overview') {
} }
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her default language to '" . $def_language . "'"); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her default language to '" . $def_language . "'");
Response::redirectTo($filename); Response::redirectTo($filename);
}
} else { } else {
// change theme
$default_theme = Settings::Get('panel.default_theme');
if ($userinfo['theme'] != '') {
$default_theme = $userinfo['theme'];
}
$themes_avail = UI::getThemes();
// change language
$default_lang = Settings::Get('panel.standardlanguage'); $default_lang = Settings::Get('panel.standardlanguage');
if ($userinfo['def_language'] != '') { if ($userinfo['def_language'] != '') {
$default_lang = $userinfo['def_language']; $default_lang = $userinfo['def_language'];
} }
UI::view('user/profile.html.twig', [ UI::view('user/change_language.html.twig', [
'themes' => $themes_avail,
'default_theme' => $default_theme,
'languages' => $languages, 'languages' => $languages,
'default_lang' => $default_lang, '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,
'default_theme' => $default_theme
]); ]);
} }
} 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') {

View File

@@ -70,7 +70,7 @@ if (($page == 'ipsandports' || $page == 'overview') && $userinfo['change_servers
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['id']) && $result['id'] == $id) { if (isset($result['id']) && $result['id'] == $id) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
IpsAndPorts::getLocal($userinfo, [ IpsAndPorts::getLocal($userinfo, [
'id' => $id 'id' => $id
@@ -91,9 +91,9 @@ if (($page == 'ipsandports' || $page == 'overview') && $userinfo['change_servers
} }
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
IpsAndPorts::getLocal($userinfo, Request::postAll())->add(); IpsAndPorts::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -119,9 +119,9 @@ if (($page == 'ipsandports' || $page == 'overview') && $userinfo['change_servers
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if ($result['ip'] != '') { if ($result['ip'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
IpsAndPorts::getLocal($userinfo, Request::postAll())->update(); IpsAndPorts::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -141,11 +141,9 @@ if (($page == 'ipsandports' || $page == 'overview') && $userinfo['change_servers
} }
} }
} elseif ($action == 'jqCheckIP') { } elseif ($action == 'jqCheckIP') {
$ip = Request::post('ip', ''); $ip = $_POST['ip'] ?? "";
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) { 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) {
echo json_encode('<div id="ipnote" class="invalid-feedback">'.lng('error.invalidip', [$ip]).'</div>'); // returns notice if private network detected so we can display it
} 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;

View File

@@ -31,7 +31,6 @@ use Froxlor\UI\Collection;
use Froxlor\UI\HTML; use Froxlor\UI\HTML;
use Froxlor\UI\Listing; use Froxlor\UI\Listing;
use Froxlor\UI\Panel\UI; use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request;
use Froxlor\UI\Response; use Froxlor\UI\Response;
if ($page == 'log' && $userinfo['change_serversettings'] == '1') { if ($page == 'log' && $userinfo['change_serversettings'] == '1') {
@@ -56,7 +55,7 @@ if ($page == 'log' && $userinfo['change_serversettings'] == '1') {
] ]
]); ]);
} elseif ($action == 'truncate') { } elseif ($action == 'truncate') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
SysLog::getLocal($userinfo, [ SysLog::getLocal($userinfo, [
'min_to_keep' => 10 'min_to_keep' => 10

View File

@@ -42,11 +42,11 @@ if ($page == 'message') {
if ($action == '') { if ($action == '') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'viewed panel_message'); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'viewed panel_message');
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
if (Request::post('recipient', -1) == 0 && $userinfo['customers_see_all'] == '1') { if ($_POST['recipient'] == 0 && $userinfo['customers_see_all'] == '1') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'sending messages to admins'); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'sending messages to admins');
$result = Database::query('SELECT `name`, `email` FROM `' . TABLE_PANEL_ADMINS . "`"); $result = Database::query('SELECT `name`, `email` FROM `' . TABLE_PANEL_ADMINS . "`");
} elseif (Request::post('recipient', -1) == 1) { } elseif ($_POST['recipient'] == 1) {
if ($userinfo['customers_see_all'] == '1') { if ($userinfo['customers_see_all'] == '1') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'sending messages to ALL customers'); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'sending messages to ALL customers');
$result = Database::query('SELECT `firstname`, `name`, `company`, `email` FROM `' . TABLE_PANEL_CUSTOMERS . "`"); $result = Database::query('SELECT `firstname`, `name`, `company`, `email` FROM `' . TABLE_PANEL_CUSTOMERS . "`");
@@ -63,8 +63,8 @@ if ($page == 'message') {
Response::standardError('norecipientsgiven'); Response::standardError('norecipientsgiven');
} }
$subject = Request::post('subject'); $subject = $_POST['subject'];
$message = wordwrap(Request::post('message'), 70); $message = wordwrap($_POST['message'], 70);
if (!empty($message)) { if (!empty($message)) {
$mailcounter = 0; $mailcounter = 0;
@@ -107,14 +107,14 @@ if ($page == 'message') {
} }
} }
} elseif ($action == 'showsuccess') { } elseif ($action == 'showsuccess') {
$sentitems = Request::get('sentitems', 0); $sentitems = isset($_GET['sentitems']) ? (int)$_GET['sentitems'] : 0;
if ($sentitems == 0) { if ($sentitems == 0) {
$note_type = 'info'; $note_type = 'info';
$note_msg = lng('message.norecipients'); $note_msg = lng('message.norecipients');
} else { } else {
$note_type = 'success'; $note_type = 'success';
$note_msg = lng('message.success', [$sentitems]); $note_msg = str_replace('%s', $sentitems, lng('message.success'));
} }
} }
@@ -128,7 +128,7 @@ if ($page == 'message') {
$messages_add_data = include_once dirname(__FILE__) . '/lib/formfields/admin/messages/formfield.messages_add.php'; $messages_add_data = include_once dirname(__FILE__) . '/lib/formfields/admin/messages/formfield.messages_add.php';
UI::view('user/form-note.html.twig', [ UI::view('user/form-note.html.twig', [
'formaction' => $linker->getLink(['section' => 'message', 'action' => '']), 'formaction' => $linker->getLink(['section' => 'message']),
'formdata' => $messages_add_data['messages_add'], 'formdata' => $messages_add_data['messages_add'],
'actions_links' => [ 'actions_links' => [
[ [

View File

@@ -70,7 +70,7 @@ if (($page == 'mysqlserver' || $page == 'overview') && $userinfo['change_servers
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['id']) && $result['id'] == $id) { if (isset($result['id']) && $result['id'] == $id) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
MysqlServer::getLocal($userinfo, [ MysqlServer::getLocal($userinfo, [
'id' => $id 'id' => $id
@@ -91,9 +91,9 @@ if (($page == 'mysqlserver' || $page == 'overview') && $userinfo['change_servers
} }
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
MysqlServer::getLocal($userinfo, Request::postAll())->add(); MysqlServer::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -119,9 +119,9 @@ if (($page == 'mysqlserver' || $page == 'overview') && $userinfo['change_servers
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['id']) && $result['id'] == $id) { if (isset($result['id']) && $result['id'] == $id) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
MysqlServer::getLocal($userinfo, Request::postAll())->update(); MysqlServer::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }

View File

@@ -33,13 +33,12 @@ 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\Request;
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 (Request::post('send') == 'send') { if ($_POST['send'] == 'send') {
opcache_reset(); opcache_reset();
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "reset OPcache"); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "reset OPcache");
header('Location: ' . $linker->getLink([ header('Location: ' . $linker->getLink([
@@ -58,30 +57,252 @@ if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_
} }
} }
if (!extension_loaded('Zend OPcache')) { if (!function_exists('opcache_get_configuration')) {
Response::standardError('no_opcacheinfo'); Response::standardError(lng('error.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");
$opcache = (new \Amnuts\Opcache\Service())->getData(); $optimizationLevels = [
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' => $opcache['version'], 'version' => $version,
'overview' => $opcache['overview'], 'overview' => $overview,
'files' => $opcache['files'], 'files' => $files,
'preload' => $opcache['preload'], 'preload' => $preload,
'directives' => $opcache['directives'], 'directives' => $directives,
'blacklist' => $opcache['blacklist'], 'blacklist' => $config['blacklist'],
'functions' => $opcache['functions'], 'functions' => get_extension_funcs('Zend OPcache')
] ]
]); ]);
} }
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]
);
}

View File

@@ -62,9 +62,9 @@ if ($page == 'overview') {
if ($action == 'add') { if ($action == 'add') {
if ((int)$userinfo['change_serversettings'] == 1) { if ((int)$userinfo['change_serversettings'] == 1) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
PhpSettings::getLocal($userinfo, Request::postAll())->add(); PhpSettings::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -114,7 +114,7 @@ if ($page == 'overview') {
if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1 && $id != 1) // cannot delete the default php.config if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1 && $id != 1) // cannot delete the default php.config
{ {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
PhpSettings::getLocal($userinfo, [ PhpSettings::getLocal($userinfo, [
'id' => $id 'id' => $id
@@ -148,9 +148,9 @@ if ($page == 'overview') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1) { if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
PhpSettings::getLocal($userinfo, Request::postAll())->update(); PhpSettings::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -200,9 +200,9 @@ if ($page == 'overview') {
if ($action == 'add') { if ($action == 'add') {
if ((int)$userinfo['change_serversettings'] == 1) { if ((int)$userinfo['change_serversettings'] == 1) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
FpmDaemons::getLocal($userinfo, Request::postAll())->add(); FpmDaemons::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -239,9 +239,9 @@ if ($page == 'overview') {
if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1 && $id != 1) // cannot delete the default php.config if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1 && $id != 1) // cannot delete the default php.config
{ {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
FpmDaemons::getLocal($userinfo, Request::postAll())->delete(); FpmDaemons::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -271,9 +271,9 @@ if ($page == 'overview') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1) { if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
FpmDaemons::getLocal($userinfo, Request::postAll())->update(); FpmDaemons::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }

View File

@@ -73,7 +73,7 @@ if ($page == '' || $page == 'overview') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['adminid'] == $result['adminid']) { if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['adminid'] == $result['adminid']) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
HostingPlans::getLocal($userinfo, [ HostingPlans::getLocal($userinfo, [
'id' => $id 'id' => $id
@@ -96,9 +96,9 @@ if ($page == '' || $page == 'overview') {
Response::standardError('nopermissionsorinvalidid'); Response::standardError('nopermissionsorinvalidid');
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
HostingPlans::getLocal($userinfo, Request::postAll())->add(); HostingPlans::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -176,9 +176,9 @@ if ($page == '' || $page == 'overview') {
} }
$result['allowed_phpconfigs'] = json_encode($result['allowed_phpconfigs']); $result['allowed_phpconfigs'] = json_encode($result['allowed_phpconfigs']);
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
HostingPlans::getLocal($userinfo, Request::postAll())->update(); HostingPlans::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }

View File

@@ -47,10 +47,10 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
$settings_data = PhpHelper::loadConfigArrayDir('./actions/admin/settings/'); $settings_data = PhpHelper::loadConfigArrayDir('./actions/admin/settings/');
Settings::loadSettingsInto($settings_data); Settings::loadSettingsInto($settings_data);
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$_part = Request::get('part', ''); $_part = isset($_GET['part']) ? $_GET['part'] : '';
if ($_part == '') { if ($_part == '') {
$_part = Request::post('part', ''); $_part = isset($_POST['part']) ? $_POST['part'] : '';
} }
if ($_part != '') { if ($_part != '') {
@@ -69,16 +69,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 (!empty(Request::post('session_sessiontimeout')) && intval(Request::post('session_sessiontimeout', 0)) < 60) { if (isset($_POST['session_sessiontimeout']) && $_POST['session_sessiontimeout'] < 60) {
Response::standardError(['session_timeout', 'session_timeout_desc']); Response::standardError(lng('error.session_timeout'), lng('error.session_timeout_desc'));
} }
try { try {
if (Form::processForm($settings_data, Request::postAll(), [ 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);
@@ -97,9 +96,9 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
Response::dynamicError($e->getMessage(), $e->getCode()); Response::dynamicError($e->getMessage(), $e->getCode());
} }
} else { } else {
$_part = Request::get('part', ''); $_part = isset($_GET['part']) ? $_GET['part'] : '';
if ($_part == '') { if ($_part == '') {
$_part = Request::post('part', ''); $_part = isset($_POST['part']) ? $_POST['part'] : '';
} }
$fields = Form::buildForm($settings_data, $_part); $fields = Form::buildForm($settings_data, $_part);
@@ -133,14 +132,14 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
} }
} }
} else { } else {
Response::standardError('error.no_phpinfo'); Response::standardError(lng('error.no_phpinfo'));
} }
UI::view('settings/phpinfo.html.twig', [ UI::view('settings/phpinfo.html.twig', [
'phpversion' => PHP_VERSION, 'phpversion' => PHP_VERSION,
'phpinfo' => $phpinfo 'phpinfo' => $phpinfo
]); ]);
} elseif ($page == 'rebuildconfigs' && $userinfo['change_serversettings'] == '1') { } elseif ($page == 'rebuildconfigs' && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "rebuild configfiles"); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "rebuild configfiles");
Cronjob::inserttask(TaskId::REBUILD_VHOST); Cronjob::inserttask(TaskId::REBUILD_VHOST);
Cronjob::inserttask(TaskId::CREATE_QUOTA); Cronjob::inserttask(TaskId::CREATE_QUOTA);
@@ -158,7 +157,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
]); ]);
} }
} elseif ($page == 'updatecounters' && $userinfo['change_serversettings'] == '1') { } elseif ($page == 'updatecounters' && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "updated resource-counters"); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "updated resource-counters");
$updatecounters = User::updateCounters(true); $updatecounters = User::updateCounters(true);
UI::view('user/resource-counter.html.twig', [ UI::view('user/resource-counter.html.twig', [
@@ -170,7 +169,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
]); ]);
} }
} elseif ($page == 'wipecleartextmailpws' && $userinfo['change_serversettings'] == '1') { } elseif ($page == 'wipecleartextmailpws' && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "wiped all cleartext mail passwords"); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "wiped all cleartext mail passwords");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = '';"); Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = '';");
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = '0' WHERE `settinggroup` = 'system' AND `varname` = 'mailpwcleartext'"); Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = '0' WHERE `settinggroup` = 'system' AND `varname` = 'mailpwcleartext'");
@@ -181,7 +180,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
]); ]);
} }
} elseif ($page == 'wipequotas' && $userinfo['change_serversettings'] == '1') { } elseif ($page == 'wipequotas' && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "wiped all mailquotas"); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "wiped all mailquotas");
// Set the quota to 0 which means unlimited // Set the quota to 0 which means unlimited
@@ -194,7 +193,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
]); ]);
} }
} elseif ($page == 'enforcequotas' && $userinfo['change_serversettings'] == '1') { } elseif ($page == 'enforcequotas' && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
// Fetch all accounts // Fetch all accounts
$result_stmt = Database::query("SELECT `quota`, `customerid` FROM `" . TABLE_MAIL_USERS . "`"); $result_stmt = Database::query("SELECT `quota`, `customerid` FROM `" . TABLE_MAIL_USERS . "`");
@@ -233,9 +232,9 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
} }
} elseif ($page == 'integritycheck' && $userinfo['change_serversettings'] == '1') { } elseif ($page == 'integritycheck' && $userinfo['change_serversettings'] == '1') {
$integrity = new IntegrityCheck(); $integrity = new IntegrityCheck();
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$integrity->fixAll(); $integrity->fixAll();
} elseif (Request::get('action') == "fix") { } elseif (isset($_GET['action']) && $_GET['action'] == "fix") {
HTML::askYesNo('admin_integritycheck_reallyfix', $filename, [ HTML::askYesNo('admin_integritycheck_reallyfix', $filename, [
'page' => $page 'page' => $page
]); ]);
@@ -273,7 +272,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
Response::standardError('jsonextensionnotfound'); Response::standardError('jsonextensionnotfound');
} }
if (Request::get('action') == "export") { if (isset($_GET['action']) && $_GET['action'] == "export") {
// export // export
try { try {
$json_result = Froxlor::getLocal($userinfo)->exportSettings(); $json_result = Froxlor::getLocal($userinfo)->exportSettings();
@@ -285,9 +284,9 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
header('Content-type: application/json'); header('Content-type: application/json');
echo $json_export; echo $json_export;
exit(); exit();
} elseif (Request::get('action') == "import") { } elseif (isset($_GET['action']) && $_GET['action'] == "import") {
// import // import
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
// get uploaded file // get uploaded file
if (isset($_FILES["import_file"]["tmp_name"])) { if (isset($_FILES["import_file"]["tmp_name"])) {
$imp_content = file_get_contents($_FILES["import_file"]["tmp_name"]); $imp_content = file_get_contents($_FILES["import_file"]["tmp_name"]);
@@ -330,8 +329,8 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
$note_type = 'info'; $note_type = 'info';
$note_msg = lng('admin.smtptestnote'); $note_msg = lng('admin.smtptestnote');
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$test_addr = Request::post('test_addr'); $test_addr = isset($_POST['test_addr']) ? $_POST['test_addr'] : null;
// Initialize the mailingsystem // Initialize the mailingsystem
$testmail = new PHPMailer(true); $testmail = new PHPMailer(true);

View File

@@ -60,8 +60,7 @@ if (Settings::Get('panel.sendalternativemail') == 1) {
} }
$file_templates = [ $file_templates = [
'index_html', 'index_html'
'unconfigured_html'
]; ];
$languages = Language::getLanguages(); $languages = Language::getLanguages();
@@ -192,7 +191,7 @@ if ($action == '') {
$result = $result_stmt->fetch(PDO::FETCH_ASSOC); $result = $result_stmt->fetch(PDO::FETCH_ASSOC);
if ($result['varname'] != '') { if ($result['varname'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$del_stmt = Database::prepare(" $del_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_TEMPLATES . "` DELETE FROM `" . TABLE_PANEL_TEMPLATES . "`
WHERE `adminid` = :adminid WHERE `adminid` = :adminid
@@ -228,7 +227,7 @@ if ($action == '') {
if (Database::num_rows() > 0) { if (Database::num_rows() > 0) {
$row = $result_stmt->fetch(PDO::FETCH_ASSOC); $row = $result_stmt->fetch(PDO::FETCH_ASSOC);
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$del_stmt = Database::prepare(" $del_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_TEMPLATES . "` DELETE FROM `" . TABLE_PANEL_TEMPLATES . "`
WHERE `adminid` = :adminid AND `id` = :id"); WHERE `adminid` = :adminid AND `id` = :id");
@@ -251,13 +250,13 @@ if ($action == '') {
Response::standardError('templatenotfound'); Response::standardError('templatenotfound');
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if (Request::post('prepare') == 'prepare') { if (isset($_POST['prepare']) && $_POST['prepare'] == 'prepare') {
// email templates // email templates
$language = htmlentities(Validate::validate(Request::post('language'), 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect')); $language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
if (!array_key_exists($language, $languages)) { if (!array_key_exists($language, $languages)) {
Response::standardError('templatelanguageinvalid'); Response::standardError('templatelanguageinvalid');
} }
$template = Validate::validate(Request::post('template'), 'template'); $template = Validate::validate($_POST['template'], 'template');
$result_stmt = Database::prepare(" $result_stmt = Database::prepare("
SELECT COUNT(*) as def FROM `" . TABLE_PANEL_TEMPLATES . "` SELECT COUNT(*) as def FROM `" . TABLE_PANEL_TEMPLATES . "`
@@ -289,15 +288,15 @@ if ($action == '') {
'formdata' => $template_add_data['template_add'], 'formdata' => $template_add_data['template_add'],
'replacers' => $template_add_data['template_replacers'] 'replacers' => $template_add_data['template_replacers']
]); ]);
} elseif (Request::post('send') == 'send' && empty(Request::post('filesend'))) { } elseif (isset($_POST['send']) && $_POST['send'] == 'send' && !isset($_POST['filesend'])) {
// email templates // email templates
$language = htmlentities(Validate::validate(Request::post('language'), 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect')); $language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
if (!array_key_exists($language, $languages)) { if (!array_key_exists($language, $languages)) {
Response::standardError('templatelanguageinvalid'); Response::standardError('templatelanguageinvalid');
} }
$template = Validate::validate(Request::post('template'), 'template'); $template = Validate::validate($_POST['template'], 'template');
$subject = Validate::validate(Request::post('subject'), 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate'); $subject = Validate::validate($_POST['subject'], 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate');
$mailbody = Validate::validate(Request::post('mailbody'), 'mailbody', '/^[^\0]+$/', 'nomailbodycreate'); $mailbody = Validate::validate($_POST['mailbody'], 'mailbody', '/^[^\0]+$/', 'nomailbodycreate');
$templates = []; $templates = [];
$result_stmt = Database::prepare(" $result_stmt = Database::prepare("
SELECT `varname` FROM `" . TABLE_PANEL_TEMPLATES . "` SELECT `varname` FROM `" . TABLE_PANEL_TEMPLATES . "`
@@ -347,10 +346,10 @@ if ($action == '') {
'page' => $page 'page' => $page
]); ]);
} }
} elseif (Request::post('filesend') == 'filesend') { } elseif (isset($_POST['filesend']) && $_POST['filesend'] == 'filesend') {
// file templates // file templates
$template = Validate::validate(Request::post('template'), 'template'); $template = Validate::validate($_POST['template'], 'template');
$filecontent = Validate::validate(Request::post('filecontent'), 'filecontent', '/^[^\0]+$/', 'filecontentnotset'); $filecontent = Validate::validate($_POST['filecontent'], 'filecontent', '/^[^\0]+$/', 'filecontentnotset');
$ins_stmt = Database::prepare(" $ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_PANEL_TEMPLATES . "` SET INSERT INTO `" . TABLE_PANEL_TEMPLATES . "` SET
@@ -371,7 +370,7 @@ if ($action == '') {
Response::redirectTo($filename, [ Response::redirectTo($filename, [
'page' => $page 'page' => $page
]); ]);
} elseif (empty(Request::get('files'))) { } elseif (!isset($_GET['files'])) {
// email templates // email templates
$add = false; $add = false;
$language_options = []; $language_options = [];
@@ -483,9 +482,9 @@ if ($action == '') {
$result = $result_stmt->fetch(PDO::FETCH_ASSOC); $result = $result_stmt->fetch(PDO::FETCH_ASSOC);
if ($result['varname'] != '') { if ($result['varname'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$subject = Validate::validate(Request::post('subject'), 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate'); $subject = Validate::validate($_POST['subject'], 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate');
$mailbody = Validate::validate(Request::post('mailbody'), 'mailbody', '/^[^\0]+$/', 'nomailbodycreate'); $mailbody = Validate::validate($_POST['mailbody'], 'mailbody', '/^[^\0]+$/', 'nomailbodycreate');
$upd_stmt = Database::prepare(" $upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET
@@ -551,8 +550,8 @@ if ($action == '') {
$row = $result_stmt->fetch(PDO::FETCH_ASSOC); $row = $result_stmt->fetch(PDO::FETCH_ASSOC);
// filetemplates // filetemplates
if (Request::post('filesend') == 'filesend') { if (isset($_POST['filesend']) && $_POST['filesend'] == 'filesend') {
$filecontent = Validate::validate(Request::post('filecontent'), 'filecontent', '/^[^\0]+$/', 'filecontentnotset'); $filecontent = Validate::validate($_POST['filecontent'], 'filecontent', '/^[^\0]+$/', 'filecontentnotset');
$upd_stmt = Database::prepare(" $upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET
`value` = :value `value` = :value

View File

@@ -34,7 +34,6 @@ use Froxlor\Install\Update;
use Froxlor\Settings; use Froxlor\Settings;
use Froxlor\System\Cronjob; use Froxlor\System\Cronjob;
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;
@@ -49,8 +48,8 @@ if ($page == 'overview') {
$successful_update = false; $successful_update = false;
$message = ''; $message = '';
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
if ((!empty(Request::post('update_preconfig')) && intval(Request::post('update_changesagreed', 0)) != 0) || empty(Request::post('update_preconfig'))) { if ((isset($_POST['update_preconfig']) && isset($_POST['update_changesagreed']) && intval($_POST['update_changesagreed']) != 0) || !isset($_POST['update_preconfig'])) {
include_once Froxlor::getInstallDir() . 'install/updatesql.php'; include_once Froxlor::getInstallDir() . 'install/updatesql.php';
User::updateCounters(); User::updateCounters();

View File

@@ -61,7 +61,7 @@ if ($action == 'delete' && $id > 0) {
'section' => 'index', 'section' => 'index',
'page' => $page 'page' => $page
]); ]);
} elseif (Request::post('send') == 'send' && $action == 'deletesure' && $id > 0) { } elseif (isset($_POST['send']) && $_POST['send'] == 'send' && $action == 'deletesure' && $id > 0) {
$chk = (AREA == 'admin' && $userinfo['customers_see_all'] == '1') ? true : false; $chk = (AREA == 'admin' && $userinfo['customers_see_all'] == '1') ? true : false;
if (AREA == 'customer') { if (AREA == 'customer') {
$chk_stmt = Database::prepare(" $chk_stmt = Database::prepare("
@@ -94,7 +94,7 @@ if ($action == 'delete' && $id > 0) {
]); ]);
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$ins_stmt = Database::prepare(" $ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_API_KEYS . "` SET INSERT INTO `" . TABLE_API_KEYS . "` SET
`apikey` = :key, `secret` = :secret, `adminid` = :aid, `customerid` = :cid, `valid_until` = '-1', `allowed_from` = '' `apikey` = :key, `secret` = :secret, `adminid` = :aid, `customerid` = :cid, `valid_until` = '-1', `allowed_from` = ''

View File

@@ -24,8 +24,20 @@
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2 * @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/ */
use Froxlor\Froxlor; declare(strict_types=1);
use Froxlor\Cli\ConfigDiff;
use Symfony\Component\Console\Application; use Symfony\Component\Console\Application;
use Froxlor\Cli\RunApiCommand;
use Froxlor\Cli\ConfigServices;
use Froxlor\Cli\PhpSessionclean;
use Froxlor\Cli\SwitchServerIp;
use Froxlor\Cli\UpdateCommand;
use Froxlor\Cli\InstallCommand;
use Froxlor\Cli\MasterCron;
use Froxlor\Cli\UserCommand;
use Froxlor\Cli\ValidateAcmeWebroot;
use Froxlor\Froxlor;
// validate correct php version // validate correct php version
if (version_compare("7.4.0", PHP_VERSION, ">=")) { if (version_compare("7.4.0", PHP_VERSION, ">=")) {
@@ -41,31 +53,14 @@ 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());
// files that are no commands $application->add(new ConfigServices());
$fileIgnoreList = [ $application->add(new PhpSessionclean());
// Current non-command files $application->add(new SwitchServerIp());
'CliCommand.php', $application->add(new UpdateCommand());
'index.html', $application->add(new InstallCommand());
'install.functions.php', $application->add(new MasterCron());
]; $application->add(new UserCommand());
// directory of commands to include $application->add(new ValidateAcmeWebroot());
$cmd_files = glob(Froxlor::getInstallDir() . '/lib/Froxlor/Cli/*.php'); $application->add(new ConfigDiff());
// 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();

View File

@@ -46,17 +46,15 @@
"ext-fileinfo": "*", "ext-fileinfo": "*",
"ext-gmp": "*", "ext-gmp": "*",
"ext-gd": "*", "ext-gd": "*",
"ext-gnupg": "*",
"phpmailer/phpmailer": "~6.0", "phpmailer/phpmailer": "~6.0",
"monolog/monolog": "^1.24", "monolog/monolog": "^1.24",
"robthree/twofactorauth": "^1.6", "robthree/twofactorauth": "^1.6",
"froxlor/idna-convert-legacy": "^2.1", "froxlor/idna-convert-legacy": "^2.1",
"voku/anti-xss": "^4.1", "voku/anti-xss": "^4.1",
"twig/twig": "^3.3", "twig/twig": "^3.3",
"erusev/parsedown": "^1.7",
"symfony/console": "^5.4", "symfony/console": "^5.4",
"pear/net_dns2": "^1.5", "pear/net_dns2": "^1.5"
"amnuts/opcache-gui": "^3.4",
"league/commonmark": "^2.4"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^9", "phpunit/phpunit": "^9",

1184
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,8 +26,7 @@
const AREA = 'customer'; const AREA = 'customer';
require __DIR__ . '/lib/init.php'; require __DIR__ . '/lib/init.php';
use Froxlor\Api\Commands\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;
@@ -41,6 +40,7 @@ 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_INFO, "viewed customer_domains::domains"); $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_domains::domains");
$parentdomain_id = (int)Request::any('pid', '0'); $parentdomain_id = (int)Request::any('pid', '0');
@@ -63,32 +63,20 @@ if ($page == 'overview' || $page == 'domains') {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
$actions_links = []; $actions_links = false;
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')
]
]; ];
} }
$actions_links[] = [ UI::view('user/table.html.twig', [
'href' => \Froxlor\Froxlor::getDocsUrl() . '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 {
@@ -106,9 +94,9 @@ if ($page == 'overview' || $page == 'domains') {
]); ]);
if (isset($result['parentdomainid']) && $result['parentdomainid'] != '0' && $alias_check['count'] == 0) { if (isset($result['parentdomainid']) && $result['parentdomainid'] != '0' && $alias_check['count'] == 0) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
SubDomains::getLocal($userinfo, Request::postAll())->delete(); SubDomains::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -127,9 +115,9 @@ if ($page == 'overview' || $page == 'domains') {
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if ($userinfo['subdomains_used'] < $userinfo['subdomains'] || $userinfo['subdomains'] == '-1') { if ($userinfo['subdomains_used'] < $userinfo['subdomains'] || $userinfo['subdomains'] == '-1') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
SubDomains::getLocal($userinfo, Request::postAll())->add(); SubDomains::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -142,7 +130,6 @@ 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']
@@ -152,14 +139,6 @@ 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
@@ -248,9 +227,9 @@ if ($page == 'overview' || $page == 'domains') {
Response::standardError('domaincannotbeedited', $result['domain']); Response::standardError('domaincannotbeedited', $result['domain']);
} }
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
SubDomains::getLocal($userinfo, Request::postAll())->update(); SubDomains::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -394,23 +373,6 @@ if ($page == 'overview' || $page == 'domains') {
} else { } else {
Response::standardError('domains_canteditdomain'); Response::standardError('domains_canteditdomain');
} }
} elseif ($action == 'jqSpeciallogfileNote') {
$domainid = intval(Request::post('id'));
$newval = intval(Request::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';

View File

@@ -27,11 +27,9 @@ const AREA = 'customer';
require __DIR__ . '/lib/init.php'; require __DIR__ . '/lib/init.php';
use Froxlor\Api\Commands\EmailAccounts; use Froxlor\Api\Commands\EmailAccounts;
use Froxlor\Api\Commands\EmailDomains;
use Froxlor\Api\Commands\EmailForwarders; use Froxlor\Api\Commands\EmailForwarders;
use Froxlor\Api\Commands\Emails; use Froxlor\Api\Commands\Emails;
use Froxlor\Cron\Mail\Rspamd; use Froxlor\Api\Commands\EmailDomains;
use Froxlor\CurrentUser;
use Froxlor\Database\Database; use Froxlor\Database\Database;
use Froxlor\FroxlorLogger; use Froxlor\FroxlorLogger;
use Froxlor\PhpHelper; use Froxlor\PhpHelper;
@@ -43,6 +41,7 @@ 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) {
@@ -68,24 +67,14 @@ if ($page == 'overview' || $page == 'emails') {
Response::dynamicError($e->getMessage()); 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::getDocsUrl() . '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, $emaildomain_list_data, 'emaildomain_list'), 'listing' => Listing::format($collection, $emaildomain_list_data, 'emaildomain_list'),
'actions_links' => $actions_links, 'actions_links' => CurrentUser::canAddResource('emails') ? [
[
'href' => $linker->getLink(['section' => 'email', 'page' => 'email_domain', 'action' => 'add']),
'label' => lng('emails.emails_add')
]
] : null,
]); ]);
} else { } else {
// only emails for one domain -> show email address listing directly // only emails for one domain -> show email address listing directly
@@ -95,7 +84,7 @@ if ($page == 'overview' || $page == 'emails') {
if ($page == 'email_domain') { if ($page == 'email_domain') {
$email_domainid = Request::any('domainid', 0); $email_domainid = Request::any('domainid', 0);
if ($action == '') { if ($action == '') {
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_email::emails"); $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_email::emails");
$sql_search = []; $sql_search = [];
if ($email_domainid > 0) { if ($email_domainid > 0) {
@@ -138,12 +127,6 @@ if ($page == 'email_domain') {
'label' => lng('emails.emails_add') 'label' => lng('emails.emails_add')
]; ];
} }
$actions_links[] = [
'href' => \Froxlor\Froxlor::getDocsUrl() . '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'),
@@ -161,11 +144,11 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['email']) && $result['email'] != '') { if (isset($result['email']) && $result['email'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Emails::getLocal($userinfo, [ Emails::getLocal($userinfo, [
'id' => $id, 'id' => $id,
'delete_userfiles' => Request::post('delete_userfiles', 0) 'delete_userfiles' => ($_POST['delete_userfiles'] ?? 0)
])->delete(); ])->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
@@ -188,9 +171,9 @@ if ($page == 'email_domain') {
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if ($userinfo['emails_used'] < $userinfo['emails'] || $userinfo['emails'] == '-1') { if ($userinfo['emails_used'] < $userinfo['emails'] || $userinfo['emails'] == '-1') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
$json_result = Emails::getLocal($userinfo, Request::postAll())->add(); $json_result = Emails::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -245,12 +228,7 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['email']) && $result['email'] != '') { if (isset($result['email']) && $result['email'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Emails::getLocal($userinfo, Request::postAll())->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
Response::redirectTo($filename, [ Response::redirectTo($filename, [
'page' => $page 'page' => $page
]); ]);
@@ -287,12 +265,64 @@ if ($page == 'email_domain') {
$email_edit_data = include_once dirname(__FILE__) . '/lib/formfields/customer/email/formfield.emails_edit.php'; $email_edit_data = include_once dirname(__FILE__) . '/lib/formfields/customer/email/formfield.emails_edit.php';
if (Settings::Get('catchall.catchall_enabled') != '1') {
unset($email_edit_data['emails_edit']['sections']['section_a']['fields']['mail_catchall']);
}
UI::view('user/form.html.twig', [ UI::view('user/form.html.twig', [
'formaction' => $linker->getLink(['section' => 'email']), 'formaction' => $linker->getLink(['section' => 'email']),
'formdata' => $email_edit_data['emails_edit'], 'formdata' => $email_edit_data['emails_edit'],
'editid' => $id 'editid' => $id
]); ]);
} }
} elseif ($action == 'togglecatchall' && $id != 0) {
try {
$json_result = Emails::getLocal($userinfo, [
'id' => $id
])->get();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
try {
Emails::getLocal($userinfo, [
'id' => $id,
'iscatchall' => ($result['iscatchall'] == '1' ? 0 : 1)
])->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
Response::redirectTo($filename, [
'page' => $page,
'domainid' => $email_domainid,
'action' => 'edit',
'id' => $id,
]);
} elseif ($action == 'togglegreylist' && $id != 0) {
try {
$json_result = Emails::getLocal($userinfo, [
'id' => $id
])->get();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
try {
Emails::getLocal($userinfo, [
'id' => $id,
'disablegreylist' => ($result['disablegreylist'] == '1' ? 0 : 1)
])->updateGreylist();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
Response::redirectTo($filename, [
'page' => $page,
'domainid' => $email_domainid,
'action' => 'edit',
'id' => $id,
]);
} }
} elseif ($page == 'accounts') { } elseif ($page == 'accounts') {
$email_domainid = Request::any('domainid', 0); $email_domainid = Request::any('domainid', 0);
@@ -307,9 +337,9 @@ if ($page == 'email_domain') {
} }
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
EmailAccounts::getLocal($userinfo, Request::postAll())->add(); EmailAccounts::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -378,9 +408,9 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['popaccountid']) && $result['popaccountid'] != '') { if (isset($result['popaccountid']) && $result['popaccountid'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
EmailAccounts::getLocal($userinfo, Request::postAll())->update(); EmailAccounts::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -437,9 +467,9 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['popaccountid']) && $result['popaccountid'] != '') { if (isset($result['popaccountid']) && $result['popaccountid'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
EmailAccounts::getLocal($userinfo, Request::postAll())->update(); EmailAccounts::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -496,9 +526,9 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['popaccountid']) && $result['popaccountid'] != '') { if (isset($result['popaccountid']) && $result['popaccountid'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
EmailAccounts::getLocal($userinfo, Request::postAll())->delete(); EmailAccounts::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -532,9 +562,9 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['email']) && $result['email'] != '') { if (isset($result['email']) && $result['email'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
EmailForwarders::getLocal($userinfo, Request::postAll())->add(); EmailForwarders::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -594,15 +624,22 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['destination']) && $result['destination'] != '') { if (isset($result['destination']) && $result['destination'] != '') {
$forwarderid = Request::any('forwarderid', 0); if (isset($_POST['forwarderid'])) {
$forwarderid = intval($_POST['forwarderid']);
} elseif (isset($_GET['forwarderid'])) {
$forwarderid = intval($_GET['forwarderid']);
} else {
$forwarderid = 0;
}
$result['destination'] = explode(' ', $result['destination']); $result['destination'] = explode(' ', $result['destination']);
if (isset($result['destination'][$forwarderid]) && $result['email'] != $result['destination'][$forwarderid]) { if (isset($result['destination'][$forwarderid]) && $result['email'] != $result['destination'][$forwarderid]) {
$forwarder = $result['destination'][$forwarderid]; $forwarder = $result['destination'][$forwarderid];
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
EmailForwarders::getLocal($userinfo, Request::postAll())->delete(); EmailForwarders::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }

View File

@@ -26,7 +26,7 @@
const AREA = 'customer'; const AREA = 'customer';
require __DIR__ . '/lib/init.php'; require __DIR__ . '/lib/init.php';
use Froxlor\Api\Commands\DataDump as DataDump; use Froxlor\Api\Commands\CustomerBackups as CustomerBackups;
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,22 +68,14 @@ 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::getDocsUrl() . '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) {
@@ -97,9 +89,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['username']) && $result['username'] != '') { if (isset($result['username']) && $result['username'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
DirProtections::getLocal($userinfo, Request::postAll())->delete(); DirProtections::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -119,9 +111,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
} }
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
DirProtections::getLocal($userinfo, Request::postAll())->add(); DirProtections::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -149,9 +141,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['username']) && $result['username'] != '') { if (isset($result['username']) && $result['username'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
DirProtections::getLocal($userinfo, Request::postAll())->update(); DirProtections::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -193,22 +185,14 @@ 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::getDocsUrl() . '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) {
@@ -222,9 +206,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['customerid']) && $result['customerid'] != '' && $result['customerid'] == $userinfo['customerid']) { if (isset($result['customerid']) && $result['customerid'] != '' && $result['customerid'] == $userinfo['customerid']) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
DirOptions::getLocal($userinfo, Request::postAll())->delete(); DirOptions::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -240,9 +224,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
} }
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
DirOptions::getLocal($userinfo, Request::postAll())->add(); DirOptions::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -271,9 +255,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if ((isset($result['customerid'])) && ($result['customerid'] != '') && ($result['customerid'] == $userinfo['customerid'])) { if ((isset($result['customerid'])) && ($result['customerid'] != '') && ($result['customerid'] == $userinfo['customerid'])) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
DirOptions::getLocal($userinfo, Request::postAll())->update(); DirOptions::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -298,18 +282,18 @@ if ($page == 'overview' || $page == 'htpasswds') {
} }
} }
} }
} elseif ($page == 'export') { } elseif ($page == 'backup') {
// 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.export')) { if (Settings::IsInList('panel.customer_hide_options', 'extras.backup')) {
Response::redirectTo('customer_index.php'); Response::redirectTo('customer_index.php');
} }
if (Settings::Get('system.exportenabled') == 1) { if (Settings::Get('system.backupenabled') == 1) {
if ($action == 'abort') { if ($action == 'abort') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "customer_extras::export - aborted scheduled data export job"); $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "customer_extras::backup - aborted scheduled backupjob");
try { try {
DataDump::getLocal($userinfo, Request::postAll())->delete(); CustomerBackups::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -318,53 +302,43 @@ if ($page == 'overview' || $page == 'htpasswds') {
'action' => '' 'action' => ''
]); ]);
} else { } else {
HTML::askYesNo('extras_reallydelete_export', $filename, [ HTML::askYesNo('extras_reallydelete_backup', $filename, [
'job_entry' => $id, 'backup_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_INFO, "viewed customer_extras::export"); $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_extras::backup");
// check whether there is a backup-job for this customer // check whether there is a backup-job for this customer
try { try {
$export_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.export.php'; $backup_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.backups.php';
$collection = (new Collection(DataDump::class, $userinfo)); $collection = (new Collection(CustomerBackups::class, $userinfo));
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
DataDump::getLocal($userinfo, Request::postAll())->add(); CustomerBackups::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
Response::standardSuccess('exportscheduled'); Response::standardSuccess('backupscheduled');
} else { } else {
$pathSelect = FileDir::makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']); $pathSelect = FileDir::makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']);
$export_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.export.php'; $backup_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.backup.php';
$actions_links = [
[
'href' => \Froxlor\Froxlor::getDocsUrl() . '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' => $export_data['export'], 'formdata' => $backup_data['backup'],
'actions_links' => $actions_links, 'tabledata' => Listing::format($collection, $backup_list_data, 'backup_list'),
'tabledata' => Listing::format($collection, $export_list_data, 'export_list'),
]); ]);
} }
} }
} else { } else {
Response::standardError('exportfunctionnotenabled'); Response::standardError('backupfunctionnotenabled');
} }
} }

View File

@@ -27,7 +27,6 @@ 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;
@@ -38,6 +37,7 @@ use Froxlor\UI\Listing;
use Froxlor\UI\Panel\UI; use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request; use Froxlor\UI\Request;
use Froxlor\UI\Response; use Froxlor\UI\Response;
use Froxlor\CurrentUser;
// redirect if this customer page is hidden via settings // redirect if this customer page is hidden via settings
if (Settings::IsInList('panel.customer_hide_options', 'ftp')) { if (Settings::IsInList('panel.customer_hide_options', 'ftp')) {
@@ -57,19 +57,15 @@ if ($page == 'overview' || $page == 'accounts') {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
$actions_links = []; $actions_links = false;
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::getDocsUrl() . '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'),
@@ -87,9 +83,9 @@ if ($page == 'overview' || $page == 'accounts') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['username']) && $result['username'] != $userinfo['loginname']) { if (isset($result['username']) && $result['username'] != $userinfo['loginname']) {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Ftps::getLocal($userinfo, Request::postAll())->delete(); Ftps::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -108,9 +104,9 @@ if ($page == 'overview' || $page == 'accounts') {
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if ($userinfo['ftps_used'] < $userinfo['ftps'] || $userinfo['ftps'] == '-1') { if ($userinfo['ftps_used'] < $userinfo['ftps'] || $userinfo['ftps'] == '-1') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Ftps::getLocal($userinfo, Request::postAll())->add(); Ftps::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -164,9 +160,9 @@ if ($page == 'overview' || $page == 'accounts') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['username']) && $result['username'] != '') { if (isset($result['username']) && $result['username'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Ftps::getLocal($userinfo, Request::postAll())->update(); Ftps::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }

View File

@@ -27,23 +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\Database\DbManager;
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\Request;
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_INFO, 'logged out'); $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'logged out');
unset($_SESSION['userinfo']); unset($_SESSION['userinfo']);
CurrentUser::setData(); CurrentUser::setData();
@@ -56,7 +54,7 @@ if ($action == 'logout') {
$result = $result['switched_user']; $result = $result['switched_user'];
session_regenerate_id(true); session_regenerate_id(true);
CurrentUser::setData($result); CurrentUser::setData($result);
$target = Request::get('target', 'index'); $target = (isset($_GET['target']) ? $_GET['target'] : 'index');
$redirect = "admin_" . $target . ".php"; $redirect = "admin_" . $target . ".php";
if (!file_exists(Froxlor::getInstallDir() . "/" . $redirect)) { if (!file_exists(Froxlor::getInstallDir() . "/" . $redirect)) {
$redirect = "admin_index.php"; $redirect = "admin_index.php";
@@ -68,7 +66,7 @@ if ($action == 'logout') {
} }
if ($page == 'overview') { if ($page == 'overview') {
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_index"); $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "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
@@ -116,11 +114,6 @@ if ($page == 'overview') {
$userinfo['traffic_bytes'] = ($userinfo['traffic'] > -1) ? $userinfo['traffic'] * 1024 : -1; $userinfo['traffic_bytes'] = ($userinfo['traffic'] > -1) ? $userinfo['traffic'] * 1024 : -1;
$userinfo['traffic_bytes_used'] = $userinfo['traffic_used'] * 1024; $userinfo['traffic_bytes_used'] = $userinfo['traffic_used'] * 1024;
if (Settings::Get('system.mail_quota_enabled')) {
$userinfo['email_quota_bytes'] = ($userinfo['email_quota'] > -1) ? $userinfo['email_quota'] * 1024 * 1024 : -1;
$userinfo['email_quota_bytes_used'] = $userinfo['email_quota_used'] * 1024 * 1024;
}
if ($usages) { if ($usages) {
$userinfo['diskspace_bytes_used'] = $usages['webspace'] * 1024; $userinfo['diskspace_bytes_used'] = $usages['webspace'] * 1024;
$userinfo['mailspace_used'] = $usages['mail'] * 1024; $userinfo['mailspace_used'] = $usages['mail'] * 1024;
@@ -138,20 +131,17 @@ if ($page == 'overview') {
'domains' => $domainArray, 'domains' => $domainArray,
'stdsubdomain' => $stdsubdomain 'stdsubdomain' => $stdsubdomain
]); ]);
} elseif ($page == 'profile') { } elseif ($page == 'change_password') {
$languages = Language::getLanguages(); if (isset($_POST['send']) && $_POST['send'] == 'send') {
$old_password = Validate::validate($_POST['old_password'], 'old password');
if (!empty($_POST)) {
if (Request::post('send') == 'changepassword') {
$old_password = Validate::validate(Request::post('old_password'), 'old password');
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) { if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) {
Response::standardError('oldpasswordnotcorrect'); Response::standardError('oldpasswordnotcorrect');
} }
try { try {
$new_password = Crypt::validatePassword(Request::post('new_password'), 'new password'); $new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
$new_password_confirm = Crypt::validatePassword(Request::post('new_password_confirm'), 'new password confirm'); $new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -186,7 +176,7 @@ if ($page == 'overview') {
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed password'); $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed password');
// Update ftp password // Update ftp password
if (Request::post('change_main_ftp') == 'true') { if (isset($_POST['change_main_ftp']) && $_POST['change_main_ftp'] == 'true') {
$cryptPassword = Crypt::makeCryptPassword($new_password); $cryptPassword = Crypt::makeCryptPassword($new_password);
$stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "` $stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "`
SET `password` = :password SET `password` = :password
@@ -202,7 +192,7 @@ if ($page == 'overview') {
} }
// Update statistics password // Update statistics password
if (Request::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 . "`
@@ -218,46 +208,15 @@ if ($page == 'overview') {
Cronjob::inserttask(TaskId::REBUILD_VHOST); Cronjob::inserttask(TaskId::REBUILD_VHOST);
} }
// Update global myqsl user password Response::redirectTo($filename);
if ($userinfo['mysqls'] != 0 && Request::post('change_global_mysql') == 'true') { }
$allowed_mysqlservers = json_decode($userinfo['allowed_mysqlserver'] ?? '[]', true);
foreach ($allowed_mysqlservers as $dbserver) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver, false);
// get DbManager
$dbm = new DbManager($log);
// give permission to the user on every access-host we have
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
if ($dbm->getManager()->userExistsOnHost($userinfo['loginname'], $mysql_access_host)) {
$dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, true);
} else { } else {
// create global mysql user if not exists UI::view('user/change_password.html.twig');
$dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, false, true);
} }
} } elseif ($page == 'change_language') {
$dbm->getManager()->flushPrivileges(); $languages = Language::getLanguages();
} if (isset($_POST['send']) && $_POST['send'] == 'send') {
} $def_language = Validate::validate($_POST['def_language'], 'default language');
Response::redirectTo($filename);
}
} elseif (Request::post('send') == 'changetheme') {
if (Settings::Get('panel.allow_theme_change_customer') == 1) {
$theme = Validate::validate(Request::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 (Request::post('send') == 'changelanguage') {
$def_language = Validate::validate(Request::post('def_language'), 'default language');
if (isset($languages[$def_language])) { if (isset($languages[$def_language])) {
try { try {
Customers::getLocal($userinfo, [ Customers::getLocal($userinfo, [
@@ -271,26 +230,42 @@ if ($page == 'overview') {
} }
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default language to '" . $def_language . "'"); $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default language to '" . $def_language . "'");
Response::redirectTo($filename); Response::redirectTo($filename);
}
} else { } else {
// change theme
$default_theme = Settings::Get('panel.default_theme');
if ($userinfo['theme'] != '') {
$default_theme = $userinfo['theme'];
}
$themes_avail = UI::getThemes();
// change language
$default_lang = Settings::Get('panel.standardlanguage'); $default_lang = Settings::Get('panel.standardlanguage');
if ($userinfo['def_language'] != '') { if ($userinfo['def_language'] != '') {
$default_lang = $userinfo['def_language']; $default_lang = $userinfo['def_language'];
} }
UI::view('user/profile.html.twig', [ UI::view('user/change_language.html.twig', [
'themes' => $themes_avail,
'default_theme' => $default_theme,
'languages' => $languages, 'languages' => $languages,
'default_lang' => $default_lang, '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,
'default_theme' => $default_theme
]); ]);
} }
} 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') {

View File

@@ -28,18 +28,16 @@ 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\Database\DbManager;
use Froxlor\FroxlorLogger; use Froxlor\FroxlorLogger;
use Froxlor\Settings; use Froxlor\Settings;
use Froxlor\System\Crypt;
use Froxlor\UI\Collection; use Froxlor\UI\Collection;
use Froxlor\UI\HTML; use Froxlor\UI\HTML;
use Froxlor\UI\Listing; 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) {
@@ -68,40 +66,20 @@ if ($page == 'overview' || $page == 'mysqls') {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
$actions_links = []; $actions_links = false;
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')
]
]; ];
} }
$view = 'user/table.html.twig'; UI::view('user/table.html.twig', [
if ($collection->count() > 0) {
$view = 'user/table-note.html.twig';
$actions_links[] = [
'href' => $linker->getLink(['section' => 'mysql', 'page' => 'mysqls', 'action' => 'global_user']),
'label' => lng('mysql.edit_global_user'),
'icon' => 'fa-solid fa-user-tie',
'class' => 'btn-outline-secondary'
];
}
$actions_links[] = [
'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/databases/',
'target' => '_blank',
'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary'
];
UI::view($view, [
'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,
'entity_info' => lng('mysql.description'), 'entity_info' => lng('mysql.description')
// alert-box
'type' => 'info',
'alert_msg' => lng('mysql.globaluserinfo', [$userinfo['loginname']]),
]); ]);
} elseif ($action == 'delete' && $id != 0) { } elseif ($action == 'delete' && $id != 0) {
try { try {
@@ -123,9 +101,9 @@ if ($page == 'overview' || $page == 'mysqls') {
$result['dbserver'] = 0; $result['dbserver'] = 0;
} }
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Mysqls::getLocal($userinfo, Request::postAll())->delete(); Mysqls::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -146,9 +124,9 @@ if ($page == 'overview' || $page == 'mysqls') {
} }
} elseif ($action == 'add') { } elseif ($action == 'add') {
if ($userinfo['mysqls_used'] < $userinfo['mysqls'] || $userinfo['mysqls'] == '-1') { if ($userinfo['mysqls_used'] < $userinfo['mysqls'] || $userinfo['mysqls'] == '-1') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
Mysqls::getLocal($userinfo, Request::postAll())->add(); Mysqls::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -186,9 +164,9 @@ if ($page == 'overview' || $page == 'mysqls') {
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
if (isset($result['databasename']) && $result['databasename'] != '') { if (isset($result['databasename']) && $result['databasename'] != '') {
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
try { try {
$json_result = Mysqls::getLocal($userinfo, Request::postAll())->update(); $json_result = Mysqls::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) { } catch (Exception $e) {
Response::dynamicError($e->getMessage()); Response::dynamicError($e->getMessage());
} }
@@ -216,45 +194,5 @@ if ($page == 'overview' || $page == 'mysqls') {
]); ]);
} }
} }
} elseif ($action == 'global_user') {
$allowed_mysqlservers = json_decode($userinfo['allowed_mysqlserver'] ?? '[]', true);
if ($userinfo['mysqls'] == 0 || empty($allowed_mysqlservers)) {
Response::dynamicError('No permission');
}
if (Request::post('send') == 'send') {
$new_password = Crypt::validatePassword(Request::post('mysql_password'));
foreach ($allowed_mysqlservers as $dbserver) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver, false);
// get DbManager
$dbm = new DbManager($log);
// give permission to the user on every access-host we have
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
if ($dbm->getManager()->userExistsOnHost($userinfo['loginname'], $mysql_access_host)) {
// update password
$dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, true, true);
} else {
// create missing user
$dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, false, true);
}
}
$dbm->getManager()->flushPrivileges();
}
Response::redirectTo($filename, [
'page' => 'overview'
]);
} else {
$mysql_global_user_data = include_once dirname(__FILE__) . '/lib/formfields/customer/mysql/formfield.mysql_global_user.php';
UI::view('user/form.html.twig', [
'formaction' => $linker->getLink(['section' => 'mysql', 'page' => 'mysqls', 'action' => 'global_user']),
'formdata' => $mysql_global_user_data['mysql_global_user'],
'editid' => $id
]);
}
} }
} }

View File

@@ -30,7 +30,6 @@ if (!defined('AREA')) {
use Froxlor\Api\Commands\DomainZones; use Froxlor\Api\Commands\DomainZones;
use Froxlor\Dns\Dns; use Froxlor\Dns\Dns;
use Froxlor\Settings;
use Froxlor\UI\Collection; use Froxlor\UI\Collection;
use Froxlor\UI\HTML; use Froxlor\UI\HTML;
use Froxlor\UI\Listing; use Froxlor\UI\Listing;
@@ -43,11 +42,11 @@ use Froxlor\UI\Response;
$domain_id = (int)Request::any('domain_id'); $domain_id = (int)Request::any('domain_id');
$record = Request::post('dns_record'); $record = isset($_POST['dns_record']) ? trim($_POST['dns_record']) : null;
$type = Request::post('dns_type', 'A'); $type = isset($_POST['dns_type']) ? $_POST['dns_type'] : 'A';
$prio = Request::post('dns_mxp'); $prio = isset($_POST['dns_mxp']) ? (int)$_POST['dns_mxp'] : null;
$content = Request::post('dns_content'); $content = isset($_POST['dns_content']) ? trim($_POST['dns_content']) : null;
$ttl = (int)Request::post('dns_ttl', Settings::get('system.defaultttl')); $ttl = isset($_POST['dns_ttl']) ? (int)$_POST['dns_ttl'] : 18000;
// get domain-name // get domain-name
$domain = Dns::getAllowedDomainEntry($domain_id, AREA, $userinfo); $domain = Dns::getAllowedDomainEntry($domain_id, AREA, $userinfo);
@@ -72,7 +71,7 @@ if ($action == 'add_record' && !empty($_POST)) {
$errors = str_replace("\n", "<br>", $e->getMessage()); $errors = str_replace("\n", "<br>", $e->getMessage());
} }
} elseif ($action == 'delete') { } elseif ($action == 'delete') {
$entry_id = (int)Request::get('id', 0); $entry_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
HTML::askYesNo('dnsentry_reallydelete', $filename, [ HTML::askYesNo('dnsentry_reallydelete', $filename, [
'id' => $entry_id, 'id' => $entry_id,
'domain_id' => $domain_id, 'domain_id' => $domain_id,
@@ -83,9 +82,9 @@ if ($action == 'add_record' && !empty($_POST)) {
'page' => $page, 'page' => $page,
'domain_id' => $domain_id 'domain_id' => $domain_id
]); ]);
} elseif (Request::post('send') == 'send' && $action == 'deletesure' && !empty($_POST)) { } elseif (isset($_POST['send']) && $_POST['send'] == 'send' && $action == 'deletesure' && !empty($_POST)) {
$entry_id = (int)Request::post('id', 0); $entry_id = isset($_POST['id']) ? (int)$_POST['id'] : 0;
$domain_id = (int)Request::post('domain_id', 0); $domain_id = isset($_POST['domain_id']) ? (int)$_POST['domain_id'] : 0;
// remove entry // remove entry
if ($entry_id > 0 && $domain_id > 0) { if ($entry_id > 0 && $domain_id > 0) {
try { try {

View File

@@ -77,7 +77,7 @@ if (!empty($errid)) {
$mail_html = nl2br($mail_body); $mail_html = nl2br($mail_body);
// send actual report to dev-team // send actual report to dev-team
if (Request::post('send') == 'send') { if (isset($_POST['send']) && $_POST['send'] == 'send') {
// send mail and say thanks // send mail and say thanks
$_mailerror = false; $_mailerror = false;
try { try {

263
index.php
View File

@@ -26,7 +26,6 @@
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;
@@ -38,7 +37,6 @@ 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;
@@ -54,7 +52,7 @@ if ($action == '2fa_entercode') {
Response::redirectTo('index.php'); Response::redirectTo('index.php');
exit(); exit();
} }
$smessage = (int)Request::get('showmessage', 0); $smessage = isset($_GET['showmessage']) ? (int)$_GET['showmessage'] : 0;
$message = ""; $message = "";
if ($smessage > 0) { if ($smessage > 0) {
$message = lng('error.2fa_wrongcode'); $message = lng('error.2fa_wrongcode');
@@ -62,7 +60,6 @@ if ($action == '2fa_entercode') {
// 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'),
'remember_me' => (Settings::Get('panel.db_version') >= 202407200) ? true : false,
'message' => $message 'message' => $message
]); ]);
} elseif ($action == '2fa_verify') { } elseif ($action == '2fa_verify') {
@@ -72,31 +69,30 @@ if ($action == '2fa_entercode') {
Response::redirectTo('index.php'); Response::redirectTo('index.php');
exit(); exit();
} }
$code = Request::post('2fa_code'); $code = isset($_POST['2fa_code']) ? $_POST['2fa_code'] : null;
$remember = Request::post('2fa_remember');
// verify entered code // verify entered code
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname')); $tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
$result = ($_SESSION['secret_2fa'] == 'email' ? true : $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3));
// get user-data // get user-data
$table = $_SESSION['uidtable_2fa']; $table = $_SESSION['uidtable_2fa'];
$field = $_SESSION['uidfield_2fa']; $field = $_SESSION['uidfield_2fa'];
$uid = $_SESSION['uid_2fa']; $uid = $_SESSION['uid_2fa'];
$isadmin = $_SESSION['unfo_2fa']; $isadmin = $_SESSION['unfo_2fa'];
if ($_SESSION['secret_2fa'] == 'email') {
// verify code set to user's data_2fa field
$sel_stmt = Database::prepare("SELECT `data_2fa` FROM " . $table . " WHERE `" . $field . "` = :uid");
$userinfo_code = Database::pexecute_first($sel_stmt, ['uid' => $uid]);
// 60sec discrepancy (possible slow email delivery)
$result = $tfa->verifyCode($userinfo_code['data_2fa'], $code, 60);
} else {
$result = $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3);
}
// either the code is valid when using authenticator-app, or we will select userdata by id and entered code // either the code is valid when using authenticator-app, or we will select userdata by id and entered code
// which is temporarily stored for the customer when using email-2fa // which is temporarily stored for the customer when using email-2fa
if ($result) { if ($result) {
$sel_param = [ $sel_param = [
'uid' => $uid 'uid' => $uid
]; ];
if ($_SESSION['secret_2fa'] == 'email') {
// verify code by selecting user by id and the temp. stored code,
// so only if it's the correct code, we get the user-data
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid AND `data_2fa` = :code");
$sel_param['code'] = $code;
} else {
// Authenticator-verification has already happened at this point, so just get the user-data
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid"); $sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid");
}
$userinfo = Database::pexecute_first($sel_stmt, $sel_param); $userinfo = Database::pexecute_first($sel_stmt, $sel_param);
// whoops, no (valid) user? Start again // whoops, no (valid) user? Start again
if (empty($userinfo)) { if (empty($userinfo)) {
@@ -108,49 +104,20 @@ if ($action == '2fa_entercode') {
$userinfo['adminsession'] = $isadmin; $userinfo['adminsession'] = $isadmin;
$userinfo['userid'] = $uid; $userinfo['userid'] = $uid;
// when using email-2fa, remove the one-time-code
if ($userinfo['type_2fa'] == '1') {
$del_stmt = Database::prepare("UPDATE " . $table . " SET `data_2fa` = '' WHERE `" . $field . "` = :uid");
Database::pexecute_first($del_stmt, [
'uid' => $uid
]);
}
// when remember is activated, set the cookie
if ($remember) {
$selector = base64_encode(Froxlor::genSessionId(9));
$authenticator = Froxlor::genSessionId(33);
$valid_until = time()+60*60*24*30;
$ins_stmt = Database::prepare("
INSERT INTO `".TABLE_PANEL_2FA_TOKENS."` SET
`selector` = :selector,
`token` = :authenticator,
`userid` = :userid,
`valid_until` = :valid_until
");
Database::pexecute($ins_stmt, [
'selector' => $selector,
'authenticator' => hash('sha256', $authenticator),
'userid' => $uid,
'valid_until' => $valid_until
]);
$cookie_params = [
'expires' => $valid_until, // 30 days
'path' => '/',
'domain' => UI::getCookieHost(),
'secure' => UI::requestIsHttps(),
'httponly' => true,
'samesite' => 'Strict'
];
setcookie('frx_2fa_remember', $selector.':'.base64_encode($authenticator), $cookie_params);
}
// if not successful somehow - start again // if not successful somehow - start again
if (!finishLogin($userinfo)) { if (!finishLogin($userinfo)) {
Response::redirectTo('index.php', [ Response::redirectTo('index.php', [
'showmessage' => '2' 'showmessage' => '2'
]); ]);
} }
// when using email-2fa, remove the one-time-code
if ($userinfo['type_2fa'] == '1') {
$del_stmt = Database::prepare("UPDATE " . $table . " SET `data_2fa` = '' WHERE `" . $field . "` = :uid");
$userinfo = Database::pexecute_first($del_stmt, [
'uid' => $uid
]);
}
exit(); exit();
} }
// wrong 2fa code - treat like "wrong password" // wrong 2fa code - treat like "wrong password"
@@ -194,41 +161,30 @@ if ($action == '2fa_entercode') {
exit(); exit();
} elseif ($action == 'login') { } elseif ($action == 'login') {
if (!empty($_POST)) { if (!empty($_POST)) {
$loginname = Validate::validate(Request::post('loginname'), 'loginname'); $loginname = Validate::validate($_POST['loginname'], 'loginname');
$password = Validate::validate(Request::post('password'), 'password'); $password = Validate::validate($_POST['password'], 'password');
$select_additional = ''; $stmt = Database::prepare("SELECT `loginname` AS `customer` FROM `" . TABLE_PANEL_CUSTOMERS . "`
if (Settings::Get('panel.db_version') >= 202312230) { WHERE `loginname`= :loginname");
$select_additional = ' AND `gui_access` = 1';
}
$stmt = Database::prepare("
SELECT `loginname` AS `customer`
FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE `loginname`= :loginname" .
$select_additional
);
Database::pexecute($stmt, [ Database::pexecute($stmt, [
"loginname" => $loginname "loginname" => $loginname
]); ]);
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
$is_admin = false;
$table = "";
if ($row && $row['customer'] == $loginname) { if ($row && $row['customer'] == $loginname) {
$table = "`" . TABLE_PANEL_CUSTOMERS . "`"; $table = "`" . TABLE_PANEL_CUSTOMERS . "`";
$uid = 'customerid'; $uid = 'customerid';
$adminsession = '0'; $adminsession = '0';
$is_admin = false;
} else { } else {
$is_admin = true;
if ((int)Settings::Get('login.domain_login') == 1) { if ((int)Settings::Get('login.domain_login') == 1) {
$domainname = $idna_convert->encode(preg_replace([ $domainname = $idna_convert->encode(preg_replace([
'/\:(\d)+$/', '/\:(\d)+$/',
'/^https?\:\/\//' '/^https?\:\/\//'
], '', $loginname)); ], '', $loginname));
$stmt = Database::prepare(" $stmt = Database::prepare("SELECT `customerid` FROM `" . TABLE_PANEL_DOMAINS . "`
SELECT `customerid` WHERE `domain` = :domain");
FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `domain` = :domain
");
Database::pexecute($stmt, [ Database::pexecute($stmt, [
"domain" => $domainname "domain" => $domainname
]); ]);
@@ -237,11 +193,8 @@ if ($action == '2fa_entercode') {
if (isset($row2['customerid']) && $row2['customerid'] > 0) { if (isset($row2['customerid']) && $row2['customerid'] > 0) {
$loginname = Customer::getCustomerDetail($row2['customerid'], 'loginname'); $loginname = Customer::getCustomerDetail($row2['customerid'], 'loginname');
if ($loginname !== false) { if ($loginname !== false) {
$stmt = Database::prepare(" $stmt = Database::prepare("SELECT `loginname` AS `customer` FROM `" . TABLE_PANEL_CUSTOMERS . "`
SELECT `loginname` AS `customer` WHERE `loginname`= :loginname");
FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE `loginname`= :loginname
");
Database::pexecute($stmt, [ Database::pexecute($stmt, [
"loginname" => $loginname "loginname" => $loginname
]); ]);
@@ -250,17 +203,13 @@ if ($action == '2fa_entercode') {
$table = "`" . TABLE_PANEL_CUSTOMERS . "`"; $table = "`" . TABLE_PANEL_CUSTOMERS . "`";
$uid = 'customerid'; $uid = 'customerid';
$adminsession = '0'; $adminsession = '0';
$is_admin = false;
} }
} }
} }
} }
} }
if (empty($table)) {
// try login as admin of no customer-login method worked
$is_admin = true;
}
if ((Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) && $is_admin == false) { if ((Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) && $is_admin == false) {
Response::redirectTo('index.php'); Response::redirectTo('index.php');
exit(); exit();
@@ -268,11 +217,9 @@ if ($action == '2fa_entercode') {
if ($is_admin) { if ($is_admin) {
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) { if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
$stmt = Database::prepare(" $stmt = Database::prepare("SELECT `loginname` AS `admin` FROM `" . TABLE_PANEL_ADMINS . "`
SELECT `loginname` AS `admin` FROM `" . TABLE_PANEL_ADMINS . "`
WHERE `loginname`= :loginname WHERE `loginname`= :loginname
AND `change_serversettings` = '1' AND `change_serversettings` = '1'");
");
Database::pexecute($stmt, [ Database::pexecute($stmt, [
"loginname" => $loginname "loginname" => $loginname
]); ]);
@@ -283,16 +230,8 @@ if ($action == '2fa_entercode') {
exit(); exit();
} }
} else { } else {
$select_additional = ''; $stmt = Database::prepare("SELECT `loginname` AS `admin` FROM `" . TABLE_PANEL_ADMINS . "`
if (Settings::Get('panel.db_version') >= 202312230) { WHERE `loginname`= :loginname");
$select_additional = ' AND `gui_access` = 1';
}
$stmt = Database::prepare("
SELECT `loginname` AS `admin`
FROM `" . TABLE_PANEL_ADMINS . "`
WHERE `loginname`= :loginname" .
$select_additional
);
Database::pexecute($stmt, [ Database::pexecute($stmt, [
"loginname" => $loginname "loginname" => $loginname
]); ]);
@@ -308,7 +247,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 tried to login."); $rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "Unknown user '" . $loginname . "' tried to login.");
Response::redirectTo('index.php', [ Response::redirectTo('index.php', [
'showmessage' => '2' 'showmessage' => '2'
@@ -317,9 +256,8 @@ if ($action == '2fa_entercode') {
} }
} }
$userinfo_stmt = Database::prepare(" $userinfo_stmt = Database::prepare("SELECT * FROM $table
SELECT * FROM $table WHERE `loginname`= :loginname WHERE `loginname`= :loginname");
");
Database::pexecute($userinfo_stmt, [ Database::pexecute($userinfo_stmt, [
"loginname" => $loginname "loginname" => $loginname
]); ]);
@@ -342,11 +280,9 @@ if ($action == '2fa_entercode') {
} else { } else {
// login correct // login correct
// reset loginfail_counter, set lastlogin_succ // reset loginfail_counter, set lastlogin_succ
$stmt = Database::prepare(" $stmt = Database::prepare("UPDATE $table
UPDATE $table
SET `lastlogin_succ`= :lastlogin_succ, `loginfail_count`='0' SET `lastlogin_succ`= :lastlogin_succ, `loginfail_count`='0'
WHERE `$uid`= :uid WHERE `$uid`= :uid");
");
Database::pexecute($stmt, [ Database::pexecute($stmt, [
"lastlogin_succ" => time(), "lastlogin_succ" => time(),
"uid" => $userinfo[$uid] "uid" => $userinfo[$uid]
@@ -356,11 +292,9 @@ if ($action == '2fa_entercode') {
} }
} else { } else {
// login incorrect // login incorrect
$stmt = Database::prepare(" $stmt = Database::prepare("UPDATE $table
UPDATE $table
SET `lastlogin_fail`= :lastlogin_fail, `loginfail_count`=`loginfail_count`+1 SET `lastlogin_fail`= :lastlogin_fail, `loginfail_count`=`loginfail_count`+1
WHERE `$uid`= :uid WHERE `$uid`= :uid");
");
Database::pexecute($stmt, [ Database::pexecute($stmt, [
"lastlogin_fail" => time(), "lastlogin_fail" => time(),
"uid" => $userinfo[$uid] "uid" => $userinfo[$uid]
@@ -370,7 +304,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 tried to login with wrong password."); $rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "User '" . $loginname . "' tried to login with wrong password.");
unset($userinfo); unset($userinfo);
Response::redirectTo('index.php', [ Response::redirectTo('index.php', [
@@ -381,25 +315,6 @@ if ($action == '2fa_entercode') {
// 2FA activated // 2FA activated
if (Settings::Get('2fa.enabled') == '1' && $userinfo['type_2fa'] > 0) { if (Settings::Get('2fa.enabled') == '1' && $userinfo['type_2fa'] > 0) {
// check for remember cookie
if (!empty($_COOKIE['frx_2fa_remember'])) {
list($selector, $authenticator) = explode(':', $_COOKIE['frx_2fa_remember']);
$sel_stmt = Database::prepare("SELECT `token` FROM `".TABLE_PANEL_2FA_TOKENS."` WHERE `selector` = :selector AND `userid` = :uid AND `valid_until` >= UNIX_TIMESTAMP()");
$token_check = Database::pexecute_first($sel_stmt, ['selector' => $selector, 'uid' => $userinfo[$uid]]);
if ($token_check && hash_equals($token_check['token'], hash('sha256', base64_decode($authenticator)))) {
if (!finishLogin($userinfo)) {
Response::redirectTo('index.php', [
'showmessage' => '2'
]);
}
exit();
}
// not found or invalid, this cookie is useless, get rid of it
unset($_COOKIE['frx_2fa_remember']);
setcookie('frx_2fa_remember', "", time()-3600);
}
// redirect to code-enter-page // redirect to code-enter-page
$_SESSION['secret_2fa'] = ($userinfo['type_2fa'] == 2 ? $userinfo['data_2fa'] : 'email'); $_SESSION['secret_2fa'] = ($userinfo['type_2fa'] == 2 ? $userinfo['data_2fa'] : 'email');
$_SESSION['uid_2fa'] = $userinfo[$uid]; $_SESSION['uid_2fa'] = $userinfo[$uid];
@@ -410,12 +325,11 @@ 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'));
$secret = $tfa->createSecret(); $code = $tfa->getCode($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" => $secret, "d2fa" => $code,
"uid" => $userinfo[$uid] "uid" => $userinfo[$uid]
]); ]);
// build up & send email // build up & send email
@@ -467,7 +381,7 @@ if ($action == '2fa_entercode') {
} }
exit(); exit();
} else { } else {
$smessage = (int)Request::get('showmessage', 0); $smessage = isset($_GET['showmessage']) ? (int)$_GET['showmessage'] : 0;
$message = ''; $message = '';
$successmessage = ''; $successmessage = '';
@@ -504,20 +418,25 @@ if ($action == '2fa_entercode') {
} }
// Pass the last used page if needed // Pass the last used page if needed
$lastscript = Request::any('script', ''); $lastscript = "";
if (!empty($lastscript)) { if (isset($_REQUEST['script']) && $_REQUEST['script'] != "") {
$lastscript = $_REQUEST['script'];
$lastscript = str_replace("..", "", $lastscript); $lastscript = str_replace("..", "", $lastscript);
$lastscript = htmlspecialchars($lastscript, ENT_QUOTES); $lastscript = htmlspecialchars($lastscript, ENT_QUOTES);
if (file_exists(__DIR__ . "/" . $lastscript)) { if (!file_exists(__DIR__ . "/" . $lastscript)) {
$_SESSION['lastscript'] = $lastscript;
} else {
$lastscript = ""; $lastscript = "";
} }
} }
$lastqrystr = Request::any('qrystr', ''); $lastqrystr = "";
if (isset($_REQUEST['qrystr']) && $_REQUEST['qrystr'] != "") {
$lastqrystr = urlencode($_REQUEST['qrystr']);
}
if (!empty($lastscript)) {
$_SESSION['lastscript'] = $lastscript;
}
if (!empty($lastqrystr)) { if (!empty($lastqrystr)) {
$lastqrystr = urlencode($lastqrystr);
$_SESSION['lastqrystr'] = $lastqrystr; $_SESSION['lastqrystr'] = $lastqrystr;
} }
@@ -535,8 +454,8 @@ if ($action == 'forgotpwd') {
$message = ''; $message = '';
if (!empty($_POST)) { if (!empty($_POST)) {
$loginname = Validate::validate(Request::post('loginname'), 'loginname'); $loginname = Validate::validate($_POST['loginname'], 'loginname');
$email = Validate::validateEmail(Request::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 . "`
WHERE `loginname`= :loginname WHERE `loginname`= :loginname
AND `email`= :email"); AND `email`= :email");
@@ -703,7 +622,7 @@ if ($action == 'forgotpwd') {
$rstlog = FroxlorLogger::getInstanceOf([ $rstlog = FroxlorLogger::getInstanceOf([
'loginname' => 'password_reset' 'loginname' => 'password_reset'
]); ]);
$rstlog->logAction(FroxlorLogger::USR_ACTION, LOG_WARNING, "Unknown user requested to set a new password, but was not found in database!"); $rstlog->logAction(FroxlorLogger::USR_ACTION, LOG_WARNING, "User '" . $loginname . "' requested to set a new password, but was not found in database!");
$message = lng('login.usernotfound'); $message = lng('login.usernotfound');
} }
@@ -733,9 +652,9 @@ if ($action == 'resetpwd') {
"oldest" => time() - 86400 "oldest" => time() - 86400
]); ]);
$activationcode = Request::get('resetcode'); if (isset($_GET['resetcode']) && strlen($_GET['resetcode']) == 50) {
if (!empty($activationcode) && strlen($activationcode) == 50) {
// Check if activation code is valid // Check if activation code is valid
$activationcode = $_GET['resetcode'];
$timestamp = substr($activationcode, 15, 10); $timestamp = substr($activationcode, 15, 10);
$third = substr($activationcode, 25, 15); $third = substr($activationcode, 25, 15);
$check = substr($activationcode, 40, 10); $check = substr($activationcode, 40, 10);
@@ -750,8 +669,8 @@ if ($action == 'resetpwd') {
if ($result !== false) { if ($result !== false) {
try { try {
$new_password = Crypt::validatePassword(Request::post('new_password'), true); $new_password = Crypt::validatePassword($_POST['new_password'], true);
$new_password_confirm = Crypt::validatePassword(Request::post('new_password_confirm'), true); $new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], true);
} catch (Exception $e) { } catch (Exception $e) {
$message = $e->getMessage(); $message = $e->getMessage();
} }
@@ -815,58 +734,6 @@ 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'] != '') {
@@ -880,8 +747,8 @@ function finishLogin($userinfo)
$theme = $userinfo['theme']; $theme = $userinfo['theme'];
} else { } else {
$theme = Settings::Get('panel.default_theme'); $theme = Settings::Get('panel.default_theme');
}
CurrentUser::setField('theme', $theme); CurrentUser::setField('theme', $theme);
}
$qryparams = []; $qryparams = [];
if (!empty($_SESSION['lastqrystr'])) { if (!empty($_SESSION['lastqrystr'])) {

View File

@@ -94,11 +94,6 @@ CREATE TABLE `mail_virtual` (
`popaccountid` int(11) NOT NULL default '0', `popaccountid` int(11) NOT NULL default '0',
`iscatchall` tinyint(1) unsigned NOT NULL default '0', `iscatchall` tinyint(1) unsigned NOT NULL default '0',
`description` varchar(255) NOT NULL DEFAULT '', `description` varchar(255) NOT NULL DEFAULT '',
`spam_tag_level` float(4,1) NOT NULL DEFAULT 7.0,
`rewrite_subject` tinyint(1) NOT NULL default '1',
`spam_kill_level` float(4,1) NOT NULL DEFAULT 14.0,
`bypass_spam` tinyint(1) NOT NULL default '0',
`policy_greylist` tinyint(1) NOT NULL default '1',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `email` (`email`) KEY `email` (`email`)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci; ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
@@ -160,10 +155,9 @@ CREATE TABLE `panel_admins` (
`type_2fa` tinyint(1) NOT NULL default '0', `type_2fa` tinyint(1) NOT NULL default '0',
`data_2fa` varchar(25) NOT NULL default '', `data_2fa` varchar(25) NOT NULL default '',
`api_allowed` tinyint(1) NOT NULL default '1', `api_allowed` tinyint(1) NOT NULL default '1',
`gui_access` 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 ROW_FORMAT=DYNAMIC; ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
DROP TABLE IF EXISTS `panel_customers`; DROP TABLE IF EXISTS `panel_customers`;
@@ -229,7 +223,6 @@ CREATE TABLE `panel_customers` (
`api_allowed` tinyint(1) NOT NULL default '1', `api_allowed` tinyint(1) NOT NULL default '1',
`logviewenabled` tinyint(1) NOT NULL default '0', `logviewenabled` tinyint(1) NOT NULL default '0',
`allowed_mysqlserver` text NOT NULL, `allowed_mysqlserver` text NOT NULL,
`gui_access` tinyint(1) NOT NULL default '1',
PRIMARY KEY (`customerid`), PRIMARY KEY (`customerid`),
UNIQUE KEY `loginname` (`loginname`) UNIQUE KEY `loginname` (`loginname`)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC; ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
@@ -285,6 +278,7 @@ 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',
@@ -306,7 +300,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 ROW_FORMAT=DYNAMIC; ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
DROP TABLE IF EXISTS `panel_ipsandports`; DROP TABLE IF EXISTS `panel_ipsandports`;
@@ -363,6 +357,23 @@ 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,
@@ -387,18 +398,22 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES
('logger', 'logfile', ''), ('logger', 'logfile', ''),
('logger', 'logtypes', 'syslog,mysql'), ('logger', 'logtypes', 'syslog,mysql'),
('logger', 'severity', '1'), ('logger', 'severity', '1'),
('antispam', 'activated', '0'), ('dkim', 'use_dkim', '0'),
('antispam', 'config_file', '/etc/rspamd/local.d/froxlor_settings.conf'), ('dkim', 'dkim_prefix', '/etc/postfix/dkim/'),
('antispam', 'reload_command', 'service rspamd restart'), ('dkim', 'dkim_domains', 'domains'),
('antispam', 'dkim_keylength', '1024'), ('dkim', 'dkim_dkimkeys', 'dkim-keys.conf'),
('dkim', 'dkimrestart_command', 'service dkim-filter restart'),
('dkim', 'privkeysuffix', '.priv'),
('admin', 'show_news_feed', '0'), ('admin', 'show_news_feed', '0'),
('admin', 'show_version_login', '0'), ('admin', 'show_version_login', '0'),
('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"'),
('dmarc', 'use_dmarc', '0'), ('dkim', 'dkim_algorithm', 'all'),
('dmarc', 'dmarc_entry', 'v=DMARC1; p=none;'), ('dkim', 'dkim_keylength', '1024'),
('dkim', 'dkim_servicetype', '0'),
('dkim', 'dkim_notes', ''),
('defaultwebsrverrhandler', 'enabled', '0'), ('defaultwebsrverrhandler', 'enabled', '0'),
('defaultwebsrverrhandler', 'err401', ''), ('defaultwebsrverrhandler', 'err401', ''),
('defaultwebsrverrhandler', 'err403', ''), ('defaultwebsrverrhandler', 'err403', ''),
@@ -496,6 +511,7 @@ opcache.save_comments
opcache.use_cwd opcache.use_cwd
opcache.fast_shutdown'), opcache.fast_shutdown'),
('phpfpm', 'ini_admin_values', 'cgi.redirect_status_env ('phpfpm', 'ini_admin_values', 'cgi.redirect_status_env
date.timezone
disable_classes disable_classes
disable_functions disable_functions
error_log error_log
@@ -539,7 +555,7 @@ opcache.validate_timestamps'),
('system', 'defaultip', '1'), ('system', 'defaultip', '1'),
('system', 'defaultsslip', ''), ('system', 'defaultsslip', ''),
('system', 'phpappendopenbasedir', '/tmp/'), ('system', 'phpappendopenbasedir', '/tmp/'),
('system', 'deactivateddocroot', '/var/www/html/froxlor/templates/misc/deactivated/'), ('system', 'deactivateddocroot', ''),
('system', 'mailpwcleartext', '0'), ('system', 'mailpwcleartext', '0'),
('system', 'last_tasks_run', '000000'), ('system', 'last_tasks_run', '000000'),
('system', 'nameservers', ''), ('system', 'nameservers', ''),
@@ -547,7 +563,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/froxlor-htpasswd/'), ('system', 'apacheconf_htpasswddir', '/etc/apache2/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'),
@@ -564,6 +580,7 @@ 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', ''),
@@ -630,7 +647,7 @@ opcache.validate_timestamps'),
('system', 'letsencryptreuseold', 0), ('system', 'letsencryptreuseold', 0),
('system', 'leenabled', '0'), ('system', 'leenabled', '0'),
('system', 'leapiversion', '2'), ('system', 'leapiversion', '2'),
('system', 'exportenabled', '0'), ('system', 'backupenabled', '0'),
('system', 'dnsenabled', '0'), ('system', 'dnsenabled', '0'),
('system', 'dns_server', 'Bind'), ('system', 'dns_server', 'Bind'),
('system', 'apacheglobaldiropt', ''), ('system', 'apacheglobaldiropt', ''),
@@ -638,8 +655,6 @@ opcache.validate_timestamps'),
('system', 'available_shells', ''), ('system', 'available_shells', ''),
('system', 'le_froxlor_enabled', '0'), ('system', 'le_froxlor_enabled', '0'),
('system', 'le_froxlor_redirect', '0'), ('system', 'le_froxlor_redirect', '0'),
('system', 'le_renew_hook', 'systemctl restart postfix dovecot proftpd'),
('system', 'le_renew_services', ''),
('system', 'letsencryptacmeconf', '/etc/apache2/conf-enabled/acme.conf'), ('system', 'letsencryptacmeconf', '/etc/apache2/conf-enabled/acme.conf'),
('system', 'mail_use_smtp', '0'), ('system', 'mail_use_smtp', '0'),
('system', 'mail_smtp_host', 'localhost'), ('system', 'mail_smtp_host', 'localhost'),
@@ -682,7 +697,7 @@ opcache.validate_timestamps'),
('system', 'distribution', ''), ('system', 'distribution', ''),
('system', 'update_channel', 'stable'), ('system', 'update_channel', 'stable'),
('system', 'updatecheck_data', ''), ('system', 'updatecheck_data', ''),
('system', 'update_notify_last', ''), ('system', 'update_notify_last', '2.0.24'),
('system', 'traffictool', 'goaccess'), ('system', 'traffictool', 'goaccess'),
('system', 'req_limit_per_interval', 60), ('system', 'req_limit_per_interval', 60),
('system', 'req_limit_interval', 60), ('system', 'req_limit_interval', 60),
@@ -690,7 +705,7 @@ opcache.validate_timestamps'),
('api', 'customer_default', '1'), ('api', 'customer_default', '1'),
('2fa', 'enabled', '1'), ('2fa', 'enabled', '1'),
('panel', 'decimal_places', '4'), ('panel', 'decimal_places', '4'),
('panel', 'adminmail', 'ADMIN_MAIL'), ('panel', 'adminmail', 'admin@SERVERNAME'),
('panel', 'phpmyadmin_url', ''), ('panel', 'phpmyadmin_url', ''),
('panel', 'webmail_url', ''), ('panel', 'webmail_url', ''),
('panel', 'webftp_url', ''), ('panel', 'webftp_url', ''),
@@ -729,9 +744,8 @@ opcache.validate_timestamps'),
('panel', 'logo_overridetheme', '0'), ('panel', 'logo_overridetheme', '0'),
('panel', 'logo_overridecustom', '0'), ('panel', 'logo_overridecustom', '0'),
('panel', 'settings_mode', '0'), ('panel', 'settings_mode', '0'),
('panel', 'menu_collapsed', '1'), ('panel', 'version', '2.0.24'),
('panel', 'version', '2.2.2'), ('panel', 'db_version', '202304260');
('panel', 'db_version', '202409280');
DROP TABLE IF EXISTS `panel_tasks`; DROP TABLE IF EXISTS `panel_tasks`;
@@ -754,7 +768,6 @@ 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;
@@ -901,7 +914,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/export', 'export', '\\Froxlor\\Cron\\System\\ExportCron', '1 HOUR', '0', 'cron_export'); (6, 'froxlor/backup', 'backup', '\\Froxlor\\Cron\\System\\BackupCron', '1 DAY', '0', 'cron_backup');
DROP TABLE IF EXISTS `ftp_quotalimits`; DROP TABLE IF EXISTS `ftp_quotalimits`;
@@ -1039,25 +1052,4 @@ 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;
DROP TABLE IF EXISTS `panel_2fa_tokens`;
CREATE TABLE `panel_2fa_tokens` (
`id` int(11) NOT NULL auto_increment,
`selector` varchar(200) NOT NULL,
`token` varchar(200) NOT NULL,
`userid` int(11) NOT NULL default '0',
`valid_until` int(15) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
FROXLORSQL; FROXLORSQL;

View File

@@ -23,11 +23,11 @@
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2 * @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/ */
use Froxlor\Database\Database;
use Froxlor\FileDir;
use Froxlor\Froxlor; use Froxlor\Froxlor;
use Froxlor\Install\Update; use Froxlor\FileDir;
use Froxlor\Database\Database;
use Froxlor\Settings; use Froxlor\Settings;
use Froxlor\Install\Update;
use Froxlor\System\Cronjob; use Froxlor\System\Cronjob;
use Froxlor\System\IPTools; use Froxlor\System\IPTools;

View File

@@ -1,254 +0,0 @@
<?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')) {
$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"
);
Update::cleanOldFiles($to_clean);
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')) {
$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",
);
Update::cleanOldFiles($to_clean);
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');
}

View File

@@ -1,185 +0,0 @@
<?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\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.1.9')) {
Update::showUpdateStep("Enhancing virtual email table");
Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `spam_tag_level` float(4,1) NOT NULL DEFAULT 7.0;");
Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `spam_kill_level` float(4,1) NOT NULL DEFAULT 14.0;");
Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `bypass_spam` tinyint(1) NOT NULL default '0';");
Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `policy_greylist` tinyint(1) NOT NULL default '1';");
Update::lastStepStatus(0);
Update::showUpdateStep("Adjusting settings");
$antispam_activated = $_POST['antispam_activated'] ?? 0;
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `settinggroup` = 'antispam', `varname` = 'activated', `value` = '" . (int)$antispam_activated . "' WHERE `settinggroup` = 'dkim' AND `varname` = 'use_dkim';");
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `settinggroup` = 'antispam', `varname` = 'reload_command', `value` = 'service rspamd restart' WHERE `settinggroup` = 'dkim' AND `varname` = 'dkimrestart_command';");
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `settinggroup` = 'antispam', `varname` = 'config_file', `value` = '/etc/rspamd/local.d/froxlor_settings.conf' WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_prefix';");
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `settinggroup` = 'antispam' WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_keylength';");
Settings::AddNew("dmarc.use_dmarc", "0");
Settings::AddNew("dmarc.dmarc_entry", "v=DMARC1; p=none;");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'privkeysuffix';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_domains';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_algorithm';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_notes';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_add_adsp';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_dkimkeys';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_servicetype';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_add_adsppolicy';");
Update::lastStepStatus(0);
if ($antispam_activated) {
Update::showUpdateStep("Converting existing domainkeys");
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `dkim` = '1' AND `dkim_pubkey` <> ''");
Database::pexecute($sel_stmt);
$upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `dkim_pubkey` = :pkey WHERE `id` = :did");
while ($domain = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
$pubkey = trim(preg_replace(
'/-----BEGIN PUBLIC KEY-----(.+)-----END PUBLIC KEY-----/s',
'$1',
str_replace("\n", '', $domain['dkim_pubkey'])
));
Database::pexecute($upd_stmt, ['pkey' => $pubkey, 'did' => $domain['id']]);
}
Update::lastStepStatus(0);
Update::showUpdateStep("Configure antispam services");
$froxlorCliBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
$currentDistro = Settings::Get('system.distribution');
$manual_command = <<<EOC
{$froxlorCliBin} froxlor:config-services -a '{"http":"x","dns":"x","smtp":"x","mail":"x","antispam":"rspamd","ftp":"x","distro":"{$currentDistro}","system":[]}'
EOC;
Update::lastStepStatus(
1,
'manual action needed',
"Please run the following command manually as root:<br><pre>" . $manual_command . "</pre>"
);
} else {
Update::showUpdateStep("Removing existing domainkeys because antispam is disabled");
Database::query("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `dkim` = '0', `dkim_id` = '0', `dkim_privkey` = '', `dkim_pubkey` = '' WHERE `dkim` = '1';");
Update::lastStepStatus(1, '!!!');
}
Update::showUpdateStep("Enhancing admin and user table");
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` ADD `gui_access` tinyint(1) NOT NULL default '1';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `gui_access` tinyint(1) NOT NULL default '1';");
Update::lastStepStatus(0);
$to_clean = [
'actions/admin/settings/180.dkim.php',
'actions/admin/settings/185.spf.php',
];
Update::cleanOldFiles($to_clean);
Froxlor::updateToDbVersion('202312230');
Froxlor::updateToVersion('2.2.0-dev1');
}
if (Froxlor::isDatabaseVersion('202312230')) {
Update::showUpdateStep("Adding new settings");
Settings::AddNew("system.le_renew_services", "");
Settings::AddNew("system.le_renew_hook", "systemctl restart postfix dovecot proftpd");
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202401090');
}
if (Froxlor::isFroxlorVersion('2.2.0-dev1')) {
Update::showUpdateStep("Updating from 2.2.0-dev1 to 2.2.0-rc1", false);
Froxlor::updateToVersion('2.2.0-rc1');
}
if (Froxlor::isDatabaseVersion('202401090')) {
Update::showUpdateStep("Adding new table for 2fa tokens");
Database::query("DROP TABLE IF EXISTS `panel_2fa_tokens`;");
$sql = "CREATE TABLE `panel_2fa_tokens` (
`id` int(11) NOT NULL auto_increment,
`selector` varchar(20) NOT NULL,
`token` varchar(200) NOT NULL,
`userid` int(11) NOT NULL default '0',
`valid_until` int(15) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;";
Database::query($sql);
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202407200');
}
if (Froxlor::isFroxlorVersion('2.2.0-rc1')) {
Update::showUpdateStep("Updating from 2.2.0-rc1 to 2.2.0-rc2", false);
Froxlor::updateToVersion('2.2.0-rc2');
}
if (Froxlor::isFroxlorVersion('2.2.0-rc2')) {
Update::showUpdateStep("Updating from 2.2.0-rc2 to 2.2.0-rc3", false);
Froxlor::updateToVersion('2.2.0-rc3');
}
if (Froxlor::isDatabaseVersion('202407200')) {
Update::showUpdateStep("Adjusting field in 2fa-token table");
Database::query("ALTER TABLE `panel_2fa_tokens` CHANGE COLUMN `selector` `selector` varchar(200) NOT NULL;");
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202408140');
}
if (Froxlor::isFroxlorVersion('2.2.0-rc3')) {
Update::showUpdateStep("Updating from 2.2.0-rc3 to 2.2.0 stable", false);
Froxlor::updateToVersion('2.2.0');
}
if (Froxlor::isFroxlorVersion('2.2.0')) {
Update::showUpdateStep("Updating from 2.2.0 to 2.2.1", false);
Froxlor::updateToVersion('2.2.1');
}
if (Froxlor::isDatabaseVersion('202408140')) {
Update::showUpdateStep("Adding new rewrite-subject field to email table");
Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `rewrite_subject` tinyint(1) NOT NULL default '1' AFTER `spam_tag_level`;");
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202409280');
}
if (Froxlor::isFroxlorVersion('2.2.1')) {
Update::showUpdateStep("Updating from 2.2.1 to 2.2.2", false);
Froxlor::updateToVersion('2.2.2');
}

View File

@@ -99,6 +99,7 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
} }
Update::lastStepStatus(0); Update::lastStepStatus(0);
Update::showUpdateStep("Cleaning up old files");
$to_clean = array( $to_clean = array(
"install/lib", "install/lib",
"install/lng", "install/lng",
@@ -120,7 +121,30 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
"lng/swedish.lng.php", "lng/swedish.lng.php",
"scripts", "scripts",
); );
Update::cleanOldFiles($to_clean); $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>');
}
}
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;

View File

@@ -34,7 +34,7 @@ $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).';
$question = '<strong>Validate DNS of domains when using Lets Encrypt</strong>'; $question = '<strong>Validate DNS of domains when using Lets Encrypt&nbsp;';
$return['system_le_domain_dnscheck'] = [ $return['system_le_domain_dnscheck'] = [
'type' => 'checkbox', 'type' => 'checkbox',
'value' => 1, 'value' => 1,

View File

@@ -1,48 +0,0 @@
<?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\Install\Update;
$preconfig = [
'title' => '2.2.x updates',
'fields' => []
];
$return = [];
if (Update::versionInUpdate($current_version, '2.2.0-dev1')) {
$has_preconfig = true;
$description = 'Froxlor now features antispam configurations using rspamd. Would you like to enable the antispam feature (required re-configuration of services)?<br><strong>ATTENTION:</strong> When not enabled and the former DomainKey feature was used, keep in mind that all existing domainkeys for all domain are being removed and the dkim-flag disabled for the domains.';
$question = '<strong>Enable antispam (recommended)</strong>&nbsp;';
$return['antispam_activated'] = [
'type' => 'checkbox',
'value' => 1,
'checked' => 0,
'label' => $question,
'prior_infotext' => $description
];
}
$preconfig['fields'] = $return;
return $preconfig;

View File

@@ -30,7 +30,7 @@ use Froxlor\Install\Update;
use Froxlor\Settings; use Froxlor\Settings;
$preconfig = [ $preconfig = [
'title' => '2.0.x updates', 'title' => '2.x updates',
'fields' => [] 'fields' => []
]; ];
$return = []; $return = [];

View File

@@ -53,9 +53,7 @@ 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.0.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.1.inc.php'));
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_2.2.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");

View File

@@ -193,8 +193,7 @@ class Ajax
UI::initTwig(); UI::initTwig();
try { try {
$force = Request::get('force', 0); $json_result = \Froxlor\Api\Commands\Froxlor::getLocal($this->userinfo)->checkUpdate();
$json_result = \Froxlor\Api\Commands\Froxlor::getLocal($this->userinfo, ['force' => $force])->checkUpdate();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
$result['full_version'] = Froxlor::getFullVersion(); $result['full_version'] = Froxlor::getFullVersion();
$result['dbversion'] = Froxlor::DBVERSION; $result['dbversion'] = Froxlor::DBVERSION;

View File

@@ -156,7 +156,7 @@ class GlobalSearch
], ],
'result_key' => 'domain_ace', 'result_key' => 'domain_ace',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'domain_ace', 'title_args' => 'domain_ace',
'href' => 'admin_domains.php?page=domains&searchfield=d.domain_ace&searchtext=' 'href' => 'admin_domains.php?page=domains&searchfield=d.domain_ace&searchtext='
] ]
@@ -172,7 +172,7 @@ class GlobalSearch
'result_key' => 'ip', 'result_key' => 'ip',
'result_groupkey' => 'ip', 'result_groupkey' => 'ip',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'ip', 'title_args' => 'ip',
'href' => 'admin_ipsandports.php?page=ipsandports&searchfield=ip&searchtext=' 'href' => 'admin_ipsandports.php?page=ipsandports&searchfield=ip&searchtext='
] ]
@@ -186,7 +186,7 @@ class GlobalSearch
], ],
'result_key' => 'id', 'result_key' => 'id',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'name', 'title_args' => 'name',
'href' => 'admin_plans.php?page=overview&searchfield=id&searchtext=' 'href' => 'admin_plans.php?page=overview&searchfield=id&searchtext='
] ]
@@ -201,7 +201,7 @@ class GlobalSearch
], ],
'result_key' => 'id', 'result_key' => 'id',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'description', 'title_args' => 'description',
'href' => 'admin_phpsettings.php?page=overview&searchfield=id&searchtext=' 'href' => 'admin_phpsettings.php?page=overview&searchfield=id&searchtext='
] ]
@@ -215,7 +215,7 @@ class GlobalSearch
], ],
'result_key' => 'id', 'result_key' => 'id',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'description', 'title_args' => 'description',
'href' => 'admin_phpsettings.php?page=fpmdaemons&searchfield=id&searchtext=' 'href' => 'admin_phpsettings.php?page=fpmdaemons&searchfield=id&searchtext='
] ]
@@ -234,7 +234,7 @@ class GlobalSearch
], ],
'result_key' => 'loginname', 'result_key' => 'loginname',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'name', 'title_args' => 'name',
'href' => 'admin_admins.php?page=admins&searchfield=loginname&searchtext=' 'href' => 'admin_admins.php?page=admins&searchfield=loginname&searchtext='
] ]
@@ -252,7 +252,7 @@ class GlobalSearch
], ],
'result_key' => 'domain_ace', 'result_key' => 'domain_ace',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'domain_ace', 'title_args' => 'domain_ace',
'href' => 'customer_domains.php?page=domains&searchfield=d.domain_ace&searchtext=' 'href' => 'customer_domains.php?page=domains&searchfield=d.domain_ace&searchtext='
] ]
@@ -266,7 +266,7 @@ class GlobalSearch
], ],
'result_key' => 'email', 'result_key' => 'email',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'email', 'title_args' => 'email',
'href' => 'customer_email.php?page=email_domain&domainid={domainid}&searchfield=m.email&searchtext=' 'href' => 'customer_email.php?page=email_domain&domainid={domainid}&searchfield=m.email&searchtext='
] ]
@@ -279,7 +279,7 @@ class GlobalSearch
], ],
'result_key' => 'domain', 'result_key' => 'domain',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'domain', 'title_args' => 'domain',
'href' => 'customer_email.php?page=emails&searchfield=d.domain&searchtext=' 'href' => 'customer_email.php?page=emails&searchfield=d.domain&searchtext='
] ]
@@ -293,7 +293,7 @@ class GlobalSearch
], ],
'result_key' => 'databasename', 'result_key' => 'databasename',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'databasename', 'title_args' => 'databasename',
'href' => 'customer_mysql.php?page=mysqls&searchfield=databasename&searchtext=' 'href' => 'customer_mysql.php?page=mysqls&searchfield=databasename&searchtext='
] ]
@@ -307,7 +307,7 @@ class GlobalSearch
], ],
'result_key' => 'username', 'result_key' => 'username',
'result_format' => [ 'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'], 'title' => ['self', 'getFieldFromResult'],
'title_args' => 'username', 'title_args' => 'username',
'href' => 'customer_ftp.php?page=accounts&searchfield=username&searchtext=' 'href' => 'customer_ftp.php?page=accounts&searchfield=username&searchtext='
] ]

View File

@@ -272,8 +272,7 @@ abstract class ApiCommand extends ApiParameter
$ops = [ $ops = [
'<', '<',
'>', '>',
'=', '='
'<>'
]; ];
$first = true; $first = true;
foreach ($search as $field => $valoper) { foreach ($search as $field => $valoper) {
@@ -397,7 +396,6 @@ abstract class ApiCommand extends ApiParameter
$nat_fields = [ $nat_fields = [
'`c`.`loginname`', '`c`.`loginname`',
'`c`.`name`',
'`a`.`loginname`', '`a`.`loginname`',
'`adminname`', '`adminname`',
'`databasename`', '`databasename`',

View File

@@ -140,18 +140,12 @@ class Admins extends ApiCommand implements ResourceEntity
* create a new admin user * create a new admin user
* *
* @param string $name * @param string $name
* required, name of the adminstrator
* @param string $email * @param string $email
* required, email address of the administrator
* @param string $new_loginname * @param string $new_loginname
* required, loginname/username of the administrator
* @param string $admin_password * @param string $admin_password
* optional, default auto-generated * optional, default auto-generated
* @param string $def_language * @param string $def_language
* * optional, ISO 639-1 language code (e.g. 'en', 'de', see lng-folder for supported languages), * optional, default is system-default language
* * default is system-default language
* @param bool $gui_access
* optional, allow login via webui, if false ONLY the login via webui is disallowed; default true
* @param bool $api_allowed * @param bool $api_allowed
* optional, default is true if system setting api.enabled is true, else false * optional, default is true if system setting api.enabled is true, else false
* @param string $custom_notes * @param string $custom_notes
@@ -225,7 +219,6 @@ class Admins extends ApiCommand implements ResourceEntity
// parameters // parameters
$def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage')); $def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage'));
$gui_access = $this->getBoolParam('gui_access', true, true);
$api_allowed = $this->getBoolParam('api_allowed', true, Settings::Get('api.enabled')); $api_allowed = $this->getBoolParam('api_allowed', true, Settings::Get('api.enabled'));
$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);
@@ -323,7 +316,6 @@ class Admins extends ApiCommand implements ResourceEntity
'name' => $name, 'name' => $name,
'email' => $email, 'email' => $email,
'lang' => $def_language, 'lang' => $def_language,
'gui_access' => $gui_access,
'api_allowed' => $api_allowed, 'api_allowed' => $api_allowed,
'change_serversettings' => $change_serversettings, 'change_serversettings' => $change_serversettings,
'customers' => $customers, 'customers' => $customers,
@@ -352,7 +344,6 @@ class Admins extends ApiCommand implements ResourceEntity
`name` = :name, `name` = :name,
`email` = :email, `email` = :email,
`def_language` = :lang, `def_language` = :lang,
`gui_access` = :gui_access,
`api_allowed` = :api_allowed, `api_allowed` = :api_allowed,
`change_serversettings` = :change_serversettings, `change_serversettings` = :change_serversettings,
`customers` = :customers, `customers` = :customers,
@@ -439,10 +430,7 @@ class Admins extends ApiCommand implements ResourceEntity
* @param string $admin_password * @param string $admin_password
* optional, default auto-generated * optional, default auto-generated
* @param string $def_language * @param string $def_language
* * optional, ISO 639-1 language code (e.g. 'en', 'de', see lng-folder for supported languages), * optional, default is system-default language
* * default is system-default language
* @param bool $gui_access
* * optional, allow login via webui, if false ONLY the login via webui is disallowed; default true
* @param bool $api_allowed * @param bool $api_allowed
* optional, default is true if system setting api.enabled is true, else false * optional, default is true if system setting api.enabled is true, else false
* @param string $custom_notes * @param string $custom_notes
@@ -536,7 +524,6 @@ class Admins extends ApiCommand implements ResourceEntity
// you cannot edit some of the details of yourself // you cannot edit some of the details of yourself
if ($result['adminid'] == $this->getUserDetail('adminid')) { if ($result['adminid'] == $this->getUserDetail('adminid')) {
$gui_access = $result['gui_access'];
$api_allowed = $result['api_allowed']; $api_allowed = $result['api_allowed'];
$deactivated = $result['deactivated']; $deactivated = $result['deactivated'];
$customers = $result['customers']; $customers = $result['customers'];
@@ -555,7 +542,6 @@ class Admins extends ApiCommand implements ResourceEntity
$traffic = $result['traffic']; $traffic = $result['traffic'];
$ipaddress = ($result['ip'] != -1 ? json_decode($result['ip'], true) : -1); $ipaddress = ($result['ip'] != -1 ? json_decode($result['ip'], true) : -1);
} else { } else {
$gui_access = $this->getBoolParam('gui_access', true, $result['gui_access']);
$api_allowed = $this->getBoolParam('api_allowed', true, $result['api_allowed']); $api_allowed = $this->getBoolParam('api_allowed', true, $result['api_allowed']);
$deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']); $deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']);
@@ -679,7 +665,6 @@ class Admins extends ApiCommand implements ResourceEntity
'name' => $name, 'name' => $name,
'email' => $email, 'email' => $email,
'lang' => $def_language, 'lang' => $def_language,
'gui_access' => $gui_access,
'api_allowed' => $api_allowed, 'api_allowed' => $api_allowed,
'change_serversettings' => $change_serversettings, 'change_serversettings' => $change_serversettings,
'customers' => $customers, 'customers' => $customers,
@@ -709,7 +694,6 @@ class Admins extends ApiCommand implements ResourceEntity
`name` = :name, `name` = :name,
`email` = :email, `email` = :email,
`def_language` = :lang, `def_language` = :lang,
`gui_access` = :gui_access,
`api_allowed` = :api_allowed, `api_allowed` = :api_allowed,
`change_serversettings` = :change_serversettings, `change_serversettings` = :change_serversettings,
`customers` = :customers, `customers` = :customers,

View File

@@ -41,22 +41,20 @@ use PDO;
/** /**
* @since 0.10.0 * @since 0.10.0
*/ */
class DataDump extends ApiCommand implements ResourceEntity class CustomerBackups extends ApiCommand implements ResourceEntity
{ {
/** /**
* add a new data dump job * add a new customer backup job
* *
* @param string $path * @param string $path
* path to store the dumped data to * path to store the backup to
* @param string $pgp_public_key * @param bool $backup_dbs
* optional pgp public key to encrypt the archive, default is empty * optional whether to backup databases, default is 0 (false)
* @param bool $dump_dbs * @param bool $backup_mail
* optional whether to include databases, default is 0 (false) * optional whether to backup mail-data, default is 0 (false)
* @param bool $dump_mail * @param bool $backup_web
* optional whether to include mail-data, default is 0 (false) * optional whether to backup web-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
@@ -74,10 +72,9 @@ class DataDump extends ApiCommand implements ResourceEntity
$path = $this->getParam('path'); $path = $this->getParam('path');
// parameter // parameter
$pgp_public_key = $this->getParam('pgp_public_key', true, ''); $backup_dbs = $this->getBoolParam('backup_dbs', true, 0);
$dump_dbs = $this->getBoolParam('dump_dbs', true, 0); $backup_mail = $this->getBoolParam('backup_mail', true, 0);
$dump_mail = $this->getBoolParam('dump_mail', true, 0); $backup_web = $this->getBoolParam('backup_web', true, 0);
$dump_web = $this->getBoolParam('dump_web', true, 0);
// get customer data // get customer data
$customer = $this->getCustomerData(); $customer = $this->getCustomerData();
@@ -89,32 +86,19 @@ class DataDump 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('dumpfoldercannotbedocroot', '', true); Response::standardError('backupfoldercannotbedocroot', '', true);
} }
// pgp public key validation if ($backup_dbs != '1') {
if (!empty($pgp_public_key)) { $backup_dbs = '0';
// 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 ($dump_dbs != '1') { if ($backup_mail != '1') {
$dump_dbs = '0'; $backup_mail = '0';
} }
if ($dump_mail != '1') { if ($backup_web != '1') {
$dump_mail = '0'; $backup_web = '0';
}
if ($dump_web != '1') {
$dump_web = '0';
} }
$task_data = [ $task_data = [
@@ -123,63 +107,61 @@ class DataDump extends ApiCommand implements ResourceEntity
'gid' => $customer['guid'], 'gid' => $customer['guid'],
'loginname' => $customer['loginname'], 'loginname' => $customer['loginname'],
'destdir' => $path, 'destdir' => $path,
'pgp_public_key' => $pgp_public_key, 'backup_dbs' => $backup_dbs,
'dump_dbs' => $dump_dbs, 'backup_mail' => $backup_mail,
'dump_mail' => $dump_mail, 'backup_web' => $backup_web
'dump_web' => $dump_web
]; ];
// schedule backup job
Cronjob::inserttask(TaskId::CREATE_CUSTOMER_BACKUP, $task_data);
// schedule export job $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added customer-backup job for '" . $customer['loginname'] . "'. Target directory: " . $userpath);
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 data dump is enabled systemwide and if accessible for customer (hide_options) * check whether backup is enabled systemwide and if accessible for customer (hide_options)
* *
* @throws Exception * @throws Exception
*/ */
private function validateAccess() private function validateAccess()
{ {
if (Settings::Get('system.exportenabled') != 1) { if (Settings::Get('system.backupenabled') != 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.export')) { if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras.backup')) {
throw new Exception("You cannot access this resource", 405); throw new Exception("You cannot access this resource", 405);
} }
} }
/** /**
* You cannot get a planned data export. * You cannot get a planned backup.
* Try DataDump.listing() * Try CustomerBackups.listing()
*/ */
public function get() public function get()
{ {
throw new Exception('You cannot get a planned data export. Try DataDump.listing()', 303); throw new Exception('You cannot get a planned backup. Try CustomerBackups.listing()', 303);
} }
/** /**
* You cannot update a planned data export. * You cannot update a planned backup.
* 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 data export. You need to delete it and re-add it.', 303); throw new Exception('You cannot update a planned backup. You need to delete it and re-add it.', 303);
} }
/** /**
* list all planned data export jobs, if called from an admin, list all planned data export jobs of all customers you are * list all planned backup-jobs, if called from an admin, list all planned backup-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 data export jobs of a specific customer by id * optional, admin-only, select backup-jobs of a specific customer by id
* @param string $loginname * @param string $loginname
* optional, admin-only, select data export jobs of a specific customer by loginname * optional, admin-only, select backup-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
@@ -199,9 +181,9 @@ class DataDump extends ApiCommand implements ResourceEntity
{ {
$this->validateAccess(); $this->validateAccess();
$customer_ids = $this->getAllowedCustomerIds('extras.export'); $customer_ids = $this->getAllowedCustomerIds('extras.backup');
// check whether there is a data export job for this customer // check whether there is a backup-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);
@@ -212,7 +194,7 @@ class DataDump extends ApiCommand implements ResourceEntity
$result[] = $entry; $result[] = $entry;
} }
} }
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list customer data dump jobs"); $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list customer-backups");
return $this->response([ return $this->response([
'count' => count($result), 'count' => count($result),
'list' => $result 'list' => $result
@@ -220,12 +202,12 @@ class DataDump extends ApiCommand implements ResourceEntity
} }
/** /**
* returns the total number of planned data exports * returns the total number of planned backups
* *
* @param int $customerid * @param int $customerid
* optional, admin-only, select data export jobs of a specific customer by id * optional, admin-only, select backup-jobs of a specific customer by id
* @param string $loginname * @param string $loginname
* optional, admin-only, select data export jobs of a specific customer by loginname * optional, admin-only, select backup-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
@@ -235,9 +217,9 @@ class DataDump extends ApiCommand implements ResourceEntity
{ {
$this->validateAccess(); $this->validateAccess();
$customer_ids = $this->getAllowedCustomerIds('extras.export'); $customer_ids = $this->getAllowedCustomerIds('extras.backup');
// check whether there is a data export job for this customer // check whether there is a backup-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);
@@ -251,10 +233,10 @@ class DataDump extends ApiCommand implements ResourceEntity
} }
/** /**
* delete a planned data export jobs by id, if called from an admin you need to specify the customerid/loginname * delete a planned backup-jobs by id, if called from an admin you need to specify the customerid/loginname
* *
* @param int $job_entry * @param int $backup_job_entry
* id of data export job * id of backup 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
@@ -266,26 +248,26 @@ class DataDump extends ApiCommand implements ResourceEntity
*/ */
public function delete() public function delete()
{ {
// get planned exports // get planned backups
$result = $this->apiCall('DataDump.listing', $this->getParamList()); $result = $this->apiCall('CustomerBackups.listing', $this->getParamList());
$entry = $this->getParam('job_entry'); $entry = $this->getParam('backup_job_entry');
$customer_ids = $this->getAllowedCustomerIds('extras.export'); $customer_ids = $this->getAllowedCustomerIds('extras.backup');
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 $exportjob) { foreach ($result['list'] as $backupjob) {
if ($exportjob['id'] == $entry && in_array($exportjob['data']['customerid'], $customer_ids)) { if ($backupjob['id'] == $entry && in_array($backupjob['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 data export job #" . $entry); $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted planned customer-backup #" . $entry);
return $this->response(true); return $this->response(true);
} }
} }
} }
throw new Exception('Data export job with id #' . $entry . ' could not be found', 404); throw new Exception('Backup job with id #' . $entry . ' could not be found', 404);
} }
} }

View File

@@ -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 webspace, mail, mysql FROM `" . TABLE_PANEL_DISKSPACE . "` SELECT * FROM `" . TABLE_PANEL_DISKSPACE . "`
WHERE `customerid` = :cid WHERE `customerid` = :cid
ORDER BY `stamp` DESC LIMIT 1 ORDER BY `stamp` DESC LIMIT 1
"); ");
@@ -109,10 +109,11 @@ 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
$domains = Database::pexecute_first($domains_stmt, [ Database::pexecute($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, [
@@ -171,7 +172,6 @@ class Customers extends ApiCommand implements ResourceEntity
* create a new customer with default ftp-user and standard-subdomain (if wanted) * create a new customer with default ftp-user and standard-subdomain (if wanted)
* *
* @param string $email * @param string $email
* required, email address of new customer
* @param string $name * @param string $name
* optional if company is set, else required * optional if company is set, else required
* @param string $firstname * @param string $firstname
@@ -190,11 +190,8 @@ class Customers extends ApiCommand implements ResourceEntity
* optional * optional
* @param int $customernumber * @param int $customernumber
* optional * optional
* @param string $def_language * @param string $def_language ,
* optional, ISO 639-1 language code (e.g. 'en', 'de', see lng-folder for supported languages), * optional, default is system-default language
* default is system-default language
* @param bool $gui_access
* optional, allow login via webui, if false ONLY the login via webui is disallowed; default true
* @param bool $api_allowed * @param bool $api_allowed
* optional, default is true if system setting api.enabled is true, else false * optional, default is true if system setting api.enabled is true, else false
* @param int $gender * @param int $gender
@@ -301,7 +298,6 @@ 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'));
$gui_access = $this->getBoolParam('gui_access', true, 1);
$api_allowed = $this->getBoolParam('api_allowed', true, (Settings::Get('api.enabled') && Settings::Get('api.customer_default'))); $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, '');
@@ -404,13 +400,6 @@ 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) {
@@ -460,28 +449,6 @@ class Customers extends ApiCommand implements ResourceEntity
if (function_exists('posix_getpwnam') && !in_array("posix_getpwnam", explode(",", ini_get('disable_functions'))) && posix_getpwnam($loginname)) { if (function_exists('posix_getpwnam') && !in_array("posix_getpwnam", explode(",", ini_get('disable_functions'))) && posix_getpwnam($loginname)) {
Response::standardError('loginnameissystemaccount', $loginname, true); Response::standardError('loginnameissystemaccount', $loginname, true);
} }
// blacklist some system-internal names that might lead to issues
Database::needSqlData();
$sqldata = Database::getSqlData();
Database::needRoot(true);
Database::needSqlData();
$sqlrdata = Database::getSqlData();
$login_blacklist = [
'root',
'admin',
'froxroot',
'froxlor',
$sqldata['user'],
$sqldata['db'],
$sqlrdata['user'],
];
unset($sqldata);
unset($sqlrdata);
$login_blacklist = array_unique($login_blacklist);
if (in_array($loginname, $login_blacklist)) {
Response::standardError('loginnameisreservedname', $loginname, true);
}
} else { } else {
$accountnumber = intval(Settings::Get('system.lastaccountnumber')) + 1; $accountnumber = intval(Settings::Get('system.lastaccountnumber')) + 1;
$loginname = Settings::Get('customer.accountprefix') . $accountnumber; $loginname = Settings::Get('customer.accountprefix') . $accountnumber;
@@ -545,7 +512,6 @@ class Customers extends ApiCommand implements ResourceEntity
'email' => $email, 'email' => $email,
'customerno' => $customernumber, 'customerno' => $customernumber,
'lang' => $def_language, 'lang' => $def_language,
'gui_access' => $gui_access,
'api_allowed' => $api_allowed, 'api_allowed' => $api_allowed,
'docroot' => $documentroot, 'docroot' => $documentroot,
'guid' => $guid, 'guid' => $guid,
@@ -588,7 +554,6 @@ class Customers extends ApiCommand implements ResourceEntity
`email` = :email, `email` = :email,
`customernumber` = :customerno, `customernumber` = :customerno,
`def_language` = :lang, `def_language` = :lang,
`gui_access` = :gui_access,
`api_allowed` = :api_allowed, `api_allowed` = :api_allowed,
`documentroot` = :docroot, `documentroot` = :docroot,
`guid` = :guid, `guid` = :guid,
@@ -738,12 +703,11 @@ class Customers extends ApiCommand implements ResourceEntity
'adminid' => $this->getUserDetail('adminid'), 'adminid' => $this->getUserDetail('adminid'),
'docroot' => $documentroot, 'docroot' => $documentroot,
'phpenabled' => $phpenabled, 'phpenabled' => $phpenabled,
'openbasedir' => '1', 'openbasedir' => '1'
'is_stdsubdomain' => 1
]; ];
$domainid = -1; $domainid = -1;
try { try {
$std_domain = $this->apiCall('Domains.add', $ins_data, true); $std_domain = $this->apiCall('Domains.add', $ins_data);
$domainid = $std_domain['id']; $domainid = $std_domain['id'];
} catch (Exception $e) { } catch (Exception $e) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_ERR, "[API] Unable to add standard-subdomain: " . $e->getMessage()); $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_ERR, "[API] Unable to add standard-subdomain: " . $e->getMessage());
@@ -762,22 +726,6 @@ class Customers extends ApiCommand implements ResourceEntity
} }
} }
// Create default mysql-user if enabled
if ($mysqls != 0) {
foreach ($allowed_mysqlserver as $dbserver) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver, false);
// get DbManager
$dbm = new DbManager($this->logger());
// give permission to the user on every access-host we have
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
$dbm->getManager()->grantPrivilegesTo($loginname, $password, $mysql_access_host, false, false, true);
}
$dbm->getManager()->flushPrivileges();
Database::needRoot(false);
}
}
if ($sendpassword == '1') { if ($sendpassword == '1') {
$srv_hostname = Settings::Get('system.hostname'); $srv_hostname = Settings::Get('system.hostname');
if (Settings::Get('system.froxlordirectlyviahostname') == '0') { if (Settings::Get('system.froxlordirectlyviahostname') == '0') {
@@ -977,7 +925,6 @@ class Customers extends ApiCommand implements ResourceEntity
* @param string $loginname * @param string $loginname
* optional, the loginname * optional, the loginname
* @param string $email * @param string $email
* optional
* @param string $name * @param string $name
* optional if company is set, else required * optional if company is set, else required
* @param string $firstname * @param string $firstname
@@ -996,11 +943,8 @@ class Customers extends ApiCommand implements ResourceEntity
* optional * optional
* @param int $customernumber * @param int $customernumber
* optional * optional
* @param string $def_language * @param string $def_language ,
* * optional, ISO 639-1 language code (e.g. 'en', 'de', see lng-folder for supported languages), * optional, default is system-default language
* * default is system-default language
* @param bool $gui_access
* optional, allow login via webui, if false ONLY the login via webui is disallowed; default true
* @param bool $api_allowed * @param bool $api_allowed
* optional, default is true if system setting api.enabled is true, else false * optional, default is true if system setting api.enabled is true, else false
* @param int $gender * @param int $gender
@@ -1011,7 +955,7 @@ class Customers extends ApiCommand implements ResourceEntity
* optional, whether to show the content of custom_notes to the customer, default 0 * optional, whether to show the content of custom_notes to the customer, default 0
* (false) * (false)
* @param string $new_customer_password * @param string $new_customer_password
* optional, set new password * optional, iset new password
* @param bool $sendpassword * @param bool $sendpassword
* optional, whether to send the password to the customer after creation, default 0 * optional, whether to send the password to the customer after creation, default 0
* (false) * (false)
@@ -1106,7 +1050,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($name) && empty($firstname)) || (empty($name) && !empty($firstname)) || (empty($name) && empty($firstname)); $company_required = empty($result['company']) && ((!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']);
@@ -1115,7 +1059,6 @@ class Customers extends ApiCommand implements ResourceEntity
$fax = $this->getParam('fax', true, $result['fax']); $fax = $this->getParam('fax', true, $result['fax']);
$customernumber = $this->getParam('customernumber', true, $result['customernumber']); $customernumber = $this->getParam('customernumber', true, $result['customernumber']);
$def_language = $this->getParam('def_language', true, $result['def_language']); $def_language = $this->getParam('def_language', true, $result['def_language']);
$gui_access = $this->getBoolParam('gui_access', true, $result['gui_access']);
$api_allowed = $this->getBoolParam('api_allowed', true, $result['api_allowed']); $api_allowed = $this->getBoolParam('api_allowed', true, $result['api_allowed']);
$gender = (int)$this->getParam('gender', true, $result['gender']); $gender = (int)$this->getParam('gender', true, $result['gender']);
$custom_notes = $this->getParam('custom_notes', true, $result['custom_notes']); $custom_notes = $this->getParam('custom_notes', true, $result['custom_notes']);
@@ -1167,12 +1110,6 @@ 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)) {
@@ -1181,7 +1118,6 @@ 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);
@@ -1336,34 +1272,12 @@ class Customers extends ApiCommand implements ResourceEntity
]); ]);
$upd_stmt = Database::prepare(" $upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `deactivated`= :deactivated WHERE `customerid` = :customerid UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `deactivated`= :deactivated WHERE `customerid` = :customerid");
");
Database::pexecute($upd_stmt, [ Database::pexecute($upd_stmt, [
'deactivated' => $deactivated, 'deactivated' => $deactivated,
'customerid' => $id 'customerid' => $id
]); ]);
// enable/disable global mysql-user (loginname)
$current_allowed_mysqlserver = isset($result['allowed_mysqlserver']) && !empty($result['allowed_mysqlserver']) ? json_decode($result['allowed_mysqlserver'], true) : [];
foreach ($current_allowed_mysqlserver as $dbserver) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver, false);
// get DbManager
$dbm = new DbManager($this->logger());
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
// Prevent access, if deactivated
if ($deactivated) {
// failsafe if user has been deleted manually (requires MySQL 4.1.2+)
$dbm->getManager()->disableUser($result['loginname'], $mysql_access_host);
} else {
// Otherwise grant access
$dbm->getManager()->enableUser($result['loginname'], $mysql_access_host, true);
}
}
$dbm->getManager()->flushPrivileges();
Database::needRoot(false);
}
// Retrieve customer's databases // Retrieve customer's databases
$databases_stmt = Database::prepare("SELECT * FROM " . TABLE_PANEL_DATABASES . " WHERE customerid = :customerid ORDER BY `dbserver`"); $databases_stmt = Database::prepare("SELECT * FROM " . TABLE_PANEL_DATABASES . " WHERE customerid = :customerid ORDER BY `dbserver`");
Database::pexecute($databases_stmt, [ Database::pexecute($databases_stmt, [
@@ -1384,7 +1298,9 @@ class Customers extends ApiCommand implements ResourceEntity
$last_dbserver = $row_database['dbserver']; $last_dbserver = $row_database['dbserver'];
} }
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) { foreach (array_unique(explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
$mysql_access_host = trim($mysql_access_host);
// Prevent access, if deactivated // Prevent access, if deactivated
if ($deactivated) { if ($deactivated) {
// failsafe if user has been deleted manually (requires MySQL 4.1.2+) // failsafe if user has been deleted manually (requires MySQL 4.1.2+)
@@ -1473,7 +1389,6 @@ class Customers extends ApiCommand implements ResourceEntity
'logviewenabled' => $logviewenabled, 'logviewenabled' => $logviewenabled,
'custom_notes' => $custom_notes, 'custom_notes' => $custom_notes,
'custom_notes_show' => $custom_notes_show, 'custom_notes_show' => $custom_notes_show,
'gui_access' => $gui_access,
'api_allowed' => $api_allowed, 'api_allowed' => $api_allowed,
'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver) 'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver)
]; ];
@@ -1517,7 +1432,6 @@ class Customers extends ApiCommand implements ResourceEntity
`logviewenabled` = :logviewenabled, `logviewenabled` = :logviewenabled,
`custom_notes` = :custom_notes, `custom_notes` = :custom_notes,
`custom_notes_show` = :custom_notes_show, `custom_notes_show` = :custom_notes_show,
`gui_access` = :gui_access,
`api_allowed` = :api_allowed, `api_allowed` = :api_allowed,
`allowed_mysqlserver` = :allowed_mysqlserver"; `allowed_mysqlserver` = :allowed_mysqlserver";
$upd_query .= $admin_upd_query; $upd_query .= $admin_upd_query;
@@ -1675,21 +1589,6 @@ class Customers extends ApiCommand implements ResourceEntity
]); ]);
$id = $result['customerid']; $id = $result['customerid'];
// remove global mysql-user (loginname)
$current_allowed_mysqlserver = isset($result['allowed_mysqlserver']) && !empty($result['allowed_mysqlserver']) ? json_decode($result['allowed_mysqlserver'], true) : [];
foreach ($current_allowed_mysqlserver as $dbserver) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver, false);
// get DbManager
$dbm = new DbManager($this->logger());
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
$dbm->getManager()->deleteUser($result['loginname'], $mysql_access_host);
}
$dbm->getManager()->flushPrivileges();
Database::needRoot(false);
}
// remove all databases
$databases_stmt = Database::prepare(" $databases_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_DATABASES . "` SELECT * FROM `" . TABLE_PANEL_DATABASES . "`
WHERE `customerid` = :id ORDER BY `dbserver` WHERE `customerid` = :id ORDER BY `dbserver`
@@ -1705,8 +1604,8 @@ class Customers extends ApiCommand implements ResourceEntity
$priv_changed = false; $priv_changed = false;
while ($row_database = $databases_stmt->fetch(PDO::FETCH_ASSOC)) { while ($row_database = $databases_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($last_dbserver != $row_database['dbserver']) { if ($last_dbserver != $row_database['dbserver']) {
$dbm->getManager()->flushPrivileges();
Database::needRoot(true, $row_database['dbserver']); Database::needRoot(true, $row_database['dbserver']);
$dbm->getManager()->flushPrivileges();
$last_dbserver = $row_database['dbserver']; $last_dbserver = $row_database['dbserver'];
} }
$dbm->getManager()->deleteDatabase($row_database['databasename']); $dbm->getManager()->deleteDatabase($row_database['databasename']);

View File

@@ -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, $customer['documentroot']); $path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
if (!empty($error404path)) { if (!empty($error404path)) {
$error404path = $this->correctErrorDocument($error404path, true); $error404path = $this->correctErrorDocument($error404path, true);

View File

@@ -84,7 +84,7 @@ class DirProtections extends ApiCommand implements ResourceEntity
// validation // validation
$path = FileDir::makeCorrectDir(Validate::validate($path, 'path', Validate::REGEX_DIR, '', [], true)); $path = FileDir::makeCorrectDir(Validate::validate($path, 'path', Validate::REGEX_DIR, '', [], true));
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']); $path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
$username = Validate::validate($username, 'username', '/^[a-zA-Z0-9][a-zA-Z0-9\-_]+\$?$/', '', [], true); $username = Validate::validate($username, 'username', '/^[a-zA-Z0-9][a-zA-Z0-9\-_]+\$?$/', '', [], true);
$authname = Validate::validate($authname, 'directory_authname', '/^[a-zA-Z0-9][a-zA-Z0-9\-_ ]+\$?$/', '', [], true); $authname = Validate::validate($authname, 'directory_authname', '/^[a-zA-Z0-9][a-zA-Z0-9\-_ ]+\$?$/', '', [], true);
$password = Validate::validate($password, 'password', '', '', [], true); $password = Validate::validate($password, 'password', '', '', [], true);

View File

@@ -115,7 +115,7 @@ class DomainZones extends ApiCommand implements ResourceEntity
// validation // validation
$errors = []; $errors = [];
if (empty(trim($record))) { if (empty($record)) {
$record = "@"; $record = "@";
} }
@@ -227,7 +227,7 @@ class DomainZones extends ApiCommand implements ResourceEntity
// remove it for checks // remove it for checks
$content = substr($content, 0, -1); $content = substr($content, 0, -1);
} }
if (!empty($content) && !Validate::validateDomain($content)) { if (!Validate::validateDomain($content)) {
$errors[] = lng('error.dns_mx_needdom'); $errors[] = lng('error.dns_mx_needdom');
} else { } else {
// check whether there is a CNAME-record for the same resource // check whether there is a CNAME-record for the same resource
@@ -244,10 +244,6 @@ class DomainZones extends ApiCommand implements ResourceEntity
} }
// append trailing dot (again) // append trailing dot (again)
$content .= '.'; $content .= '.';
// if content is only ".", the prio needs to be 0 which results in a "null mx" entry
if ($content == '.' && $prio != 0) {
$prio = 0;
}
} elseif ($type == 'NS') { } elseif ($type == 'NS') {
// check for trailing dot // check for trailing dot
if (substr($content, -1) == '.') { if (substr($content, -1) == '.') {
@@ -306,8 +302,6 @@ 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);

View File

@@ -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` as `customer_deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`, `c`.`adminid` as customeradmin, `d`.*, `c`.`loginname`, `c`.`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 ips, default false * optional, return only ssl enabled ip's, 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,6 +190,9 @@ 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
@@ -207,7 +210,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 to include non-ssl specialsettings in the generated ssl-vhost, default false * optional, whether or not 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
@@ -216,7 +219,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 is considered a full path, not relative to customer-docroot. Also * aware, if path starts with / it it 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)
@@ -241,7 +244,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 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)
* @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
@@ -249,9 +252,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 to add subdomains to the HSTS header * optional whether or not to add subdomains to the HSTS header
* @param bool $hsts_preload * @param bool $hsts_preload
* optional whether to preload HSTS header value * optional whether or not 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
@@ -260,7 +263,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 to override system-tls settings like protocol, ssl-ciphers and if applicable * optional whether or not 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
@@ -274,8 +277,7 @@ class Domains extends ApiCommand implements ResourceEntity
* $override_tls is true * $override_tls is true
* @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 $is_stdsubdomain (internally) *
* optional whether this is a standard subdomain for a customer which is being added so no usage is decreased
* @access admin * @access admin
* @return string json-encoded array * @return string json-encoded array
* @throws Exception * @throws Exception
@@ -283,8 +285,7 @@ class Domains extends ApiCommand implements ResourceEntity
public function add() public function add()
{ {
if ($this->isAdmin()) { if ($this->isAdmin()) {
$is_stdsubdomain = $this->isInternal() ? $this->getBoolParam('is_stdsubdomain', true, 0) : false; if ($this->getUserDetail('domains_used') < $this->getUserDetail('domains') || $this->getUserDetail('domains') == '-1') {
if ($is_stdsubdomain || $this->getUserDetail('domains_used') < $this->getUserDetail('domains') || $this->getUserDetail('domains') == '-1') {
// parameters // parameters
$p_domain = $this->getParam('domain'); $p_domain = $this->getParam('domain');
@@ -297,6 +298,7 @@ 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);
@@ -318,9 +320,9 @@ class Domains extends ApiCommand implements ResourceEntity
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1); $mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, 0); $ssl_redirect = $this->getBoolParam('ssl_redirect', true, 0);
$letsencrypt = $this->getBoolParam('letsencrypt', true, 0); $letsencrypt = $this->getBoolParam('letsencrypt', true, 0);
$sslenabled = $this->getBoolParam('sslenabled', true, 1);
$dont_use_default_ssl_ipandport_if_empty = $this->getBoolParam('dont_use_default_ssl_ipandport_if_empty', true, 0); $dont_use_default_ssl_ipandport_if_empty = $this->getBoolParam('dont_use_default_ssl_ipandport_if_empty', true, 0);
$p_ssl_ipandports = $this->getParam('ssl_ipandport', true, $dont_use_default_ssl_ipandport_if_empty ? [] : explode(',', Settings::Get('system.defaultsslip'))); $p_ssl_ipandports = $this->getParam('ssl_ipandport', true, $dont_use_default_ssl_ipandport_if_empty ? [] : explode(',', Settings::Get('system.defaultsslip')));
$sslenabled = $this->getBoolParam('sslenabled', true, 1);
$http2 = $this->getBoolParam('http2', true, 0); $http2 = $this->getBoolParam('http2', true, 0);
$hsts_maxage = $this->getParam('hsts_maxage', true, 0); $hsts_maxage = $this->getParam('hsts_maxage', true, 0);
$hsts_sub = $this->getBoolParam('hsts_sub', true, 0); $hsts_sub = $this->getBoolParam('hsts_sub', true, 0);
@@ -351,8 +353,6 @@ 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();
@@ -521,8 +521,7 @@ class Domains extends ApiCommand implements ResourceEntity
$mod_fcgid_maxrequests = '-1'; $mod_fcgid_maxrequests = '-1';
} }
} else { } else {
// set default to whether the customer has php enabled or not $phpenabled = '1';
$phpenabled = $customer['phpenabled'];
$openbasedir = '1'; $openbasedir = '1';
if ((int)Settings::Get('phpfpm.enabled') == 1) { if ((int)Settings::Get('phpfpm.enabled') == 1) {
@@ -549,10 +548,6 @@ 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;
@@ -670,6 +665,10 @@ 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([
@@ -724,6 +723,7 @@ class Domains extends ApiCommand implements ResourceEntity
'phpsettingid' => $phpsettingid, 'phpsettingid' => $phpsettingid,
'mod_fcgid_starter' => $mod_fcgid_starter, 'mod_fcgid_starter' => $mod_fcgid_starter,
'mod_fcgid_maxrequests' => $mod_fcgid_maxrequests, 'mod_fcgid_maxrequests' => $mod_fcgid_maxrequests,
'ismainbutsubto' => $issubof,
'letsencrypt' => $letsencrypt, 'letsencrypt' => $letsencrypt,
'http2' => $http2, 'http2' => $http2,
'hsts' => $hsts_maxage, 'hsts' => $hsts_maxage,
@@ -777,6 +777,7 @@ 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,
@@ -797,15 +798,12 @@ class Domains extends ApiCommand implements ResourceEntity
$ins_data['id'] = $domainid; $ins_data['id'] = $domainid;
unset($ins_data); unset($ins_data);
if (!$is_stdsubdomain) {
$upd_stmt = Database::prepare(" $upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_ADMINS . "` SET `domains_used` = `domains_used` + 1 UPDATE `" . TABLE_PANEL_ADMINS . "` SET `domains_used` = `domains_used` + 1
WHERE `adminid` = :adminid WHERE `adminid` = :adminid");
");
Database::pexecute($upd_stmt, [ Database::pexecute($upd_stmt, [
'adminid' => $adminid 'adminid' => $adminid
], true, true); ], true, true);
}
$ins_stmt = Database::prepare(" $ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_DOMAINTOIP . "` SET INSERT INTO `" . TABLE_DOMAINTOIP . "` SET
@@ -836,9 +834,6 @@ class Domains extends ApiCommand implements ResourceEntity
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
Cronjob::inserttask(TaskId::REBUILD_DNS); Cronjob::inserttask(TaskId::REBUILD_DNS);
if ($dkim == '1') {
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
}
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added domain '" . $domain . "'"); $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added domain '" . $domain . "'");
@@ -1074,6 +1069,9 @@ 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
@@ -1091,7 +1089,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 to include non-ssl specialsettings in the generated ssl-vhost, default false * optional, whether or not 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
@@ -1103,7 +1101,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 is considered a full path, not relative to customer-docroot. Also * aware, if path starts with / it it 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)
@@ -1132,7 +1130,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 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)
* @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
@@ -1140,9 +1138,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 to add subdomains to the HSTS header * optional whether or not to add subdomains to the HSTS header
* @param bool $hsts_preload * @param bool $hsts_preload
* optional whether to preload HSTS header value * optional whether or not 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
@@ -1152,8 +1150,6 @@ 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
@@ -1195,6 +1191,7 @@ 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']);
@@ -1222,7 +1219,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 = $remove_ssl_ipandport ? false : $this->getBoolParam('sslenabled', true, $result['ssl_enabled']); $sslenabled = $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']);
@@ -1249,7 +1246,6 @@ 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("
@@ -1416,7 +1412,7 @@ class Domains extends ApiCommand implements ResourceEntity
$zonefile = $result['zonefile']; $zonefile = $result['zonefile'];
} }
if (Settings::Get('antispam.activated') != '1') { if (Settings::Get('dkim.use_dkim') != '1') {
$dkim = $result['dkim']; $dkim = $result['dkim'];
} }
@@ -1532,16 +1528,13 @@ class Domains extends ApiCommand implements ResourceEntity
if ($remove_ssl_ipandport || (!empty($p_ssl_ipandports) && $p_ssl_ipandports[0] == -1)) { if ($remove_ssl_ipandport || (!empty($p_ssl_ipandports) && $p_ssl_ipandports[0] == -1)) {
$ssl_ipandports = []; $ssl_ipandports = [];
} }
if (Settings::Get('system.use_ssl') == "1" && $sslenabled && empty($ssl_ipandports)) { if (Settings::Get('system.use_ssl') == "0" || 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;
// act like $remove_ssl_ipandport // we need this for the json_encode
$ssl_ipandports = []; // if ssl is disabled or no ssl-ip/port exists
$ssl_ipandports[] = -1;
// HSTS // HSTS
$hsts_maxage = 0; $hsts_maxage = 0;
@@ -1571,7 +1564,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 (($result['letsencrypt'] != $letsencrypt || $result['ssl_redirect'] != $ssl_redirect) && $ssl_redirect > 0 && $letsencrypt == 1) { if ($ssl_redirect > 0 && $letsencrypt == 1 && $result['letsencrypt'] != $letsencrypt) {
$ssl_redirect = 2; $ssl_redirect = 2;
} }
@@ -1647,6 +1640,10 @@ 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';
} }
@@ -1660,7 +1657,6 @@ class Domains extends ApiCommand implements ResourceEntity
|| $iswildcarddomain != $result['iswildcarddomain'] || $iswildcarddomain != $result['iswildcarddomain']
|| $phpenabled != $result['phpenabled'] || $phpenabled != $result['phpenabled']
|| $openbasedir != $result['openbasedir'] || $openbasedir != $result['openbasedir']
|| $openbasedir_path != $result['openbasedir_path']
|| $phpsettingid != $result['phpsettingid'] || $phpsettingid != $result['phpsettingid']
|| $mod_fcgid_starter != $result['mod_fcgid_starter'] || $mod_fcgid_starter != $result['mod_fcgid_starter']
|| $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests'] || $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests']
@@ -1670,6 +1666,7 @@ class Domains extends ApiCommand implements ResourceEntity
|| $writeaccesslog != $result['writeaccesslog'] || $writeaccesslog != $result['writeaccesslog']
|| $writeerrorlog != $result['writeerrorlog'] || $writeerrorlog != $result['writeerrorlog']
|| $aliasdomain != $result['aliasdomain'] || $aliasdomain != $result['aliasdomain']
|| $issubof != $result['ismainbutsubto']
|| $email_only != $result['email_only'] || $email_only != $result['email_only']
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1') || ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|| $letsencrypt != $result['letsencrypt'] || $letsencrypt != $result['letsencrypt']
@@ -1678,15 +1675,10 @@ class Domains extends ApiCommand implements ResourceEntity
|| $hsts_sub != $result['hsts_sub'] || $hsts_sub != $result['hsts_sub']
|| $hsts_preload != $result['hsts_preload'] || $hsts_preload != $result['hsts_preload']
|| $ocsp_stapling != $result['ocsp_stapling'] || $ocsp_stapling != $result['ocsp_stapling']
|| $sslenabled != $result['ssl_enabled']
) { ) {
Cronjob::inserttask(TaskId::REBUILD_VHOST); Cronjob::inserttask(TaskId::REBUILD_VHOST);
} }
if ($dkim != $result['dkim']) {
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
}
if ($speciallogfile != $result['speciallogfile'] && $speciallogverified != '1') { if ($speciallogfile != $result['speciallogfile'] && $speciallogverified != '1') {
$speciallogfile = $result['speciallogfile']; $speciallogfile = $result['speciallogfile'];
} }
@@ -1831,7 +1823,7 @@ class Domains extends ApiCommand implements ResourceEntity
$update_data['wwwserveralias'] = $wwwserveralias; $update_data['wwwserveralias'] = $wwwserveralias;
$update_data['iswildcarddomain'] = $iswildcarddomain; $update_data['iswildcarddomain'] = $iswildcarddomain;
$update_data['phpenabled'] = $phpenabled; $update_data['phpenabled'] = $phpenabled;
$update_data['openbasedir'] = $openbasedir; $update_data['openbasedir'] = $openbasedir;;
$update_data['openbasedir_path'] = $openbasedir_path; $update_data['openbasedir_path'] = $openbasedir_path;
$update_data['speciallogfile'] = $speciallogfile; $update_data['speciallogfile'] = $speciallogfile;
$update_data['phpsettingid'] = $phpsettingid; $update_data['phpsettingid'] = $phpsettingid;
@@ -1845,6 +1837,7 @@ 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;
@@ -1859,7 +1852,6 @@ 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("
@@ -1893,6 +1885,7 @@ 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,
@@ -1906,36 +1899,11 @@ 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;
@@ -1953,7 +1921,6 @@ 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 = '';
@@ -1986,8 +1953,7 @@ 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
"); ");
@@ -2107,11 +2073,12 @@ 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
* @param bool $delete_userfiles
* optional, delete email account files on filesystem (if any), default false
* *
* @access admin * @access admin
* @return string json-encoded array * @return string json-encoded array
@@ -2123,8 +2090,8 @@ class Domains extends ApiCommand implements ResourceEntity
$id = $this->getParam('id', true, 0); $id = $this->getParam('id', true, 0);
$dn_optional = $id > 0; $dn_optional = $id > 0;
$domainname = $this->getParam('domainname', $dn_optional, ''); $domainname = $this->getParam('domainname', $dn_optional, '');
$is_stdsubdomain = $this->getBoolParam('is_stdsubdomain', true, 0); $is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0);
$delete_user_emailfiles = $this->getBoolParam('delete_userfiles', 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,
@@ -2132,10 +2099,15 @@ 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) WHERE (`id` = :id OR `parentdomainid` = :id " . $rsd_sql . ")");
");
Database::pexecute($subresult_stmt, [ Database::pexecute($subresult_stmt, [
'id' => $id 'id' => $id
], true, true); ], true, true);
@@ -2148,14 +2120,6 @@ class Domains extends ApiCommand implements ResourceEntity
$idString = implode(' OR ', $idString); $idString = implode(' OR ', $idString);
if ($idString != '') { if ($idString != '') {
if ($delete_user_emailfiles) {
// determine all connected email-accounts
$emailaccount_sel = Database::prepare("SELECT `email`, `homedir`, `maildir` FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString);
Database::pexecute($emailaccount_sel, $paramString, true, true);
while ($emailacc_row = $emailaccount_sel->fetch(PDO::FETCH_ASSOC)) {
Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $emailacc_row['email'], FileDir::makeCorrectDir($emailacc_row['homedir'] . '/' . $emailacc_row['maildir']));
}
}
$del_stmt = Database::prepare(" $del_stmt = Database::prepare("
DELETE FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString); DELETE FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString);
Database::pexecute($del_stmt, $paramString, true, true); Database::pexecute($del_stmt, $paramString, true, true);
@@ -2165,10 +2129,23 @@ 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 WHERE `id` = :id OR `parentdomainid` = :id " . $rsd_sql);
");
Database::pexecute($del_stmt, [ Database::pexecute($del_stmt, [
'id' => $id 'id' => $id
], true, true); ], true, true);
@@ -2253,118 +2230,4 @@ 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);
}
} }

View File

@@ -95,13 +95,9 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
$customer = $this->getCustomerData('email_accounts'); $customer = $this->getCustomerData('email_accounts');
// check for imap||pop3 == 1, see #1298 // check for imap||pop3 == 1, see #1298
// d00p, 6.5.2023 @revert this - if a customer has resources which allow email accounts
// it implicitly allowed SMTP, e.g. sending of emails which also requires an account to exist
/*
if ($customer['imap'] != '1' && $customer['pop3'] != '1') { if ($customer['imap'] != '1' && $customer['pop3'] != '1') {
Response::standardError('notallowedtouseaccounts', '', true); Response::standardError('notallowedtouseaccounts', '', true);
} }
*/
if (!empty($emailaddr)) { if (!empty($emailaddr)) {
$idna_convert = new IdnaWrapper(); $idna_convert = new IdnaWrapper();
@@ -157,10 +153,10 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
// prefix hash-algo // prefix hash-algo
switch (Settings::Get('system.passwordcryptfunc')) { switch (Settings::Get('system.passwordcryptfunc')) {
case 'argon2i': case PASSWORD_ARGON2I:
$cpPrefix = '{ARGON2I}'; $cpPrefix = '{ARGON2I}';
break; break;
case 'argon2id': case PASSWORD_ARGON2ID:
$cpPrefix = '{ARGON2ID}'; $cpPrefix = '{ARGON2ID}';
break; break;
default: default:
@@ -404,10 +400,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 'argon2i': case PASSWORD_ARGON2I:
$cpPrefix = '{ARGON2I}'; $cpPrefix = '{ARGON2I}';
break; break;
case 'argon2id': case PASSWORD_ARGON2ID:
$cpPrefix = '{ARGON2ID}'; $cpPrefix = '{ARGON2ID}';
break; break;
default: default:
@@ -523,7 +519,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
$result = $this->apiCall('Emails.get', [ $result = $this->apiCall('Emails.get', [
'id' => $id, 'id' => $id,
'emailaddr' => $emailaddr 'emailaddr' => $emailaddr
], true); ]);
$id = $result['id']; $id = $result['id'];
if (empty($result['popaccountid']) || $result['popaccountid'] == 0) { if (empty($result['popaccountid']) || $result['popaccountid'] == 0) {
@@ -563,7 +559,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
} }
if ($delete_userfiles) { if ($delete_userfiles) {
Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $customer['loginname'], FileDir::makeCorrectDir($result['homedir'] . '/' . $result['maildir'])); Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $customer['loginname'], $result['email_full']);
} }
// decrease usage for customer // decrease usage for customer

View File

@@ -69,7 +69,7 @@ class EmailDomains extends ApiCommand implements ResourceEntity
$result = []; $result = [];
$query_fields = []; $query_fields = [];
$result_stmt = Database::prepare(" $result_stmt = Database::prepare("
SELECT DISTINCT d.domain, d.domain_ace, e.domainid, SELECT DISTINCT d.domain, e.domainid,
COUNT(e.email) as addresses, COUNT(e.email) as addresses,
IFNULL(SUM(CASE WHEN e.popaccountid > 0 THEN 1 ELSE 0 END), 0) as accounts, IFNULL(SUM(CASE WHEN e.popaccountid > 0 THEN 1 ELSE 0 END), 0) as accounts,
IFNULL(SUM( IFNULL(SUM(

View File

@@ -28,12 +28,10 @@ namespace Froxlor\Api\Commands;
use Exception; use Exception;
use Froxlor\Api\ApiCommand; use Froxlor\Api\ApiCommand;
use Froxlor\Api\ResourceEntity; use Froxlor\Api\ResourceEntity;
use Froxlor\Cron\TaskId;
use Froxlor\Database\Database; use Froxlor\Database\Database;
use Froxlor\FroxlorLogger; use Froxlor\FroxlorLogger;
use Froxlor\Idna\IdnaWrapper; use Froxlor\Idna\IdnaWrapper;
use Froxlor\Settings; use Froxlor\Settings;
use Froxlor\System\Cronjob;
use Froxlor\UI\Response; use Froxlor\UI\Response;
use Froxlor\Validate\Validate; use Froxlor\Validate\Validate;
use PDO; use PDO;
@@ -51,16 +49,6 @@ class Emails extends ApiCommand implements ResourceEntity
* name of the address before @ * name of the address before @
* @param string $domain * @param string $domain
* domain-name for the email-address * domain-name for the email-address
* @param float $spam_tag_level
* optional, score which is required to tag emails as spam, default: 7.0
* @param bool $rewrite_subject
* optional, whether to add ***SPAM*** to the email's subject if applicable, default true
* @param float $spam_kill_level
* optional, score which is required to discard emails, default: 14.0
* @param boolean $bypass_spam
* optional, disable spam-filter entirely, default: no
* @param boolean $policy_greylist
* optional, enable grey-listing, default: yes
* @param boolean $iscatchall * @param boolean $iscatchall
* optional, make this address a catchall address, default: no * optional, make this address a catchall address, default: no
* @param int $customerid * @param int $customerid
@@ -86,31 +74,23 @@ class Emails extends ApiCommand implements ResourceEntity
$domain = $this->getParam('domain'); $domain = $this->getParam('domain');
// parameters // parameters
$spam_tag_level = $this->getParam('spam_tag_level', true, '7.0');
$rewrite_subject = $this->getBoolParam('rewrite_subject', true, 1);
$spam_kill_level = $this->getUlParam('spam_kill_level', 'spam_kill_level_ul', true, '14.0');
$bypass_spam = $this->getBoolParam('bypass_spam', true, 0);
$policy_greylist = $this->getBoolParam('policy_greylist', true, 1);
$iscatchall = $this->getBoolParam('iscatchall', true, 0); $iscatchall = $this->getBoolParam('iscatchall', true, 0);
$disablegreylist = $this->getBoolParam('disablegreylist', true, 0);
$description = $this->getParam('description', true, ''); $description = $this->getParam('description', true, '');
// validation // validation
$idna_convert = new IdnaWrapper();
if (substr($domain, 0, 4) != 'xn--') { if (substr($domain, 0, 4) != 'xn--') {
$idna_convert = new IdnaWrapper();
$domain = $idna_convert->encode(Validate::validate($domain, 'domain', '', '', [], true)); $domain = $idna_convert->encode(Validate::validate($domain, 'domain', '', '', [], true));
} }
$email_part = $idna_convert->encode($email_part);
// check domain and whether it's an email-enabled domain // check domain and whether it's an email-enabled domain
// use internal call because the customer might have 'domains' in customer_hide_options // use internal call because the customer might have 'domains' in customer_hide_options
$domain_check = $this->apiCall('SubDomains.get', [ $domain_check = $this->apiCall('SubDomains.get', [
'domainname' => $domain 'domainname' => $domain
], true); ], true);
if ((int)$domain_check['isemaildomain'] == 0) { if ($domain_check['isemaildomain'] == 0) {
Response::standardError('maindomainnonexist', $idna_convert->decode($domain), true); Response::standardError('maindomainnonexist', $domain, true);
}
if ((int)$domain_check['deactivated'] == 1) {
Response::standardError('maindomaindeactivated', $idna_convert->decode($domain), true);
} }
if (Settings::Get('catchall.catchall_enabled') != '1') { if (Settings::Get('catchall.catchall_enabled') != '1') {
@@ -131,7 +111,7 @@ class Emails extends ApiCommand implements ResourceEntity
// validate it // validate it
if (!Validate::validateEmail($email_full)) { if (!Validate::validateEmail($email_full)) {
Response::standardError('emailiswrong', $idna_convert->decode($email_full), true); Response::standardError('emailiswrong', $email_full, true);
} }
// get needed customer info to reduce the email-address-counter by one // get needed customer info to reduce the email-address-counter by one
@@ -139,7 +119,7 @@ class Emails extends ApiCommand implements ResourceEntity
// duplicate check // duplicate check
$stmt = Database::prepare(" $stmt = Database::prepare("
SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid` FROM `" . TABLE_MAIL_VIRTUAL . "` SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid`, `disablegreylist` FROM `" . TABLE_MAIL_VIRTUAL . "`
WHERE (`email` = :email OR `email_full` = :emailfull ) WHERE (`email` = :email OR `email_full` = :emailfull )
AND `customerid`= :cid AND `customerid`= :cid
"); ");
@@ -152,51 +132,36 @@ class Emails extends ApiCommand implements ResourceEntity
if ($email_check) { if ($email_check) {
if (strtolower($email_check['email_full']) == strtolower($email_full)) { if (strtolower($email_check['email_full']) == strtolower($email_full)) {
Response::standardError('emailexistalready', $idna_convert->decode($email_full), true); Response::standardError('emailexistalready', $email_full, true);
} elseif ($email_check['email'] == $email) { } elseif ($email_check['email'] == $email) {
Response::standardError('youhavealreadyacatchallforthisdomain', '', true); Response::standardError('youhavealreadyacatchallforthisdomain', '', true);
} }
} }
$spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1})?$/', '', [7.0], true);
if ($spam_kill_level > -1) {
$spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1})?$/', '', [14.0], true);
}
$description = Validate::validate(trim($description), 'description', Validate::REGEX_DESC_TEXT, '', [], true);
$stmt = Database::prepare(" $stmt = Database::prepare("
INSERT INTO `" . TABLE_MAIL_VIRTUAL . "` SET INSERT INTO `" . TABLE_MAIL_VIRTUAL . "` SET
`customerid` = :cid, `customerid` = :cid,
`email` = :email, `email` = :email,
`email_full` = :email_full, `email_full` = :email_full,
`spam_tag_level` = :spam_tag_level,
`rewrite_subject` = :rewrite_subject,
`spam_kill_level` = :spam_kill_level,
`bypass_spam` = :bypass_spam,
`policy_greylist` = :policy_greylist,
`iscatchall` = :iscatchall, `iscatchall` = :iscatchall,
`domainid` = :domainid, `domainid` = :domainid,
`description` = :description `description` = :description,
`disablegreylist` = :disablegreylist
"); ");
$params = [ $params = [
"cid" => $customer['customerid'], "cid" => $customer['customerid'],
"email" => $email, "email" => $email,
"email_full" => $email_full, "email_full" => $email_full,
"spam_tag_level" => $spam_tag_level,
"rewrite_subject" => $rewrite_subject,
"spam_kill_level" => $spam_kill_level,
"bypass_spam" => $bypass_spam,
"policy_greylist" => $policy_greylist,
"iscatchall" => $iscatchall, "iscatchall" => $iscatchall,
"domainid" => $domain_check['id'], "domainid" => $domain_check['id'],
"description" => $description "description" => $description,
"disablegreylist" => $disablegreylist
]; ];
Database::pexecute($stmt, $params, true, true); Database::pexecute($stmt, $params, true, true);
// update customer usage // update customer usage
Customers::increaseUsage($customer['customerid'], 'emails_used'); Customers::increaseUsage($customer['customerid'], 'emails_used');
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[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', [
@@ -229,12 +194,12 @@ class Emails extends ApiCommand implements ResourceEntity
$customer_ids = $this->getAllowedCustomerIds('email'); $customer_ids = $this->getAllowedCustomerIds('email');
$params['idea'] = ($id <= 0 ? $emailaddr : $id); $params['idea'] = ($id <= 0 ? $emailaddr : $id);
$result_stmt = Database::prepare("SELECT v.*, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize` " . ($this->isInternal() ? ", `u`.`homedir`, `u`.`maildir`" : "") . " $result_stmt = Database::prepare("SELECT v.`id`, v.`email`, v.`email_full`, v.`iscatchall`, v.`disablegreylist`, v.`destination`, v.`customerid`, v.`popaccountid`, v.`domainid`, v.`description`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
FROM `" . TABLE_MAIL_VIRTUAL . "` v FROM `" . TABLE_MAIL_VIRTUAL . "` v
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id` LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ") WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
AND " . (is_numeric($params['idea']) ? "v.`id`= :idea" : "(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_INFO, "[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'] . "'");
@@ -255,16 +220,6 @@ class Emails extends ApiCommand implements ResourceEntity
* 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
* optional, required when called as admin (if $customerid is not specified) * optional, required when called as admin (if $customerid is not specified)
* @param float $spam_tag_level
* optional, score which is required to tag emails as spam, default: 7.0
* @param bool $rewrite_subject
* optional, whether to add ***SPAM*** to the email's subject if applicable, default true
* @param float $spam_kill_level
* optional, score which is required to discard emails, default: 14.0
* @param boolean $bypass_spam
* optional, disable spam-filter entirely, default: no
* @param boolean $policy_greylist
* optional, enable grey-listing, default: yes
* @param boolean $iscatchall * @param boolean $iscatchall
* optional * optional
* @param string $description * @param string $description
@@ -280,6 +235,15 @@ class Emails extends ApiCommand implements ResourceEntity
throw new Exception("You cannot access this resource", 405); throw new Exception("You cannot access this resource", 405);
} }
// if enabling catchall is not allowed by settings, we do not need
// to run update()
if (Settings::Get('catchall.catchall_enabled') != '1') {
Response::standardError([
'operationnotpermitted',
'featureisdisabled'
], 'catchall', true);
}
$id = $this->getParam('id', true, 0); $id = $this->getParam('id', true, 0);
$ea_optional = $id > 0; $ea_optional = $id > 0;
$emailaddr = $this->getParam('emailaddr', $ea_optional, ''); $emailaddr = $this->getParam('emailaddr', $ea_optional, '');
@@ -291,33 +255,15 @@ class Emails extends ApiCommand implements ResourceEntity
$id = $result['id']; $id = $result['id'];
// parameters // parameters
$spam_tag_level = $this->getParam('spam_tag_level', true, $result['spam_tag_level']);
$rewrite_subject = $this->getBoolParam('rewrite_subject', true, $result['rewrite_subject']);
$spam_kill_level = $this->getUlParam('spam_kill_level', 'spam_kill_level_ul', true, $result['spam_kill_level']);
$bypass_spam = $this->getBoolParam('bypass_spam', true, $result['bypass_spam']);
$policy_greylist = $this->getBoolParam('policy_greylist', true, $result['policy_greylist']);
$iscatchall = $this->getBoolParam('iscatchall', true, $result['iscatchall']); $iscatchall = $this->getBoolParam('iscatchall', true, $result['iscatchall']);
$description = $this->getParam('description', true, $result['description']); $description = $this->getParam('description', true, $result['description']);
// if enabling catchall is not allowed by settings, we do not need
// to run update()
if ($iscatchall && $result['iscatchall'] == 0 && Settings::Get('catchall.catchall_enabled') != '1') {
Response::standardError([
'operationnotpermitted',
'featureisdisabled'
], 'catchall', true);
}
// get needed customer info to reduce the email-address-counter by one // get needed customer info to reduce the email-address-counter by one
$customer = $this->getCustomerData(); $customer = $this->getCustomerData();
// check for catchall-flag // check for catchall-flag
$email = $result['email_full'];
if ($iscatchall) { if ($iscatchall) {
$iscatchall = '1'; $iscatchall = '1';
$email = $result['email'];
// update only required if it was not a catchall before
if ($result['iscatchall'] == 0) {
$email_parts = explode('@', $result['email_full']); $email_parts = explode('@', $result['email_full']);
$email = '@' . $email_parts[1]; $email = '@' . $email_parts[1];
// catchall check // catchall check
@@ -333,41 +279,24 @@ class Emails extends ApiCommand implements ResourceEntity
if ($email_check) { if ($email_check) {
Response::standardError('youhavealreadyacatchallforthisdomain', '', true); Response::standardError('youhavealreadyacatchallforthisdomain', '', true);
} }
} else {
$iscatchall = '0';
$email = $result['email_full'];
} }
}
$spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1,2})?$/', '', [7.0], true);
if ($spam_kill_level > -1) {
$spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1,2})?$/', '', [14.0], true);
}
$description = Validate::validate(trim($description), 'description', Validate::REGEX_DESC_TEXT, '', [], true);
$stmt = Database::prepare(" $stmt = Database::prepare("
UPDATE `" . TABLE_MAIL_VIRTUAL . "` SET UPDATE `" . TABLE_MAIL_VIRTUAL . "`
`email` = :email , SET `email` = :email , `iscatchall` = :caflag, `description` = :description
`spam_tag_level` = :spam_tag_level,
`rewrite_subject` = :rewrite_subject,
`spam_kill_level` = :spam_kill_level,
`bypass_spam` = :bypass_spam,
`policy_greylist` = :policy_greylist,
`iscatchall` = :caflag,
`description` = :description
WHERE `customerid`= :cid AND `id`= :id WHERE `customerid`= :cid AND `id`= :id
"); ");
$params = [ $params = [
"email" => $email, "email" => $email,
"spam_tag_level" => $spam_tag_level,
"rewrite_subject" => $rewrite_subject,
"spam_kill_level" => $spam_kill_level,
"bypass_spam" => $bypass_spam,
"policy_greylist" => $policy_greylist,
"caflag" => $iscatchall, "caflag" => $iscatchall,
"description" => $description, "description" => $description,
"cid" => $customer['customerid'], "cid" => $customer['customerid'],
"id" => $id "id" => $id
]; ];
Database::pexecute($stmt, $params, true, true); Database::pexecute($stmt, $params, true, true);
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[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', [
@@ -376,6 +305,81 @@ class Emails extends ApiCommand implements ResourceEntity
return $this->response($result); return $this->response($result);
} }
/**
* toggle greylist flag of given email address either by id or email-address
*
* @param int $id
* optional, the email-address-id
* @param string $emailaddr
* optional, the email-address
* @param int $customerid
* optional, required when called as admin (if $loginname is not specified)
* @param string $loginname
* optional, required when called as admin (if $customerid is not specified)
* @param boolean $greylist
* optional
* @param string $description
* optional custom description (currently not used/shown in the frontend), default empty
*
* @access admin, customer
* @return string json-encoded array
* @throws Exception
*/
public function updateGreylist()
{
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
throw new Exception("You cannot access this resource", 405);
}
// if enabling catchall is not allowed by settings, we do not need
// to run update()
/** if (Settings::Get('catchall.catchall_enabled') != '1') {
Response::standardError([
'operationnotpermitted',
'featureisdisabled'
], 'catchall', true);
} */
$id = $this->getParam('id', true, 0);
$ea_optional = $id > 0;
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
$result = $this->apiCall('Emails.get', [
'id' => $id,
'emailaddr' => $emailaddr
]);
$id = $result['id'];
$email = $result['email'];
// parameters
$disablegreylist = $this->getBoolParam('disablegreylist', true, $result['disablegreylist']);
$description = $this->getParam('description', true, $result['description']);
// get needed customer info to reduce the email-address-counter by one
$customer = $this->getCustomerData();
// check for catchall-flag
$stmt = Database::prepare("
UPDATE `" . TABLE_MAIL_VIRTUAL . "`
SET `email` = :email , `disablegreylist` = :grflag, `description` = :description
WHERE `customerid`= :cid AND `id`= :id
");
$params = [
"email" => $email,
"grflag" => $disablegreylist,
"description" => $description,
"cid" => $customer['customerid'],
"id" => $id
];
Database::pexecute($stmt, $params, true, true);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] toggled greylist-flag for email address '" . $result['email_full'] . "'");
$result = $this->apiCall('Emails.get', [
'emailaddr' => $result['email_full']
]);
return $this->response($result);
}
/** /**
* list all email addresses, if called from an admin, list all email addresses of all customers you are allowed to * list all email addresses, if called from an admin, list all email addresses of all customers you are allowed to
* view, or specify id or loginname for one specific customer * view, or specify id or loginname for one specific customer
@@ -405,16 +409,13 @@ class Emails extends ApiCommand implements ResourceEntity
$result = []; $result = [];
$query_fields = []; $query_fields = [];
$result_stmt = Database::prepare(" $result_stmt = Database::prepare("
SELECT m.*, d.`domain`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize` SELECT m.`id`, m.`domainid`, m.`email`, m.`email_full`, m.`iscatchall`, m.`disablegreylist`, m.`destination`, m.`popaccountid`, d.`domain`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
FROM `" . TABLE_MAIL_VIRTUAL . "` m FROM `" . TABLE_MAIL_VIRTUAL . "` m
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`) LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`)
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`) LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`)
WHERE m.`customerid` IN (" . implode(", ", $customer_ids) . ")" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit()); WHERE m.`customerid` IN (" . implode(", ", $customer_ids) . ")" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
Database::pexecute($result_stmt, $query_fields, true, true); Database::pexecute($result_stmt, $query_fields, true, true);
$idna_convert = new IdnaWrapper();
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$row['email'] = $idna_convert->decode($row['email']);
$row['email_full'] = $idna_convert->decode($row['email_full']);
$result[] = $row; $result[] = $row;
} }
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list email-addresses"); $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list email-addresses");

View File

@@ -202,7 +202,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
// validation // validation
$description = Validate::validate($description, 'description', Validate::REGEX_DESC_TEXT, '', [], true); $description = Validate::validate($description, 'description', Validate::REGEX_DESC_TEXT, '', [], true);
$reload_cmd = Validate::validate($reload_cmd, 'reload_cmd', '/^[a-z0-9\/\._\-@ ]+$/i', '', [], true); $reload_cmd = Validate::validate($reload_cmd, 'reload_cmd', '/^[a-z0-9\/\._\- ]+$/i', '', [], true);
$sel_stmt = Database::prepare("SELECT `id` FROM `".TABLE_PANEL_FPMDAEMONS."` WHERE `reload_cmd` = :rc"); $sel_stmt = Database::prepare("SELECT `id` FROM `".TABLE_PANEL_FPMDAEMONS."` WHERE `reload_cmd` = :rc");
$dupcheck = Database::pexecute_first($sel_stmt, ['rc' => $reload_cmd]); $dupcheck = Database::pexecute_first($sel_stmt, ['rc' => $reload_cmd]);
if ($dupcheck && $dupcheck['id']) { if ($dupcheck && $dupcheck['id']) {
@@ -327,7 +327,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity
// validation // validation
$description = Validate::validate($description, 'description', Validate::REGEX_DESC_TEXT, '', [], true); $description = Validate::validate($description, 'description', Validate::REGEX_DESC_TEXT, '', [], true);
$reload_cmd = Validate::validate($reload_cmd, 'reload_cmd', '/^[a-z0-9\/\._\-@ ]+$/i', '', [], true); $reload_cmd = Validate::validate($reload_cmd, 'reload_cmd', '/^[a-z0-9\/\._\- ]+$/i', '', [], true);
$sel_stmt = Database::prepare("SELECT `id` FROM `".TABLE_PANEL_FPMDAEMONS."` WHERE `reload_cmd` = :rc"); $sel_stmt = Database::prepare("SELECT `id` FROM `".TABLE_PANEL_FPMDAEMONS."` WHERE `reload_cmd` = :rc");
$dupcheck = Database::pexecute_first($sel_stmt, ['rc' => $reload_cmd]); $dupcheck = Database::pexecute_first($sel_stmt, ['rc' => $reload_cmd]);
if ($dupcheck && $dupcheck['id'] != $id) { if ($dupcheck && $dupcheck['id'] != $id) {

View File

@@ -37,7 +37,6 @@ 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;
@@ -82,7 +81,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') != 'stable' ? Settings::Get('system.update_channel').' ' : ''), AutoUpdate::getFromResult('version'), $this->version]); $text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') == 'testing' ? 'testing ' : ''), 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,
@@ -259,91 +258,17 @@ 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 0 (panel.password_min_length) * optional length of password, defaults to 10
* *
* @access admin, customer * @access admin, customer
* @return string * @return string
* @throws Exception
*/ */
public function generatePassword(): string public function generatePassword()
{ {
$length = $this->getParam('length', true, 0); $length = $this->getParam('length', true, 10);
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
* *

View File

@@ -72,8 +72,6 @@ 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
@@ -86,7 +84,6 @@ 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
@@ -174,19 +171,18 @@ 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, $customer['documentroot']); $path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
$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, :loginenabled, :guid, :guid, :shell)"); VALUES (:customerid, :username, :description, :password, :homedir, 'y', :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
]; ];
@@ -393,8 +389,6 @@ 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
@@ -425,7 +419,6 @@ 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);
@@ -437,10 +430,6 @@ 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();
@@ -469,7 +458,7 @@ class Ftps extends ApiCommand implements ResourceEntity
// path update? // path update?
if ($path != '') { if ($path != '') {
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']); $path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
if ($path != $result['homedir']) { if ($path != $result['homedir']) {
$stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "` $stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "`
@@ -491,14 +480,13 @@ 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, `login_enabled` = :loginenabled SET `description` = :desc, `shell` = :shell
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);

View File

@@ -201,7 +201,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
// validation // validation
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true); $name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT); $description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_CONF_TEXT);
if (Settings::Get('system.mail_quota_enabled') != '1') { if (Settings::Get('system.mail_quota_enabled') != '1') {
$value_arr['email_quota'] = -1; $value_arr['email_quota'] = -1;
@@ -383,7 +383,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity
// validation // validation
$name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true); $name = Validate::validate(trim($name), 'name', Validate::REGEX_DESC_TEXT, '', [], true);
$description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_DESC_TEXT); $description = Validate::validate(str_replace("\r\n", "\n", $description), 'description', Validate::REGEX_CONF_TEXT);
if (Settings::Get('system.mail_quota_enabled') != '1') { if (Settings::Get('system.mail_quota_enabled') != '1') {
$value_arr['email_quota'] = -1; $value_arr['email_quota'] = -1;

View File

@@ -176,9 +176,8 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
if ((int)Settings::Get('system.use_ssl') == 1) { if ((int)Settings::Get('system.use_ssl') == 1) {
$ssl = (bool)$this->getBoolParam('ssl', true, 0); $ssl = (bool)$this->getBoolParam('ssl', true, 0);
$cert_optional = !($ssl && empty(Settings::Get('system.ssl_cert_file'))); $ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', !$ssl, ''), 'ssl_cert_file', '', '', [], true);
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', $cert_optional, ''), 'ssl_cert_file', '', '', [], true); $ssl_key_file = Validate::validate($this->getParam('ssl_key_file', !$ssl, ''), 'ssl_key_file', '', '', [], true);
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', $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, '');
@@ -416,9 +415,8 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity
if ((int)Settings::Get('system.use_ssl') == 1) { if ((int)Settings::Get('system.use_ssl') == 1) {
$ssl = (bool)$this->getBoolParam('ssl', true, $result['ssl']); $ssl = (bool)$this->getBoolParam('ssl', true, $result['ssl']);
$cert_optional = !($ssl && empty(Settings::Get('system.ssl_cert_file'))); $ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', !$ssl, $result['ssl_cert_file']), 'ssl_cert_file', '', '', [], true);
$ssl_cert_file = Validate::validate($this->getParam('ssl_cert_file', $cert_optional, $result['ssl_cert_file']), 'ssl_cert_file', '', '', [], true); $ssl_key_file = Validate::validate($this->getParam('ssl_key_file', !$ssl, $result['ssl_key_file']), 'ssl_key_file', '', '', [], true);
$ssl_key_file = Validate::validate($this->getParam('ssl_key_file', $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']);

View File

@@ -54,7 +54,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
* @param string $description * @param string $description
* optional, description for database * optional, description for database
* @param string $custom_suffix * @param string $custom_suffix
* optional, name for database if customer.mysqlprefix setting is set to "DBNAME" * optional, name for database
* @param bool $sendinfomail * @param bool $sendinfomail
* optional, send created resource-information to customer, default: false * optional, send created resource-information to customer, default: false
* @param int $customerid * @param int $customerid
@@ -110,9 +110,6 @@ class Mysqls extends ApiCommand implements ResourceEntity
$dbm = new DbManager($this->logger()); $dbm = new DbManager($this->logger());
if (strtoupper(Settings::Get('customer.mysqlprefix')) == 'DBNAME' && !empty($databasename)) { if (strtoupper(Settings::Get('customer.mysqlprefix')) == 'DBNAME' && !empty($databasename)) {
if (strlen($newdb_params['loginname'] . '_' . $databasename) > Database::getSqlUsernameLength()) {
throw new Exception("Database name cannot be longer than " . (Database::getSqlUsernameLength() - strlen($newdb_params['loginname'] . '_')) . " characters.", 406);
}
$username = $dbm->createDatabase($newdb_params['loginname'] . '_' . $databasename, $password, $dbserver); $username = $dbm->createDatabase($newdb_params['loginname'] . '_' . $databasename, $password, $dbserver);
} else { } else {
$username = $dbm->createDatabase($newdb_params['loginname'], $password, $dbserver, $newdb_params['mysql_lastaccountnumber']); $username = $dbm->createDatabase($newdb_params['loginname'], $password, $dbserver, $newdb_params['mysql_lastaccountnumber']);

View File

@@ -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 $pass_authorizationheader * @param bool $phpfpm_pass_authorizationheader
* optional whether to pass authorization header to webserver if FPM/FCGID 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,
* 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");
$pass_authorizationheader = $this->getBoolParam('pass_authorizationheader', true, 0); $fpm_pass_authorizationheader = $this->getBoolParam('phpfpm_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,6 +312,7 @@ 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);
@@ -376,7 +377,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' => $pass_authorizationheader, 'fpmpassauth' => $fpm_pass_authorizationheader,
'ofc' => $override_fpmconfig, 'ofc' => $override_fpmconfig,
'pm' => $pmanager, 'pm' => $pmanager,
'max_children' => $max_children, 'max_children' => $max_children,
@@ -463,7 +464,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 $pass_authorizationheader * @param bool $phpfpm_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,
@@ -515,7 +516,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']);
$pass_authorizationheader = $this->getBoolParam('pass_authorizationheader', true, $result['pass_authorizationheader']); $fpm_pass_authorizationheader = $this->getBoolParam('phpfpm_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']);
@@ -547,6 +548,7 @@ 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);
@@ -612,7 +614,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' => $pass_authorizationheader, 'fpmpassauth' => $fpm_pass_authorizationheader,
'ofc' => $override_fpmconfig, 'ofc' => $override_fpmconfig,
'pm' => $pmanager, 'pm' => $pmanager,
'max_children' => $max_children, 'max_children' => $max_children,

View File

@@ -67,8 +67,6 @@ class SubDomains extends ApiCommand implements ResourceEntity
* optional, php-settings-id, if empty the $domain value is used * optional, php-settings-id, if empty the $domain value is used
* @param int $redirectcode * @param int $redirectcode
* optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES * optional, redirect-code-id from TABLE_PANEL_REDIRECTCODES
* @param int $speciallogfile
* optional, whether to create an exclusive web-logfile for this domain (1) or not (0) or inherit value from parentdomain (2, default)
* @param bool $sslenabled * @param bool $sslenabled
* optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default * optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default
* 1 (true) * 1 (true)
@@ -109,7 +107,6 @@ class SubDomains extends ApiCommand implements ResourceEntity
$openbasedir_path = $this->getParam('openbasedir_path', true, 0); $openbasedir_path = $this->getParam('openbasedir_path', true, 0);
$phpsettingid = $this->getParam('phpsettingid', true, 0); $phpsettingid = $this->getParam('phpsettingid', true, 0);
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default')); $redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
$speciallogfile = intval($this->getParam('speciallogfile', true, 2));
$isemaildomain = $this->getParam('isemaildomain', true, 0); $isemaildomain = $this->getParam('isemaildomain', true, 0);
if (Settings::Get('system.use_ssl')) { if (Settings::Get('system.use_ssl')) {
$sslenabled = $this->getBoolParam('sslenabled', true, 1); $sslenabled = $this->getBoolParam('sslenabled', true, 1);
@@ -232,9 +229,6 @@ 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
@@ -279,11 +273,6 @@ 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
@@ -296,8 +285,6 @@ class SubDomains extends ApiCommand implements ResourceEntity
// assign default config // assign default config
$phpsid_result['phpsettingid'] = 1; $phpsid_result['phpsettingid'] = 1;
} }
if ($domain_check['phpenabled'] == 1) {
// check whether the customer has chosen its own php-config // check whether the customer has chosen its own php-config
if ($phpsettingid > 0 && $phpsettingid != $phpsid_result['phpsettingid']) { if ($phpsettingid > 0 && $phpsettingid != $phpsid_result['phpsettingid']) {
$phpsid_result['phpsettingid'] = intval($phpsettingid); $phpsid_result['phpsettingid'] = intval($phpsettingid);
@@ -315,7 +302,6 @@ class SubDomains extends ApiCommand implements ResourceEntity
Response::standardError('notallowedphpconfigused', '', true); Response::standardError('notallowedphpconfigused', '', true);
} }
} }
}
// actually insert domain // actually insert domain
$stmt = Database::prepare(" $stmt = Database::prepare("
@@ -365,7 +351,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" => $speciallogfile == 2 ? $domain_check['speciallogfile'] : $speciallogfile, "speciallogfile" => $domain_check['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'],
@@ -567,9 +553,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, $customer['documentroot']); $path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $completedomain);
} else { } else {
$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']); $path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
} }
} else { } else {
// no it's not, create a redirect // no it's not, create a redirect
@@ -602,11 +588,6 @@ 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)
@@ -664,8 +645,6 @@ 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']);
@@ -775,10 +754,6 @@ 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 = [
@@ -800,7 +775,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)$result['phpenabled'] == 1 && ((int)Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1)) { if ((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);
} }
@@ -811,21 +786,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
Domain::updateRedirectOfDomain($id, $redirectcode); Domain::updateRedirectOfDomain($id, $redirectcode);
} }
if ($path != $result['documentroot'] 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']) {
|| $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,
@@ -841,8 +802,7 @@ 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 = [
@@ -860,7 +820,6 @@ 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
]; ];
@@ -906,7 +865,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
} }
/** /**
* lists all customer domain/subdomain entries * lists all subdomain entries
* *
* @param bool $with_ips * @param bool $with_ips
* optional, default true * optional, default true
@@ -951,12 +910,17 @@ 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`.*'
@@ -968,6 +932,9 @@ 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`',
@@ -982,12 +949,9 @@ 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`',
'`d`.`email_only`',
]; ];
} }
$query_fields = []; $query_fields = [];
// prepare select statement // prepare select statement
@@ -998,7 +962,8 @@ class SubDomains extends ApiCommand implements ResourceEntity
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `da` ON `da`.`aliasdomain`=`d`.`id` LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `da` ON `da`.`aliasdomain`=`d`.`id`
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) . ")
" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit()); 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());
$result = []; $result = [];
Database::pexecute($domains_stmt, $query_fields, true, true); Database::pexecute($domains_stmt, $query_fields, true, true);
@@ -1082,8 +1047,10 @@ 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')) {
@@ -1092,20 +1059,22 @@ class SubDomains extends ApiCommand implements ResourceEntity
$customer_ids = [ $customer_ids = [
$this->getUserDetail('customerid') $this->getUserDetail('customerid')
]; ];
$customer_stdsubs = [
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
];
} }
if (!empty($customer_ids)) {
// prepare select statement // prepare select statement
$domains_stmt = Database::prepare(" $domains_stmt = Database::prepare("
SELECT COUNT(*) as num_subdom SELECT COUNT(*) as num_subdom
FROM `" . TABLE_PANEL_DOMAINS . "` `d` FROM `" . TABLE_PANEL_DOMAINS . "` `d`
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ") WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
AND `d`.`email_only` = '0'
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")
"); ");
$result = Database::pexecute_first($domains_stmt, null, true, true); $result = Database::pexecute_first($domains_stmt, null, true, true);
if ($result) { if ($result) {
return $this->response($result['num_subdom']); return $this->response($result['num_subdom']);
} }
}
return $this->response(0); return $this->response(0);
} }

View File

@@ -90,8 +90,6 @@ 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_INFO, "[API] list log-entries"); $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list log-entries");
@@ -225,7 +223,7 @@ class SysLog extends ApiCommand implements ResourceEntity
} }
$params['trunc'] = $truncatedate; $params['trunc'] = $truncatedate;
Database::pexecute($result_stmt, $params, true, true); Database::pexecute($result_stmt, $params, true, true);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] truncated the froxlor syslog"); $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] truncated the froxlor syslog");
return $this->response(true); return $this->response(true);
} }
throw new Exception("Not allowed to execute given command.", 403); throw new Exception("Not allowed to execute given command.", 403);

View File

@@ -112,11 +112,11 @@ class FroxlorRPC
* *
* @return bool * @return bool
*/ */
public static function validateAllowedFrom(array $allowed_from, string $remote_addr): bool private 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 direct matches // check for diret matches
if (in_array($remote_addr, $allowed_from)) { if (in_array($remote_addr, $allowed_from)) {
return true; return true;
} }

View File

@@ -25,18 +25,19 @@
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 PDO; use Froxlor\Database\Database;
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(OutputInterface $output, bool $ignore_has_updates = false): int protected function validateRequirements(InputInterface $input, 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.</>");
@@ -115,11 +116,9 @@ class CliCommand extends Command
return $userinfo; return $userinfo;
} }
protected function runUpdate(OutputInterface $output, bool $manual = false): int private function runUpdate(OutputInterface $output): int
{ {
if (!$manual) {
$output->writeln('<comment>Automatic update is activated and we are going to proceed without any notices</>'); $output->writeln('<comment>Automatic update is activated and we are going to proceed without any notices</>');
}
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php'; include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
define('_CRON_UPDATE', 1); define('_CRON_UPDATE', 1);
ob_start([ ob_start([
@@ -128,11 +127,11 @@ class CliCommand extends Command
]); ]);
include_once Froxlor::getInstallDir() . '/install/updatesql.php'; include_once Froxlor::getInstallDir() . '/install/updatesql.php';
ob_end_flush(); ob_end_flush();
$output->writeln('<info>' . ($manual ? 'Database' : 'Automatic') . ' update done - you should check your settings to be sure everything is fine</>'); $output->writeln('<info>Automatic update done - you should check your settings to be sure everything is fine</>');
return self::SUCCESS; return self::SUCCESS;
} }
private function cleanUpdateOutput($buffer): string private function cleanUpdateOutput($buffer)
{ {
return strip_tags(preg_replace("/<br\W*?\/>/", "\n", $buffer)); return strip_tags(preg_replace("/<br\W*?\/>/", "\n", $buffer));
} }

View File

@@ -45,9 +45,6 @@ final class ConfigDiff extends CliCommand
->addOption('diff-params', '', InputOption::VALUE_REQUIRED, 'Additional parameters for `diff`, e.g. --diff-params="--color=always"'); ->addOption('diff-params', '', InputOption::VALUE_REQUIRED, 'Additional parameters for `diff`, e.g. --diff-params="--color=always"');
} }
/**
* @throws \Exception
*/
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
require Froxlor::getInstallDir() . '/lib/functions.php'; require Froxlor::getInstallDir() . '/lib/functions.php';

View File

@@ -25,7 +25,6 @@
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;
@@ -41,12 +40,14 @@ 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',
'bullseye', 'bullseye',
'buster',
'focal', 'focal',
'jammy', 'jammy',
'noble',
]; ];
protected function configure() protected function configure()
@@ -61,9 +62,11 @@ 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): int protected function execute(InputInterface $input, OutputInterface $output)
{ {
$result = $this->validateRequirements($output); $result = self::SUCCESS;
$result = $this->validateRequirements($input, $output);
require Froxlor::getInstallDir() . '/lib/functions.php'; require Froxlor::getInstallDir() . '/lib/functions.php';
@@ -90,7 +93,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($output, $io); $result = $this->createConfig($input, $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')) {
@@ -155,10 +158,7 @@ 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' => ""
@@ -171,8 +171,8 @@ final class ConfigServices extends CliCommand
$distributions_select_data = []; $distributions_select_data = [];
//set default os. //set default os.
$os_dist = ['ID' => 'bookworm']; $os_dist = ['ID' => 'bullseye'];
$os_version = ['0' => '12']; $os_version = ['0' => '11'];
$os_default = $os_dist['ID']; $os_default = $os_dist['ID'];
//read os-release //read os-release
@@ -217,10 +217,6 @@ final class ConfigServices extends CliCommand
$_daemons_config['distro'] = $io->choice('Choose distribution', $valid_dists, $os_default); $_daemons_config['distro'] = $io->choice('Choose distribution', $valid_dists, $os_default);
// go through all services and let user check whether to include it or not // go through all services and let user check whether to include it or not
if (empty($_daemons_config['distro']) || !file_exists($config_dir . '/' . $_daemons_config['distro']. ".xml")) {
$output->writeln('<error>Empty or non-existing distribution given.</>');
return self::INVALID;
}
$configfiles = new ConfigParser($config_dir . '/' . $_daemons_config['distro'] . ".xml"); $configfiles = new ConfigParser($config_dir . '/' . $_daemons_config['distro'] . ".xml");
$services = $configfiles->getServices(); $services = $configfiles->getServices();
@@ -289,10 +285,7 @@ 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');
@@ -356,12 +349,7 @@ final class ConfigServices extends CliCommand
} }
if (!empty($decoded_config)) { if (!empty($decoded_config)) {
$config_dir = Froxlor::getInstallDir() . 'lib/configfiles/'; $config_dir = Froxlor::getInstallDir() . 'lib/configfiles/';
if (empty($decoded_config['distro']) || !file_exists($config_dir . '/' . $decoded_config['distro']. ".xml")) {
$output->writeln('<error>Empty or non-existing distribution given. Please login with an admin, go to "System -> Configuration" and select your correct distribution in the top-right corner or specify valid distribution name for "distro" parameter.</>');
return self::INVALID;
}
$configfiles = new ConfigParser($config_dir . '/' . $decoded_config['distro'] . ".xml"); $configfiles = new ConfigParser($config_dir . '/' . $decoded_config['distro'] . ".xml");
$services = $configfiles->getServices(); $services = $configfiles->getServices();
$replace_arr = $this->getReplacerArray(); $replace_arr = $this->getReplacerArray();
@@ -410,7 +398,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)) . PHP_EOL); file_put_contents($action['name'], trim(strtr($action['content'], $replace_arr)));
} 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") {
@@ -419,7 +407,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)) . PHP_EOL); file_put_contents($fileaction['name'], trim(strtr($fileaction['content'], $replace_arr)));
} }
} }
} }
@@ -441,10 +429,7 @@ 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') != '') {
@@ -453,7 +438,7 @@ final class ConfigServices extends CliCommand
$customer_tmpdir = Settings::Get('phpfpm.tmpdir'); $customer_tmpdir = Settings::Get('phpfpm.tmpdir');
} }
// try to convert nameserver hosts to ip's // try to convert namserver hosts to ip's
$ns_ips = ""; $ns_ips = "";
$known_ns_ips = []; $known_ns_ips = [];
if (Settings::Get('system.nameservers') != '') { if (Settings::Get('system.nameservers') != '') {
@@ -499,12 +484,12 @@ final class ConfigServices extends CliCommand
Database::needSqlData(); Database::needSqlData();
$sql = Database::getSqlData(); $sql = Database::getSqlData();
return [ $replace_arr = [
'<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>' => $sql['socket'] ?? null, '<SQL_SOCKET>' => isset($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'),
@@ -522,7 +507,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;
} }
} }

View File

@@ -26,16 +26,13 @@
namespace Froxlor\Cli; namespace Froxlor\Cli;
use Exception; use Exception;
use Froxlor\Config\ConfigParser;
use Froxlor\Database\Database;
use Froxlor\Froxlor; use Froxlor\Froxlor;
use Froxlor\Config\ConfigParser;
use Froxlor\Install\Install; use Froxlor\Install\Install;
use Froxlor\Install\Install\Core; use Froxlor\Install\Install\Core;
use Froxlor\Settings;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
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,14 +50,10 @@ final class InstallCommand extends Command
$this->setDescription('Installation process to use instead of web-ui'); $this->setDescription('Installation process to use instead of web-ui');
$this->addArgument('input-file', InputArgument::OPTIONAL, 'Optional JSON array file to use for unattended installations'); $this->addArgument('input-file', InputArgument::OPTIONAL, 'Optional JSON array file to use for unattended installations');
$this->addOption('print-example-file', 'p', InputOption::VALUE_NONE, 'Outputs an example JSON content to be used with the input file parameter') $this->addOption('print-example-file', 'p', InputOption::VALUE_NONE, 'Outputs an example JSON content to be used with the input file parameter')
->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');
->addOption('show-sysinfo', 's', InputOption::VALUE_NONE, 'Outputs system information about your froxlor installation');
} }
/** protected function execute(InputInterface $input, OutputInterface $output)
* @throws Exception
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$result = self::SUCCESS; $result = self::SUCCESS;
@@ -76,15 +69,6 @@ final class InstallCommand extends Command
return self::INVALID; return self::INVALID;
} }
if ($input->getOption('show-sysinfo') !== false) {
if (!file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) {
$output->writeln("<error>Could not find froxlor's userdata.inc.php file. You can use this parameter only with an installed froxlor system.</>");
return self::INVALID;
}
$this->printSysInfo($output);
return self::SUCCESS;
}
session_start(); session_start();
require __DIR__ . '/install.functions.php'; require __DIR__ . '/install.functions.php';
@@ -153,12 +137,10 @@ final class InstallCommand extends Command
$decoded_input = []; $decoded_input = [];
} }
return $this->showStep(0, $extended, $decoded_input); $result = $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;
@@ -224,7 +206,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'] = $this->cliTextFormat($fielddata['label'], " "); $fielddata['label'] = strip_tags(str_replace("<br>", " ", $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) {
@@ -280,17 +262,15 @@ 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($this->cliTextFormat($section['description'])); $this->io->note($section['description']);
$cmdfield = $section['fields']['system']; $cmdfield = $section['fields']['system'];
$this->io->success([ $this->io->success([
$cmdfield['label'], $cmdfield['label'],
$cmdfield['value'] $cmdfield['value']
]); ]);
if (!isset($decoded_input['manual_config']) || (bool)$decoded_input['manual_config'] === false) {
if (!empty($decoded_input) || $this->io->confirm('Execute command now?', false)) { if (!empty($decoded_input) || $this->io->confirm('Execute command now?', false)) {
passthru($cmdfield['value']); passthru($cmdfield['value']);
} }
}
break; break;
} }
return $result; return $result;
@@ -320,7 +300,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 == 'target_servername') { if ($name == 'system' || $name == 'manual_config' || $name == 'target_servername') {
continue; continue;
} }
if ($field['type'] == 'text' || $field['type'] == 'email') { if ($field['type'] == 'text' || $field['type'] == 'email') {
@@ -361,61 +341,4 @@ final class InstallCommand extends Command
curl_close($ch); curl_close($ch);
fclose($fp); fclose($fp);
} }
private function printSysInfo(OutputInterface $output)
{
$php_sapi = 'mod_php';
$php_version = phpversion();
if (Settings::Get('system.mod_fcgid') == '1') {
$php_sapi = 'FCGID';
if (Settings::Get('system.mod_fcgid_ownvhost') == '1') {
$php_sapi .= ' (+ froxlor)';
}
} elseif (Settings::Get('phpfpm.enabled') == '1') {
$php_sapi = 'PHP-FPM';
if (Settings::Get('phpfpm.enabled_ownvhost') == '1') {
$php_sapi .= ' (+ froxlor)';
}
}
$kernel = 'unknown';
if (function_exists('posix_uname')) {
$kernel_nfo = posix_uname();
$kernel = $kernel_nfo['release'] . ' (' . $kernel_nfo['machine'] . ')';
}
$ips = [];
$ips_stmt = Database::query("SELECT CONCAT(`ip`, ' (', `port`, ')') as ipaddr FROM `" . TABLE_PANEL_IPSANDPORTS . "` ORDER BY `id`");
while ($ip = $ips_stmt->fetch(\PDO::FETCH_ASSOC)) {
$ips[] = $ip['ipaddr'];
}
$table = new Table($output);
$table
->setHeaders([
'Key', 'Value'
])
->setRows([
['Froxlor', Froxlor::getVersionString()],
['Update-channel', Settings::Get('system.update_channel')],
['Hostname', Settings::Get('system.hostname')],
['Install-dir', Froxlor::getInstallDir()],
['PHP CLI', $php_version],
['PHP SAPI', $php_sapi],
['Webserver', Settings::Get('system.webserver')],
['Kernel', $kernel],
['Database', Database::getAttribute(\PDO::ATTR_SERVER_VERSION)],
['Distro config', Settings::Get('system.distribution')],
['IP addresses', implode("\n", $ips)],
]);
$table->setStyle('box');
$table->render();
}
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);
}
} }

View File

@@ -25,20 +25,19 @@
namespace Froxlor\Cli; namespace Froxlor\Cli;
use Exception; use PDO;
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,18 +51,16 @@ final class MasterCron extends CliCommand
$this->setName('froxlor:cron'); $this->setName('froxlor:cron');
$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, 9 = re-generate rspamd configs, 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 given job or, if none given, forces re-generating of config-files (webserver, nameserver, etc.)') ->addOption('force', 'f', InputOption::VALUE_NONE, '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 = $this->validateRequirements($output); $result = self::SUCCESS;
$result = $this->validateRequirements($input, $output);
if ($result != self::SUCCESS) { if ($result != self::SUCCESS) {
// requirements failed, exit // requirements failed, exit
@@ -74,14 +71,12 @@ final class MasterCron extends CliCommand
// handle force option // handle force option
if ($input->getOption('force')) { if ($input->getOption('force')) {
if (empty($jobs) || in_array('tasks', $jobs)) { // rebuild all config files
Cronjob::inserttask(TaskId::REBUILD_VHOST); Cronjob::inserttask(TaskId::REBUILD_VHOST);
Cronjob::inserttask(TaskId::REBUILD_DNS); Cronjob::inserttask(TaskId::REBUILD_DNS);
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
Cronjob::inserttask(TaskId::CREATE_QUOTA); Cronjob::inserttask(TaskId::CREATE_QUOTA);
Cronjob::inserttask(TaskId::REBUILD_CRON); Cronjob::inserttask(TaskId::REBUILD_CRON);
$jobs[] = 'tasks'; array_push($jobs, 'tasks');
}
define('CRON_IS_FORCED', 1); define('CRON_IS_FORCED', 1);
} }
// handle debug option // handle debug option
@@ -96,9 +91,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, [TaskId::REBUILD_VHOST, TaskId::REBUILD_DNS, TaskId::REBUILD_RSPAMD, TaskId::CREATE_QUOTA, TaskId::REBUILD_CRON])) { if (in_array($ttr, [1, 4, 10, 99])) {
Cronjob::inserttask($ttr); Cronjob::inserttask($ttr);
$jobs[] = 'tasks'; array_push($jobs, 'tasks');
} else { } else {
$output->writeln('<comment>Unknown task number "' . $ttr . '"</>'); $output->writeln('<comment>Unknown task number "' . $ttr . '"</>');
} }
@@ -144,7 +139,7 @@ final class MasterCron extends CliCommand
$cronfile::run(); $cronfile::run();
} }
// free the lockfile // free the lockfile
$this->unlockJob(); $this->unlockJob($job);
} }
} }
@@ -171,16 +166,30 @@ final class MasterCron extends CliCommand
FroxlorLogger::getInstanceOf()->setCronLog(0); FroxlorLogger::getInstanceOf()->setCronLog(0);
} }
// clean up possible old login-links and 2fa tokens
Database::query("DELETE FROM `" . TABLE_PANEL_LOGINLINKS . "` WHERE `valid_until` < UNIX_TIMESTAMP()");
Database::query("DELETE FROM `" . TABLE_PANEL_2FA_TOKENS . "` 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
@@ -207,6 +216,21 @@ 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
{ {
@@ -219,7 +243,7 @@ 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(); $this->unlockJob($job);
} else { } else {
// cronjob still running, output info and stop // cronjob still running, output info and stop
$output->writeln([ $output->writeln([
@@ -240,48 +264,8 @@ final class MasterCron extends CliCommand
return true; return true;
} }
private function unlockJob(): bool private function unlockJob(string $job): 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')));
}
}
}
} }

View File

@@ -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): int protected function execute(InputInterface $input, OutputInterface $output)
{ {
$result = $this->validateRequirements($output); $result = $this->validateRequirements($input, $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 than maxlifetime and delete them // find all files older then 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");
} }
} }

View File

@@ -26,12 +26,14 @@
namespace Froxlor\Cli; namespace Froxlor\Cli;
use Exception; use Exception;
use Froxlor\Froxlor; 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\InputArgument;
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
{ {
@@ -46,9 +48,11 @@ 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): int protected function execute(InputInterface $input, OutputInterface $output)
{ {
$result = $this->validateRequirements($output); $result = self::SUCCESS;
$result = $this->validateRequirements($input, $output);
require Froxlor::getInstallDir() . '/lib/functions.php'; require Froxlor::getInstallDir() . '/lib/functions.php';
@@ -106,9 +110,6 @@ 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);

View File

@@ -43,9 +43,11 @@ 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): int protected function execute(InputInterface $input, OutputInterface $output)
{ {
$result = $this->validateRequirements($output); $result = self::SUCCESS;
$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.</>');
@@ -81,7 +83,6 @@ 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) {

View File

@@ -27,18 +27,14 @@ namespace Froxlor\Cli;
use Exception; use Exception;
use Froxlor\Froxlor; use Froxlor\Froxlor;
use Froxlor\Install\AutoUpdate;
use Froxlor\Install\Preconfig;
use Froxlor\Install\Update;
use Froxlor\Settings; use Froxlor\Settings;
use Froxlor\Install\Update;
use Froxlor\Install\AutoUpdate;
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;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;
final class UpdateCommand extends CliCommand final class UpdateCommand extends CliCommand
{ {
@@ -48,9 +44,6 @@ 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('show-update-options', 'o', InputOption::VALUE_NONE, 'Show possible update option parameter for the update if any. Only usable in combination with "check-only".')
->addOption('update-options', 'O', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Parameter list of update options.')
->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.');
@@ -60,40 +53,7 @@ final class UpdateCommand extends CliCommand
{ {
$result = self::SUCCESS; $result = self::SUCCESS;
// database update only $result = $this->validateRequirements($input, $output);
if ($input->getOption('database')) {
$result = $this->validateRequirements($output, true);
if ($result == self::SUCCESS) {
require Froxlor::getInstallDir() . '/lib/functions.php';
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
$output->writeln('<info>' . lng('update.dbupdate_required') . '</>');
if ($input->getOption('check-only')) {
$output->writeln('<comment>Doing nothing because of "check-only" flag.</>');
$this->askUpdateOptions($input, $output, null, false);
} else {
$yestoall = $input->getOption('yes-to-all') !== false;
$helper = $this->getHelper('question');
$this->askUpdateOptions($input, $output, $helper, $yestoall);
$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';
@@ -111,7 +71,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') != 'stable' ? Settings::Get('system.update_channel') . ' ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]); $text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') == 'testing' ? 'testing ' : ''), 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]);
} }
@@ -162,7 +122,6 @@ final class UpdateCommand extends CliCommand
// check whether we only wanted to check // check whether we only wanted to check
if ($input->getOption('check-only')) { if ($input->getOption('check-only')) {
//$output->writeln('<comment>Not proceeding as "check-only" is specified</>'); //$output->writeln('<comment>Not proceeding as "check-only" is specified</>');
$this->askUpdateOptions($input, $output, null, false);
return $result; return $result;
} else { } else {
$yestoall = $input->getOption('yes-to-all') !== false; $yestoall = $input->getOption('yes-to-all') !== false;
@@ -185,12 +144,9 @@ final class UpdateCommand extends CliCommand
if ($auex == 0) { if ($auex == 0) {
$output->writeln("<info>Froxlor files updated successfully.</>"); $output->writeln("<info>Froxlor files updated successfully.</>");
$result = self::SUCCESS; $result = self::SUCCESS;
$this->askUpdateOptions($input, $output, $helper, $yestoall);
$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->runUpdate($output, true); $result = $this->updateDatabase();
} }
} else { } else {
$errmsg = 'error.autoupdate_' . $auex; $errmsg = 'error.autoupdate_' . $auex;
@@ -209,141 +165,12 @@ final class UpdateCommand extends CliCommand
return $result; return $result;
} }
/**
* @param InputInterface $input
* @param OutputInterface $output
* @param $helper
* @param bool $yestoall
* @return void
*/
private function askUpdateOptions(InputInterface $input, OutputInterface $output, $helper, bool $yestoall = false)
{
// check for preconfigs
$preconfig = Preconfig::getPreConfig(true);
$show_options_only = $input->getOption('show-update-options') !== false;
if (!is_null($helper) && $show_options_only) {
$output->writeln('<comment>Unsetting "show-update-options" due to not being called with "check-only".</>');
$show_options_only = false;
}
$update_options = [];
// set parameters
$uOptions = $input->getOption('update-options');
if (!empty($uOptions)) {
$options_value = [];
foreach ($uOptions as $givenOption) {
$optVal = explode("=", $givenOption);
if (count($optVal) == 2) {
$options_value[$optVal[0]] = $optVal[1];
}
}
}
if (!empty($preconfig)) {
krsort($preconfig);
foreach ($preconfig as $section) {
if (!$show_options_only) {
$output->writeln("<info>Updater questions for " . $section['title'] . "</>");
}
foreach ($section['fields'] as $update_field => $metainfo) {
if (isset($options_value[$update_field])) {
$output->writeln('Setting given parameter "' . $update_field . '" to "' . $options_value[$update_field] . '"');
$_POST[$update_field] = $options_value[$update_field];
continue;
}
$default = null;
$question_text = html_entity_decode(strip_tags($metainfo['label']), ENT_QUOTES | ENT_IGNORE, "UTF-8");
if ($metainfo['type'] == 'checkbox') {
$default = (int)$metainfo['checked'];
if ($show_options_only) {
$update_options[] = [
'name' => $update_field,
'question' => $question_text,
'default' => $default,
'choices' => '0: No' . PHP_EOL . '1: Yes' . PHP_EOL
];
} else {
$question = new ConfirmationQuestion($question_text . ' [' . ($metainfo['checked'] ? 'yes' : 'no') . '] ', (bool)$metainfo['checked'], '/^(y|j)/i');
}
} elseif ($metainfo['type'] == 'select') {
$default = $metainfo['selected'];
$choices = "";
foreach (array_values($metainfo['select_var'] ?? []) as $index => $choice) {
$choices .= $index . ': ' . $choice . PHP_EOL;
}
if ($show_options_only) {
$update_options[] = [
'name' => $update_field,
'question' => $question_text,
'default' => !empty($default) ? $default : '-',
'choices' => $choices
];
} else {
$question = new ChoiceQuestion(
$question_text,
array_values($metainfo['select_var'] ?? []),
$metainfo['selected']
);
$question->setValidator(function ($answer) use ($metainfo): string {
$key = array_keys($metainfo['select_var'])[(int)$answer] ?? false; // Find the key based on the selected value
if ($key === false) {
throw new \RuntimeException('Invalid selection.');
}
return $key;
});
}
} elseif ($metainfo['type'] == 'text') {
$default = $metainfo['value'] ?? '';
if ($show_options_only) {
$update_options[] = [
'name' => $update_field,
'question' => $question_text,
'default' => $default,
'choices' => PHP_EOL
];
} else {
$question = new Question($question_text . (!empty($metainfo['value']) ? ' [' . $metainfo['value'] . ']' : ''), $default);
$question->setValidator(function (string $answer) use ($metainfo): string {
if (($metainfo['mandatory'] ?? false) && empty($answer)) {
throw new \RuntimeException(
'Answer cannot be empty'
);
}
if (!empty($metainfo['pattern'] ?? "") && !preg_match("/" . $metainfo['pattern'] . "/", $answer)) {
throw new \RuntimeException('Answer does not seem to be in valid format');
}
return $answer;
});
}
} else {
$output->writeln("<error>Unknown type " . $metainfo['type'] . "</error>");
continue;
}
if (!$show_options_only) {
if ($yestoall) {
$_POST[$update_field] = $default;
} else {
$_POST[$update_field] = $helper->ask($input, $output, $question);
}
}
}
}
if ($show_options_only) {
$io = new SymfonyStyle($input, $output);
$io->table(
['Parameter', 'Description', 'Default', 'Choices'],
$update_options
);
}
}
}
private function mailNotify(InputInterface $input, OutputInterface $output) private function mailNotify(InputInterface $input, OutputInterface $output)
{ {
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') != 'stable' ? Settings::Get('system.update_channel') . ' ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]); $text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') == 'testing' ? 'testing ' : ''), 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');
@@ -355,4 +182,22 @@ 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));
}
} }

View File

@@ -26,15 +26,15 @@
namespace Froxlor\Cli; namespace Froxlor\Cli;
use Exception; use Exception;
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\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
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): int protected function execute(InputInterface $input, OutputInterface $output)
{ {
$result = self::SUCCESS; $result = self::SUCCESS;
$result = $this->validateRequirements($output); $result = $this->validateRequirements($input, $output);
require Froxlor::getInstallDir() . '/lib/functions.php'; require Froxlor::getInstallDir() . '/lib/functions.php';

View File

@@ -48,12 +48,11 @@ final class ValidateAcmeWebroot extends CliCommand
$this->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for confirmation, update files if necessary'); $this->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for confirmation, update files if necessary');
} }
/** protected function execute(InputInterface $input, OutputInterface $output)
* @throws \Exception
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$result = $this->validateRequirements($output, true); $result = self::SUCCESS;
$result = $this->validateRequirements($input, $output, true);
$io = new SymfonyStyle($input, $output); $io = new SymfonyStyle($input, $output);
@@ -139,6 +138,8 @@ final class ValidateAcmeWebroot extends CliCommand
$io->info("Domain '" . $domain . "' Le_Webroot value is correct"); $io->info("Domain '" . $domain . "' Le_Webroot value is correct");
} }
break; break;
} else {
continue;
} }
} }
} }

View File

@@ -91,9 +91,6 @@ class ConfigDaemon
$this->fullxml = $xml; $this->fullxml = $xml;
$this->xpath = $xpath; $this->xpath = $xpath;
$this->daemon = $this->fullxml->xpath($this->xpath); $this->daemon = $this->fullxml->xpath($this->xpath);
if (count($this->daemon) !== 1) {
throw new Exception('XPath "' . $this->xpath . '" didn\'t return exactly one element');
}
$attributes = $this->daemon[0]->attributes(); $attributes = $this->daemon[0]->attributes();
if ($attributes['title'] != '') { if ($attributes['title'] != '') {
$this->title = $this->parseContent((string)$attributes['title']); $this->title = $this->parseContent((string)$attributes['title']);
@@ -412,7 +409,7 @@ class ConfigDaemon
} }
$return[] = [ $return[] = [
'type' => 'command', 'type' => 'command',
'content' => '[ -f ' . $this->parseContent($attributes['name']) . ' ] && ' . $cmd . ' "' . $this->parseContent($attributes['name']) . '" "' . $this->parseContent($attributes['name']) . '.frx.bak"', 'content' => $cmd . ' "' . $this->parseContent($attributes['name']) . '" "' . $this->parseContent($attributes['name']) . '.frx.bak"',
'execute' => "pre" 'execute' => "pre"
]; ];
} }

View File

@@ -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>' => $sql['socket'] ?? null, '<SQL_SOCKET>' => isset($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,15 +127,12 @@ 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>' => Froxlor::getInstallDir(), '<BASE_PATH>' => FileDir::makeCorrectDir(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 = "";

View File

@@ -55,18 +55,19 @@ 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, not creating any zones...'); $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'No domains found for nameserver-config, skipping...');
$this->bindconf_file = ''; return;
} 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) { foreach ($domains as $domain) {
if ($domain['is_child']) { if ($domain['ismainbutsubto'] > 0) {
// domains that are subdomains to other main domains are handled by recursion within walkDomainList() // domains with ismainbutsubto>0 are handled by recursion within walkDomainList()
continue; 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');
fwrite($bindconf_file_handler, $this->bindconf_file); fwrite($bindconf_file_handler, $this->bindconf_file);
@@ -113,7 +114,7 @@ class Bind extends DnsBase
$isFroxlorHostname = true; $isFroxlorHostname = true;
} }
if (!$domain['is_child']) { if ($domain['ismainbutsubto'] == 0) {
$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']);

View File

@@ -26,7 +26,6 @@
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;
@@ -117,6 +116,83 @@ abstract class DnsBase
} }
} }
public function writeDKIMconfigs()
{
if (Settings::Get('dkim.use_dkim') == '1') {
if (!file_exists(FileDir::makeCorrectDir(Settings::Get('dkim.dkim_prefix')))) {
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir(Settings::Get('dkim.dkim_prefix'))));
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir(Settings::Get('dkim.dkim_prefix'))));
}
$dkimdomains = '';
$dkimkeys = '';
$result_domains_stmt = Database::query("
SELECT `id`, `domain`, `dkim`, `dkim_id`, `dkim_pubkey`, `dkim_privkey`
FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `dkim` = '1' ORDER BY `id` ASC
");
while ($domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
$privkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/mx.' . $domain['domain'] . '.' . Settings::Get('dkim.privkeysuffix'));
$pubkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/mx.' . $domain['domain'] . '.public');
if ($domain['dkim_privkey'] == '' || $domain['dkim_pubkey'] == '') {
$max_dkim_id_stmt = Database::query("SELECT MAX(`dkim_id`) as `max_dkim_id` FROM `" . TABLE_PANEL_DOMAINS . "`");
$max_dkim_id = $max_dkim_id_stmt->fetch(PDO::FETCH_ASSOC);
$domain['dkim_id'] = (int)$max_dkim_id['max_dkim_id'] + 1;
FileDir::safe_exec('openssl genrsa -out ' . escapeshellarg($privkey_filename) . ' ' . Settings::Get('dkim.dkim_keylength'));
$domain['dkim_privkey'] = file_get_contents($privkey_filename);
FileDir::safe_exec("chmod 0640 " . escapeshellarg($privkey_filename));
FileDir::safe_exec('openssl rsa -in ' . escapeshellarg($privkey_filename) . ' -pubout -outform pem -out ' . escapeshellarg($pubkey_filename));
$domain['dkim_pubkey'] = file_get_contents($pubkey_filename);
FileDir::safe_exec("chmod 0664 " . escapeshellarg($pubkey_filename));
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
`dkim_id` = :dkimid,
`dkim_privkey` = :privkey,
`dkim_pubkey` = :pubkey
WHERE `id` = :id
");
$upd_data = [
'dkimid' => $domain['dkim_id'],
'privkey' => $domain['dkim_privkey'],
'pubkey' => $domain['dkim_pubkey'],
'id' => $domain['id']
];
Database::pexecute($upd_stmt, $upd_data);
}
if (!file_exists($privkey_filename) && $domain['dkim_privkey'] != '') {
$privkey_file_handler = fopen($privkey_filename, "w");
fwrite($privkey_file_handler, $domain['dkim_privkey']);
fclose($privkey_file_handler);
FileDir::safe_exec("chmod 0640 " . escapeshellarg($privkey_filename));
}
if (!file_exists($pubkey_filename) && $domain['dkim_pubkey'] != '') {
$pubkey_file_handler = fopen($pubkey_filename, "w");
fwrite($pubkey_file_handler, $domain['dkim_pubkey']);
fclose($pubkey_file_handler);
FileDir::safe_exec("chmod 0644 " . escapeshellarg($pubkey_filename));
}
$dkimdomains .= $domain['domain'] . "\n";
$dkimkeys .= "*@" . $domain['domain'] . ":" . $domain['domain'] . ":" . $privkey_filename . "\n";
}
$dkimdomains_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/' . Settings::Get('dkim.dkim_domains'));
$dkimdomains_file_handler = fopen($dkimdomains_filename, "w");
fwrite($dkimdomains_file_handler, $dkimdomains);
fclose($dkimdomains_file_handler);
$dkimkeys_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/' . Settings::Get('dkim.dkim_dkimkeys'));
$dkimkeys_file_handler = fopen($dkimkeys_filename, "w");
fwrite($dkimkeys_file_handler, $dkimkeys);
fclose($dkimkeys_file_handler);
FileDir::safe_exec(escapeshellcmd(Settings::Get('dkim.dkimrestart_command')));
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Dkim-milter reloaded');
}
}
protected function getDomainList() protected function getDomainList()
{ {
$result_domains_stmt = Database::query(" $result_domains_stmt = Database::query("
@@ -132,15 +208,16 @@ 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
`" . TABLE_PANEL_DOMAINS . "` `d` `" . TABLE_PANEL_DOMAINS . "` `d`
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`) LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
WHERE WHERE
`d`.`isbinddomain` = '1' `d`.`isbinddomain` = '1' aND `d`.`deactivated` = '0'
ORDER BY ORDER BY
LENGTH(`d`.`domain`), `d`.`domain` ASC `d`.`domain` ASC
"); ");
$domains = []; $domains = [];
@@ -162,10 +239,11 @@ 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[0] = $hostname_arr; $domains['none'] = $hostname_arr;
} }
if (empty($domains)) { if (empty($domains)) {
@@ -177,23 +255,18 @@ abstract class DnsBase
if (!isset($domains[$key]['children'])) { if (!isset($domains[$key]['children'])) {
$domains[$key]['children'] = []; $domains[$key]['children'] = [];
} }
if (!isset($domains[$key]['is_child'])) { if ($domains[$key]['ismainbutsubto'] > 0) {
$domains[$key]['is_child'] = false; if (isset($domains[$domains[$key]['ismainbutsubto']])) {
} $domains[$domains[$key]['ismainbutsubto']]['children'][] = $domains[$key]['id'];
$children = Domain::getMainSubdomainIds($key); } else {
if (count($children) > 0) { $domains[$key]['ismainbutsubto'] = 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, ' ') . "list of child domain ids"); $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");
foreach ($domains as $domain) { foreach ($domains as $domain) {
$logLine = str_pad($domain['id'], 9, ' ') . str_pad($domain['domain'], 40, ' ') . join(', ', $domain['children']); $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']);
$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